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