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