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