001/* 002 * $Id$ 003 */ 004 005package edu.jas.application; 006 007 008import java.io.Serializable; 009import java.util.ArrayList; 010import java.util.Collections; 011import java.util.Comparator; 012import java.util.List; 013import java.util.SortedSet; 014import java.util.TreeSet; 015 016import org.apache.logging.log4j.LogManager; 017import org.apache.logging.log4j.Logger; 018 019import edu.jas.gb.WordGroebnerBaseAbstract; 020import edu.jas.gb.WordGroebnerBaseSeq; 021import edu.jas.gb.WordReduction; 022import edu.jas.gb.WordReductionSeq; 023import edu.jas.gbufd.PolyGBUtil; 024import edu.jas.kern.Scripting; 025import edu.jas.poly.GenWordPolynomial; 026import edu.jas.poly.GenWordPolynomialRing; 027import edu.jas.poly.PolyUtil; 028import edu.jas.poly.Word; 029import edu.jas.structure.GcdRingElem; 030import edu.jas.structure.NotInvertibleException; 031 032 033/** 034 * Word Ideal implements some methods for ideal arithmetic, for example 035 * containment, sum or product. <b>Note:</b> only two-sided ideals. 036 * @author Heinz Kredel 037 */ 038public class WordIdeal<C extends GcdRingElem<C>> implements Comparable<WordIdeal<C>>, Serializable { 039 040 041 private static final Logger logger = LogManager.getLogger(WordIdeal.class); 042 043 044 private static final boolean debug = logger.isDebugEnabled(); 045 046 047 /** 048 * The data structure is a list of word polynomials. 049 */ 050 protected List<GenWordPolynomial<C>> list; 051 052 053 /** 054 * Reference to the word polynomial ring. 055 */ 056 protected GenWordPolynomialRing<C> ring; 057 058 059 /** 060 * Indicator if list is a Groebner Base. 061 */ 062 protected boolean isGB; 063 064 065 /** 066 * Indicator if test has been performed if this is a Groebner Base. 067 */ 068 protected boolean testGB; 069 070 071 /** 072 * Groebner base engine. 073 */ 074 protected final WordGroebnerBaseAbstract<C> bb; 075 076 077 /** 078 * Reduction engine. 079 */ 080 protected final WordReduction<C> red; 081 082 083 /** 084 * Constructor. 085 * @param ring word polynomial ring 086 */ 087 public WordIdeal(GenWordPolynomialRing<C> ring) { 088 this(ring, new ArrayList<GenWordPolynomial<C>>()); 089 } 090 091 092 /** 093 * Constructor. 094 * @param ring word polynomial ring 095 * @param list word polynomial list 096 */ 097 public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list) { 098 this(ring, list, false); 099 } 100 101 102 /** 103 * Constructor. 104 * @param ring word polynomial ring 105 * @param list word polynomial list 106 * @param bb Groebner Base engine 107 * @param red Reduction engine 108 */ 109 public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, 110 WordGroebnerBaseAbstract<C> bb, WordReduction<C> red) { 111 this(ring, list, false, bb, red); 112 } 113 114 115 /** 116 * Constructor. 117 * @param ring word polynomial ring 118 * @param list word polynomial list 119 * @param gb true if list is known to be a Groebner Base, else false 120 */ 121 public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, boolean gb) { 122 this(ring, list, gb, new WordGroebnerBaseSeq<C>(), new WordReductionSeq<C>()); 123 //this(list, gb, topt, GBFactory.getImplementation(list.ring.coFac)); 124 } 125 126 127 /** 128 * Constructor. 129 * @param ring word polynomial ring 130 * @param list word polynomial list 131 * @param gb true if list is known to be a Groebner Base, else false 132 * @param bb Groebner Base engine 133 */ 134 public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, boolean gb, 135 WordGroebnerBaseAbstract<C> bb) { 136 this(ring, list, gb, bb, bb.red); 137 } 138 139 140 /** 141 * Constructor. 142 * @param ring word polynomial ring 143 * @param list word polynomial list 144 * @param gb true if list is known to be a Groebner Base, else false 145 * @param bb Groebner Base engine 146 * @param red Reduction engine 147 */ 148 public WordIdeal(GenWordPolynomialRing<C> ring, List<GenWordPolynomial<C>> list, boolean gb, 149 WordGroebnerBaseAbstract<C> bb, WordReduction<C> red) { 150 if (ring == null) { 151 throw new IllegalArgumentException("ring may not be null"); 152 } 153 if (list == null) { 154 throw new IllegalArgumentException("list may not be null"); 155 } 156 this.ring = ring; 157 this.list = list; 158 this.isGB = gb; 159 this.testGB = (gb ? true : false); // ?? 160 this.bb = bb; 161 this.red = red; 162 if (debug) { 163 logger.info("constructed: {}", this); 164 } 165 } 166 167 168 /** 169 * Clone this. 170 * @return a copy of this. 171 */ 172 public WordIdeal<C> copy() { 173 return new WordIdeal<C>(ring, new ArrayList<GenWordPolynomial<C>>(list), isGB, bb, red); 174 } 175 176 177 /** 178 * Get the List of GenWordPolynomials. 179 * @return (cast) list.list 180 */ 181 public List<GenWordPolynomial<C>> getList() { 182 return list; 183 } 184 185 186 /** 187 * Get the GenWordPolynomialRing. 188 * @return (cast) list.ring 189 */ 190 public GenWordPolynomialRing<C> getRing() { 191 return ring; 192 } 193 194 195 /** 196 * Get the zero ideal. 197 * @return ideal(0) 198 */ 199 public WordIdeal<C> getZERO() { 200 List<GenWordPolynomial<C>> z = new ArrayList<GenWordPolynomial<C>>(0); 201 return new WordIdeal<C>(ring, z, true, bb, red); 202 } 203 204 205 /** 206 * Get the one ideal. 207 * @return ideal(1) 208 */ 209 public WordIdeal<C> getONE() { 210 List<GenWordPolynomial<C>> one = new ArrayList<GenWordPolynomial<C>>(1); 211 one.add(getRing().getONE()); 212 return new WordIdeal<C>(ring, one, true, bb, red); 213 } 214 215 216 /** 217 * String representation of the word ideal. 218 * @see java.lang.Object#toString() 219 */ 220 @Override 221 public String toString() { 222 StringBuffer sb = new StringBuffer("("); 223 boolean first = true; 224 for (GenWordPolynomial<C> p : list) { 225 if (!first) { 226 sb.append(","); 227 } else { 228 first = false; 229 } 230 sb.append(p.toString()); 231 } 232 sb.append(")"); 233 return sb.toString(); 234 } 235 236 237 /** 238 * Get a scripting compatible string representation. 239 * @return script compatible representation for this Element. 240 * @see edu.jas.structure.Element#toScript() 241 */ 242 public String toScript() { 243 StringBuffer s = new StringBuffer(); 244 switch (Scripting.getLang()) { 245 case Ruby: 246 s.append("WordPolyIdeal.new("); 247 break; 248 case Python: 249 default: 250 s.append("WordIdeal("); 251 } 252 if (ring != null) { 253 s.append(ring.toScript()); 254 } 255 if (list == null) { 256 s.append(")"); 257 return s.toString(); 258 } 259 switch (Scripting.getLang()) { 260 case Ruby: 261 s.append(",\"\",["); 262 break; 263 case Python: 264 default: 265 s.append(",list=["); 266 } 267 boolean first = true; 268 String sa = null; 269 for (GenWordPolynomial<C> oa : list) { 270 sa = oa.toScript(); 271 if (first) { 272 first = false; 273 } else { 274 s.append(", "); 275 } 276 //s.append("( " + sa + " )"); 277 s.append(sa); 278 } 279 s.append("])"); 280 return s.toString(); 281 } 282 283 284 /** 285 * Comparison with any other object. <b>Note:</b> If not both ideals are 286 * Groebner Bases, then false may be returned even the ideals are equal. 287 * @see java.lang.Object#equals(java.lang.Object) 288 */ 289 @Override 290 @SuppressWarnings("unchecked") 291 public boolean equals(Object b) { 292 if (!(b instanceof WordIdeal)) { 293 logger.warn("equals no Ideal"); 294 return false; 295 } 296 WordIdeal<C> B = null; 297 try { 298 B = (WordIdeal<C>) b; 299 } catch (ClassCastException ignored) { 300 return false; 301 } 302 SortedSet<GenWordPolynomial<C>> s = new TreeSet<GenWordPolynomial<C>>(list); 303 SortedSet<GenWordPolynomial<C>> t = new TreeSet<GenWordPolynomial<C>>(B.list); 304 if (isGB && B.isGB) { //requires also monic polys 305 return s.equals(t); 306 } 307 if (s.equals(t)) { 308 return true; 309 } 310 //System.out.println("no GBs contains"); 311 return this.contains(B) && B.contains(this); 312 } 313 314 315 /** 316 * WordIdeal comparison. 317 * @param L other word ideal. 318 * @return compareTo() of polynomial lists. 319 */ 320 public int compareTo(WordIdeal<C> L) { 321 int si = Math.min(L.list.size(), list.size()); 322 int s = 0; 323 final Comparator<Word> wc = ring.alphabet.getAscendComparator(); 324 Comparator<GenWordPolynomial<C>> cmp = new Comparator<GenWordPolynomial<C>>() { 325 326 327 public int compare(GenWordPolynomial<C> p1, GenWordPolynomial<C> p2) { 328 Word w1 = p1.leadingWord(); 329 Word w2 = p2.leadingWord(); 330 if (w1 == null) { 331 return -1; // dont care 332 } 333 if (w2 == null) { 334 return 1; // dont care 335 } 336 if (w1.length() != w2.length()) { 337 if (w1.length() > w2.length()) { 338 return 1; // dont care 339 } 340 return -1; // dont care 341 } 342 return wc.compare(w1, w2); 343 } 344 }; 345 346 List<GenWordPolynomial<C>> l1 = new ArrayList<GenWordPolynomial<C>>(list); 347 List<GenWordPolynomial<C>> l2 = new ArrayList<GenWordPolynomial<C>>(L.list); 348 //Collections.sort(l1); 349 //Collections.sort(l2); 350 Collections.sort(l1, cmp); 351 Collections.sort(l2, cmp); 352 for (int i = 0; i < si; i++) { 353 GenWordPolynomial<C> a = l1.get(i); 354 GenWordPolynomial<C> b = l2.get(i); 355 s = a.compareTo(b); 356 if (s != 0) { 357 return s; 358 } 359 } 360 if (list.size() > si) { 361 return 1; 362 } 363 if (L.list.size() > si) { 364 return -1; 365 } 366 return s; 367 } 368 369 370 /** 371 * Hash code for this word ideal. 372 * @see java.lang.Object#hashCode() 373 */ 374 @Override 375 public int hashCode() { 376 int h; 377 h = list.hashCode(); 378 if (isGB) { 379 h = h << 1; 380 } 381 if (testGB) { 382 h += 1; 383 } 384 return h; 385 } 386 387 388 /** 389 * Test if ZERO ideal. 390 * @return true, if this is the 0 ideal, else false 391 */ 392 public boolean isZERO() { 393 //return list.isZERO(); 394 if (list == null) { // never true 395 return true; 396 } 397 for (GenWordPolynomial<C> p : list) { 398 if (p == null) { 399 continue; 400 } 401 if (!p.isZERO()) { 402 return false; 403 } 404 } 405 return true; 406 } 407 408 409 /** 410 * Test if ONE is contained in the ideal. To test for a proper ideal use 411 * <code>! id.isONE()</code>. 412 * @return true, if this is the 1 ideal, else false 413 */ 414 public boolean isONE() { 415 //return list.isONE(); 416 if (list == null) { 417 return false; 418 } 419 for (GenWordPolynomial<C> p : list) { 420 if (p == null) { 421 continue; 422 } 423 if (p.isONE()) { 424 return true; 425 } 426 } 427 return false; 428 } 429 430 431 /** 432 * Test if this is a twosided Groebner base. 433 * @return true, if this is a twosided Groebner base, else false 434 */ 435 public boolean isGB() { 436 if (testGB) { 437 return isGB; 438 } 439 logger.warn("isGB computing"); 440 isGB = bb.isGB(getList()); 441 testGB = true; 442 return isGB; 443 } 444 445 446 /** 447 * Do Groebner Base. Compute the Groebner Base for this ideal. 448 */ 449 @SuppressWarnings("unchecked") 450 public void doGB() { 451 if (isGB && testGB) { 452 return; 453 } 454 List<GenWordPolynomial<C>> G = getList(); 455 logger.info("doGB computing = {}", G); 456 list = bb.GB(G); 457 isGB = true; 458 testGB = true; 459 return; 460 } 461 462 463 /** 464 * Groebner Base. Get a Groebner Base for this ideal. 465 * @return twosidedGB(this) 466 */ 467 public WordIdeal<C> GB() { 468 if (isGB) { 469 return this; 470 } 471 doGB(); 472 return this; 473 } 474 475 476 /** 477 * Word ideal containment. Test if B is contained in this ideal. Note: this 478 * is eventually modified to become a Groebner Base. 479 * @param B word ideal 480 * @return true, if B is contained in this, else false 481 */ 482 public boolean contains(WordIdeal<C> B) { 483 if (B == null || B.isZERO()) { 484 return true; 485 } 486 return contains(B.getList()); 487 } 488 489 490 /** 491 * Word ideal containment. Test if b is contained in this ideal. Note: this 492 * is eventually modified to become a Groebner Base. 493 * @param b word polynomial 494 * @return true, if b is contained in this, else false 495 */ 496 public boolean contains(GenWordPolynomial<C> b) { 497 if (b == null || b.isZERO()) { 498 return true; 499 } 500 if (this.isONE()) { 501 return true; 502 } 503 if (this.isZERO()) { 504 return false; 505 } 506 if (!isGB) { 507 doGB(); 508 } 509 GenWordPolynomial<C> z = red.normalform(getList(), b); 510 if (z == null || z.isZERO()) { 511 return true; 512 } 513 return false; 514 } 515 516 517 /** 518 * Word ideal containment. Test if each b in B is contained in this ideal. 519 * Note: this is eventually modified to become a Groebner Base. 520 * @param B list of word polynomials 521 * @return true, if each b in B is contained in this, else false 522 */ 523 public boolean contains(List<GenWordPolynomial<C>> B) { 524 if (B == null || B.size() == 0) { 525 return true; 526 } 527 if (this.isONE()) { 528 return true; 529 } 530 if (!isGB) { 531 doGB(); 532 } 533 List<GenWordPolynomial<C>> si = getList(); 534 for (GenWordPolynomial<C> b : B) { 535 if (b == null) { 536 continue; 537 } 538 GenWordPolynomial<C> z = red.normalform(si, b); 539 if (!z.isZERO()) { 540 System.out.println("contains nf(b) != 0: " + b + ", z = " + z); 541 //System.out.println("contains nf(b) != 0: si = " + si); 542 return false; 543 } 544 } 545 return true; 546 } 547 548 549 /** 550 * Word ideal summation. Generators for the sum of ideals. Note: if both 551 * ideals are Groebner bases, a Groebner base is returned. 552 * @param B word ideal 553 * @return ideal(this+B) 554 */ 555 public WordIdeal<C> sum(WordIdeal<C> B) { 556 if (B == null || B.isZERO()) { 557 return this; 558 } 559 if (this.isZERO()) { 560 return B; 561 } 562 int s = getList().size() + B.getList().size(); 563 List<GenWordPolynomial<C>> c; 564 c = new ArrayList<GenWordPolynomial<C>>(s); 565 c.addAll(getList()); 566 c.addAll(B.getList()); 567 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false); 568 if (isGB && B.isGB) { 569 I.doGB(); 570 } 571 return I; 572 } 573 574 575 /** 576 * Word summation. Generators for the sum of ideal and a polynomial. Note: 577 * if this ideal is a Groebner base, a Groebner base is returned. 578 * @param b word polynomial 579 * @return ideal(this+{b}) 580 */ 581 public WordIdeal<C> sum(GenWordPolynomial<C> b) { 582 if (b == null || b.isZERO()) { 583 return this; 584 } 585 int s = getList().size() + 1; 586 List<GenWordPolynomial<C>> c; 587 c = new ArrayList<GenWordPolynomial<C>>(s); 588 c.addAll(getList()); 589 c.add(b); 590 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false); 591 if (isGB) { 592 I.doGB(); 593 } 594 return I; 595 } 596 597 598 /** 599 * Word summation. Generators for the sum of this ideal and a list of 600 * polynomials. Note: if this ideal is a Groebner base, a Groebner base is 601 * returned. 602 * @param L list of word polynomials 603 * @return ideal(this+L) 604 */ 605 public WordIdeal<C> sum(List<GenWordPolynomial<C>> L) { 606 if (L == null || L.isEmpty()) { 607 return this; 608 } 609 int s = getList().size() + L.size(); 610 List<GenWordPolynomial<C>> c = new ArrayList<GenWordPolynomial<C>>(s); 611 c.addAll(getList()); 612 c.addAll(L); 613 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false); 614 if (isGB) { 615 I.doGB(); 616 } 617 return I; 618 } 619 620 621 /** 622 * Product. Generators for the product of ideals. Note: if both ideals are 623 * Groebner bases, a Groebner base is returned. 624 * @param B word ideal 625 * @return ideal(this*B) 626 */ 627 public WordIdeal<C> product(WordIdeal<C> B) { 628 if (B == null || B.isZERO()) { 629 return B; 630 } 631 if (this.isZERO()) { 632 return this; 633 } 634 int s = getList().size() * B.getList().size(); 635 List<GenWordPolynomial<C>> c; 636 c = new ArrayList<GenWordPolynomial<C>>(s); 637 for (GenWordPolynomial<C> p : getList()) { 638 for (GenWordPolynomial<C> q : B.getList()) { 639 q = p.multiply(q); 640 c.add(q); 641 } 642 } 643 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false); 644 if (isGB && B.isGB) { 645 I.doGB(); 646 } 647 return I; 648 } 649 650 651 /** 652 * Left product. Generators for the product this by a polynomial. 653 * @param b word polynomial 654 * @return ideal(this*b) 655 */ 656 public WordIdeal<C> product(GenWordPolynomial<C> b) { 657 if (b == null || b.isZERO()) { 658 return getZERO(); 659 } 660 if (this.isZERO()) { 661 return this; 662 } 663 List<GenWordPolynomial<C>> c; 664 c = new ArrayList<GenWordPolynomial<C>>(getList().size()); 665 for (GenWordPolynomial<C> p : getList()) { 666 GenWordPolynomial<C> q = p.multiply(b); 667 c.add(q); 668 } 669 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false); 670 if (isGB) { 671 I.doGB(); 672 } 673 return I; 674 } 675 676 677 /* 678 * Intersection. Generators for the intersection of ideals. Using an 679 * iterative algorithm. 680 * @param Bl list of word ideals 681 * @return ideal(cap_i B_i), a Groebner base 682 */ 683 public WordIdeal<C> intersect(List<WordIdeal<C>> Bl) { 684 if (Bl == null || Bl.size() == 0) { 685 return getZERO(); 686 } 687 WordIdeal<C> I = null; 688 for (WordIdeal<C> B : Bl) { 689 if (I == null) { 690 I = B; 691 continue; 692 } 693 if (I.isONE()) { 694 return I; 695 } 696 I = I.intersect(B); 697 } 698 return I; 699 } 700 701 702 /* 703 * Intersection. Generators for the intersection of ideals. 704 * @param B word ideal 705 * @return ideal(this cap B), a Groebner base 706 */ 707 public WordIdeal<C> intersect(WordIdeal<C> B) { 708 if (B == null || B.isZERO()) { // (0) 709 return B; 710 } 711 if (this.isZERO()) { 712 return this; 713 } 714 List<GenWordPolynomial<C>> c = PolyGBUtil.<C> intersect(getRing(), getList(), B.getList()); 715 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, true); 716 return I; 717 } 718 719 720 /* 721 * Intersection. Generators for the intersection of a ideal with a 722 * word polynomial ring. The polynomial ring of this ideal must be 723 * a contraction of R and the TermOrder must be an elimination 724 * order. 725 * @param R word polynomial ring 726 * @return ideal(this cap R) 727 */ 728 public WordIdeal<C> intersect(GenWordPolynomialRing<C> R) { 729 if (R == null) { 730 throw new IllegalArgumentException("R may not be null"); 731 } 732 List<GenWordPolynomial<C>> H = PolyUtil.<C> intersect(R, getList()); 733 return new WordIdeal<C>(R, H, isGB); 734 } 735 736 737 /* 738 * Eliminate. Generators for the intersection of this ideal with a word 739 * polynomial ring. The word polynomial ring of this ideal must be a 740 * contraction of R and the TermOrder must be an elimination order. 741 * @param R word polynomial ring 742 * @return ideal(this cap R) 743 */ 744 public WordIdeal<C> eliminate(GenWordPolynomialRing<C> R) { 745 if (R == null) { 746 throw new IllegalArgumentException("R may not be null"); 747 } 748 if (getRing().equals(R)) { 749 return this; 750 } 751 return intersect(R); 752 } 753 754 755 /* 756 * Quotient. Generators for the word ideal quotient. 757 * @param h word polynomial 758 * @return ideal(this : h), a Groebner base 759 public WordIdeal<C> quotient(GenWordPolynomial<C> h) { 760 if (h == null) { // == (0) 761 return this; 762 } 763 if (h.isZERO()) { 764 return this; 765 } 766 if (this.isZERO()) { 767 return this; 768 } 769 List<GenWordPolynomial<C>> H; 770 H = new ArrayList<GenWordPolynomial<C>>(1); 771 H.add(h); 772 WordIdeal<C> Hi = new WordIdeal<C>(getRing(), H, true); 773 WordIdeal<C> I = this.intersect(Hi); 774 List<GenWordPolynomial<C>> Q; 775 Q = new ArrayList<GenWordPolynomial<C>>(I.getList().size()); 776 for (GenWordPolynomial<C> q : I.getList()) { 777 q = (GenWordPolynomial<C>) q.divide(h); // remainder == 0 778 Q.add(q); 779 } 780 return new WordIdeal<C>(getRing(), Q, true); 781 } 782 */ 783 784 785 /* 786 * Quotient. Generators for the word ideal quotient. 787 * @param H word ideal 788 * @return ideal(this : H), a Groebner base 789 public WordIdeal<C> quotient(WordIdeal<C> H) { 790 if (H == null || H.isZERO()) { // == (0) 791 return this; 792 } 793 if (this.isZERO()) { 794 return this; 795 } 796 WordIdeal<C> Q = null; 797 for (GenWordPolynomial<C> h : H.getList()) { 798 WordIdeal<C> Hi = this.quotient(h); 799 if (Q == null) { 800 Q = Hi; 801 } else { 802 Q = Q.intersect(Hi); 803 } 804 } 805 return Q; 806 } 807 */ 808 809 810 /** 811 * Power. Generators for the power of this word ideal. Note: if this ideal 812 * is a Groebner base, a Groebner base is returned. 813 * @param d integer 814 * @return ideal(this^d) 815 */ 816 public WordIdeal<C> power(int d) { 817 if (d <= 0) { 818 return getONE(); 819 } 820 if (this.isZERO() || this.isONE()) { 821 return this; 822 } 823 WordIdeal<C> c = this; 824 for (int i = 1; i < d; i++) { 825 c = c.product(this); 826 } 827 return c; 828 } 829 830 831 /** 832 * Normalform for element. 833 * @param h word polynomial 834 * @return left normalform of h with respect to this 835 */ 836 public GenWordPolynomial<C> normalform(GenWordPolynomial<C> h) { 837 if (h == null) { 838 return h; 839 } 840 if (h.isZERO()) { 841 return h; 842 } 843 if (this.isZERO()) { 844 return h; 845 } 846 GenWordPolynomial<C> r; 847 r = red.normalform(getList(), h); 848 return r; 849 } 850 851 852 /** 853 * Normalform for list of word elements. 854 * @param L word polynomial list 855 * @return list of left normalforms of the elements of L with respect to 856 * this 857 */ 858 public List<GenWordPolynomial<C>> normalform(List<GenWordPolynomial<C>> L) { 859 if (L == null) { 860 return L; 861 } 862 if (L.size() == 0) { 863 return L; 864 } 865 if (this.isZERO()) { 866 return L; 867 } 868 List<GenWordPolynomial<C>> M = new ArrayList<GenWordPolynomial<C>>(L.size()); 869 for (GenWordPolynomial<C> h : L) { 870 GenWordPolynomial<C> r = normalform(h); 871 if (r != null && !r.isZERO()) { 872 M.add(r); 873 } 874 } 875 return M; 876 } 877 878 879 /** 880 * Inverse for element modulo this ideal. 881 * @param h word polynomial 882 * @return inverse of h with respect to this, if defined 883 */ 884 public GenWordPolynomial<C> inverse(GenWordPolynomial<C> h) { 885 if (h == null || h.isZERO()) { 886 throw new NotInvertibleException("zero not invertible"); 887 } 888 if (this.isZERO()) { 889 throw new NotInvertibleException("zero ideal"); 890 } 891 if (h.isUnit()) { 892 return h.inverse(); 893 } 894 if (isUnit(h)) { 895 logger.warn("{} is invertable, but inverse not computed", h); 896 } 897 throw new UnsupportedOperationException("inverse of " + h); 898 /* TODO compute inverse 899 doGB(); 900 List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.list.size()); 901 F.add(h); 902 F.addAll(getList()); 903 //System.out.println("F = " + F); 904 WordExtendedGB<C> x = bb.extLeftGB(F); 905 List<GenWordPolynomial<C>> G = x.G; 906 //System.out.println("G = " + G); 907 GenWordPolynomial<C> one = null; 908 int i = -1; 909 for (GenWordPolynomial<C> p : G) { 910 i++; 911 if (p == null) { 912 continue; 913 } 914 if (p.isUnit()) { 915 one = p; 916 break; 917 } 918 } 919 if (one == null) { 920 throw new NotInvertibleException("one == null: h = " + h); 921 } 922 List<GenWordPolynomial<C>> row = x.G2F.get(i); // != -1 923 //System.out.println("row = " + row); 924 GenWordPolynomial<C> g = row.get(0); 925 if (g == null || g.isZERO()) { 926 throw new NotInvertibleException("g == 0: h = " + h); 927 } 928 GenWordPolynomial<C> gp = red.leftNormalform(getList(), g); 929 if (gp.isZERO()) { // can happen with solvable rings 930 throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g); 931 } 932 // adjust leading coefficient of g to get g*h == 1 933 GenWordPolynomial<C> f = g.multiply(h); 934 //System.out.println("f = " + f); 935 GenWordPolynomial<C> k = red.leftNormalform(getList(), f); 936 //System.out.println("k = " + k); 937 if (!k.isONE()) { 938 C lbc = k.leadingBaseCoefficient(); 939 lbc = lbc.inverse(); 940 g = g.multiply(lbc); 941 } 942 return g; 943 */ 944 } 945 946 947 /** 948 * Test if element is a unit modulo this ideal. 949 * @param h word polynomial 950 * @return true if h is a unit with respect to this, else false 951 */ 952 public boolean isUnit(GenWordPolynomial<C> h) { 953 if (h == null || h.isZERO()) { 954 return false; 955 } 956 if (this.isZERO()) { 957 return false; 958 } 959 if (h.isUnit()) { 960 return true; 961 } 962 // test this + (h) == 1: then ex p, q: pp*this**qq + p*h*q = 1 963 List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.size()); 964 F.add(h); 965 F.addAll(getList()); 966 List<GenWordPolynomial<C>> G = bb.GB(F); 967 if (debug) { 968 logger.info("isUnit GB = {}", G); 969 } 970 for (GenWordPolynomial<C> p : G) { 971 if (p == null) { 972 continue; 973 } 974 if (p.isUnit()) { 975 return true; 976 } 977 } 978 return false; 979 } 980 981 982 /** 983 * Ideal common zero test. 984 * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. 985 */ 986 public int commonZeroTest() { 987 if (this.isZERO()) { 988 return 1; 989 } 990 if (!isGB) { 991 doGB(); 992 } 993 if (this.isONE()) { 994 return -1; 995 } 996 return bb.commonZeroTest(getList()); 997 } 998 999 1000 /** 1001 * Test if this ideal is maximal. 1002 * @return true, if this is certainly maximal and not one, 1003 * false, if this is one, has dimension ≥ 1 or it is not jet determined if it is maximal. 1004 */ 1005 public boolean isMaximal() { 1006 if (commonZeroTest() != 0) { 1007 return false; 1008 } 1009 for (Long d : univariateDegrees()) { 1010 if (d > 1L) { 1011 return false; 1012 } 1013 } 1014 return true; 1015 } 1016 1017 1018 /** 1019 * Univariate head term degrees. 1020 * @return a list of the degrees of univariate head terms. 1021 */ 1022 public List<Long> univariateDegrees() { 1023 List<Long> ud = new ArrayList<Long>(); 1024 if (this.isZERO()) { 1025 return ud; 1026 } 1027 if (!isGB) { 1028 doGB(); 1029 } 1030 if (this.isONE()) { 1031 return ud; 1032 } 1033 return bb.univariateDegrees(getList()); 1034 } 1035 1036 1037 /* 1038 * Construct univariate polynomials of minimal degree in all variables in 1039 * zero dimensional ideal(G). 1040 * @return list of univariate word polynomial of minimal degree in each 1041 * variable in ideal(G) 1042 */ 1043 1044 1045 /* 1046 * Construct univariate polynomial of minimal degree in variable i in zero 1047 * dimensional ideal(G). 1048 * @param i variable index. 1049 * @return univariate word polynomial of minimal degree in variable i in 1050 * ideal(G) 1051 */ 1052 1053}