001/* 002 * $Id: WordIdeal.java 5876 2018-07-25 10:17:18Z kredel $ 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.Logger; 017import org.apache.logging.log4j.LogManager; 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.Word; 028import edu.jas.poly.PolyUtil; 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("GB 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 774 WordIdeal<C> I = this.intersect(Hi); 775 776 List<GenWordPolynomial<C>> Q; 777 Q = new ArrayList<GenWordPolynomial<C>>(I.getList().size()); 778 for (GenWordPolynomial<C> q : I.getList()) { 779 q = (GenWordPolynomial<C>) q.divide(h); // remainder == 0 780 Q.add(q); 781 } 782 return new WordIdeal<C>(getRing(), Q, true); 783 } 784 */ 785 786 787 /* 788 * Quotient. Generators for the word ideal quotient. 789 * @param H word ideal 790 * @return ideal(this : H), a Groebner base 791 public WordIdeal<C> quotient(WordIdeal<C> H) { 792 if (H == null || H.isZERO()) { // == (0) 793 return this; 794 } 795 if (this.isZERO()) { 796 return this; 797 } 798 WordIdeal<C> Q = null; 799 for (GenWordPolynomial<C> h : H.getList()) { 800 WordIdeal<C> Hi = this.quotient(h); 801 if (Q == null) { 802 Q = Hi; 803 } else { 804 Q = Q.intersect(Hi); 805 } 806 } 807 return Q; 808 } 809 */ 810 811 812 /** 813 * Power. Generators for the power of this word ideal. Note: if this 814 * ideal is a Groebner base, a Groebner base is returned. 815 * @param d integer 816 * @return ideal(this^d) 817 */ 818 public WordIdeal<C> power(int d) { 819 if (d <= 0) { 820 return getONE(); 821 } 822 if (this.isZERO() || this.isONE()) { 823 return this; 824 } 825 WordIdeal<C> c = this; 826 for (int i = 1; i < d; i++) { 827 c = c.product(this); 828 } 829 return c; 830 } 831 832 833 /** 834 * Normalform for element. 835 * @param h word polynomial 836 * @return left normalform of h with respect to this 837 */ 838 public GenWordPolynomial<C> normalform(GenWordPolynomial<C> h) { 839 if (h == null) { 840 return h; 841 } 842 if (h.isZERO()) { 843 return h; 844 } 845 if (this.isZERO()) { 846 return h; 847 } 848 GenWordPolynomial<C> r; 849 r = red.normalform(getList(), h); 850 return r; 851 } 852 853 854 /** 855 * Normalform for list of word elements. 856 * @param L word polynomial list 857 * @return list of left normalforms of the elements of L with respect to 858 * this 859 */ 860 public List<GenWordPolynomial<C>> normalform(List<GenWordPolynomial<C>> L) { 861 if (L == null) { 862 return L; 863 } 864 if (L.size() == 0) { 865 return L; 866 } 867 if (this.isZERO()) { 868 return L; 869 } 870 List<GenWordPolynomial<C>> M = new ArrayList<GenWordPolynomial<C>>(L.size()); 871 for (GenWordPolynomial<C> h : L) { 872 GenWordPolynomial<C> r = normalform(h); 873 if (r != null && !r.isZERO()) { 874 M.add(r); 875 } 876 } 877 return M; 878 } 879 880 881 /** 882 * Inverse for element modulo this ideal. 883 * @param h word polynomial 884 * @return inverse of h with respect to this, if defined 885 */ 886 public GenWordPolynomial<C> inverse(GenWordPolynomial<C> h) { 887 if (h == null || h.isZERO()) { 888 throw new NotInvertibleException("zero not invertible"); 889 } 890 if (this.isZERO()) { 891 throw new NotInvertibleException("zero ideal"); 892 } 893 if (h.isUnit()) { 894 return h.inverse(); 895 } 896 throw new UnsupportedOperationException("inverse of " + h); 897 /* TODO together with isUnit 898 doGB(); 899 List<GenWordPolynomial<C>> F = new ArrayList<GenWordPolynomial<C>>(1 + list.list.size()); 900 F.add(h); 901 F.addAll(getList()); 902 //System.out.println("F = " + F); 903 WordExtendedGB<C> x = bb.extLeftGB(F); 904 List<GenWordPolynomial<C>> G = x.G; 905 //System.out.println("G = " + G); 906 GenWordPolynomial<C> one = null; 907 int i = -1; 908 for (GenWordPolynomial<C> p : G) { 909 i++; 910 if (p == null) { 911 continue; 912 } 913 if (p.isUnit()) { 914 one = p; 915 break; 916 } 917 } 918 if (one == null) { 919 throw new NotInvertibleException("one == null: h = " + h); 920 } 921 List<GenWordPolynomial<C>> row = x.G2F.get(i); // != -1 922 //System.out.println("row = " + row); 923 GenWordPolynomial<C> g = row.get(0); 924 if (g == null || g.isZERO()) { 925 throw new NotInvertibleException("g == 0: h = " + h); 926 } 927 GenWordPolynomial<C> gp = red.leftNormalform(getList(), g); 928 if (gp.isZERO()) { // can happen with solvable rings 929 throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g); 930 } 931 // adjust leading coefficient of g to get g*h == 1 932 GenWordPolynomial<C> f = g.multiply(h); 933 //System.out.println("f = " + f); 934 GenWordPolynomial<C> k = red.leftNormalform(getList(), f); 935 //System.out.println("k = " + k); 936 if (!k.isONE()) { 937 C lbc = k.leadingBaseCoefficient(); 938 lbc = lbc.inverse(); 939 g = g.multiply(lbc); 940 } 941 return g; 942 */ 943 } 944 945 946 /** 947 * Test if element is a unit modulo this ideal. 948 * @param h word polynomial 949 * @return true if h is a unit with respect to this, else false 950 */ 951 public boolean isUnit(GenWordPolynomial<C> h) { 952 if (h == null || h.isZERO()) { 953 return false; 954 } 955 if (this.isZERO()) { 956 return false; 957 } 958 if (h.isUnit()) { 959 return true; 960 } 961 /* TODO together with inverse 962 // test this + (h) == 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 */ 979 return false; 980 } 981 982 983 /** 984 * Ideal common zero test. 985 * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. 986 */ 987 public int commonZeroTest() { 988 if (this.isZERO()) { 989 return 1; 990 } 991 if (!isGB) { 992 doGB(); 993 } 994 if (this.isONE()) { 995 return -1; 996 } 997 return bb.commonZeroTest(getList()); 998 } 999 1000 1001 /** 1002 * Test if this ideal is maximal. 1003 * @return true, if this is maximal and not one, else false. 1004 */ 1005 public boolean isMaximal() { 1006 if (commonZeroTest() != 0) { 1007 return false; 1008 } 1009 for (Long d : univariateDegrees()) { 1010 if (d > 1L) { 1011 // todo: test if univariate irreducible and no multiple polynomials 1012 return false; 1013 } 1014 } 1015 return true; 1016 } 1017 1018 1019 /** 1020 * Univariate head term degrees. 1021 * @return a list of the degrees of univariate head terms. 1022 */ 1023 public List<Long> univariateDegrees() { 1024 List<Long> ud = new ArrayList<Long>(); 1025 if (this.isZERO()) { 1026 return ud; 1027 } 1028 if (!isGB) { 1029 doGB(); 1030 } 1031 if (this.isONE()) { 1032 return ud; 1033 } 1034 return bb.univariateDegrees(getList()); 1035 } 1036 1037 1038 /* 1039 * Construct univariate polynomials of minimal degree in all variables in 1040 * zero dimensional ideal(G). 1041 * @return list of univariate word polynomial of minimal degree in each 1042 * variable in ideal(G) 1043 public List<GenWordPolynomial<C>> constructUnivariate() { 1044 List<GenWordPolynomial<C>> univs = new ArrayList<GenWordPolynomial<C>>(); 1045 for (int i = ring.alphabet.length() - 1; i >= 0; i--) { 1046 GenWordPolynomial<C> u = constructUnivariate(i); 1047 univs.add(u); 1048 } 1049 return univs; 1050 } 1051 */ 1052 1053 1054 /* 1055 * Construct univariate polynomial of minimal degree in variable i in zero 1056 * dimensional ideal(G). 1057 * @param i variable index. 1058 * @return univariate word polynomial of minimal degree in variable i in 1059 * ideal(G) 1060 public GenWordPolynomial<C> constructUnivariate(int i) { 1061 doGB(); 1062 return bb.constructUnivariate(i, getList()); 1063 } 1064 */ 1065 1066}