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