001/*
002 * $Id: Local.java 4125 2012-08-19 19:05:22Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import org.apache.log4j.Logger;
009
010import edu.jas.structure.GcdRingElem;
011import edu.jas.structure.RingElem;
012
013
014/**
015 * Local element based on RingElem pairs. Objects of this class are (nearly)
016 * immutable.
017 * @author Heinz Kredel
018 * @fix Not jet working because of monic GBs.
019 */
020public class Local<C extends RingElem<C>> implements RingElem<Local<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     * Clone this.
150     * @see java.lang.Object#clone()
151     */
152    @Override
153    public Local<C> copy() {
154        return new Local<C>(ring, num, den, true);
155    }
156
157
158    /**
159     * Is Local zero.
160     * @return If this is 0 then true is returned, else false.
161     * @see edu.jas.structure.RingElem#isZERO()
162     */
163    public boolean isZERO() {
164        return num.isZERO();
165    }
166
167
168    /**
169     * Is Local one.
170     * @return If this is 1 then true is returned, else false.
171     * @see edu.jas.structure.RingElem#isONE()
172     */
173    public boolean isONE() {
174        return num.equals(den);
175    }
176
177
178    /**
179     * Is Local unit.
180     * @return If this is a unit then true is returned, else false.
181     * @see edu.jas.structure.RingElem#isUnit()
182     */
183    public boolean isUnit() {
184        if (isunit > 0) {
185            return true;
186        }
187        if (isunit == 0) {
188            return false;
189        }
190        // not jet known
191        if (num.isZERO()) {
192            isunit = 0;
193            return false;
194        }
195        C p = num.remainder(ring.ideal);
196        boolean u = (p != null && !p.isZERO());
197        if (u) {
198            isunit = 1;
199        } else {
200            isunit = 0;
201        }
202        return (u);
203    }
204
205
206    /**
207     * Get the String representation as RingElem.
208     * @see java.lang.Object#toString()
209     */
210    @Override
211    public String toString() {
212        return "Local[ " + num.toString() + " / " + den.toString() + " ]";
213    }
214
215
216    /**
217     * Get a scripting compatible string representation.
218     * @return script compatible representation for this Element.
219     * @see edu.jas.structure.Element#toScript()
220     */
221    //JAVA6only: @Override
222    public String toScript() {
223        // Python case
224        return "Local( " + num.toScript() + " , " + den.toScript() + " )";
225    }
226
227
228    /**
229     * Get a scripting compatible string representation of the factory.
230     * @return script compatible representation for this ElemFactory.
231     * @see edu.jas.structure.Element#toScriptFactory()
232     */
233    //JAVA6only: @Override
234    public String toScriptFactory() {
235        // Python case
236        return factory().toScript();
237    }
238
239
240    /**
241     * Local comparison.
242     * @param b Local.
243     * @return sign(this-b).
244     */
245    //JAVA6only: @Override
246    public int compareTo(Local<C> b) {
247        if (b == null || b.isZERO()) {
248            return this.signum();
249        }
250        C r = num.multiply(b.den);
251        C s = den.multiply(b.num);
252        C x = r.subtract(s);
253        return x.signum();
254    }
255
256
257    /**
258     * Comparison with any other object.
259     * @see java.lang.Object#equals(java.lang.Object)
260     */
261    @SuppressWarnings("unchecked")
262    // not jet working
263    @Override
264    public boolean equals(Object b) {
265        if (!(b instanceof Local)) {
266            return false;
267        }
268        Local<C> a = null;
269        try {
270            a = (Local<C>) b;
271        } catch (ClassCastException e) {
272        }
273        if (a == null) {
274            return false;
275        }
276        return (0 == compareTo(a));
277    }
278
279
280    /**
281     * Hash code for this local.
282     * @see java.lang.Object#hashCode()
283     */
284    @Override
285    public int hashCode() {
286        int h;
287        h = ring.hashCode();
288        h = 37 * h + num.hashCode();
289        h = 37 * h + den.hashCode();
290        return h;
291    }
292
293
294    /**
295     * Local absolute value.
296     * @return the absolute value of this.
297     * @see edu.jas.structure.RingElem#abs()
298     */
299    public Local<C> abs() {
300        return new Local<C>(ring, num.abs(), den, true);
301    }
302
303
304    /**
305     * Local summation.
306     * @param S Local.
307     * @return this+S.
308     */
309    public Local<C> sum(Local<C> S) {
310        if (S == null || S.isZERO()) {
311            return this;
312        }
313        C n = num.multiply(S.den);
314        n = n.sum(den.multiply(S.num));
315        C d = den.multiply(S.den);
316        return new Local<C>(ring, n, d, false);
317    }
318
319
320    /**
321     * Local negate.
322     * @return -this.
323     * @see edu.jas.structure.RingElem#negate()
324     */
325    public Local<C> negate() {
326        return new Local<C>(ring, num.negate(), den, true);
327    }
328
329
330    /**
331     * Local signum.
332     * @see edu.jas.structure.RingElem#signum()
333     * @return signum(this).
334     */
335    public int signum() {
336        return num.signum();
337    }
338
339
340    /**
341     * Local subtraction.
342     * @param S Local.
343     * @return this-S.
344     */
345    public Local<C> subtract(Local<C> S) {
346        if (S == null || S.isZERO()) {
347            return this;
348        }
349        C n = num.multiply(S.den);
350        n = n.subtract(den.multiply(S.num));
351        C d = den.multiply(S.den);
352        return new Local<C>(ring, n, d, false);
353    }
354
355
356    /**
357     * Local division.
358     * @param S Local.
359     * @return this/S.
360     */
361    public Local<C> divide(Local<C> S) {
362        return multiply(S.inverse());
363    }
364
365
366    /**
367     * Local inverse.
368     * @see edu.jas.structure.RingElem#inverse()
369     * @return S with S = 1/this if defined.
370     */
371    public Local<C> inverse() {
372        if (isONE()) {
373            return this;
374        }
375        if (isUnit()) {
376            return new Local<C>(ring, den, num, true);
377        }
378        throw new ArithmeticException("element not invertible " + this);
379    }
380
381
382    /**
383     * Local remainder.
384     * @param S Local.
385     * @return this - (this/S)*S.
386     */
387    public Local<C> remainder(Local<C> S) {
388        if (num.isZERO()) {
389            throw new ArithmeticException("element not invertible " + this);
390        }
391        if (S.isUnit()) {
392            return ring.getZERO();
393        } else {
394            throw new UnsupportedOperationException("remainder not implemented" + S);
395        }
396    }
397
398
399    /**
400     * Local multiplication.
401     * @param S Local.
402     * @return this*S.
403     */
404    public Local<C> multiply(Local<C> S) {
405        if (S == null || S.isZERO()) {
406            return S;
407        }
408        if (num.isZERO()) {
409            return this;
410        }
411        if (S.isONE()) {
412            return this;
413        }
414        if (this.isONE()) {
415            return S;
416        }
417        C n = num.multiply(S.num);
418        C d = den.multiply(S.den);
419        return new Local<C>(ring, n, d, false);
420    }
421
422
423    /**
424     * Greatest common divisor. <b>Note: </b>Not implemented, throws
425     * UnsupportedOperationException.
426     * @param b other element.
427     * @return gcd(this,b).
428     */
429    public Local<C> gcd(Local<C> b) {
430        throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName());
431    }
432
433
434    /**
435     * Extended greatest common divisor. <b>Note: </b>Not implemented, throws
436     * UnsupportedOperationException.
437     * @param b other element.
438     * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b).
439     */
440    public Local<C>[] egcd(Local<C> b) {
441        throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName());
442    }
443
444}