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