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