/* ------------------------ Constructor * ------------------------ */ /** QR Decomposition, computed by Householder reflections. @param A Rectangular matrix @return Structure to access R and the Householder vectors and compute Q. */ public QRDecomposition(CoreMatrix A) { // Initialize. QR = A.getArrayCopy(); m = A.getRowDimension(); n = A.getColumnDimension(); Rdiag = new double[n]; // Main loop. for (int k = 0; k < n; k++) { // Compute 2-norm of k-th column without under/overflow. double nrm = 0; for (int i = k; i < m; i++) { nrm = Maths.hypot(nrm, QR[i, k]); } if (nrm != 0.0) { // Form k-th Householder vector. if (QR[k, k] < 0) { nrm = -nrm; } for (int i = k; i < m; i++) { QR[i, k] /= nrm; } QR[k, k] += 1.0; // Apply transformation to remaining columns. for (int j = k + 1; j < n; j++) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i, k] * QR[i, j]; } s = -s / QR[k, k]; for (int i = k; i < m; i++) { QR[i, j] += s * QR[i, k]; } } } Rdiag[k] = -nrm; } }
/** Get a subCoreMatrix. @param r Array of row indices. @param c Array of column indices. @return A(r(:),c(:)) @exception Exception SubCoreMatrix indices */ public CoreMatrix getMatrix(int[] r, int[] c) { CoreMatrix X = new CoreMatrix(r.Length, c.Length); double[,] B = X.getArray(); try { for (int i = 0; i < r.Length; i++) { for (int j = 0; j < c.Length; j++) { B[i, j] = A[r[i], c[j]]; } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } return X; }
/** Least squares solution of A*X = B @param B A Matrix with as many rows as A and any number of columns. @return X that minimizes the two norm of Q*R*X-B. @exception IllegalArgumentException Matrix row dimensions must agree. @exception RuntimeException Matrix is rank deficient. */ public CoreMatrix solve(CoreMatrix B) { if (B.getRowDimension() != m) { throw new Exception("Matrix row dimensions must agree."); } if (!this.isFullRank()) { throw new Exception("Matrix is rank deficient."); } // Copy right hand side int nx = B.getColumnDimension(); double[,] X = B.getArrayCopy(); // Compute Y = transpose(Q)*B for (int k = 0; k < n; k++) { for (int j = 0; j < nx; j++) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i, k] * X[i, j]; } s = -s / QR[k, k]; for (int i = k; i < m; i++) { X[i, j] += s * QR[i, k]; } } } // Solve R*X = Y; for (int k = n - 1; k >= 0; k--) { for (int j = 0; j < nx; j++) { X[k, j] /= Rdiag[k]; } for (int i = 0; i < k; i++) { for (int j = 0; j < nx; j++) { X[i, j] -= X[k, j] * QR[i, k]; } } } return (new CoreMatrix(X, n, nx).getMatrix(0, n - 1, 0, nx - 1)); }
/** Return the upper triangular factor @return R */ public CoreMatrix getR() { CoreMatrix X = new CoreMatrix(n, n); double[,] R = X.getArray(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i < j) { R[i, j] = QR[i, j]; } else if (i == j) { R[i, j] = Rdiag[i]; } else { R[i, j] = 0.0; } } } return X; }
/** Return the block diagonal eigenvalue matrix @return D */ public CoreMatrix getD() { CoreMatrix X = new CoreMatrix(n, n); double[,] D = X.getArray(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { D[i, j] = 0.0; } D[i, i] = d[i]; if (e[i] > 0) { D[i, i + 1] = e[i]; } else if (e[i] < 0) { D[i, i - 1] = e[i]; } } return X; }
/* ------------------------ Constructor * ------------------------ */ /** LU Decomposition @param A Rectangular matrix @return Structure to access L, U and piv. */ public LUDecomposition(CoreMatrix A) { // Use a "left-looking", dot-product, Crout/Doolittle algorithm. LU = A.getArrayCopy(); m = A.getRowDimension(); n = A.getColumnDimension(); piv = new int[m]; for (int i = 0; i < m; i++) { piv[i] = i; } pivsign = 1; double[] LUrowi = new double[m]; 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++) { for (int h = 0; i < m; i++) LUrowi[h] = LU[i, h]; // 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 ki = 0; ki < n; ki++) { double t = LU[p, ki]; LU[p, ki] = LU[j, ki]; LU[j, ki] = 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]; } } } }
/** Return upper triangular factor @return U */ public CoreMatrix getU() { CoreMatrix X = new CoreMatrix(n, n); double[,] U = X.getArray(); 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; }
/* ------------------------ Private Methods * ------------------------ */ /** Check if size(A) == size(B) **/ private void checkCoreMatrixDimensions(CoreMatrix B) { if (B.m != m || B.n != n) { throw new Exception("CoreMatrix dimensions must agree."); } }
/** CoreMatrix transpose. @return A' */ public CoreMatrix transpose() { CoreMatrix X = new CoreMatrix(n, m); double[,] C = X.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { C[j, i] = A[i, j]; } } return X; }
/** Set a subCoreMatrix. @param i0 Initial row index @param i1 Final row index @param c Array of column indices. @param X A(i0:i1,c(:)) @exception Exception SubCoreMatrix indices */ public void setMatrix(int i0, int i1, int[] c, CoreMatrix X) { try { for (int i = i0; i <= i1; i++) { for (int j = 0; j < c.Length; j++) { A[i, c[j]] = X.get(i - i0, j); } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } }
/** Set a subCoreMatrix. @param r Array of row indices. @param j0 Initial column index @param j1 Final column index @param X A(r(:),j0:j1) @exception Exception SubCoreMatrix indices */ public void setMatrix(int[] r, int j0, int j1, CoreMatrix X) { try { for (int i = 0; i < r.Length; i++) { for (int j = j0; j <= j1; j++) { A[r[i], j] = X.get(i, j - j0); } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } }
/** Set a subCoreMatrix. @param r Array of row indices. @param c Array of column indices. @param X A(r(:),c(:)) @exception Exception SubCoreMatrix indices */ public void setMatrix(int[] r, int[] c, CoreMatrix X) { try { for (int i = 0; i < r.Length; i++) { for (int j = 0; j < c.Length; j++) { A[r[i], c[j]] = X.get(i, j); } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } }
/** Set a subCoreMatrix. @param i0 Initial row index @param i1 Final row index @param j0 Initial column index @param j1 Final column index @param X A(i0:i1,j0:j1) @exception Exception SubCoreMatrix indices */ public void setMatrix(int i0, int i1, int j0, int j1, CoreMatrix X) { try { for (int i = i0; i <= i1; i++) { for (int j = j0; j <= j1; j++) { A[i, j] = X.get(i - i0, j - j0); } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } }
/** Get a subCoreMatrix. @param r Array of row indices. @param i0 Initial column index @param i1 Final column index @return A(r(:),j0:j1) @exception Exception SubCoreMatrix indices */ public CoreMatrix getMatrix(int[] r, int j0, int j1) { CoreMatrix X = new CoreMatrix(r.Length, j1 - j0 + 1); double[,] B = X.getArray(); try { for (int i = 0; i < r.Length; i++) { for (int j = j0; j <= j1; j++) { B[i, j - j0] = A[r[i], j]; } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } return X; }
/** Get a subCoreMatrix. @param i0 Initial row index @param i1 Final row index @param c Array of column indices. @return A(i0:i1,c(:)) @exception Exception SubCoreMatrix indices */ public CoreMatrix getMatrix(int i0, int i1, int[] c) { CoreMatrix X = new CoreMatrix(i1 - i0 + 1, c.Length); double[,] B = X.getArray(); try { for (int i = i0; i <= i1; i++) { for (int j = 0; j < c.Length; j++) { B[i - i0, j] = A[i, c[j]]; } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } return X; }
/** Solve X*A = B, which is also A'*X' = B' @param B right hand side @return solution if A is square, least squares solution otherwise. */ public CoreMatrix solveTranspose(CoreMatrix B) { return transpose().solve(B.transpose()); }
/** Generate identity CoreMatrix @param m Number of rows. @param n Number of colums. @return An m-by-n CoreMatrix with ones on the diagonal and zeros elsewhere. */ public static CoreMatrix identity(int m, int n) { CoreMatrix A = new CoreMatrix(m, n); double[,] X = A.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { X[i, j] = (i == j ? 1.0 : 0.0); } } return A; }
/** Unary minus @return -A */ public CoreMatrix uminus() { CoreMatrix X = new CoreMatrix(m, n); double[,] C = X.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { C[i, j] = -A[i, j]; } } return X; }
/** Return lower triangular factor @return L */ public CoreMatrix getL() { CoreMatrix X = new CoreMatrix(m, n); double[,] L = X.getArray(); 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; }
/** Element-by-element multiplication in place, A = A.*B @param B another CoreMatrix @return A.*B */ public CoreMatrix arrayTimesEquals(CoreMatrix B) { checkCoreMatrixDimensions(B); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { A[i, j] = A[i, j] * B.A[i, j]; } } return this; }
/** 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 CoreMatrix solve(CoreMatrix B) { if (B.getRowDimension() != m) { throw new Exception("Matrix row dimensions must agree."); } if (!this.isNonsingular()) { throw new Exception("Matrix is singular."); } // Copy right hand side with pivoting int nx = B.getColumnDimension(); CoreMatrix Xmat = B.getMatrix(piv, 0, nx - 1); double[,] X = Xmat.getArray(); // 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; }
/** Element-by-element left division, C = A.\B @param B another CoreMatrix @return A.\B */ public CoreMatrix arrayLeftDivide(CoreMatrix B) { checkCoreMatrixDimensions(B); CoreMatrix X = new CoreMatrix(m, n); double[,] C = X.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { C[i, j] = B.A[i, j] / A[i, j]; } } return X; }
/* ------------------------ Constructor * ------------------------ */ /** Check for symmetry, then construct the eigenvalue decomposition @param A Square matrix @return Structure to access D and V. */ public EigenvalueDecomposition(CoreMatrix Arg) { double[,] A = Arg.getArray(); n = Arg.getColumnDimension(); V = new double[n, n]; d = new double[n]; e = new double[n]; issymmetric = true; for (int j = 0; (j < n) & issymmetric; j++) { for (int i = 0; (i < n) & issymmetric; i++) { issymmetric = (A[i, j] == A[j, i]); } } if (issymmetric) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { V[i, j] = A[i, j]; } } // Tridiagonalize. tred2(); // Diagonalize. tql2(); } else { H = new double[n, n]; ort = new double[n]; for (int j = 0; j < n; j++) { for (int i = 0; i < n; i++) { H[i, j] = A[i, j]; } } // Reduce to Hessenberg form. orthes(); // Reduce Hessenberg to real Schur form. hqr2(); } }
/** Element-by-element left division in place, A = A.\B @param B another CoreMatrix @return A.\B */ public CoreMatrix arrayLeftDivideEquals(CoreMatrix B) { checkCoreMatrixDimensions(B); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { A[i, j] = B.A[i, j] / A[i, j]; } } return this; }
/** Return the Householder vectors @return Lower trapezoidal matrix whose columns define the reflections */ public CoreMatrix getH() { CoreMatrix X = new CoreMatrix(m, n); double[,] H = X.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i >= j) { H[i, j] = QR[i, j]; } else { H[i, j] = 0.0; } } } return X; }
/** Multiply a CoreMatrix by a scalar, C = s*A @param s scalar @return s*A */ public CoreMatrix times(double s) { CoreMatrix X = new CoreMatrix(m, n); double[,] C = X.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { C[i, j] = s * A[i, j]; } } return X; }
/** Generate and return the (economy-sized) orthogonal factor @return Q */ public CoreMatrix getQ() { CoreMatrix X = new CoreMatrix(m, n); double[,] Q = X.getArray(); for (int k = n - 1; k >= 0; k--) { for (int i = 0; i < m; i++) { Q[i, k] = 0.0; } Q[k, k] = 1.0; for (int j = k; j < n; j++) { if (QR[k, k] != 0) { double s = 0.0; for (int i = k; i < m; i++) { s += QR[i, k] * Q[i, j]; } s = -s / QR[k, k]; for (int i = k; i < m; i++) { Q[i, j] += s * QR[i, k]; } } } } return X; }
/** Linear algebraic CoreMatrix multiplication, A * B @param B another CoreMatrix @return CoreMatrix product, A * B @exception IllegalArgumentException CoreMatrix inner dimensions must agree. */ public CoreMatrix times(CoreMatrix B) { if (B.m != n) { throw new Exception("CoreMatrix inner dimensions must agree."); } CoreMatrix X = new CoreMatrix(m, B.n); double[,] C = X.getArray(); double[] Bcolj = new double[n]; for (int j = 0; j < B.n; j++) { for (int k = 0; k < n; k++) { Bcolj[k] = B.A[k, j]; } for (int i = 0; i < m; i++) { double[] Arowi = new double[n]; for (int z = 0; z < n; z++) Arowi[z] = A[i, z]; double s = 0; for (int k = 0; k < n; k++) { s += Arowi[k] * Bcolj[k]; } C[i, j] = s; } } return X; }
/** Solve A*X = B @param B right hand side @return solution if A is square, least squares solution otherwise */ public CoreMatrix solve(CoreMatrix B) { return (m == n ? (new LUDecomposition(this)).solve(B) : (new QRDecomposition(this)).solve(B)); }
/** Get a subCoreMatrix. @param i0 Initial row index @param i1 Final row index @param j0 Initial column index @param j1 Final column index @return A(i0:i1,j0:j1) @exception Exception SubCoreMatrix indices */ public CoreMatrix getMatrix(int i0, int i1, int j0, int j1) { CoreMatrix X = new CoreMatrix(i1 - i0 + 1, j1 - j0 + 1); double[,] B = X.getArray(); try { for (int i = i0; i <= i1; i++) { for (int j = j0; j <= j1; j++) { B[i - i0, j - j0] = A[i, j]; } } } catch (Exception) { throw new Exception("SubCoreMatrix indices"); } return X; }