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 ≤ v ≤ (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 ≤ v ≤ (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 ≤ v ≤ (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 ≤ v ≤ (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 }