OpenMD 3.1
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
SVD.hpp
1#ifndef JAMA_SVD_H
2#define JAMA_SVD_H
3
4#include <algorithm>
5
7// for min(), max() below
8#include <cmath>
9// for abs() below
10
11using namespace OpenMD;
12using namespace std;
13
14namespace JAMA {
15 /** Singular Value Decomposition.
16 <P>
17 For an m-by-n matrix A with m >= n, the singular value decomposition is
18 an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and
19 an n-by-n orthogonal matrix V so that A = U*S*V'.
20 <P>
21 The singular values, sigma(k) = S(k,k), are ordered so that
22 sigma(0) >= sigma(1) >= ... >= sigma(n-1).
23 <P>
24 The singular value decompostion always exists, so the constructor will
25 never fail. The matrix condition number and the effective numerical
26 rank can be computed from this decomposition.
27
28 <p>
29 (Adapted from JAMA, a Java Matrix Library, developed by jointly
30 by the Mathworks and NIST; see http://math.nist.gov/javanumerics/jama).
31 */
32 template<class Real>
33 class SVD {
36 int m, n;
37
38 public:
39 SVD(const DynamicRectMatrix<Real>& Arg) {
40 m = Arg.getNRow();
41 n = Arg.getNCol();
42 int nu = min(m, n);
43 s = DynamicVector<Real>(min(m + 1, n));
44 U = DynamicRectMatrix<Real>(m, nu, Real(0));
47 DynamicVector<Real> work(m);
49
50 int wantu = 1; /* boolean */
51 int wantv = 1; /* boolean */
52 int i = 0, j = 0, k = 0;
53
54 // Reduce A to bidiagonal form, storing the diagonal elements
55 // in s and the super-diagonal elements in e.
56
57 int nct = min(m - 1, n);
58 int nrt = max(0, min(n - 2, m));
59
60 for (k = 0; k < max(nct, nrt); k++) {
61 if (k < nct) {
62 // Compute the transformation for the k-th column and
63 // place the k-th diagonal in s(k).
64 // Compute 2-norm of k-th column without under/overflow.
65 s(k) = 0;
66 for (i = k; i < m; i++) {
67 s(k) = hypot(s(k), A(i, k));
68 }
69 if (s(k) != 0.0) {
70 if (A(k, k) < 0.0) { s(k) = -s(k); }
71 for (i = k; i < m; i++) {
72 A(i, k) /= s(k);
73 }
74 A(k, k) += 1.0;
75 }
76 s(k) = -s(k);
77 }
78 for (j = k + 1; j < n; j++) {
79 if ((k < nct) && (s(k) != 0.0)) {
80 // Apply the transformation.
81
82 Real t(0.0);
83 for (i = k; i < m; i++) {
84 t += A(i, k) * A(i, j);
85 }
86 t = -t / A(k, k);
87 for (i = k; i < m; i++) {
88 A(i, j) += t * A(i, k);
89 }
90 }
91
92 // Place the k-th row of A into e for the
93 // subsequent calculation of the row transformation.
94
95 e(j) = A(k, j);
96 }
97 if (wantu & (k < nct)) {
98 // Place the transformation in U for subsequent back
99 // multiplication.
100
101 for (i = k; i < m; i++) {
102 U(i, k) = A(i, k);
103 }
104 }
105 if (k < nrt) {
106 // Compute the k-th row transformation and place the
107 // k-th super-diagonal in e(k).
108 // Compute 2-norm without under/overflow.
109 e(k) = 0;
110 for (i = k + 1; i < n; i++) {
111 e(k) = hypot(e(k), e(i));
112 }
113 if (e(k) != 0.0) {
114 if (e(k + 1) < 0.0) { e(k) = -e(k); }
115 for (i = k + 1; i < n; i++) {
116 e(i) /= e(k);
117 }
118 e(k + 1) += 1.0;
119 }
120 e(k) = -e(k);
121 if ((k + 1 < m) & (e(k) != 0.0)) {
122 // Apply the transformation.
123
124 for (i = k + 1; i < m; i++) {
125 work(i) = 0.0;
126 }
127 for (j = k + 1; j < n; j++) {
128 for (i = k + 1; i < m; i++) {
129 work(i) += e(j) * A(i, j);
130 }
131 }
132 for (j = k + 1; j < n; j++) {
133 Real t(-e(j) / e(k + 1));
134 for (i = k + 1; i < m; i++) {
135 A(i, j) += t * work(i);
136 }
137 }
138 }
139 if (wantv) {
140 // Place the transformation in V for subsequent
141 // back multiplication.
142
143 for (i = k + 1; i < n; i++) {
144 V(i, k) = e(i);
145 }
146 }
147 }
148 }
149
150 // Set up the final bidiagonal matrix or order p.
151
152 int p = min(n, m + 1);
153 if (nct < n) { s(nct) = A(nct, nct); }
154 if (m < p) { s(p - 1) = 0.0; }
155 if (nrt + 1 < p) { e(nrt) = A(nrt, p - 1); }
156 e(p - 1) = 0.0;
157
158 // If required, generate U.
159
160 if (wantu) {
161 for (j = nct; j < nu; j++) {
162 for (i = 0; i < m; i++) {
163 U(i, j) = 0.0;
164 }
165 U(j, j) = 1.0;
166 }
167 for (k = nct - 1; k >= 0; k--) {
168 if (s(k) != 0.0) {
169 for (j = k + 1; j < nu; j++) {
170 Real t(0.0);
171 for (i = k; i < m; i++) {
172 t += U(i, k) * U(i, j);
173 }
174 t = -t / U(k, k);
175 for (i = k; i < m; i++) {
176 U(i, j) += t * U(i, k);
177 }
178 }
179 for (i = k; i < m; i++) {
180 U(i, k) = -U(i, k);
181 }
182 U(k, k) = 1.0 + U(k, k);
183 for (i = 0; i < k - 1; i++) {
184 U(i, k) = 0.0;
185 }
186 } else {
187 for (i = 0; i < m; i++) {
188 U(i, k) = 0.0;
189 }
190 U(k, k) = 1.0;
191 }
192 }
193 }
194
195 // If required, generate V.
196
197 if (wantv) {
198 for (k = n - 1; k >= 0; k--) {
199 if ((k < nrt) & (e(k) != 0.0)) {
200 for (j = k + 1; j < nu; j++) {
201 Real t(0.0);
202 for (i = k + 1; i < n; i++) {
203 t += V(i, k) * V(i, j);
204 }
205 t = -t / V(k + 1, k);
206 for (i = k + 1; i < n; i++) {
207 V(i, j) += t * V(i, k);
208 }
209 }
210 }
211 for (i = 0; i < n; i++) {
212 V(i, k) = 0.0;
213 }
214 V(k, k) = 1.0;
215 }
216 }
217
218 // Main iteration loop for the singular values.
219
220 int pp = p - 1;
221 int iter = 0;
222 Real eps(pow(2.0, -52.0));
223 while (p > 0) {
224 int k = 0;
225 int kase = 0;
226
227 // Here is where a test for too many iterations would go.
228
229 // This section of the program inspects for
230 // negligible elements in the s and e arrays. On
231 // completion the variables kase and k are set as follows.
232
233 // kase = 1 if s(p) and e(k-1) are negligible and k<p
234 // kase = 2 if s(k) is negligible and k<p
235 // kase = 3 if e(k-1) is negligible, k<p, and
236 // s(k), ..., s(p) are not negligible (qr step).
237 // kase = 4 if e(p-1) is negligible (convergence).
238
239 for (k = p - 2; k >= -1; k--) {
240 if (k == -1) { break; }
241 if (abs(e(k)) <= eps * (abs(s(k)) + abs(s(k + 1)))) {
242 e(k) = 0.0;
243 break;
244 }
245 }
246 if (k == p - 2) {
247 kase = 4;
248 } else {
249 int ks;
250 for (ks = p - 1; ks >= k; ks--) {
251 if (ks == k) { break; }
252 Real t((ks != p ? abs(e(ks)) : 0.) +
253 (ks != k + 1 ? abs(e(ks - 1)) : 0.));
254 if (abs(s(ks)) <= eps * t) {
255 s(ks) = 0.0;
256 break;
257 }
258 }
259 if (ks == k) {
260 kase = 3;
261 } else if (ks == p - 1) {
262 kase = 1;
263 } else {
264 kase = 2;
265 k = ks;
266 }
267 }
268 k++;
269
270 // Perform the task indicated by kase.
271
272 switch (kase) {
273 // Deflate negligible s(p).
274
275 case 1: {
276 Real f(e(p - 2));
277 e(p - 2) = 0.0;
278 for (j = p - 2; j >= k; j--) {
279 Real t(hypot(s(j), f));
280 Real cs(s(j) / t);
281 Real sn(f / t);
282 s(j) = t;
283 if (j != k) {
284 f = -sn * e(j - 1);
285 e(j - 1) = cs * e(j - 1);
286 }
287 if (wantv) {
288 for (i = 0; i < n; i++) {
289 t = cs * V(i, j) + sn * V(i, p - 1);
290 V(i, p - 1) = -sn * V(i, j) + cs * V(i, p - 1);
291 V(i, j) = t;
292 }
293 }
294 }
295 } break;
296
297 // Split at negligible s(k).
298
299 case 2: {
300 Real f(e(k - 1));
301 e(k - 1) = 0.0;
302 for (j = k; j < p; j++) {
303 Real t(hypot(s(j), f));
304 Real cs(s(j) / t);
305 Real sn(f / t);
306 s(j) = t;
307 f = -sn * e(j);
308 e(j) = cs * e(j);
309 if (wantu) {
310 for (i = 0; i < m; i++) {
311 t = cs * U(i, j) + sn * U(i, k - 1);
312 U(i, k - 1) = -sn * U(i, j) + cs * U(i, k - 1);
313 U(i, j) = t;
314 }
315 }
316 }
317 } break;
318
319 // Perform one qr step.
320
321 case 3: {
322 // Calculate the shift.
323
324 Real scale =
325 max(max(max(max(abs(s(p - 1)), abs(s(p - 2))), abs(e(p - 2))),
326 abs(s(k))),
327 abs(e(k)));
328 Real sp = s(p - 1) / scale;
329 Real spm1 = s(p - 2) / scale;
330 Real epm1 = e(p - 2) / scale;
331 Real sk = s(k) / scale;
332 Real ek = e(k) / scale;
333 Real b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0;
334 Real c = (sp * epm1) * (sp * epm1);
335 Real shift = 0.0;
336 if ((b != 0.0) || (c != 0.0)) {
337 shift = sqrt(b * b + c);
338 if (b < 0.0) { shift = -shift; }
339 shift = c / (b + shift);
340 }
341 Real f = (sk + sp) * (sk - sp) + shift;
342 Real g = sk * ek;
343
344 // Chase zeros.
345
346 for (j = k; j < p - 1; j++) {
347 Real t = hypot(f, g);
348 Real cs = f / t;
349 Real sn = g / t;
350 if (j != k) { e(j - 1) = t; }
351 f = cs * s(j) + sn * e(j);
352 e(j) = cs * e(j) - sn * s(j);
353 g = sn * s(j + 1);
354 s(j + 1) = cs * s(j + 1);
355 if (wantv) {
356 for (i = 0; i < n; i++) {
357 t = cs * V(i, j) + sn * V(i, j + 1);
358 V(i, j + 1) = -sn * V(i, j) + cs * V(i, j + 1);
359 V(i, j) = t;
360 }
361 }
362 t = hypot(f, g);
363 cs = f / t;
364 sn = g / t;
365 s(j) = t;
366 f = cs * e(j) + sn * s(j + 1);
367 s(j + 1) = -sn * e(j) + cs * s(j + 1);
368 g = sn * e(j + 1);
369 e(j + 1) = cs * e(j + 1);
370 if (wantu && (j < m - 1)) {
371 for (i = 0; i < m; i++) {
372 t = cs * U(i, j) + sn * U(i, j + 1);
373 U(i, j + 1) = -sn * U(i, j) + cs * U(i, j + 1);
374 U(i, j) = t;
375 }
376 }
377 }
378 e(p - 2) = f;
379 iter = iter + 1;
380 } break;
381
382 // Convergence.
383
384 case 4: {
385 // Make the singular values positive.
386
387 if (s(k) <= 0.0) {
388 s(k) = (s(k) < 0.0 ? -s(k) : 0.0);
389 if (wantv) {
390 for (i = 0; i <= pp; i++) {
391 V(i, k) = -V(i, k);
392 }
393 }
394 }
395
396 // Order the singular values.
397
398 while (k < pp) {
399 if (s(k) >= s(k + 1)) { break; }
400 Real t = s(k);
401 s(k) = s(k + 1);
402 s(k + 1) = t;
403 if (wantv && (k < n - 1)) {
404 for (i = 0; i < n; i++) {
405 t = V(i, k + 1);
406 V(i, k + 1) = V(i, k);
407 V(i, k) = t;
408 }
409 }
410 if (wantu && (k < m - 1)) {
411 for (i = 0; i < m; i++) {
412 t = U(i, k + 1);
413 U(i, k + 1) = U(i, k);
414 U(i, k) = t;
415 }
416 }
417 k++;
418 }
419 iter = 0;
420 p--;
421 } break;
422 }
423 }
424 }
425
426 void getU(DynamicRectMatrix<Real>& A) {
427 int minm = min(m + 1, n);
428
429 A = DynamicRectMatrix<Real>(m, minm);
430
431 for (int i = 0; i < m; i++)
432 for (int j = 0; j < minm; j++)
433 A(i, j) = U(i, j);
434 }
435
436 /* Return the right singular vectors */
437 void getV(DynamicRectMatrix<Real>& A) { A = V; }
438
439 /** Return the one-dimensional array of singular values */
441
442 /** Return the diagonal matrix of singular values
443 @return S
444 */
446 A = DynamicRectMatrix<Real>(n, n);
447 for (int i = 0; i < n; i++) {
448 for (int j = 0; j < n; j++) {
449 A(i, j) = 0.0;
450 }
451 A(i, i) = s(i);
452 }
453 }
454
455 /** Two norm (max(S)) */
456 Real norm2() { return s(0); }
457
458 /** Two norm of condition number (max(S)/min(S)) */
459 Real cond() { return s(0) / s(min(m, n) - 1); }
460
461 /** Effective numerical matrix rank
462 @return Number of nonnegligible singular values.
463 */
464 int rank() {
465 Real eps = pow(2.0, -52.0);
466 Real tol = max(m, n) * s(0) * eps;
467 int r = 0;
468 for (int i = 0; i < s.dim(); i++) {
469 if (s(i) > tol) { r++; }
470 }
471 return r;
472 }
473 };
474} // namespace JAMA
475#endif
476// JAMA_SVD_H
Singular Value Decomposition.
Definition SVD.hpp:33
void getS(DynamicRectMatrix< Real > &A)
Return the diagonal matrix of singular values.
Definition SVD.hpp:445
int rank()
Effective numerical matrix rank.
Definition SVD.hpp:464
Real norm2()
Two norm (max(S))
Definition SVD.hpp:456
Real cond()
Two norm of condition number (max(S)/min(S))
Definition SVD.hpp:459
void getSingularValues(DynamicVector< Real > &x)
Return the one-dimensional array of singular values.
Definition SVD.hpp:440
rectangular matrix class
Dynamically-sized vector class.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.