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