001/* 002 * $Id: Ideal.java 5839 2018-05-20 20:30:09Z kredel $ 003 */ 004 005package edu.jas.application; 006 007 008import java.io.Serializable; 009import java.util.ArrayList; 010import java.util.Arrays; 011import java.util.HashSet; 012import java.util.Iterator; 013import java.util.List; 014import java.util.Set; 015import java.util.SortedMap; 016 017import org.apache.log4j.Logger; 018 019import edu.jas.gb.ExtendedGB; 020import edu.jas.gb.GroebnerBaseAbstract; 021import edu.jas.gb.Reduction; 022import edu.jas.gbufd.GBFactory; 023import edu.jas.gbufd.GroebnerBasePartial; 024import edu.jas.gbufd.PolyGBUtil; 025import edu.jas.gbufd.SyzygyAbstract; 026import edu.jas.gbufd.SyzygySeq; 027import edu.jas.poly.AlgebraicNumber; 028import edu.jas.poly.AlgebraicNumberRing; 029import edu.jas.poly.ExpVector; 030import edu.jas.poly.GenPolynomial; 031import edu.jas.poly.GenPolynomialRing; 032import edu.jas.poly.OptimizedPolynomialList; 033import edu.jas.poly.PolyUtil; 034import edu.jas.poly.PolynomialList; 035import edu.jas.poly.TermOrder; 036import edu.jas.poly.TermOrderOptimization; 037import edu.jas.structure.GcdRingElem; 038import edu.jas.structure.NotInvertibleException; 039import edu.jas.structure.RingFactory; 040import edu.jas.ufd.FactorAbstract; 041import edu.jas.ufd.GCDFactory; 042import edu.jas.ufd.GreatestCommonDivisor; 043import edu.jas.ufd.PolyUfdUtil; 044import edu.jas.ufd.Quotient; 045import edu.jas.ufd.QuotientRing; 046import edu.jas.ufd.SquarefreeAbstract; 047import edu.jas.ufd.SquarefreeFactory; 048 049 050/** 051 * Ideal implements some methods for ideal arithmetic, for example intersection, 052 * quotient and zero and positive dimensional ideal decomposition. 053 * @author Heinz Kredel 054 */ 055public class Ideal<C extends GcdRingElem<C>> implements Comparable<Ideal<C>>, Serializable { 056 057 058 private static final Logger logger = Logger.getLogger(Ideal.class); 059 060 061 private static final boolean debug = logger.isDebugEnabled(); 062 063 064 /** 065 * The data structure is a PolynomialList. 066 */ 067 protected PolynomialList<C> list; 068 069 070 /** 071 * Indicator if list is a Groebner Base. 072 */ 073 protected boolean isGB; 074 075 076 /** 077 * Indicator if test has been performed if this is a Groebner Base. 078 */ 079 protected boolean testGB; 080 081 082 /** 083 * Indicator if list has optimized term order. 084 */ 085 protected boolean isTopt; 086 087 088 /** 089 * Groebner base engine. 090 */ 091 protected final GroebnerBaseAbstract<C> bb; 092 093 094 /** 095 * Reduction engine. 096 */ 097 protected final Reduction<C> red; 098 099 100 /** 101 * Squarefree decomposition engine. 102 */ 103 protected final SquarefreeAbstract<C> engine; 104 105 106 /** 107 * Constructor. 108 * @param ring polynomial ring 109 */ 110 public Ideal(GenPolynomialRing<C> ring) { 111 this(ring, new ArrayList<GenPolynomial<C>>()); 112 } 113 114 115 /** 116 * Constructor. 117 * @param ring polynomial ring 118 * @param F list of polynomials 119 */ 120 public Ideal(GenPolynomialRing<C> ring, List<GenPolynomial<C>> F) { 121 this(new PolynomialList<C>(ring, F)); 122 } 123 124 125 /** 126 * Constructor. 127 * @param ring polynomial ring 128 * @param F list of polynomials 129 * @param gb true if F is known to be a Groebner Base, else false 130 */ 131 public Ideal(GenPolynomialRing<C> ring, List<GenPolynomial<C>> F, boolean gb) { 132 this(new PolynomialList<C>(ring, F), gb); 133 } 134 135 136 /** 137 * Constructor. 138 * @param ring polynomial ring 139 * @param F list of polynomials 140 * @param gb true if F is known to be a Groebner Base, else false 141 * @param topt true if term order is optimized, else false 142 */ 143 public Ideal(GenPolynomialRing<C> ring, List<GenPolynomial<C>> F, boolean gb, boolean topt) { 144 this(new PolynomialList<C>(ring, F), gb, topt); 145 } 146 147 148 /** 149 * Constructor. 150 * @param list polynomial list 151 */ 152 public Ideal(PolynomialList<C> list) { 153 this(list, false); 154 } 155 156 157 /** 158 * Constructor. 159 * @param list polynomial list 160 * @param bb Groebner Base engine 161 * @param red Reduction engine 162 */ 163 public Ideal(PolynomialList<C> list, GroebnerBaseAbstract<C> bb, Reduction<C> red) { 164 this(list, false, bb, red); 165 } 166 167 168 /** 169 * Constructor. 170 * @param list polynomial list 171 * @param gb true if list is known to be a Groebner Base, else false 172 */ 173 public Ideal(PolynomialList<C> list, boolean gb) { 174 //this(list, gb, new GroebnerBaseSeqIter<C>(new OrderedSyzPairlist<C>()), new ReductionSeq<C>() ); 175 //this(list, gb, new GroebnerBaseSeq<C>(new OrderedSyzPairlist<C>()), new ReductionSeq<C>() ); 176 this(list, gb, GBFactory.getImplementation(list.ring.coFac)); 177 } 178 179 180 /** 181 * Constructor. 182 * @param list polynomial list 183 * @param gb true if list is known to be a Groebner Base, else false 184 * @param topt true if term order is optimized, else false 185 */ 186 public Ideal(PolynomialList<C> list, boolean gb, boolean topt) { 187 //this(list, gb, topt, new GroebnerBaseSeqIter<C>(new OrderedSyzPairlist<C>()), new ReductionSeq<C>()); 188 this(list, gb, topt, GBFactory.getImplementation(list.ring.coFac)); 189 } 190 191 192 /** 193 * Constructor. 194 * @param list polynomial list 195 * @param gb true if list is known to be a Groebner Base, else false 196 * @param bb Groebner Base engine 197 * @param red Reduction engine 198 */ 199 public Ideal(PolynomialList<C> list, boolean gb, GroebnerBaseAbstract<C> bb, Reduction<C> red) { 200 this(list, gb, false, bb, red); 201 } 202 203 204 /** 205 * Constructor. 206 * @param list polynomial list 207 * @param gb true if list is known to be a Groebner Base, else false 208 * @param bb Groebner Base engine 209 */ 210 public Ideal(PolynomialList<C> list, boolean gb, GroebnerBaseAbstract<C> bb) { 211 this(list, gb, false, bb, bb.red); 212 } 213 214 215 /** 216 * Constructor. 217 * @param list polynomial list 218 * @param gb true if list is known to be a Groebner Base, else false 219 * @param topt true if term order is optimized, else false 220 * @param bb Groebner Base engine 221 */ 222 public Ideal(PolynomialList<C> list, boolean gb, boolean topt, GroebnerBaseAbstract<C> bb) { 223 this(list, gb, topt, bb, bb.red); 224 } 225 226 227 /** 228 * Constructor. 229 * @param list polynomial list 230 * @param gb true if list is known to be a Groebner Base, else false 231 * @param topt true if term order is optimized, else false 232 * @param bb Groebner Base engine 233 * @param red Reduction engine 234 */ 235 public Ideal(PolynomialList<C> list, boolean gb, boolean topt, GroebnerBaseAbstract<C> bb, 236 Reduction<C> red) { 237 if (list == null || list.list == null) { 238 throw new IllegalArgumentException("list and list.list may not be null"); 239 } 240 this.list = list; 241 this.isGB = gb; 242 this.isTopt = topt; 243 this.testGB = (gb ? true : false); // ?? 244 this.bb = bb; 245 this.red = red; 246 this.engine = SquarefreeFactory.<C> getImplementation(list.ring.coFac); 247 } 248 249 250 /** 251 * Clone this. 252 * @return a copy of this. 253 */ 254 public Ideal<C> copy() { 255 return new Ideal<C>(list.copy(), isGB, isTopt, bb, red); 256 } 257 258 259 /** 260 * Get the List of GenPolynomials. 261 * @return list.list 262 */ 263 public List<GenPolynomial<C>> getList() { 264 return list.list; 265 } 266 267 268 /** 269 * Get the GenPolynomialRing. 270 * @return list.ring 271 */ 272 public GenPolynomialRing<C> getRing() { 273 return list.ring; 274 } 275 276 277 /** 278 * Get the zero ideal. 279 * @return ideal(0) 280 */ 281 public Ideal<C> getZERO() { 282 List<GenPolynomial<C>> z = new ArrayList<GenPolynomial<C>>(0); 283 PolynomialList<C> pl = new PolynomialList<C>(getRing(), z); 284 return new Ideal<C>(pl, true, isTopt, bb, red); 285 } 286 287 288 /** 289 * Get the one ideal. 290 * @return ideal(1) 291 */ 292 public Ideal<C> getONE() { 293 List<GenPolynomial<C>> one = new ArrayList<GenPolynomial<C>>(1); 294 one.add(list.ring.getONE()); 295 PolynomialList<C> pl = new PolynomialList<C>(getRing(), one); 296 return new Ideal<C>(pl, true, isTopt, bb, red); 297 } 298 299 300 /** 301 * String representation of the ideal. 302 * @see java.lang.Object#toString() 303 */ 304 @Override 305 public String toString() { 306 return list.toString(); 307 } 308 309 310 /** 311 * Get a scripting compatible string representation. 312 * @return script compatible representation for this Element. 313 * @see edu.jas.structure.Element#toScript() 314 */ 315 public String toScript() { 316 // Python case 317 return list.toScript(); 318 } 319 320 321 /** 322 * Comparison with any other object. Note: If both ideals are not Groebner 323 * Bases, then false may be returned even the ideals are equal. 324 * @see java.lang.Object#equals(java.lang.Object) 325 */ 326 @Override 327 @SuppressWarnings("unchecked") 328 public boolean equals(Object b) { 329 if (!(b instanceof Ideal)) { 330 logger.warn("equals no Ideal"); 331 return false; 332 } 333 Ideal<C> B = null; 334 try { 335 B = (Ideal<C>) b; 336 } catch (ClassCastException ignored) { 337 return false; 338 } 339 //if ( isGB && B.isGB ) { 340 // return list.equals( B.list ); requires also monic polys 341 //} else { // compute GBs ? 342 return this.contains(B) && B.contains(this); 343 //} 344 } 345 346 347 /** 348 * Ideal list comparison. 349 * @param L other Ideal. 350 * @return compareTo() of polynomial lists. 351 */ 352 public int compareTo(Ideal<C> L) { 353 return list.compareTo(L.list); 354 } 355 356 357 /** 358 * Hash code for this ideal. 359 * @see java.lang.Object#hashCode() 360 */ 361 @Override 362 public int hashCode() { 363 int h; 364 h = list.hashCode(); 365 if (isGB) { 366 h = h << 1; 367 } 368 if (testGB) { 369 h += 1; 370 } 371 return h; 372 } 373 374 375 /** 376 * Test if ZERO ideal. 377 * @return true, if this is the 0 ideal, else false 378 */ 379 public boolean isZERO() { 380 return list.isZERO(); 381 } 382 383 384 /** 385 * Test if ONE is contained in the ideal. To test for a proper ideal use 386 * <code>! id.isONE()</code>. 387 * @return true, if this is the 1 ideal, else false 388 */ 389 public boolean isONE() { 390 return list.isONE(); 391 } 392 393 394 /** 395 * Optimize the term order. 396 */ 397 public void doToptimize() { 398 if (isTopt) { 399 return; 400 } 401 list = TermOrderOptimization.<C> optimizeTermOrder(list); 402 isTopt = true; 403 if (isGB) { 404 isGB = false; 405 doGB(); 406 } 407 return; 408 } 409 410 411 /** 412 * Test if this is a Groebner base. 413 * @return true, if this is a Groebner base, else false 414 */ 415 public boolean isGB() { 416 if (testGB) { 417 return isGB; 418 } 419 logger.warn("isGB computing"); 420 isGB = bb.isGB(getList()); 421 testGB = true; 422 return isGB; 423 } 424 425 426 /** 427 * Do Groebner Base. compute the Groebner Base for this ideal. 428 */ 429 @SuppressWarnings("unchecked") 430 public void doGB() { 431 if (isGB && testGB) { 432 return; 433 } 434 //logger.warn("GB computing"); 435 List<GenPolynomial<C>> G = getList(); 436 logger.info("GB computing = " + G); 437 G = bb.GB(G); 438 if (isTopt) { 439 List<Integer> perm = ((OptimizedPolynomialList<C>) list).perm; 440 list = new OptimizedPolynomialList<C>(perm, getRing(), G); 441 } else { 442 list = new PolynomialList<C>(getRing(), G); 443 } 444 isGB = true; 445 testGB = true; 446 return; 447 } 448 449 450 /** 451 * Groebner Base. Get a Groebner Base for this ideal. 452 * @return GB(this) 453 */ 454 public Ideal<C> GB() { 455 if (isGB) { 456 return this; 457 } 458 doGB(); 459 return this; 460 } 461 462 463 /** 464 * Ideal containment. Test if B is contained in this ideal. Note: this is 465 * eventually modified to become a Groebner Base. 466 * @param B ideal 467 * @return true, if B is contained in this, else false 468 */ 469 public boolean contains(Ideal<C> B) { 470 if (B == null || B.isZERO()) { 471 return true; 472 } 473 return contains(B.getList()); 474 } 475 476 477 /** 478 * Ideal containment. Test if b is contained in this ideal. Note: this is 479 * eventually modified to become a Groebner Base. 480 * @param b polynomial 481 * @return true, if b is contained in this, else false 482 */ 483 public boolean contains(GenPolynomial<C> b) { 484 if (b == null || b.isZERO()) { 485 return true; 486 } 487 if (this.isONE()) { 488 return true; 489 } 490 if (this.isZERO()) { 491 return false; 492 } 493 if (!isGB) { 494 doGB(); 495 } 496 GenPolynomial<C> z; 497 z = red.normalform(getList(), b); 498 if (z == null || z.isZERO()) { 499 return true; 500 } 501 return false; 502 } 503 504 505 /** 506 * Ideal containment. Test if each b in B is contained in this ideal. Note: 507 * this is eventually modified to become a Groebner Base. 508 * @param B list of polynomials 509 * @return true, if each b in B is contained in this, else false 510 */ 511 public boolean contains(List<GenPolynomial<C>> B) { 512 if (B == null || B.size() == 0) { 513 return true; 514 } 515 if (this.isONE()) { 516 return true; 517 } 518 if (!isGB) { 519 doGB(); 520 } 521 for (GenPolynomial<C> b : B) { 522 if (b == null) { 523 continue; 524 } 525 GenPolynomial<C> z = red.normalform(getList(), b); 526 if (!z.isZERO()) { 527 //System.out.println("contains nf(b) != 0: " + b); 528 return false; 529 } 530 } 531 return true; 532 } 533 534 535 /** 536 * Summation. Generators for the sum of ideals. Note: if both ideals are 537 * Groebner bases, a Groebner base is returned. 538 * @param B ideal 539 * @return ideal(this+B) 540 */ 541 public Ideal<C> sum(Ideal<C> B) { 542 if (B == null || B.isZERO()) { 543 return this; 544 } 545 if (this.isZERO()) { 546 return B; 547 } 548 int s = getList().size() + B.getList().size(); 549 List<GenPolynomial<C>> c; 550 c = new ArrayList<GenPolynomial<C>>(s); 551 c.addAll(getList()); 552 c.addAll(B.getList()); 553 Ideal<C> I = new Ideal<C>(getRing(), c, false); 554 if (isGB && B.isGB) { 555 I.doGB(); 556 } 557 return I; 558 } 559 560 561 /** 562 * Summation. Generators for the sum of ideal and a polynomial. Note: if 563 * this ideal is a Groebner base, a Groebner base is returned. 564 * @param b polynomial 565 * @return ideal(this+{b}) 566 */ 567 public Ideal<C> sum(GenPolynomial<C> b) { 568 if (b == null || b.isZERO()) { 569 return this; 570 } 571 int s = getList().size() + 1; 572 List<GenPolynomial<C>> c; 573 c = new ArrayList<GenPolynomial<C>>(s); 574 c.addAll(getList()); 575 c.add(b); 576 Ideal<C> I = new Ideal<C>(getRing(), c, false); 577 if (isGB) { 578 I.doGB(); 579 } 580 return I; 581 } 582 583 584 /** 585 * Summation. Generators for the sum of this ideal and a list of 586 * polynomials. Note: if this ideal is a Groebner base, a Groebner base is 587 * returned. 588 * @param L list of polynomials 589 * @return ideal(this+L) 590 */ 591 public Ideal<C> sum(List<GenPolynomial<C>> L) { 592 if (L == null || L.isEmpty()) { 593 return this; 594 } 595 int s = getList().size() + L.size(); 596 List<GenPolynomial<C>> c = new ArrayList<GenPolynomial<C>>(s); 597 c.addAll(getList()); 598 c.addAll(L); 599 Ideal<C> I = new Ideal<C>(getRing(), c, false); 600 if (isGB) { 601 I.doGB(); 602 } 603 return I; 604 } 605 606 607 /** 608 * Product. Generators for the product of ideals. Note: if both ideals are 609 * Groebner bases, a Groebner base is returned. 610 * @param B ideal 611 * @return ideal(this*B) 612 */ 613 public Ideal<C> product(Ideal<C> B) { 614 if (B == null || B.isZERO()) { 615 return B; 616 } 617 if (this.isZERO()) { 618 return this; 619 } 620 int s = getList().size() * B.getList().size(); 621 List<GenPolynomial<C>> c; 622 c = new ArrayList<GenPolynomial<C>>(s); 623 for (GenPolynomial<C> p : getList()) { 624 for (GenPolynomial<C> q : B.getList()) { 625 q = p.multiply(q); 626 c.add(q); 627 } 628 } 629 Ideal<C> I = new Ideal<C>(getRing(), c, false); 630 if (isGB && B.isGB) { 631 I.doGB(); 632 } 633 return I; 634 } 635 636 637 /** 638 * Product. Generators for the product this ideal by a polynomial. Note: if 639 * this ideal is a Groebner base, a Groebner base is returned. 640 * @param b polynomial 641 * @return ideal(this*b) 642 */ 643 public Ideal<C> product(GenPolynomial<C> b) { 644 if (b == null || b.isZERO()) { 645 return getZERO(); 646 } 647 if (this.isZERO()) { 648 return this; 649 } 650 List<GenPolynomial<C>> c; 651 c = new ArrayList<GenPolynomial<C>>(getList().size()); 652 for (GenPolynomial<C> p : getList()) { 653 GenPolynomial<C> q = p.multiply(b); 654 c.add(q); 655 } 656 Ideal<C> I = new Ideal<C>(getRing(), c, false); 657 if (isGB) { 658 I.doGB(); 659 } 660 return I; 661 } 662 663 664 /** 665 * Intersection. Generators for the intersection of ideals. Using an 666 * iterative algorithm. 667 * @param Bl list of ideals 668 * @return ideal(cap_i B_i), a Groebner base 669 */ 670 public Ideal<C> intersect(List<Ideal<C>> Bl) { 671 if (Bl == null || Bl.size() == 0) { 672 return getZERO(); 673 } 674 Ideal<C> I = null; 675 for (Ideal<C> B : Bl) { 676 if (I == null) { 677 I = B; 678 continue; 679 } 680 if (I.isONE()) { 681 return I; 682 } 683 I = I.intersect(B); 684 } 685 return I; 686 } 687 688 689 /** 690 * Intersection. Generators for the intersection of ideals. 691 * @param B ideal 692 * @return ideal(this \cap B), a Groebner base 693 */ 694 public Ideal<C> intersect(Ideal<C> B) { 695 if (B == null || B.isZERO()) { // (0) 696 return B; 697 } 698 if (this.isZERO()) { 699 return this; 700 } 701 List<GenPolynomial<C>> c = PolyGBUtil.<C> intersect(getRing(), getList(), B.getList()); 702 Ideal<C> I = new Ideal<C>(getRing(), c, true); 703 return I; 704 } 705 706 707 /** 708 * Intersection. Generators for the intersection of a ideal with a 709 * polynomial ring. The polynomial ring of this ideal must be a contraction 710 * of R and the TermOrder must be an elimination order. 711 * @param R polynomial ring 712 * @return ideal(this \cap R) 713 */ 714 public Ideal<C> intersect(GenPolynomialRing<C> R) { 715 if (R == null) { 716 throw new IllegalArgumentException("R may not be null"); 717 } 718 List<GenPolynomial<C>> H = PolyUtil.<C> intersect(R, getList()); 719 return new Ideal<C>(R, H, isGB, isTopt); 720 } 721 722 723 /** 724 * Eliminate. Generators for the intersection of a ideal with a polynomial 725 * ring. The polynomial rings must have variable names. 726 * @param R polynomial ring 727 * @return ideal(this \cap R) 728 */ 729 public Ideal<C> eliminate(GenPolynomialRing<C> R) { 730 if (R == null) { 731 throw new IllegalArgumentException("R may not be null"); 732 } 733 if (list.ring.equals(R)) { 734 return this; 735 } 736 String[] ename = R.getVars(); 737 Ideal<C> I = eliminate(ename); 738 return I.intersect(R); 739 } 740 741 742 /** 743 * Eliminate. Preparation of generators for the intersection of a ideal with 744 * a polynomial ring. 745 * @param ename variables for the elimination ring. 746 * @return ideal(this) in K[ename,{vars \ ename}]) 747 */ 748 public Ideal<C> eliminate(String... ename) { 749 //System.out.println("ename = " + Arrays.toString(ename)); 750 if (ename == null) { 751 throw new IllegalArgumentException("ename may not be null"); 752 } 753 String[] aname = getRing().getVars(); 754 //System.out.println("aname = " + Arrays.toString(aname)); 755 if (aname == null) { 756 throw new IllegalArgumentException("aname may not be null"); 757 } 758 759 GroebnerBasePartial<C> bbp = new GroebnerBasePartial<C>(bb, null); 760 String[] rname = GroebnerBasePartial.remainingVars(aname, ename); 761 //System.out.println("rname = " + Arrays.toString(rname)); 762 PolynomialList<C> Pl = null; 763 if (rname.length == 0) { 764 if (Arrays.deepEquals(aname, ename)) { 765 return this; 766 } 767 Pl = bbp.partialGB(getList(), ename); // normal GB 768 } else { 769 Pl = bbp.elimPartialGB(getList(), rname, ename); // reversed! 770 } 771 //System.out.println("Pl = " + Pl); 772 if (debug) { 773 logger.debug("elimination GB = " + Pl); 774 } 775 Ideal<C> I = new Ideal<C>(Pl, true); 776 return I; 777 } 778 779 780 /** 781 * Quotient. Generators for the ideal quotient. 782 * @param h polynomial 783 * @return ideal(this : h), a Groebner base 784 */ 785 public Ideal<C> quotient(GenPolynomial<C> h) { 786 if (h == null) { // == (0) 787 return this; 788 } 789 if (h.isZERO()) { 790 return this; 791 } 792 if (this.isZERO()) { 793 return this; 794 } 795 List<GenPolynomial<C>> H; 796 H = new ArrayList<GenPolynomial<C>>(1); 797 H.add(h); 798 Ideal<C> Hi = new Ideal<C>(getRing(), H, true); 799 800 Ideal<C> I = this.intersect(Hi); 801 802 List<GenPolynomial<C>> Q; 803 Q = new ArrayList<GenPolynomial<C>>(I.getList().size()); 804 for (GenPolynomial<C> q : I.getList()) { 805 q = q.divide(h); // remainder == 0 806 Q.add(q); 807 } 808 return new Ideal<C>(getRing(), Q, true /*false?*/); 809 } 810 811 812 /** 813 * Quotient. Generators for the ideal quotient. 814 * @param H ideal 815 * @return ideal(this : H), a Groebner base 816 */ 817 public Ideal<C> quotient(Ideal<C> H) { 818 if (H == null) { // == (0) 819 return this; 820 } 821 if (H.isZERO()) { 822 return this; 823 } 824 if (this.isZERO()) { 825 return this; 826 } 827 Ideal<C> Q = null; 828 for (GenPolynomial<C> h : H.getList()) { 829 Ideal<C> Hi = this.quotient(h); 830 if (Q == null) { 831 Q = Hi; 832 } else { 833 Q = Q.intersect(Hi); 834 } 835 } 836 return Q; 837 } 838 839 840 /** 841 * Infinite quotient. Generators for the infinite ideal quotient. 842 * @param h polynomial 843 * @return ideal(this : h<sup>s</sup>), a Groebner base 844 */ 845 public Ideal<C> infiniteQuotientRab(GenPolynomial<C> h) { 846 if (h == null || h.isZERO()) { // == (0) 847 return getONE(); 848 } 849 if (h.isONE()) { 850 return this; 851 } 852 if (this.isZERO()) { 853 return this; 854 } 855 Ideal<C> I = this.GB(); // should be already 856 List<GenPolynomial<C>> a = I.getList(); 857 List<GenPolynomial<C>> c; 858 c = new ArrayList<GenPolynomial<C>>(a.size() + 1); 859 860 GenPolynomialRing<C> tfac = getRing().extend(1); 861 // term order is also adjusted 862 for (GenPolynomial<C> p : a) { 863 p = p.extend(tfac, 0, 0L); // p 864 c.add(p); 865 } 866 GenPolynomial<C> q = h.extend(tfac, 0, 1L); 867 GenPolynomial<C> r = tfac.getONE(); // h.extend( tfac, 0, 0L ); 868 GenPolynomial<C> hs = q.subtract(r); // 1 - t*h // (1-t)*h 869 c.add(hs); 870 logger.warn("infiniteQuotientRab computing GB "); 871 List<GenPolynomial<C>> g = bb.GB(c); 872 if (debug) { 873 logger.info("infiniteQuotientRab = " + tfac + ", c = " + c); 874 logger.info("infiniteQuotientRab GB = " + g); 875 } 876 Ideal<C> E = new Ideal<C>(tfac, g, true); 877 Ideal<C> Is = E.intersect(getRing()); 878 return Is; 879 } 880 881 882 /** 883 * Infinite quotient exponent. 884 * @param h polynomial 885 * @param Q quotient this : h^\infinity 886 * @return s with Q = this : h<sup>s</sup> 887 */ 888 public int infiniteQuotientExponent(GenPolynomial<C> h, Ideal<C> Q) { 889 int s = 0; 890 if (h == null) { // == 0 891 return s; 892 } 893 if (h.isZERO() || h.isONE()) { 894 return s; 895 } 896 if (this.isZERO() || this.isONE()) { 897 return s; 898 } 899 //see below: if (this.contains(Q)) { 900 // return s; 901 //} 902 GenPolynomial<C> p = getRing().getONE(); 903 for (GenPolynomial<C> q : Q.getList()) { 904 if (this.contains(q)) { 905 continue; 906 } 907 //System.out.println("q = " + q + ", p = " + p + ", s = " + s); 908 GenPolynomial<C> qp = q.multiply(p); 909 while (!this.contains(qp)) { 910 p = p.multiply(h); 911 s++; 912 qp = q.multiply(p); 913 } 914 } 915 return s; 916 } 917 918 919 /** 920 * Infinite quotient. Generators for the infinite ideal quotient. 921 * @param h polynomial 922 * @return ideal(this : h<sup>s</sup>), a Groebner base 923 */ 924 public Ideal<C> infiniteQuotient(GenPolynomial<C> h) { 925 if (h == null) { // == (0) 926 return this; 927 } 928 if (h.isZERO()) { 929 return this; 930 } 931 if (this.isZERO()) { 932 return this; 933 } 934 int s = 0; 935 Ideal<C> I = this.GB(); // should be already 936 GenPolynomial<C> hs = h; 937 Ideal<C> Is = I; 938 939 boolean eq = false; 940 while (!eq) { 941 Is = I.quotient(hs); 942 Is = Is.GB(); // should be already 943 logger.info("infiniteQuotient s = " + s); 944 eq = Is.contains(I); // I.contains(Is) always 945 if (!eq) { 946 I = Is; 947 s++; 948 // hs = hs.multiply( h ); 949 } 950 } 951 return Is; 952 } 953 954 955 /** 956 * Radical membership test. 957 * @param h polynomial 958 * @return true if h is contained in the radical of ideal(this), else false. 959 */ 960 public boolean isRadicalMember(GenPolynomial<C> h) { 961 if (h == null) { // == (0) 962 return true; 963 } 964 if (h.isZERO()) { 965 return true; 966 } 967 if (this.isZERO()) { 968 return true; 969 } 970 Ideal<C> x = infiniteQuotientRab(h); 971 if (debug) { 972 logger.debug("infiniteQuotientRab = " + x); 973 } 974 return x.isONE(); 975 } 976 977 978 /** 979 * Infinite quotient. Generators for the infinite ideal quotient. 980 * @param h polynomial 981 * @return ideal(this : h<sup>s</sup>), a Groebner base 982 */ 983 public Ideal<C> infiniteQuotientOld(GenPolynomial<C> h) { 984 if (h == null) { // == (0) 985 return this; 986 } 987 if (h.isZERO()) { 988 return this; 989 } 990 if (this.isZERO()) { 991 return this; 992 } 993 int s = 0; 994 Ideal<C> I = this.GB(); // should be already 995 GenPolynomial<C> hs = h; 996 997 boolean eq = false; 998 while (!eq) { 999 Ideal<C> Is = I.quotient(hs); 1000 Is = Is.GB(); // should be already 1001 logger.debug("infiniteQuotient s = " + s); 1002 eq = Is.contains(I); // I.contains(Is) always 1003 if (!eq) { 1004 I = Is; 1005 s++; 1006 hs = hs.multiply(h); 1007 } 1008 } 1009 return I; 1010 } 1011 1012 1013 /** 1014 * Infinite Quotient. Generators for the ideal infinite quotient. 1015 * @param H ideal 1016 * @return ideal(this : H<sup>s</sup>), a Groebner base 1017 */ 1018 public Ideal<C> infiniteQuotient(Ideal<C> H) { 1019 if (H == null) { // == (0) 1020 return this; 1021 } 1022 if (H.isZERO()) { 1023 return this; 1024 } 1025 if (this.isZERO()) { 1026 return this; 1027 } 1028 Ideal<C> Q = null; 1029 for (GenPolynomial<C> h : H.getList()) { 1030 Ideal<C> Hi = this.infiniteQuotient(h); 1031 if (Q == null) { 1032 Q = Hi; 1033 } else { 1034 Q = Q.intersect(Hi); 1035 } 1036 } 1037 return Q; 1038 } 1039 1040 1041 /** 1042 * Infinite Quotient. Generators for the ideal infinite quotient. 1043 * @param H ideal 1044 * @return ideal(this : H<sup>s</sup>), a Groebner base 1045 */ 1046 public Ideal<C> infiniteQuotientRab(Ideal<C> H) { 1047 if (H == null) { // == (0) 1048 return this; 1049 } 1050 if (H.isZERO()) { 1051 return this; 1052 } 1053 if (this.isZERO()) { 1054 return this; 1055 } 1056 Ideal<C> Q = null; 1057 for (GenPolynomial<C> h : H.getList()) { 1058 Ideal<C> Hi = this.infiniteQuotientRab(h); 1059 if (Q == null) { 1060 Q = Hi; 1061 } else { 1062 Q = Q.intersect(Hi); 1063 } 1064 } 1065 return Q; 1066 } 1067 1068 1069 /** 1070 * Power. Generators for the power of this ideal. Note: if this ideal is a 1071 * Groebner base, a Groebner base is returned. 1072 * @param d integer 1073 * @return ideal(this^d) 1074 */ 1075 public Ideal<C> power(int d) { 1076 if (d <= 0) { 1077 return getONE(); 1078 } 1079 if (this.isZERO() || this.isONE()) { 1080 return this; 1081 } 1082 Ideal<C> c = this; 1083 for (int i = 1; i < d; i++) { 1084 c = c.product(this); 1085 } 1086 return c; 1087 } 1088 1089 1090 /** 1091 * Normalform for element. 1092 * @param h polynomial 1093 * @return normalform of h with respect to this 1094 */ 1095 public GenPolynomial<C> normalform(GenPolynomial<C> h) { 1096 if (h == null) { 1097 return h; 1098 } 1099 if (h.isZERO()) { 1100 return h; 1101 } 1102 if (this.isZERO()) { 1103 return h; 1104 } 1105 GenPolynomial<C> r; 1106 r = red.normalform(list.list, h); 1107 return r; 1108 } 1109 1110 1111 /** 1112 * Normalform for list of elements. 1113 * @param L polynomial list 1114 * @return list of normalforms of the elements of L with respect to this 1115 */ 1116 public List<GenPolynomial<C>> normalform(List<GenPolynomial<C>> L) { 1117 if (L == null) { 1118 return L; 1119 } 1120 if (L.size() == 0) { 1121 return L; 1122 } 1123 if (this.isZERO()) { 1124 return L; 1125 } 1126 List<GenPolynomial<C>> M = new ArrayList<GenPolynomial<C>>(L.size()); 1127 for (GenPolynomial<C> h : L) { 1128 GenPolynomial<C> r = normalform(h); 1129 if (r != null && !r.isZERO()) { 1130 M.add(r); 1131 } 1132 } 1133 return M; 1134 } 1135 1136 1137 /** 1138 * Annihilator for element modulo this ideal. 1139 * @param h polynomial 1140 * @return annihilator of h with respect to this 1141 */ 1142 public Ideal<C> annihilator(GenPolynomial<C> h) { 1143 if (h == null || h.isZERO()) { 1144 return getZERO(); 1145 } 1146 if (this.isZERO()) { 1147 return this; 1148 } 1149 doGB(); 1150 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(1 + getList().size()); 1151 F.add(h); 1152 F.addAll(getList()); 1153 //System.out.println("F = " + F); 1154 SyzygyAbstract<C> syz = new SyzygySeq<C>(getRing().coFac); 1155 List<List<GenPolynomial<C>>> S = syz.zeroRelationsArbitrary(F); 1156 //System.out.println("S = " + S); 1157 List<GenPolynomial<C>> gen = new ArrayList<GenPolynomial<C>>(S.size()); 1158 for (List<GenPolynomial<C>> rel : S) { 1159 if (rel == null || rel.isEmpty()) { 1160 continue; 1161 } 1162 GenPolynomial<C> p = rel.get(0); 1163 if (p == null || p.isZERO()) { 1164 continue; 1165 } 1166 gen.add(p); 1167 } 1168 Ideal<C> ann = new Ideal<C>(getRing(), gen); 1169 //System.out.println("ann = " + ann); 1170 return ann; 1171 } 1172 1173 1174 /** 1175 * Test for annihilator of element modulo this ideal. 1176 * @param h polynomial 1177 * @param A ideal 1178 * @return true, if A is the annihilator of h with respect to this 1179 */ 1180 public boolean isAnnihilator(GenPolynomial<C> h, Ideal<C> A) { 1181 Ideal<C> B = A.product(h); 1182 return contains(B); 1183 } 1184 1185 1186 /** 1187 * Annihilator for ideal modulo this ideal. 1188 * @param H ideal 1189 * @return annihilator of H with respect to this 1190 */ 1191 public Ideal<C> annihilator(Ideal<C> H) { 1192 if (H == null || H.isZERO()) { 1193 return getZERO(); 1194 } 1195 if (this.isZERO()) { 1196 return this; 1197 } 1198 Ideal<C> ann = null; 1199 for (GenPolynomial<C> h : H.getList()) { 1200 Ideal<C> Hi = this.annihilator(h); 1201 if (ann == null) { 1202 ann = Hi; 1203 } else { 1204 ann = ann.intersect(Hi); 1205 } 1206 } 1207 return ann; 1208 } 1209 1210 1211 /** 1212 * Test for annihilator of ideal modulo this ideal. 1213 * @param H ideal 1214 * @param A ideal 1215 * @return true, if A is the annihilator of H with respect to this 1216 */ 1217 public boolean isAnnihilator(Ideal<C> H, Ideal<C> A) { 1218 Ideal<C> B = A.product(H); 1219 return contains(B); 1220 } 1221 1222 1223 /** 1224 * Inverse for element modulo this ideal. 1225 * @param h polynomial 1226 * @return inverse of h with respect to this, if defined 1227 */ 1228 public GenPolynomial<C> inverse(GenPolynomial<C> h) { 1229 if (h == null || h.isZERO()) { 1230 throw new NotInvertibleException("zero not invertible"); 1231 } 1232 if (this.isZERO()) { 1233 throw new NotInvertibleException("zero ideal"); 1234 } 1235 if (h.isUnit()) { 1236 return h.inverse(); 1237 } 1238 doGB(); 1239 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(1 + list.list.size()); 1240 F.add(h); 1241 F.addAll(list.list); 1242 //System.out.println("F = " + F); 1243 ExtendedGB<C> x = bb.extGB(F); 1244 List<GenPolynomial<C>> G = x.G; 1245 //System.out.println("G = " + G); 1246 GenPolynomial<C> one = null; 1247 int i = -1; 1248 for (GenPolynomial<C> p : G) { 1249 i++; 1250 if (p == null) { 1251 continue; 1252 } 1253 if (p.isUnit()) { 1254 one = p; 1255 break; 1256 } 1257 } 1258 if (one == null) { 1259 throw new NotInvertibleException(" h = " + h); 1260 } 1261 List<GenPolynomial<C>> row = x.G2F.get(i); // != -1 1262 GenPolynomial<C> g = row.get(0); 1263 if (g == null || g.isZERO()) { 1264 throw new NotInvertibleException(" h = " + h); 1265 } 1266 // adjust g to get g*h == 1 1267 GenPolynomial<C> f = g.multiply(h); 1268 GenPolynomial<C> k = red.normalform(list.list, f); 1269 if (!k.isONE()) { 1270 C lbc = k.leadingBaseCoefficient(); 1271 lbc = lbc.inverse(); 1272 g = g.multiply(lbc); 1273 } 1274 if (debug) { 1275 //logger.info("inv G = " + G); 1276 //logger.info("inv G2F = " + x.G2F); 1277 //logger.info("inv row "+i+" = " + row); 1278 //logger.info("inv h = " + h); 1279 //logger.info("inv g = " + g); 1280 //logger.info("inv f = " + f); 1281 f = g.multiply(h); 1282 k = red.normalform(list.list, f); 1283 logger.debug("inv k = " + k); 1284 if (!k.isUnit()) { 1285 throw new NotInvertibleException(" k = " + k); 1286 } 1287 } 1288 return g; 1289 } 1290 1291 1292 /** 1293 * Test if element is a unit modulo this ideal. 1294 * @param h polynomial 1295 * @return true if h is a unit with respect to this, else false 1296 */ 1297 public boolean isUnit(GenPolynomial<C> h) { 1298 if (h == null || h.isZERO()) { 1299 return false; 1300 } 1301 if (this.isZERO()) { 1302 return false; 1303 } 1304 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(1 + list.list.size()); 1305 F.add(h); 1306 F.addAll(list.list); 1307 List<GenPolynomial<C>> G = bb.GB(F); 1308 for (GenPolynomial<C> p : G) { 1309 if (p == null) { 1310 continue; 1311 } 1312 if (p.isUnit()) { 1313 return true; 1314 } 1315 } 1316 return false; 1317 } 1318 1319 1320 /** 1321 * Radical approximation. Squarefree generators for the ideal. 1322 * @return squarefree(this), a Groebner base 1323 */ 1324 public Ideal<C> squarefree() { 1325 if (this.isZERO()) { 1326 return this; 1327 } 1328 Ideal<C> R = this; 1329 Ideal<C> Rp = null; 1330 List<GenPolynomial<C>> li, ri; 1331 while (true) { 1332 li = R.getList(); 1333 ri = new ArrayList<GenPolynomial<C>>(li); //.size() ); 1334 for (GenPolynomial<C> h : li) { 1335 GenPolynomial<C> r = engine.squarefreePart(h); 1336 ri.add(r); 1337 } 1338 Rp = new Ideal<C>(R.getRing(), ri, false); 1339 Rp.doGB(); 1340 if (R.equals(Rp)) { 1341 break; 1342 } 1343 R = Rp; 1344 } 1345 return R; 1346 } 1347 1348 1349 /** 1350 * Ideal common zero test. 1351 * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. 1352 */ 1353 public int commonZeroTest() { 1354 if (this.isZERO()) { 1355 return 1; 1356 } 1357 if (!isGB) { 1358 doGB(); 1359 } 1360 if (this.isONE()) { 1361 return -1; 1362 } 1363 return bb.commonZeroTest(getList()); 1364 } 1365 1366 1367 /** 1368 * Test if this ideal is maximal. 1369 * @return true, if this is maximal and not one, else false. 1370 */ 1371 public boolean isMaximal() { 1372 if (commonZeroTest() != 0) { 1373 return false; 1374 } 1375 for (Long d : univariateDegrees()) { 1376 if (d > 1L) { 1377 // todo: test if univariate irreducible and no multiple polynomials 1378 return false; 1379 } 1380 } 1381 return true; 1382 } 1383 1384 1385 /** 1386 * Univariate head term degrees. 1387 * @return a list of the degrees of univariate head terms. 1388 */ 1389 public List<Long> univariateDegrees() { 1390 List<Long> ud = new ArrayList<Long>(); 1391 if (this.isZERO()) { 1392 return ud; 1393 } 1394 if (!isGB) { 1395 doGB(); 1396 } 1397 if (this.isONE()) { 1398 return ud; 1399 } 1400 return bb.univariateDegrees(getList()); 1401 } 1402 1403 1404 /** 1405 * Ideal dimension. 1406 * @return a dimension container (dim,maxIndep,list(maxIndep),vars). 1407 */ 1408 public Dimension dimension() { 1409 int t = commonZeroTest(); 1410 Set<Integer> S = new HashSet<Integer>(); 1411 Set<Set<Integer>> M = new HashSet<Set<Integer>>(); 1412 if (t <= 0) { 1413 return new Dimension(t, S, M, this.list.ring.getVars()); 1414 } 1415 int d = 0; 1416 Set<Integer> U = new HashSet<Integer>(); 1417 for (int i = 0; i < this.list.ring.nvar; i++) { 1418 U.add(i); 1419 } 1420 M = dimension(S, U, M); 1421 for (Set<Integer> m : M) { 1422 int dp = m.size(); 1423 if (dp > d) { 1424 d = dp; 1425 S = m; 1426 } 1427 } 1428 return new Dimension(d, S, M, this.list.ring.getVars()); 1429 } 1430 1431 1432 /** 1433 * Ideal dimension. 1434 * @param S is a set of independent variables. 1435 * @param U is a set of variables of unknown status. 1436 * @param M is a list of maximal sets of independent variables. 1437 * @return a list of maximal sets of independent variables, eventually 1438 * containing S. 1439 */ 1440 protected Set<Set<Integer>> dimension(Set<Integer> S, Set<Integer> U, Set<Set<Integer>> M) { 1441 Set<Set<Integer>> MP = M; 1442 Set<Integer> UP = new HashSet<Integer>(U); 1443 for (Integer j : U) { 1444 UP.remove(j); 1445 Set<Integer> SP = new HashSet<Integer>(S); 1446 SP.add(j); 1447 if (!containsHT(SP, getList())) { 1448 MP = dimension(SP, UP, MP); 1449 } 1450 } 1451 boolean contained = false; 1452 for (Set<Integer> m : MP) { 1453 if (m.containsAll(S)) { 1454 contained = true; 1455 break; 1456 } 1457 } 1458 if (!contained) { 1459 MP.add(S); 1460 } 1461 return MP; 1462 } 1463 1464 1465 /** 1466 * Ideal head term containment test. 1467 * @param G list of polynomials. 1468 * @param H index set. 1469 * @return true, if the vaiables of the head terms of each polynomial in G 1470 * are contained in H, else false. 1471 */ 1472 protected boolean containsHT(Set<Integer> H, List<GenPolynomial<C>> G) { 1473 Set<Integer> S = null; 1474 for (GenPolynomial<C> p : G) { 1475 if (p == null) { 1476 continue; 1477 } 1478 ExpVector e = p.leadingExpVector(); 1479 if (e == null) { 1480 continue; 1481 } 1482 int[] v = e.dependencyOnVariables(); 1483 if (v == null) { 1484 continue; 1485 } 1486 //System.out.println("v = " + Arrays.toString(v)); 1487 if (S == null) { // revert indices 1488 S = new HashSet<Integer>(H.size()); 1489 int r = e.length() - 1; 1490 for (Integer i : H) { 1491 S.add(r - i); 1492 } 1493 } 1494 if (contains(v, S)) { // v \subset S 1495 return true; 1496 } 1497 } 1498 return false; 1499 } 1500 1501 1502 /** 1503 * Set containment. is v \subset H. 1504 * @param v index array. 1505 * @param H index set. 1506 * @return true, if each element of v is contained in H, else false . 1507 */ 1508 protected boolean contains(int[] v, Set<Integer> H) { 1509 for (int i = 0; i < v.length; i++) { 1510 if (!H.contains(v[i])) { 1511 return false; 1512 } 1513 } 1514 return true; 1515 } 1516 1517 1518 /** 1519 * Construct univariate polynomials of minimal degree in all variables in 1520 * zero dimensional ideal(G). 1521 * @return list of univariate polynomial of minimal degree in each variable 1522 * in ideal(G) 1523 */ 1524 public List<GenPolynomial<C>> constructUnivariate() { 1525 List<GenPolynomial<C>> univs = new ArrayList<GenPolynomial<C>>(); 1526 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1527 GenPolynomial<C> u = constructUnivariate(i); 1528 univs.add(u); 1529 } 1530 return univs; 1531 } 1532 1533 1534 /** 1535 * Construct univariate polynomial of minimal degree in variable i in zero 1536 * dimensional ideal(G). 1537 * @param i variable index. 1538 * @return univariate polynomial of minimal degree in variable i in ideal(G) 1539 */ 1540 public GenPolynomial<C> constructUnivariate(int i) { 1541 doGB(); 1542 return bb.constructUnivariate(i, getList()); 1543 } 1544 1545 1546 /** 1547 * Zero dimensional radical decompostition. See Seidenbergs lemma 92, and 1548 * BWK lemma 8.13. 1549 * @return intersection of radical ideals G_i with ideal(this) subseteq 1550 * cap_i( ideal(G_i) ) 1551 */ 1552 public List<IdealWithUniv<C>> zeroDimRadicalDecomposition() { 1553 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 1554 if (this.isZERO()) { 1555 return dec; 1556 } 1557 IdealWithUniv<C> iwu = new IdealWithUniv<C>(this, new ArrayList<GenPolynomial<C>>()); 1558 dec.add(iwu); 1559 if (this.isONE()) { 1560 return dec; 1561 } 1562 if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { 1563 logger.warn("must use prime decomposition for char p and infinite coefficient rings, found " 1564 + list.ring.coFac.toScript()); 1565 return zeroDimPrimeDecomposition(); 1566 } 1567 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1568 List<IdealWithUniv<C>> part = new ArrayList<IdealWithUniv<C>>(); 1569 for (IdealWithUniv<C> id : dec) { 1570 //System.out.println("id = " + id + ", i = " + i); 1571 GenPolynomial<C> u = id.ideal.constructUnivariate(i); 1572 SortedMap<GenPolynomial<C>, Long> facs = engine.baseSquarefreeFactors(u); 1573 if (facs == null || facs.size() == 0 1574 || (facs.size() == 1 && facs.get(facs.firstKey()) == 1L)) { 1575 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1576 iup.addAll(id.upolys); 1577 iup.add(u); 1578 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(id.ideal, iup); 1579 part.add(Ipu); 1580 continue; // irreducible 1581 } 1582 if (logger.isInfoEnabled()) { 1583 logger.info("squarefree facs = " + facs); 1584 } 1585 GenPolynomialRing<C> mfac = id.ideal.list.ring; 1586 int j = mfac.nvar - 1 - i; 1587 for (GenPolynomial<C> p : facs.keySet()) { 1588 // make p multivariate 1589 GenPolynomial<C> pm = p.extendUnivariate(mfac, j); 1590 // mfac.parse( p.toString() ); 1591 //stem.out.println("pm = " + pm); 1592 Ideal<C> Ip = id.ideal.sum(pm); 1593 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1594 iup.addAll(id.upolys); 1595 iup.add(p); 1596 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(Ip, iup); 1597 if (debug) { 1598 logger.info("ideal with squarefree facs = " + Ipu); 1599 } 1600 part.add(Ipu); 1601 } 1602 } 1603 dec = part; 1604 //part = new ArrayList<IdealWithUniv<C>>(); 1605 } 1606 return dec; 1607 } 1608 1609 1610 /** 1611 * Test for Zero dimensional radical. See Seidenbergs lemma 92, and BWK 1612 * lemma 8.13. 1613 * @return true if this is an zero dimensional radical ideal, else false 1614 */ 1615 public boolean isZeroDimRadical() { 1616 if (this.isZERO()) { 1617 return false; 1618 } 1619 if (this.isONE()) { 1620 return false; // not 0-dim 1621 } 1622 if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { 1623 logger.warn("radical only for char 0 or finite coefficient rings, but found " 1624 + list.ring.coFac.toScript()); 1625 } 1626 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1627 GenPolynomial<C> u = constructUnivariate(i); 1628 boolean t = engine.isSquarefree(u); 1629 if (!t) { 1630 System.out.println("not squarefree " + engine.squarefreePart(u) + ", " + u); 1631 return false; 1632 } 1633 } 1634 return true; 1635 } 1636 1637 1638 /** 1639 * Zero dimensional ideal irreducible decompostition. See algorithm DIRGZD 1640 * of BGK 1986 and also PREDEC of the Gröbner bases book 1993. 1641 * @return intersection H, of ideals G_i with ideal(this) subseteq cap_i( 1642 * ideal(G_i) ) and each ideal G_i has only irreducible minimal 1643 * univariate polynomials and the G_i are pairwise co-prime. 1644 */ 1645 public List<IdealWithUniv<C>> zeroDimDecomposition() { 1646 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 1647 if (this.isZERO()) { 1648 return dec; 1649 } 1650 IdealWithUniv<C> iwu = new IdealWithUniv<C>(this, new ArrayList<GenPolynomial<C>>()); 1651 dec.add(iwu); 1652 if (this.isONE()) { 1653 return dec; 1654 } 1655 FactorAbstract<C> ufd = FactorFactory.<C> getImplementation(list.ring.coFac); 1656 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1657 List<IdealWithUniv<C>> part = new ArrayList<IdealWithUniv<C>>(); 1658 for (IdealWithUniv<C> id : dec) { 1659 //System.out.println("id.ideal = " + id.ideal); 1660 GenPolynomial<C> u = id.ideal.constructUnivariate(i); 1661 SortedMap<GenPolynomial<C>, Long> facs = ufd.baseFactors(u); 1662 if (facs.size() == 0 || (facs.size() == 1 && facs.get(facs.firstKey()) == 1L)) { 1663 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1664 iup.addAll(id.upolys); 1665 iup.add(u); 1666 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(id.ideal, iup); 1667 part.add(Ipu); 1668 continue; // irreducible 1669 } 1670 if (debug) { 1671 logger.info("irreducible facs = " + facs); 1672 } 1673 GenPolynomialRing<C> mfac = id.ideal.list.ring; 1674 int j = mfac.nvar - 1 - i; 1675 for (GenPolynomial<C> p : facs.keySet()) { 1676 // make p multivariate 1677 GenPolynomial<C> pm = p.extendUnivariate(mfac, j); 1678 // mfac.parse( p.toString() ); 1679 //System.out.println("pm = " + pm); 1680 Ideal<C> Ip = id.ideal.sum(pm); 1681 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1682 iup.addAll(id.upolys); 1683 iup.add(p); 1684 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(Ip, iup); 1685 part.add(Ipu); 1686 } 1687 } 1688 dec = part; 1689 //part = new ArrayList<IdealWithUniv<C>>(); 1690 } 1691 return dec; 1692 } 1693 1694 1695 /** 1696 * Zero dimensional ideal irreducible decompostition extension. One step 1697 * decomposition via a minimal univariate polynomial in the lowest variable, 1698 * used after each normalPosition step. 1699 * @param upol list of univariate polynomials 1700 * @param og list of other generators for the ideal 1701 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 1702 * ideal(G_i) ) and all minimal univariate polynomials of all G_i 1703 * are irreducible 1704 */ 1705 public List<IdealWithUniv<C>> zeroDimDecompositionExtension(List<GenPolynomial<C>> upol, 1706 List<GenPolynomial<C>> og) { 1707 if (upol == null || upol.size() + 1 != list.ring.nvar) { 1708 throw new IllegalArgumentException("univariate polynomial list not correct " + upol); 1709 } 1710 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 1711 if (this.isZERO()) { 1712 return dec; 1713 } 1714 IdealWithUniv<C> iwu = new IdealWithUniv<C>(this, upol); 1715 if (this.isONE()) { 1716 dec.add(iwu); 1717 return dec; 1718 } 1719 FactorAbstract<C> ufd = FactorFactory.<C> getImplementation(list.ring.coFac); 1720 int i = list.ring.nvar - 1; 1721 //IdealWithUniv<C> id = new IdealWithUniv<C>(this,upol); 1722 GenPolynomial<C> u = this.constructUnivariate(i); 1723 SortedMap<GenPolynomial<C>, Long> facs = ufd.baseFactors(u); 1724 if (facs.size() == 1 && facs.get(facs.firstKey()) == 1L) { 1725 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1726 iup.add(u); // new polynomial first 1727 iup.addAll(upol); 1728 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(this, iup, og); 1729 dec.add(Ipu); 1730 return dec; 1731 } 1732 if (true) { 1733 logger.info("irreducible facs = " + facs); 1734 } 1735 GenPolynomialRing<C> mfac = list.ring; 1736 int j = mfac.nvar - 1 - i; 1737 for (GenPolynomial<C> p : facs.keySet()) { 1738 // make p multivariate 1739 GenPolynomial<C> pm = p.extendUnivariate(mfac, j); 1740 //System.out.println("pm = " + pm); 1741 Ideal<C> Ip = this.sum(pm); 1742 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1743 iup.add(p); // new polynomial first 1744 iup.addAll(upol); 1745 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(Ip, iup, og); 1746 dec.add(Ipu); 1747 } 1748 return dec; 1749 } 1750 1751 1752 /** 1753 * Test for zero dimensional ideal decompostition. 1754 * @param L intersection of ideals G_i with ideal(G) subseteq cap_i( 1755 * ideal(G_i) ) and all minimal univariate polynomials of all G_i 1756 * are irreducible 1757 * @return true if L is a zero dimensional irreducible decomposition of 1758 * this, else false 1759 */ 1760 public boolean isZeroDimDecomposition(List<IdealWithUniv<C>> L) { 1761 if (L == null || L.size() == 0) { 1762 if (this.isZERO()) { 1763 return true; 1764 } 1765 return false; 1766 } 1767 // add lower variables if L contains ideals from field extensions 1768 GenPolynomialRing<C> ofac = list.ring; 1769 int r = ofac.nvar; 1770 int rp = L.get(0).ideal.list.ring.nvar; 1771 int d = rp - r; 1772 //System.out.println("d = " + d); 1773 Ideal<C> Id = this; 1774 if (d > 0) { 1775 GenPolynomialRing<C> nfac = ofac.extendLower(d); 1776 //System.out.println("nfac = " + nfac); 1777 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size()); 1778 for (GenPolynomial<C> p : getList()) { 1779 //System.out.println("p = " + p); 1780 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1781 //System.out.println("q = " + q); 1782 elist.add(q); 1783 } 1784 Id = new Ideal<C>(nfac, elist, isGB, isTopt); 1785 } 1786 // test if this is contained in the intersection 1787 for (IdealWithUniv<C> I : L) { 1788 boolean t = I.ideal.contains(Id); 1789 if (!t) { 1790 System.out.println("not contained " + this + " in " + I.ideal); 1791 return false; 1792 } 1793 } 1794 // test if all univariate polynomials are contained in the respective ideal 1795 //List<GenPolynomial<C>> upprod = new ArrayList<GenPolynomial<C>>(rp); 1796 for (IdealWithUniv<C> I : L) { 1797 GenPolynomialRing<C> mfac = I.ideal.list.ring; 1798 int i = 0; 1799 for (GenPolynomial<C> p : I.upolys) { 1800 GenPolynomial<C> pm = p.extendUnivariate(mfac, i++); 1801 //System.out.println("pm = " + pm + ", p = " + p); 1802 boolean t = I.ideal.contains(pm); 1803 if (!t) { 1804 System.out.println("not contained " + pm + " in " + I.ideal); 1805 return false; 1806 } 1807 } 1808 } 1809 return true; 1810 } 1811 1812 1813 /** 1814 * Compute normal position for variables i and j. 1815 * @param i first variable index 1816 * @param j second variable index 1817 * @param og other generators for the ideal 1818 * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] 1819 */ 1820 public IdealWithUniv<C> normalPositionFor(int i, int j, List<GenPolynomial<C>> og) { 1821 // extend variables by one 1822 GenPolynomialRing<C> ofac = list.ring; 1823 if (ofac.tord.getEvord() != TermOrder.INVLEX) { 1824 throw new IllegalArgumentException("invalid term order for normalPosition " + ofac.tord); 1825 } 1826 if (ofac.characteristic().signum() == 0) { 1827 return normalPositionForChar0(i, j, og); 1828 } 1829 return normalPositionForCharP(i, j, og); 1830 } 1831 1832 1833 /** 1834 * Compute normal position for variables i and j, characteristic zero. 1835 * @param i first variable index 1836 * @param j second variable index 1837 * @param og other generators for the ideal 1838 * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] 1839 */ 1840 IdealWithUniv<C> normalPositionForChar0(int i, int j, List<GenPolynomial<C>> og) { 1841 // extend variables by one 1842 GenPolynomialRing<C> ofac = list.ring; 1843 GenPolynomialRing<C> nfac = ofac.extendLower(1); 1844 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size() + 1); 1845 for (GenPolynomial<C> p : getList()) { 1846 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1847 //System.out.println("q = " + q); 1848 elist.add(q); 1849 } 1850 List<GenPolynomial<C>> ogen = new ArrayList<GenPolynomial<C>>(); 1851 if (og != null && og.size() > 0) { 1852 for (GenPolynomial<C> p : og) { 1853 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1854 //System.out.println("q = " + q); 1855 ogen.add(q); 1856 } 1857 } 1858 Ideal<C> I = new Ideal<C>(nfac, elist, true); 1859 //System.out.println("I = " + I); 1860 int ip = list.ring.nvar - 1 - i; 1861 int jp = list.ring.nvar - 1 - j; 1862 GenPolynomial<C> xi = nfac.univariate(ip); 1863 GenPolynomial<C> xj = nfac.univariate(jp); 1864 GenPolynomial<C> z = nfac.univariate(nfac.nvar - 1); 1865 // compute GBs until value of t is OK 1866 Ideal<C> Ip; 1867 GenPolynomial<C> zp; 1868 int t = 0; 1869 do { 1870 t--; 1871 // zp = z - ( xj - xi * t ) 1872 zp = z.subtract(xj.subtract(xi.multiply(nfac.fromInteger(t)))); 1873 zp = zp.monic(); 1874 Ip = I.sum(zp); 1875 //System.out.println("Ip = " + Ip); 1876 if (-t % 5 == 0) { 1877 logger.info("normal position, t = " + t); 1878 } 1879 } while (!Ip.isNormalPositionFor(i + 1, j + 1)); 1880 if (debug) { 1881 logger.info("normal position = " + Ip); 1882 } 1883 ogen.add(zp); 1884 IdealWithUniv<C> Ips = new IdealWithUniv<C>(Ip, null, ogen); 1885 return Ips; 1886 } 1887 1888 1889 /** 1890 * Compute normal position for variables i and j, positive characteristic. 1891 * @param i first variable index 1892 * @param j second variable index 1893 * @param og other generators for the ideal 1894 * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] 1895 */ 1896 @SuppressWarnings({ "unchecked", "cast" }) 1897 IdealWithUniv<C> normalPositionForCharP(int i, int j, List<GenPolynomial<C>> og) { 1898 // extend variables by one 1899 GenPolynomialRing<C> ofac = list.ring; 1900 GenPolynomialRing<C> nfac = ofac.extendLower(1); 1901 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size() + 1); 1902 for (GenPolynomial<C> p : getList()) { 1903 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1904 //System.out.println("q = " + q); 1905 elist.add(q); 1906 } 1907 List<GenPolynomial<C>> ogen = new ArrayList<GenPolynomial<C>>(); 1908 if (og != null && og.size() > 0) { 1909 for (GenPolynomial<C> p : og) { 1910 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1911 //System.out.println("q = " + q); 1912 ogen.add(q); 1913 } 1914 } 1915 Ideal<C> I = new Ideal<C>(nfac, elist, true); 1916 //System.out.println("I = " + I); 1917 int ip = list.ring.nvar - 1 - i; 1918 int jp = list.ring.nvar - 1 - j; 1919 GenPolynomial<C> xi = nfac.univariate(ip); 1920 GenPolynomial<C> xj = nfac.univariate(jp); 1921 GenPolynomial<C> z = nfac.univariate(nfac.nvar - 1); 1922 // compute GBs until value of t is OK 1923 Ideal<C> Ip; 1924 GenPolynomial<C> zp; 1925 AlgebraicNumberRing<C> afac = null; 1926 Iterator<AlgebraicNumber<C>> aiter = null; 1927 //String obr = ""; 1928 //String cbr = ""; 1929 int t = 0; 1930 do { 1931 t--; 1932 // zp = z - ( xj - xi * t ) 1933 GenPolynomial<C> tn; 1934 if (afac == null) { 1935 tn = nfac.fromInteger(t); 1936 if (tn.isZERO()) { 1937 RingFactory<C> fac = nfac.coFac; 1938 //int braces = 2; 1939 while (!(fac instanceof AlgebraicNumberRing)) { 1940 if (fac instanceof GenPolynomialRing) { 1941 GenPolynomialRing<C> pfac = (GenPolynomialRing<C>) (Object) fac; 1942 fac = pfac.coFac; 1943 } else if (fac instanceof QuotientRing) { 1944 QuotientRing<C> pfac = (QuotientRing<C>) (Object) fac; 1945 fac = pfac.ring.coFac; 1946 } else { 1947 throw new ArithmeticException( 1948 "field elements exhausted, need algebraic extension of base ring"); 1949 } 1950 //braces++; 1951 } 1952 //for (int ii = 0; ii < braces; ii++) { 1953 // obr += "{ "; 1954 // cbr += " }"; 1955 //} 1956 afac = (AlgebraicNumberRing<C>) (Object) fac; 1957 logger.info("afac = " + afac.toScript()); 1958 aiter = afac.iterator(); 1959 AlgebraicNumber<C> an = aiter.next(); 1960 for (int kk = 0; kk < afac.characteristic().intValue(); kk++) { 1961 an = aiter.next(); 1962 } 1963 //System.out.println("an,iter = " + an); 1964 //tn = nfac.parse(obr + an.toString() + cbr); 1965 tn = nfac.parse(an.toString()); 1966 //System.out.println("tn = " + tn); 1967 //if (false) { 1968 // throw new RuntimeException("probe"); 1969 //} 1970 } 1971 } else { 1972 if (!aiter.hasNext()) { 1973 throw new ArithmeticException( 1974 "field elements exhausted, normal position not reachable: !aiter.hasNext(): " 1975 + t); 1976 } 1977 AlgebraicNumber<C> an = aiter.next(); 1978 //System.out.println("an,iter = " + an); 1979 //tn = nfac.parse(obr + an.toString() + cbr); 1980 tn = nfac.parse(an.toString()); 1981 //System.out.println("tn = " + tn); 1982 } 1983 if (tn.isZERO()) { 1984 throw new ArithmeticException( 1985 "field elements exhausted, normal position not reachable: tn == 0: " + t); 1986 } 1987 zp = z.subtract(xj.subtract(xi.multiply(tn))); 1988 zp = zp.monic(); 1989 Ip = I.sum(zp); 1990 //System.out.println("Ip = " + Ip); 1991 if (-t % 4 == 0) { 1992 logger.info("normal position, t = " + t); 1993 logger.info("normal position, GB = " + Ip); 1994 if (t < -550) { 1995 throw new ArithmeticException("normal position not reached in " + t + " steps"); 1996 } 1997 } 1998 } while (!Ip.isNormalPositionFor(i + 1, j + 1)); 1999 if (debug) { 2000 logger.info("normal position = " + Ip); 2001 } 2002 ogen.add(zp); 2003 IdealWithUniv<C> Ips = new IdealWithUniv<C>(Ip, null, ogen); 2004 return Ips; 2005 } 2006 2007 2008 /** 2009 * Test if this ideal is in normal position for variables i and j. 2010 * @param i first variable index 2011 * @param j second variable index 2012 * @return true if this is in normal position with respect to i and j 2013 */ 2014 public boolean isNormalPositionFor(int i, int j) { 2015 // called in extended ring! 2016 int ip = list.ring.nvar - 1 - i; 2017 int jp = list.ring.nvar - 1 - j; 2018 boolean iOK = false; 2019 boolean jOK = false; 2020 for (GenPolynomial<C> p : getList()) { 2021 if (p.isZERO()) { 2022 continue; 2023 } 2024 ExpVector e = p.leadingExpVector(); 2025 int[] dov = e.dependencyOnVariables(); 2026 //System.out.println("dov = " + Arrays.toString(dov)); 2027 if (dov.length == 0) { 2028 throw new IllegalArgumentException("ideal dimension is not zero"); 2029 } 2030 if (dov[0] == ip) { 2031 if (e.totalDeg() != 1) { 2032 return false; 2033 } 2034 iOK = true; 2035 } else if (dov[0] == jp) { 2036 if (e.totalDeg() != 1) { 2037 return false; 2038 } 2039 jOK = true; 2040 } 2041 if (iOK && jOK) { 2042 return true; 2043 } 2044 } 2045 return iOK && jOK; 2046 } 2047 2048 2049 /** 2050 * Normal position index, separate for polynomials with more than 2 2051 * variables. See also 2052 * <a href="http://krum.rz.uni-mannheim.de/mas/src/masring/DIPDEC0.mi.html" 2053 * >mas.masring.DIPDEC0#DIGISR</a> 2054 * @return (i,j) for non-normal variables 2055 */ 2056 public int[] normalPositionIndex2Vars() { 2057 int[] np = null; 2058 int i = -1; 2059 int j = -1; 2060 for (GenPolynomial<C> p : getList()) { 2061 if (p.isZERO()) { 2062 continue; 2063 } 2064 ExpVector e = p.leadingExpVector(); 2065 int[] dov = e.dependencyOnVariables(); 2066 //System.out.println("dov_head = " + Arrays.toString(dov)); 2067 if (dov.length == 0) { 2068 throw new IllegalArgumentException("ideal dimension is not zero " + p); 2069 } 2070 // search bi-variate head terms 2071 if (dov.length >= 2) { 2072 i = dov[0]; 2073 j = dov[1]; 2074 break; 2075 } 2076 int n = dov[0]; 2077 GenPolynomial<C> q = p.reductum(); 2078 if (q.isZERO()) { 2079 continue; 2080 } 2081 e = q.degreeVector(); 2082 dov = e.dependencyOnVariables(); 2083 //System.out.println("dov_red = " + Arrays.toString(dov)); 2084 int k = Arrays.binarySearch(dov, n); 2085 int len = 2; 2086 if (k >= 0) { 2087 len = 3; 2088 } 2089 // search bi-variate reductas 2090 if (dov.length >= len) { 2091 switch (k) { 2092 case 0: 2093 i = dov[1]; 2094 j = dov[2]; 2095 break; 2096 case 1: 2097 i = dov[0]; 2098 j = dov[2]; 2099 break; 2100 case 2: 2101 i = dov[0]; 2102 j = dov[1]; 2103 break; 2104 default: 2105 i = dov[0]; 2106 j = dov[1]; 2107 break; 2108 } 2109 break; 2110 } 2111 } 2112 if (i < 0 || j < 0) { 2113 return np; 2114 } 2115 // adjust index 2116 i = list.ring.nvar - 1 - i; 2117 j = list.ring.nvar - 1 - j; 2118 np = new int[] { j, i }; // reverse 2119 logger.info("normalPositionIndex2Vars, np = " + Arrays.toString(np)); 2120 return np; 2121 } 2122 2123 2124 /** 2125 * Normal position index, separate multiple univariate polynomials. See also 2126 * <a href="http://krum.rz.uni-mannheim.de/mas/src/masring/DIPDEC0.mi.html"> 2127 * mas.masring.DIPDEC0#DIGISM</a> 2128 * @return (i,j) for non-normal variables 2129 */ 2130 public int[] normalPositionIndexUnivars() { 2131 int[] np = null; //new int[] { -1, -1 }; 2132 int i = -1; 2133 int j = -1; 2134 // search multiple univariate polynomials with degree >= 2 2135 for (GenPolynomial<C> p : getList()) { 2136 if (p.isZERO()) { 2137 continue; 2138 } 2139 ExpVector e = p.degreeVector(); 2140 int[] dov = e.dependencyOnVariables(); 2141 long t = e.totalDeg(); // lt(p) would be enough 2142 //System.out.println("dov_univ = " + Arrays.toString(dov) + ", e = " + e); 2143 if (dov.length == 0) { 2144 throw new IllegalArgumentException("ideal dimension is not zero"); 2145 } 2146 if (dov.length == 1 && t >= 2L) { 2147 if (i == -1) { 2148 i = dov[0]; 2149 } else if (j == -1) { 2150 j = dov[0]; 2151 if (i > j) { 2152 int x = i; 2153 i = j; 2154 j = x; 2155 } 2156 } 2157 } 2158 if (i >= 0 && j >= 0) { 2159 break; 2160 } 2161 } 2162 if (i < 0 || j < 0) { 2163 // search polynomials with univariate head term and degree >= 2 2164 for (GenPolynomial<C> p : getList()) { 2165 if (p.isZERO()) { 2166 continue; 2167 } 2168 ExpVector e = p.leadingExpVector(); 2169 long t = e.totalDeg(); 2170 if (t >= 2) { 2171 e = p.degreeVector(); 2172 int[] dov = e.dependencyOnVariables(); 2173 //System.out.println("dov_univ2 = " + Arrays.toString(dov) + " e = " + e); 2174 if (dov.length == 0) { 2175 throw new IllegalArgumentException("ideal dimension is not zero"); 2176 } 2177 if (dov.length >= 2) { 2178 i = dov[0]; 2179 j = dov[1]; 2180 } 2181 } 2182 if (i >= 0 && j >= 0) { 2183 break; 2184 } 2185 } 2186 } 2187 if (i < 0 || j < 0) { 2188 return np; 2189 } 2190 // adjust index 2191 i = list.ring.nvar - 1 - i; 2192 j = list.ring.nvar - 1 - j; 2193 np = new int[] { j, i }; // reverse 2194 logger.info("normalPositionIndexUnivars, np = " + Arrays.toString(np)); 2195 return np; 2196 } 2197 2198 2199 /** 2200 * Zero dimensional ideal decompostition for real roots. See algorithm 2201 * mas.masring.DIPDEC0#DINTSR. 2202 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2203 * ideal(G_i) ) and each G_i contains at most bi-variate polynomials 2204 * and all univariate minimal polynomials are irreducible 2205 */ 2206 public List<IdealWithUniv<C>> zeroDimRootDecomposition() { 2207 List<IdealWithUniv<C>> dec = zeroDimDecomposition(); 2208 if (this.isZERO()) { 2209 return dec; 2210 } 2211 if (this.isONE()) { 2212 return dec; 2213 } 2214 List<IdealWithUniv<C>> rdec = new ArrayList<IdealWithUniv<C>>(); 2215 while (dec.size() > 0) { 2216 IdealWithUniv<C> id = dec.remove(0); 2217 int[] ri = id.ideal.normalPositionIndex2Vars(); 2218 if (ri == null || ri.length != 2) { 2219 rdec.add(id); 2220 } else { 2221 IdealWithUniv<C> I = id.ideal.normalPositionFor(ri[0], ri[1], id.others); 2222 List<IdealWithUniv<C>> rd = I.ideal.zeroDimDecompositionExtension(id.upolys, I.others); 2223 //System.out.println("r_rd = " + rd); 2224 dec.addAll(rd); 2225 } 2226 } 2227 return rdec; 2228 } 2229 2230 2231 /** 2232 * Zero dimensional ideal prime decompostition. See algorithm 2233 * mas.masring.DIPDEC0#DINTSS. 2234 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2235 * ideal(G_i) ) and each G_i is a prime ideal 2236 */ 2237 public List<IdealWithUniv<C>> zeroDimPrimeDecomposition() { 2238 List<IdealWithUniv<C>> pdec = zeroDimPrimeDecompositionFE(); 2239 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2240 if (pdec.size() == 1) { // already prime 2241 IdealWithUniv<C> Ip = pdec.get(0); 2242 int s = Ip.upolys.size() - getRing().nvar; // skip field ext univariate polys 2243 List<GenPolynomial<C>> upol = Ip.upolys.subList(s, Ip.upolys.size()); 2244 Ip = new IdealWithUniv<C>(this, upol); 2245 dec.add(Ip); 2246 return dec; 2247 } 2248 for (IdealWithUniv<C> Ip : pdec) { 2249 if (Ip.ideal.getRing().nvar == getRing().nvar) { // no field extension 2250 dec.add(Ip); 2251 } else { // remove field extension 2252 // add other generators for performance 2253 Ideal<C> Id = Ip.ideal; 2254 if (Ip.others != null) { 2255 //System.out.println("adding Ip.others = " + Ip.others); 2256 List<GenPolynomial<C>> pp = new ArrayList<GenPolynomial<C>>(); 2257 pp.addAll(Id.getList()); 2258 pp.addAll(Ip.others); 2259 Id = new Ideal<C>(Id.getRing(), pp); 2260 } 2261 Ideal<C> Is = Id.eliminate(getRing()); 2262 //System.out.println("Is = " + Is); 2263 int s = Ip.upolys.size() - getRing().nvar; // skip field ext univariate polys 2264 List<GenPolynomial<C>> upol = Ip.upolys.subList(s, Ip.upolys.size()); 2265 IdealWithUniv<C> Iu = new IdealWithUniv<C>(Is, upol); 2266 //,Ip.others); used above and must be ignored here 2267 dec.add(Iu); 2268 } 2269 } 2270 return dec; 2271 } 2272 2273 2274 /** 2275 * Zero dimensional ideal prime decompostition, with field extension. See 2276 * algorithm mas.masring.DIPDEC0#DINTSS. 2277 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2278 * ideal(G_i) ) and each G_i is a prime ideal with eventually 2279 * containing field extension variables 2280 */ 2281 public List<IdealWithUniv<C>> zeroDimPrimeDecompositionFE() { 2282 List<IdealWithUniv<C>> dec = zeroDimRootDecomposition(); 2283 if (this.isZERO()) { 2284 return dec; 2285 } 2286 if (this.isONE()) { 2287 return dec; 2288 } 2289 List<IdealWithUniv<C>> rdec = new ArrayList<IdealWithUniv<C>>(); 2290 while (dec.size() > 0) { 2291 IdealWithUniv<C> id = dec.remove(0); 2292 int[] ri = id.ideal.normalPositionIndexUnivars(); 2293 if (ri == null || ri.length != 2) { 2294 rdec.add(id); 2295 } else { 2296 IdealWithUniv<C> I = id.ideal.normalPositionFor(ri[0], ri[1], id.others); 2297 List<IdealWithUniv<C>> rd = I.ideal.zeroDimDecompositionExtension(id.upolys, I.others); 2298 //System.out.println("rd = " + rd); 2299 dec.addAll(rd); 2300 } 2301 } 2302 return rdec; 2303 } 2304 2305 2306 /** 2307 * Zero dimensional ideal associated primary ideal. See algorithm 2308 * mas.masring.DIPIDEAL#DIRLPI. 2309 * @param P prime ideal associated to this 2310 * @return primary ideal of this with respect to the associated pime ideal P 2311 */ 2312 public Ideal<C> primaryIdeal(Ideal<C> P) { 2313 Ideal<C> Qs = P; 2314 Ideal<C> Q; 2315 int e = 0; 2316 do { 2317 Q = Qs; 2318 e++; 2319 Qs = Q.product(P); 2320 } while (Qs.contains(this)); 2321 boolean t; 2322 Ideal<C> As; 2323 do { 2324 As = this.sum(Qs); 2325 t = As.contains(Q); 2326 if (!t) { 2327 Q = Qs; 2328 e++; 2329 Qs = Q.product(P); 2330 } 2331 } while (!t); 2332 logger.info("exponent = " + e); 2333 return As; 2334 } 2335 2336 2337 /** 2338 * Zero dimensional ideal primary decompostition. 2339 * @return list of primary components of primary ideals G_i (pairwise 2340 * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with 2341 * the associated primes 2342 */ 2343 public List<PrimaryComponent<C>> zeroDimPrimaryDecomposition() { 2344 List<IdealWithUniv<C>> pdec = zeroDimPrimeDecomposition(); 2345 if (logger.isInfoEnabled()) { 2346 logger.info("prim decomp = " + pdec); 2347 } 2348 return zeroDimPrimaryDecomposition(pdec); 2349 } 2350 2351 2352 /** 2353 * Zero dimensional ideal elimination to original ring. 2354 * @param pdec list of prime ideals G_i 2355 * @return intersection of pairwise co-prime prime ideals G_i in the ring of 2356 * this with ideal(this) = cap_i( ideal(G_i) ) 2357 */ 2358 public List<IdealWithUniv<C>> zeroDimElimination(List<IdealWithUniv<C>> pdec) { 2359 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2360 if (this.isZERO()) { 2361 return dec; 2362 } 2363 if (this.isONE()) { 2364 dec.add(pdec.get(0)); 2365 return dec; 2366 } 2367 List<IdealWithUniv<C>> qdec = new ArrayList<IdealWithUniv<C>>(); 2368 for (IdealWithUniv<C> Ip : pdec) { 2369 //System.out.println("Ip = " + Ip); 2370 List<GenPolynomial<C>> epol = new ArrayList<GenPolynomial<C>>(); 2371 epol.addAll(Ip.ideal.getList()); 2372 GenPolynomialRing<C> mfac = Ip.ideal.list.ring; 2373 int j = 0; 2374 // add univariate polynomials for performance 2375 for (GenPolynomial<C> p : Ip.upolys) { 2376 GenPolynomial<C> pm = p.extendUnivariate(mfac, j++); 2377 if (j != 1) { // skip double 2378 epol.add(pm); 2379 } 2380 } 2381 // add other generators for performance 2382 if (Ip.others != null) { 2383 epol.addAll(Ip.others); 2384 } 2385 Ideal<C> Ipp = new Ideal<C>(mfac, epol); 2386 // logger.info("eliminate_1 = " + Ipp); 2387 TermOrder to = null; 2388 if (mfac.tord.getEvord() != TermOrder.IGRLEX) { 2389 List<GenPolynomial<C>> epols = new ArrayList<GenPolynomial<C>>(); 2390 to = new TermOrder(TermOrder.IGRLEX); 2391 GenPolynomialRing<C> smfac = new GenPolynomialRing<C>(mfac.coFac, mfac.nvar, to, 2392 mfac.getVars()); 2393 for (GenPolynomial<C> p : epol) { 2394 GenPolynomial<C> pm = smfac.copy(p); 2395 epols.add(pm.monic()); 2396 } 2397 //epol = epols; 2398 Ipp = new Ideal<C>(smfac, epols); 2399 } 2400 epol = red.irreducibleSet(Ipp.getList()); 2401 Ipp = new Ideal<C>(Ipp.getRing(), epol); 2402 if (logger.isInfoEnabled()) { 2403 logger.info("eliminate = " + Ipp); 2404 } 2405 Ideal<C> Is = Ipp.eliminate(list.ring); 2406 //System.out.println("Is = " + Is); 2407 if (to != null && !Is.list.ring.equals(list.ring)) { 2408 List<GenPolynomial<C>> epols = new ArrayList<GenPolynomial<C>>(); 2409 for (GenPolynomial<C> p : Is.getList()) { 2410 GenPolynomial<C> pm = list.ring.copy(p); 2411 epols.add(pm); 2412 } 2413 Is = new Ideal<C>(list.ring, epols); 2414 //System.out.println("Is = " + Is); 2415 } 2416 int k = Ip.upolys.size() - list.ring.nvar; 2417 List<GenPolynomial<C>> up = new ArrayList<GenPolynomial<C>>(); 2418 for (int i = 0; i < list.ring.nvar; i++) { 2419 up.add(Ip.upolys.get(i + k)); 2420 } 2421 IdealWithUniv<C> Ie = new IdealWithUniv<C>(Is, up); 2422 qdec.add(Ie); 2423 } 2424 return qdec; 2425 } 2426 2427 2428 /** 2429 * Zero dimensional ideal primary decompostition. 2430 * @param pdec list of prime ideals G_i with no field extensions 2431 * @return list of primary components of primary ideals G_i (pairwise 2432 * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with 2433 * the associated primes 2434 */ 2435 public List<PrimaryComponent<C>> zeroDimPrimaryDecomposition(List<IdealWithUniv<C>> pdec) { 2436 List<PrimaryComponent<C>> dec = new ArrayList<PrimaryComponent<C>>(); 2437 if (this.isZERO()) { 2438 return dec; 2439 } 2440 if (this.isONE()) { 2441 PrimaryComponent<C> pc = new PrimaryComponent<C>(pdec.get(0).ideal, pdec.get(0)); 2442 dec.add(pc); 2443 return dec; 2444 } 2445 for (IdealWithUniv<C> Ip : pdec) { 2446 Ideal<C> Qs = this.primaryIdeal(Ip.ideal); 2447 PrimaryComponent<C> pc = new PrimaryComponent<C>(Qs, Ip); 2448 dec.add(pc); 2449 } 2450 return dec; 2451 } 2452 2453 2454 /** 2455 * Test for primary ideal decompostition. 2456 * @param L list of primary components G_i 2457 * @return true if ideal(this) == cap_i( ideal(G_i) ) 2458 */ 2459 public boolean isPrimaryDecomposition(List<PrimaryComponent<C>> L) { 2460 // test if this is contained in the intersection 2461 for (PrimaryComponent<C> I : L) { 2462 boolean t = I.primary.contains(this); 2463 if (!t) { 2464 System.out.println("not contained " + this + " in " + I); 2465 return false; 2466 } 2467 } 2468 Ideal<C> isec = null; 2469 for (PrimaryComponent<C> I : L) { 2470 if (isec == null) { 2471 isec = I.primary; 2472 } else { 2473 isec = isec.intersect(I.primary); 2474 } 2475 } 2476 return this.contains(isec); 2477 } 2478 2479 2480 /** 2481 * Ideal extension. 2482 * @param vars list of variables for a polynomial ring for extension 2483 * @return ideal G, with coefficients in QuotientRing(GenPolynomialRing 2484 * <C>(vars)) 2485 */ 2486 public IdealWithUniv<Quotient<C>> extension(String... vars) { 2487 GenPolynomialRing<C> fac = getRing(); 2488 GenPolynomialRing<C> efac = new GenPolynomialRing<C>(fac.coFac, vars.length, fac.tord, vars); 2489 IdealWithUniv<Quotient<C>> ext = extension(efac); 2490 return ext; 2491 } 2492 2493 2494 /** 2495 * Ideal extension. 2496 * @param efac polynomial ring for extension 2497 * @return ideal G, with coefficients in QuotientRing(efac) 2498 */ 2499 public IdealWithUniv<Quotient<C>> extension(GenPolynomialRing<C> efac) { 2500 QuotientRing<C> qfac = new QuotientRing<C>(efac); 2501 IdealWithUniv<Quotient<C>> ext = extension(qfac); 2502 return ext; 2503 } 2504 2505 2506 /** 2507 * Ideal extension. 2508 * @param qfac quotient polynomial ring for extension 2509 * @return ideal G, with coefficients in qfac 2510 */ 2511 public IdealWithUniv<Quotient<C>> extension(QuotientRing<C> qfac) { 2512 GenPolynomialRing<C> fac = getRing(); 2513 GenPolynomialRing<C> efac = qfac.ring; 2514 String[] rvars = GroebnerBasePartial.remainingVars(fac.getVars(), efac.getVars()); 2515 //System.out.println("rvars = " + Arrays.toString(rvars)); 2516 2517 GroebnerBasePartial<C> bbp = new GroebnerBasePartial<C>(); 2518 //wrong: OptimizedPolynomialList<C> pgb = bbp.partialGB(getList(),rvars); 2519 OptimizedPolynomialList<C> pgb = bbp.elimPartialGB(getList(), rvars, efac.getVars()); 2520 if (logger.isInfoEnabled()) { 2521 logger.info("rvars = " + Arrays.toString(rvars)); 2522 logger.info("partialGB = " + pgb); 2523 } 2524 2525 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(efac, rvars.length, 2526 fac.tord, rvars); 2527 List<GenPolynomial<C>> plist = pgb.list; 2528 List<GenPolynomial<GenPolynomial<C>>> rpgb = PolyUtil.<C> recursive(rfac, plist); 2529 //System.out.println("rfac = " + rfac); 2530 GenPolynomialRing<Quotient<C>> qpfac = new GenPolynomialRing<Quotient<C>>(qfac, rfac); 2531 List<GenPolynomial<Quotient<C>>> qpgb = PolyUfdUtil.<C> quotientFromIntegralCoefficients(qpfac, rpgb); 2532 //System.out.println("qpfac = " + qpfac); 2533 2534 // compute f 2535 GreatestCommonDivisor<C> ufd = GCDFactory.getImplementation(fac.coFac); 2536 GenPolynomial<C> f = null; // qfac.ring.getONE(); 2537 for (GenPolynomial<GenPolynomial<C>> p : rpgb) { 2538 if (f == null) { 2539 f = p.leadingBaseCoefficient(); 2540 } else { 2541 f = ufd.lcm(f, p.leadingBaseCoefficient()); 2542 } 2543 } 2544 //SquarefreeAbstract<C> sqf = SquarefreeFactory.getImplementation(fac.coFac); 2545 //not required: f = sqf.squarefreePart(f); 2546 GenPolynomial<GenPolynomial<C>> fp = rfac.getONE().multiply(f); 2547 GenPolynomial<Quotient<C>> fq = PolyUfdUtil.<C> quotientFromIntegralCoefficients(qpfac, fp); 2548 if (logger.isInfoEnabled()) { 2549 logger.info("extension f = " + f); 2550 logger.info("ext = " + qpgb); 2551 } 2552 List<GenPolynomial<Quotient<C>>> upols = new ArrayList<GenPolynomial<Quotient<C>>>(0); 2553 List<GenPolynomial<Quotient<C>>> opols = new ArrayList<GenPolynomial<Quotient<C>>>(1); 2554 opols.add(fq); 2555 2556 qpgb = PolyUtil.<Quotient<C>> monic(qpgb); 2557 Ideal<Quotient<C>> ext = new Ideal<Quotient<C>>(qpfac, qpgb); 2558 IdealWithUniv<Quotient<C>> extu = new IdealWithUniv<Quotient<C>>(ext, upols, opols); 2559 return extu; 2560 } 2561 2562 2563 /** 2564 * Ideal contraction and permutation. 2565 * @param eideal extension ideal of this. 2566 * @return contraction ideal of eideal in this polynomial ring 2567 */ 2568 public IdealWithUniv<C> permContraction(IdealWithUniv<Quotient<C>> eideal) { 2569 return Ideal.<C> permutation(getRing(), Ideal.<C> contraction(eideal)); 2570 } 2571 2572 2573 /** 2574 * Ideal contraction. 2575 * @param eid extension ideal of this. 2576 * @return contraction ideal of eid in distributed polynomial ring 2577 */ 2578 public static <C extends GcdRingElem<C>> IdealWithUniv<C> contraction(IdealWithUniv<Quotient<C>> eid) { 2579 Ideal<Quotient<C>> eideal = eid.ideal; 2580 List<GenPolynomial<Quotient<C>>> qgb = eideal.getList(); 2581 QuotientRing<C> qfac = (QuotientRing<C>) eideal.getRing().coFac; 2582 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(qfac.ring, 2583 eideal.getRing()); 2584 GenPolynomialRing<C> dfac = qfac.ring.extend(eideal.getRing().getVars()); 2585 TermOrder to = new TermOrder(qfac.ring.tord.getEvord()); 2586 dfac = new GenPolynomialRing<C>(dfac.coFac, dfac.nvar, to, dfac.getVars()); 2587 //System.out.println("qfac = " + qfac); 2588 //System.out.println("rfac = " + rfac); 2589 //System.out.println("dfac = " + dfac); 2590 // convert polynomials 2591 List<GenPolynomial<GenPolynomial<C>>> cgb = PolyUfdUtil.<C> integralFromQuotientCoefficients(rfac, 2592 qgb); 2593 List<GenPolynomial<C>> dgb = PolyUtil.<C> distribute(dfac, cgb); 2594 Ideal<C> cont = new Ideal<C>(dfac, dgb); 2595 // convert other polynomials 2596 List<GenPolynomial<C>> opols = new ArrayList<GenPolynomial<C>>(); 2597 if (eid.others != null && eid.others.size() > 0) { 2598 List<GenPolynomial<GenPolynomial<C>>> orpol = PolyUfdUtil 2599 .<C> integralFromQuotientCoefficients(rfac, eid.others); 2600 List<GenPolynomial<C>> opol = PolyUtil.<C> distribute(dfac, orpol); 2601 opols.addAll(opol); 2602 } 2603 // convert univariate polynomials 2604 List<GenPolynomial<C>> upols = new ArrayList<GenPolynomial<C>>(0); 2605 int i = 0; 2606 for (GenPolynomial<Quotient<C>> p : eid.upolys) { 2607 GenPolynomial<Quotient<C>> pm = p.extendUnivariate(eideal.getRing(), i++); 2608 //System.out.println("pm = " + pm + ", p = " + p); 2609 GenPolynomial<GenPolynomial<C>> urpol = PolyUfdUtil.<C> integralFromQuotientCoefficients(rfac, 2610 pm); 2611 GenPolynomial<C> upol = PolyUtil.<C> distribute(dfac, urpol); 2612 upols.add(upol); 2613 //System.out.println("upol = " + upol); 2614 } 2615 // compute f 2616 GreatestCommonDivisor<C> ufd = GCDFactory.getImplementation(qfac.ring.coFac); 2617 GenPolynomial<C> f = null; // qfac.ring.getONE(); 2618 for (GenPolynomial<GenPolynomial<C>> p : cgb) { 2619 if (f == null) { 2620 f = p.leadingBaseCoefficient(); 2621 } else { 2622 f = ufd.lcm(f, p.leadingBaseCoefficient()); 2623 } 2624 } 2625 GenPolynomial<GenPolynomial<C>> fp = rfac.getONE().multiply(f); 2626 f = PolyUtil.<C> distribute(dfac, fp); 2627 if (logger.isInfoEnabled()) { 2628 logger.info("contraction f = " + f); 2629 logger.info("cont = " + cont); 2630 } 2631 opols.add(f); 2632 if (f.isONE()) { 2633 IdealWithUniv<C> cf = new IdealWithUniv<C>(cont, upols, opols); 2634 return cf; 2635 } 2636 // compute ideal quotient by f 2637 Ideal<C> Q = cont.infiniteQuotientRab(f); 2638 IdealWithUniv<C> Qu = new IdealWithUniv<C>(Q, upols, opols); 2639 return Qu; 2640 } 2641 2642 2643 /** 2644 * Ideal permutation. 2645 * @param oring polynomial ring to which variables are back permuted. 2646 * @param Cont ideal to be permuted 2647 * @return permutation of cont in polynomial ring oring 2648 */ 2649 public static <C extends GcdRingElem<C>> IdealWithUniv<C> permutation(GenPolynomialRing<C> oring, 2650 IdealWithUniv<C> Cont) { 2651 Ideal<C> cont = Cont.ideal; 2652 GenPolynomialRing<C> dfac = cont.getRing(); 2653 // (back) permutation of variables 2654 String[] ovars = oring.getVars(); 2655 String[] dvars = dfac.getVars(); 2656 //System.out.println("ovars = " + Arrays.toString(ovars)); 2657 //System.out.println("dvars = " + Arrays.toString(dvars)); 2658 if (Arrays.deepEquals(ovars, dvars)) { // nothing to do 2659 return Cont; 2660 } 2661 List<Integer> perm = GroebnerBasePartial.getPermutation(dvars, ovars); 2662 //System.out.println("perm = " + perm); 2663 GenPolynomialRing<C> pfac = cont.getRing().permutation(perm); 2664 if (logger.isInfoEnabled()) { 2665 logger.info("pfac = " + pfac); 2666 } 2667 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, cont.getList()); 2668 //System.out.println("ppolys = " + ppolys); 2669 cont = new Ideal<C>(pfac, ppolys); 2670 if (logger.isDebugEnabled()) { 2671 logger.info("perm cont = " + cont); 2672 } 2673 List<GenPolynomial<C>> opolys = TermOrderOptimization.<C> permutation(perm, pfac, Cont.others); 2674 //System.out.println("opolys = " + opolys); 2675 List<GenPolynomial<C>> upolys = TermOrderOptimization.<C> permutation(perm, pfac, Cont.upolys); 2676 //System.out.println("opolys = " + opolys); 2677 IdealWithUniv<C> Cu = new IdealWithUniv<C>(cont, upolys, opolys); 2678 return Cu; 2679 } 2680 2681 2682 /** 2683 * Ideal radical. 2684 * @return the radical ideal of this 2685 */ 2686 public Ideal<C> radical() { 2687 List<IdealWithUniv<C>> rdec = radicalDecomposition(); 2688 List<Ideal<C>> dec = new ArrayList<Ideal<C>>(rdec.size()); 2689 for (IdealWithUniv<C> ru : rdec) { 2690 dec.add(ru.ideal); 2691 } 2692 Ideal<C> R = intersect(dec); 2693 return R; 2694 } 2695 2696 2697 /** 2698 * Ideal radical decompostition. 2699 * @return intersection of ideals G_i with radical(this) eq cap_i( 2700 * ideal(G_i) ) and each G_i is a radical ideal and the G_i are 2701 * pairwise co-prime 2702 */ 2703 public List<IdealWithUniv<C>> radicalDecomposition() { 2704 // check dimension 2705 int z = commonZeroTest(); 2706 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2707 List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 2708 // dimension -1 2709 if (z < 0) { 2710 IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 2711 dec.add(id); // see GB book 2712 return dec; 2713 } 2714 // dimension 0 2715 if (z == 0) { 2716 dec = zeroDimRadicalDecomposition(); 2717 return dec; 2718 } 2719 // dimension > 0 2720 if (this.isZERO()) { 2721 return dec; 2722 } 2723 if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { 2724 // must not be the case at this point 2725 logger.warn("must use prime decomposition for char p and infinite coefficient rings, found " 2726 + list.ring.coFac.toScript()); 2727 return primeDecomposition(); 2728 } 2729 Dimension dim = dimension(); 2730 if (logger.isInfoEnabled()) { 2731 logger.info("dimension = " + dim); 2732 } 2733 2734 // a short maximal independent set with small variables 2735 Set<Set<Integer>> M = dim.M; 2736 Set<Integer> min = null; 2737 for (Set<Integer> m : M) { 2738 if (min == null) { 2739 min = m; 2740 continue; 2741 } 2742 if (m.size() < min.size()) { 2743 min = m; 2744 } 2745 } 2746 int ms = min.size(); 2747 Integer[] ia = new Integer[0]; 2748 int mx = min.toArray(ia)[ms - 1]; 2749 for (Set<Integer> m : M) { 2750 if (m.size() == ms) { 2751 int mxx = m.toArray(ia)[ms - 1]; 2752 if (mxx < mx) { 2753 min = m; 2754 mx = mxx; 2755 } 2756 } 2757 } 2758 //System.out.println("min = " + min); 2759 String[] mvars = new String[min.size()]; 2760 int j = 0; 2761 for (Integer i : min) { 2762 mvars[j++] = dim.v[i]; 2763 } 2764 if (logger.isInfoEnabled()) { 2765 logger.info("extension for variables = " + Arrays.toString(mvars) + ", indexes = " + min); 2766 } 2767 // reduce to dimension zero 2768 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 2769 if (logger.isInfoEnabled()) { 2770 logger.info("extension = " + Ext); 2771 } 2772 2773 List<IdealWithUniv<Quotient<C>>> edec = Ext.ideal.zeroDimRadicalDecomposition(); 2774 if (logger.isInfoEnabled()) { 2775 logger.info("0-dim radical decomp = " + edec); 2776 } 2777 // remove field extensions are not required 2778 // reconstruct dimension 2779 for (IdealWithUniv<Quotient<C>> ep : edec) { 2780 IdealWithUniv<C> cont = permContraction(ep); 2781 //System.out.println("cont = " + cont); 2782 dec.add(cont); 2783 } 2784 IdealWithUniv<C> extcont = permContraction(Ext); 2785 //System.out.println("extcont = " + extcont); 2786 2787 // get f 2788 List<GenPolynomial<C>> ql = extcont.others; 2789 if (ql.size() == 0) { // should not happen 2790 return dec; 2791 } 2792 GenPolynomial<C> fx = ql.get(0); 2793 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 2794 if (fx.isONE()) { 2795 return dec; 2796 } 2797 Ideal<C> T = sum(fx); 2798 //System.out.println("T.rec = " + T.getList()); 2799 if (T.isONE()) { 2800 logger.info("1 in ideal for " + fx); 2801 return dec; 2802 } 2803 if (logger.isInfoEnabled()) { 2804 logger.info("radical decomp ext-cont fx = " + fx); 2805 logger.info("recursion radical decomp T = " + T); 2806 } 2807 // recursion: 2808 List<IdealWithUniv<C>> Tdec = T.radicalDecomposition(); 2809 if (logger.isInfoEnabled()) { 2810 logger.info("recursion radical decomp = " + Tdec); 2811 } 2812 dec.addAll(Tdec); 2813 return dec; 2814 } 2815 2816 2817 /** 2818 * Ideal irreducible decompostition. 2819 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2820 * ideal(G_i) ) and each G_i is an ideal with irreducible univariate 2821 * polynomials (after extension to a zero dimensional ideal) and the 2822 * G_i are pairwise co-prime 2823 */ 2824 public List<IdealWithUniv<C>> decomposition() { 2825 // check dimension 2826 int z = commonZeroTest(); 2827 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2828 // dimension -1 2829 if (z < 0) { 2830 //List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 2831 //IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 2832 //dec.add(id); see GB book 2833 return dec; 2834 } 2835 // dimension 0 2836 if (z == 0) { 2837 dec = zeroDimDecomposition(); 2838 return dec; 2839 } 2840 // dimension > 0 2841 if (this.isZERO()) { 2842 return dec; 2843 } 2844 Dimension dim = dimension(); 2845 if (logger.isInfoEnabled()) { 2846 logger.info("dimension = " + dim); 2847 } 2848 2849 // shortest maximal independent set 2850 Set<Set<Integer>> M = dim.M; 2851 Set<Integer> min = null; 2852 for (Set<Integer> m : M) { 2853 if (min == null) { 2854 min = m; 2855 continue; 2856 } 2857 if (m.size() < min.size()) { 2858 min = m; 2859 } 2860 } 2861 //System.out.println("min = " + min); 2862 String[] mvars = new String[min.size()]; 2863 int j = 0; 2864 for (Integer i : min) { 2865 mvars[j++] = dim.v[i]; 2866 } 2867 if (logger.isInfoEnabled()) { 2868 logger.info("extension for variables = " + Arrays.toString(mvars)); 2869 } 2870 // reduce to dimension zero 2871 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 2872 if (logger.isInfoEnabled()) { 2873 logger.info("extension = " + Ext); 2874 } 2875 2876 List<IdealWithUniv<Quotient<C>>> edec = Ext.ideal.zeroDimDecomposition(); 2877 if (logger.isInfoEnabled()) { 2878 logger.info("0-dim irred decomp = " + edec); 2879 } 2880 // remove field extensions are not required 2881 // reconstruct dimension 2882 for (IdealWithUniv<Quotient<C>> ep : edec) { 2883 IdealWithUniv<C> cont = permContraction(ep); 2884 //System.out.println("cont = " + cont); 2885 dec.add(cont); 2886 } 2887 IdealWithUniv<C> extcont = permContraction(Ext); 2888 //System.out.println("extcont = " + extcont); 2889 2890 // get f 2891 List<GenPolynomial<C>> ql = extcont.others; 2892 if (ql.size() == 0) { // should not happen 2893 return dec; 2894 } 2895 GenPolynomial<C> fx = ql.get(0); 2896 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 2897 if (fx.isONE()) { 2898 return dec; 2899 } 2900 Ideal<C> T = sum(fx); 2901 //System.out.println("T.rec = " + T.getList()); 2902 if (T.isONE()) { 2903 logger.info("1 in ideal for " + fx); 2904 return dec; 2905 } 2906 if (logger.isInfoEnabled()) { 2907 logger.info("irred decomp ext-cont fx = " + fx); 2908 logger.info("recursion irred decomp T = " + T); 2909 } 2910 // recursion: 2911 List<IdealWithUniv<C>> Tdec = T.decomposition(); 2912 if (logger.isInfoEnabled()) { 2913 logger.info("recursion irred decomposition = " + Tdec); 2914 } 2915 dec.addAll(Tdec); 2916 return dec; 2917 } 2918 2919 2920 /** 2921 * Ideal prime decompostition. 2922 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2923 * ideal(G_i) ) and each G_i is a prime ideal and the G_i are 2924 * pairwise co-prime 2925 */ 2926 public List<IdealWithUniv<C>> primeDecomposition() { 2927 // check dimension 2928 int z = commonZeroTest(); 2929 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2930 // dimension -1 2931 if (z < 0) { 2932 //List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 2933 //IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 2934 //dec.add(id); see GB book 2935 return dec; 2936 } 2937 // dimension 0 2938 if (z == 0) { 2939 dec = zeroDimPrimeDecomposition(); 2940 return dec; 2941 } 2942 // dimension > 0 2943 if (this.isZERO()) { 2944 return dec; 2945 } 2946 Dimension dim = dimension(); 2947 if (logger.isInfoEnabled()) { 2948 logger.info("dimension = " + dim); 2949 } 2950 2951 // shortest maximal independent set 2952 Set<Set<Integer>> M = dim.M; 2953 Set<Integer> min = null; 2954 for (Set<Integer> m : M) { 2955 if (min == null) { 2956 min = m; 2957 continue; 2958 } 2959 if (m.size() < min.size()) { 2960 min = m; 2961 } 2962 } 2963 //System.out.println("min = " + min); 2964 String[] mvars = new String[min.size()]; 2965 int j = 0; 2966 for (Integer i : min) { 2967 mvars[j++] = dim.v[i]; 2968 } 2969 if (logger.isInfoEnabled()) { 2970 logger.info("extension for variables = " + Arrays.toString(mvars)); 2971 } 2972 // reduce to dimension zero 2973 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 2974 if (logger.isInfoEnabled()) { 2975 logger.info("extension = " + Ext); 2976 } 2977 List<IdealWithUniv<Quotient<C>>> edec = Ext.ideal.zeroDimPrimeDecomposition(); 2978 if (logger.isInfoEnabled()) { 2979 logger.info("0-dim prime decomp = " + edec); 2980 } 2981 // remove field extensions, already done 2982 // reconstruct dimension 2983 for (IdealWithUniv<Quotient<C>> ep : edec) { 2984 IdealWithUniv<C> cont = permContraction(ep); 2985 //System.out.println("cont = " + cont); 2986 dec.add(cont); 2987 } 2988 // get f 2989 IdealWithUniv<C> extcont = permContraction(Ext); 2990 //System.out.println("extcont = " + extcont); 2991 List<GenPolynomial<C>> ql = extcont.others; 2992 if (ql.size() == 0) { // should not happen 2993 return dec; 2994 } 2995 GenPolynomial<C> fx = ql.get(0); 2996 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 2997 if (fx.isONE()) { 2998 return dec; 2999 } 3000 // compute exponent not required 3001 Ideal<C> T = sum(fx); 3002 //System.out.println("T.rec = " + T.getList()); 3003 if (T.isONE()) { 3004 logger.info("1 in ideal for " + fx); 3005 return dec; 3006 } 3007 if (logger.isInfoEnabled()) { 3008 logger.info("prime decomp ext-cont fx = " + fx); 3009 logger.info("recursion prime decomp T = " + T); 3010 } 3011 // recursion: 3012 List<IdealWithUniv<C>> Tdec = T.primeDecomposition(); 3013 if (logger.isInfoEnabled()) { 3014 logger.info("recursion prime decomp = " + Tdec); 3015 } 3016 dec.addAll(Tdec); 3017 return dec; 3018 } 3019 3020 3021 /** 3022 * Test for ideal decompostition. 3023 * @param L intersection of ideals G_i with ideal(G) eq cap_i(ideal(G_i) ) 3024 * @return true if L is a decomposition of this, else false 3025 */ 3026 public boolean isDecomposition(List<IdealWithUniv<C>> L) { 3027 if (L == null || L.size() == 0) { 3028 if (this.isZERO()) { 3029 return true; 3030 } 3031 return false; 3032 } 3033 GenPolynomialRing<C> ofac = list.ring; 3034 int r = ofac.nvar; 3035 int rp = L.get(0).ideal.list.ring.nvar; 3036 int d = rp - r; 3037 //System.out.println("d = " + d); 3038 Ideal<C> Id = this; 3039 if (d > 0) { // add lower variables 3040 GenPolynomialRing<C> nfac = ofac.extendLower(d); 3041 //System.out.println("nfac = " + nfac); 3042 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size()); 3043 for (GenPolynomial<C> p : getList()) { 3044 //System.out.println("p = " + p); 3045 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 3046 //System.out.println("q = " + q); 3047 elist.add(q); 3048 } 3049 Id = new Ideal<C>(nfac, elist, isGB, isTopt); 3050 } 3051 3052 // test if this is contained in the intersection 3053 for (IdealWithUniv<C> I : L) { 3054 boolean t = I.ideal.contains(Id); 3055 if (!t) { 3056 System.out.println("not contained " + this + " in " + I.ideal); 3057 return false; 3058 } 3059 } 3060 // // test if all univariate polynomials are contained in the respective ideal 3061 // for (IdealWithUniv<C> I : L) { 3062 // GenPolynomialRing<C> mfac = I.ideal.list.ring; 3063 // int i = 0; 3064 // for (GenPolynomial<C> p : I.upolys) { 3065 // GenPolynomial<C> pm = p.extendUnivariate(mfac, i++); 3066 // //System.out.println("pm = " + pm + ", p = " + p); 3067 // boolean t = I.ideal.contains(pm); 3068 // if (!t) { 3069 // System.out.println("not contained " + pm + " in " + I.ideal); 3070 // return false; 3071 // } 3072 // } 3073 // } 3074 return true; 3075 } 3076 3077 3078 /** 3079 * Ideal primary decompostition. 3080 * @return list of primary components of primary ideals G_i (pairwise 3081 * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with 3082 * the associated primes 3083 */ 3084 public List<PrimaryComponent<C>> primaryDecomposition() { 3085 // check dimension 3086 int z = commonZeroTest(); 3087 List<PrimaryComponent<C>> dec = new ArrayList<PrimaryComponent<C>>(); 3088 // dimension -1 3089 if (z < 0) { 3090 //List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 3091 //IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 3092 //PrimaryComponent<C> pc = new PrimaryComponent<C>(this, id); 3093 //dec.add(pc); see GB book 3094 return dec; 3095 } 3096 // dimension 0 3097 if (z == 0) { 3098 dec = zeroDimPrimaryDecomposition(); 3099 return dec; 3100 } 3101 // dimension > 0 3102 if (this.isZERO()) { 3103 return dec; 3104 } 3105 Dimension dim = dimension(); 3106 if (logger.isInfoEnabled()) { 3107 logger.info("dimension = " + dim); 3108 } 3109 3110 // shortest maximal independent set 3111 Set<Set<Integer>> M = dim.M; 3112 Set<Integer> min = null; 3113 for (Set<Integer> m : M) { 3114 if (min == null) { 3115 min = m; 3116 continue; 3117 } 3118 if (m.size() < min.size()) { 3119 min = m; 3120 } 3121 } 3122 //System.out.println("min = " + min); 3123 String[] mvars = new String[min.size()]; 3124 int j = 0; 3125 for (Integer i : min) { 3126 mvars[j++] = dim.v[i]; 3127 } 3128 if (logger.isInfoEnabled()) { 3129 logger.info("extension for variables = " + Arrays.toString(mvars)); 3130 } 3131 // reduce to dimension zero 3132 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 3133 if (logger.isInfoEnabled()) { 3134 logger.info("extension = " + Ext); 3135 } 3136 3137 List<PrimaryComponent<Quotient<C>>> edec = Ext.ideal.zeroDimPrimaryDecomposition(); 3138 if (logger.isInfoEnabled()) { 3139 logger.info("0-dim primary decomp = " + edec); 3140 } 3141 // remove field extensions, already done 3142 // reconstruct dimension 3143 List<GenPolynomial<Quotient<C>>> upq = new ArrayList<GenPolynomial<Quotient<C>>>(); 3144 for (PrimaryComponent<Quotient<C>> ep : edec) { 3145 IdealWithUniv<Quotient<C>> epu = new IdealWithUniv<Quotient<C>>(ep.primary, upq); 3146 IdealWithUniv<C> contq = permContraction(epu); 3147 IdealWithUniv<C> contp = permContraction(ep.prime); 3148 PrimaryComponent<C> pc = new PrimaryComponent<C>(contq.ideal, contp); 3149 //System.out.println("pc = " + pc); 3150 dec.add(pc); 3151 } 3152 3153 // get f 3154 IdealWithUniv<C> extcont = permContraction(Ext); 3155 if (debug) { 3156 logger.info("cont(Ext) = " + extcont); 3157 } 3158 List<GenPolynomial<C>> ql = extcont.others; 3159 if (ql.size() == 0) { // should not happen 3160 return dec; 3161 } 3162 GenPolynomial<C> fx = ql.get(0); 3163 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 3164 if (fx.isONE()) { 3165 return dec; 3166 } 3167 // compute exponent 3168 int s = this.infiniteQuotientExponent(fx, extcont.ideal); 3169 if (s == 0) { 3170 logger.info("exponent is 0 "); 3171 return dec; 3172 } 3173 if (s > 1) { 3174 fx = fx.power(s); 3175 } 3176 if (debug) { 3177 logger.info("exponent fx = " + s + ", fx^s = " + fx); 3178 } 3179 3180 Ideal<C> T = sum(fx); 3181 //System.out.println("T.rec = " + T.getList()); 3182 if (T.isONE()) { 3183 logger.info("1 in ideal for " + fx); 3184 return dec; 3185 } 3186 if (logger.isInfoEnabled()) { 3187 logger.info("primmary decomp ext-cont fx = " + fx); 3188 logger.info("recursion primary decomp T = " + T); 3189 } 3190 // recursion: 3191 List<PrimaryComponent<C>> Tdec = T.primaryDecomposition(); 3192 if (logger.isInfoEnabled()) { 3193 logger.info("recursion primary decomp = " + Tdec); 3194 } 3195 dec.addAll(Tdec); 3196 return dec; 3197 } 3198 3199}