001/* 002 * $Id$ 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.LogManager; 018import org.apache.logging.log4j.Logger; 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 logger.debug("elimination GB = {}", Pl); 774 Ideal<C> I = new Ideal<C>(Pl, true); 775 return I; 776 } 777 778 779 /** 780 * Quotient. Generators for the ideal quotient. 781 * @param h polynomial 782 * @return ideal(this : h), a Groebner base 783 */ 784 public Ideal<C> quotient(GenPolynomial<C> h) { 785 if (h == null) { // == (0) 786 return this; 787 } 788 if (h.isZERO()) { 789 return this; 790 } 791 if (this.isZERO()) { 792 return this; 793 } 794 List<GenPolynomial<C>> H; 795 H = new ArrayList<GenPolynomial<C>>(1); 796 H.add(h); 797 Ideal<C> Hi = new Ideal<C>(getRing(), H, true); 798 799 Ideal<C> I = this.intersect(Hi); 800 801 List<GenPolynomial<C>> Q; 802 Q = new ArrayList<GenPolynomial<C>>(I.getList().size()); 803 for (GenPolynomial<C> q : I.getList()) { 804 q = q.divide(h); // remainder == 0 805 Q.add(q); 806 } 807 return new Ideal<C>(getRing(), Q, true /*false?*/); 808 } 809 810 811 /** 812 * Quotient. Generators for the ideal quotient. 813 * @param H ideal 814 * @return ideal(this : H), a Groebner base 815 */ 816 public Ideal<C> quotient(Ideal<C> H) { 817 if (H == null) { // == (0) 818 return this; 819 } 820 if (H.isZERO()) { 821 return this; 822 } 823 if (this.isZERO()) { 824 return this; 825 } 826 Ideal<C> Q = null; 827 for (GenPolynomial<C> h : H.getList()) { 828 Ideal<C> Hi = this.quotient(h); 829 if (Q == null) { 830 Q = Hi; 831 } else { 832 Q = Q.intersect(Hi); 833 } 834 } 835 return Q; 836 } 837 838 839 /** 840 * Infinite quotient. Generators for the infinite ideal quotient. 841 * @param h polynomial 842 * @return ideal(this : h<sup>s</sup>), a Groebner base 843 */ 844 public Ideal<C> infiniteQuotientRab(GenPolynomial<C> h) { 845 if (h == null || h.isZERO()) { // == (0) 846 return getONE(); 847 } 848 if (h.isONE()) { 849 return this; 850 } 851 if (this.isZERO()) { 852 return this; 853 } 854 Ideal<C> I = this.GB(); // should be already 855 List<GenPolynomial<C>> a = I.getList(); 856 List<GenPolynomial<C>> c; 857 c = new ArrayList<GenPolynomial<C>>(a.size() + 1); 858 859 GenPolynomialRing<C> tfac = getRing().extend(1); 860 // term order is also adjusted 861 for (GenPolynomial<C> p : a) { 862 p = p.extend(tfac, 0, 0L); // p 863 c.add(p); 864 } 865 GenPolynomial<C> q = h.extend(tfac, 0, 1L); 866 GenPolynomial<C> r = tfac.getONE(); // h.extend( tfac, 0, 0L ); 867 GenPolynomial<C> hs = q.subtract(r); // 1 - t*h // (1-t)*h 868 c.add(hs); 869 logger.warn("infiniteQuotientRab computing GB "); 870 List<GenPolynomial<C>> g = bb.GB(c); 871 if (debug) { 872 logger.info("infiniteQuotientRab = {}, c = {}", tfac, c); 873 logger.info("infiniteQuotientRab GB = {}", g); 874 } 875 Ideal<C> E = new Ideal<C>(tfac, g, true); 876 Ideal<C> Is = E.intersect(getRing()); 877 return Is; 878 } 879 880 881 /** 882 * Infinite quotient exponent. 883 * @param h polynomial 884 * @param Q quotient this : h^\infinity 885 * @return s with Q = this : h<sup>s</sup> 886 */ 887 public int infiniteQuotientExponent(GenPolynomial<C> h, Ideal<C> Q) { 888 int s = 0; 889 if (h == null) { // == 0 890 return s; 891 } 892 if (h.isZERO() || h.isONE()) { 893 return s; 894 } 895 if (this.isZERO() || this.isONE()) { 896 return s; 897 } 898 //see below: if (this.contains(Q)) { 899 // return s; 900 //} 901 GenPolynomial<C> p = getRing().getONE(); 902 for (GenPolynomial<C> q : Q.getList()) { 903 if (this.contains(q)) { 904 continue; 905 } 906 //System.out.println("q = " + q + ", p = " + p + ", s = " + s); 907 GenPolynomial<C> qp = q.multiply(p); 908 while (!this.contains(qp)) { 909 p = p.multiply(h); 910 s++; 911 qp = q.multiply(p); 912 } 913 } 914 return s; 915 } 916 917 918 /** 919 * Infinite quotient. Generators for the infinite ideal quotient. 920 * @param h polynomial 921 * @return ideal(this : h<sup>s</sup>), a Groebner base 922 */ 923 public Ideal<C> infiniteQuotient(GenPolynomial<C> h) { 924 if (h == null) { // == (0) 925 return this; 926 } 927 if (h.isZERO()) { 928 return this; 929 } 930 if (this.isZERO()) { 931 return this; 932 } 933 int s = 0; 934 Ideal<C> I = this.GB(); // should be already 935 GenPolynomial<C> hs = h; 936 Ideal<C> Is = I; 937 938 boolean eq = false; 939 while (!eq) { 940 Is = I.quotient(hs); 941 Is = Is.GB(); // should be already 942 logger.info("infiniteQuotient s = {}", s); 943 eq = Is.contains(I); // I.contains(Is) always 944 if (!eq) { 945 I = Is; 946 s++; 947 // hs = hs.multiply( h ); 948 } 949 } 950 return Is; 951 } 952 953 954 /** 955 * Radical membership test. 956 * @param h polynomial 957 * @return true if h is contained in the radical of ideal(this), else false. 958 */ 959 public boolean isRadicalMember(GenPolynomial<C> h) { 960 if (h == null) { // == (0) 961 return true; 962 } 963 if (h.isZERO()) { 964 return true; 965 } 966 if (this.isZERO()) { 967 return true; 968 } 969 Ideal<C> x = infiniteQuotientRab(h); 970 if (debug) { 971 logger.debug("infiniteQuotientRab = {}", x); 972 } 973 return x.isONE(); 974 } 975 976 977 /** 978 * Infinite quotient. Generators for the infinite ideal quotient. 979 * @param h polynomial 980 * @return ideal(this : h<sup>s</sup>), a Groebner base 981 */ 982 public Ideal<C> infiniteQuotientOld(GenPolynomial<C> h) { 983 if (h == null) { // == (0) 984 return this; 985 } 986 if (h.isZERO()) { 987 return this; 988 } 989 if (this.isZERO()) { 990 return this; 991 } 992 int s = 0; 993 Ideal<C> I = this.GB(); // should be already 994 GenPolynomial<C> hs = h; 995 996 boolean eq = false; 997 while (!eq) { 998 Ideal<C> Is = I.quotient(hs); 999 Is = Is.GB(); // should be already 1000 logger.debug("infiniteQuotient s = {}", s); 1001 eq = Is.contains(I); // I.contains(Is) always 1002 if (!eq) { 1003 I = Is; 1004 s++; 1005 hs = hs.multiply(h); 1006 } 1007 } 1008 return I; 1009 } 1010 1011 1012 /** 1013 * Infinite Quotient. Generators for the ideal infinite quotient. 1014 * @param H ideal 1015 * @return ideal(this : H<sup>s</sup>), a Groebner base 1016 */ 1017 public Ideal<C> infiniteQuotient(Ideal<C> H) { 1018 if (H == null) { // == (0) 1019 return this; 1020 } 1021 if (H.isZERO()) { 1022 return this; 1023 } 1024 if (this.isZERO()) { 1025 return this; 1026 } 1027 Ideal<C> Q = null; 1028 for (GenPolynomial<C> h : H.getList()) { 1029 Ideal<C> Hi = this.infiniteQuotient(h); 1030 if (Q == null) { 1031 Q = Hi; 1032 } else { 1033 Q = Q.intersect(Hi); 1034 } 1035 } 1036 return Q; 1037 } 1038 1039 1040 /** 1041 * Infinite Quotient. Generators for the ideal infinite quotient. 1042 * @param H ideal 1043 * @return ideal(this : H<sup>s</sup>), a Groebner base 1044 */ 1045 public Ideal<C> infiniteQuotientRab(Ideal<C> H) { 1046 if (H == null) { // == (0) 1047 return this; 1048 } 1049 if (H.isZERO()) { 1050 return this; 1051 } 1052 if (this.isZERO()) { 1053 return this; 1054 } 1055 Ideal<C> Q = null; 1056 for (GenPolynomial<C> h : H.getList()) { 1057 Ideal<C> Hi = this.infiniteQuotientRab(h); 1058 if (Q == null) { 1059 Q = Hi; 1060 } else { 1061 Q = Q.intersect(Hi); 1062 } 1063 } 1064 return Q; 1065 } 1066 1067 1068 /** 1069 * Power. Generators for the power of this ideal. Note: if this ideal is a 1070 * Groebner base, a Groebner base is returned. 1071 * @param d integer 1072 * @return ideal(this^d) 1073 */ 1074 public Ideal<C> power(int d) { 1075 if (d <= 0) { 1076 return getONE(); 1077 } 1078 if (this.isZERO() || this.isONE()) { 1079 return this; 1080 } 1081 Ideal<C> c = this; 1082 for (int i = 1; i < d; i++) { 1083 c = c.product(this); 1084 } 1085 return c; 1086 } 1087 1088 1089 /** 1090 * Normalform for element. 1091 * @param h polynomial 1092 * @return normalform of h with respect to this 1093 */ 1094 public GenPolynomial<C> normalform(GenPolynomial<C> h) { 1095 if (h == null) { 1096 return h; 1097 } 1098 if (h.isZERO()) { 1099 return h; 1100 } 1101 if (this.isZERO()) { 1102 return h; 1103 } 1104 GenPolynomial<C> r; 1105 r = red.normalform(list.list, h); 1106 return r; 1107 } 1108 1109 1110 /** 1111 * Normalform for list of elements. 1112 * @param L polynomial list 1113 * @return list of normalforms of the elements of L with respect to this 1114 */ 1115 public List<GenPolynomial<C>> normalform(List<GenPolynomial<C>> L) { 1116 if (L == null) { 1117 return L; 1118 } 1119 if (L.size() == 0) { 1120 return L; 1121 } 1122 if (this.isZERO()) { 1123 return L; 1124 } 1125 List<GenPolynomial<C>> M = new ArrayList<GenPolynomial<C>>(L.size()); 1126 for (GenPolynomial<C> h : L) { 1127 GenPolynomial<C> r = normalform(h); 1128 if (r != null && !r.isZERO()) { 1129 M.add(r); 1130 } 1131 } 1132 return M; 1133 } 1134 1135 1136 /** 1137 * Annihilator for element modulo this ideal. 1138 * @param h polynomial 1139 * @return annihilator of h with respect to this 1140 */ 1141 public Ideal<C> annihilator(GenPolynomial<C> h) { 1142 if (h == null || h.isZERO()) { 1143 return getZERO(); 1144 } 1145 if (this.isZERO()) { 1146 return this; 1147 } 1148 doGB(); 1149 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(1 + getList().size()); 1150 F.add(h); 1151 F.addAll(getList()); 1152 //System.out.println("F = " + F); 1153 SyzygyAbstract<C> syz = new SyzygySeq<C>(getRing().coFac); 1154 List<List<GenPolynomial<C>>> S = syz.zeroRelationsArbitrary(F); 1155 //System.out.println("S = " + S); 1156 List<GenPolynomial<C>> gen = new ArrayList<GenPolynomial<C>>(S.size()); 1157 for (List<GenPolynomial<C>> rel : S) { 1158 if (rel == null || rel.isEmpty()) { 1159 continue; 1160 } 1161 GenPolynomial<C> p = rel.get(0); 1162 if (p == null || p.isZERO()) { 1163 continue; 1164 } 1165 gen.add(p); 1166 } 1167 Ideal<C> ann = new Ideal<C>(getRing(), gen); 1168 //System.out.println("ann = " + ann); 1169 return ann; 1170 } 1171 1172 1173 /** 1174 * Test for annihilator of element modulo this ideal. 1175 * @param h polynomial 1176 * @param A ideal 1177 * @return true, if A is the annihilator of h with respect to this 1178 */ 1179 public boolean isAnnihilator(GenPolynomial<C> h, Ideal<C> A) { 1180 Ideal<C> B = A.product(h); 1181 return contains(B); 1182 } 1183 1184 1185 /** 1186 * Annihilator for ideal modulo this ideal. 1187 * @param H ideal 1188 * @return annihilator of H with respect to this 1189 */ 1190 public Ideal<C> annihilator(Ideal<C> H) { 1191 if (H == null || H.isZERO()) { 1192 return getZERO(); 1193 } 1194 if (this.isZERO()) { 1195 return this; 1196 } 1197 Ideal<C> ann = null; 1198 for (GenPolynomial<C> h : H.getList()) { 1199 Ideal<C> Hi = this.annihilator(h); 1200 if (ann == null) { 1201 ann = Hi; 1202 } else { 1203 ann = ann.intersect(Hi); 1204 } 1205 } 1206 return ann; 1207 } 1208 1209 1210 /** 1211 * Test for annihilator of ideal modulo this ideal. 1212 * @param H ideal 1213 * @param A ideal 1214 * @return true, if A is the annihilator of H with respect to this 1215 */ 1216 public boolean isAnnihilator(Ideal<C> H, Ideal<C> A) { 1217 Ideal<C> B = A.product(H); 1218 return contains(B); 1219 } 1220 1221 1222 /** 1223 * Inverse for element modulo this ideal. 1224 * @param h polynomial 1225 * @return inverse of h with respect to this, if defined 1226 */ 1227 public GenPolynomial<C> inverse(GenPolynomial<C> h) { 1228 if (h == null || h.isZERO()) { 1229 throw new NotInvertibleException("zero not invertible"); 1230 } 1231 if (this.isZERO()) { 1232 throw new NotInvertibleException("zero ideal"); 1233 } 1234 if (h.isUnit()) { 1235 return h.inverse(); 1236 } 1237 doGB(); 1238 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(1 + list.list.size()); 1239 F.add(h); 1240 F.addAll(list.list); 1241 //System.out.println("F = " + F); 1242 ExtendedGB<C> x = bb.extGB(F); 1243 List<GenPolynomial<C>> G = x.G; 1244 //System.out.println("G = " + G); 1245 GenPolynomial<C> one = null; 1246 int i = -1; 1247 for (GenPolynomial<C> p : G) { 1248 i++; 1249 if (p == null) { 1250 continue; 1251 } 1252 if (p.isUnit()) { 1253 one = p; 1254 break; 1255 } 1256 } 1257 if (one == null) { 1258 throw new NotInvertibleException(" h = " + h); 1259 } 1260 List<GenPolynomial<C>> row = x.G2F.get(i); // != -1 1261 GenPolynomial<C> g = row.get(0); 1262 if (g == null || g.isZERO()) { 1263 throw new NotInvertibleException(" h = " + h); 1264 } 1265 // adjust g to get g*h == 1 1266 GenPolynomial<C> f = g.multiply(h); 1267 GenPolynomial<C> k = red.normalform(list.list, f); 1268 if (!k.isONE()) { 1269 C lbc = k.leadingBaseCoefficient(); 1270 lbc = lbc.inverse(); 1271 g = g.multiply(lbc); 1272 } 1273 if (debug) { 1274 //logger.info("inv G = {}", G); 1275 //logger.info("inv G2F = {}", x.G2F); 1276 //logger.info("inv row {} = {}", i, row); 1277 //logger.info("inv h = {}", h); 1278 //logger.info("inv g = {}", g); 1279 //logger.info("inv f = {}", f); 1280 f = g.multiply(h); 1281 k = red.normalform(list.list, f); 1282 logger.debug("inv k = {}", k); 1283 if (!k.isUnit()) { 1284 throw new NotInvertibleException(" k = " + k); 1285 } 1286 } 1287 return g; 1288 } 1289 1290 1291 /** 1292 * Test if element is a unit modulo this ideal. 1293 * @param h polynomial 1294 * @return true if h is a unit with respect to this, else false 1295 */ 1296 public boolean isUnit(GenPolynomial<C> h) { 1297 if (h == null || h.isZERO()) { 1298 return false; 1299 } 1300 if (this.isZERO()) { 1301 return false; 1302 } 1303 List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(1 + list.list.size()); 1304 F.add(h); 1305 F.addAll(list.list); 1306 List<GenPolynomial<C>> G = bb.GB(F); 1307 for (GenPolynomial<C> p : G) { 1308 if (p == null) { 1309 continue; 1310 } 1311 if (p.isUnit()) { 1312 return true; 1313 } 1314 } 1315 return false; 1316 } 1317 1318 1319 /** 1320 * Radical approximation. Squarefree generators for the ideal. 1321 * @return squarefree(this), a Groebner base 1322 */ 1323 public Ideal<C> squarefree() { 1324 if (this.isZERO()) { 1325 return this; 1326 } 1327 Ideal<C> R = this; 1328 Ideal<C> Rp = null; 1329 List<GenPolynomial<C>> li, ri; 1330 while (true) { 1331 li = R.getList(); 1332 ri = new ArrayList<GenPolynomial<C>>(li); //.size() ); 1333 for (GenPolynomial<C> h : li) { 1334 GenPolynomial<C> r = engine.squarefreePart(h); 1335 ri.add(r); 1336 } 1337 Rp = new Ideal<C>(R.getRing(), ri, false); 1338 Rp.doGB(); 1339 if (R.equals(Rp)) { 1340 break; 1341 } 1342 R = Rp; 1343 } 1344 return R; 1345 } 1346 1347 1348 /** 1349 * Ideal common zero test. 1350 * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. 1351 */ 1352 public int commonZeroTest() { 1353 if (this.isZERO()) { 1354 return 1; 1355 } 1356 if (!isGB) { 1357 doGB(); 1358 } 1359 if (this.isONE()) { 1360 return -1; 1361 } 1362 return bb.commonZeroTest(getList()); 1363 } 1364 1365 1366 /** 1367 * Test if this ideal is maximal. 1368 * @return true, if this is certainly maximal and not one, else false. 1369 */ 1370 public boolean isMaximal() { 1371 if (commonZeroTest() != 0) { 1372 return false; 1373 } 1374 long dm = 1L; 1375 for (Long d : univariateDegrees()) { 1376 if (d > 1L) { 1377 dm = d; 1378 } 1379 } 1380 if (dm == 1L) { 1381 return true; 1382 } 1383 // eventually prime decomposition of zero dimensional ideal 1384 if (list.ring.tord.getEvord() != TermOrder.INVLEX) { // skip test(?) 1385 logger.warn("TermOrder {} != INVLEX, isMaximal prime depomposition skipped", list.ring.tord); 1386 return false; 1387 } 1388 List<IdealWithUniv<C>> pdec = zeroDimPrimeDecompositionFE(); 1389 if (pdec.size() != 1) { // not prime 1390 return false; 1391 } 1392 return true; 1393 } 1394 1395 1396 /** 1397 * Univariate head term degrees. 1398 * @return a list of the degrees of univariate head terms. 1399 */ 1400 public List<Long> univariateDegrees() { 1401 List<Long> ud = new ArrayList<Long>(); 1402 if (this.isZERO()) { 1403 return ud; 1404 } 1405 if (!isGB) { 1406 doGB(); 1407 } 1408 if (this.isONE()) { 1409 return ud; 1410 } 1411 return bb.univariateDegrees(getList()); 1412 } 1413 1414 1415 /** 1416 * Ideal dimension. 1417 * @return a dimension container (dim,maxIndep,list(maxIndep),vars). 1418 */ 1419 public Dimension dimension() { 1420 int t = commonZeroTest(); 1421 Set<Integer> S = new HashSet<Integer>(); 1422 Set<Set<Integer>> M = new HashSet<Set<Integer>>(); 1423 if (t <= 0) { 1424 return new Dimension(t, S, M, this.list.ring.getVars()); 1425 } 1426 int d = 0; 1427 Set<Integer> U = new HashSet<Integer>(); 1428 for (int i = 0; i < this.list.ring.nvar; i++) { 1429 U.add(i); 1430 } 1431 M = dimension(S, U, M); 1432 for (Set<Integer> m : M) { 1433 int dp = m.size(); 1434 if (dp > d) { 1435 d = dp; 1436 S = m; 1437 } 1438 } 1439 return new Dimension(d, S, M, this.list.ring.getVars()); 1440 } 1441 1442 1443 /** 1444 * Ideal dimension. 1445 * @param S is a set of independent variables. 1446 * @param U is a set of variables of unknown status. 1447 * @param M is a list of maximal sets of independent variables. 1448 * @return a list of maximal sets of independent variables, eventually 1449 * containing S. 1450 */ 1451 protected Set<Set<Integer>> dimension(Set<Integer> S, Set<Integer> U, Set<Set<Integer>> M) { 1452 Set<Set<Integer>> MP = M; 1453 Set<Integer> UP = new HashSet<Integer>(U); 1454 for (Integer j : U) { 1455 UP.remove(j); 1456 Set<Integer> SP = new HashSet<Integer>(S); 1457 SP.add(j); 1458 if (!containsHT(SP, getList())) { 1459 MP = dimension(SP, UP, MP); 1460 } 1461 } 1462 boolean contained = false; 1463 for (Set<Integer> m : MP) { 1464 if (m.containsAll(S)) { 1465 contained = true; 1466 break; 1467 } 1468 } 1469 if (!contained) { 1470 MP.add(S); 1471 } 1472 return MP; 1473 } 1474 1475 1476 /** 1477 * Ideal head term containment test. 1478 * @param G list of polynomials. 1479 * @param H index set. 1480 * @return true, if the vaiables of the head terms of each polynomial in G 1481 * are contained in H, else false. 1482 */ 1483 protected boolean containsHT(Set<Integer> H, List<GenPolynomial<C>> G) { 1484 Set<Integer> S = null; 1485 for (GenPolynomial<C> p : G) { 1486 if (p == null) { 1487 continue; 1488 } 1489 ExpVector e = p.leadingExpVector(); 1490 if (e == null) { 1491 continue; 1492 } 1493 int[] v = e.dependencyOnVariables(); 1494 if (v == null) { 1495 continue; 1496 } 1497 //System.out.println("v = " + Arrays.toString(v)); 1498 if (S == null) { // revert indices 1499 S = new HashSet<Integer>(H.size()); 1500 int r = e.length() - 1; 1501 for (Integer i : H) { 1502 S.add(r - i); 1503 } 1504 } 1505 if (contains(v, S)) { // v \subset S 1506 return true; 1507 } 1508 } 1509 return false; 1510 } 1511 1512 1513 /** 1514 * Set containment. is v \subset H. 1515 * @param v index array. 1516 * @param H index set. 1517 * @return true, if each element of v is contained in H, else false . 1518 */ 1519 protected boolean contains(int[] v, Set<Integer> H) { 1520 for (int i = 0; i < v.length; i++) { 1521 if (!H.contains(v[i])) { 1522 return false; 1523 } 1524 } 1525 return true; 1526 } 1527 1528 1529 /** 1530 * Construct univariate polynomials of minimal degree in all variables in 1531 * zero dimensional ideal(G). 1532 * @return list of univariate polynomial of minimal degree in each variable 1533 * in ideal(G) 1534 */ 1535 public List<GenPolynomial<C>> constructUnivariate() { 1536 List<GenPolynomial<C>> univs = new ArrayList<GenPolynomial<C>>(); 1537 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1538 GenPolynomial<C> u = constructUnivariate(i); 1539 univs.add(u); 1540 } 1541 return univs; 1542 } 1543 1544 1545 /** 1546 * Construct univariate polynomial of minimal degree in variable i in zero 1547 * dimensional ideal(G). 1548 * @param i variable index. 1549 * @return univariate polynomial of minimal degree in variable i in ideal(G) 1550 */ 1551 public GenPolynomial<C> constructUnivariate(int i) { 1552 doGB(); 1553 return bb.constructUnivariate(i, getList()); 1554 } 1555 1556 1557 /** 1558 * Zero dimensional radical decompostition. See Seidenbergs lemma 92, and 1559 * BWK lemma 8.13. 1560 * @return intersection of radical ideals G_i with ideal(this) subseteq 1561 * cap_i( ideal(G_i) ) 1562 */ 1563 public List<IdealWithUniv<C>> zeroDimRadicalDecomposition() { 1564 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 1565 if (this.isZERO()) { 1566 return dec; 1567 } 1568 IdealWithUniv<C> iwu = new IdealWithUniv<C>(this, new ArrayList<GenPolynomial<C>>()); 1569 dec.add(iwu); 1570 if (this.isONE()) { 1571 return dec; 1572 } 1573 if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { 1574 logger.warn("must use prime decomposition for char p and infinite coefficient rings, found {}", 1575 list.ring.coFac.toScript()); 1576 return zeroDimPrimeDecomposition(); 1577 } 1578 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1579 List<IdealWithUniv<C>> part = new ArrayList<IdealWithUniv<C>>(); 1580 for (IdealWithUniv<C> id : dec) { 1581 //System.out.println("id = " + id + ", i = " + i); 1582 GenPolynomial<C> u = id.ideal.constructUnivariate(i); 1583 SortedMap<GenPolynomial<C>, Long> facs = engine.baseSquarefreeFactors(u); 1584 if (facs == null || facs.size() == 0 1585 || (facs.size() == 1 && facs.get(facs.firstKey()) == 1L)) { 1586 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1587 iup.addAll(id.upolys); 1588 iup.add(u); 1589 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(id.ideal, iup); 1590 part.add(Ipu); 1591 continue; // irreducible 1592 } 1593 logger.info("squarefree facs = {}", facs); 1594 GenPolynomialRing<C> mfac = id.ideal.list.ring; 1595 int j = mfac.nvar - 1 - i; 1596 for (GenPolynomial<C> p : facs.keySet()) { 1597 // make p multivariate 1598 GenPolynomial<C> pm = p.extendUnivariate(mfac, j); 1599 // mfac.parse( p.toString() ); 1600 //System.out.println("pm = " + pm); 1601 Ideal<C> Ip = id.ideal.sum(pm); 1602 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1603 iup.addAll(id.upolys); 1604 iup.add(p); 1605 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(Ip, iup); 1606 if (debug) { 1607 logger.info("ideal with squarefree facs = {}", Ipu); 1608 } 1609 part.add(Ipu); 1610 } 1611 } 1612 dec = part; 1613 //part = new ArrayList<IdealWithUniv<C>>(); 1614 } 1615 return dec; 1616 } 1617 1618 1619 /** 1620 * Test for Zero dimensional radical. See Seidenbergs lemma 92, and BWK 1621 * lemma 8.13. 1622 * @return true if this is an zero dimensional radical ideal, else false 1623 */ 1624 public boolean isZeroDimRadical() { 1625 if (this.isZERO()) { 1626 return false; 1627 } 1628 if (this.isONE()) { 1629 return false; // not 0-dim 1630 } 1631 if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { 1632 logger.warn("radical only for char 0 or finite coefficient rings, but found {}", 1633 list.ring.coFac.toScript()); 1634 } 1635 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1636 GenPolynomial<C> u = constructUnivariate(i); 1637 boolean t = engine.isSquarefree(u); 1638 if (!t) { 1639 System.out.println("not squarefree " + engine.squarefreePart(u) + ", " + u); 1640 return false; 1641 } 1642 } 1643 return true; 1644 } 1645 1646 1647 /** 1648 * Zero dimensional ideal irreducible decompostition. See algorithm DIRGZD 1649 * of BGK 1986 and also PREDEC of the Gröbner bases book 1993. 1650 * @return intersection H, of ideals G_i with ideal(this) subseteq cap_i( 1651 * ideal(G_i) ) and each ideal G_i has only irreducible minimal 1652 * univariate polynomials and the G_i are pairwise co-prime. 1653 */ 1654 public List<IdealWithUniv<C>> zeroDimDecomposition() { 1655 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 1656 if (this.isZERO()) { 1657 return dec; 1658 } 1659 IdealWithUniv<C> iwu = new IdealWithUniv<C>(this, new ArrayList<GenPolynomial<C>>()); 1660 dec.add(iwu); 1661 if (this.isONE()) { 1662 return dec; 1663 } 1664 FactorAbstract<C> ufd = FactorFactory.<C> getImplementation(list.ring.coFac); 1665 for (int i = list.ring.nvar - 1; i >= 0; i--) { 1666 List<IdealWithUniv<C>> part = new ArrayList<IdealWithUniv<C>>(); 1667 for (IdealWithUniv<C> id : dec) { 1668 //System.out.println("id.ideal = " + id.ideal); 1669 GenPolynomial<C> u = id.ideal.constructUnivariate(i); 1670 SortedMap<GenPolynomial<C>, Long> facs = ufd.baseFactors(u); 1671 if (facs.size() == 0 || (facs.size() == 1 && facs.get(facs.firstKey()) == 1L)) { 1672 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1673 iup.addAll(id.upolys); 1674 iup.add(u); 1675 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(id.ideal, iup); 1676 part.add(Ipu); 1677 continue; // irreducible 1678 } 1679 if (debug) { 1680 logger.info("irreducible facs = {}", facs); 1681 } 1682 GenPolynomialRing<C> mfac = id.ideal.list.ring; 1683 int j = mfac.nvar - 1 - i; 1684 for (GenPolynomial<C> p : facs.keySet()) { 1685 // make p multivariate 1686 GenPolynomial<C> pm = p.extendUnivariate(mfac, j); 1687 // mfac.parse( p.toString() ); 1688 //System.out.println("pm = " + pm); 1689 Ideal<C> Ip = id.ideal.sum(pm); 1690 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1691 iup.addAll(id.upolys); 1692 iup.add(p); 1693 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(Ip, iup); 1694 part.add(Ipu); 1695 } 1696 } 1697 dec = part; 1698 //part = new ArrayList<IdealWithUniv<C>>(); 1699 } 1700 return dec; 1701 } 1702 1703 1704 /** 1705 * Zero dimensional ideal irreducible decompostition extension. One step 1706 * decomposition via a minimal univariate polynomial in the lowest variable, 1707 * used after each normalPosition step. 1708 * @param upol list of univariate polynomials 1709 * @param og list of other generators for the ideal 1710 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 1711 * ideal(G_i) ) and all minimal univariate polynomials of all G_i 1712 * are irreducible 1713 */ 1714 public List<IdealWithUniv<C>> zeroDimDecompositionExtension(List<GenPolynomial<C>> upol, 1715 List<GenPolynomial<C>> og) { 1716 if (upol == null || upol.size() + 1 != list.ring.nvar) { 1717 throw new IllegalArgumentException("univariate polynomial list not correct " + upol); 1718 } 1719 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 1720 if (this.isZERO()) { 1721 return dec; 1722 } 1723 IdealWithUniv<C> iwu = new IdealWithUniv<C>(this, upol); 1724 if (this.isONE()) { 1725 dec.add(iwu); 1726 return dec; 1727 } 1728 FactorAbstract<C> ufd = FactorFactory.<C> getImplementation(list.ring.coFac); 1729 int i = list.ring.nvar - 1; 1730 //IdealWithUniv<C> id = new IdealWithUniv<C>(this,upol); 1731 GenPolynomial<C> u = this.constructUnivariate(i); 1732 SortedMap<GenPolynomial<C>, Long> facs = ufd.baseFactors(u); 1733 if (facs.size() == 1 && facs.get(facs.firstKey()) == 1L) { 1734 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1735 iup.add(u); // new polynomial first 1736 iup.addAll(upol); 1737 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(this, iup, og); 1738 dec.add(Ipu); 1739 return dec; 1740 } 1741 logger.info("irreducible facs = {}", facs); 1742 GenPolynomialRing<C> mfac = list.ring; 1743 int j = mfac.nvar - 1 - i; 1744 for (GenPolynomial<C> p : facs.keySet()) { 1745 // make p multivariate 1746 GenPolynomial<C> pm = p.extendUnivariate(mfac, j); 1747 //System.out.println("pm = " + pm); 1748 Ideal<C> Ip = this.sum(pm); 1749 List<GenPolynomial<C>> iup = new ArrayList<GenPolynomial<C>>(); 1750 iup.add(p); // new polynomial first 1751 iup.addAll(upol); 1752 IdealWithUniv<C> Ipu = new IdealWithUniv<C>(Ip, iup, og); 1753 dec.add(Ipu); 1754 } 1755 return dec; 1756 } 1757 1758 1759 /** 1760 * Test for zero dimensional ideal decompostition. 1761 * @param L intersection of ideals G_i with ideal(G) subseteq cap_i( 1762 * ideal(G_i) ) and all minimal univariate polynomials of all G_i 1763 * are irreducible 1764 * @return true if L is a zero dimensional irreducible decomposition of 1765 * this, else false 1766 */ 1767 public boolean isZeroDimDecomposition(List<IdealWithUniv<C>> L) { 1768 if (L == null || L.size() == 0) { 1769 if (this.isZERO()) { 1770 return true; 1771 } 1772 return false; 1773 } 1774 // add lower variables if L contains ideals from field extensions 1775 GenPolynomialRing<C> ofac = list.ring; 1776 int r = ofac.nvar; 1777 int rp = L.get(0).ideal.list.ring.nvar; 1778 int d = rp - r; 1779 //System.out.println("d = " + d); 1780 Ideal<C> Id = this; 1781 if (d > 0) { 1782 GenPolynomialRing<C> nfac = ofac.extendLower(d); 1783 //System.out.println("nfac = " + nfac); 1784 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size()); 1785 for (GenPolynomial<C> p : getList()) { 1786 //System.out.println("p = " + p); 1787 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1788 //System.out.println("q = " + q); 1789 elist.add(q); 1790 } 1791 Id = new Ideal<C>(nfac, elist, isGB, isTopt); 1792 } 1793 // test if this is contained in the intersection 1794 for (IdealWithUniv<C> I : L) { 1795 boolean t = I.ideal.contains(Id); 1796 if (!t) { 1797 System.out.println("not contained " + this + " in " + I.ideal); 1798 return false; 1799 } 1800 } 1801 // test if all univariate polynomials are contained in the respective ideal 1802 //List<GenPolynomial<C>> upprod = new ArrayList<GenPolynomial<C>>(rp); 1803 for (IdealWithUniv<C> I : L) { 1804 GenPolynomialRing<C> mfac = I.ideal.list.ring; 1805 int i = 0; 1806 for (GenPolynomial<C> p : I.upolys) { 1807 GenPolynomial<C> pm = p.extendUnivariate(mfac, i++); 1808 //System.out.println("pm = " + pm + ", p = " + p); 1809 boolean t = I.ideal.contains(pm); 1810 if (!t) { 1811 System.out.println("not contained " + pm + " in " + I.ideal); 1812 return false; 1813 } 1814 } 1815 } 1816 return true; 1817 } 1818 1819 1820 /** 1821 * Compute normal position for variables i and j. 1822 * @param i first variable index 1823 * @param j second variable index 1824 * @param og other generators for the ideal 1825 * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] 1826 */ 1827 public IdealWithUniv<C> normalPositionFor(int i, int j, List<GenPolynomial<C>> og) { 1828 // extend variables by one 1829 GenPolynomialRing<C> ofac = list.ring; 1830 if (ofac.tord.getEvord() != TermOrder.INVLEX) { 1831 throw new IllegalArgumentException("invalid term order for normalPosition " + ofac.tord); 1832 } 1833 if (ofac.characteristic().signum() == 0) { 1834 return normalPositionForChar0(i, j, og); 1835 } 1836 return normalPositionForCharP(i, j, og); 1837 } 1838 1839 1840 /** 1841 * Compute normal position for variables i and j, characteristic zero. 1842 * @param i first variable index 1843 * @param j second variable index 1844 * @param og other generators for the ideal 1845 * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] 1846 */ 1847 IdealWithUniv<C> normalPositionForChar0(int i, int j, List<GenPolynomial<C>> og) { 1848 // extend variables by one 1849 GenPolynomialRing<C> ofac = list.ring; 1850 GenPolynomialRing<C> nfac = ofac.extendLower(1); 1851 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size() + 1); 1852 for (GenPolynomial<C> p : getList()) { 1853 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1854 //System.out.println("q = " + q); 1855 elist.add(q); 1856 } 1857 List<GenPolynomial<C>> ogen = new ArrayList<GenPolynomial<C>>(); 1858 if (og != null && og.size() > 0) { 1859 for (GenPolynomial<C> p : og) { 1860 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1861 //System.out.println("q = " + q); 1862 ogen.add(q); 1863 } 1864 } 1865 Ideal<C> I = new Ideal<C>(nfac, elist, true); 1866 //System.out.println("I = " + I); 1867 int ip = list.ring.nvar - 1 - i; 1868 int jp = list.ring.nvar - 1 - j; 1869 GenPolynomial<C> xi = nfac.univariate(ip); 1870 GenPolynomial<C> xj = nfac.univariate(jp); 1871 GenPolynomial<C> z = nfac.univariate(nfac.nvar - 1); 1872 // compute GBs until value of t is OK 1873 Ideal<C> Ip; 1874 GenPolynomial<C> zp; 1875 int t = 0; 1876 do { 1877 t--; 1878 // zp = z - ( xj - xi * t ) 1879 zp = z.subtract(xj.subtract(xi.multiply(nfac.fromInteger(t)))); 1880 zp = zp.monic(); 1881 Ip = I.sum(zp); 1882 //System.out.println("Ip = " + Ip); 1883 if (-t % 5 == 0) { 1884 logger.info("normal position, t = {}", t); 1885 } 1886 } while (!Ip.isNormalPositionFor(i + 1, j + 1)); 1887 if (debug) { 1888 logger.info("normal position = {}", Ip); 1889 } 1890 ogen.add(zp); 1891 IdealWithUniv<C> Ips = new IdealWithUniv<C>(Ip, null, ogen); 1892 return Ips; 1893 } 1894 1895 1896 /** 1897 * Compute normal position for variables i and j, positive characteristic. 1898 * @param i first variable index 1899 * @param j second variable index 1900 * @param og other generators for the ideal 1901 * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] 1902 */ 1903 @SuppressWarnings({ "unchecked", "cast" }) 1904 IdealWithUniv<C> normalPositionForCharP(int i, int j, List<GenPolynomial<C>> og) { 1905 // extend variables by one 1906 GenPolynomialRing<C> ofac = list.ring; 1907 GenPolynomialRing<C> nfac = ofac.extendLower(1); 1908 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size() + 1); 1909 for (GenPolynomial<C> p : getList()) { 1910 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1911 //System.out.println("q = " + q); 1912 elist.add(q); 1913 } 1914 List<GenPolynomial<C>> ogen = new ArrayList<GenPolynomial<C>>(); 1915 if (og != null && og.size() > 0) { 1916 for (GenPolynomial<C> p : og) { 1917 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 1918 //System.out.println("q = " + q); 1919 ogen.add(q); 1920 } 1921 } 1922 Ideal<C> I = new Ideal<C>(nfac, elist, true); 1923 //System.out.println("I = " + I); 1924 int ip = list.ring.nvar - 1 - i; 1925 int jp = list.ring.nvar - 1 - j; 1926 GenPolynomial<C> xi = nfac.univariate(ip); 1927 GenPolynomial<C> xj = nfac.univariate(jp); 1928 GenPolynomial<C> z = nfac.univariate(nfac.nvar - 1); 1929 // compute GBs until value of t is OK 1930 Ideal<C> Ip; 1931 GenPolynomial<C> zp; 1932 AlgebraicNumberRing<C> afac = null; 1933 Iterator<AlgebraicNumber<C>> aiter = null; 1934 //String obr = ""; 1935 //String cbr = ""; 1936 int t = 0; 1937 do { 1938 t--; 1939 // zp = z - ( xj - xi * t ) 1940 GenPolynomial<C> tn; 1941 if (afac == null) { 1942 tn = nfac.fromInteger(t); 1943 if (tn.isZERO()) { 1944 RingFactory<C> fac = nfac.coFac; 1945 //int braces = 2; 1946 while (!(fac instanceof AlgebraicNumberRing)) { 1947 if (fac instanceof GenPolynomialRing) { 1948 GenPolynomialRing<C> pfac = (GenPolynomialRing<C>) (Object) fac; 1949 fac = pfac.coFac; 1950 } else if (fac instanceof QuotientRing) { 1951 QuotientRing<C> pfac = (QuotientRing<C>) (Object) fac; 1952 fac = pfac.ring.coFac; 1953 } else { 1954 throw new ArithmeticException( 1955 "field elements exhausted, need algebraic extension of base ring"); 1956 } 1957 //braces++; 1958 } 1959 //for (int ii = 0; ii < braces; ii++) { 1960 // obr += "{ "; 1961 // cbr += " }"; 1962 //} 1963 afac = (AlgebraicNumberRing<C>) (Object) fac; 1964 logger.info("afac = {}", afac.toScript()); 1965 aiter = afac.iterator(); 1966 AlgebraicNumber<C> an = aiter.next(); 1967 for (int kk = 0; kk < afac.characteristic().intValueExact(); kk++) { 1968 an = aiter.next(); 1969 } 1970 //System.out.println("an,iter = " + an); 1971 //tn = nfac.parse(obr + an.toString() + cbr); 1972 tn = nfac.parse(an.toString()); 1973 //System.out.println("tn = " + tn); 1974 //if (false) { 1975 // throw new RuntimeException("probe"); 1976 //} 1977 } 1978 } else { 1979 if (!aiter.hasNext()) { 1980 throw new ArithmeticException( 1981 "field elements exhausted, normal position not reachable: !aiter.hasNext(): " 1982 + t); 1983 } 1984 AlgebraicNumber<C> an = aiter.next(); 1985 //System.out.println("an,iter = " + an); 1986 //tn = nfac.parse(obr + an.toString() + cbr); 1987 tn = nfac.parse(an.toString()); 1988 //System.out.println("tn = " + tn); 1989 } 1990 if (tn.isZERO()) { 1991 throw new ArithmeticException( 1992 "field elements exhausted, normal position not reachable: tn == 0: " + t); 1993 } 1994 zp = z.subtract(xj.subtract(xi.multiply(tn))); 1995 zp = zp.monic(); 1996 Ip = I.sum(zp); 1997 //System.out.println("Ip = " + Ip); 1998 if (-t % 4 == 0) { 1999 logger.info("normal position, t = {}", t); 2000 logger.info("normal position, GB = {}", Ip); 2001 if (t < -550) { 2002 throw new ArithmeticException("normal position not reached in " + t + " steps"); 2003 } 2004 } 2005 } while (!Ip.isNormalPositionFor(i + 1, j + 1)); 2006 if (debug) { 2007 logger.info("normal position = {}", Ip); 2008 } 2009 ogen.add(zp); 2010 IdealWithUniv<C> Ips = new IdealWithUniv<C>(Ip, null, ogen); 2011 return Ips; 2012 } 2013 2014 2015 /** 2016 * Test if this ideal is in normal position for variables i and j. 2017 * @param i first variable index 2018 * @param j second variable index 2019 * @return true if this is in normal position with respect to i and j 2020 */ 2021 public boolean isNormalPositionFor(int i, int j) { 2022 // called in extended ring! 2023 int ip = list.ring.nvar - 1 - i; 2024 int jp = list.ring.nvar - 1 - j; 2025 boolean iOK = false; 2026 boolean jOK = false; 2027 for (GenPolynomial<C> p : getList()) { 2028 if (p.isZERO()) { 2029 continue; 2030 } 2031 ExpVector e = p.leadingExpVector(); 2032 int[] dov = e.dependencyOnVariables(); 2033 //System.out.println("dov = " + Arrays.toString(dov)); 2034 if (dov.length == 0) { 2035 throw new IllegalArgumentException("ideal dimension is not zero"); 2036 } 2037 if (dov[0] == ip) { 2038 if (e.totalDeg() != 1) { 2039 return false; 2040 } 2041 iOK = true; 2042 } else if (dov[0] == jp) { 2043 if (e.totalDeg() != 1) { 2044 return false; 2045 } 2046 jOK = true; 2047 } 2048 if (iOK && jOK) { 2049 return true; 2050 } 2051 } 2052 return iOK && jOK; 2053 } 2054 2055 2056 /** 2057 * Normal position index, separate for polynomials with more than 2 2058 * variables. See also 2059 * <a href="http://krum.rz.uni-mannheim.de/mas/src/masring/DIPDEC0.mi.html" 2060 * >mas.masring.DIPDEC0#DIGISR</a> 2061 * @return (i,j) for non-normal variables 2062 */ 2063 public int[] normalPositionIndex2Vars() { 2064 int i = -1; 2065 int j = -1; 2066 for (GenPolynomial<C> p : getList()) { 2067 if (p.isZERO()) { 2068 continue; 2069 } 2070 ExpVector e = p.leadingExpVector(); 2071 int[] dov = e.dependencyOnVariables(); 2072 //System.out.println("dov_head = " + Arrays.toString(dov)); 2073 if (dov.length == 0) { 2074 throw new IllegalArgumentException("ideal dimension is not zero " + p); 2075 } 2076 // search bi-variate head terms 2077 if (dov.length >= 2) { 2078 i = dov[0]; 2079 j = dov[1]; 2080 break; 2081 } 2082 int n = dov[0]; 2083 GenPolynomial<C> q = p.reductum(); 2084 if (q.isZERO()) { 2085 continue; 2086 } 2087 e = q.degreeVector(); 2088 dov = e.dependencyOnVariables(); 2089 //System.out.println("dov_red = " + Arrays.toString(dov)); 2090 int k = Arrays.binarySearch(dov, n); 2091 int len = 2; 2092 if (k >= 0) { 2093 len = 3; 2094 } 2095 // search bi-variate reductas 2096 if (dov.length >= len) { 2097 switch (k) { 2098 case 0: 2099 i = dov[1]; 2100 j = dov[2]; 2101 break; 2102 case 1: 2103 i = dov[0]; 2104 j = dov[2]; 2105 break; 2106 case 2: 2107 i = dov[0]; 2108 j = dov[1]; 2109 break; 2110 default: 2111 i = dov[0]; 2112 j = dov[1]; 2113 break; 2114 } 2115 break; 2116 } 2117 } 2118 if (i < 0 || j < 0) { 2119 return (int[]) null; 2120 } 2121 // adjust index 2122 i = list.ring.nvar - 1 - i; 2123 j = list.ring.nvar - 1 - j; 2124 final int[] np = new int[] { j, i }; // reverse 2125 logger.info("normalPositionIndex2Vars, np = {}", () -> Arrays.toString(np)); 2126 return np; 2127 } 2128 2129 2130 /** 2131 * Normal position index, separate multiple univariate polynomials. See also 2132 * <a href="http://krum.rz.uni-mannheim.de/mas/src/masring/DIPDEC0.mi.html"> 2133 * mas.masring.DIPDEC0#DIGISM</a> 2134 * @return (i,j) for non-normal variables 2135 */ 2136 public int[] normalPositionIndexUnivars() { 2137 //int[] np = null; //new int[] { -1, -1 }; 2138 int i = -1; 2139 int j = -1; 2140 // search multiple univariate polynomials with degree >= 2 2141 for (GenPolynomial<C> p : getList()) { 2142 if (p.isZERO()) { 2143 continue; 2144 } 2145 ExpVector e = p.degreeVector(); 2146 int[] dov = e.dependencyOnVariables(); 2147 long t = e.totalDeg(); // lt(p) would be enough 2148 //System.out.println("dov_univ = " + Arrays.toString(dov) + ", e = " + e); 2149 if (dov.length == 0) { 2150 throw new IllegalArgumentException("ideal dimension is not zero"); 2151 } 2152 if (dov.length == 1 && t >= 2L) { 2153 if (i == -1) { 2154 i = dov[0]; 2155 } else if (j == -1) { 2156 j = dov[0]; 2157 if (i > j) { 2158 int x = i; 2159 i = j; 2160 j = x; 2161 } 2162 } 2163 } 2164 if (i >= 0 && j >= 0) { 2165 break; 2166 } 2167 } 2168 if (i < 0 || j < 0) { 2169 // search polynomials with univariate head term and degree >= 2 2170 for (GenPolynomial<C> p : getList()) { 2171 if (p.isZERO()) { 2172 continue; 2173 } 2174 ExpVector e = p.leadingExpVector(); 2175 long t = e.totalDeg(); 2176 if (t >= 2) { 2177 e = p.degreeVector(); 2178 int[] dov = e.dependencyOnVariables(); 2179 //System.out.println("dov_univ2 = " + Arrays.toString(dov) + " e = " + e); 2180 if (dov.length == 0) { 2181 throw new IllegalArgumentException("ideal dimension is not zero"); 2182 } 2183 if (dov.length >= 2) { 2184 i = dov[0]; 2185 j = dov[1]; 2186 } 2187 } 2188 if (i >= 0 && j >= 0) { 2189 break; 2190 } 2191 } 2192 } 2193 if (i < 0 || j < 0) { 2194 return (int[]) null; 2195 } 2196 // adjust index 2197 i = list.ring.nvar - 1 - i; 2198 j = list.ring.nvar - 1 - j; 2199 final int[] np = new int[] { j, i }; // reverse 2200 logger.info("normalPositionIndexUnivars, np = {}", () -> Arrays.toString(np)); 2201 return np; 2202 } 2203 2204 2205 /** 2206 * Zero dimensional ideal decompostition for real roots. See algorithm 2207 * mas.masring.DIPDEC0#DINTSR. 2208 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2209 * ideal(G_i) ) and each G_i contains at most bi-variate polynomials 2210 * and all univariate minimal polynomials are irreducible 2211 */ 2212 public List<IdealWithUniv<C>> zeroDimRootDecomposition() { 2213 List<IdealWithUniv<C>> dec = zeroDimDecomposition(); 2214 if (this.isZERO()) { 2215 return dec; 2216 } 2217 if (this.isONE()) { 2218 return dec; 2219 } 2220 List<IdealWithUniv<C>> rdec = new ArrayList<IdealWithUniv<C>>(); 2221 while (dec.size() > 0) { 2222 IdealWithUniv<C> id = dec.remove(0); 2223 int[] ri = id.ideal.normalPositionIndex2Vars(); 2224 if (ri == null || ri.length != 2) { 2225 rdec.add(id); 2226 } else { 2227 IdealWithUniv<C> I = id.ideal.normalPositionFor(ri[0], ri[1], id.others); 2228 List<IdealWithUniv<C>> rd = I.ideal.zeroDimDecompositionExtension(id.upolys, I.others); 2229 //System.out.println("r_rd = " + rd); 2230 dec.addAll(rd); 2231 } 2232 } 2233 return rdec; 2234 } 2235 2236 2237 /** 2238 * Zero dimensional ideal prime decompostition. See algorithm 2239 * mas.masring.DIPDEC0#DINTSS. 2240 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2241 * ideal(G_i) ) and each G_i is a prime ideal 2242 */ 2243 public List<IdealWithUniv<C>> zeroDimPrimeDecomposition() { 2244 List<IdealWithUniv<C>> pdec = zeroDimPrimeDecompositionFE(); 2245 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2246 if (pdec.size() == 1) { // already prime 2247 IdealWithUniv<C> Ip = pdec.get(0); 2248 int s = Ip.upolys.size() - getRing().nvar; // skip field ext univariate polys 2249 List<GenPolynomial<C>> upol = Ip.upolys.subList(s, Ip.upolys.size()); 2250 Ip = new IdealWithUniv<C>(this, upol); 2251 dec.add(Ip); 2252 return dec; 2253 } 2254 for (IdealWithUniv<C> Ip : pdec) { 2255 if (Ip.ideal.getRing().nvar == getRing().nvar) { // no field extension 2256 dec.add(Ip); 2257 } else { // remove field extension 2258 // add other generators for performance 2259 Ideal<C> Id = Ip.ideal; 2260 if (Ip.others != null) { 2261 //System.out.println("adding Ip.others = " + Ip.others); 2262 List<GenPolynomial<C>> pp = new ArrayList<GenPolynomial<C>>(); 2263 pp.addAll(Id.getList()); 2264 pp.addAll(Ip.others); 2265 Id = new Ideal<C>(Id.getRing(), pp); 2266 } 2267 Ideal<C> Is = Id.eliminate(getRing()); 2268 //System.out.println("Is = " + Is); 2269 int s = Ip.upolys.size() - getRing().nvar; // skip field ext univariate polys 2270 List<GenPolynomial<C>> upol = Ip.upolys.subList(s, Ip.upolys.size()); 2271 IdealWithUniv<C> Iu = new IdealWithUniv<C>(Is, upol); 2272 //,Ip.others); used above and must be ignored here 2273 dec.add(Iu); 2274 } 2275 } 2276 return dec; 2277 } 2278 2279 2280 /** 2281 * Zero dimensional ideal prime decompostition, with field extension. See 2282 * algorithm mas.masring.DIPDEC0#DINTSS. 2283 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2284 * ideal(G_i) ) and each G_i is a prime ideal with eventually 2285 * containing field extension variables 2286 */ 2287 public List<IdealWithUniv<C>> zeroDimPrimeDecompositionFE() { 2288 List<IdealWithUniv<C>> dec = zeroDimRootDecomposition(); 2289 if (this.isZERO()) { 2290 return dec; 2291 } 2292 if (this.isONE()) { 2293 return dec; 2294 } 2295 List<IdealWithUniv<C>> rdec = new ArrayList<IdealWithUniv<C>>(); 2296 while (dec.size() > 0) { 2297 IdealWithUniv<C> id = dec.remove(0); 2298 int[] ri = id.ideal.normalPositionIndexUnivars(); 2299 if (ri == null || ri.length != 2) { 2300 rdec.add(id); 2301 } else { 2302 IdealWithUniv<C> I = id.ideal.normalPositionFor(ri[0], ri[1], id.others); 2303 List<IdealWithUniv<C>> rd = I.ideal.zeroDimDecompositionExtension(id.upolys, I.others); 2304 //System.out.println("rd = " + rd); 2305 dec.addAll(rd); 2306 } 2307 } 2308 return rdec; 2309 } 2310 2311 2312 /** 2313 * Zero dimensional ideal associated primary ideal. See algorithm 2314 * mas.masring.DIPIDEAL#DIRLPI. 2315 * @param P prime ideal associated to this 2316 * @return primary ideal of this with respect to the associated pime ideal P 2317 */ 2318 public Ideal<C> primaryIdeal(Ideal<C> P) { 2319 Ideal<C> Qs = P; 2320 Ideal<C> Q; 2321 int e = 0; 2322 do { 2323 Q = Qs; 2324 e++; 2325 Qs = Q.product(P); 2326 } while (Qs.contains(this)); 2327 boolean t; 2328 Ideal<C> As; 2329 do { 2330 As = this.sum(Qs); 2331 t = As.contains(Q); 2332 if (!t) { 2333 Q = Qs; 2334 e++; 2335 Qs = Q.product(P); 2336 } 2337 } while (!t); 2338 logger.info("exponent = {}", e); 2339 return As; 2340 } 2341 2342 2343 /** 2344 * Zero dimensional ideal primary decompostition. 2345 * @return list of primary components of primary ideals G_i (pairwise 2346 * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with 2347 * the associated primes 2348 */ 2349 public List<PrimaryComponent<C>> zeroDimPrimaryDecomposition() { 2350 List<IdealWithUniv<C>> pdec = zeroDimPrimeDecomposition(); 2351 logger.info("prim decomp = {}", pdec); 2352 return zeroDimPrimaryDecomposition(pdec); 2353 } 2354 2355 2356 /** 2357 * Zero dimensional ideal elimination to original ring. 2358 * @param pdec list of prime ideals G_i 2359 * @return intersection of pairwise co-prime prime ideals G_i in the ring of 2360 * this with ideal(this) = cap_i( ideal(G_i) ) 2361 */ 2362 public List<IdealWithUniv<C>> zeroDimElimination(List<IdealWithUniv<C>> pdec) { 2363 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2364 if (this.isZERO()) { 2365 return dec; 2366 } 2367 if (this.isONE()) { 2368 dec.add(pdec.get(0)); 2369 return dec; 2370 } 2371 List<IdealWithUniv<C>> qdec = new ArrayList<IdealWithUniv<C>>(); 2372 for (IdealWithUniv<C> Ip : pdec) { 2373 //System.out.println("Ip = " + Ip); 2374 List<GenPolynomial<C>> epol = new ArrayList<GenPolynomial<C>>(); 2375 epol.addAll(Ip.ideal.getList()); 2376 GenPolynomialRing<C> mfac = Ip.ideal.list.ring; 2377 int j = 0; 2378 // add univariate polynomials for performance 2379 for (GenPolynomial<C> p : Ip.upolys) { 2380 GenPolynomial<C> pm = p.extendUnivariate(mfac, j++); 2381 if (j != 1) { // skip double 2382 epol.add(pm); 2383 } 2384 } 2385 // add other generators for performance 2386 if (Ip.others != null) { 2387 epol.addAll(Ip.others); 2388 } 2389 Ideal<C> Ipp = new Ideal<C>(mfac, epol); 2390 // logger.info("eliminate_1 = {}", Ipp); 2391 TermOrder to = null; 2392 if (mfac.tord.getEvord() != TermOrder.IGRLEX) { 2393 List<GenPolynomial<C>> epols = new ArrayList<GenPolynomial<C>>(); 2394 to = new TermOrder(TermOrder.IGRLEX); 2395 GenPolynomialRing<C> smfac = new GenPolynomialRing<C>(mfac.coFac, mfac.nvar, to, 2396 mfac.getVars()); 2397 for (GenPolynomial<C> p : epol) { 2398 GenPolynomial<C> pm = smfac.copy(p); 2399 epols.add(pm.monic()); 2400 } 2401 //epol = epols; 2402 Ipp = new Ideal<C>(smfac, epols); 2403 } 2404 epol = red.irreducibleSet(Ipp.getList()); 2405 Ipp = new Ideal<C>(Ipp.getRing(), epol); 2406 logger.info("eliminate = {}", Ipp); 2407 Ideal<C> Is = Ipp.eliminate(list.ring); 2408 //System.out.println("Is = " + Is); 2409 if (to != null && !Is.list.ring.equals(list.ring)) { 2410 List<GenPolynomial<C>> epols = new ArrayList<GenPolynomial<C>>(); 2411 for (GenPolynomial<C> p : Is.getList()) { 2412 GenPolynomial<C> pm = list.ring.copy(p); 2413 epols.add(pm); 2414 } 2415 Is = new Ideal<C>(list.ring, epols); 2416 //System.out.println("Is = " + Is); 2417 } 2418 int k = Ip.upolys.size() - list.ring.nvar; 2419 List<GenPolynomial<C>> up = new ArrayList<GenPolynomial<C>>(); 2420 for (int i = 0; i < list.ring.nvar; i++) { 2421 up.add(Ip.upolys.get(i + k)); 2422 } 2423 IdealWithUniv<C> Ie = new IdealWithUniv<C>(Is, up); 2424 qdec.add(Ie); 2425 } 2426 return qdec; 2427 } 2428 2429 2430 /** 2431 * Zero dimensional ideal primary decompostition. 2432 * @param pdec list of prime ideals G_i with no field extensions 2433 * @return list of primary components of primary ideals G_i (pairwise 2434 * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with 2435 * the associated primes 2436 */ 2437 public List<PrimaryComponent<C>> zeroDimPrimaryDecomposition(List<IdealWithUniv<C>> pdec) { 2438 List<PrimaryComponent<C>> dec = new ArrayList<PrimaryComponent<C>>(); 2439 if (this.isZERO()) { 2440 return dec; 2441 } 2442 if (this.isONE()) { 2443 PrimaryComponent<C> pc = new PrimaryComponent<C>(pdec.get(0).ideal, pdec.get(0)); 2444 dec.add(pc); 2445 return dec; 2446 } 2447 for (IdealWithUniv<C> Ip : pdec) { 2448 Ideal<C> Qs = this.primaryIdeal(Ip.ideal); 2449 PrimaryComponent<C> pc = new PrimaryComponent<C>(Qs, Ip); 2450 dec.add(pc); 2451 } 2452 return dec; 2453 } 2454 2455 2456 /** 2457 * Test for primary ideal decompostition. 2458 * @param L list of primary components G_i 2459 * @return true if ideal(this) == cap_i( ideal(G_i) ) 2460 */ 2461 public boolean isPrimaryDecomposition(List<PrimaryComponent<C>> L) { 2462 // test if this is contained in the intersection 2463 for (PrimaryComponent<C> I : L) { 2464 boolean t = I.primary.contains(this); 2465 if (!t) { 2466 System.out.println("not contained " + this + " in " + I); 2467 return false; 2468 } 2469 } 2470 Ideal<C> isec = null; 2471 for (PrimaryComponent<C> I : L) { 2472 if (isec == null) { 2473 isec = I.primary; 2474 } else { 2475 isec = isec.intersect(I.primary); 2476 } 2477 } 2478 return this.contains(isec); 2479 } 2480 2481 2482 /** 2483 * Ideal extension. 2484 * @param vars list of variables for a polynomial ring for extension 2485 * @return ideal G, with coefficients in QuotientRing(GenPolynomialRing 2486 * <C>(vars)) 2487 */ 2488 public IdealWithUniv<Quotient<C>> extension(String... vars) { 2489 GenPolynomialRing<C> fac = getRing(); 2490 GenPolynomialRing<C> efac = new GenPolynomialRing<C>(fac.coFac, vars.length, fac.tord, vars); 2491 IdealWithUniv<Quotient<C>> ext = extension(efac); 2492 return ext; 2493 } 2494 2495 2496 /** 2497 * Ideal extension. 2498 * @param efac polynomial ring for extension 2499 * @return ideal G, with coefficients in QuotientRing(efac) 2500 */ 2501 public IdealWithUniv<Quotient<C>> extension(GenPolynomialRing<C> efac) { 2502 QuotientRing<C> qfac = new QuotientRing<C>(efac); 2503 IdealWithUniv<Quotient<C>> ext = extension(qfac); 2504 return ext; 2505 } 2506 2507 2508 /** 2509 * Ideal extension. 2510 * @param qfac quotient polynomial ring for extension 2511 * @return ideal G, with coefficients in qfac 2512 */ 2513 public IdealWithUniv<Quotient<C>> extension(QuotientRing<C> qfac) { 2514 GenPolynomialRing<C> fac = getRing(); 2515 GenPolynomialRing<C> efac = qfac.ring; 2516 String[] rvars = GroebnerBasePartial.remainingVars(fac.getVars(), efac.getVars()); 2517 //System.out.println("rvars = " + Arrays.toString(rvars)); 2518 2519 GroebnerBasePartial<C> bbp = new GroebnerBasePartial<C>(); 2520 //wrong: OptimizedPolynomialList<C> pgb = bbp.partialGB(getList(),rvars); 2521 OptimizedPolynomialList<C> pgb = bbp.elimPartialGB(getList(), rvars, efac.getVars()); 2522 logger.info("rvars = {}", Arrays.toString(rvars)); 2523 logger.info("partialGB = {}", pgb); 2524 2525 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(efac, rvars.length, 2526 fac.tord, rvars); 2527 List<GenPolynomial<C>> plist = pgb.list; 2528 List<GenPolynomial<GenPolynomial<C>>> rpgb = PolyUtil.<C> recursive(rfac, plist); 2529 //System.out.println("rfac = " + rfac); 2530 GenPolynomialRing<Quotient<C>> qpfac = new GenPolynomialRing<Quotient<C>>(qfac, rfac); 2531 List<GenPolynomial<Quotient<C>>> qpgb = PolyUfdUtil.<C> quotientFromIntegralCoefficients(qpfac, rpgb); 2532 //System.out.println("qpfac = " + qpfac); 2533 2534 // compute f 2535 GreatestCommonDivisor<C> ufd = GCDFactory.getImplementation(fac.coFac); 2536 GenPolynomial<C> f = null; // qfac.ring.getONE(); 2537 for (GenPolynomial<GenPolynomial<C>> p : rpgb) { 2538 if (f == null) { 2539 f = p.leadingBaseCoefficient(); 2540 } else { 2541 f = ufd.lcm(f, p.leadingBaseCoefficient()); 2542 } 2543 } 2544 //SquarefreeAbstract<C> sqf = SquarefreeFactory.getImplementation(fac.coFac); 2545 //not required: f = sqf.squarefreePart(f); 2546 GenPolynomial<GenPolynomial<C>> fp = rfac.getONE().multiply(f); 2547 GenPolynomial<Quotient<C>> fq = PolyUfdUtil.<C> quotientFromIntegralCoefficients(qpfac, fp); 2548 logger.info("extension f = {}", f); 2549 logger.info("ext = {}", qpgb); 2550 List<GenPolynomial<Quotient<C>>> upols = new ArrayList<GenPolynomial<Quotient<C>>>(0); 2551 List<GenPolynomial<Quotient<C>>> opols = new ArrayList<GenPolynomial<Quotient<C>>>(1); 2552 opols.add(fq); 2553 2554 qpgb = PolyUtil.<Quotient<C>> monic(qpgb); 2555 Ideal<Quotient<C>> ext = new Ideal<Quotient<C>>(qpfac, qpgb); 2556 IdealWithUniv<Quotient<C>> extu = new IdealWithUniv<Quotient<C>>(ext, upols, opols); 2557 return extu; 2558 } 2559 2560 2561 /** 2562 * Ideal contraction and permutation. 2563 * @param eideal extension ideal of this. 2564 * @return contraction ideal of eideal in this polynomial ring 2565 */ 2566 public IdealWithUniv<C> permContraction(IdealWithUniv<Quotient<C>> eideal) { 2567 return Ideal.<C> permutation(getRing(), Ideal.<C> contraction(eideal)); 2568 } 2569 2570 2571 /** 2572 * Ideal contraction. 2573 * @param eid extension ideal of this. 2574 * @return contraction ideal of eid in distributed polynomial ring 2575 */ 2576 public static <C extends GcdRingElem<C>> IdealWithUniv<C> contraction(IdealWithUniv<Quotient<C>> eid) { 2577 Ideal<Quotient<C>> eideal = eid.ideal; 2578 List<GenPolynomial<Quotient<C>>> qgb = eideal.getList(); 2579 QuotientRing<C> qfac = (QuotientRing<C>) eideal.getRing().coFac; 2580 GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(qfac.ring, 2581 eideal.getRing()); 2582 GenPolynomialRing<C> dfac = qfac.ring.extend(eideal.getRing().getVars()); 2583 TermOrder to = new TermOrder(qfac.ring.tord.getEvord()); 2584 dfac = new GenPolynomialRing<C>(dfac.coFac, dfac.nvar, to, dfac.getVars()); 2585 //System.out.println("qfac = " + qfac); 2586 //System.out.println("rfac = " + rfac); 2587 //System.out.println("dfac = " + dfac); 2588 // convert polynomials 2589 List<GenPolynomial<GenPolynomial<C>>> cgb = PolyUfdUtil.<C> integralFromQuotientCoefficients(rfac, 2590 qgb); 2591 List<GenPolynomial<C>> dgb = PolyUtil.<C> distribute(dfac, cgb); 2592 Ideal<C> cont = new Ideal<C>(dfac, dgb); 2593 // convert other polynomials 2594 List<GenPolynomial<C>> opols = new ArrayList<GenPolynomial<C>>(); 2595 if (eid.others != null && eid.others.size() > 0) { 2596 List<GenPolynomial<GenPolynomial<C>>> orpol = PolyUfdUtil 2597 .<C> integralFromQuotientCoefficients(rfac, eid.others); 2598 List<GenPolynomial<C>> opol = PolyUtil.<C> distribute(dfac, orpol); 2599 opols.addAll(opol); 2600 } 2601 // convert univariate polynomials 2602 List<GenPolynomial<C>> upols = new ArrayList<GenPolynomial<C>>(0); 2603 int i = 0; 2604 for (GenPolynomial<Quotient<C>> p : eid.upolys) { 2605 GenPolynomial<Quotient<C>> pm = p.extendUnivariate(eideal.getRing(), i++); 2606 //System.out.println("pm = " + pm + ", p = " + p); 2607 GenPolynomial<GenPolynomial<C>> urpol = PolyUfdUtil.<C> integralFromQuotientCoefficients(rfac, 2608 pm); 2609 GenPolynomial<C> upol = PolyUtil.<C> distribute(dfac, urpol); 2610 upols.add(upol); 2611 //System.out.println("upol = " + upol); 2612 } 2613 // compute f 2614 GreatestCommonDivisor<C> ufd = GCDFactory.getImplementation(qfac.ring.coFac); 2615 GenPolynomial<C> f = null; // qfac.ring.getONE(); 2616 for (GenPolynomial<GenPolynomial<C>> p : cgb) { 2617 if (f == null) { 2618 f = p.leadingBaseCoefficient(); 2619 } else { 2620 f = ufd.lcm(f, p.leadingBaseCoefficient()); 2621 } 2622 } 2623 GenPolynomial<GenPolynomial<C>> fp = rfac.getONE().multiply(f); 2624 f = PolyUtil.<C> distribute(dfac, fp); 2625 logger.info("contraction f = {}", f); 2626 logger.info("cont = {}", cont); 2627 opols.add(f); 2628 if (f.isONE()) { 2629 IdealWithUniv<C> cf = new IdealWithUniv<C>(cont, upols, opols); 2630 return cf; 2631 } 2632 // compute ideal quotient by f 2633 Ideal<C> Q = cont.infiniteQuotientRab(f); 2634 IdealWithUniv<C> Qu = new IdealWithUniv<C>(Q, upols, opols); 2635 return Qu; 2636 } 2637 2638 2639 /** 2640 * Ideal permutation. 2641 * @param oring polynomial ring to which variables are back permuted. 2642 * @param Cont ideal to be permuted 2643 * @return permutation of cont in polynomial ring oring 2644 */ 2645 public static <C extends GcdRingElem<C>> IdealWithUniv<C> permutation(GenPolynomialRing<C> oring, 2646 IdealWithUniv<C> Cont) { 2647 Ideal<C> cont = Cont.ideal; 2648 GenPolynomialRing<C> dfac = cont.getRing(); 2649 // (back) permutation of variables 2650 String[] ovars = oring.getVars(); 2651 String[] dvars = dfac.getVars(); 2652 //System.out.println("ovars = " + Arrays.toString(ovars)); 2653 //System.out.println("dvars = " + Arrays.toString(dvars)); 2654 if (Arrays.deepEquals(ovars, dvars)) { // nothing to do 2655 return Cont; 2656 } 2657 List<Integer> perm = GroebnerBasePartial.getPermutation(dvars, ovars); 2658 //System.out.println("perm = " + perm); 2659 GenPolynomialRing<C> pfac = cont.getRing().permutation(perm); 2660 logger.info("pfac = {}", pfac); 2661 List<GenPolynomial<C>> ppolys = TermOrderOptimization.<C> permutation(perm, pfac, cont.getList()); 2662 //System.out.println("ppolys = " + ppolys); 2663 cont = new Ideal<C>(pfac, ppolys); 2664 if (logger.isDebugEnabled()) { 2665 logger.info("perm cont = {}", cont); 2666 } 2667 List<GenPolynomial<C>> opolys = TermOrderOptimization.<C> permutation(perm, pfac, Cont.others); 2668 //System.out.println("opolys = " + opolys); 2669 List<GenPolynomial<C>> upolys = TermOrderOptimization.<C> permutation(perm, pfac, Cont.upolys); 2670 //System.out.println("opolys = " + opolys); 2671 IdealWithUniv<C> Cu = new IdealWithUniv<C>(cont, upolys, opolys); 2672 return Cu; 2673 } 2674 2675 2676 /** 2677 * Ideal radical. 2678 * @return the radical ideal of this 2679 */ 2680 public Ideal<C> radical() { 2681 List<IdealWithUniv<C>> rdec = radicalDecomposition(); 2682 List<Ideal<C>> dec = new ArrayList<Ideal<C>>(rdec.size()); 2683 for (IdealWithUniv<C> ru : rdec) { 2684 dec.add(ru.ideal); 2685 } 2686 Ideal<C> R = intersect(dec); 2687 return R; 2688 } 2689 2690 2691 /** 2692 * Ideal radical decompostition. 2693 * @return intersection of ideals G_i with radical(this) eq cap_i( 2694 * ideal(G_i) ) and each G_i is a radical ideal and the G_i are 2695 * pairwise co-prime 2696 */ 2697 public List<IdealWithUniv<C>> radicalDecomposition() { 2698 // check dimension 2699 int z = commonZeroTest(); 2700 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2701 List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 2702 // dimension -1 2703 if (z < 0) { 2704 IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 2705 dec.add(id); // see GB book 2706 return dec; 2707 } 2708 // dimension 0 2709 if (z == 0) { 2710 dec = zeroDimRadicalDecomposition(); 2711 return dec; 2712 } 2713 // dimension > 0 2714 if (this.isZERO()) { 2715 return dec; 2716 } 2717 if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { 2718 // must not be the case at this point 2719 logger.warn("must use prime decomposition for char p and infinite coefficient rings, found {}", 2720 list.ring.coFac.toScript()); 2721 return primeDecomposition(); 2722 } 2723 Dimension dim = dimension(); 2724 logger.info("dimension = {}", dim); 2725 2726 // a short maximal independent set with small variables 2727 Set<Set<Integer>> M = dim.M; 2728 Set<Integer> min = null; 2729 for (Set<Integer> m : M) { 2730 if (min == null) { 2731 min = m; 2732 continue; 2733 } 2734 if (m.size() < min.size()) { 2735 min = m; 2736 } 2737 } 2738 int ms = min.size(); 2739 Integer[] ia = new Integer[0]; 2740 int mx = min.toArray(ia)[ms - 1]; 2741 for (Set<Integer> m : M) { 2742 if (m.size() == ms) { 2743 int mxx = m.toArray(ia)[ms - 1]; 2744 if (mxx < mx) { 2745 min = m; 2746 mx = mxx; 2747 } 2748 } 2749 } 2750 //System.out.println("min = " + min); 2751 String[] mvars = new String[min.size()]; 2752 int j = 0; 2753 for (Integer i : min) { 2754 mvars[j++] = dim.v[i]; 2755 } 2756 logger.info("extension for variables = {}, indexes = {}", Arrays.toString(mvars), min); 2757 // reduce to dimension zero 2758 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 2759 logger.info("extension = {}", Ext); 2760 2761 List<IdealWithUniv<Quotient<C>>> edec = Ext.ideal.zeroDimRadicalDecomposition(); 2762 logger.info("0-dim radical decomp = {}", edec); 2763 // remove field extensions are not required 2764 // reconstruct dimension 2765 for (IdealWithUniv<Quotient<C>> ep : edec) { 2766 IdealWithUniv<C> cont = permContraction(ep); 2767 //System.out.println("cont = " + cont); 2768 dec.add(cont); 2769 } 2770 IdealWithUniv<C> extcont = permContraction(Ext); 2771 //System.out.println("extcont = " + extcont); 2772 2773 // get f 2774 List<GenPolynomial<C>> ql = extcont.others; 2775 if (ql.size() == 0) { // should not happen 2776 return dec; 2777 } 2778 GenPolynomial<C> fx = ql.get(0); 2779 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 2780 if (fx.isONE()) { 2781 return dec; 2782 } 2783 Ideal<C> T = sum(fx); 2784 //System.out.println("T.rec = " + T.getList()); 2785 if (T.isONE()) { 2786 logger.info("1 in ideal for {}", fx); 2787 return dec; 2788 } 2789 logger.info("radical decomp ext-cont fx = {}", fx); 2790 logger.info("recursion radical decomp T = {}", T); 2791 // recursion: 2792 List<IdealWithUniv<C>> Tdec = T.radicalDecomposition(); 2793 logger.info("recursion radical decomp = {}", Tdec); 2794 dec.addAll(Tdec); 2795 return dec; 2796 } 2797 2798 2799 /** 2800 * Ideal irreducible decompostition. 2801 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2802 * ideal(G_i) ) and each G_i is an ideal with irreducible univariate 2803 * polynomials (after extension to a zero dimensional ideal) and the 2804 * G_i are pairwise co-prime 2805 */ 2806 public List<IdealWithUniv<C>> decomposition() { 2807 // check dimension 2808 int z = commonZeroTest(); 2809 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2810 // dimension -1 2811 if (z < 0) { 2812 //List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 2813 //IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 2814 //dec.add(id); see GB book 2815 return dec; 2816 } 2817 // dimension 0 2818 if (z == 0) { 2819 dec = zeroDimDecomposition(); 2820 return dec; 2821 } 2822 // dimension > 0 2823 if (this.isZERO()) { 2824 return dec; 2825 } 2826 Dimension dim = dimension(); 2827 logger.info("dimension = {}", dim); 2828 2829 // shortest maximal independent set 2830 Set<Set<Integer>> M = dim.M; 2831 Set<Integer> min = null; 2832 for (Set<Integer> m : M) { 2833 if (min == null) { 2834 min = m; 2835 continue; 2836 } 2837 if (m.size() < min.size()) { 2838 min = m; 2839 } 2840 } 2841 //System.out.println("min = " + min); 2842 String[] mvars = new String[min.size()]; 2843 int j = 0; 2844 for (Integer i : min) { 2845 mvars[j++] = dim.v[i]; 2846 } 2847 logger.info("extension for variables = {}", Arrays.toString(mvars)); 2848 // reduce to dimension zero 2849 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 2850 logger.info("extension = {}", Ext); 2851 2852 List<IdealWithUniv<Quotient<C>>> edec = Ext.ideal.zeroDimDecomposition(); 2853 logger.info("0-dim irred decomp = {}", edec); 2854 // remove field extensions are not required 2855 // reconstruct dimension 2856 for (IdealWithUniv<Quotient<C>> ep : edec) { 2857 IdealWithUniv<C> cont = permContraction(ep); 2858 //System.out.println("cont = " + cont); 2859 dec.add(cont); 2860 } 2861 IdealWithUniv<C> extcont = permContraction(Ext); 2862 //System.out.println("extcont = " + extcont); 2863 2864 // get f 2865 List<GenPolynomial<C>> ql = extcont.others; 2866 if (ql.size() == 0) { // should not happen 2867 return dec; 2868 } 2869 GenPolynomial<C> fx = ql.get(0); 2870 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 2871 if (fx.isONE()) { 2872 return dec; 2873 } 2874 Ideal<C> T = sum(fx); 2875 //System.out.println("T.rec = " + T.getList()); 2876 if (T.isONE()) { 2877 logger.info("1 in ideal for {}", fx); 2878 return dec; 2879 } 2880 logger.info("irred decomp ext-cont fx = {}", fx); 2881 logger.info("recursion irred decomp T = {}", T); 2882 // recursion: 2883 List<IdealWithUniv<C>> Tdec = T.decomposition(); 2884 logger.info("recursion irred decomposition = {}", Tdec); 2885 dec.addAll(Tdec); 2886 return dec; 2887 } 2888 2889 2890 /** 2891 * Ideal prime decompostition. 2892 * @return intersection of ideals G_i with ideal(this) subseteq cap_i( 2893 * ideal(G_i) ) and each G_i is a prime ideal and the G_i are 2894 * pairwise co-prime 2895 */ 2896 public List<IdealWithUniv<C>> primeDecomposition() { 2897 // check dimension 2898 int z = commonZeroTest(); 2899 List<IdealWithUniv<C>> dec = new ArrayList<IdealWithUniv<C>>(); 2900 // dimension -1 2901 if (z < 0) { 2902 //List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 2903 //IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 2904 //dec.add(id); see GB book 2905 return dec; 2906 } 2907 // dimension 0 2908 if (z == 0) { 2909 dec = zeroDimPrimeDecomposition(); 2910 return dec; 2911 } 2912 // dimension > 0 2913 if (this.isZERO()) { 2914 return dec; 2915 } 2916 Dimension dim = dimension(); 2917 logger.info("dimension = {}", dim); 2918 2919 // shortest maximal independent set 2920 Set<Set<Integer>> M = dim.M; 2921 Set<Integer> min = null; 2922 for (Set<Integer> m : M) { 2923 if (min == null) { 2924 min = m; 2925 continue; 2926 } 2927 if (m.size() < min.size()) { 2928 min = m; 2929 } 2930 } 2931 //System.out.println("min = " + min); 2932 String[] mvars = new String[min.size()]; 2933 int j = 0; 2934 for (Integer i : min) { 2935 mvars[j++] = dim.v[i]; 2936 } 2937 logger.info("extension for variables = {}", Arrays.toString(mvars)); 2938 // reduce to dimension zero 2939 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 2940 logger.info("extension = {}", Ext); 2941 List<IdealWithUniv<Quotient<C>>> edec = Ext.ideal.zeroDimPrimeDecomposition(); 2942 logger.info("0-dim prime decomp = {}", edec); 2943 // remove field extensions, already done 2944 // reconstruct dimension 2945 for (IdealWithUniv<Quotient<C>> ep : edec) { 2946 IdealWithUniv<C> cont = permContraction(ep); 2947 //System.out.println("cont = " + cont); 2948 dec.add(cont); 2949 } 2950 // get f 2951 IdealWithUniv<C> extcont = permContraction(Ext); 2952 //System.out.println("extcont = " + extcont); 2953 List<GenPolynomial<C>> ql = extcont.others; 2954 if (ql.size() == 0) { // should not happen 2955 return dec; 2956 } 2957 GenPolynomial<C> fx = ql.get(0); 2958 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 2959 if (fx.isONE()) { 2960 return dec; 2961 } 2962 // compute exponent not required 2963 Ideal<C> T = sum(fx); 2964 //System.out.println("T.rec = " + T.getList()); 2965 if (T.isONE()) { 2966 logger.info("1 in ideal for {}", fx); 2967 return dec; 2968 } 2969 logger.info("prime decomp ext-cont fx = {}", fx); 2970 logger.info("recursion prime decomp T = {}", T); 2971 // recursion: 2972 List<IdealWithUniv<C>> Tdec = T.primeDecomposition(); 2973 logger.info("recursion prime decomp = {}", Tdec); 2974 dec.addAll(Tdec); 2975 return dec; 2976 } 2977 2978 2979 /** 2980 * Test for ideal decompostition. 2981 * @param L intersection of ideals G_i with ideal(G) eq cap_i(ideal(G_i) ) 2982 * @return true if L is a decomposition of this, else false 2983 */ 2984 public boolean isDecomposition(List<IdealWithUniv<C>> L) { 2985 if (L == null || L.size() == 0) { 2986 if (this.isZERO()) { 2987 return true; 2988 } 2989 return false; 2990 } 2991 GenPolynomialRing<C> ofac = list.ring; 2992 int r = ofac.nvar; 2993 int rp = L.get(0).ideal.list.ring.nvar; 2994 int d = rp - r; 2995 //System.out.println("d = " + d); 2996 Ideal<C> Id = this; 2997 if (d > 0) { // add lower variables 2998 GenPolynomialRing<C> nfac = ofac.extendLower(d); 2999 //System.out.println("nfac = " + nfac); 3000 List<GenPolynomial<C>> elist = new ArrayList<GenPolynomial<C>>(list.list.size()); 3001 for (GenPolynomial<C> p : getList()) { 3002 //System.out.println("p = " + p); 3003 GenPolynomial<C> q = p.extendLower(nfac, 0, 0L); 3004 //System.out.println("q = " + q); 3005 elist.add(q); 3006 } 3007 Id = new Ideal<C>(nfac, elist, isGB, isTopt); 3008 } 3009 3010 // test if this is contained in the intersection 3011 for (IdealWithUniv<C> I : L) { 3012 boolean t = I.ideal.contains(Id); 3013 if (!t) { 3014 System.out.println("not contained " + this + " in " + I.ideal); 3015 return false; 3016 } 3017 } 3018 // // test if all univariate polynomials are contained in the respective ideal 3019 // for (IdealWithUniv<C> I : L) { 3020 // GenPolynomialRing<C> mfac = I.ideal.list.ring; 3021 // int i = 0; 3022 // for (GenPolynomial<C> p : I.upolys) { 3023 // GenPolynomial<C> pm = p.extendUnivariate(mfac, i++); 3024 // //System.out.println("pm = " + pm + ", p = " + p); 3025 // boolean t = I.ideal.contains(pm); 3026 // if (!t) { 3027 // System.out.println("not contained " + pm + " in " + I.ideal); 3028 // return false; 3029 // } 3030 // } 3031 // } 3032 return true; 3033 } 3034 3035 3036 /** 3037 * Ideal primary decompostition. 3038 * @return list of primary components of primary ideals G_i (pairwise 3039 * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with 3040 * the associated primes 3041 */ 3042 public List<PrimaryComponent<C>> primaryDecomposition() { 3043 // check dimension 3044 int z = commonZeroTest(); 3045 List<PrimaryComponent<C>> dec = new ArrayList<PrimaryComponent<C>>(); 3046 // dimension -1 3047 if (z < 0) { 3048 //List<GenPolynomial<C>> ups = new ArrayList<GenPolynomial<C>>(); 3049 //IdealWithUniv<C> id = new IdealWithUniv<C>(this, ups); 3050 //PrimaryComponent<C> pc = new PrimaryComponent<C>(this, id); 3051 //dec.add(pc); see GB book 3052 return dec; 3053 } 3054 // dimension 0 3055 if (z == 0) { 3056 dec = zeroDimPrimaryDecomposition(); 3057 return dec; 3058 } 3059 // dimension > 0 3060 if (this.isZERO()) { 3061 return dec; 3062 } 3063 Dimension dim = dimension(); 3064 logger.info("dimension = {}", dim); 3065 3066 // shortest maximal independent set 3067 Set<Set<Integer>> M = dim.M; 3068 Set<Integer> min = null; 3069 for (Set<Integer> m : M) { 3070 if (min == null) { 3071 min = m; 3072 continue; 3073 } 3074 if (m.size() < min.size()) { 3075 min = m; 3076 } 3077 } 3078 //System.out.println("min = " + min); 3079 String[] mvars = new String[min.size()]; 3080 int j = 0; 3081 for (Integer i : min) { 3082 mvars[j++] = dim.v[i]; 3083 } 3084 logger.info("extension for variables = {}", Arrays.toString(mvars)); 3085 // reduce to dimension zero 3086 IdealWithUniv<Quotient<C>> Ext = extension(mvars); 3087 logger.info("extension = {}", Ext); 3088 3089 List<PrimaryComponent<Quotient<C>>> edec = Ext.ideal.zeroDimPrimaryDecomposition(); 3090 logger.info("0-dim primary decomp = {}", edec); 3091 // remove field extensions, already done 3092 // reconstruct dimension 3093 List<GenPolynomial<Quotient<C>>> upq = new ArrayList<GenPolynomial<Quotient<C>>>(); 3094 for (PrimaryComponent<Quotient<C>> ep : edec) { 3095 IdealWithUniv<Quotient<C>> epu = new IdealWithUniv<Quotient<C>>(ep.primary, upq); 3096 IdealWithUniv<C> contq = permContraction(epu); 3097 IdealWithUniv<C> contp = permContraction(ep.prime); 3098 PrimaryComponent<C> pc = new PrimaryComponent<C>(contq.ideal, contp); 3099 //System.out.println("pc = " + pc); 3100 dec.add(pc); 3101 } 3102 3103 // get f 3104 IdealWithUniv<C> extcont = permContraction(Ext); 3105 if (debug) { 3106 logger.info("cont(Ext) = {}", extcont); 3107 } 3108 List<GenPolynomial<C>> ql = extcont.others; 3109 if (ql.size() == 0) { // should not happen 3110 return dec; 3111 } 3112 GenPolynomial<C> fx = ql.get(0); 3113 //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); 3114 if (fx.isONE()) { 3115 return dec; 3116 } 3117 // compute exponent 3118 int s = this.infiniteQuotientExponent(fx, extcont.ideal); 3119 if (s == 0) { 3120 logger.info("exponent is 0 "); 3121 return dec; 3122 } 3123 if (s > 1) { 3124 fx = fx.power(s); 3125 } 3126 if (debug) { 3127 logger.info("exponent fx = {}", s + ", fx^s = {}", fx); 3128 } 3129 3130 Ideal<C> T = sum(fx); 3131 //System.out.println("T.rec = " + T.getList()); 3132 if (T.isONE()) { 3133 logger.info("1 in ideal for {}", fx); 3134 return dec; 3135 } 3136 logger.info("primmary decomp ext-cont fx = {}", fx); 3137 logger.info("recursion primary decomp T = {}", T); 3138 // recursion: 3139 List<PrimaryComponent<C>> Tdec = T.primaryDecomposition(); 3140 logger.info("recursion primary decomp = {}", Tdec); 3141 dec.addAll(Tdec); 3142 return dec; 3143 } 3144 3145}