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