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.ReductionAbstract;
017import edu.jas.gb.ReductionSeq;
018import edu.jas.gb.SolvableGroebnerBaseAbstract;
019import edu.jas.gb.SolvableReductionAbstract;
020import edu.jas.gb.SolvableReductionSeq;
021import edu.jas.gb.WordGroebnerBaseAbstract;
022import edu.jas.gb.WordGroebnerBaseSeq;
023import edu.jas.poly.ExpVector;
024import edu.jas.poly.GenPolynomial;
025import edu.jas.poly.GenPolynomialRing;
026import edu.jas.poly.GenSolvablePolynomial;
027import edu.jas.poly.GenSolvablePolynomialRing;
028import edu.jas.poly.GenWordPolynomial;
029import edu.jas.poly.GenWordPolynomialRing;
030import edu.jas.poly.PolyUtil;
031import edu.jas.structure.GcdRingElem;
032import edu.jas.structure.RingElem;
033
034
035/**
036 * Package gbufd utilities.
037 * @author Heinz Kredel
038 */
039
040public class PolyGBUtil {
041
042
043    private static final Logger logger = LogManager.getLogger(PolyGBUtil.class);
044
045
046    private static final boolean debug = logger.isDebugEnabled();
047
048
049    /**
050     * Test for resultant.
051     * @param A generic polynomial.
052     * @param B generic polynomial.
053     * @param r generic polynomial.
054     * @return true if res(A,B) isContained in ideal(A,B), else false.
055     */
056    public static <C extends GcdRingElem<C>> boolean isResultant(GenPolynomial<C> A, GenPolynomial<C> B,
057                    GenPolynomial<C> r) {
058        if (r == null || r.isZERO()) {
059            return true;
060        }
061        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(r.ring.coFac);
062        List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(2);
063        F.add(A);
064        F.add(B);
065        List<GenPolynomial<C>> G = bb.GB(F);
066        //System.out.println("G = " + G);
067        GenPolynomial<C> n = bb.red.normalform(G, r);
068        //System.out.println("n = " + n);
069        return n.isZERO();
070    }
071
072
073    /**
074     * Top pseudo reduction wrt the main variables.
075     * @param P generic polynomial.
076     * @param A list of generic polynomials sorted according to appearing main
077     *            variables.
078     * @return top pseudo remainder of P wrt. A for the appearing variables.
079     */
080    public static <C extends RingElem<C>> GenPolynomial<C> topPseudoRemainder(List<GenPolynomial<C>> A,
081                    GenPolynomial<C> P) {
082        if (A == null || A.isEmpty()) {
083            return P.monic();
084        }
085        if (P.isZERO()) {
086            return P;
087        }
088        //System.out.println("remainder, P = " + P);
089        GenPolynomialRing<C> pfac = A.get(0).ring;
090        if (pfac.nvar <= 1) { // recursion base 
091            GenPolynomial<C> R = PolyUtil.<C> baseSparsePseudoRemainder(P, A.get(0));
092            return R.monic();
093        }
094        // select polynomials according to the main variable
095        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
096        GenPolynomial<C> Q = A.get(0); // wrong, must eventually search polynomial
097        GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac, Q);
098        GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
099        GenPolynomial<GenPolynomial<C>> rr;
100        if (qr.isONE()) {
101            return P.ring.getZERO();
102        }
103        if (qr.degree(0) > 0) {
104            rr = PolyUtil.<C> recursiveSparsePseudoRemainder(pr, qr);
105            //System.out.println("remainder, pr = " + pr);
106            //System.out.println("remainder, qr = " + qr);
107            //System.out.println("remainder, rr = " + rr);
108        } else {
109            rr = pr;
110        }
111        if (rr.degree(0) > 0) {
112            GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr);
113            return R.monic();
114            // not further reduced wrt. other variables = top-reduction only
115        }
116        List<GenPolynomial<C>> zeroDeg = zeroDegrees(A);
117        GenPolynomial<C> R = topPseudoRemainder(zeroDeg, rr.leadingBaseCoefficient());
118        R = R.extend(pfac, 0, 0L);
119        return R.monic();
120    }
121
122
123    /**
124     * Top coefficient pseudo remainder of the leading coefficient of P wrt A in
125     * the main variables.
126     * @param P generic polynomial in n+1 variables.
127     * @param A list of generic polynomials in n variables sorted according to
128     *            appearing main variables.
129     * @return pseudo remainder of the leading coefficient of P wrt A.
130     */
131    public static <C extends RingElem<C>> GenPolynomial<C> topCoefficientPseudoRemainder(
132                    List<GenPolynomial<C>> A, GenPolynomial<C> P) {
133        if (A == null || A.isEmpty()) {
134            return P.monic();
135        }
136        if (P.isZERO()) {
137            return P;
138        }
139        GenPolynomialRing<C> pfac = P.ring;
140        GenPolynomialRing<C> pfac1 = A.get(0).ring;
141        if (pfac1.nvar <= 1) { // recursion base 
142            GenPolynomial<C> a = A.get(0);
143            GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(pfac.nvar - 1);
144            GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
145            // ldcf(P,x_m) = q a + r 
146            GenPolynomial<GenPolynomial<C>> rr = PolyGBUtil.<C> coefficientPseudoRemainderBase(pr, a);
147            GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr);
148            return R.monic();
149        }
150        // select polynomials according to the main variable
151        GenPolynomialRing<GenPolynomial<C>> rfac1 = pfac1.recursive(1);
152        int nv = pfac.nvar - pfac1.nvar;
153        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1 + nv);
154        GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> rfac2 = rfac.recursive(nv);
155        if (debug) {
156            logger.info("rfac =" + rfac);
157        }
158        GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
159        GenPolynomial<GenPolynomial<GenPolynomial<C>>> pr2 = PolyUtil.<GenPolynomial<C>> recursive(rfac2, pr);
160        //System.out.println("recursion, pr2 = " + pr2);
161        GenPolynomial<C> Q = A.get(0);
162        GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac1, Q);
163        GenPolynomial<GenPolynomial<GenPolynomial<C>>> rr;
164        if (qr.isONE()) {
165            return P.ring.getZERO();
166        }
167        if (qr.degree(0) > 0) {
168            // pseudo remainder:  ldcf(P,x_m) = a q + r 
169            rr = PolyGBUtil.<C> coefficientPseudoRemainder(pr2, qr);
170            //System.out.println("recursion, qr  = " + qr);
171            //System.out.println("recursion, pr  = " + pr2);
172            //System.out.println("recursion, rr  = " + rr);
173        } else {
174            rr = pr2;
175        }
176        // reduction wrt. the other variables
177        List<GenPolynomial<C>> zeroDeg = zeroDegrees(A);
178        GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<GenPolynomial<C>> distribute(rfac, rr);
179        GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, Rr);
180        R = topCoefficientPseudoRemainder(zeroDeg, R);
181        return R.monic();
182    }
183
184
185    /**
186     * Polynomial leading coefficient pseudo remainder.
187     * @param P generic polynomial in n+1 variables.
188     * @param A generic polynomial in n variables.
189     * @return pseudo remainder of the leading coefficient of P wrt A, with
190     *         ldcf(A)<sup>m'</sup> P = quotient * A + remainder.
191     */
192    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<GenPolynomial<C>>> coefficientPseudoRemainder(
193                    GenPolynomial<GenPolynomial<GenPolynomial<C>>> P, GenPolynomial<GenPolynomial<C>> A) {
194        if (A == null || A.isZERO()) { // findbugs
195            throw new ArithmeticException(P + " division by zero " + A);
196        }
197        if (A.isONE()) {
198            return P.ring.getZERO();
199        }
200        if (P.isZERO() || P.isONE()) {
201            return P;
202        }
203        GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> pfac = P.ring;
204        GenPolynomialRing<GenPolynomial<C>> afac = A.ring; // == pfac.coFac
205        GenPolynomial<GenPolynomial<GenPolynomial<C>>> r = P;
206        GenPolynomial<GenPolynomial<C>> h;
207        GenPolynomial<GenPolynomial<GenPolynomial<C>>> hr;
208        GenPolynomial<GenPolynomial<C>> ldcf = P.leadingBaseCoefficient();
209        long m = ldcf.degree(0);
210        long n = A.degree(0);
211        GenPolynomial<C> c = A.leadingBaseCoefficient();
212        GenPolynomial<GenPolynomial<C>> cc = afac.getZERO().sum(c);
213        //System.out.println("cc = " + cc);
214        ExpVector e = A.leadingExpVector();
215        for (long i = m; i >= n; i--) {
216            if (r.isZERO()) {
217                return r;
218            }
219            GenPolynomial<GenPolynomial<C>> p = r.leadingBaseCoefficient();
220            ExpVector g = r.leadingExpVector();
221            long k = p.degree(0);
222            if (i == k) {
223                GenPolynomial<C> pl = p.leadingBaseCoefficient();
224                ExpVector f = p.leadingExpVector();
225                f = f.subtract(e);
226                r = r.multiply(cc); // coeff cc
227                h = A.multiply(pl, f); // coeff ac
228                hr = new GenPolynomial<GenPolynomial<GenPolynomial<C>>>(pfac, h, g);
229                r = r.subtract(hr);
230            } else {
231                r = r.multiply(cc);
232            }
233            //System.out.println("r = " + r);
234        }
235        if (r.degree(0) < P.degree(0)) { // recursion for degree
236            r = coefficientPseudoRemainder(r, A);
237        }
238        return r;
239    }
240
241
242    /**
243     * Polynomial leading coefficient pseudo remainder, base case.
244     * @param P generic polynomial in 1+1 variables.
245     * @param A generic polynomial in 1 variable.
246     * @return pseudo remainder of the leading coefficient of P wrt. A, with
247     *         ldcf(A)<sup>m'</sup> P = quotient * A + remainder.
248     */
249    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> coefficientPseudoRemainderBase(
250                    GenPolynomial<GenPolynomial<C>> P, GenPolynomial<C> A) {
251        if (A == null || A.isZERO()) { // findbugs
252            throw new ArithmeticException(P + " division by zero " + A);
253        }
254        if (A.isONE()) {
255            return P.ring.getZERO();
256        }
257        if (P.isZERO() || P.isONE()) {
258            return P;
259        }
260        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
261        GenPolynomialRing<C> afac = A.ring; // == pfac.coFac
262        GenPolynomial<GenPolynomial<C>> r = P;
263        GenPolynomial<C> h;
264        GenPolynomial<GenPolynomial<C>> hr;
265        GenPolynomial<C> ldcf = P.leadingBaseCoefficient();
266        long m = ldcf.degree(0);
267        long n = A.degree(0);
268        C c = A.leadingBaseCoefficient();
269        GenPolynomial<C> cc = afac.getZERO().sum(c);
270        //System.out.println("cc = " + cc);
271        ExpVector e = A.leadingExpVector();
272        for (long i = m; i >= n; i--) {
273            if (r.isZERO()) {
274                return r;
275            }
276            GenPolynomial<C> p = r.leadingBaseCoefficient();
277            ExpVector g = r.leadingExpVector();
278            long k = p.degree(0);
279            if (i == k) {
280                C pl = p.leadingBaseCoefficient();
281                ExpVector f = p.leadingExpVector();
282                f = f.subtract(e);
283                r = r.multiply(cc); // coeff cc
284                h = A.multiply(pl, f); // coeff ac
285                hr = new GenPolynomial<GenPolynomial<C>>(pfac, h, g);
286                r = r.subtract(hr);
287            } else {
288                r = r.multiply(cc);
289            }
290            //System.out.println("r = " + r);
291        }
292        if (r.degree(0) < P.degree(0)) { // recursion for degree
293            r = coefficientPseudoRemainderBase(r, A);
294        }
295        return r;
296    }
297
298
299    /**
300     * Extract polynomials with degree zero in the main variable.
301     * @param A list of generic polynomials in n variables.
302     * @return Z = [a_i] with deg(a_i,x_n) = 0 and in n-1 variables.
303     */
304    public static <C extends RingElem<C>> List<GenPolynomial<C>> zeroDegrees(List<GenPolynomial<C>> A) {
305        if (A == null || A.isEmpty()) {
306            return A;
307        }
308        GenPolynomialRing<C> pfac = A.get(0).ring;
309        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
310        List<GenPolynomial<C>> zeroDeg = new ArrayList<GenPolynomial<C>>(A.size());
311        for (int i = 0; i < A.size(); i++) {
312            GenPolynomial<C> q = A.get(i);
313            GenPolynomial<GenPolynomial<C>> fr = PolyUtil.<C> recursive(rfac, q);
314            if (fr.degree(0) == 0) {
315                zeroDeg.add(fr.leadingBaseCoefficient());
316            }
317        }
318        return zeroDeg;
319    }
320
321
322    /**
323     * Intersection. Generators for the intersection of ideals.
324     * @param pfac polynomial ring
325     * @param A list of polynomials
326     * @param B list of polynomials
327     * @return generators for (A \cap B)
328     */
329    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> intersect(GenPolynomialRing<C> pfac,
330                    List<GenPolynomial<C>> A, List<GenPolynomial<C>> B) {
331        if (A == null || A.isEmpty()) { // (0)
332            return B;
333        }
334        if (B == null || B.isEmpty()) { // (0)
335            return A;
336        }
337        int s = A.size() + B.size();
338        List<GenPolynomial<C>> c = new ArrayList<GenPolynomial<C>>(s);
339        GenPolynomialRing<C> tfac = pfac.extend(1);
340        // term order is also adjusted
341        for (GenPolynomial<C> p : A) {
342            p = p.extend(tfac, 0, 1L); // t*p
343            c.add(p);
344        }
345        for (GenPolynomial<C> p : B) {
346            GenPolynomial<C> q = p.extend(tfac, 0, 1L);
347            GenPolynomial<C> r = p.extend(tfac, 0, 0L);
348            p = r.subtract(q); // (1-t)*p
349            c.add(p);
350        }
351        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(tfac.coFac);
352        logger.warn("intersect computing GB");
353        List<GenPolynomial<C>> G = bb.GB(c);
354        if (debug) {
355            logger.debug("intersect GB = " + G);
356        }
357        List<GenPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G);
358        return I;
359    }
360
361
362    /**
363     * Intersection. Generators for the intersection of ideals.
364     * @param pfac solvable polynomial ring
365     * @param A list of polynomials
366     * @param B list of polynomials
367     * @return generators for (A \cap B)
368     */
369    public static <C extends GcdRingElem<C>> List<GenSolvablePolynomial<C>> intersect(
370                    GenSolvablePolynomialRing<C> pfac, List<GenSolvablePolynomial<C>> A,
371                    List<GenSolvablePolynomial<C>> B) {
372        if (A == null || A.isEmpty()) { // (0)
373            return B;
374        }
375        if (B == null || B.isEmpty()) { // (0)
376            return A;
377        }
378        int s = A.size() + B.size();
379        List<GenSolvablePolynomial<C>> c = new ArrayList<GenSolvablePolynomial<C>>(s);
380        GenSolvablePolynomialRing<C> tfac = pfac.extend(1);
381        // term order is also adjusted
382        for (GenSolvablePolynomial<C> p : A) {
383            p = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L); // t*p
384            c.add(p);
385        }
386        for (GenSolvablePolynomial<C> p : B) {
387            GenSolvablePolynomial<C> q = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L);
388            GenSolvablePolynomial<C> r = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 0L);
389            p = (GenSolvablePolynomial<C>) r.subtract(q); // (1-t)*p
390            c.add(p);
391        }
392        SolvableGroebnerBaseAbstract<C> sbb = SGBFactory.<C> getImplementation(tfac.coFac);
393        //new SolvableGroebnerBaseSeq<C>();
394        logger.warn("intersect computing GB");
395        List<GenSolvablePolynomial<C>> g = sbb.leftGB(c);
396        //List<GenSolvablePolynomial<C>> g = sbb.twosidedGB(c);
397        if (debug) {
398            logger.debug("intersect GB = " + g);
399        }
400        List<GenSolvablePolynomial<C>> I = PolyUtil.<C> intersect(pfac, g);
401        return I;
402    }
403
404
405    /**
406     * Intersection. Generators for the intersection of word ideals.
407     * @param pfac word polynomial ring
408     * @param A list of word polynomials
409     * @param B list of word polynomials
410     * @return generators for (A \cap B) if it exists
411     */
412    public static <C extends GcdRingElem<C>> List<GenWordPolynomial<C>> intersect(
413                    GenWordPolynomialRing<C> pfac, List<GenWordPolynomial<C>> A,
414                    List<GenWordPolynomial<C>> B) {
415        if (A == null || A.isEmpty()) { // (0)
416            return B;
417        }
418        if (B == null || B.isEmpty()) { // (0)
419            return A;
420        }
421        int s = A.size() + B.size();
422        List<GenWordPolynomial<C>> L = new ArrayList<GenWordPolynomial<C>>(s);
423        GenWordPolynomialRing<C> tfac = pfac.extend(1);
424        List<GenWordPolynomial<C>> gens = tfac.univariateList();
425        //System.out.println("gens = " + gens);
426        GenWordPolynomial<C> t = gens.get(gens.size() - 1);
427        //System.out.println("t = " + t);
428        // make t commute with other variables
429        for (GenWordPolynomial<C> p : gens) {
430            if (t == p) {
431                continue;
432            }
433            GenWordPolynomial<C> c = t.multiply(p).subtract(p.multiply(t)); // t p - p t
434            L.add(c);
435        }
436        for (GenWordPolynomial<C> p : A) {
437            p = tfac.valueOf(p).multiply(t); // t p
438            L.add(p);
439        }
440        for (GenWordPolynomial<C> p : B) {
441            GenWordPolynomial<C> q = tfac.valueOf(p).multiply(t);
442            GenWordPolynomial<C> r = tfac.valueOf(p);
443            p = r.subtract(q); // (1-t) p
444            L.add(p);
445        }
446        //System.out.println("L = " + L);
447        WordGroebnerBaseAbstract<C> bb = new WordGroebnerBaseSeq<C>();
448        logger.warn("intersect computing GB");
449        List<GenWordPolynomial<C>> G = bb.GB(L);
450        //System.out.println("G = " + G);
451        if (debug) {
452            logger.debug("intersect GB = " + G);
453        }
454        List<GenWordPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G);
455        return I;
456    }
457
458
459    /**
460     * Solvable quotient and remainder via reduction.
461     * @param n first solvable polynomial.
462     * @param d second solvable polynomial.
463     * @return [ n/d, n - (n/d)*d ]
464     */
465    @SuppressWarnings("unchecked")
466    public static <C extends GcdRingElem<C>> GenSolvablePolynomial<C>[] quotientRemainder(
467                    GenSolvablePolynomial<C> n, GenSolvablePolynomial<C> d) {
468        GenSolvablePolynomial<C>[] res = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
469        if (d.isZERO()) {
470            throw new RuntimeException("division by zero: " + n + "/" + d);
471        }
472        if (n.isZERO()) {
473            res[0] = n;
474            res[1] = n;
475            return res;
476        }
477        GenSolvablePolynomialRing<C> r = n.ring;
478        if (d.isONE()) {
479            res[0] = n;
480            res[1] = r.getZERO();
481            return res;
482        }
483        // divide
484        List<GenSolvablePolynomial<C>> Q = new ArrayList<GenSolvablePolynomial<C>>(1);
485        Q.add(r.getZERO());
486        List<GenSolvablePolynomial<C>> D = new ArrayList<GenSolvablePolynomial<C>>(1);
487        D.add(d);
488        SolvableReductionAbstract<C> sred = new SolvableReductionSeq<C>();
489        res[1] = sred.rightNormalform(Q, D, n); // left
490        res[0] = Q.get(0);
491        return res;
492    }
493
494
495    /**
496     * Subring generators.
497     * @param A list of polynomials in n variables.
498     * @return a Groebner base of polynomials in m &gt; n variables generating the subring of K[A].
499     */
500    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> subRing(List<GenPolynomial<C>> A) {
501        if (A == null || A.isEmpty()) {
502            return A;
503        }
504        GenPolynomialRing<C> pfac = A.get(0).ring;
505        logger.debug("pfac = " + pfac.toScript());
506        int n = pfac.nvar;
507        List<GenPolynomial<C>> Ap = new ArrayList<GenPolynomial<C>>();
508        for (GenPolynomial<C> a : A) {
509             if (a == null || a.isZERO() || a.isONE()) {
510                continue;
511            }
512            Ap.add(a);
513        }
514        int k = Ap.size();
515        if (k == 0) {
516            return Ap;
517        }
518        GenPolynomialRing<C> rfac = pfac.extendLower(k);
519        logger.debug("rfac = " + rfac.toScript());
520        assert rfac.nvar == n + k : "rfac.nvar == n+k";
521        List<GenPolynomial<C>> sr = new ArrayList<GenPolynomial<C>>();
522        int i = 0;
523        for (GenPolynomial<C> a : Ap) {
524            GenPolynomial<C> b = a.extendLower(rfac, 0, 0L);
525            b = b.subtract(pfac.getONE().extendLower(rfac, i++, 1L));
526            //System.out.println("a = " + a);
527            //System.out.println("b = " + b);
528            sr.add(b);
529        }
530        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(pfac.coFac);
531        List<GenPolynomial<C>> srg = bb.GB(sr);
532        return srg;
533    }
534
535
536    /**
537     * Subring membership.
538     * @param A Groebner base of polynomials in m &gt; n variables generating 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        return map.size() == 1 && map.keySet().contains(g.ring.evzero);
564    }
565
566
567    /**
568     * Subring and membership test.
569     * @param A list of polynomials in n variables.
570     * @param g polynomial in n variables.
571     * @return true, if g \in K[A], else false.
572     */
573    public static <C extends GcdRingElem<C>> boolean subRingAndMember(List<GenPolynomial<C>> A,
574                    GenPolynomial<C> g) {
575        if (A == null || A.isEmpty()) {
576            return true;
577        }
578        List<GenPolynomial<C>> srg = PolyGBUtil.<C> subRing(A);
579        return PolyGBUtil.<C> subRingMember(srg, g);
580    }
581
582}