package sim.util.matrix; public class DenseMatrix extends Matrix { public double[][] vals; public DenseMatrix(int m, int n) { this.m = m; this.n = n; this.vals = new double[m][n]; } public DenseMatrix(double[][] vals) { this.vals = vals; this.m = vals.length; this.n = vals[0].length; } public Vector times(Vector B) { double thism = this.m; double thisn = this.n; double[] result = new double[this.m]; double[] bvals = B.vals; double[][] thisvals = this.vals; if (thisn != B.m) throw new RuntimeException("Matrix dimensions don't agree"); for (int i = 0; i < thism; i++) { double[] thisrow = thisvals[i]; double res = 0; for (int j = 0; j < thisn; j++) res += thisrow[j] * bvals[j]; result[i] = res; } return new Vector(result); } public String toString() { double[][] vals = this.vals; String result = ""; for (int i = 0; i < this.m; i++) { for (int j = 0; j < this.n; j++) result += (" " + vals[i][j]); result += "\n"; } return result; } /////////////////////////////////////////////////////////////////// // Got (and slightly adapted all the rest of the code code // from JAMA - http://math.nist.gov/javanumerics/jama/ /////////////////////////////////////////////////////////////////// public DenseMatrix solve (DenseMatrix B) { if (this.m != this.n) throw new RuntimeException("Attempting to solve non-square matrix"); return (new LUDecomposition(this)).solve(B); } public DenseMatrix times(DenseMatrix other) { int thism = this.m; int thisn = this.n; int otherm = other.m; int othern = other.n; double[][] thisvals = this.vals; double[][] othervals = other.vals; if (otherm != thisn) throw new IllegalArgumentException("Matrix inner dimensions must agree."); DenseMatrix X = new DenseMatrix(thism,othern); double[][] C = X.vals; double[] Bcolj = new double[n]; for (int j = 0; j < othern; j++) { for (int k = 0; k < thisn; k++) Bcolj[k] = othervals[k][j]; for (int i = 0; i < m; i++) { double[] Arowi = thisvals[i]; double s = 0; for (int k = 0; k < thisn; k++) s += Arowi[k]*Bcolj[k]; C[i][j] = s; } } return X; } public DenseMatrix getSubMatrix (int[] r, int j0, int j1) { DenseMatrix X = new DenseMatrix(r.length,j1-j0+1); double[][] B = X.vals; try { for (int i = 0; i < r.length; i++) { for (int j = j0; j <= j1; j++) B[i][j-j0] = vals[r[i]][j]; } } catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } return X; } public Vector times(Vector B, Vector C) { double thism = this.m; double thisn = this.n; double[] cvals = C.vals; double[] bvals = B.vals; double[][] thisvals = this.vals; if (thisn != B.m) throw new RuntimeException("Matrix dimensions don't agree"); if (thism != C.m) throw new RuntimeException("Result vector wrong size"); for (int i = 0; i < thism; i++) { double[] thisrow = thisvals[i]; double res = 0; for (int j = 0; j < thisn; j++) res += thisrow[j] * bvals[j]; cvals[i] = res; } return C; } public Vector transposeTimes(Vector B) { return transposeTimes(B, new Vector(this.m)); } public Vector transposeTimes(Vector B, Vector C) { double thism = this.m; double thisn = this.n; double[] result = C.vals; double[] bvals = B.vals; double[][] thisvals = this.vals; if (thism != B.m) throw new RuntimeException("Matrix dimensions don't agree"); for (int i = 0; i < thisn; i++) { double res = 0; for (int j = 0; j < thism; j++) res += vals[j][i] * bvals[j]; result[i] = res; } return C; } public DiagonalMatrix getDiagonalMatrix() { if (this.m != this.n) throw new RuntimeException("Matrix is not square"); DiagonalMatrix result = new DiagonalMatrix(this.m); for (int i = 0; i < this.m; i++) result.vals[i] = this.vals[i][i]; return result; } public void setSubMatrix (int i0, int i1, int j0, int j1, DenseMatrix X) { try { for (int i = i0; i <= i1; i++) { for (int j = j0; j <= j1; j++) vals[i][j] = X.vals[i-i0][j-j0]; } } catch(ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } } public DenseMatrix transpose() { double[][] thisvals = this.vals; int thism = m; int thisn = n; DenseMatrix X = new DenseMatrix(thisn,thism); double[][] C = X.vals; for (int i = 0; i < thism; i++) { double[] row = thisvals[i]; for (int j = 0; j < thisn; j++) C[j][i] = row[j]; } return X; } public DenseMatrix minus(DenseMatrix other) { int thism = m; int thisn = n; if (thism != other.m && thisn != other.n) throw new RuntimeException("Matrix dimensions don't agreee"); double[][] thisvals = this.vals; double[][] othervals = other.vals; DenseMatrix X = new DenseMatrix(thism,thisn); double[][] C = X.vals; for (int i = 0; i < thism; i++) { double[] thisrow = thisvals[i]; double[] otherrow = othervals[i]; double[] resultrow = C[i]; for (int j = 0; j < thisn; j++) resultrow[j] = thisrow[j] - otherrow[j]; } return X; } public DenseMatrix plus(DenseMatrix other) { int thism = m; int thisn = n; if (thism != other.m && thisn != other.n) throw new RuntimeException("Matrix dimensions don't agreee"); double[][] thisvals = this.vals; double[][] othervals = other.vals; DenseMatrix X = new DenseMatrix(thism,thisn); double[][] C = X.vals; for (int i = 0; i < thism; i++) { double[] thisrow = thisvals[i]; double[] otherrow = othervals[i]; double[] resultrow = C[i]; for (int j = 0; j < thisn; j++) resultrow[j] = thisrow[j] + otherrow[j]; } return X; } public DenseMatrix times(double value) { int thism = m; int thisn = n; double[][] thisvals = this.vals; DenseMatrix X = new DenseMatrix(thism,thisn); double[][] C = X.vals; for (int i = 0; i < thism; i++) { double[] thisrow = thisvals[i]; double[] resultrow = C[i]; for (int j = 0; j < thisn; j++) resultrow[j] = thisrow[j] * value; } return X; } private class LUDecomposition implements java.io.Serializable { /* ------------------------ Class variables * ------------------------ */ /** 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 @return Structure to access L, U and piv. */ public LUDecomposition(DenseMatrix A) { // Use a "left-looking", dot-product, Crout/Doolittle algorithm. LU = A.vals; m = A.m; n = A.n; 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 DenseMatrix getL() { DenseMatrix X = new DenseMatrix(m,n); double[][] L = X.vals; 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 DenseMatrix getU() { DenseMatrix X = new DenseMatrix(n,n); double[][] U = X.vals; 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] = (double) 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 = (double) 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 DenseMatrix solve(DenseMatrix B) { if (B.m != 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.n; DenseMatrix Xmat = B.getSubMatrix(piv,0,nx-1); double[][] X = Xmat.vals; // 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; } } }