001/*
002 * $Id: GreatestCommonDivisorSimple.java 5543 2016-07-24 18:45:47Z kredel $
003 */
004
005package edu.jas.fd;
006
007
008import org.apache.log4j.Logger;
009
010import edu.jas.poly.GenPolynomial;
011import edu.jas.poly.GenSolvablePolynomial;
012import edu.jas.poly.PolyUtil;
013import edu.jas.structure.GcdRingElem;
014import edu.jas.structure.RingFactory;
015
016
017/**
018 * (Non-unique) factorization domain greatest common divisor common algorithms
019 * with monic polynomial remainder sequence. If C is a field, then the monic PRS
020 * (on coefficients) is computed otherwise no simplifications in the reduction
021 * are made.
022 * @param <C> coefficient type
023 * @author Heinz Kredel
024 */
025
026public class GreatestCommonDivisorSimple<C extends GcdRingElem<C>> extends GreatestCommonDivisorAbstract<C> {
027
028
029    private static final Logger logger = Logger.getLogger(GreatestCommonDivisorSimple.class);
030
031
032    private static final boolean debug = logger.isDebugEnabled();
033
034
035    /**
036     * Constructor.
037     * @param cf coefficient ring.
038     */
039    public GreatestCommonDivisorSimple(RingFactory<C> cf) {
040        super(cf);
041    }
042
043
044    /**
045     * Univariate GenSolvablePolynomial greatest common divisor. Uses
046     * pseudoRemainder for remainder.
047     * @param P univariate GenSolvablePolynomial.
048     * @param S univariate GenSolvablePolynomial.
049     * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S).
050     */
051    @Override
052    public GenSolvablePolynomial<C> leftBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
053        if (S == null || S.isZERO()) {
054            return P;
055        }
056        if (P == null || P.isZERO()) {
057            return S;
058        }
059        if (P.ring.nvar > 1) {
060            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
061        }
062        boolean field = P.ring.coFac.isField();
063        long e = P.degree(0);
064        long f = S.degree(0);
065        GenSolvablePolynomial<C> q;
066        GenSolvablePolynomial<C> r;
067        if (f > e) {
068            r = P;
069            q = S;
070            long g = f;
071            f = e;
072            e = g;
073        } else {
074            q = P;
075            r = S;
076        }
077        if (debug) {
078            logger.debug("degrees: e = " + e + ", f = " + f);
079        }
080        C c;
081        if (field) {
082            r = r.monic();
083            q = q.monic();
084            c = P.ring.getONECoefficient();
085        } else {
086            r = (GenSolvablePolynomial<C>) r.abs();
087            q = (GenSolvablePolynomial<C>) q.abs();
088            C a = rightBaseContent(r);
089            C b = rightBaseContent(q);
090            r = divide(r, a); // indirection
091            q = divide(q, b); // indirection
092            c = gcd(a, b); // indirection
093        }
094        //System.out.println("baseCont: gcd(cont) = " + b);
095        if (r.isONE()) {
096            return r.multiply(c);
097        }
098        if (q.isONE()) {
099            return q.multiply(c);
100        }
101        GenSolvablePolynomial<C> x;
102        //System.out.println("baseGCD: q = " + q);
103        //System.out.println("baseGCD: r = " + r);
104        while (!r.isZERO()) {
105            x = FDUtil.<C> leftBaseSparsePseudoRemainder(q, r);
106            q = r;
107            if (field) {
108                r = x.monic();
109            } else {
110                r = x;
111            }
112            //System.out.println("baseGCD: q = " + q);
113            //System.out.println("baseGCD: r = " + r);
114        }
115        ///q = leftBasePrimitivePart(q);
116        q = rightBasePrimitivePart(q);
117        return (GenSolvablePolynomial<C>) (q.multiply(c)).abs();
118    }
119
120
121    /**
122     * Univariate GenSolvablePolynomial right greatest common divisor. Uses
123     * pseudoRemainder for remainder.
124     * @param P univariate GenSolvablePolynomial.
125     * @param S univariate GenSolvablePolynomial.
126     * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'.
127     */
128    @Override
129    public GenSolvablePolynomial<C> rightBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
130        if (S == null || S.isZERO()) {
131            return P;
132        }
133        if (P == null || P.isZERO()) {
134            return S;
135        }
136        if (P.ring.nvar > 1) {
137            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
138        }
139        boolean field = P.ring.coFac.isField();
140        long e = P.degree(0);
141        long f = S.degree(0);
142        GenSolvablePolynomial<C> q;
143        GenSolvablePolynomial<C> r;
144        if (f > e) {
145            r = P;
146            q = S;
147            long g = f;
148            f = e;
149            e = g;
150        } else {
151            q = P;
152            r = S;
153        }
154        if (debug) {
155            logger.debug("degrees: e = " + e + ", f = " + f);
156        }
157        C c;
158        if (field) {
159            r = r.monic();
160            q = q.monic();
161            c = P.ring.getONECoefficient();
162        } else {
163            r = (GenSolvablePolynomial<C>) r.abs();
164            q = (GenSolvablePolynomial<C>) q.abs();
165            C a = leftBaseContent(r);
166            C b = leftBaseContent(q);
167            r = divide(r, a); // indirection
168            q = divide(q, b); // indirection
169            c = gcd(a, b); // indirection
170        }
171        //System.out.println("baseCont: gcd(cont) = " + b);
172        if (r.isONE()) {
173            return r.multiply(c);
174        }
175        if (q.isONE()) {
176            return q.multiply(c);
177        }
178        GenSolvablePolynomial<C> x;
179        //System.out.println("baseGCD: q = " + q);
180        //System.out.println("baseGCD: r = " + r);
181        while (!r.isZERO()) {
182            x = FDUtil.<C> rightBaseSparsePseudoRemainder(q, r);
183            q = r;
184            if (field) {
185                r = x.monic();
186            } else {
187                r = x;
188            }
189            //System.out.println("baseGCD: q = " + q);
190            //System.out.println("baseGCD: r = " + r);
191        }
192        ///q = rightBasePrimitivePart(q);
193        q = leftBasePrimitivePart(q);
194        return (GenSolvablePolynomial<C>) (q.multiplyLeft(c)).abs();
195    }
196
197
198    /**
199     * Univariate GenSolvablePolynomial left recursive greatest common divisor.
200     * Uses pseudoRemainder for remainder.
201     * @param P univariate recursive GenSolvablePolynomial.
202     * @param S univariate recursive GenSolvablePolynomial.
203     * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where
204     *         deg_main(p) = deg_main(s) == 0.
205     */
206    @Override
207    public GenSolvablePolynomial<GenPolynomial<C>> leftRecursiveUnivariateGcd(
208                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
209        if (S == null || S.isZERO()) {
210            return P;
211        }
212        if (P == null || P.isZERO()) {
213            return S;
214        }
215        if (P.ring.nvar > 1) {
216            throw new IllegalArgumentException("no univariate polynomial");
217        }
218        boolean field = P.leadingBaseCoefficient().ring.coFac.isField();
219        long e = P.degree(0);
220        long f = S.degree(0);
221        GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs, qp, rp;
222        if (f > e) {
223            r = P;
224            q = S;
225            long g = f;
226            f = e;
227            e = g;
228        } else if (f < e) {
229            q = P;
230            r = S;
231        } else { // f == e
232            if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) {
233                q = P;
234                r = S;
235            } else {
236                r = P;
237                q = S;
238            }
239        }
240        if (debug) {
241            logger.debug("degrees: e = " + e + ", f = " + f);
242        }
243        if (field) {
244            r = PolyUtil.<C> monic(r);
245            q = PolyUtil.<C> monic(q);
246        } else {
247            r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs();
248            q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs();
249        }
250        GenSolvablePolynomial<C> a = rightRecursiveContent(r);
251        ///rs = FDUtil.<C> recursiveDivideRightEval(r, a);  
252        rs = FDUtil.<C> recursiveLeftDivide(r, a); 
253        //rs = FDUtil.<C> recursiveRightDivide(r, a);
254        if (debug) {
255            logger.info("recCont a = " + a + ", r = " + r);
256            logger.info("recCont r/a = " + rs + ", r%a = " + r.subtract(rs.multiply(a)));
257            if (!r.equals(rs.multiply(a))) {
258                if (!rs.multiplyLeft(a).equals(r)) {
259                    System.out.println("recGcd, r         = " + r);
260                    System.out.println("recGcd, cont(r)   = " + a);
261                    System.out.println("recGcd, pp(r)     = " + rs);
262                    System.out.println("recGcd, pp(r)c(r) = " + rs.multiply(a));
263                    System.out.println("recGcd, c(r)pp(r) = " + rs.multiplyLeft(a));
264                    throw new RuntimeException("recGcd, pp: not divisible");
265                }
266            }
267        }
268        r = rs;
269        GenSolvablePolynomial<C> b = rightRecursiveContent(q);
270        ///qs = FDUtil.<C> recursiveDivideRightEval(q, b);  
271        qs = FDUtil.<C> recursiveLeftDivide(q, b); 
272        //qs = FDUtil.<C> recursiveRightDivide(q, b);
273        if (debug) {
274            logger.info("recCont b = " + b + ", q = " + q);
275            logger.info("recCont q/b = " + qs + ", q%b = " + q.subtract(qs.multiply(b)));
276            if (!q.equals(qs.multiply(b))) {
277                if (!qs.multiplyLeft(b).equals(q)) {
278                    System.out.println("recGcd, q         = " + q);
279                    System.out.println("recGcd, cont(q)   = " + b);
280                    System.out.println("recGcd, pp(q)     = " + qs);
281                    System.out.println("recGcd, pp(q)c(q) = " + qs.multiply(b));
282                    System.out.println("recGcd, c(q)pp(q) = " + qs.multiplyLeft(b));
283                    throw new RuntimeException("recGcd, pp: not divisible");
284                }
285            }
286        }
287        q = qs;
288        logger.info("Gcd(content).ring = " + a.ring.toScript() + ", a = " + a + ", b = " + b);
289        //no: GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion
290        GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion
291        logger.info("Gcd(contents) c = " + c + ", a = " + a + ", b = " + b);
292        if (r.isONE()) {
293            return r.multiply(c);
294        }
295        if (q.isONE()) {
296            return q.multiply(c);
297        }
298        if (debug) {
299            logger.info("r.ring = " + r.ring.toScript());
300            logger.info("gcd-loop, start: q = " + q + ", r = " + r);
301        }
302        while (!r.isZERO()) {
303            x = FDUtil.<C> recursiveSparsePseudoRemainder(q, r);
304            q = r;
305            if (field) {
306                r = PolyUtil.<C> monic(x);
307            } else {
308                r = x;
309            }
310            if (debug) {
311                logger.info("gcd-loop, rem: q = " + q + ", r = " + r);
312            }
313        }
314        if (debug) {
315            logger.info("gcd(div) = " + q + ", rs = " + rs + ", qs = " + qs);
316            rp = FDUtil.<C> recursiveSparsePseudoRemainder(rs, q);
317            qp = FDUtil.<C> recursiveSparsePseudoRemainder(qs, q);
318            if (!qp.isZERO() || !rp.isZERO()) {
319                logger.info("gcd(div): rem(r,g) = " + rp + ", rem(q,g) = " + qp);
320                rp = FDUtil.<C> recursivePseudoQuotient(rs, q);
321                qp = FDUtil.<C> recursivePseudoQuotient(qs, q);
322                logger.info("gcd(div): r/g = " + rp + ", q/g = " + qp);
323                throw new RuntimeException("recGcd, div: not divisible");
324            }
325        }
326        qp = q;
327        q = rightRecursivePrimitivePart(q);
328        if (!qp.equals(q)) {
329            logger.info("gcd(pp) = " + q + ", qp = " + qp);
330        }
331        q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiply(c).abs();
332        return q;
333    }
334
335
336    /**
337     * Univariate GenSolvablePolynomial right recursive greatest common divisor.
338     * Uses pseudoRemainder for remainder.
339     * @param P univariate recursive GenSolvablePolynomial.
340     * @param S univariate recursive GenSolvablePolynomial.
341     * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where
342     *         deg_main(p) = deg_main(s) == 0.
343     */
344    @Override
345    public GenSolvablePolynomial<GenPolynomial<C>> rightRecursiveUnivariateGcd(
346                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
347        if (S == null || S.isZERO()) {
348            return P;
349        }
350        if (P == null || P.isZERO()) {
351            return S;
352        }
353        if (P.ring.nvar > 1) {
354            throw new IllegalArgumentException("no univariate polynomial");
355        }
356        boolean field = P.leadingBaseCoefficient().ring.coFac.isField();
357        long e = P.degree(0);
358        long f = S.degree(0);
359        GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs, qp, rp;
360        if (f > e) {
361            r = P;
362            q = S;
363            long g = f;
364            f = e;
365            e = g;
366        } else if (f < e) {
367            q = P;
368            r = S;
369        } else { // f == e
370            if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) {
371                q = P;
372                r = S;
373            } else {
374                r = P;
375                q = S;
376            }
377        }
378        if (debug) {
379            logger.debug("RI-degrees: e = " + e + ", f = " + f);
380        }
381        if (field) {
382            r = PolyUtil.<C> monic(r);
383            q = PolyUtil.<C> monic(q);
384        } else {
385            r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs();
386            q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs();
387        }
388        GenSolvablePolynomial<C> a = leftRecursiveContent(r);
389        rs = FDUtil.<C> recursiveRightDivide(r, a);
390        //no: rs = FDUtil.<C> recursiveLeftDivide(r, a);
391        //no: rs = FDUtil.<C> recursiveRightPseudoQuotient(r, a);
392        if (debug) {
393            logger.info("RI-recCont a = " + a + ", r = " + r);
394            logger.info("RI-recCont r/a = " + r + ", r%a = " + r.subtract(rs.multiplyLeft(a)));
395            if (!r.equals(rs.multiplyLeft(a))) { // Left
396                System.out.println("RI-recGcd, r         = " + r);
397                System.out.println("RI-recGcd, cont(r)   = " + a);
398                System.out.println("RI-recGcd, pp(r)     = " + rs);
399                System.out.println("RI-recGcd, pp(r)c(r) = " + rs.multiply(a));
400                System.out.println("RI-recGcd, c(r)pp(r) = " + rs.multiplyLeft(a));
401                throw new RuntimeException("RI-recGcd, pp: not divisible");
402            }
403        }
404        r = rs;
405        GenSolvablePolynomial<C> b = leftRecursiveContent(q);
406        qs = FDUtil.<C> recursiveRightDivide(q, b);
407        if (debug) {
408            logger.info("RI-recCont b = " + b + ", q = " + q);
409            logger.info("RI-recCont q/b = " + qs + ", q%b = " + q.subtract(qs.multiplyLeft(b)));
410            if (!q.equals(qs.multiplyLeft(b))) { // Left
411                System.out.println("RI-recGcd, q         = " + q);
412                System.out.println("RI-recGcd, cont(q)   = " + b);
413                System.out.println("RI-recGcd, pp(q)     = " + qs);
414                System.out.println("RI-recGcd, pp(q)c(q) = " + qs.multiply(b));
415                System.out.println("RI-recGcd, c(q)pp(q) = " + qs.multiplyLeft(b));
416                throw new RuntimeException("RI-recGcd, pp: not divisible");
417            }
418        }
419        q = qs;
420        //no: GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion
421        GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion
422        logger.info("RI-Gcd(contents) c = " + c + ", a = " + a + ", b = " + b);
423        if (r.isONE()) {
424            return r.multiplyLeft(c);
425        }
426        if (q.isONE()) {
427            return q.multiplyLeft(c);
428        }
429        if (debug) {
430            logger.info("RI-r.ring = " + r.ring.toScript());
431            logger.info("RI-gcd-loop, start: q = " + q + ", r = " + r);
432        }
433        while (!r.isZERO()) {
434            x = FDUtil.<C> recursiveRightSparsePseudoRemainder(q, r);
435            q = r;
436            if (field) {
437                r = PolyUtil.<C> monic(x);
438            } else {
439                r = x;
440            }
441            if (debug) {
442                logger.info("RI-gcd-loop, rem: q = " + q + ", r = " + r);
443            }
444        }
445        if (debug) {
446            logger.info("RI-gcd(div) = " + q + ", rs = " + rs + ", qs = " + qs);
447            rp = FDUtil.<C> recursiveRightSparsePseudoRemainder(rs, q);
448            qp = FDUtil.<C> recursiveRightSparsePseudoRemainder(qs, q);
449            if (!qp.isZERO() || !rp.isZERO()) {
450                logger.info("RI-gcd(div): rem(r,g) = " + rp + ", rem(q,g) = " + qp);
451                rp = FDUtil.<C> recursivePseudoQuotient(rs, q);
452                qp = FDUtil.<C> recursivePseudoQuotient(qs, q);
453                logger.info("RI-gcd(div): r/g = " + rp + ", q/g = " + qp);
454                //logger.info("gcd(div): rp*g = " + rp.multiply(q) + ", qp*g = " + qp.multiply(q));
455                throw new RuntimeException("recGcd, div: not divisible");
456            }
457        }
458        qp = q;
459        logger.info("RI-recGcd(P,S) pre pp okay: qp = " + qp);
460        //q = rightRecursivePrimitivePart(q);
461        q = leftRecursivePrimitivePart(q); // sic
462        if (!qp.equals(q)) {
463            logger.info("RI-gcd(pp) = " + q + ", qp = " + qp); // + ", ring = " + P.ring.toScript());
464        }
465        q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiplyLeft(c).abs();
466        return q;
467    }
468
469}