001/* 002 * $Id: GenMatrixRing.java 5682 2017-01-01 16:48:55Z kredel $ 003 */ 004 005package edu.jas.vector; 006 007 008// import java.io.IOException; 009import java.io.Reader; 010import java.math.BigInteger; 011import java.util.ArrayList; 012import java.util.List; 013import java.util.Random; 014import java.util.function.BiFunction; 015 016import org.apache.log4j.Logger; 017 018import edu.jas.kern.StringUtil; 019import edu.jas.structure.AlgebraFactory; 020import edu.jas.structure.RingElem; 021import edu.jas.structure.RingFactory; 022 023 024/** 025 * GenMatrixRing implements a generic matrix algebra factory with RingFactory. 026 * Matrices of n rows and m columns over C. 027 * @author Heinz Kredel 028 */ 029 030public class GenMatrixRing<C extends RingElem<C>> implements AlgebraFactory<GenMatrix<C>, C> { 031 032 033 private static final Logger logger = Logger.getLogger(GenMatrixRing.class); 034 035 036 public final RingFactory<C> coFac; 037 038 039 public final int rows; 040 041 042 public final int cols; 043 044 045 public final int blocksize; 046 047 048 public final static int DEFAULT_BSIZE = 10; 049 050 051 public final GenMatrix<C> ZERO; 052 053 054 public final GenMatrix<C> ONE; 055 056 057 private final static Random random = new Random(); 058 059 060 public final static float DEFAULT_DENSITY = 0.5f; 061 062 063 private final float density = DEFAULT_DENSITY; 064 065 066 /** 067 * Constructors for GenMatrixRing. 068 * @param b coefficient factory. 069 * @param r number of rows. 070 * @param c number of colums. 071 */ 072 public GenMatrixRing(RingFactory<C> b, int r, int c) { 073 this(b, r, c, DEFAULT_BSIZE); 074 } 075 076 077 /** 078 * Constructors for GenMatrixRing. 079 * @param b coefficient factory. 080 * @param r number of rows. 081 * @param c number of colums. 082 * @param s block size for blocked operations. 083 */ 084 @SuppressWarnings("unchecked") 085 public GenMatrixRing(RingFactory<C> b, int r, int c, int s) { 086 if (b == null) { 087 throw new IllegalArgumentException("RingFactory is null"); 088 } 089 if (r < 1) { 090 throw new IllegalArgumentException("rows < 1 " + r); 091 } 092 if (c < 1) { 093 throw new IllegalArgumentException("cols < 1 " + c); 094 } 095 coFac = b; 096 rows = r; 097 cols = c; 098 blocksize = s; 099 ArrayList<C> z = new ArrayList<C>(cols); 100 for (int i = 0; i < cols; i++) { 101 z.add(coFac.getZERO()); 102 } 103 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 104 for (int i = 0; i < rows; i++) { 105 m.add(new ArrayList<C>(z)); // z.clone(); 106 } 107 ZERO = new GenMatrix<C>(this, m); 108 m = new ArrayList<ArrayList<C>>(rows); 109 C one = coFac.getONE(); 110 ArrayList<C> v; 111 for (int i = 0; i < rows; i++) { 112 if (i < cols) { 113 v = new ArrayList<C>(z); // z.clone(); 114 v.set(i, one); 115 m.add(v); 116 } 117 } 118 ONE = new GenMatrix<C>(this, m); 119 logger.info(rows + " x " + cols + " with blocksize " + blocksize + " matrix ring over " 120 + coFac.toScript() + " constructed"); 121 } 122 123 124 /** 125 * Get the String representation as RingElem. 126 * @see java.lang.Object#toString() 127 */ 128 @Override 129 public String toString() { 130 StringBuffer s = new StringBuffer(); 131 s.append(coFac.getClass().getSimpleName()); 132 s.append("[" + rows + "," + cols + "]"); 133 return s.toString(); 134 } 135 136 137 /** 138 * Get a scripting compatible string representation. 139 * @return script compatible representation for this ElemFactory. 140 * @see edu.jas.structure.ElemFactory#toScript() 141 */ 142 @Override 143 public String toScript() { 144 // Python case 145 StringBuffer s = new StringBuffer("Mat("); 146 String f = null; 147 try { 148 f = ((RingElem<C>) coFac).toScriptFactory(); // sic 149 } catch (Exception e) { 150 f = coFac.toScript(); 151 } 152 s.append(f + "," + rows + "," + cols + ")"); 153 return s.toString(); 154 } 155 156 157 /** 158 * Get the constant one for the GenMatrix. 159 * @return ZERO. 160 */ 161 public GenMatrix<C> getZERO() { 162 return ZERO; 163 } 164 165 166 /** 167 * Get the constant one for the GenMatrix. 168 * @return 1. 169 */ 170 public GenMatrix<C> getONE() { 171 return ONE; 172 } 173 174 175 /** 176 * Get a list of the generating elements. 177 * @return list of generators for the algebraic structure. 178 * @see edu.jas.structure.ElemFactory#generators() 179 */ 180 public List<GenMatrix<C>> generators() { 181 List<C> rgens = coFac.generators(); 182 List<GenMatrix<C>> gens = new ArrayList<GenMatrix<C>>(rows * cols * rgens.size()); 183 for (int i = 0; i < rows; i++) { 184 for (int j = 0; j < cols; j++) { 185 for (C el : rgens) { 186 GenMatrix<C> g = ZERO.set(i, j, el); // uses clone() 187 gens.add(g); 188 } 189 } 190 } 191 return gens; 192 } 193 194 195 /** 196 * Is this structure finite or infinite. 197 * @return true if this structure is finite, else false. 198 * @see edu.jas.structure.ElemFactory#isFinite() 199 */ 200 public boolean isFinite() { 201 return coFac.isFinite(); 202 } 203 204 205 /** 206 * Comparison with any other object. 207 * @see java.lang.Object#equals(java.lang.Object) 208 */ 209 @Override 210 public boolean equals(Object other) { 211 if (!(other instanceof GenMatrixRing)) { 212 return false; 213 } 214 GenMatrixRing omod = (GenMatrixRing) other; 215 if (rows != omod.rows) { 216 return false; 217 } 218 if (cols != omod.cols) { 219 return false; 220 } 221 if (!coFac.equals(omod.coFac)) { 222 return false; 223 } 224 return true; 225 } 226 227 228 /** 229 * Hash code for this matrix ring. 230 * @see java.lang.Object#hashCode() 231 */ 232 @Override 233 public int hashCode() { 234 int h; 235 h = rows * 17 + cols; 236 h = 37 * h + coFac.hashCode(); 237 return h; 238 } 239 240 241 /** 242 * Query if this ring is a field. May return false if it is to hard to 243 * determine if this ring is a field. 244 * @return true if it is known that this ring is a field, else false. 245 */ 246 public boolean isField() { 247 return false; 248 } 249 250 251 /** 252 * Query if this monoid is commutative. 253 * @return true if this monoid is commutative, else false. 254 */ 255 public boolean isCommutative() { 256 return false; 257 } 258 259 260 /** 261 * Query if this ring is associative. 262 * @return true if this monoid is associative, else false. 263 */ 264 public boolean isAssociative() { 265 return (rows == cols); 266 } 267 268 269 /** 270 * Characteristic of this ring. 271 * @return characteristic of this ring. 272 */ 273 public java.math.BigInteger characteristic() { 274 return coFac.characteristic(); 275 } 276 277 278 /** 279 * Transposed matrix ring. 280 * @return transposed ring factory. 281 */ 282 public GenMatrixRing<C> transpose() { 283 if (rows == cols) { 284 return this; 285 } 286 return new GenMatrixRing<C>(coFac, cols, rows, blocksize); 287 } 288 289 290 /** 291 * Product matrix ring for multiplication. 292 * @param other matrix ring factory. 293 * @return product ring factory. 294 */ 295 public GenMatrixRing<C> product(GenMatrixRing<C> other) { 296 if (cols != other.rows) { 297 throw new IllegalArgumentException("invalid dimensions in product"); 298 } 299 if (!coFac.equals(other.coFac)) { 300 throw new IllegalArgumentException("invalid coefficients in product"); 301 } 302 if (rows == other.rows && cols == other.cols) { 303 return this; 304 } 305 return new GenMatrixRing<C>(coFac, rows, other.cols, blocksize); 306 } 307 308 309 /** 310 * Get the matrix for a. 311 * @param a long 312 * @return matrix corresponding to a. 313 */ 314 public GenMatrix<C> fromInteger(long a) { 315 C c = coFac.fromInteger(a); 316 return ONE.scalarMultiply(c); 317 } 318 319 320 /** 321 * Get the matrix for a. 322 * @param a long 323 * @return matrix corresponding to a. 324 */ 325 public GenMatrix<C> fromInteger(BigInteger a) { 326 C c = coFac.fromInteger(a); 327 return ONE.scalarMultiply(c); 328 } 329 330 331 /** 332 * From List of coefficients. 333 * @param om list of list of coefficients. 334 */ 335 public GenMatrix<C> fromList(List<List<C>> om) { 336 if (om == null) { 337 return ZERO; 338 } 339 if (om.size() > rows) { 340 throw new IllegalArgumentException("size v > rows " + om + " > " + rows); 341 } 342 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 343 for (int i = 0; i < rows; i++) { 344 List<C> ov = om.get(i); 345 ArrayList<C> v; 346 if (ov == null) { 347 v = ZERO.matrix.get(0); 348 } else { 349 if (ov.size() > cols) { 350 throw new IllegalArgumentException("size v > cols " + ov + " > " + cols); 351 } 352 v = new ArrayList<C>(cols); 353 v.addAll(ov); 354 // pad with zeros if required: 355 for (int j = v.size(); j < cols; j++) { 356 v.add(coFac.getZERO()); 357 } 358 } 359 m.add(v); 360 } 361 return new GenMatrix<C>(this, m); 362 } 363 364 365 /** 366 * Random matrix. 367 * @param k size of random coefficients. 368 */ 369 public GenMatrix<C> random(int k) { 370 return random(k, density, random); 371 } 372 373 374 /** 375 * Random matrix. 376 * @param k size of random coefficients. 377 * @param q density of nozero coefficients. 378 */ 379 public GenMatrix<C> random(int k, float q) { 380 return random(k, q, random); 381 } 382 383 384 /** 385 * Random matrix. 386 * @param k size of random coefficients. 387 * @param random is a source for random bits. 388 * @return a random element. 389 */ 390 public GenMatrix<C> random(int k, Random random) { 391 return random(k, density, random); 392 } 393 394 395 /** 396 * Random matrix. 397 * @param k size of random coefficients. 398 * @param q density of nozero coefficients. 399 * @param random is a source for random bits. 400 * @return a random element. 401 */ 402 public GenMatrix<C> random(int k, float q, Random random) { 403 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 404 for (int i = 0; i < rows; i++) { 405 ArrayList<C> v = new ArrayList<C>(cols); 406 for (int j = 0; j < cols; j++) { 407 C e; 408 if (random.nextFloat() < q) { 409 e = coFac.random(k, random); 410 } else { 411 e = coFac.getZERO(); 412 } 413 v.add(e); 414 } 415 m.add(v); 416 } 417 return new GenMatrix<C>(this, m); 418 } 419 420 421 /** 422 * Random upper triangular matrix. 423 * @param k size of random coefficients. 424 * @param q density of nozero coefficients. 425 */ 426 public GenMatrix<C> randomUpper(int k, float q) { 427 return randomUpper(k, q, random); 428 } 429 430 431 /** 432 * Random upper triangular matrix. 433 * @param k size of random coefficients. 434 * @param q density of nozero coefficients. 435 * @param random is a source for random bits. 436 * @return a random element. 437 */ 438 public GenMatrix<C> randomUpper(int k, float q, Random random) { 439 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 440 for (int i = 0; i < rows; i++) { 441 ArrayList<C> v = new ArrayList<C>(cols); 442 for (int j = 0; j < cols; j++) { 443 C e = coFac.getZERO(); 444 if (j >= i) { 445 if (random.nextFloat() < q) { 446 e = coFac.random(k, random); 447 } 448 } 449 v.add(e); 450 } 451 m.add(v); 452 } 453 return new GenMatrix<C>(this, m); 454 } 455 456 457 /** 458 * Random lower triangular matrix. 459 * @param k size of random coefficients. 460 * @param q density of nozero coefficients. 461 */ 462 public GenMatrix<C> randomLower(int k, float q) { 463 return randomLower(k, q, random); 464 } 465 466 467 /** 468 * Random lower triangular matrix. 469 * @param k size of random coefficients. 470 * @param q density of nozero coefficients. 471 * @param random is a source for random bits. 472 * @return a random element. 473 */ 474 public GenMatrix<C> randomLower(int k, float q, Random random) { 475 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 476 for (int i = 0; i < rows; i++) { 477 ArrayList<C> v = new ArrayList<C>(cols); 478 for (int j = 0; j < cols; j++) { 479 C e = coFac.getZERO(); 480 if (j <= i) { 481 if (random.nextFloat() < q) { 482 e = coFac.random(k, random); 483 } 484 } 485 v.add(e); 486 } 487 m.add(v); 488 } 489 return new GenMatrix<C>(this, m); 490 } 491 492 493 /** 494 * Copy matrix. 495 * @param c matrix to copy. 496 * @return copy of the matrix 497 */ 498 public GenMatrix<C> copy(GenMatrix<C> c) { 499 if (c == null) { 500 return c; 501 } 502 return c.copy(); 503 } 504 505 506 /** 507 * Generate matrix via lambda expression. 508 * @param gener lambda expression. 509 * @return the generated matrix. 510 */ 511 public GenMatrix<C> generate(BiFunction<Integer, Integer, C> gener) { 512 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 513 for (int i = 0; i < rows; i++) { 514 ArrayList<C> v = new ArrayList<C>(cols); 515 for (int j = 0; j < cols; j++) { 516 C e = gener.apply(i, j); 517 v.add(e); 518 } 519 m.add(v); 520 } 521 return new GenMatrix<C>(this, m); 522 } 523 524 525 /** 526 * Parse a matrix from a String. Syntax: [ [ c, ..., c ], ..., [ c, ..., c ] 527 * ] 528 * @param s input String. 529 * @return parsed matrix 530 */ 531 public GenMatrix<C> parse(String s) { 532 int i = s.indexOf("["); 533 if (i >= 0) { 534 s = s.substring(i + 1); 535 } 536 ArrayList<ArrayList<C>> mat = new ArrayList<ArrayList<C>>(rows); 537 ArrayList<C> v; 538 GenVector<C> vec; 539 GenVectorModul<C> vmod = new GenVectorModul<C>(coFac, cols); 540 String e; 541 int j; 542 do { 543 i = s.indexOf("]"); // delimit vector 544 j = s.lastIndexOf("]"); // delimit matrix 545 if (i != j) { 546 if (i >= 0) { 547 e = s.substring(0, i); 548 s = s.substring(i); 549 vec = vmod.parse(e); 550 v = (ArrayList<C>) vec.val; 551 mat.add(v); 552 i = s.indexOf(","); 553 if (i >= 0) { 554 s = s.substring(i + 1); 555 } 556 } 557 } else { // matrix delimiter 558 if (i >= 0) { 559 e = s.substring(0, i); 560 if (e.trim().length() > 0) { 561 throw new RuntimeException("Error e not empty " + e); 562 } 563 //s = s.substring(i + 1); 564 } 565 break; 566 } 567 } while (i >= 0); 568 return new GenMatrix<C>(this, mat); 569 } 570 571 572 /** 573 * Parse a matrix from a Reader. 574 * @param r Reader. 575 * @return parsed matrix 576 */ 577 public GenMatrix<C> parse(Reader r) { 578 String s = StringUtil.nextPairedString(r, '[', ']'); 579 return parse(s); 580 } 581 582}