1 /*
2  * This file is part of ELKI:
3  * Environment for Developing KDD-Applications Supported by Index-Structures
4  *
5  * Copyright (C) 2018
6  * ELKI Development Team
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Affero General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Affero General Public License for more details.
17  *
18  * You should have received a copy of the GNU Affero General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 package de.lmu.ifi.dbs.elki.math.linearalgebra;
22 
23 import static java.lang.Math.abs;
24 import static java.lang.Math.max;
25 
26 import java.util.Arrays;
27 
28 import net.jafama.FastMath;
29 
30 /**
31  * Eigenvalues and eigenvectors of a real matrix.
32  * <p>
33  * If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is diagonal
34  * and the eigenvector matrix V is orthogonal. I.e. A =
35  * V.times(D.timesTranspose(V)) and V.timesTranspose(V) equals the identity
36  * matrix.
37  * <p>
38  * If A is not symmetric, then the eigenvalue matrix D is block diagonal with
39  * the real eigenvalues in 1-by-1 blocks and any complex eigenvalues, lambda +
40  * i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda]. The columns of V represent
41  * the eigenvectors in the sense that A*V = V*D, i.e. A.times(V) equals
42  * V.times(D). The matrix V may be badly conditioned, or even singular, so the
43  * validity of the equation A = V*D*inverse(V) depends upon V.cond().
44  *
45  * @author Arthur Zimek
46  * @since 0.1
47  */
48 public class EigenvalueDecomposition {
49   /**
50    * Row and column dimension (square matrix).
51    *
52    * @serial matrix dimension.
53    */
54   private final int n;
55 
56   /**
57    * Arrays for internal storage of eigenvalues.
58    *
59    * @serial internal storage of eigenvalues.
60    */
61   private double[] d, e;
62 
63   /**
64    * Array for internal storage of eigenvectors.
65    *
66    * @serial internal storage of eigenvectors.
67    */
68   private double[][] V;
69 
70   /**
71    * Array for internal storage of nonsymmetric Hessenberg form.
72    *
73    * @serial internal storage of nonsymmetric Hessenberg form.
74    */
75   private double[][] H;
76 
77   /**
78    * Working storage for nonsymmetric algorithm.
79    *
80    * @serial working storage for nonsymmetric algorithm.
81    */
82   private double[] ort;
83 
84   /**
85    * Check for symmetry, then construct the eigenvalue decomposition
86    *
87    * @param A Square matrix
88    */
EigenvalueDecomposition(double[][] A)89   public EigenvalueDecomposition(double[][] A) {
90     n = A.length;
91     d = new double[n];
92     e = new double[n];
93 
94     boolean issymmetric = true;
95     for(int j = 0; (j < n) && issymmetric; j++) {
96       for(int i = 0; (i < n) && issymmetric; i++) {
97         issymmetric = (A[i][j] == A[j][i]);
98         if(Double.isNaN(A[i][j])) {
99           throw new IllegalArgumentException("NaN in EigenvalueDecomposition!");
100         }
101         if(Double.isInfinite(A[i][j])) {
102           throw new IllegalArgumentException("+-inf in EigenvalueDecomposition!");
103         }
104       }
105     }
106 
107     if(issymmetric) {
108       V = VMath.copy(A);
109       // Tridiagonalize.
110       tred2();
111       // Diagonalize.
112       tql2();
113     }
114     else {
115       V = new double[n][n];
116       H = VMath.copy(A);
117       ort = new double[n];
118       // Reduce to Hessenberg form.
119       orthes();
120       // Reduce Hessenberg to real Schur form.
121       hqr2();
122     }
123     // Sort eigenvalues and corresponding vectors.
124     sortEigen();
125   }
126 
127   /**
128    * Symmetric Householder reduction to tridiagonal form.
129    */
tred2()130   private void tred2() {
131     // This is derived from the Algol procedures tred2 by
132     // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
133     // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
134     // Fortran subroutine in EISPACK.
135     System.arraycopy(V[n - 1], 0, d, 0, n);
136 
137     // Householder reduction to tridiagonal form.
138     for(int i = n - 1; i > 0; i--) {
139       double[] V_i = V[i], V_im1 = V[i - 1];
140       // Scale to avoid under/overflow.
141       double scale = 0.;
142       for(int k = 0; k < i; k++) {
143         scale += abs(d[k]);
144       }
145       if(scale < Double.MIN_NORMAL) {
146         e[i] = d[i - 1];
147         for(int j = 0; j < i; j++) {
148           d[j] = V_im1[j];
149           V_i[j] = V[j][i] = 0.;
150         }
151         d[i] = 0;
152         continue;
153       }
154       // Generate Householder vector.
155       double h = 0.;
156       for(int k = 0; k < i; k++) {
157         double dk = d[k] /= scale;
158         h += dk * dk;
159       }
160       {
161         double f = d[i - 1], g = FastMath.sqrt(h);
162         g = (f > 0) ? -g : g;
163         e[i] = scale * g;
164         h -= f * g;
165         d[i - 1] = f - g;
166         Arrays.fill(e, 0, i, 0.);
167       }
168 
169       // Apply similarity transformation to remaining columns.
170       for(int j = 0; j < i; j++) {
171         final double[] Vj = V[j];
172         double dj = Vj[i] = d[j], ej = e[j] + Vj[j] * dj;
173         for(int k = j + 1; k <= i - 1; k++) {
174           final double Vkj = V[k][j];
175           ej += Vkj * d[k];
176           e[k] += Vkj * dj;
177         }
178         e[j] = ej;
179       }
180       double sum = 0.;
181       for(int j = 0; j < i; j++) {
182         sum += (e[j] /= h) * d[j];
183       }
184       double hh = sum / (h + h);
185       for(int j = 0; j < i; j++) {
186         e[j] -= hh * d[j];
187       }
188       for(int j = 0; j < i; j++) {
189         double dj = d[j], ej = e[j];
190         for(int k = j; k <= i - 1; k++) {
191           V[k][j] -= (dj * e[k] + ej * d[k]);
192         }
193         d[j] = V_im1[j];
194         V_i[j] = 0.;
195       }
196       d[i] = h;
197     }
198 
199     // Accumulate transformations.
200     tred2AccumulateTransformations();
201     System.arraycopy(V[n - 1], 0, d, 0, n);
202     Arrays.fill(V[n - 1], 0.);
203     V[n - 1][n - 1] = 1.;
204     e[0] = 0.;
205   }
206 
tred2AccumulateTransformations()207   private void tred2AccumulateTransformations() {
208     for(int i = 0; i < n - 1; i++) {
209       final double[] Vi = V[i];
210       V[n - 1][i] = Vi[i];
211       Vi[i] = 1.;
212       final double h = d[i + 1];
213       if(h > 0.0 || h < 0.0) {
214         for(int k = 0; k <= i; k++) {
215           d[k] = V[k][i + 1] / h;
216         }
217         for(int j = 0; j <= i; j++) {
218           double g = 0.0;
219           for(int k = 0; k <= i; k++) {
220             final double[] Vk = V[k];
221             g += Vk[i + 1] * Vk[j];
222           }
223           for(int k = 0; k <= i; k++) {
224             V[k][j] -= g * d[k];
225           }
226         }
227       }
228       for(int k = 0; k <= i; k++) {
229         V[k][i + 1] = 0.0;
230       }
231     }
232   }
233 
234   /**
235    * Symmetric tridiagonal QL algorithm.
236    */
tql2()237   private void tql2() {
238     // This is derived from the Algol procedures tql2, by
239     // Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
240     // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
241     // Fortran subroutine in EISPACK.
242 
243     System.arraycopy(e, 1, e, 0, n - 1);
244     e[n - 1] = 0.;
245 
246     double f = 0., tst1 = 0.;
247     for(int l = 0; l < n; l++) {
248       // Find small subdiagonal element
249       tst1 = max(tst1, abs(d[l]) + abs(e[l]));
250       int m = l;
251       for(; m < n; ++m) {
252         if(abs(e[m]) <= 0x1P-52 * tst1) {
253           break;
254         }
255       }
256 
257       // If m == l, d[l] is an eigenvalue,
258       // otherwise, iterate.
259       if(m > l) {
260         do {
261           // Compute implicit shift
262           f += tql2ComputeImplicitShift(l);
263           // Implicit QL transformation.
264           tql2ImplicitQL(l, m, d[l + 1]);
265           // Check for convergence.
266           // TODO: Iteration limit?
267         }
268         while(abs(e[l]) > 0x1P-52 * tst1);
269       }
270       d[l] += f;
271       e[l] = 0.;
272     }
273   }
274 
tql2ComputeImplicitShift(int l)275   private double tql2ComputeImplicitShift(int l) {
276     final double el = e[l], g = d[l], p = (d[l + 1] - g) / (2. * el);
277     final double r = FastMath.sqrt(p * p + 1.);
278     final double pr = (p >= 0) ? p + r : p - r;
279     final double dl = d[l] = el / pr;
280     d[l + 1] = el * pr;
281     final double h = g - dl;
282     for(int i = l + 2; i < n; i++) {
283       d[i] -= h;
284     }
285     return h;
286   }
287 
tql2ImplicitQL(int l, int m, double dl1)288   private void tql2ImplicitQL(int l, int m, double dl1) {
289     double p = d[m], c = 1., c2 = 1., c3 = 1., s = 0., s2 = 0.;
290     final double el1 = e[l + 1];
291     for(int i = m - 1; i >= l; i--) {
292       c3 = c2;
293       c2 = c;
294       s2 = s;
295       final double di = d[i], ei = e[i];
296       double g = c * ei, h = c * p, r = FastMath.hypot(p, ei);
297       e[i + 1] = s * r;
298       s = ei / r;
299       c = p / r;
300       p = c * di - s * g;
301       d[i + 1] = h + s * (c * g + s * di);
302 
303       // Accumulate transformation.
304       for(int k = 0; k < n; k++) {
305         final double[] Vk = V[k];
306         h = Vk[i + 1];
307         Vk[i + 1] = s * Vk[i] + c * h;
308         Vk[i] = c * Vk[i] - s * h;
309       }
310     }
311     p = -s * s2 * c3 * el1 * e[l] / dl1;
312     e[l] = s * p;
313     d[l] = c * p;
314   }
315 
sortEigen()316   private void sortEigen() {
317     for(int i = 0; i < n - 1; i++) {
318       // Find maximum:
319       int k = i;
320       double p = abs(d[i]);
321       for(int j = i + 1; j < n; j++) {
322         final double d_j = abs(d[j]);
323         if(d_j > p) {
324           k = j;
325           p = d_j;
326         }
327       }
328       if(k == i) {
329         continue;
330       }
331       // Swap Eigenvalues
332       double tmp = d[k]; // p, or -p...
333       d[k] = d[i];
334       d[i] = tmp;
335       // Swap columns of V
336       for(int j = 0; j < n; j++) {
337         final double[] Vj = V[j];
338         final double swap = Vj[i];
339         Vj[i] = Vj[k];
340         Vj[k] = swap;
341       }
342     }
343   }
344 
345   /**
346    * Nonsymmetric reduction to Hessenberg form.
347    */
orthes()348   private void orthes() {
349     // FIXME: does this fail on NaN/inf values?
350 
351     // This is derived from the Algol procedures orthes and ortran,
352     // by Martin and Wilkinson, Handbook for Auto. Comp.,
353     // Vol.ii-Linear Algebra, and the corresponding
354     // Fortran subroutines in EISPACK.
355 
356     final int low = 0, high = n - 1;
357     for(int m = low + 1; m <= high - 1; m++) {
358       // Scale column.
359       double scale = 0.0;
360       for(int i = m; i <= high; i++) {
361         scale += abs(H[i][m - 1]);
362       }
363       if(scale > 0.0 || scale < 0.0) {
364         // Compute Householder transformation.
365         double h = 0.0;
366         for(int i = high; i >= m; i--) {
367           double oi = ort[i] = H[i][m - 1] / scale;
368           h += oi * oi;
369         }
370         double g = FastMath.sqrt(h), om = ort[m];
371         g = (om > 0) ? -g : g;
372         h -= om * g;
373         ort[m] = om - g;
374 
375         // Apply Householder similarity transformation
376         // H = (I-u*u'/h)*H*(I-u*u')/h)
377 
378         for(int j = m; j < n; j++) {
379           double f = 0.0;
380           for(int i = high; i >= m; i--) {
381             f += ort[i] * H[i][j];
382           }
383           f /= h;
384           for(int i = m; i <= high; i++) {
385             H[i][j] -= f * ort[i];
386           }
387         }
388 
389         for(int i = 0; i <= high; i++) {
390           final double[] Hi = H[i];
391           double f = 0.0;
392           for(int j = high; j >= m; j--) {
393             f += ort[j] * Hi[j];
394           }
395           f /= h;
396           for(int j = m; j <= high; j++) {
397             Hi[j] -= f * ort[j];
398           }
399         }
400         ort[m] *= scale;
401         H[m][m - 1] = scale * g;
402       }
403     }
404 
405     // Accumulate transformations (Algol's ortran).
406     for(int i = 0; i < n; i++) {
407       Arrays.fill(V[i], 0.);
408       V[i][i] = 1.;
409     }
410 
411     for(int m = high - 1; m >= low + 1; m--) {
412       final double[] H_m = H[m];
413       if(H_m[m - 1] != 0.0) {
414         for(int i = m + 1; i <= high; i++) {
415           ort[i] = H[i][m - 1];
416         }
417         final double ort_m = ort[m];
418         for(int j = m; j <= high; j++) {
419           double g = 0.0;
420           for(int i = m; i <= high; i++) {
421             g += ort[i] * V[i][j];
422           }
423           // Double division avoids possible underflow
424           g = (g / ort_m) / H_m[m - 1];
425           for(int i = m; i <= high; i++) {
426             V[i][j] += g * ort[i];
427           }
428         }
429       }
430     }
431   }
432 
433   /** Complex scalar division, writing into buf[off++] */
cdiv(double xr, double xi, double yr, double yi, double[] buf, int off)434   private static void cdiv(double xr, double xi, double yr, double yi, double[] buf, int off) {
435     if(abs(yr) > abs(yi)) {
436       final double r = yi / yr, d = yr + r * yi;
437       buf[off] = (xr + r * xi) / d;
438       buf[off + 1] = (xi - r * xr) / d;
439     }
440     else {
441       final double r = yr / yi, d = yi + r * yr;
442       buf[off] = (r * xr + xi) / d;
443       buf[off + 1] = (r * xi - xr) / d;
444     }
445   }
446 
447   /** Nonsymmetric reduction from Hessenberg to real Schur form. */
hqr2()448   private void hqr2() {
449     // FIXME: does this fail on NaN/inf values?
450 
451     // This is derived from the Algol procedure hqr2,
452     // by Martin and Wilkinson, Handbook for Auto. Comp.,
453     // Vol.ii-Linear Algebra, and the corresponding
454     // Fortran subroutine in EISPACK.
455 
456     // Initialize
457     final int nn = this.n, low = 0, high = nn - 1;
458 
459     // Store roots isolated by balanc and compute matrix norm
460     double norm = 0.;
461     for(int i = 0; i < nn; i++) {
462       // If eventually allowing low,high to be set, use this:
463       // if(i < low || i > high) { d[i] = H[i][i]; e[i] = 0.; }
464       for(int j = (i > 0 ? i - 1 : 0); j < nn; j++) {
465         norm += abs(H[i][j]);
466       }
467     }
468 
469     // Outer loop over eigenvalue index
470     {
471       double exshift = 0.0;
472       // double p = 0, q = 0, r = 0; // , s = 0, z = 0;
473       int iter = 0;
474       for(int n = nn - 1; n >= low;) {
475         // Look for single small sub-diagonal element
476         int l = n;
477         for(; l > low; --l) {
478           double s = abs(H[l - 1][l - 1]) + abs(H[l][l]);
479           if(abs(H[l][l - 1]) < 0x1P-52 * (s == 0. ? norm : s)) {
480             break;
481           }
482         }
483 
484         // Check for convergence
485         if(l == n) {
486           // One root found
487           d[n] = (H[n][n] += exshift);
488           e[n] = 0.;
489           n--;
490           iter = 0;
491           continue;
492         }
493         final double[] Hn = H[n], Hnm1 = H[n - 1];
494         if(l == n - 1) {
495           // Two roots found
496           double w = Hn[n - 1] * Hnm1[n];
497           double p = (Hnm1[n - 1] - Hn[n]) * 0.5, q = p * p + w;
498           double x = (Hn[n] += exshift), z = FastMath.sqrt(abs(q));
499           Hnm1[n - 1] += exshift;
500 
501           if(q >= 0) {
502             // Real pair
503             z = (p >= 0) ? p + z : p - z;
504             d[n - 1] = x + z;
505             d[n] = (z != 0.) ? x - w / z : d[n - 1];
506             e[n] = e[n - 1] = 0.;
507             x = Hn[n - 1];
508             double s = abs(x) + abs(z);
509             p = x / s;
510             q = z / s;
511             double r = FastMath.hypot(p, q);
512             p /= r;
513             q /= r;
514 
515             // Row modification
516             for(int j = n - 1; j < nn; j++) {
517               double tmp = Hnm1[j];
518               Hnm1[j] = q * tmp + p * Hn[j];
519               Hn[j] = q * Hn[j] - p * tmp;
520             }
521 
522             // Column modification
523             for(int i = 0; i <= n; i++) {
524               modifyQP(H[i], n, p, q);
525             }
526 
527             // Accumulate transformations
528             for(int i = low; i <= high; i++) {
529               modifyQP(V[i], n, p, q);
530             }
531           }
532           else {
533             // Complex pair
534             d[n] = d[n - 1] = x + p;
535             e[n] = -(e[n - 1] = z);
536           }
537           n -= 2;
538           iter = 0;
539           continue;
540         }
541         // No convergence yet
542 
543         // Form shift
544         double x = Hn[n], y = 0., w = 0.;
545         y = Hnm1[n - 1];
546         w = Hn[n - 1] * Hnm1[n];
547 
548         // Wilkinson's original ad hoc shift
549         if(iter == 10) {
550           exshift += x;
551           for(int i = low; i <= n; i++) {
552             H[i][i] -= x;
553           }
554           double s = abs(Hn[n - 1]) + abs(Hnm1[n - 2]);
555           x = y = 0.75 * s;
556           w = -0.4375 * s * s;
557         }
558 
559         // MATLAB's new ad hoc shift
560         if(iter == 30) {
561           double s = (y - x) * 0.5;
562           s = s * s + w;
563           if(s > 0) {
564             s = FastMath.sqrt(s);
565             s = (y < x) ? -s : s;
566             s = x - w / ((y - x) * 0.5 + s);
567             for(int i = low; i <= n; i++) {
568               H[i][i] -= s;
569             }
570             exshift += s;
571             x = y = w = 0.964;
572           }
573         }
574 
575         ++iter; // (Could check iteration count here.)
576 
577         double p = 0., q = 0., r = 0.;
578         // Look for two consecutive small sub-diagonal elements
579         int m = n - 2;
580         for(; m >= l; m--) {
581           final double[] Hm = H[m], Hmp1 = H[m + 1];
582           final double z = Hm[m], xz = x - z;
583           p = (xz * (y - z) - w) / Hmp1[m] + Hm[m + 1];
584           q = Hmp1[m + 1] - xz - y;
585           r = H[m + 2][m + 1];
586           double tmp = abs(p) + abs(q) + abs(r);
587           p /= tmp;
588           q /= tmp;
589           r /= tmp;
590           if(m == l || abs(Hm[m - 1]) * (abs(q) + abs(r)) < 0x1P-52 * (abs(p) * (abs(H[m - 1][m - 1]) + abs(z) + abs(Hmp1[m + 1])))) {
591             break;
592           }
593         }
594 
595         for(int i = m + 2; i <= n; i++) {
596           final double[] Hi = H[i];
597           Hi[i - 2] = 0.;
598           if(i > m + 2) {
599             Hi[i - 3] = 0.;
600           }
601         }
602 
603         // Double QR step involving rows l:n and columns m:n
604         for(int k = m, last = n - 1; k <= last; k++) {
605           boolean notlast = (k != last);
606           final double[] Hk = H[k], Hkp1 = H[k + 1],
607               Hkp2 = notlast ? H[k + 2] : null;
608           if(k != m) {
609             p = Hk[k - 1];
610             q = Hkp1[k - 1];
611             r = notlast ? Hkp2[k - 1] : 0.;
612             x = abs(p) + abs(q) + abs(r);
613             if(x == 0.0) {
614               continue; // Jama 1.0.3 fix
615             }
616             p /= x;
617             q /= x;
618             r /= x;
619           }
620           double s = FastMath.hypot(p, q, r);
621           s = (p < 0) ? -s : s;
622           if(s != 0) {
623             if(k != m) {
624               Hk[k - 1] = -s * x;
625             }
626             else if(l != m) {
627               Hk[k - 1] = -Hk[k - 1];
628             }
629             p += s;
630             x = p / s;
631             y = q / s;
632             double z = r / s;
633             q /= p;
634             r /= p;
635 
636             // Row modification
637             for(int j = k; j < nn; j++) {
638               double tmp = Hk[j] + q * Hkp1[j];
639               if(notlast) {
640                 tmp += r * Hkp2[j];
641                 Hkp2[j] -= tmp * z;
642               }
643               Hk[j] -= tmp * x;
644               Hkp1[j] -= tmp * y;
645             }
646 
647             // Column modification
648             for(int i = 0; i <= Math.min(n, k + 3); i++) {
649               modifyQR(H[i], k, notlast, q, r, x, y, z);
650             }
651 
652             // Accumulate transformations
653             for(int i = low; i <= high; i++) {
654               modifyQR(V[i], k, notlast, q, r, x, y, z);
655             }
656           } // (s != 0)
657         } // k loop
658         // check convergence
659       } // while (n >= low)
660     }
661 
662     if(norm == 0.0) {
663       return;
664     }
665 
666     // Backsubstitute to find vectors of upper triangular form
667     for(int n = nn - 1; n >= 0; n--) {
668       double p = d[n], q = e[n];
669       if(q == 0) {
670         hqr2BacksubstituteReal(n, p, norm);
671       }
672       else if(q < 0) {
673         hqr2BacksubstituteComplex(n, p, q, norm);
674       }
675     }
676 
677     // Vectors of isolated roots
678     // Only matters if the user can modify low, high:
679     // for(int i = 0; i < nn; i++) {
680     // if(i < low || i > high) { System.arraycopy(H[i], i, V[i], i, nn - i); }
681     // }
682 
683     // Back transformation to get eigenvectors of original matrix
684     hqr2BackTransformation(nn, low, high);
685   }
686 
modifyQP(final double[] Hi, int n, double p, double q)687   private static void modifyQP(final double[] Hi, int n, double p, double q) {
688     double tmp = Hi[n - 1];
689     Hi[n - 1] = q * tmp + p * Hi[n];
690     Hi[n] = q * Hi[n] - p * tmp;
691   }
692 
modifyQR(final double[] Hi, int k, boolean notlast, double q, double r, double x, double y, double z)693   private static void modifyQR(final double[] Hi, int k, boolean notlast, double q, double r, double x, double y, double z) {
694     double tmp = x * Hi[k] + y * Hi[k + 1];
695     if(notlast) {
696       tmp += z * Hi[k + 2];
697       Hi[k + 2] -= tmp * r;
698     }
699     Hi[k] -= tmp;
700     Hi[k + 1] -= tmp * q;
701   }
702 
703   // Real vector
hqr2BacksubstituteReal(int n, double p, double norm)704   private void hqr2BacksubstituteReal(int n, double p, double norm) {
705     H[n][n] = 1.0;
706     double s = 0, z = 0;
707     for(int i = n - 1, l = n; i >= 0; i--) {
708       final double[] Hi = H[i];
709       double w = Hi[i] - p, r = 0.;
710       for(int j = l; j <= n; j++) {
711         r += Hi[j] * H[j][n];
712       }
713       if(e[i] < 0.0) {
714         z = w;
715         s = r;
716         continue;
717       }
718       l = i;
719       if(!(e[i] > 0.0)) {
720         Hi[n] = -r / ((w > 0.0 || w < 0.0) ? w : (0x1P-52 * norm));
721       }
722       else {
723         // Solve real equations
724         final double[] Hip1 = H[i + 1];
725         final double x = Hi[i + 1], y = Hip1[i], dip = d[i] - p, ei = e[i];
726         final double t = Hi[n] = (x * s - z * r) / (dip * dip + ei * ei);
727         Hip1[n] = (abs(x) > abs(z)) ? (-r - w * t) / x : (-s - y * t) / z;
728       }
729 
730       // Overflow control
731       final double t = abs(Hi[n]);
732       if((0x1P-52 * t) * t > 1) {
733         for(int j = i; j <= n; j++) {
734           H[j][n] /= t;
735         }
736       }
737     }
738   }
739 
740   // Complex vector
hqr2BacksubstituteComplex(int n, double p, double q, double norm)741   private void hqr2BacksubstituteComplex(int n, double p, double q, double norm) {
742     final double[] Hn = H[n], Hnm1 = H[n - 1];
743     // Last vector component imaginary so matrix is triangular
744     final double tmp = Hn[n - 1];
745     if(abs(tmp) > abs(Hnm1[n])) {
746       Hnm1[n - 1] = q / tmp;
747       Hnm1[n] = -(Hn[n] - p) / tmp;
748     }
749     else {
750       cdiv(0., -Hnm1[n], Hnm1[n - 1] - p, q, Hnm1, n - 1);
751     }
752     Hn[n - 1] = 0.;
753     Hn[n] = 1.;
754     double r = 0., s = 0., z = 0.;
755     for(int i = n - 2, l = n - 1; i >= 0; i--) {
756       final double[] Hi = H[i], Hip1 = H[i + 1];
757       double w = Hi[i] - p, ra = 0., sa = 0.;
758       for(int j = l; j <= n; j++) {
759         final double Hij = Hi[j];
760         final double[] Hj = H[j];
761         ra += Hij * Hj[n - 1];
762         sa += Hij * Hj[n];
763       }
764 
765       if(e[i] < 0.) {
766         z = w;
767         r = ra;
768         s = sa;
769         continue;
770       }
771       l = i;
772       if(!(e[i] > 0.0)) {
773         cdiv(-ra, -sa, w, q, Hi, n - 1);
774       }
775       else {
776         // Solve complex equations
777         final double x = Hi[i + 1], y = Hip1[i], dip = d[i] - p;
778         double vr = dip * dip + e[i] * e[i] - q * q, vi = dip * 2. * q;
779         if(vr == 0. && vi == 0.) {
780           vr = 0x1P-52 * norm * (abs(w) + abs(q) + abs(x) + abs(y) + abs(z));
781         }
782         cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi, Hi, n - 1);
783         if(abs(x) > (abs(z) + abs(q))) {
784           Hip1[n - 1] = (-ra - w * Hi[n - 1] + q * Hi[n]) / x;
785           Hip1[n] = (-sa - w * Hi[n] - q * Hi[n - 1]) / x;
786         }
787         else {
788           cdiv(-r - y * Hi[n - 1], -s - y * Hi[n], z, q, Hip1, n - 1);
789         }
790       }
791 
792       // Overflow control
793       double t = max(abs(Hi[n - 1]), abs(Hi[n]));
794       if((0x1P-52 * t) * t > 1) {
795         for(int j = i; j <= n; j++) {
796           final double[] Hj = H[j];
797           Hj[n - 1] /= t;
798           Hj[n] /= t;
799         }
800       }
801     }
802   }
803 
804   /**
805    * Back transformation to get eigenvectors of original matrix.
806    */
hqr2BackTransformation(int nn, int low, int high)807   private void hqr2BackTransformation(int nn, int low, int high) {
808     for(int j = nn - 1; j >= low; j--) {
809       final int last = j < high ? j : high;
810       for(int i = low; i <= high; i++) {
811         final double[] Vi = V[i];
812         double sum = 0.;
813         for(int k = low; k <= last; k++) {
814           sum += Vi[k] * H[k][j];
815         }
816         Vi[j] = sum;
817       }
818     }
819   }
820 
821   /**
822    * Return the eigenvector matrix
823    *
824    * @return V
825    */
826   public double[][] getV() {
827     return V;
828   }
829 
830   /**
831    * Return the real parts of the eigenvalues
832    *
833    * @return real(diag(D))
834    */
835   public double[] getRealEigenvalues() {
836     return d;
837   }
838 
839   /**
840    * Return the imaginary parts of the eigenvalues
841    *
842    * @return imag(diag(D))
843    */
844   public double[] getImagEigenvalues() {
845     return e;
846   }
847 
848   /**
849    * Return the block diagonal eigenvalue matrix
850    *
851    * @return D
852    */
853   public double[][] getD() {
854     double[][] D = new double[n][n];
855     for(int i = 0; i < n; i++) {
856       final double e_i = e[i];
857       final double[] D_i = D[i];
858       D_i[i] = d[i];
859       if(e_i > 0) {
860         D_i[i + 1] = e_i;
861       }
862       else if(e_i < 0) {
863         D_i[i - 1] = e_i;
864       } // else: e_i = 0
865     }
866     return D;
867   }
868 }
869