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