001/* 002 * $Id: SolvableIdeal.java 5868 2018-07-20 15:44:13Z kredel $ 003 */ 004 005package edu.jas.application; 006 007 008import java.io.Serializable; 009import java.util.ArrayList; 010import java.util.List; 011 012import org.apache.logging.log4j.Logger; 013import org.apache.logging.log4j.LogManager; 014 015import edu.jas.gb.SolvableExtendedGB; 016import edu.jas.gb.SolvableGroebnerBaseAbstract; 017import edu.jas.gb.SolvableReduction; 018import edu.jas.gb.SolvableReductionSeq; 019import edu.jas.gbufd.PolyGBUtil; 020import edu.jas.gbufd.SGBFactory; 021import edu.jas.gbufd.SolvableSyzygyAbstract; 022import edu.jas.gbufd.SolvableSyzygySeq; 023import edu.jas.poly.GenSolvablePolynomial; 024import edu.jas.poly.GenSolvablePolynomialRing; 025import edu.jas.poly.PolyUtil; 026import edu.jas.poly.PolynomialList; 027import edu.jas.structure.GcdRingElem; 028import edu.jas.structure.NotInvertibleException; 029 030 031/** 032 * Solvable Ideal implements some methods for ideal arithmetic, for example sum, 033 * intersection, quotient. <b>Note:</b> only left ideals at the moment. 034 * @author Heinz Kredel 035 */ 036public class SolvableIdeal<C extends GcdRingElem<C>> implements Comparable<SolvableIdeal<C>>, Serializable { 037 038 039 private static final Logger logger = LogManager.getLogger(SolvableIdeal.class); 040 041 042 private static final boolean debug = logger.isDebugEnabled(); 043 044 045 /** 046 * Side variant of ideal. 047 */ 048 public static enum Side { 049 left, right, twosided 050 } 051 052 053 /** 054 * The data structure is a PolynomialList. 055 */ 056 protected PolynomialList<C> list; 057 058 059 /** 060 * Indicator if list is a Groebner Base. 061 */ 062 protected boolean isGB; 063 064 065 /** 066 * Indicator of side of Groebner Base. 067 */ 068 protected Side sided; 069 070 071 /** 072 * Indicator if test has been performed if this is a Groebner Base. 073 */ 074 protected boolean testGB; 075 076 077 /** 078 * Indicator if list has optimized term order. 079 */ 080 protected boolean isTopt; 081 082 083 /** 084 * Groebner base engine. 085 */ 086 protected final SolvableGroebnerBaseAbstract<C> bb; 087 088 089 /** 090 * Reduction engine. 091 */ 092 protected final SolvableReduction<C> red; 093 094 095 /** 096 * Constructor. 097 * @param ring solvable polynomial ring 098 */ 099 public SolvableIdeal(GenSolvablePolynomialRing<C> ring) { 100 this(ring, new ArrayList<GenSolvablePolynomial<C>>()); 101 } 102 103 104 /** 105 * Constructor. 106 * @param ring solvable polynomial ring 107 * @param F list of solvable polynomials 108 */ 109 public SolvableIdeal(GenSolvablePolynomialRing<C> ring, List<GenSolvablePolynomial<C>> F) { 110 this(new PolynomialList<C>(ring, F)); 111 } 112 113 114 /** 115 * Constructor. 116 * @param ring solvable polynomial ring 117 * @param F list of solvable polynomials 118 * @param gb true if F is known to be a Groebner Base, else false 119 */ 120 public SolvableIdeal(GenSolvablePolynomialRing<C> ring, List<GenSolvablePolynomial<C>> F, boolean gb) { 121 this(new PolynomialList<C>(ring, F), gb); 122 } 123 124 125 /** 126 * Constructor. 127 * @param ring solvable polynomial ring 128 * @param F list of solvable polynomials 129 * @param gb true if F is known to be a Groebner Base, else false 130 * @param topt true if term order is optimized, else false 131 */ 132 public SolvableIdeal(GenSolvablePolynomialRing<C> ring, List<GenSolvablePolynomial<C>> F, boolean gb, 133 boolean topt) { 134 this(new PolynomialList<C>(ring, F), gb, topt); 135 } 136 137 138 /** 139 * Constructor. 140 * @param ring solvable polynomial ring 141 * @param F list of solvable polynomials 142 * @param s side variant of ideal or Groebner Base 143 */ 144 public SolvableIdeal(GenSolvablePolynomialRing<C> ring, List<GenSolvablePolynomial<C>> F, Side s) { 145 this(new PolynomialList<C>(ring, F), false, false, s); 146 } 147 148 149 /** 150 * Constructor. 151 * @param ring solvable polynomial ring 152 * @param F list of solvable polynomials 153 * @param gb true if F is known to be a Groebner Base, else false 154 * @param s side variant of ideal or Groebner Base 155 */ 156 public SolvableIdeal(GenSolvablePolynomialRing<C> ring, List<GenSolvablePolynomial<C>> F, boolean gb, 157 Side s) { 158 this(new PolynomialList<C>(ring, F), gb, false, s); 159 } 160 161 162 /** 163 * Constructor. 164 * @param list solvable polynomial list 165 */ 166 public SolvableIdeal(PolynomialList<C> list) { 167 this(list, false); 168 } 169 170 171 /** 172 * Constructor. 173 * @param list solvable polynomial list 174 * @param bb Groebner Base engine 175 * @param red Reduction engine 176 */ 177 public SolvableIdeal(PolynomialList<C> list, SolvableGroebnerBaseAbstract<C> bb, 178 SolvableReduction<C> red) { 179 this(list, false, bb, red); 180 } 181 182 183 /** 184 * Constructor. 185 * @param list solvable polynomial list 186 * @param gb true if list is known to be a Groebner Base, else false 187 */ 188 public SolvableIdeal(PolynomialList<C> list, boolean gb) { 189 //this(list, gb, new SolvableGroebnerBaseSeq<C>(), new SolvableReductionSeq<C>()); 190 this(list, gb, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq<C>()); 191 } 192 193 194 /** 195 * Constructor. 196 * @param list solvable polynomial list 197 * @param gb true if list is known to be a Groebner Base, else false 198 * @param topt true if term order is optimized, else false 199 */ 200 public SolvableIdeal(PolynomialList<C> list, boolean gb, boolean topt) { 201 //this(list, gb, topt, new SolvableGroebnerBaseSeq<C>(), new SolvableReductionSeq<C>()); 202 this(list, gb, topt, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq<C>()); 203 } 204 205 206 /** 207 * Constructor. 208 * @param list solvable polynomial list 209 * @param gb true if list is known to be a Groebner Base, else false 210 * @param s side variant of ideal or Groebner Base 211 */ 212 public SolvableIdeal(PolynomialList<C> list, boolean gb, Side s) { 213 //this(list, gb, false, new SolvableGroebnerBaseSeq<C>(), new SolvableReductionSeq<C>()); 214 this(list, gb, false, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq<C>(), 215 s); 216 } 217 218 219 /** 220 * Constructor. 221 * @param list solvable polynomial list 222 * @param gb true if list is known to be a Groebner Base, else false 223 * @param topt true if term order is optimized, else false 224 * @param s side variant of ideal or Groebner Base 225 */ 226 public SolvableIdeal(PolynomialList<C> list, boolean gb, boolean topt, Side s) { 227 //this(list, gb, topt, new SolvableGroebnerBaseSeq<C>(), new SolvableReductionSeq<C>()); 228 this(list, gb, topt, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq<C>(), s); 229 } 230 231 232 /** 233 * Constructor. 234 * @param list solvable polynomial list 235 * @param gb true if list is known to be a Groebner Base, else false 236 * @param bb Groebner Base engine 237 * @param red Reduction engine 238 */ 239 public SolvableIdeal(PolynomialList<C> list, boolean gb, SolvableGroebnerBaseAbstract<C> bb, 240 SolvableReduction<C> red) { 241 this(list, gb, false, bb, red); 242 } 243 244 245 /** 246 * Constructor. 247 * @param list solvable polynomial list 248 * @param gb true if list is known to be a Groebner Base, else false 249 * @param bb Groebner Base engine 250 */ 251 public SolvableIdeal(PolynomialList<C> list, boolean gb, SolvableGroebnerBaseAbstract<C> bb) { 252 this(list, gb, false, bb, bb.sred); 253 } 254 255 256 /** 257 * Constructor. 258 * @param list solvable polynomial list 259 * @param gb true if list is known to be a Groebner Base, else false 260 * @param topt true if term order is optimized, else false 261 * @param bb Groebner Base engine 262 */ 263 public SolvableIdeal(PolynomialList<C> list, boolean gb, boolean topt, 264 SolvableGroebnerBaseAbstract<C> bb) { 265 this(list, gb, topt, bb, bb.sred); 266 } 267 268 269 /** 270 * Constructor. 271 * @param list solvable polynomial list 272 * @param gb true if list is known to be a Groebner Base, else false 273 * @param topt true if term order is optimized, else false 274 * @param bb Groebner Base engine 275 * @param red Reduction engine 276 */ 277 public SolvableIdeal(PolynomialList<C> list, boolean gb, boolean topt, SolvableGroebnerBaseAbstract<C> bb, 278 SolvableReduction<C> red) { 279 this(list, gb, topt, bb, red, Side.left); 280 } 281 282 283 /** 284 * Constructor. 285 * @param list solvable polynomial list 286 * @param gb true if list is known to be a Groebner Base, else false 287 * @param topt true if term order is optimized, else false 288 * @param bb Groebner Base engine 289 * @param red Reduction engine 290 * @param s side variant of ideal or Groebner Base 291 */ 292 public SolvableIdeal(PolynomialList<C> list, boolean gb, boolean topt, SolvableGroebnerBaseAbstract<C> bb, 293 SolvableReduction<C> red, Side s) { 294 if (list == null || list.list == null) { 295 throw new IllegalArgumentException("list and list.list may not be null"); 296 } 297 this.list = list; 298 this.isGB = gb; 299 this.isTopt = topt; 300 this.testGB = (gb ? true : false); // ?? 301 this.bb = bb; 302 this.red = red; 303 if (s == null) { 304 s = Side.left; // default 305 } 306 this.sided = s; 307 } 308 309 310 /** 311 * Clone this. 312 * @return a copy of this. 313 */ 314 public SolvableIdeal<C> copy() { 315 return new SolvableIdeal<C>(list.copy(), isGB, isTopt, bb, red, sided); 316 } 317 318 319 /** 320 * Get the List of GenSolvablePolynomials. 321 * @return (cast) list.list 322 */ 323 public List<GenSolvablePolynomial<C>> getList() { 324 return list.getSolvableList(); 325 } 326 327 328 /** 329 * Get the GenSolvablePolynomialRing. 330 * @return (cast) list.ring 331 */ 332 public GenSolvablePolynomialRing<C> getRing() { 333 return list.getSolvableRing(); 334 } 335 336 337 /** 338 * Get the zero ideal. 339 * @return ideal(0) 340 */ 341 public SolvableIdeal<C> getZERO() { 342 List<GenSolvablePolynomial<C>> z = new ArrayList<GenSolvablePolynomial<C>>(0); 343 PolynomialList<C> pl = new PolynomialList<C>(getRing(), z); 344 return new SolvableIdeal<C>(pl, true, isTopt, bb, red, sided); 345 } 346 347 348 /** 349 * Get the one ideal. 350 * @return ideal(1) 351 */ 352 public SolvableIdeal<C> getONE() { 353 List<GenSolvablePolynomial<C>> one = new ArrayList<GenSolvablePolynomial<C>>(1); 354 one.add(getRing().getONE()); 355 PolynomialList<C> pl = new PolynomialList<C>(getRing(), one); 356 return new SolvableIdeal<C>(pl, true, isTopt, bb, red, sided); 357 } 358 359 360 /** 361 * String representation of the solvable ideal. 362 * @see java.lang.Object#toString() 363 */ 364 @Override 365 public String toString() { 366 return list.toString() + " # " + sided; 367 } 368 369 370 /** 371 * Get a scripting compatible string representation. 372 * @return script compatible representation for this Element. 373 * @see edu.jas.structure.Element#toScript() 374 */ 375 public String toScript() { 376 // any script case 377 return list.toScript() + " # " + sided; 378 } 379 380 381 /** 382 * Comparison with any other object. <b>Note:</b> If not both ideals are 383 * Groebner Bases, then false may be returned even the ideals are equal. 384 * @see java.lang.Object#equals(java.lang.Object) 385 */ 386 @Override 387 @SuppressWarnings("unchecked") 388 public boolean equals(Object b) { 389 if (!(b instanceof SolvableIdeal)) { 390 logger.warn("equals no Ideal"); 391 return false; 392 } 393 SolvableIdeal<C> B = null; 394 try { 395 B = (SolvableIdeal<C>) b; 396 } catch (ClassCastException ignored) { 397 return false; 398 } 399 //if ( isGB && B.isGB ) { 400 // return list.equals( B.list ); requires also monic polys 401 //} else { // compute GBs ? 402 return this.contains(B) && B.contains(this); 403 //} 404 } 405 406 407 /** 408 * SolvableIdeal comparison. 409 * @param L other solvable ideal. 410 * @return compareTo() of polynomial lists. 411 */ 412 public int compareTo(SolvableIdeal<C> L) { 413 return list.compareTo(L.list); 414 } 415 416 417 /** 418 * Hash code for this solvable ideal. 419 * @see java.lang.Object#hashCode() 420 */ 421 @Override 422 public int hashCode() { 423 int h; 424 h = list.hashCode(); 425 if (isGB) { 426 h = h << 1; 427 } 428 if (testGB) { 429 h += 1; 430 } 431 return h; 432 } 433 434 435 /** 436 * Test if ZERO ideal. 437 * @return true, if this is the 0 ideal, else false 438 */ 439 public boolean isZERO() { 440 return list.isZERO(); 441 } 442 443 444 /** 445 * Test if ONE is contained in the ideal. To test for a proper ideal use 446 * <code>! id.isONE()</code>. 447 * @return true, if this is the 1 ideal, else false 448 */ 449 public boolean isONE() { 450 return list.isONE(); 451 } 452 453 454 /** 455 * Test if this is a left Groebner base. 456 * @return true, if this is a left Groebner base, else false 457 */ 458 public boolean isGB() { 459 if (testGB && sided == Side.left) { 460 return isGB; 461 } 462 logger.warn("isLeftGB computing"); 463 boolean igb = bb.isLeftGB(getList()); 464 if (sided != Side.left) { 465 logger.warn("wrong usage for is left sided GB: " + sided); 466 //sided = Side.left; 467 } else { 468 isGB = igb; 469 testGB = true; 470 } 471 return igb; 472 } 473 474 475 /** 476 * Do Groebner Base. compute the left Groebner Base for this ideal. 477 */ 478 @SuppressWarnings("unchecked") 479 public void doGB() { 480 if (isGB && sided == Side.left) { 481 return; 482 } 483 if (isGB && sided == Side.twosided) { 484 return; 485 } 486 if (sided == Side.right) { 487 logger.warn("wrong usage for left sided GB: " + sided); 488 throw new IllegalArgumentException("wrong usage for left sided GB: " + sided); 489 } 490 List<GenSolvablePolynomial<C>> G = getList(); 491 if (sided == Side.left) { 492 logger.info("leftGB computing = " + G); 493 G = bb.leftGB(G); 494 } 495 if (sided == Side.twosided) { 496 logger.info("twosidedGB computing = " + G); 497 G = bb.twosidedGB(G); 498 } 499 //if (isTopt) { 500 // List<Integer> perm = ((OptimizedPolynomialList<C>) list).perm; 501 // list = new OptimizedPolynomialList<C>(perm, getRing(), G); 502 //} else { 503 //} 504 list = new PolynomialList<C>(getRing(), G); 505 isGB = true; 506 testGB = true; 507 //sided = Side.left; 508 return; 509 } 510 511 512 /** 513 * Groebner Base. Get a left Groebner Base for this ideal. 514 * @return leftGB(this) 515 */ 516 public SolvableIdeal<C> GB() { 517 if (isGB && sided == Side.left) { 518 return this; 519 } 520 doGB(); 521 return this; 522 } 523 524 525 /** 526 * Test if this is a twosided Groebner base. 527 * @return true, if this is a twosided Groebner base, else false 528 */ 529 public boolean isTwosidedGB() { 530 if (testGB && sided == Side.twosided) { 531 return isGB; 532 } 533 logger.warn("isTwosidedGB computing"); 534 isGB = bb.isTwosidedGB(getList()); 535 testGB = true; 536 sided = Side.twosided; 537 return isGB; 538 } 539 540 541 /** 542 * Groebner Base. Get a twosided Groebner Base for this ideal. 543 * @return twosidedGB(this) 544 */ 545 public SolvableIdeal<C> twosidedGB() { 546 if (isGB && sided == Side.twosided) { 547 return this; 548 } 549 //logger.warn("GB computing"); 550 List<GenSolvablePolynomial<C>> G = getList(); 551 logger.info("twosidedGB computing = " + G); 552 G = bb.twosidedGB(G); 553 PolynomialList<C> li = new PolynomialList<C>(getRing(), G); 554 SolvableIdeal<C> tsgb = new SolvableIdeal<C>(li, true, true, bb, red, Side.twosided); 555 return tsgb; 556 } 557 558 559 /** 560 * Test if this is a right Groebner base. 561 * @return true, if this is a right Groebner base, else false 562 */ 563 public boolean isRightGB() { 564 if (testGB && sided == Side.right) { 565 return isGB; 566 } 567 if (isGB && sided == Side.twosided) { 568 return true; 569 } 570 logger.warn("isRightGB computing"); 571 isGB = bb.isRightGB(getList()); 572 testGB = true; 573 sided = Side.right; 574 return isGB; 575 } 576 577 578 /** 579 * Groebner Base. Get a right Groebner Base for this ideal. 580 * @return rightGB(this) 581 */ 582 public SolvableIdeal<C> rightGB() { 583 if (isGB && sided == Side.twosided) { 584 return this; 585 } 586 if (isGB && sided == Side.right) { 587 return this; 588 } 589 //logger.warn("GB computing"); 590 List<GenSolvablePolynomial<C>> G = getList(); 591 logger.info("rightGB computing = " + G); 592 G = bb.rightGB(G); 593 PolynomialList<C> li = new PolynomialList<C>(getRing(), G); 594 SolvableIdeal<C> rgb = new SolvableIdeal<C>(li, true, true, bb, red, Side.right); 595 return rgb; 596 } 597 598 599 /** 600 * Solvable ideal containment. Test if B is contained in this ideal. Note: 601 * this is eventually modified to become a Groebner Base. 602 * @param B solvable ideal 603 * @return true, if B is contained in this, else false 604 */ 605 public boolean contains(SolvableIdeal<C> B) { 606 if (B == null || B.isZERO()) { 607 return true; 608 } 609 return contains(B.getList()); 610 } 611 612 613 /** 614 * Solvable ideal containment. Test if b is contained in this ideal. Note: 615 * this is eventually modified to become a Groebner Base. 616 * @param b solvable polynomial 617 * @return true, if b is contained in this, else false 618 */ 619 public boolean contains(GenSolvablePolynomial<C> b) { 620 if (b == null || b.isZERO()) { 621 return true; 622 } 623 if (this.isONE()) { 624 return true; 625 } 626 if (this.isZERO()) { 627 return false; 628 } 629 if (!isGB) { 630 doGB(); 631 } 632 GenSolvablePolynomial<C> z = red.leftNormalform(getList(), b); 633 if (z == null || z.isZERO()) { 634 return true; 635 } 636 return false; 637 } 638 639 640 /** 641 * Solvable ideal containment. Test if each b in B is contained in this 642 * ideal. Note: this is eventually modified to become a Groebner Base. 643 * @param B list of solvable polynomials 644 * @return true, if each b in B is contained in this, else false 645 */ 646 public boolean contains(List<GenSolvablePolynomial<C>> B) { 647 if (B == null || B.size() == 0) { 648 return true; 649 } 650 if (this.isONE()) { 651 return true; 652 } 653 if (!isGB) { 654 doGB(); 655 } 656 List<GenSolvablePolynomial<C>> si = getList(); 657 for (GenSolvablePolynomial<C> b : B) { 658 if (b == null) { 659 continue; 660 } 661 GenSolvablePolynomial<C> z = red.leftNormalform(si, b); 662 if (!z.isZERO()) { 663 logger.info("contains nf(b) != 0: " + z + " of " + b); 664 // + ", si = " + si + ", ring = " + z.ring.toScript()); 665 return false; 666 } 667 } 668 return true; 669 } 670 671 672 /** 673 * Solvable ideal summation. Generators for the sum of ideals. Note: if both 674 * ideals are Groebner bases, a Groebner base is returned. 675 * @param B solvable ideal 676 * @return ideal(this+B) 677 */ 678 public SolvableIdeal<C> sum(SolvableIdeal<C> B) { 679 if (B == null || B.isZERO()) { 680 return this; 681 } 682 if (this.isZERO()) { 683 return B; 684 } 685 int s = getList().size() + B.getList().size(); 686 List<GenSolvablePolynomial<C>> c; 687 c = new ArrayList<GenSolvablePolynomial<C>>(s); 688 c.addAll(getList()); 689 c.addAll(B.getList()); 690 SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided); 691 if (isGB && B.isGB) { 692 I.doGB(); // left, twosided, right handled in doGB 693 } 694 return I; 695 } 696 697 698 /** 699 * Solvable summation. Generators for the sum of ideal and a polynomial. 700 * Note: if this ideal is a Groebner base, a Groebner base is returned. 701 * @param b solvable polynomial 702 * @return ideal(this+{b}) 703 */ 704 public SolvableIdeal<C> sum(GenSolvablePolynomial<C> b) { 705 if (b == null || b.isZERO()) { 706 return this; 707 } 708 int s = getList().size() + 1; 709 List<GenSolvablePolynomial<C>> c; 710 c = new ArrayList<GenSolvablePolynomial<C>>(s); 711 c.addAll(getList()); 712 c.add(b); 713 SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided); 714 if (isGB) { 715 I.doGB(); 716 } 717 return I; 718 } 719 720 721 /** 722 * Solvable summation. Generators for the sum of this ideal and a list of 723 * polynomials. Note: if this ideal is a Groebner base, a Groebner base is 724 * returned. 725 * @param L list of solvable polynomials 726 * @return ideal(this+L) 727 */ 728 public SolvableIdeal<C> sum(List<GenSolvablePolynomial<C>> L) { 729 if (L == null || L.isEmpty()) { 730 return this; 731 } 732 int s = getList().size() + L.size(); 733 List<GenSolvablePolynomial<C>> c = new ArrayList<GenSolvablePolynomial<C>>(s); 734 c.addAll(getList()); 735 c.addAll(L); 736 SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided); 737 if (isGB) { 738 I.doGB(); 739 } 740 return I; 741 } 742 743 744 /** 745 * Product. Generators for the product of ideals. Note: if both ideals are 746 * Groebner bases, a Groebner base is returned. 747 * @param B solvable ideal 748 * @return ideal(this*B) 749 */ 750 public SolvableIdeal<C> product(SolvableIdeal<C> B) { 751 if (B == null || B.isZERO()) { 752 return B; 753 } 754 if (this.isZERO()) { 755 return this; 756 } 757 int s = getList().size() * B.getList().size(); 758 List<GenSolvablePolynomial<C>> c; 759 c = new ArrayList<GenSolvablePolynomial<C>>(s); 760 for (GenSolvablePolynomial<C> p : getList()) { 761 for (GenSolvablePolynomial<C> q : B.getList()) { 762 q = p.multiply(q); 763 c.add(q); 764 } 765 } 766 SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided); 767 if (isGB && B.isGB) { 768 I.doGB(); 769 } 770 return I; 771 } 772 773 774 /** 775 * Left product. Generators for the product this by a polynomial. 776 * @param b solvable polynomial 777 * @return ideal(this*b) 778 */ 779 public SolvableIdeal<C> product(GenSolvablePolynomial<C> b) { 780 if (b == null || b.isZERO()) { 781 return getZERO(); 782 } 783 if (this.isZERO()) { 784 return this; 785 } 786 List<GenSolvablePolynomial<C>> c; 787 c = new ArrayList<GenSolvablePolynomial<C>>(getList().size()); 788 for (GenSolvablePolynomial<C> p : getList()) { 789 GenSolvablePolynomial<C> q = p.multiply(b); 790 c.add(q); 791 } 792 SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided); 793 if (isGB) { 794 I.doGB(); 795 } 796 return I; 797 } 798 799 800 /** 801 * Intersection. Generators for the intersection of ideals. Using an 802 * iterative algorithm. 803 * @param Bl list of solvable ideals 804 * @return ideal(cap_i B_i), a Groebner base 805 */ 806 public SolvableIdeal<C> intersect(List<SolvableIdeal<C>> Bl) { 807 if (Bl == null || Bl.size() == 0) { 808 return getZERO(); 809 } 810 SolvableIdeal<C> I = null; 811 for (SolvableIdeal<C> B : Bl) { 812 if (I == null) { 813 I = B; 814 continue; 815 } 816 if (I.isONE()) { 817 return I; 818 } 819 I = I.intersect(B); 820 } 821 return I; 822 } 823 824 825 /** 826 * Intersection. Generators for the intersection of ideals. 827 * @param B solvable ideal 828 * @return ideal(this \cap B), a Groebner base 829 */ 830 public SolvableIdeal<C> intersect(SolvableIdeal<C> B) { 831 if (B == null || B.isZERO()) { // (0) 832 return B; 833 } 834 if (this.isZERO()) { 835 return this; 836 } 837 List<GenSolvablePolynomial<C>> c = PolyGBUtil.<C> intersect(getRing(), getList(), B.getList()); 838 SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, true, sided); 839 return I; 840 } 841 842 843 /** 844 * Intersection. Generators for the intersection of a ideal with a 845 * polynomial ring. The polynomial ring R must be a contraction 846 * of this ideal and the TermOrder must be an elimination order. 847 * @param R solvable polynomial ring 848 * @return ideal(this \cap R) 849 */ 850 public SolvableIdeal<C> intersect(GenSolvablePolynomialRing<C> R) { 851 if (R == null) { 852 throw new IllegalArgumentException("R may not be null"); 853 } 854 String[] rvars = R.getVars(); 855 String[] tvars = getRing().getVars(); 856 for (int i = 0; i < rvars.length; i++) { 857 if (!rvars[i].equals(tvars[i])) { 858 throw new IllegalArgumentException("no contraction: " + R.toScript() 859 + " of " + getRing().toScript()); 860 } 861 } 862 List<GenSolvablePolynomial<C>> H = PolyUtil.<C> intersect(R, getList()); 863 return new SolvableIdeal<C>(R, H, isGB, sided); 864 } 865 866 867 /** 868 * Eliminate. Generators for the intersection of this ideal with a solvable 869 * polynomial ring. The solvable polynomial ring of this ideal must be a 870 * contraction of R and the TermOrder must be an elimination order. 871 * @param R solvable polynomial ring 872 * @return ideal(this \cap R) 873 */ 874 public SolvableIdeal<C> eliminate(GenSolvablePolynomialRing<C> R) { 875 if (R == null) { 876 throw new IllegalArgumentException("R may not be null"); 877 } 878 if (getRing().equals(R)) { 879 return this; 880 } 881 return intersect(R); 882 } 883 884 885 /** 886 * Quotient. Generators for the solvable ideal quotient. 887 * @param h solvable polynomial 888 * @return ideal(this : h), a Groebner base 889 */ 890 //@SuppressWarnings("unchecked") 891 public SolvableIdeal<C> quotient(GenSolvablePolynomial<C> h) { 892 if (h == null) { // == (0) 893 return this; 894 } 895 if (h.isZERO()) { 896 return this; 897 } 898 if (this.isZERO()) { 899 return this; 900 } 901 List<GenSolvablePolynomial<C>> H; 902 H = new ArrayList<GenSolvablePolynomial<C>>(1); 903 H.add(h); 904 SolvableIdeal<C> Hi = new SolvableIdeal<C>(getRing(), H, true, sided); 905 906 SolvableIdeal<C> I = this.intersect(Hi); 907 908 List<GenSolvablePolynomial<C>> Q; 909 Q = new ArrayList<GenSolvablePolynomial<C>>(I.getList().size()); 910 GenSolvablePolynomial<C> p; 911 for (GenSolvablePolynomial<C> q : I.getList()) { 912 p = q.divide(h); // remainder == 0, (GenSolvablePolynomial<C>) 913 if (!p.isZERO()) { 914 p = p.monic(); 915 Q.add(p); 916 } 917 if (debug) { 918 GenSolvablePolynomial<C> r = q.remainder(h); // (GenSolvablePolynomial<C>) 919 if (!r.isZERO()) { 920 System.out.println("error remainder !=0: " + r + ", q = " + q + ", h = " + h); 921 throw new RuntimeException("remainder !=0"); 922 } 923 } 924 } 925 return new SolvableIdeal<C>(getRing(), Q, true /*false?*/, sided); 926 } 927 928 929 /** 930 * Quotient. Generators for the solvable ideal quotient. 931 * @param H solvable ideal 932 * @return ideal(this : H), a Groebner base 933 */ 934 public SolvableIdeal<C> quotient(SolvableIdeal<C> H) { 935 if (H == null || H.isZERO()) { // == (0) 936 return this; 937 } 938 if (this.isZERO()) { 939 return this; 940 } 941 SolvableIdeal<C> Q = null; 942 for (GenSolvablePolynomial<C> h : H.getList()) { 943 SolvableIdeal<C> Hi = this.quotient(h); 944 if (Q == null) { 945 Q = Hi; 946 } else { 947 Q = Q.intersect(Hi); 948 } 949 } 950 return Q; 951 } 952 953 954 /** 955 * Infinite quotient. Generators for the infinite solvable ideal quotient. 956 * @param h solvable polynomial 957 * @return ideal(this : h<sup>s</sup>), a Groebner base 958 */ 959 public SolvableIdeal<C> infiniteQuotientRab(GenSolvablePolynomial<C> h) { 960 if (h == null || h.isZERO()) { // == (0) 961 return getONE(); 962 } 963 if (h.isONE()) { 964 return this; 965 } 966 if (this.isZERO()) { 967 return this; 968 } 969 if (!getRing().isCommutative()) { 970 throw new UnsupportedOperationException("Rabinowich trick only for commutative polynomial rings"); 971 } 972 SolvableIdeal<C> I = this.GB(); // should be already 973 List<GenSolvablePolynomial<C>> a = I.getList(); 974 List<GenSolvablePolynomial<C>> c; 975 c = new ArrayList<GenSolvablePolynomial<C>>(a.size() + 1); 976 977 GenSolvablePolynomialRing<C> tfac = getRing().extend(1); 978 // term order is also adjusted 979 for (GenSolvablePolynomial<C> p : a) { 980 p = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 0L); // p 981 c.add(p); 982 } 983 GenSolvablePolynomial<C> q = (GenSolvablePolynomial<C>) h.extend(tfac, 0, 1L); 984 GenSolvablePolynomial<C> r = tfac.getONE(); // h.extend( tfac, 0, 0L ); 985 GenSolvablePolynomial<C> hs = (GenSolvablePolynomial<C>) q.subtract(r); // 1 - t*h // (1-t)*h 986 c.add(hs); 987 logger.warn("infiniteQuotientRab computing GB "); 988 List<GenSolvablePolynomial<C>> g = bb.leftGB(c); 989 if (debug) { 990 logger.info("infiniteQuotientRab = " + tfac + ", c = " + c); 991 logger.info("infiniteQuotientRab GB = " + g); 992 } 993 SolvableIdeal<C> E = new SolvableIdeal<C>(tfac, g, true, sided); 994 SolvableIdeal<C> Is = E.intersect(getRing()); 995 return Is; 996 } 997 998 999 /** 1000 * Infinite quotient exponent. 1001 * @param h solvable polynomial 1002 * @param Q quotient this : h^\infinity 1003 * @return s with Q = this : h<sup>s</sup> 1004 */ 1005 public int infiniteQuotientExponent(GenSolvablePolynomial<C> h, SolvableIdeal<C> Q) { 1006 int s = 0; 1007 if (h == null) { // == 0 1008 return s; 1009 } 1010 if (h.isZERO() || h.isONE()) { 1011 return s; 1012 } 1013 if (this.isZERO() || this.isONE()) { 1014 return s; 1015 } 1016 //see below: if (this.contains(Q)) { 1017 // return s; 1018 //} 1019 GenSolvablePolynomial<C> p = getRing().getONE(); 1020 for (GenSolvablePolynomial<C> q : Q.getList()) { 1021 if (this.contains(q)) { 1022 continue; 1023 } 1024 //System.out.println("q = " + q + ", p = " + p + ", s = " + s); 1025 GenSolvablePolynomial<C> qp = q.multiply(p); 1026 while (!this.contains(qp)) { 1027 p = p.multiply(h); 1028 s++; 1029 qp = q.multiply(p); 1030 } 1031 } 1032 return s; 1033 } 1034 1035 1036 /** 1037 * Infinite quotient. Generators for the infinite solvable ideal quotient. 1038 * @param h solvable polynomial 1039 * @return ideal(this : h<sup>s</sup>), a Groebner base 1040 */ 1041 public SolvableIdeal<C> infiniteQuotient(GenSolvablePolynomial<C> h) { 1042 if (h == null) { // == (0) 1043 return this; 1044 } 1045 if (h.isZERO()) { 1046 return this; 1047 } 1048 if (this.isZERO()) { 1049 return this; 1050 } 1051 int s = 0; 1052 SolvableIdeal<C> I = this.GB(); // should be already 1053 GenSolvablePolynomial<C> hs = h; 1054 SolvableIdeal<C> Is = null; 1055 logger.info("infiniteQuotient hs = " + hs); 1056 long dm = -1; 1057 boolean eq = false; 1058 while (!eq) { 1059 Is = I.quotient(hs); 1060 Is = Is.GB(); // should be already 1061 //logger.info("ideal Is = " + Is); 1062 logger.info("infiniteQuotient s = " + s); 1063 if (Is.isZERO()) { 1064 logger.warn("infiniteQuotient does not exist"); 1065 return I; 1066 } 1067 eq = Is.contains(I); // I.contains(Is) always 1068 if (!eq) { 1069 long ds = PolyUtil.<C> totalDegree(Is.list.getList()); 1070 if (dm < 0) { 1071 dm = ds; 1072 } 1073 //System.out.println("deg(Is) = " + ds); 1074 if (ds > dm) { 1075 logger.warn("no convergence in infiniteQuotient (dm,ds): " + dm + " < " + ds); 1076 return I; 1077 //throw new RuntimeException("no convergence in infiniteQuotient"); 1078 } 1079 I = Is; 1080 s++; 1081 // hs = hs.multiply( h ); 1082 } 1083 } 1084 return Is; 1085 } 1086 1087 1088 /** 1089 * Radical membership test. 1090 * @param h solvable polynomial 1091 * @return true if h is contained in the radical of ideal(this), else false. 1092 */ 1093 public boolean isRadicalMember(GenSolvablePolynomial<C> h) { 1094 if (h == null) { // == (0) 1095 return true; 1096 } 1097 if (h.isZERO()) { 1098 return true; 1099 } 1100 if (this.isZERO()) { 1101 return true; 1102 } 1103 SolvableIdeal<C> x = infiniteQuotientRab(h); // may fail 1104 if (debug) { 1105 logger.debug("infiniteQuotientRab = " + x); 1106 } 1107 return x.isONE(); 1108 } 1109 1110 1111 /** 1112 * Infinite Quotient. Generators for the solvable ideal infinite quotient. 1113 * @param H solvable ideal 1114 * @return ideal(this : H<sup>s</sup>), a Groebner base 1115 */ 1116 public SolvableIdeal<C> infiniteQuotient(SolvableIdeal<C> H) { 1117 if (H == null) { // == (0) 1118 return this; 1119 } 1120 if (H.isZERO()) { 1121 return this; 1122 } 1123 if (this.isZERO()) { 1124 return this; 1125 } 1126 SolvableIdeal<C> Q = null; 1127 for (GenSolvablePolynomial<C> h : H.getList()) { 1128 SolvableIdeal<C> Hi = this.infiniteQuotient(h); 1129 if (Q == null) { 1130 Q = Hi; 1131 } else { 1132 Q = Q.intersect(Hi); 1133 } 1134 } 1135 return Q; 1136 } 1137 1138 1139 /** 1140 * Infinite Quotient. Generators for the solvable ideal infinite quotient. 1141 * @param H solvable ideal 1142 * @return ideal(this : H<sup>s</sup>), a Groebner base 1143 */ 1144 public SolvableIdeal<C> infiniteQuotientRab(SolvableIdeal<C> H) { 1145 if (H == null) { // == (0) 1146 return this; 1147 } 1148 if (H.isZERO()) { 1149 return this; 1150 } 1151 if (this.isZERO()) { 1152 return this; 1153 } 1154 SolvableIdeal<C> Q = null; 1155 for (GenSolvablePolynomial<C> h : H.getList()) { 1156 SolvableIdeal<C> Hi = this.infiniteQuotientRab(h); // may fail 1157 if (Q == null) { 1158 Q = Hi; 1159 } else { 1160 Q = Q.intersect(Hi); 1161 } 1162 } 1163 return Q; 1164 } 1165 1166 1167 /** 1168 * Power. Generators for the power of this solvable ideal. Note: if this 1169 * ideal is a Groebner base, a Groebner base is returned. 1170 * @param d integer 1171 * @return ideal(this^d) 1172 */ 1173 public SolvableIdeal<C> power(int d) { 1174 if (d <= 0) { 1175 return getONE(); 1176 } 1177 if (this.isZERO() || this.isONE()) { 1178 return this; 1179 } 1180 SolvableIdeal<C> c = this; 1181 for (int i = 1; i < d; i++) { 1182 c = c.product(this); 1183 } 1184 return c; 1185 } 1186 1187 1188 /** 1189 * Normalform for element. 1190 * @param h solvable polynomial 1191 * @return left normalform of h with respect to this 1192 */ 1193 public GenSolvablePolynomial<C> normalform(GenSolvablePolynomial<C> h) { 1194 if (h == null) { 1195 return h; 1196 } 1197 if (h.isZERO()) { 1198 return h; 1199 } 1200 if (this.isZERO()) { 1201 return h; 1202 } 1203 GenSolvablePolynomial<C> r; 1204 r = red.leftNormalform(getList(), h); 1205 return r; 1206 } 1207 1208 1209 /** 1210 * Normalform for list of solvable elements. 1211 * @param L solvable polynomial list 1212 * @return list of left normalforms of the elements of L with respect to 1213 * this 1214 */ 1215 public List<GenSolvablePolynomial<C>> normalform(List<GenSolvablePolynomial<C>> L) { 1216 if (L == null) { 1217 return L; 1218 } 1219 if (L.size() == 0) { 1220 return L; 1221 } 1222 if (this.isZERO()) { 1223 return L; 1224 } 1225 List<GenSolvablePolynomial<C>> M = new ArrayList<GenSolvablePolynomial<C>>(L.size()); 1226 for (GenSolvablePolynomial<C> h : L) { 1227 GenSolvablePolynomial<C> r = normalform(h); 1228 if (r != null && !r.isZERO()) { 1229 M.add(r); 1230 } 1231 } 1232 return M; 1233 } 1234 1235 1236 /** 1237 * Annihilator for element modulo this ideal. 1238 * @param h solvable polynomial 1239 * @return annihilator of h with respect to this 1240 */ 1241 public SolvableIdeal<C> annihilator(GenSolvablePolynomial<C> h) { 1242 if (h == null || h.isZERO()) { 1243 return getZERO(); 1244 } 1245 if (this.isZERO()) { 1246 return this; 1247 } 1248 doGB(); 1249 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(1 + getList().size()); 1250 F.add(h); 1251 F.addAll(getList()); 1252 //System.out.println("F = " + F); 1253 SolvableSyzygyAbstract<C> syz = new SolvableSyzygySeq<C>(getRing().coFac); 1254 List<List<GenSolvablePolynomial<C>>> S = syz.leftZeroRelationsArbitrary(F); 1255 //System.out.println("S = " + S); 1256 List<GenSolvablePolynomial<C>> gen = new ArrayList<GenSolvablePolynomial<C>>(S.size()); 1257 for (List<GenSolvablePolynomial<C>> rel : S) { 1258 if (rel == null || rel.isEmpty()) { 1259 continue; 1260 } 1261 GenSolvablePolynomial<C> p = rel.get(0); 1262 if (p == null || p.isZERO()) { 1263 continue; 1264 } 1265 gen.add(p); 1266 } 1267 SolvableIdeal<C> ann = new SolvableIdeal<C>(getRing(), gen, false, sided); 1268 //System.out.println("ann = " + ann); 1269 return ann; 1270 } 1271 1272 1273 /** 1274 * Test for annihilator of element modulo this ideal. 1275 * @param h solvable polynomial 1276 * @param A solvable ideal 1277 * @return true, if A is the annihilator of h with respect to this 1278 */ 1279 public boolean isAnnihilator(GenSolvablePolynomial<C> h, SolvableIdeal<C> A) { 1280 SolvableIdeal<C> B = A.product(h); 1281 return contains(B); 1282 } 1283 1284 1285 /** 1286 * Annihilator for ideal modulo this ideal. 1287 * @param H solvable ideal 1288 * @return annihilator of H with respect to this 1289 */ 1290 public SolvableIdeal<C> annihilator(SolvableIdeal<C> H) { 1291 if (H == null || H.isZERO()) { 1292 return getZERO(); 1293 } 1294 if (this.isZERO()) { 1295 return this; 1296 } 1297 SolvableIdeal<C> ann = null; 1298 for (GenSolvablePolynomial<C> h : H.getList()) { 1299 SolvableIdeal<C> Hi = this.annihilator(h); 1300 if (ann == null) { 1301 ann = Hi; 1302 } else { 1303 ann = ann.intersect(Hi); 1304 } 1305 } 1306 return ann; 1307 } 1308 1309 1310 /** 1311 * Test for annihilator of ideal modulo this ideal. 1312 * @param H solvable ideal 1313 * @param A solvable ideal 1314 * @return true, if A is the annihilator of H with respect to this 1315 */ 1316 public boolean isAnnihilator(SolvableIdeal<C> H, SolvableIdeal<C> A) { 1317 SolvableIdeal<C> B = A.product(H); 1318 return contains(B); 1319 } 1320 1321 1322 /** 1323 * Inverse for element modulo this ideal. 1324 * @param h solvable polynomial 1325 * @return inverse of h with respect to this, if defined 1326 */ 1327 public GenSolvablePolynomial<C> inverse(GenSolvablePolynomial<C> h) { 1328 if (h == null || h.isZERO()) { 1329 throw new NotInvertibleException("zero not invertible"); 1330 } 1331 if (this.isZERO()) { 1332 throw new NotInvertibleException("zero ideal"); 1333 } 1334 if (h.isUnit()) { 1335 return (GenSolvablePolynomial<C>) h.inverse(); 1336 } 1337 doGB(); 1338 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(1 + list.list.size()); 1339 F.add(h); 1340 F.addAll(getList()); 1341 //System.out.println("F = " + F); 1342 SolvableExtendedGB<C> x = bb.extLeftGB(F); 1343 List<GenSolvablePolynomial<C>> G = x.G; 1344 //System.out.println("G = " + G); 1345 GenSolvablePolynomial<C> one = null; 1346 int i = -1; 1347 for (GenSolvablePolynomial<C> p : G) { 1348 i++; 1349 if (p == null) { 1350 continue; 1351 } 1352 if (p.isUnit()) { 1353 one = p; 1354 break; 1355 } 1356 } 1357 if (one == null) { 1358 throw new NotInvertibleException("one == null: h = " + h); 1359 } 1360 List<GenSolvablePolynomial<C>> row = x.G2F.get(i); // != -1 1361 //System.out.println("row = " + row); 1362 GenSolvablePolynomial<C> g = row.get(0); 1363 if (g == null || g.isZERO()) { 1364 throw new NotInvertibleException("g == 0: h = " + h); 1365 } 1366 GenSolvablePolynomial<C> gp = red.leftNormalform(getList(), g); 1367 if (gp.isZERO()) { // can happen with solvable rings 1368 throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g); 1369 } 1370 // adjust leading coefficient of g to get g*h == 1 1371 GenSolvablePolynomial<C> f = g.multiply(h); 1372 //System.out.println("f = " + f); 1373 GenSolvablePolynomial<C> k = red.leftNormalform(getList(), f); 1374 //System.out.println("k = " + k); 1375 if (!k.isONE()) { 1376 C lbc = k.leadingBaseCoefficient(); 1377 lbc = lbc.inverse(); 1378 g = g.multiply(lbc); 1379 } 1380 if (debug) { 1381 //logger.info("inv G = " + G); 1382 //logger.info("inv G2F = " + x.G2F); 1383 //logger.info("inv row "+i+" = " + row); 1384 //logger.info("inv h = " + h); 1385 //logger.info("inv g = " + g); 1386 //logger.info("inv f = " + f); 1387 f = g.multiply(h); 1388 k = red.leftNormalform(getList(), f); 1389 logger.debug("inv k = " + k); 1390 if (!k.isUnit()) { 1391 throw new NotInvertibleException(" k = " + k); 1392 } 1393 } 1394 return g; 1395 } 1396 1397 1398 /** 1399 * Test if element is a unit modulo this ideal. 1400 * @param h solvable polynomial 1401 * @return true if h is a unit with respect to this, else false 1402 */ 1403 public boolean isUnit(GenSolvablePolynomial<C> h) { 1404 if (h == null || h.isZERO()) { 1405 return false; 1406 } 1407 if (this.isZERO()) { 1408 return false; 1409 } 1410 List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(1 + list.list.size()); 1411 F.add(h); 1412 F.addAll(getList()); 1413 List<GenSolvablePolynomial<C>> G = bb.leftGB(F); 1414 for (GenSolvablePolynomial<C> p : G) { 1415 if (p == null) { 1416 continue; 1417 } 1418 if (p.isUnit()) { 1419 return true; 1420 } 1421 } 1422 return false; 1423 } 1424 1425 1426 /** 1427 * Ideal common zero test. 1428 * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. 1429 */ 1430 public int commonZeroTest() { 1431 if (this.isZERO()) { 1432 return 1; 1433 } 1434 if (!isGB) { 1435 doGB(); 1436 } 1437 if (this.isONE()) { 1438 return -1; 1439 } 1440 return bb.commonZeroTest(getList()); 1441 } 1442 1443 1444 /** 1445 * Test if this ideal is maximal. 1446 * @return true, if this is maximal and not one, else false. 1447 */ 1448 public boolean isMaximal() { 1449 if (commonZeroTest() != 0) { 1450 return false; 1451 } 1452 for (Long d : univariateDegrees()) { 1453 if (d > 1L) { 1454 // todo: test if univariate irreducible and no multiple polynomials 1455 return false; 1456 } 1457 } 1458 return true; 1459 } 1460 1461 1462 /** 1463 * Univariate head term degrees. 1464 * @return a list of the degrees of univariate head terms. 1465 */ 1466 public List<Long> univariateDegrees() { 1467 List<Long> ud = new ArrayList<Long>(); 1468 if (this.isZERO()) { 1469 return ud; 1470 } 1471 if (!isGB) { 1472 doGB(); 1473 } 1474 if (this.isONE()) { 1475 return ud; 1476 } 1477 return bb.univariateDegrees(getList()); 1478 } 1479 1480 1481 /** 1482 * Ideal dimension. 1483 * @return a dimension container (dim,maxIndep,list(maxIndep),vars). 1484 */ 1485 public Dimension dimension() { 1486 Ideal<C> ci = new Ideal<C>(list); 1487 return ci.dimension(); 1488 } 1489 1490 1491 /** 1492 * Construct univariate polynomials of minimal degree in all variables in 1493 * zero dimensional ideal(G). 1494 * @return list of univariate solvable polynomial of minimal degree in each 1495 * variable in ideal(G) 1496 */ 1497 public List<GenSolvablePolynomial<C>> constructUnivariate() { 1498 List<GenSolvablePolynomial<C>> univs = new ArrayList<GenSolvablePolynomial<C>>(); 1499 for (int i = getRing().nvar - 1; i >= 0; i--) { 1500 GenSolvablePolynomial<C> u = constructUnivariate(i); 1501 univs.add(u); 1502 } 1503 return univs; 1504 } 1505 1506 1507 /** 1508 * Construct univariate polynomial of minimal degree in variable i in zero 1509 * dimensional ideal(G). 1510 * @param i variable index. 1511 * @return univariate solvable polynomial of minimal degree in variable i in 1512 * ideal(G) 1513 */ 1514 public GenSolvablePolynomial<C> constructUnivariate(int i) { 1515 doGB(); 1516 return bb.constructUnivariate(i, getList()); 1517 } 1518 1519}