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