Java examples for java.lang:Math Matrix
Compute matrix inversion of a symmetric, positive definite matrix by using the Cholesky Decomposition L of the matrix A.
/*/*from ww w .j a v a2 s. c o m*/ * Java Information Dynamics Toolkit (JIDT) * Copyright (C) 2012, Joseph T. Lizier * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import java.io.PrintStream; import java.util.Arrays; import java.util.Comparator; import java.util.Vector; public class Main{ /** * Compute matrix inversion of a symmetric, positive definite matrix * by using the Cholesky Decomposition L of the matrix A. * Since A = L L^T, then A^-1 = (L^T)^-1 L^-1, and the inverses * of * * @param A matrix to be inverted * @return the inverse of A * @throws Exception when the matrix is not symmetric or positive definite * @see #CholeskyDecomposition(double[][]) */ public static double[][] invertSymmPosDefMatrix(double[][] A) throws Exception { // First do the Cholesky Decomposition: double[][] L = CholeskyDecomposition(A); return solveViaCholeskyResult(L, identityMatrix(A.length)); } /** * <p>Make the Cholesky decomposition L of a given input matrix A, * where: * <ol> * <li>A is symmetric and positive definite (has full rank)</li> * <li>A = L L^T (L^T is the transpose of L - here A has real * entries only, though a Cholesky decomposition is possible * with complex entries)</li> * <li>L is a lower triangular matrix</li> * </ol> * We perform the decomposition using the Cholesky?Banachiewicz * algorithm, computing L from the top left, row by row (see wikipedia) * </p> * * <p>This method has been adapted from the JAMA project (public domain software) * </p> * * @param A input matrix * @return L * @throws Exception when the matrix A is not square, is asymmetric, or * not positive definite * @see {@link en.wikipedia.org/wiki/Cholesky_decomposition} * @see {@link http://mathworld.wolfram.com/CholeskyDecomposition.html} * @see {@link http://en.wikipedia.org/wiki/Positive-definite_matrix} * @see {@link http://math.nist.gov/javanumerics/jama/} * @see {@link http://www2.gsu.edu/~mkteer/npdmatri.html} */ public static double[][] CholeskyDecomposition(double[][] A) throws Exception { int n = A.length; double[][] L = new double[n][n]; // Loop over all rows: for (int j = 0; j < n; j++) { // Check length of row keeps this a square matrix: if (A[j].length != n) { throw new Exception( "CholeskyDecomposition is only performed on square matrices"); } double d = 0.0; for (int k = 0; k < j; k++) { double s = 0.0; for (int i = 0; i < k; i++) { s += L[k][i] * L[j][i]; } L[j][k] = s = (A[j][k] - s) / L[k][k]; d = d + s * s; // Check that these matrix entries remain symmetric: if (A[k][j] != A[j][k]) { throw new Exception( "CholeskyDecomposition is only performed on symmetric matrices"); } } d = A[j][j] - d; // Check the positive definite condition: if (d <= 0.0) { // Throw an error with some suggestions. The last suggestion is from my observations // from a simple test with Matlab - I should find a reference for this ... throw new NonPositiveDefiniteMatrixException( "CholeskyDecomposition is only performed on positive-definite matrices. " + "Some reasons for non-positive-definite matrix are listed at http://www2.gsu.edu/~mkteer/npdmatri.html - " + "note: a correlation matrix is non-positive-definite if you have more variables than observations"); } L[j][j] = Math.sqrt(d); // Set the upper triangular part to all zeros: for (int k = j + 1; k < n; k++) { L[j][k] = 0.0; } } return L; } /** * <p>Solve A*X = B, where A = L*L^T via Cholesky decomposition. * </p> * * <p>This method has been adapted from the JAMA project (public domain software) * </p> * * @param L Cholesky decomposition of the matrix A * @param B matrix with as many rows as A and any number of columns * @return X so that A*X = B * @see {@link http://math.nist.gov/javanumerics/jama/} * @see #CholeskyDecomposition(double[][]) */ public static double[][] solveViaCholeskyResult(double[][] L, double[][] B) { int aRows = L.length; if (aRows != B.length) { throw new IllegalArgumentException( "Matrix row dimensions must agree."); } // Copy B matrix double[][] X = MatrixUtils.arrayCopy(B); int bCols = B[0].length; // Solve L*Y = B; for (int k = 0; k < aRows; k++) { for (int j = 0; j < bCols; j++) { for (int i = 0; i < k; i++) { X[k][j] -= X[i][j] * L[k][i]; } X[k][j] /= L[k][k]; } } // Solve L'*X = Y; for (int k = aRows - 1; k >= 0; k--) { for (int j = 0; j < bCols; j++) { for (int i = k + 1; i < aRows; i++) { X[k][j] -= X[i][j] * L[i][k]; } X[k][j] /= L[k][k]; } } return X; } /** * Generate the identity matrix of the given size * * @param size (size along one dimension) * @return two dimensional double array representing the identity matrix */ public static double[][] identityMatrix(int size) { double[][] I = new double[size][size]; for (int r = 0; r < size; r++) { I[r][r] = 1.0; } return I; } /** * Copies all rows and columns between two double arrays * * @param src * @param dest */ public static void arrayCopy(double[][] src, double[][] dest) { for (int r = 0; r < src.length; r++) { System.arraycopy(src[r], 0, dest[r], 0, src[r].length); } } /** * Copies all rows and columns between two double arrays * * @param src * @param dest */ public static double[][] arrayCopy(double[][] src) { double[][] dest = new double[src.length][]; for (int r = 0; r < src.length; r++) { dest[r] = new double[src[r].length]; System.arraycopy(src[r], 0, dest[r], 0, src[r].length); } return dest; } /** * Copies the required rows and columns between two * double arrays * * @param src * @param srcStartRow * @param srcStartCol * @param dest * @param destStartRow * @param destStartCol * @param rows * @param cols */ public static void arrayCopy(double[][] src, int srcStartRow, int srcStartCol, double[][] dest, int destStartRow, int destStartCol, int rows, int cols) { for (int r = 0; r < rows; r++) { System.arraycopy(src[srcStartRow + r], srcStartCol, dest[destStartRow + r], destStartCol, cols); } } /** * Copies all rows and columns between two int arrays * * @param src * @param dest */ public static void arrayCopy(int[][] src, int[][] dest) { for (int r = 0; r < src.length; r++) { System.arraycopy(src[r], 0, dest[r], 0, src[r].length); } } /** * Copies the required rows and columns between two * double arrays * * @param src * @param srcStartRow * @param srcStartCol * @param dest * @param destStartRow * @param destStartCol * @param rows * @param cols */ public static void arrayCopy(int[][] src, int srcStartRow, int srcStartCol, int[][] dest, int destStartRow, int destStartCol, int rows, int cols) { for (int r = 0; r < rows; r++) { System.arraycopy(src[srcStartRow + r], srcStartCol, dest[destStartRow + r], destStartCol, cols); } } }