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