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