/Users/lyon/j4p/src/math/linearAlgebra/Matrix.java
|
1 package math.linearAlgebra;
2
3 import math.linearAlgebra.util.Maths;
4
5 import java.io.BufferedReader;
6 import java.io.PrintWriter;
7 import java.io.StreamTokenizer;
8 import java.text.DecimalFormat;
9 import java.text.DecimalFormatSymbols;
10 import java.text.NumberFormat;
11 import java.util.Locale;
12
13 /**
14 linearAlgebra = Java Matrix class.
15 <P>
16 The Java Matrix Class provides the fundamental operations of numerical
17 linear algebra. Various constructors create Matrices from two dimensional
18 arrays of double precision floating point numbers. Various "gets" and
19 "sets" provide access to submatrices and matrix elements. Several methods
20 implement basic matrix arithmetic, including matrix addition and
21 multiplication, matrix norms, and element-by-element array operations.
22 Methods for reading and printing matrices are also included. All the
23 operations in this version of the Matrix Class involve real matrices.
24 Complex matrices may be handled in a future version.
25 <P>
26 Five fundamental matrix decompositions, which consist of pairs or triples
27 of matrices, permutation vectors, and the like, produce results in five
28 decomposition classes. These decompositions are accessed by the Matrix
29 class to compute solutions of simultaneous linear equations, determinants,
30 inverses and other matrix functions. The five decompositions are:
31 <P><UL>
32 <LI>Cholesky Decomposition of symmetric, positive definite matrices.
33 <LI>LU Decomposition of rectangular matrices.
34 <LI>QR Decomposition of rectangular matrices.
35 <LI>Singular Value Decomposition of rectangular matrices.
36 <LI>Eigenvalue Decomposition of both symmetric and nonsymmetric square matrices.
37 </UL>
38 <DL>
39 <DT><B>Example of use:</B></DT>
40 <P>
41 <DD>Solve a linear system A x = b and compute the residual norm, ||b - A x||.
42 <P><PRE>
43 double[][] vals = {{1.,2.,3},{4.,5.,6.},{7.,8.,10.}};
44 Matrix A = new Matrix(vals);
45 Matrix b = Matrix.random(3,1);
46 Matrix x = A.solve(b);
47 Matrix r = A.times(x).minus(b);
48 double rnorm = r.normInf();
49 </PRE></DD>
50 </DL>
51
52 @author The MathWorks, Inc. and the National Institute of Standards and Technology.
53 @version 5 August 1998
54 */
55
56 public class Matrix implements Cloneable, java.io.Serializable {
57
58 /* ------------------------
59 Class variables
60 * ------------------------ */
61
62 /** Array for internal storage of elements.
63 @serial internal array storage.
64 */
65 private double[][] A;
66
67 /** Row and column dimensions.
68 @serial row dimension.
69 @serial column dimension.
70 */
71 private int m, n;
72
73 /* ------------------------
74 Constructors
75 * ------------------------ */
76
77 /** Construct an m-by-n matrix of zeros.
78 @param m Number of rows.
79 @param n Number of colums.
80 */
81
82 public Matrix(int m, int n) {
83 this.m = m;
84 this.n = n;
85 A = new double[m][n];
86 }
87
88 /** Construct an m-by-n constant matrix.
89 @param m Number of rows.
90 @param n Number of colums.
91 @param s Fill the matrix with this scalar value.
92 */
93
94 public Matrix(int m, int n, double s) {
95 this.m = m;
96 this.n = n;
97 A = new double[m][n];
98 for (int i = 0; i < m; i++) {
99 for (int j = 0; j < n; j++) {
100 A[i][j] = s;
101 }
102 }
103 }
104
105 /** Construct a matrix from a 2-D array.
106 @param A Two-dimensional array of doubles.
107 @exception IllegalArgumentException All rows must have the same length
108 @see #constructWithCopy
109 */
110
111 public Matrix(double[][] A) {
112 m = A.length;
113 n = A[0].length;
114 for (int i = 0; i < m; i++) {
115 if (A[i].length != n) {
116 throw new IllegalArgumentException("All rows must have the same length.");
117 }
118 }
119 this.A = A;
120 }
121
122 /** Construct a matrix quickly without checking arguments.
123 @param A Two-dimensional array of doubles.
124 @param m Number of rows.
125 @param n Number of colums.
126 */
127
128 public Matrix(double[][] A, int m, int n) {
129 this.A = A;
130 this.m = m;
131 this.n = n;
132 }
133
134 /** Construct a matrix from a one-dimensional packed array
135 @param vals One-dimensional array of doubles, packed by columns (ala Fortran).
136 @param m Number of rows.
137 @exception IllegalArgumentException Array length must be a multiple of m.
138 */
139
140 public Matrix(double vals[], int m) {
141 this.m = m;
142 n = (m != 0 ? vals.length / m : 0);
143 if (m * n != vals.length) {
144 throw new IllegalArgumentException("Array length must be a multiple of m.");
145 }
146 A = new double[m][n];
147 for (int i = 0; i < m; i++) {
148 for (int j = 0; j < n; j++) {
149 A[i][j] = vals[i + j * m];
150 }
151 }
152 }
153
154 /* ------------------------
155 Public Methods
156 * ------------------------ */
157
158 /** Construct a matrix from a copy of a 2-D array.
159 @param A Two-dimensional array of doubles.
160 @exception IllegalArgumentException All rows must have the same length
161 */
162
163 public static Matrix constructWithCopy(double[][] A) {
164 int m = A.length;
165 int n = A[0].length;
166 Matrix X = new Matrix(m, n);
167 double[][] C = X.getArray();
168 for (int i = 0; i < m; i++) {
169 if (A[i].length != n) {
170 throw new IllegalArgumentException
171 ("All rows must have the same length.");
172 }
173 for (int j = 0; j < n; j++) {
174 C[i][j] = A[i][j];
175 }
176 }
177 return X;
178 }
179
180 /** Make a deep copy of a matrix
181 */
182
183 public Matrix copy() {
184 Matrix X = new Matrix(m, n);
185 double[][] C = X.getArray();
186 for (int i = 0; i < m; i++) {
187 for (int j = 0; j < n; j++) {
188 C[i][j] = A[i][j];
189 }
190 }
191 return X;
192 }
193
194 /** Clone the Matrix object.
195 */
196
197 public Object clone() {
198 return this.copy();
199 }
200
201 /** Access the internal two-dimensional array.
202 @return Pointer to the two-dimensional array of matrix elements.
203 */
204
205 public double[][] getArray() {
206 return A;
207 }
208
209 /** Copy the internal two-dimensional array.
210 @return Two-dimensional array copy of matrix elements.
211 */
212
213 public double[][] getArrayCopy() {
214 double[][] C = new double[m][n];
215 for (int i = 0; i < m; i++) {
216 for (int j = 0; j < n; j++) {
217 C[i][j] = A[i][j];
218 }
219 }
220 return C;
221 }
222
223 /** Make a one-dimensional column packed copy of the internal array.
224 @return Matrix elements packed in a one-dimensional array by columns.
225 */
226
227 public double[] getColumnPackedCopy() {
228 double[] vals = new double[m * n];
229 for (int i = 0; i < m; i++) {
230 for (int j = 0; j < n; j++) {
231 vals[i + j * m] = A[i][j];
232 }
233 }
234 return vals;
235 }
236
237 /** Make a one-dimensional row packed copy of the internal array.
238 @return Matrix elements packed in a one-dimensional array by rows.
239 */
240
241 public double[] getRowPackedCopy() {
242 double[] vals = new double[m * n];
243 for (int i = 0; i < m; i++) {
244 for (int j = 0; j < n; j++) {
245 vals[i * n + j] = A[i][j];
246 }
247 }
248 return vals;
249 }
250
251 /** Get row dimension.
252 @return m, the number of rows.
253 */
254
255 public int getRowDimension() {
256 return m;
257 }
258
259 /** Get column dimension.
260 @return n, the number of columns.
261 */
262
263 public int getColumnDimension() {
264 return n;
265 }
266
267 /** Get a single element.
268 @param i Row index.
269 @param j Column index.
270 @return A(i,j)
271 @exception ArrayIndexOutOfBoundsException
272 */
273
274 public double get(int i, int j) {
275 return A[i][j];
276 }
277
278 /** Get a submatrix.
279 @param i0 Initial row index
280 @param i1 Final row index
281 @param j0 Initial column index
282 @param j1 Final column index
283 @return A(i0:i1,j0:j1)
284 @exception ArrayIndexOutOfBoundsException Submatrix indices
285 */
286
287 public Matrix getMatrix(int i0, int i1, int j0, int j1) {
288 Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
289 double[][] B = X.getArray();
290 try {
291 for (int i = i0; i <= i1; i++) {
292 for (int j = j0; j <= j1; j++) {
293 B[i - i0][j - j0] = A[i][j];
294 }
295 }
296 } catch (ArrayIndexOutOfBoundsException e) {
297 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
298 }
299 return X;
300 }
301
302 /** Get a submatrix.
303 @param r Array of row indices.
304 @param c Array of column indices.
305 @return A(r(:),c(:))
306 @exception ArrayIndexOutOfBoundsException Submatrix indices
307 */
308
309 public Matrix getMatrix(int[] r, int[] c) {
310 Matrix X = new Matrix(r.length, c.length);
311 double[][] B = X.getArray();
312 try {
313 for (int i = 0; i < r.length; i++) {
314 for (int j = 0; j < c.length; j++) {
315 B[i][j] = A[r[i]][c[j]];
316 }
317 }
318 } catch (ArrayIndexOutOfBoundsException e) {
319 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
320 }
321 return X;
322 }
323
324 /** Get a submatrix.
325 @param i0 Initial row index
326 @param i1 Final row index
327 @param c Array of column indices.
328 @return A(i0:i1,c(:))
329 @exception ArrayIndexOutOfBoundsException Submatrix indices
330 */
331
332 public Matrix getMatrix(int i0, int i1, int[] c) {
333 Matrix X = new Matrix(i1 - i0 + 1, c.length);
334 double[][] B = X.getArray();
335 try {
336 for (int i = i0; i <= i1; i++) {
337 for (int j = 0; j < c.length; j++) {
338 B[i - i0][j] = A[i][c[j]];
339 }
340 }
341 } catch (ArrayIndexOutOfBoundsException e) {
342 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
343 }
344 return X;
345 }
346
347 /** Get a submatrix.
348 @param r Array of row indices.
349 @param j0 Initial column index
350 @param j1 Final column index
351 @return A(r(:),j0:j1)
352 @exception ArrayIndexOutOfBoundsException Submatrix indices
353 */
354
355 public Matrix getMatrix(int[] r, int j0, int j1) {
356 Matrix X = new Matrix(r.length, j1 - j0 + 1);
357 double[][] B = X.getArray();
358 try {
359 for (int i = 0; i < r.length; i++) {
360 for (int j = j0; j <= j1; j++) {
361 B[i][j - j0] = A[r[i]][j];
362 }
363 }
364 } catch (ArrayIndexOutOfBoundsException e) {
365 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
366 }
367 return X;
368 }
369
370 /** Set a single element.
371 @param i Row index.
372 @param j Column index.
373 @param s A(i,j).
374 @exception ArrayIndexOutOfBoundsException
375 */
376
377 public void set(int i, int j, double s) {
378 A[i][j] = s;
379 }
380
381 /** Set a submatrix.
382 @param i0 Initial row index
383 @param i1 Final row index
384 @param j0 Initial column index
385 @param j1 Final column index
386 @param X A(i0:i1,j0:j1)
387 @exception ArrayIndexOutOfBoundsException Submatrix indices
388 */
389
390 public void setMatrix(int i0, int i1, int j0, int j1, Matrix X) {
391 try {
392 for (int i = i0; i <= i1; i++) {
393 for (int j = j0; j <= j1; j++) {
394 A[i][j] = X.get(i - i0, j - j0);
395 }
396 }
397 } catch (ArrayIndexOutOfBoundsException e) {
398 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
399 }
400 }
401
402 /** Set a submatrix.
403 @param r Array of row indices.
404 @param c Array of column indices.
405 @param X A(r(:),c(:))
406 @exception ArrayIndexOutOfBoundsException Submatrix indices
407 */
408
409 public void setMatrix(int[] r, int[] c, Matrix X) {
410 try {
411 for (int i = 0; i < r.length; i++) {
412 for (int j = 0; j < c.length; j++) {
413 A[r[i]][c[j]] = X.get(i, j);
414 }
415 }
416 } catch (ArrayIndexOutOfBoundsException e) {
417 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
418 }
419 }
420
421 /** Set a submatrix.
422 @param r Array of row indices.
423 @param j0 Initial column index
424 @param j1 Final column index
425 @param X A(r(:),j0:j1)
426 @exception ArrayIndexOutOfBoundsException Submatrix indices
427 */
428
429 public void setMatrix(int[] r, int j0, int j1, Matrix X) {
430 try {
431 for (int i = 0; i < r.length; i++) {
432 for (int j = j0; j <= j1; j++) {
433 A[r[i]][j] = X.get(i, j - j0);
434 }
435 }
436 } catch (ArrayIndexOutOfBoundsException e) {
437 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
438 }
439 }
440
441 /** Set a submatrix.
442 @param i0 Initial row index
443 @param i1 Final row index
444 @param c Array of column indices.
445 @param X A(i0:i1,c(:))
446 @exception ArrayIndexOutOfBoundsException Submatrix indices
447 */
448
449 public void setMatrix(int i0, int i1, int[] c, Matrix X) {
450 try {
451 for (int i = i0; i <= i1; i++) {
452 for (int j = 0; j < c.length; j++) {
453 A[i][c[j]] = X.get(i - i0, j);
454 }
455 }
456 } catch (ArrayIndexOutOfBoundsException e) {
457 throw new ArrayIndexOutOfBoundsException("Submatrix indices");
458 }
459 }
460
461 /** Matrix transpose.
462 @return A'
463 */
464
465 public Matrix transpose() {
466 Matrix X = new Matrix(n, m);
467 double[][] C = X.getArray();
468 for (int i = 0; i < m; i++) {
469 for (int j = 0; j < n; j++) {
470 C[j][i] = A[i][j];
471 }
472 }
473 return X;
474 }
475
476 /** One norm
477 @return maximum column sum.
478 */
479
480 public double norm1() {
481 double f = 0;
482 for (int j = 0; j < n; j++) {
483 double s = 0;
484 for (int i = 0; i < m; i++) {
485 s += Math.abs(A[i][j]);
486 }
487 f = Math.max(f, s);
488 }
489 return f;
490 }
491
492 /** Two norm
493 @return maximum singular value.
494 */
495
496 public double norm2() {
497 return (new SingularValueDecomposition(this).norm2());
498 }
499
500 /** Infinity norm
501 @return maximum row sum.
502 */
503
504 public double normInf() {
505 double f = 0;
506 for (int i = 0; i < m; i++) {
507 double s = 0;
508 for (int j = 0; j < n; j++) {
509 s += Math.abs(A[i][j]);
510 }
511 f = Math.max(f, s);
512 }
513 return f;
514 }
515
516 /** Frobenius norm
517 @return sqrt of sum of squares of all elements.
518 */
519
520 public double normF() {
521 double f = 0;
522 for (int i = 0; i < m; i++) {
523 for (int j = 0; j < n; j++) {
524 f = Maths.hypot(f, A[i][j]);
525 }
526 }
527 return f;
528 }
529
530 /** Unary minus
531 @return -A
532 */
533
534 public Matrix uminus() {
535 Matrix X = new Matrix(m, n);
536 double[][] C = X.getArray();
537 for (int i = 0; i < m; i++) {
538 for (int j = 0; j < n; j++) {
539 C[i][j] = -A[i][j];
540 }
541 }
542 return X;
543 }
544
545 /** C = A + B
546 @param B another matrix
547 @return A + B
548 */
549
550 public Matrix plus(Matrix B) {
551 checkMatrixDimensions(B);
552 Matrix X = new Matrix(m, n);
553 double[][] C = X.getArray();
554 for (int i = 0; i < m; i++) {
555 for (int j = 0; j < n; j++) {
556 C[i][j] = A[i][j] + B.A[i][j];
557 }
558 }
559 return X;
560 }
561
562 /** A = A + B
563 @param B another matrix
564 @return A + B
565 */
566
567 public Matrix plusEquals(Matrix B) {
568 checkMatrixDimensions(B);
569 for (int i = 0; i < m; i++) {
570 for (int j = 0; j < n; j++) {
571 A[i][j] = A[i][j] + B.A[i][j];
572 }
573 }
574 return this;
575 }
576
577 /** C = A - B
578 @param B another matrix
579 @return A - B
580 */
581
582 public Matrix minus(Matrix B) {
583 checkMatrixDimensions(B);
584 Matrix X = new Matrix(m, n);
585 double[][] C = X.getArray();
586 for (int i = 0; i < m; i++) {
587 for (int j = 0; j < n; j++) {
588 C[i][j] = A[i][j] - B.A[i][j];
589 }
590 }
591 return X;
592 }
593
594 /** A = A - B
595 @param B another matrix
596 @return A - B
597 */
598
599 public Matrix minusEquals(Matrix B) {
600 checkMatrixDimensions(B);
601 for (int i = 0; i < m; i++) {
602 for (int j = 0; j < n; j++) {
603 A[i][j] = A[i][j] - B.A[i][j];
604 }
605 }
606 return this;
607 }
608
609 /** Element-by-element multiplication, C = A.*B
610 @param B another matrix
611 @return A.*B
612 */
613
614 public Matrix arrayTimes(Matrix B) {
615 checkMatrixDimensions(B);
616 Matrix X = new Matrix(m, n);
617 double[][] C = X.getArray();
618 for (int i = 0; i < m; i++) {
619 for (int j = 0; j < n; j++) {
620 C[i][j] = A[i][j] * B.A[i][j];
621 }
622 }
623 return X;
624 }
625
626 /** Element-by-element multiplication in place, A = A.*B
627 @param B another matrix
628 @return A.*B
629 */
630
631 public Matrix arrayTimesEquals(Matrix B) {
632 checkMatrixDimensions(B);
633 for (int i = 0; i < m; i++) {
634 for (int j = 0; j < n; j++) {
635 A[i][j] = A[i][j] * B.A[i][j];
636 }
637 }
638 return this;
639 }
640
641 /** Element-by-element right division, C = A./B
642 @param B another matrix
643 @return A./B
644 */
645
646 public Matrix arrayRightDivide(Matrix B) {
647 checkMatrixDimensions(B);
648 Matrix X = new Matrix(m, n);
649 double[][] C = X.getArray();
650 for (int i = 0; i < m; i++) {
651 for (int j = 0; j < n; j++) {
652 C[i][j] = A[i][j] / B.A[i][j];
653 }
654 }
655 return X;
656 }
657
658 /** Element-by-element right division in place, A = A./B
659 @param B another matrix
660 @return A./B
661 */
662
663 public Matrix arrayRightDivideEquals(Matrix B) {
664 checkMatrixDimensions(B);
665 for (int i = 0; i < m; i++) {
666 for (int j = 0; j < n; j++) {
667 A[i][j] = A[i][j] / B.A[i][j];
668 }
669 }
670 return this;
671 }
672
673 /** Element-by-element left division, C = A.\B
674 @param B another matrix
675 @return A.\B
676 */
677
678 public Matrix arrayLeftDivide(Matrix B) {
679 checkMatrixDimensions(B);
680 Matrix X = new Matrix(m, n);
681 double[][] C = X.getArray();
682 for (int i = 0; i < m; i++) {
683 for (int j = 0; j < n; j++) {
684 C[i][j] = B.A[i][j] / A[i][j];
685 }
686 }
687 return X;
688 }
689
690 /** Element-by-element left division in place, A = A.\B
691 @param B another matrix
692 @return A.\B
693 */
694
695 public Matrix arrayLeftDivideEquals(Matrix B) {
696 checkMatrixDimensions(B);
697 for (int i = 0; i < m; i++) {
698 for (int j = 0; j < n; j++) {
699 A[i][j] = B.A[i][j] / A[i][j];
700 }
701 }
702 return this;
703 }
704
705 /** Multiply a matrix by a scalar, C = s*A
706 @param s scalar
707 @return s*A
708 */
709
710 public Matrix times(double s) {
711 Matrix X = new Matrix(m, n);
712 double[][] C = X.getArray();
713 for (int i = 0; i < m; i++) {
714 for (int j = 0; j < n; j++) {
715 C[i][j] = s * A[i][j];
716 }
717 }
718 return X;
719 }
720
721 /** Multiply a matrix by a scalar in place, A = s*A
722 @param s scalar
723 @return replace A by s*A
724 */
725
726 public Matrix timesEquals(double s) {
727 for (int i = 0; i < m; i++) {
728 for (int j = 0; j < n; j++) {
729 A[i][j] = s * A[i][j];
730 }
731 }
732 return this;
733 }
734
735 /** Linear algebraic matrix multiplication, A * B
736 @param B another matrix
737 @return Matrix product, A * B
738 @exception IllegalArgumentException Matrix inner dimensions must agree.
739 */
740
741 public Matrix times(Matrix B) {
742 if (B.m != n) {
743 throw new IllegalArgumentException("Matrix inner dimensions must agree.");
744 }
745 Matrix X = new Matrix(m, B.n);
746 double[][] C = X.getArray();
747 double[] Bcolj = new double[n];
748 for (int j = 0; j < B.n; j++) {
749 for (int k = 0; k < n; k++) {
750 Bcolj[k] = B.A[k][j];
751 }
752 for (int i = 0; i < m; i++) {
753 double[] Arowi = A[i];
754 double s = 0;
755 for (int k = 0; k < n; k++) {
756 s += Arowi[k] * Bcolj[k];
757 }
758 C[i][j] = s;
759 }
760 }
761 return X;
762 }
763
764 /** LU Decomposition
765 @return LUDecomposition
766 @see LUDecomposition
767 */
768
769 public LUDecomposition lu() {
770 return new LUDecomposition(this);
771 }
772
773 /** QR Decomposition
774 @return QRDecomposition
775 @see QRDecomposition
776 */
777
778 public QRDecomposition qr() {
779 return new QRDecomposition(this);
780 }
781
782 /** Cholesky Decomposition
783 @return CholeskyDecomposition
784 @see CholeskyDecomposition
785 */
786
787 public CholeskyDecomposition chol() {
788 return new CholeskyDecomposition(this);
789 }
790
791 /** Singular Value Decomposition
792 @return SingularValueDecomposition
793 @see SingularValueDecomposition
794 */
795
796 public SingularValueDecomposition svd() {
797 return new SingularValueDecomposition(this);
798 }
799
800 /** Eigenvalue Decomposition
801 @return EigenvalueDecomposition
802 @see EigenvalueDecomposition
803 */
804
805 public EigenvalueDecomposition eig() {
806 return new EigenvalueDecomposition(this);
807 }
808
809 /** Solve A*X = B
810 @param B right hand side
811 @return solution if A is square, least squares solution otherwise
812 */
813
814 public Matrix solve(Matrix B) {
815 return (m == n ? (new LUDecomposition(this)).solve(B) :
816 (new QRDecomposition(this)).solve(B));
817 }
818
819 /** Solve X*A = B, which is also A'*X' = B'
820 @param B right hand side
821 @return solution if A is square, least squares solution otherwise.
822 */
823
824 public Matrix solveTranspose(Matrix B) {
825 return transpose().solve(B.transpose());
826 }
827
828 /** Matrix inverse or pseudoinverse
829 @return inverse(A) if A is square, pseudoinverse otherwise.
830 */
831
832 public Matrix inverse() {
833 return solve(identity(m, m));
834 }
835
836 /** Matrix determinant
837 @return determinant
838 */
839
840 public double det() {
841 return new LUDecomposition(this).det();
842 }
843
844 /** Matrix rank
845 @return effective numerical rank, obtained from SVD.
846 */
847
848 public int rank() {
849 return new SingularValueDecomposition(this).rank();
850 }
851
852 /** Matrix condition (2 norm)
853 @return ratio of largest to smallest singular value.
854 */
855
856 public double cond() {
857 return new SingularValueDecomposition(this).cond();
858 }
859
860 /** Matrix trace.
861 @return sum of the diagonal elements.
862 */
863
864 public double trace() {
865 double t = 0;
866 for (int i = 0; i < Math.min(m, n); i++) {
867 t += A[i][i];
868 }
869 return t;
870 }
871
872 /** Generate matrix with random elements
873 @param m Number of rows.
874 @param n Number of colums.
875 @return An m-by-n matrix with uniformly distributed random elements.
876 */
877
878 public static Matrix random(int m, int n) {
879 Matrix A = new Matrix(m, n);
880 double[][] X = A.getArray();
881 for (int i = 0; i < m; i++) {
882 for (int j = 0; j < n; j++) {
883 X[i][j] = Math.random();
884 }
885 }
886 return A;
887 }
888
889 /** Generate identity matrix
890 @param m Number of rows.
891 @param n Number of colums.
892 @return An m-by-n matrix with ones on the diagonal and zeros elsewhere.
893 */
894
895 public static Matrix identity(int m, int n) {
896 Matrix A = new Matrix(m, n);
897 double[][] X = A.getArray();
898 for (int i = 0; i < m; i++) {
899 for (int j = 0; j < n; j++) {
900 X[i][j] = (i == j ? 1.0 : 0.0);
901 }
902 }
903 return A;
904 }
905
906
907 /** Print the matrix to stdout. Line the elements up in columns
908 * with a Fortran-like 'Fw.d' style format.
909 @param w Column width.
910 @param d Number of digits after the decimal.
911 */
912
913 public void print(int w, int d) {
914 print(new PrintWriter(System.out, true), w, d);
915 }
916
917 /** Print the matrix to the output stream. Line the elements up in
918 * columns with a Fortran-like 'Fw.d' style format.
919 @param output Output stream.
920 @param w Column width.
921 @param d Number of digits after the decimal.
922 */
923
924 public void print(PrintWriter output, int w, int d) {
925 DecimalFormat format = new DecimalFormat();
926 format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
927 format.setMinimumIntegerDigits(1);
928 format.setMaximumFractionDigits(d);
929 format.setMinimumFractionDigits(d);
930 format.setGroupingUsed(false);
931 print(output, format, w + 2);
932 }
933
934 /** Print the matrix to stdout. Line the elements up in columns.
935 * Use the format object, and right justify within columns of width
936 * characters.
937 * Note that is the matrix is to be read back in, you probably will want
938 * to use a NumberFormat that is set to US Locale.
939 @param format A Formatting object for individual elements.
940 @param width Field width for each column.
941 @see java.text.DecimalFormat#setDecimalFormatSymbols
942 */
943
944 public void print(NumberFormat format, int width) {
945 print(new PrintWriter(System.out, true), format, width);
946 }
947
948 // DecimalFormat is a little disappointing coming from Fortran or C's printf.
949 // Since it doesn't pad on the left, the elements will come out different
950 // widths. Consequently, we'll pass the desired column width in as an
951 // argument and do the extra padding ourselves.
952
953 /** Print the matrix to the output stream. Line the elements up in columns.
954 * Use the format object, and right justify within columns of width
955 * characters.
956 * Note that is the matrix is to be read back in, you probably will want
957 * to use a NumberFormat that is set to US Locale.
958 @param output the output stream.
959 @param format A formatting object to format the matrix elements
960 @param width Column width.
961 @see java.text.DecimalFormat#setDecimalFormatSymbols
962 */
963
964 public void print(PrintWriter output, NumberFormat format, int width) {
965 output.println(); // start on new line.
966 for (int i = 0; i < m; i++) {
967 for (int j = 0; j < n; j++) {
968 String s = format.format(A[i][j]); // format the number
969 int padding = Math.max(1, width - s.length()); // At _least_ 1 space
970 for (int k = 0; k < padding; k++)
971 output.print(' ');
972 output.print(s);
973 }
974 output.println();
975 }
976 output.println(); // end with blank line.
977 }
978
979 /** Read a matrix from a stream. The format is the same the print method,
980 * so printed matrices can be read back in (provided they were printed using
981 * US Locale). Elements are separated by
982 * whitespace, all the elements for each row appear on a single line,
983 * the last row is followed by a blank line.
984 @param input the input stream.
985 */
986
987 public static Matrix read(BufferedReader input) throws java.io.IOException {
988 StreamTokenizer tokenizer = new StreamTokenizer(input);
989
990 // Although StreamTokenizer will parse numbers, it doesn't recognize
991 // scientific notation (E or D); however, Double.valueOf does.
992 // The strategy here is to disable StreamTokenizer's number parsing.
993 // We'll only get whitespace delimited words, EOL's and EOF's.
994 // These words should all be numbers, for Double.valueOf to parse.
995
996 tokenizer.resetSyntax();
997 tokenizer.wordChars(0, 255);
998 tokenizer.whitespaceChars(0, ' ');
999 tokenizer.eolIsSignificant(true);
1000 java.util.Vector v = new java.util.Vector();
1001
1002 // Ignore initial empty lines
1003 while (tokenizer.nextToken() == StreamTokenizer.TT_EOL) ;
1004 if (tokenizer.ttype == StreamTokenizer.TT_EOF)
1005 throw new java.io.IOException("Unexpected EOF on matrix read.");
1006 do {
1007 v.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st row.
1008 } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
1009
1010 int n = v.size(); // Now we've got the number of columns!
1011 double row[] = new double[n];
1012 for (int j = 0; j < n; j++) // extract the elements of the 1st row.
1013 row[j] = ((Double) v.elementAt(j)).doubleValue();
1014 v.removeAllElements();
1015 v.addElement(row); // Start storing rows instead of columns.
1016 while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
1017 // While non-empty lines
1018 v.addElement(row = new double[n]);
1019 int j = 0;
1020 do {
1021 if (j >= n)
1022 throw new java.io.IOException
1023 ("Row " + v.size() + " is too long.");
1024 row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
1025 } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
1026 if (j < n)
1027 throw new java.io.IOException
1028 ("Row " + v.size() + " is too short.");
1029 }
1030 int m = v.size(); // Now we've got the number of rows.
1031 double[][] A = new double[m][];
1032 v.copyInto(A); // copy the rows out of the vector
1033 return new Matrix(A);
1034 }
1035
1036
1037 /* ------------------------
1038 Private Methods
1039 * ------------------------ */
1040
1041 /** Check if size(A) == size(B) **/
1042
1043 private void checkMatrixDimensions(Matrix B) {
1044 if (B.m != m || B.n != n) {
1045 throw new IllegalArgumentException("Matrix dimensions must agree.");
1046 }
1047 }
1048
1049 }
1050