ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-4/src/math/SVD.hpp
Revision: 3509
Committed: Wed May 20 19:35:05 2009 UTC (15 years, 1 month ago) by cli2
File size: 10829 byte(s)
Log Message:
Modifications to support RMSD calculations, removing classes we aren't using.

File Contents

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