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