001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import org.apache.logging.log4j.LogManager;
009import org.apache.logging.log4j.Logger;
010
011import edu.jas.poly.GenPolynomial;
012import edu.jas.poly.PolyUtil;
013import edu.jas.structure.GcdRingElem;
014
015
016/**
017 * Greatest common divisor algorithms with primitive polynomial remainder
018 * sequence.
019 * @author Heinz Kredel
020 */
021
022public class GreatestCommonDivisorPrimitive<C extends GcdRingElem<C>>
023                extends GreatestCommonDivisorAbstract<C> {
024
025
026    private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorPrimitive.class);
027
028
029    private static final boolean debug = logger.isDebugEnabled();
030
031
032    /**
033     * Univariate GenPolynomial greatest common divisor. Uses pseudoRemainder for
034     * remainder.
035     * @param P univariate GenPolynomial.
036     * @param S univariate GenPolynomial.
037     * @return gcd(P,S).
038     */
039    @Override
040    public GenPolynomial<C> baseGcd(GenPolynomial<C> P, GenPolynomial<C> S) {
041        if (S == null || S.isZERO()) {
042            return P;
043        }
044        if (P == null || P.isZERO()) {
045            return S;
046        }
047        if (P.ring.nvar > 1) {
048            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
049        }
050        long e = P.degree(0);
051        long f = S.degree(0);
052        GenPolynomial<C> q;
053        GenPolynomial<C> r;
054        if (f > e) {
055            r = P;
056            q = S;
057            long g = f;
058            f = e;
059            e = g;
060        } else {
061            q = P;
062            r = S;
063        }
064        if (debug) {
065            logger.debug("degrees: e = {}, f = {}", e, f);
066        }
067        r = r.abs();
068        q = q.abs();
069        C a = baseContent(r);
070        C b = baseContent(q);
071        C c = gcd(a, b); // indirection
072        r = divide(r, a); // indirection
073        q = divide(q, b); // indirection
074        if (r.isONE()) {
075            return r.multiply(c);
076        }
077        if (q.isONE()) {
078            return q.multiply(c);
079        }
080        GenPolynomial<C> x;
081        while (!r.isZERO()) {
082            x = PolyUtil.<C> baseSparsePseudoRemainder(q, r);
083            q = r;
084            r = basePrimitivePart(x);
085        }
086        return (q.multiply(c)).abs();
087    }
088
089
090    /**
091     * Univariate GenPolynomial recursive greatest common divisor. Uses
092     * pseudoRemainder for remainder.
093     * @param P univariate recursive GenPolynomial.
094     * @param S univariate recursive GenPolynomial.
095     * @return gcd(P,S).
096     */
097    @Override
098    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateGcd(GenPolynomial<GenPolynomial<C>> P,
099                    GenPolynomial<GenPolynomial<C>> S) {
100        if (S == null || S.isZERO()) {
101            return P;
102        }
103        if (P == null || P.isZERO()) {
104            return S;
105        }
106        if (P.ring.nvar > 1) {
107            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
108        }
109        long e = P.degree(0);
110        long f = S.degree(0);
111        GenPolynomial<GenPolynomial<C>> q;
112        GenPolynomial<GenPolynomial<C>> r;
113        if (f > e) {
114            r = P;
115            q = S;
116            long g = f;
117            f = e;
118            e = g;
119        } else {
120            q = P;
121            r = S;
122        }
123        if (debug) {
124            logger.debug("degrees: e = {}, f = {}", e, f);
125        }
126        r = r.abs();
127        q = q.abs();
128        GenPolynomial<C> a = recursiveContent(r);
129        GenPolynomial<C> b = recursiveContent(q);
130
131        GenPolynomial<C> c = gcd(a, b); // go to recursion
132        //System.out.println("rgcd c = " + c);
133        r = PolyUtil.<C> recursiveDivide(r, a);
134        q = PolyUtil.<C> recursiveDivide(q, b);
135        if (r.isONE()) {
136            return r.multiply(c);
137        }
138        if (q.isONE()) {
139            return q.multiply(c);
140        }
141        GenPolynomial<GenPolynomial<C>> x;
142        while (!r.isZERO()) {
143            x = PolyUtil.<C> recursiveSparsePseudoRemainder(q, r);
144            if (logger.isDebugEnabled()) {
145                logger.info("recursiveSparsePseudoRemainder.bits = {}", x.bitLength());
146            }
147            q = r;
148            r = recursivePrimitivePart(x);
149        }
150        return q.abs().multiply(c); //.abs();
151    }
152
153}