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