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