1 // This code has been mechanically translated from the original FORTRAN 2 // code at http://netlib.org/minpack. 3 4 /** Authors: Lars Tandle Kyllingstad 5 Copyright: Copyright (c) 2009, Lars T. Kyllingstad. All rights reserved. 6 License: Boost Licence 1.0 7 */ 8 module scid.ports.minpack.qrfac; 9 10 11 private import std.algorithm: min, max; 12 private import std.math: sqrt; 13 14 private import scid.ports.minpack.enorm; 15 16 17 18 19 /** This subroutine uses Householder transformations with column 20 pivoting (optional) to compute a QR factorization of the 21 m by n matrix A. That is, qrfac determines an orthogonal 22 matrix Q, a permutation matrix P, and an upper trapezoidal 23 matrix R with diagonal elements of nonincreasing magnitude, 24 such that AP = QR. The Householder transformation for 25 column k, k = 1,2,...,min(m,n), is of the form 26 --- 27 t 28 i - (1/u(k)) u u 29 --- 30 where u has zeros in the first k-1 positions. The form of 31 this transformation and the method of pivoting first 32 appeared in the corresponding LINPACK subroutine. 33 34 Params: 35 36 m = a positive integer input variable set to the number 37 of rows of a. 38 39 n = a positive integer input variable set to the number 40 of columns of a. 41 42 a = an m by n array. on input a contains the matrix for 43 which the qr factorization is to be computed. on output 44 the strict upper trapezoidal part of a contains the strict 45 upper trapezoidal part of r, and the lower trapezoidal 46 part of a contains a factored form of q (the non-trivial 47 elements of the u vectors described above). 48 49 lda = a positive integer input variable not less than m 50 which specifies the leading dimension of the array a. 51 52 pivot = a logical input variable. if pivot is set true, 53 then column pivoting is enforced. if pivot is set false, 54 then no column pivoting is done. 55 56 ipvt = an integer output array of length lipvt. ipvt 57 defines the permutation matrix p such that a*p = q*r. 58 column j of p is column ipvt(j) of the identity matrix. 59 if pivot is false, ipvt is not referenced. 60 61 lipvt = a positive integer input variable. if pivot is false, 62 then lipvt may be as small as 1. if pivot is true, then 63 lipvt must be at least n. 64 65 rdiag = an output array of length n which contains the 66 diagonal elements of r. 67 68 acnorm = an output array of length n which contains the 69 norms of the corresponding columns of the input matrix a. 70 if this information is not needed, then acnorm can coincide 71 with rdiag. 72 73 wa = a work array of length n. if pivot is false, then wa 74 can coincide with rdiag. 75 */ 76 void qrfac(Real)(size_t m, size_t n, Real* a, size_t lda, 77 bool pivot, size_t* ipvt, size_t lipvt, Real* rdiag, Real* acnorm, 78 Real* wa) 79 { 80 size_t i, j, ij, ikmax, jp1, k, kmax, minmn; 81 Real ajnorm, sum, temp; 82 83 enum : Real 84 { 85 one = 1.0, 86 p05 = 0.05, 87 zero = 0.0, 88 89 // epsmch is the machine precision 90 epsmch = Real.epsilon 91 } 92 93 94 // Compute the initial column norms and initialize several arrays. 95 for (j=0; j<n; j++) 96 { 97 acnorm[j] = enorm(m, a+j*m); 98 rdiag[j] = acnorm[j]; 99 wa[j] = rdiag[j]; 100 if (pivot) ipvt[j] = j; 101 } 102 103 104 // Reduce A to R with Householder transformations. 105 minmn = min(m, n); 106 for (j=0; j<minmn; j++) 107 { 108 if (pivot) 109 { 110 // Bring the column of largest norm into the pivot position. 111 kmax = j; 112 for (k=j; k<n; k++) 113 if (rdiag[k] > rdiag[kmax]) kmax = k; 114 115 if (kmax != j) 116 { 117 for (i=0; i<m; i++) 118 { 119 ij = i + j*lda; 120 ikmax = i + kmax*lda; 121 temp = a[ij]; 122 a[ij] = a[ikmax]; 123 a[ikmax] = temp; 124 } 125 126 rdiag[kmax] = rdiag[j]; 127 wa[kmax] = wa[j]; 128 k = ipvt[j]; 129 ipvt[j] = ipvt[kmax]; 130 ipvt[kmax] = k; 131 } 132 } 133 134 135 // Compute the Householder transformation to reduce the 136 // j-th column of A to a multiple of the j-th unit vector. 137 ajnorm = enorm(m-j, a+j+j*lda); 138 if (ajnorm != zero) 139 { 140 if (a[j+j*lda] < zero) ajnorm = -ajnorm; 141 for (i=j; i<m; i++) 142 a[i+j*lda] /= ajnorm; 143 a[j+j*lda] += one; 144 145 146 // Apply the transformation to the remaining columns 147 // and update the norms. 148 jp1 = j + 1; 149 if (n >= jp1) 150 { 151 for (k=jp1; k<n; k++) 152 { 153 sum = zero; 154 for (i=j; i<m; i++) 155 sum += a[i+j*lda]*a[i+k*lda]; 156 temp = sum/a[j+j*lda]; 157 for (i=j; i<m; i++) 158 a[i+k*lda] -= temp*a[i+j*lda]; 159 160 if (pivot && rdiag[k] != zero) 161 { 162 temp = a[j+k*lda]/rdiag[k]; 163 rdiag[k] *= sqrt(max(zero, one-temp*temp)); 164 if (p05*((rdiag[k]/wa[k])^^2) <= epsmch) 165 { 166 rdiag[k] = enorm(m-j-1, a+jp1+k*lda); 167 wa[k] = rdiag[k]; 168 } 169 } 170 } 171 } 172 } 173 rdiag[j] = -ajnorm; 174 } 175 } 176 177 178 unittest { alias qrfac!(real) rqrfac; }