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