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