001/*
002 * $Id: GreatestCommonDivisorSubres.java 5847 2018-06-24 13:46:53Z elbarbary $
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.log4j.Logger;
012
013import edu.jas.poly.GenPolynomial;
014import edu.jas.poly.GenPolynomialRing;
015import edu.jas.poly.PolyUtil;
016import edu.jas.structure.GcdRingElem;
017import edu.jas.structure.RingFactory;
018
019
020/**
021 * Greatest common divisor algorithms with subresultant polynomial remainder
022 * sequence.
023 * @author Heinz Kredel
024 * @author Youssef Elbarbary
025 */
026
027public class GreatestCommonDivisorSubres<C extends GcdRingElem<C>> extends GreatestCommonDivisorAbstract<C> {
028
029
030    private static final Logger logger = Logger.getLogger(GreatestCommonDivisorSubres.class);
031
032
033    private static final boolean debug = logger.isDebugEnabled();
034
035
036    /**
037     * GenPolynomial pseudo remainder. For univariate polynomials.
038     * @param P GenPolynomial.
039     * @param S nonzero GenPolynomial.
040     * @return remainder with ldcf(S)<sup>m</sup> P = quotient * S + remainder.
041     * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial).
042     * @deprecated Use
043     *             {@link edu.jas.poly.PolyUtil#baseDensePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)}
044     *             instead
045     */
046    @Deprecated
047    public GenPolynomial<C> basePseudoRemainder(GenPolynomial<C> P, GenPolynomial<C> S) {
048        return PolyUtil.<C> baseDensePseudoRemainder(P, S);
049    }
050
051
052    /**
053     * GenPolynomial pseudo remainder. For recursive polynomials.
054     * @param P recursive GenPolynomial.
055     * @param S nonzero recursive GenPolynomial.
056     * @return remainder with ldcf(S)<sup>m</sup> P = quotient * S + remainder.
057     * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial).
058     * @deprecated Use
059     *             {@link edu.jas.poly.PolyUtil#recursiveDensePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)}
060     *             instead
061     */
062    @Deprecated
063    public GenPolynomial<GenPolynomial<C>> recursivePseudoRemainder(GenPolynomial<GenPolynomial<C>> P,
064                    GenPolynomial<GenPolynomial<C>> S) {
065        return PolyUtil.<C> recursiveDensePseudoRemainder(P, S);
066    }
067
068
069    /**
070     * Univariate GenPolynomial greatest comon divisor. Uses pseudoRemainder for
071     * remainder.
072     * @param P univariate GenPolynomial.
073     * @param S univariate GenPolynomial.
074     * @return gcd(P,S).
075     */
076    @Override
077    public GenPolynomial<C> baseGcd(GenPolynomial<C> P, GenPolynomial<C> S) {
078        if (S == null || S.isZERO()) {
079            return P;
080        }
081        if (P == null || P.isZERO()) {
082            return S;
083        }
084        if (P.ring.nvar > 1) {
085            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
086        }
087        long e = P.degree(0);
088        long f = S.degree(0);
089        GenPolynomial<C> q;
090        GenPolynomial<C> r;
091        if (f > e) {
092            r = P;
093            q = S;
094            long g = f;
095            f = e;
096            e = g;
097        } else {
098            q = P;
099            r = S;
100        }
101        if (debug) {
102            logger.debug("degrees: e = " + e + ", f = " + f);
103        }
104        r = r.abs();
105        q = q.abs();
106        C a = baseContent(r);
107        C b = baseContent(q);
108        C c = gcd(a, b); // indirection
109        r = divide(r, a); // indirection
110        q = divide(q, b); // indirection
111        if (r.isONE()) {
112            return r.multiply(c);
113        }
114        if (q.isONE()) {
115            return q.multiply(c);
116        }
117        C g = r.ring.getONECoefficient();
118        C h = r.ring.getONECoefficient();
119        GenPolynomial<C> x;
120        C z;
121        while (!r.isZERO()) {
122            long delta = q.degree(0) - r.degree(0);
123            //System.out.println("delta    = " + delta);
124            x = PolyUtil.<C> baseDensePseudoRemainder(q, r);
125            q = r;
126            if (!x.isZERO()) {
127                z = g.multiply(h.power(delta)); //power(P.ring.coFac, h, delta));
128                //System.out.println("z  = " + z);
129                r = x.divide(z);
130                g = q.leadingBaseCoefficient();
131                z = g.power(delta); //power(P.ring.coFac, g, delta);
132                h = z.divide(h.power(delta - 1)); //power(P.ring.coFac, h, delta - 1));
133                //System.out.println("g  = " + g);
134                //System.out.println("h  = " + h);
135            } else {
136                r = x;
137            }
138        }
139        q = basePrimitivePart(q);
140        return (q.multiply(c)).abs();
141    }
142
143
144    /**
145     * Univariate GenPolynomial recursive greatest comon divisor. Uses
146     * pseudoRemainder for remainder.
147     * @param P univariate recursive GenPolynomial.
148     * @param S univariate recursive GenPolynomial.
149     * @return gcd(P,S).
150     */
151    @Override
152    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateGcd(GenPolynomial<GenPolynomial<C>> P,
153                    GenPolynomial<GenPolynomial<C>> S) {
154        if (S == null || S.isZERO()) {
155            return P;
156        }
157        if (P == null || P.isZERO()) {
158            return S;
159        }
160        if (P.ring.nvar > 1) {
161            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
162        }
163        long e = P.degree(0);
164        long f = S.degree(0);
165        GenPolynomial<GenPolynomial<C>> q;
166        GenPolynomial<GenPolynomial<C>> r;
167        if (f > e) {
168            r = P;
169            q = S;
170            long g = f;
171            f = e;
172            e = g;
173        } else {
174            q = P;
175            r = S;
176        }
177        if (debug) {
178            logger.debug("degrees: e = " + e + ", f = " + f);
179        }
180        r = r.abs();
181        q = q.abs();
182        GenPolynomial<C> a = recursiveContent(r);
183        GenPolynomial<C> b = recursiveContent(q);
184
185        GenPolynomial<C> c = gcd(a, b); // go to recursion
186        //System.out.println("rgcd c = " + c);
187        r = PolyUtil.<C> recursiveDivide(r, a);
188        q = PolyUtil.<C> recursiveDivide(q, b);
189        if (r.isONE()) {
190            return r.multiply(c);
191        }
192        if (q.isONE()) {
193            return q.multiply(c);
194        }
195        GenPolynomial<C> g = r.ring.getONECoefficient();
196        GenPolynomial<C> h = r.ring.getONECoefficient();
197        GenPolynomial<GenPolynomial<C>> x;
198        GenPolynomial<C> z = null;
199        while (!r.isZERO()) {
200            long delta = q.degree(0) - r.degree(0);
201            //System.out.println("rgcd delta = " + delta);
202            x = PolyUtil.<C> recursiveDensePseudoRemainder(q, r);
203            if (logger.isDebugEnabled()) {
204                logger.info("recursiveDensePseudoRemainder.bits = " + x.bitLength());
205            }
206            q = r;
207            if (!x.isZERO()) {
208                z = g.multiply(h.power(delta)); //power(P.ring.coFac, h, delta));
209                r = PolyUtil.<C> recursiveDivide(x, z);
210                g = q.leadingBaseCoefficient();
211                z = g.power(delta); //power(P.ring.coFac, g, delta);
212                h = PolyUtil.<C> basePseudoDivide(z, h.power(delta - 1)); // power(P.ring.coFac, h, delta - 1)
213            } else {
214                r = x;
215            }
216        }
217        q = recursivePrimitivePart(q);
218        return q.abs().multiply(c); //.abs();
219    }
220
221
222    /**
223     * Univariate GenPolynomial resultant. Uses pseudoRemainder for remainder.
224     * @param P univariate GenPolynomial.
225     * @param S univariate GenPolynomial.
226     * @return res(P,S).
227     */
228    @Override
229    public GenPolynomial<C> baseResultant(GenPolynomial<C> P, GenPolynomial<C> S) {
230        if (S == null || S.isZERO()) {
231            return S;
232        }
233        if (P == null || P.isZERO()) {
234            return P;
235        }
236        if (P.ring.nvar > 1) {
237            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
238        }
239        long e = P.degree(0);
240        long f = S.degree(0);
241        GenPolynomial<C> q;
242        GenPolynomial<C> r;
243        if (f > e) {
244            r = P;
245            q = S;
246            long g = f;
247            f = e;
248            e = g;
249        } else {
250            q = P;
251            r = S;
252        }
253        //r = r.abs();
254        //q = q.abs();
255        C a = baseContent(r);
256        C b = baseContent(q);
257        r = divide(r, a); // indirection
258        q = divide(q, b); // indirection
259        RingFactory<C> cofac = P.ring.coFac;
260        C g = cofac.getONE();
261        C h = cofac.getONE();
262        C t = a.power(e); //power(cofac, a, e);
263        t = t.multiply(b.power(f)); //power(cofac, b, f));
264        long s = 1;
265        GenPolynomial<C> x;
266        C z;
267        while (r.degree(0) > 0) {
268            long delta = q.degree(0) - r.degree(0);
269            //System.out.println("delta    = " + delta);
270            if ((q.degree(0) % 2 != 0) && (r.degree(0) % 2 != 0)) {
271                s = -s;
272            }
273            x = PolyUtil.<C> baseDensePseudoRemainder(q, r);
274            //System.out.println("x  = " + x);
275            q = r;
276            if (x.degree(0) > 0) {
277                z = g.multiply(h.power(delta)); //power(cofac, h, delta));
278                //System.out.println("z  = " + z);
279                r = x.divide(z);
280                g = q.leadingBaseCoefficient();
281                z = g.power(delta); //power(cofac, g, delta);
282                h = z.divide(h.power(delta - 1));
283            } else {
284                r = x;
285            }
286        }
287        z = r.leadingBaseCoefficient().power(q.degree(0)); //power(cofac, r.leadingBaseCoefficient(), q.degree(0));
288        h = z.divide(h.power(q.degree() - 1)); //power(cofac, h, q.degree(0) - 1));
289        z = h.multiply(t);
290        if (s < 0) {
291            z = z.negate();
292        }
293        x = P.ring.getONE().multiply(z);
294        return x;
295    }
296
297
298    /**
299     * Univariate GenPolynomial recursive resultant. Uses pseudoRemainder for
300     * remainder.
301     * @param P univariate recursive GenPolynomial.
302     * @param S univariate recursive GenPolynomial.
303     * @return res(P,S).
304     */
305    @Override
306    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<C>> P,
307                    GenPolynomial<GenPolynomial<C>> S) {
308        if (S == null || S.isZERO()) {
309            return S;
310        }
311        if (P == null || P.isZERO()) {
312            return P;
313        }
314        if (P.ring.nvar > 1) {
315            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
316        }
317        long e = P.degree(0);
318        long f = S.degree(0);
319        GenPolynomial<GenPolynomial<C>> q;
320        GenPolynomial<GenPolynomial<C>> r;
321        if (f > e) {
322            r = P;
323            q = S;
324            long g = f;
325            f = e;
326            e = g;
327        } else {
328            q = P;
329            r = S;
330        }
331        r = r.abs();
332        q = q.abs();
333        GenPolynomial<C> a = recursiveContent(r);
334        GenPolynomial<C> b = recursiveContent(q);
335        r = PolyUtil.<C> recursiveDivide(r, a);
336        q = PolyUtil.<C> recursiveDivide(q, b);
337        RingFactory<GenPolynomial<C>> cofac = P.ring.coFac;
338        GenPolynomial<C> g = cofac.getONE();
339        GenPolynomial<C> h = cofac.getONE();
340        GenPolynomial<GenPolynomial<C>> x;
341        GenPolynomial<C> t;
342        if (f == 0 && e == 0 && g.ring.nvar > 0) {
343            // if coeffs are multivariate (and non constant)
344            // otherwise it would be 1
345            t = resultant(a, b);
346            x = P.ring.getONE().multiply(t);
347            return x;
348        }
349        t = a.power(e); //power(cofac, a, e);
350        t = t.multiply(b.power(f)); //power(cofac, b, f));
351        long s = 1;
352        GenPolynomial<C> z;
353        while (r.degree(0) > 0) {
354            long delta = q.degree(0) - r.degree(0);
355            //System.out.println("delta    = " + delta);
356            if ((q.degree(0) % 2 != 0) && (r.degree(0) % 2 != 0)) {
357                s = -s;
358            }
359            x = PolyUtil.<C> recursiveDensePseudoRemainder(q, r);
360            //System.out.println("x  = " + x);
361            q = r;
362            if (x.degree(0) > 0) {
363                z = g.multiply(h.power(delta)); //power(P.ring.coFac, h, delta));
364                r = PolyUtil.<C> recursiveDivide(x, z);
365                g = q.leadingBaseCoefficient();
366                z = g.power(delta); //power(cofac, g, delta);
367                h = PolyUtil.<C> basePseudoDivide(z, h.power(delta - 1)); //power(cofac, h, delta - 1));
368            } else {
369                r = x;
370            }
371        }
372        z = r.leadingBaseCoefficient().power(q.degree(0)); //power(cofac, r.leadingBaseCoefficient(), q.degree(0));
373        h = PolyUtil.<C> basePseudoDivide(z, h.power(q.degree() - 1)); //power(cofac, h, q.degree(0) - 1));
374        z = h.multiply(t);
375        if (s < 0) {
376            z = z.negate();
377        }
378        x = P.ring.getONE().multiply(z);
379        return x;
380    }
381
382
383    /**
384     * Univariate GenPolynomial recursive Subresultant list. Uses
385     * pseudoRemainder for remainder.
386     * @param P univariate recursive GenPolynomial.
387     * @param S univariate recursive GenPolynomial.
388     * @return subResList(P,S).
389     * @author Youssef Elbarbary
390     */
391    public List<GenPolynomial<GenPolynomial<C>>> recursiveUnivariateSubResultantList(
392                    GenPolynomial<GenPolynomial<C>> P, GenPolynomial<GenPolynomial<C>> S) {
393        List<GenPolynomial<GenPolynomial<C>>> myList = new ArrayList<GenPolynomial<GenPolynomial<C>>>();
394        if (S == null || S.isZERO()) {
395            myList.add(S);
396            return myList;
397        }
398        if (P == null || P.isZERO()) {
399            myList.add(P);
400            return myList;
401        }
402        if (P.ring.nvar > 1) {
403            throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial");
404        }
405        long e = P.degree(0);
406        long f = S.degree(0);
407        GenPolynomial<GenPolynomial<C>> q;
408        GenPolynomial<GenPolynomial<C>> r;
409        if (f > e) {
410            r = P;
411            q = S;
412            long g = f;
413            f = e;
414            e = g;
415        } else {
416            q = P;
417            r = S;
418        }
419        r = r.abs();
420        q = q.abs();
421        GenPolynomial<C> a = recursiveContent(r);
422        GenPolynomial<C> b = recursiveContent(q);
423        r = PolyUtil.<C> recursiveDivide(r, a);
424        q = PolyUtil.<C> recursiveDivide(q, b);
425        RingFactory<GenPolynomial<C>> cofac = P.ring.coFac;
426        GenPolynomial<C> g = cofac.getONE();
427        GenPolynomial<C> h = cofac.getONE();
428        GenPolynomial<GenPolynomial<C>> x;
429        GenPolynomial<C> t;
430        if (f == 0 && e == 0 && g.ring.nvar > 0) {
431            // if coeffs are multivariate (and non constant)
432            // otherwise it would be 1
433            t = resultant(a, b);
434            x = P.ring.getONE().multiply(t);
435            myList.add(x);
436            return myList;
437        }
438        t = a.power(e); // power(cofac, a, e);
439        t = t.multiply(b.power(f)); // power(cofac, b, f));
440        long s = 1;
441        GenPolynomial<C> z;
442        myList.add(P); // adding R0
443        myList.add(S); // adding R1
444        while (r.degree(0) > 0) {
445            long delta = q.degree(0) - r.degree(0);
446            if ((q.degree(0) % 2 != 0) && (r.degree(0) % 2 != 0)) {
447                s = -s;
448            }
449            x = PolyUtil.<C> recursiveDensePseudoRemainder(q, r);
450            q = r;
451            if (x.degree(0) >= 0) { // fixed: this was changed from > to >=
452                z = g.multiply(h.power(delta)); // power(P.ring.coFac, h, delta));
453                r = PolyUtil.<C> recursiveDivide(x, z);
454                myList.add(r);
455                g = q.leadingBaseCoefficient();
456                z = g.power(delta); // power(cofac, g, delta);
457                h = PolyUtil.<C> basePseudoDivide(z, h.power(delta - 1)); // power(cofac, h, delta - 1));
458            } else {
459                r = x;
460                myList.add(r);
461            }
462        }
463        z = r.leadingBaseCoefficient().power(q.degree(0)); // power(cofac, r.leadingBaseCoefficient(), q.degree(0));
464        h = PolyUtil.<C> basePseudoDivide(z, h.power(q.degree() - 1)); // power(cofac, h, q.degree(0) - 1));
465        z = h.multiply(t);
466        if (s < 0) {
467            z = z.negate();
468        }
469        x = P.ring.getONE().multiply(z);
470        myList.add(x);
471        // Printing the Subresultant List
472        //System.out.println("Liste von den SubResultanten(A - tD'):");
473        //for (int i = 0; i < myList.size(); i++) { // just for printing the list
474        //    System.out.println(myList.get(i));
475        //}
476        if (logger.isInfoEnabled()) {
477            System.out.println("subResCoeffs: " + myList);
478            //logger.info("subResCoeffs: " + myList);
479        }
480        return myList;
481    }
482
483
484    /**
485     * GenPolynomial base coefficient discriminant.
486     * @param P GenPolynomial.
487     * @return discriminant(P).
488     */
489    public GenPolynomial<C> baseDiscriminant(GenPolynomial<C> P) {
490        if (P == null) {
491            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
492        }
493        if (P.isZERO()) {
494            return P;
495        }
496        GenPolynomialRing<C> pfac = P.ring;
497        if (pfac.nvar > 1) {
498            throw new IllegalArgumentException(this.getClass().getName() + " P not univariate");
499        }
500        C a = P.leadingBaseCoefficient();
501        a = a.inverse();
502        GenPolynomial<C> Pp = PolyUtil.<C> baseDeriviative(P);
503        GenPolynomial<C> res = baseResultant(P, Pp);
504        GenPolynomial<C> disc = res.multiply(a);
505        long n = P.degree(0);
506        n = n * (n - 1);
507        n = n / 2;
508        if (n % 2L != 0L) {
509            disc = disc.negate();
510        }
511        return disc;
512    }
513
514}