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