/Users/lyon/j4p/src/math/linearAlgebra/EigenvalueDecomposition.java
|
1 package math.linearAlgebra;
2
3 import math.linearAlgebra.util.Maths;
4
5 /** Eigenvalues and eigenvectors of a real matrix.
6 <P>
7 If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is
8 diagonal and the eigenvector matrix V is orthogonal.
9 I.e. A = V.times(D.times(V.transpose())) and
10 V.times(V.transpose()) equals the identity matrix.
11 <P>
12 If A is not symmetric, then the eigenvalue matrix D is block diagonal
13 with the real eigenvalues in 1-by-1 blocks and any complex eigenvalues,
14 lambda + i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda]. The
15 columns of V represent the eigenvectors in the sense that A*V = V*D,
16 i.e. A.times(V) equals V.times(D). The matrix V may be badly
17 conditioned, or even singular, so the validity of the equation
18 A = V*D*inverse(V) depends upon V.cond().
19 **/
20
21 public class EigenvalueDecomposition implements java.io.Serializable {
22
23 /* ------------------------
24 Class variables
25 * ------------------------ */
26
27 /** Row and column dimension (square matrix).
28 @serial matrix dimension.
29 */
30 private int n;
31
32 /** Symmetry flag.
33 @serial internal symmetry flag.
34 */
35 private boolean issymmetric;
36
37 /** Arrays for internal storage of eigenvalues.
38 @serial internal storage of eigenvalues.
39 */
40 private double[] d, e;
41
42 /** Array for internal storage of eigenvectors.
43 @serial internal storage of eigenvectors.
44 */
45 private double[][] V;
46
47 /** Array for internal storage of nonsymmetric Hessenberg form.
48 @serial internal storage of nonsymmetric Hessenberg form.
49 */
50 private double[][] H;
51
52 /** Working storage for nonsymmetric algorithm.
53 @serial working storage for nonsymmetric algorithm.
54 */
55 private double[] ort;
56
57 /* ------------------------
58 Private Methods
59 * ------------------------ */
60
61 // Symmetric Householder reduction to tridiagonal form.
62
63 private void tred2() {
64
65 // This is derived from the Algol procedures tred2 by
66 // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
67 // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
68 // Fortran subroutine in EISPACK.
69
70 for (int j = 0; j < n; j++) {
71 d[j] = V[n - 1][j];
72 }
73
74 // Householder reduction to tridiagonal form.
75
76 for (int i = n - 1; i > 0; i--) {
77
78 // Scale to avoid under/overflow.
79
80 double scale = 0.0;
81 double h = 0.0;
82 for (int k = 0; k < i; k++) {
83 scale = scale + Math.abs(d[k]);
84 }
85 if (scale == 0.0) {
86 e[i] = d[i - 1];
87 for (int j = 0; j < i; j++) {
88 d[j] = V[i - 1][j];
89 V[i][j] = 0.0;
90 V[j][i] = 0.0;
91 }
92 } else {
93
94 // Generate Householder vector.
95
96 for (int k = 0; k < i; k++) {
97 d[k] /= scale;
98 h += d[k] * d[k];
99 }
100 double f = d[i - 1];
101 double g = Math.sqrt(h);
102 if (f > 0) {
103 g = -g;
104 }
105 e[i] = scale * g;
106 h = h - f * g;
107 d[i - 1] = f - g;
108 for (int j = 0; j < i; j++) {
109 e[j] = 0.0;
110 }
111
112 // Apply similarity transformation to remaining columns.
113
114 for (int j = 0; j < i; j++) {
115 f = d[j];
116 V[j][i] = f;
117 g = e[j] + V[j][j] * f;
118 for (int k = j + 1; k <= i - 1; k++) {
119 g += V[k][j] * d[k];
120 e[k] += V[k][j] * f;
121 }
122 e[j] = g;
123 }
124 f = 0.0;
125 for (int j = 0; j < i; j++) {
126 e[j] /= h;
127 f += e[j] * d[j];
128 }
129 double hh = f / (h + h);
130 for (int j = 0; j < i; j++) {
131 e[j] -= hh * d[j];
132 }
133 for (int j = 0; j < i; j++) {
134 f = d[j];
135 g = e[j];
136 for (int k = j; k <= i - 1; k++) {
137 V[k][j] -= (f * e[k] + g * d[k]);
138 }
139 d[j] = V[i - 1][j];
140 V[i][j] = 0.0;
141 }
142 }
143 d[i] = h;
144 }
145
146 // Accumulate transformations.
147
148 for (int i = 0; i < n - 1; i++) {
149 V[n - 1][i] = V[i][i];
150 V[i][i] = 1.0;
151 double h = d[i + 1];
152 if (h != 0.0) {
153 for (int k = 0; k <= i; k++) {
154 d[k] = V[k][i + 1] / h;
155 }
156 for (int j = 0; j <= i; j++) {
157 double g = 0.0;
158 for (int k = 0; k <= i; k++) {
159 g += V[k][i + 1] * V[k][j];
160 }
161 for (int k = 0; k <= i; k++) {
162 V[k][j] -= g * d[k];
163 }
164 }
165 }
166 for (int k = 0; k <= i; k++) {
167 V[k][i + 1] = 0.0;
168 }
169 }
170 for (int j = 0; j < n; j++) {
171 d[j] = V[n - 1][j];
172 V[n - 1][j] = 0.0;
173 }
174 V[n - 1][n - 1] = 1.0;
175 e[0] = 0.0;
176 }
177
178 // Symmetric tridiagonal QL algorithm.
179
180 private void tql2() {
181
182 // This is derived from the Algol procedures tql2, by
183 // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
184 // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
185 // Fortran subroutine in EISPACK.
186
187 for (int i = 1; i < n; i++) {
188 e[i - 1] = e[i];
189 }
190 e[n - 1] = 0.0;
191
192 double f = 0.0;
193 double tst1 = 0.0;
194 double eps = Math.pow(2.0, -52.0);
195 for (int l = 0; l < n; l++) {
196
197 // Find small subdiagonal element
198
199 tst1 = Math.max(tst1, Math.abs(d[l]) + Math.abs(e[l]));
200 int m = l;
201 while (m < n) {
202 if (Math.abs(e[m]) <= eps * tst1) {
203 break;
204 }
205 m++;
206 }
207
208 // If m == l, d[l] is an eigenvalue,
209 // otherwise, iterate.
210
211 if (m > l) {
212 int iter = 0;
213 do {
214 iter = iter + 1; // (Could check iteration count here.)
215
216 // Compute implicit shift
217
218 double g = d[l];
219 double p = (d[l + 1] - g) / (2.0 * e[l]);
220 double r = Maths.hypot(p, 1.0);
221 if (p < 0) {
222 r = -r;
223 }
224 d[l] = e[l] / (p + r);
225 d[l + 1] = e[l] * (p + r);
226 double dl1 = d[l + 1];
227 double h = g - d[l];
228 for (int i = l + 2; i < n; i++) {
229 d[i] -= h;
230 }
231 f = f + h;
232
233 // Implicit QL transformation.
234
235 p = d[m];
236 double c = 1.0;
237 double c2 = c;
238 double c3 = c;
239 double el1 = e[l + 1];
240 double s = 0.0;
241 double s2 = 0.0;
242 for (int i = m - 1; i >= l; i--) {
243 c3 = c2;
244 c2 = c;
245 s2 = s;
246 g = c * e[i];
247 h = c * p;
248 r = Maths.hypot(p, e[i]);
249 e[i + 1] = s * r;
250 s = e[i] / r;
251 c = p / r;
252 p = c * d[i] - s * g;
253 d[i + 1] = h + s * (c * g + s * d[i]);
254
255 // Accumulate transformation.
256
257 for (int k = 0; k < n; k++) {
258 h = V[k][i + 1];
259 V[k][i + 1] = s * V[k][i] + c * h;
260 V[k][i] = c * V[k][i] - s * h;
261 }
262 }
263 p = -s * s2 * c3 * el1 * e[l] / dl1;
264 e[l] = s * p;
265 d[l] = c * p;
266
267 // Check for convergence.
268
269 } while (Math.abs(e[l]) > eps * tst1);
270 }
271 d[l] = d[l] + f;
272 e[l] = 0.0;
273 }
274
275 // Sort eigenvalues and corresponding vectors.
276
277 for (int i = 0; i < n - 1; i++) {
278 int k = i;
279 double p = d[i];
280 for (int j = i + 1; j < n; j++) {
281 if (d[j] < p) {
282 k = j;
283 p = d[j];
284 }
285 }
286 if (k != i) {
287 d[k] = d[i];
288 d[i] = p;
289 for (int j = 0; j < n; j++) {
290 p = V[j][i];
291 V[j][i] = V[j][k];
292 V[j][k] = p;
293 }
294 }
295 }
296 }
297
298 // Nonsymmetric reduction to Hessenberg form.
299
300 private void orthes() {
301
302 // This is derived from the Algol procedures orthes and ortran,
303 // by Martin and Wilkinson, Handbook for Auto. Comp.,
304 // Vol.ii-Linear Algebra, and the corresponding
305 // Fortran subroutines in EISPACK.
306
307 int low = 0;
308 int high = n - 1;
309
310 for (int m = low + 1; m <= high - 1; m++) {
311
312 // Scale column.
313
314 double scale = 0.0;
315 for (int i = m; i <= high; i++) {
316 scale = scale + Math.abs(H[i][m - 1]);
317 }
318 if (scale != 0.0) {
319
320 // Compute Householder transformation.
321
322 double h = 0.0;
323 for (int i = high; i >= m; i--) {
324 ort[i] = H[i][m - 1] / scale;
325 h += ort[i] * ort[i];
326 }
327 double g = Math.sqrt(h);
328 if (ort[m] > 0) {
329 g = -g;
330 }
331 h = h - ort[m] * g;
332 ort[m] = ort[m] - g;
333
334 // Apply Householder similarity transformation
335 // H = (I-u*u'/h)*H*(I-u*u')/h)
336
337 for (int j = m; j < n; j++) {
338 double f = 0.0;
339 for (int i = high; i >= m; i--) {
340 f += ort[i] * H[i][j];
341 }
342 f = f / h;
343 for (int i = m; i <= high; i++) {
344 H[i][j] -= f * ort[i];
345 }
346 }
347
348 for (int i = 0; i <= high; i++) {
349 double f = 0.0;
350 for (int j = high; j >= m; j--) {
351 f += ort[j] * H[i][j];
352 }
353 f = f / h;
354 for (int j = m; j <= high; j++) {
355 H[i][j] -= f * ort[j];
356 }
357 }
358 ort[m] = scale * ort[m];
359 H[m][m - 1] = scale * g;
360 }
361 }
362
363 // Accumulate transformations (Algol's ortran).
364
365 for (int i = 0; i < n; i++) {
366 for (int j = 0; j < n; j++) {
367 V[i][j] = (i == j ? 1.0 : 0.0);
368 }
369 }
370
371 for (int m = high - 1; m >= low + 1; m--) {
372 if (H[m][m - 1] != 0.0) {
373 for (int i = m + 1; i <= high; i++) {
374 ort[i] = H[i][m - 1];
375 }
376 for (int j = m; j <= high; j++) {
377 double g = 0.0;
378 for (int i = m; i <= high; i++) {
379 g += ort[i] * V[i][j];
380 }
381 // Double division avoids possible underflow
382 g = (g / ort[m]) / H[m][m - 1];
383 for (int i = m; i <= high; i++) {
384 V[i][j] += g * ort[i];
385 }
386 }
387 }
388 }
389 }
390
391
392 // Complex scalar division.
393
394 private transient double cdivr, cdivi;
395
396 private void cdiv(double xr, double xi, double yr, double yi) {
397 double r,d;
398 if (Math.abs(yr) > Math.abs(yi)) {
399 r = yi / yr;
400 d = yr + r * yi;
401 cdivr = (xr + r * xi) / d;
402 cdivi = (xi - r * xr) / d;
403 } else {
404 r = yr / yi;
405 d = yi + r * yr;
406 cdivr = (r * xr + xi) / d;
407 cdivi = (r * xi - xr) / d;
408 }
409 }
410
411
412 // Nonsymmetric reduction from Hessenberg to real Schur form.
413
414 private void hqr2() {
415
416 // This is derived from the Algol procedure hqr2,
417 // by Martin and Wilkinson, Handbook for Auto. Comp.,
418 // Vol.ii-Linear Algebra, and the corresponding
419 // Fortran subroutine in EISPACK.
420
421 // Initialize
422
423 int nn = this.n;
424 int n = nn - 1;
425 int low = 0;
426 int high = nn - 1;
427 double eps = Math.pow(2.0, -52.0);
428 double exshift = 0.0;
429 double p = 0,q = 0,r = 0,s = 0,z = 0,t,w,x,y;
430
431 // Store roots isolated by balanc and compute matrix norm
432
433 double norm = 0.0;
434 for (int i = 0; i < nn; i++) {
435 if (i < low | i > high) {
436 d[i] = H[i][i];
437 e[i] = 0.0;
438 }
439 for (int j = Math.max(i - 1, 0); j < nn; j++) {
440 norm = norm + Math.abs(H[i][j]);
441 }
442 }
443
444 // Outer loop over eigenvalue index
445
446 int iter = 0;
447 while (n >= low) {
448
449 // Look for single small sub-diagonal element
450
451 int l = n;
452 while (l > low) {
453 s = Math.abs(H[l - 1][l - 1]) + Math.abs(H[l][l]);
454 if (s == 0.0) {
455 s = norm;
456 }
457 if (Math.abs(H[l][l - 1]) < eps * s) {
458 break;
459 }
460 l--;
461 }
462
463 // Check for convergence
464 // One root found
465
466 if (l == n) {
467 H[n][n] = H[n][n] + exshift;
468 d[n] = H[n][n];
469 e[n] = 0.0;
470 n--;
471 iter = 0;
472
473 // Two roots found
474
475 } else if (l == n - 1) {
476 w = H[n][n - 1] * H[n - 1][n];
477 p = (H[n - 1][n - 1] - H[n][n]) / 2.0;
478 q = p * p + w;
479 z = Math.sqrt(Math.abs(q));
480 H[n][n] = H[n][n] + exshift;
481 H[n - 1][n - 1] = H[n - 1][n - 1] + exshift;
482 x = H[n][n];
483
484 // Real pair
485
486 if (q >= 0) {
487 if (p >= 0) {
488 z = p + z;
489 } else {
490 z = p - z;
491 }
492 d[n - 1] = x + z;
493 d[n] = d[n - 1];
494 if (z != 0.0) {
495 d[n] = x - w / z;
496 }
497 e[n - 1] = 0.0;
498 e[n] = 0.0;
499 x = H[n][n - 1];
500 s = Math.abs(x) + Math.abs(z);
501 p = x / s;
502 q = z / s;
503 r = Math.sqrt(p * p + q * q);
504 p = p / r;
505 q = q / r;
506
507 // Row modification
508
509 for (int j = n - 1; j < nn; j++) {
510 z = H[n - 1][j];
511 H[n - 1][j] = q * z + p * H[n][j];
512 H[n][j] = q * H[n][j] - p * z;
513 }
514
515 // Column modification
516
517 for (int i = 0; i <= n; i++) {
518 z = H[i][n - 1];
519 H[i][n - 1] = q * z + p * H[i][n];
520 H[i][n] = q * H[i][n] - p * z;
521 }
522
523 // Accumulate transformations
524
525 for (int i = low; i <= high; i++) {
526 z = V[i][n - 1];
527 V[i][n - 1] = q * z + p * V[i][n];
528 V[i][n] = q * V[i][n] - p * z;
529 }
530
531 // Complex pair
532
533 } else {
534 d[n - 1] = x + p;
535 d[n] = x + p;
536 e[n - 1] = z;
537 e[n] = -z;
538 }
539 n = n - 2;
540 iter = 0;
541
542 // No convergence yet
543
544 } else {
545
546 // Form shift
547
548 x = H[n][n];
549 y = 0.0;
550 w = 0.0;
551 if (l < n) {
552 y = H[n - 1][n - 1];
553 w = H[n][n - 1] * H[n - 1][n];
554 }
555
556 // Wilkinson's original ad hoc shift
557
558 if (iter == 10) {
559 exshift += x;
560 for (int i = low; i <= n; i++) {
561 H[i][i] -= x;
562 }
563 s = Math.abs(H[n][n - 1]) + Math.abs(H[n - 1][n - 2]);
564 x = y = 0.75 * s;
565 w = -0.4375 * s * s;
566 }
567
568 // MATLAB's new ad hoc shift
569
570 if (iter == 30) {
571 s = (y - x) / 2.0;
572 s = s * s + w;
573 if (s > 0) {
574 s = Math.sqrt(s);
575 if (y < x) {
576 s = -s;
577 }
578 s = x - w / ((y - x) / 2.0 + s);
579 for (int i = low; i <= n; i++) {
580 H[i][i] -= s;
581 }
582 exshift += s;
583 x = y = w = 0.964;
584 }
585 }
586
587 iter = iter + 1; // (Could check iteration count here.)
588
589 // Look for two consecutive small sub-diagonal elements
590
591 int m = n - 2;
592 while (m >= l) {
593 z = H[m][m];
594 r = x - z;
595 s = y - z;
596 p = (r * s - w) / H[m + 1][m] + H[m][m + 1];
597 q = H[m + 1][m + 1] - z - r - s;
598 r = H[m + 2][m + 1];
599 s = Math.abs(p) + Math.abs(q) + Math.abs(r);
600 p = p / s;
601 q = q / s;
602 r = r / s;
603 if (m == l) {
604 break;
605 }
606 if (Math.abs(H[m][m - 1]) * (Math.abs(q) + Math.abs(r)) <
607 eps * (Math.abs(p) * (Math.abs(H[m - 1][m - 1]) + Math.abs(z) +
608 Math.abs(H[m + 1][m + 1])))) {
609 break;
610 }
611 m--;
612 }
613
614 for (int i = m + 2; i <= n; i++) {
615 H[i][i - 2] = 0.0;
616 if (i > m + 2) {
617 H[i][i - 3] = 0.0;
618 }
619 }
620
621 // Double QR step involving rows l:n and columns m:n
622
623 for (int k = m; k <= n - 1; k++) {
624 boolean notlast = (k != n - 1);
625 if (k != m) {
626 p = H[k][k - 1];
627 q = H[k + 1][k - 1];
628 r = (notlast ? H[k + 2][k - 1] : 0.0);
629 x = Math.abs(p) + Math.abs(q) + Math.abs(r);
630 if (x != 0.0) {
631 p = p / x;
632 q = q / x;
633 r = r / x;
634 }
635 }
636 if (x == 0.0) {
637 break;
638 }
639 s = Math.sqrt(p * p + q * q + r * r);
640 if (p < 0) {
641 s = -s;
642 }
643 if (s != 0) {
644 if (k != m) {
645 H[k][k - 1] = -s * x;
646 } else if (l != m) {
647 H[k][k - 1] = -H[k][k - 1];
648 }
649 p = p + s;
650 x = p / s;
651 y = q / s;
652 z = r / s;
653 q = q / p;
654 r = r / p;
655
656 // Row modification
657
658 for (int j = k; j < nn; j++) {
659 p = H[k][j] + q * H[k + 1][j];
660 if (notlast) {
661 p = p + r * H[k + 2][j];
662 H[k + 2][j] = H[k + 2][j] - p * z;
663 }
664 H[k][j] = H[k][j] - p * x;
665 H[k + 1][j] = H[k + 1][j] - p * y;
666 }
667
668 // Column modification
669
670 for (int i = 0; i <= Math.min(n, k + 3); i++) {
671 p = x * H[i][k] + y * H[i][k + 1];
672 if (notlast) {
673 p = p + z * H[i][k + 2];
674 H[i][k + 2] = H[i][k + 2] - p * r;
675 }
676 H[i][k] = H[i][k] - p;
677 H[i][k + 1] = H[i][k + 1] - p * q;
678 }
679
680 // Accumulate transformations
681
682 for (int i = low; i <= high; i++) {
683 p = x * V[i][k] + y * V[i][k + 1];
684 if (notlast) {
685 p = p + z * V[i][k + 2];
686 V[i][k + 2] = V[i][k + 2] - p * r;
687 }
688 V[i][k] = V[i][k] - p;
689 V[i][k + 1] = V[i][k + 1] - p * q;
690 }
691 } // (s != 0)
692 } // k loop
693 } // check convergence
694 } // while (n >= low)
695
696 // Backsubstitute to find vectors of upper triangular form
697
698 if (norm == 0.0) {
699 return;
700 }
701
702 for (n = nn - 1; n >= 0; n--) {
703 p = d[n];
704 q = e[n];
705
706 // Real vector
707
708 if (q == 0) {
709 int l = n;
710 H[n][n] = 1.0;
711 for (int i = n - 1; i >= 0; i--) {
712 w = H[i][i] - p;
713 r = 0.0;
714 for (int j = l; j <= n; j++) {
715 r = r + H[i][j] * H[j][n];
716 }
717 if (e[i] < 0.0) {
718 z = w;
719 s = r;
720 } else {
721 l = i;
722 if (e[i] == 0.0) {
723 if (w != 0.0) {
724 H[i][n] = -r / w;
725 } else {
726 H[i][n] = -r / (eps * norm);
727 }
728
729 // Solve real equations
730
731 } else {
732 x = H[i][i + 1];
733 y = H[i + 1][i];
734 q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
735 t = (x * s - z * r) / q;
736 H[i][n] = t;
737 if (Math.abs(x) > Math.abs(z)) {
738 H[i + 1][n] = (-r - w * t) / x;
739 } else {
740 H[i + 1][n] = (-s - y * t) / z;
741 }
742 }
743
744 // Overflow control
745
746 t = Math.abs(H[i][n]);
747 if ((eps * t) * t > 1) {
748 for (int j = i; j <= n; j++) {
749 H[j][n] = H[j][n] / t;
750 }
751 }
752 }
753 }
754
755 // Complex vector
756
757 } else if (q < 0) {
758 int l = n - 1;
759
760 // Last vector component imaginary so matrix is triangular
761
762 if (Math.abs(H[n][n - 1]) > Math.abs(H[n - 1][n])) {
763 H[n - 1][n - 1] = q / H[n][n - 1];
764 H[n - 1][n] = -(H[n][n] - p) / H[n][n - 1];
765 } else {
766 cdiv(0.0, -H[n - 1][n], H[n - 1][n - 1] - p, q);
767 H[n - 1][n - 1] = cdivr;
768 H[n - 1][n] = cdivi;
769 }
770 H[n][n - 1] = 0.0;
771 H[n][n] = 1.0;
772 for (int i = n - 2; i >= 0; i--) {
773 double ra,sa,vr,vi;
774 ra = 0.0;
775 sa = 0.0;
776 for (int j = l; j <= n; j++) {
777 ra = ra + H[i][j] * H[j][n - 1];
778 sa = sa + H[i][j] * H[j][n];
779 }
780 w = H[i][i] - p;
781
782 if (e[i] < 0.0) {
783 z = w;
784 r = ra;
785 s = sa;
786 } else {
787 l = i;
788 if (e[i] == 0) {
789 cdiv(-ra, -sa, w, q);
790 H[i][n - 1] = cdivr;
791 H[i][n] = cdivi;
792 } else {
793
794 // Solve complex equations
795
796 x = H[i][i + 1];
797 y = H[i + 1][i];
798 vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
799 vi = (d[i] - p) * 2.0 * q;
800 if (vr == 0.0 & vi == 0.0) {
801 vr = eps * norm * (Math.abs(w) + Math.abs(q) +
802 Math.abs(x) + Math.abs(y) + Math.abs(z));
803 }
804 cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi);
805 H[i][n - 1] = cdivr;
806 H[i][n] = cdivi;
807 if (Math.abs(x) > (Math.abs(z) + Math.abs(q))) {
808 H[i + 1][n - 1] = (-ra - w * H[i][n - 1] + q * H[i][n]) / x;
809 H[i + 1][n] = (-sa - w * H[i][n] - q * H[i][n - 1]) / x;
810 } else {
811 cdiv(-r - y * H[i][n - 1], -s - y * H[i][n], z, q);
812 H[i + 1][n - 1] = cdivr;
813 H[i + 1][n] = cdivi;
814 }
815 }
816
817 // Overflow control
818
819 t = Math.max(Math.abs(H[i][n - 1]), Math.abs(H[i][n]));
820 if ((eps * t) * t > 1) {
821 for (int j = i; j <= n; j++) {
822 H[j][n - 1] = H[j][n - 1] / t;
823 H[j][n] = H[j][n] / t;
824 }
825 }
826 }
827 }
828 }
829 }
830
831 // Vectors of isolated roots
832
833 for (int i = 0; i < nn; i++) {
834 if (i < low | i > high) {
835 for (int j = i; j < nn; j++) {
836 V[i][j] = H[i][j];
837 }
838 }
839 }
840
841 // Back transformation to get eigenvectors of original matrix
842
843 for (int j = nn - 1; j >= low; j--) {
844 for (int i = low; i <= high; i++) {
845 z = 0.0;
846 for (int k = low; k <= Math.min(j, high); k++) {
847 z = z + V[i][k] * H[k][j];
848 }
849 V[i][j] = z;
850 }
851 }
852 }
853
854
855 /* ------------------------
856 Constructor
857 * ------------------------ */
858
859 /** Check for symmetry, then construct the eigenvalue decomposition
860 @param A Square matrix
861 @return Structure to access D and V.
862 */
863
864 public EigenvalueDecomposition(Matrix Arg) {
865 double[][] A = Arg.getArray();
866 n = Arg.getColumnDimension();
867 V = new double[n][n];
868 d = new double[n];
869 e = new double[n];
870
871 issymmetric = true;
872 for (int j = 0; (j < n) & issymmetric; j++) {
873 for (int i = 0; (i < n) & issymmetric; i++) {
874 issymmetric = (A[i][j] == A[j][i]);
875 }
876 }
877
878 if (issymmetric) {
879 for (int i = 0; i < n; i++) {
880 for (int j = 0; j < n; j++) {
881 V[i][j] = A[i][j];
882 }
883 }
884
885 // Tridiagonalize.
886 tred2();
887
888 // Diagonalize.
889 tql2();
890
891 } else {
892 H = new double[n][n];
893 ort = new double[n];
894
895 for (int j = 0; j < n; j++) {
896 for (int i = 0; i < n; i++) {
897 H[i][j] = A[i][j];
898 }
899 }
900
901 // Reduce to Hessenberg form.
902 orthes();
903
904 // Reduce Hessenberg to real Schur form.
905 hqr2();
906 }
907 }
908
909 /* ------------------------
910 Public Methods
911 * ------------------------ */
912
913 /** Return the eigenvector matrix
914 @return V
915 */
916
917 public Matrix getV() {
918 return new Matrix(V, n, n);
919 }
920
921 /** Return the real parts of the eigenvalues
922 @return real(diag(D))
923 */
924
925 public double[] getRealEigenvalues() {
926 return d;
927 }
928
929 /** Return the imaginary parts of the eigenvalues
930 @return imag(diag(D))
931 */
932
933 public double[] getImagEigenvalues() {
934 return e;
935 }
936
937 /** Return the block diagonal eigenvalue matrix
938 @return D
939 */
940
941 public Matrix getD() {
942 Matrix X = new Matrix(n, n);
943 double[][] D = X.getArray();
944 for (int i = 0; i < n; i++) {
945 for (int j = 0; j < n; j++) {
946 D[i][j] = 0.0;
947 }
948 D[i][i] = d[i];
949 if (e[i] > 0) {
950 D[i][i + 1] = e[i];
951 } else if (e[i] < 0) {
952 D[i][i - 1] = e[i];
953 }
954 }
955 return X;
956 }
957 }
958