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