001/*
002 * $Id: GroebnerBaseAbstract.java 5908 2018-08-25 11:49:29Z kredel $
003 */
004
005package edu.jas.gb;
006
007
008import java.util.ArrayList;
009import java.util.Collections;
010import java.util.HashSet;
011import java.util.List;
012import java.util.ListIterator;
013import java.util.Map;
014import java.util.Set;
015import java.util.TreeMap;
016
017import org.apache.logging.log4j.Logger;
018import org.apache.logging.log4j.LogManager; 
019
020import edu.jas.poly.ExpVector;
021import edu.jas.poly.GenPolynomial;
022import edu.jas.poly.GenPolynomialRing;
023import edu.jas.poly.ModuleList;
024import edu.jas.poly.OrderedPolynomialList;
025import edu.jas.poly.PolyUtil;
026import edu.jas.poly.PolynomialList;
027import edu.jas.poly.TermOrder;
028import edu.jas.structure.RingElem;
029import edu.jas.structure.RingFactory;
030import edu.jas.vector.BasicLinAlg;
031
032
033/**
034 * Groebner Bases abstract class. Implements common Groebner bases and GB test
035 * methods.
036 * @param <C> coefficient type
037 * @author Heinz Kredel
038 * 
039 * @see edu.jas.application.GBAlgorithmBuilder
040 * @see edu.jas.gbufd.GBFactory
041 */
042
043public abstract class GroebnerBaseAbstract<C extends RingElem<C>> implements GroebnerBase<C> {
044
045
046    private static final Logger logger = LogManager.getLogger(GroebnerBaseAbstract.class);
047
048
049    private static final boolean debug = logger.isDebugEnabled();
050
051
052    /**
053     * Reduction engine.
054     */
055    public final Reduction<C> red;
056
057
058    /**
059     * Strategy for pair selection.
060     */
061    public final PairList<C> strategy;
062
063
064    /**
065     * linear algebra engine.
066     */
067    public final BasicLinAlg<GenPolynomial<C>> blas;
068
069
070    /**
071     * Constructor.
072     */
073    public GroebnerBaseAbstract() {
074        this(new ReductionSeq<C>());
075    }
076
077
078    /**
079     * Constructor.
080     * @param red Reduction engine
081     */
082    public GroebnerBaseAbstract(Reduction<C> red) {
083        this(red, new OrderedPairlist<C>());
084    }
085
086
087    /**
088     * Constructor.
089     * @param pl pair selection strategy
090     */
091    public GroebnerBaseAbstract(PairList<C> pl) {
092        this(new ReductionSeq<C>(), pl);
093    }
094
095
096    /**
097     * Constructor.
098     * @param red Reduction engine
099     * @param pl pair selection strategy
100     */
101    public GroebnerBaseAbstract(Reduction<C> red, PairList<C> pl) {
102        if (red == null) {
103            red = new ReductionSeq<C>();
104        }
105        this.red = red;
106        if (pl == null) {
107            pl = new OrderedPairlist<C>();
108        }
109        this.strategy = pl;
110        blas = new BasicLinAlg<GenPolynomial<C>>();
111    }
112
113
114    /**
115     * Get the String representation with GB engines.
116     * @see java.lang.Object#toString()
117     */
118    @Override
119    public String toString() {
120        return this.getClass().getSimpleName();
121    }
122
123
124    /**
125     * Normalize polynomial list.
126     * @param A list of polynomials.
127     * @return list of polynomials with zeros removed and ones/units reduced.
128     */
129    public List<GenPolynomial<C>> normalizeZerosOnes(List<GenPolynomial<C>> A) {
130        if (A == null) {
131            return A;
132        }
133        List<GenPolynomial<C>> N = new ArrayList<GenPolynomial<C>>(A.size());
134        if (A.isEmpty()) {
135            return N;
136        }
137        for (GenPolynomial<C> p : A) {
138            if (p == null || p.isZERO()) {
139                continue;
140            }
141            if (p.isUnit()) {
142                N.clear();
143                N.add(p.ring.getONE());
144                return N;
145            }
146            N.add(p.abs());
147        }
148        //N.trimToSize();
149        return N;
150    }
151
152
153    /**
154     * Groebner base test.
155     * @param F polynomial list.
156     * @return true, if F is a Groebner base, else false.
157     */
158    public boolean isGB(List<GenPolynomial<C>> F) {
159        return isGB(0, F);
160    }
161
162
163    /**
164     * Groebner base test.
165     * @param modv module variable number.
166     * @param F polynomial list.
167     * @return true, if F is a Groebner base, else false.
168     */
169    public boolean isGB(int modv, List<GenPolynomial<C>> F) {
170        return isGB(modv, F, true);
171    }
172
173
174    /**
175     * Groebner base test.
176     * @param F polynomial list.
177     * @param b true for simple test, false for GB test.
178     * @return true, if F is a Groebner base, else false.
179     */
180    public boolean isGB(List<GenPolynomial<C>> F, boolean b) {
181        return isGB(0, F, b);
182    }
183
184
185    /**
186     * Groebner base test.
187     * @param modv module variable number.
188     * @param F polynomial list.
189     * @param b true for simple test, false for GB test.
190     * @return true, if F is a Groebner base, else false.
191     */
192    public boolean isGB(int modv, List<GenPolynomial<C>> F, boolean b) {
193        if (b) {
194            return isGBsimple(modv, F);
195        }
196        return isGBidem(modv, F);
197    }
198
199
200    /**
201     * Groebner base simple test.
202     * @param modv module variable number.
203     * @param F polynomial list.
204     * @return true, if F is a Groebner base, else false.
205     */
206    public boolean isGBsimple(int modv, List<GenPolynomial<C>> F) {
207        if (F == null || F.isEmpty()) {
208            return true;
209        }
210        GenPolynomial<C> pi, pj, s, h;
211        ExpVector ei, ej, eij;
212        for (int i = 0; i < F.size(); i++) {
213            pi = F.get(i);
214            ei = pi.leadingExpVector();
215            for (int j = i + 1; j < F.size(); j++) {
216                pj = F.get(j);
217                ej = pj.leadingExpVector();
218                if (!red.moduleCriterion(modv, ei, ej)) {
219                    continue;
220                }
221                eij = ei.lcm(ej);
222                if (!red.criterion4(ei, ej, eij)) {
223                    continue;
224                }
225                if (!criterion3(i, j, eij, F)) {
226                    continue;
227                }
228                s = red.SPolynomial(pi, pj);
229                if (s.isZERO()) {
230                    continue;
231                }
232                //System.out.println("i, j = " + i + ", " + j); 
233                h = red.normalform(F, s);
234                if (!h.isZERO()) {
235                    logger.info("no GB: pi = " + pi + ", pj = " + pj);
236                    logger.info("s  = " + s + ", h = " + h);
237                    return false;
238                }
239            }
240        }
241        return true;
242    }
243
244
245    /**
246     * GB criterium 3.
247     * @return true if the S-polynomial(i,j) is required.
248     */
249    boolean criterion3(int i, int j, ExpVector eij, List<GenPolynomial<C>> P) {
250        assert i < j;
251        //for ( int k = 0; k < P.size(); k++ ) {
252        // not of much use
253        for (int k = 0; k < i; k++) {
254            GenPolynomial<C> A = P.get(k);
255            ExpVector ek = A.leadingExpVector();
256            if (eij.multipleOf(ek)) {
257                return false;
258            }
259        }
260        return true;
261    }
262
263
264    /**
265     * Groebner base idempotence test.
266     * @param modv module variable number.
267     * @param F polynomial list.
268     * @return true, if F is equal to GB(F), else false.
269     */
270    public boolean isGBidem(int modv, List<GenPolynomial<C>> F) {
271        if (F == null || F.isEmpty()) {
272            return true;
273        }
274        GenPolynomialRing<C> pring = F.get(0).ring;
275        List<GenPolynomial<C>> G = GB(modv, F);
276        PolynomialList<C> Fp = new PolynomialList<C>(pring, F);
277        PolynomialList<C> Gp = new PolynomialList<C>(pring, G);
278        return Fp.compareTo(Gp) == 0;
279    }
280
281
282    /**
283     * Common zero test.
284     * @param F polynomial list.
285     * @return -1, 0 or 1 if dimension(ideal(F)) &eq; -1, 0 or &ge; 1.
286     */
287    public int commonZeroTest(List<GenPolynomial<C>> F) {
288        if (F == null || F.isEmpty()) {
289            return 1;
290        }
291        GenPolynomialRing<C> pfac = F.get(0).ring;
292        if (pfac.nvar <= 0) {
293            return -1;
294        }
295        //int uht = 0;
296        Set<Integer> v = new HashSet<Integer>(); // for non reduced GBs
297        for (GenPolynomial<C> p : F) {
298            if (p.isZERO()) {
299                continue;
300            }
301            if (p.isConstant()) { // for non-monic lists
302                return -1;
303            }
304            ExpVector e = p.leadingExpVector();
305            if (e == null) {
306                continue;
307            }
308            int[] u = e.dependencyOnVariables();
309            if (u == null) {
310                continue;
311            }
312            if (u.length == 1) {
313                //uht++;
314                v.add(u[0]);
315            }
316        }
317        if (pfac.nvar == v.size()) {
318            return 0;
319        }
320        return 1;
321    }
322
323
324    /**
325     * Groebner base using pairlist class.
326     * @param F polynomial list.
327     * @return GB(F) a Groebner base of F.
328     */
329    public List<GenPolynomial<C>> GB(List<GenPolynomial<C>> F) {
330        return GB(0, F);
331    }
332
333
334    /**
335     * isGB.
336     * @param M a module basis.
337     * @return true, if M is a Groebner base, else false.
338     */
339    public boolean isGB(ModuleList<C> M) {
340        return isGB(M,false);
341    }
342
343    
344    /**
345     * isGB.
346     * @param M a module basis.
347     * @param top true for TOP term order, false for POT term order.
348     * @return true, if M is a Groebner base, else false.
349     */
350    public boolean isGB(ModuleList<C> M, boolean top) {
351        if (M == null || M.list == null) {
352            return true;
353        }
354        if (M.rows == 0 || M.cols == 0) {
355            return true;
356        }
357        PolynomialList<C> F = M.getPolynomialList(top);
358        int modv = M.cols; // > 0  
359        return isGB(modv, F.list);
360    }
361
362
363    /**
364     * GB.
365     * @param M a module basis.
366     * @return GB(M), a Groebner base of M.
367     */
368    public ModuleList<C> GB(ModuleList<C> M) {
369        return GB(M,false);
370    }
371
372    
373    /**
374     * GB.
375     * @param M a module basis.
376     * @param top true for TOP term order, false for POT term order.
377     * @return GB(M), a Groebner base of M wrt. TOP or POT.
378     */
379    public ModuleList<C> GB(ModuleList<C> M, boolean top) {
380        ModuleList<C> N = M;
381        if (M == null || M.list == null) {
382            return N;
383        }
384        if (M.rows == 0 || M.cols == 0) {
385            return N;
386        }
387        PolynomialList<C> F = M.getPolynomialList(top);
388        int modv = M.cols;
389        List<GenPolynomial<C>> G = GB(modv, F.list);
390        F = new PolynomialList<C>(F.ring, G);
391        N = F.getModuleList(modv);
392        return N;
393    }
394
395
396    /**
397     * Extended Groebner base using critical pair class.
398     * @param F polynomial list.
399     * @return a container for a Groebner base G of F together with
400     *         back-and-forth transformations.
401     */
402    public ExtendedGB<C> extGB(List<GenPolynomial<C>> F) {
403        return extGB(0, F);
404    }
405
406
407    /**
408     * Extended Groebner base using critical pair class.
409     * @param modv module variable number.
410     * @param F polynomial list.
411     * @return a container for a Groebner base G of F together with
412     *         back-and-forth transformations.
413     */
414    public ExtendedGB<C> extGB(int modv, List<GenPolynomial<C>> F) {
415        throw new UnsupportedOperationException("extGB not implemented in " + this.getClass().getSimpleName());
416    }
417
418
419    /**
420     * Minimal ordered Groebner basis.
421     * @param Gp a Groebner base.
422     * @return a reduced Groebner base of Gp.
423     */
424    public List<GenPolynomial<C>> minimalGB(List<GenPolynomial<C>> Gp) {
425        if (Gp == null || Gp.size() <= 1) {
426            return Gp;
427        }
428        // remove zero polynomials
429        List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(Gp.size());
430        for (GenPolynomial<C> a : Gp) {
431            if (a != null && !a.isZERO()) { // always true in GB()
432                // already positive a = a.abs();
433                G.add(a);
434            }
435        }
436        if (G.size() <= 1) {
437            return G;
438        }
439        // remove top reducible polynomials
440        GenPolynomial<C> a;
441        List<GenPolynomial<C>> F;
442        F = new ArrayList<GenPolynomial<C>>(G.size());
443        while (G.size() > 0) {
444            a = G.remove(0);
445            if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) {
446                // drop polynomial 
447                if (debug) {
448                    System.out.println("dropped " + a);
449                    List<GenPolynomial<C>> ff;
450                    ff = new ArrayList<GenPolynomial<C>>(G);
451                    ff.addAll(F);
452                    a = red.normalform(ff, a);
453                    if (!a.isZERO()) {
454                        System.out.println("error, nf(a) " + a);
455                    }
456                }
457            } else {
458                F.add(a);
459            }
460        }
461        G = F;
462        if (G.size() <= 1) {
463            return G;
464        }
465        // reduce remaining polynomials
466        Collections.reverse(G); // important for lex GB
467        int len = G.size();
468        if (debug) {
469            System.out.println("#G " + len);
470            for (GenPolynomial<C> aa : G) {
471                System.out.println("aa = " + aa.length() + ", lt = " + aa.getMap().keySet());
472            }
473        }
474        int i = 0;
475        while (i < len) {
476            a = G.remove(0);
477            if (debug) {
478                System.out.println("doing " + a.length() + ", lt = " + a.leadingExpVector());
479            }
480            a = red.normalform(G, a);
481            G.add(a); // adds as last
482            i++;
483        }
484        Collections.reverse(G); // undo reverse
485        return G;
486    }
487
488
489    /**
490     * Test for minimal ordered Groebner basis.
491     * @param Gp an ideal base.
492     * @return true, if Gp is a reduced minimal Groebner base.
493     */
494    public boolean isMinimalGB(List<GenPolynomial<C>> Gp) {
495        if (Gp == null || Gp.size() == 0) {
496            return true;
497        }
498        // test for zero polynomials
499        for (GenPolynomial<C> a : Gp) {
500            if (a == null || a.isZERO()) {
501                if (debug) {
502                    logger.debug("zero polynomial " + a);
503                }
504                return false;
505            }
506        }
507        // test for top reducible polynomials
508        List<GenPolynomial<C>> G = new ArrayList<GenPolynomial<C>>(Gp);
509        List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(G.size());
510        while (G.size() > 0) {
511            GenPolynomial<C> a = G.remove(0);
512            if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) {
513                if (debug) {
514                    logger.debug("top reducible polynomial " + a);
515                }
516                return false;
517            }
518            F.add(a);
519        }
520        G = F;
521        if (G.size() <= 1) {
522            return true;
523        }
524        // test reducibility of polynomials
525        int len = G.size();
526        int i = 0;
527        while (i < len) {
528            GenPolynomial<C> a = G.remove(0);
529            if (!red.isNormalform(G, a)) {
530                if (debug) {
531                    logger.debug("reducible polynomial " + a);
532                }
533                return false;
534            }
535            G.add(a); // re-adds as last
536            i++;
537        }
538        return true;
539    }
540
541
542    /**
543     * Test if reduction matrix.
544     * @param exgb an ExtendedGB container.
545     * @return true, if exgb contains a reduction matrix, else false.
546     */
547    public boolean isReductionMatrix(ExtendedGB<C> exgb) {
548        if (exgb == null) {
549            return true;
550        }
551        return isReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F);
552    }
553
554
555    /**
556     * Test if reduction matrix.
557     * @param F a polynomial list.
558     * @param G a Groebner base.
559     * @param Mf a possible reduction matrix.
560     * @param Mg a possible reduction matrix.
561     * @return true, if Mg and Mf are reduction matrices, else false.
562     */
563    public boolean isReductionMatrix(List<GenPolynomial<C>> F, List<GenPolynomial<C>> G,
564                    List<List<GenPolynomial<C>>> Mf, List<List<GenPolynomial<C>>> Mg) {
565        // no more check G and Mg: G * Mg[i] == 0
566        // check F and Mg: F * Mg[i] == G[i]
567        int k = 0;
568        for (List<GenPolynomial<C>> row : Mg) {
569            boolean t = red.isReductionNF(row, F, G.get(k), null);
570            if (!t) {
571                logger.error("F isReductionMatrix s, k = " + F.size() + ", " + k);
572                return false;
573            }
574            k++;
575        }
576        // check G and Mf: G * Mf[i] == F[i]
577        k = 0;
578        for (List<GenPolynomial<C>> row : Mf) {
579            boolean t = red.isReductionNF(row, G, F.get(k), null);
580            if (!t) {
581                logger.error("G isReductionMatrix s, k = " + G.size() + ", " + k);
582                return false;
583            }
584            k++;
585        }
586        return true;
587    }
588
589
590    /**
591     * Normalize M. Make all rows the same size and make certain column elements
592     * zero.
593     * @param M a reduction matrix.
594     * @return normalized M.
595     */
596    public List<List<GenPolynomial<C>>> normalizeMatrix(int flen, List<List<GenPolynomial<C>>> M) {
597        if (M == null) {
598            return M;
599        }
600        if (M.size() == 0) {
601            return M;
602        }
603        List<List<GenPolynomial<C>>> N = new ArrayList<List<GenPolynomial<C>>>();
604        List<List<GenPolynomial<C>>> K = new ArrayList<List<GenPolynomial<C>>>();
605        int len = M.get(M.size() - 1).size(); // longest row
606        // pad / extend rows
607        for (List<GenPolynomial<C>> row : M) {
608            List<GenPolynomial<C>> nrow = new ArrayList<GenPolynomial<C>>(row);
609            for (int i = row.size(); i < len; i++) {
610                nrow.add(null);
611            }
612            N.add(nrow);
613        }
614        // System.out.println("norm N fill = " + N);
615        // make zero columns
616        int k = flen;
617        for (int i = 0; i < N.size(); i++) { // 0
618            List<GenPolynomial<C>> row = N.get(i);
619            if (debug) {
620                logger.info("row = " + row);
621            }
622            K.add(row);
623            if (i < flen) { // skip identity part
624                continue;
625            }
626            List<GenPolynomial<C>> xrow;
627            GenPolynomial<C> a;
628            //System.out.println("norm i = " + i);
629            for (int j = i + 1; j < N.size(); j++) {
630                List<GenPolynomial<C>> nrow = N.get(j);
631                //System.out.println("nrow j = " +j + ", " + nrow);
632                if (k < nrow.size()) { // always true
633                    a = nrow.get(k);
634                    //System.out.println("k, a = " + k + ", " + a);
635                    if (a != null && !a.isZERO()) {
636                        xrow = blas.scalarProduct(a, row);
637                        xrow = blas.vectorAdd(xrow, nrow);
638                        //System.out.println("xrow = " + xrow);
639                        N.set(j, xrow);
640                    }
641                }
642            }
643            k++;
644        }
645        //System.out.println("norm K reduc = " + K);
646        // truncate 
647        N.clear();
648        for (List<GenPolynomial<C>> row : K) {
649            List<GenPolynomial<C>> tr = new ArrayList<GenPolynomial<C>>();
650            for (int i = 0; i < flen; i++) {
651                tr.add(row.get(i));
652            }
653            N.add(tr);
654        }
655        K = N;
656        //System.out.println("norm K trunc = " + K);
657        return K;
658    }
659
660
661    /**
662     * Minimal extended groebner basis.
663     * @param Gp a Groebner base.
664     * @param M a reduction matrix, is modified.
665     * @return a (partially) reduced Groebner base of Gp in a container.
666     */
667    public ExtendedGB<C> minimalExtendedGB(int flen, List<GenPolynomial<C>> Gp, List<List<GenPolynomial<C>>> M) {
668        if (Gp == null) {
669            return null; //new ExtendedGB<C>(null,Gp,null,M);
670        }
671        if (Gp.size() <= 1) {
672            return new ExtendedGB<C>(null, Gp, null, M);
673        }
674        List<GenPolynomial<C>> G;
675        List<GenPolynomial<C>> F;
676        G = new ArrayList<GenPolynomial<C>>(Gp);
677        F = new ArrayList<GenPolynomial<C>>(Gp.size());
678
679        List<List<GenPolynomial<C>>> Mg;
680        List<List<GenPolynomial<C>>> Mf;
681        Mg = new ArrayList<List<GenPolynomial<C>>>(M.size());
682        Mf = new ArrayList<List<GenPolynomial<C>>>(M.size());
683        List<GenPolynomial<C>> row;
684        for (List<GenPolynomial<C>> r : M) {
685            // must be copied also
686            row = new ArrayList<GenPolynomial<C>>(r);
687            Mg.add(row);
688        }
689        row = null;
690
691        GenPolynomial<C> a;
692        ExpVector e;
693        ExpVector f;
694        GenPolynomial<C> p;
695        boolean mt;
696        ListIterator<GenPolynomial<C>> it;
697        ArrayList<Integer> ix = new ArrayList<Integer>();
698        ArrayList<Integer> jx = new ArrayList<Integer>();
699        int k = 0;
700        //System.out.println("flen, Gp, M = " + flen + ", " + Gp.size() + ", " + M.size() );
701        while (G.size() > 0) {
702            a = G.remove(0);
703            e = a.leadingExpVector();
704
705            it = G.listIterator();
706            mt = false;
707            while (it.hasNext() && !mt) {
708                p = it.next();
709                f = p.leadingExpVector();
710                mt = e.multipleOf(f);
711            }
712            it = F.listIterator();
713            while (it.hasNext() && !mt) {
714                p = it.next();
715                f = p.leadingExpVector();
716                mt = e.multipleOf(f);
717            }
718            //System.out.println("k, mt = " + k + ", " + mt);
719            if (!mt) {
720                F.add(a);
721                ix.add(k);
722            } else { // drop polynomial and corresponding row and column
723                // F.add( a.ring.getZERO() );
724                jx.add(k);
725            }
726            k++;
727        }
728        if (debug) {
729            logger.debug("ix, #M, jx = " + ix + ", " + Mg.size() + ", " + jx);
730        }
731        int fix = -1; // copied polys
732        // copy Mg to Mf as indicated by ix
733        for (int i = 0; i < ix.size(); i++) {
734            int u = ix.get(i);
735            if (u >= flen && fix == -1) {
736                fix = Mf.size();
737            }
738            //System.out.println("copy u, fix = " + u + ", " + fix);
739            if (u >= 0) {
740                row = Mg.get(u);
741                Mf.add(row);
742            }
743        }
744        if (F.size() <= 1 || fix == -1) {
745            return new ExtendedGB<C>(null, F, null, Mf);
746        }
747        // must return, since extended normalform has not correct order of polys
748        /*
749        G = F;
750        F = new ArrayList<GenPolynomial<C>>( G.size() );
751        List<GenPolynomial<C>> temp;
752        k = 0;
753        final int len = G.size();
754        while ( G.size() > 0 ) {
755            a = G.remove(0);
756            if ( k >= fix ) { // dont touch copied polys
757               row = Mf.get( k );
758               //System.out.println("doing k = " + k + ", " + a);
759               // must keep order, but removed polys missing
760               temp = new ArrayList<GenPolynomial<C>>( len );
761               temp.addAll( F );
762               temp.add( a.ring.getZERO() ); // ??
763               temp.addAll( G );
764               //System.out.println("row before = " + row);
765               a = red.normalform( row, temp, a );
766               //System.out.println("row after  = " + row);
767            }
768            F.add( a );
769            k++;
770        }
771        // does Mf need renormalization?
772        */
773        return new ExtendedGB<C>(null, F, null, Mf);
774    }
775
776
777    /**
778     * Univariate head term degrees.
779     * @param A list of polynomials.
780     * @return a list of the degrees of univariate head terms.
781     */
782    public List<Long> univariateDegrees(List<GenPolynomial<C>> A) {
783        List<Long> ud = new ArrayList<Long>();
784        if (A == null || A.size() == 0) {
785            return ud;
786        }
787        GenPolynomialRing<C> pfac = A.get(0).ring;
788        if (pfac.nvar <= 0) {
789            return ud;
790        }
791        //int uht = 0;
792        Map<Integer, Long> v = new TreeMap<Integer, Long>(); // for non reduced GBs
793        for (GenPolynomial<C> p : A) {
794            ExpVector e = p.leadingExpVector();
795            if (e == null) {
796                continue;
797            }
798            int[] u = e.dependencyOnVariables();
799            if (u == null) {
800                continue;
801            }
802            if (u.length == 1) {
803                //uht++;
804                Long d = v.get(u[0]);
805                if (d == null) {
806                    v.put(u[0], e.getVal(u[0]));
807                }
808            }
809        }
810        for (int i = 0; i < pfac.nvar; i++) {
811            Long d = v.get(i);
812            ud.add(d);
813        }
814        //Collections.reverse(ud);
815        return ud;
816    }
817
818
819    /**
820     * Construct univariate polynomial of minimal degree in variable i of a zero
821     * dimensional ideal(G).
822     * @param i variable index.
823     * @param G list of polynomials, a monic reduced Gr&ouml;bner base of a zero
824     *            dimensional ideal.
825     * @return univariate polynomial of minimal degree in variable i in ideal(G)
826     */
827    public GenPolynomial<C> constructUnivariate(int i, List<GenPolynomial<C>> G) {
828        if (G == null || G.size() == 0) {
829            throw new IllegalArgumentException("G may not be null or empty");
830        }
831        //logger.info("G in  = " + G);
832        //Collections.reverse(G); // test
833        G = OrderedPolynomialList.<C> sort(G); // better performance
834        List<Long> ud = univariateDegrees(G);
835        if (ud.size() <= i) {
836            //logger.info("univ pol, ud = " + ud);
837            throw new IllegalArgumentException("ideal(G) not zero dimensional " + ud);
838        }
839        int ll = 0;
840        Long di = ud.get(i);
841        if (di != null) {
842            ll = (int) (long) di;
843        } else {
844            throw new IllegalArgumentException("ideal(G) not zero dimensional");
845        }
846        long vsdim = 1;
847        for (Long d : ud) {
848            if (d != null) {
849                vsdim *= d;
850            }
851        }
852        logger.info("univariate construction, deg = " + ll + ", vsdim = " + vsdim);
853        GenPolynomialRing<C> pfac = G.get(0).ring;
854        RingFactory<C> cfac = pfac.coFac;
855        String var = pfac.getVars()[pfac.nvar - 1 - i];
856        GenPolynomialRing<C> ufac = new GenPolynomialRing<C>(cfac, 1, new TermOrder(TermOrder.INVLEX),
857                        new String[] { var });
858
859        GenPolynomialRing<C> cpfac = new GenPolynomialRing<C>(cfac, ll, new TermOrder(TermOrder.INVLEX));
860        GenPolynomialRing<GenPolynomial<C>> rfac = new GenPolynomialRing<GenPolynomial<C>>(cpfac, pfac);
861        GenPolynomial<GenPolynomial<C>> P = rfac.getZERO();
862        for (int k = 0; k < ll; k++) {
863            GenPolynomial<GenPolynomial<C>> Pp = rfac.univariate(i, k);
864            GenPolynomial<C> cp = cpfac.univariate(cpfac.nvar - 1 - k);
865            Pp = Pp.multiply(cp);
866            P = P.sum(Pp);
867        }
868        if (debug) {
869            logger.info("univariate construction, P = " + P);
870            logger.info("univariate construction, deg_*(G) = " + ud);
871            //throw new RuntimeException("check");
872        }
873        GenPolynomial<C> X;
874        GenPolynomial<C> XP;
875        // solve system of linear equations for the coefficients of the univariate polynomial
876        List<GenPolynomial<C>> ls;
877        int z = -1;
878        do {
879            //System.out.println("ll  = " + ll);
880            GenPolynomial<GenPolynomial<C>> Pp = rfac.univariate(i, ll);
881            GenPolynomial<C> cp = cpfac.univariate(cpfac.nvar - 1 - ll);
882            Pp = Pp.multiply(cp);
883            P = P.sum(Pp);
884            X = pfac.univariate(i, ll);
885            XP = red.normalform(G, X);
886            if (debug) {
887                logger.info("XP = " + XP);
888            }
889            GenPolynomial<GenPolynomial<C>> XPp = PolyUtil.<C> toRecursive(rfac, XP);
890            GenPolynomial<GenPolynomial<C>> XPs = XPp.sum(P);
891            ls = new ArrayList<GenPolynomial<C>>(XPs.getMap().values());
892            //System.out.println("ls,1 = " + ls);
893            ls = red.irreducibleSet(ls);
894            z = commonZeroTest(ls);
895            if (z != 0) {
896                ll++;
897                if (ll > vsdim) {
898                    logger.info("univariate construction, P = " + P);
899                    logger.info("univariate construction, nf(P) = " + XP);
900                    logger.info("G = " + G);
901                    throw new ArithmeticException(
902                                    "univariate polynomial degree greater than vector space dimansion");
903                }
904                cpfac = cpfac.extend(1);
905                rfac = new GenPolynomialRing<GenPolynomial<C>>(cpfac, pfac);
906                P = PolyUtil.<C> extendCoefficients(rfac, P, 0, 0L);
907                XPp = PolyUtil.<C> extendCoefficients(rfac, XPp, 0, 1L);
908                P = P.sum(XPp);
909            }
910        } while (z != 0); // && ll <= 5 && !XP.isZERO()
911        // construct result polynomial
912        GenPolynomial<C> pol = ufac.univariate(0, ll);
913        for (GenPolynomial<C> pc : ls) {
914            ExpVector e = pc.leadingExpVector();
915            if (e == null) {
916                continue;
917            }
918            int[] v = e.dependencyOnVariables();
919            if (v == null || v.length == 0) {
920                continue;
921            }
922            int vi = v[0];
923            C lc = pc.leadingBaseCoefficient();
924            C tc = pc.trailingBaseCoefficient();
925            tc = tc.negate();
926            if (!lc.isONE()) {
927                tc = tc.divide(lc);
928            }
929            GenPolynomial<C> pi = ufac.univariate(0, ll - 1 - vi);
930            pi = pi.multiply(tc);
931            pol = pol.sum(pi);
932        }
933        if (logger.isInfoEnabled()) {
934            logger.info("univariate construction, pol = " + pol);
935        }
936        return pol;
937    }
938
939
940    /**
941     * Cleanup and terminate ThreadPool.
942     */
943    public void terminate() {
944        logger.info("terminate not implemented");
945        //throw new RuntimeException("get a stack trace");
946    }
947
948
949    /**
950     * Cancel ThreadPool.
951     */
952    public int cancel() {
953        logger.info("cancel not implemented");
954        return 0;
955    }
956
957}