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