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