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 for (GenWordPolynomial<C> b : B) { 534 if (b == null) { 535 continue; 536 } 537 if (!contains(b)) { 538 System.out.println("contains nf(b) != 0: " + b); 539 return false; 540 } 541 } 542 return true; 543 } 544 545 546 /** 547 * Word ideal summation. Generators for the sum of ideals. Note: if both 548 * ideals are Groebner bases, a Groebner base is returned. 549 * @param B word ideal 550 * @return ideal(this+B) 551 */ 552 public WordIdeal<C> sum(WordIdeal<C> B) { 553 if (B == null || B.isZERO()) { 554 return this; 555 } 556 if (this.isZERO()) { 557 return B; 558 } 559 return sum(B.getList()); 560 // int s = getList().size() + B.getList().size(); 561 // List<GenWordPolynomial<C>> c; 562 // c = new ArrayList<GenWordPolynomial<C>>(s); 563 // c.addAll(getList()); 564 // c.addAll(B.getList()); 565 // WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false, bb); 566 // if (isGB && B.isGB) { 567 // I.doGB(); 568 // } 569 // return I; 570 } 571 572 573 /** 574 * Word summation. Generators for the sum of ideal and a polynomial. Note: 575 * if this ideal is a Groebner base, a Groebner base is returned. 576 * @param b word polynomial 577 * @return ideal(this+{b}) 578 */ 579 public WordIdeal<C> sum(GenWordPolynomial<C> b) { 580 if (b == null || b.isZERO()) { 581 return this; 582 } 583 int s = getList().size() + 1; 584 List<GenWordPolynomial<C>> c; 585 c = new ArrayList<GenWordPolynomial<C>>(s); 586 c.addAll(getList()); 587 c.add(b); 588 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false, bb); 589 if (isGB) { 590 I.doGB(); 591 } 592 return I; 593 } 594 595 596 /** 597 * Word summation. Generators for the sum of this ideal and a list of 598 * polynomials. Note: if this ideal is a Groebner base, a Groebner base is 599 * returned. 600 * @param L list of word polynomials 601 * @return ideal(this+L) 602 */ 603 public WordIdeal<C> sum(List<GenWordPolynomial<C>> L) { 604 if (L == null || L.isEmpty()) { 605 return this; 606 } 607 int s = getList().size() + L.size(); 608 List<GenWordPolynomial<C>> c = new ArrayList<GenWordPolynomial<C>>(s); 609 c.addAll(getList()); 610 c.addAll(L); 611 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false, bb); 612 if (isGB) { 613 I.doGB(); 614 } 615 return I; 616 } 617 618 619 /** 620 * Product. Generators for the product of ideals. Note: if both ideals are 621 * Groebner bases, a Groebner base is returned. 622 * @param B word ideal 623 * @return ideal(this*B) 624 */ 625 public WordIdeal<C> product(WordIdeal<C> B) { 626 if (B == null || B.isZERO()) { 627 return B; 628 } 629 if (this.isZERO()) { 630 return this; 631 } 632 int s = getList().size() * B.getList().size(); 633 List<GenWordPolynomial<C>> c; 634 c = new ArrayList<GenWordPolynomial<C>>(s); 635 for (GenWordPolynomial<C> p : getList()) { 636 for (GenWordPolynomial<C> q : B.getList()) { 637 q = p.multiply(q); 638 c.add(q); 639 } 640 } 641 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false, bb); 642 if (isGB && B.isGB) { 643 I.doGB(); 644 } 645 return I; 646 } 647 648 649 /** 650 * Left product. Generators for the product this by a polynomial. 651 * @param b word polynomial 652 * @return ideal(this*b) 653 */ 654 public WordIdeal<C> product(GenWordPolynomial<C> b) { 655 if (b == null || b.isZERO()) { 656 return getZERO(); 657 } 658 if (this.isZERO()) { 659 return this; 660 } 661 List<GenWordPolynomial<C>> c; 662 c = new ArrayList<GenWordPolynomial<C>>(getList().size()); 663 for (GenWordPolynomial<C> p : getList()) { 664 GenWordPolynomial<C> q = p.multiply(b); 665 c.add(q); 666 } 667 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, false, bb); 668 if (isGB) { 669 I.doGB(); 670 } 671 return I; 672 } 673 674 675 /* 676 * Intersection. Generators for the intersection of ideals. Using an 677 * iterative algorithm. 678 * @param Bl list of word ideals 679 * @return ideal(cap_i B_i), a Groebner base 680 */ 681 public WordIdeal<C> intersect(List<WordIdeal<C>> Bl) { 682 if (Bl == null || Bl.size() == 0) { 683 return getZERO(); 684 } 685 WordIdeal<C> I = null; 686 for (WordIdeal<C> B : Bl) { 687 if (I == null) { 688 I = B; 689 continue; 690 } 691 if (I.isONE()) { 692 return I; 693 } 694 I = I.intersect(B); 695 } 696 return I; 697 } 698 699 700 /* 701 * Intersection. Generators for the intersection of ideals. 702 * @param B word ideal 703 * @return ideal(this cap B), a Groebner base 704 */ 705 public WordIdeal<C> intersect(WordIdeal<C> B) { 706 if (B == null || B.isZERO()) { // (0) 707 return B; 708 } 709 if (this.isZERO()) { 710 return this; 711 } 712 List<GenWordPolynomial<C>> c = PolyGBUtil.<C> intersect(getRing(), getList(), B.getList(), bb); 713 WordIdeal<C> I = new WordIdeal<C>(getRing(), c, true, bb); 714 return I; 715 } 716 717 718 /* 719 * Intersection. Generators for the intersection of a ideal with a 720 * word polynomial ring. The polynomial ring of this ideal must be 721 * a contraction of R and the TermOrder must be an elimination 722 * order. 723 * @param R word polynomial ring 724 * @return ideal(this cap R) 725 */ 726 public WordIdeal<C> intersect(GenWordPolynomialRing<C> R) { 727 if (R == null) { 728 throw new IllegalArgumentException("R may not be null"); 729 } 730 List<GenWordPolynomial<C>> H = PolyUtil.<C> intersect(R, getList()); 731 return new WordIdeal<C>(R, H, isGB, bb); 732 } 733 734 735 /* 736 * Eliminate. Generators for the intersection of this ideal with a word 737 * polynomial ring. The word polynomial ring of this ideal must be a 738 * contraction of R and the TermOrder must be an elimination order. 739 * @param R word polynomial ring 740 * @return ideal(this cap R) 741 */ 742 public WordIdeal<C> eliminate(GenWordPolynomialRing<C> R) { 743 if (R == null) { 744 throw new IllegalArgumentException("R may not be null"); 745 } 746 if (getRing().equals(R)) { 747 return this; 748 } 749 return intersect(R); 750 } 751 752 753 /* 754 * Quotient. Generators for the word ideal quotient. 755 * @param h word polynomial 756 * @return ideal(this : h), a Groebner base 757 public WordIdeal<C> quotient(GenWordPolynomial<C> h) { 758 if (h == null) { // == (0) 759 return this; 760 } 761 if (h.isZERO()) { 762 return this; 763 } 764 if (this.isZERO()) { 765 return this; 766 } 767 List<GenWordPolynomial<C>> H; 768 H = new ArrayList<GenWordPolynomial<C>>(1); 769 H.add(h); 770 WordIdeal<C> Hi = new WordIdeal<C>(getRing(), H, true, bb); 771 WordIdeal<C> I = this.intersect(Hi); 772 List<GenWordPolynomial<C>> Q; 773 Q = new ArrayList<GenWordPolynomial<C>>(I.getList().size()); 774 for (GenWordPolynomial<C> q : I.getList()) { 775 q = (GenWordPolynomial<C>) q.divide(h); // remainder == 0 776 Q.add(q); 777 } 778 return new WordIdeal<C>(getRing(), Q, true, bb); 779 } 780 */ 781 782 783 /* 784 * Quotient. Generators for the word ideal quotient. 785 * @param H word ideal 786 * @return ideal(this : H), a Groebner base 787 public WordIdeal<C> quotient(WordIdeal<C> H) { 788 if (H == null || H.isZERO()) { // == (0) 789 return this; 790 } 791 if (this.isZERO()) { 792 return this; 793 } 794 WordIdeal<C> Q = null; 795 for (GenWordPolynomial<C> h : H.getList()) { 796 WordIdeal<C> Hi = this.quotient(h); 797 if (Q == null) { 798 Q = Hi; 799 } else { 800 Q = Q.intersect(Hi); 801 } 802 } 803 return Q; 804 } 805 */ 806 807 808 /** 809 * Power. Generators for the power of this word ideal. Note: if this ideal 810 * is a Groebner base, a Groebner base is returned. 811 * @param d integer 812 * @return ideal(this^d) 813 */ 814 public WordIdeal<C> power(int d) { 815 if (d <= 0) { 816 return getONE(); 817 } 818 if (this.isZERO() || this.isONE()) { 819 return this; 820 } 821 WordIdeal<C> c = this; 822 for (int i = 1; i < d; i++) { 823 c = c.product(this); 824 } 825 return c; 826 } 827 828 829 /** 830 * Normalform for element. 831 * @param h word polynomial 832 * @return left normalform of h with respect to this 833 */ 834 public GenWordPolynomial<C> normalform(GenWordPolynomial<C> h) { 835 if (h == null) { 836 return h; 837 } 838 if (h.isZERO()) { 839 return h; 840 } 841 if (this.isZERO()) { 842 return h; 843 } 844 GenWordPolynomial<C> r; 845 r = red.normalform(getList(), h); 846 return r; 847 } 848 849 850 /** 851 * Normalform for list of word elements. 852 * @param L word polynomial list 853 * @return list of left normalforms of the elements of L with respect to 854 * this 855 */ 856 public List<GenWordPolynomial<C>> normalform(List<GenWordPolynomial<C>> L) { 857 if (L == null) { 858 return L; 859 } 860 if (L.size() == 0) { 861 return L; 862 } 863 if (this.isZERO()) { 864 return L; 865 } 866 List<GenWordPolynomial<C>> M = new ArrayList<GenWordPolynomial<C>>(L.size()); 867 for (GenWordPolynomial<C> h : L) { 868 GenWordPolynomial<C> r = normalform(h); 869 if (r != null && !r.isZERO()) { 870 M.add(r); 871 } 872 } 873 return M; 874 } 875 876 877 /** 878 * Inverse for element modulo this ideal. 879 * @param h word polynomial 880 * @return inverse of h with respect to this, if defined 881 */ 882 public GenWordPolynomial<C> inverse(GenWordPolynomial<C> h) { 883 if (h == null || h.isZERO()) { 884 throw new NotInvertibleException("zero not invertible"); 885 } 886 if (this.isZERO()) { 887 throw new NotInvertibleException("zero ideal"); 888 } 889 if (h.isUnit()) { 890 return h.inverse(); 891 } 892 if (isUnit(h)) { 893 logger.warn("{} is invertable, but inverse not computed", h); 894 } 895 throw new UnsupportedOperationException("inverse of " + h); 896 /* TODO compute inverse 897 doGB(); 898 List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.list.size()); 899 F.add(h); 900 F.addAll(getList()); 901 //System.out.println("F = " + F); 902 WordExtendedGB<C> x = bb.extLeftGB(F); 903 List<GenWordPolynomial<C>> G = x.G; 904 //System.out.println("G = " + G); 905 GenWordPolynomial<C> one = null; 906 int i = -1; 907 for (GenWordPolynomial<C> p : G) { 908 i++; 909 if (p == null) { 910 continue; 911 } 912 if (p.isUnit()) { 913 one = p; 914 break; 915 } 916 } 917 if (one == null) { 918 throw new NotInvertibleException("one == null: h = " + h); 919 } 920 List<GenWordPolynomial<C>> row = x.G2F.get(i); // != -1 921 //System.out.println("row = " + row); 922 GenWordPolynomial<C> g = row.get(0); 923 if (g == null || g.isZERO()) { 924 throw new NotInvertibleException("g == 0: h = " + h); 925 } 926 GenWordPolynomial<C> gp = red.leftNormalform(getList(), g); 927 if (gp.isZERO()) { // can happen with solvable rings 928 throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g); 929 } 930 // adjust leading coefficient of g to get g*h == 1 931 GenWordPolynomial<C> f = g.multiply(h); 932 //System.out.println("f = " + f); 933 GenWordPolynomial<C> k = red.leftNormalform(getList(), f); 934 //System.out.println("k = " + k); 935 if (!k.isONE()) { 936 C lbc = k.leadingBaseCoefficient(); 937 lbc = lbc.inverse(); 938 g = g.multiply(lbc); 939 } 940 return g; 941 */ 942 } 943 944 945 /** 946 * Test if element is a unit modulo this ideal. 947 * @param h word polynomial 948 * @return true if h is a unit with respect to this, else false 949 */ 950 public boolean isUnit(GenWordPolynomial<C> h) { 951 if (h == null || h.isZERO()) { 952 return false; 953 } 954 if (this.isZERO()) { 955 return false; 956 } 957 if (h.isUnit()) { 958 return true; 959 } 960 // test this + (h) == 1: then ex p, q: pp*this**qq + p*h*q = 1 961 List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.size()); 962 F.add(h); 963 F.addAll(getList()); 964 List<GenWordPolynomial<C>> G = bb.GB(F); 965 if (debug) { 966 logger.info("isUnit GB = {}", G); 967 } 968 for (GenWordPolynomial<C> p : G) { 969 if (p == null) { 970 continue; 971 } 972 if (p.isUnit()) { 973 return true; 974 } 975 } 976 return false; 977 } 978 979 980 /** 981 * Ideal common zero test. 982 * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. 983 */ 984 public int commonZeroTest() { 985 if (this.isZERO()) { 986 return 1; 987 } 988 if (!isGB) { 989 doGB(); 990 } 991 if (this.isONE()) { 992 return -1; 993 } 994 return bb.commonZeroTest(getList()); 995 } 996 997 998 /** 999 * Test if this ideal is maximal. 1000 * @return true, if this is certainly maximal and not one, 1001 * false, if this is one, has dimension ≥ 1 or it is not jet determined if it is maximal. 1002 */ 1003 public boolean isMaximal() { 1004 if (commonZeroTest() != 0) { 1005 return false; 1006 } 1007 for (Long d : univariateDegrees()) { 1008 if (d > 1L) { 1009 return false; 1010 } 1011 } 1012 return true; 1013 } 1014 1015 1016 /** 1017 * Univariate head term degrees. 1018 * @return a list of the degrees of univariate head terms. 1019 */ 1020 public List<Long> univariateDegrees() { 1021 List<Long> ud = new ArrayList<Long>(); 1022 if (this.isZERO()) { 1023 return ud; 1024 } 1025 if (!isGB) { 1026 doGB(); 1027 } 1028 if (this.isONE()) { 1029 return ud; 1030 } 1031 return bb.univariateDegrees(getList()); 1032 } 1033 1034 1035 /* 1036 * Construct univariate polynomials of minimal degree in all variables in 1037 * zero dimensional ideal(G). 1038 * @return list of univariate word polynomial of minimal degree in each 1039 * variable in ideal(G) 1040 */ 1041 1042 1043 /* 1044 * Construct univariate polynomial of minimal degree in variable i in zero 1045 * dimensional ideal(G). 1046 * @param i variable index. 1047 * @return univariate word polynomial of minimal degree in variable i in 1048 * ideal(G) 1049 */ 1050 1051}