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