001/* 002 * $Id: GenWordPolynomial.java 5292 2015-08-05 21:54:16Z kredel $ 003 */ 004 005package edu.jas.poly; 006 007 008import java.util.Collections; 009import java.util.Iterator; 010import java.util.Map; 011import java.util.SortedMap; 012import java.util.TreeMap; 013 014import org.apache.log4j.Logger; 015 016import edu.jas.kern.PreemptingException; 017import edu.jas.structure.NotInvertibleException; 018import edu.jas.structure.RingElem; 019import edu.jas.structure.UnaryFunctor; 020 021 022/** 023 * GenWordPolynomial generic polynomials implementing RingElem. Non-commutative 024 * string polynomials over C. Objects of this class are intended to be 025 * immutable. The implementation is based on TreeMap respectively SortedMap from 026 * words to coefficients. Only the coefficients are modeled with generic types, 027 * the "exponents" are fixed to Word. C can also be a non integral domain, e.g. 028 * a ModInteger, i.e. it may contain zero divisors, since multiply() does check 029 * for zeros. 030 * @param <C> coefficient type 031 * @author Heinz Kredel 032 */ 033public final class GenWordPolynomial<C extends RingElem<C>> implements RingElem<GenWordPolynomial<C>>, 034 Iterable<WordMonomial<C>> { 035 036 037 /** 038 * The factory for the polynomial ring. 039 */ 040 public final GenWordPolynomialRing<C> ring; 041 042 043 /** 044 * The data structure for polynomials. 045 */ 046 final SortedMap<Word, C> val; // do not change to TreeMap 047 048 049 private static final Logger logger = Logger.getLogger(GenWordPolynomial.class); 050 051 052 private final boolean debug = logger.isDebugEnabled(); 053 054 055 // protected GenWordPolynomial() { ring = null; val = null; } // don't use 056 057 058 /** 059 * Private constructor for GenWordPolynomial. 060 * @param r polynomial ring factory. 061 * @param t TreeMap with correct ordering. 062 */ 063 private GenWordPolynomial(GenWordPolynomialRing<C> r, TreeMap<Word, C> t) { 064 ring = r; 065 val = t; 066 if (ring.checkPreempt) { 067 if (Thread.currentThread().isInterrupted()) { 068 logger.debug("throw PreemptingException"); 069 throw new PreemptingException(); 070 } 071 } 072 } 073 074 075 /** 076 * Constructor for zero GenWordPolynomial. 077 * @param r polynomial ring factory. 078 */ 079 public GenWordPolynomial(GenWordPolynomialRing<C> r) { 080 this(r, new TreeMap<Word, C>(r.alphabet.getDescendComparator())); 081 } 082 083 084 /** 085 * Constructor for GenWordPolynomial c * x<sup>e</sup>. 086 * @param r polynomial ring factory. 087 * @param c coefficient. 088 * @param e word. 089 */ 090 public GenWordPolynomial(GenWordPolynomialRing<C> r, C c, Word e) { 091 this(r); 092 if (!c.isZERO()) { 093 val.put(e, c); 094 } 095 } 096 097 098 /** 099 * Constructor for GenWordPolynomial c * x<sup>0</sup>. 100 * @param r polynomial ring factory. 101 * @param c coefficient. 102 */ 103 public GenWordPolynomial(GenWordPolynomialRing<C> r, C c) { 104 this(r, c, r.wone); 105 } 106 107 108 /** 109 * Constructor for GenWordPolynomial x<sup>e</sup>. 110 * @param r polynomial ring factory. 111 * @param e word. 112 */ 113 public GenWordPolynomial(GenWordPolynomialRing<C> r, Word e) { 114 this(r, r.coFac.getONE(), e); 115 } 116 117 118 /** 119 * Constructor for GenWordPolynomial x<sup>e</sup>. 120 * @param r polynomial ring factory. 121 * @param e exponent vector. 122 */ 123 public GenWordPolynomial(GenWordPolynomialRing<C> r, ExpVector e) { 124 this(r, r.coFac.getONE(), r.alphabet.valueOf(e)); 125 } 126 127 128 /** 129 * Constructor for GenWordPolynomial c * x<sup>e</sup>. 130 * @param r polynomial ring factory. 131 * @param c coefficient. 132 * @param e exponent vector. 133 */ 134 public GenWordPolynomial(GenWordPolynomialRing<C> r, C c, ExpVector e) { 135 this(r, c, r.alphabet.valueOf(e)); 136 } 137 138 139 /** 140 * Constructor for GenWordPolynomial. 141 * @param r polynomial ring factory. 142 * @param v the SortedMap of some other polynomial. 143 */ 144 protected GenWordPolynomial(GenWordPolynomialRing<C> r, SortedMap<Word, C> v) { 145 this(r); 146 val.putAll(v); // assume no zero coefficients 147 } 148 149 150 /** 151 * Get the corresponding element factory. 152 * @return factory for this Element. 153 * @see edu.jas.structure.Element#factory() 154 */ 155 public GenWordPolynomialRing<C> factory() { 156 return ring; 157 } 158 159 160 /** 161 * Copy this GenWordPolynomial. 162 * @return copy of this. 163 */ 164 public GenWordPolynomial<C> copy() { 165 return new GenWordPolynomial<C>(ring, this.val); 166 } 167 168 169 /** 170 * Length of GenWordPolynomial. 171 * @return number of coefficients of this GenWordPolynomial. 172 */ 173 public int length() { 174 return val.size(); 175 } 176 177 178 /** 179 * Word to coefficient map of GenWordPolynomial. 180 * @return val as unmodifiable SortedMap. 181 */ 182 public SortedMap<Word, C> getMap() { 183 // return val; 184 return Collections.<Word, C> unmodifiableSortedMap(val); 185 } 186 187 188 /** 189 * Put a Word to coefficient entry into the internal map of this 190 * GenWordPolynomial. <b>Note:</b> Do not use this method unless you are 191 * constructing a new polynomial. this is modified and breaks the 192 * immutability promise of this class. 193 * @param c coefficient. 194 * @param e word. 195 */ 196 public void doPutToMap(Word e, C c) { 197 if (debug) { 198 C a = val.get(e); 199 if (a != null) { 200 logger.error("map entry exists " + e + " to " + a + " new " + c); 201 } 202 } 203 if (!c.isZERO()) { 204 val.put(e, c); 205 } 206 } 207 208 209 /** 210 * Remove a Word to coefficient entry from the internal map of this 211 * GenWordPolynomial. <b>Note:</b> Do not use this method unless you are 212 * constructing a new polynomial. this is modified and breaks the 213 * immutability promise of this class. 214 * @param e Word. 215 * @param c expected coefficient, null for ignore. 216 */ 217 public void doRemoveFromMap(Word e, C c) { 218 C b = val.remove(e); 219 if (debug) { 220 if (c == null) { // ignore b 221 return; 222 } 223 if (!c.equals(b)) { 224 logger.error("map entry wrong " + e + " to " + c + " old " + b); 225 } 226 } 227 } 228 229 230 /** 231 * Put an a sorted map of words to coefficients into the internal map of 232 * this GenWordPolynomial. <b>Note:</b> Do not use this method unless you 233 * are constructing a new polynomial. this is modified and breaks the 234 * immutability promise of this class. 235 * @param vals sorted map of wordss and coefficients. 236 */ 237 public void doPutToMap(SortedMap<Word, C> vals) { 238 for (Map.Entry<Word, C> me : vals.entrySet()) { 239 Word e = me.getKey(); 240 if (debug) { 241 C a = val.get(e); 242 if (a != null) { 243 logger.error("map entry exists " + e + " to " + a + " new " + me.getValue()); 244 } 245 } 246 C c = me.getValue(); 247 if (!c.isZERO()) { 248 val.put(e, c); 249 } 250 } 251 } 252 253 254 /** 255 * String representation of GenWordPolynomial. 256 * @see java.lang.Object#toString() 257 */ 258 @Override 259 public String toString() { 260 if (isZERO()) { 261 return "0"; 262 } 263 if (isONE()) { 264 return "1"; 265 } 266 StringBuffer s = new StringBuffer(); 267 if (val.size() > 1) { 268 s.append("( "); 269 } 270 boolean parenthesis = false; 271 boolean first = true; 272 for (Map.Entry<Word, C> m : val.entrySet()) { 273 C c = m.getValue(); 274 if (first) { 275 first = false; 276 } else { 277 if (c.signum() < 0) { 278 s.append(" - "); 279 c = c.negate(); 280 } else { 281 s.append(" + "); 282 } 283 } 284 Word e = m.getKey(); 285 if (!c.isONE() || e.isONE()) { 286 if (parenthesis) { 287 s.append("( "); 288 } 289 String cs = c.toString(); 290 if (cs.indexOf("+")>=0||cs.indexOf("-")>=0) { 291 s.append("( " + cs + " )"); 292 } else { 293 s.append(cs); 294 } 295 if (parenthesis) { 296 s.append(" )"); 297 } 298 if (!e.isONE()) { 299 s.append(" "); 300 } 301 } 302 s.append(e.toString()); 303 } 304 if (val.size() > 1) { 305 s.append(" )"); 306 } 307 return s.toString(); 308 } 309 310 311 /** 312 * Get a scripting compatible string representation. 313 * @return script compatible representation for this Element. 314 * @see edu.jas.structure.Element#toScript() 315 */ 316 @Override 317 public String toScript() { 318 if (isZERO()) { 319 return "0"; 320 } 321 if (isONE()) { 322 return "1"; 323 } 324 StringBuffer s = new StringBuffer(); 325 if (val.size() > 1) { 326 s.append("( "); 327 } 328 final boolean parenthesis = false; 329 boolean first = true; 330 for (Map.Entry<Word, C> m : val.entrySet()) { 331 C c = m.getValue(); 332 if (first) { 333 first = false; 334 } else { 335 if (c.signum() < 0) { 336 s.append(" - "); 337 c = c.negate(); 338 } else { 339 s.append(" + "); 340 } 341 } 342 Word e = m.getKey(); 343 if (!c.isONE() || e.isONE()) { 344 if (parenthesis) { 345 s.append("( "); 346 } 347 String cs = c.toScript(); 348 if (cs.indexOf("+")>=0||cs.indexOf("-")>=0) { 349 s.append("( " + cs + " )"); 350 } else { 351 s.append(cs); 352 } 353 if (parenthesis) { 354 s.append(" )"); 355 } 356 if (!e.isONE()) { 357 s.append(" * "); 358 } 359 } 360 s.append(e.toScript()); 361 } 362 if (val.size() > 1) { 363 s.append(" )"); 364 } 365 return s.toString(); 366 } 367 368 369 /** 370 * Get a scripting compatible string representation of the factory. 371 * @return script compatible representation for this ElemFactory. 372 * @see edu.jas.structure.Element#toScriptFactory() 373 */ 374 @Override 375 public String toScriptFactory() { 376 // Python case 377 return factory().toScript(); 378 } 379 380 381 /** 382 * Is GenWordPolynomial<C> zero. 383 * @return If this is 0 then true is returned, else false. 384 * @see edu.jas.structure.RingElem#isZERO() 385 */ 386 public boolean isZERO() { 387 return (val.size() == 0); 388 } 389 390 391 /** 392 * Is GenWordPolynomial<C> one. 393 * @return If this is 1 then true is returned, else false. 394 * @see edu.jas.structure.RingElem#isONE() 395 */ 396 public boolean isONE() { 397 if (val.size() != 1) { 398 return false; 399 } 400 C c = val.get(ring.wone); 401 if (c == null) { 402 return false; 403 } 404 return c.isONE(); 405 } 406 407 408 /** 409 * Is GenWordPolynomial<C> a unit. 410 * @return If this is a unit then true is returned, else false. 411 * @see edu.jas.structure.RingElem#isUnit() 412 */ 413 public boolean isUnit() { 414 if (val.size() != 1) { 415 return false; 416 } 417 C c = val.get(ring.wone); 418 if (c == null) { 419 return false; 420 } 421 return c.isUnit(); 422 } 423 424 425 /** 426 * Is GenWordPolynomial<C> a constant. 427 * @return If this is a constant polynomial then true is returned, else 428 * false. 429 */ 430 public boolean isConstant() { 431 if (val.size() != 1) { 432 return false; 433 } 434 C c = val.get(ring.wone); 435 if (c == null) { 436 return false; 437 } 438 return true; 439 } 440 441 442 /** 443 * Is GenWordPolynomial<C> homogeneous. 444 * @return true, if this is homogeneous, else false. 445 */ 446 public boolean isHomogeneous() { 447 if (val.size() <= 1) { 448 return true; 449 } 450 long deg = -1; 451 for (Word e : val.keySet()) { 452 if (deg < 0) { 453 deg = e.degree(); 454 } else if (deg != e.degree()) { 455 return false; 456 } 457 } 458 return true; 459 } 460 461 462 /** 463 * Comparison with any other object. 464 * @see java.lang.Object#equals(java.lang.Object) 465 */ 466 @Override 467 @SuppressWarnings("unchecked") 468 public boolean equals(Object B) { 469 if (B == null) { 470 return false; 471 } 472 if (!(B instanceof GenWordPolynomial)) { 473 return false; 474 } 475 GenWordPolynomial<C> a = (GenWordPolynomial<C>) B; 476 return this.compareTo(a) == 0; 477 } 478 479 480 /** 481 * Hash code for this polynomial. 482 * @see java.lang.Object#hashCode() 483 */ 484 @Override 485 public int hashCode() { 486 int h; 487 h = (ring.hashCode() << 27); 488 h += val.hashCode(); 489 return h; 490 } 491 492 493 /** 494 * GenWordPolynomial comparison. 495 * @param b GenWordPolynomial. 496 * @return sign(this-b). 497 */ 498 public int compareTo(GenWordPolynomial<C> b) { 499 if (b == null) { 500 return 1; 501 } 502 SortedMap<Word, C> av = this.val; 503 SortedMap<Word, C> bv = b.val; 504 Iterator<Map.Entry<Word, C>> ai = av.entrySet().iterator(); 505 Iterator<Map.Entry<Word, C>> bi = bv.entrySet().iterator(); 506 int s = 0; 507 int c = 0; 508 while (ai.hasNext() && bi.hasNext()) { 509 Map.Entry<Word, C> aie = ai.next(); 510 Map.Entry<Word, C> bie = bi.next(); 511 Word ae = aie.getKey(); 512 Word be = bie.getKey(); 513 s = ae.compareTo(be); 514 //System.out.println("s = " + s + ", " + ae + ", " +be); 515 if (s != 0) { 516 return s; 517 } 518 if (c == 0) { 519 C ac = aie.getValue(); //av.get(ae); 520 C bc = bie.getValue(); //bv.get(be); 521 c = ac.compareTo(bc); 522 } 523 } 524 if (ai.hasNext()) { 525 return 1; 526 } 527 if (bi.hasNext()) { 528 return -1; 529 } 530 // now all keys are equal 531 return c; 532 } 533 534 535 /** 536 * GenWordPolynomial signum. 537 * @return sign(ldcf(this)). 538 */ 539 public int signum() { 540 if (this.isZERO()) { 541 return 0; 542 } 543 Word t = val.firstKey(); 544 C c = val.get(t); 545 return c.signum(); 546 } 547 548 549 /** 550 * Number of variables. 551 * @return ring.alphabet.length(). 552 */ 553 public int numberOfVariables() { 554 return ring.alphabet.length(); 555 } 556 557 558 /** 559 * Leading monomial. 560 * @return first map entry. 561 */ 562 public Map.Entry<Word, C> leadingMonomial() { 563 if (val.size() == 0) 564 return null; 565 Iterator<Map.Entry<Word, C>> ai = val.entrySet().iterator(); 566 return ai.next(); 567 } 568 569 570 /** 571 * Leading word. 572 * @return first highest word. 573 */ 574 public Word leadingWord() { 575 if (val.size() == 0) { 576 return ring.wone; // null? needs changes? 577 } 578 return val.firstKey(); 579 } 580 581 582 /** 583 * Trailing word. 584 * @return last lowest word. 585 */ 586 public Word trailingWord() { 587 if (val.size() == 0) { 588 return ring.wone; // or null ?; 589 } 590 return val.lastKey(); 591 } 592 593 594 /** 595 * Leading base coefficient. 596 * @return first coefficient. 597 */ 598 public C leadingBaseCoefficient() { 599 if (val.size() == 0) { 600 return ring.coFac.getZERO(); 601 } 602 return val.get(val.firstKey()); 603 } 604 605 606 /** 607 * Trailing base coefficient. 608 * @return coefficient of constant term. 609 */ 610 public C trailingBaseCoefficient() { 611 C c = val.get(ring.wone); 612 if (c == null) { 613 return ring.coFac.getZERO(); 614 } 615 return c; 616 } 617 618 619 /** 620 * Coefficient. 621 * @param e word. 622 * @return coefficient for given word. 623 */ 624 public C coefficient(Word e) { 625 C c = val.get(e); 626 if (c == null) { 627 c = ring.coFac.getZERO(); 628 } 629 return c; 630 } 631 632 633 /** 634 * Reductum. 635 * @return this - leading monomial. 636 */ 637 public GenWordPolynomial<C> reductum() { 638 if (val.size() <= 1) { 639 return ring.getZERO(); 640 } 641 Iterator<Word> ai = val.keySet().iterator(); 642 Word lt = ai.next(); 643 lt = ai.next(); // size > 1 644 SortedMap<Word, C> red = val.tailMap(lt); 645 return new GenWordPolynomial<C>(ring, red); 646 } 647 648 649 /** 650 * Maximal degree. 651 * @return maximal degree in any variables. 652 */ 653 public long degree() { 654 if (val.size() == 0) { 655 return 0; // 0 or -1 ?; 656 } 657 long deg = 0; 658 for (Word e : val.keySet()) { 659 long d = e.degree(); 660 if (d > deg) { 661 deg = d; 662 } 663 } 664 return deg; 665 } 666 667 668 /** 669 * GenWordPolynomial maximum norm. 670 * @return ||this||. 671 */ 672 public C maxNorm() { 673 C n = ring.getZEROCoefficient(); 674 for (C c : val.values()) { 675 C x = c.abs(); 676 if (n.compareTo(x) < 0) { 677 n = x; 678 } 679 } 680 return n; 681 } 682 683 684 /** 685 * GenWordPolynomial sum norm. 686 * @return sum of all absolute values of coefficients. 687 */ 688 public C sumNorm() { 689 C n = ring.getZEROCoefficient(); 690 for (C c : val.values()) { 691 C x = c.abs(); 692 n = n.sum(x); 693 } 694 return n; 695 } 696 697 698 /** 699 * GenWordPolynomial summation. 700 * @param S GenWordPolynomial. 701 * @return this+S. 702 */ 703 public GenWordPolynomial<C> sum(GenWordPolynomial<C> S) { 704 if (S == null) { 705 return this; 706 } 707 if (S.isZERO()) { 708 return this; 709 } 710 if (this.isZERO()) { 711 return S; 712 } 713 assert (ring.alphabet == S.ring.alphabet); 714 GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 715 SortedMap<Word, C> nv = n.val; 716 SortedMap<Word, C> sv = S.val; 717 for (Map.Entry<Word, C> me : sv.entrySet()) { 718 Word e = me.getKey(); 719 C y = me.getValue(); //sv.get(e); // assert y != null 720 C x = nv.get(e); 721 if (x != null) { 722 x = x.sum(y); 723 if (!x.isZERO()) { 724 nv.put(e, x); 725 } else { 726 nv.remove(e); 727 } 728 } else { 729 nv.put(e, y); 730 } 731 } 732 return n; 733 } 734 735 736 /** 737 * GenWordPolynomial addition. This method is not very efficient, since this 738 * is copied. 739 * @param a coefficient. 740 * @param e word. 741 * @return this + a e. 742 */ 743 public GenWordPolynomial<C> sum(C a, Word e) { 744 if (a == null) { 745 return this; 746 } 747 if (a.isZERO()) { 748 return this; 749 } 750 GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 751 SortedMap<Word, C> nv = n.val; 752 C x = nv.get(e); 753 if (x != null) { 754 x = x.sum(a); 755 if (!x.isZERO()) { 756 nv.put(e, x); 757 } else { 758 nv.remove(e); 759 } 760 } else { 761 nv.put(e, a); 762 } 763 return n; 764 } 765 766 767 /** 768 * GenWordPolynomial addition. This method is not very efficient, since this 769 * is copied. 770 * @param a coefficient. 771 * @return this + a x<sup>0</sup>. 772 */ 773 public GenWordPolynomial<C> sum(C a) { 774 return sum(a, ring.wone); 775 } 776 777 778 /** 779 * GenWordPolynomial subtraction. 780 * @param S GenWordPolynomial. 781 * @return this-S. 782 */ 783 public GenWordPolynomial<C> subtract(GenWordPolynomial<C> S) { 784 if (S == null) { 785 return this; 786 } 787 if (S.isZERO()) { 788 return this; 789 } 790 if (this.isZERO()) { 791 return S.negate(); 792 } 793 assert (ring.alphabet == S.ring.alphabet); 794 GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 795 SortedMap<Word, C> nv = n.val; 796 SortedMap<Word, C> sv = S.val; 797 for (Map.Entry<Word, C> me : sv.entrySet()) { 798 Word e = me.getKey(); 799 C y = me.getValue(); //sv.get(e); // assert y != null 800 C x = nv.get(e); 801 if (x != null) { 802 x = x.subtract(y); 803 if (!x.isZERO()) { 804 nv.put(e, x); 805 } else { 806 nv.remove(e); 807 } 808 } else { 809 nv.put(e, y.negate()); 810 } 811 } 812 return n; 813 } 814 815 816 /** 817 * GenWordPolynomial subtraction. This method is not very efficient, since 818 * this is copied. 819 * @param a coefficient. 820 * @param e word. 821 * @return this - a e. 822 */ 823 public GenWordPolynomial<C> subtract(C a, Word e) { 824 if (a == null) { 825 return this; 826 } 827 if (a.isZERO()) { 828 return this; 829 } 830 GenWordPolynomial<C> n = this.copy(); //new GenWordPolynomial<C>(ring, val); 831 SortedMap<Word, C> nv = n.val; 832 C x = nv.get(e); 833 if (x != null) { 834 x = x.subtract(a); 835 if (!x.isZERO()) { 836 nv.put(e, x); 837 } else { 838 nv.remove(e); 839 } 840 } else { 841 nv.put(e, a.negate()); 842 } 843 return n; 844 } 845 846 847 /** 848 * GenWordPolynomial subtract. This method is not very efficient, since this 849 * is copied. 850 * @param a coefficient. 851 * @return this + a x<sup>0</sup>. 852 */ 853 public GenWordPolynomial<C> subtract(C a) { 854 return subtract(a, ring.wone); 855 } 856 857 858 /** 859 * GenWordPolynomial negation. 860 * @return -this. 861 */ 862 public GenWordPolynomial<C> negate() { 863 GenWordPolynomial<C> n = ring.getZERO().copy(); 864 SortedMap<Word, C> v = n.val; 865 for (Map.Entry<Word, C> m : val.entrySet()) { 866 C x = m.getValue(); // != null, 0 867 v.put(m.getKey(), x.negate()); 868 } 869 return n; 870 } 871 872 873 /** 874 * GenWordPolynomial absolute value, i.e. leadingCoefficient > 0. 875 * @return abs(this). 876 */ 877 public GenWordPolynomial<C> abs() { 878 if (leadingBaseCoefficient().signum() < 0) { 879 return this.negate(); 880 } 881 return this; 882 } 883 884 885 /** 886 * GenWordPolynomial multiplication. 887 * @param S GenWordPolynomial. 888 * @return this*S. 889 */ 890 public GenWordPolynomial<C> multiply(GenWordPolynomial<C> S) { 891 if (S == null) { 892 return ring.getZERO(); 893 } 894 if (S.isZERO()) { 895 return ring.getZERO(); 896 } 897 if (this.isZERO()) { 898 return this; 899 } 900 assert (ring.alphabet == S.ring.alphabet); 901 GenWordPolynomial<C> p = ring.getZERO().copy(); 902 SortedMap<Word, C> pv = p.val; 903 for (Map.Entry<Word, C> m1 : val.entrySet()) { 904 C c1 = m1.getValue(); 905 Word e1 = m1.getKey(); 906 for (Map.Entry<Word, C> m2 : S.val.entrySet()) { 907 C c2 = m2.getValue(); 908 Word e2 = m2.getKey(); 909 C c = c1.multiply(c2); // check non zero if not domain 910 if (!c.isZERO()) { 911 Word e = e1.multiply(e2); 912 C c0 = pv.get(e); 913 if (c0 == null) { 914 pv.put(e, c); 915 } else { 916 c0 = c0.sum(c); 917 if (!c0.isZERO()) { 918 pv.put(e, c0); 919 } else { 920 pv.remove(e); 921 } 922 } 923 } 924 } 925 } 926 return p; 927 } 928 929 930 /** 931 * GenWordPolynomial left and right multiplication. Product with two 932 * polynomials. 933 * @param S GenWordPolynomial. 934 * @param T GenWordPolynomial. 935 * @return S*this*T. 936 */ 937 public GenWordPolynomial<C> multiply(GenWordPolynomial<C> S, GenWordPolynomial<C> T) { 938 if (S.isZERO() || T.isZERO()) { 939 return ring.getZERO(); 940 } 941 if (S.isONE()) { 942 return multiply(T); 943 } 944 if (T.isONE()) { 945 return S.multiply(this); 946 } 947 return S.multiply(this).multiply(T); 948 } 949 950 951 /** 952 * GenWordPolynomial multiplication. Product with coefficient ring element. 953 * @param s coefficient. 954 * @return this*s. 955 */ 956 public GenWordPolynomial<C> multiply(C s) { 957 if (s == null) { 958 return ring.getZERO(); 959 } 960 if (s.isZERO()) { 961 return ring.getZERO(); 962 } 963 if (this.isZERO()) { 964 return this; 965 } 966 GenWordPolynomial<C> p = ring.getZERO().copy(); 967 SortedMap<Word, C> pv = p.val; 968 for (Map.Entry<Word, C> m1 : val.entrySet()) { 969 C c1 = m1.getValue(); 970 Word e1 = m1.getKey(); 971 C c = c1.multiply(s); // check non zero if not domain 972 if (!c.isZERO()) { 973 pv.put(e1, c); // or m1.setValue( c ) 974 } 975 } 976 return p; 977 } 978 979 980 /** 981 * GenWordPolynomial multiplication. Product with coefficient ring element. 982 * @param s coefficient. 983 * @param t coefficient. 984 * @return s*this*t. 985 */ 986 public GenWordPolynomial<C> multiply(C s, C t) { 987 if (s == null || t == null) { 988 return ring.getZERO(); 989 } 990 if (s.isZERO() || t.isZERO()) { 991 return ring.getZERO(); 992 } 993 if (this.isZERO()) { 994 return this; 995 } 996 GenWordPolynomial<C> p = ring.getZERO().copy(); 997 SortedMap<Word, C> pv = p.val; 998 for (Map.Entry<Word, C> m1 : val.entrySet()) { 999 C c1 = m1.getValue(); 1000 Word e = m1.getKey(); 1001 C c = s.multiply(c1).multiply(t); // check non zero if not domain 1002 if (!c.isZERO()) { 1003 pv.put(e, c); // or m1.setValue( c ) 1004 } 1005 } 1006 return p; 1007 } 1008 1009 1010 /** 1011 * GenWordPolynomial monic, i.e. leadingCoefficient == 1. If 1012 * leadingCoefficient is not invertible returns this unmodified. 1013 * @return monic(this). 1014 */ 1015 public GenWordPolynomial<C> monic() { 1016 if (this.isZERO()) { 1017 return this; 1018 } 1019 C lc = leadingBaseCoefficient(); 1020 if (!lc.isUnit()) { 1021 //System.out.println("lc = "+lc); 1022 return this; 1023 } 1024 C lm = lc.inverse(); 1025 return multiply(lm); 1026 } 1027 1028 1029 /** 1030 * GenWordPolynomial multiplication. Product with ring element and word. 1031 * @param s coefficient. 1032 * @param e left word. 1033 * @return this * s e. 1034 */ 1035 public GenWordPolynomial<C> multiply(C s, Word e) { 1036 if (s == null) { 1037 return ring.getZERO(); 1038 } 1039 if (s.isZERO()) { 1040 return ring.getZERO(); 1041 } 1042 if (this.isZERO()) { 1043 return this; 1044 } 1045 GenWordPolynomial<C> p = ring.getZERO().copy(); 1046 SortedMap<Word, C> pv = p.val; 1047 for (Map.Entry<Word, C> m1 : val.entrySet()) { 1048 C c1 = m1.getValue(); 1049 Word e1 = m1.getKey(); 1050 C c = c1.multiply(s); // check non zero if not domain 1051 if (!c.isZERO()) { 1052 Word e2 = e1.multiply(e); 1053 pv.put(e2, c); 1054 } 1055 } 1056 return p; 1057 } 1058 1059 1060 /** 1061 * GenWordPolynomial left and right multiplication. Product with ring 1062 * element and two words. 1063 * @param e left word. 1064 * @param f right word. 1065 * @return e * this * f. 1066 */ 1067 public GenWordPolynomial<C> multiply(Word e, Word f) { 1068 if (this.isZERO()) { 1069 return this; 1070 } 1071 if (e.isONE()) { 1072 return multiply(f); 1073 } 1074 GenWordPolynomial<C> p = ring.getZERO().copy(); 1075 SortedMap<Word, C> pv = p.val; 1076 for (Map.Entry<Word, C> m1 : val.entrySet()) { 1077 C c = m1.getValue(); 1078 Word e1 = m1.getKey(); 1079 Word e2 = e.multiply(e1.multiply(f)); 1080 pv.put(e2, c); 1081 } 1082 return p; 1083 } 1084 1085 1086 /** 1087 * GenWordPolynomial left and right multiplication. Product with ring 1088 * element and two words. 1089 * @param s coefficient. 1090 * @param e left word. 1091 * @param f right word. 1092 * @return e * this * s * f. 1093 */ 1094 public GenWordPolynomial<C> multiply(C s, Word e, Word f) { 1095 if (s == null) { 1096 return ring.getZERO(); 1097 } 1098 if (s.isZERO()) { 1099 return ring.getZERO(); 1100 } 1101 if (this.isZERO()) { 1102 return this; 1103 } 1104 if (e.isONE()) { 1105 return multiply(s, f); 1106 } 1107 C c = ring.coFac.getONE(); 1108 return multiply(c, e, s, f); // sic, history 1109 } 1110 1111 1112 /** 1113 * GenWordPolynomial left and right multiplication. Product with ring 1114 * element and two words. 1115 * @param s coefficient. 1116 * @param e left word. 1117 * @param t coefficient. 1118 * @param f right word. 1119 * @return s * e * this * t * f. 1120 */ 1121 public GenWordPolynomial<C> multiply(C s, Word e, C t, Word f) { 1122 if (s == null) { 1123 return ring.getZERO(); 1124 } 1125 if (s.isZERO()) { 1126 return ring.getZERO(); 1127 } 1128 if (this.isZERO()) { 1129 return this; 1130 } 1131 GenWordPolynomial<C> p = ring.getZERO().copy(); 1132 SortedMap<Word, C> pv = p.val; 1133 for (Map.Entry<Word, C> m1 : val.entrySet()) { 1134 C c1 = m1.getValue(); 1135 C c = s.multiply(c1).multiply(t); // check non zero if not domain 1136 if (!c.isZERO()) { 1137 Word e1 = m1.getKey(); 1138 Word e2 = e.multiply(e1).multiply(f); 1139 pv.put(e2, c); 1140 } 1141 } 1142 return p; 1143 } 1144 1145 1146 /** 1147 * GenWordPolynomial multiplication. Product with word. 1148 * @param e word (!= null). 1149 * @return this * e. 1150 */ 1151 public GenWordPolynomial<C> multiply(Word e) { 1152 if (this.isZERO()) { 1153 return this; 1154 } 1155 GenWordPolynomial<C> p = ring.getZERO().copy(); 1156 SortedMap<Word, C> pv = p.val; 1157 for (Map.Entry<Word, C> m1 : val.entrySet()) { 1158 C c1 = m1.getValue(); 1159 Word e1 = m1.getKey(); 1160 Word e2 = e1.multiply(e); 1161 pv.put(e2, c1); 1162 } 1163 return p; 1164 } 1165 1166 1167 /** 1168 * GenWordPolynomial multiplication. Product with 'monomial'. 1169 * @param m 'monomial'. 1170 * @return this * m. 1171 */ 1172 public GenWordPolynomial<C> multiply(Map.Entry<Word, C> m) { 1173 if (m == null) { 1174 return ring.getZERO(); 1175 } 1176 return multiply(m.getValue(), m.getKey()); 1177 } 1178 1179 1180 /** 1181 * GenWordPolynomial division. Division by coefficient ring element. Fails, 1182 * if exact division is not possible. 1183 * @param s coefficient. 1184 * @return this/s. 1185 */ 1186 public GenWordPolynomial<C> divide(C s) { 1187 if (s == null || s.isZERO()) { 1188 throw new ArithmeticException(this.getClass().getName() + " division by zero"); 1189 } 1190 if (this.isZERO()) { 1191 return this; 1192 } 1193 //C t = s.inverse(); 1194 //return multiply(t); 1195 GenWordPolynomial<C> p = ring.getZERO().copy(); 1196 SortedMap<Word, C> pv = p.val; 1197 for (Map.Entry<Word, C> m : val.entrySet()) { 1198 Word e = m.getKey(); 1199 C c1 = m.getValue(); 1200 C c = c1.divide(s); // is divideLeft 1201 if (debug) { 1202 C x = c1.remainder(s); 1203 if (!x.isZERO()) { 1204 logger.info("divide x = " + x); 1205 throw new ArithmeticException(this.getClass().getName() + " no exact division: " + c1 1206 + "/" + s); 1207 } 1208 } 1209 if (c.isZERO()) { 1210 throw new ArithmeticException(this.getClass().getName() + " no exact division: " + c1 + "/" 1211 + s + ", in " + this); 1212 } 1213 pv.put(e, c); // or m1.setValue( c ) 1214 } 1215 return p; 1216 } 1217 1218 1219 /** 1220 * GenWordPolynomial division with remainder. Fails, if exact division by 1221 * leading base coefficient is not possible. Meaningful only for univariate 1222 * polynomials over fields, but works in any case. 1223 * @param S nonzero GenWordPolynomial with invertible leading coefficient. 1224 * @return [ quotient , remainder ] with this = quotient * S + remainder and 1225 * deg(remainder) < deg(S) or remiander = 0. 1226 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1227 * . 1228 */ 1229 @SuppressWarnings("unchecked") 1230 public GenWordPolynomial<C>[] quotientRemainder(GenWordPolynomial<C> S) { 1231 if (S == null || S.isZERO()) { 1232 throw new ArithmeticException(this.getClass().getName() + " division by zero"); 1233 } 1234 C c = S.leadingBaseCoefficient(); 1235 if (!c.isUnit()) { 1236 throw new ArithmeticException(this.getClass().getName() + " lbcf not invertible " + c); 1237 } 1238 C ci = c.inverse(); 1239 C one = ring.coFac.getONE(); 1240 assert (ring.alphabet == S.ring.alphabet); 1241 WordFactory.WordComparator cmp = ring.alphabet.getDescendComparator(); 1242 Word e = S.leadingWord(); 1243 GenWordPolynomial<C> h; 1244 GenWordPolynomial<C> q = ring.getZERO().copy(); 1245 GenWordPolynomial<C> r = this.copy(); 1246 while (!r.isZERO()) { 1247 Word f = r.leadingWord(); 1248 if (f.multipleOf(e)) { 1249 C a = r.leadingBaseCoefficient(); 1250 Word[] g = f.divideWord(e); // divide not sufficient 1251 //logger.info("div: f = " + f + ", e = " + e + ", g = " + g[0] + ", " + g[1]); 1252 a = a.multiply(ci); 1253 q = q.sum(a, g[0].multiply(g[1])); 1254 h = S.multiply(a, g[0], one, g[1]); 1255 r = r.subtract(h); 1256 Word fr = r.leadingWord(); 1257 if (cmp.compare(f, fr) > 0) { // non noetherian reduction 1258 throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr); 1259 } 1260 } else { 1261 break; 1262 } 1263 } 1264 GenWordPolynomial<C>[] ret = new GenWordPolynomial[2]; 1265 ret[0] = q; 1266 ret[1] = r; 1267 return ret; 1268 } 1269 1270 1271 /** 1272 * GenWordPolynomial division. Fails, if exact division by leading base 1273 * coefficient is not possible. Meaningful only for univariate polynomials 1274 * over fields, but works in any case. 1275 * @param S nonzero GenWordPolynomial with invertible leading coefficient. 1276 * @return quotient with this = quotient * S + remainder. 1277 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1278 * . 1279 */ 1280 public GenWordPolynomial<C> divide(GenWordPolynomial<C> S) { 1281 return quotientRemainder(S)[0]; 1282 } 1283 1284 1285 /** 1286 * GenWordPolynomial remainder. Fails, if exact division by leading base 1287 * coefficient is not possible. Meaningful only for univariate polynomials 1288 * over fields, but works in any case. 1289 * @param S nonzero GenWordPolynomial with invertible leading coefficient. 1290 * @return remainder with this = quotient * S + remainder. 1291 * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) 1292 * . 1293 */ 1294 public GenWordPolynomial<C> remainder(GenWordPolynomial<C> S) { 1295 if (S == null || S.isZERO()) { 1296 throw new ArithmeticException(this.getClass().getName() + " division by zero"); 1297 } 1298 C c = S.leadingBaseCoefficient(); 1299 if (!c.isUnit()) { 1300 throw new ArithmeticException(this.getClass().getName() + " lbc not invertible " + c); 1301 } 1302 C ci = c.inverse(); 1303 C one = ring.coFac.getONE(); 1304 assert (ring.alphabet == S.ring.alphabet); 1305 WordFactory.WordComparator cmp = ring.alphabet.getDescendComparator(); 1306 Word e = S.leadingWord(); 1307 GenWordPolynomial<C> h; 1308 GenWordPolynomial<C> r = this.copy(); 1309 while (!r.isZERO()) { 1310 Word f = r.leadingWord(); 1311 if (f.multipleOf(e)) { 1312 C a = r.leadingBaseCoefficient(); 1313 Word[] g = f.divideWord(e); // divide not sufficient 1314 //logger.info("rem: f = " + f + ", e = " + e + ", g = " + g[0] + ", " + g[1]); 1315 a = a.multiply(ci); 1316 h = S.multiply(a, g[0], one, g[1]); 1317 r = r.subtract(h); 1318 Word fr = r.leadingWord(); 1319 if (cmp.compare(f, fr) > 0) { // non noetherian reduction 1320 throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr); 1321 } 1322 } else { 1323 break; 1324 } 1325 } 1326 return r; 1327 } 1328 1329 1330 /** 1331 * GenWordPolynomial greatest common divisor. Only for univariate 1332 * polynomials over fields. 1333 * @param S GenWordPolynomial. 1334 * @return gcd(this,S). 1335 */ 1336 public GenWordPolynomial<C> gcd(GenWordPolynomial<C> S) { 1337 if (S == null || S.isZERO()) { 1338 return this; 1339 } 1340 if (this.isZERO()) { 1341 return S; 1342 } 1343 if (ring.alphabet.length() != 1) { 1344 throw new IllegalArgumentException("no univariate polynomial " + ring); 1345 } 1346 GenWordPolynomial<C> x; 1347 GenWordPolynomial<C> q = this; 1348 GenWordPolynomial<C> r = S; 1349 while (!r.isZERO()) { 1350 x = q.remainder(r); 1351 q = r; 1352 r = x; 1353 } 1354 return q.monic(); // normalize 1355 } 1356 1357 1358 /** 1359 * GenWordPolynomial extended greatest comon divisor. Only for univariate 1360 * polynomials over fields. 1361 * @param S GenWordPolynomial. 1362 * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). 1363 */ 1364 @SuppressWarnings("unchecked") 1365 public GenWordPolynomial<C>[] egcd(GenWordPolynomial<C> S) { 1366 GenWordPolynomial<C>[] ret = new GenWordPolynomial[3]; 1367 ret[0] = null; 1368 ret[1] = null; 1369 ret[2] = null; 1370 if (S == null || S.isZERO()) { 1371 ret[0] = this; 1372 ret[1] = this.ring.getONE(); 1373 ret[2] = this.ring.getZERO(); 1374 return ret; 1375 } 1376 if (this.isZERO()) { 1377 ret[0] = S; 1378 ret[1] = this.ring.getZERO(); 1379 ret[2] = this.ring.getONE(); 1380 return ret; 1381 } 1382 if (ring.alphabet.length() != 1) { 1383 throw new IllegalArgumentException("no univariate polynomial " + ring); 1384 } 1385 if (this.isConstant() && S.isConstant()) { 1386 C t = this.leadingBaseCoefficient(); 1387 C s = S.leadingBaseCoefficient(); 1388 C[] gg = t.egcd(s); 1389 //System.out.println("coeff gcd = " + Arrays.toString(gg)); 1390 GenWordPolynomial<C> z = this.ring.getZERO(); 1391 ret[0] = z.sum(gg[0]); 1392 ret[1] = z.sum(gg[1]); 1393 ret[2] = z.sum(gg[2]); 1394 return ret; 1395 } 1396 GenWordPolynomial<C>[] qr; 1397 GenWordPolynomial<C> q = this; 1398 GenWordPolynomial<C> r = S; 1399 GenWordPolynomial<C> c1 = ring.getONE().copy(); 1400 GenWordPolynomial<C> d1 = ring.getZERO().copy(); 1401 GenWordPolynomial<C> c2 = ring.getZERO().copy(); 1402 GenWordPolynomial<C> d2 = ring.getONE().copy(); 1403 GenWordPolynomial<C> x1; 1404 GenWordPolynomial<C> x2; 1405 while (!r.isZERO()) { 1406 qr = q.quotientRemainder(r); 1407 q = qr[0]; 1408 x1 = c1.subtract(q.multiply(d1)); 1409 x2 = c2.subtract(q.multiply(d2)); 1410 c1 = d1; 1411 c2 = d2; 1412 d1 = x1; 1413 d2 = x2; 1414 q = r; 1415 r = qr[1]; 1416 } 1417 // normalize ldcf(q) to 1, i.e. make monic 1418 C g = q.leadingBaseCoefficient(); 1419 if (g.isUnit()) { 1420 C h = g.inverse(); 1421 q = q.multiply(h); 1422 c1 = c1.multiply(h); 1423 c2 = c2.multiply(h); 1424 } 1425 //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); 1426 ret[0] = q; 1427 ret[1] = c1; 1428 ret[2] = c2; 1429 return ret; 1430 } 1431 1432 1433 /** 1434 * GenWordPolynomial half extended greatest comon divisor. Only for 1435 * univariate polynomials over fields. 1436 * @param S GenWordPolynomial. 1437 * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S). 1438 */ 1439 @SuppressWarnings("unchecked") 1440 public GenWordPolynomial<C>[] hegcd(GenWordPolynomial<C> S) { 1441 GenWordPolynomial<C>[] ret = new GenWordPolynomial[2]; 1442 ret[0] = null; 1443 ret[1] = null; 1444 if (S == null || S.isZERO()) { 1445 ret[0] = this; 1446 ret[1] = this.ring.getONE(); 1447 return ret; 1448 } 1449 if (this.isZERO()) { 1450 ret[0] = S; 1451 return ret; 1452 } 1453 if (ring.alphabet.length() != 1) { 1454 throw new IllegalArgumentException("no univariate polynomial " + ring); 1455 } 1456 GenWordPolynomial<C>[] qr; 1457 GenWordPolynomial<C> q = this; 1458 GenWordPolynomial<C> r = S; 1459 GenWordPolynomial<C> c1 = ring.getONE().copy(); 1460 GenWordPolynomial<C> d1 = ring.getZERO().copy(); 1461 GenWordPolynomial<C> x1; 1462 while (!r.isZERO()) { 1463 qr = q.quotientRemainder(r); 1464 q = qr[0]; 1465 x1 = c1.subtract(q.multiply(d1)); 1466 c1 = d1; 1467 d1 = x1; 1468 q = r; 1469 r = qr[1]; 1470 } 1471 // normalize ldcf(q) to 1, i.e. make monic 1472 C g = q.leadingBaseCoefficient(); 1473 if (g.isUnit()) { 1474 C h = g.inverse(); 1475 q = q.multiply(h); 1476 c1 = c1.multiply(h); 1477 } 1478 //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); 1479 ret[0] = q; 1480 ret[1] = c1; 1481 return ret; 1482 } 1483 1484 1485 /** 1486 * GenWordPolynomial inverse. Required by RingElem. Throws not invertible 1487 * exception. 1488 */ 1489 public GenWordPolynomial<C> inverse() { 1490 if (isUnit()) { // only possible if ldbcf is unit 1491 C c = leadingBaseCoefficient().inverse(); 1492 return ring.getONE().multiply(c); 1493 } 1494 throw new NotInvertibleException("element not invertible " + this + " :: " + ring); 1495 } 1496 1497 1498 /** 1499 * GenWordPolynomial modular inverse. Only for univariate polynomials over 1500 * fields. 1501 * @param m GenWordPolynomial. 1502 * @return a with with a*this = 1 mod m. 1503 */ 1504 public GenWordPolynomial<C> modInverse(GenWordPolynomial<C> m) { 1505 if (this.isZERO()) { 1506 throw new NotInvertibleException("zero is not invertible"); 1507 } 1508 GenWordPolynomial<C>[] hegcd = this.hegcd(m); 1509 GenWordPolynomial<C> a = hegcd[0]; 1510 if (!a.isUnit()) { // gcd != 1 1511 throw new NotInvertibleException("element not invertible, gcd != 1"); 1512 } 1513 GenWordPolynomial<C> b = hegcd[1]; 1514 if (b.isZERO()) { // when m divides this, e.g. m.isUnit() 1515 throw new NotInvertibleException("element not invertible, divisible by modul"); 1516 } 1517 return b; 1518 } 1519 1520 1521 /** 1522 * Iterator over coefficients. 1523 * @return val.values().iterator(). 1524 */ 1525 public Iterator<C> coefficientIterator() { 1526 return val.values().iterator(); 1527 } 1528 1529 1530 /** 1531 * Iterator over words. 1532 * @return val.keySet().iterator(). 1533 */ 1534 public Iterator<Word> wordIterator() { 1535 return val.keySet().iterator(); 1536 } 1537 1538 1539 /** 1540 * Iterator over monomials. 1541 * @return a PolyIterator. 1542 */ 1543 public Iterator<WordMonomial<C>> iterator() { 1544 return new WordPolyIterator<C>(val); 1545 } 1546 1547 1548 /** 1549 * Map a unary function to the coefficients. 1550 * @param f evaluation functor. 1551 * @return new polynomial with coefficients f(this(e)). 1552 */ 1553 public GenWordPolynomial<C> map(final UnaryFunctor<? super C, C> f) { 1554 GenWordPolynomial<C> n = ring.getZERO().copy(); 1555 SortedMap<Word, C> nv = n.val; 1556 for (WordMonomial<C> m : this) { 1557 //logger.info("m = " + m); 1558 C c = f.eval(m.c); 1559 if (c != null && !c.isZERO()) { 1560 nv.put(m.e, c); 1561 } 1562 } 1563 return n; 1564 } 1565 1566}