001/* 002 * $Id$ 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.LogManager; 017import org.apache.logging.log4j.Logger; 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 columns. 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 columns. 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("{} x {} matrix ring with blocksize {} over {} constructed", 121 rows, cols, blocksize, coFac); 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) && coFac.isAssociative(); 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 * Stack matrix ring. this on top of other. 312 * @param other matrix ring factory. 313 * @return stack ring factory. 314 */ 315 public GenMatrixRing<C> stack(GenMatrixRing<C> other) { 316 if (cols != other.cols) { 317 throw new IllegalArgumentException("invalid dimensions in stack"); 318 } 319 if (!coFac.equals(other.coFac)) { 320 throw new IllegalArgumentException("invalid coefficients in stack"); 321 } 322 if (other.rows == 0) { 323 return this; 324 } 325 int stackrows = rows+other.rows; 326 return new GenMatrixRing<C>(coFac, stackrows, cols, blocksize); 327 } 328 329 330 /** 331 * Concat matrix ring. this before of other. 332 * @param other matrix ring factory. 333 * @return concat ring factory. 334 */ 335 public GenMatrixRing<C> concat(GenMatrixRing<C> other) { 336 if (rows != other.rows) { 337 throw new IllegalArgumentException("invalid dimensions in concat"); 338 } 339 if (!coFac.equals(other.coFac)) { 340 throw new IllegalArgumentException("invalid coefficients in stack"); 341 } 342 if (other.cols == 0) { 343 return this; 344 } 345 int concatcols = cols+other.cols; 346 return new GenMatrixRing<C>(coFac, rows, concatcols, blocksize); 347 } 348 349 350 /** 351 * Get the matrix for a. 352 * @param a long 353 * @return matrix corresponding to a. 354 */ 355 public GenMatrix<C> fromInteger(long a) { 356 C c = coFac.fromInteger(a); 357 return ONE.scalarMultiply(c); 358 } 359 360 361 /** 362 * Get the matrix for a. 363 * @param a long 364 * @return matrix corresponding to a. 365 */ 366 public GenMatrix<C> fromInteger(BigInteger a) { 367 C c = coFac.fromInteger(a); 368 return ONE.scalarMultiply(c); 369 } 370 371 372 /** 373 * From List of coefficients. 374 * @param om list of list of coefficients. 375 */ 376 public GenMatrix<C> fromList(List<List<C>> om) { 377 if (om == null) { 378 return ZERO; 379 } 380 if (om.size() > rows) { 381 throw new IllegalArgumentException("size v > rows " + om + " > " + rows); 382 } 383 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 384 for (int i = 0; i < rows; i++) { 385 List<C> ov = om.get(i); 386 ArrayList<C> v; 387 if (ov == null) { 388 v = ZERO.matrix.get(0); 389 } else { 390 if (ov.size() > cols) { 391 throw new IllegalArgumentException("size v > cols " + ov + " > " + cols); 392 } 393 v = new ArrayList<C>(cols); 394 v.addAll(ov); 395 // pad with zeros if required: 396 for (int j = v.size(); j < cols; j++) { 397 v.add(coFac.getZERO()); 398 } 399 } 400 m.add(v); 401 } 402 return new GenMatrix<C>(this, m); 403 } 404 405 406 /** 407 * From List of GenVectors. 408 * @param om list of GenVectors. 409 */ 410 public GenMatrix<C> fromVectors(List<GenVector<C>> om) { 411 List<List<C>> mat = new ArrayList<List<C>>(); 412 for (GenVector<C> row : om) { 413 List<C> nr = new ArrayList<C>(row.val); 414 mat.add(nr); 415 } 416 //List<C> zero = this.getZERO().getRow(0).val; 417 //for (int i = mat.size(); i < rows; i++) { 418 // mat.add(zero); 419 //} 420 GenMatrixRing<C> rfac = new GenMatrixRing<C>(coFac,mat.size(),cols); 421 return rfac.fromList(mat); 422 } 423 424 425 /** 426 * Random matrix. 427 * @param k size of random coefficients. 428 */ 429 public GenMatrix<C> random(int k) { 430 return random(k, density, random); 431 } 432 433 434 /** 435 * Random matrix. 436 * @param k size of random coefficients. 437 * @param q density of nozero coefficients. 438 */ 439 public GenMatrix<C> random(int k, float q) { 440 return random(k, q, random); 441 } 442 443 444 /** 445 * Random matrix. 446 * @param k size of random coefficients. 447 * @param random is a source for random bits. 448 * @return a random element. 449 */ 450 public GenMatrix<C> random(int k, Random random) { 451 return random(k, density, random); 452 } 453 454 455 /** 456 * Random matrix. 457 * @param k size of random coefficients. 458 * @param q density of nozero coefficients. 459 * @param random is a source for random bits. 460 * @return a random element. 461 */ 462 public GenMatrix<C> random(int k, float q, Random random) { 463 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 464 for (int i = 0; i < rows; i++) { 465 ArrayList<C> v = new ArrayList<C>(cols); 466 for (int j = 0; j < cols; j++) { 467 C e; 468 if (random.nextFloat() < q) { 469 e = coFac.random(k, random); 470 } else { 471 e = coFac.getZERO(); 472 } 473 v.add(e); 474 } 475 m.add(v); 476 } 477 return new GenMatrix<C>(this, m); 478 } 479 480 481 /** 482 * Random upper triangular matrix. 483 * @param k size of random coefficients. 484 * @param q density of nozero coefficients. 485 */ 486 public GenMatrix<C> randomUpper(int k, float q) { 487 return randomUpper(k, q, random); 488 } 489 490 491 /** 492 * Random upper triangular matrix. 493 * @param k size of random coefficients. 494 * @param q density of nozero coefficients. 495 * @param random is a source for random bits. 496 * @return a random element. 497 */ 498 public GenMatrix<C> randomUpper(int k, float q, Random random) { 499 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 500 for (int i = 0; i < rows; i++) { 501 ArrayList<C> v = new ArrayList<C>(cols); 502 for (int j = 0; j < cols; j++) { 503 C e = coFac.getZERO(); 504 if (j >= i) { 505 if (random.nextFloat() < q) { 506 e = coFac.random(k, random); 507 } 508 } 509 v.add(e); 510 } 511 m.add(v); 512 } 513 return new GenMatrix<C>(this, m); 514 } 515 516 517 /** 518 * Random lower triangular matrix. 519 * @param k size of random coefficients. 520 * @param q density of nozero coefficients. 521 */ 522 public GenMatrix<C> randomLower(int k, float q) { 523 return randomLower(k, q, random); 524 } 525 526 527 /** 528 * Random lower triangular matrix. 529 * @param k size of random coefficients. 530 * @param q density of nozero coefficients. 531 * @param random is a source for random bits. 532 * @return a random element. 533 */ 534 public GenMatrix<C> randomLower(int k, float q, Random random) { 535 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 536 for (int i = 0; i < rows; i++) { 537 ArrayList<C> v = new ArrayList<C>(cols); 538 for (int j = 0; j < cols; j++) { 539 C e = coFac.getZERO(); 540 if (j <= i) { 541 if (random.nextFloat() < q) { 542 e = coFac.random(k, random); 543 } 544 } 545 v.add(e); 546 } 547 m.add(v); 548 } 549 return new GenMatrix<C>(this, m); 550 } 551 552 553 /** 554 * Copy matrix. 555 * @param c matrix to copy. 556 * @return copy of the matrix 557 */ 558 public GenMatrix<C> copy(GenMatrix<C> c) { 559 if (c == null) { 560 return c; 561 } 562 return c.copy(); 563 } 564 565 566 /** 567 * Generate matrix via lambda expression. 568 * @param gener lambda expression. 569 * @return the generated matrix. 570 */ 571 public GenMatrix<C> generate(BiFunction<Integer, Integer, C> gener) { 572 ArrayList<ArrayList<C>> m = new ArrayList<ArrayList<C>>(rows); 573 for (int i = 0; i < rows; i++) { 574 ArrayList<C> v = new ArrayList<C>(cols); 575 for (int j = 0; j < cols; j++) { 576 C e = gener.apply(i, j); 577 v.add(e); 578 } 579 m.add(v); 580 } 581 return new GenMatrix<C>(this, m); 582 } 583 584 585 /** 586 * Parse a matrix from a String. Syntax: [ [ c, ..., c ], ..., [ c, ..., c ] 587 * ] 588 * @param s input String. 589 * @return parsed matrix 590 */ 591 public GenMatrix<C> parse(String s) { 592 int i = s.indexOf("["); 593 if (i >= 0) { 594 s = s.substring(i + 1); 595 } 596 ArrayList<ArrayList<C>> mat = new ArrayList<ArrayList<C>>(rows); 597 ArrayList<C> v; 598 GenVector<C> vec; 599 GenVectorModul<C> vmod = new GenVectorModul<C>(coFac, cols); 600 String e; 601 int j; 602 do { 603 i = s.indexOf("]"); // delimit vector 604 j = s.lastIndexOf("]"); // delimit matrix 605 if (i != j) { 606 if (i >= 0) { 607 e = s.substring(0, i); 608 s = s.substring(i); 609 vec = vmod.parse(e); 610 v = new ArrayList<C>(vec.val); 611 mat.add(v); 612 i = s.indexOf(","); 613 if (i >= 0) { 614 s = s.substring(i + 1); 615 } 616 } 617 } else { // matrix delimiter 618 if (i >= 0) { 619 e = s.substring(0, i); 620 if (e.trim().length() > 0) { 621 throw new RuntimeException("Error e not empty " + e); 622 } 623 //s = s.substring(i + 1); 624 } 625 break; 626 } 627 } while (i >= 0); 628 return new GenMatrix<C>(this, mat); 629 } 630 631 632 /** 633 * Parse a matrix from a Reader. 634 * @param r Reader. 635 * @return parsed matrix 636 */ 637 public GenMatrix<C> parse(Reader r) { 638 String s = StringUtil.nextPairedString(r, '[', ']'); 639 return parse(s); 640 } 641 642}