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