1 9 package org.jscience.mathematics.matrices; 10 11 import java.io.Serializable ; 12 import java.util.Collection ; 13 import java.util.Iterator ; 14 15 import javolution.realtime.ConcurrentContext; 16 import javolution.realtime.PoolContext; 17 import javolution.realtime.RealtimeObject; 18 import javolution.realtime.ConcurrentContext.Logic; 19 import javolution.realtime.Realtime.ObjectSpace; 20 import javolution.lang.MathLib; 21 import javolution.lang.Text; 22 import javolution.lang.TextBuilder; 23 import javolution.xml.XmlElement; 24 import javolution.xml.XmlFormat; 25 26 import org.jscience.mathematics.numbers.Integer32; 27 28 51 public class Matrix<O extends Operable<O>> extends RealtimeObject implements 52 Operable<Matrix<O>>, Serializable { 53 54 64 protected static final XmlFormat<Matrix> XML = new XmlFormat<Matrix>( 65 Matrix.class) { 66 public void format(Matrix matrix, XmlElement xml) { 67 xml.setAttribute("rows", matrix.m); 68 xml.setAttribute("columns", matrix.n); 69 final int nm = matrix.m * matrix.n; 70 for (int i = 0; i < nm; i++) { 71 xml.getContent().add(matrix.o[i]); 72 } 73 } 74 75 public Matrix parse(XmlElement xml) { 76 return Matrix.valueOf(xml.getAttribute("rows", 1), xml 77 .getAttribute("columns", 1), (Collection <Operable>) xml 78 .getContent()); 79 } 80 }; 81 82 85 final O[] o; 86 87 90 int m; 91 92 95 int n; 96 97 102 Matrix(int size) { 103 this.o = (O[]) new Operable[size]; 104 } 105 106 116 public Matrix(O[][] elements) { 117 this.m = elements.length; 118 this.n = elements[0].length; 119 this.o = (O[]) new Operable[m * n]; 120 for (int i = 0; i < m; i++) { 121 if (elements[i].length != n) 122 throw new IllegalArgumentException ( 123 "All rows must have the same length."); 124 System.arraycopy(elements[i], 0, o, i * n, n); 125 } 126 } 127 128 141 public static <O extends Operable<O>> Matrix<O> valueOf(int m, int n, 142 O diagonal, O other) { 143 Matrix<O> M = newInstance(m, n); 144 for (int i = 0; i < m; i++) { 145 for (int j = 0; j < n; j++) { 146 M.o[i * n + j] = (i != j) ? other : diagonal; 147 } 148 } 149 return M; 150 } 151 152 164 public static <O extends Operable<O>> Matrix<O> valueOf(O[][] elements) { 165 int m = elements.length; 166 int n = elements[0].length; 167 Matrix<O> M = newInstance(m, n); 168 for (int i = 0; i < m; i++) { 169 if (elements[i].length != n) 170 throw new IllegalArgumentException ( 171 "All rows must have the same length."); 172 System.arraycopy(elements[i], 0, M.o, i * n, n); 173 } 174 return M; 175 } 176 177 188 public static <O extends Operable<O>> Matrix<O> valueOf(int m, int n, 189 Collection <O> elements) { 190 if (elements.size() != m * n) 191 throw new MatrixException(m * n + " elements expected but found " 192 + elements.size()); 193 Matrix<O> M = newInstance(m, n); 194 Iterator <O> iterator = elements.iterator(); 195 for (int i = 0; i < m; i++) { 196 for (int j = 0; j < n; j++) { 197 M.o[i * n + j] = iterator.next(); 198 } 199 } 200 return M; 201 } 202 203 208 public final int getNumberOfRows() { 209 return m; 210 } 211 212 217 public final int getNumberOfColumns() { 218 return n; 219 } 220 221 226 public final boolean isSquare() { 227 return m == n; 228 } 229 230 239 public final O get(int i, int j) { 240 if ((i < 0) || (i >= m) || (j < 0) || (j >= n)) 241 throw new IndexOutOfBoundsException ("i: " + i + ", j: " + j 242 + " (matrix[" + m + "," + n + "])"); 243 return o[i * n + j]; 244 } 245 246 256 public final Matrix<O> getMatrix(int i0, int i1, int j0, int j1) { 257 int Mm = i1 - i0 + 1; 258 int Mn = j1 - j0 + 1; 259 Matrix<O> M = newInstance(Mm, Mn); 260 for (int i = 0; i < Mm; i++) { 261 for (int j = 0; j < Mn; j++) { 262 M.o[i * Mn + j] = this.o[(i + i0) * m + j + j0]; 263 } 264 } 265 return M; 266 } 267 268 276 public final Matrix<O> getMatrix(int[] rows, int[] columns) { 277 int Mn = rows.length; 278 int Mm = columns.length; 279 Matrix<O> M = newInstance(Mm, Mn); 280 for (int i = 0; i < Mm; i++) { 281 for (int j = 0; j < Mn; j++) { 282 M.o[i * Mn + j] = this.o[rows[i] * n + columns[j]]; 283 } 284 } 285 return M; 286 } 287 288 299 public final LUDecomposition<O> lu() { 300 return LUDecomposition.valueOf(this); 301 } 302 303 310 public boolean equals(Object that) { 311 if (this == that) { 312 return true; 313 } else if (that instanceof Matrix) { 314 Matrix M = (Matrix) that; 315 if (M.m != this.m || M.n != this.n) { 316 return false; 317 } else { 318 for (int i = m * n; i > 0;) { 319 if (!this.o[--i].equals(M.o[i])) { 320 return false; 321 } 322 } 323 return true; 324 } 325 } else { 326 return false; 327 } 328 } 329 330 337 public int hashCode() { 338 int code = 0; 339 for (int i = m * n; i > 0;) { 340 code += o[--i].hashCode(); 341 } 342 return code; 343 } 344 345 350 public Matrix<O> opposite() { 351 Matrix<O> M = newInstance(m, n); 352 for (int i = m * n; i > 0;) { 353 M.o[--i] = this.o[i].opposite(); 354 } 355 return M; 356 } 357 358 365 public Matrix<O> plus(Matrix<O> that) { 366 if ((this.m == that.m) && (this.n == that.n)) { 367 Matrix<O> M = newInstance(m, n); 368 for (int i = m * n; i > 0;) { 369 M.o[--i] = this.o[i].plus(that.o[i]); 370 } 371 return M; 372 } else { 373 throw new MatrixException(); 374 } 375 } 376 377 384 public Matrix<O> minus(Matrix<O> that) { 385 if ((this.m == that.m) && (this.n == that.n)) { 386 Matrix<O> M = newInstance(m, n); 387 for (int i = m * n; i > 0;) { 388 M.o[--i] = this.o[i].plus(that.o[i].opposite()); 389 } 390 return M; 391 } else { 392 throw new MatrixException(); 393 } 394 } 395 396 402 public Matrix<O> times(O k) { 403 Matrix<O> M = newInstance(m, n); 404 for (int i = m * n; i > 0;) { 405 M.o[--i] = k.times(this.o[i]); 406 } 407 return M; 408 } 409 410 418 public Matrix<O> times(Matrix<O> that) { 419 if (this.n == that.m) { 420 Matrix<O> M = newInstance(this.m, that.n); 421 for (int i = 0; i < this.m; i++) { 422 final int i_m = i * n; 423 for (int j = 0; j < that.n; j++) { 424 O sum = this.o[i_m].times(that.o[j]); 425 for (int k = 1; k < this.n; k++) { 426 sum = sum.plus(this.o[i_m + k].times(that.o[k * that.n 427 + j])); 428 } 429 M.o[i * M.n + j] = sum; 430 } 431 } 432 return M; 433 } else { 434 throw new MatrixException(); 435 } 436 } 437 438 446 public Matrix<O> divide(Matrix<O> that) { 447 return this.times(that.reciprocal()); 448 } 449 450 457 public Matrix<O> reciprocal() { 458 if (!isSquare()) 459 throw new MatrixException("Matrix not square"); 460 return lu().inverse(); 461 } 462 463 473 public Matrix<O> inverse() { 474 if (isSquare()) 475 return lu().inverse(); 476 Matrix<O> thisTranspose = this.transpose(); 477 return (thisTranspose.times(this)).inverse().times(thisTranspose); 478 } 479 480 489 public Matrix<O> tensor(Matrix<O> that) { 490 Matrix<O> C = newInstance(this.m * that.m, this.n * that.n); 491 boolean endCol = false; 492 int cCount = 0, rCount = 0; 493 int subMatrix = 0, iref = 0, jref = 0; 494 for (int j = 0; j < n; j++) { 495 for (int i = 0; i < m; i++) { 496 Matrix<O> X = that.times(o[i * this.n + j]); 497 rCount = subMatrix % m; 498 if (rCount > 0) { 499 endCol = true; 500 } 501 if ((rCount == 0) && (endCol == true)) { 502 cCount++; 503 } 504 for (int y = 0; y < that.n; y++) { 505 for (int x = 0; x < that.m; x++) { 506 iref = x + (rCount * that.m); 507 jref = y + (cCount * that.m); 508 C.o[iref * C.n + jref] = X.get(x, y); 509 } 510 } 511 subMatrix++; 512 } 513 } 514 return C; 515 } 516 517 522 public Text toText() { 523 TextBuilder cb = TextBuilder.newInstance(); 524 cb.append("{"); 525 for (int i = 0; i < m; i++) { 526 cb.append("{"); 527 for (int j = 0; j < n; j++) { 528 cb.append(o[i * n + j]); 529 if (j != n - 1) { 530 cb.append(", "); 531 } 532 } 533 if (i != m - 1) { 534 cb.append("},\n"); 535 } 536 } 537 cb.append("}}"); 538 return cb.toText(); 539 } 540 541 546 public Matrix<O> transpose() { 547 Matrix<O> M = newInstance(n, m); 548 for (int i = 0; i < m; i++) { 549 for (int j = 0; j < n; j++) { 550 M.o[j * m + i] = o[i * n + j]; 551 } 552 } 553 return M; 554 } 555 556 565 public O determinant() { 566 return (O) lu().determinant(); 567 } 568 569 580 public O cofactor(int i, int j) { 581 Matrix<O> M = newInstance(m - 1, n - 1); 582 int row = 0; 583 for (int k1 = 0; k1 < m; k1++) { 584 if (k1 == i) { 585 continue; 586 } 587 int column = 0; 588 for (int k2 = 0; k2 < n; k2++) { 589 if (k2 == j) { 590 continue; 591 } 592 M.o[row * M.n + column] = o[k1 * n + k2]; 593 column++; 594 } 595 row++; 596 } 597 return M.determinant(); 598 } 599 600 605 public O trace() { 606 O sum = o[0]; 607 for (int i = MathLib.min(m, n); i > 1;) { 608 sum = sum.plus(o[--i * n + i]); 609 } 610 return sum; 611 } 612 613 623 public Matrix<O> adjoint() { 624 Matrix<O> M = newInstance(m, n); 625 for (int i = 0; i < m; i++) { 626 for (int j = 0; j < n; j++) { 627 M.o[i * n + j] = ((i + j) % 2 == 0) ? this.cofactor(i, j) 628 : this.cofactor(i, j).opposite(); 629 } 630 } 631 return M.transpose(); 632 } 633 634 641 public Matrix<O> pow(int exp) { 642 if (exp > 0) { 643 PoolContext.enter(); 644 try { 645 Matrix<O> pow2 = this; 646 Matrix<O> result = null; 647 while (exp >= 1) { if ((exp & 1) == 1) { 649 result = (result == null) ? pow2 : result.times(pow2); 650 } 651 pow2 = pow2.times(pow2); 652 exp >>>= 1; 653 } 654 result.export(); 655 return result; 656 } finally { 657 PoolContext.exit(); 658 } 659 } else if (exp == 0) { 660 return this.times(this.inverse()); } else { 662 return this.pow(-exp).inverse(); 663 } 664 } 665 666 public boolean move(ObjectSpace os) { 668 if (super.move(os)) { 669 for (int i = m * n; i > 0;) { 670 o[--i].move(os); 671 } 672 return true; 673 } 674 return false; 675 } 676 677 685 static <O extends Operable<O>> Matrix<O> newInstance(int m, int n) { 686 if (n == 1) 687 return Vector.newInstance(m); 688 Matrix M; 689 final int size = n * m; 690 if (size <= 1 << 3) { 691 M = FACTORY_3.object(); 692 } else if (size <= 1 << 6) { 693 M = FACTORY_6.object(); 694 } else if (size <= 1 << 9) { 695 M = FACTORY_9.object(); 696 } else if (size <= 1 << 12) { 697 M = FACTORY_12.object(); 698 } else if (size <= 1 << 15) { 699 M = FACTORY_15.object(); 700 } else if (size <= 1 << 18) { 701 M = FACTORY_18.object(); 702 } else if (size <= 1 << 21) { 703 M = FACTORY_21.object(); 704 } else if (size <= 1 << 24) { 705 M = FACTORY_24.object(); 706 } else if (size <= 1 << 27) { 707 M = FACTORY_27.object(); 708 } else if (size <= 1 << 30) { 709 M = FACTORY_30.object(); 710 } else { 711 throw new UnsupportedOperationException ("Matrix too large"); 712 } 713 M.m = m; 714 M.n = n; 715 return M; 716 } 717 718 721 private static final Factory<Matrix> FACTORY_3 = new Factory<Matrix>() { 722 protected Matrix create() { 723 return new Matrix(1 << 3); 724 } 725 }; 726 727 private static final Factory<Matrix> FACTORY_6 = new Factory<Matrix>() { 728 protected Matrix create() { 729 return new Matrix(1 << 6); 730 } 731 }; 732 733 private static final Factory<Matrix> FACTORY_9 = new Factory<Matrix>() { 734 protected Matrix create() { 735 return new Matrix(1 << 9); 736 } 737 }; 738 739 private static final Factory<Matrix> FACTORY_12 = new Factory<Matrix>() { 740 protected Matrix create() { 741 return new Matrix(1 << 12); 742 } 743 }; 744 745 private static final Factory<Matrix> FACTORY_15 = new Factory<Matrix>() { 746 protected Matrix create() { 747 return new Matrix(1 << 15); 748 } 749 }; 750 751 private static final Factory<Matrix> FACTORY_18 = new Factory<Matrix>() { 752 protected Matrix create() { 753 return new Matrix(1 << 18); 754 } 755 }; 756 757 private static final Factory<Matrix> FACTORY_21 = new Factory<Matrix>() { 758 protected Matrix create() { 759 return new Matrix(1 << 21); 760 } 761 }; 762 763 private static final Factory<Matrix> FACTORY_24 = new Factory<Matrix>() { 764 protected Matrix create() { 765 return new Matrix(1 << 24); 766 } 767 }; 768 769 private static final Factory<Matrix> FACTORY_27 = new Factory<Matrix>() { 770 protected Matrix create() { 771 return new Matrix(1 << 27); 772 } 773 }; 774 775 private static final Factory<Matrix> FACTORY_30 = new Factory<Matrix>() { 776 protected Matrix create() { 777 return new Matrix(1 << 30); 778 } 779 }; 780 781 private static final long serialVersionUID = 1L; 782 783 } | Popular Tags |