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