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