ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/math/jama_qr.hpp
Revision: 1336
Committed: Tue Apr 7 20:16:26 2009 UTC (16 years ago) by gezelter
File size: 7361 byte(s)
Log Message:
adding jama and tnt libraries for various linear algebra routines

File Contents

# Content
1 #ifndef JAMA_QR_H
2 #define JAMA_QR_H
3
4 #include "tnt_array1d.hpp"
5 #include "tnt_array2d.hpp"
6 #include "tnt_math_utils.hpp"
7
8 namespace JAMA
9 {
10
11 /**
12 <p>
13 Classical QR Decompisition:
14 for an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n
15 orthogonal matrix Q and an n-by-n upper triangular matrix R so that
16 A = Q*R.
17 <P>
18 The QR decompostion always exists, even if the matrix does not have
19 full rank, so the constructor will never fail. The primary use of the
20 QR decomposition is in the least squares solution of nonsquare systems
21 of simultaneous linear equations. This will fail if isFullRank()
22 returns 0 (false).
23
24 <p>
25 The Q and R factors can be retrived via the getQ() and getR()
26 methods. Furthermore, a solve() method is provided to find the
27 least squares solution of Ax=b using the QR factors.
28
29 <p>
30 (Adapted from JAMA, a Java Matrix Library, developed by jointly
31 by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
32 */
33
34 template <class Real>
35 class QR {
36
37
38 /** Array for internal storage of decomposition.
39 @serial internal array storage.
40 */
41
42 TNT::Array2D<Real> QR_;
43
44 /** Row and column dimensions.
45 @serial column dimension.
46 @serial row dimension.
47 */
48 int m, n;
49
50 /** Array for internal storage of diagonal of R.
51 @serial diagonal of R.
52 */
53 TNT::Array1D<Real> Rdiag;
54
55
56 public:
57
58 /**
59 Create a QR factorization object for A.
60
61 @param A rectangular (m>=n) matrix.
62 */
63 QR(const TNT::Array2D<Real> &A) /* constructor */
64 {
65 QR_ = A.copy();
66 m = A.dim1();
67 n = A.dim2();
68 Rdiag = TNT::Array1D<Real>(n);
69 int i=0, j=0, k=0;
70
71 // Main loop.
72 for (k = 0; k < n; k++) {
73 // Compute 2-norm of k-th column without under/overflow.
74 Real nrm = 0;
75 for (i = k; i < m; i++) {
76 nrm = TNT::hypot(nrm,QR_[i][k]);
77 }
78
79 if (nrm != 0.0) {
80 // Form k-th Householder vector.
81 if (QR_[k][k] < 0) {
82 nrm = -nrm;
83 }
84 for (i = k; i < m; i++) {
85 QR_[i][k] /= nrm;
86 }
87 QR_[k][k] += 1.0;
88
89 // Apply transformation to remaining columns.
90 for (j = k+1; j < n; j++) {
91 Real s = 0.0;
92 for (i = k; i < m; i++) {
93 s += QR_[i][k]*QR_[i][j];
94 }
95 s = -s/QR_[k][k];
96 for (i = k; i < m; i++) {
97 QR_[i][j] += s*QR_[i][k];
98 }
99 }
100 }
101 Rdiag[k] = -nrm;
102 }
103 }
104
105
106 /**
107 Flag to denote the matrix is of full rank.
108
109 @return 1 if matrix is full rank, 0 otherwise.
110 */
111 int isFullRank() const
112 {
113 for (int j = 0; j < n; j++)
114 {
115 if (Rdiag[j] == 0)
116 return 0;
117 }
118 return 1;
119 }
120
121
122
123
124 /**
125
126 Retreive the Householder vectors from QR factorization
127 @returns lower trapezoidal matrix whose columns define the reflections
128 */
129
130 TNT::Array2D<Real> getHouseholder (void) const
131 {
132 TNT::Array2D<Real> H(m,n);
133
134 /* note: H is completely filled in by algorithm, so
135 initializaiton of H is not necessary.
136 */
137 for (int i = 0; i < m; i++)
138 {
139 for (int j = 0; j < n; j++)
140 {
141 if (i >= j) {
142 H[i][j] = QR_[i][j];
143 } else {
144 H[i][j] = 0.0;
145 }
146 }
147 }
148 return H;
149 }
150
151
152
153 /** Return the upper triangular factor, R, of the QR factorization
154 @return R
155 */
156
157 TNT::Array2D<Real> getR() const
158 {
159 TNT::Array2D<Real> R(n,n);
160 for (int i = 0; i < n; i++) {
161 for (int j = 0; j < n; j++) {
162 if (i < j) {
163 R[i][j] = QR_[i][j];
164 } else if (i == j) {
165 R[i][j] = Rdiag[i];
166 } else {
167 R[i][j] = 0.0;
168 }
169 }
170 }
171 return R;
172 }
173
174
175
176
177
178 /**
179 Generate and return the (economy-sized) orthogonal factor
180 @param Q the (ecnomy-sized) orthogonal factor (Q*R=A).
181 */
182
183 TNT::Array2D<Real> getQ() const
184 {
185 int i=0, j=0, k=0;
186
187 TNT::Array2D<Real> Q(m,n);
188 for (k = n-1; k >= 0; k--) {
189 for (i = 0; i < m; i++) {
190 Q[i][k] = 0.0;
191 }
192 Q[k][k] = 1.0;
193 for (j = k; j < n; j++) {
194 if (QR_[k][k] != 0) {
195 Real s = 0.0;
196 for (i = k; i < m; i++) {
197 s += QR_[i][k]*Q[i][j];
198 }
199 s = -s/QR_[k][k];
200 for (i = k; i < m; i++) {
201 Q[i][j] += s*QR_[i][k];
202 }
203 }
204 }
205 }
206 return Q;
207 }
208
209
210 /** Least squares solution of A*x = b
211 @param B m-length array (vector).
212 @return x n-length array (vector) that minimizes the two norm of Q*R*X-B.
213 If B is non-conformant, or if QR.isFullRank() is false,
214 the routine returns a null (0-length) vector.
215 */
216
217 TNT::Array1D<Real> solve(const TNT::Array1D<Real> &b) const
218 {
219 if (b.dim1() != m) /* arrays must be conformant */
220 return TNT::Array1D<Real>();
221
222 if ( !isFullRank() ) /* matrix is rank deficient */
223 {
224 return TNT::Array1D<Real>();
225 }
226
227 TNT::Array1D<Real> x = b.copy();
228
229 // Compute Y = transpose(Q)*b
230 for (int k = 0; k < n; k++)
231 {
232 Real s = 0.0;
233 for (int i = k; i < m; i++)
234 {
235 s += QR_[i][k]*x[i];
236 }
237 s = -s/QR_[k][k];
238 for (int i = k; i < m; i++)
239 {
240 x[i] += s*QR_[i][k];
241 }
242 }
243 // Solve R*X = Y;
244 for (int k = n-1; k >= 0; k--)
245 {
246 x[k] /= Rdiag[k];
247 for (int i = 0; i < k; i++) {
248 x[i] -= x[k]*QR_[i][k];
249 }
250 }
251
252
253 /* return n x nx portion of X */
254 TNT::Array1D<Real> x_(n);
255 for (int i=0; i<n; i++)
256 x_[i] = x[i];
257
258 return x_;
259 }
260
261 /** Least squares solution of A*X = B
262 @param B m x k Array (must conform).
263 @return X n x k Array that minimizes the two norm of Q*R*X-B. If
264 B is non-conformant, or if QR.isFullRank() is false,
265 the routine returns a null (0x0) array.
266 */
267
268 TNT::Array2D<Real> solve(const TNT::Array2D<Real> &B) const
269 {
270 if (B.dim1() != m) /* arrays must be conformant */
271 return TNT::Array2D<Real>(0,0);
272
273 if ( !isFullRank() ) /* matrix is rank deficient */
274 {
275 return TNT::Array2D<Real>(0,0);
276 }
277
278 int nx = B.dim2();
279 TNT::Array2D<Real> X = B.copy();
280 int i=0, j=0, k=0;
281
282 // Compute Y = transpose(Q)*B
283 for (k = 0; k < n; k++) {
284 for (j = 0; j < nx; j++) {
285 Real s = 0.0;
286 for (i = k; i < m; i++) {
287 s += QR_[i][k]*X[i][j];
288 }
289 s = -s/QR_[k][k];
290 for (i = k; i < m; i++) {
291 X[i][j] += s*QR_[i][k];
292 }
293 }
294 }
295 // Solve R*X = Y;
296 for (k = n-1; k >= 0; k--) {
297 for (j = 0; j < nx; j++) {
298 X[k][j] /= Rdiag[k];
299 }
300 for (i = 0; i < k; i++) {
301 for (j = 0; j < nx; j++) {
302 X[i][j] -= X[k][j]*QR_[i][k];
303 }
304 }
305 }
306
307
308 /* return n x nx portion of X */
309 TNT::Array2D<Real> X_(n,nx);
310 for (i=0; i<n; i++)
311 for (j=0; j<nx; j++)
312 X_[i][j] = X[i][j];
313
314 return X_;
315 }
316
317
318 };
319
320
321 }
322 // namespace JAMA
323
324 #endif
325 // JAMA_QR__H
326