001/*
002 * $Id: SolvableQuotient.java 5872 2018-07-20 16:01:46Z kredel $
003 */
004
005package edu.jas.fd;
006
007
008import java.util.Arrays;
009
010import org.apache.logging.log4j.Logger;
011import org.apache.logging.log4j.LogManager; 
012
013import edu.jas.kern.PrettyPrint;
014import edu.jas.poly.ExpVector;
015import edu.jas.poly.GenPolynomial;
016import edu.jas.poly.GenSolvablePolynomial;
017import edu.jas.structure.GcdRingElem;
018import edu.jas.structure.QuotPair;
019
020
021/**
022 * SolvableQuotient, that is a (left) rational function, based on
023 * GenSolvablePolynomial with RingElem interface. Objects of this class are
024 * immutable.
025 * @author Heinz Kredel
026 */
027public class SolvableQuotient<C extends GcdRingElem<C>>
028                implements GcdRingElem<SolvableQuotient<C>>, QuotPair<GenPolynomial<C>> {
029    // should be QuotPair<GenSolvablePolynomial<C>
030
031
032    private static final Logger logger = LogManager.getLogger(SolvableQuotient.class);
033
034
035    private static final boolean debug = logger.isDebugEnabled();
036
037
038    /**
039     * SolvableQuotient class factory data structure.
040     */
041    public final SolvableQuotientRing<C> ring;
042
043
044    /**
045     * Numerator part of the element data structure.
046     */
047    public final GenSolvablePolynomial<C> num;
048
049
050    /**
051     * Denominator part of the element data structure.
052     */
053    public final GenSolvablePolynomial<C> den;
054
055
056    /**
057     * The constructor creates a SolvableQuotient object from a ring factory.
058     * @param r ring factory.
059     */
060    public SolvableQuotient(SolvableQuotientRing<C> r) {
061        this(r, r.ring.getZERO());
062    }
063
064
065    /**
066     * The constructor creates a SolvableQuotient object from a ring factory and
067     * a numerator polynomial. The denominator is assumed to be 1.
068     * @param r ring factory.
069     * @param n numerator solvable polynomial.
070     */
071    public SolvableQuotient(SolvableQuotientRing<C> r, GenSolvablePolynomial<C> n) {
072        this(r, n, r.ring.getONE(), true);
073    }
074
075
076    /**
077     * The constructor creates a SolvableQuotient object from a ring factory and
078     * a numerator and denominator solvable polynomial.
079     * @param r ring factory.
080     * @param n numerator polynomial.
081     * @param d denominator polynomial.
082     */
083    public SolvableQuotient(SolvableQuotientRing<C> r, GenSolvablePolynomial<C> n,
084                    GenSolvablePolynomial<C> d) {
085        this(r, n, d, false);
086    }
087
088
089    /**
090     * The constructor creates a SolvableQuotient object from a ring factory and
091     * a numerator and denominator polynomial.
092     * @param r ring factory.
093     * @param n numerator polynomial.
094     * @param d denominator polynomial.
095     * @param isred <em>unused at the moment</em>.
096     */
097    protected SolvableQuotient(SolvableQuotientRing<C> r, GenSolvablePolynomial<C> n,
098                    GenSolvablePolynomial<C> d, boolean isred) {
099        if (d == null || d.isZERO()) {
100            throw new IllegalArgumentException("denominator may not be zero");
101        }
102        ring = r;
103        if (d.signum() < 0) {
104            n = (GenSolvablePolynomial<C>) n.negate();
105            d = (GenSolvablePolynomial<C>) d.negate();
106        }
107        if (isred) {
108            num = n;
109            den = d;
110            return;
111        }
112        C lc = d.leadingBaseCoefficient();
113        if (!lc.isONE() && lc.isUnit()) {
114            lc = lc.inverse();
115            n = n.multiply(lc);
116            d = d.multiply(lc);
117        }
118        if (n.compareTo(d) == 0) {
119            num = ring.ring.getONE();
120            den = ring.ring.getONE();
121            return;
122        }
123        if (n.negate().compareTo(d) == 0) {
124            num = (GenSolvablePolynomial<C>) ring.ring.getONE().negate();
125            den = ring.ring.getONE();
126            return;
127        }
128        if (n.isZERO()) {
129            num = n;
130            den = ring.ring.getONE();
131            return;
132        }
133        //if (n.isONE() || d.isONE()) {
134        if (n.isConstant() || d.isConstant()) {
135            num = n;
136            den = d;
137            return;
138        }
139        // must reduce to lowest terms
140        // not perfect, TODO 
141        //GenSolvablePolynomial<C>[] gcd = PolyModUtil.<C> syzGcdCofactors(r.ring, n, d);
142        GenSolvablePolynomial<C>[] gcd = FDUtil.<C> leftGcdCofactors(r.ring, n, d);
143        if (!gcd[0].isONE()) {
144            logger.info("constructor: gcd = " + Arrays.toString(gcd)); // + ", " + n + ", " +d);
145            n = gcd[1];
146            d = gcd[2];
147        }
148        gcd = FDUtil.<C> rightGcdCofactors(r.ring, n, d);
149        if (!gcd[0].isONE()) {
150            logger.info("constructor: gcd = " + Arrays.toString(gcd)); // + ", " + n + ", " +d);
151            n = gcd[1];
152            d = gcd[2];
153        }
154        // not perfect, TODO 
155        GenSolvablePolynomial<C>[] simp = ring.engine.leftSimplifier(n, d);
156        logger.info("simp: " + Arrays.toString(simp) + ", " + n + ", " + d);
157        num = simp[0];
158        den = simp[1];
159    }
160
161
162    /**
163     * Get the corresponding element factory.
164     * @return factory for this Element.
165     * @see edu.jas.structure.Element#factory()
166     */
167    public SolvableQuotientRing<C> factory() {
168        return ring;
169    }
170
171
172    /**
173     * Numerator.
174     * @see edu.jas.structure.QuotPair#numerator()
175     */
176    public GenSolvablePolynomial<C> numerator() {
177        return num;
178    }
179
180
181    /**
182     * Denominator.
183     * @see edu.jas.structure.QuotPair#denominator()
184     */
185    public GenSolvablePolynomial<C> denominator() {
186        return den;
187    }
188
189
190    /**
191     * Clone this.
192     * @see java.lang.Object#clone()
193     */
194    @Override
195    public SolvableQuotient<C> copy() {
196        return new SolvableQuotient<C>(ring, num, den, true);
197    }
198
199
200    /**
201     * Is SolvableQuotient zero.
202     * @return If this is 0 then true is returned, else false.
203     * @see edu.jas.structure.RingElem#isZERO()
204     */
205    public boolean isZERO() {
206        return num.isZERO();
207    }
208
209
210    /**
211     * Is SolvableQuotient one.
212     * @return If this is 1 then true is returned, else false.
213     * @see edu.jas.structure.RingElem#isONE()
214     */
215    public boolean isONE() {
216        return num.compareTo(den) == 0;
217    }
218
219
220    /**
221     * Is SolvableQuotient a unit.
222     * @return If this is a unit then true is returned, else false.
223     * @see edu.jas.structure.RingElem#isUnit()
224     */
225    public boolean isUnit() {
226        if (num.isZERO()) {
227            return false;
228        }
229        return true;
230    }
231
232
233    /**
234     * Is Qoutient a constant.
235     * @return true, if this has constant numerator and denominator, else false.
236     */
237    public boolean isConstant() {
238        return num.isConstant() && den.isConstant();
239    }
240
241
242    /**
243     * Get the String representation as RingElem.
244     * @see java.lang.Object#toString()
245     */
246    @Override
247    public String toString() {
248        if (PrettyPrint.isTrue()) {
249            String s = "{ " + num.toString(ring.ring.getVars());
250            if (!den.isONE()) {
251                s += " | " + den.toString(ring.ring.getVars());
252            }
253            return s + " }";
254        }
255        return "SolvableQuotient[ " + num.toString() + " | " + den.toString() + " ]";
256    }
257
258
259    /**
260     * Get a scripting compatible string representation.
261     * @return script compatible representation for this Element.
262     * @see edu.jas.structure.Element#toScript()
263     */
264    @Override
265    public String toScript() {
266        // any scripting case
267        if (den.isONE()) {
268            return num.toScript();
269        }
270        return num.toScript() + " / " + den.toScript();
271    }
272
273
274    /**
275     * Get a scripting compatible string representation of the factory.
276     * @return script compatible representation for this ElemFactory.
277     * @see edu.jas.structure.Element#toScriptFactory()
278     */
279    @Override
280    public String toScriptFactory() {
281        return factory().toScript();
282    }
283
284
285    /**
286     * SolvableQuotient comparison.
287     * @param b SolvableQuotient.
288     * @return sign(this-b).
289     */
290    @Override
291    public int compareTo(SolvableQuotient<C> b) {
292        if (b == null || b.isZERO()) {
293            return this.signum();
294        }
295        if (this.isZERO()) {
296            return -b.signum();
297        }
298        // assume sign(den,b.den) > 0
299        int s1 = num.signum();
300        int s2 = b.num.signum();
301        int t = (s1 - s2) / 2;
302        if (t != 0) {
303            return t;
304        }
305        if (den.compareTo(b.den) == 0) {
306            return num.compareTo(b.num);
307        }
308        GenSolvablePolynomial<C> r, s;
309        // if (den.isONE()) {
310        //     r = b.den.multiply(num);
311        //     s = b.num;
312        //     return r.compareTo(s);
313        // }
314        // if (b.den.isONE()) {
315        //     r = num;
316        //     s = den.multiply(b.num);
317        //     return r.compareTo(s);
318        // }
319        GenSolvablePolynomial<C>[] oc = ring.engine.leftOreCond(den, b.den);
320        if (debug) {
321            System.out.println("oc[0] den =<>= oc[1] b.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") ("
322                            + b.den + ")");
323        }
324        r = oc[0].multiply(num);
325        s = oc[1].multiply(b.num);
326        //System.out.println("r = " + r);
327        //System.out.println("s = " + s);
328        return r.compareTo(s);
329    }
330
331
332    /**
333     * Comparison with any other object.
334     * @see java.lang.Object#equals(java.lang.Object)
335     */
336    @SuppressWarnings("unchecked")
337    @Override
338    public boolean equals(Object b) {
339        if (b == null) {
340            return false;
341        }
342        if (!(b instanceof SolvableQuotient)) {
343            return false;
344        }
345        SolvableQuotient<C> a = (SolvableQuotient<C>) b;
346        if (num.equals(a.num) && den.equals(a.den)) { // short cut
347            return true;
348        }
349        return compareTo(a) == 0;
350    }
351
352
353    /**
354     * Hash code for this element.
355     * @see java.lang.Object#hashCode()
356     */
357    @Override
358    public int hashCode() {
359        int h;
360        h = ring.hashCode();
361        h = 37 * h + num.hashCode();
362        h = 37 * h + den.hashCode();
363        return h;
364    }
365
366
367    /**
368     * SolvableQuotient right fraction. <b>Note:</b> It is not possible to
369     * distinguish right from left fractions in the current implementation. So
370     * it is not possible to compute with right fractions.
371     * @return SolvableQuotient(a,b), where den<sup>-1</sup> num = a b
372     *         <sup>-1</sup>
373     */
374    public SolvableQuotient<C> rightFraction() {
375        if (isZERO() || isONE()) {
376            return this;
377        }
378        GenSolvablePolynomial<C>[] oc = ring.engine.rightOreCond(num, den);
379        return new SolvableQuotient<C>(ring, oc[1], oc[0], true); // reversed, true is wrong but okay
380    }
381
382
383    /**
384     * Test if SolvableQuotient right fraction. <b>Note:</b> It is not possible
385     * to distinguish right from left fractions in the current implementation.
386     * So it is not possible to compute with right fractions.
387     * @param s = SolvableQuotient(a,b)
388     * @return true if s is a right fraction of this, i.e. den<sup>-1</sup> num
389     *         = a b<sup>-1</sup>
390     */
391    public boolean isRightFraction(SolvableQuotient<C> s) {
392        if (isZERO()) {
393            return s.isZERO();
394        }
395        if (isONE()) {
396            return s.isONE();
397        }
398        GenSolvablePolynomial<C> x = den.multiply(s.num);
399        GenSolvablePolynomial<C> y = num.multiply(s.den);
400        return x.compareTo(y) == 0;
401    }
402
403
404    /**
405     * SolvableQuotient absolute value.
406     * @return the absolute value of this.
407     * @see edu.jas.structure.RingElem#abs()
408     */
409    public SolvableQuotient<C> abs() {
410        return new SolvableQuotient<C>(ring, (GenSolvablePolynomial<C>) num.abs(), den, true);
411    }
412
413
414    /**
415     * SolvableQuotient summation.
416     * @param S SolvableQuotient.
417     * @return this+S.
418     */
419    public SolvableQuotient<C> sum(SolvableQuotient<C> S) {
420        if (S == null || S.isZERO()) {
421            return this;
422        }
423        if (this.isZERO()) {
424            return S;
425        }
426        GenSolvablePolynomial<C> n, d, n1, n2;
427        if (den.isONE() && S.den.isONE()) {
428            n = (GenSolvablePolynomial<C>) num.sum(S.num);
429            return new SolvableQuotient<C>(ring, n, den, true);
430        }
431        /* wrong:
432        if (den.isONE()) {
433            n = S.den.multiply(num);
434            n = (GenSolvablePolynomial<C>) n.sum(S.num);
435            return new SolvableQuotient<C>(ring, n, S.den, false);
436        }
437        if (S.den.isONE()) {
438            n = den.multiply(S.num);
439            n = (GenSolvablePolynomial<C>) n.sum(num);
440            return new SolvableQuotient<C>(ring, n, den, false);
441        }
442        */
443        if (den.compareTo(S.den) == 0) { // correct ?
444            //d = den.multiply(den);
445            //n1 = den.multiply(S.num);
446            //n2 = S.den.multiply(num);
447            n = (GenSolvablePolynomial<C>) num.sum(S.num);
448            return new SolvableQuotient<C>(ring, n, den, false);
449        }
450        // general case
451        GenSolvablePolynomial<C>[] oc = ring.engine.leftOreCond(den, S.den);
452        if (debug) {
453            System.out.println("oc[0] den =sum= oc[1] S.den: (" + oc[0] + ") (" + den + ") = (" + oc[1]
454                            + ") (" + S.den + ")");
455        }
456        d = oc[0].multiply(den);
457        n1 = oc[0].multiply(num);
458        n2 = oc[1].multiply(S.num);
459        n = (GenSolvablePolynomial<C>) n1.sum(n2);
460        //System.out.println("n = " + n);
461        //System.out.println("d = " + d);
462        return new SolvableQuotient<C>(ring, n, d, false);
463    }
464
465
466    /**
467     * SolvableQuotient negate.
468     * @return -this.
469     * @see edu.jas.structure.RingElem#negate()
470     */
471    public SolvableQuotient<C> negate() {
472        return new SolvableQuotient<C>(ring, (GenSolvablePolynomial<C>) num.negate(), den, true);
473    }
474
475
476    /**
477     * SolvableQuotient signum.
478     * @see edu.jas.structure.RingElem#signum()
479     * @return signum(this).
480     */
481    public int signum() {
482        // assume sign(den) > 0
483        return num.signum();
484    }
485
486
487    /**
488     * SolvableQuotient subtraction.
489     * @param S SolvableQuotient.
490     * @return this-S.
491     */
492    public SolvableQuotient<C> subtract(SolvableQuotient<C> S) {
493        return sum(S.negate());
494    }
495
496
497    /**
498     * SolvableQuotient division.
499     * @param S SolvableQuotient.
500     * @return this/S.
501     */
502    public SolvableQuotient<C> divide(SolvableQuotient<C> S) {
503        return multiply(S.inverse());
504    }
505
506
507    /**
508     * SolvableQuotient inverse.
509     * @see edu.jas.structure.RingElem#inverse()
510     * @return S with S = 1/this.
511     */
512    public SolvableQuotient<C> inverse() {
513        if (num.isZERO()) {
514            throw new ArithmeticException("element not invertible " + this);
515        }
516        return new SolvableQuotient<C>(ring, den, num, true);
517    }
518
519
520    /**
521     * SolvableQuotient remainder.
522     * @param S SolvableQuotient.
523     * @return this - (this/S)*S.
524     */
525    public SolvableQuotient<C> remainder(SolvableQuotient<C> S) {
526        if (S.isZERO()) {
527            throw new ArithmeticException("element not invertible " + S);
528        }
529        return ring.getZERO();
530    }
531
532
533    /**
534     * Quotient and remainder by division of this by S.
535     * @param S a SolvableQuotient
536     * @return [this/S, this - (this/S)*S].
537     */
538    @SuppressWarnings("unchecked")
539    public SolvableQuotient<C>[] quotientRemainder(SolvableQuotient<C> S) {
540        return new SolvableQuotient[] { divide(S), remainder(S) };
541    }
542
543
544    /**
545     * SolvableQuotient multiplication.
546     * @param S SolvableQuotient.
547     * @return this*S.
548     */
549    public SolvableQuotient<C> multiply(SolvableQuotient<C> S) {
550        if (S == null || S.isZERO()) {
551            return S;
552        }
553        if (num.isZERO()) {
554            return this;
555        }
556        if (S.isONE()) {
557            return this;
558        }
559        if (this.isONE()) {
560            return S;
561        }
562        GenSolvablePolynomial<C> n, d;
563        if (den.isONE() && S.den.isONE()) {
564            n = num.multiply(S.num);
565            return new SolvableQuotient<C>(ring, n, den, true);
566        }
567        /* wrong:
568        if (den.isONE()) { 
569            d = S.den;
570            n = num.multiply(S.num);
571            return new SolvableQuotient<C>(ring, n, d, false);
572        }
573        if (S.den.isONE()) { 
574            d = den;
575            n = num.multiply(S.num);
576            return new SolvableQuotient<C>(ring, n, d, false);
577        }
578        */
579        // if ( den.compareTo(S.den) == 0 ) { // not correct ?
580        //     d = den.multiply(den);
581        //     n = num.multiply(S.num);
582        //     return new SolvableQuotient<C>(ring, n, d, false);
583        // }
584        GenSolvablePolynomial<C>[] oc = ring.engine.leftOreCond(num, S.den);
585        n = oc[1].multiply(S.num);
586        d = oc[0].multiply(den);
587        if (debug) {
588            System.out.println("oc[0] num =mult= oc[1] S.den: (" + oc[0] + ") (" + num + ") = (" + oc[1]
589                            + ") (" + S.den + ")");
590        }
591        return new SolvableQuotient<C>(ring, n, d, false);
592    }
593
594
595    /**
596     * SolvableQuotient multiplication by GenSolvablePolynomial.
597     * @param b GenSolvablePolynomial<C>.
598     * @return this*b.
599     */
600    public SolvableQuotient<C> multiply(GenSolvablePolynomial<C> b) {
601        if (b == null || b.isZERO()) {
602            return ring.getZERO();
603        }
604        if (num.isZERO()) {
605            return this;
606        }
607        if (b.isONE()) {
608            return this;
609        }
610        GenSolvablePolynomial<C> n = num.multiply(b);
611        return new SolvableQuotient<C>(ring, n, den, false);
612    }
613
614
615    /**
616     * SolvableQuotient multiplication by coefficient.
617     * @param b coefficient.
618     * @return this*b.
619     */
620    public SolvableQuotient<C> multiply(C b) {
621        if (b == null || b.isZERO()) {
622            return ring.getZERO();
623        }
624        if (num.isZERO()) {
625            return this;
626        }
627        if (b.isONE()) {
628            return this;
629        }
630        GenSolvablePolynomial<C> n = num.multiply(b);
631        return new SolvableQuotient<C>(ring, n, den, false);
632    }
633
634
635    /**
636     * SolvableQuotient multiplication by exponent.
637     * @param e exponent vector.
638     * @return this*b.
639     */
640    public SolvableQuotient<C> multiply(ExpVector e) {
641        if (e == null || e.isZERO()) {
642            return this;
643        }
644        if (num.isZERO()) {
645            return this;
646        }
647        GenSolvablePolynomial<C> n = num.multiply(e);
648        return new SolvableQuotient<C>(ring, n, den, false);
649    }
650
651
652    /**
653     * SolvableQuotient monic.
654     * @return this with monic value part.
655     */
656    public SolvableQuotient<C> monic() {
657        if (num.isZERO()) {
658            return this;
659        }
660        C lbc = num.leadingBaseCoefficient();
661        if (!lbc.isUnit()) {
662            return this;
663        }
664        lbc = lbc.inverse();
665        //lbc = lbc.abs();
666        GenSolvablePolynomial<C> n = num.multiply(lbc);
667        //GenSolvablePolynomial<C> d = (GenSolvablePolynomial<C>) den.multiply(lbc);
668        return new SolvableQuotient<C>(ring, n, den, true);
669    }
670
671
672    /**
673     * Greatest common divisor.
674     * @param b other element.
675     * @return gcd(this,b).
676     */
677    public SolvableQuotient<C> gcd(SolvableQuotient<C> b) {
678        if (b == null || b.isZERO()) {
679            return this;
680        }
681        if (this.isZERO()) {
682            return b;
683        }
684        if (this.equals(b)) {
685            return this;
686        }
687        return ring.getONE();
688    }
689
690
691    /**
692     * Extended greatest common divisor.
693     * @param b other element.
694     * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
695     */
696    @SuppressWarnings("unchecked")
697    public SolvableQuotient<C>[] egcd(SolvableQuotient<C> b) {
698        @SuppressWarnings("cast")
699        SolvableQuotient<C>[] ret = (SolvableQuotient<C>[]) new SolvableQuotient[3];
700        ret[0] = null;
701        ret[1] = null;
702        ret[2] = null;
703        if (b == null || b.isZERO()) {
704            ret[0] = this;
705            return ret;
706        }
707        if (this.isZERO()) {
708            ret[0] = b;
709            return ret;
710        }
711        GenSolvablePolynomial<C> two = ring.ring.fromInteger(2);
712        ret[0] = ring.getONE();
713        ret[1] = (this.multiply(two)).inverse();
714        ret[2] = (b.multiply(two)).inverse();
715        return ret;
716    }
717
718}