/** * Returns the orthogonal U matrix. * * @param U If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public virtual FMatrixRMaj getU(FMatrixRMaj U, bool transpose, bool compact) { U = handleU(U, transpose, compact, m, n, min); CommonOps_FDRM.setIdentity(U); for (int i = 0; i < m; i++) { u[i] = 0; } for (int j = min - 1; j >= 0; j--) { u[j] = 1; for (int i = j + 1; i < m; i++) { u[i] = UBV.get(i, j); } if (transpose) { QrHelperFunctions_FDRM.rank1UpdateMultL(U, u, gammasU[j], j, j, m); } else { QrHelperFunctions_FDRM.rank1UpdateMultR(U, u, gammasU[j], j, j, m, this.b); } } return(U); }
/** * Returns the orthogonal V matrix. * * @param V If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public virtual FMatrixRMaj getV(FMatrixRMaj V, bool transpose, bool compact) { V = handleV(V, transpose, compact, m, n, min); CommonOps_FDRM.setIdentity(V); // UBV.print(); // todo the very first multiplication can be avoided by setting to the rank1update output for (int j = min - 1; j >= 0; j--) { u[j + 1] = 1; for (int i = j + 2; i < n; i++) { u[i] = UBV.get(j, i); } if (transpose) { QrHelperFunctions_FDRM.rank1UpdateMultL(V, u, gammasV[j], j + 1, j + 1, n); } else { QrHelperFunctions_FDRM.rank1UpdateMultR(V, u, gammasV[j], j + 1, j + 1, n, this.b); } } return(V); }
public void performImplicitSingleStep(int x1, int x2, float eigenvalue) { if (!createBulgeSingleStep(x1, eigenvalue)) { return; } // get rid of the bump if (Q != null) { QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 2, _temp.data); if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32)) { throw new InvalidOperationException("Bad"); } } if (printHumps) { Console.WriteLine("Applied first Q matrix, it should be humped now. A = "); A.print("%12.3fe"); Console.WriteLine("Pushing the hump off the matrix."); } // perform simple steps for (int i = x1; i < x2 - 1; i++) { if (bulgeSingleStepQn(i) && Q != null) { QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 3, _temp.data); if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TESTP_F32)) { throw new InvalidOperationException("Bad"); } } if (printHumps) { Console.WriteLine("i = " + i + " A = "); A.print("%12.3fe"); } } if (checkHessenberg && !MatrixFeatures_FDRM.isUpperTriangle(A, 1, UtilEjml.TESTP_F32)) { A.print("%12.3fe"); throw new InvalidOperationException("Bad matrix"); } }
public override /**/ double quality() { return(SpecializedOps_FDRM.qualityTriangular(R)); } /** * Solves for X using the QR decomposition. * * @param B A matrix that is n by m. Not modified. * @param X An n by m matrix where the solution is written to. Modified. */ public override void solve(FMatrixRMaj B, FMatrixRMaj X) { if (X.numRows != numCols) { throw new ArgumentException("Unexpected dimensions for X: X rows = " + X.numRows + " expected = " + numCols); } else if (B.numRows != numRows || B.numCols != X.numCols) { throw new ArgumentException("Unexpected dimensions for B"); } int BnumCols = B.numCols; // solve each column one by one for (int colB = 0; colB < BnumCols; colB++) { // make a copy of this column in the vector for (int i = 0; i < numRows; i++) { a.data[i] = B.data[i * BnumCols + colB]; } // Solve Qa=b // a = Q'b // a = Q_{n-1}...Q_2*Q_1*b // // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for (int n = 0; n < numCols; n++) { float[] u = QR[n]; float vv = u[n]; u[n] = 1; QrHelperFunctions_FDRM.rank1UpdateMultR(a, u, gammas[n], 0, n, numRows, temp.data); u[n] = vv; } // solve for Rx = b using the standard upper triangular solver TriangularSolver_FDRM.solveU(R.data, a.data, numCols); // save the results for (int i = 0; i < numCols; i++) { X.data[i * X.numCols + colB] = a.data[i]; } } }
/** * An orthogonal matrix that has the following property: H = Q<sup>T</sup>AQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public FMatrixRMaj getQ(FMatrixRMaj Q) { Q = UtilDecompositons_FDRM.checkIdentity(Q, N, N); for (int j = N - 2; j >= 0; j--) { u[j + 1] = 1; for (int i = j + 2; i < N; i++) { u[i] = QH.get(i, j); } QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u, gammas[j], j + 1, j + 1, N, b); } return(Q); }
protected void computeU(int k) { float[] b = UBV.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow float max = 0; for (int i = k; i < m; i++) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. float val = u[i] = b[i * n + k]; val = Math.Abs(val); if (val > max) { max = val; } } if (max > 0) { // -------- set up the reflector Q_k float tau = QrHelperFunctions_FDRM.computeTauAndDivide(k, m, u, max); // write the reflector into the lower left column of the matrix // while dividing u by nu float nu = u[k] + tau; QrHelperFunctions_FDRM.divideElements_Bcol(k + 1, m, n, u, b, k, nu); u[k] = 1.0f; float gamma = nu / tau; gammasU[k] = gamma; // ---------- multiply on the left by Q_k QrHelperFunctions_FDRM.rank1UpdateMultR(UBV, u, gamma, k + 1, k, m, this.b); b[k * n + k] = -tau * max; } else { gammasU[k] = 0; } }
/** * An orthogonal matrix that has the following property: T = Q<sup>T</sup>AQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public FMatrixRMaj getQ(FMatrixRMaj Q) { Q = UtilDecompositons_FDRM.checkIdentity(Q, N, N); for (int i = 0; i < N; i++) { w[i] = 0; } for (int j = N - 2; j >= 0; j--) { w[j + 1] = 1; for (int i = j + 2; i < N; i++) { w[i] = QT.get(j, i); } QrHelperFunctions_FDRM.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b); // Q.print(); } return(Q); }
/** * An orthogonal matrix that has the following property: T = Q<sup>T</sup>AQ * * @param Q If not null then the results will be stored here. Otherwise a new matrix will be created. * @return The extracted Q matrix. */ public virtual FMatrixRMaj getQ(FMatrixRMaj Q, bool transposed) { Q = UtilDecompositons_FDRM.checkIdentity(Q, N, N); for (int i = 0; i < N; i++) { w[i] = 0; } if (transposed) { for (int j = N - 2; j >= 0; j--) { w[j + 1] = 1; for (int i = j + 2; i < N; i++) { w[i] = QT.data[j * N + i]; } QrHelperFunctions_FDRM.rank1UpdateMultL(Q, w, gammas[j + 1], j + 1, j + 1, N); } } else { for (int j = N - 2; j >= 0; j--) { w[j + 1] = 1; for (int i = j + 2; i < N; i++) { w[i] = QT.get(j, i); } QrHelperFunctions_FDRM.rank1UpdateMultR(Q, w, gammas[j + 1], j + 1, j + 1, N, b); } } return(Q); }
public override void solve(FMatrixRMaj B, FMatrixRMaj X) { if (X.numRows != numCols) { throw new ArgumentException("Unexpected dimensions for X"); } else if (B.numRows != numRows || B.numCols != X.numCols) { throw new ArgumentException("Unexpected dimensions for B"); } int BnumCols = B.numCols; // get the pivots and transpose them int[] pivots = decomposition.getColPivots(); float[][] qr = decomposition.getQR(); float[] gammas = decomposition.getGammas(); // solve each column one by one for (int colB = 0; colB < BnumCols; colB++) { x_basic.reshape(numRows, 1); Y.reshape(numRows, 1); // make a copy of this column in the vector for (int i = 0; i < numRows; i++) { x_basic.data[i] = B.get(i, colB); } // Solve Q*x=b => x = Q'*b // Q_n*b = (I-gamma*u*u^T)*b = b - u*(gamma*U^T*b) for (int i = 0; i < rank; i++) { float[] u = qr[i]; float vv = u[i]; u[i] = 1; QrHelperFunctions_FDRM.rank1UpdateMultR(x_basic, u, gammas[i], 0, i, numRows, Y.data); u[i] = vv; } // solve for Rx = b using the standard upper triangular solver TriangularSolver_FDRM.solveU(R11.data, x_basic.data, rank); // finish the basic solution by filling in zeros x_basic.reshape(numCols, 1, true); for (int i = rank; i < numCols; i++) { x_basic.data[i] = 0; } if (norm2Solution && rank < numCols) { upgradeSolution(x_basic); } // save the results for (int i = 0; i < numCols; i++) { X.set(pivots[i], colB, x_basic.data[i]); } } }
public bool bulgeSingleStepQn(int i, float a11, float a21, float threshold, bool set) { float max; if (normalize) { max = Math.Abs(a11); if (max < Math.Abs(a21)) { max = Math.Abs(a21); } // if( max <= Math.Abs(A.get(i,i))*UtilEjml.F_EPS ) { if (max <= threshold) { // Console.WriteLine("i = "+i); // A.print(); if (set) { A.set(i, i - 1, 0); A.set(i + 1, i - 1, 0); } return(false); } a11 /= max; a21 /= max; } else { max = 1; } // compute the reflector using the b's above float tau = (float)Math.Sqrt(a11 * a11 + a21 * a21); if (a11 < 0) { tau = -tau; } float div = a11 + tau; u.set(i, 0, 1); u.set(i + 1, 0, a21 / div); gamma = div / tau; // compute A_1 = Q_1^T * A * Q_1 // apply Q*A - just do the 3 rows QrHelperFunctions_FDRM.rank1UpdateMultR(A, u.data, gamma, 0, i, i + 2, _temp.data); if (set) { A.set(i, i - 1, -max * tau); A.set(i + 1, i - 1, 0); } // apply A*Q - just the three things QrHelperFunctions_FDRM.rank1UpdateMultL(A, u.data, gamma, 0, i, i + 2); if (checkUncountable && MatrixFeatures_FDRM.hasUncountable(A)) { throw new InvalidOperationException("bad matrix"); } return(true); }
private void performImplicitDoubleStep(int x1, int x2, float b11, float b21, float b31) { if (!bulgeDoubleStepQn(x1, b11, b21, b31, 0, false)) { return; } // get rid of the bump if (Q != null) { QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x1, x1 + 3, _temp.data); if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32)) { u.print(); Q.print(); throw new InvalidOperationException("Bad"); } } if (printHumps) { Console.WriteLine("Applied first Q matrix, it should be humped now. A = "); A.print("%12.3fe"); Console.WriteLine("Pushing the hump off the matrix."); } // perform float steps for (int i = x1; i < x2 - 2; i++) { if (bulgeDoubleStepQn(i) && Q != null) { QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, i + 1, i + 4, _temp.data); if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32)) { throw new InvalidOperationException("Bad"); } } if (printHumps) { Console.WriteLine("i = " + i + " A = "); A.print("%12.3fe"); } } if (printHumps) { Console.WriteLine("removing last bump"); } // the last one has to be a single step if (x2 - 2 >= 0 && bulgeSingleStepQn(x2 - 2) && Q != null) { QrHelperFunctions_FDRM.rank1UpdateMultR(Q, u.data, gamma, 0, x2 - 1, x2 + 1, _temp.data); if (checkOrthogonal && !MatrixFeatures_FDRM.isOrthogonal(Q, UtilEjml.TEST_F32)) { throw new InvalidOperationException("Bad"); } } if (printHumps) { Console.WriteLine(" A = "); A.print("%12.3fe"); } // A.print("%12.3fe"); if (checkHessenberg && !MatrixFeatures_FDRM.isUpperTriangle(A, 1, UtilEjml.TEST_F32)) { A.print("%12.3fe"); throw new InvalidOperationException("Bad matrix"); } }
/** * Internal function for computing the decomposition. */ private bool _decompose() { float[] h = QH.data; for (int k = 0; k < N - 2; k++) { // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow float max = 0; for (int i = k + 1; i < N; i++) { // copy the householder vector to vector outside of the matrix to reduce caching issues // big improvement on larger matrices and a relatively small performance hit on small matrices. float val = u[i] = h[i * N + k]; val = Math.Abs(val); if (val > max) { max = val; } } if (max > 0) { // -------- set up the reflector Q_k float tau = 0; // normalize to reduce overflow/underflow // and compute tau for the reflector for (int i = k + 1; i < N; i++) { float val = u[i] /= max; tau += val * val; } tau = (float)Math.Sqrt(tau); if (u[k + 1] < 0) { tau = -tau; } // write the reflector into the lower left column of the matrix float nu = u[k + 1] + tau; u[k + 1] = 1.0f; for (int i = k + 2; i < N; i++) { h[i * N + k] = u[i] /= nu; } float gamma = nu / tau; gammas[k] = gamma; // ---------- multiply on the left by Q_k QrHelperFunctions_FDRM.rank1UpdateMultR(QH, u, gamma, k + 1, k + 1, N, b); // ---------- multiply on the right by Q_k QrHelperFunctions_FDRM.rank1UpdateMultL(QH, u, gamma, 0, k + 1, N); // since the first element in the householder vector is known to be 1 // store the full upper hessenberg h[(k + 1) * N + k] = -tau * max; } else { gammas[k] = 0; } } return(true); }