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