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.debug("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 = rightBaseContent(r);
088            C b = rightBaseContent(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.multiply(c);
096        }
097        if (q.isONE()) {
098            return q.multiply(c);
099        }
100        GenSolvablePolynomial<C> x;
101        //System.out.println("baseGCD: q = " + q);
102        //System.out.println("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            //System.out.println("baseGCD: q = " + q);
112            //System.out.println("baseGCD: r = " + r);
113        }
114        ///q = leftBasePrimitivePart(q);
115        q = rightBasePrimitivePart(q);
116        return (GenSolvablePolynomial<C>) (q.multiply(c)).abs();
117    }
118
119
120    /**
121     * Univariate GenSolvablePolynomial right greatest common divisor. Uses
122     * pseudoRemainder for remainder.
123     * @param P univariate GenSolvablePolynomial.
124     * @param S univariate GenSolvablePolynomial.
125     * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'.
126     */
127    @Override
128    public GenSolvablePolynomial<C> rightBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
129        if (S == null || S.isZERO()) {
130            return P;
131        }
132        if (P == null || P.isZERO()) {
133            return S;
134        }
135        if (P.ring.nvar > 1) {
136            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
137        }
138        boolean field = P.ring.coFac.isField();
139        long e = P.degree(0);
140        long f = S.degree(0);
141        GenSolvablePolynomial<C> q;
142        GenSolvablePolynomial<C> r;
143        if (f > e) {
144            r = P;
145            q = S;
146            long g = f;
147            f = e;
148            e = g;
149        } else {
150            q = P;
151            r = S;
152        }
153        logger.debug("degrees: e = {}, f = {}", e, f);
154        C c;
155        if (field) {
156            r = r.monic();
157            q = q.monic();
158            c = P.ring.getONECoefficient();
159        } else {
160            r = (GenSolvablePolynomial<C>) r.abs();
161            q = (GenSolvablePolynomial<C>) q.abs();
162            C a = leftBaseContent(r);
163            C b = leftBaseContent(q);
164            r = divide(r, a); // indirection
165            q = divide(q, b); // indirection
166            c = gcd(a, b); // indirection
167        }
168        //System.out.println("baseCont: gcd(cont) = " + b);
169        if (r.isONE()) {
170            return r.multiply(c);
171        }
172        if (q.isONE()) {
173            return q.multiply(c);
174        }
175        GenSolvablePolynomial<C> x;
176        //System.out.println("baseGCD: q = " + q);
177        //System.out.println("baseGCD: r = " + r);
178        while (!r.isZERO()) {
179            x = FDUtil.<C> rightBaseSparsePseudoRemainder(q, r);
180            q = r;
181            if (field) {
182                r = x.monic();
183            } else {
184                r = x;
185            }
186            //System.out.println("baseGCD: q = " + q);
187            //System.out.println("baseGCD: r = " + r);
188        }
189        ///q = rightBasePrimitivePart(q);
190        q = leftBasePrimitivePart(q);
191        return (GenSolvablePolynomial<C>) (q.multiplyLeft(c)).abs();
192    }
193
194
195    /**
196     * Univariate GenSolvablePolynomial left recursive greatest common divisor.
197     * Uses pseudoRemainder for remainder.
198     * @param P univariate recursive GenSolvablePolynomial.
199     * @param S univariate recursive GenSolvablePolynomial.
200     * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where
201     *         deg_main(p) = deg_main(s) == 0.
202     */
203    @Override
204    public GenSolvablePolynomial<GenPolynomial<C>> leftRecursiveUnivariateGcd(
205                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
206        if (S == null || S.isZERO()) {
207            return P;
208        }
209        if (P == null || P.isZERO()) {
210            return S;
211        }
212        if (P.ring.nvar > 1) {
213            throw new IllegalArgumentException("no univariate polynomial");
214        }
215        boolean field = P.leadingBaseCoefficient().ring.coFac.isField();
216        long e = P.degree(0);
217        long f = S.degree(0);
218        GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs, qp, rp;
219        if (f > e) {
220            r = P;
221            q = S;
222            long g = f;
223            f = e;
224            e = g;
225        } else if (f < e) {
226            q = P;
227            r = S;
228        } else { // f == e
229            if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) {
230                q = P;
231                r = S;
232            } else {
233                r = P;
234                q = S;
235            }
236        }
237        logger.debug("degrees: e = {}, f = {}", e, f);
238        if (field) {
239            r = PolyUtil.<C> monic(r);
240            q = PolyUtil.<C> monic(q);
241        } else {
242            r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs();
243            q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs();
244        }
245        GenSolvablePolynomial<C> a = rightRecursiveContent(r);
246        ///rs = FDUtil.<C> recursiveDivideRightEval(r, a);  
247        rs = FDUtil.<C> recursiveLeftDivide(r, a); 
248        //rs = FDUtil.<C> recursiveRightDivide(r, a);
249        if (debug) {
250            logger.info("recCont a = {}, r = {}", a, r);
251            logger.info("recCont r/a = {}, r%a = {}", rs, r.subtract(rs.multiply(a)));
252            if (!r.equals(rs.multiply(a))) {
253                if (!rs.multiplyLeft(a).equals(r)) {
254                    System.out.println("recGcd, r         = " + r);
255                    System.out.println("recGcd, cont(r)   = " + a);
256                    System.out.println("recGcd, pp(r)     = " + rs);
257                    System.out.println("recGcd, pp(r)c(r) = " + rs.multiply(a));
258                    System.out.println("recGcd, c(r)pp(r) = " + rs.multiplyLeft(a));
259                    throw new RuntimeException("recGcd, pp: not divisible");
260                }
261            }
262        }
263        r = rs;
264        GenSolvablePolynomial<C> b = rightRecursiveContent(q);
265        ///qs = FDUtil.<C> recursiveDivideRightEval(q, b);  
266        qs = FDUtil.<C> recursiveLeftDivide(q, b); 
267        //qs = FDUtil.<C> recursiveRightDivide(q, b);
268        if (debug) {
269            logger.info("recCont b = {}, q = {}", b, q);
270            logger.info("recCont q/b = {}, q%b = {}", qs, q.subtract(qs.multiply(b)));
271            if (!q.equals(qs.multiply(b))) {
272                if (!qs.multiplyLeft(b).equals(q)) {
273                    System.out.println("recGcd, q         = " + q);
274                    System.out.println("recGcd, cont(q)   = " + b);
275                    System.out.println("recGcd, pp(q)     = " + qs);
276                    System.out.println("recGcd, pp(q)c(q) = " + qs.multiply(b));
277                    System.out.println("recGcd, c(q)pp(q) = " + qs.multiplyLeft(b));
278                    throw new RuntimeException("recGcd, pp: not divisible");
279                }
280            }
281        }
282        q = qs;
283        logger.info("Gcd(content).ring = {}, a = {}, b = {}", a.ring.toScript(), a, b);
284        //no: GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion
285        GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion
286        logger.info("Gcd(contents) c = {}, a = {}, b = {}", c, a, b);
287        if (r.isONE()) {
288            return r.multiply(c);
289        }
290        if (q.isONE()) {
291            return q.multiply(c);
292        }
293        if (debug) {
294            logger.info("r.ring = {}", r.ring.toScript());
295            logger.info("gcd-loop, start: q = {}, r = {}", q, r);
296        }
297        while (!r.isZERO()) {
298            x = FDUtil.<C> recursiveSparsePseudoRemainder(q, r);
299            q = r;
300            if (field) {
301                r = PolyUtil.<C> monic(x);
302            } else {
303                r = x;
304            }
305            if (debug) {
306                logger.info("gcd-loop, rem: q = {}, r = {}", q, r);
307            }
308        }
309        if (debug) {
310            logger.info("gcd(div) = {}, rs = {}, qs = {}", q, rs, qs);
311            rp = FDUtil.<C> recursiveSparsePseudoRemainder(rs, q);
312            qp = FDUtil.<C> recursiveSparsePseudoRemainder(qs, q);
313            if (!qp.isZERO() || !rp.isZERO()) {
314                logger.info("gcd(div): rem(r,g) = {}, rem(q,g) = {}", rp, qp);
315                rp = FDUtil.<C> recursivePseudoQuotient(rs, q);
316                qp = FDUtil.<C> recursivePseudoQuotient(qs, q);
317                logger.info("gcd(div): r/g = {}, q/g = {}", rp, qp);
318                throw new RuntimeException("recGcd, div: not divisible");
319            }
320        }
321        qp = q;
322        q = rightRecursivePrimitivePart(q);
323        if (!qp.equals(q)) {
324            logger.info("gcd(pp) = {}, qp = {}", q, qp);
325        }
326        q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiply(c).abs();
327        return q;
328    }
329
330
331    /**
332     * Univariate GenSolvablePolynomial right recursive greatest common divisor.
333     * Uses pseudoRemainder for remainder.
334     * @param P univariate recursive GenSolvablePolynomial.
335     * @param S univariate recursive GenSolvablePolynomial.
336     * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where
337     *         deg_main(p) = deg_main(s) == 0.
338     */
339    @Override
340    public GenSolvablePolynomial<GenPolynomial<C>> rightRecursiveUnivariateGcd(
341                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
342        if (S == null || S.isZERO()) {
343            return P;
344        }
345        if (P == null || P.isZERO()) {
346            return S;
347        }
348        if (P.ring.nvar > 1) {
349            throw new IllegalArgumentException("no univariate polynomial");
350        }
351        boolean field = P.leadingBaseCoefficient().ring.coFac.isField();
352        long e = P.degree(0);
353        long f = S.degree(0);
354        GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs, qp, rp;
355        if (f > e) {
356            r = P;
357            q = S;
358            long g = f;
359            f = e;
360            e = g;
361        } else if (f < e) {
362            q = P;
363            r = S;
364        } else { // f == e
365            if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) {
366                q = P;
367                r = S;
368            } else {
369                r = P;
370                q = S;
371            }
372        }
373        if (debug) {
374            logger.debug("RI-degrees: e = {}, f = {}", e, f);
375        }
376        if (field) {
377            r = PolyUtil.<C> monic(r);
378            q = PolyUtil.<C> monic(q);
379        } else {
380            r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs();
381            q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs();
382        }
383        GenSolvablePolynomial<C> a = leftRecursiveContent(r);
384        rs = FDUtil.<C> recursiveRightDivide(r, a);
385        //no: rs = FDUtil.<C> recursiveLeftDivide(r, a);
386        //no: rs = FDUtil.<C> recursiveRightPseudoQuotient(r, a);
387        if (debug) {
388            logger.info("RI-recCont a = {}, r = {}", a, r);
389            logger.info("RI-recCont r/a = {}, r%a = {}", r, r.subtract(rs.multiplyLeft(a)));
390            if (!r.equals(rs.multiplyLeft(a))) { // Left
391                System.out.println("RI-recGcd, r         = " + r);
392                System.out.println("RI-recGcd, cont(r)   = " + a);
393                System.out.println("RI-recGcd, pp(r)     = " + rs);
394                System.out.println("RI-recGcd, pp(r)c(r) = " + rs.multiply(a));
395                System.out.println("RI-recGcd, c(r)pp(r) = " + rs.multiplyLeft(a));
396                throw new RuntimeException("RI-recGcd, pp: not divisible");
397            }
398        }
399        r = rs;
400        GenSolvablePolynomial<C> b = leftRecursiveContent(q);
401        qs = FDUtil.<C> recursiveRightDivide(q, b);
402        if (debug) {
403            logger.info("RI-recCont b = {}, q = {}", b, q);
404            logger.info("RI-recCont q/b = {}, q%b = {}", qs, q.subtract(qs.multiplyLeft(b)));
405            if (!q.equals(qs.multiplyLeft(b))) { // Left
406                System.out.println("RI-recGcd, q         = " + q);
407                System.out.println("RI-recGcd, cont(q)   = " + b);
408                System.out.println("RI-recGcd, pp(q)     = " + qs);
409                System.out.println("RI-recGcd, pp(q)c(q) = " + qs.multiply(b));
410                System.out.println("RI-recGcd, c(q)pp(q) = " + qs.multiplyLeft(b));
411                throw new RuntimeException("RI-recGcd, pp: not divisible");
412            }
413        }
414        q = qs;
415        //no: GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion
416        GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion
417        logger.info("RI-Gcd(contents) c = {}, a = {}, b = {}", c, a, b);
418        if (r.isONE()) {
419            return r.multiplyLeft(c);
420        }
421        if (q.isONE()) {
422            return q.multiplyLeft(c);
423        }
424        if (debug) {
425            logger.info("RI-r.ring = {}", r.ring.toScript());
426            logger.info("RI-gcd-loop, start: q = {}, r = {}", q, r);
427        }
428        while (!r.isZERO()) {
429            x = FDUtil.<C> recursiveRightSparsePseudoRemainder(q, r);
430            q = r;
431            if (field) {
432                r = PolyUtil.<C> monic(x);
433            } else {
434                r = x;
435            }
436            if (debug) {
437                logger.info("RI-gcd-loop, rem: q = {}, r = {}", q, r);
438            }
439        }
440        if (debug) {
441            logger.info("RI-gcd(div) = {}, rs = {}, qs = {}", q, rs, qs);
442            rp = FDUtil.<C> recursiveRightSparsePseudoRemainder(rs, q);
443            qp = FDUtil.<C> recursiveRightSparsePseudoRemainder(qs, q);
444            if (!qp.isZERO() || !rp.isZERO()) {
445                logger.info("RI-gcd(div): rem(r,g) = {}, rem(q,g) = {}", rp, qp);
446                rp = FDUtil.<C> recursivePseudoQuotient(rs, q);
447                qp = FDUtil.<C> recursivePseudoQuotient(qs, q);
448                logger.info("RI-gcd(div): r/g = {}, q/g = {}", rp, qp);
449                //logger.info("gcd(div): rp*g = {},  qp*g = {}", rp.multiply(q), qp.multiply(q));
450                throw new RuntimeException("recGcd, div: not divisible");
451            }
452        }
453        qp = q;
454        logger.info("RI-recGcd(P,S) pre pp okay: qp = {}", qp);
455        //q = rightRecursivePrimitivePart(q);
456        q = leftRecursivePrimitivePart(q); // sic
457        if (!qp.equals(q)) {
458            logger.info("RI-gcd(pp) = {}, qp = {}", q, qp); // + ", ring = {}", P.ring.toScript());
459        }
460        q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiplyLeft(c).abs();
461        return q;
462    }
463
464}