/** * Returns the Q matrix. */ public DMatrixRMaj getQ() { DMatrixRMaj Q = CommonOps_DDRM.identity(QR.numRows); DMatrixRMaj Q_k = new DMatrixRMaj(QR.numRows, QR.numRows); DMatrixRMaj u = new DMatrixRMaj(QR.numRows, 1); DMatrixRMaj temp = new DMatrixRMaj(QR.numRows, QR.numRows); int N = Math.Min(QR.numCols, QR.numRows); // compute Q by first extracting the householder vectors from the columns of QR and then applying it to Q for (int j = N - 1; j >= 0; j--) { CommonOps_DDRM.extract(QR, j, QR.numRows, j, j + 1, u, j, 0); u.set(j, 1.0); // A = (I - γ*u*u<sup>T</sup>)*A<br> CommonOps_DDRM.setIdentity(Q_k); CommonOps_DDRM.multAddTransB(-gammas[j], u, u, Q_k); CommonOps_DDRM.mult(Q_k, Q, temp); Q.set(temp); } return(Q); }
/** * <p> * Creates a reflector from the provided vector and gamma.<br> * <br> * Q = I - γ u u<sup>T</sup><br> * </p> * * <p> * In practice {@link VectorVectorMult_DDRM#householder(double, DMatrixD1, DMatrixD1, DMatrixD1)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. * </p> * * @param u A vector. Not modified. * @param gamma To produce a reflector gamma needs to be equal to 2/||u||. * @return An orthogonal reflector. */ public static DMatrixRMaj createReflector(DMatrixRMaj u, double gamma) { if (!MatrixFeatures_DDRM.isVector(u)) { throw new ArgumentException("u must be a vector"); } DMatrixRMaj Q = CommonOps_DDRM.identity(u.getNumElements()); CommonOps_DDRM.multAddTransB(-gamma, u, u, Q); return(Q); }
/** * <p> * Creates a reflector from the provided vector.<br> * <br> * Q = I - γ u u<sup>T</sup><br> * γ = 2/||u||<sup>2</sup> * </p> * * <p> * In practice {@link VectorVectorMult_DDRM#householder(double, DMatrixD1, DMatrixD1, DMatrixD1)} multHouseholder} * should be used for performance reasons since there is no need to calculate Q explicitly. * </p> * * @param u A vector. Not modified. * @return An orthogonal reflector. */ public static DMatrixRMaj createReflector(DMatrix1Row u) { if (!MatrixFeatures_DDRM.isVector(u)) { throw new ArgumentException("u must be a vector"); } double norm = NormOps_DDRM.fastNormF(u); double gamma = -2.0 / (norm * norm); DMatrixRMaj Q = CommonOps_DDRM.identity(u.getNumElements()); CommonOps_DDRM.multAddTransB(gamma, u, u, Q); return(Q); }
/** * Computes the QR decomposition of the provided matrix. * * @param A Matrix which is to be decomposed. Not modified. */ public void decompose(DMatrixRMaj A) { this.QR = (DMatrixRMaj)A.copy(); int N = Math.Min(A.numCols, A.numRows); gammas = new double[A.numCols]; DMatrixRMaj A_small = new DMatrixRMaj(A.numRows, A.numCols); DMatrixRMaj A_mod = new DMatrixRMaj(A.numRows, A.numCols); DMatrixRMaj v = new DMatrixRMaj(A.numRows, 1); DMatrixRMaj Q_k = new DMatrixRMaj(A.numRows, A.numRows); for (int i = 0; i < N; i++) { // reshape temporary variables A_small.reshape(QR.numRows - i, QR.numCols - i, false); A_mod.reshape(A_small.numRows, A_small.numCols, false); v.reshape(A_small.numRows, 1, false); Q_k.reshape(v.getNumElements(), v.getNumElements(), false); // use extract matrix to get the column that is to be zeroed CommonOps_DDRM.extract(QR, i, QR.numRows, i, i + 1, v, 0, 0); double max = CommonOps_DDRM.elementMaxAbs(v); if (max > 0 && v.getNumElements() > 1) { // normalize to reduce overflow issues CommonOps_DDRM.divide(v, max); // compute the magnitude of the vector double tau = NormOps_DDRM.normF(v); if (v.get(0) < 0) { tau *= -1.0; } double u_0 = v.get(0) + tau; double gamma = u_0 / tau; CommonOps_DDRM.divide(v, u_0); v.set(0, 1.0); // extract the submatrix of A which is being operated on CommonOps_DDRM.extract(QR, i, QR.numRows, i, QR.numCols, A_small, 0, 0); // A = (I - γ*u*u<sup>T</sup>)A CommonOps_DDRM.setIdentity(Q_k); CommonOps_DDRM.multAddTransB(-gamma, v, v, Q_k); CommonOps_DDRM.mult(Q_k, A_small, A_mod); // save the results CommonOps_DDRM.insert(A_mod, QR, i, i); CommonOps_DDRM.insert(v, QR, i, i); QR.unsafe_set(i, i, -tau * max); // save gamma for recomputing Q later on gammas[i] = gamma; } } }