001/*
002 * $Id: GreatestCommonDivisorPrimitive.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 primitive polynomial remainder sequence.
020 * @param <C> coefficient type
021 * @author Heinz Kredel
022 */
023
024public class GreatestCommonDivisorPrimitive<C extends GcdRingElem<C>> extends
025                GreatestCommonDivisorAbstract<C> {
026
027
028    private static final Logger logger = Logger.getLogger(GreatestCommonDivisorPrimitive.class);
029
030
031    private static final boolean debug = logger.isDebugEnabled();
032
033
034    /**
035     * Constructor.
036     * @param cf coefficient ring.
037     */
038    public GreatestCommonDivisorPrimitive(RingFactory<C> cf) {
039        super(cf);
040    }
041
042
043    /**
044     * Univariate GenSolvablePolynomial greatest common divisor. Uses
045     * pseudoRemainder for remainder.
046     * @param P univariate GenSolvablePolynomial.
047     * @param S univariate GenSolvablePolynomial.
048     * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S).
049     */
050    @Override
051    public GenSolvablePolynomial<C> leftBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
052        if (S == null || S.isZERO()) {
053            return P;
054        }
055        if (P == null || P.isZERO()) {
056            return S;
057        }
058        if (P.ring.nvar > 1) {
059            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
060        }
061        boolean field = P.ring.coFac.isField();
062        long e = P.degree(0);
063        long f = S.degree(0);
064        GenSolvablePolynomial<C> q;
065        GenSolvablePolynomial<C> r;
066        if (f > e) {
067            r = P;
068            q = S;
069            long g = f;
070            f = e;
071            e = g;
072        } else {
073            q = P;
074            r = S;
075        }
076        if (debug) {
077            logger.debug("degrees: e = " + e + ", f = " + f);
078        }
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 = leftBasePrimitivePart(x);
110            }
111            //System.out.println("baseGCD: q = " + q);
112            //System.out.println("baseGCD: r = " + r);
113        }
114        return (GenSolvablePolynomial<C>) (q.multiply(c)).abs();
115    }
116
117
118    /**
119     * Univariate GenSolvablePolynomial right greatest common divisor. Uses
120     * pseudoRemainder for remainder.
121     * @param P univariate GenSolvablePolynomial.
122     * @param S univariate GenSolvablePolynomial.
123     * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'.
124     */
125    @Override
126    public GenSolvablePolynomial<C> rightBaseGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
127        if (S == null || S.isZERO()) {
128            return P;
129        }
130        if (P == null || P.isZERO()) {
131            return S;
132        }
133        if (P.ring.nvar > 1) {
134            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
135        }
136        boolean field = P.ring.coFac.isField();
137        long e = P.degree(0);
138        long f = S.degree(0);
139        GenSolvablePolynomial<C> q;
140        GenSolvablePolynomial<C> r;
141        if (f > e) {
142            r = P;
143            q = S;
144            long g = f;
145            f = e;
146            e = g;
147        } else {
148            q = P;
149            r = S;
150        }
151        if (debug) {
152            logger.debug("degrees: e = " + e + ", f = " + f);
153        }
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 = rightBasePrimitivePart(x);
185            }
186            //System.out.println("baseGCD: q = " + q);
187            //System.out.println("baseGCD: r = " + r);
188        }
189        return (GenSolvablePolynomial<C>) (q.multiplyLeft(c)).abs();
190    }
191
192
193    /**
194     * Univariate GenSolvablePolynomial left recursive greatest common divisor.
195     * Uses pseudoRemainder for remainder.
196     * @param P univariate recursive GenSolvablePolynomial.
197     * @param S univariate recursive GenSolvablePolynomial.
198     * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where
199     *         deg_main(p) = deg_main(s) == 0.
200     */
201    @Override
202    public GenSolvablePolynomial<GenPolynomial<C>> leftRecursiveUnivariateGcd(
203                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
204        if (S == null || S.isZERO()) {
205            return P;
206        }
207        if (P == null || P.isZERO()) {
208            return S;
209        }
210        if (P.ring.nvar > 1) {
211            throw new IllegalArgumentException("no univariate polynomial");
212        }
213        boolean field = P.leadingBaseCoefficient().ring.coFac.isField();
214        long e = P.degree(0);
215        long f = S.degree(0);
216        GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs;
217        if (f > e) {
218            r = P;
219            q = S;
220            long g = f;
221            f = e;
222            e = g;
223        } else if (f < e) {
224            q = P;
225            r = S;
226        } else { // f == e
227            if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) {
228                q = P;
229                r = S;
230            } else {
231                r = P;
232                q = S;
233            }
234        }
235        if (debug) {
236            logger.debug("degrees: e = " + e + ", f = " + f);
237        }
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> recursiveLeftDivide(r, a);
247        if (debug) {
248            logger.info("recCont a = " + a + ", r = " + r);
249            logger.info("recCont r/a = " + rs + ", r%a = " + r.subtract(rs.multiply(a)));
250            if (!r.equals(rs.multiply(a))) {
251                System.out.println("recGcd, r         = " + r);
252                System.out.println("recGcd, cont(r)   = " + a);
253                System.out.println("recGcd, pp(r)     = " + rs);
254                System.out.println("recGcd, pp(r)c(r) = " + rs.multiply(a));
255                System.out.println("recGcd, c(r)pp(r) = " + rs.multiplyLeft(a));
256                throw new RuntimeException("recGcd, pp: not divisible");
257            }
258        }
259        r = rs;
260        GenSolvablePolynomial<C> b = rightRecursiveContent(q);
261        qs = FDUtil.<C> recursiveLeftDivide(q, b);
262        if (debug) {
263            logger.info("recCont b = " + b + ", q = " + q);
264            logger.info("recCont q/b = " + qs + ", q%b = " + q.subtract(qs.multiply(b)));
265            if (!q.equals(qs.multiply(b))) {
266                System.out.println("recGcd, q         = " + q);
267                System.out.println("recGcd, cont(q)   = " + b);
268                System.out.println("recGcd, pp(q)     = " + qs);
269                System.out.println("recGcd, pp(q)c(q) = " + qs.multiply(b));
270                System.out.println("recGcd, c(q)pp(q) = " + qs.multiplyLeft(b));
271                throw new RuntimeException("recGcd, pp: not divisible");
272            }
273        }
274        q = qs;
275        //no: GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion
276        GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion
277        logger.info("Gcd(contents) c = " + c + ", a = " + a + ", b = " + b);
278        if (r.isONE()) {
279            return r.multiply(c);
280        }
281        if (q.isONE()) {
282            return q.multiply(c);
283        }
284        if (debug) {
285            logger.info("r.ring = " + r.ring.toScript());
286        }
287        while (!r.isZERO()) {
288            x = FDUtil.<C> recursiveSparsePseudoRemainder(q, r);
289            q = r;
290            r = rightRecursivePrimitivePart(x);
291            if (field) {
292                r = PolyUtil.<C> monic(r);
293            }
294        }
295        if (debug) {
296            logger.info("gcd(pp) = " + q + ", ring = " + P.ring.toScript());
297        }
298        q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiply(c).abs();
299        return q;
300    }
301
302
303    /**
304     * Univariate GenSolvablePolynomial right recursive greatest common divisor.
305     * Uses pseudoRemainder for remainder.
306     * @param P univariate recursive GenSolvablePolynomial.
307     * @param S univariate recursive GenSolvablePolynomial.
308     * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where
309     *         deg_main(p) = deg_main(s) == 0.
310     */
311    @Override
312    public GenSolvablePolynomial<GenPolynomial<C>> rightRecursiveUnivariateGcd(
313                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
314        if (S == null || S.isZERO()) {
315            return P;
316        }
317        if (P == null || P.isZERO()) {
318            return S;
319        }
320        if (P.ring.nvar > 1) {
321            throw new IllegalArgumentException("no univariate polynomial");
322        }
323        boolean field = P.leadingBaseCoefficient().ring.coFac.isField();
324        long e = P.degree(0);
325        long f = S.degree(0);
326        GenSolvablePolynomial<GenPolynomial<C>> q, r, x, qs, rs;
327        if (f > e) {
328            r = P;
329            q = S;
330            long g = f;
331            f = e;
332            e = g;
333        } else if (f < e) {
334            q = P;
335            r = S;
336        } else { // f == e
337            if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) {
338                q = P;
339                r = S;
340            } else {
341                r = P;
342                q = S;
343            }
344        }
345        if (debug) {
346            logger.debug("RI-degrees: e = " + e + ", f = " + f);
347        }
348        if (field) {
349            r = PolyUtil.<C> monic(r);
350            q = PolyUtil.<C> monic(q);
351        } else {
352            r = (GenSolvablePolynomial<GenPolynomial<C>>) r.abs();
353            q = (GenSolvablePolynomial<GenPolynomial<C>>) q.abs();
354        }
355        GenSolvablePolynomial<C> a = leftRecursiveContent(r);
356        rs = FDUtil.<C> recursiveRightDivide(r, a);
357        if (debug) {
358            logger.info("RI-recCont a = " + a + ", r = " + r);
359            logger.info("RI-recCont r/a = " + r + ", r%a = " + r.subtract(rs.multiplyLeft(a)));
360            if (!r.equals(rs.multiplyLeft(a))) {
361                System.out.println("RI-recGcd, r         = " + r);
362                System.out.println("RI-recGcd, cont(r)   = " + a);
363                System.out.println("RI-recGcd, pp(r)     = " + rs);
364                System.out.println("RI-recGcd, c(r)pp(r) = " + rs.multiplyLeft(a));
365                throw new RuntimeException("RI-recGcd, pp: not divisible");
366            }
367        }
368        r = rs;
369        GenSolvablePolynomial<C> b = leftRecursiveContent(q);
370        qs = FDUtil.<C> recursiveRightDivide(q, b);
371        if (debug) {
372            logger.info("RI-recCont b = " + b + ", q = " + q);
373            logger.info("RI-recCont q/b = " + qs + ", q%b = " + q.subtract(qs.multiplyLeft(b)));
374            if (!q.equals(qs.multiplyLeft(b))) {
375                System.out.println("RI-recGcd, q         = " + q);
376                System.out.println("RI-recGcd, cont(q)   = " + b);
377                System.out.println("RI-recGcd, pp(q)     = " + qs);
378                System.out.println("RI-recGcd, c(q)pp(q) = " + qs.multiplyLeft(b));
379                throw new RuntimeException("RI-recGcd, pp: not divisible");
380            }
381        }
382        q = qs;
383        //no: GenSolvablePolynomial<C> c = rightGcd(a, b); // go to recursion
384        GenSolvablePolynomial<C> c = leftGcd(a, b); // go to recursion
385        logger.info("RI-Gcd(contents) c = " + c + ", a = " + a + ", b = " + b);
386        if (r.isONE()) {
387            return r.multiplyLeft(c);
388        }
389        if (q.isONE()) {
390            return q.multiplyLeft(c);
391        }
392        if (debug) {
393            logger.info("RI-r.ring = " + r.ring.toScript());
394        }
395        while (!r.isZERO()) {
396            x = FDUtil.<C> recursiveRightSparsePseudoRemainder(q, r);
397            q = r;
398            r = leftRecursivePrimitivePart(x);
399            if (field) {
400                r = PolyUtil.<C> monic(r);
401            }
402        }
403        if (debug) {
404            logger.info("RI-gcd(pp) = " + q + ", ring = " + P.ring.toScript());
405        }
406        q = (GenSolvablePolynomial<GenPolynomial<C>>) q.multiplyLeft(c).abs();
407        return q;
408    }
409
410}