001/*
002 * $Id: GreatestCommonDivisorAbstract.java 5731 2017-02-11 11:38:15Z kredel $
003 */
004
005package edu.jas.fd;
006
007
008import java.util.ArrayList;
009import java.util.Arrays;
010import java.util.List;
011
012import org.apache.log4j.Logger;
013
014import edu.jas.gbufd.SolvableSyzygyAbstract;
015import edu.jas.gbufd.SolvableSyzygySeq;
016import edu.jas.poly.GenPolynomial;
017import edu.jas.poly.GenSolvablePolynomial;
018import edu.jas.poly.GenSolvablePolynomialRing;
019import edu.jas.poly.PolyUtil;
020import edu.jas.poly.RecSolvablePolynomial;
021import edu.jas.poly.RecSolvablePolynomialRing;
022import edu.jas.structure.GcdRingElem;
023import edu.jas.structure.RingFactory;
024import edu.jas.structure.StarRingElem;
025import edu.jas.ufd.GCDFactory;
026
027
028/**
029 * (Non-unique) factorization domain greatest common divisor common algorithms.
030 * @param <C> coefficient type
031 * @author Heinz Kredel
032 */
033
034public abstract class GreatestCommonDivisorAbstract<C extends GcdRingElem<C>>
035                implements GreatestCommonDivisor<C> {
036
037
038    private static final Logger logger = Logger.getLogger(GreatestCommonDivisorAbstract.class);
039
040
041    private static final boolean debug = logger.isDebugEnabled();
042
043
044    /**
045     * Engine for syzygy computation.
046     */
047    final SolvableSyzygyAbstract<C> syz;
048
049
050    /**
051     * Coefficient ring.
052     */
053    final RingFactory<C> coFac;
054
055
056    /*
057     * Engine for commutative gcd computation.
058     */
059    //edu.jas.ufd.GreatestCommonDivisorAbstract<C> cgcd;
060
061
062    /**
063     * Constructor.
064     * @param cf coefficient ring.
065     */
066    public GreatestCommonDivisorAbstract(RingFactory<C> cf) {
067        this(cf, new SolvableSyzygySeq<C>(cf));
068    }
069
070
071    /**
072     * Constructor.
073     * @param cf coefficient ring.
074     * @param s algorithm for SolvableSyzygy computation.
075     */
076    public GreatestCommonDivisorAbstract(RingFactory<C> cf, SolvableSyzygyAbstract<C> s) {
077        coFac = cf;
078        syz = s;
079        //cgcd = GCDFactory.<C> getImplementation(pfac.coFac);
080    }
081
082
083    /**
084     * Get the String representation.
085     * @see java.lang.Object#toString()
086     */
087    @Override
088    public String toString() {
089        return getClass().getName();
090    }
091
092
093    /**
094     * GenSolvablePolynomial base coefficient content.
095     * @param P GenSolvablePolynomial.
096     * @return cont(P) with pp(P)*cont(P) = P.
097     */
098    public C leftBaseContent(GenSolvablePolynomial<C> P) {
099        if (P == null) {
100            throw new IllegalArgumentException("P == null");
101        }
102        if (P.isZERO()) {
103            return P.ring.getZEROCoefficient();
104        }
105        if (P.ring.coFac.isField()) { // so to make monic
106            return P.leadingBaseCoefficient();
107        }
108        C d = null;
109        for (C c : P.getMap().values()) {
110            if (d == null) {
111                d = c;
112            } else {
113                d = d.leftGcd(c);
114            }
115            if (d.isONE()) {
116                return d;
117            }
118        }
119        if (d.signum() < 0) {
120            d = d.negate();
121        }
122        return d;
123    }
124
125
126    /**
127     * GenSolvablePolynomial right base coefficient content.
128     * @param P GenSolvablePolynomial.
129     * @return cont(P) with cont(P)*pp(P) = P.
130     */
131    public C rightBaseContent(GenSolvablePolynomial<C> P) {
132        if (P == null) {
133            throw new IllegalArgumentException("P == null");
134        }
135        if (P.isZERO()) {
136            return P.ring.getZEROCoefficient();
137        }
138        if (P.ring.coFac.isField()) { // so to make monic
139            return P.leadingBaseCoefficient(); // todo check move to right
140        }
141        C d = null;
142        for (C c : P.getMap().values()) {
143            if (d == null) {
144                d = c;
145            } else {
146                d = d.rightGcd(c); // DONE does now exist
147            }
148            if (d.isONE()) {
149                return d;
150            }
151        }
152        if (d.signum() < 0) {
153            d = d.negate();
154        }
155        return d;
156    }
157
158
159    /**
160     * GenSolvablePolynomial base coefficient primitive part.
161     * @param P GenSolvablePolynomial.
162     * @return pp(P) with pp(P)*cont(P) = P.
163     */
164    public GenSolvablePolynomial<C> leftBasePrimitivePart(GenSolvablePolynomial<C> P) {
165        if (P == null) {
166            throw new IllegalArgumentException("P == null");
167        }
168        if (P.isZERO()) {
169            return P;
170        }
171        C d = leftBaseContent(P);
172        if (d.isONE()) {
173            return P;
174        }
175        if (P.ring.coFac.isField()) { // make monic
176            return P.multiplyLeft(d.inverse()); // avoid the divisions
177            //return P.multiply( d.inverse() ); // avoid the divisions
178        }
179        //GenSolvablePolynomial<C> pp = (GenSolvablePolynomial<C>) P.rightDivideCoeff(d); // rightDivide TODO/done
180        GenSolvablePolynomial<C> pp = (GenSolvablePolynomial<C>) P.leftDivideCoeff(d); // TODO
181        if (debug) {
182            GenSolvablePolynomial<C> p = pp.multiplyLeft(d);
183            if (!p.equals(P)) {
184                throw new ArithmeticException("pp(p)*cont(p) != p: ");
185            }
186        }
187        return pp;
188    }
189
190
191    /**
192     * GenSolvablePolynomial right base coefficient primitive part.
193     * @param P GenSolvablePolynomial.
194     * @return pp(P) with cont(P)*pp(P) = P.
195     */
196    public GenSolvablePolynomial<C> rightBasePrimitivePart(GenSolvablePolynomial<C> P) {
197        if (P == null) {
198            throw new IllegalArgumentException("P == null");
199        }
200        if (P.isZERO()) {
201            return P;
202        }
203        C d = rightBaseContent(P);
204        if (d.isONE()) {
205            return P;
206        }
207        if (P.ring.coFac.isField()) { // make monic
208            return P.multiplyLeft(d.inverse()); // avoid the divisions
209        }
210        GenSolvablePolynomial<C> pp = (GenSolvablePolynomial<C>) P.leftDivideCoeff(d); // leftDivide TODO/done
211        if (debug) {
212            GenSolvablePolynomial<C> p = pp.multiplyLeft(d);
213            if (!p.equals(P)) {
214                throw new ArithmeticException("pp(p)*cont(p) != p: ");
215            }
216        }
217        return pp;
218    }
219
220
221    /**
222     * Univariate GenSolvablePolynomial greatest common divisor. Uses sparse
223     * pseudoRemainder for remainder.
224     * @param P univariate GenSolvablePolynomial.
225     * @param S univariate GenSolvablePolynomial.
226     * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S).
227     */
228    public abstract GenSolvablePolynomial<C> leftBaseGcd(GenSolvablePolynomial<C> P,
229                    GenSolvablePolynomial<C> S);
230
231
232    /**
233     * Univariate GenSolvablePolynomial right greatest common divisor. Uses
234     * sparse pseudoRemainder for remainder.
235     * @param P univariate GenSolvablePolynomial.
236     * @param S univariate GenSolvablePolynomial.
237     * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'.
238     */
239    public abstract GenSolvablePolynomial<C> rightBaseGcd(GenSolvablePolynomial<C> P,
240                    GenSolvablePolynomial<C> S);
241
242
243    /**
244     * GenSolvablePolynomial commuting recursive content.
245     * @param P recursive GenSolvablePolynomial with commuting main and
246     *            coefficient variables.
247     * @return cont(P) with cont(P)*pp(P) = pp(P)*cont(P).
248     */
249    public GenSolvablePolynomial<C> recursiveContent(GenSolvablePolynomial<GenPolynomial<C>> P) {
250        if (P == null) {
251            throw new IllegalArgumentException("P == null");
252        }
253        if (P instanceof RecSolvablePolynomial) {
254            RecSolvablePolynomialRing<C> rfac = (RecSolvablePolynomialRing<C>) P.ring;
255            if (!rfac.coeffTable.isEmpty()) {
256                throw new IllegalArgumentException("P is a RecSolvablePolynomial, use recursiveContent()");
257            }
258        }
259        if (P.isZERO()) {
260            return (GenSolvablePolynomial<C>) P.ring.getZEROCoefficient();
261        }
262        if (P.isONE()) {
263            return (GenSolvablePolynomial<C>) P.ring.getONECoefficient();
264        }
265        if (P.leadingBaseCoefficient().isONE()) {
266            return (GenSolvablePolynomial<C>) P.ring.getONECoefficient();
267        }
268        //GenSolvablePolynomial<GenPolynomial<C>> p = P;
269        GenSolvablePolynomial<C> d = null;
270        for (GenPolynomial<C> cp : P.getMap().values()) {
271            GenSolvablePolynomial<C> c = (GenSolvablePolynomial<C>) cp;
272            if (d == null) {
273                d = c;
274            } else {
275                ///d = leftGcd(d, c); // go to recursion
276                d = rightGcd(d, c); // go to recursion
277            }
278            if (d.isONE()) {
279                return d;
280            }
281        }
282        return (GenSolvablePolynomial<C>) d.abs();
283    }
284
285
286    /**
287     * GenSolvablePolynomial right recursive content.
288     * @param P recursive GenSolvablePolynomial.
289     * @return cont(P) with pp(P)*cont(P) = P.
290     */
291    public GenSolvablePolynomial<C> rightRecursiveContent(GenSolvablePolynomial<GenPolynomial<C>> P) {
292        if (P == null) {
293            throw new IllegalArgumentException("P != null");
294        }
295        if (P.isZERO()) {
296            return (GenSolvablePolynomial<C>) P.ring.getZEROCoefficient();
297        }
298        if (P.leadingBaseCoefficient().isONE()) {
299            return (GenSolvablePolynomial<C>) P.ring.getONECoefficient();
300        }
301        GenSolvablePolynomial<C> d = null, cs = null, x;
302        GenSolvablePolynomial<GenPolynomial<C>> Pr = P.rightRecursivePolynomial();
303        logger.info("RI-recCont: P = " + P + ", right(P) = " + Pr);
304        for (GenPolynomial<C> c : Pr.getMap().values()) {
305            cs = (GenSolvablePolynomial<C>) c;
306            if (d == null) {
307                d = cs;
308            } else {
309                x = d;
310                d = leftGcd(d, cs); // go to recursion, P = P'*gcd(P,S)
311                ///d = rightGcd(d, cs); // go to recursion,  P = gcd(P,S)*P'
312                logger.info("RI-recCont: d = " + x + ", cs = " + cs + ", d = " + d);
313            }
314            if (d.isONE()) {
315                return d;
316            }
317        }
318        return (GenSolvablePolynomial<C>) d.abs();
319    }
320
321
322    /**
323     * GenSolvablePolynomial right recursive primitive part.
324     * @param P recursive GenSolvablePolynomial.
325     * @return pp(P) with pp(P)*cont(P) = P.
326     */
327    public GenSolvablePolynomial<GenPolynomial<C>> rightRecursivePrimitivePart(
328                    GenSolvablePolynomial<GenPolynomial<C>> P) {
329        if (P == null) {
330            throw new IllegalArgumentException("P == null");
331        }
332        if (P.isZERO()) {
333            return P;
334        }
335        GenSolvablePolynomial<C> d = rightRecursiveContent(P);
336        if (d.isONE()) {
337            return P;
338        }
339        GenSolvablePolynomial<GenPolynomial<C>> pp;
340        pp = FDUtil.<C> recursiveLeftDivide(P, d); //RightEval
341        if (debug) { // not checkable
342            if (!P.equals(pp.multiply(d))) {
343                System.out.println("RI-ppart, P         = " + P);
344                System.out.println("RI-ppart, cont(P)   = " + d);
345                System.out.println("RI-ppart, pp(P)     = " + pp);
346                System.out.println("RI-ppart, pp(P)c(P) = " + pp.multiply(d));
347                throw new RuntimeException("RI-primitivePart: P != pp(P)*cont(P)");
348            }
349        }
350        return pp;
351    }
352
353
354    /**
355     * GenSolvablePolynomial left recursive content.
356     * @param P recursive GenSolvablePolynomial.
357     * @return cont(P) with cont(P)*pp(P) = P.
358     */
359    public GenSolvablePolynomial<C> leftRecursiveContent(GenSolvablePolynomial<GenPolynomial<C>> P) {
360        if (P == null) {
361            throw new IllegalArgumentException("P != null");
362        }
363        if (P.isZERO()) {
364            return (GenSolvablePolynomial<C>) P.ring.getZEROCoefficient();
365        }
366        if (P.leadingBaseCoefficient().isONE()) {
367            return (GenSolvablePolynomial<C>) P.ring.getONECoefficient();
368        }
369        GenSolvablePolynomial<C> d = null, cs = null;
370        GenSolvablePolynomial<GenPolynomial<C>> Pr = P; //FDUtil.<C> rightRecursivePolynomial(P);
371        logger.info("recCont: P = " + P + ", right(P) = " + Pr);
372        for (GenPolynomial<C> c : Pr.getMap().values()) {
373            cs = (GenSolvablePolynomial<C>) c;
374            if (d == null) {
375                d = cs;
376            } else {
377                d = rightGcd(d, cs); // go to recursion
378                ///d = leftGcd(d, cs); // go to recursion
379                logger.info("recCont: cs = " + cs + ", d = " + d);
380            }
381            if (d.isONE()) {
382                return d;
383            }
384        }
385        return (GenSolvablePolynomial<C>) d.abs();
386    }
387
388
389    /**
390     * GenSolvablePolynomial left recursive primitive part.
391     * @param P recursive GenSolvablePolynomial.
392     * @return pp(P) with cont(P)*pp(P) = P.
393     */
394    public GenSolvablePolynomial<GenPolynomial<C>> leftRecursivePrimitivePart(
395                    GenSolvablePolynomial<GenPolynomial<C>> P) {
396        if (P == null) {
397            throw new IllegalArgumentException("P == null");
398        }
399        if (P.isZERO()) {
400            return P;
401        }
402        GenSolvablePolynomial<C> d = leftRecursiveContent(P);
403        if (d.isONE()) {
404            return P;
405        }
406        GenSolvablePolynomial<GenPolynomial<C>> pp;
407        pp = FDUtil.<C> recursiveRightDivide(P, d);
408        if (debug) { // not checkable
409            if (!P.equals(pp.multiplyLeft(d))) {
410                System.out.println("ppart, P         = " + P);
411                System.out.println("ppart, cont(P)   = " + d);
412                System.out.println("ppart, pp(P)     = " + pp);
413                System.out.println("ppart, pp(P)c(P) = " + pp.multiplyLeft(d));
414                throw new RuntimeException("primitivePart: P != cont(P)*pp(P)");
415            }
416        }
417        return pp;
418    }
419
420
421    /**
422     * GenSolvablePolynomial base recursive content.
423     * @param P recursive GenSolvablePolynomial.
424     * @return baseCont(P) with pp(P)*cont(P) = P.
425     */
426    public C baseRecursiveContent(GenSolvablePolynomial<GenPolynomial<C>> P) {
427        if (P == null) {
428            throw new IllegalArgumentException("P == null");
429        }
430        if (P.isZERO()) {
431            GenSolvablePolynomialRing<C> cf = (GenSolvablePolynomialRing<C>) P.ring.coFac;
432            return cf.coFac.getZERO();
433        }
434        C d = null;
435        for (GenPolynomial<C> cp : P.getMap().values()) {
436            GenSolvablePolynomial<C> c = (GenSolvablePolynomial<C>) cp;
437            C cc = leftBaseContent(c);
438            if (d == null) {
439                d = cc;
440            } else {
441                d = gcd(d, cc);
442            }
443            if (d.isONE()) {
444                return d;
445            }
446        }
447        return d.abs();
448    }
449
450
451    /**
452     * GenSolvablePolynomial base recursive primitive part.
453     * @param P recursive GenSolvablePolynomial.
454     * @return basePP(P) with pp(P)*cont(P) = P.
455     */
456    public GenSolvablePolynomial<GenPolynomial<C>> baseRecursivePrimitivePart(
457                    GenSolvablePolynomial<GenPolynomial<C>> P) {
458        if (P == null) {
459            throw new IllegalArgumentException("P == null");
460        }
461        if (P.isZERO()) {
462            return P;
463        }
464        C d = baseRecursiveContent(P);
465        if (d.isONE()) {
466            return P;
467        }
468        GenSolvablePolynomial<GenPolynomial<C>> pp = (GenSolvablePolynomial<GenPolynomial<C>>) PolyUtil
469                        .<C> baseRecursiveDivide(P, d);
470        return pp;
471    }
472
473
474    /**
475     * GenSolvablePolynomial left recursive greatest common divisor. Uses
476     * pseudoRemainder for remainder.
477     * @param P recursive GenSolvablePolynomial.
478     * @param S recursive GenSolvablePolynomial.
479     * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where
480     *         deg_main(p) = deg_main(s) == 0.
481     */
482    @SuppressWarnings("unchecked")
483    public GenSolvablePolynomial<GenPolynomial<C>> leftRecursiveGcd(GenSolvablePolynomial<GenPolynomial<C>> P,
484                    GenSolvablePolynomial<GenPolynomial<C>> S) {
485        if (S == null || S.isZERO()) {
486            return P;
487        }
488        if (P == null || P.isZERO()) {
489            return S;
490        }
491        if (P.ring.nvar == 1) {
492            return leftRecursiveUnivariateGcd(P, S);
493        }
494        // distributed polynomials gcd
495        GenSolvablePolynomialRing<GenPolynomial<C>> rfac = P.ring;
496        GenSolvablePolynomialRing<C> dfac;
497        if (rfac instanceof RecSolvablePolynomialRing) {
498            RecSolvablePolynomialRing<C> rf = (RecSolvablePolynomialRing<C>) rfac;
499            dfac = RecSolvablePolynomialRing.<C> distribute(rf);
500        } else {
501            GenSolvablePolynomialRing<C> df = (GenSolvablePolynomialRing) rfac;
502            dfac = df.distribute();
503        }
504        GenSolvablePolynomial<C> Pd = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(dfac, P);
505        GenSolvablePolynomial<C> Sd = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(dfac, S);
506        GenSolvablePolynomial<C> Dd = leftGcd(Pd, Sd);
507        // convert to recursive
508        GenSolvablePolynomial<GenPolynomial<C>> C = (GenSolvablePolynomial<GenPolynomial<C>>) PolyUtil
509                        .<C> recursive(rfac, Dd);
510        return C;
511    }
512
513
514    /**
515     * GenSolvablePolynomial right recursive greatest common divisor. Uses
516     * pseudoRemainder for remainder.
517     * @param P recursive GenSolvablePolynomial.
518     * @param S recursive GenSolvablePolynomial.
519     * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where
520     *         deg_main(p) = deg_main(s) == 0.
521     */
522    @SuppressWarnings("unchecked")
523    public GenSolvablePolynomial<GenPolynomial<C>> rightRecursiveGcd(
524                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S) {
525        if (S == null || S.isZERO()) {
526            return P;
527        }
528        if (P == null || P.isZERO()) {
529            return S;
530        }
531        if (P.ring.nvar == 1) {
532            return rightRecursiveUnivariateGcd(P, S);
533        }
534        // distributed polynomials gcd
535        GenSolvablePolynomialRing<GenPolynomial<C>> rfac = P.ring;
536        GenSolvablePolynomialRing<C> dfac;
537        if (rfac instanceof RecSolvablePolynomialRing) {
538            RecSolvablePolynomialRing<C> rf = (RecSolvablePolynomialRing<C>) rfac;
539            dfac = RecSolvablePolynomialRing.<C> distribute(rf);
540        } else {
541            GenSolvablePolynomialRing<C> df = (GenSolvablePolynomialRing) rfac;
542            dfac = df.distribute();
543        }
544        GenSolvablePolynomial<C> Pd = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(dfac, P);
545        GenSolvablePolynomial<C> Sd = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(dfac, S);
546        GenSolvablePolynomial<C> Dd = rightGcd(Pd, Sd);
547        // convert to recursive
548        GenSolvablePolynomial<GenPolynomial<C>> C = (GenSolvablePolynomial<GenPolynomial<C>>) PolyUtil
549                        .<C> recursive(rfac, Dd);
550        return C;
551    }
552
553
554    /**
555     * Univariate GenSolvablePolynomial recursive greatest common divisor. Uses
556     * pseudoRemainder for remainder.
557     * @param P univariate recursive GenSolvablePolynomial.
558     * @param S univariate recursive GenSolvablePolynomial.
559     * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where
560     *         deg_main(p) = deg_main(s) == 0.
561     */
562    public abstract GenSolvablePolynomial<GenPolynomial<C>> leftRecursiveUnivariateGcd(
563                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S);
564
565
566    /**
567     * Univariate GenSolvablePolynomial right recursive greatest common divisor.
568     * Uses pseudoRemainder for remainder.
569     * @param P univariate recursive GenSolvablePolynomial.
570     * @param S univariate recursive GenSolvablePolynomial.
571     * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where
572     *         deg_main(p) = deg_main(s) == 0.
573     */
574    public abstract GenSolvablePolynomial<GenPolynomial<C>> rightRecursiveUnivariateGcd(
575                    GenSolvablePolynomial<GenPolynomial<C>> P, GenSolvablePolynomial<GenPolynomial<C>> S);
576
577
578    /**
579     * GenSolvablePolynomial right content.
580     * @param P GenSolvablePolynomial.
581     * @return cont(P) with pp(P)*cont(P) = P.
582     */
583    public GenSolvablePolynomial<C> rightContent(GenSolvablePolynomial<C> P) {
584        if (P == null) {
585            throw new IllegalArgumentException("P == null");
586        }
587        GenSolvablePolynomialRing<C> pfac = P.ring;
588        if (pfac.nvar <= 1) {
589            // baseContent not possible by return type
590            throw new IllegalArgumentException("use baseContent() for univariate polynomials");
591        }
592        GenSolvablePolynomialRing<GenPolynomial<C>> rfac // = (RecSolvablePolynomialRing<C>) 
593                        = pfac.recursive(1);
594
595        GenSolvablePolynomial<GenPolynomial<C>> Pr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac,
596                        P);
597        GenSolvablePolynomial<C> D = rightRecursiveContent(Pr);
598        return D;
599    }
600
601
602    /**
603     * GenSolvablePolynomial right primitive part.
604     * @param P GenSolvablePolynomial.
605     * @return pp(P) with pp(P)*cont(P) = P.
606     */
607    public GenSolvablePolynomial<C> rightPrimitivePart(GenSolvablePolynomial<C> P) {
608        if (P == null) {
609            throw new IllegalArgumentException("P == null");
610        }
611        if (P.isZERO()) {
612            return P;
613        }
614        GenSolvablePolynomialRing<C> pfac = P.ring;
615        if (pfac.nvar <= 1) {
616            return rightBasePrimitivePart(P);
617        }
618        GenSolvablePolynomialRing<GenPolynomial<C>> rfac = /*(RecSolvablePolynomialRing<C>)*/pfac
619                        .recursive(1);
620
621        GenSolvablePolynomial<GenPolynomial<C>> Pr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac,
622                        P);
623        GenSolvablePolynomial<GenPolynomial<C>> PP = rightRecursivePrimitivePart(Pr);
624
625        GenSolvablePolynomial<C> D = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(pfac, PP);
626        return D;
627    }
628
629
630    /**
631     * GenSolvablePolynomial left content.
632     * @param P GenSolvablePolynomial.
633     * @return cont(P) with cont(P)*pp(P) = P.
634     */
635    public GenSolvablePolynomial<C> leftContent(GenSolvablePolynomial<C> P) {
636        if (P == null) {
637            throw new IllegalArgumentException("P == null");
638        }
639        GenSolvablePolynomialRing<C> pfac = P.ring;
640        if (pfac.nvar <= 1) {
641            // baseContent not possible by return type
642            throw new IllegalArgumentException("use baseContent() for univariate polynomials");
643        }
644        GenSolvablePolynomialRing<GenPolynomial<C>> rfac // = (RecSolvablePolynomialRing<C>) 
645                        = pfac.recursive(1);
646
647        GenSolvablePolynomial<GenPolynomial<C>> Pr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac,
648                        P);
649        GenSolvablePolynomial<C> D = leftRecursiveContent(Pr);
650        return D;
651    }
652
653
654    /**
655     * GenSolvablePolynomial left primitive part.
656     * @param P GenSolvablePolynomial.
657     * @return pp(P) with cont(P)*pp(P) = P.
658     */
659    public GenSolvablePolynomial<C> leftPrimitivePart(GenSolvablePolynomial<C> P) {
660        if (P == null) {
661            throw new IllegalArgumentException("P == null");
662        }
663        if (P.isZERO()) {
664            return P;
665        }
666        GenSolvablePolynomialRing<C> pfac = P.ring;
667        if (pfac.nvar <= 1) {
668            return leftBasePrimitivePart(P);
669        }
670        GenSolvablePolynomialRing<GenPolynomial<C>> rfac = /*(RecSolvablePolynomialRing<C>)*/pfac
671                        .recursive(1);
672
673        GenSolvablePolynomial<GenPolynomial<C>> Pr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac,
674                        P);
675        GenSolvablePolynomial<GenPolynomial<C>> PP = leftRecursivePrimitivePart(Pr);
676
677        GenSolvablePolynomial<C> D = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(pfac, PP);
678        return D;
679    }
680
681
682    /**
683     * GenSolvablePolynomial division. Indirection to GenSolvablePolynomial
684     * method.
685     * @param a GenSolvablePolynomial.
686     * @param b coefficient.
687     * @return a' = a/b with a = a'*b.
688     */
689    public GenSolvablePolynomial<C> divide(GenSolvablePolynomial<C> a, C b) {
690        if (b == null || b.isZERO()) {
691            throw new IllegalArgumentException("division by zero");
692
693        }
694        if (a == null || a.isZERO()) {
695            return a;
696        }
697        return (GenSolvablePolynomial<C>) a.divide(b);
698    }
699
700
701    /*
702     * GenSolvablePolynomial right division. Indirection to GenSolvablePolynomial
703     * method.
704     * @param a GenSolvablePolynomial.
705     * @param b coefficient.
706     * @return a' = a/b with a = b*a'.
707    public GenSolvablePolynomial<C> rightDivide(GenSolvablePolynomial<C> a, C b) {
708        if (b == null || b.isZERO()) {
709            throw new IllegalArgumentException("division by zero");
710    
711        }
712        if (a == null || a.isZERO()) {
713            return a;
714        }
715        return (GenSolvablePolynomial<C>) a.rightDivide(b);
716    }
717     */
718
719
720    /**
721     * Coefficient greatest common divisor. Indirection to coefficient method.
722     * @param a coefficient.
723     * @param b coefficient.
724     * @return gcd(a,b) with a = a'*gcd(a,b) and b = b'*gcd(a,b).
725     */
726    public C gcd(C a, C b) {
727        if (b == null || b.isZERO()) {
728            return a;
729        }
730        if (a == null || a.isZERO()) {
731            return b;
732        }
733        return a.gcd(b);
734    }
735
736
737    /**
738     * GenSolvablePolynomial greatest common divisor.
739     * @param P GenSolvablePolynomial.
740     * @param S GenSolvablePolynomial.
741     * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where
742     *         deg_main(p) = deg_main(s) == 0.
743     */
744    public GenSolvablePolynomial<C> leftGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
745        if (S == null || S.isZERO()) {
746            return P;
747        }
748        if (P == null || P.isZERO()) {
749            return S;
750        }
751        if (P.isONE()) {
752            return P;
753        }
754        if (S.isONE()) {
755            return S;
756        }
757        GenSolvablePolynomialRing<C> pfac = P.ring;
758        if (pfac.nvar <= 1) {
759            GenSolvablePolynomial<C> T = leftBaseGcd(P, S);
760            return T;
761        }
762        GenSolvablePolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); //RecSolvablePolynomialRing<C>
763        GenSolvablePolynomial<GenPolynomial<C>> Pr, Sr, Dr;
764        Pr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac, P);
765        Sr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac, S);
766        Dr = leftRecursiveUnivariateGcd(Pr, Sr);
767        GenSolvablePolynomial<C> D = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(pfac, Dr);
768        if (debug) { // not checkable
769            GenSolvablePolynomial<C> ps = FDUtil.<C> rightBaseSparsePseudoRemainder(P, D);
770            GenSolvablePolynomial<C> ss = FDUtil.<C> rightBaseSparsePseudoRemainder(S, D);
771            if (!ps.isZERO() || !ss.isZERO()) {
772                System.out.println("fullGcd, D  = " + D);
773                System.out.println("fullGcd, P  = " + P);
774                System.out.println("fullGcd, S  = " + S);
775                System.out.println("fullGcd, ps = " + ps);
776                System.out.println("fullGcd, ss = " + ss);
777                throw new RuntimeException("fullGcd: not divisible");
778            }
779            logger.info("fullGcd(P,S) okay: D = " + D + ", P = " + P + ", S = " + S);
780        }
781        return D;
782    }
783
784
785    /**
786     * GenSolvablePolynomial left least common multiple.
787     * @param P GenSolvablePolynomial.
788     * @param S GenSolvablePolynomial.
789     * @return lcm(P,S) with lcm(P,S) = P'*P = S'*S.
790     */
791    public GenSolvablePolynomial<C> leftLcm(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
792        GenSolvablePolynomial<C>[] oc = leftOreCond(P, S);
793        return oc[0].multiply(P);
794    }
795
796
797    /**
798     * GenSolvablePolynomial right greatest common divisor.
799     * @param P GenSolvablePolynomial.
800     * @param S GenSolvablePolynomial.
801     * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where
802     *         deg_main(p) = deg_main(s) == 0.
803     */
804    public GenSolvablePolynomial<C> rightGcd(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
805        if (S == null || S.isZERO()) {
806            return P;
807        }
808        if (P == null || P.isZERO()) {
809            return S;
810        }
811        if (P.isONE()) {
812            return P;
813        }
814        if (S.isONE()) {
815            return S;
816        }
817        GenSolvablePolynomialRing<C> pfac = P.ring;
818        if (pfac.nvar <= 1) {
819            GenSolvablePolynomial<C> T = rightBaseGcd(P, S);
820            return T;
821        }
822        GenSolvablePolynomialRing<GenPolynomial<C>> rfac = pfac.recursive(1); //RecSolvablePolynomialRing<C>
823        GenSolvablePolynomial<GenPolynomial<C>> Pr, Sr, Dr;
824        Pr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac, P);
825        Sr = (RecSolvablePolynomial<C>) PolyUtil.<C> recursive(rfac, S);
826        Dr = rightRecursiveUnivariateGcd(Pr, Sr);
827        GenSolvablePolynomial<C> D = (GenSolvablePolynomial<C>) PolyUtil.<C> distribute(pfac, Dr);
828        if (debug) { // not checkable
829            GenSolvablePolynomial<C> ps = FDUtil.<C> leftBaseSparsePseudoRemainder(P, D);
830            GenSolvablePolynomial<C> ss = FDUtil.<C> leftBaseSparsePseudoRemainder(S, D);
831            if (!ps.isZERO() || !ss.isZERO()) {
832                System.out.println("RI-fullGcd, D  = " + D);
833                System.out.println("RI-fullGcd, P  = " + P);
834                System.out.println("RI-fullGcd, S  = " + S);
835                System.out.println("RI-fullGcd, ps = " + ps);
836                System.out.println("RI-fullGcd, ss = " + ss);
837                throw new RuntimeException("RI-fullGcd: not divisible");
838            }
839            logger.info("RI-fullGcd(P,S) okay: D = " + D);
840        }
841        return D;
842    }
843
844
845    /**
846     * GenSolvablePolynomial right least common multiple.
847     * @param P GenSolvablePolynomial.
848     * @param S GenSolvablePolynomial.
849     * @return lcm(P,S) with lcm(P,S) = P*P' = S*S'.
850     */
851    public GenSolvablePolynomial<C> rightLcm(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S) {
852        GenSolvablePolynomial<C>[] oc = rightOreCond(P, S);
853        return P.multiply(oc[0]);
854    }
855
856
857    /**
858     * List of GenSolvablePolynomials left greatest common divisor.
859     * @param A non empty list of GenSolvablePolynomials.
860     * @return gcd(A_i) with A_i = A'_i*gcd(A_i)*a_i, where deg_main(a_i) == 0.
861     */
862    public GenSolvablePolynomial<C> leftGcd(List<GenSolvablePolynomial<C>> A) {
863        if (A == null || A.isEmpty()) {
864            throw new IllegalArgumentException("A may not be empty");
865        }
866        GenSolvablePolynomial<C> g = A.get(0);
867        for (int i = 1; i < A.size(); i++) {
868            GenSolvablePolynomial<C> f = A.get(i);
869            g = leftGcd(g, f);
870        }
871        return g;
872    }
873
874
875    /**
876     * GenSolvablePolynomial co-prime list.
877     * @param A list of GenSolvablePolynomials.
878     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
879     *         a in A there exists b in B with b|a. B does not contain zero or
880     *         constant polynomials.
881     */
882    public List<GenSolvablePolynomial<C>> leftCoPrime(List<GenSolvablePolynomial<C>> A) {
883        if (A == null || A.isEmpty()) {
884            return A;
885        }
886        List<GenSolvablePolynomial<C>> B = new ArrayList<GenSolvablePolynomial<C>>(A.size());
887        // make a coprime to rest of list
888        GenSolvablePolynomial<C> a = A.get(0);
889        //System.out.println("a = " + a);
890        if (!a.isZERO() && !a.isConstant()) {
891            for (int i = 1; i < A.size(); i++) {
892                GenSolvablePolynomial<C> b = A.get(i);
893                GenSolvablePolynomial<C> g = leftGcd(a, b);
894                if (!g.isONE()) {
895                    a = FDUtil.<C> leftBasePseudoQuotient(a, g);
896                    b = FDUtil.<C> leftBasePseudoQuotient(b, g);
897                    GenSolvablePolynomial<C> gp = leftGcd(a, g); //.abs();
898                    while (!gp.isONE()) {
899                        a = FDUtil.<C> leftBasePseudoQuotient(a, gp);
900                        g = FDUtil.<C> leftBasePseudoQuotient(g, gp);
901                        B.add(g); // gcd(a,g) == 1
902                        g = gp;
903                        gp = leftGcd(a, gp);
904                    }
905                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
906                        B.add(g); // gcd(a,g) == 1
907                    }
908                }
909                if (!b.isZERO() && !b.isConstant()) {
910                    B.add(b); // gcd(a,b) == 1
911                }
912            }
913        } else {
914            B.addAll(A.subList(1, A.size()));
915        }
916        // make rest coprime
917        B = leftCoPrime(B);
918        //System.out.println("B = " + B);
919        if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
920            a = (GenSolvablePolynomial<C>) a.abs();
921            B.add(a);
922        }
923        return B;
924    }
925
926
927    /**
928     * GenSolvablePolynomial left co-prime list.
929     * @param A list of GenSolvablePolynomials.
930     * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant
931     *         a in A there exists b in B with b|a. B does not contain zero or
932     *         constant polynomials.
933     */
934    public List<GenSolvablePolynomial<C>> leftCoPrimeRec(List<GenSolvablePolynomial<C>> A) {
935        if (A == null || A.isEmpty()) {
936            return A;
937        }
938        List<GenSolvablePolynomial<C>> B = new ArrayList<GenSolvablePolynomial<C>>();
939        // make a co-prime to rest of list
940        for (GenSolvablePolynomial<C> a : A) {
941            //System.out.println("a = " + a);
942            B = leftCoPrime(a, B);
943            //System.out.println("B = " + B);
944        }
945        return B;
946    }
947
948
949    /**
950     * GenSolvablePolynomial left co-prime list.
951     * @param a GenSolvablePolynomial.
952     * @param P co-prime list of GenSolvablePolynomials.
953     * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a
954     *         there exists b in P with b|a. B does not contain zero or constant
955     *         polynomials.
956     */
957    public List<GenSolvablePolynomial<C>> leftCoPrime(GenSolvablePolynomial<C> a,
958                    List<GenSolvablePolynomial<C>> P) {
959        if (a == null || a.isZERO() || a.isConstant()) {
960            return P;
961        }
962        List<GenSolvablePolynomial<C>> B = new ArrayList<GenSolvablePolynomial<C>>(P.size() + 1);
963        // make a coprime to elements of the list P
964        for (int i = 0; i < P.size(); i++) {
965            GenSolvablePolynomial<C> b = P.get(i);
966            GenSolvablePolynomial<C> g = leftGcd(a, b);
967            if (!g.isONE()) {
968                a = FDUtil.<C> leftBasePseudoQuotient(a, g);
969                b = FDUtil.<C> leftBasePseudoQuotient(b, g);
970                // make g co-prime to new a, g is co-prime to c != b in P, B
971                GenSolvablePolynomial<C> gp = leftGcd(a, g);
972                while (!gp.isONE()) {
973                    a = FDUtil.<C> leftBasePseudoQuotient(a, gp);
974                    g = FDUtil.<C> leftBasePseudoQuotient(g, gp);
975                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
976                        B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
977                    }
978                    g = gp;
979                    gp = leftGcd(a, gp);
980                }
981                // make new g co-prime to new b
982                gp = leftGcd(b, g);
983                while (!gp.isONE()) {
984                    b = FDUtil.<C> leftBasePseudoQuotient(b, gp);
985                    g = FDUtil.<C> leftBasePseudoQuotient(g, gp);
986                    if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
987                        B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
988                    }
989                    g = gp;
990                    gp = leftGcd(b, gp);
991                }
992                if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) {
993                    B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B
994                }
995            }
996            if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) {
997                B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B
998            }
999        }
1000        if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) {
1001            B.add(a);
1002        }
1003        return B;
1004    }
1005
1006
1007    /**
1008     * GenSolvablePolynomial test for co-prime list.
1009     * @param A list of GenSolvablePolynomials.
1010     * @return true if gcd(b,c) = 1 for all b != c in B, else false.
1011     */
1012    public boolean isLeftCoPrime(List<GenSolvablePolynomial<C>> A) {
1013        if (A == null || A.isEmpty()) {
1014            return true;
1015        }
1016        if (A.size() == 1) {
1017            return true;
1018        }
1019        for (int i = 0; i < A.size(); i++) {
1020            GenSolvablePolynomial<C> a = A.get(i);
1021            for (int j = i + 1; j < A.size(); j++) {
1022                GenSolvablePolynomial<C> b = A.get(j);
1023                GenSolvablePolynomial<C> g = leftGcd(a, b);
1024                if (!g.isONE()) {
1025                    System.out.println("not co-prime, a: " + a);
1026                    System.out.println("not co-prime, b: " + b);
1027                    System.out.println("not co-prime, g: " + g);
1028                    return false;
1029                }
1030            }
1031        }
1032        return true;
1033    }
1034
1035
1036    /**
1037     * GenSolvablePolynomial test for left co-prime list of given list.
1038     * @param A list of GenSolvablePolynomials.
1039     * @param P list of co-prime GenSolvablePolynomials.
1040     * @return true if isCoPrime(P) and for all a in A exists p in P with p | a,
1041     *         else false.
1042     */
1043    public boolean isLeftCoPrime(List<GenSolvablePolynomial<C>> P, List<GenSolvablePolynomial<C>> A) {
1044        if (!isLeftCoPrime(P)) {
1045            return false;
1046        }
1047        if (A == null || A.isEmpty()) {
1048            return true;
1049        }
1050        for (GenSolvablePolynomial<C> q : A) {
1051            if (q.isZERO() || q.isConstant()) {
1052                continue;
1053            }
1054            boolean divides = false;
1055            for (GenSolvablePolynomial<C> p : P) {
1056                GenSolvablePolynomial<C> a = FDUtil.<C> leftBaseSparsePseudoRemainder(q, p);
1057                if (a.isZERO()) { // p divides q
1058                    divides = true;
1059                    break;
1060                }
1061            }
1062            if (!divides) {
1063                System.out.println("no divisor for: " + q);
1064                return false;
1065            }
1066        }
1067        return true;
1068    }
1069
1070
1071    /**
1072     * Univariate GenSolvablePolynomial extended greatest common divisor. Uses
1073     * sparse pseudoRemainder for remainder.
1074     * @param P univariate GenSolvablePolynomial.
1075     * @param S univariate GenSolvablePolynomial.
1076     * @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S).
1077     */
1078    @SuppressWarnings({ "unchecked", "cast" })
1079    public GenSolvablePolynomial<C>[] baseExtendedGcd(GenSolvablePolynomial<C> P,
1080                    GenSolvablePolynomial<C> S) {
1081        //return P.egcd(S);
1082        GenSolvablePolynomial<C>[] hegcd = baseHalfExtendedGcd(P, S);
1083        GenSolvablePolynomial<C>[] ret = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[3];
1084        ret[0] = hegcd[0];
1085        ret[1] = hegcd[1];
1086        GenSolvablePolynomial<C> x = (GenSolvablePolynomial<C>) hegcd[0].subtract(hegcd[1].multiply(P));
1087        GenSolvablePolynomial<C>[] qr = FDUtil.<C> leftBasePseudoQuotientRemainder(x, S);
1088        // assert qr[1].isZERO() 
1089        ret[2] = qr[0];
1090        return ret;
1091    }
1092
1093
1094    /**
1095     * Univariate GenSolvablePolynomial half extended greatest comon divisor.
1096     * Uses sparse pseudoRemainder for remainder.
1097     * @param S GenSolvablePolynomial.
1098     * @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S).
1099     */
1100    @SuppressWarnings({ "unchecked", "cast" })
1101    public GenSolvablePolynomial<C>[] baseHalfExtendedGcd(GenSolvablePolynomial<C> P,
1102                    GenSolvablePolynomial<C> S) {
1103        if (P == null || S == null) {
1104            throw new IllegalArgumentException("null P or S not allowed");
1105        }
1106        GenSolvablePolynomial<C>[] ret = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
1107        ret[0] = null;
1108        ret[1] = null;
1109        if (S.isZERO()) {
1110            ret[0] = P;
1111            ret[1] = P.ring.getONE();
1112            return ret;
1113        }
1114        if (P.isZERO()) {
1115            ret[0] = S;
1116            ret[1] = S.ring.getZERO();
1117            return ret;
1118        }
1119        if (P.ring.nvar != 1) {
1120            throw new IllegalArgumentException("for univariate polynomials only " + P.ring);
1121        }
1122        GenSolvablePolynomial<C> q = P;
1123        GenSolvablePolynomial<C> r = S;
1124        GenSolvablePolynomial<C> c1 = P.ring.getONE().copy();
1125        GenSolvablePolynomial<C> d1 = P.ring.getZERO().copy();
1126        while (!r.isZERO()) {
1127            GenSolvablePolynomial<C>[] qr = FDUtil.<C> leftBasePseudoQuotientRemainder(q, r);
1128            //q.divideAndRemainder(r);
1129            q = qr[0];
1130            GenSolvablePolynomial<C> x = (GenSolvablePolynomial<C>) c1.subtract(q.multiply(d1));
1131            c1 = d1;
1132            d1 = x;
1133            q = r;
1134            r = qr[1];
1135        }
1136        // normalize ldcf(q) to 1, i.e. make monic
1137        C g = q.leadingBaseCoefficient();
1138        if (g.isUnit()) {
1139            C h = g.inverse();
1140            q = q.multiply(h);
1141            c1 = c1.multiply(h);
1142        }
1143        //assert ( ((c1.multiply(P)).remainder(S).equals(q) )); 
1144        ret[0] = q;
1145        ret[1] = c1;
1146        return ret;
1147    }
1148
1149
1150    /**
1151     * Univariate GenSolvablePolynomial greatest common divisor diophantine
1152     * version.
1153     * @param P univariate GenSolvablePolynomial.
1154     * @param S univariate GenSolvablePolynomial.
1155     * @param c univariate GenSolvablePolynomial.
1156     * @return [ a, b ] with a*P + b*S = c and deg(a) &lt; deg(S).
1157     */
1158    @SuppressWarnings({ "unchecked", "cast" })
1159    public GenSolvablePolynomial<C>[] baseGcdDiophant(GenSolvablePolynomial<C> P, GenSolvablePolynomial<C> S,
1160                    GenSolvablePolynomial<C> c) {
1161        GenSolvablePolynomial<C>[] egcd = baseExtendedGcd(P, S);
1162        GenSolvablePolynomial<C> g = egcd[0];
1163        GenSolvablePolynomial<C>[] qr = FDUtil.<C> leftBasePseudoQuotientRemainder(c, g);
1164        if (!qr[1].isZERO()) {
1165            throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g);
1166        }
1167        GenSolvablePolynomial<C> q = qr[0];
1168        GenSolvablePolynomial<C> a = egcd[1].multiply(q);
1169        GenSolvablePolynomial<C> b = egcd[2].multiply(q);
1170        if (!a.isZERO() && a.degree(0) >= S.degree(0)) {
1171            qr = FDUtil.<C> leftBasePseudoQuotientRemainder(a, S);
1172            a = qr[1];
1173            b = (GenSolvablePolynomial<C>) b.sum(P.multiply(qr[0]));
1174        }
1175        GenSolvablePolynomial<C>[] ret = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
1176        ret[0] = a;
1177        ret[1] = b;
1178        if (debug) {
1179            GenSolvablePolynomial<C> y = (GenSolvablePolynomial<C>) ret[0].multiply(P)
1180                            .sum(ret[1].multiply(S));
1181            if (!y.equals(c)) {
1182                System.out.println("P  = " + P);
1183                System.out.println("S  = " + S);
1184                System.out.println("c  = " + c);
1185                System.out.println("a  = " + a);
1186                System.out.println("b  = " + b);
1187                System.out.println("y  = " + y);
1188                throw new ArithmeticException("not diophant, x = " + y.subtract(c));
1189            }
1190        }
1191        return ret;
1192    }
1193
1194
1195    /**
1196     * Coefficient left Ore condition. Generators for the left Ore condition of
1197     * two coefficients.
1198     * @param a coefficient.
1199     * @param b coefficient.
1200     * @return [oa, ob] = leftOreCond(a,b), with oa*a == ob*b.
1201     */
1202    @SuppressWarnings("unchecked")
1203    public C[] leftOreCond(C a, C b) {
1204        if (a == null || a.isZERO() || b == null || b.isZERO()) {
1205            throw new IllegalArgumentException("a and b must be non zero");
1206        }
1207        C[] oc = (C[]) new GcdRingElem[2];
1208        if (a instanceof GenSolvablePolynomial && b instanceof GenSolvablePolynomial) {
1209            GenSolvablePolynomial ap = (GenSolvablePolynomial) a;
1210            GenSolvablePolynomial bp = (GenSolvablePolynomial) b;
1211            GenSolvablePolynomial[] ocp = leftOreCond(ap, bp);
1212            oc[0] = (C) ocp[0];
1213            oc[1] = (C) ocp[1];
1214            return oc;
1215        }
1216        RingFactory<C> rf = coFac; // not usable: (RingFactory<C>) a.factory();
1217        if (a.equals(b)) { // required because of rationals gcd
1218            oc[0] = rf.getONE();
1219            oc[1] = rf.getONE();
1220            logger.info("Ore multiple: " + Arrays.toString(oc));
1221            return oc;
1222        }
1223        if (a.equals(b.negate())) { // required because of rationals gcd
1224            oc[0] = rf.getONE();
1225            oc[1] = rf.getONE().negate();
1226            logger.info("Ore multiple: " + Arrays.toString(oc));
1227            return oc;
1228        }
1229        if (rf.isCommutative()) {
1230            if (debug) {
1231                logger.info("left Ore condition on coefficients, commutative case: " + a + ", " + b);
1232            }
1233            C gcd = a.gcd(b);
1234            if (gcd.isONE()) {
1235                oc[0] = b;
1236                oc[1] = a;
1237                if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) {
1238                    oc[0] = oc[0].negate();
1239                    oc[1] = oc[1].negate();
1240                }
1241                logger.info("Ore multiple: " + Arrays.toString(oc));
1242                return oc;
1243            }
1244            C p = a.multiply(b);
1245            C lcm = p.divide(gcd).abs();
1246            oc[0] = lcm.divide(a);
1247            oc[1] = lcm.divide(b);
1248            if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) {
1249                oc[0] = oc[0].negate();
1250                oc[1] = oc[1].negate();
1251            }
1252            logger.info("Ore multiple: lcm=" + lcm + ", gcd=" + gcd + ", " + Arrays.toString(oc));
1253            return oc;
1254        }
1255        // now non-commutative
1256        if (rf.isField()) {
1257            logger.info("left Ore condition on coefficients, skew field " + rf + " case: " + a + ", " + b);
1258            //C gcd = a.gcd(b); // always one 
1259            //C lcm = rf.getONE();
1260            oc[0] = a.inverse(); //lcm.divide(a);
1261            oc[1] = b.inverse(); //lcm.divide(b);
1262            logger.info("Ore multiple: " + Arrays.toString(oc));
1263            return oc;
1264        }
1265        if (b instanceof StarRingElem) {
1266            logger.info("left Ore condition on coefficients, StarRing case: " + a + ", " + b);
1267            C bs = (C) ((StarRingElem) b).conjugate();
1268            oc[0] = bs.multiply(b); // bar(b) b a = s a 
1269            oc[1] = a.multiply(bs); // a bar(b) b = a s
1270            logger.info("Ore multiple: " + Arrays.toString(oc));
1271            return oc;
1272        }
1273        throw new UnsupportedOperationException(
1274                        "leftOreCond not implemented for " + rf.getClass() + ", rf = " + rf.toScript());
1275        //return oc;
1276    }
1277
1278
1279    /**
1280     * Left Ore condition. Generators for the left Ore condition of two solvable
1281     * polynomials.
1282     * @param a solvable polynomial
1283     * @param b solvable polynomial
1284     * @return [p,q] with p*a = q*b
1285     */
1286    @SuppressWarnings({ "unchecked", "cast" })
1287    public GenSolvablePolynomial<C>[] leftOreCond(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) {
1288        if (a == null || a.isZERO() || b == null || b.isZERO()) {
1289            throw new IllegalArgumentException("a and b must be non zero");
1290        }
1291        GenSolvablePolynomialRing<C> pfac = a.ring;
1292        GenSolvablePolynomial<C>[] oc = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
1293        if (a.equals(b)) {
1294            oc[0] = pfac.getONE();
1295            oc[1] = pfac.getONE();
1296            return oc;
1297        }
1298        if (a.equals(b.negate())) {
1299            oc[0] = pfac.getONE();
1300            oc[1] = (GenSolvablePolynomial<C>) pfac.getONE().negate();
1301            return oc;
1302        }
1303        if (pfac.isCommutative()) {
1304            logger.info("left Ore condition, polynomial commutative case: " + a + ", " + b);
1305            edu.jas.ufd.GreatestCommonDivisorAbstract<C> cgcd = GCDFactory.<C> getImplementation(pfac.coFac);
1306            GenSolvablePolynomial<C> lcm = (GenSolvablePolynomial<C>) cgcd.lcm(a, b);
1307            //oc[0] = FDUtil.<C> basePseudoQuotient(lcm, a);
1308            //oc[1] = FDUtil.<C> basePseudoQuotient(lcm, b);
1309            oc[0] = (GenSolvablePolynomial<C>) PolyUtil.<C> basePseudoDivide(lcm, a);
1310            oc[1] = (GenSolvablePolynomial<C>) PolyUtil.<C> basePseudoDivide(lcm, b);
1311            logger.info("Ore multiple: " + lcm + ", " + Arrays.toString(oc));
1312            return oc;
1313        }
1314        oc = syz.leftOreCond(a, b);
1315        //logger.info("Ore multiple: " + oc[0].multiply(a) + ", " + Arrays.toString(oc));
1316        return oc;
1317    }
1318
1319
1320    /**
1321     * Coefficient rigth Ore condition. Generators for the right Ore condition
1322     * of two coefficients.
1323     * @param a coefficient.
1324     * @param b coefficient.
1325     * @return [oa, ob] = rightOreCond(a,b), with a*oa == b*ob.
1326     */
1327    @SuppressWarnings("unchecked")
1328    public C[] rightOreCond(C a, C b) {
1329        if (a == null || a.isZERO() || b == null || b.isZERO()) {
1330            throw new IllegalArgumentException("a and b must be non zero");
1331        }
1332        C[] oc = (C[]) new GcdRingElem[2];
1333        if (a instanceof GenSolvablePolynomial && b instanceof GenSolvablePolynomial) {
1334            GenSolvablePolynomial ap = (GenSolvablePolynomial) a;
1335            GenSolvablePolynomial bp = (GenSolvablePolynomial) b;
1336            GenSolvablePolynomial[] ocp = rightOreCond(ap, bp);
1337            oc[0] = (C) ocp[0];
1338            oc[1] = (C) ocp[1];
1339            return oc;
1340        }
1341        RingFactory<C> rf = coFac; // not usable: (RingFactory<C>) a.factory();
1342        if (a.equals(b)) { // required because of rationals gcd
1343            oc[0] = rf.getONE();
1344            oc[1] = rf.getONE();
1345            return oc;
1346        }
1347        if (a.equals(b.negate())) { // required because of rationals gcd
1348            oc[0] = rf.getONE();
1349            oc[1] = rf.getONE().negate();
1350            return oc;
1351        }
1352        if (rf.isCommutative()) {
1353            logger.info("right Ore condition on coefficients, commutative case: " + a + ", " + b);
1354            C gcd = a.gcd(b);
1355            if (gcd.isONE()) {
1356                oc[0] = b;
1357                oc[1] = a;
1358                if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) {
1359                    oc[0] = oc[0].negate();
1360                    oc[1] = oc[1].negate();
1361                }
1362                return oc;
1363            }
1364            C p = a.multiply(b);
1365            C lcm = p.divide(gcd).abs();
1366            oc[0] = lcm.divide(a);
1367            oc[1] = lcm.divide(b);
1368            if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) {
1369                oc[0] = oc[0].negate();
1370                oc[1] = oc[1].negate();
1371            }
1372            logger.info("Ore multiple: " + lcm + ", " + Arrays.toString(oc));
1373            return oc;
1374        }
1375        // now non-commutative
1376        if (rf.isField()) {
1377            logger.info("right Ore condition on coefficients, skew field " + rf + " case: " + a + ", " + b);
1378            //C gcd = a.gcd(b); // always one 
1379            //C lcm = rf.getONE();
1380            oc[0] = a.inverse(); //lcm.divide(a);
1381            oc[1] = b.inverse(); //lcm.divide(b);
1382            logger.info("Ore multiple: " + Arrays.toString(oc));
1383            return oc;
1384        }
1385        if (b instanceof StarRingElem) {
1386            logger.info("right Ore condition on coefficients, StarRing case: " + a + ", " + b);
1387            C bs = (C) ((StarRingElem) b).conjugate();
1388            oc[0] = b.multiply(bs); // a b bar(b) = a s
1389            oc[1] = bs.multiply(a); // b bar(b) a = s a 
1390            logger.info("Ore multiple: " + Arrays.toString(oc));
1391            return oc;
1392        }
1393        throw new UnsupportedOperationException(
1394                        "rightOreCond not implemented for " + rf.getClass() + ", rf = " + rf.toScript());
1395        //return oc;
1396    }
1397
1398
1399    /**
1400     * Right Ore condition. Generators for the right Ore condition of two
1401     * solvable polynomials.
1402     * @param a solvable polynomial
1403     * @param b solvable polynomial
1404     * @return [p,q] with a*p = b*q
1405     */
1406    @SuppressWarnings({ "unchecked", "cast" })
1407    public GenSolvablePolynomial<C>[] rightOreCond(GenSolvablePolynomial<C> a, GenSolvablePolynomial<C> b) {
1408        if (a == null || a.isZERO() || b == null || b.isZERO()) {
1409            throw new IllegalArgumentException("a and b must be non zero");
1410        }
1411        GenSolvablePolynomialRing<C> pfac = a.ring;
1412        GenSolvablePolynomial<C>[] oc = (GenSolvablePolynomial<C>[]) new GenSolvablePolynomial[2];
1413        if (a.equals(b)) {
1414            oc[0] = pfac.getONE();
1415            oc[1] = pfac.getONE();
1416            return oc;
1417        }
1418        if (a.equals(b.negate())) {
1419            oc[0] = pfac.getONE();
1420            oc[1] = (GenSolvablePolynomial<C>) pfac.getONE().negate();
1421            return oc;
1422        }
1423        if (pfac.isCommutative()) {
1424            logger.info("right Ore condition, polynomial commutative case: " + a + ", " + b);
1425            edu.jas.ufd.GreatestCommonDivisorAbstract<C> cgcd = GCDFactory.<C> getImplementation(pfac.coFac);
1426            GenSolvablePolynomial<C> lcm = (GenSolvablePolynomial<C>) cgcd.lcm(a, b);
1427            //oc[0] = FDUtil.<C> basePseudoQuotient(lcm, a);
1428            //oc[1] = FDUtil.<C> basePseudoQuotient(lcm, b);
1429            oc[0] = (GenSolvablePolynomial<C>) PolyUtil.<C> basePseudoDivide(lcm, a);
1430            oc[1] = (GenSolvablePolynomial<C>) PolyUtil.<C> basePseudoDivide(lcm, b);
1431            logger.info("Ore multiple: " + lcm + ", " + Arrays.toString(oc));
1432            return oc;
1433        }
1434        oc = syz.rightOreCond(a, b);
1435        //logger.info("Ore multiple: " + oc[0].multiply(a) + ", " + Arrays.toString(oc));
1436        return oc;
1437    }
1438
1439}