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