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