/** * Matrix transpose. * * @return A' */ public Matrix transpose() { Matrix X = new Matrix(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; }
/** * Unary minus * * @return -A */ public Matrix uminus() { Matrix X = new Matrix(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; }
/** * Generate identity matrix * * @param m Number of rows. * @param n Number of colums. * @return An m-by-n matrix with ones on the diagonal and zeros elsewhere. */ public static Matrix identity(int m, int n) { Matrix A = new Matrix(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; }
/** * Generate matrix with random elements * * @param m Number of rows. * @param n Number of colums. * @return An m-by-n matrix with uniformly distributed random elements. */ public static Matrix random(int m, int n) { Matrix A = new Matrix(m, n); double[][] X = A.getArray(); for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { X[i][j] = Math.random(); } } return A; }
/** * Multiply a matrix by a scalar, C = s*A * * @param s scalar * @return s*A */ public Matrix times(double s) { Matrix X = new Matrix(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; }
/** * Element-by-element left division, C = A.\B * * @param B another matrix * @return A.\B */ public Matrix arrayLeftDivide(Matrix B) { checkMatrixDimensions(B); Matrix X = new Matrix(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; }
/** * Return the Householder vectors * * @return Lower trapezoidal matrix whose columns define the reflections */ public Matrix getH() { Matrix X = new Matrix(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; }
/** * Get a submatrix. * * @param r Array of row indices. * @param j0 Initial column index * @param j1 Final column index * @return A(r(:),j0:j1) * @exception ArrayIndexOutOfBoundsException Submatrix indices */ public Matrix getMatrix(int[] r, int j0, int j1) { Matrix X = new Matrix(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 (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } return X; }
/** * Get a submatrix. * * @param i0 Initial row index * @param i1 Final row index * @param c Array of column indices. * @return A(i0:i1,c(:)) * @exception ArrayIndexOutOfBoundsException Submatrix indices */ public Matrix getMatrix(int i0, int i1, int[] c) { Matrix X = new Matrix(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 (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } return X; }
/** * Get a submatrix. * * @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 ArrayIndexOutOfBoundsException Submatrix indices */ public Matrix getMatrix(int i0, int i1, int j0, int j1) { Matrix X = new Matrix(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 (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } return X; }
/** * Construct a matrix from a copy of a 2-D array. * * @param A Two-dimensional array of doubles. * @exception IllegalArgumentException All rows must have the same length */ public static Matrix constructWithCopy(double[][] A) { int m = A.length; int n = A[0].length; Matrix X = new Matrix(m, n); double[][] C = X.getArray(); for (int i = 0; i < m; i++) { if (A[i].length != n) { throw new IllegalArgumentException("All rows must have the same length."); } for (int j = 0; j < n; j++) { C[i][j] = A[i][j]; } } return X; }
/** * Return the upper triangular factor * * @return R */ public Matrix getR() { Matrix X = new Matrix(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; }
/** * Set a submatrix. * * @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 ArrayIndexOutOfBoundsException Submatrix indices */ public void setMatrix(int i0, int i1, int j0, int j1, Matrix 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 (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } }
/** * Set a submatrix. * * @param r Array of row indices. * @param j0 Initial column index * @param j1 Final column index * @param X A(r(:),j0:j1) * @exception ArrayIndexOutOfBoundsException Submatrix indices */ public void setMatrix(int[] r, int j0, int j1, Matrix 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 (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } }
/** * Set a submatrix. * * @param i0 Initial row index * @param i1 Final row index * @param c Array of column indices. * @param X A(i0:i1,c(:)) * @exception ArrayIndexOutOfBoundsException Submatrix indices */ public void setMatrix(int i0, int i1, int[] c, Matrix 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 (ArrayIndexOutOfBoundsException e) { throw new ArrayIndexOutOfBoundsException("Submatrix indices"); } }
/** * QR Decomposition, computed by Householder reflections. * * @param A Rectangular matrix * @return Structure to access R and the Householder vectors and compute Q. */ public QRDecomposition(Matrix 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; } }
/** * Linear algebraic matrix multiplication, A * B * * @param B another matrix * @return Matrix product, A * B * @exception IllegalArgumentException Matrix inner dimensions must agree. */ public Matrix times(Matrix B) { if (B.m != n) { throw new IllegalArgumentException("Matrix inner dimensions must agree."); } Matrix X = new Matrix(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 = A[i]; double s = 0; for (int k = 0; k < n; k++) { s += Arowi[k] * Bcolj[k]; } C[i][j] = s; } } 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 Matrix solve(Matrix B) { if (B.getRowDimension() != m) { throw new IllegalArgumentException("Matrix row dimensions must agree."); } if (!this.isFullRank()) { throw new RuntimeException("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 Matrix(X, n, nx).getMatrix(0, n - 1, 0, nx - 1)); }
/** * Generate and return the (economy-sized) orthogonal factor * * @return Q */ public Matrix getQ() { Matrix X = new Matrix(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; }
/** * 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 Matrix solveTranspose(Matrix B) { return transpose().solve(B.transpose()); }