001/*
002 * $Id$
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 + "-GB: " + isGB;
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 + "-GB: " + isGB;
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 SolvableIdeal");
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/right/twosided Groebner base, else false
457     */
458    public boolean isGB() {
459        if (testGB) {
460            return isGB;
461        }
462        testGB = true;
463        boolean igb = false;
464        if (sided == Side.left) {
465            igb = bb.isLeftGB(getList());
466        } else if (sided == Side.right) {
467            igb = bb.isRightGB(getList());
468        } else if (sided == Side.twosided) {
469            igb = bb.isTwosidedGB(getList());
470        }
471        isGB = igb;
472        return isGB;
473    }
474
475
476    /**
477     * Do Groebner Base. compute the left Groebner Base for this ideal.
478     */
479    @SuppressWarnings("unchecked")
480    public void doGB() {
481        if (isGB && sided == Side.left) {
482            return;
483        }
484        if (isGB && sided == Side.twosided) {
485            return;
486        }
487        if (isGB && sided == Side.right) {
488            return;
489        }
490        // if (sided == Side.right) {
491        //     logger.warn("wrong usage for left sided GB: {}", sided);
492        //     throw new IllegalArgumentException("wrong usage for left sided GB: " + sided);
493        // }
494        List<GenSolvablePolynomial<C>> G = getList();
495        if (sided == Side.left) {
496            logger.info("leftGB computing = {}", G);
497            G = bb.leftGB(G);
498        } else if (sided == Side.twosided) {
499            logger.info("twosidedGB computing = {}", G);
500            G = bb.twosidedGB(G);
501        } else if (sided == Side.right) {
502            logger.info("rightGB computing = {}", G);
503            G = bb.rightGB(G);
504        }
505        //if (isTopt) {
506        //    List<Integer> perm = ((OptimizedPolynomialList<C>) list).perm;
507        //    list = new OptimizedPolynomialList<C>(perm, getRing(), G);
508        //} else {
509        //}
510        list = new PolynomialList<C>(getRing(), G);
511        isGB = true;
512        testGB = true;
513        return;
514    }
515
516
517    /**
518     * Groebner Base. Get a left Groebner Base for this ideal.
519     * @return leftGB(this)
520     */
521    public SolvableIdeal<C> GB() {
522        if (isGB && sided == Side.left) {
523            return this;
524        }
525        doGB();
526        return this;
527    }
528
529
530    /**
531     * Test if this is a twosided Groebner base.
532     * @return true, if this is a twosided Groebner base, else false
533     */
534    public boolean isTwosidedGB() {
535        if (testGB && sided == Side.twosided) {
536            return isGB;
537        }
538        logger.warn("isTwosidedGB computing");
539        isGB = bb.isTwosidedGB(getList());
540        testGB = true;
541        //sided = Side.twosided;
542        return isGB;
543    }
544
545
546    /**
547     * Groebner Base. Get a twosided Groebner Base for this ideal.
548     * @return twosidedGB(this)
549     */
550    public SolvableIdeal<C> twosidedGB() {
551        if (isGB && sided == Side.twosided) {
552            return this;
553        }
554        //logger.warn("GB computing");
555        List<GenSolvablePolynomial<C>> G = getList();
556        logger.info("twosidedGB computing = {}", G);
557        G = bb.twosidedGB(G);
558        PolynomialList<C> li = new PolynomialList<C>(getRing(), G);
559        SolvableIdeal<C> tsgb = new SolvableIdeal<C>(li, true, true, bb, red, Side.twosided);
560        return tsgb;
561    }
562
563
564    /**
565     * Test if this is a right Groebner base.
566     * @return true, if this is a right Groebner base, else false
567     */
568    public boolean isRightGB() {
569        if (testGB && sided == Side.right) {
570            return isGB;
571        }
572        if (isGB && sided == Side.twosided) {
573            return true;
574        }
575        logger.warn("isRightGB computing");
576        isGB = bb.isRightGB(getList());
577        testGB = true;
578        //sided = Side.right;
579        return isGB;
580    }
581
582
583    /**
584     * Groebner Base. Get a right Groebner Base for this ideal.
585     * @return rightGB(this)
586     */
587    public SolvableIdeal<C> rightGB() {
588        if (isGB && sided == Side.twosided) {
589            return this;
590        }
591        if (isGB && sided == Side.right) {
592            return this;
593        }
594        //logger.warn("GB computing");
595        List<GenSolvablePolynomial<C>> G = getList();
596        logger.info("rightGB computing = {}", G);
597        G = bb.rightGB(G);
598        PolynomialList<C> li = new PolynomialList<C>(getRing(), G);
599        SolvableIdeal<C> rgb = new SolvableIdeal<C>(li, true, true, bb, red, Side.right);
600        return rgb;
601    }
602
603
604    /**
605     * Solvable ideal containment. Test if B is contained in this ideal. Note:
606     * this is eventually modified to become a Groebner Base.
607     * @param B solvable ideal
608     * @return true, if B is contained in this, else false
609     */
610    public boolean contains(SolvableIdeal<C> B) {
611        if (B == null || B.isZERO()) {
612            return true;
613        }
614        return contains(B.getList());
615    }
616
617
618    /**
619     * Solvable ideal containment. Test if b is contained in this
620     * left/right/twosided ideal. Note: this is eventually modified to
621     * become a Groebner Base.
622     * @param b solvable polynomial
623     * @return true, if b is contained in this, else false
624     */
625    public boolean contains(GenSolvablePolynomial<C> b) {
626        if (b == null || b.isZERO()) {
627            return true;
628        }
629        if (this.isONE()) {
630            return true;
631        }
632        if (this.isZERO()) {
633            return false;
634        }
635        if (!isGB) {
636            doGB();
637        }
638        GenSolvablePolynomial<C> z = normalform(b); // left/right/twosided
639        if (z == null || z.isZERO()) {
640            return true;
641        }
642        return false;
643    }
644
645
646    /**
647     * Solvable ideal containment. Test if each b in B is contained in
648     * this left/right/twosided ideal. Note: this is eventually
649     * modified to become a Groebner Base.
650     * @param B list of solvable polynomials
651     * @return true, if each b in B is contained in this, else false
652     */
653    public boolean contains(List<GenSolvablePolynomial<C>> B) {
654        if (B == null || B.size() == 0) {
655            return true;
656        }
657        if (this.isONE()) {
658            return true;
659        }
660        if (!isGB) {
661            doGB();
662        }
663        List<GenSolvablePolynomial<C>> si = getList();
664        for (GenSolvablePolynomial<C> b : B) {
665            if (b == null) {
666                continue;
667            }
668            if (! contains(b)) {
669                return false;
670            }
671        }
672        return true;
673    }
674
675
676    /**
677     * Solvable ideal summation. Generators for the sum of ideals. Note: if both
678     * ideals are Groebner bases, a Groebner base is returned.
679     * @param B solvable ideal
680     * @return ideal(this+B)
681     */
682    public SolvableIdeal<C> sum(SolvableIdeal<C> B) {
683        if (B == null || B.isZERO()) {
684            return this;
685        }
686        if (this.isZERO()) {
687            return B;
688        }
689        return sum(B.getList());
690    }
691
692
693    /**
694     * Solvable summation. Generators for the sum of ideal and a polynomial.
695     * Note: if this ideal is a Groebner base, a Groebner base is returned.
696     * @param b solvable polynomial
697     * @return ideal(this+{b})
698     */
699    public SolvableIdeal<C> sum(GenSolvablePolynomial<C> b) {
700        if (b == null || b.isZERO()) {
701            return this;
702        }
703        List<GenSolvablePolynomial<C>> B = new ArrayList<GenSolvablePolynomial<C>>(1);
704        B.add(b);
705        return sum(B);
706    }
707
708
709    /**
710     * Solvable summation. Generators for the sum of this ideal and a list of
711     * polynomials. Note: if this ideal is a Groebner base, a Groebner base is
712     * returned.
713     * @param L list of solvable polynomials
714     * @return ideal(this+L)
715     */
716    public SolvableIdeal<C> sum(List<GenSolvablePolynomial<C>> L) {
717        if (L == null || L.isEmpty()) {
718            return this;
719        }
720        int s = getList().size() + L.size();
721        List<GenSolvablePolynomial<C>> c = new ArrayList<GenSolvablePolynomial<C>>(s);
722        c.addAll(getList());
723        c.addAll(L);
724        SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided);
725        if (isGB) {
726            I.doGB(); // left/right/twosided
727        }
728        return I;
729    }
730
731
732    /**
733     * Product. Generators for the product of ideals. Note: if both ideals are
734     * Groebner bases, a Groebner base is returned.
735     * @param B solvable ideal
736     * @return ideal(this*B)
737     */
738    public SolvableIdeal<C> product(SolvableIdeal<C> B) {
739        if (B == null || B.isZERO()) {
740            return B;
741        }
742        if (this.isZERO()) {
743            return this;
744        }
745        int s = getList().size() * B.getList().size();
746        List<GenSolvablePolynomial<C>> c;
747        c = new ArrayList<GenSolvablePolynomial<C>>(s);
748        for (GenSolvablePolynomial<C> p : getList()) {
749            for (GenSolvablePolynomial<C> q : B.getList()) {
750                q = p.multiply(q);
751                c.add(q);
752            }
753        }
754        SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided);
755        if (isGB && B.isGB) {
756            I.doGB(); // left/right/twosided
757        }
758        return I;
759    }
760
761
762    /**
763     * Product. Generators for the product of this by a polynomial.
764     * @param b solvable polynomial
765     * @return ideal(this*b)
766     */
767    public SolvableIdeal<C> product(GenSolvablePolynomial<C> b) {
768        if (b == null || b.isZERO()) {
769            return getZERO();
770        }
771        if (this.isZERO()) {
772            return this;
773        }
774        List<GenSolvablePolynomial<C>> c;
775        c = new ArrayList<GenSolvablePolynomial<C>>(getList().size());
776        for (GenSolvablePolynomial<C> p : getList()) {
777            GenSolvablePolynomial<C> q = p.multiply(b);
778            c.add(q);
779        }
780        SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided);
781        if (isGB) {
782            I.doGB(); // left/right/twosided
783        }
784        return I;
785    }
786
787
788    /**
789     * Left product. Generators for the product of a polynomial by this.
790     * @param b solvable polynomial
791     * @return ideal(b*this)
792     */
793    public SolvableIdeal<C> leftProduct(GenSolvablePolynomial<C> b) {
794        if (b == null || b.isZERO()) {
795            return getZERO();
796        }
797        if (this.isZERO()) {
798            return this;
799        }
800        List<GenSolvablePolynomial<C>> c;
801        c = new ArrayList<GenSolvablePolynomial<C>>(getList().size());
802        for (GenSolvablePolynomial<C> p : getList()) {
803            GenSolvablePolynomial<C> q = b.multiply(p);
804            c.add(q);
805        }
806        SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, false, sided);
807        if (isGB) {
808            I.doGB(); // left/right/twosided
809        }
810        return I;
811    }
812
813
814    /**
815     * Intersection. Generators for the intersection of ideals. Using an
816     * iterative algorithm.
817     * @param Bl list of solvable ideals
818     * @return ideal(cap_i B_i), a Groebner base
819     */
820    public SolvableIdeal<C> intersect(List<SolvableIdeal<C>> Bl) {
821        if (Bl == null || Bl.size() == 0) {
822            return getZERO();
823        }
824        SolvableIdeal<C> I = null;
825        for (SolvableIdeal<C> B : Bl) {
826            if (I == null) {
827                I = B;
828                continue;
829            }
830            if (I.isONE()) {
831                return I;
832            }
833            I = I.intersect(B);
834        }
835        return I;
836    }
837
838
839    /**
840     * Intersection. Generators for the intersection of ideals.
841     * @param B solvable ideal
842     * @return ideal(this \cap B), a Groebner base
843     */
844    public SolvableIdeal<C> intersect(SolvableIdeal<C> B) {
845        if (B == null || B.isZERO()) { // (0)
846            return B;
847        }
848        if (this.isZERO()) {
849            return this;
850        }
851        List<GenSolvablePolynomial<C>> c = PolyGBUtil.<C> intersect(getRing(), getList(), B.getList());
852        SolvableIdeal<C> I = new SolvableIdeal<C>(getRing(), c, true, sided);
853        return I;
854    }
855
856
857    /**
858     * Intersection. Generators for the intersection of a ideal with a
859     * polynomial ring. The polynomial ring R must be a contraction
860     * of this ideal and the TermOrder must be an elimination order.
861     * @param R solvable polynomial ring
862     * @return ideal(this \cap R)
863     */
864    public SolvableIdeal<C> intersect(GenSolvablePolynomialRing<C> R) {
865        if (R == null) {
866            throw new IllegalArgumentException("R may not be null");
867        }
868        String[] rvars = R.getVars();
869        String[] tvars = getRing().getVars();
870        for (int i = 0; i < rvars.length; i++) {
871            if (!rvars[i].equals(tvars[i])) {
872                throw new IllegalArgumentException("no contraction: " + R.toScript() 
873                                                 + " of " + getRing().toScript());
874            }
875        }
876        List<GenSolvablePolynomial<C>> H = PolyUtil.<C> intersect(R, getList());
877        return new SolvableIdeal<C>(R, H, isGB, sided);
878    }
879
880
881    /**
882     * Eliminate. Generators for the intersection of this ideal with a solvable
883     * polynomial ring. The solvable polynomial ring of this ideal must be a
884     * contraction of R and the TermOrder must be an elimination order.
885     * @param R solvable polynomial ring
886     * @return ideal(this \cap R)
887     */
888    public SolvableIdeal<C> eliminate(GenSolvablePolynomialRing<C> R) {
889        if (R == null) {
890            throw new IllegalArgumentException("R may not be null");
891        }
892        if (getRing().equals(R)) {
893            return this;
894        }
895        return intersect(R);
896    }
897
898
899    /**
900     * Quotient. Generators for the solvable ideal quotient.
901     * @param h solvable polynomial
902     * @return ideal(this : h), a Groebner base
903     */
904    //@SuppressWarnings("unchecked")
905    public SolvableIdeal<C> quotient(GenSolvablePolynomial<C> h) {
906        if (h == null) { // == (0)
907            return this;
908        }
909        if (h.isZERO()) {
910            return this;
911        }
912        if (this.isZERO()) {
913            return this;
914        }
915        List<GenSolvablePolynomial<C>> H;
916        H = new ArrayList<GenSolvablePolynomial<C>>(1);
917        H.add(h);
918        SolvableIdeal<C> Hi = new SolvableIdeal<C>(getRing(), H, true, sided);
919
920        SolvableIdeal<C> I = this.intersect(Hi);
921
922        List<GenSolvablePolynomial<C>> Q;
923        Q = new ArrayList<GenSolvablePolynomial<C>>(I.getList().size());
924        GenSolvablePolynomial<C> p;
925        for (GenSolvablePolynomial<C> q : I.getList()) {
926            p = q.divide(h); // remainder == 0, (GenSolvablePolynomial<C>)
927            if (!p.isZERO()) {
928                p = p.monic();
929                Q.add(p);
930            }
931            if (debug) {
932                GenSolvablePolynomial<C> r = q.remainder(h); // (GenSolvablePolynomial<C>)
933                if (!r.isZERO()) {
934                    System.out.println("error remainder !=0: " + r + ", q = " + q + ", h = " + h);
935                    throw new RuntimeException("remainder !=0");
936                }
937            }
938        }
939        return new SolvableIdeal<C>(getRing(), Q, true /*false?*/, sided);
940    }
941
942
943    /**
944     * Quotient. Generators for the solvable ideal quotient.
945     * @param H solvable ideal
946     * @return ideal(this : H), a Groebner base
947     */
948    public SolvableIdeal<C> quotient(SolvableIdeal<C> H) {
949        if (H == null || H.isZERO()) { // == (0)
950            return this;
951        }
952        if (this.isZERO()) {
953            return this;
954        }
955        SolvableIdeal<C> Q = null;
956        for (GenSolvablePolynomial<C> h : H.getList()) {
957            SolvableIdeal<C> Hi = this.quotient(h);
958            if (Q == null) {
959                Q = Hi;
960            } else {
961                Q = Q.intersect(Hi);
962            }
963        }
964        return Q;
965    }
966
967
968    /**
969     * Infinite quotient. Generators for the infinite solvable ideal quotient.
970     * @param h solvable polynomial
971     * @return ideal(this : h<sup>s</sup>), a Groebner base
972     */
973    public SolvableIdeal<C> infiniteQuotientRab(GenSolvablePolynomial<C> h) {
974        if (h == null || h.isZERO()) { // == (0)
975            return getONE();
976        }
977        if (h.isONE()) {
978            return this;
979        }
980        if (this.isZERO()) {
981            return this;
982        }
983        if (!getRing().isCommutative()) {
984            throw new UnsupportedOperationException("Rabinowich trick only for commutative polynomial rings");
985        }
986        SolvableIdeal<C> I = this.GB(); // should be already
987        List<GenSolvablePolynomial<C>> a = I.getList();
988        List<GenSolvablePolynomial<C>> c;
989        c = new ArrayList<GenSolvablePolynomial<C>>(a.size() + 1);
990
991        GenSolvablePolynomialRing<C> tfac = getRing().extend(1);
992        // term order is also adjusted
993        for (GenSolvablePolynomial<C> p : a) {
994            p = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 0L); // p
995            c.add(p);
996        }
997        GenSolvablePolynomial<C> q = (GenSolvablePolynomial<C>) h.extend(tfac, 0, 1L);
998        GenSolvablePolynomial<C> r = tfac.getONE(); // h.extend( tfac, 0, 0L );
999        GenSolvablePolynomial<C> hs = (GenSolvablePolynomial<C>) q.subtract(r); // 1 - t*h // (1-t)*h
1000        c.add(hs);
1001        logger.warn("infiniteQuotientRab computing GB ");
1002        List<GenSolvablePolynomial<C>> g = bb.leftGB(c);
1003        if (debug) {
1004            logger.info("infiniteQuotientRab    = {}, c = {}", tfac, c);
1005            logger.info("infiniteQuotientRab GB = {}", g);
1006        }
1007        SolvableIdeal<C> E = new SolvableIdeal<C>(tfac, g, true, sided);
1008        SolvableIdeal<C> Is = E.intersect(getRing());
1009        return Is;
1010    }
1011
1012
1013    /**
1014     * Infinite quotient exponent.
1015     * @param h solvable polynomial
1016     * @param Q quotient this : h^\infinity
1017     * @return s with Q = this : h<sup>s</sup>
1018     */
1019    public int infiniteQuotientExponent(GenSolvablePolynomial<C> h, SolvableIdeal<C> Q) {
1020        int s = 0;
1021        if (h == null) { // == 0
1022            return s;
1023        }
1024        if (h.isZERO() || h.isONE()) {
1025            return s;
1026        }
1027        if (this.isZERO() || this.isONE()) {
1028            return s;
1029        }
1030        //see below: if (this.contains(Q)) {
1031        //    return s;
1032        //}
1033        GenSolvablePolynomial<C> p = getRing().getONE();
1034        for (GenSolvablePolynomial<C> q : Q.getList()) {
1035            if (this.contains(q)) {
1036                continue;
1037            }
1038            //System.out.println("q = " + q + ", p = " + p + ", s = " + s);
1039            GenSolvablePolynomial<C> qp = q.multiply(p);
1040            while (!this.contains(qp)) {
1041                p = p.multiply(h);
1042                s++;
1043                qp = q.multiply(p);
1044            }
1045        }
1046        return s;
1047    }
1048
1049
1050    /**
1051     * Infinite quotient. Generators for the infinite solvable ideal quotient.
1052     * @param h solvable polynomial
1053     * @return ideal(this : h<sup>s</sup>), a Groebner base
1054     */
1055    public SolvableIdeal<C> infiniteQuotient(GenSolvablePolynomial<C> h) {
1056        if (h == null) { // == (0)
1057            return this;
1058        }
1059        if (h.isZERO()) {
1060            return this;
1061        }
1062        if (this.isZERO()) {
1063            return this;
1064        }
1065        int s = 0;
1066        SolvableIdeal<C> I = this.GB(); // should be already
1067        GenSolvablePolynomial<C> hs = h;
1068        SolvableIdeal<C> Is = null;
1069        logger.info("infiniteQuotient hs = {}", hs);
1070        long dm = -1;
1071        boolean eq = false;
1072        while (!eq) {
1073            Is = I.quotient(hs);
1074            Is = Is.GB(); // should be already
1075            //logger.info("ideal Is = {}", Is);
1076            logger.info("infiniteQuotient s = {}", s);
1077            if (Is.isZERO()) {
1078                logger.warn("infiniteQuotient does not exist");
1079                return I;
1080            }
1081            eq = Is.contains(I); // I.contains(Is) always
1082            if (!eq) {
1083                long ds = PolyUtil.<C> totalDegree(Is.list.getList());
1084                if (dm < 0) {
1085                    dm = ds;
1086                }
1087                //System.out.println("deg(Is) = " + ds);
1088                if (ds > dm) {
1089                    logger.warn("no convergence in infiniteQuotient (dm,ds): {} < {}", dm, ds);
1090                    return I;
1091                    //throw new RuntimeException("no convergence in infiniteQuotient");
1092                }
1093                I = Is;
1094                s++;
1095                // hs = hs.multiply( h );
1096            }
1097        }
1098        return Is;
1099    }
1100
1101
1102    /**
1103     * Radical membership test.
1104     * @param h solvable polynomial
1105     * @return true if h is contained in the radical of ideal(this), else false.
1106     */
1107    public boolean isRadicalMember(GenSolvablePolynomial<C> h) {
1108        if (h == null) { // == (0)
1109            return true;
1110        }
1111        if (h.isZERO()) {
1112            return true;
1113        }
1114        if (this.isZERO()) {
1115            return true;
1116        }
1117        SolvableIdeal<C> x = infiniteQuotientRab(h); // may fail
1118        if (debug) {
1119            logger.debug("infiniteQuotientRab = {}", x);
1120        }
1121        return x.isONE();
1122    }
1123
1124
1125    /**
1126     * Infinite Quotient. Generators for the solvable ideal infinite quotient.
1127     * @param H solvable ideal
1128     * @return ideal(this : H<sup>s</sup>), a Groebner base
1129     */
1130    public SolvableIdeal<C> infiniteQuotient(SolvableIdeal<C> H) {
1131        if (H == null) { // == (0)
1132            return this;
1133        }
1134        if (H.isZERO()) {
1135            return this;
1136        }
1137        if (this.isZERO()) {
1138            return this;
1139        }
1140        SolvableIdeal<C> Q = null;
1141        for (GenSolvablePolynomial<C> h : H.getList()) {
1142            SolvableIdeal<C> Hi = this.infiniteQuotient(h);
1143            if (Q == null) {
1144                Q = Hi;
1145            } else {
1146                Q = Q.intersect(Hi);
1147            }
1148        }
1149        return Q;
1150    }
1151
1152
1153    /**
1154     * Infinite Quotient. Generators for the solvable ideal infinite quotient.
1155     * @param H solvable ideal
1156     * @return ideal(this : H<sup>s</sup>), a Groebner base
1157     */
1158    public SolvableIdeal<C> infiniteQuotientRab(SolvableIdeal<C> H) {
1159        if (H == null) { // == (0)
1160            return this;
1161        }
1162        if (H.isZERO()) {
1163            return this;
1164        }
1165        if (this.isZERO()) {
1166            return this;
1167        }
1168        SolvableIdeal<C> Q = null;
1169        for (GenSolvablePolynomial<C> h : H.getList()) {
1170            SolvableIdeal<C> Hi = this.infiniteQuotientRab(h); // may fail
1171            if (Q == null) {
1172                Q = Hi;
1173            } else {
1174                Q = Q.intersect(Hi);
1175            }
1176        }
1177        return Q;
1178    }
1179
1180
1181    /**
1182     * Power. Generators for the power of this solvable ideal. Note: if this
1183     * ideal is a Groebner base, a Groebner base is returned.
1184     * @param d integer
1185     * @return ideal(this^d)
1186     */
1187    public SolvableIdeal<C> power(int d) {
1188        if (d <= 0) {
1189            return getONE();
1190        }
1191        if (this.isZERO() || this.isONE()) {
1192            return this;
1193        }
1194        SolvableIdeal<C> c = this;
1195        for (int i = 1; i < d; i++) {
1196            c = c.product(this);
1197        }
1198        return c;
1199    }
1200
1201
1202    /**
1203     * Normalform for element.
1204     * @param h solvable polynomial
1205     * @return left/right/twosided normalform of h with respect to this
1206     */
1207    public GenSolvablePolynomial<C> normalform(GenSolvablePolynomial<C> h) {
1208        if (h == null) {
1209            return h;
1210        }
1211        if (h.isZERO()) {
1212            return h;
1213        }
1214        if (this.isZERO()) {
1215            return h;
1216        }
1217        GenSolvablePolynomial<C> r;
1218        if (sided == Side.left) {
1219            r = red.leftNormalform(getList(), h);
1220        } else if (sided == Side.right) {
1221            r = red.rightNormalform(getList(), h);
1222        } else { //if (sided == Side.twosided) {
1223            //r = red.twosidedNormalform(getList(), h);
1224            //r = red.normalform(getList(), h);
1225            r = red.leftNormalform(getList(), h);
1226        }
1227        return r;
1228    }
1229
1230
1231    /**
1232     * Normalform for list of solvable elements.
1233     * @param L solvable polynomial list
1234     * @return list of left normalforms of the elements of L with respect to
1235     *         this
1236     */
1237    public List<GenSolvablePolynomial<C>> normalform(List<GenSolvablePolynomial<C>> L) {
1238        if (L == null) {
1239            return L;
1240        }
1241        if (L.isEmpty()) {
1242            return L;
1243        }
1244        if (this.isZERO()) {
1245            return L;
1246        }
1247        List<GenSolvablePolynomial<C>> M = new ArrayList<GenSolvablePolynomial<C>>(L.size());
1248        for (GenSolvablePolynomial<C> h : L) {
1249            GenSolvablePolynomial<C> r = normalform(h);
1250            if (r != null && !r.isZERO()) {
1251                M.add(r);
1252            }
1253        }
1254        return M;
1255    }
1256
1257
1258    /**
1259     * Annihilator for element modulo this ideal.
1260     * @param h solvable polynomial
1261     * @return annihilator of h with respect to this
1262     */
1263    public SolvableIdeal<C> annihilator(GenSolvablePolynomial<C> h) {
1264        if (h == null || h.isZERO()) {
1265            return getZERO();
1266        }
1267        if (this.isZERO()) {
1268            return this;
1269        }
1270        doGB();
1271        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(1 + getList().size());
1272        F.add(h);
1273        F.addAll(getList());
1274        //System.out.println("F = " + F);
1275        SolvableSyzygyAbstract<C> syz = new SolvableSyzygySeq<C>(getRing().coFac);
1276        List<List<GenSolvablePolynomial<C>>> S = syz.leftZeroRelationsArbitrary(F);
1277        //System.out.println("S = " + S);
1278        List<GenSolvablePolynomial<C>> gen = new ArrayList<GenSolvablePolynomial<C>>(S.size());
1279        for (List<GenSolvablePolynomial<C>> rel : S) {
1280            if (rel == null || rel.isEmpty()) {
1281                continue;
1282            }
1283            GenSolvablePolynomial<C> p = rel.get(0);
1284            if (p == null || p.isZERO()) {
1285                continue;
1286            }
1287            gen.add(p);
1288        }
1289        SolvableIdeal<C> ann = new SolvableIdeal<C>(getRing(), gen, false, sided);
1290        //System.out.println("ann = " + ann);
1291        return ann;
1292    }
1293
1294
1295    /**
1296     * Test for annihilator of element modulo this ideal.
1297     * @param h solvable polynomial
1298     * @param A solvable ideal
1299     * @return true, if A is the annihilator of h with respect to this
1300     */
1301    public boolean isAnnihilator(GenSolvablePolynomial<C> h, SolvableIdeal<C> A) {
1302        SolvableIdeal<C> B = A.product(h);
1303        return contains(B);
1304    }
1305
1306
1307    /**
1308     * Annihilator for ideal modulo this ideal.
1309     * @param H solvable ideal
1310     * @return annihilator of H with respect to this
1311     */
1312    public SolvableIdeal<C> annihilator(SolvableIdeal<C> H) {
1313        if (H == null || H.isZERO()) {
1314            return getZERO();
1315        }
1316        if (this.isZERO()) {
1317            return this;
1318        }
1319        SolvableIdeal<C> ann = null;
1320        for (GenSolvablePolynomial<C> h : H.getList()) {
1321            SolvableIdeal<C> Hi = this.annihilator(h);
1322            if (ann == null) {
1323                ann = Hi;
1324            } else {
1325                ann = ann.intersect(Hi);
1326            }
1327        }
1328        return ann;
1329    }
1330
1331
1332    /**
1333     * Test for annihilator of ideal modulo this ideal.
1334     * @param H solvable ideal
1335     * @param A solvable ideal
1336     * @return true, if A is the annihilator of H with respect to this
1337     */
1338    public boolean isAnnihilator(SolvableIdeal<C> H, SolvableIdeal<C> A) {
1339        SolvableIdeal<C> B = A.product(H);
1340        return contains(B);
1341    }
1342
1343
1344    /**
1345     * Inverse for element modulo this ideal.
1346     * @param h solvable polynomial
1347     * @return inverse of h with respect to this, if defined
1348     */
1349    public GenSolvablePolynomial<C> inverse(GenSolvablePolynomial<C> h) {
1350        if (h == null || h.isZERO()) {
1351            throw new NotInvertibleException("zero not invertible");
1352        }
1353        if (this.isZERO()) {
1354            throw new NotInvertibleException("zero ideal");
1355        }
1356        doGB();
1357        if (this.isONE()) {
1358            throw new NotInvertibleException("one ideal");
1359        }
1360        if (h.isUnit()) {
1361            return (GenSolvablePolynomial<C>) h.inverse();
1362        }
1363        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(1 + list.list.size());
1364        F.add(h);
1365        F.addAll(getList());
1366        //System.out.println("F = " + F);
1367        SolvableExtendedGB<C> x = bb.extLeftGB(F);
1368        List<GenSolvablePolynomial<C>> G = x.G;
1369        //System.out.println("G = " + G);
1370        GenSolvablePolynomial<C> one = null;
1371        int i = -1;
1372        for (GenSolvablePolynomial<C> p : G) {
1373            i++;
1374            if (p == null) {
1375                continue;
1376            }
1377            if (p.isUnit()) {
1378                one = p;
1379                break;
1380            }
1381        }
1382        if (one == null) {
1383            throw new NotInvertibleException("one == null: h = " + h);
1384        }
1385        List<GenSolvablePolynomial<C>> row = x.G2F.get(i); // != -1
1386        //System.out.println("row = " + row);
1387        GenSolvablePolynomial<C> g = row.get(0);
1388        if (g == null || g.isZERO()) {
1389            throw new NotInvertibleException("g == 0: h = " + h);
1390        }
1391        GenSolvablePolynomial<C> gp = red.leftNormalform(getList(), g);
1392        if (gp.isZERO()) { // can happen with solvable rings
1393            throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g);
1394        }
1395        // adjust leading coefficient of g to get g*h == 1
1396        GenSolvablePolynomial<C> f = g.multiply(h);
1397        //System.out.println("f = " + f);
1398        GenSolvablePolynomial<C> k = red.leftNormalform(getList(), f);
1399        //System.out.println("k = " + k);
1400        if (!k.isONE()) {
1401            C lbc = k.leadingBaseCoefficient();
1402            lbc = lbc.inverse();
1403            g = g.multiply(lbc);
1404        }
1405        if (debug) {
1406            //logger.info("inv G = {}", G);
1407            //logger.info("inv G2F = {}", x.G2F);
1408            //logger.info("inv row {} = {}", i, row);
1409            //logger.info("inv h = {}", h);
1410            //logger.info("inv g = {}", g);
1411            //logger.info("inv f = {}", f);
1412            f = g.multiply(h);
1413            k = red.leftNormalform(getList(), f);
1414            logger.debug("inv k = {}", k);
1415            if (!k.isUnit()) {
1416                throw new NotInvertibleException(" k = " + k);
1417            }
1418        }
1419        return g;
1420    }
1421
1422
1423    /**
1424     * Test if element is a unit modulo this ideal.
1425     * @param h solvable polynomial
1426     * @return true if h is a unit with respect to this, else false
1427     */
1428    public boolean isUnit(GenSolvablePolynomial<C> h) {
1429        if (h == null || h.isZERO()) {
1430            return false;
1431        }
1432        if (this.isZERO()) {
1433            return false;
1434        }
1435        doGB();
1436        if (this.isONE()) {
1437            return false;
1438        }
1439        List<GenSolvablePolynomial<C>> F = new ArrayList<GenSolvablePolynomial<C>>(1 + list.list.size());
1440        F.add(h);
1441        F.addAll(getList());
1442        List<GenSolvablePolynomial<C>> G = bb.leftGB(F);
1443        for (GenSolvablePolynomial<C> p : G) {
1444            if (p == null) {
1445                continue;
1446            }
1447            if (p.isUnit()) {
1448                return true;
1449            }
1450        }
1451        return false;
1452    }
1453
1454
1455    /**
1456     * Ideal common zero test.
1457     * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or &ge; 1.
1458     */
1459    public int commonZeroTest() {
1460        if (this.isZERO()) {
1461            return 1;
1462        }
1463        if (!isGB) {
1464            doGB();
1465        }
1466        if (this.isONE()) {
1467            return -1;
1468        }
1469        return bb.commonZeroTest(getList());
1470    }
1471
1472
1473    /**
1474     * Test if this ideal is maximal.
1475     * @return true, if this is certainly maximal and not one, 
1476     *         false, if this is one, has dimension &ge; 1 or it is not jet determined if it is maximal.
1477     */
1478    public boolean isMaximal() {
1479        if (commonZeroTest() != 0) {
1480            return false;
1481        }
1482        for (Long d : univariateDegrees()) {
1483            if (d > 1L) {
1484                return false;
1485            }
1486        }
1487        return true;
1488    }
1489
1490
1491    /**
1492     * Univariate head term degrees.
1493     * @return a list of the degrees of univariate head terms.
1494     */
1495    public List<Long> univariateDegrees() {
1496        List<Long> ud = new ArrayList<Long>();
1497        if (this.isZERO()) {
1498            return ud;
1499        }
1500        if (!isGB) {
1501            doGB();
1502        }
1503        if (this.isONE()) {
1504            return ud;
1505        }
1506        return bb.univariateDegrees(getList());
1507    }
1508
1509
1510    /**
1511     * Ideal dimension.
1512     * @return a dimension container (dim,maxIndep,list(maxIndep),vars).
1513     */
1514    public Dimension dimension() {
1515        Ideal<C> ci = new Ideal<C>(list);
1516        return ci.dimension();
1517    }
1518
1519
1520    /**
1521     * Construct univariate polynomials of minimal degree in all variables in
1522     * zero dimensional ideal(G).
1523     * @return list of univariate solvable polynomial of minimal degree in each
1524     *         variable in ideal(G)
1525     */
1526    public List<GenSolvablePolynomial<C>> constructUnivariate() {
1527        List<GenSolvablePolynomial<C>> univs = new ArrayList<GenSolvablePolynomial<C>>();
1528        for (int i = getRing().nvar - 1; i >= 0; i--) {
1529            GenSolvablePolynomial<C> u = constructUnivariate(i);
1530            univs.add(u);
1531        }
1532        return univs;
1533    }
1534
1535
1536    /**
1537     * Construct univariate polynomial of minimal degree in variable i in zero
1538     * dimensional ideal(G).
1539     * @param i variable index.
1540     * @return univariate solvable polynomial of minimal degree in variable i in
1541     *         ideal(G)
1542     */
1543    public GenSolvablePolynomial<C> constructUnivariate(int i) {
1544        doGB();
1545        return bb.constructUnivariate(i, getList());
1546    }
1547
1548}