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