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