001/*
002 * $Id: ProductRing.java 5872 2018-07-20 16:01:46Z kredel $
003 */
004
005package edu.jas.arith;
006
007
008import java.io.Reader;
009import java.io.StringReader;
010import java.util.ArrayList;
011import java.util.List;
012import java.util.Random;
013import java.util.SortedMap;
014import java.util.TreeMap;
015
016import org.apache.logging.log4j.Logger;
017import org.apache.logging.log4j.LogManager; 
018
019import edu.jas.structure.RingElem;
020import edu.jas.structure.RingFactory;
021
022
023/**
024 * Direct product ring factory based on RingElem and RingFactory module. Objects
025 * of this class are <b>mutable</b>.
026 * @author Heinz Kredel
027 */
028public class ProductRing<C extends RingElem<C>> implements RingFactory<Product<C>> {
029
030
031    private static final Logger logger = LogManager.getLogger(ProductRing.class);
032
033
034    //private static final boolean debug = logger.isDebugEnabled();
035
036
037    /**
038     * Ring factory is n copies.
039     */
040    protected int nCopies;
041
042
043    /**
044     * One Ring factory.
045     */
046    protected final RingFactory<C> ring;
047
048
049    /**
050     * Ring factory list.
051     */
052    protected final List<RingFactory<C>> ringList;
053
054
055    /**
056     * A default random sequence generator.
057     */
058    protected final static Random random = new Random();
059
060
061    /**
062     * The constructor creates a ProductRing object from an ring factory and a
063     * modul.
064     * @param r ring factory.
065     * @param n number of copies.
066     */
067    public ProductRing(RingFactory<C> r, int n) {
068        ring = r;
069        nCopies = n;
070        ringList = null;
071    }
072
073
074    /**
075     * The constructor creates a ProductRing object from an ring factory and a
076     * modul.
077     * @param l list of ring factories.
078     */
079    public ProductRing(List<RingFactory<C>> l) {
080        ringList = l;
081        ring = null;
082        nCopies = 0;
083    }
084
085
086    /**
087     * Get ring factory at index i.
088     * @param i index.
089     * @return RingFactory_i.
090     */
091    public RingFactory<C> getFactory(int i) {
092        if (nCopies != 0) {
093            if (0 <= i && i < nCopies) {
094                return ring;
095            }
096            logger.info("index: " + i);
097            throw new IllegalArgumentException("index out of bound " + this);
098        }
099        return ringList.get(i);
100    }
101
102
103    /**
104     * Add a ring factory.
105     * @param rf new ring factory.
106     */
107    public synchronized void addFactory(RingFactory<C> rf) {
108        if (nCopies != 0) {
109            if (ring.equals(rf)) {
110                nCopies++;
111            }
112            throw new IllegalArgumentException("wrong RingFactory: " + rf);
113        }
114        ringList.add(rf);
115    }
116
117
118    /**
119     * Contains a ring factory.
120     * @param rf ring factory.
121     * @return true, if rf is contained in this, else false.
122     */
123    public boolean containsFactory(RingFactory<C> rf) {
124        if (nCopies != 0) {
125            if (ring.equals(rf)) {
126                return true;
127            }
128            return false; // misleading
129        }
130        return ringList.contains(rf);
131    }
132
133
134    /**
135     * Is this structure finite or infinite.
136     * @return true if this structure is finite, else false.
137     * @see edu.jas.structure.ElemFactory#isFinite()
138     */
139    public boolean isFinite() {
140        if (nCopies != 0) {
141            return ring.isFinite();
142        }
143        for (RingFactory<C> f : ringList) {
144            boolean b = f.isFinite();
145            if (!b) {
146                return false;
147            }
148        }
149        return true;
150    }
151
152
153    /**
154     * Copy Product element c.
155     * @param c
156     * @return a copy of c.
157     */
158    public Product<C> copy(Product<C> c) {
159        return new Product<C>(c.ring, c.val, c.isunit);
160    }
161
162
163    /**
164     * Get the zero element.
165     * @return 0 as Product.
166     */
167    public Product<C> getZERO() {
168        return new Product<C>(this);
169    }
170
171
172    /**
173     * Get the one element.
174     * @return 1 as Product.
175     */
176    public Product<C> getONE() {
177        SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
178        if (nCopies != 0) {
179            for (int i = 0; i < nCopies; i++) {
180                elem.put(i, ring.getONE());
181            }
182        } else {
183            int i = 0;
184            for (RingFactory<C> f : ringList) {
185                elem.put(i, f.getONE());
186                i++;
187            }
188        }
189        return new Product<C>(this, elem, 1);
190    }
191
192
193    /**
194     * Get a list of the generating elements.
195     * @return list of generators for the algebraic structure.
196     * @see edu.jas.structure.ElemFactory#generators()
197     */
198    public List<Product<C>> generators() {
199        List<Product<C>> gens = new ArrayList<Product<C>>(/*nCopies*ring.generators.size()*/);
200        int n = nCopies;
201        if (n == 0) {
202            n = ringList.size();
203        }
204        for (int i = 0; i < n; i++) {
205            //System.out.println("i = " + i + ", n = " + n);
206            RingFactory<C> f = getFactory(i);
207            List<? extends C> rgens = f.generators();
208            for (C c : rgens) {
209                SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
210                elem.put(i, c);
211                Product<C> g = new Product<C>(this, elem);
212                //g = g.fillOne();
213                gens.add(g);
214            }
215        }
216        return gens;
217    }
218
219
220    /**
221     * Get an atomic element.
222     * @param i index.
223     * @return e_i as Product.
224     */
225    public Product<C> getAtomic(int i) {
226        if (i < 0 || i >= length()) {
227            throw new IllegalArgumentException("index out of bounds " + i);
228        }
229        SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
230        if (nCopies != 0) {
231            elem.put(i, ring.getONE());
232        } else {
233            RingFactory<C> f = ringList.get(i);
234            elem.put(i, f.getONE());
235        }
236        return new Product<C>(this, elem, 1);
237    }
238
239
240    /**
241     * Get the number of factors of this ring.
242     * @return nCopies or ringList.size().
243     */
244    public int length() {
245        if (nCopies != 0) {
246            return nCopies;
247        }
248        return ringList.size();
249    }
250
251
252    /**
253     * Query if this ring is commutative.
254     * @return true if this ring is commutative, else false.
255     */
256    public boolean isCommutative() {
257        if (nCopies != 0) {
258            return ring.isCommutative();
259        }
260        for (RingFactory<C> f : ringList) {
261            if (!f.isCommutative()) {
262                return false;
263            }
264        }
265        return true;
266    }
267
268
269    /**
270     * Query if this ring is associative.
271     * @return true if this ring is associative, else false.
272     */
273    public boolean isAssociative() {
274        if (nCopies != 0) {
275            return ring.isAssociative();
276        }
277        for (RingFactory<C> f : ringList) {
278            if (!f.isAssociative()) {
279                return false;
280            }
281        }
282        return true;
283    }
284
285
286    /**
287     * Query if this ring is a field.
288     * @return true or false.
289     */
290    public boolean isField() {
291        if (nCopies != 0) {
292            if (nCopies == 1) {
293                return ring.isField();
294            }
295        } else {
296            if (ringList.size() == 1) {
297                return ringList.get(0).isField();
298            }
299        }
300        return false;
301    }
302
303
304    /**
305     * Query if this ring consists only of fields.
306     * @return true or false.
307     */
308    public boolean onlyFields() {
309        if (nCopies != 0) {
310            return ring.isField();
311        }
312        for (RingFactory<C> f : ringList) {
313            if (!f.isField()) {
314                return false;
315            }
316        }
317        return true;
318    }
319
320
321    /**
322     * Characteristic of this ring.
323     * @return minimal characteristic of ring component.
324     */
325    public java.math.BigInteger characteristic() {
326        if (nCopies != 0) {
327            return ring.characteristic();
328        }
329        java.math.BigInteger c = null;
330        java.math.BigInteger d;
331        for (RingFactory<C> f : ringList) {
332            if (c == null) {
333                c = f.characteristic();
334            } else {
335                d = f.characteristic();
336                if (c.compareTo(d) > 0) { // c > d
337                    c = d;
338                }
339            }
340        }
341        return c;
342    }
343
344
345    /**
346     * Get a Product element from a BigInteger value.
347     * @param a BigInteger.
348     * @return a Product.
349     */
350    public Product<C> fromInteger(java.math.BigInteger a) {
351        SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
352        if (nCopies != 0) {
353            C c = ring.fromInteger(a);
354            for (int i = 0; i < nCopies; i++) {
355                elem.put(i, c);
356            }
357        } else {
358            int i = 0;
359            for (RingFactory<C> f : ringList) {
360                elem.put(i, f.fromInteger(a));
361                i++;
362            }
363        }
364        return new Product<C>(this, elem);
365    }
366
367
368    /**
369     * Get a Product element from a long value.
370     * @param a long.
371     * @return a Product.
372     */
373    public Product<C> fromInteger(long a) {
374        return fromInteger(new java.math.BigInteger("" + a));
375    }
376
377
378    /**
379     * Get the String representation as RingFactory.
380     * @see java.lang.Object#toString()
381     */
382    @Override
383    public String toString() {
384        if (nCopies != 0) {
385            String cf = ring.toString();
386            if (cf.matches("[0-9].*")) {
387                cf = ring.getClass().getSimpleName();
388            }
389            return "ProductRing[ " + cf + "^" + nCopies + " ]";
390        }
391        StringBuffer sb = new StringBuffer("ProductRing[ ");
392        int i = 0;
393        for (RingFactory<C> f : ringList) {
394            if (i != 0) {
395                sb.append(", ");
396            }
397            String cf = f.toString();
398            if (cf.matches("[0-9].*")) {
399                cf = f.getClass().getSimpleName();
400            }
401            sb.append(cf);
402            i++;
403        }
404        sb.append(" ]");
405        return sb.toString();
406    }
407
408
409    /**
410     * Get a scripting compatible string representation.
411     * @return script compatible representation for this ElemFactory.
412     * @see edu.jas.structure.ElemFactory#toScript()
413     */
414    @Override
415    public String toScript() {
416        // Python case
417        StringBuffer s = new StringBuffer("RR( [ ");
418        for (int i = 0; i < length(); i++) {
419            if (i > 0) {
420                s.append(", ");
421            }
422            RingFactory<C> v = getFactory(i);
423            String f = null;
424            try {
425                f = ((RingElem<C>) v).toScriptFactory(); // sic
426            } catch (Exception e) {
427                f = v.toScript();
428            }
429            s.append(f);
430        }
431        s.append(" ] )");
432        return s.toString();
433    }
434
435
436    /**
437     * Comparison with any other object.
438     * @see java.lang.Object#equals(java.lang.Object)
439     */
440    @Override
441    @SuppressWarnings("unchecked")
442    public boolean equals(Object b) {
443        if (b == null) {
444            return false;
445        }
446        if (!(b instanceof ProductRing)) {
447            return false;
448        }
449        ProductRing<C> a = (ProductRing<C>) b;
450        if (nCopies != 0) {
451            if (nCopies != a.nCopies || !ring.equals(a.ring)) {
452                return false;
453            }
454        } else {
455            if (ringList.size() != a.ringList.size()) {
456                return false;
457            }
458            int i = 0;
459            for (RingFactory<C> f : ringList) {
460                if (!f.equals(a.ringList.get(i))) {
461                    return false;
462                }
463                i++;
464            }
465        }
466        return true;
467    }
468
469
470    /**
471     * Hash code for this product ring.
472     * @see java.lang.Object#hashCode()
473     */
474    @Override
475    public int hashCode() {
476        int h = 0;
477        if (nCopies != 0) {
478            h = ring.hashCode();
479            h = 37 * h + nCopies;
480        } else {
481            for (RingFactory<C> f : ringList) {
482                h = 37 * h + f.hashCode();
483            }
484        }
485        return h;
486    }
487
488
489    /**
490     * Product random.
491     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
492     * @return a random product element v.
493     */
494    public Product<C> random(int n) {
495        return random(n, 0.5f);
496    }
497
498
499    /**
500     * Product random.
501     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
502     * @param q density of nozero entries.
503     * @return a random product element v.
504     */
505    public Product<C> random(int n, float q) {
506        return random(n, q, random);
507    }
508
509
510    /**
511     * Product random.
512     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
513     * @param rnd is a source for random bits.
514     * @return a random product element v.
515     */
516    public Product<C> random(int n, Random rnd) {
517        return random(n, 0.5f, random);
518    }
519
520
521    /**
522     * Product random.
523     * @param n such that 0 &le; v &le; (2<sup>n</sup>-1).
524     * @param q density of nozero entries.
525     * @param rnd is a source for random bits.
526     * @return a random product element v.
527     */
528    public Product<C> random(int n, float q, Random rnd) {
529        SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
530        float d;
531        if (nCopies != 0) {
532            for (int i = 0; i < nCopies; i++) {
533                d = rnd.nextFloat();
534                if (d < q) {
535                    C r = ring.random(n, rnd);
536                    if (!r.isZERO()) {
537                        elem.put(i, r);
538                    }
539                }
540            }
541        } else {
542            int i = 0;
543            for (RingFactory<C> f : ringList) {
544                d = rnd.nextFloat();
545                if (d < q) {
546                    C r = f.random(n, rnd);
547                    if (!r.isZERO()) {
548                        elem.put(i, r);
549                    }
550                }
551                i++;
552            }
553        }
554        return new Product<C>(this, elem);
555    }
556
557
558    /**
559     * Parse Product from String.
560     * @param s String.
561     * @return Product from s.
562     */
563    public Product<C> parse(String s) {
564        StringReader sr = new StringReader(s);
565        return parse(sr);
566    }
567
568
569    /**
570     * Parse Product from Reader. Syntax: p1 ... pn (no commas)
571     * @param r Reader.
572     * @return next Product from r.
573     */
574    public Product<C> parse(Reader r) {
575        SortedMap<Integer, C> elem = new TreeMap<Integer, C>();
576        if (nCopies != 0) {
577            for (int i = 0; i < nCopies; i++) {
578                elem.put(i, ring.parse(r));
579            }
580        } else {
581            int i = 0;
582            for (RingFactory<C> f : ringList) {
583                elem.put(i, f.parse(r));
584                i++;
585            }
586        }
587        return new Product<C>(this, elem);
588    }
589
590}