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