001/*
002 * $Id$
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Map;
011
012import org.apache.logging.log4j.LogManager;
013import org.apache.logging.log4j.Logger;
014
015import edu.jas.gb.GroebnerBaseAbstract;
016import edu.jas.gb.SolvableGroebnerBaseAbstract;
017import edu.jas.gb.SolvableReductionAbstract;
018import edu.jas.gb.SolvableReductionSeq;
019import edu.jas.gb.WordGroebnerBaseAbstract;
020import edu.jas.gb.WordGroebnerBaseSeq;
021import edu.jas.poly.ExpVector;
022import edu.jas.poly.GenPolynomial;
023import edu.jas.poly.GenPolynomialRing;
024import edu.jas.poly.GenSolvablePolynomial;
025import edu.jas.poly.GenSolvablePolynomialRing;
026import edu.jas.poly.GenWordPolynomial;
027import edu.jas.poly.GenWordPolynomialRing;
028import edu.jas.poly.PolyUtil;
029import edu.jas.structure.GcdRingElem;
030import edu.jas.structure.RingElem;
031
032
033/**
034 * Package gbufd utilities.
035 * @author Heinz Kredel
036 */
037
038public class PolyGBUtil {
039
040
041    private static final Logger logger = LogManager.getLogger(PolyGBUtil.class);
042
043
044    private static final boolean debug = logger.isDebugEnabled();
045
046
047    /**
048     * Test for resultant.
049     * @param A generic polynomial.
050     * @param B generic polynomial.
051     * @param r generic polynomial.
052     * @return true if res(A,B) isContained in ideal(A,B), else false.
053     */
054    public static <C extends GcdRingElem<C>> boolean isResultant(GenPolynomial<C> A, GenPolynomial<C> B,
055                    GenPolynomial<C> r) {
056        if (r == null || r.isZERO()) {
057            return true;
058        }
059        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(r.ring.coFac);
060        List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(2);
061        F.add(A);
062        F.add(B);
063        List<GenPolynomial<C>> G = bb.GB(F);
064        //System.out.println("G = " + G);
065        GenPolynomial<C> n = bb.red.normalform(G, r);
066        //System.out.println("n = " + n);
067        return n.isZERO();
068    }
069
070
071    /**
072     * Top pseudo reduction wrt the main variables.
073     * @param P generic polynomial.
074     * @param A list of generic polynomials sorted according to appearing main
075     *            variables.
076     * @return top pseudo remainder of P wrt. A for the appearing variables.
077     */
078    public static <C extends RingElem<C>> GenPolynomial<C> topPseudoRemainder(List<GenPolynomial<C>> A,
079                    GenPolynomial<C> P) {
080        if (A == null || A.isEmpty()) {
081            return P.monic();
082        }
083        if (P.isZERO()) {
084            return P;
085        }
086        //System.out.println("remainder, P = " + P);
087        GenPolynomialRing<C> pfac = A.get(0).ring;
088        if (pfac.nvar <= 1) { // recursion base 
089            GenPolynomial<C> R = PolyUtil.<C> baseSparsePseudoRemainder(P, A.get(0));
090            return R.monic();
091        }
092        // select polynomials according to the main variable
093        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
094        GenPolynomial<C> Q = A.get(0); // wrong, must eventually search polynomial
095        GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac, Q);
096        GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
097        GenPolynomial<GenPolynomial<C>> rr;
098        if (qr.isONE()) {
099            return P.ring.getZERO();
100        }
101        if (qr.degree(0) > 0) {
102            rr = PolyUtil.<C> recursiveSparsePseudoRemainder(pr, qr);
103            //System.out.println("remainder, pr = " + pr);
104            //System.out.println("remainder, qr = " + qr);
105            //System.out.println("remainder, rr = " + rr);
106        } else {
107            rr = pr;
108        }
109        if (rr.degree(0) > 0) {
110            GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr);
111            return R.monic();
112            // not further reduced wrt. other variables = top-reduction only
113        }
114        List<GenPolynomial<C>> zeroDeg = zeroDegrees(A);
115        GenPolynomial<C> R = topPseudoRemainder(zeroDeg, rr.leadingBaseCoefficient());
116        R = R.extend(pfac, 0, 0L);
117        return R.monic();
118    }
119
120
121    /**
122     * Top coefficient pseudo remainder of the leading coefficient of P wrt A in
123     * the main variables.
124     * @param P generic polynomial in n+1 variables.
125     * @param A list of generic polynomials in n variables sorted according to
126     *            appearing main variables.
127     * @return pseudo remainder of the leading coefficient of P wrt A.
128     */
129    public static <C extends RingElem<C>> GenPolynomial<C> topCoefficientPseudoRemainder(
130                    List<GenPolynomial<C>> A, GenPolynomial<C> P) {
131        if (A == null || A.isEmpty()) {
132            return P.monic();
133        }
134        if (P.isZERO()) {
135            return P;
136        }
137        GenPolynomialRing<C> pfac = P.ring;
138        GenPolynomialRing<C> pfac1 = A.get(0).ring;
139        if (pfac1.nvar <= 1) { // recursion base 
140            GenPolynomial<C> a = A.get(0);
141            GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(pfac.nvar - 1);
142            GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
143            // ldcf(P,x_m) = q a + r 
144            GenPolynomial<GenPolynomial<C>> rr = PolyGBUtil.<C> coefficientPseudoRemainderBase(pr, a);
145            GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr);
146            return R.monic();
147        }
148        // select polynomials according to the main variable
149        GenPolynomialRing<GenPolynomial<C>> rfac1 = pfac1.recursive(1);
150        int nv = pfac.nvar - pfac1.nvar;
151        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1 + nv);
152        GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> rfac2 = rfac.recursive(nv);
153        if (debug) {
154            logger.info("rfac = {}", rfac);
155        }
156        GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
157        GenPolynomial<GenPolynomial<GenPolynomial<C>>> pr2 = PolyUtil.<GenPolynomial<C>> recursive(rfac2, pr);
158        //System.out.println("recursion, pr2 = " + pr2);
159        GenPolynomial<C> Q = A.get(0);
160        GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac1, Q);
161        GenPolynomial<GenPolynomial<GenPolynomial<C>>> rr;
162        if (qr.isONE()) {
163            return P.ring.getZERO();
164        }
165        if (qr.degree(0) > 0) {
166            // pseudo remainder:  ldcf(P,x_m) = a q + r 
167            rr = PolyGBUtil.<C> coefficientPseudoRemainder(pr2, qr);
168            //System.out.println("recursion, qr  = " + qr);
169            //System.out.println("recursion, pr  = " + pr2);
170            //System.out.println("recursion, rr  = " + rr);
171        } else {
172            rr = pr2;
173        }
174        // reduction wrt. the other variables
175        List<GenPolynomial<C>> zeroDeg = zeroDegrees(A);
176        GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<GenPolynomial<C>> distribute(rfac, rr);
177        GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, Rr);
178        R = topCoefficientPseudoRemainder(zeroDeg, R);
179        return R.monic();
180    }
181
182
183    /**
184     * Polynomial leading coefficient pseudo remainder.
185     * @param P generic polynomial in n+1 variables.
186     * @param A generic polynomial in n variables.
187     * @return pseudo remainder of the leading coefficient of P wrt A, with
188     *         ldcf(A)<sup>m'</sup> P = quotient * A + remainder.
189     */
190    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<GenPolynomial<C>>> coefficientPseudoRemainder(
191                    GenPolynomial<GenPolynomial<GenPolynomial<C>>> P, GenPolynomial<GenPolynomial<C>> A) {
192        if (A == null || A.isZERO()) { // findbugs
193            throw new ArithmeticException(P + " division by zero " + A);
194        }
195        if (A.isONE()) {
196            return P.ring.getZERO();
197        }
198        if (P.isZERO() || P.isONE()) {
199            return P;
200        }
201        GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> pfac = P.ring;
202        GenPolynomialRing<GenPolynomial<C>> afac = A.ring; // == pfac.coFac
203        GenPolynomial<GenPolynomial<GenPolynomial<C>>> r = P;
204        GenPolynomial<GenPolynomial<C>> h;
205        GenPolynomial<GenPolynomial<GenPolynomial<C>>> hr;
206        GenPolynomial<GenPolynomial<C>> ldcf = P.leadingBaseCoefficient();
207        long m = ldcf.degree(0);
208        long n = A.degree(0);
209        GenPolynomial<C> c = A.leadingBaseCoefficient();
210        GenPolynomial<GenPolynomial<C>> cc = afac.getZERO().sum(c);
211        //System.out.println("cc = " + cc);
212        ExpVector e = A.leadingExpVector();
213        for (long i = m; i >= n; i--) {
214            if (r.isZERO()) {
215                return r;
216            }
217            GenPolynomial<GenPolynomial<C>> p = r.leadingBaseCoefficient();
218            ExpVector g = r.leadingExpVector();
219            long k = p.degree(0);
220            if (i == k) {
221                GenPolynomial<C> pl = p.leadingBaseCoefficient();
222                ExpVector f = p.leadingExpVector();
223                f = f.subtract(e);
224                r = r.multiply(cc); // coeff cc
225                h = A.multiply(pl, f); // coeff ac
226                hr = new GenPolynomial<GenPolynomial<GenPolynomial<C>>>(pfac, h, g);
227                r = r.subtract(hr);
228            } else {
229                r = r.multiply(cc);
230            }
231            //System.out.println("r = " + r);
232        }
233        if (r.degree(0) < P.degree(0)) { // recursion for degree
234            r = coefficientPseudoRemainder(r, A);
235        }
236        return r;
237    }
238
239
240    /**
241     * Polynomial leading coefficient pseudo remainder, base case.
242     * @param P generic polynomial in 1+1 variables.
243     * @param A generic polynomial in 1 variable.
244     * @return pseudo remainder of the leading coefficient of P wrt. A, with
245     *         ldcf(A)<sup>m'</sup> P = quotient * A + remainder.
246     */
247    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> coefficientPseudoRemainderBase(
248                    GenPolynomial<GenPolynomial<C>> P, GenPolynomial<C> A) {
249        if (A == null || A.isZERO()) { // findbugs
250            throw new ArithmeticException(P + " division by zero " + A);
251        }
252        if (A.isONE()) {
253            return P.ring.getZERO();
254        }
255        if (P.isZERO() || P.isONE()) {
256            return P;
257        }
258        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
259        GenPolynomialRing<C> afac = A.ring; // == pfac.coFac
260        GenPolynomial<GenPolynomial<C>> r = P;
261        GenPolynomial<C> h;
262        GenPolynomial<GenPolynomial<C>> hr;
263        GenPolynomial<C> ldcf = P.leadingBaseCoefficient();
264        long m = ldcf.degree(0);
265        long n = A.degree(0);
266        C c = A.leadingBaseCoefficient();
267        GenPolynomial<C> cc = afac.getZERO().sum(c);
268        //System.out.println("cc = " + cc);
269        ExpVector e = A.leadingExpVector();
270        for (long i = m; i >= n; i--) {
271            if (r.isZERO()) {
272                return r;
273            }
274            GenPolynomial<C> p = r.leadingBaseCoefficient();
275            ExpVector g = r.leadingExpVector();
276            long k = p.degree(0);
277            if (i == k) {
278                C pl = p.leadingBaseCoefficient();
279                ExpVector f = p.leadingExpVector();
280                f = f.subtract(e);
281                r = r.multiply(cc); // coeff cc
282                h = A.multiply(pl, f); // coeff ac
283                hr = new GenPolynomial<GenPolynomial<C>>(pfac, h, g);
284                r = r.subtract(hr);
285            } else {
286                r = r.multiply(cc);
287            }
288            //System.out.println("r = " + r);
289        }
290        if (r.degree(0) < P.degree(0)) { // recursion for degree
291            r = coefficientPseudoRemainderBase(r, A);
292        }
293        return r;
294    }
295
296
297    /**
298     * Extract polynomials with degree zero in the main variable.
299     * @param A list of generic polynomials in n variables.
300     * @return Z = [a_i] with deg(a_i,x_n) = 0 and in n-1 variables.
301     */
302    public static <C extends RingElem<C>> List<GenPolynomial<C>> zeroDegrees(List<GenPolynomial<C>> A) {
303        if (A == null || A.isEmpty()) {
304            return A;
305        }
306        GenPolynomialRing<C> pfac = A.get(0).ring;
307        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
308        List<GenPolynomial<C>> zeroDeg = new ArrayList<GenPolynomial<C>>(A.size());
309        for (int i = 0; i < A.size(); i++) {
310            GenPolynomial<C> q = A.get(i);
311            GenPolynomial<GenPolynomial<C>> fr = PolyUtil.<C> recursive(rfac, q);
312            if (fr.degree(0) == 0) {
313                zeroDeg.add(fr.leadingBaseCoefficient());
314            }
315        }
316        return zeroDeg;
317    }
318
319
320    /**
321     * Intersection. Generators for the intersection of ideals.
322     * @param pfac polynomial ring
323     * @param A list of polynomials
324     * @param B list of polynomials
325     * @return generators for (A \cap B)
326     */
327    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> intersect(GenPolynomialRing<C> pfac,
328                    List<GenPolynomial<C>> A, List<GenPolynomial<C>> B) {
329        if (A == null || A.isEmpty()) { // (0)
330            return B;
331        }
332        if (B == null || B.isEmpty()) { // (0)
333            return A;
334        }
335        int s = A.size() + B.size();
336        List<GenPolynomial<C>> c = new ArrayList<GenPolynomial<C>>(s);
337        GenPolynomialRing<C> tfac = pfac.extend(1);
338        // term order is also adjusted
339        for (GenPolynomial<C> p : A) {
340            p = p.extend(tfac, 0, 1L); // t*p
341            c.add(p);
342        }
343        for (GenPolynomial<C> p : B) {
344            GenPolynomial<C> q = p.extend(tfac, 0, 1L);
345            GenPolynomial<C> r = p.extend(tfac, 0, 0L);
346            p = r.subtract(q); // (1-t)*p
347            c.add(p);
348        }
349        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(tfac.coFac);
350        logger.warn("intersect computing GB");
351        List<GenPolynomial<C>> G = bb.GB(c);
352        if (debug) {
353            logger.debug("intersect GB = {}", G);
354        }
355        List<GenPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G);
356        return I;
357    }
358
359
360    /**
361     * Intersection. Generators for the intersection of ideals.
362     * @param pfac solvable polynomial ring
363     * @param A list of polynomials
364     * @param B list of polynomials
365     * @return generators for (A \cap B)
366     */
367    public static <C extends GcdRingElem<C>> List<GenSolvablePolynomial<C>> intersect(
368                    GenSolvablePolynomialRing<C> pfac, List<GenSolvablePolynomial<C>> A,
369                    List<GenSolvablePolynomial<C>> B) {
370        if (A == null || A.isEmpty()) { // (0)
371            return B;
372        }
373        if (B == null || B.isEmpty()) { // (0)
374            return A;
375        }
376        int s = A.size() + B.size();
377        List<GenSolvablePolynomial<C>> c = new ArrayList<GenSolvablePolynomial<C>>(s);
378        GenSolvablePolynomialRing<C> tfac = pfac.extend(1);
379        // term order is also adjusted
380        for (GenSolvablePolynomial<C> p : A) {
381            p = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L); // t*p
382            c.add(p);
383        }
384        for (GenSolvablePolynomial<C> p : B) {
385            GenSolvablePolynomial<C> q = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L);
386            GenSolvablePolynomial<C> r = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 0L);
387            p = (GenSolvablePolynomial<C>) r.subtract(q); // (1-t)*p
388            c.add(p);
389        }
390        SolvableGroebnerBaseAbstract<C> sbb = SGBFactory.<C> getImplementation(tfac.coFac);
391        //new SolvableGroebnerBaseSeq<C>();
392        logger.warn("intersect computing GB");
393        List<GenSolvablePolynomial<C>> g = sbb.leftGB(c);
394        //List<GenSolvablePolynomial<C>> g = sbb.twosidedGB(c);
395        if (debug) {
396            logger.debug("intersect GB = {}", g);
397        }
398        List<GenSolvablePolynomial<C>> I = PolyUtil.<C> intersect(pfac, g);
399        return I;
400    }
401
402
403    /**
404     * Intersection. Generators for the intersection of word ideals.
405     * @param pfac word polynomial ring
406     * @param A list of word polynomials
407     * @param B list of word polynomials
408     * @return generators for (A \cap B) if it exists
409     */
410    public static <C extends GcdRingElem<C>> List<GenWordPolynomial<C>> intersect(
411                    GenWordPolynomialRing<C> pfac, List<GenWordPolynomial<C>> A,
412                    List<GenWordPolynomial<C>> B) {
413        if (A == null || A.isEmpty()) { // (0)
414            return B;
415        }
416        if (B == null || B.isEmpty()) { // (0)
417            return A;
418        }
419        int s = A.size() + B.size();
420        List<GenWordPolynomial<C>> L = new ArrayList<GenWordPolynomial<C>>(s);
421        GenWordPolynomialRing<C> tfac = pfac.extend(1);
422        List<GenWordPolynomial<C>> gens = tfac.univariateList();
423        //System.out.println("gens = " + gens);
424        GenWordPolynomial<C> t = gens.get(gens.size() - 1);
425        //System.out.println("t = " + t);
426        // make t commute with other variables
427        for (GenWordPolynomial<C> p : gens) {
428            if (t == p) {
429                continue;
430            }
431            GenWordPolynomial<C> c = t.multiply(p).subtract(p.multiply(t)); // t p - p t
432            L.add(c);
433        }
434        for (GenWordPolynomial<C> p : A) {
435            p = tfac.valueOf(p).multiply(t); // t p
436            L.add(p);
437        }
438        for (GenWordPolynomial<C> p : B) {
439            GenWordPolynomial<C> q = tfac.valueOf(p).multiply(t);
440            GenWordPolynomial<C> r = tfac.valueOf(p);
441            p = r.subtract(q); // (1-t) p
442            L.add(p);
443        }
444        //System.out.println("L = " + L);
445        WordGroebnerBaseAbstract<C> bb = new WordGroebnerBaseSeq<C>();
446        logger.warn("intersect computing GB");
447        List<GenWordPolynomial<C>> G = bb.GB(L);
448        //System.out.println("G = " + G);
449        if (debug) {
450            logger.debug("intersect GB = {}", G);
451        }
452        List<GenWordPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G);
453        return I;
454    }
455
456
457    /**
458     * Solvable quotient and remainder via reduction.
459     * @param n first solvable polynomial.
460     * @param d second solvable polynomial.
461     * @return [ n/d, n - (n/d)*d ]
462     */
463    @SuppressWarnings({"cast","unchecked"})
464    public static <C extends GcdRingElem<C>> GenSolvablePolynomial<C>[] quotientRemainder(
465                    GenSolvablePolynomial<C> n, GenSolvablePolynomial<C> d) {
466        GenSolvablePolynomial<C>[] res = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
467        if (d.isZERO()) {
468            throw new RuntimeException("division by zero: " + n + "/" + d);
469        }
470        if (n.isZERO()) {
471            res[0] = n;
472            res[1] = n;
473            return res;
474        }
475        GenSolvablePolynomialRing<C> r = n.ring;
476        if (d.isONE()) {
477            res[0] = n;
478            res[1] = r.getZERO();
479            return res;
480        }
481        // divide
482        List<GenSolvablePolynomial<C>> Q = new ArrayList<GenSolvablePolynomial<C>>(1);
483        Q.add(r.getZERO());
484        List<GenSolvablePolynomial<C>> D = new ArrayList<GenSolvablePolynomial<C>>(1);
485        D.add(d);
486        SolvableReductionAbstract<C> sred = new SolvableReductionSeq<C>();
487        res[1] = sred.rightNormalform(Q, D, n); // left
488        res[0] = Q.get(0);
489        return res;
490    }
491
492
493    /**
494     * Subring generators.
495     * @param A list of polynomials in n variables.
496     * @return a Groebner base of polynomials in m &gt; n variables generating
497     *         the subring of K[A].
498     */
499    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> subRing(List<GenPolynomial<C>> A) {
500        if (A == null || A.isEmpty()) {
501            return A;
502        }
503        GenPolynomialRing<C> pfac = A.get(0).ring;
504        logger.debug("pfac = {}", pfac); //.toScript()
505        int n = pfac.nvar;
506        List<GenPolynomial<C>> Ap = new ArrayList<GenPolynomial<C>>();
507        for (GenPolynomial<C> a : A) {
508            if (a == null || a.isZERO() || a.isONE()) {
509                continue;
510            }
511            Ap.add(a);
512        }
513        int k = Ap.size();
514        if (k == 0) {
515            return Ap;
516        }
517        GenPolynomialRing<C> rfac = pfac.extendLower(k);
518        logger.debug("rfac = {}", rfac); //.toScript()
519        assert rfac.nvar == n + k : "rfac.nvar == n+k";
520        List<GenPolynomial<C>> sr = new ArrayList<GenPolynomial<C>>();
521        int i = 0;
522        for (GenPolynomial<C> a : Ap) {
523            GenPolynomial<C> b = a.extendLower(rfac, 0, 0L);
524            b = b.subtract(pfac.getONE().extendLower(rfac, i++, 1L));
525            //System.out.println("a = " + a);
526            //System.out.println("b = " + b);
527            sr.add(b);
528        }
529        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(pfac.coFac);
530        List<GenPolynomial<C>> srg = bb.GB(sr);
531        return srg;
532    }
533
534
535    /**
536     * Subring membership.
537     * @param A Groebner base of polynomials in m &gt; n variables generating
538     *            the subring of elements of K[A].
539     * @param g polynomial in n variables.
540     * @return true, if g \in K[A], else false.
541     */
542    public static <C extends GcdRingElem<C>> boolean subRingMember(List<GenPolynomial<C>> A,
543                    GenPolynomial<C> g) {
544        if (A == null || A.isEmpty()) {
545            return true;
546        }
547        GenPolynomialRing<C> pfac = A.get(0).ring;
548        GenPolynomial<C> m = g;
549        if (pfac.nvar != g.ring.nvar) {
550            m = m.extendLower(pfac, 0, 0L);
551        } else {
552            throw new IllegalArgumentException("g must be extended: " + pfac.nvar + " == " + g.ring.nvar
553                            + " did you mean method subRingAndMember()?");
554        }
555        //ReductionAbstract<C> red = new ReductionSeq<C>();
556        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(pfac.coFac);
557        GenPolynomial<C> r = bb.red.normalform(A, m);
558        //System.out.println("r = " + r);
559        GenPolynomialRing<C> cfac = pfac.contract(g.ring.nvar);
560        logger.debug("cfac = {}", cfac); //.toScript()
561        Map<ExpVector, GenPolynomial<C>> map = r.contract(cfac);
562        //System.out.println("map = " + map);
563        boolean t = map.size() == 1 && map.keySet().contains(g.ring.evzero);
564        if (!t) {
565            System.out.println("false: map = " + map);
566        }
567        return t;
568    }
569
570
571    /**
572     * Subring and membership test.
573     * @param A list of polynomials in n variables.
574     * @param g polynomial in n variables.
575     * @return true, if g \in K[A], else false.
576     */
577    public static <C extends GcdRingElem<C>> boolean subRingAndMember(List<GenPolynomial<C>> A,
578                    GenPolynomial<C> g) {
579        if (A == null || A.isEmpty()) {
580            return true;
581        }
582        List<GenPolynomial<C>> srg = PolyGBUtil.<C> subRing(A);
583        return PolyGBUtil.<C> subRingMember(srg, g);
584    }
585
586
587    /**
588     * Chinese remainder theorem.
589     * @param F = ( F_i ) list of list of polynomials in n variables.
590     * @param A = ( f_i ) list of polynomials in n variables.
591     * @return p \in \Cap_i (f_i + ideal(F_i)) if it exists, else null.
592     */
593    public static <C extends GcdRingElem<C>> GenPolynomial<C> chineseRemainderTheorem(
594                    List<List<GenPolynomial<C>>> F, List<GenPolynomial<C>> A) {
595        if (F == null || F.isEmpty() || A == null || A.isEmpty()) {
596            throw new IllegalArgumentException("F and A may not be empty or null");
597        }
598        int m = F.size();
599        if (m != A.size()) {
600            throw new IllegalArgumentException("size(F) and size(A) must be equal");
601        }
602        GenPolynomialRing<C> pfac = A.get(0).ring;
603        logger.debug("pfac = {}", pfac); //.toScript()
604        GenPolynomialRing<C> rfac = pfac.extend(m);
605        logger.debug("rfac = {}", rfac); //.toScript()
606        GenPolynomial<C> y = rfac.getONE();
607        GenPolynomial<C> f = rfac.getZERO();
608        int i = 0;
609        List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(); //m**2?
610        //System.out.println("A = " + A);
611        for (List<GenPolynomial<C>> Fi : F) {
612            GenPolynomial<C> Yi = pfac.getONE().extend(rfac, i, 1L);
613            y = y.subtract(Yi);
614            List<GenPolynomial<C>> Fip = new ArrayList<GenPolynomial<C>>(Fi.size());
615            //System.out.println("Fi = " + Fi);
616            for (GenPolynomial<C> a : Fi) {
617                GenPolynomial<C> b = a.extend(rfac, i, 1L);
618                Fip.add(b);
619            }
620            //System.out.println("Fip = " + Fip);
621            Fp.addAll(Fip);
622            GenPolynomial<C> a = A.get(i);
623            //System.out.println("a = " + a);
624            f = f.sum(a.extend(rfac, i, 1L));
625            i++;
626        }
627        Fp.add(y);
628        //System.out.println("f = " + f);
629        //System.out.println("Fp = " + Fp);
630        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(pfac.coFac);
631        List<GenPolynomial<C>> Fpp = bb.GB(Fp);
632        //System.out.println("Fpp = " + Fpp);
633        GenPolynomial<C> h = bb.red.normalform(Fpp, f);
634        //System.out.println("h = " + h);
635        ////PseudoReduction<C> pr = new PseudoReductionSeq<C>();
636        ////PseudoReductionEntry<C> fz = pr.normalformFactor(Fpp, f);
637        ////System.out.println("fz = " + fz);
638        List<GenPolynomial<C>> H = new ArrayList<GenPolynomial<C>>();
639        H.add(h);
640        H = PolyUtil.<C> intersect(pfac, H);
641        //System.out.println("H != (): " + (! H.isEmpty()));
642        if (H.isEmpty()) {
643            return null;
644        }
645        return H.get(0);
646    }
647
648
649    /**
650     * Is Chinese remainder.
651     * @param F = ( F_i ) list of list of polynomials in n variables.
652     * @param A = ( f_i ) list of polynomials in n variables.
653     * @param h polynomial in n variables.
654     * @return true if h \in \Cap_i (f_i + ideal(F_i)), else false.
655     */
656    public static <C extends GcdRingElem<C>> boolean isChineseRemainder(List<List<GenPolynomial<C>>> F,
657                    List<GenPolynomial<C>> A, GenPolynomial<C> h) {
658        if (h == null) {
659            return false;
660        }
661        if (F == null || F.isEmpty() || A == null || A.isEmpty()) {
662            return false;
663        }
664        if (F.size() != A.size()) {
665            return false;
666        }
667        GenPolynomialRing<C> pfac = h.ring;
668        if (!pfac.coFac.isField()) {
669            //System.out.println("pfac = " + pfac.toScript());
670            logger.error("only for field coefficients: {}", pfac); //.toScript()
671            //throw new IllegalArgumentException("only for field coefficients: " + pfac.toScript());
672        }
673        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(pfac.coFac);
674        int i = 0;
675        for (List<GenPolynomial<C>> Fi : F) {
676            List<GenPolynomial<C>> Fp = bb.GB(Fi);
677            //System.out.println("Fp = " + Fp);
678            GenPolynomial<C> a = A.get(i);
679            GenPolynomial<C> fi = bb.red.normalform(Fp, h.subtract(a));
680            if (!fi.isZERO()) {
681                //System.out.println("Fp = " + Fp + ", Fi = " + Fi);
682                //System.out.println("h  = " + h  + ", a  = " + a  + ", fi  = " + fi);
683                logger.info("h-a = {}, fi  = {}", h.subtract(a), fi);
684                return false;
685            }
686            i++;
687        }
688        return true;
689    }
690
691
692    /**
693     * Chinese remainder theorem, interpolation.
694     * @param fac polynomial ring over K in n variables.
695     * @param E = ( E_i ), E_i = ( e_ij ) list of list of elements of K, the evaluation points.
696     * @param V = ( f_i ) list of elements of K, the evaluation values.
697     * @return p \in K[X1,...,Xn], with p(E_i) = f_i, if it exists, else null.
698     */
699    @SuppressWarnings({"cast","unchecked"})
700    public static <C extends GcdRingElem<C>> GenPolynomial<C> CRTInterpolation(
701                  GenPolynomialRing<C> fac, List<List<C>> E, List<C> V) {
702        if (E == null || E.isEmpty() || V == null || V.isEmpty()) {
703            throw new IllegalArgumentException("E and V may not be empty or null");
704        }
705        int m = E.size();
706        if (m != V.size()) {
707            throw new IllegalArgumentException("size(E) and size(V) must be equal");
708        }
709        //System.out.println("fac = " + fac.toScript());
710        List<List<GenPolynomial<C>>> F = new ArrayList<List<GenPolynomial<C>>>(E.size());
711        List<GenPolynomial<C>> A = new ArrayList<GenPolynomial<C>>(V.size());
712        List<GenPolynomial<C>> gen = (List<GenPolynomial<C>>) fac.univariateList();
713        //System.out.println("gen = " + gen);
714        int i = 0;
715        for (List<C> Ei : E) {
716            List<GenPolynomial<C>> Fi = new ArrayList<GenPolynomial<C>>();
717            int j = 0;
718            for (C eij : Ei) {
719                GenPolynomial<C> ep = gen.get(j);
720                ep = ep.subtract( fac.valueOf(eij) );
721                Fi.add(ep);
722                j++;
723            }
724            F.add(Fi);
725            String ai = " " + V.get(i); // (sic) .toString() not possible
726            //System.out.println("ai = " + ai);
727            GenPolynomial<C> ap = fac.valueOf(ai);
728            A.add(ap);
729            i++;
730        }
731        //System.out.println("F = " + F);
732        //System.out.println("A = " + A);
733        GenPolynomial<C> p = PolyGBUtil. <C>chineseRemainderTheorem(F,A);
734        //System.out.println("p = " + p);
735        //System.out.println("t = " + PolyGBUtil. <C>isChineseRemainder(F,A,p));
736        return p;
737    }
738
739}