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