001/*
002 * $Id$
003 */
004
005package edu.jas.ufd;
006
007
008import java.util.ArrayList;
009import java.util.List;
010
011import org.apache.logging.log4j.Logger;
012import org.apache.logging.log4j.LogManager; 
013
014import edu.jas.poly.GenPolynomial;
015import edu.jas.poly.GenPolynomialRing;
016import edu.jas.poly.PolyUtil;
017import edu.jas.structure.GcdRingElem;
018import edu.jas.structure.RingFactory;
019
020
021/**
022 * Greatest common divisor algorithms.
023 * @author Heinz Kredel
024 */
025
026public abstract class GreatestCommonDivisorAbstract<C extends GcdRingElem<C>>
027                implements GreatestCommonDivisor<C> {
028
029
030    private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorAbstract.class);
031
032
033    private static final boolean debug = logger.isDebugEnabled();
034
035
036    /**
037     * Get the String representation.
038     * @see java.lang.Object#toString()
039     */
040    @Override
041    public String toString() {
042        return getClass().getName();
043    }
044
045
046    /**
047     * GenPolynomial base coefficient content.
048     * @param P GenPolynomial.
049     * @return cont(P).
050     */
051    public C baseContent(GenPolynomial<C> P) {
052        if (P == null) {
053            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
054        }
055        if (P.isZERO()) {
056            return P.ring.getZEROCoefficient();
057        }
058        C d = null;
059        for (C c : P.getMap().values()) {
060            if (d == null) {
061                d = c;
062            } else {
063                d = d.gcd(c);
064            }
065            if (d.isONE()) {
066                return d;
067            }
068        }
069        if (d.signum() < 0) {
070            d = d.negate();
071        }
072        return d;
073    }
074
075
076    /**
077     * GenPolynomial base coefficient primitive part.
078     * @param P GenPolynomial.
079     * @return pp(P).
080     */
081    public GenPolynomial<C> basePrimitivePart(GenPolynomial<C> P) {
082        if (P == null) {
083            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
084        }
085        if (P.isZERO()) {
086            return P;
087        }
088        C d = baseContent(P);
089        if (d.isONE()) {
090            return P;
091        }
092        GenPolynomial<C> pp = P.divide(d);
093        if (debug) {
094            GenPolynomial<C> p = pp.multiply(d);
095            if (!p.equals(P)) {
096                throw new ArithmeticException("pp(p)*cont(p) != p: ");
097            }
098        }
099        return pp;
100    }
101
102
103    /**
104     * List of GenPolynomial base coefficient primitive part.
105     * @param F list of GenPolynomials.
106     * @return pp(F).
107     */
108    public List<GenPolynomial<C>> basePrimitivePart(List<GenPolynomial<C>> F) {
109        if (F == null || F.isEmpty()) {
110            return F;
111        }
112        List<GenPolynomial<C>> Pp = new ArrayList<GenPolynomial<C>>(F.size());
113        for (GenPolynomial<C> f : F) {
114            GenPolynomial<C> p = basePrimitivePart(f);
115            Pp.add(p);
116        }
117        return Pp;
118    }
119
120
121    /**
122     * Univariate GenPolynomial greatest common divisor. Uses sparse
123     * pseudoRemainder for remainder.
124     * @param P univariate GenPolynomial.
125     * @param S univariate GenPolynomial.
126     * @return gcd(P,S).
127     */
128    public abstract GenPolynomial<C> baseGcd(GenPolynomial<C> P, GenPolynomial<C> S);
129
130
131    /**
132     * GenPolynomial recursive content.
133     * @param P recursive GenPolynomial.
134     * @return cont(P).
135     */
136    public GenPolynomial<C> recursiveContent(GenPolynomial<GenPolynomial<C>> P) {
137        if (P == null) {
138            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
139        }
140        if (P.isZERO()) {
141            return P.ring.getZEROCoefficient();
142        }
143        GenPolynomial<C> d = null;
144        for (GenPolynomial<C> c : P.getMap().values()) {
145            if (d == null) {
146                d = c;
147            } else {
148                d = gcd(d, c); // go to recursion
149            }
150            if (d.isONE()) {
151                return d;
152            }
153        }
154        return d.abs();
155    }
156
157
158    /**
159     * GenPolynomial recursive primitive part.
160     * @param P recursive GenPolynomial.
161     * @return pp(P).
162     */
163    public GenPolynomial<GenPolynomial<C>> recursivePrimitivePart(GenPolynomial<GenPolynomial<C>> P) {
164        if (P == null) {
165            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
166        }
167        if (P.isZERO()) {
168            return P;
169        }
170        GenPolynomial<C> d = recursiveContent(P);
171        if (d.isONE()) {
172            return P;
173        }
174        GenPolynomial<GenPolynomial<C>> pp = PolyUtil.<C> recursiveDivide(P, d);
175        return pp;
176    }
177
178
179    /**
180     * List of recursive GenPolynomial base coefficient primitive part.
181     * @param F list of recursive GenPolynomials.
182     * @return pp(F).
183     */
184    public List<GenPolynomial<GenPolynomial<C>>> recursivePrimitivePart(
185                    List<GenPolynomial<GenPolynomial<C>>> F) {
186        if (F == null || F.isEmpty()) {
187            return F;
188        }
189        List<GenPolynomial<GenPolynomial<C>>> Pp = new ArrayList<GenPolynomial<GenPolynomial<C>>>(F.size());
190        for (GenPolynomial<GenPolynomial<C>> f : F) {
191            GenPolynomial<GenPolynomial<C>> p = recursivePrimitivePart(f);
192            Pp.add(p);
193        }
194        return Pp;
195    }
196
197
198    /**
199     * GenPolynomial base recursive content.
200     * @param P recursive GenPolynomial.
201     * @return baseCont(P).
202     */
203    public C baseRecursiveContent(GenPolynomial<GenPolynomial<C>> P) {
204        if (P == null) {
205            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
206        }
207        if (P.isZERO()) {
208            GenPolynomialRing<C> cf = (GenPolynomialRing<C>) P.ring.coFac;
209            return cf.coFac.getZERO();
210        }
211        C d = null;
212        for (GenPolynomial<C> c : P.getMap().values()) {
213            C cc = baseContent(c);
214            if (d == null) {
215                d = cc;
216            } else {
217                d = gcd(d, cc);
218            }
219            if (d.isONE()) {
220                return d;
221            }
222        }
223        if (d.signum() < 0) {
224            d = d.negate();
225        }
226        return d;
227    }
228
229
230    /**
231     * GenPolynomial base recursive primitive part.
232     * @param P recursive GenPolynomial.
233     * @return basePP(P).
234     */
235    public GenPolynomial<GenPolynomial<C>> baseRecursivePrimitivePart(GenPolynomial<GenPolynomial<C>> P) {
236        if (P == null) {
237            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
238        }
239        if (P.isZERO()) {
240            return P;
241        }
242        C d = baseRecursiveContent(P);
243        if (d.isONE()) {
244            return P;
245        }
246        GenPolynomial<GenPolynomial<C>> pp = PolyUtil.<C> baseRecursiveDivide(P, d);
247        return pp;
248    }
249
250
251    /**
252     * GenPolynomial recursive greatest common divisor. Uses pseudoRemainder for
253     * remainder.
254     * @param P recursive GenPolynomial.
255     * @param S recursive GenPolynomial.
256     * @return gcd(P,S).
257     */
258    public GenPolynomial<GenPolynomial<C>> recursiveGcd(GenPolynomial<GenPolynomial<C>> P,
259                    GenPolynomial<GenPolynomial<C>> S) {
260        if (S == null || S.isZERO()) {
261            return P;
262        }
263        if (P == null || P.isZERO()) {
264            return S;
265        }
266        if (P.ring.nvar <= 1) {
267            return recursiveUnivariateGcd(P, S);
268        }
269        // distributed polynomials gcd
270        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
271        RingFactory<GenPolynomial<C>> rrfac = rfac.coFac;
272        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rrfac;
273        GenPolynomialRing<C> dfac = cfac.extend(rfac.nvar);
274        GenPolynomial<C> Pd = PolyUtil.<C> distribute(dfac, P);
275        GenPolynomial<C> Sd = PolyUtil.<C> distribute(dfac, S);
276        GenPolynomial<C> Dd = gcd(Pd, Sd);
277        // convert to recursive
278        GenPolynomial<GenPolynomial<C>> C = PolyUtil.<C> recursive(rfac, Dd);
279        return C;
280    }
281
282
283    /**
284     * Univariate GenPolynomial recursive greatest common divisor. Uses
285     * pseudoRemainder for remainder.
286     * @param P univariate recursive GenPolynomial.
287     * @param S univariate recursive GenPolynomial.
288     * @return gcd(P,S).
289     */
290    public abstract GenPolynomial<GenPolynomial<C>> recursiveUnivariateGcd(GenPolynomial<GenPolynomial<C>> P,
291                    GenPolynomial<GenPolynomial<C>> S);
292
293
294    /**
295     * GenPolynomial content.
296     * @param P GenPolynomial.
297     * @return cont(P).
298     */
299    public GenPolynomial<C> content(GenPolynomial<C> P) {
300        if (P == null) {
301            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
302        }
303        GenPolynomialRing<C> pfac = P.ring;
304        if (pfac.nvar <= 1) {
305            // baseContent not possible by return type
306            throw new IllegalArgumentException(
307                            this.getClass().getName() + " use baseContent for univariate polynomials");
308
309        }
310        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
311        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
312        GenPolynomial<C> D = recursiveContent(Pr);
313        return D;
314    }
315
316
317    /**
318     * GenPolynomial primitive part.
319     * @param P GenPolynomial.
320     * @return pp(P).
321     */
322    public GenPolynomial<C> primitivePart(GenPolynomial<C> P) {
323        return contentPrimitivePart(P)[1];
324    }
325
326
327    /**
328     * GenPolynomial content and primitive part.
329     * @param P GenPolynomial.
330     * @return { cont(P), pp(P) }
331     */
332    @SuppressWarnings("unchecked")
333    public GenPolynomial<C>[] contentPrimitivePart(GenPolynomial<C> P) {
334        if (P == null) {
335            throw new IllegalArgumentException(this.getClass().getName() + " P != null");
336        }
337        GenPolynomial<C>[] ret = new GenPolynomial[2];
338        GenPolynomialRing<C> pfac = P.ring;
339        if (P.isZERO()) {
340            ret[0] = pfac.getZERO();
341            ret[1] = pfac.getZERO();
342            return ret;
343        }
344        if (pfac.nvar <= 1) {
345            C Pc = baseContent(P);
346            GenPolynomial<C> Pp = P;
347            if (!Pc.isONE()) {
348                Pp = P.divide(Pc);
349            }
350            ret[0] = pfac.valueOf(Pc);
351            ret[1] = Pp;
352            return ret;
353        }
354        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
355        //GenPolynomialRing<C> cfac = rfac.coFac;
356        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
357        GenPolynomial<C> Pc = recursiveContent(Pr);
358        // primitive part
359        GenPolynomial<GenPolynomial<C>> Pp = Pr;
360        if (!Pc.isONE()) {
361            Pp = PolyUtil.<C> recursiveDivide(Pr, Pc);
362        }
363        GenPolynomial<C> Ppd = PolyUtil.<C> distribute(pfac, Pp);
364        ret[0] = Pc; // sic!
365        ret[1] = Ppd;
366        return ret;
367    }
368
369
370    /**
371     * GenPolynomial division. Indirection to GenPolynomial method.
372     * @param a GenPolynomial.
373     * @param b coefficient.
374     * @return a/b.
375     */
376    public GenPolynomial<C> divide(GenPolynomial<C> a, C b) {
377        if (b == null || b.isZERO()) {
378            throw new IllegalArgumentException("division by zero");
379
380        }
381        if (a == null || a.isZERO()) {
382            return a;
383        }
384        return a.divide(b);
385    }
386
387
388    /**
389     * Coefficient greatest common divisor. Indirection to coefficient method.
390     * @param a coefficient.
391     * @param b coefficient.
392     * @return gcd(a,b).
393     */
394    public C gcd(C a, C b) {
395        if (b == null || b.isZERO()) {
396            return a;
397        }
398        if (a == null || a.isZERO()) {
399            return b;
400        }
401        return a.gcd(b);
402    }
403
404
405    /**
406     * GenPolynomial greatest common divisor.
407     * @param P GenPolynomial.
408     * @param S GenPolynomial.
409     * @return gcd(P,S).
410     */
411    public GenPolynomial<C> gcd(GenPolynomial<C> P, GenPolynomial<C> S) {
412        if (S == null || S.isZERO()) {
413            return P;
414        }
415        if (P == null || P.isZERO()) {
416            return S;
417        }
418        GenPolynomialRing<C> pfac = P.ring;
419        if (pfac.nvar <= 1) {
420            GenPolynomial<C> T = baseGcd(P, S);
421            return T;
422        }
423        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
424        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
425        GenPolynomial<GenPolynomial<C>> Sr = PolyUtil.<C> recursive(rfac, S);
426        GenPolynomial<GenPolynomial<C>> Dr = recursiveUnivariateGcd(Pr, Sr);
427        GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr);
428        return D;
429    }
430
431
432    /**
433     * GenPolynomial least common multiple.
434     * @param P GenPolynomial.
435     * @param S GenPolynomial.
436     * @return lcm(P,S).
437     */
438    public GenPolynomial<C> lcm(GenPolynomial<C> P, GenPolynomial<C> S) {
439        if (S == null || S.isZERO()) {
440            return S;
441        }
442        if (P == null || P.isZERO()) {
443            return P;
444        }
445        GenPolynomial<C> C = gcd(P, S);
446        GenPolynomial<C> A = P.multiply(S);
447        return PolyUtil.<C> basePseudoDivide(A, C);
448    }
449
450
451    /**
452     * List of GenPolynomials greatest common divisor.
453     * @param A non empty list of GenPolynomials.
454     * @return gcd(A_i).
455     */
456    public GenPolynomial<C> gcd(List<GenPolynomial<C>> A) {
457        if (A == null || A.isEmpty()) {
458            throw new IllegalArgumentException("A may not be empty");
459        }
460        GenPolynomial<C> g = A.get(0);
461        for (int i = 1; i < A.size(); i++) {
462            GenPolynomial<C> f = A.get(i);
463            g = gcd(g, f);
464        }
465        return g;
466    }
467
468
469    /**
470     * Univariate GenPolynomial resultant.
471     * @param P univariate GenPolynomial.
472     * @param S univariate GenPolynomial.
473     * @return res(P,S).
474     * @throws UnsupportedOperationException if there is no implementation in
475     *             the sub-class.
476     */
477    @SuppressWarnings("unused")
478    public GenPolynomial<C> baseResultant(GenPolynomial<C> P, GenPolynomial<C> S) {
479        throw new UnsupportedOperationException("not implemented");
480    }
481
482
483    /**
484     * Univariate GenPolynomial recursive resultant.
485     * @param P univariate recursive GenPolynomial.
486     * @param S univariate recursive GenPolynomial.
487     * @return res(P,S).
488     * @throws UnsupportedOperationException if there is no implementation in
489     *             the sub-class.
490     */
491    @SuppressWarnings("unused")
492    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<C>> P,
493                    GenPolynomial<GenPolynomial<C>> S) {
494        throw new UnsupportedOperationException("not implemented");
495    }
496
497
498    /**
499     * GenPolynomial recursive resultant.
500     * @param P univariate recursive GenPolynomial.
501     * @param S univariate recursive GenPolynomial.
502     * @return res(P,S).
503     * @throws UnsupportedOperationException if there is no implementation in
504     *             the sub-class.
505     */
506    public GenPolynomial<GenPolynomial<C>> recursiveResultant(GenPolynomial<GenPolynomial<C>> P,
507                    GenPolynomial<GenPolynomial<C>> S) {
508        if (S == null || S.isZERO()) {
509            return S;
510        }
511        if (P == null || P.isZERO()) {
512            return P;
513        }
514        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
515        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rfac.coFac;
516        GenPolynomialRing<C> dfac = cfac.extend(rfac.getVars());
517        GenPolynomial<C> Pp = PolyUtil.<C> distribute(dfac, P);
518        GenPolynomial<C> Sp = PolyUtil.<C> distribute(dfac, S);
519        GenPolynomial<C> res = resultant(Pp, Sp);
520        GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<C> recursive(rfac, res);
521        return Rr;
522    }
523
524
525    /**
526     * GenPolynomial resultant. The input polynomials are considered as
527     * univariate polynomials in the main variable.
528     * @param P GenPolynomial.
529     * @param S GenPolynomial.
530     * @return res(P,S).
531     * @see edu.jas.ufd.GreatestCommonDivisorSubres#recursiveResultant
532     * @throws UnsupportedOperationException if there is no implementation in
533     *             the sub-class.
534     */
535    public GenPolynomial<C> resultant(GenPolynomial<C> P, GenPolynomial<C> S) {
536        if (S == null || S.isZERO()) {
537            return S;
538        }
539        if (P == null || P.isZERO()) {
540            return P;
541        }
542        // no more hacked: GreatestCommonDivisorSubres<C> ufd_sr = new GreatestCommonDivisorSubres<C>();
543        GenPolynomialRing<C> pfac = P.ring;
544        if (pfac.nvar <= 1) {
545            return baseResultant(P, S);
546        }
547        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
548        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
549        GenPolynomial<GenPolynomial<C>> Sr = PolyUtil.<C> recursive(rfac, S);
550
551        GenPolynomial<GenPolynomial<C>> Dr = recursiveUnivariateResultant(Pr, Sr);
552        GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr);
553        return D;
554    }
555
556
557    /**
558     * GenPolynomial co-prime list.
559     * @param A list of GenPolynomials.
560     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
561     *         a in A there exists b in B with b|a. B does not contain zero or
562     *         constant polynomials.
563     */
564    public List<GenPolynomial<C>> coPrime(List<GenPolynomial<C>> A) {
565        if (A == null || A.isEmpty()) {
566            return A;
567        }
568        List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(A.size());
569        // make a coprime to rest of list
570        GenPolynomial<C> a = A.get(0);
571        //System.out.println("a = " + a);
572        if (!a.isZERO() && !a.isConstant()) {
573            for (int i = 1; i < A.size(); i++) {
574                GenPolynomial<C> b = A.get(i);
575                GenPolynomial<C> g = gcd(a, b).abs();
576                if (!g.isONE()) {
577                    a = PolyUtil.<C> basePseudoDivide(a, g);
578                    b = PolyUtil.<C> basePseudoDivide(b, g);
579                    GenPolynomial<C> gp = gcd(a, g).abs();
580                    while (!gp.isONE()) {
581                        a = PolyUtil.<C> basePseudoDivide(a, gp);
582                        g = PolyUtil.<C> basePseudoDivide(g, gp);
583                        B.add(g); // gcd(a,g) == 1
584                        g = gp;
585                        gp = gcd(a, gp).abs();
586                    }
587                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
588                        B.add(g); // gcd(a,g) == 1
589                    }
590                }
591                if (!b.isZERO() && !b.isConstant()) {
592                    B.add(b); // gcd(a,b) == 1
593                }
594            }
595        } else {
596            B.addAll(A.subList(1, A.size()));
597        }
598        // make rest coprime
599        B = coPrime(B);
600        //System.out.println("B = " + B);
601        if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
602            a = a.abs();
603            B.add(a);
604        }
605        return B;
606    }
607
608
609    /**
610     * GenPolynomial co-prime list.
611     * @param A list of GenPolynomials.
612     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
613     *         a in A there exists b in B with b|a. B does not contain zero or
614     *         constant polynomials.
615     */
616    public List<GenPolynomial<C>> coPrimeRec(List<GenPolynomial<C>> A) {
617        if (A == null || A.isEmpty()) {
618            return A;
619        }
620        List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>();
621        // make a co-prime to rest of list
622        for (GenPolynomial<C> a : A) {
623            //System.out.println("a = " + a);
624            B = coPrime(a, B);
625            //System.out.println("B = " + B);
626        }
627        return B;
628    }
629
630
631    /**
632     * GenPolynomial co-prime list.
633     * @param a GenPolynomial.
634     * @param P co-prime list of GenPolynomials.
635     * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a
636     *         there exists b in P with b|a. B does not contain zero or constant
637     *         polynomials.
638     */
639    public List<GenPolynomial<C>> coPrime(GenPolynomial<C> a, List<GenPolynomial<C>> P) {
640        if (a == null || a.isZERO() || a.isConstant()) {
641            return P;
642        }
643        List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(P.size() + 1);
644        // make a coprime to elements of the list P
645        for (int i = 0; i < P.size(); i++) {
646            GenPolynomial<C> b = P.get(i);
647            GenPolynomial<C> g = gcd(a, b).abs();
648            if (!g.isONE()) {
649                a = PolyUtil.<C> basePseudoDivide(a, g);
650                b = PolyUtil.<C> basePseudoDivide(b, g);
651                // make g co-prime to new a, g is co-prime to c != b in P, B
652                GenPolynomial<C> gp = gcd(a, g).abs();
653                while (!gp.isONE()) {
654                    a = PolyUtil.<C> basePseudoDivide(a, gp);
655                    g = PolyUtil.<C> basePseudoDivide(g, gp);
656                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
657                        B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
658                    }
659                    g = gp;
660                    gp = gcd(a, gp).abs();
661                }
662                // make new g co-prime to new b
663                gp = gcd(b, g).abs();
664                while (!gp.isONE()) {
665                    b = PolyUtil.<C> basePseudoDivide(b, gp);
666                    g = PolyUtil.<C> basePseudoDivide(g, gp);
667                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
668                        B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
669                    }
670                    g = gp;
671                    gp = gcd(b, gp).abs();
672                }
673                if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
674                    B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
675                }
676            }
677            if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) {
678                B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B
679            }
680        }
681        if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
682            B.add(a);
683        }
684        return B;
685    }
686
687
688    /**
689     * GenPolynomial test for co-prime list.
690     * @param A list of GenPolynomials.
691     * @return true if gcd(b,c) = 1 for all b != c in B, else false.
692     */
693    public boolean isCoPrime(List<GenPolynomial<C>> A) {
694        if (A == null || A.isEmpty()) {
695            return true;
696        }
697        if (A.size() == 1) {
698            return true;
699        }
700        for (int i = 0; i < A.size(); i++) {
701            GenPolynomial<C> a = A.get(i);
702            for (int j = i + 1; j < A.size(); j++) {
703                GenPolynomial<C> b = A.get(j);
704                GenPolynomial<C> g = gcd(a, b);
705                if (!g.isONE()) {
706                    System.out.println("not co-prime, a: " + a);
707                    System.out.println("not co-prime, b: " + b);
708                    System.out.println("not co-prime, g: " + g);
709                    return false;
710                }
711            }
712        }
713        return true;
714    }
715
716
717    /**
718     * GenPolynomial test for co-prime list of given list.
719     * @param A list of GenPolynomials.
720     * @param P list of co-prime GenPolynomials.
721     * @return true if isCoPrime(P) and for all a in A exists p in P with p | a,
722     *         else false.
723     */
724    public boolean isCoPrime(List<GenPolynomial<C>> P, List<GenPolynomial<C>> A) {
725        if (!isCoPrime(P)) {
726            return false;
727        }
728        if (A == null || A.isEmpty()) {
729            return true;
730        }
731        for (GenPolynomial<C> q : A) {
732            if (q.isZERO() || q.isConstant()) {
733                continue;
734            }
735            boolean divides = false;
736            for (GenPolynomial<C> p : P) {
737                GenPolynomial<C> a = PolyUtil.<C> baseSparsePseudoRemainder(q, p);
738                if (a.isZERO()) { // p divides q
739                    divides = true;
740                    break;
741                }
742            }
743            if (!divides) {
744                System.out.println("no divisor for: " + q);
745                return false;
746            }
747        }
748        return true;
749    }
750
751
752    /**
753     * Univariate GenPolynomial extended greatest common divisor. Uses sparse
754     * pseudoRemainder for remainder.
755     * @param P univariate GenPolynomial.
756     * @param S univariate GenPolynomial.
757     * @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S).
758     */
759    @SuppressWarnings("unchecked")
760    public GenPolynomial<C>[] baseExtendedGcd(GenPolynomial<C> P, GenPolynomial<C> S) {
761        //return P.egcd(S);
762        GenPolynomial<C>[] hegcd = baseHalfExtendedGcd(P, S);
763        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[3];
764        ret[0] = hegcd[0];
765        ret[1] = hegcd[1];
766        GenPolynomial<C> x = hegcd[0].subtract(hegcd[1].multiply(P));
767        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(x, S);
768        // assert qr[1].isZERO() 
769        ret[2] = qr[0];
770        return ret;
771    }
772
773
774    /**
775     * Univariate GenPolynomial half extended greatest common divisor. Uses
776     * sparse pseudoRemainder for remainder.
777     * @param S GenPolynomial.
778     * @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S).
779     */
780    @SuppressWarnings("unchecked")
781    public GenPolynomial<C>[] baseHalfExtendedGcd(GenPolynomial<C> P, GenPolynomial<C> S) {
782        //if ( P == null ) {
783        //    throw new IllegalArgumentException("null P not allowed");
784        //}
785        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[2];
786        ret[0] = null;
787        ret[1] = null;
788        if (S == null || S.isZERO()) {
789            ret[0] = P;
790            ret[1] = P.ring.getONE();
791            return ret;
792        }
793        if (P == null || P.isZERO()) {
794            ret[0] = S;
795            ret[1] = S.ring.getZERO();
796            return ret;
797        }
798        if (P.ring.nvar != 1) {
799            throw new IllegalArgumentException(
800                            this.getClass().getName() + " not univariate polynomials " + P.ring);
801        }
802        GenPolynomial<C> q = P;
803        GenPolynomial<C> r = S;
804        GenPolynomial<C> c1 = P.ring.getONE().copy();
805        GenPolynomial<C> d1 = P.ring.getZERO().copy();
806        while (!r.isZERO()) {
807            GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(q, r);
808            //q.divideAndRemainder(r);
809            q = qr[0];
810            GenPolynomial<C> x = c1.subtract(q.multiply(d1));
811            c1 = d1;
812            d1 = x;
813            q = r;
814            r = qr[1];
815        }
816        // normalize ldcf(q) to 1, i.e. make monic
817        C g = q.leadingBaseCoefficient();
818        if (g.isUnit()) {
819            C h = g.inverse();
820            q = q.multiply(h);
821            c1 = c1.multiply(h);
822        }
823        //assert ( ((c1.multiply(P)).remainder(S).equals(q) )); 
824        ret[0] = q;
825        ret[1] = c1;
826        return ret;
827    }
828
829
830    /**
831     * Univariate GenPolynomial greatest common divisor diophantine version.
832     * @param P univariate GenPolynomial.
833     * @param S univariate GenPolynomial.
834     * @param c univariate GenPolynomial.
835     * @return [ a, b ] with a*P + b*S = c and deg(a) &lt; deg(S).
836     */
837    @SuppressWarnings("unchecked")
838    public GenPolynomial<C>[] baseGcdDiophant(GenPolynomial<C> P, GenPolynomial<C> S, GenPolynomial<C> c) {
839        GenPolynomial<C>[] egcd = baseExtendedGcd(P, S);
840        GenPolynomial<C> g = egcd[0];
841        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(c, g);
842        if (!qr[1].isZERO()) {
843            throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g);
844        }
845        GenPolynomial<C> q = qr[0];
846        GenPolynomial<C> a = egcd[1].multiply(q);
847        GenPolynomial<C> b = egcd[2].multiply(q);
848        if (!a.isZERO() && a.degree(0) >= S.degree(0)) {
849            qr = PolyUtil.<C> basePseudoQuotientRemainder(a, S);
850            a = qr[1];
851            b = b.sum(P.multiply(qr[0]));
852        }
853        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[2];
854        ret[0] = a;
855        ret[1] = b;
856
857        if (debug) {
858            GenPolynomial<C> y = ret[0].multiply(P).sum(ret[1].multiply(S));
859            if (!y.equals(c)) {
860                System.out.println("P  = " + P);
861                System.out.println("S  = " + S);
862                System.out.println("c  = " + c);
863                System.out.println("a  = " + a);
864                System.out.println("b  = " + b);
865                System.out.println("y  = " + y);
866                throw new ArithmeticException("not diophant, x = " + y.subtract(c));
867            }
868        }
869        return ret;
870    }
871
872
873    /**
874     * Univariate GenPolynomial partial fraction decomposition.
875     * @param A univariate GenPolynomial.
876     * @param P univariate GenPolynomial.
877     * @param S univariate GenPolynomial.
878     * @return [ A0, Ap, As ] with A/(P*S) = A0 + Ap/P + As/S with deg(Ap) &lt;
879     *         deg(P) and deg(As) &lt; deg(S).
880     */
881    @SuppressWarnings("unchecked")
882    public GenPolynomial<C>[] basePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P,
883                    GenPolynomial<C> S) {
884        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[3];
885        ret[0] = null;
886        ret[1] = null;
887        ret[2] = null;
888        GenPolynomial<C> ps = P.multiply(S);
889        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, ps);
890        ret[0] = qr[0];
891        GenPolynomial<C> r = qr[1];
892        GenPolynomial<C>[] diop = baseGcdDiophant(S, P, r); // switch arguments
893
894        //         GenPolynomial<C> x = diop[0].multiply(S).sum( diop[1].multiply(P) );
895        //         if ( !x.equals(r) ) {
896        //             System.out.println("r  = " + r);
897        //             System.out.println("x  = " + x);
898        //             throw new RuntimeException("not partial fraction, x = " + x);
899        //         }
900
901        ret[1] = diop[0];
902        ret[2] = diop[1];
903        if (ret[1].degree(0) >= P.degree(0)) {
904            qr = PolyUtil.<C> basePseudoQuotientRemainder(ret[1], P);
905            ret[0] = ret[0].sum(qr[0]);
906            ret[1] = qr[1];
907        }
908        if (ret[2].degree(0) >= S.degree(0)) {
909            qr = PolyUtil.<C> basePseudoQuotientRemainder(ret[2], S);
910            ret[0] = ret[0].sum(qr[0]);
911            ret[2] = qr[1];
912        }
913        return ret;
914    }
915
916
917    /**
918     * Univariate GenPolynomial partial fraction decomposition.
919     * @param A univariate GenPolynomial.
920     * @param P univariate GenPolynomial.
921     * @param e exponent for P.
922     * @return [ F0, F1, ..., Fe ] with A/(P^e) = sum( Fi / P^i ) with deg(Fi) &lt;
923     *         deg(P).
924     */
925    public List<GenPolynomial<C>> basePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, int e) {
926        if (A == null || P == null || e == 0) {
927            throw new IllegalArgumentException("null A, P or e = 0 not allowed");
928        }
929        List<GenPolynomial<C>> pf = new ArrayList<GenPolynomial<C>>(e);
930        if (A.isZERO()) {
931            for (int i = 0; i < e; i++) {
932                pf.add(A);
933            }
934            return pf;
935        }
936        if (e == 1) {
937            GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, P);
938            pf.add(qr[0]);
939            pf.add(qr[1]);
940            return pf;
941        }
942        GenPolynomial<C> a = A;
943        for (int j = e; j > 0; j--) {
944            GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(a, P);
945            a = qr[0];
946            pf.add(0, qr[1]);
947        }
948        pf.add(0, a);
949        return pf;
950    }
951
952
953    /**
954     * Univariate GenPolynomial partial fraction decomposition.
955     * @param A univariate GenPolynomial.
956     * @param D list of co-prime univariate GenPolynomials.
957     * @return [ A0, A1,..., An ] with A/prod(D) = A0 + sum( Ai/Di ) with
958     *         deg(Ai) &lt; deg(Di).
959     */
960    public List<GenPolynomial<C>> basePartialFraction(GenPolynomial<C> A, List<GenPolynomial<C>> D) {
961        if (D == null || A == null) {
962            throw new IllegalArgumentException("null A or D not allowed");
963        }
964        List<GenPolynomial<C>> pf = new ArrayList<GenPolynomial<C>>(D.size() + 1);
965        if (A.isZERO() || D.size() == 0) {
966            pf.add(A);
967            for (int i = 0; i < D.size(); i++) {
968                pf.add(A);
969            }
970            return pf;
971        }
972        List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size() - 1);
973        GenPolynomial<C> P = A.ring.getONE();
974        GenPolynomial<C> d1 = null;
975        for (GenPolynomial<C> d : D) {
976            if (d1 == null) {
977                d1 = d;
978            } else {
979                P = P.multiply(d);
980                Dp.add(d);
981            }
982        }
983        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, P.multiply(d1));
984        GenPolynomial<C> A0 = qr[0];
985        GenPolynomial<C> r = qr[1];
986        if (D.size() == 1) {
987            pf.add(A0);
988            pf.add(r);
989            return pf;
990        }
991        GenPolynomial<C>[] diop = baseGcdDiophant(P, d1, r); // switch arguments
992        GenPolynomial<C> A1 = diop[0];
993        GenPolynomial<C> S = diop[1];
994        List<GenPolynomial<C>> Fr = basePartialFraction(S, Dp);
995        A0 = A0.sum(Fr.remove(0));
996        pf.add(A0);
997        pf.add(A1);
998        pf.addAll(Fr);
999        return pf;
1000    }
1001
1002
1003    /**
1004     * Test for Univariate GenPolynomial partial fraction decomposition.
1005     * @param A univariate GenPolynomial.
1006     * @param D list of (co-prime) univariate GenPolynomials.
1007     * @param F list of univariate GenPolynomials from a partial fraction
1008     *            computation.
1009     * @return true if A/prod(D) = F0 + sum( Fi/Di ) with deg(Fi) &lt; deg(Di), Fi
1010     *         in F, else false.
1011     */
1012    public boolean isBasePartialFraction(GenPolynomial<C> A, List<GenPolynomial<C>> D,
1013                    List<GenPolynomial<C>> F) {
1014        if (D == null || A == null || F == null) {
1015            throw new IllegalArgumentException("null A, F or D not allowed");
1016        }
1017        if (D.size() != F.size() - 1) {
1018            return false;
1019        }
1020        // A0*prod(D) + sum( Ai * Dip ), Dip = prod(D,j!=i)
1021        GenPolynomial<C> P = A.ring.getONE();
1022        for (GenPolynomial<C> d : D) {
1023            P = P.multiply(d);
1024        }
1025        List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F);
1026        GenPolynomial<C> A0 = Fp.remove(0).multiply(P);
1027        //System.out.println("A0 = " + A0);
1028        int j = 0;
1029        for (GenPolynomial<C> Fi : Fp) {
1030            P = A.ring.getONE();
1031            int i = 0;
1032            for (GenPolynomial<C> d : D) {
1033                if (i != j) {
1034                    P = P.multiply(d);
1035                }
1036                i++;
1037            }
1038            //System.out.println("Fi = " + Fi);
1039            //System.out.println("P  = " + P);
1040            A0 = A0.sum(Fi.multiply(P));
1041            //System.out.println("A0 = " + A0);
1042            j++;
1043        }
1044        boolean t = A.equals(A0);
1045        if (!t) {
1046            System.out.println("not isPartFrac = " + A0);
1047        }
1048        return t;
1049    }
1050
1051
1052    /**
1053     * Test for Univariate GenPolynomial partial fraction decomposition.
1054     * @param A univariate GenPolynomial.
1055     * @param P univariate GenPolynomial.
1056     * @param e exponent for P.
1057     * @param F list of univariate GenPolynomials from a partial fraction
1058     *            computation.
1059     * @return true if A/(P^e) = F0 + sum( Fi / P^i ) with deg(Fi) &lt; deg(P), Fi
1060     *         in F, else false.
1061     */
1062    public boolean isBasePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, int e,
1063                    List<GenPolynomial<C>> F) {
1064        if (A == null || P == null || F == null || e == 0) {
1065            throw new IllegalArgumentException("null A, P, F or e = 0 not allowed");
1066        }
1067        GenPolynomial<C> A0 = basePartialFractionValue(P, e, F);
1068        boolean t = A.equals(A0);
1069        if (!t) {
1070            System.out.println("not isPartFrac = " + A0);
1071        }
1072        return t;
1073    }
1074
1075
1076    /**
1077     * Test for Univariate GenPolynomial partial fraction decomposition.
1078     * @param P univariate GenPolynomial.
1079     * @param e exponent for P.
1080     * @param F list of univariate GenPolynomials from a partial fraction
1081     *            computation.
1082     * @return (F0 + sum( Fi / P^i )) * P^e.
1083     */
1084    public GenPolynomial<C> basePartialFractionValue(GenPolynomial<C> P, int e, List<GenPolynomial<C>> F) {
1085        if (P == null || F == null || e == 0) {
1086            throw new IllegalArgumentException("null P, F or e = 0 not allowed");
1087        }
1088        GenPolynomial<C> A0 = P.ring.getZERO();
1089        for (GenPolynomial<C> Fi : F) {
1090            A0 = A0.multiply(P);
1091            A0 = A0.sum(Fi);
1092        }
1093        return A0;
1094    }
1095
1096}