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 &ge; 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}