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