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