001/*
002 * $Id: AlgebraicNumberRing.java 5997 2020-03-17 15:34:31Z kredel $
003 */
004
005package edu.jas.poly;
006
007
008import java.io.Reader;
009import java.util.ArrayList;
010import java.util.Iterator;
011import java.util.List;
012import java.util.Random;
013
014import org.apache.logging.log4j.LogManager;
015import org.apache.logging.log4j.Logger;
016
017import edu.jas.kern.Scripting;
018import edu.jas.structure.RingElem;
019import edu.jas.structure.RingFactory;
020import edu.jas.util.CartesianProduct;
021import edu.jas.util.CartesianProductInfinite;
022
023
024/**
025 * Algebraic number factory. Based on GenPolynomial factory with RingElem
026 * interface. Objects of this class are immutable.
027 * @author Heinz Kredel
028 */
029
030public class AlgebraicNumberRing<C extends RingElem<C>>
031                implements RingFactory<AlgebraicNumber<C>>, Iterable<AlgebraicNumber<C>> {
032
033
034    /**
035     * Ring part of the factory data structure.
036     */
037    public final GenPolynomialRing<C> ring;
038
039
040    /**
041     * Module part of the factory data structure.
042     */
043    public final GenPolynomial<C> modul;
044
045
046    /**
047     * Indicator if this ring is a field
048     */
049    protected int isField = -1; // initially unknown
050
051
052    private static final Logger logger = LogManager.getLogger(AlgebraicNumberRing.class);
053
054
055    //  private static final boolean debug = logger.isDebugEnabled();
056
057
058    /**
059     * The constructor creates a AlgebraicNumber factory object from a
060     * GenPolynomial objects module.
061     * @param m module GenPolynomial<C>.
062     */
063    public AlgebraicNumberRing(GenPolynomial<C> m) {
064        ring = m.ring;
065        modul = m; // assert m != 0
066        if (ring.nvar > 1) {
067            throw new IllegalArgumentException("only univariate polynomials allowed");
068        }
069    }
070
071
072    /**
073     * The constructor creates a AlgebraicNumber factory object from a
074     * GenPolynomial objects module.
075     * @param m module GenPolynomial<C>.
076     * @param isField indicator if m is prime.
077     */
078    public AlgebraicNumberRing(GenPolynomial<C> m, boolean isField) {
079        ring = m.ring;
080        modul = m; // assert m != 0
081        this.isField = (isField ? 1 : 0);
082        if (ring.nvar > 1) {
083            throw new IllegalArgumentException("only univariate polynomials allowed");
084        }
085    }
086
087
088    /**
089     * Get the module part.
090     * @return modul.
091     */
092    public GenPolynomial<C> getModul() {
093        return modul;
094    }
095
096
097    /**
098     * Copy AlgebraicNumber element c.
099     * @param c algebraic number to copy.
100     * @return a copy of c.
101     */
102    public AlgebraicNumber<C> copy(AlgebraicNumber<C> c) {
103        return new AlgebraicNumber<C>(this, c.val);
104    }
105
106
107    /**
108     * Get the zero element.
109     * @return 0 as AlgebraicNumber.
110     */
111    public AlgebraicNumber<C> getZERO() {
112        return new AlgebraicNumber<C>(this, ring.getZERO());
113    }
114
115
116    /**
117     * Get the one element.
118     * @return 1 as AlgebraicNumber.
119     */
120    public AlgebraicNumber<C> getONE() {
121        return new AlgebraicNumber<C>(this, ring.getONE());
122    }
123
124
125    /**
126     * Get the generating element.
127     * @return alpha as AlgebraicNumber.
128     */
129    public AlgebraicNumber<C> getGenerator() {
130        return new AlgebraicNumber<C>(this, ring.univariate(0));
131    }
132
133
134    /**
135     * Get a list of the generating elements.
136     * @return list of generators for the algebraic structure.
137     * @see edu.jas.structure.ElemFactory#generators()
138     */
139    public List<AlgebraicNumber<C>> generators() {
140        List<GenPolynomial<C>> gc = ring.generators();
141        List<AlgebraicNumber<C>> gens = new ArrayList<AlgebraicNumber<C>>(gc.size());
142        for (GenPolynomial<C> g : gc) {
143            gens.add(new AlgebraicNumber<C>(this, g));
144        }
145        return gens;
146    }
147
148
149    /**
150     * Is this structure finite or infinite.
151     * @return true if this structure is finite, else false.
152     * @see edu.jas.structure.ElemFactory#isFinite()
153     */
154    public boolean isFinite() {
155        return ring.coFac.isFinite();
156    }
157
158
159    /**
160     * Query if this ring is commutative.
161     * @return true if this ring is commutative, else false.
162     */
163    public boolean isCommutative() {
164        return ring.isCommutative();
165    }
166
167
168    /**
169     * Query if this ring is associative.
170     * @return true if this ring is associative, else false.
171     */
172    public boolean isAssociative() {
173        return ring.isAssociative();
174    }
175
176
177    /**
178     * Query if this ring is a field.
179     * @return true if modul is prime, else false.
180     */
181    public boolean isField() {
182        if (isField > 0) {
183            return true;
184        }
185        if (isField == 0) {
186            return false;
187        }
188        if (!ring.coFac.isField()) {
189            isField = 0;
190            return false;
191        }
192        return false;
193    }
194
195
196    /**
197     * Set field property of this ring.
198     * @param field true, if this ring is determined to be a field, false, if it
199     *            is determined that it is not a field.
200     */
201    public void setField(boolean field) {
202        if (isField > 0 && field) {
203            return;
204        }
205        if (isField == 0 && !field) {
206            return;
207        }
208        if (field) {
209            isField = 1;
210        } else {
211            isField = 0;
212        }
213        return;
214    }
215
216
217    /**
218     * Get the internal field indicator.
219     * @return internal field indicator.
220     */
221    public int getField() {
222        return isField;
223    }
224
225
226    /**
227     * Characteristic of this ring.
228     * @return characteristic of this ring.
229     */
230    public java.math.BigInteger characteristic() {
231        return ring.characteristic();
232    }
233
234
235    /**
236     * Get a AlgebraicNumber element from a BigInteger value.
237     * @param a BigInteger.
238     * @return a AlgebraicNumber.
239     */
240    public AlgebraicNumber<C> fillFromInteger(java.math.BigInteger a) {
241        if (characteristic().signum() == 0) {
242            return new AlgebraicNumber<C>(this, ring.fromInteger(a));
243        }
244        java.math.BigInteger p = characteristic();
245        java.math.BigInteger b = a;
246        GenPolynomial<C> v = ring.getZERO();
247        GenPolynomial<C> x = ring.univariate(0, 1L);
248        GenPolynomial<C> t = ring.getONE();
249        do {
250            java.math.BigInteger[] qr = b.divideAndRemainder(p);
251            java.math.BigInteger q = qr[0];
252            java.math.BigInteger r = qr[1];
253            //System.out.println("q = " + q + ", r = " +r);
254            GenPolynomial<C> rp = ring.fromInteger(r);
255            v = v.sum(t.multiply(rp));
256            t = t.multiply(x);
257            b = q;
258        } while (!b.equals(java.math.BigInteger.ZERO));
259        AlgebraicNumber<C> an = new AlgebraicNumber<C>(this, v);
260        logger.info("fill(" + a + ") = " + v + ", mod: " + an);
261        //RuntimeException e = new RuntimeException("hihihi");
262        //e.printStackTrace();
263        return an;
264    }
265
266
267    /**
268     * Get a AlgebraicNumber element from a long value.
269     * @param a long.
270     * @return a AlgebraicNumber.
271     */
272    public AlgebraicNumber<C> fillFromInteger(long a) {
273        return fillFromInteger(new java.math.BigInteger("" + a));
274    }
275
276
277    /**
278     * Get a AlgebraicNumber element from a BigInteger value.
279     * @param a BigInteger.
280     * @return a AlgebraicNumber.
281     */
282    public AlgebraicNumber<C> fromInteger(java.math.BigInteger a) {
283        return new AlgebraicNumber<C>(this, ring.fromInteger(a));
284    }
285
286
287    /**
288     * Get a AlgebraicNumber element from a long value.
289     * @param a long.
290     * @return a AlgebraicNumber.
291     */
292    public AlgebraicNumber<C> fromInteger(long a) {
293        return new AlgebraicNumber<C>(this, ring.fromInteger(a));
294        //         if ( characteristic().signum() == 0 ) {
295        //         }
296        //         return fromInteger( new java.math.BigInteger(""+a) );
297    }
298
299
300    /**
301     * Get the String representation as RingFactory.
302     * @see java.lang.Object#toString()
303     */
304    @Override
305    public String toString() {
306        return "AlgebraicNumberRing[ " + modul.toString() + " | isField=" + isField + " :: " + ring.toString()
307                        + " ]";
308    }
309
310
311    /**
312     * Get a scripting compatible string representation.
313     * @return script compatible representation for this ElemFactory.
314     * @see edu.jas.structure.ElemFactory#toScript()
315     */
316    @Override
317    public String toScript() {
318        StringBuffer s = new StringBuffer();
319        s.append("AN(");
320        s.append(modul.toScript());
321        switch (Scripting.getLang()) {
322        case Ruby:
323            s.append((isField() ? ",true" : ",false"));
324            break;
325        case Python:
326        default:
327            s.append((isField() ? ",True" : ",False"));
328        }
329        s.append(",");
330        s.append(ring.toScript());
331        s.append(")");
332        return s.toString();
333    }
334
335
336    /**
337     * Comparison with any other object.
338     * @see java.lang.Object#equals(java.lang.Object)
339     */
340    @Override
341    @SuppressWarnings("unchecked")
342    // not jet working
343    public boolean equals(Object b) {
344        if (b == null) {
345            return false;
346        }
347        if (!(b instanceof AlgebraicNumberRing)) {
348            return false;
349        }
350        AlgebraicNumberRing<C> a = (AlgebraicNumberRing<C>) b;
351        return modul.equals(a.modul);
352    }
353
354
355    /**
356     * Hash code for this AlgebraicNumber.
357     * @see java.lang.Object#hashCode()
358     */
359    @Override
360    public int hashCode() {
361        return 37 * modul.hashCode() + ring.hashCode();
362    }
363
364
365    /**
366     * AlgebraicNumber random.
367     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
368     * @return a random integer mod modul.
369     */
370    public AlgebraicNumber<C> random(int n) {
371        GenPolynomial<C> x = ring.random(n).monic();
372        return new AlgebraicNumber<C>(this, x);
373    }
374
375
376    /**
377     * AlgebraicNumber random.
378     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
379     * @param rnd is a source for random bits.
380     * @return a random integer mod modul.
381     */
382    public AlgebraicNumber<C> random(int n, Random rnd) {
383        GenPolynomial<C> x = ring.random(n, rnd).monic();
384        return new AlgebraicNumber<C>(this, x);
385    }
386
387
388    /**
389     * Parse AlgebraicNumber from String.
390     * @param s String.
391     * @return AlgebraicNumber from s.
392     */
393    public AlgebraicNumber<C> parse(String s) {
394        GenPolynomial<C> x = ring.parse(s);
395        return new AlgebraicNumber<C>(this, x);
396    }
397
398
399    /**
400     * Parse AlgebraicNumber from Reader.
401     * @param r Reader.
402     * @return next AlgebraicNumber from r.
403     */
404    public AlgebraicNumber<C> parse(Reader r) {
405        GenPolynomial<C> x = ring.parse(r);
406        return new AlgebraicNumber<C>(this, x);
407    }
408
409
410    /**
411     * AlgebraicNumber chinese remainder algorithm. Assert deg(c.modul) >=
412     * deg(a.modul) and c.modul * a.modul = this.modul.
413     * @param c AlgebraicNumber.
414     * @param ci inverse of c.modul in ring of a.
415     * @param a other AlgebraicNumber.
416     * @return S, with S mod c.modul == c and S mod a.modul == a.
417     */
418    public AlgebraicNumber<C> chineseRemainder(AlgebraicNumber<C> c, AlgebraicNumber<C> ci,
419                    AlgebraicNumber<C> a) {
420        if (true) { // debug
421            if (c.ring.modul.compareTo(a.ring.modul) < 1) {
422                System.out.println("AlgebraicNumber error " + c + ", " + a);
423            }
424        }
425        AlgebraicNumber<C> b = new AlgebraicNumber<C>(a.ring, c.val);
426        // c mod a.modul
427        // c( tbcf(a.modul) ) if deg(a.modul)==1
428        AlgebraicNumber<C> d = a.subtract(b); // a-c mod a.modul
429        if (d.isZERO()) {
430            return new AlgebraicNumber<C>(this, c.val);
431        }
432        b = d.multiply(ci); // b = (a-c)*ci mod a.modul
433        // (c.modul*b)+c mod this.modul = c mod c.modul = 
434        // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul
435        GenPolynomial<C> s = c.ring.modul.multiply(b.val);
436        s = s.sum(c.val);
437        return new AlgebraicNumber<C>(this, s);
438    }
439
440
441    /**
442     * AlgebraicNumber interpolation algorithm. Assert deg(c.modul) >=
443     * deg(A.modul) and c.modul * A.modul = this.modul. Special case with
444     * deg(A.modul) == 1. Similar algorithm as chinese remainder algortihm.
445     * @param c AlgebraicNumber.
446     * @param ci inverse of (c.modul)(a) in ring of A.
447     * @param am trailing base coefficient of modul of other AlgebraicNumber A.
448     * @param a value of other AlgebraicNumber A.
449     * @return S, with S(c) == c and S(A) == a.
450     */
451    public AlgebraicNumber<C> interpolate(AlgebraicNumber<C> c, C ci, C am, C a) {
452        C b = PolyUtil.<C> evaluateMain(ring.coFac /*a*/, c.val, am);
453        // c mod a.modul
454        // c( tbcf(a.modul) ) if deg(a.modul)==1
455        C d = a.subtract(b); // a-c mod a.modul
456        if (d.isZERO()) {
457            return new AlgebraicNumber<C>(this, c.val);
458        }
459        b = d.multiply(ci); // b = (a-c)*ci mod a.modul
460        // (c.modul*b)+c mod this.modul = c mod c.modul = 
461        // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul
462        GenPolynomial<C> s = c.ring.modul.multiply(b);
463        s = s.sum(c.val);
464        return new AlgebraicNumber<C>(this, s);
465    }
466
467
468    /**
469     * Depth of extension field tower.
470     * @return number of nested algebraic extension fields
471     */
472    @SuppressWarnings({ "unchecked", "cast" })
473    public int depth() {
474        AlgebraicNumberRing<C> arr = this;
475        int depth = 1;
476        RingFactory<C> cf = arr.ring.coFac;
477        if (cf instanceof AlgebraicNumberRing) {
478            arr = (AlgebraicNumberRing<C>) (Object) cf;
479            depth += arr.depth();
480        }
481        return depth;
482    }
483
484
485    /**
486     * Degree of extension field.
487     * @return degree of this algebraic extension field
488     */
489    public long extensionDegree() {
490        long degree = modul.degree(0);
491        return degree;
492    }
493
494
495    /**
496     * Total degree of nested extension fields.
497     * @return degree of tower of algebraic extension fields
498     */
499    @SuppressWarnings({ "unchecked", "cast" })
500    public long totalExtensionDegree() {
501        long degree = modul.degree(0);
502        AlgebraicNumberRing<C> arr = this;
503        RingFactory<C> cf = arr.ring.coFac;
504        if (cf instanceof AlgebraicNumberRing) {
505            arr = (AlgebraicNumberRing<C>) (Object) cf;
506            if (degree == 0L) {
507                degree = arr.totalExtensionDegree();
508            } else {
509                degree *= arr.totalExtensionDegree();
510            }
511        }
512        return degree;
513    }
514
515
516    /**
517     * Get a AlgebraicNumber iterator. <b>Note: </b> Only for finite field
518     * coefficients or fields which are iterable.
519     * @return a iterator over all algebraic numbers in this ring.
520     */
521    public Iterator<AlgebraicNumber<C>> iterator() {
522        return new AlgebraicNumberIterator<C>(this);
523    }
524
525}
526
527
528/**
529 * Algebraic number iterator.
530 * @author Heinz Kredel
531 */
532class AlgebraicNumberIterator<C extends RingElem<C>> implements Iterator<AlgebraicNumber<C>> {
533
534
535    /**
536     * data structure.
537     */
538    final Iterator<List<C>> iter;
539
540
541    final List<GenPolynomial<C>> powers;
542
543
544    final AlgebraicNumberRing<C> aring;
545
546
547    private static final Logger logger = LogManager.getLogger(AlgebraicNumberIterator.class);
548
549
550    //  private static final boolean debug = logger.isDebugEnabled();
551
552
553    /**
554     * CartesianProduct iterator constructor.
555     * @param aring AlgebraicNumberRing components of the Cartesian product.
556     */
557    @SuppressWarnings("unchecked")
558    public AlgebraicNumberIterator(AlgebraicNumberRing<C> aring) {
559        RingFactory<C> cf = aring.ring.coFac;
560        this.aring = aring;
561        long d = aring.modul.degree(0);
562        //System.out.println("d = " + d);
563        powers = new ArrayList<GenPolynomial<C>>((int) d);
564        for (long j = d - 1; j >= 0L; j--) {
565            powers.add(aring.ring.univariate(0, j));
566        }
567        //System.out.println("powers = " + powers);
568        if (!(cf instanceof Iterable)) {
569            throw new IllegalArgumentException("only for iterable coefficients implemented");
570        }
571        List<Iterable<C>> comps = new ArrayList<Iterable<C>>((int) d);
572        Iterable<C> cfi = (Iterable<C>) cf;
573        for (long j = 0L; j < d; j++) {
574            comps.add(cfi);
575        }
576        if (cf.isFinite()) {
577            CartesianProduct<C> tuples = new CartesianProduct<C>(comps);
578            iter = tuples.iterator();
579        } else {
580            CartesianProductInfinite<C> tuples = new CartesianProductInfinite<C>(comps);
581            iter = tuples.iterator();
582        }
583        if (logger.isInfoEnabled()) {
584            logger.info("iterator for degree " + d + ", finite = " + cf.isFinite());
585        }
586    }
587
588
589    /**
590     * Test for availability of a next tuple.
591     * @return true if the iteration has more tuples, else false.
592     */
593    public boolean hasNext() {
594        return iter.hasNext();
595    }
596
597
598    /**
599     * Get next tuple.
600     * @return next tuple.
601     */
602    public AlgebraicNumber<C> next() {
603        List<C> coeffs = iter.next();
604        //System.out.println("coeffs = " + coeffs);
605        GenPolynomial<C> pol = aring.ring.getZERO();
606        int i = 0;
607        for (GenPolynomial<C> f : powers) {
608            C c = coeffs.get(i++);
609            if (c.isZERO()) {
610                continue;
611            }
612            pol = pol.sum(f.multiply(c));
613        }
614        return new AlgebraicNumber<C>(aring, pol);
615    }
616
617
618    /**
619     * Remove a tuple if allowed.
620     */
621    public void remove() {
622        throw new UnsupportedOperationException("cannnot remove tuples");
623    }
624
625}