001/*
002 * $Id: PolyGBUtil.java 5264 2015-07-27 14:19:57Z kredel $
003 */
004
005package edu.jas.gbufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.log4j.Logger;
012
013import edu.jas.gb.GroebnerBaseAbstract;
014import edu.jas.gb.SolvableGroebnerBaseAbstract;
015import edu.jas.gb.SolvableGroebnerBaseSeq;
016import edu.jas.gb.SolvableReductionAbstract;
017import edu.jas.gb.SolvableReductionSeq;
018import edu.jas.poly.ExpVector;
019import edu.jas.poly.GenPolynomial;
020import edu.jas.poly.GenPolynomialRing;
021import edu.jas.poly.GenSolvablePolynomial;
022import edu.jas.poly.GenSolvablePolynomialRing;
023import edu.jas.poly.PolyUtil;
024import edu.jas.structure.GcdRingElem;
025import edu.jas.structure.RingElem;
026
027
028/**
029 * Package gbufd utilities.
030 * @author Heinz Kredel
031 */
032
033public class PolyGBUtil {
034
035
036    public static final Logger logger = Logger.getLogger(PolyGBUtil.class);
037
038
039    private static boolean debug = logger.isDebugEnabled();
040
041
042    /**
043     * Test for resultant.
044     * @param A generic polynomial.
045     * @param B generic polynomial.
046     * @param r generic polynomial.
047     * @return true if res(A,B) isContained in ideal(A,B), else false.
048     */
049    public static <C extends GcdRingElem<C>> boolean isResultant(GenPolynomial<C> A, GenPolynomial<C> B,
050                    GenPolynomial<C> r) {
051        if (r == null || r.isZERO()) {
052            return true;
053        }
054        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(r.ring.coFac);
055        List<GenPolynomial<C>> F = new ArrayList<GenPolynomial<C>>(2);
056        F.add(A);
057        F.add(B);
058        List<GenPolynomial<C>> G = bb.GB(F);
059        //System.out.println("G = " + G);
060        GenPolynomial<C> n = bb.red.normalform(G, r);
061        //System.out.println("n = " + n);
062        return n.isZERO();
063    }
064
065
066    /**
067     * Top pseudo reduction wrt the main variables.
068     * @param P generic polynomial.
069     * @param A list of generic polynomials sorted according to appearing main
070     *            variables.
071     * @return top pseudo remainder of P wrt. A for the appearing variables.
072     */
073    public static <C extends RingElem<C>> GenPolynomial<C> topPseudoRemainder(List<GenPolynomial<C>> A,
074                    GenPolynomial<C> P) {
075        if (A == null || A.isEmpty()) {
076            return P.monic();
077        }
078        if (P.isZERO()) {
079            return P;
080        }
081        //System.out.println("remainder, P = " + P);
082        GenPolynomialRing<C> pfac = A.get(0).ring;
083        if (pfac.nvar <= 1) { // recursion base 
084            GenPolynomial<C> R = PolyUtil.<C> baseSparsePseudoRemainder(P, A.get(0));
085            return R.monic();
086        }
087        // select polynomials according to the main variable
088        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
089        GenPolynomial<C> Q = A.get(0); // wrong, must eventually search polynomial
090        GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac, Q);
091        GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
092        GenPolynomial<GenPolynomial<C>> rr;
093        if (qr.isONE()) {
094            return P.ring.getZERO();
095        }
096        if (qr.degree(0) > 0) {
097            rr = PolyUtil.<C> recursiveSparsePseudoRemainder(pr, qr);
098            //System.out.println("remainder, pr = " + pr);
099            //System.out.println("remainder, qr = " + qr);
100            //System.out.println("remainder, rr = " + rr);
101        } else {
102            rr = pr;
103        }
104        if (rr.degree(0) > 0) {
105            GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr);
106            return R.monic();
107            // not further reduced wrt. other variables = top-reduction only
108        }
109        List<GenPolynomial<C>> zeroDeg = zeroDegrees(A);
110        GenPolynomial<C> R = topPseudoRemainder(zeroDeg, rr.leadingBaseCoefficient());
111        R = R.extend(pfac, 0, 0L);
112        return R.monic();
113    }
114
115
116    /**
117     * Top coefficient pseudo remainder of the leading coefficient of P wrt A in
118     * the main variables.
119     * @param P generic polynomial in n+1 variables.
120     * @param A list of generic polynomials in n variables sorted according to
121     *            appearing main variables.
122     * @return pseudo remainder of the leading coefficient of P wrt A.
123     */
124    public static <C extends RingElem<C>> GenPolynomial<C> topCoefficientPseudoRemainder(
125                    List<GenPolynomial<C>> A, GenPolynomial<C> P) {
126        if (A == null || A.isEmpty()) {
127            return P.monic();
128        }
129        if (P.isZERO()) {
130            return P;
131        }
132        GenPolynomialRing<C> pfac = P.ring;
133        GenPolynomialRing<C> pfac1 = A.get(0).ring;
134        if (pfac1.nvar <= 1) { // recursion base 
135            GenPolynomial<C> a = A.get(0);
136            GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(pfac.nvar - 1);
137            GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
138            // ldcf(P,x_m) = q a + r 
139            GenPolynomial<GenPolynomial<C>> rr = PolyGBUtil.<C> coefficientPseudoRemainderBase(pr, a);
140            GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, rr);
141            return R.monic();
142        }
143        // select polynomials according to the main variable
144        GenPolynomialRing<GenPolynomial<C>> rfac1 = pfac1.recursive(1);
145        int nv = pfac.nvar - pfac1.nvar;
146        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1 + nv);
147        GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> rfac2 = rfac.recursive(nv);
148        if (debug) {
149            logger.info("rfac =" + rfac);
150        }
151        GenPolynomial<GenPolynomial<C>> pr = PolyUtil.<C> recursive(rfac, P);
152        GenPolynomial<GenPolynomial<GenPolynomial<C>>> pr2 = PolyUtil.<GenPolynomial<C>> recursive(rfac2, pr);
153        //System.out.println("recursion, pr2 = " + pr2);
154        GenPolynomial<C> Q = A.get(0);
155        GenPolynomial<GenPolynomial<C>> qr = PolyUtil.<C> recursive(rfac1, Q);
156        GenPolynomial<GenPolynomial<GenPolynomial<C>>> rr;
157        if (qr.isONE()) {
158            return P.ring.getZERO();
159        }
160        if (qr.degree(0) > 0) {
161            // pseudo remainder:  ldcf(P,x_m) = a q + r 
162            rr = PolyGBUtil.<C> coefficientPseudoRemainder(pr2, qr);
163            //System.out.println("recursion, qr  = " + qr);
164            //System.out.println("recursion, pr  = " + pr2);
165            //System.out.println("recursion, rr  = " + rr);
166        } else {
167            rr = pr2;
168        }
169        // reduction wrt. the other variables
170        List<GenPolynomial<C>> zeroDeg = zeroDegrees(A);
171        GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<GenPolynomial<C>> distribute(rfac, rr);
172        GenPolynomial<C> R = PolyUtil.<C> distribute(pfac, Rr);
173        R = topCoefficientPseudoRemainder(zeroDeg, R);
174        return R.monic();
175    }
176
177
178    /**
179     * Polynomial leading coefficient pseudo remainder.
180     * @param P generic polynomial in n+1 variables.
181     * @param A generic polynomial in n variables.
182     * @return pseudo remainder of the leading coefficient of P wrt A, with
183     *         ldcf(A)<sup>m'</sup> P = quotient * A + remainder.
184     */
185    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<GenPolynomial<C>>> coefficientPseudoRemainder(
186                    GenPolynomial<GenPolynomial<GenPolynomial<C>>> P, GenPolynomial<GenPolynomial<C>> A) {
187        if (A == null || A.isZERO()) { // findbugs
188            throw new ArithmeticException(P + " division by zero " + A);
189        }
190        if (A.isONE()) {
191            return P.ring.getZERO();
192        }
193        if (P.isZERO() || P.isONE()) {
194            return P;
195        }
196        GenPolynomialRing<GenPolynomial<GenPolynomial<C>>> pfac = P.ring;
197        GenPolynomialRing<GenPolynomial<C>> afac = A.ring; // == pfac.coFac
198        GenPolynomial<GenPolynomial<GenPolynomial<C>>> r = P;
199        GenPolynomial<GenPolynomial<C>> h;
200        GenPolynomial<GenPolynomial<GenPolynomial<C>>> hr;
201        GenPolynomial<GenPolynomial<C>> ldcf = P.leadingBaseCoefficient();
202        long m = ldcf.degree(0);
203        long n = A.degree(0);
204        GenPolynomial<C> c = A.leadingBaseCoefficient();
205        GenPolynomial<GenPolynomial<C>> cc = afac.getZERO().sum(c);
206        //System.out.println("cc = " + cc);
207        ExpVector e = A.leadingExpVector();
208        for (long i = m; i >= n; i--) {
209            if (r.isZERO()) {
210                return r;
211            }
212            GenPolynomial<GenPolynomial<C>> p = r.leadingBaseCoefficient();
213            ExpVector g = r.leadingExpVector();
214            long k = p.degree(0);
215            if (i == k) {
216                GenPolynomial<C> pl = p.leadingBaseCoefficient();
217                ExpVector f = p.leadingExpVector();
218                f = f.subtract(e);
219                r = r.multiply(cc); // coeff cc
220                h = A.multiply(pl, f); // coeff ac
221                hr = new GenPolynomial<GenPolynomial<GenPolynomial<C>>>(pfac, h, g);
222                r = r.subtract(hr);
223            } else {
224                r = r.multiply(cc);
225            }
226            //System.out.println("r = " + r);
227        }
228        if (r.degree(0) < P.degree(0)) { // recursion for degree
229            r = coefficientPseudoRemainder(r, A);
230        }
231        return r;
232    }
233
234
235    /**
236     * Polynomial leading coefficient pseudo remainder, base case.
237     * @param P generic polynomial in 1+1 variables.
238     * @param A generic polynomial in 1 variable.
239     * @return pseudo remainder of the leading coefficient of P wrt. A, with
240     *         ldcf(A)<sup>m'</sup> P = quotient * A + remainder.
241     */
242    public static <C extends RingElem<C>> GenPolynomial<GenPolynomial<C>> coefficientPseudoRemainderBase(
243                    GenPolynomial<GenPolynomial<C>> P, GenPolynomial<C> A) {
244        if (A == null || A.isZERO()) { // findbugs
245            throw new ArithmeticException(P + " division by zero " + A);
246        }
247        if (A.isONE()) {
248            return P.ring.getZERO();
249        }
250        if (P.isZERO() || P.isONE()) {
251            return P;
252        }
253        GenPolynomialRing<GenPolynomial<C>> pfac = P.ring;
254        GenPolynomialRing<C> afac = A.ring; // == pfac.coFac
255        GenPolynomial<GenPolynomial<C>> r = P;
256        GenPolynomial<C> h;
257        GenPolynomial<GenPolynomial<C>> hr;
258        GenPolynomial<C> ldcf = P.leadingBaseCoefficient();
259        long m = ldcf.degree(0);
260        long n = A.degree(0);
261        C c = A.leadingBaseCoefficient();
262        GenPolynomial<C> cc = afac.getZERO().sum(c);
263        //System.out.println("cc = " + cc);
264        ExpVector e = A.leadingExpVector();
265        for (long i = m; i >= n; i--) {
266            if (r.isZERO()) {
267                return r;
268            }
269            GenPolynomial<C> p = r.leadingBaseCoefficient();
270            ExpVector g = r.leadingExpVector();
271            long k = p.degree(0);
272            if (i == k) {
273                C pl = p.leadingBaseCoefficient();
274                ExpVector f = p.leadingExpVector();
275                f = f.subtract(e);
276                r = r.multiply(cc); // coeff cc
277                h = A.multiply(pl, f); // coeff ac
278                hr = new GenPolynomial<GenPolynomial<C>>(pfac, h, g);
279                r = r.subtract(hr);
280            } else {
281                r = r.multiply(cc);
282            }
283            //System.out.println("r = " + r);
284        }
285        if (r.degree(0) < P.degree(0)) { // recursion for degree
286            r = coefficientPseudoRemainderBase(r, A);
287        }
288        return r;
289    }
290
291
292    /**
293     * Extract polynomials with degree zero in the main variable.
294     * @param A list of generic polynomials in n variables.
295     * @return Z = [a_i] with deg(a_i,x_n) = 0 and in n-1 variables.
296     */
297    public static <C extends RingElem<C>> List<GenPolynomial<C>> zeroDegrees(List<GenPolynomial<C>> A) {
298        if (A == null || A.isEmpty()) {
299            return A;
300        }
301        GenPolynomialRing<C> pfac = A.get(0).ring;
302        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
303        List<GenPolynomial<C>> zeroDeg = new ArrayList<GenPolynomial<C>>(A.size());
304        for (int i = 0; i < A.size(); i++) {
305            GenPolynomial<C> q = A.get(i);
306            GenPolynomial<GenPolynomial<C>> fr = PolyUtil.<C> recursive(rfac, q);
307            if (fr.degree(0) == 0) {
308                zeroDeg.add(fr.leadingBaseCoefficient());
309            }
310        }
311        return zeroDeg;
312    }
313
314
315    /**
316     * Intersection. Generators for the intersection of ideals.
317     * @param pfac polynomial ring
318     * @param A list of polynomials
319     * @param B list of polynomials
320     * @return generators for (A \cap B)
321     */
322    public static <C extends GcdRingElem<C>> List<GenPolynomial<C>> intersect(GenPolynomialRing<C> pfac,
323                    List<GenPolynomial<C>> A, List<GenPolynomial<C>> B) {
324        if (A == null || A.isEmpty()) { // (0)
325            return B;
326        }
327        if (B == null || B.isEmpty()) { // (0)
328            return A;
329        }
330        int s = A.size() + B.size();
331        List<GenPolynomial<C>> c = new ArrayList<GenPolynomial<C>>(s);
332        GenPolynomialRing<C> tfac = pfac.extend(1);
333        // term order is also adjusted
334        for (GenPolynomial<C> p : A) {
335            p = p.extend(tfac, 0, 1L); // t*p
336            c.add(p);
337        }
338        for (GenPolynomial<C> p : B) {
339            GenPolynomial<C> q = p.extend(tfac, 0, 1L);
340            GenPolynomial<C> r = p.extend(tfac, 0, 0L);
341            p = r.subtract(q); // (1-t)*p
342            c.add(p);
343        }
344        GroebnerBaseAbstract<C> bb = GBFactory.<C> getImplementation(tfac.coFac);
345        logger.warn("intersect computing GB");
346        List<GenPolynomial<C>> G = bb.GB(c);
347        if (debug) {
348            logger.debug("intersect GB = " + G);
349        }
350        List<GenPolynomial<C>> I = PolyUtil.<C> intersect(pfac, G);
351        return I;
352    }
353
354
355    /**
356     * Intersection. Generators for the intersection of ideals.
357     * @param pfac solvable polynomial ring
358     * @param A list of polynomials
359     * @param B list of polynomials
360     * @return generators for (A \cap B)
361     */
362    public static <C extends GcdRingElem<C>> List<GenSolvablePolynomial<C>> intersect(
363                    GenSolvablePolynomialRing<C> pfac, List<GenSolvablePolynomial<C>> A,
364                    List<GenSolvablePolynomial<C>> B) {
365        if (A == null || A.isEmpty()) { // (0)
366            return B;
367        }
368        if (B == null || B.isEmpty()) { // (0)
369            return A;
370        }
371        int s = A.size() + B.size();
372        List<GenSolvablePolynomial<C>> c = new ArrayList<GenSolvablePolynomial<C>>(s);
373        GenSolvablePolynomialRing<C> tfac = pfac.extend(1);
374        // term order is also adjusted
375        for (GenSolvablePolynomial<C> p : A) {
376            p = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L); // t*p
377            c.add(p);
378        }
379        for (GenSolvablePolynomial<C> p : B) {
380            GenSolvablePolynomial<C> q = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 1L);
381            GenSolvablePolynomial<C> r = (GenSolvablePolynomial<C>) p.extend(tfac, 0, 0L);
382            p = (GenSolvablePolynomial<C>) r.subtract(q); // (1-t)*p
383            c.add(p);
384        }
385        SolvableGroebnerBaseAbstract<C> sbb = SGBFactory.<C> getImplementation(tfac.coFac);
386        //new SolvableGroebnerBaseSeq<C>();
387        logger.warn("intersect computing GB");
388        List<GenSolvablePolynomial<C>> g = sbb.leftGB(c);
389        //List<GenSolvablePolynomial<C>> g = sbb.twosidedGB(c);
390        if (debug) {
391            logger.debug("intersect GB = " + g);
392        }
393        List<GenSolvablePolynomial<C>> I = PolyUtil.<C> intersect(pfac, g);
394        return I;
395    }
396
397
398    /**
399     * Solvable quotient and remainder via reduction.
400     * @param n first solvable polynomial.
401     * @param d second solvable polynomial.
402     * @return [ n/d, n - (n/d)*d ]
403     */
404    @SuppressWarnings("cast")
405    public static <C extends GcdRingElem<C>> GenSolvablePolynomial<C>[] quotientRemainder(
406                    GenSolvablePolynomial<C> n, GenSolvablePolynomial<C> d) {
407        GenSolvablePolynomial<C>[] res = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
408        if (d.isZERO()) {
409            throw new RuntimeException("division by zero: " + n + "/" + d);
410        }
411        if (n.isZERO()) {
412            res[0] = n;
413            res[1] = n;
414            return res;
415        }
416        GenSolvablePolynomialRing<C> r = n.ring;
417        if (d.isONE()) {
418            res[0] = n;
419            res[1] = r.getZERO();
420            return res;
421        }
422        // divide
423        List<GenSolvablePolynomial<C>> Q = new ArrayList<GenSolvablePolynomial<C>>(1);
424        Q.add(r.getZERO());
425        List<GenSolvablePolynomial<C>> D = new ArrayList<GenSolvablePolynomial<C>>(1);
426        D.add(d);
427        SolvableReductionAbstract<C> sred = new SolvableReductionSeq<C>();
428        res[1] = sred.rightNormalform(Q, D, n); // left
429        res[0] = Q.get(0);
430        return res;
431    }
432
433}