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