001/* 002 * $Id: GenPolynomial.java 5372 2015-12-29 15:07:37Z kredel $ 003 */ 004 005package edu.jas.poly; 006 007 008import java.util.Collections; 009import java.util.Iterator; 010import java.util.Map; 011import java.util.SortedMap; 012import java.util.TreeMap; 013import java.util.List; 014import java.util.ArrayList; 015 016import org.apache.log4j.Logger; 017 018import edu.jas.kern.PreemptingException; 019import edu.jas.kern.PrettyPrint; 020import edu.jas.structure.NotInvertibleException; 021import edu.jas.structure.RingElem; 022import edu.jas.structure.UnaryFunctor; 023 024 025/** 026 * GenPolynomial generic polynomials implementing RingElem. n-variate ordered 027 * polynomials over C. Objects of this class are intended to be immutable. The 028 * implementation is based on TreeMap respectively SortedMap from exponents to 029 * coefficients. Only the coefficients are modeled with generic types, the 030 * exponents are fixed to ExpVector with long entries (this will eventually be 031 * changed in the future). C can also be a non integral domain, e.g. a 032 * ModInteger, i.e. it may contain zero divisors, since multiply() does now 033 * check for zeros. <b>Note:</b> multiply() now checks for wrong method dispatch 034 * for GenSolvablePolynomial. 035 * @param <C> coefficient type 036 * @author Heinz Kredel 037 */ 038public class GenPolynomial<C extends RingElem<C>> implements RingElem<GenPolynomial<C>>, /* not yet Polynomial<C> */ 039Iterable<Monomial<C>> { 040 041 042 /** 043 * The factory for the polynomial ring. 044 */ 045 public final GenPolynomialRing<C> ring; 046 047 048 /** 049 * The data structure for polynomials. 050 */ 051 protected final SortedMap<ExpVector, C> val; // do not change to TreeMap 052 053 054 private static final Logger logger = Logger.getLogger(GenPolynomial.class); 055 056 057 private final boolean debug = logger.isDebugEnabled(); 058 059 060 // protected GenPolynomial() { ring = null; val = null; } // don't use 061 062 063 /** 064 * Private constructor for GenPolynomial. 065 * @param r polynomial ring factory. 066 * @param t TreeMap with correct ordering. 067 */ 068 private GenPolynomial(GenPolynomialRing<C> r, TreeMap<ExpVector, C> t) { 069 ring = r; 070 val = t; 071 if (ring.checkPreempt) { 072 if (Thread.currentThread().isInterrupted()) { 073 logger.debug("throw PreemptingException"); 074 throw new PreemptingException(); 075 } 076 } 077 } 078 079 080 /** 081 * Constructor for zero GenPolynomial. 082 * @param r polynomial ring factory. 083 */ 084 public GenPolynomial(GenPolynomialRing<C> r) { 085 this(r, new TreeMap<ExpVector, C>(r.tord.getDescendComparator())); 086 } 087 088 089 /** 090 * Constructor for GenPolynomial c * x<sup>e</sup>. 091 * @param r polynomial ring factory. 092 * @param c coefficient. 093 * @param e exponent. 094 */ 095 public GenPolynomial(GenPolynomialRing<C> r, C c, ExpVector e) { 096 this(r); 097 if (!c.isZERO()) { 098 val.put(e, c); 099 } 100 } 101 102 103 /** 104 * Constructor for GenPolynomial c * x<sup>0</sup>. 105 * @param r polynomial ring factory. 106 * @param c coefficient. 107 */ 108 public GenPolynomial(GenPolynomialRing<C> r, C c) { 109 this(r, c, r.evzero); 110 } 111 112 113 /** 114 * Constructor for GenPolynomial x<sup>e</sup>. 115 * @param r polynomial ring factory. 116 * @param e exponent. 117 */ 118 public GenPolynomial(GenPolynomialRing<C> r, ExpVector e) { 119 this(r, r.coFac.getONE(), e); 120 } 121 122 123 /** 124 * Constructor for GenPolynomial. 125 * @param r polynomial ring factory. 126 * @param v the SortedMap of some other polynomial. 127 */ 128 protected GenPolynomial(GenPolynomialRing<C> r, SortedMap<ExpVector, C> v) { 129 this(r); 130 if (v.size() > 0) { 131 GenPolynomialRing.creations++; 132 val.putAll(v); // assume no zero coefficients and val is empty 133 } 134 } 135 136 137 /** 138 * Get the corresponding element factory. 139 * @return factory for this Element. 140 * @see edu.jas.structure.Element#factory() 141 */ 142 public GenPolynomialRing<C> factory() { 143 return ring; 144 } 145 146 147 /** 148 * Copy this GenPolynomial. 149 * @return copy of this. 150 */ 151 public GenPolynomial<C> copy() { 152 return new GenPolynomial<C>(ring, this.val); 153 } 154 155 156 /** 157 * Length of GenPolynomial. 158 * @return number of coefficients of this GenPolynomial. 159 */ 160 public int length() { 161 return val.size(); 162 } 163 164 165 /** 166 * ExpVector to coefficient map of GenPolynomial. 167 * @return val as unmodifiable SortedMap. 168 */ 169 public SortedMap<ExpVector, C> getMap() { 170 // return val; 171 return Collections.<ExpVector, C> unmodifiableSortedMap(val); 172 } 173 174 175 /** 176 * Put an ExpVector to coefficient entry into the internal map of this 177 * GenPolynomial. <b>Note:</b> Do not use this method unless you are 178 * constructing a new polynomial. this is modified and breaks the 179 * immutability promise of this class. 180 * @param c coefficient. 181 * @param e exponent. 182 */ 183 public void doPutToMap(ExpVector e, C c) { 184 if (debug) { 185 C a = val.get(e); 186 if (a != null) { 187 logger.error("map entry exists " + e + " to " + a + " new " + c); 188 } 189 } 190 if (!c.isZERO()) { 191 val.put(e, c); 192 } 193 } 194 195 196 /** 197 * Remove an ExpVector to coefficient entry from the internal map of this 198 * GenPolynomial. <b>Note:</b> Do not use this method unless you are 199 * constructing a new polynomial. this is modified and breaks the 200 * immutability promise of this class. 201 * @param e exponent. 202 * @param c expected coefficient, null for ignore. 203 */ 204 public void doRemoveFromMap(ExpVector e, C c) { 205 C b = val.remove(e); 206 if (debug) { 207 if (c == null) { // ignore b 208 return; 209 } 210 if (!c.equals(b)) { 211 logger.error("map entry wrong " + e + " to " + c + " old " + b); 212 } 213 } 214 } 215 216 217 /** 218 * Put an a sorted map of exponents to coefficients into the internal map of 219 * this GenPolynomial. <b>Note:</b> Do not use this method unless you are 220 * constructing a new polynomial. this is modified and breaks the 221 * immutability promise of this class. 222 * @param vals sorted map of exponents and coefficients. 223 */ 224 public void doPutToMap(SortedMap<ExpVector, C> vals) { 225 for (Map.Entry<ExpVector, C> me : vals.entrySet()) { 226 ExpVector e = me.getKey(); 227 if (debug) { 228 C a = val.get(e); 229 if (a != null) { 230 logger.error("map entry exists " + e + " to " + a + " new " + me.getValue()); 231 } 232 } 233 C c = me.getValue(); 234 if (!c.isZERO()) { 235 val.put(e, c); 236 } 237 } 238 } 239 240 241 /** 242 * String representation of GenPolynomial. 243 * @see java.lang.Object#toString() 244 */ 245 @Override 246 public String toString() { 247 if (ring.vars != null) { 248 return toString(ring.vars); 249 } 250 StringBuffer s = new StringBuffer(); 251 s.append(this.getClass().getSimpleName() + ":"); 252 s.append(ring.coFac.getClass().getSimpleName()); 253 if (ring.coFac.characteristic().signum() != 0) { 254 s.append("(" + ring.coFac.characteristic() + ")"); 255 } 256 s.append("[ "); 257 boolean first = true; 258 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 259 if (first) { 260 first = false; 261 } else { 262 s.append(", "); 263 } 264 s.append(m.getValue().toString()); 265 s.append(" "); 266 s.append(m.getKey().toString()); 267 } 268 s.append(" ] "); // no not use: ring.toString() ); 269 return s.toString(); 270 } 271 272 273 /** 274 * String representation of GenPolynomial. 275 * @param v names for variables. 276 * @see java.lang.Object#toString() 277 */ 278 public String toString(String[] v) { 279 StringBuffer s = new StringBuffer(); 280 if (PrettyPrint.isTrue()) { 281 if (val.isEmpty()) { 282 s.append("0"); 283 } else { 284 // s.append( "( " ); 285 boolean first = true; 286 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 287 C c = m.getValue(); 288 if (first) { 289 first = false; 290 } else { 291 if (c.signum() < 0) { 292 s.append(" - "); 293 c = c.negate(); 294 } else { 295 s.append(" + "); 296 } 297 } 298 ExpVector e = m.getKey(); 299 if (!c.isONE() || e.isZERO()) { 300 String cs = c.toString(); 301 //if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { 302 if (cs.indexOf("-") >= 0 || cs.indexOf("+") >= 0) { 303 s.append("( "); 304 s.append(cs); 305 s.append(" )"); 306 } else { 307 s.append(cs); 308 } 309 s.append(" "); 310 } 311 if (e != null && v != null) { 312 s.append(e.toString(v)); 313 } else { 314 s.append(e); 315 } 316 } 317 //s.append(" )"); 318 } 319 } else { 320 s.append(this.getClass().getSimpleName() + "[ "); 321 if (val.isEmpty()) { 322 s.append("0"); 323 } else { 324 boolean first = true; 325 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 326 C c = m.getValue(); 327 if (first) { 328 first = false; 329 } else { 330 if (c.signum() < 0) { 331 s.append(" - "); 332 c = c.negate(); 333 } else { 334 s.append(" + "); 335 } 336 } 337 ExpVector e = m.getKey(); 338 if (!c.isONE() || e.isZERO()) { 339 s.append(c.toString()); 340 s.append(" "); 341 } 342 s.append(e.toString(v)); 343 } 344 } 345 s.append(" ] "); // no not use: ring.toString() ); 346 } 347 return s.toString(); 348 } 349 350 351 /** 352 * Get a scripting compatible string representation. 353 * @return script compatible representation for this Element. 354 * @see edu.jas.structure.Element#toScript() 355 */ 356 @Override 357 public String toScript() { 358 // Python case 359 if (isZERO()) { 360 return "0"; 361 } 362 StringBuffer s = new StringBuffer(); 363 if (val.size() > 1) { 364 s.append("( "); 365 } 366 String[] v = ring.vars; 367 if (v == null) { 368 v = GenPolynomialRing.newVars("x", ring.nvar); 369 } 370 boolean first = true; 371 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 372 C c = m.getValue(); 373 if (first) { 374 first = false; 375 } else { 376 if (c.signum() < 0) { 377 s.append(" - "); 378 c = c.negate(); 379 } else { 380 s.append(" + "); 381 } 382 } 383 ExpVector e = m.getKey(); 384 String cs = c.toScript(); 385 boolean parenthesis = (cs.indexOf("-") >= 0 || cs.indexOf("+") >= 0); 386 if (!c.isONE() || e.isZERO()) { 387 if (parenthesis) { 388 s.append("( "); 389 } 390 s.append(cs); 391 if (parenthesis) { 392 s.append(" )"); 393 } 394 if (!e.isZERO()) { 395 s.append(" * "); 396 } 397 } 398 s.append(e.toScript(v)); 399 } 400 if (val.size() > 1) { 401 s.append(" )"); 402 } 403 return s.toString(); 404 } 405 406 407 /** 408 * Get a scripting compatible string representation of the factory. 409 * @return script compatible representation for this ElemFactory. 410 * @see edu.jas.structure.Element#toScriptFactory() 411 */ 412 @Override 413 public String toScriptFactory() { 414 // Python case 415 return factory().toScript(); 416 } 417 418 419 /** 420 * Is GenPolynomial<C> zero. 421 * @return If this is 0 then true is returned, else false. 422 * @see edu.jas.structure.RingElem#isZERO() 423 */ 424 public boolean isZERO() { 425 return val.isEmpty(); 426 } 427 428 429 /** 430 * Is GenPolynomial<C> one. 431 * @return If this is 1 then true is returned, else false. 432 * @see edu.jas.structure.RingElem#isONE() 433 */ 434 public boolean isONE() { 435 if (val.size() != 1) { 436 return false; 437 } 438 C c = val.get(ring.evzero); 439 if (c == null) { 440 return false; 441 } 442 return c.isONE(); 443 } 444 445 446 /** 447 * Is GenPolynomial<C> a unit. 448 * @return If this is a unit then true is returned, else false. 449 * @see edu.jas.structure.RingElem#isUnit() 450 */ 451 public boolean isUnit() { 452 if (val.size() != 1) { 453 return false; 454 } 455 C c = val.get(ring.evzero); 456 if (c == null) { 457 return false; 458 } 459 return c.isUnit(); 460 } 461 462 463 /** 464 * Is GenPolynomial<C> a constant. 465 * @return If this is a constant polynomial then true is returned, else 466 * false. 467 */ 468 public boolean isConstant() { 469 if (val.size() != 1) { 470 return false; 471 } 472 C c = val.get(ring.evzero); 473 if (c == null) { 474 return false; 475 } 476 return true; 477 } 478 479 480 /** 481 * Is GenPolynomial<C> homogeneous. 482 * @return true, if this is homogeneous, else false. 483 */ 484 public boolean isHomogeneous() { 485 if (val.size() <= 1) { 486 return true; 487 } 488 long deg = -1; 489 for (ExpVector e : val.keySet()) { 490 if (deg < 0) { 491 deg = e.totalDeg(); 492 } else if (deg != e.totalDeg()) { 493 return false; 494 } 495 } 496 return true; 497 } 498 499 500 /** 501 * Comparison with any other object. 502 * @see java.lang.Object#equals(java.lang.Object) 503 */ 504 @Override 505 @SuppressWarnings("unchecked") 506 public boolean equals(Object B) { 507 if (B == null) { 508 return false; 509 } 510 if (!(B instanceof GenPolynomial)) { 511 return false; 512 } 513 GenPolynomial<C> a = (GenPolynomial<C>) B; 514 return this.compareTo(a) == 0; 515 } 516 517 518 /** 519 * Hash code for this polynomial. 520 * @see java.lang.Object#hashCode() 521 */ 522 @Override 523 public int hashCode() { 524 int h; 525 h = (ring.hashCode() << 27); 526 h += val.hashCode(); 527 return h; 528 } 529 530 531 /** 532 * GenPolynomial comparison. 533 * @param b GenPolynomial. 534 * @return sign(this-b). 535 */ 536 public int compareTo(GenPolynomial<C> b) { 537 if (b == null) { 538 return 1; 539 } 540 SortedMap<ExpVector, C> av = this.val; 541 SortedMap<ExpVector, C> bv = b.val; 542 Iterator<Map.Entry<ExpVector, C>> ai = av.entrySet().iterator(); 543 Iterator<Map.Entry<ExpVector, C>> bi = bv.entrySet().iterator(); 544 int s = 0; 545 int c = 0; 546 while (ai.hasNext() && bi.hasNext()) { 547 Map.Entry<ExpVector, C> aie = ai.next(); 548 Map.Entry<ExpVector, C> bie = bi.next(); 549 ExpVector ae = aie.getKey(); 550 ExpVector be = bie.getKey(); 551 s = ae.compareTo(be); 552 if (s != 0) { 553 //System.out.println("s = " + s + ", " + ring.toScript(ae) + ", " + ring.toScript(be)); 554 return s; 555 } 556 if (c == 0) { 557 C ac = aie.getValue(); //av.get(ae); 558 C bc = bie.getValue(); //bv.get(be); 559 c = ac.compareTo(bc); 560 } 561 } 562 if (ai.hasNext()) { 563 //System.out.println("ai = " + ai); 564 return 1; 565 } 566 if (bi.hasNext()) { 567 //System.out.println("bi = " + bi); 568 return -1; 569 } 570 //if (c != 0) { 571 //System.out.println("c = " + c); 572 //} 573 // now all keys are equal 574 return c; 575 } 576 577 578 /** 579 * GenPolynomial signum. 580 * @return sign(ldcf(this)). 581 */ 582 public int signum() { 583 if (this.isZERO()) { 584 return 0; 585 } 586 ExpVector t = val.firstKey(); 587 C c = val.get(t); 588 return c.signum(); 589 } 590 591 592 /** 593 * Number of variables. 594 * @return ring.nvar. 595 */ 596 public int numberOfVariables() { 597 return ring.nvar; 598 } 599 600 601 /** 602 * Leading monomial. 603 * @return first map entry. 604 */ 605 public Map.Entry<ExpVector, C> leadingMonomial() { 606 if (val.isEmpty()) { 607 return null; 608 } 609 Iterator<Map.Entry<ExpVector, C>> ai = val.entrySet().iterator(); 610 return ai.next(); 611 } 612 613 614 /** 615 * Leading exponent vector. 616 * @return first exponent. 617 */ 618 public ExpVector leadingExpVector() { 619 if (val.isEmpty()) { 620 return null; // ring.evzero? needs many changes 621 } 622 return val.firstKey(); 623 } 624 625 626 /** 627 * Trailing exponent vector. 628 * @return last exponent. 629 */ 630 public ExpVector trailingExpVector() { 631 if (val.isEmpty()) { 632 return null; //ring.evzero; // or null ?; 633 } 634 return val.lastKey(); 635 } 636 637 638 /** 639 * Leading base coefficient. 640 * @return first coefficient. 641 */ 642 public C leadingBaseCoefficient() { 643 if (val.isEmpty()) { 644 return ring.coFac.getZERO(); 645 } 646 return val.get(val.firstKey()); 647 } 648 649 650 /** 651 * Trailing base coefficient. 652 * @return coefficient of constant term. 653 */ 654 public C trailingBaseCoefficient() { 655 C c = val.get(ring.evzero); 656 if (c == null) { 657 return ring.coFac.getZERO(); 658 } 659 return c; 660 } 661 662 663 /** 664 * Coefficient. 665 * @param e exponent. 666 * @return coefficient for given exponent. 667 */ 668 public C coefficient(ExpVector e) { 669 C c = val.get(e); 670 if (c == null) { 671 c = ring.coFac.getZERO(); 672 } 673 return c; 674 } 675 676 677 /** 678 * Reductum. 679 * @return this - leading monomial. 680 */ 681 public GenPolynomial<C> reductum() { 682 if (val.size() <= 1) { 683 return ring.getZERO(); 684 } 685 Iterator<ExpVector> ai = val.keySet().iterator(); 686 ExpVector lt = ai.next(); 687 lt = ai.next(); // size > 1 688 SortedMap<ExpVector, C> red = val.tailMap(lt); 689 GenPolynomial<C> r = ring.getZERO().copy(); 690 r.doPutToMap(red); // new GenPolynomial<C>(ring, red); 691 return r; 692 } 693 694 695 /** 696 * Degree in variable i. 697 * @return maximal degree in the variable i. 698 */ 699 public long degree(int i) { 700 if (val.isEmpty()) { 701 return -1L; // 0 or -1 ?; 702 } 703 int j; 704 if (i >= 0) { 705 j = ring.nvar - 1 - i; 706 } else { // python like -1 means main variable 707 j = ring.nvar + i; 708 } 709 long deg = 0; 710 for (ExpVector e : val.keySet()) { 711 long d = e.getVal(j); 712 if (d > deg) { 713 deg = d; 714 } 715 } 716 return deg; 717 } 718 719 720 /** 721 * Maximal degree. 722 * @return maximal degree in any variables. 723 */ 724 public long degree() { 725 if (val.isEmpty()) { 726 return -1L; // 0 or -1 ?; 727 } 728 long deg = 0; 729 for (ExpVector e : val.keySet()) { 730 long d = e.maxDeg(); 731 if (d > deg) { 732 deg = d; 733 } 734 } 735 return deg; 736 } 737 738 739 /** 740 * Total degree. 741 * @return total degree in any variables. 742 */ 743 public long totalDegree() { 744 if (val.isEmpty()) { 745 return -1L; // 0 or -1 ?; 746 } 747 long deg = 0; 748 for (ExpVector e : val.keySet()) { 749 long d = e.totalDeg(); 750 if (d > deg) { 751 deg = d; 752 } 753 } 754 return deg; 755 } 756 757 758 /** 759 * Weight degree. 760 * @return weight degree in all variables. 761 */ 762 public long weightDegree() { 763 long[][] w = ring.tord.getWeight(); 764 if (w == null || w.length == 0) { 765 return totalDegree(); // assume weight 1 766 } 767 if (val.isEmpty()) { 768 return -1L; // 0 or -1 ?; 769 } 770 long deg = 0; 771 for (ExpVector e : val.keySet()) { 772 long d = e.weightDeg(w); 773 if (d > deg) { 774 deg = d; 775 } 776 } 777 return deg; 778 } 779 780 781 /** 782 * Leading weight polynomial. 783 * @return polynomial with terms of maximal weight degree. 784 */ 785 public GenPolynomial<C> leadingWeightPolynomial() { 786 if (val.isEmpty()) { 787 return ring.getZERO(); 788 } 789 long[][] w = ring.tord.getWeight(); 790 long maxw; 791 if (w == null || w.length == 0) { 792 maxw = totalDegree(); // assume weights = 1 793 } else { 794 maxw = weightDegree(); 795 } 796 GenPolynomial<C> wp = new GenPolynomial<C>(ring); 797 for (Map.Entry<ExpVector,C> m : val.entrySet()) { 798 ExpVector e = m.getKey(); 799 long d = e.weightDeg(w); 800 if (d >= maxw) { 801 wp.val.put(e, m.getValue()); 802 } 803 } 804 return wp; 805 } 806 807 808 /** 809 * Is GenPolynomial<C> homogeneous with respect to a weight. 810 * @return true, if this is weight homogeneous, else false. 811 */ 812 public boolean isWeightHomogeneous() { 813 if (val.size() <= 1) { 814 return true; 815 } 816 long[][] w = ring.tord.getWeight(); 817 if (w == null || w.length == 0) { 818 return isHomogeneous(); // assume weights = 1 819 } 820 long deg = -1; 821 for (ExpVector e : val.keySet()) { 822 if (deg < 0) { 823 deg = e.weightDeg(w); 824 } else if (deg != e.weightDeg(w)) { 825 return false; 826 } 827 } 828 return true; 829 } 830 831 832 /** 833 * Maximal degree vector. 834 * @return maximal degree vector of all variables. 835 */ 836 public ExpVector degreeVector() { 837 if (val.isEmpty()) { 838 return null; //deg; 839 } 840 ExpVector deg = ring.evzero; 841 for (ExpVector e : val.keySet()) { 842 deg = deg.lcm(e); 843 } 844 return deg; 845 } 846 847 848 /** 849 * Delta of exponent vectors. 850 * @return list of u-v, where u = lt() and v != u in this. 851 */ 852 public List<ExpVector> deltaExpVectors() { 853 List<ExpVector> de = new ArrayList<ExpVector>(val.size()); 854 if (val.isEmpty()) { 855 return de; 856 } 857 ExpVector u = null; 858 for (ExpVector e : val.keySet()) { 859 if ( u == null ) { 860 u = e; 861 } else { 862 ExpVector v = u.subtract(e); 863 de.add(v); 864 } 865 } 866 return de; 867 } 868 869 870 /** 871 * GenPolynomial maximum norm. 872 * @return ||this||. 873 */ 874 public C maxNorm() { 875 C n = ring.getZEROCoefficient(); 876 for (C c : val.values()) { 877 C x = c.abs(); 878 if (n.compareTo(x) < 0) { 879 n = x; 880 } 881 } 882 return n; 883 } 884 885 886 /** 887 * GenPolynomial sum norm. 888 * @return sum of all absolute values of coefficients. 889 */ 890 public C sumNorm() { 891 C n = ring.getZEROCoefficient(); 892 for (C c : val.values()) { 893 C x = c.abs(); 894 n = n.sum(x); 895 } 896 return n; 897 } 898 899 900 /** 901 * GenPolynomial summation. 902 * @param S GenPolynomial. 903 * @return this+S. 904 */ 905 //public <T extends GenPolynomial<C>> T sum(T /*GenPolynomial<C>*/ S) { 906 public GenPolynomial<C> sum(GenPolynomial<C> S) { 907 if (S == null) { 908 return this; 909 } 910 if (S.isZERO()) { 911 return this; 912 } 913 if (this.isZERO()) { 914 return S; 915 } 916 assert (ring.nvar == S.ring.nvar); 917 GenPolynomial<C> n = this.copy(); //new GenPolynomial<C>(ring, val); 918 SortedMap<ExpVector, C> nv = n.val; 919 SortedMap<ExpVector, C> sv = S.val; 920 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 921 ExpVector e = me.getKey(); 922 C y = me.getValue(); //sv.get(e); // assert y != null 923 C x = nv.get(e); 924 if (x != null) { 925 x = x.sum(y); 926 if (!x.isZERO()) { 927 nv.put(e, x); 928 } else { 929 nv.remove(e); 930 } 931 } else { 932 nv.put(e, y); 933 } 934 } 935 return n; 936 } 937 938 939 /** 940 * GenPolynomial addition. This method is not very efficient, since this is 941 * copied. 942 * @param a coefficient. 943 * @param e exponent. 944 * @return this + a x<sup>e</sup>. 945 */ 946 public GenPolynomial<C> sum(C a, ExpVector e) { 947 if (a == null) { 948 return this; 949 } 950 if (a.isZERO()) { 951 return this; 952 } 953 GenPolynomial<C> n = this.copy(); //new GenPolynomial<C>(ring, val); 954 SortedMap<ExpVector, C> nv = n.val; 955 //if ( nv.size() == 0 ) { nv.put(e,a); return n; } 956 C x = nv.get(e); 957 if (x != null) { 958 x = x.sum(a); 959 if (!x.isZERO()) { 960 nv.put(e, x); 961 } else { 962 nv.remove(e); 963 } 964 } else { 965 nv.put(e, a); 966 } 967 return n; 968 } 969 970 971 /** 972 * GenPolynomial addition. This method is not very efficient, since this is 973 * copied. 974 * @param a coefficient. 975 * @return this + a x<sup>0</sup>. 976 */ 977 public GenPolynomial<C> sum(C a) { 978 return sum(a, ring.evzero); 979 } 980 981 982 /** 983 * GenPolynomial destructive summation. 984 * @param S GenPolynomial. 985 */ 986 public void doAddTo(GenPolynomial<C> S) { 987 if (S == null || S.isZERO()) { 988 return; 989 } 990 if (this.isZERO()) { 991 this.val.putAll(S.val); 992 return; 993 } 994 assert (ring.nvar == S.ring.nvar); 995 SortedMap<ExpVector, C> nv = this.val; 996 SortedMap<ExpVector, C> sv = S.val; 997 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 998 ExpVector e = me.getKey(); 999 C y = me.getValue(); //sv.get(e); // assert y != null 1000 C x = nv.get(e); 1001 if (x != null) { 1002 x = x.sum(y); 1003 if (!x.isZERO()) { 1004 nv.put(e, x); 1005 } else { 1006 nv.remove(e); 1007 } 1008 } else { 1009 nv.put(e, y); 1010 } 1011 } 1012 return; 1013 } 1014 1015 1016 /** 1017 * GenPolynomial destructive summation. 1018 * @param a coefficient. 1019 * @param e exponent. 1020 */ 1021 public void doAddTo(C a, ExpVector e) { 1022 if (a == null || a.isZERO()) { 1023 return; 1024 } 1025 SortedMap<ExpVector, C> nv = this.val; 1026 C x = nv.get(e); 1027 if (x != null) { 1028 x = x.sum(a); 1029 if (!x.isZERO()) { 1030 nv.put(e, x); 1031 } else { 1032 nv.remove(e); 1033 } 1034 } else { 1035 nv.put(e, a); 1036 } 1037 return; 1038 } 1039 1040 1041 /** 1042 * GenPolynomial destructive summation. 1043 * @param a coefficient. 1044 */ 1045 public void doAddTo(C a) { 1046 doAddTo(a, ring.evzero); 1047 } 1048 1049 1050 /** 1051 * GenPolynomial subtraction. 1052 * @param S GenPolynomial. 1053 * @return this-S. 1054 */ 1055 public GenPolynomial<C> subtract(GenPolynomial<C> S) { 1056 if (S == null) { 1057 return this; 1058 } 1059 if (S.isZERO()) { 1060 return this; 1061 } 1062 if (this.isZERO()) { 1063 return S.negate(); 1064 } 1065 assert (ring.nvar == S.ring.nvar); 1066 GenPolynomial<C> n = this.copy(); //new GenPolynomial<C>(ring, val); 1067 SortedMap<ExpVector, C> nv = n.val; 1068 SortedMap<ExpVector, C> sv = S.val; 1069 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1070 ExpVector e = me.getKey(); 1071 C y = me.getValue(); //sv.get(e); // assert y != null 1072 C x = nv.get(e); 1073 if (x != null) { 1074 x = x.subtract(y); 1075 if (!x.isZERO()) { 1076 nv.put(e, x); 1077 } else { 1078 nv.remove(e); 1079 } 1080 } else { 1081 nv.put(e, y.negate()); 1082 } 1083 } 1084 return n; 1085 } 1086 1087 1088 /** 1089 * GenPolynomial subtraction. This method is not very efficient, since this 1090 * is copied. 1091 * @param a coefficient. 1092 * @param e exponent. 1093 * @return this - a x<sup>e</sup>. 1094 */ 1095 public GenPolynomial<C> subtract(C a, ExpVector e) { 1096 if (a == null || a.isZERO()) { 1097 return this; 1098 } 1099 GenPolynomial<C> n = this.copy(); 1100 SortedMap<ExpVector, C> nv = n.val; 1101 C x = nv.get(e); 1102 if (x != null) { 1103 x = x.subtract(a); 1104 if (!x.isZERO()) { 1105 nv.put(e, x); 1106 } else { 1107 nv.remove(e); 1108 } 1109 } else { 1110 nv.put(e, a.negate()); 1111 } 1112 return n; 1113 } 1114 1115 1116 /** 1117 * GenPolynomial subtract. This method is not very efficient, since this is 1118 * copied. 1119 * @param a coefficient. 1120 * @return this + a x<sup>0</sup>. 1121 */ 1122 public GenPolynomial<C> subtract(C a) { 1123 return subtract(a, ring.evzero); 1124 } 1125 1126 1127 /** 1128 * GenPolynomial subtract a multiple. 1129 * @param a coefficient. 1130 * @param S GenPolynomial. 1131 * @return this - a S. 1132 */ 1133 public GenPolynomial<C> subtractMultiple(C a, GenPolynomial<C> S) { 1134 if (a == null || a.isZERO()) { 1135 return this; 1136 } 1137 if (S == null || S.isZERO()) { 1138 return this; 1139 } 1140 if (this.isZERO()) { 1141 return S.multiply(a.negate()); 1142 } 1143 assert (ring.nvar == S.ring.nvar); 1144 GenPolynomial<C> n = this.copy(); 1145 SortedMap<ExpVector, C> nv = n.val; 1146 SortedMap<ExpVector, C> sv = S.val; 1147 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1148 ExpVector f = me.getKey(); 1149 C y = me.getValue(); // assert y != null 1150 y = a.multiply(y); 1151 C x = nv.get(f); 1152 if (x != null) { 1153 x = x.subtract(y); 1154 if (!x.isZERO()) { 1155 nv.put(f, x); 1156 } else { 1157 nv.remove(f); 1158 } 1159 } else if (!y.isZERO()) { 1160 nv.put(f, y.negate()); 1161 } 1162 } 1163 return n; 1164 } 1165 1166 1167 /** 1168 * GenPolynomial subtract a multiple. 1169 * @param a coefficient. 1170 * @param e exponent. 1171 * @param S GenPolynomial. 1172 * @return this - a x<sup>e</sup> S. 1173 */ 1174 public GenPolynomial<C> subtractMultiple(C a, ExpVector e, GenPolynomial<C> S) { 1175 if (a == null || a.isZERO()) { 1176 return this; 1177 } 1178 if (S == null || S.isZERO()) { 1179 return this; 1180 } 1181 if (this.isZERO()) { 1182 return S.multiply(a.negate(), e); 1183 } 1184 assert (ring.nvar == S.ring.nvar); 1185 GenPolynomial<C> n = this.copy(); 1186 SortedMap<ExpVector, C> nv = n.val; 1187 SortedMap<ExpVector, C> sv = S.val; 1188 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1189 ExpVector f = me.getKey(); 1190 f = e.sum(f); 1191 C y = me.getValue(); // assert y != null 1192 y = a.multiply(y); 1193 C x = nv.get(f); 1194 if (x != null) { 1195 x = x.subtract(y); 1196 if (!x.isZERO()) { 1197 nv.put(f, x); 1198 } else { 1199 nv.remove(f); 1200 } 1201 } else if (!y.isZERO()) { 1202 nv.put(f, y.negate()); 1203 } 1204 } 1205 return n; 1206 } 1207 1208 1209 /** 1210 * GenPolynomial scale and subtract a multiple. 1211 * @param b scale factor. 1212 * @param a coefficient. 1213 * @param S GenPolynomial. 1214 * @return this * b - a S. 1215 */ 1216 public GenPolynomial<C> scaleSubtractMultiple(C b, C a, GenPolynomial<C> S) { 1217 if (a == null || S == null) { 1218 return this.multiply(b); 1219 } 1220 if (a.isZERO() || S.isZERO()) { 1221 return this.multiply(b); 1222 } 1223 if (this.isZERO() || b == null || b.isZERO()) { 1224 return S.multiply(a.negate()); //left? 1225 } 1226 if (b.isONE()) { 1227 return subtractMultiple(a, S); 1228 } 1229 assert (ring.nvar == S.ring.nvar); 1230 GenPolynomial<C> n = this.multiply(b); 1231 SortedMap<ExpVector, C> nv = n.val; 1232 SortedMap<ExpVector, C> sv = S.val; 1233 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1234 ExpVector f = me.getKey(); 1235 //f = e.sum(f); 1236 C y = me.getValue(); // assert y != null 1237 y = a.multiply(y); // now y can be zero 1238 C x = nv.get(f); 1239 if (x != null) { 1240 x = x.subtract(y); 1241 if (!x.isZERO()) { 1242 nv.put(f, x); 1243 } else { 1244 nv.remove(f); 1245 } 1246 } else if (!y.isZERO()) { 1247 nv.put(f, y.negate()); 1248 } 1249 } 1250 return n; 1251 } 1252 1253 1254 /** 1255 * GenPolynomial scale and subtract a multiple. 1256 * @param b scale factor. 1257 * @param a coefficient. 1258 * @param e exponent. 1259 * @param S GenPolynomial. 1260 * @return this * b - a x<sup>e</sup> S. 1261 */ 1262 public GenPolynomial<C> scaleSubtractMultiple(C b, C a, ExpVector e, GenPolynomial<C> S) { 1263 if (a == null || S == null) { 1264 return this.multiply(b); 1265 } 1266 if (a.isZERO() || S.isZERO()) { 1267 return this.multiply(b); 1268 } 1269 if (this.isZERO() || b == null || b.isZERO()) { 1270 return S.multiply(a.negate(), e); 1271 } 1272 if (b.isONE()) { 1273 return subtractMultiple(a, e, S); 1274 } 1275 assert (ring.nvar == S.ring.nvar); 1276 GenPolynomial<C> n = this.multiply(b); 1277 SortedMap<ExpVector, C> nv = n.val; 1278 SortedMap<ExpVector, C> sv = S.val; 1279 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1280 ExpVector f = me.getKey(); 1281 f = e.sum(f); 1282 C y = me.getValue(); // assert y != null 1283 y = a.multiply(y); // now y can be zero 1284 C x = nv.get(f); 1285 if (x != null) { 1286 x = x.subtract(y); 1287 if (!x.isZERO()) { 1288 nv.put(f, x); 1289 } else { 1290 nv.remove(f); 1291 } 1292 } else if (!y.isZERO()) { 1293 nv.put(f, y.negate()); 1294 } 1295 } 1296 return n; 1297 } 1298 1299 1300 /** 1301 * GenPolynomial scale and subtract a multiple. 1302 * @param b scale factor. 1303 * @param g scale exponent. 1304 * @param a coefficient. 1305 * @param e exponent. 1306 * @param S GenPolynomial. 1307 * @return this * a x<sup>g</sup> - a x<sup>e</sup> S. 1308 */ 1309 public GenPolynomial<C> scaleSubtractMultiple(C b, ExpVector g, C a, ExpVector e, GenPolynomial<C> S) { 1310 if (a == null || S == null) { 1311 return this.multiply(b, g); 1312 } 1313 if (a.isZERO() || S.isZERO()) { 1314 return this.multiply(b, g); 1315 } 1316 if (this.isZERO() || b == null || b.isZERO()) { 1317 return S.multiply(a.negate(), e); 1318 } 1319 if (b.isONE() && g.isZERO()) { 1320 return subtractMultiple(a, e, S); 1321 } 1322 assert (ring.nvar == S.ring.nvar); 1323 GenPolynomial<C> n = this.multiply(b, g); 1324 SortedMap<ExpVector, C> nv = n.val; 1325 SortedMap<ExpVector, C> sv = S.val; 1326 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1327 ExpVector f = me.getKey(); 1328 f = e.sum(f); 1329 C y = me.getValue(); // assert y != null 1330 y = a.multiply(y); // y can be zero now 1331 C x = nv.get(f); 1332 if (x != null) { 1333 x = x.subtract(y); 1334 if (!x.isZERO()) { 1335 nv.put(f, x); 1336 } else { 1337 nv.remove(f); 1338 } 1339 } else if (!y.isZERO()) { 1340 nv.put(f, y.negate()); 1341 } 1342 } 1343 return n; 1344 } 1345 1346 1347 /** 1348 * GenPolynomial negation. 1349 * @return -this. 1350 */ 1351 public GenPolynomial<C> negate() { 1352 GenPolynomial<C> n = ring.getZERO().copy(); 1353 //new GenPolynomial<C>(ring, ring.getZERO().val); 1354 SortedMap<ExpVector, C> v = n.val; 1355 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1356 C x = m.getValue(); // != null, 0 1357 v.put(m.getKey(), x.negate()); 1358 // or m.setValue( x.negate() ) if this cloned 1359 } 1360 return n; 1361 } 1362 1363 1364 /** 1365 * GenPolynomial absolute value, i.e. leadingCoefficient > 0. 1366 * @return abs(this). 1367 */ 1368 public GenPolynomial<C> abs() { 1369 if (leadingBaseCoefficient().signum() < 0) { 1370 return this.negate(); 1371 } 1372 return this; 1373 } 1374 1375 1376 /** 1377 * GenPolynomial multiplication. 1378 * @param S GenPolynomial. 1379 * @return this*S. 1380 */ 1381 public GenPolynomial<C> multiply(GenPolynomial<C> S) { 1382 if (S == null) { 1383 return ring.getZERO(); 1384 } 1385 if (S.isZERO()) { 1386 return ring.getZERO(); 1387 } 1388 if (this.isZERO()) { 1389 return this; 1390 } 1391 assert (ring.nvar == S.ring.nvar); 1392 if (this instanceof GenSolvablePolynomial && S instanceof GenSolvablePolynomial) { 1393 //throw new RuntimeException("wrong method dispatch in JRE "); 1394 logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); 1395 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1396 GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S; 1397 return T.multiply(Sp); 1398 } 1399 GenPolynomial<C> p = ring.getZERO().copy(); 1400 SortedMap<ExpVector, C> pv = p.val; 1401 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1402 C c1 = m1.getValue(); 1403 ExpVector e1 = m1.getKey(); 1404 for (Map.Entry<ExpVector, C> m2 : S.val.entrySet()) { 1405 C c2 = m2.getValue(); 1406 ExpVector e2 = m2.getKey(); 1407 C c = c1.multiply(c2); // check non zero if not domain 1408 if (!c.isZERO()) { 1409 ExpVector e = e1.sum(e2); 1410 C c0 = pv.get(e); 1411 if (c0 == null) { 1412 pv.put(e, c); 1413 } else { 1414 c0 = c0.sum(c); 1415 if (!c0.isZERO()) { 1416 pv.put(e, c0); 1417 } else { 1418 pv.remove(e); 1419 } 1420 } 1421 } 1422 } 1423 } 1424 return p; 1425 } 1426 1427 1428 /** 1429 * GenPolynomial multiplication. Product with coefficient ring element. 1430 * @param s coefficient. 1431 * @return this*s. 1432 */ 1433 public GenPolynomial<C> multiply(C s) { 1434 if (s == null) { 1435 return ring.getZERO(); 1436 } 1437 if (s.isZERO()) { 1438 return ring.getZERO(); 1439 } 1440 if (this.isZERO()) { 1441 return this; 1442 } 1443 if (this instanceof GenSolvablePolynomial) { 1444 //throw new RuntimeException("wrong method dispatch in JRE "); 1445 logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix"); 1446 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1447 return T.multiply(s); 1448 } 1449 GenPolynomial<C> p = ring.getZERO().copy(); 1450 SortedMap<ExpVector, C> pv = p.val; 1451 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1452 C c1 = m1.getValue(); 1453 ExpVector e1 = m1.getKey(); 1454 C c = c1.multiply(s); // check non zero if not domain 1455 if (!c.isZERO()) { 1456 pv.put(e1, c); // or m1.setValue( c ) 1457 } 1458 } 1459 return p; 1460 } 1461 1462 1463 /** 1464 * GenPolynomial monic, i.e. leadingCoefficient == 1. If leadingCoefficient 1465 * is not invertible returns this unmodified. 1466 * @return monic(this). 1467 */ 1468 public GenPolynomial<C> monic() { 1469 if (this.isZERO()) { 1470 return this; 1471 } 1472 C lc = leadingBaseCoefficient(); 1473 if (!lc.isUnit()) { 1474 //System.out.println("lc = "+lc); 1475 return this; 1476 } 1477 C lm = lc.inverse(); 1478 return multiply(lm); 1479 } 1480 1481 1482 /** 1483 * GenPolynomial multiplication. Product with ring element and exponent 1484 * vector. 1485 * @param s coefficient. 1486 * @param e exponent. 1487 * @return this * s x<sup>e</sup>. 1488 */ 1489 public GenPolynomial<C> multiply(C s, ExpVector e) { 1490 if (s == null) { 1491 return ring.getZERO(); 1492 } 1493 if (s.isZERO()) { 1494 return ring.getZERO(); 1495 } 1496 if (this.isZERO()) { 1497 return this; 1498 } 1499 if (this instanceof GenSolvablePolynomial) { 1500 //throw new RuntimeException("wrong method dispatch in JRE "); 1501 logger.debug("warn: wrong method dispatch in JRE multiply(s,e) - trying to fix"); 1502 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1503 return T.multiply(s, e); 1504 } 1505 GenPolynomial<C> p = ring.getZERO().copy(); 1506 SortedMap<ExpVector, C> pv = p.val; 1507 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1508 C c1 = m1.getValue(); 1509 ExpVector e1 = m1.getKey(); 1510 C c = c1.multiply(s); // check non zero if not domain 1511 if (!c.isZERO()) { 1512 ExpVector e2 = e1.sum(e); 1513 pv.put(e2, c); 1514 } 1515 } 1516 return p; 1517 } 1518 1519 1520 /** 1521 * GenPolynomial multiplication. Product with exponent vector. 1522 * @param e exponent (!= null). 1523 * @return this * x<sup>e</sup>. 1524 */ 1525 public GenPolynomial<C> multiply(ExpVector e) { 1526 // assert e != null. This is never allowed. 1527 if (this.isZERO()) { 1528 return this; 1529 } 1530 if (this instanceof GenSolvablePolynomial) { 1531 //throw new RuntimeException("wrong method dispatch in JRE "); 1532 logger.debug("warn: wrong method dispatch in JRE multiply(e) - trying to fix"); 1533 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1534 return T.multiply(e); 1535 } 1536 GenPolynomial<C> p = ring.getZERO().copy(); 1537 SortedMap<ExpVector, C> pv = p.val; 1538 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1539 C c1 = m1.getValue(); 1540 ExpVector e1 = m1.getKey(); 1541 ExpVector e2 = e1.sum(e); 1542 pv.put(e2, c1); 1543 } 1544 return p; 1545 } 1546 1547 1548 /** 1549 * GenPolynomial multiplication. Product with 'monomial'. 1550 * @param m 'monomial'. 1551 * @return this * m. 1552 */ 1553 public GenPolynomial<C> multiply(Map.Entry<ExpVector, C> m) { 1554 if (m == null) { 1555 return ring.getZERO(); 1556 } 1557 return multiply(m.getValue(), m.getKey()); 1558 } 1559 1560 1561 /** 1562 * GenPolynomial division. Division by coefficient ring element. Fails, if 1563 * exact division is not possible. 1564 * @param s coefficient. 1565 * @return this/s. 1566 */ 1567 public GenPolynomial<C> divide(C s) { 1568 if (s == null || s.isZERO()) { 1569 throw new ArithmeticException("division by zero"); 1570 } 1571 if (this.isZERO()) { 1572 return this; 1573 } 1574 //C t = s.inverse(); 1575 //return multiply(t); 1576 GenPolynomial<C> p = ring.getZERO().copy(); 1577 SortedMap<ExpVector, C> pv = p.val; 1578 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1579 ExpVector e = m.getKey(); 1580 C c1 = m.getValue(); 1581 C c = c1.divide(s); 1582 if (debug) { 1583 C x = c1.remainder(s); 1584 if (!x.isZERO()) { 1585 logger.info("divide x = " + x); 1586 throw new ArithmeticException("no exact division: " + c1 + "/" + s); 1587 } 1588 } 1589 if (c.isZERO()) { 1590 throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); 1591 } 1592 pv.put(e, c); // or m1.setValue( c ) 1593 } 1594 return p; 1595 } 1596 1597 1598 /** 1599 * GenPolynomial division with remainder. Fails, if exact division by 1600 * leading base coefficient is not possible. Meaningful only for univariate 1601 * polynomials over fields, but works in any case. 1602 * @param S nonzero GenPolynomial with invertible leading coefficient. 1603 * @return [ quotient , remainder ] with this = quotient * S + remainder and 1604 * deg(remainder) < deg(S) or remiander = 0. 1605 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1606 */ 1607 @SuppressWarnings("unchecked") 1608 public GenPolynomial<C>[] quotientRemainder(GenPolynomial<C> S) { 1609 if (S == null || S.isZERO()) { 1610 throw new ArithmeticException("division by zero"); 1611 } 1612 C c = S.leadingBaseCoefficient(); 1613 if (!c.isUnit()) { 1614 throw new ArithmeticException("lbcf not invertible " + c); 1615 } 1616 C ci = c.inverse(); 1617 assert (ring.nvar == S.ring.nvar); 1618 ExpVector e = S.leadingExpVector(); 1619 GenPolynomial<C> h; 1620 GenPolynomial<C> q = ring.getZERO().copy(); 1621 GenPolynomial<C> r = this.copy(); 1622 while (!r.isZERO()) { 1623 ExpVector f = r.leadingExpVector(); 1624 if (f.multipleOf(e)) { 1625 C a = r.leadingBaseCoefficient(); 1626 f = f.subtract(e); 1627 a = a.multiply(ci); 1628 q = q.sum(a, f); 1629 h = S.multiply(a, f); 1630 r = r.subtract(h); 1631 } else { 1632 break; 1633 } 1634 } 1635 GenPolynomial<C>[] ret = new GenPolynomial[2]; 1636 ret[0] = q; 1637 ret[1] = r; 1638 return ret; 1639 } 1640 1641 1642 /** 1643 * GenPolynomial division with remainder. Fails, if exact division by 1644 * leading base coefficient is not possible. Meaningful only for univariate 1645 * polynomials over fields, but works in any case. 1646 * @param S nonzero GenPolynomial with invertible leading coefficient. 1647 * @return [ quotient , remainder ] with this = quotient * S + remainder and 1648 * deg(remainder) < deg(S) or remiander = 0. 1649 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1650 * @deprecated use quotientRemainder() 1651 */ 1652 @Deprecated 1653 public GenPolynomial<C>[] divideAndRemainder(GenPolynomial<C> S) { 1654 return quotientRemainder(S); 1655 } 1656 1657 1658 /** 1659 * GenPolynomial division. Fails, if exact division by leading base 1660 * coefficient is not possible. Meaningful only for univariate polynomials 1661 * over fields, but works in any case. 1662 * @param S nonzero GenPolynomial with invertible leading coefficient. 1663 * @return quotient with this = quotient * S + remainder. 1664 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1665 */ 1666 public GenPolynomial<C> divide(GenPolynomial<C> S) { 1667 if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) { 1668 //throw new RuntimeException("wrong method dispatch in JRE "); 1669 //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); 1670 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1671 GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S; 1672 return T.quotientRemainder(Sp)[0]; 1673 } 1674 return quotientRemainder(S)[0]; 1675 } 1676 1677 1678 /** 1679 * GenPolynomial remainder. Fails, if exact division by leading base 1680 * coefficient is not possible. Meaningful only for univariate polynomials 1681 * over fields, but works in any case. 1682 * @param S nonzero GenPolynomial with invertible leading coefficient. 1683 * @return remainder with this = quotient * S + remainder. 1684 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1685 */ 1686 public GenPolynomial<C> remainder(GenPolynomial<C> S) { 1687 if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) { 1688 //throw new RuntimeException("wrong method dispatch in JRE "); 1689 //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); 1690 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1691 GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S; 1692 return T.quotientRemainder(Sp)[1]; 1693 } 1694 if (S == null || S.isZERO()) { 1695 throw new ArithmeticException("division by zero"); 1696 } 1697 C c = S.leadingBaseCoefficient(); 1698 if (!c.isUnit()) { 1699 throw new ArithmeticException("lbc not invertible " + c); 1700 } 1701 C ci = c.inverse(); 1702 assert (ring.nvar == S.ring.nvar); 1703 ExpVector e = S.leadingExpVector(); 1704 GenPolynomial<C> h; 1705 GenPolynomial<C> r = this.copy(); 1706 while (!r.isZERO()) { 1707 ExpVector f = r.leadingExpVector(); 1708 if (f.multipleOf(e)) { 1709 C a = r.leadingBaseCoefficient(); 1710 f = f.subtract(e); 1711 //logger.info("red div = " + e); 1712 a = a.multiply(ci); 1713 h = S.multiply(a, f); 1714 r = r.subtract(h); 1715 } else { 1716 break; 1717 } 1718 } 1719 return r; 1720 } 1721 1722 1723 /** 1724 * GenPolynomial greatest common divisor. Only for univariate polynomials 1725 * over fields. 1726 * @param S GenPolynomial. 1727 * @return gcd(this,S). 1728 */ 1729 public GenPolynomial<C> gcd(GenPolynomial<C> S) { 1730 if (S == null || S.isZERO()) { 1731 return this; 1732 } 1733 if (this.isZERO()) { 1734 return S; 1735 } 1736 if (ring.nvar != 1) { 1737 throw new IllegalArgumentException("not univariate polynomials" + ring); 1738 } 1739 GenPolynomial<C> x; 1740 GenPolynomial<C> q = this; 1741 GenPolynomial<C> r = S; 1742 while (!r.isZERO()) { 1743 x = q.remainder(r); 1744 q = r; 1745 r = x; 1746 } 1747 return q.monic(); // normalize 1748 } 1749 1750 1751 /** 1752 * GenPolynomial extended greatest comon divisor. Only for univariate 1753 * polynomials over fields. 1754 * @param S GenPolynomial. 1755 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 1756 */ 1757 @SuppressWarnings("unchecked") 1758 public GenPolynomial<C>[] egcd(GenPolynomial<C> S) { 1759 GenPolynomial<C>[] ret = new GenPolynomial[3]; 1760 ret[0] = null; 1761 ret[1] = null; 1762 ret[2] = null; 1763 if (S == null || S.isZERO()) { 1764 ret[0] = this; 1765 ret[1] = this.ring.getONE(); 1766 ret[2] = this.ring.getZERO(); 1767 return ret; 1768 } 1769 if (this.isZERO()) { 1770 ret[0] = S; 1771 ret[1] = this.ring.getZERO(); 1772 ret[2] = this.ring.getONE(); 1773 return ret; 1774 } 1775 if (ring.nvar != 1) { 1776 throw new IllegalArgumentException(this.getClass().getName() + " not univariate polynomials" 1777 + ring); 1778 } 1779 if (this.isConstant() && S.isConstant()) { 1780 C t = this.leadingBaseCoefficient(); 1781 C s = S.leadingBaseCoefficient(); 1782 C[] gg = t.egcd(s); 1783 //System.out.println("coeff gcd = " + Arrays.toString(gg)); 1784 GenPolynomial<C> z = this.ring.getZERO(); 1785 ret[0] = z.sum(gg[0]); 1786 ret[1] = z.sum(gg[1]); 1787 ret[2] = z.sum(gg[2]); 1788 return ret; 1789 } 1790 GenPolynomial<C>[] qr; 1791 GenPolynomial<C> q = this; 1792 GenPolynomial<C> r = S; 1793 GenPolynomial<C> c1 = ring.getONE().copy(); 1794 GenPolynomial<C> d1 = ring.getZERO().copy(); 1795 GenPolynomial<C> c2 = ring.getZERO().copy(); 1796 GenPolynomial<C> d2 = ring.getONE().copy(); 1797 GenPolynomial<C> x1; 1798 GenPolynomial<C> x2; 1799 while (!r.isZERO()) { 1800 qr = q.quotientRemainder(r); 1801 q = qr[0]; 1802 x1 = c1.subtract(q.multiply(d1)); 1803 x2 = c2.subtract(q.multiply(d2)); 1804 c1 = d1; 1805 c2 = d2; 1806 d1 = x1; 1807 d2 = x2; 1808 q = r; 1809 r = qr[1]; 1810 } 1811 // normalize ldcf(q) to 1, i.e. make monic 1812 C g = q.leadingBaseCoefficient(); 1813 if (g.isUnit()) { 1814 C h = g.inverse(); 1815 q = q.multiply(h); 1816 c1 = c1.multiply(h); 1817 c2 = c2.multiply(h); 1818 } 1819 //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); 1820 ret[0] = q; 1821 ret[1] = c1; 1822 ret[2] = c2; 1823 return ret; 1824 } 1825 1826 1827 /** 1828 * GenPolynomial half extended greatest comon divisor. Only for univariate 1829 * polynomials over fields. 1830 * @param S GenPolynomial. 1831 * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S). 1832 */ 1833 @SuppressWarnings("unchecked") 1834 public GenPolynomial<C>[] hegcd(GenPolynomial<C> S) { 1835 GenPolynomial<C>[] ret = new GenPolynomial[2]; 1836 ret[0] = null; 1837 ret[1] = null; 1838 if (S == null || S.isZERO()) { 1839 ret[0] = this; 1840 ret[1] = this.ring.getONE(); 1841 return ret; 1842 } 1843 if (this.isZERO()) { 1844 ret[0] = S; 1845 return ret; 1846 } 1847 if (ring.nvar != 1) { 1848 throw new IllegalArgumentException(this.getClass().getName() + " not univariate polynomials" 1849 + ring); 1850 } 1851 GenPolynomial<C>[] qr; 1852 GenPolynomial<C> q = this; 1853 GenPolynomial<C> r = S; 1854 GenPolynomial<C> c1 = ring.getONE().copy(); 1855 GenPolynomial<C> d1 = ring.getZERO().copy(); 1856 GenPolynomial<C> x1; 1857 while (!r.isZERO()) { 1858 qr = q.quotientRemainder(r); 1859 q = qr[0]; 1860 x1 = c1.subtract(q.multiply(d1)); 1861 c1 = d1; 1862 d1 = x1; 1863 q = r; 1864 r = qr[1]; 1865 } 1866 // normalize ldcf(q) to 1, i.e. make monic 1867 C g = q.leadingBaseCoefficient(); 1868 if (g.isUnit()) { 1869 C h = g.inverse(); 1870 q = q.multiply(h); 1871 c1 = c1.multiply(h); 1872 } 1873 //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); 1874 ret[0] = q; 1875 ret[1] = c1; 1876 return ret; 1877 } 1878 1879 1880 /** 1881 * GenPolynomial inverse. Required by RingElem. Throws not invertible 1882 * exception. 1883 */ 1884 public GenPolynomial<C> inverse() { 1885 if (isUnit()) { // only possible if ldbcf is unit 1886 C c = leadingBaseCoefficient().inverse(); 1887 return ring.getONE().multiply(c); 1888 } 1889 throw new NotInvertibleException("element not invertible " + this + " :: " + ring); 1890 } 1891 1892 1893 /** 1894 * GenPolynomial modular inverse. Only for univariate polynomials over 1895 * fields. 1896 * @param m GenPolynomial. 1897 * @return a with with a*this = 1 mod m. 1898 */ 1899 public GenPolynomial<C> modInverse(GenPolynomial<C> m) { 1900 if (this.isZERO()) { 1901 throw new NotInvertibleException("zero is not invertible"); 1902 } 1903 GenPolynomial<C>[] hegcd = this.hegcd(m); 1904 GenPolynomial<C> a = hegcd[0]; 1905 if (!a.isUnit()) { // gcd != 1 1906 throw new AlgebraicNotInvertibleException("element not invertible, gcd != 1", m, a, m.divide(a)); 1907 } 1908 GenPolynomial<C> b = hegcd[1]; 1909 if (b.isZERO()) { // when m divides this, e.g. m.isUnit() 1910 throw new NotInvertibleException("element not invertible, divisible by modul"); 1911 } 1912 return b; 1913 } 1914 1915 1916 /** 1917 * Extend variables. Used e.g. in module embedding. Extend all ExpVectors by 1918 * i elements and multiply by x_j^k. 1919 * @param pfac extended polynomial ring factory (by i variables). 1920 * @param j index of variable to be used for multiplication. 1921 * @param k exponent for x_j. 1922 * @return extended polynomial. 1923 */ 1924 public GenPolynomial<C> extend(GenPolynomialRing<C> pfac, int j, long k) { 1925 if (ring.equals(pfac)) { // nothing to do 1926 return this; 1927 } 1928 GenPolynomial<C> Cp = pfac.getZERO().copy(); 1929 if (this.isZERO()) { 1930 return Cp; 1931 } 1932 int i = pfac.nvar - ring.nvar; 1933 Map<ExpVector, C> C = Cp.val; //getMap(); 1934 Map<ExpVector, C> A = val; 1935 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 1936 ExpVector e = y.getKey(); 1937 C a = y.getValue(); 1938 ExpVector f = e.extend(i, j, k); 1939 C.put(f, a); 1940 } 1941 return Cp; 1942 } 1943 1944 1945 /** 1946 * Extend lower variables. Used e.g. in module embedding. Extend all 1947 * ExpVectors by i lower elements and multiply by x_j^k. 1948 * @param pfac extended polynomial ring factory (by i variables). 1949 * @param j index of variable to be used for multiplication. 1950 * @param k exponent for x_j. 1951 * @return extended polynomial. 1952 */ 1953 public GenPolynomial<C> extendLower(GenPolynomialRing<C> pfac, int j, long k) { 1954 if (ring.equals(pfac)) { // nothing to do 1955 return this; 1956 } 1957 GenPolynomial<C> Cp = pfac.getZERO().copy(); 1958 if (this.isZERO()) { 1959 return Cp; 1960 } 1961 int i = pfac.nvar - ring.nvar; 1962 Map<ExpVector, C> C = Cp.val; //getMap(); 1963 Map<ExpVector, C> A = val; 1964 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 1965 ExpVector e = y.getKey(); 1966 C a = y.getValue(); 1967 ExpVector f = e.extendLower(i, j, k); 1968 C.put(f, a); 1969 } 1970 return Cp; 1971 } 1972 1973 1974 /** 1975 * Contract variables. Used e.g. in module embedding. Remove i elements of 1976 * each ExpVector. 1977 * @param pfac contracted polynomial ring factory (by i variables). 1978 * @return Map of exponents and contracted polynomials. <b>Note:</b> could 1979 * return SortedMap 1980 */ 1981 public Map<ExpVector, GenPolynomial<C>> contract(GenPolynomialRing<C> pfac) { 1982 GenPolynomial<C> zero = pfac.getZERO(); //not pfac.coFac; 1983 TermOrder t = new TermOrder(TermOrder.INVLEX); 1984 Map<ExpVector, GenPolynomial<C>> B = new TreeMap<ExpVector, GenPolynomial<C>>(t.getAscendComparator()); 1985 if (this.isZERO()) { 1986 return B; 1987 } 1988 int i = ring.nvar - pfac.nvar; 1989 Map<ExpVector, C> A = val; 1990 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 1991 ExpVector e = y.getKey(); 1992 C a = y.getValue(); 1993 ExpVector f = e.contract(0, i); 1994 ExpVector g = e.contract(i, e.length() - i); 1995 GenPolynomial<C> p = B.get(f); 1996 if (p == null) { 1997 p = zero; 1998 } 1999 p = p.sum(a, g); 2000 B.put(f, p); 2001 } 2002 return B; 2003 } 2004 2005 2006 /** 2007 * Contract variables to coefficient polynomial. Remove i elements of each 2008 * ExpVector, removed elements must be zero. 2009 * @param pfac contracted polynomial ring factory (by i variables). 2010 * @return contracted coefficient polynomial. 2011 */ 2012 public GenPolynomial<C> contractCoeff(GenPolynomialRing<C> pfac) { 2013 Map<ExpVector, GenPolynomial<C>> ms = contract(pfac); 2014 GenPolynomial<C> c = pfac.getZERO(); 2015 for (Map.Entry<ExpVector, GenPolynomial<C>> m : ms.entrySet()) { 2016 if (m.getKey().isZERO()) { 2017 c = m.getValue(); 2018 } else { 2019 throw new RuntimeException("wrong coefficient contraction " + m + ", pol = " + c); 2020 } 2021 } 2022 return c; 2023 } 2024 2025 2026 /** 2027 * Extend univariate to multivariate polynomial. This is an univariate 2028 * polynomial in variable i of the polynomial ring, it is extended to the 2029 * given polynomial ring. 2030 * @param pfac extended polynomial ring factory. 2031 * @param i index of the variable of this polynomial in pfac. 2032 * @return extended multivariate polynomial. 2033 */ 2034 public GenPolynomial<C> extendUnivariate(GenPolynomialRing<C> pfac, int i) { 2035 if (i < 0 || pfac.nvar < i) { 2036 throw new IllegalArgumentException("index " + i + "out of range " + pfac.nvar); 2037 } 2038 if (ring.nvar != 1) { 2039 throw new IllegalArgumentException("polynomial not univariate " + ring.nvar); 2040 } 2041 if (this.isONE()) { 2042 return pfac.getONE(); 2043 } 2044 int j = pfac.nvar - 1 - i; 2045 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2046 if (this.isZERO()) { 2047 return Cp; 2048 } 2049 Map<ExpVector, C> C = Cp.val; //getMap(); 2050 Map<ExpVector, C> A = val; 2051 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2052 ExpVector e = y.getKey(); 2053 long n = e.getVal(0); 2054 C a = y.getValue(); 2055 ExpVector f = ExpVector.create(pfac.nvar, j, n); 2056 C.put(f, a); // assert not contained 2057 } 2058 return Cp; 2059 } 2060 2061 2062 /** 2063 * Make homogeneous. 2064 * @param pfac extended polynomial ring factory (by 1 variable). 2065 * @return homogeneous polynomial. 2066 */ 2067 public GenPolynomial<C> homogenize(GenPolynomialRing<C> pfac) { 2068 if (ring.equals(pfac)) { // not implemented 2069 throw new UnsupportedOperationException("case with same ring not implemented"); 2070 } 2071 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2072 if (this.isZERO()) { 2073 return Cp; 2074 } 2075 long deg = totalDegree(); 2076 //int i = pfac.nvar - ring.nvar; 2077 Map<ExpVector, C> C = Cp.val; //getMap(); 2078 Map<ExpVector, C> A = val; 2079 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2080 ExpVector e = y.getKey(); 2081 C a = y.getValue(); 2082 long d = deg - e.totalDeg(); 2083 ExpVector f = e.extend(1, 0, d); 2084 C.put(f, a); 2085 } 2086 return Cp; 2087 } 2088 2089 2090 /** 2091 * Dehomogenize. 2092 * @param pfac contracted polynomial ring factory (by 1 variable). 2093 * @return in homogeneous polynomial. 2094 */ 2095 public GenPolynomial<C> deHomogenize(GenPolynomialRing<C> pfac) { 2096 if (ring.equals(pfac)) { // not implemented 2097 throw new UnsupportedOperationException("case with same ring not implemented"); 2098 } 2099 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2100 if (this.isZERO()) { 2101 return Cp; 2102 } 2103 Map<ExpVector, C> C = Cp.val; //getMap(); 2104 Map<ExpVector, C> A = val; 2105 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2106 ExpVector e = y.getKey(); 2107 C a = y.getValue(); 2108 ExpVector f = e.contract(1, pfac.nvar); 2109 C.put(f, a); 2110 } 2111 return Cp; 2112 } 2113 2114 2115 /** 2116 * Reverse variables. Used e.g. in opposite rings. 2117 * @return polynomial with reversed variables. 2118 */ 2119 public GenPolynomial<C> reverse(GenPolynomialRing<C> oring) { 2120 GenPolynomial<C> Cp = oring.getZERO().copy(); 2121 if (this.isZERO()) { 2122 return Cp; 2123 } 2124 int k = -1; 2125 if (oring.tord.getEvord2() != 0 && oring.partial) { 2126 k = oring.tord.getSplit(); 2127 } 2128 2129 Map<ExpVector, C> C = Cp.val; //getMap(); 2130 Map<ExpVector, C> A = val; 2131 ExpVector f; 2132 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2133 ExpVector e = y.getKey(); 2134 if (k >= 0) { 2135 f = e.reverse(k); 2136 } else { 2137 f = e.reverse(); 2138 } 2139 C a = y.getValue(); 2140 C.put(f, a); 2141 } 2142 return Cp; 2143 } 2144 2145 2146 /** 2147 * Iterator over coefficients. 2148 * @return val.values().iterator(). 2149 */ 2150 public Iterator<C> coefficientIterator() { 2151 return val.values().iterator(); 2152 } 2153 2154 2155 /** 2156 * Iterator over exponents. 2157 * @return val.keySet().iterator(). 2158 */ 2159 public Iterator<ExpVector> exponentIterator() { 2160 return val.keySet().iterator(); 2161 } 2162 2163 2164 /** 2165 * Iterator over monomials. 2166 * @return a PolyIterator. 2167 */ 2168 public Iterator<Monomial<C>> iterator() { 2169 return new PolyIterator<C>(val); 2170 } 2171 2172 2173 /** 2174 * Map a unary function to the coefficients. 2175 * @param f evaluation functor. 2176 * @return new polynomial with coefficients f(this(e)). 2177 */ 2178 public GenPolynomial<C> map(final UnaryFunctor<? super C, C> f) { 2179 GenPolynomial<C> n = ring.getZERO().copy(); 2180 SortedMap<ExpVector, C> nv = n.val; 2181 for (Monomial<C> m : this) { 2182 //logger.info("m = " + m); 2183 C c = f.eval(m.c); 2184 if (c != null && !c.isZERO()) { 2185 nv.put(m.e, c); 2186 } 2187 } 2188 return n; 2189 } 2190 2191}