001    package aima.util;
002    
003    import java.io.BufferedReader;
004    import java.io.PrintWriter;
005    import java.io.StreamTokenizer;
006    import java.text.DecimalFormat;
007    import java.text.DecimalFormatSymbols;
008    import java.text.NumberFormat;
009    import java.util.List;
010    import java.util.Locale;
011    
012    /**
013     * Jama = Java Matrix class.
014     * <P>
015     * The Java Matrix Class provides the fundamental operations of numerical linear
016     * algebra. Various constructors create Matrices from two dimensional arrays of
017     * double precision floating point numbers. Various "gets" and "sets" provide
018     * access to submatrices and matrix elements. Several methods implement basic
019     * matrix arithmetic, including matrix addition and multiplication, matrix
020     * norms, and element-by-element array operations. Methods for reading and
021     * printing matrices are also included. All the operations in this version of
022     * the Matrix Class involve real matrices. Complex matrices may be handled in a
023     * future version.
024     * <P>
025     * Five fundamental matrix decompositions, which consist of pairs or triples of
026     * matrices, permutation vectors, and the like, produce results in five
027     * decomposition classes. These decompositions are accessed by the Matrix class
028     * to compute solutions of simultaneous linear equations, determinants, inverses
029     * and other matrix functions. The five decompositions are:
030     * <P>
031     * <UL>
032     * <LI>Cholesky Decomposition of symmetric, positive definite matrices.
033     * <LI>LU Decomposition of rectangular matrices.
034     * <LI>QR Decomposition of rectangular matrices.
035     * <LI>Singular Value Decomposition of rectangular matrices.
036     * <LI>Eigenvalue Decomposition of both symmetric and nonsymmetric square
037     * matrices.
038     * </UL>
039     * <DL>
040     * <DT><B>Example of use:</B></DT>
041     * <P>
042     * <DD>Solve a linear system A x = b and compute the residual norm, ||b - A
043     * x||.
044     * <P>
045     * 
046     * <PRE>
047     * double[][] vals = { { 1., 2., 3 }, { 4., 5., 6. }, { 7., 8., 10. } };
048     * Matrix A = new Matrix(vals);
049     * Matrix b = Matrix.random(3, 1);
050     * Matrix x = A.solve(b);
051     * Matrix r = A.times(x).minus(b);
052     * double rnorm = r.normInf();
053     * </PRE>
054     * 
055     * </DD>
056     * </DL>
057     * 
058     * @author The MathWorks, Inc. and the National Institute of Standards and
059     *         Technology.
060     * @version 5 August 1998
061     */
062    
063    public class Matrix implements Cloneable, java.io.Serializable {
064    
065            /*
066             * ------------------------ Class variables ------------------------
067             */
068    
069            /**
070             * Array for internal storage of elements.
071             * 
072             * @serial internal array storage.
073             */
074            private final double[][] A;
075    
076            /**
077             * Row and column dimensions.
078             * 
079             * @serial row dimension.
080             * @serial column dimension.
081             */
082            private final int m, n;
083    
084            /*
085             * ------------------------ Constructors ------------------------
086             */
087    
088            /** Construct a diagonal Matrix from the given List of doubles */
089            public static Matrix createDiagonalMatrix(List<Double> values) {
090                    Matrix m = new Matrix(values.size(), values.size(), 0);
091                    for (int i = 0; i < values.size(); i++) {
092                            m.set(i, i, values.get(i));
093                    }
094                    return m;
095            }
096    
097            /**
098             * Construct an m-by-n matrix of zeros.
099             * 
100             * @param m
101             *            Number of rows.
102             * @param n
103             *            Number of colums.
104             */
105    
106            public Matrix(int m, int n) {
107                    this.m = m;
108                    this.n = n;
109                    A = new double[m][n];
110            }
111    
112            /**
113             * Construct an m-by-n constant matrix.
114             * 
115             * @param m
116             *            Number of rows.
117             * @param n
118             *            Number of colums.
119             * @param s
120             *            Fill the matrix with this scalar value.
121             */
122    
123            public Matrix(int m, int n, double s) {
124                    this.m = m;
125                    this.n = n;
126                    A = new double[m][n];
127                    for (int i = 0; i < m; i++) {
128                            for (int j = 0; j < n; j++) {
129                                    A[i][j] = s;
130                            }
131                    }
132            }
133    
134            /**
135             * Construct a matrix from a 2-D array.
136             * 
137             * @param A
138             *            Two-dimensional array of doubles.
139             * @exception IllegalArgumentException
140             *                All rows must have the same length
141             * @see #constructWithCopy
142             */
143    
144            public Matrix(double[][] A) {
145                    m = A.length;
146                    n = A[0].length;
147                    for (int i = 0; i < m; i++) {
148                            if (A[i].length != n) {
149                                    throw new IllegalArgumentException(
150                                                    "All rows must have the same length.");
151                            }
152                    }
153                    this.A = A;
154            }
155    
156            /**
157             * Construct a matrix quickly without checking arguments.
158             * 
159             * @param A
160             *            Two-dimensional array of doubles.
161             * @param m
162             *            Number of rows.
163             * @param n
164             *            Number of colums.
165             */
166    
167            public Matrix(double[][] A, int m, int n) {
168                    this.A = A;
169                    this.m = m;
170                    this.n = n;
171            }
172    
173            /**
174             * Construct a matrix from a one-dimensional packed array
175             * 
176             * @param vals
177             *            One-dimensional array of doubles, packed by columns (ala
178             *            Fortran).
179             * @param m
180             *            Number of rows.
181             * @exception IllegalArgumentException
182             *                Array length must be a multiple of m.
183             */
184    
185            public Matrix(double vals[], int m) {
186                    this.m = m;
187                    n = (m != 0 ? vals.length / m : 0);
188                    if (m * n != vals.length) {
189                            throw new IllegalArgumentException(
190                                            "Array length must be a multiple of m.");
191                    }
192                    A = new double[m][n];
193                    for (int i = 0; i < m; i++) {
194                            for (int j = 0; j < n; j++) {
195                                    A[i][j] = vals[i + j * m];
196                            }
197                    }
198            }
199    
200            /*
201             * ------------------------ Public Methods ------------------------
202             */
203    
204            /**
205             * Construct a matrix from a copy of a 2-D array.
206             * 
207             * @param A
208             *            Two-dimensional array of doubles.
209             * @exception IllegalArgumentException
210             *                All rows must have the same length
211             */
212    
213            public static Matrix constructWithCopy(double[][] A) {
214                    int m = A.length;
215                    int n = A[0].length;
216                    Matrix X = new Matrix(m, n);
217                    double[][] C = X.getArray();
218                    for (int i = 0; i < m; i++) {
219                            if (A[i].length != n) {
220                                    throw new IllegalArgumentException(
221                                                    "All rows must have the same length.");
222                            }
223                            for (int j = 0; j < n; j++) {
224                                    C[i][j] = A[i][j];
225                            }
226                    }
227                    return X;
228            }
229    
230            /**
231             * Make a deep copy of a matrix
232             */
233    
234            public Matrix copy() {
235                    Matrix X = new Matrix(m, n);
236                    double[][] C = X.getArray();
237                    for (int i = 0; i < m; i++) {
238                            for (int j = 0; j < n; j++) {
239                                    C[i][j] = A[i][j];
240                            }
241                    }
242                    return X;
243            }
244    
245            /**
246             * Clone the Matrix object.
247             */
248    
249            @Override
250            public Object clone() {
251                    return this.copy();
252            }
253    
254            /**
255             * Access the internal two-dimensional array.
256             * 
257             * @return Pointer to the two-dimensional array of matrix elements.
258             */
259    
260            public double[][] getArray() {
261                    return A;
262            }
263    
264            /**
265             * Copy the internal two-dimensional array.
266             * 
267             * @return Two-dimensional array copy of matrix elements.
268             */
269    
270            public double[][] getArrayCopy() {
271                    double[][] C = new double[m][n];
272                    for (int i = 0; i < m; i++) {
273                            for (int j = 0; j < n; j++) {
274                                    C[i][j] = A[i][j];
275                            }
276                    }
277                    return C;
278            }
279    
280            /**
281             * Make a one-dimensional column packed copy of the internal array.
282             * 
283             * @return Matrix elements packed in a one-dimensional array by columns.
284             */
285    
286            public double[] getColumnPackedCopy() {
287                    double[] vals = new double[m * n];
288                    for (int i = 0; i < m; i++) {
289                            for (int j = 0; j < n; j++) {
290                                    vals[i + j * m] = A[i][j];
291                            }
292                    }
293                    return vals;
294            }
295    
296            /**
297             * Make a one-dimensional row packed copy of the internal array.
298             * 
299             * @return Matrix elements packed in a one-dimensional array by rows.
300             */
301    
302            public double[] getRowPackedCopy() {
303                    double[] vals = new double[m * n];
304                    for (int i = 0; i < m; i++) {
305                            for (int j = 0; j < n; j++) {
306                                    vals[i * n + j] = A[i][j];
307                            }
308                    }
309                    return vals;
310            }
311    
312            /**
313             * Get row dimension.
314             * 
315             * @return m, the number of rows.
316             */
317    
318            public int getRowDimension() {
319                    return m;
320            }
321    
322            /**
323             * Get column dimension.
324             * 
325             * @return n, the number of columns.
326             */
327    
328            public int getColumnDimension() {
329                    return n;
330            }
331    
332            /**
333             * Get a single element.
334             * 
335             * @param i
336             *            Row index.
337             * @param j
338             *            Column index.
339             * @return A(i,j)
340             * @exception ArrayIndexOutOfBoundsException
341             */
342    
343            public double get(int i, int j) {
344                    return A[i][j];
345            }
346    
347            /**
348             * Get a submatrix.
349             * 
350             * @param i0
351             *            Initial row index
352             * @param i1
353             *            Final row index
354             * @param j0
355             *            Initial column index
356             * @param j1
357             *            Final column index
358             * @return A(i0:i1,j0:j1)
359             * @exception ArrayIndexOutOfBoundsException
360             *                Submatrix indices
361             */
362    
363            public Matrix getMatrix(int i0, int i1, int j0, int j1) {
364                    Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
365                    double[][] B = X.getArray();
366                    try {
367                            for (int i = i0; i <= i1; i++) {
368                                    for (int j = j0; j <= j1; j++) {
369                                            B[i - i0][j - j0] = A[i][j];
370                                    }
371                            }
372                    } catch (ArrayIndexOutOfBoundsException e) {
373                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
374                    }
375                    return X;
376            }
377    
378            /**
379             * Get a submatrix.
380             * 
381             * @param r
382             *            Array of row indices.
383             * @param c
384             *            Array of column indices.
385             * @return A(r(:),c(:))
386             * @exception ArrayIndexOutOfBoundsException
387             *                Submatrix indices
388             */
389    
390            public Matrix getMatrix(int[] r, int[] c) {
391                    Matrix X = new Matrix(r.length, c.length);
392                    double[][] B = X.getArray();
393                    try {
394                            for (int i = 0; i < r.length; i++) {
395                                    for (int j = 0; j < c.length; j++) {
396                                            B[i][j] = A[r[i]][c[j]];
397                                    }
398                            }
399                    } catch (ArrayIndexOutOfBoundsException e) {
400                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
401                    }
402                    return X;
403            }
404    
405            /**
406             * Get a submatrix.
407             * 
408             * @param i0
409             *            Initial row index
410             * @param i1
411             *            Final row index
412             * @param c
413             *            Array of column indices.
414             * @return A(i0:i1,c(:))
415             * @exception ArrayIndexOutOfBoundsException
416             *                Submatrix indices
417             */
418    
419            public Matrix getMatrix(int i0, int i1, int[] c) {
420                    Matrix X = new Matrix(i1 - i0 + 1, c.length);
421                    double[][] B = X.getArray();
422                    try {
423                            for (int i = i0; i <= i1; i++) {
424                                    for (int j = 0; j < c.length; j++) {
425                                            B[i - i0][j] = A[i][c[j]];
426                                    }
427                            }
428                    } catch (ArrayIndexOutOfBoundsException e) {
429                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
430                    }
431                    return X;
432            }
433    
434            /**
435             * Get a submatrix.
436             * 
437             * @param r
438             *            Array of row indices.
439             * @param j0
440             *            Initial column index
441             * @param j1
442             *            Final column index
443             * @return A(r(:),j0:j1)
444             * @exception ArrayIndexOutOfBoundsException
445             *                Submatrix indices
446             */
447    
448            public Matrix getMatrix(int[] r, int j0, int j1) {
449                    Matrix X = new Matrix(r.length, j1 - j0 + 1);
450                    double[][] B = X.getArray();
451                    try {
452                            for (int i = 0; i < r.length; i++) {
453                                    for (int j = j0; j <= j1; j++) {
454                                            B[i][j - j0] = A[r[i]][j];
455                                    }
456                            }
457                    } catch (ArrayIndexOutOfBoundsException e) {
458                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
459                    }
460                    return X;
461            }
462    
463            /**
464             * Set a single element.
465             * 
466             * @param i
467             *            Row index.
468             * @param j
469             *            Column index.
470             * @param s
471             *            A(i,j).
472             * @exception ArrayIndexOutOfBoundsException
473             */
474    
475            public void set(int i, int j, double s) {
476                    A[i][j] = s;
477            }
478    
479            /**
480             * Set a submatrix.
481             * 
482             * @param i0
483             *            Initial row index
484             * @param i1
485             *            Final row index
486             * @param j0
487             *            Initial column index
488             * @param j1
489             *            Final column index
490             * @param X
491             *            A(i0:i1,j0:j1)
492             * @exception ArrayIndexOutOfBoundsException
493             *                Submatrix indices
494             */
495    
496            public void setMatrix(int i0, int i1, int j0, int j1, Matrix X) {
497                    try {
498                            for (int i = i0; i <= i1; i++) {
499                                    for (int j = j0; j <= j1; j++) {
500                                            A[i][j] = X.get(i - i0, j - j0);
501                                    }
502                            }
503                    } catch (ArrayIndexOutOfBoundsException e) {
504                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
505                    }
506            }
507    
508            /**
509             * Set a submatrix.
510             * 
511             * @param r
512             *            Array of row indices.
513             * @param c
514             *            Array of column indices.
515             * @param X
516             *            A(r(:),c(:))
517             * @exception ArrayIndexOutOfBoundsException
518             *                Submatrix indices
519             */
520    
521            public void setMatrix(int[] r, int[] c, Matrix X) {
522                    try {
523                            for (int i = 0; i < r.length; i++) {
524                                    for (int j = 0; j < c.length; j++) {
525                                            A[r[i]][c[j]] = X.get(i, j);
526                                    }
527                            }
528                    } catch (ArrayIndexOutOfBoundsException e) {
529                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
530                    }
531            }
532    
533            /**
534             * Set a submatrix.
535             * 
536             * @param r
537             *            Array of row indices.
538             * @param j0
539             *            Initial column index
540             * @param j1
541             *            Final column index
542             * @param X
543             *            A(r(:),j0:j1)
544             * @exception ArrayIndexOutOfBoundsException
545             *                Submatrix indices
546             */
547    
548            public void setMatrix(int[] r, int j0, int j1, Matrix X) {
549                    try {
550                            for (int i = 0; i < r.length; i++) {
551                                    for (int j = j0; j <= j1; j++) {
552                                            A[r[i]][j] = X.get(i, j - j0);
553                                    }
554                            }
555                    } catch (ArrayIndexOutOfBoundsException e) {
556                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
557                    }
558            }
559    
560            /**
561             * Set a submatrix.
562             * 
563             * @param i0
564             *            Initial row index
565             * @param i1
566             *            Final row index
567             * @param c
568             *            Array of column indices.
569             * @param X
570             *            A(i0:i1,c(:))
571             * @exception ArrayIndexOutOfBoundsException
572             *                Submatrix indices
573             */
574    
575            public void setMatrix(int i0, int i1, int[] c, Matrix X) {
576                    try {
577                            for (int i = i0; i <= i1; i++) {
578                                    for (int j = 0; j < c.length; j++) {
579                                            A[i][c[j]] = X.get(i - i0, j);
580                                    }
581                            }
582                    } catch (ArrayIndexOutOfBoundsException e) {
583                            throw new ArrayIndexOutOfBoundsException("Submatrix indices");
584                    }
585            }
586    
587            /**
588             * Matrix transpose.
589             * 
590             * @return A'
591             */
592    
593            public Matrix transpose() {
594                    Matrix X = new Matrix(n, m);
595                    double[][] C = X.getArray();
596                    for (int i = 0; i < m; i++) {
597                            for (int j = 0; j < n; j++) {
598                                    C[j][i] = A[i][j];
599                            }
600                    }
601                    return X;
602            }
603    
604            /**
605             * One norm
606             * 
607             * @return maximum column sum.
608             */
609    
610            public double norm1() {
611                    double f = 0;
612                    for (int j = 0; j < n; j++) {
613                            double s = 0;
614                            for (int i = 0; i < m; i++) {
615                                    s += Math.abs(A[i][j]);
616                            }
617                            f = Math.max(f, s);
618                    }
619                    return f;
620            }
621    
622            /**
623             * Two norm
624             * 
625             * @return maximum singular value.
626             */
627    
628            // public double norm2 () {
629            // return (new SingularValueDecomposition(this).norm2());
630            // }
631            /**
632             * Infinity norm
633             * 
634             * @return maximum row sum.
635             */
636    
637            public double normInf() {
638                    double f = 0;
639                    for (int i = 0; i < m; i++) {
640                            double s = 0;
641                            for (int j = 0; j < n; j++) {
642                                    s += Math.abs(A[i][j]);
643                            }
644                            f = Math.max(f, s);
645                    }
646                    return f;
647            }
648    
649            /**
650             * Frobenius norm
651             * 
652             * @return sqrt of sum of squares of all elements.
653             */
654    
655            // public double normF () {
656            // double f = 0;
657            // for (int i = 0; i < m; i++) {
658            // for (int j = 0; j < n; j++) {
659            // f = Maths.hypot(f,A[i][j]);
660            // }
661            // }
662            // return f;
663            // }
664            /**
665             * Unary minus
666             * 
667             * @return -A
668             */
669    
670            public Matrix uminus() {
671                    Matrix X = new Matrix(m, n);
672                    double[][] C = X.getArray();
673                    for (int i = 0; i < m; i++) {
674                            for (int j = 0; j < n; j++) {
675                                    C[i][j] = -A[i][j];
676                            }
677                    }
678                    return X;
679            }
680    
681            /**
682             * C = A + B
683             * 
684             * @param B
685             *            another matrix
686             * @return A + B
687             */
688    
689            public Matrix plus(Matrix B) {
690                    checkMatrixDimensions(B);
691                    Matrix X = new Matrix(m, n);
692                    double[][] C = X.getArray();
693                    for (int i = 0; i < m; i++) {
694                            for (int j = 0; j < n; j++) {
695                                    C[i][j] = A[i][j] + B.A[i][j];
696                            }
697                    }
698                    return X;
699            }
700    
701            /**
702             * A = A + B
703             * 
704             * @param B
705             *            another matrix
706             * @return A + B
707             */
708    
709            public Matrix plusEquals(Matrix B) {
710                    checkMatrixDimensions(B);
711                    for (int i = 0; i < m; i++) {
712                            for (int j = 0; j < n; j++) {
713                                    A[i][j] = A[i][j] + B.A[i][j];
714                            }
715                    }
716                    return this;
717            }
718    
719            /**
720             * C = A - B
721             * 
722             * @param B
723             *            another matrix
724             * @return A - B
725             */
726    
727            public Matrix minus(Matrix B) {
728                    checkMatrixDimensions(B);
729                    Matrix X = new Matrix(m, n);
730                    double[][] C = X.getArray();
731                    for (int i = 0; i < m; i++) {
732                            for (int j = 0; j < n; j++) {
733                                    C[i][j] = A[i][j] - B.A[i][j];
734                            }
735                    }
736                    return X;
737            }
738    
739            /**
740             * A = A - B
741             * 
742             * @param B
743             *            another matrix
744             * @return A - B
745             */
746    
747            public Matrix minusEquals(Matrix B) {
748                    checkMatrixDimensions(B);
749                    for (int i = 0; i < m; i++) {
750                            for (int j = 0; j < n; j++) {
751                                    A[i][j] = A[i][j] - B.A[i][j];
752                            }
753                    }
754                    return this;
755            }
756    
757            /**
758             * Element-by-element multiplication, C = A.*B
759             * 
760             * @param B
761             *            another matrix
762             * @return A.*B
763             */
764    
765            public Matrix arrayTimes(Matrix B) {
766                    checkMatrixDimensions(B);
767                    Matrix X = new Matrix(m, n);
768                    double[][] C = X.getArray();
769                    for (int i = 0; i < m; i++) {
770                            for (int j = 0; j < n; j++) {
771                                    C[i][j] = A[i][j] * B.A[i][j];
772                            }
773                    }
774                    return X;
775            }
776    
777            /**
778             * Element-by-element multiplication in place, A = A.*B
779             * 
780             * @param B
781             *            another matrix
782             * @return A.*B
783             */
784    
785            public Matrix arrayTimesEquals(Matrix B) {
786                    checkMatrixDimensions(B);
787                    for (int i = 0; i < m; i++) {
788                            for (int j = 0; j < n; j++) {
789                                    A[i][j] = A[i][j] * B.A[i][j];
790                            }
791                    }
792                    return this;
793            }
794    
795            /**
796             * Element-by-element right division, C = A./B
797             * 
798             * @param B
799             *            another matrix
800             * @return A./B
801             */
802    
803            public Matrix arrayRightDivide(Matrix B) {
804                    checkMatrixDimensions(B);
805                    Matrix X = new Matrix(m, n);
806                    double[][] C = X.getArray();
807                    for (int i = 0; i < m; i++) {
808                            for (int j = 0; j < n; j++) {
809                                    C[i][j] = A[i][j] / B.A[i][j];
810                            }
811                    }
812                    return X;
813            }
814    
815            /**
816             * Element-by-element right division in place, A = A./B
817             * 
818             * @param B
819             *            another matrix
820             * @return A./B
821             */
822    
823            public Matrix arrayRightDivideEquals(Matrix B) {
824                    checkMatrixDimensions(B);
825                    for (int i = 0; i < m; i++) {
826                            for (int j = 0; j < n; j++) {
827                                    A[i][j] = A[i][j] / B.A[i][j];
828                            }
829                    }
830                    return this;
831            }
832    
833            /**
834             * Element-by-element left division, C = A.\B
835             * 
836             * @param B
837             *            another matrix
838             * @return A.\B
839             */
840    
841            public Matrix arrayLeftDivide(Matrix B) {
842                    checkMatrixDimensions(B);
843                    Matrix X = new Matrix(m, n);
844                    double[][] C = X.getArray();
845                    for (int i = 0; i < m; i++) {
846                            for (int j = 0; j < n; j++) {
847                                    C[i][j] = B.A[i][j] / A[i][j];
848                            }
849                    }
850                    return X;
851            }
852    
853            /**
854             * Element-by-element left division in place, A = A.\B
855             * 
856             * @param B
857             *            another matrix
858             * @return A.\B
859             */
860    
861            public Matrix arrayLeftDivideEquals(Matrix B) {
862                    checkMatrixDimensions(B);
863                    for (int i = 0; i < m; i++) {
864                            for (int j = 0; j < n; j++) {
865                                    A[i][j] = B.A[i][j] / A[i][j];
866                            }
867                    }
868                    return this;
869            }
870    
871            /**
872             * Multiply a matrix by a scalar, C = s*A
873             * 
874             * @param s
875             *            scalar
876             * @return s*A
877             */
878    
879            public Matrix times(double s) {
880                    Matrix X = new Matrix(m, n);
881                    double[][] C = X.getArray();
882                    for (int i = 0; i < m; i++) {
883                            for (int j = 0; j < n; j++) {
884                                    C[i][j] = s * A[i][j];
885                            }
886                    }
887                    return X;
888            }
889    
890            /**
891             * Multiply a matrix by a scalar in place, A = s*A
892             * 
893             * @param s
894             *            scalar
895             * @return replace A by s*A
896             */
897    
898            public Matrix timesEquals(double s) {
899                    for (int i = 0; i < m; i++) {
900                            for (int j = 0; j < n; j++) {
901                                    A[i][j] = s * A[i][j];
902                            }
903                    }
904                    return this;
905            }
906    
907            /**
908             * Linear algebraic matrix multiplication, A * B
909             * 
910             * @param B
911             *            another matrix
912             * @return Matrix product, A * B
913             * @exception IllegalArgumentException
914             *                Matrix inner dimensions must agree.
915             */
916    
917            public Matrix times(Matrix B) {
918                    if (B.m != n) {
919                            throw new IllegalArgumentException(
920                                            "Matrix inner dimensions must agree.");
921                    }
922                    Matrix X = new Matrix(m, B.n);
923                    double[][] C = X.getArray();
924                    double[] Bcolj = new double[n];
925                    for (int j = 0; j < B.n; j++) {
926                            for (int k = 0; k < n; k++) {
927                                    Bcolj[k] = B.A[k][j];
928                            }
929                            for (int i = 0; i < m; i++) {
930                                    double[] Arowi = A[i];
931                                    double s = 0;
932                                    for (int k = 0; k < n; k++) {
933                                            s += Arowi[k] * Bcolj[k];
934                                    }
935                                    C[i][j] = s;
936                            }
937                    }
938                    return X;
939            }
940    
941            /**
942             * LU Decomposition
943             * 
944             * @return LUDecomposition
945             * @see LUDecomposition
946             */
947    
948            public LUDecomposition lu() {
949                    return new LUDecomposition(this);
950            }
951    
952            // /** QR Decomposition
953            // @return QRDecomposition
954            // @see QRDecomposition
955            // */
956            //
957            // public QRDecomposition qr () {
958            // return new QRDecomposition(this);
959            // }
960            //
961            // /** Cholesky Decomposition
962            // @return CholeskyDecomposition
963            // @see CholeskyDecomposition
964            // */
965            //
966            // public CholeskyDecomposition chol () {
967            // return new CholeskyDecomposition(this);
968            // }
969            //
970            // /** Singular Value Decomposition
971            // @return SingularValueDecomposition
972            // @see SingularValueDecomposition
973            // */
974            //
975            // public SingularValueDecomposition svd () {
976            // return new SingularValueDecomposition(this);
977            // }
978            //
979            // /** Eigenvalue Decomposition
980            // @return EigenvalueDecomposition
981            // @see EigenvalueDecomposition
982            // */
983            //
984            // public EigenvalueDecomposition eig () {
985            // return new EigenvalueDecomposition(this);
986            // }
987    
988            /**
989             * Solve A*X = B
990             * 
991             * @param B
992             *            right hand side
993             * @return solution if A is square, least squares solution otherwise
994             */
995    
996            public Matrix solve(Matrix B) {
997                    // assumed m == n
998                    return new LUDecomposition(this).solve(B);
999    
1000            }
1001    
1002            /**
1003             * Solve X*A = B, which is also A'*X' = B'
1004             * 
1005             * @param B
1006             *            right hand side
1007             * @return solution if A is square, least squares solution otherwise.
1008             */
1009    
1010            public Matrix solveTranspose(Matrix B) {
1011                    return transpose().solve(B.transpose());
1012            }
1013    
1014            /**
1015             * Matrix inverse or pseudoinverse
1016             * 
1017             * @return inverse(A) if A is square, pseudoinverse otherwise.
1018             */
1019    
1020            public Matrix inverse() {
1021                    return solve(identity(m, m));
1022            }
1023    
1024            /**
1025             * Matrix determinant
1026             * 
1027             * @return determinant
1028             */
1029    
1030            public double det() {
1031                    return new LUDecomposition(this).det();
1032            }
1033    
1034            /**
1035             * Matrix rank
1036             * 
1037             * @return effective numerical rank, obtained from SVD.
1038             */
1039    
1040            // public int rank () {
1041            // return new SingularValueDecomposition(this).rank();
1042            // }
1043            //
1044            // /** Matrix condition (2 norm)
1045            // @return ratio of largest to smallest singular value.
1046            // */
1047            //
1048            // public double cond () {
1049            // return new SingularValueDecomposition(this).cond();
1050            // }
1051            /**
1052             * Matrix trace.
1053             * 
1054             * @return sum of the diagonal elements.
1055             */
1056    
1057            public double trace() {
1058                    double t = 0;
1059                    for (int i = 0; i < Math.min(m, n); i++) {
1060                            t += A[i][i];
1061                    }
1062                    return t;
1063            }
1064    
1065            /**
1066             * Generate matrix with random elements
1067             * 
1068             * @param m
1069             *            Number of rows.
1070             * @param n
1071             *            Number of colums.
1072             * @return An m-by-n matrix with uniformly distributed random elements.
1073             */
1074    
1075            public static Matrix random(int m, int n) {
1076                    Matrix A = new Matrix(m, n);
1077                    double[][] X = A.getArray();
1078                    for (int i = 0; i < m; i++) {
1079                            for (int j = 0; j < n; j++) {
1080                                    X[i][j] = Math.random();
1081                            }
1082                    }
1083                    return A;
1084            }
1085    
1086            /**
1087             * Generate identity matrix
1088             * 
1089             * @param m
1090             *            Number of rows.
1091             * @param n
1092             *            Number of colums.
1093             * @return An m-by-n matrix with ones on the diagonal and zeros elsewhere.
1094             */
1095    
1096            public static Matrix identity(int m, int n) {
1097                    Matrix A = new Matrix(m, n);
1098                    double[][] X = A.getArray();
1099                    for (int i = 0; i < m; i++) {
1100                            for (int j = 0; j < n; j++) {
1101                                    X[i][j] = (i == j ? 1.0 : 0.0);
1102                            }
1103                    }
1104                    return A;
1105            }
1106    
1107            /**
1108             * Print the matrix to stdout. Line the elements up in columns with a
1109             * Fortran-like 'Fw.d' style format.
1110             * 
1111             * @param w
1112             *            Column width.
1113             * @param d
1114             *            Number of digits after the decimal.
1115             */
1116    
1117            public void print(int w, int d) {
1118                    print(new PrintWriter(System.out, true), w, d);
1119            }
1120    
1121            /**
1122             * Print the matrix to the output stream. Line the elements up in columns
1123             * with a Fortran-like 'Fw.d' style format.
1124             * 
1125             * @param output
1126             *            Output stream.
1127             * @param w
1128             *            Column width.
1129             * @param d
1130             *            Number of digits after the decimal.
1131             */
1132    
1133            public void print(PrintWriter output, int w, int d) {
1134                    DecimalFormat format = new DecimalFormat();
1135                    format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
1136                    format.setMinimumIntegerDigits(1);
1137                    format.setMaximumFractionDigits(d);
1138                    format.setMinimumFractionDigits(d);
1139                    format.setGroupingUsed(false);
1140                    print(output, format, w + 2);
1141            }
1142    
1143            /**
1144             * Print the matrix to stdout. Line the elements up in columns. Use the
1145             * format object, and right justify within columns of width characters. Note
1146             * that is the matrix is to be read back in, you probably will want to use a
1147             * NumberFormat that is set to US Locale.
1148             * 
1149             * @param format
1150             *            A Formatting object for individual elements.
1151             * @param width
1152             *            Field width for each column.
1153             * @see java.text.DecimalFormat#setDecimalFormatSymbols
1154             */
1155    
1156            public void print(NumberFormat format, int width) {
1157                    print(new PrintWriter(System.out, true), format, width);
1158            }
1159    
1160            // DecimalFormat is a little disappointing coming from Fortran or C's
1161            // printf.
1162            // Since it doesn't pad on the left, the elements will come out different
1163            // widths. Consequently, we'll pass the desired column width in as an
1164            // argument and do the extra padding ourselves.
1165    
1166            /**
1167             * Print the matrix to the output stream. Line the elements up in columns.
1168             * Use the format object, and right justify within columns of width
1169             * characters. Note that is the matrix is to be read back in, you probably
1170             * will want to use a NumberFormat that is set to US Locale.
1171             * 
1172             * @param output
1173             *            the output stream.
1174             * @param format
1175             *            A formatting object to format the matrix elements
1176             * @param width
1177             *            Column width.
1178             * @see java.text.DecimalFormat#setDecimalFormatSymbols
1179             */
1180    
1181            public void print(PrintWriter output, NumberFormat format, int width) {
1182                    output.println(); // start on new line.
1183                    for (int i = 0; i < m; i++) {
1184                            for (int j = 0; j < n; j++) {
1185                                    String s = format.format(A[i][j]); // format the number
1186                                    int padding = Math.max(1, width - s.length()); // At _least_ 1
1187                                    // space
1188                                    for (int k = 0; k < padding; k++)
1189                                            output.print(' ');
1190                                    output.print(s);
1191                            }
1192                            output.println();
1193                    }
1194                    output.println(); // end with blank line.
1195            }
1196    
1197            /**
1198             * Read a matrix from a stream. The format is the same the print method, so
1199             * printed matrices can be read back in (provided they were printed using US
1200             * Locale). Elements are separated by whitespace, all the elements for each
1201             * row appear on a single line, the last row is followed by a blank line.
1202             * 
1203             * @param input
1204             *            the input stream.
1205             */
1206    
1207            public static Matrix read(BufferedReader input) throws java.io.IOException {
1208                    StreamTokenizer tokenizer = new StreamTokenizer(input);
1209    
1210                    // Although StreamTokenizer will parse numbers, it doesn't recognize
1211                    // scientific notation (E or D); however, Double.valueOf does.
1212                    // The strategy here is to disable StreamTokenizer's number parsing.
1213                    // We'll only get whitespace delimited words, EOL's and EOF's.
1214                    // These words should all be numbers, for Double.valueOf to parse.
1215    
1216                    tokenizer.resetSyntax();
1217                    tokenizer.wordChars(0, 255);
1218                    tokenizer.whitespaceChars(0, ' ');
1219                    tokenizer.eolIsSignificant(true);
1220                    java.util.Vector v = new java.util.Vector();
1221    
1222                    // Ignore initial empty lines
1223                    while (tokenizer.nextToken() == StreamTokenizer.TT_EOL)
1224                            ;
1225                    if (tokenizer.ttype == StreamTokenizer.TT_EOF)
1226                            throw new java.io.IOException("Unexpected EOF on matrix read.");
1227                    do {
1228                            v.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st
1229                            // row.
1230                    } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
1231    
1232                    int n = v.size(); // Now we've got the number of columns!
1233                    double row[] = new double[n];
1234                    for (int j = 0; j < n; j++)
1235                            // extract the elements of the 1st row.
1236                            row[j] = ((Double) v.elementAt(j)).doubleValue();
1237                    v.removeAllElements();
1238                    v.addElement(row); // Start storing rows instead of columns.
1239                    while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
1240                            // While non-empty lines
1241                            v.addElement(row = new double[n]);
1242                            int j = 0;
1243                            do {
1244                                    if (j >= n)
1245                                            throw new java.io.IOException("Row " + v.size()
1246                                                            + " is too long.");
1247                                    row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
1248                            } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
1249                            if (j < n)
1250                                    throw new java.io.IOException("Row " + v.size()
1251                                                    + " is too short.");
1252                    }
1253                    int m = v.size(); // Now we've got the number of rows.
1254                    double[][] A = new double[m][];
1255                    v.copyInto(A); // copy the rows out of the vector
1256                    return new Matrix(A);
1257            }
1258    
1259            @Override
1260            public String toString() {
1261                    StringBuffer buf = new StringBuffer();
1262                    for (int i = 0; i < getRowDimension(); i++) {
1263    
1264                            for (int j = 0; j < getColumnDimension(); j++) {
1265                                    buf.append(get(i, j));
1266                                    buf.append(" ");
1267                            }
1268                            buf.append("\n");
1269                    }
1270    
1271                    return buf.toString();
1272            }
1273    
1274            /*
1275             * ------------------------ Private Methods ------------------------
1276             */
1277    
1278            /** Check if size(A) == size(B) * */
1279    
1280            private void checkMatrixDimensions(Matrix B) {
1281                    if (B.m != m || B.n != n) {
1282                            throw new IllegalArgumentException("Matrix dimensions must agree.");
1283                    }
1284            }
1285    
1286    }