/* * ********** * * subroutine qrfac * * this subroutine uses householder transformations with column * pivoting (optional) to compute a qr factorization of the * m by n matrix a. that is, qrfac determines an orthogonal * matrix q, a permutation matrix p, and an upper trapezoidal * matrix r with diagonal elements of nonincreasing magnitude, * such that a*p = q*r. the householder transformation for * column k, k = 1,2,...,min(m,n), is of the form * * t * i - (1/u(k))*u*u * * where u has zeros in the first k-1 positions. the form of * this transformation and the method of pivoting first * appeared in the corresponding linpack subroutine. * * the subroutine statement is * * subroutine qrfac(m,n,a,lda,pivot,ipvt,lipvt,rdiag,acnorm,wa) * * where * * m is a positive integer input variable set to the number * of rows of a. * * n is a positive integer input variable set to the number * of columns of a. * * a is an m by n array. on input a contains the matrix for * which the qr factorization is to be computed. on output * the strict upper trapezoidal part of a contains the strict * upper trapezoidal part of r, and the lower trapezoidal * part of a contains a factored form of q (the non-trivial * elements of the u vectors described above). * * lda is a positive integer input variable not less than m * which specifies the leading dimension of the array a. * * pivot is a logical input variable. if pivot is set true, * then column pivoting is enforced. if pivot is set false, * then no column pivoting is done. * * ipvt is an integer output array of length lipvt. ipvt * defines the permutation matrix p such that a*p = q*r. * column j of p is column ipvt(j) of the identity matrix. * if pivot is false, ipvt is not referenced. * * lipvt is a positive integer input variable. if pivot is false, * then lipvt may be as small as 1. if pivot is true, then * lipvt must be at least n. * * rdiag is an output array of length n which contains the * diagonal elements of r. * * acnorm is an output array of length n which contains the * norms of the corresponding columns of the input matrix a. * if this information is not needed, then acnorm can coincide * with rdiag. * * wa is a work array of length n. if pivot is false, then wa * can coincide with rdiag. * * subprograms called * * minpack-supplied ... dpmpar,enorm * * fortran-supplied ... dmax1,dsqrt,min0 * * argonne national laboratory. minpack project. march 1980. * burton s. garbow, kenneth e. hillstrom, jorge j. more * * ********** */ public static void qrfac(int m, int n, Matrix a, int dummy1, int pivot, ref List<int> ipvt, int dummy2, ref Vector rdiag, ref Vector acnorm, Vector wa) { int i, ij, jj, j, jp1, k, kmax, minmn; double ajnorm, sum, temp; double zero = 0.0; double one = 1.0; double p05 = 0.05; /* * compute the initial column norms and initialize several arrays. */ ij = 0; for (j = 0; j < n; j++) { acnorm[j] = enorm(m, a.GetRange(ij, m)); rdiag[j] = acnorm[j]; wa[j] = rdiag[j]; if (pivot != 0) ipvt[j] = j; ij += m; /* m*j */ } /* * reduce a to r with householder transformations. */ minmn = min0(m, n); for (j = 0; j < minmn; j++) { if (pivot == 0) goto L40; /* * bring the column of largest norm into the pivot position. */ kmax = j; for (k = j; k < n; k++) { if (rdiag[k] > rdiag[kmax]) kmax = k; } if (kmax == j) goto L40; ij = m * j; jj = m * kmax; for (i = 0; i < m; i++) { temp = a[ij]; /* [i+m*j] */ a[ij] = a[jj]; /* [i+m*kmax] */ a[jj] = temp; ij += 1; jj += 1; } rdiag[kmax] = rdiag[j]; wa[kmax] = wa[j]; k = ipvt[j]; ipvt[j] = ipvt[kmax]; ipvt[kmax] = k; L40: /* * compute the householder transformation to reduce the * j-th column of a to a multiple of the j-th unit vector. */ jj = j + m * j; ajnorm = enorm(m - j, a.GetRange(jj, m-j)); if (ajnorm == zero) goto L100; if (a[jj] < zero) ajnorm = -ajnorm; ij = jj; for (i = j; i < m; i++) { a[ij] /= ajnorm; ij += 1; /* [i+m*j] */ } a[jj] += one; /* * apply the transformation to the remaining columns * and update the norms. */ jp1 = j + 1; if (jp1 < n) { for (k = jp1; k < n; k++) { sum = zero; ij = j + m * k; jj = j + m * j; for (i = j; i < m; i++) { sum += a[jj] * a[ij]; ij += 1; /* [i+m*k] */ jj += 1; /* [i+m*j] */ } temp = sum / a[j + m * j]; ij = j + m * k; jj = j + m * j; for (i = j; i < m; i++) { a[ij] -= temp * a[jj]; ij += 1; /* [i+m*k] */ jj += 1; /* [i+m*j] */ } if ((pivot != 0) && (rdiag[k] != zero)) { temp = a[j + m * k] / rdiag[k]; temp = dmax1(zero, one - temp * temp); rdiag[k] *= Math.Sqrt(temp); temp = rdiag[k] / wa[k]; if ((p05 * temp * temp) <= MACHEP) { rdiag[k] = enorm(m - j - 1, a.GetRange(jp1+m*k, m - j - 1)); wa[k] = rdiag[k]; } } } } L100: rdiag[j] = -ajnorm; } }