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