/** * Internal function for computing the decomposition. */ private bool _decompose() { float[] h = QH.data; for (int k = 0; k < N - 2; k++) { // k = column u[k * 2] = 0; u[k * 2 + 1] = 0; float max = QrHelperFunctions_CDRM.extractColumnAndMax(QH, k + 1, N, k, u, 0); if (max > 0) { // -------- set up the reflector Q_k float gamma = QrHelperFunctions_CDRM.computeTauGammaAndDivide(k + 1, N, u, max, tau); gammas[k] = gamma; // divide u by u_0 float real_u_0 = u[(k + 1) * 2] + tau.real; float imag_u_0 = u[(k + 1) * 2 + 1] + tau.imaginary; QrHelperFunctions_CDRM.divideElements(k + 2, N, u, 0, real_u_0, imag_u_0); // write the reflector into the lower left column of the matrix for (int i = k + 2; i < N; i++) { h[(i * N + k) * 2] = u[i * 2]; h[(i * N + k) * 2 + 1] = u[i * 2 + 1]; } u[(k + 1) * 2] = 1; u[(k + 1) * 2 + 1] = 0; // ---------- multiply on the left by Q_k QrHelperFunctions_CDRM.rank1UpdateMultR(QH, u, 0, gamma, k + 1, k + 1, N, b); // ---------- multiply on the right by Q_k QrHelperFunctions_CDRM.rank1UpdateMultL(QH, u, 0, 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) * 2] = -tau.real * max; h[((k + 1) * N + k) * 2 + 1] = -tau.imaginary * max; } else { gammas[k] = 0; } } return(true); }
/** * Computes and performs the similar a transform for submatrix k. */ private void similarTransform(int k) { float[] t = QT.data; // find the largest value in this column // this is used to normalize the column and mitigate overflow/underflow float max = QrHelperFunctions_CDRM.computeRowMax(QT, k, k + 1, N); if (max > 0) { float gamma = QrHelperFunctions_CDRM.computeTauGammaAndDivide(k * N + k + 1, k * N + N, t, max, tau); gammas[k] = gamma; // divide u by u_0 float real_u_0 = t[(k * N + k + 1) * 2] + tau.real; float imag_u_0 = t[(k * N + k + 1) * 2 + 1] + tau.imaginary; QrHelperFunctions_CDRM.divideElements(k + 2, N, t, k * N, real_u_0, imag_u_0); // A column is zeroed first. However a row is being used to store because it reduces // cache misses. Need to compute the conjugate to have the correct householder operation for (int i = k + 2; i < N; i++) { t[(k * N + i) * 2 + 1] = -t[(k * N + i) * 2 + 1]; } t[(k * N + k + 1) * 2] = 1.0f; t[(k * N + k + 1) * 2 + 1] = 0; // ---------- Specialized householder that takes advantage of the symmetry // QrHelperFunctions_CDRM.rank1UpdateMultR(QT,QT.data,k*N,gamma,k+1,k+1,N,w); // QrHelperFunctions_CDRM.rank1UpdateMultL(QT,QT.data,k*N,gamma,k+1,k+1,N); householderSymmetric(k, gamma); // since the first element in the householder vector is known to be 1 // store the full upper hessenberg t[(k * N + k + 1) * 2] = -tau.real * max; t[(k * N + k + 1) * 2 + 1] = -tau.imaginary * max; } else { gammas[k] = 0; } }