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 " + e + " to " + a + " new " + 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 " + e + " to " + c + " old " + 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 " + e + " to " + a + " new " + 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 logger.info("ab = " + ab + ", a = " + a + ", b = " + b + ", u = " + u + ", e = " + e 909 + ", v = " + v); 910 } 911 } 912 } 913 } 914 return fp; 915 } 916 917 918 /** 919 * Is GenPolynomial<C> homogeneous with respect to a weight. 920 * @return true, if this is weight homogeneous, else false. 921 */ 922 public boolean isWeightHomogeneous() { 923 if (val.size() <= 1) { 924 return true; 925 } 926 long[][] w = ring.tord.getWeight(); 927 if (w == null || w.length == 0) { 928 return isHomogeneous(); // assume weights = 1 929 } 930 long deg = -1; 931 for (ExpVector e : val.keySet()) { 932 if (deg < 0) { 933 deg = e.weightDeg(w); 934 } else if (deg != e.weightDeg(w)) { 935 return false; 936 } 937 } 938 return true; 939 } 940 941 942 /** 943 * Maximal degree vector. 944 * @return maximal degree vector of all variables. 945 */ 946 public ExpVector degreeVector() { 947 if (val.isEmpty()) { 948 return null; //deg; 949 } 950 ExpVector deg = ring.evzero; 951 for (ExpVector e : val.keySet()) { 952 deg = deg.lcm(e); 953 } 954 return deg; 955 } 956 957 958 /** 959 * Delta of exponent vectors. 960 * @return list of u-v, where u = lt() and v != u in this. 961 */ 962 public List<ExpVector> deltaExpVectors() { 963 List<ExpVector> de = new ArrayList<ExpVector>(val.size()); 964 if (val.isEmpty()) { 965 return de; 966 } 967 ExpVector u = null; 968 for (ExpVector e : val.keySet()) { 969 if (u == null) { 970 u = e; 971 } else { 972 ExpVector v = u.subtract(e); 973 de.add(v); 974 } 975 } 976 return de; 977 } 978 979 980 /** 981 * Delta of exponent vectors. 982 * @param u marked ExpVector in this.expVectors 983 * @return list of u-v, where v != u in this.expVectors. 984 */ 985 public List<ExpVector> deltaExpVectors(ExpVector u) { 986 List<ExpVector> de = new ArrayList<ExpVector>(val.size()); 987 if (val.isEmpty()) { 988 return de; 989 } 990 for (ExpVector e : val.keySet()) { 991 ExpVector v = u.subtract(e); 992 if (v.isZERO()) { 993 continue; 994 } 995 de.add(v); 996 } 997 return de; 998 } 999 1000 1001 /** 1002 * GenPolynomial maximum norm. 1003 * @return ||this|| the maximum of all absolute values of coefficients. 1004 */ 1005 public C maxNorm() { 1006 C n = ring.getZEROCoefficient(); 1007 for (C c : val.values()) { 1008 C x = c.abs(); 1009 if (n.compareTo(x) < 0) { 1010 n = x; 1011 } 1012 } 1013 return n; 1014 } 1015 1016 1017 /** 1018 * GenPolynomial sum norm. 1019 * @return sum of all absolute values of coefficients. 1020 */ 1021 public C sumNorm() { 1022 C n = ring.getZEROCoefficient(); 1023 for (C c : val.values()) { 1024 C x = c.abs(); 1025 n = n.sum(x); 1026 } 1027 return n; 1028 } 1029 1030 1031 /** 1032 * GenPolynomial square norm. 1033 * @return the sum all squared values of coefficients. 1034 */ 1035 public C squareNorm() { 1036 C n = ring.getZEROCoefficient(); 1037 for (C c : val.values()) { 1038 C x = c.abs(); 1039 x = x.multiply(x); 1040 n = n.sum(x); 1041 } 1042 return n; 1043 } 1044 1045 1046 /** 1047 * GenPolynomial summation. 1048 * @param S GenPolynomial. 1049 * @return this+S. 1050 */ 1051 //public <T extends GenPolynomial<C>> T sum(T /*GenPolynomial<C>*/ S) { 1052 public GenPolynomial<C> sum(GenPolynomial<C> S) { 1053 if (S == null || S.isZERO()) { 1054 return this; 1055 } 1056 if (this.isZERO()) { 1057 return S; 1058 } 1059 if (this.length() < (3 * S.length()) / 5) { 1060 return S.sum(this); // performance 1061 } 1062 assert (ring.nvar == S.ring.nvar); 1063 GenPolynomial<C> n = this.copy(); 1064 SortedMap<ExpVector, C> nv = n.val; 1065 SortedMap<ExpVector, C> sv = S.val; 1066 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1067 ExpVector e = me.getKey(); 1068 C y = me.getValue(); // assert y != null 1069 C x = nv.get(e); 1070 if (x != null) { 1071 x = x.sum(y); 1072 if (!x.isZERO()) { 1073 nv.put(e, x); 1074 } else { 1075 nv.remove(e); 1076 } 1077 } else { 1078 nv.put(e, y); 1079 } 1080 } 1081 return n; 1082 } 1083 1084 1085 /** 1086 * GenPolynomial addition. This method is not very efficient, since this is 1087 * copied. 1088 * @param a coefficient. 1089 * @param e exponent. 1090 * @return this + a x<sup>e</sup>. 1091 */ 1092 public GenPolynomial<C> sum(C a, ExpVector e) { 1093 if (a == null) { 1094 return this; 1095 } 1096 if (a.isZERO()) { 1097 return this; 1098 } 1099 GenPolynomial<C> n = this.copy(); 1100 SortedMap<ExpVector, C> nv = n.val; 1101 //if ( nv.size() == 0 ) { nv.put(e,a); return n; } 1102 C x = nv.get(e); 1103 if (x != null) { 1104 x = x.sum(a); 1105 if (!x.isZERO()) { 1106 nv.put(e, x); 1107 } else { 1108 nv.remove(e); 1109 } 1110 } else { 1111 nv.put(e, a); 1112 } 1113 return n; 1114 } 1115 1116 1117 /** 1118 * GenPolynomial addition. This method is not very efficient, since this is 1119 * copied. 1120 * @param m monomial. 1121 * @return this + m. 1122 */ 1123 public GenPolynomial<C> sum(Monomial<C> m) { 1124 return sum(m.coefficient(), m.exponent()); 1125 } 1126 1127 1128 /** 1129 * GenPolynomial addition. This method is not very efficient, since this is 1130 * copied. 1131 * @param a coefficient. 1132 * @return this + a x<sup>0</sup>. 1133 */ 1134 public GenPolynomial<C> sum(C a) { 1135 return sum(a, ring.evzero); 1136 } 1137 1138 1139 /** 1140 * GenPolynomial destructive summation. 1141 * @param S GenPolynomial. 1142 */ 1143 public void doAddTo(GenPolynomial<C> S) { 1144 if (S == null || S.isZERO()) { 1145 return; 1146 } 1147 if (this.isZERO()) { 1148 this.val.putAll(S.val); 1149 return; 1150 } 1151 assert (ring.nvar == S.ring.nvar); 1152 SortedMap<ExpVector, C> nv = this.val; 1153 SortedMap<ExpVector, C> sv = S.val; 1154 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1155 ExpVector e = me.getKey(); 1156 C y = me.getValue(); // assert y != null 1157 C x = nv.get(e); 1158 if (x != null) { 1159 x = x.sum(y); 1160 if (!x.isZERO()) { 1161 nv.put(e, x); 1162 } else { 1163 nv.remove(e); 1164 } 1165 } else { 1166 nv.put(e, y); 1167 } 1168 } 1169 return; 1170 } 1171 1172 1173 /** 1174 * GenPolynomial destructive summation. 1175 * @param a coefficient. 1176 * @param e exponent. 1177 */ 1178 public void doAddTo(C a, ExpVector e) { 1179 if (a == null || a.isZERO()) { 1180 return; 1181 } 1182 SortedMap<ExpVector, C> nv = this.val; 1183 C x = nv.get(e); 1184 if (x != null) { 1185 x = x.sum(a); 1186 if (!x.isZERO()) { 1187 nv.put(e, x); 1188 } else { 1189 nv.remove(e); 1190 } 1191 } else { 1192 nv.put(e, a); 1193 } 1194 return; 1195 } 1196 1197 1198 /** 1199 * GenPolynomial destructive summation. 1200 * @param a coefficient. 1201 */ 1202 public void doAddTo(C a) { 1203 doAddTo(a, ring.evzero); 1204 } 1205 1206 1207 /** 1208 * GenPolynomial subtraction. 1209 * @param S GenPolynomial. 1210 * @return this-S. 1211 */ 1212 public GenPolynomial<C> subtract(GenPolynomial<C> S) { 1213 if (S == null) { 1214 return this; 1215 } 1216 if (S.isZERO()) { 1217 return this; 1218 } 1219 if (this.isZERO()) { 1220 return S.negate(); 1221 } 1222 assert (ring.nvar == S.ring.nvar); 1223 GenPolynomial<C> n = this.copy(); 1224 SortedMap<ExpVector, C> nv = n.val; 1225 SortedMap<ExpVector, C> sv = S.val; 1226 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1227 ExpVector e = me.getKey(); 1228 C y = me.getValue(); // assert y != null 1229 C x = nv.get(e); 1230 if (x != null) { 1231 x = x.subtract(y); 1232 if (!x.isZERO()) { 1233 nv.put(e, x); 1234 } else { 1235 nv.remove(e); 1236 } 1237 } else { 1238 nv.put(e, y.negate()); 1239 } 1240 } 1241 return n; 1242 } 1243 1244 1245 /** 1246 * GenPolynomial subtraction. This method is not very efficient, since this 1247 * is copied. 1248 * @param a coefficient. 1249 * @param e exponent. 1250 * @return this - a x<sup>e</sup>. 1251 */ 1252 public GenPolynomial<C> subtract(C a, ExpVector e) { 1253 if (a == null || a.isZERO()) { 1254 return this; 1255 } 1256 GenPolynomial<C> n = this.copy(); 1257 SortedMap<ExpVector, C> nv = n.val; 1258 C x = nv.get(e); 1259 if (x != null) { 1260 x = x.subtract(a); 1261 if (!x.isZERO()) { 1262 nv.put(e, x); 1263 } else { 1264 nv.remove(e); 1265 } 1266 } else { 1267 nv.put(e, a.negate()); 1268 } 1269 return n; 1270 } 1271 1272 1273 /** 1274 * GenPolynomial subtraction. This method is not very efficient, since this 1275 * is copied. 1276 * @param m monomial. 1277 * @return this - m. 1278 */ 1279 public GenPolynomial<C> subtract(Monomial<C> m) { 1280 return subtract(m.coefficient(), m.exponent()); 1281 } 1282 1283 1284 /** 1285 * GenPolynomial subtract. This method is not very efficient, since this is 1286 * copied. 1287 * @param a coefficient. 1288 * @return this + a x<sup>0</sup>. 1289 */ 1290 public GenPolynomial<C> subtract(C a) { 1291 return subtract(a, ring.evzero); 1292 } 1293 1294 1295 /** 1296 * GenPolynomial subtract a multiple. 1297 * @param a coefficient. 1298 * @param S GenPolynomial. 1299 * @return this - a S. 1300 */ 1301 public GenPolynomial<C> subtractMultiple(C a, GenPolynomial<C> S) { 1302 if (a == null || a.isZERO()) { 1303 return this; 1304 } 1305 if (S == null || S.isZERO()) { 1306 return this; 1307 } 1308 if (this.isZERO()) { 1309 return S.multiply(a.negate()); 1310 } 1311 assert (ring.nvar == S.ring.nvar); 1312 GenPolynomial<C> n = this.copy(); 1313 SortedMap<ExpVector, C> nv = n.val; 1314 SortedMap<ExpVector, C> sv = S.val; 1315 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1316 ExpVector f = me.getKey(); 1317 C y = me.getValue(); // assert y != null 1318 y = a.multiply(y); 1319 C x = nv.get(f); 1320 if (x != null) { 1321 x = x.subtract(y); 1322 if (!x.isZERO()) { 1323 nv.put(f, x); 1324 } else { 1325 nv.remove(f); 1326 } 1327 } else if (!y.isZERO()) { 1328 nv.put(f, y.negate()); 1329 } 1330 } 1331 return n; 1332 } 1333 1334 1335 /** 1336 * GenPolynomial subtract a multiple. 1337 * @param a coefficient. 1338 * @param e exponent. 1339 * @param S GenPolynomial. 1340 * @return this - a x<sup>e</sup> S. 1341 */ 1342 public GenPolynomial<C> subtractMultiple(C a, ExpVector e, GenPolynomial<C> S) { 1343 if (a == null || a.isZERO()) { 1344 return this; 1345 } 1346 if (S == null || S.isZERO()) { 1347 return this; 1348 } 1349 if (this.isZERO()) { 1350 return S.multiply(a.negate(), e); 1351 } 1352 assert (ring.nvar == S.ring.nvar); 1353 GenPolynomial<C> n = this.copy(); 1354 SortedMap<ExpVector, C> nv = n.val; 1355 SortedMap<ExpVector, C> sv = S.val; 1356 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1357 ExpVector f = me.getKey(); 1358 f = e.sum(f); 1359 C y = me.getValue(); // assert y != null 1360 y = a.multiply(y); 1361 C x = nv.get(f); 1362 if (x != null) { 1363 x = x.subtract(y); 1364 if (!x.isZERO()) { 1365 nv.put(f, x); 1366 } else { 1367 nv.remove(f); 1368 } 1369 } else if (!y.isZERO()) { 1370 nv.put(f, y.negate()); 1371 } 1372 } 1373 return n; 1374 } 1375 1376 1377 /** 1378 * GenPolynomial scale and subtract a multiple. 1379 * @param b scale factor. 1380 * @param a coefficient. 1381 * @param S GenPolynomial. 1382 * @return this * b - a S. 1383 */ 1384 public GenPolynomial<C> scaleSubtractMultiple(C b, C a, GenPolynomial<C> S) { 1385 if (a == null || S == null) { 1386 return this.multiply(b); 1387 } 1388 if (a.isZERO() || S.isZERO()) { 1389 return this.multiply(b); 1390 } 1391 if (this.isZERO() || b == null || b.isZERO()) { 1392 return S.multiply(a.negate()); //left? 1393 } 1394 if (b.isONE()) { 1395 return subtractMultiple(a, S); 1396 } 1397 assert (ring.nvar == S.ring.nvar); 1398 GenPolynomial<C> n = this.multiply(b); 1399 SortedMap<ExpVector, C> nv = n.val; 1400 SortedMap<ExpVector, C> sv = S.val; 1401 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1402 ExpVector f = me.getKey(); 1403 //f = e.sum(f); 1404 C y = me.getValue(); // assert y != null 1405 y = a.multiply(y); // now y can be zero 1406 C x = nv.get(f); 1407 if (x != null) { 1408 x = x.subtract(y); 1409 if (!x.isZERO()) { 1410 nv.put(f, x); 1411 } else { 1412 nv.remove(f); 1413 } 1414 } else if (!y.isZERO()) { 1415 nv.put(f, y.negate()); 1416 } 1417 } 1418 return n; 1419 } 1420 1421 1422 /** 1423 * GenPolynomial scale and subtract a multiple. 1424 * @param b scale factor. 1425 * @param a coefficient. 1426 * @param e exponent. 1427 * @param S GenPolynomial. 1428 * @return this * b - a x<sup>e</sup> S. 1429 */ 1430 public GenPolynomial<C> scaleSubtractMultiple(C b, C a, ExpVector e, GenPolynomial<C> S) { 1431 if (a == null || S == null) { 1432 return this.multiply(b); 1433 } 1434 if (a.isZERO() || S.isZERO()) { 1435 return this.multiply(b); 1436 } 1437 if (this.isZERO() || b == null || b.isZERO()) { 1438 return S.multiply(a.negate(), e); 1439 } 1440 if (b.isONE()) { 1441 return subtractMultiple(a, e, S); 1442 } 1443 assert (ring.nvar == S.ring.nvar); 1444 GenPolynomial<C> n = this.multiply(b); 1445 SortedMap<ExpVector, C> nv = n.val; 1446 SortedMap<ExpVector, C> sv = S.val; 1447 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1448 ExpVector f = me.getKey(); 1449 f = e.sum(f); 1450 C y = me.getValue(); // assert y != null 1451 y = a.multiply(y); // now y can be zero 1452 C x = nv.get(f); 1453 if (x != null) { 1454 x = x.subtract(y); 1455 if (!x.isZERO()) { 1456 nv.put(f, x); 1457 } else { 1458 nv.remove(f); 1459 } 1460 } else if (!y.isZERO()) { 1461 nv.put(f, y.negate()); 1462 } 1463 } 1464 return n; 1465 } 1466 1467 1468 /** 1469 * GenPolynomial scale and subtract a multiple. 1470 * @param b scale factor. 1471 * @param g scale exponent. 1472 * @param a coefficient. 1473 * @param e exponent. 1474 * @param S GenPolynomial. 1475 * @return this * a x<sup>g</sup> - a x<sup>e</sup> S. 1476 */ 1477 public GenPolynomial<C> scaleSubtractMultiple(C b, ExpVector g, C a, ExpVector e, GenPolynomial<C> S) { 1478 if (a == null || S == null) { 1479 return this.multiply(b, g); 1480 } 1481 if (a.isZERO() || S.isZERO()) { 1482 return this.multiply(b, g); 1483 } 1484 if (this.isZERO() || b == null || b.isZERO()) { 1485 return S.multiply(a.negate(), e); 1486 } 1487 if (b.isONE() && g.isZERO()) { 1488 return subtractMultiple(a, e, S); 1489 } 1490 assert (ring.nvar == S.ring.nvar); 1491 GenPolynomial<C> n = this.multiply(b, g); 1492 SortedMap<ExpVector, C> nv = n.val; 1493 SortedMap<ExpVector, C> sv = S.val; 1494 for (Map.Entry<ExpVector, C> me : sv.entrySet()) { 1495 ExpVector f = me.getKey(); 1496 f = e.sum(f); 1497 C y = me.getValue(); // assert y != null 1498 y = a.multiply(y); // y can be zero now 1499 C x = nv.get(f); 1500 if (x != null) { 1501 x = x.subtract(y); 1502 if (!x.isZERO()) { 1503 nv.put(f, x); 1504 } else { 1505 nv.remove(f); 1506 } 1507 } else if (!y.isZERO()) { 1508 nv.put(f, y.negate()); 1509 } 1510 } 1511 return n; 1512 } 1513 1514 1515 /** 1516 * GenPolynomial negation, alternative implementation. 1517 * @return -this. 1518 */ 1519 public GenPolynomial<C> negateAlt() { 1520 GenPolynomial<C> n = ring.getZERO().copy(); 1521 SortedMap<ExpVector, C> v = n.val; 1522 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1523 C x = m.getValue(); // != null, 0 1524 v.put(m.getKey(), x.negate()); 1525 } 1526 return n; 1527 } 1528 1529 1530 /** 1531 * GenPolynomial negation. 1532 * @return -this. 1533 */ 1534 public GenPolynomial<C> negate() { 1535 GenPolynomial<C> n = this.copy(); 1536 SortedMap<ExpVector, C> v = n.val; 1537 for (Map.Entry<ExpVector, C> m : v.entrySet()) { 1538 C x = m.getValue(); // != null, 0 1539 m.setValue(x.negate()); // okay 1540 } 1541 return n; 1542 } 1543 1544 1545 /** 1546 * GenPolynomial absolute value, i.e. leadingCoefficient > 0. 1547 * @return abs(this). 1548 */ 1549 public GenPolynomial<C> abs() { 1550 if (leadingBaseCoefficient().signum() < 0) { 1551 return this.negate(); 1552 } 1553 return this; 1554 } 1555 1556 1557 /** 1558 * GenPolynomial multiplication. 1559 * @param S GenPolynomial. 1560 * @return this*S. 1561 */ 1562 public GenPolynomial<C> multiply(GenPolynomial<C> S) { 1563 if (S == null) { 1564 return ring.getZERO(); 1565 } 1566 if (S.isZERO()) { 1567 return ring.getZERO(); 1568 } 1569 if (this.isZERO()) { 1570 return this; 1571 } 1572 assert (ring.nvar == S.ring.nvar); 1573 if (this instanceof GenSolvablePolynomial && S instanceof GenSolvablePolynomial) { 1574 //throw new RuntimeException("wrong method dispatch in JRE "); 1575 logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); 1576 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1577 GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S; 1578 return T.multiply(Sp); 1579 } 1580 GenPolynomial<C> p = ring.getZERO().copy(); 1581 SortedMap<ExpVector, C> pv = p.val; 1582 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1583 C c1 = m1.getValue(); 1584 ExpVector e1 = m1.getKey(); 1585 for (Map.Entry<ExpVector, C> m2 : S.val.entrySet()) { 1586 C c2 = m2.getValue(); 1587 ExpVector e2 = m2.getKey(); 1588 C c = c1.multiply(c2); // check non zero if not domain 1589 if (!c.isZERO()) { 1590 ExpVector e = e1.sum(e2); 1591 C c0 = pv.get(e); 1592 if (c0 == null) { 1593 pv.put(e, c); 1594 } else { 1595 c0 = c0.sum(c); 1596 if (!c0.isZERO()) { 1597 pv.put(e, c0); 1598 } else { 1599 pv.remove(e); 1600 } 1601 } 1602 } 1603 } 1604 } 1605 return p; 1606 } 1607 1608 1609 /** 1610 * GenPolynomial multiplication. Product with coefficient ring element. 1611 * @param s coefficient. 1612 * @return this*s. 1613 */ 1614 public GenPolynomial<C> multiply(C s) { 1615 if (s == null || s.isZERO()) { 1616 return ring.getZERO(); 1617 } 1618 if (this.isZERO()) { 1619 return this; 1620 } 1621 if (this instanceof GenSolvablePolynomial) { 1622 //throw new RuntimeException("wrong method dispatch in JRE "); 1623 logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix"); 1624 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1625 return T.multiply(s); 1626 } 1627 GenPolynomial<C> p = ring.getZERO().copy(); 1628 SortedMap<ExpVector, C> pv = p.val; 1629 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1630 C a = m.getValue(); 1631 ExpVector e = m.getKey(); 1632 C c = a.multiply(s); // check non zero if not domain 1633 if (!c.isZERO()) { 1634 pv.put(e, c); // not m1.setValue( c ) 1635 } 1636 } 1637 return p; 1638 } 1639 1640 1641 /** 1642 * GenPolynomial left multiplication. Left product with coefficient ring 1643 * element. 1644 * @param s coefficient. 1645 * @return s*this. 1646 */ 1647 public GenPolynomial<C> multiplyLeft(C s) { 1648 if (s == null || s.isZERO()) { 1649 return ring.getZERO(); 1650 } 1651 if (this.isZERO()) { 1652 return this; 1653 } 1654 if (this instanceof GenSolvablePolynomial) { 1655 //throw new RuntimeException("wrong method dispatch in JRE "); 1656 logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix"); 1657 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1658 return T.multiplyLeft(s); 1659 } 1660 GenPolynomial<C> p = ring.getZERO().copy(); 1661 SortedMap<ExpVector, C> pv = p.val; 1662 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1663 C a = m.getValue(); 1664 ExpVector e = m.getKey(); 1665 C c = s.multiply(a); 1666 if (!c.isZERO()) { 1667 pv.put(e, c); 1668 } 1669 } 1670 return p; 1671 } 1672 1673 1674 /** 1675 * GenPolynomial monic, i.e. leadingCoefficient == 1. If leadingCoefficient 1676 * is not invertible returns this unmodified. 1677 * @return monic(this). 1678 */ 1679 public GenPolynomial<C> monic() { 1680 if (this.isZERO()) { 1681 return this; 1682 } 1683 C lc = leadingBaseCoefficient(); 1684 if (!lc.isUnit()) { 1685 //System.out.println("lc = "+lc); 1686 return this; 1687 } 1688 C lm = lc.inverse(); 1689 return multiplyLeft(lm); 1690 } 1691 1692 1693 /** 1694 * GenPolynomial multiplication. Product with ring element and exponent 1695 * vector. 1696 * @param s coefficient. 1697 * @param e exponent. 1698 * @return this * s x<sup>e</sup>. 1699 */ 1700 public GenPolynomial<C> multiply(C s, ExpVector e) { 1701 if (s == null) { 1702 return ring.getZERO(); 1703 } 1704 if (s.isZERO()) { 1705 return ring.getZERO(); 1706 } 1707 if (this.isZERO()) { 1708 return this; 1709 } 1710 if (e == null) { // exp vector of zero polynomial 1711 return ring.getZERO(); 1712 } 1713 if (this instanceof GenSolvablePolynomial) { 1714 //throw new RuntimeException("wrong method dispatch in JRE "); 1715 logger.debug("warn: wrong method dispatch in JRE multiply(s,e) - trying to fix"); 1716 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1717 return T.multiply(s, e); 1718 } 1719 GenPolynomial<C> p = ring.getZERO().copy(); 1720 SortedMap<ExpVector, C> pv = p.val; 1721 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1722 C c1 = m1.getValue(); 1723 ExpVector e1 = m1.getKey(); 1724 C c = c1.multiply(s); // check non zero if not domain 1725 if (!c.isZERO()) { 1726 ExpVector e2 = e1.sum(e); 1727 pv.put(e2, c); 1728 } 1729 } 1730 return p; 1731 } 1732 1733 1734 /** 1735 * GenPolynomial multiplication. Product with exponent vector. 1736 * @param e exponent (!= null). 1737 * @return this * x<sup>e</sup>. 1738 */ 1739 public GenPolynomial<C> multiply(ExpVector e) { 1740 if (e == null) { // exp vector of zero polynomial 1741 return ring.getZERO(); 1742 } 1743 // assert e != null. This is seldom allowed. 1744 if (this.isZERO()) { 1745 return this; 1746 } 1747 if (this instanceof GenSolvablePolynomial) { 1748 //throw new RuntimeException("wrong method dispatch in JRE "); 1749 logger.debug("warn: wrong method dispatch in JRE multiply(e) - trying to fix"); 1750 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1751 return T.multiply(e); 1752 } 1753 GenPolynomial<C> p = ring.getZERO().copy(); 1754 SortedMap<ExpVector, C> pv = p.val; 1755 for (Map.Entry<ExpVector, C> m1 : val.entrySet()) { 1756 C c1 = m1.getValue(); 1757 ExpVector e1 = m1.getKey(); 1758 ExpVector e2 = e1.sum(e); 1759 pv.put(e2, c1); 1760 } 1761 return p; 1762 } 1763 1764 1765 /** 1766 * GenPolynomial multiplication. Product with 'monomial'. 1767 * @param m 'monomial'. 1768 * @return this * m. 1769 */ 1770 public GenPolynomial<C> multiply(Map.Entry<ExpVector, C> m) { 1771 if (m == null) { 1772 return ring.getZERO(); 1773 } 1774 return multiply(m.getValue(), m.getKey()); 1775 } 1776 1777 1778 /** 1779 * GenPolynomial division. Division by coefficient ring element. Fails, if 1780 * exact division is not possible. 1781 * @param s coefficient. 1782 * @return s**(-1) * this. 1783 */ 1784 public GenPolynomial<C> divide(C s) { 1785 if (s == null || s.isZERO()) { 1786 throw new ArithmeticException("division by zero"); 1787 } 1788 if (this.isZERO()) { 1789 return this; 1790 } 1791 //C t = s.inverse(); 1792 //return multiply(t); 1793 GenPolynomial<C> p = ring.getZERO().copy(); 1794 SortedMap<ExpVector, C> pv = p.val; 1795 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1796 ExpVector e = m.getKey(); 1797 C c1 = m.getValue(); 1798 C c = c1.divide(s); 1799 if (debug) { 1800 C x = c1.remainder(s); 1801 if (!x.isZERO()) { 1802 logger.info("divide x = " + x); 1803 throw new ArithmeticException("no exact division: " + c1 + "/" + s); 1804 } 1805 } 1806 if (c.isZERO()) { 1807 throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); 1808 } 1809 pv.put(e, c); // not m1.setValue( c ) 1810 } 1811 return p; 1812 } 1813 1814 1815 /** 1816 * GenPolynomial right division. Right division by coefficient ring element. 1817 * Fails, if exact division is not possible. 1818 * @param s coefficient. 1819 * @return this * s**(-1). 1820 */ 1821 public GenPolynomial<C> rightDivideCoeff(C s) { 1822 if (s == null || s.isZERO()) { 1823 throw new ArithmeticException("division by zero"); 1824 } 1825 if (this.isZERO()) { 1826 return this; 1827 } 1828 //C t = s.inverse(); 1829 //return multiply(t); 1830 GenPolynomial<C> p = ring.getZERO().copy(); 1831 SortedMap<ExpVector, C> pv = p.val; 1832 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1833 ExpVector e = m.getKey(); 1834 C c1 = m.getValue(); 1835 C c = c1.rightDivide(s); 1836 if (debug) { 1837 C x = c1.rightRemainder(s); 1838 if (!x.isZERO()) { 1839 logger.info("divide x = " + x); 1840 throw new ArithmeticException("no exact division: " + c1 + "/" + s); 1841 } 1842 } 1843 if (c.isZERO()) { 1844 throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); 1845 } 1846 pv.put(e, c); // not m1.setValue( c ) 1847 } 1848 return p; 1849 } 1850 1851 1852 /** 1853 * GenPolynomial left division. Left division by coefficient ring element. 1854 * Fails, if exact division is not possible. 1855 * @param s coefficient. 1856 * @return s**(-1) * this. 1857 */ 1858 public GenPolynomial<C> leftDivideCoeff(C s) { 1859 if (s == null || s.isZERO()) { 1860 throw new ArithmeticException("division by zero"); 1861 } 1862 if (this.isZERO()) { 1863 return this; 1864 } 1865 //C t = s.inverse(); 1866 //return multiply(t); 1867 GenPolynomial<C> p = ring.getZERO().copy(); 1868 SortedMap<ExpVector, C> pv = p.val; 1869 for (Map.Entry<ExpVector, C> m : val.entrySet()) { 1870 ExpVector e = m.getKey(); 1871 C c1 = m.getValue(); 1872 C c = c1.leftDivide(s); 1873 if (debug) { 1874 C x = c1.leftRemainder(s); 1875 if (!x.isZERO()) { 1876 logger.info("divide x = " + x); 1877 throw new ArithmeticException("no exact division: " + c1 + "/" + s); 1878 } 1879 } 1880 if (c.isZERO()) { 1881 throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); 1882 } 1883 pv.put(e, c); // not m1.setValue( c ) 1884 } 1885 return p; 1886 } 1887 1888 1889 /** 1890 * GenPolynomial division with remainder. Fails, if exact division by 1891 * leading base coefficient is not possible. Meaningful only for univariate 1892 * polynomials over fields, but works in any case. 1893 * @param S nonzero GenPolynomial with invertible leading coefficient. 1894 * @return [ quotient , remainder ] with this = quotient * S + remainder and 1895 * deg(remainder) < deg(S) or remiander = 0. 1896 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1897 */ 1898 @SuppressWarnings("unchecked") 1899 public GenPolynomial<C>[] quotientRemainder(GenPolynomial<C> S) { 1900 if (S == null || S.isZERO()) { 1901 throw new ArithmeticException("division by zero"); 1902 } 1903 C c = S.leadingBaseCoefficient(); 1904 if (!c.isUnit()) { 1905 throw new ArithmeticException("lbcf not invertible " + c); 1906 } 1907 C ci = c.inverse(); 1908 assert (ring.nvar == S.ring.nvar); 1909 ExpVector e = S.leadingExpVector(); 1910 GenPolynomial<C> h; 1911 GenPolynomial<C> q = ring.getZERO().copy(); 1912 GenPolynomial<C> r = this.copy(); 1913 while (!r.isZERO()) { 1914 ExpVector f = r.leadingExpVector(); 1915 if (f.multipleOf(e)) { 1916 C a = r.leadingBaseCoefficient(); 1917 ExpVector g = f.subtract(e); 1918 a = a.multiply(ci); 1919 q = q.sum(a, g); 1920 h = S.multiply(a, g); 1921 r = r.subtract(h); 1922 assert (!f.equals(r.leadingExpVector())) : "leadingExpVector not descending: " + f; 1923 } else { 1924 break; 1925 } 1926 } 1927 GenPolynomial<C>[] ret = new GenPolynomial[2]; 1928 ret[0] = q; 1929 ret[1] = r; 1930 return ret; 1931 } 1932 1933 1934 /** 1935 * GenPolynomial division. Fails, if exact division by leading base 1936 * coefficient is not possible. Meaningful only for univariate polynomials 1937 * over fields, but works in any case. 1938 * @param S nonzero GenPolynomial with invertible leading coefficient. 1939 * @return quotient with this = quotient * S + remainder. 1940 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1941 */ 1942 public GenPolynomial<C> divide(GenPolynomial<C> S) { 1943 if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) { 1944 //throw new RuntimeException("wrong method dispatch in JRE "); 1945 //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); 1946 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1947 GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S; 1948 return T.quotientRemainder(Sp)[0]; 1949 } 1950 return quotientRemainder(S)[0]; 1951 } 1952 1953 1954 /** 1955 * GenPolynomial remainder. Fails, if exact division by leading base 1956 * coefficient is not possible. Meaningful only for univariate polynomials 1957 * over fields, but works in any case. 1958 * @param S nonzero GenPolynomial with invertible leading coefficient. 1959 * @return remainder with this = quotient * S + remainder. 1960 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1961 */ 1962 public GenPolynomial<C> remainder(GenPolynomial<C> S) { 1963 if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) { 1964 //throw new RuntimeException("wrong method dispatch in JRE "); 1965 //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); 1966 GenSolvablePolynomial<C> T = (GenSolvablePolynomial<C>) this; 1967 GenSolvablePolynomial<C> Sp = (GenSolvablePolynomial<C>) S; 1968 return T.quotientRemainder(Sp)[1]; 1969 } 1970 if (S == null || S.isZERO()) { 1971 throw new ArithmeticException("division by zero"); 1972 } 1973 C c = S.leadingBaseCoefficient(); 1974 if (!c.isUnit()) { 1975 throw new ArithmeticException("lbc not invertible " + c); 1976 } 1977 C ci = c.inverse(); 1978 assert (ring.nvar == S.ring.nvar); 1979 ExpVector e = S.leadingExpVector(); 1980 GenPolynomial<C> h; 1981 GenPolynomial<C> r = this.copy(); 1982 while (!r.isZERO()) { 1983 ExpVector f = r.leadingExpVector(); 1984 if (f.multipleOf(e)) { 1985 C a = r.leadingBaseCoefficient(); 1986 ExpVector g = f.subtract(e); 1987 //logger.info("red div = " + e); 1988 a = a.multiply(ci); 1989 h = S.multiply(a, g); 1990 r = r.subtract(h); 1991 assert (!f.equals(r.leadingExpVector())) : "leadingExpVector not descending: " + f; 1992 } else { 1993 break; 1994 } 1995 } 1996 return r; 1997 } 1998 1999 2000 /** 2001 * GenPolynomial greatest common divisor. Only for univariate polynomials 2002 * over fields. 2003 * @param S GenPolynomial. 2004 * @return gcd(this,S). 2005 */ 2006 public GenPolynomial<C> gcd(GenPolynomial<C> S) { 2007 if (S == null || S.isZERO()) { 2008 return this; 2009 } 2010 if (this.isZERO()) { 2011 return S; 2012 } 2013 if (ring.nvar != 1) { 2014 throw new IllegalArgumentException("not univariate polynomials" + ring); 2015 } 2016 GenPolynomial<C> x; 2017 GenPolynomial<C> q = this; 2018 GenPolynomial<C> r = S; 2019 while (!r.isZERO()) { 2020 x = q.remainder(r); 2021 q = r; 2022 r = x; 2023 } 2024 return q.monic(); // normalize 2025 } 2026 2027 2028 /** 2029 * GenPolynomial extended greatest comon divisor. Only for univariate 2030 * polynomials over fields. 2031 * @param S GenPolynomial. 2032 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 2033 */ 2034 @SuppressWarnings("unchecked") 2035 public GenPolynomial<C>[] egcd(GenPolynomial<C> S) { 2036 GenPolynomial<C>[] ret = new GenPolynomial[3]; 2037 ret[0] = null; 2038 ret[1] = null; 2039 ret[2] = null; 2040 if (S == null || S.isZERO()) { 2041 ret[0] = this; 2042 ret[1] = this.ring.getONE(); 2043 ret[2] = this.ring.getZERO(); 2044 return ret; 2045 } 2046 if (this.isZERO()) { 2047 ret[0] = S; 2048 ret[1] = this.ring.getZERO(); 2049 ret[2] = this.ring.getONE(); 2050 return ret; 2051 } 2052 if (ring.nvar != 1) { 2053 throw new IllegalArgumentException( 2054 this.getClass().getName() + " not univariate polynomials" + ring); 2055 } 2056 if (this.isConstant() && S.isConstant()) { 2057 C t = this.leadingBaseCoefficient(); 2058 C s = S.leadingBaseCoefficient(); 2059 C[] gg = t.egcd(s); 2060 //System.out.println("coeff gcd = " + Arrays.toString(gg)); 2061 GenPolynomial<C> z = this.ring.getZERO(); 2062 ret[0] = z.sum(gg[0]); 2063 ret[1] = z.sum(gg[1]); 2064 ret[2] = z.sum(gg[2]); 2065 return ret; 2066 } 2067 GenPolynomial<C>[] qr; 2068 GenPolynomial<C> q = this; 2069 GenPolynomial<C> r = S; 2070 GenPolynomial<C> c1 = ring.getONE().copy(); 2071 GenPolynomial<C> d1 = ring.getZERO().copy(); 2072 GenPolynomial<C> c2 = ring.getZERO().copy(); 2073 GenPolynomial<C> d2 = ring.getONE().copy(); 2074 GenPolynomial<C> x1; 2075 GenPolynomial<C> x2; 2076 while (!r.isZERO()) { 2077 qr = q.quotientRemainder(r); 2078 q = qr[0]; 2079 x1 = c1.subtract(q.multiply(d1)); 2080 x2 = c2.subtract(q.multiply(d2)); 2081 c1 = d1; 2082 c2 = d2; 2083 d1 = x1; 2084 d2 = x2; 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 c2 = c2.multiply(h); 2095 } 2096 //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); 2097 ret[0] = q; 2098 ret[1] = c1; 2099 ret[2] = c2; 2100 return ret; 2101 } 2102 2103 2104 /** 2105 * GenPolynomial half extended greatest comon divisor. Only for univariate 2106 * polynomials over fields. 2107 * @param S GenPolynomial. 2108 * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S). 2109 */ 2110 @SuppressWarnings("unchecked") 2111 public GenPolynomial<C>[] hegcd(GenPolynomial<C> S) { 2112 GenPolynomial<C>[] ret = new GenPolynomial[2]; 2113 ret[0] = null; 2114 ret[1] = null; 2115 if (S == null || S.isZERO()) { 2116 ret[0] = this; 2117 ret[1] = this.ring.getONE(); 2118 return ret; 2119 } 2120 if (this.isZERO()) { 2121 ret[0] = S; 2122 return ret; 2123 } 2124 if (ring.nvar != 1) { 2125 throw new IllegalArgumentException( 2126 this.getClass().getName() + " not univariate polynomials" + ring); 2127 } 2128 GenPolynomial<C>[] qr; 2129 GenPolynomial<C> q = this; 2130 GenPolynomial<C> r = S; 2131 GenPolynomial<C> c1 = ring.getONE().copy(); 2132 GenPolynomial<C> d1 = ring.getZERO().copy(); 2133 GenPolynomial<C> x1; 2134 while (!r.isZERO()) { 2135 qr = q.quotientRemainder(r); 2136 q = qr[0]; 2137 x1 = c1.subtract(q.multiply(d1)); 2138 c1 = d1; 2139 d1 = x1; 2140 q = r; 2141 r = qr[1]; 2142 } 2143 // normalize ldcf(q) to 1, i.e. make monic 2144 C g = q.leadingBaseCoefficient(); 2145 if (g.isUnit()) { 2146 C h = g.inverse(); 2147 q = q.multiply(h); 2148 c1 = c1.multiply(h); 2149 } 2150 //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); 2151 ret[0] = q; 2152 ret[1] = c1; 2153 return ret; 2154 } 2155 2156 2157 /** 2158 * GenPolynomial inverse. Required by RingElem. Throws not invertible 2159 * exception. 2160 */ 2161 public GenPolynomial<C> inverse() { 2162 if (isUnit()) { // only possible if ldbcf is unit 2163 C c = leadingBaseCoefficient().inverse(); 2164 return ring.getONE().multiply(c); 2165 } 2166 throw new NotInvertibleException("element not invertible " + this + " :: " + ring); 2167 } 2168 2169 2170 /** 2171 * GenPolynomial modular inverse. Only for univariate polynomials over 2172 * fields. 2173 * @param m GenPolynomial. 2174 * @return a with with a*this = 1 mod m. 2175 */ 2176 public GenPolynomial<C> modInverse(GenPolynomial<C> m) { 2177 if (this.isZERO()) { 2178 throw new NotInvertibleException("zero is not invertible"); 2179 } 2180 GenPolynomial<C>[] hegcd = this.hegcd(m); 2181 GenPolynomial<C> a = hegcd[0]; 2182 if (!a.isUnit()) { // gcd != 1 2183 throw new AlgebraicNotInvertibleException("element not invertible, gcd != 1", m, a, m.divide(a)); 2184 } 2185 GenPolynomial<C> b = hegcd[1]; 2186 if (b.isZERO()) { // when m divides this, e.g. m.isUnit() 2187 throw new NotInvertibleException("element not invertible, divisible by modul"); 2188 } 2189 return b; 2190 } 2191 2192 2193 /** 2194 * Extend variables. Used e.g. in module embedding. Extend all ExpVectors by 2195 * i elements and multiply by x_j^k. 2196 * @param pfac extended polynomial ring factory (by i variables). 2197 * @param j index of variable to be used for multiplication. 2198 * @param k exponent for x_j. 2199 * @return extended polynomial. 2200 */ 2201 public GenPolynomial<C> extend(GenPolynomialRing<C> pfac, int j, long k) { 2202 if (ring.equals(pfac)) { // nothing to do 2203 return this; 2204 } 2205 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2206 if (this.isZERO()) { 2207 return Cp; 2208 } 2209 int i = pfac.nvar - ring.nvar; 2210 Map<ExpVector, C> C = Cp.val; //getMap(); 2211 Map<ExpVector, C> A = val; 2212 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2213 ExpVector e = y.getKey(); 2214 C a = y.getValue(); 2215 ExpVector f = e.extend(i, j, k); 2216 C.put(f, a); 2217 } 2218 return Cp; 2219 } 2220 2221 2222 /** 2223 * Extend lower variables. Used e.g. in module embedding. Extend all 2224 * ExpVectors by i lower elements and multiply by x_j^k. 2225 * @param pfac extended polynomial ring factory (by i variables). 2226 * @param j index of variable to be used for multiplication. 2227 * @param k exponent for x_j. 2228 * @return extended polynomial. 2229 */ 2230 public GenPolynomial<C> extendLower(GenPolynomialRing<C> pfac, int j, long k) { 2231 if (ring.equals(pfac)) { // nothing to do 2232 return this; 2233 } 2234 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2235 if (this.isZERO()) { 2236 return Cp; 2237 } 2238 int i = pfac.nvar - ring.nvar; 2239 Map<ExpVector, C> C = Cp.val; //getMap(); 2240 Map<ExpVector, C> A = val; 2241 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2242 ExpVector e = y.getKey(); 2243 C a = y.getValue(); 2244 ExpVector f = e.extendLower(i, j, k); 2245 C.put(f, a); 2246 } 2247 return Cp; 2248 } 2249 2250 2251 /** 2252 * Contract variables. Used e.g. in module embedding. Remove i elements of 2253 * each ExpVector. 2254 * @param pfac contracted polynomial ring factory (by i variables). 2255 * @return Map of exponents and contracted polynomials. <b>Note:</b> could 2256 * return SortedMap 2257 */ 2258 public Map<ExpVector, GenPolynomial<C>> contract(GenPolynomialRing<C> pfac) { 2259 GenPolynomial<C> zero = pfac.getZERO(); //not pfac.coFac; 2260 TermOrder t = new TermOrder(TermOrder.INVLEX); 2261 Map<ExpVector, GenPolynomial<C>> B = new TreeMap<ExpVector, GenPolynomial<C>>( 2262 t.getAscendComparator()); 2263 if (this.isZERO()) { 2264 return B; 2265 } 2266 int i = ring.nvar - pfac.nvar; 2267 Map<ExpVector, C> A = val; 2268 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2269 ExpVector e = y.getKey(); 2270 C a = y.getValue(); 2271 ExpVector f = e.contract(0, i); 2272 ExpVector g = e.contract(i, e.length() - i); 2273 GenPolynomial<C> p = B.get(f); 2274 if (p == null) { 2275 p = zero; 2276 } 2277 p = p.sum(a, g); 2278 B.put(f, p); 2279 } 2280 return B; 2281 } 2282 2283 2284 /** 2285 * Contract variables to coefficient polynomial. Remove i elements of each 2286 * ExpVector, removed elements must be zero. 2287 * @param pfac contracted polynomial ring factory (by i variables). 2288 * @return contracted coefficient polynomial. 2289 */ 2290 public GenPolynomial<C> contractCoeff(GenPolynomialRing<C> pfac) { 2291 Map<ExpVector, GenPolynomial<C>> ms = contract(pfac); 2292 GenPolynomial<C> c = pfac.getZERO(); 2293 for (Map.Entry<ExpVector, GenPolynomial<C>> m : ms.entrySet()) { 2294 if (m.getKey().isZERO()) { 2295 c = m.getValue(); 2296 } else { 2297 throw new RuntimeException("wrong coefficient contraction " + m + ", pol = " + c); 2298 } 2299 } 2300 return c; 2301 } 2302 2303 2304 /** 2305 * Extend univariate to multivariate polynomial. This is an univariate 2306 * polynomial in variable i of the polynomial ring, it is extended to the 2307 * given polynomial ring. 2308 * @param pfac extended polynomial ring factory. 2309 * @param i index of the variable of this polynomial in pfac. 2310 * @return extended multivariate polynomial. 2311 */ 2312 public GenPolynomial<C> extendUnivariate(GenPolynomialRing<C> pfac, int i) { 2313 if (i < 0 || pfac.nvar < i) { 2314 throw new IllegalArgumentException("index " + i + "out of range " + pfac.nvar); 2315 } 2316 if (ring.nvar != 1) { 2317 throw new IllegalArgumentException("polynomial not univariate " + ring.nvar); 2318 } 2319 if (this.isONE()) { 2320 return pfac.getONE(); 2321 } 2322 int j = pfac.nvar - 1 - i; 2323 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2324 if (this.isZERO()) { 2325 return Cp; 2326 } 2327 Map<ExpVector, C> C = Cp.val; //getMap(); 2328 Map<ExpVector, C> A = val; 2329 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2330 ExpVector e = y.getKey(); 2331 long n = e.getVal(0); 2332 C a = y.getValue(); 2333 ExpVector f = ExpVector.create(pfac.nvar, j, n); 2334 C.put(f, a); // assert not contained 2335 } 2336 return Cp; 2337 } 2338 2339 2340 /** 2341 * Make homogeneous. 2342 * @param pfac extended polynomial ring factory (by 1 variable). 2343 * @return homogeneous polynomial. 2344 */ 2345 public GenPolynomial<C> homogenize(GenPolynomialRing<C> pfac) { 2346 if (ring.equals(pfac)) { // not implemented 2347 throw new UnsupportedOperationException("case with same ring not implemented"); 2348 } 2349 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2350 if (this.isZERO()) { 2351 return Cp; 2352 } 2353 long deg = totalDegree(); 2354 //int i = pfac.nvar - ring.nvar; 2355 Map<ExpVector, C> C = Cp.val; //getMap(); 2356 Map<ExpVector, C> A = val; 2357 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2358 ExpVector e = y.getKey(); 2359 C a = y.getValue(); 2360 long d = deg - e.totalDeg(); 2361 ExpVector f = e.extend(1, 0, d); 2362 C.put(f, a); 2363 } 2364 return Cp; 2365 } 2366 2367 2368 /** 2369 * Dehomogenize. 2370 * @param pfac contracted polynomial ring factory (by 1 variable). 2371 * @return in homogeneous polynomial. 2372 */ 2373 public GenPolynomial<C> deHomogenize(GenPolynomialRing<C> pfac) { 2374 if (ring.equals(pfac)) { // not implemented 2375 throw new UnsupportedOperationException("case with same ring not implemented"); 2376 } 2377 GenPolynomial<C> Cp = pfac.getZERO().copy(); 2378 if (this.isZERO()) { 2379 return Cp; 2380 } 2381 Map<ExpVector, C> C = Cp.val; //getMap(); 2382 Map<ExpVector, C> A = val; 2383 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2384 ExpVector e = y.getKey(); 2385 C a = y.getValue(); 2386 ExpVector f = e.contract(1, pfac.nvar); 2387 C.put(f, a); 2388 } 2389 return Cp; 2390 } 2391 2392 2393 /** 2394 * Reverse variables. Used e.g. in opposite rings. 2395 * @return polynomial with reversed variables. 2396 */ 2397 public GenPolynomial<C> reverse(GenPolynomialRing<C> oring) { 2398 GenPolynomial<C> Cp = oring.getZERO().copy(); 2399 if (this.isZERO()) { 2400 return Cp; 2401 } 2402 int k = -1; 2403 if (oring.tord.getEvord2() != 0 && oring.partial) { 2404 k = oring.tord.getSplit(); 2405 } 2406 2407 Map<ExpVector, C> C = Cp.val; //getMap(); 2408 Map<ExpVector, C> A = val; 2409 ExpVector f; 2410 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2411 ExpVector e = y.getKey(); 2412 if (k >= 0) { 2413 f = e.reverse(k); 2414 } else { 2415 f = e.reverse(); 2416 } 2417 C a = y.getValue(); 2418 C.put(f, a); 2419 } 2420 return Cp; 2421 } 2422 2423 2424 /** 2425 * GenPolynomial inflate. Only for univariate polynomials over fields. 2426 * @param e exponent. 2427 * @return this(x**e) 2428 */ 2429 public GenPolynomial<C> inflate(long e) { 2430 if (e == 1) { 2431 return this; 2432 } 2433 if (this.isZERO()) { 2434 return this; 2435 } 2436 if (ring.nvar != 1) { 2437 throw new IllegalArgumentException( 2438 this.getClass().getName() + " not univariate polynomial" + ring); 2439 } 2440 GenPolynomial<C> Cp = ring.getZERO().copy(); 2441 Map<ExpVector, C> C = Cp.val; //getMap(); 2442 Map<ExpVector, C> A = val; 2443 ExpVector f; 2444 for (Map.Entry<ExpVector, C> y : A.entrySet()) { 2445 ExpVector g = y.getKey(); 2446 f = g.scalarMultiply(e); 2447 C a = y.getValue(); 2448 C.put(f, a); 2449 } 2450 return Cp; 2451 } 2452 2453 2454 /** 2455 * Iterator over coefficients. 2456 * @return val.values().iterator(). 2457 */ 2458 public Iterator<C> coefficientIterator() { 2459 return val.values().iterator(); 2460 } 2461 2462 2463 /** 2464 * Iterator over exponents. 2465 * @return val.keySet().iterator(). 2466 */ 2467 public Iterator<ExpVector> exponentIterator() { 2468 return val.keySet().iterator(); 2469 } 2470 2471 2472 /** 2473 * Iterator over monomials. 2474 * @return a PolyIterator. 2475 */ 2476 public Iterator<Monomial<C>> iterator() { 2477 return new PolyIterator<C>(val); 2478 } 2479 2480 2481 /** 2482 * Spliterator over monomials. 2483 * @return a PolySpliterator. 2484 */ 2485 public Spliterator<Monomial<C>> spliterator() { 2486 return new PolySpliterator<C>(val); 2487 } 2488 2489 2490 /** 2491 * Map a unary function to the coefficients. 2492 * @param f evaluation functor. 2493 * @return new polynomial with coefficients f(this.coefficients). 2494 */ 2495 public GenPolynomial<C> map(final UnaryFunctor<? super C, C> f) { 2496 GenPolynomial<C> n = ring.getZERO().copy(); 2497 SortedMap<ExpVector, C> nv = n.val; 2498 for (Map.Entry<ExpVector, C> m : this.val.entrySet()) { 2499 //logger.info("m = " + m); 2500 C c = f.eval(m.getValue()); 2501 if (c != null && !c.isZERO()) { 2502 nv.put(m.getKey(), c); 2503 } 2504 } 2505 return n; 2506 } 2507 2508 2509 /* 2510 * Map a unary function to the coefficients. 2511 * @param f evaluation functor. 2512 * @return new polynomial with coefficients f(this.coefficients). 2513 */ 2514 GenPolynomial<C> mapWrong(final UnaryFunctor<? super C, C> f) { 2515 GenPolynomial<C> n = this.copy(); 2516 SortedMap<ExpVector, C> nv = n.val; 2517 for (Map.Entry<ExpVector, C> m : nv.entrySet()) { 2518 //logger.info("m = " + m); 2519 C c = f.eval(m.getValue()); 2520 if (c != null && !c.isZERO()) { 2521 m.setValue(c); // not okay 2522 } else { 2523 // not possible nv.remove(m.getKey()); 2524 } 2525 } 2526 return n; 2527 } 2528 2529 2530 /** 2531 * Map a function to the polynomial stream entries. 2532 * @param f evaluation functor. 2533 * @return new polynomial with f(this.entries). 2534 */ 2535 public GenPolynomial<C> mapOnStream( 2536 final Function<? super Map.Entry<ExpVector, C>, ? extends Map.Entry<ExpVector, C>> f) { 2537 return mapOnStream(f, false); 2538 } 2539 2540 2541 /** 2542 * Map a function to the polynomial stream entries. 2543 * @param f evaluation functor. 2544 * @return new polynomial with f(this.entries). 2545 */ 2546 public GenPolynomial<C> mapOnStream( 2547 final Function<? super Map.Entry<ExpVector, C>, ? extends Map.Entry<ExpVector, C>> f, 2548 boolean parallel) { 2549 Stream<Map.Entry<ExpVector, C>> st; 2550 if (parallel) { 2551 st = val.entrySet().parallelStream(); 2552 } else { 2553 st = val.entrySet().stream(); 2554 } 2555 Map<ExpVector, C> m = st.map(f).filter(me -> !me.getValue().isZERO()) 2556 .collect(Collectors.toMap(me -> me.getKey(), me -> me.getValue())); 2557 //Stream<Map.Entry<ExpVector,C>> stp = st.map(f); 2558 //Stream<Map.Entry<ExpVector,C>> stf = stp.filter(me -> !me.getValue().isZERO()); 2559 //Map<ExpVector,C> m = stf.collect(Collectors.toMap(me -> me.getKey(), me -> me.getValue())); 2560 return new GenPolynomial<C>(ring, m); 2561 } 2562 2563 2564 /** 2565 * Returns the number of bits in the representation of this polynomial. 2566 * @return number of bits in the representation of this polynomial, 2567 * including sign bits. 2568 */ 2569 public long bitLength() { 2570 if (blen < 0L) { 2571 long n = 0L; 2572 for (Monomial<C> m : this) { 2573 n += m.e.bitLength(); 2574 //n += m.c.bitLength(); // todo add bitLength to Element 2575 try { // hack 2576 Method method = m.c.getClass().getMethod("bitLength", (Class<?>[]) null); 2577 n += (Long) method.invoke(m.c, (Object[]) null); 2578 } catch (NoSuchMethodException e) { 2579 logger.error("Exception, class: " + m.c.getClass()); 2580 throw new RuntimeException(e); 2581 } catch (IllegalAccessException e) { 2582 logger.error("Exception, class: " + m.c.getClass()); 2583 throw new RuntimeException(e); 2584 } catch (InvocationTargetException e) { 2585 logger.error("Exception, class: " + m.c.getClass()); 2586 throw new RuntimeException(e); 2587 } 2588 } 2589 blen = n; 2590 //System.out.println("bitLength(poly) = " + blen); 2591 } 2592 return blen; 2593 } 2594 2595 //private void writeObject(java.io.ObjectOutputStream out) throws IOException { 2596 // out.defaultWriteObject(); 2597 //} 2598 2599 2600 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { 2601 in.defaultReadObject(); 2602 blen = -1; 2603 hash = -1; 2604 } 2605}