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