diff options
Diffstat (limited to 'src/de/lmu/ifi/dbs/elki/math/linearalgebra/LUDecomposition.java')
-rw-r--r-- | src/de/lmu/ifi/dbs/elki/math/linearalgebra/LUDecomposition.java | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/src/de/lmu/ifi/dbs/elki/math/linearalgebra/LUDecomposition.java b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/LUDecomposition.java new file mode 100644 index 00000000..07faa89d --- /dev/null +++ b/src/de/lmu/ifi/dbs/elki/math/linearalgebra/LUDecomposition.java @@ -0,0 +1,295 @@ +package de.lmu.ifi.dbs.elki.math.linearalgebra; +/* +This file is part of ELKI: +Environment for Developing KDD-Applications Supported by Index-Structures + +Copyright (C) 2011 +Ludwig-Maximilians-Universität München +Lehr- und Forschungseinheit für Datenbanksysteme +ELKI Development Team + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero 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 Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/** + * LU Decomposition. + * <P> + * For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n unit + * lower triangular matrix L, an n-by-n upper triangular matrix U, and a + * permutation vector piv of length m so that A(piv,:) = L*U. If m < n, then + * L is m-by-m and U is m-by-n. + * <P> + * The LU decompostion with pivoting always exists, even if the matrix is + * singular, so the constructor will never fail. The primary use of the LU + * decomposition is in the solution of square systems of simultaneous linear + * equations. This will fail if isNonsingular() returns false. + * + * @apiviz.uses Matrix - - transforms + */ +public class LUDecomposition implements java.io.Serializable { + /** + * Serial version + */ + private static final long serialVersionUID = 1L; + + /** + * Array for internal storage of decomposition. + * + * @serial internal array storage. + */ + private double[][] LU; + + /** + * Row and column dimensions, and pivot sign. + * + * @serial column dimension. + * @serial row dimension. + * @serial pivot sign. + */ + private int m, n, pivsign; + + /** + * Internal storage of pivot vector. + * + * @serial pivot vector. + */ + private int[] piv; + + /* + * ------------------------ Constructor ------------------------ + */ + + /** + * LU Decomposition + * + * @param A Rectangular matrix + */ + public LUDecomposition(Matrix A) { + // Use a "left-looking", dot-product, Crout/Doolittle algorithm. + + LU = A.getArrayCopy(); + m = A.getRowDimensionality(); + n = A.getColumnDimensionality(); + piv = new int[m]; + for(int i = 0; i < m; i++) { + piv[i] = i; + } + pivsign = 1; + double[] LUrowi; + double[] LUcolj = new double[m]; + + // Outer loop. + + for(int j = 0; j < n; j++) { + // Make a copy of the j-th column to localize references. + + for(int i = 0; i < m; i++) { + LUcolj[i] = LU[i][j]; + } + + // Apply previous transformations. + + for(int i = 0; i < m; i++) { + LUrowi = LU[i]; + + // Most of the time is spent in the following dot product. + + int kmax = Math.min(i, j); + double s = 0.0; + for(int k = 0; k < kmax; k++) { + s += LUrowi[k] * LUcolj[k]; + } + + LUrowi[j] = LUcolj[i] -= s; + } + + // Find pivot and exchange if necessary. + + int p = j; + for(int i = j + 1; i < m; i++) { + if(Math.abs(LUcolj[i]) > Math.abs(LUcolj[p])) { + p = i; + } + } + if(p != j) { + for(int k = 0; k < n; k++) { + double t = LU[p][k]; + LU[p][k] = LU[j][k]; + LU[j][k] = t; + } + int k = piv[p]; + piv[p] = piv[j]; + piv[j] = k; + pivsign = -pivsign; + } + + // Compute multipliers. + + if(j < m & LU[j][j] != 0.0) { + for(int i = j + 1; i < m; i++) { + LU[i][j] /= LU[j][j]; + } + } + } + } + + /* + * ------------------------ Public Methods ------------------------ + */ + + /** + * Is the matrix nonsingular? + * + * @return true if U, and hence A, is nonsingular. + */ + public boolean isNonsingular() { + for(int j = 0; j < n; j++) { + if(LU[j][j] == 0) { + return false; + } + } + return true; + } + + /** + * Return lower triangular factor + * + * @return L + */ + public Matrix getL() { + Matrix X = new Matrix(m, n); + double[][] L = X.getArrayRef(); + for(int i = 0; i < m; i++) { + for(int j = 0; j < n; j++) { + if(i > j) { + L[i][j] = LU[i][j]; + } + else if(i == j) { + L[i][j] = 1.0; + } + else { + L[i][j] = 0.0; + } + } + } + return X; + } + + /** + * Return upper triangular factor + * + * @return U + */ + public Matrix getU() { + Matrix X = new Matrix(n, n); + double[][] U = X.getArrayRef(); + for(int i = 0; i < n; i++) { + for(int j = 0; j < n; j++) { + if(i <= j) { + U[i][j] = LU[i][j]; + } + else { + U[i][j] = 0.0; + } + } + } + return X; + } + + /** + * Return pivot permutation vector + * + * @return piv + */ + public int[] getPivot() { + int[] p = new int[m]; + for(int i = 0; i < m; i++) { + p[i] = piv[i]; + } + return p; + } + + /** + * Return pivot permutation vector as a one-dimensional double array + * + * @return (double) piv + */ + public double[] getDoublePivot() { + double[] vals = new double[m]; + for(int i = 0; i < m; i++) { + vals[i] = piv[i]; + } + return vals; + } + + /** + * Determinant + * + * @return det(A) + * @exception IllegalArgumentException Matrix must be square + */ + public double det() { + if(m != n) { + throw new IllegalArgumentException("Matrix must be square."); + } + double d = pivsign; + for(int j = 0; j < n; j++) { + d *= LU[j][j]; + } + return d; + } + + /** + * Solve A*X = B + * + * @param B A Matrix with as many rows as A and any number of columns. + * @return X so that L*U*X = B(piv,:) + * @exception IllegalArgumentException Matrix row dimensions must agree. + * @exception RuntimeException Matrix is singular. + */ + public Matrix solve(Matrix B) { + if(B.getRowDimensionality() != m) { + throw new IllegalArgumentException("Matrix row dimensions must agree."); + } + if(!this.isNonsingular()) { + throw new RuntimeException("Matrix is singular."); + } + + // Copy right hand side with pivoting + int nx = B.getColumnDimensionality(); + Matrix Xmat = B.getMatrix(piv, 0, nx - 1); + double[][] X = Xmat.getArrayRef(); + + // Solve L*Y = B(piv,:) + for(int k = 0; k < n; k++) { + for(int i = k + 1; i < n; i++) { + for(int j = 0; j < nx; j++) { + X[i][j] -= X[k][j] * LU[i][k]; + } + } + } + // Solve U*X = Y; + for(int k = n - 1; k >= 0; k--) { + for(int j = 0; j < nx; j++) { + X[k][j] /= LU[k][k]; + } + for(int i = 0; i < k; i++) { + for(int j = 0; j < nx; j++) { + X[i][j] -= X[k][j] * LU[i][k]; + } + } + } + return Xmat; + } +}
\ No newline at end of file |