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