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