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