001/*
002 * $Id: GreatestCommonDivisorAbstract.java 5871 2018-07-20 15:58:45Z kredel $
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        /*
425        GenPolynomialRing<C> cfac = pfac.contract(1);
426        GenPolynomialRing<GenPolynomial<C>> rfac;
427        if (pfac.getVars() != null && pfac.getVars().length > 0) {
428            String[] v = new String[] { pfac.getVars()[pfac.nvar - 1] };
429            rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, 1, v);
430        } else {
431            rfac = new GenPolynomialRing<GenPolynomial<C>>(cfac, 1);
432        }
433        */
434        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
435        GenPolynomial<GenPolynomial<C>> Sr = PolyUtil.<C> recursive(rfac, S);
436        GenPolynomial<GenPolynomial<C>> Dr = recursiveUnivariateGcd(Pr, Sr);
437        GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr);
438        return D;
439    }
440
441
442    /**
443     * GenPolynomial least common multiple.
444     * @param P GenPolynomial.
445     * @param S GenPolynomial.
446     * @return lcm(P,S).
447     */
448    public GenPolynomial<C> lcm(GenPolynomial<C> P, GenPolynomial<C> S) {
449        if (S == null || S.isZERO()) {
450            return S;
451        }
452        if (P == null || P.isZERO()) {
453            return P;
454        }
455        GenPolynomial<C> C = gcd(P, S);
456        GenPolynomial<C> A = P.multiply(S);
457        return PolyUtil.<C> basePseudoDivide(A, C);
458    }
459
460
461    /**
462     * List of GenPolynomials greatest common divisor.
463     * @param A non empty list of GenPolynomials.
464     * @return gcd(A_i).
465     */
466    public GenPolynomial<C> gcd(List<GenPolynomial<C>> A) {
467        if (A == null || A.isEmpty()) {
468            throw new IllegalArgumentException("A may not be empty");
469        }
470        GenPolynomial<C> g = A.get(0);
471        for (int i = 1; i < A.size(); i++) {
472            GenPolynomial<C> f = A.get(i);
473            g = gcd(g, f);
474        }
475        return g;
476    }
477
478
479    /**
480     * Univariate GenPolynomial resultant.
481     * @param P univariate GenPolynomial.
482     * @param S univariate GenPolynomial.
483     * @return res(P,S).
484     * @throws UnsupportedOperationException if there is no implementation in
485     *             the sub-class.
486     */
487    @SuppressWarnings("unused")
488    public GenPolynomial<C> baseResultant(GenPolynomial<C> P, GenPolynomial<C> S) {
489        throw new UnsupportedOperationException("not implmented");
490    }
491
492
493    /**
494     * Univariate GenPolynomial recursive resultant.
495     * @param P univariate recursive GenPolynomial.
496     * @param S univariate recursive GenPolynomial.
497     * @return res(P,S).
498     * @throws UnsupportedOperationException if there is no implementation in
499     *             the sub-class.
500     */
501    @SuppressWarnings("unused")
502    public GenPolynomial<GenPolynomial<C>> recursiveUnivariateResultant(GenPolynomial<GenPolynomial<C>> P,
503                    GenPolynomial<GenPolynomial<C>> S) {
504        throw new UnsupportedOperationException("not implmented");
505    }
506
507
508    /**
509     * GenPolynomial recursive resultant.
510     * @param P univariate recursive GenPolynomial.
511     * @param S univariate recursive GenPolynomial.
512     * @return res(P,S).
513     * @throws UnsupportedOperationException if there is no implementation in
514     *             the sub-class.
515     */
516    public GenPolynomial<GenPolynomial<C>> recursiveResultant(GenPolynomial<GenPolynomial<C>> P,
517                    GenPolynomial<GenPolynomial<C>> S) {
518        if (S == null || S.isZERO()) {
519            return S;
520        }
521        if (P == null || P.isZERO()) {
522            return P;
523        }
524        GenPolynomialRing<GenPolynomial<C>> rfac = P.ring;
525        GenPolynomialRing<C> cfac = (GenPolynomialRing<C>) rfac.coFac;
526        GenPolynomialRing<C> dfac = cfac.extend(rfac.getVars());
527        GenPolynomial<C> Pp = PolyUtil.<C> distribute(dfac, P);
528        GenPolynomial<C> Sp = PolyUtil.<C> distribute(dfac, S);
529        GenPolynomial<C> res = resultant(Pp, Sp);
530        GenPolynomial<GenPolynomial<C>> Rr = PolyUtil.<C> recursive(rfac, res);
531        return Rr;
532    }
533
534
535    /**
536     * GenPolynomial resultant. The input polynomials are considered as
537     * univariate polynomials in the main variable.
538     * @param P GenPolynomial.
539     * @param S GenPolynomial.
540     * @return res(P,S).
541     * @see edu.jas.ufd.GreatestCommonDivisorSubres#recursiveResultant
542     * @throws UnsupportedOperationException if there is no implementation in
543     *             the sub-class.
544     */
545    public GenPolynomial<C> resultant(GenPolynomial<C> P, GenPolynomial<C> S) {
546        if (S == null || S.isZERO()) {
547            return S;
548        }
549        if (P == null || P.isZERO()) {
550            return P;
551        }
552        // no more hacked: GreatestCommonDivisorSubres<C> ufd_sr = new GreatestCommonDivisorSubres<C>();
553        GenPolynomialRing<C> pfac = P.ring;
554        if (pfac.nvar <= 1) {
555            return baseResultant(P, S);
556        }
557        GenPolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1);
558        GenPolynomial<GenPolynomial<C>> Pr = PolyUtil.<C> recursive(rfac, P);
559        GenPolynomial<GenPolynomial<C>> Sr = PolyUtil.<C> recursive(rfac, S);
560
561        GenPolynomial<GenPolynomial<C>> Dr = recursiveUnivariateResultant(Pr, Sr);
562        GenPolynomial<C> D = PolyUtil.<C> distribute(pfac, Dr);
563        return D;
564    }
565
566
567    /**
568     * GenPolynomial co-prime list.
569     * @param A list of GenPolynomials.
570     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
571     *         a in A there exists b in B with b|a. B does not contain zero or
572     *         constant polynomials.
573     */
574    public List<GenPolynomial<C>> coPrime(List<GenPolynomial<C>> A) {
575        if (A == null || A.isEmpty()) {
576            return A;
577        }
578        List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(A.size());
579        // make a coprime to rest of list
580        GenPolynomial<C> a = A.get(0);
581        //System.out.println("a = " + a);
582        if (!a.isZERO() && !a.isConstant()) {
583            for (int i = 1; i < A.size(); i++) {
584                GenPolynomial<C> b = A.get(i);
585                GenPolynomial<C> g = gcd(a, b).abs();
586                if (!g.isONE()) {
587                    a = PolyUtil.<C> basePseudoDivide(a, g);
588                    b = PolyUtil.<C> basePseudoDivide(b, g);
589                    GenPolynomial<C> gp = gcd(a, g).abs();
590                    while (!gp.isONE()) {
591                        a = PolyUtil.<C> basePseudoDivide(a, gp);
592                        g = PolyUtil.<C> basePseudoDivide(g, gp);
593                        B.add(g); // gcd(a,g) == 1
594                        g = gp;
595                        gp = gcd(a, gp).abs();
596                    }
597                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
598                        B.add(g); // gcd(a,g) == 1
599                    }
600                }
601                if (!b.isZERO() && !b.isConstant()) {
602                    B.add(b); // gcd(a,b) == 1
603                }
604            }
605        } else {
606            B.addAll(A.subList(1, A.size()));
607        }
608        // make rest coprime
609        B = coPrime(B);
610        //System.out.println("B = " + B);
611        if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
612            a = a.abs();
613            B.add(a);
614        }
615        return B;
616    }
617
618
619    /**
620     * GenPolynomial co-prime list.
621     * @param A list of GenPolynomials.
622     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
623     *         a in A there exists b in B with b|a. B does not contain zero or
624     *         constant polynomials.
625     */
626    public List<GenPolynomial<C>> coPrimeRec(List<GenPolynomial<C>> A) {
627        if (A == null || A.isEmpty()) {
628            return A;
629        }
630        List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>();
631        // make a co-prime to rest of list
632        for (GenPolynomial<C> a : A) {
633            //System.out.println("a = " + a);
634            B = coPrime(a, B);
635            //System.out.println("B = " + B);
636        }
637        return B;
638    }
639
640
641    /**
642     * GenPolynomial co-prime list.
643     * @param a GenPolynomial.
644     * @param P co-prime list of GenPolynomials.
645     * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a
646     *         there exists b in P with b|a. B does not contain zero or constant
647     *         polynomials.
648     */
649    public List<GenPolynomial<C>> coPrime(GenPolynomial<C> a, List<GenPolynomial<C>> P) {
650        if (a == null || a.isZERO() || a.isConstant()) {
651            return P;
652        }
653        List<GenPolynomial<C>> B = new ArrayList<GenPolynomial<C>>(P.size() + 1);
654        // make a coprime to elements of the list P
655        for (int i = 0; i < P.size(); i++) {
656            GenPolynomial<C> b = P.get(i);
657            GenPolynomial<C> g = gcd(a, b).abs();
658            if (!g.isONE()) {
659                a = PolyUtil.<C> basePseudoDivide(a, g);
660                b = PolyUtil.<C> basePseudoDivide(b, g);
661                // make g co-prime to new a, g is co-prime to c != b in P, B
662                GenPolynomial<C> gp = gcd(a, g).abs();
663                while (!gp.isONE()) {
664                    a = PolyUtil.<C> basePseudoDivide(a, gp);
665                    g = PolyUtil.<C> basePseudoDivide(g, gp);
666                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
667                        B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
668                    }
669                    g = gp;
670                    gp = gcd(a, gp).abs();
671                }
672                // make new g co-prime to new b
673                gp = gcd(b, g).abs();
674                while (!gp.isONE()) {
675                    b = PolyUtil.<C> basePseudoDivide(b, gp);
676                    g = PolyUtil.<C> basePseudoDivide(g, gp);
677                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
678                        B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
679                    }
680                    g = gp;
681                    gp = gcd(b, gp).abs();
682                }
683                if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
684                    B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
685                }
686            }
687            if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) {
688                B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B
689            }
690        }
691        if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
692            B.add(a);
693        }
694        return B;
695    }
696
697
698    /**
699     * GenPolynomial test for co-prime list.
700     * @param A list of GenPolynomials.
701     * @return true if gcd(b,c) = 1 for all b != c in B, else false.
702     */
703    public boolean isCoPrime(List<GenPolynomial<C>> A) {
704        if (A == null || A.isEmpty()) {
705            return true;
706        }
707        if (A.size() == 1) {
708            return true;
709        }
710        for (int i = 0; i < A.size(); i++) {
711            GenPolynomial<C> a = A.get(i);
712            for (int j = i + 1; j < A.size(); j++) {
713                GenPolynomial<C> b = A.get(j);
714                GenPolynomial<C> g = gcd(a, b);
715                if (!g.isONE()) {
716                    System.out.println("not co-prime, a: " + a);
717                    System.out.println("not co-prime, b: " + b);
718                    System.out.println("not co-prime, g: " + g);
719                    return false;
720                }
721            }
722        }
723        return true;
724    }
725
726
727    /**
728     * GenPolynomial test for co-prime list of given list.
729     * @param A list of GenPolynomials.
730     * @param P list of co-prime GenPolynomials.
731     * @return true if isCoPrime(P) and for all a in A exists p in P with p | a,
732     *         else false.
733     */
734    public boolean isCoPrime(List<GenPolynomial<C>> P, List<GenPolynomial<C>> A) {
735        if (!isCoPrime(P)) {
736            return false;
737        }
738        if (A == null || A.isEmpty()) {
739            return true;
740        }
741        for (GenPolynomial<C> q : A) {
742            if (q.isZERO() || q.isConstant()) {
743                continue;
744            }
745            boolean divides = false;
746            for (GenPolynomial<C> p : P) {
747                GenPolynomial<C> a = PolyUtil.<C> baseSparsePseudoRemainder(q, p);
748                if (a.isZERO()) { // p divides q
749                    divides = true;
750                    break;
751                }
752            }
753            if (!divides) {
754                System.out.println("no divisor for: " + q);
755                return false;
756            }
757        }
758        return true;
759    }
760
761
762    /**
763     * Univariate GenPolynomial extended greatest common divisor. Uses sparse
764     * pseudoRemainder for remainder.
765     * @param P univariate GenPolynomial.
766     * @param S univariate GenPolynomial.
767     * @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S).
768     */
769    @SuppressWarnings("cast")
770    public GenPolynomial<C>[] baseExtendedGcd(GenPolynomial<C> P, GenPolynomial<C> S) {
771        //return P.egcd(S);
772        GenPolynomial<C>[] hegcd = baseHalfExtendedGcd(P, S);
773        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[3];
774        ret[0] = hegcd[0];
775        ret[1] = hegcd[1];
776        GenPolynomial<C> x = hegcd[0].subtract(hegcd[1].multiply(P));
777        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(x, S);
778        // assert qr[1].isZERO() 
779        ret[2] = qr[0];
780        return ret;
781    }
782
783
784    /**
785     * Univariate GenPolynomial half extended greatest comon divisor. Uses
786     * sparse pseudoRemainder for remainder.
787     * @param S GenPolynomial.
788     * @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S).
789     */
790    @SuppressWarnings("cast")
791    public GenPolynomial<C>[] baseHalfExtendedGcd(GenPolynomial<C> P, GenPolynomial<C> S) {
792        //if ( P == null ) {
793        //    throw new IllegalArgumentException("null P not allowed");
794        //}
795        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[2];
796        ret[0] = null;
797        ret[1] = null;
798        if (S == null || S.isZERO()) {
799            ret[0] = P;
800            ret[1] = P.ring.getONE();
801            return ret;
802        }
803        if (P == null || P.isZERO()) {
804            ret[0] = S;
805            ret[1] = S.ring.getZERO();
806            return ret;
807        }
808        if (P.ring.nvar != 1) {
809            throw new IllegalArgumentException(
810                            this.getClass().getName() + " not univariate polynomials " + P.ring);
811        }
812        GenPolynomial<C> q = P;
813        GenPolynomial<C> r = S;
814        GenPolynomial<C> c1 = P.ring.getONE().copy();
815        GenPolynomial<C> d1 = P.ring.getZERO().copy();
816        while (!r.isZERO()) {
817            GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(q, r);
818            //q.divideAndRemainder(r);
819            q = qr[0];
820            GenPolynomial<C> x = c1.subtract(q.multiply(d1));
821            c1 = d1;
822            d1 = x;
823            q = r;
824            r = qr[1];
825        }
826        // normalize ldcf(q) to 1, i.e. make monic
827        C g = q.leadingBaseCoefficient();
828        if (g.isUnit()) {
829            C h = g.inverse();
830            q = q.multiply(h);
831            c1 = c1.multiply(h);
832        }
833        //assert ( ((c1.multiply(P)).remainder(S).equals(q) )); 
834        ret[0] = q;
835        ret[1] = c1;
836        return ret;
837    }
838
839
840    /**
841     * Univariate GenPolynomial greatest common divisor diophantine version.
842     * @param P univariate GenPolynomial.
843     * @param S univariate GenPolynomial.
844     * @param c univariate GenPolynomial.
845     * @return [ a, b ] with a*P + b*S = c and deg(a) < deg(S).
846     */
847    @SuppressWarnings("cast")
848    public GenPolynomial<C>[] baseGcdDiophant(GenPolynomial<C> P, GenPolynomial<C> S, GenPolynomial<C> c) {
849        GenPolynomial<C>[] egcd = baseExtendedGcd(P, S);
850        GenPolynomial<C> g = egcd[0];
851        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(c, g);
852        if (!qr[1].isZERO()) {
853            throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g);
854        }
855        GenPolynomial<C> q = qr[0];
856        GenPolynomial<C> a = egcd[1].multiply(q);
857        GenPolynomial<C> b = egcd[2].multiply(q);
858        if (!a.isZERO() && a.degree(0) >= S.degree(0)) {
859            qr = PolyUtil.<C> basePseudoQuotientRemainder(a, S);
860            a = qr[1];
861            b = b.sum(P.multiply(qr[0]));
862        }
863        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[2];
864        ret[0] = a;
865        ret[1] = b;
866
867        if (debug) {
868            GenPolynomial<C> y = ret[0].multiply(P).sum(ret[1].multiply(S));
869            if (!y.equals(c)) {
870                System.out.println("P  = " + P);
871                System.out.println("S  = " + S);
872                System.out.println("c  = " + c);
873                System.out.println("a  = " + a);
874                System.out.println("b  = " + b);
875                System.out.println("y  = " + y);
876                throw new ArithmeticException("not diophant, x = " + y.subtract(c));
877            }
878        }
879        return ret;
880    }
881
882
883    /**
884     * Univariate GenPolynomial partial fraction decomposition.
885     * @param A univariate GenPolynomial.
886     * @param P univariate GenPolynomial.
887     * @param S univariate GenPolynomial.
888     * @return [ A0, Ap, As ] with A/(P*S) = A0 + Ap/P + As/S with deg(Ap) <
889     *         deg(P) and deg(As) < deg(S).
890     */
891    @SuppressWarnings("cast")
892    public GenPolynomial<C>[] basePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P,
893                    GenPolynomial<C> S) {
894        GenPolynomial<C>[] ret = (GenPolynomial<C>[]) new GenPolynomial[3];
895        ret[0] = null;
896        ret[1] = null;
897        ret[2] = null;
898        GenPolynomial<C> ps = P.multiply(S);
899        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, ps);
900        ret[0] = qr[0];
901        GenPolynomial<C> r = qr[1];
902        GenPolynomial<C>[] diop = baseGcdDiophant(S, P, r); // switch arguments
903
904        //         GenPolynomial<C> x = diop[0].multiply(S).sum( diop[1].multiply(P) );
905        //         if ( !x.equals(r) ) {
906        //             System.out.println("r  = " + r);
907        //             System.out.println("x  = " + x);
908        //             throw new RuntimeException("not partial fraction, x = " + x);
909        //         }
910
911        ret[1] = diop[0];
912        ret[2] = diop[1];
913        if (ret[1].degree(0) >= P.degree(0)) {
914            qr = PolyUtil.<C> basePseudoQuotientRemainder(ret[1], P);
915            ret[0] = ret[0].sum(qr[0]);
916            ret[1] = qr[1];
917        }
918        if (ret[2].degree(0) >= S.degree(0)) {
919            qr = PolyUtil.<C> basePseudoQuotientRemainder(ret[2], S);
920            ret[0] = ret[0].sum(qr[0]);
921            ret[2] = qr[1];
922        }
923        return ret;
924    }
925
926
927    /**
928     * Univariate GenPolynomial partial fraction decomposition.
929     * @param A univariate GenPolynomial.
930     * @param P univariate GenPolynomial.
931     * @param e exponent for P.
932     * @return [ F0, F1, ..., Fe ] with A/(P^e) = sum( Fi / P^i ) with deg(Fi) <
933     *         deg(P).
934     */
935    public List<GenPolynomial<C>> basePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, int e) {
936        if (A == null || P == null || e == 0) {
937            throw new IllegalArgumentException("null A, P or e = 0 not allowed");
938        }
939        List<GenPolynomial<C>> pf = new ArrayList<GenPolynomial<C>>(e);
940        if (A.isZERO()) {
941            for (int i = 0; i < e; i++) {
942                pf.add(A);
943            }
944            return pf;
945        }
946        if (e == 1) {
947            GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, P);
948            pf.add(qr[0]);
949            pf.add(qr[1]);
950            return pf;
951        }
952        GenPolynomial<C> a = A;
953        for (int j = e; j > 0; j--) {
954            GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(a, P);
955            a = qr[0];
956            pf.add(0, qr[1]);
957        }
958        pf.add(0, a);
959        return pf;
960    }
961
962
963    /**
964     * Univariate GenPolynomial partial fraction decomposition.
965     * @param A univariate GenPolynomial.
966     * @param D list of co-prime univariate GenPolynomials.
967     * @return [ A0, A1,..., An ] with A/prod(D) = A0 + sum( Ai/Di ) with
968     *         deg(Ai) < deg(Di).
969     */
970    public List<GenPolynomial<C>> basePartialFraction(GenPolynomial<C> A, List<GenPolynomial<C>> D) {
971        if (D == null || A == null) {
972            throw new IllegalArgumentException("null A or D not allowed");
973        }
974        List<GenPolynomial<C>> pf = new ArrayList<GenPolynomial<C>>(D.size() + 1);
975        if (A.isZERO() || D.size() == 0) {
976            pf.add(A);
977            for (int i = 0; i < D.size(); i++) {
978                pf.add(A);
979            }
980            return pf;
981        }
982        List<GenPolynomial<C>> Dp = new ArrayList<GenPolynomial<C>>(D.size() - 1);
983        GenPolynomial<C> P = A.ring.getONE();
984        GenPolynomial<C> d1 = null;
985        for (GenPolynomial<C> d : D) {
986            if (d1 == null) {
987                d1 = d;
988            } else {
989                P = P.multiply(d);
990                Dp.add(d);
991            }
992        }
993        GenPolynomial<C>[] qr = PolyUtil.<C> basePseudoQuotientRemainder(A, P.multiply(d1));
994        GenPolynomial<C> A0 = qr[0];
995        GenPolynomial<C> r = qr[1];
996        if (D.size() == 1) {
997            pf.add(A0);
998            pf.add(r);
999            return pf;
1000        }
1001        GenPolynomial<C>[] diop = baseGcdDiophant(P, d1, r); // switch arguments
1002        GenPolynomial<C> A1 = diop[0];
1003        GenPolynomial<C> S = diop[1];
1004        List<GenPolynomial<C>> Fr = basePartialFraction(S, Dp);
1005        A0 = A0.sum(Fr.remove(0));
1006        pf.add(A0);
1007        pf.add(A1);
1008        pf.addAll(Fr);
1009        return pf;
1010    }
1011
1012
1013    /**
1014     * Test for Univariate GenPolynomial partial fraction decomposition.
1015     * @param A univariate GenPolynomial.
1016     * @param D list of (co-prime) univariate GenPolynomials.
1017     * @param F list of univariate GenPolynomials from a partial fraction
1018     *            computation.
1019     * @return true if A/prod(D) = F0 + sum( Fi/Di ) with deg(Fi) < deg(Di), Fi
1020     *         in F, else false.
1021     */
1022    public boolean isBasePartialFraction(GenPolynomial<C> A, List<GenPolynomial<C>> D,
1023                    List<GenPolynomial<C>> F) {
1024        if (D == null || A == null || F == null) {
1025            throw new IllegalArgumentException("null A, F or D not allowed");
1026        }
1027        if (D.size() != F.size() - 1) {
1028            return false;
1029        }
1030        // A0*prod(D) + sum( Ai * Dip ), Dip = prod(D,j!=i)
1031        GenPolynomial<C> P = A.ring.getONE();
1032        for (GenPolynomial<C> d : D) {
1033            P = P.multiply(d);
1034        }
1035        List<GenPolynomial<C>> Fp = new ArrayList<GenPolynomial<C>>(F);
1036        GenPolynomial<C> A0 = Fp.remove(0).multiply(P);
1037        //System.out.println("A0 = " + A0);
1038        int j = 0;
1039        for (GenPolynomial<C> Fi : Fp) {
1040            P = A.ring.getONE();
1041            int i = 0;
1042            for (GenPolynomial<C> d : D) {
1043                if (i != j) {
1044                    P = P.multiply(d);
1045                }
1046                i++;
1047            }
1048            //System.out.println("Fi = " + Fi);
1049            //System.out.println("P  = " + P);
1050            A0 = A0.sum(Fi.multiply(P));
1051            //System.out.println("A0 = " + A0);
1052            j++;
1053        }
1054        boolean t = A.equals(A0);
1055        if (!t) {
1056            System.out.println("not isPartFrac = " + A0);
1057        }
1058        return t;
1059    }
1060
1061
1062    /**
1063     * Test for Univariate GenPolynomial partial fraction decomposition.
1064     * @param A univariate GenPolynomial.
1065     * @param P univariate GenPolynomial.
1066     * @param e exponent for P.
1067     * @param F list of univariate GenPolynomials from a partial fraction
1068     *            computation.
1069     * @return true if A/(P^e) = F0 + sum( Fi / P^i ) with deg(Fi) < deg(P), Fi
1070     *         in F, else false.
1071     */
1072    public boolean isBasePartialFraction(GenPolynomial<C> A, GenPolynomial<C> P, int e,
1073                    List<GenPolynomial<C>> F) {
1074        if (A == null || P == null || F == null || e == 0) {
1075            throw new IllegalArgumentException("null A, P, F or e = 0 not allowed");
1076        }
1077        GenPolynomial<C> A0 = basePartialFractionValue(P, e, F);
1078        boolean t = A.equals(A0);
1079        if (!t) {
1080            System.out.println("not isPartFrac = " + A0);
1081        }
1082        return t;
1083    }
1084
1085
1086    /**
1087     * Test for Univariate GenPolynomial partial fraction decomposition.
1088     * @param P univariate GenPolynomial.
1089     * @param e exponent for P.
1090     * @param F list of univariate GenPolynomials from a partial fraction
1091     *            computation.
1092     * @return (F0 + sum( Fi / P^i )) * P^e.
1093     */
1094    public GenPolynomial<C> basePartialFractionValue(GenPolynomial<C> P, int e, List<GenPolynomial<C>> F) {
1095        if (P == null || F == null || e == 0) {
1096            throw new IllegalArgumentException("null P, F or e = 0 not allowed");
1097        }
1098        GenPolynomial<C> A0 = P.ring.getZERO();
1099        for (GenPolynomial<C> Fi : F) {
1100            A0 = A0.multiply(P);
1101            A0 = A0.sum(Fi);
1102        }
1103        return A0;
1104    }
1105
1106}