bpp-core3  3.0.0
EigenValue.h
Go to the documentation of this file.
1 //
2 // File: EigenValue.h
3 // Authors:
4 // Julien Dutheil
5 // Created: 2004-04-07 16:24:00
6 //
7 
8 /*
9  Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
10 
11  This software is a computer program whose purpose is to provide classes
12  for numerical calculus. This file is part of the Bio++ project.
13 
14  This software is governed by the CeCILL license under French law and
15  abiding by the rules of distribution of free software. You can use,
16  modify and/ or redistribute the software under the terms of the CeCILL
17  license as circulated by CEA, CNRS and INRIA at the following URL
18  "http://www.cecill.info".
19 
20  As a counterpart to the access to the source code and rights to copy,
21  modify and redistribute granted by the license, users are provided only
22  with a limited warranty and the software's author, the holder of the
23  economic rights, and the successive licensors have only limited
24  liability.
25 
26  In this respect, the user's attention is drawn to the risks associated
27  with loading, using, modifying and/or developing or reproducing the
28  software by the user in light of its specific status of free software,
29  that may mean that it is complicated to manipulate, and that also
30  therefore means that it is reserved for developers and experienced
31  professionals having in-depth computer knowledge. Users are therefore
32  encouraged to load and test the software's suitability as regards their
33  requirements in conditions enabling the security of their systems and/or
34  data to be ensured and, more generally, to use and operate it in the
35  same conditions as regards security.
36 
37  The fact that you are presently reading this means that you have had
38  knowledge of the CeCILL license and that you accept its terms.
39 */
40 
41 #ifndef BPP_NUMERIC_MATRIX_EIGENVALUE_H
42 #define BPP_NUMERIC_MATRIX_EIGENVALUE_H
43 
44 
45 
46 #define TOST(i) static_cast<size_t>(i)
47 
48 #include <algorithm>
49 // for min(), max() below
50 
51 #include <cmath>
52 // for abs() below
53 #include <climits>
54 
55 #include "Matrix.h"
56 #include "../NumTools.h"
57 
58 namespace bpp
59 {
105 template<class Real>
107 {
108 private:
112  size_t n_;
113 
118 
124  std::vector<Real> d_; /* real part */
125  std::vector<Real> e_; /* img part */
132 
139 
140 
147 
153  std::vector<Real> ort_;
154 
163  void tred2()
164  {
165  for (size_t j = 0; j < n_; j++)
166  {
167  d_[j] = V_(n_ - 1, j);
168  }
169 
170  // Householder reduction to tridiagonal form.
171 
172  for (size_t i = n_ - 1; i > 0; i--)
173  {
174  // Scale to avoid under/overflow.
175 
176  Real scale = 0.0;
177  Real h = 0.0;
178  for (size_t k = 0; k < i; ++k)
179  {
180  scale = scale + NumTools::abs<Real>(d_[k]);
181  }
182  if (scale == 0.0)
183  {
184  e_[i] = d_[i - 1];
185  for (size_t j = 0; j < i; ++j)
186  {
187  d_[j] = V_(i - 1, j);
188  V_(i, j) = 0.0;
189  V_(j, i) = 0.0;
190  }
191  }
192  else
193  {
194  // Generate Householder vector.
195 
196  for (size_t k = 0; k < i; ++k)
197  {
198  d_[k] /= scale;
199  h += d_[k] * d_[k];
200  }
201  Real f = d_[i - 1];
202  Real g = sqrt(h);
203  if (f > 0)
204  {
205  g = -g;
206  }
207  e_[i] = scale * g;
208  h = h - f * g;
209  d_[i - 1] = f - g;
210  for (size_t j = 0; j < i; ++j)
211  {
212  e_[j] = 0.0;
213  }
214 
215  // Apply similarity transformation to remaining columns.
216 
217  for (size_t j = 0; j < i; ++j)
218  {
219  f = d_[j];
220  V_(j, i) = f;
221  g = e_[j] + V_(j, j) * f;
222  for (size_t k = j + 1; k <= i - 1; k++)
223  {
224  g += V_(k, j) * d_[k];
225  e_[k] += V_(k, j) * f;
226  }
227  e_[j] = g;
228  }
229  f = 0.0;
230  for (size_t j = 0; j < i; ++j)
231  {
232  e_[j] /= h;
233  f += e_[j] * d_[j];
234  }
235  Real hh = f / (h + h);
236  for (size_t j = 0; j < i; ++j)
237  {
238  e_[j] -= hh * d_[j];
239  }
240  for (size_t j = 0; j < i; ++j)
241  {
242  f = d_[j];
243  g = e_[j];
244  for (size_t k = j; k <= i - 1; ++k)
245  {
246  V_(k, j) -= (f * e_[k] + g * d_[k]);
247  }
248  d_[j] = V_(i - 1, j);
249  V_(i, j) = 0.0;
250  }
251  }
252  d_[i] = h;
253  }
254 
255  // Accumulate transformations.
256 
257  for (size_t i = 0; i < n_ - 1; i++)
258  {
259  V_(n_ - 1, i) = V_(i, i);
260  V_(i, i) = 1.0;
261  Real h = d_[i + 1];
262  if (h != 0.0)
263  {
264  for (size_t k = 0; k <= i; k++)
265  {
266  d_[k] = V_(k, i + 1) / h;
267  }
268  for (size_t j = 0; j <= i; j++)
269  {
270  Real g = 0.0;
271  for (size_t k = 0; k <= i; k++)
272  {
273  g += V_(k, i + 1) * V_(k, j);
274  }
275  for (size_t k = 0; k <= i; k++)
276  {
277  V_(k, j) -= g * d_[k];
278  }
279  }
280  }
281  for (size_t k = 0; k <= i; k++)
282  {
283  V_(k, i + 1) = 0.0;
284  }
285  }
286  for (size_t j = 0; j < n_; j++)
287  {
288  d_[j] = V_(n_ - 1, j);
289  V_(n_ - 1, j) = 0.0;
290  }
291  V_(n_ - 1, n_ - 1) = 1.0;
292  e_[0] = 0.0;
293  }
294 
303  void tql2 ()
304  {
305  for (size_t i = 1; i < n_; i++)
306  {
307  e_[i - 1] = e_[i];
308  }
309  e_[n_ - 1] = 0.0;
310 
311  Real f = 0.0;
312  Real tst1 = 0.0;
313  Real eps = std::pow(2.0, -52.0);
314  for (size_t l = 0; l < n_; ++l)
315  {
316  // Find small subdiagonal element
317 
318  tst1 = std::max(tst1, NumTools::abs<Real>(d_[l]) + NumTools::abs<Real>(e_[l]));
319  size_t m = l;
320 
321  // Original while-loop from Java code
322  while (m < n_)
323  {
324  if (NumTools::abs<Real>(e_[m]) <= eps * tst1)
325  {
326  break;
327  }
328  m++;
329  }
330 
331  // If m == l, d_[l] is an eigenvalue,
332  // otherwise, iterate.
333 
334  if (m > l)
335  {
336  int iter = 0;
337  do
338  {
339  iter = iter + 1; // (Could check iteration count here.)
340 
341  // Compute implicit shift
342 
343  Real g = d_[l];
344  Real p = (d_[l + 1] - g) / (2.0 * e_[l]);
345  Real r = hypot(p, 1.0);
346  if (p < 0)
347  {
348  r = -r;
349  }
350  d_[l] = e_[l] / (p + r);
351  d_[l + 1] = e_[l] * (p + r);
352  Real dl1 = d_[l + 1];
353  Real h = g - d_[l];
354  for (size_t i = l + 2; i < n_; ++i)
355  {
356  d_[i] -= h;
357  }
358  f = f + h;
359 
360  // Implicit QL transformation.
361 
362  p = d_[m];
363  Real c = 1.0;
364  Real c2 = c;
365  Real c3 = c;
366  Real el1 = e_[l + 1];
367  Real s = 0.0;
368  Real s2 = 0.0;
369  // for (size_t i = m - 1; i >= l; --i)
370  for (size_t ii = m; ii > l; --ii)
371  {
372  size_t i = ii - 1; // to avoid infinite loop!
373  c3 = c2;
374  c2 = c;
375  s2 = s;
376  g = c * e_[i];
377  h = c * p;
378  r = hypot(p, e_[i]);
379  e_[i + 1] = s * r;
380  s = e_[i] / r;
381  c = p / r;
382  p = c * d_[i] - s * g;
383  d_[i + 1] = h + s * (c * g + s * d_[i]);
384 
385  // Accumulate transformation.
386 
387  for (size_t k = 0; k < n_; k++)
388  {
389  h = V_(k, i + 1);
390  V_(k, i + 1) = s * V_(k, i) + c * h;
391  V_(k, i) = c * V_(k, i) - s * h;
392  }
393  }
394  p = -s * s2 * c3 * el1 * e_[l] / dl1;
395  e_[l] = s * p;
396  d_[l] = c * p;
397 
398  // Check for convergence.
399  }
400  while (NumTools::abs<Real>(e_[l]) > eps * tst1);
401  }
402  d_[l] = d_[l] + f;
403  e_[l] = 0.0;
404  }
405 
406  // Sort eigenvalues and corresponding vectors.
407 
408  for (size_t i = 0; n_ > 0 && i < n_ - 1; i++)
409  {
410  size_t k = i;
411  Real p = d_[i];
412  for (size_t j = i + 1; j < n_; j++)
413  {
414  if (d_[j] < p)
415  {
416  k = j;
417  p = d_[j];
418  }
419  }
420  if (k != i)
421  {
422  d_[k] = d_[i];
423  d_[i] = p;
424  for (size_t j = 0; j < n_; j++)
425  {
426  p = V_(j, i);
427  V_(j, i) = V_(j, k);
428  V_(j, k) = p;
429  }
430  }
431  }
432  }
433 
442  void orthes()
443  {
444  if (n_ == 0) return;
445  size_t low = 0;
446  size_t high = n_ - 1;
447 
448  for (size_t m = low + 1; m <= high - 1; ++m)
449  {
450  // Scale column.
451 
452  Real scale = 0.0;
453  for (size_t i = m; i <= high; ++i)
454  {
455  scale = scale + NumTools::abs<Real>(H_(i, m - 1));
456  }
457  if (scale != 0.0)
458  {
459  // Compute Householder transformation.
460 
461  Real h = 0.0;
462  for (size_t i = high; i >= m; --i)
463  {
464  ort_[i] = H_(i, m - 1) / scale;
465  h += ort_[i] * ort_[i];
466  }
467  Real g = sqrt(h);
468  if (ort_[m] > 0)
469  {
470  g = -g;
471  }
472  h = h - ort_[m] * g;
473  ort_[m] = ort_[m] - g;
474 
475  // Apply Householder similarity transformation
476  // H = (I-u*u'/h)*H*(I-u*u')/h)
477 
478  for (size_t j = m; j < n_; ++j)
479  {
480  Real f = 0.0;
481  for (size_t i = high; i >= m; --i)
482  {
483  f += ort_[i] * H_(i, j);
484  }
485  f = f / h;
486  for (size_t i = m; i <= high; ++i)
487  {
488  H_(i, j) -= f * ort_[i];
489  }
490  }
491 
492  for (size_t i = 0; i <= high; ++i)
493  {
494  Real f = 0.0;
495  for (size_t j = high; j >= m; --j)
496  {
497  f += ort_[j] * H_(i, j);
498  }
499  f = f / h;
500  for (size_t j = m; j <= high; ++j)
501  {
502  H_(i, j) -= f * ort_[j];
503  }
504  }
505  ort_[m] = scale * ort_[m];
506  H_(m, m - 1) = scale * g;
507  }
508  }
509 
510  // Accumulate transformations (Algol's ortran).
511 
512  for (size_t i = 0; i < n_; i++)
513  {
514  for (size_t j = 0; j < n_; j++)
515  {
516  V_(i, j) = (i == j ? 1.0 : 0.0);
517  }
518  }
519 
520  for (size_t m = high - 1; m >= low + 1; --m)
521  {
522  if (H_(m, m - 1) != 0.0)
523  {
524  for (size_t i = m + 1; i <= high; ++i)
525  {
526  ort_[i] = H_(i, m - 1);
527  }
528  for (size_t j = m; j <= high; ++j)
529  {
530  Real g = 0.0;
531  for (size_t i = m; i <= high; i++)
532  {
533  g += ort_[i] * V_(i, j);
534  }
535  // Double division avoids possible underflow
536  g = (g / ort_[m]) / H_(m, m - 1);
537  for (size_t i = m; i <= high; ++i)
538  {
539  V_(i, j) += g * ort_[i];
540  }
541  }
542  }
543  }
544  }
545 
546 
547  // Complex scalar division.
548 
549  Real cdivr, cdivi;
550  void cdiv(Real xr, Real xi, Real yr, Real yi)
551  {
552  Real r, d;
553  if (NumTools::abs<Real>(yr) > NumTools::abs<Real>(yi))
554  {
555  r = yi / yr;
556  d = yr + r * yi;
557  cdivr = (xr + r * xi) / d;
558  cdivi = (xi - r * xr) / d;
559  }
560  else
561  {
562  r = yr / yi;
563  d = yi + r * yr;
564  cdivr = (r * xr + xi) / d;
565  cdivi = (r * xi - xr) / d;
566  }
567  }
568 
569 
570  // Nonsymmetric reduction from Hessenberg to real Schur form.
571 
572  void hqr2 ()
573  {
574  // This is derived from the Algol procedure hqr2,
575  // by Martin and Wilkinson, Handbook for Auto. Comp.,
576  // Vol.ii-Linear Algebra, and the corresponding
577  // Fortran subroutine in EISPACK.
578 
579  // Initialize
580 
581  int nn = static_cast<int>(this->n_);
582  int n = nn - 1;
583  int low = 0;
584  int high = nn - 1;
585  Real eps = std::pow(2.0, -52.0);
586  Real exshift = 0.0;
587  Real p = 0, q = 0, r = 0, s = 0, z = 0, t, w, x, y;
588 
589  // Store roots isolated by balanc and compute matrix norm
590 
591  Real norm = 0.0;
592  for (int i = 0; i < nn; i++)
593  {
594  if ((i < low) || (i > high))
595  {
596  d_[TOST(i)] = H_(TOST(i), TOST(i));
597  e_[TOST(i)] = 0.0;
598  }
599  for (int j = std::max(i - 1, 0); j < nn; j++)
600  {
601  norm = norm + NumTools::abs<Real>(H_(TOST(i), TOST(j)));
602  }
603  }
604 
605  // Outer loop over eigenvalue index
606 
607  int iter = 0;
608  while (n >= low)
609  {
610  // Look for single small sub-diagonal element
611 
612  int l = n;
613  while (l > low)
614  {
615  s = NumTools::abs<Real>(H_(TOST(l - 1), TOST(l - 1))) + NumTools::abs<Real>(H_(TOST(l), TOST(l)));
616  if (s == 0.0)
617  {
618  s = norm;
619  }
620  if (NumTools::abs<Real>(H_(TOST(l), TOST(l - 1))) < eps * s)
621  {
622  break;
623  }
624  l--;
625  }
626 
627  // Check for convergence
628  // One root found
629 
630  if (l == n)
631  {
632  H_(TOST(n), TOST(n)) = H_(TOST(n), TOST(n)) + exshift;
633  d_[TOST(n)] = H_(TOST(n), TOST(n));
634  e_[TOST(n)] = 0.0;
635  n--;
636  iter = 0;
637 
638  // Two roots found
639  }
640  else if (l == n - 1)
641  {
642  w = H_(TOST(n), TOST(n - 1)) * H_(TOST(n - 1), TOST(n));
643  p = (H_(TOST(n - 1), TOST(n - 1)) - H_(TOST(n), TOST(n))) / 2.0;
644  q = p * p + w;
645  z = sqrt(NumTools::abs<Real>(q));
646  H_(TOST(n), TOST(n)) = H_(TOST(n), TOST(n)) + exshift;
647  H_(TOST(n - 1), TOST(n - 1)) = H_(TOST(n - 1), TOST(n - 1)) + exshift;
648  x = H_(TOST(n), TOST(n));
649 
650  // Real pair
651 
652  if (q >= 0)
653  {
654  if (p >= 0)
655  {
656  z = p + z;
657  }
658  else
659  {
660  z = p - z;
661  }
662  d_[TOST(n - 1)] = x + z;
663  d_[TOST(n)] = d_[TOST(n - 1)];
664  if (z != 0.0)
665  {
666  d_[TOST(n)] = x - w / z;
667  }
668  e_[TOST(n - 1)] = 0.0;
669  e_[TOST(n)] = 0.0;
670  x = H_(TOST(n), TOST(n - 1));
671  s = NumTools::abs<Real>(x) + NumTools::abs<Real>(z);
672  p = x / s;
673  q = z / s;
674  r = sqrt(p * p + q * q);
675  p = p / r;
676  q = q / r;
677 
678  // Row modification
679 
680  for (int j = n - 1; j < nn; j++)
681  {
682  z = H_(TOST(n - 1), TOST(j));
683  H_(TOST(n - 1), TOST(j)) = q * z + p * H_(TOST(n), TOST(j));
684  H_(TOST(n), TOST(j)) = q * H_(TOST(n), TOST(j)) - p * z;
685  }
686 
687  // Column modification
688 
689  for (int i = 0; i <= n; i++)
690  {
691  z = H_(TOST(i), TOST(n - 1));
692  H_(TOST(i), TOST(n - 1)) = q * z + p * H_(TOST(i), TOST(n));
693  H_(TOST(i), TOST(n)) = q * H_(TOST(i), TOST(n)) - p * z;
694  }
695 
696  // Accumulate transformations
697 
698  for (int i = low; i <= high; i++)
699  {
700  z = V_(TOST(i), TOST(n - 1));
701  V_(TOST(i), TOST(n - 1)) = q * z + p * V_(TOST(i), TOST(n));
702  V_(TOST(i), TOST(n)) = q * V_(TOST(i), TOST(n)) - p * z;
703  }
704 
705  // Complex pair
706  }
707  else
708  {
709  d_[TOST(n - 1)] = x + p;
710  d_[TOST(n)] = x + p;
711  e_[TOST(n - 1)] = z;
712  e_[TOST(n)] = -z;
713  }
714  n = n - 2;
715  iter = 0;
716 
717  // No convergence yet
718  }
719  else
720  {
721  // Form shift
722 
723  x = H_(TOST(n), TOST(n));
724  y = 0.0;
725  w = 0.0;
726  if (l < n)
727  {
728  y = H_(TOST(n - 1), TOST(n - 1));
729  w = H_(TOST(n), TOST(n - 1)) * H_(TOST(n - 1), TOST(n));
730  }
731 
732  // Wilkinson's original ad hoc shift
733 
734  if (iter == 10)
735  {
736  exshift += x;
737  for (int i = low; i <= n; i++)
738  {
739  H_(TOST(i), TOST(i)) -= x;
740  }
741  s = NumTools::abs<Real>(H_(TOST(n), TOST(n - 1))) + NumTools::abs<Real>(H_(TOST(n - 1), TOST(n - 2)));
742  x = y = 0.75 * s;
743  w = -0.4375 * s * s;
744  }
745 
746  // MATLAB's new ad hoc shift
747  if (iter == 30)
748  {
749  s = (y - x) / 2.0;
750  s = s * s + w;
751  if (s > 0)
752  {
753  s = sqrt(s);
754  if (y < x)
755  {
756  s = -s;
757  }
758  s = x - w / ((y - x) / 2.0 + s);
759  for (int i = low; i <= n; i++)
760  {
761  H_(TOST(i), TOST(i)) -= s;
762  }
763  exshift += s;
764  x = y = w = 0.964;
765  }
766  }
767 
768  iter = iter + 1; // (Could check iteration count here.)
769 
770  // Look for two consecutive small sub-diagonal elements
771 
772  int m = n - 2;
773  while (m >= l)
774  {
775  z = H_(TOST(m), TOST(m));
776  r = x - z;
777  s = y - z;
778  p = (r * s - w) / H_(TOST(m + 1), TOST(m)) + H_(TOST(m), TOST(m + 1));
779  q = H_(TOST(m + 1), TOST(m + 1)) - z - r - s;
780  r = H_(TOST(m + 2), TOST(m + 1));
781  s = NumTools::abs<Real>(p) + NumTools::abs<Real>(q) + NumTools::abs<Real>(r);
782  p = p / s;
783  q = q / s;
784  r = r / s;
785  if (m == l)
786  {
787  break;
788  }
789  if (NumTools::abs<Real>(H_(TOST(m), TOST(m - 1))) * (NumTools::abs<Real>(q) + NumTools::abs<Real>(r)) <
790  eps * (NumTools::abs<Real>(p) * (NumTools::abs<Real>(H_(TOST(m - 1), TOST(m - 1))) + NumTools::abs<Real>(z) +
791  NumTools::abs<Real>(H_(TOST(m + 1), TOST(m + 1))))))
792  {
793  break;
794  }
795  m--;
796  }
797 
798  for (int i = m + 2; i <= n; i++)
799  {
800  H_(TOST(i), TOST(i - 2)) = 0.0;
801  if (i > m + 2)
802  {
803  H_(TOST(i), TOST(i - 3)) = 0.0;
804  }
805  }
806 
807  // Double QR step involving rows l:n and columns m:n
808 
809  for (int k = m; k <= n - 1; k++)
810  {
811  int notlast = (k != n - 1);
812  if (k != m)
813  {
814  p = H_(TOST(k), TOST(k - 1));
815  q = H_(TOST(k + 1), TOST(k - 1));
816  r = (notlast ? H_(TOST(k + 2), TOST(k - 1)) : 0.0);
817  x = NumTools::abs<Real>(p) + NumTools::abs<Real>(q) + NumTools::abs<Real>(r);
818  if (x != 0.0)
819  {
820  p = p / x;
821  q = q / x;
822  r = r / x;
823  }
824  }
825  if (x == 0.0)
826  {
827  break;
828  }
829  s = sqrt(p * p + q * q + r * r);
830  if (p < 0)
831  {
832  s = -s;
833  }
834  if (s != 0)
835  {
836  if (k != m)
837  {
838  H_(TOST(k), TOST(k - 1)) = -s * x;
839  }
840  else if (l != m)
841  {
842  H_(TOST(k), TOST(k - 1)) = -H_(TOST(k), TOST(k - 1));
843  }
844  p = p + s;
845  x = p / s;
846  y = q / s;
847  z = r / s;
848  q = q / p;
849  r = r / p;
850 
851  // Row modification
852 
853  for (int j = k; j < nn; j++)
854  {
855  p = H_(TOST(k), TOST(j)) + q * H_(TOST(k + 1), TOST(j));
856  if (notlast)
857  {
858  p = p + r * H_(TOST(k + 2), TOST(j));
859  H_(TOST(k + 2), TOST(j)) = H_(TOST(k + 2), TOST(j)) - p * z;
860  }
861  H_(TOST(k), TOST(j)) = H_(TOST(k), TOST(j)) - p * x;
862  H_(TOST(k + 1), TOST(j)) = H_(TOST(k + 1), TOST(j)) - p * y;
863  }
864 
865  // Column modification
866 
867  for (int i = 0; i <= std::min(n, k + 3); i++)
868  {
869  p = x * H_(TOST(i), TOST(k)) + y * H_(TOST(i), TOST(k + 1));
870  if (notlast)
871  {
872  p = p + z * H_(TOST(i), TOST(k + 2));
873  H_(TOST(i), TOST(k + 2)) = H_(TOST(i), TOST(k + 2)) - p * r;
874  }
875  H_(TOST(i), TOST(k)) = H_(TOST(i), TOST(k)) - p;
876  H_(TOST(i), TOST(k + 1)) = H_(TOST(i), TOST(k + 1)) - p * q;
877  }
878 
879  // Accumulate transformations
880 
881  for (int i = low; i <= high; i++)
882  {
883  p = x * V_(TOST(i), TOST(k)) + y * V_(TOST(i), TOST(k + 1));
884  if (notlast)
885  {
886  p = p + z * V_(TOST(i), TOST(k + 2));
887  V_(TOST(i), TOST(k + 2)) = V_(TOST(i), TOST(k + 2)) - p * r;
888  }
889  V_(TOST(i), TOST(k)) = V_(TOST(i), TOST(k)) - p;
890  V_(TOST(i), TOST(k + 1)) = V_(TOST(i), TOST(k + 1)) - p * q;
891  }
892  } // (s != 0)
893  } // k loop
894  } // check convergence
895  } // while (n >= low)
896 
897  // Backsubstitute to find vectors of upper triangular form
898 
899  if (norm == 0.0)
900  {
901  return;
902  }
903 
904  for (n = nn - 1; n >= 0; n--)
905  {
906  p = d_[TOST(n)];
907  q = e_[TOST(n)];
908 
909  // Real vector
910 
911  if (q == 0)
912  {
913  int l = n;
914  H_(TOST(n), TOST(n)) = 1.0;
915  for (int i = n - 1; i >= 0; i--)
916  {
917  w = H_(TOST(i), TOST(i)) - p;
918  r = 0.0;
919  for (int j = l; j <= n; j++)
920  {
921  r = r + H_(TOST(i), TOST(j)) * H_(TOST(j), TOST(n));
922  }
923  if (e_[TOST(i)] < 0.0)
924  {
925  z = w;
926  s = r;
927  }
928  else
929  {
930  l = i;
931  if (e_[TOST(i)] == 0.0)
932  {
933  if (w != 0.0)
934  {
935  H_(TOST(i), TOST(n)) = -r / w;
936  }
937  else
938  {
939  H_(TOST(i), TOST(n)) = -r / (eps * norm);
940  }
941 
942  // Solve real equations
943  }
944  else
945  {
946  x = H_(TOST(i), TOST(i + 1));
947  y = H_(TOST(i + 1), TOST(i));
948  q = (d_[TOST(i)] - p) * (d_[TOST(i)] - p) + e_[TOST(i)] * e_[TOST(i)];
949  t = (x * s - z * r) / q;
950  H_(TOST(i), TOST(n)) = t;
951  if (NumTools::abs<Real>(x) > NumTools::abs<Real>(z))
952  {
953  H_(TOST(i + 1), TOST(n)) = (-r - w * t) / x;
954  }
955  else
956  {
957  H_(TOST(i + 1), TOST(n)) = (-s - y * t) / z;
958  }
959  }
960 
961  // Overflow control
962 
963  t = NumTools::abs<Real>(H_(TOST(i), TOST(n)));
964  if ((eps * t) * t > 1)
965  {
966  for (int j = i; j <= n; j++)
967  {
968  H_(TOST(j), TOST(n)) = H_(TOST(j), TOST(n)) / t;
969  }
970  }
971  }
972  }
973 
974  // Complex vector
975  }
976  else if (q < 0)
977  {
978  int l = n - 1;
979 
980  // Last vector component imaginary so matrix is triangular
981 
982  if (NumTools::abs<Real>(H_(TOST(n), TOST(n - 1))) > NumTools::abs<Real>(H_(TOST(n - 1), TOST(n))))
983  {
984  H_(TOST(n - 1), TOST(n - 1)) = q / H_(TOST(n), TOST(n - 1));
985  H_(TOST(n - 1), TOST(n)) = -(H_(TOST(n), TOST(n)) - p) / H_(TOST(n), TOST(n - 1));
986  }
987  else
988  {
989  cdiv(0.0, -H_(TOST(n - 1), TOST(n)), H_(TOST(n - 1), TOST(n - 1)) - p, q);
990  H_(TOST(n - 1), TOST(n - 1)) = cdivr;
991  H_(TOST(n - 1), TOST(n)) = cdivi;
992  }
993  H_(TOST(n), TOST(n - 1)) = 0.0;
994  H_(TOST(n), TOST(n)) = 1.0;
995  for (int i = n - 2; i >= 0; i--)
996  {
997  Real ra, sa, vr, vi;
998  ra = 0.0;
999  sa = 0.0;
1000  for (int j = l; j <= n; j++)
1001  {
1002  ra = ra + H_(TOST(i), TOST(j)) * H_(TOST(j), TOST(n - 1));
1003  sa = sa + H_(TOST(i), TOST(j)) * H_(TOST(j), TOST(n));
1004  }
1005  w = H_(TOST(i), TOST(i)) - p;
1006 
1007  if (e_[TOST(i)] < 0.0)
1008  {
1009  z = w;
1010  r = ra;
1011  s = sa;
1012  }
1013  else
1014  {
1015  l = i;
1016  if (e_[TOST(i)] == 0)
1017  {
1018  cdiv(-ra, -sa, w, q);
1019  H_(TOST(i), TOST(n - 1)) = cdivr;
1020  H_(TOST(i), TOST(n)) = cdivi;
1021  }
1022  else
1023  {
1024  // Solve complex equations
1025 
1026  x = H_(TOST(i), TOST(i + 1));
1027  y = H_(TOST(i + 1), TOST(i));
1028  vr = (d_[TOST(i)] - p) * (d_[TOST(i)] - p) + e_[TOST(i)] * e_[TOST(i)] - q * q;
1029  vi = (d_[TOST(i)] - p) * 2.0 * q;
1030  if ((vr == 0.0) && (vi == 0.0))
1031  {
1032  vr = eps * norm * (NumTools::abs<Real>(w) + NumTools::abs<Real>(q) +
1033  NumTools::abs<Real>(x) + NumTools::abs<Real>(y) + NumTools::abs<Real>(z));
1034  }
1035  cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi);
1036  H_(TOST(i), TOST(n - 1)) = cdivr;
1037  H_(TOST(i), TOST(n)) = cdivi;
1038  if (NumTools::abs<Real>(x) > (NumTools::abs<Real>(z) + NumTools::abs<Real>(q)))
1039  {
1040  H_(TOST(i + 1), TOST(n - 1)) = (-ra - w * H_(TOST(i), TOST(n - 1)) + q * H_(TOST(i), TOST(n))) / x;
1041  H_(TOST(i + 1), TOST(n)) = (-sa - w * H_(TOST(i), TOST(n)) - q * H_(TOST(i), TOST(n - 1))) / x;
1042  }
1043  else
1044  {
1045  cdiv(-r - y * H_(TOST(i), TOST(n - 1)), -s - y * H_(TOST(i), TOST(n)), z, q);
1046  H_(TOST(i + 1), TOST(n - 1)) = cdivr;
1047  H_(TOST(i + 1), TOST(n)) = cdivi;
1048  }
1049  }
1050 
1051  // Overflow control
1052  t = std::max(NumTools::abs<Real>(H_(TOST(i), TOST(n - 1))), NumTools::abs<Real>(H_(TOST(i), TOST(n))));
1053  if ((eps * t) * t > 1)
1054  {
1055  for (int j = i; j <= n; j++)
1056  {
1057  H_(TOST(j), TOST(n - 1)) = H_(TOST(j), TOST(n - 1)) / t;
1058  H_(TOST(j), TOST(n)) = H_(TOST(j), TOST(n)) / t;
1059  }
1060  }
1061  }
1062  }
1063  }
1064  }
1065 
1066  // Vectors of isolated roots
1067 
1068  for (int i = 0; i < nn; i++)
1069  {
1070  if (i < low || i > high)
1071  {
1072  for (int j = i; j < nn; j++)
1073  {
1074  V_(TOST(i), TOST(j)) = H_(TOST(i), TOST(j));
1075  }
1076  }
1077  }
1078 
1079  // Back transformation to get eigenvectors of original matrix
1080 
1081  for (int j = nn - 1; j >= low; j--)
1082  {
1083  for (int i = low; i <= high; i++)
1084  {
1085  z = 0.0;
1086  for (int k = low; k <= std::min(j, high); k++)
1087  {
1088  z = z + V_(TOST(i), TOST(k)) * H_(TOST(k), TOST(j));
1089  }
1090  V_(TOST(i), TOST(j)) = z;
1091  }
1092  }
1093  }
1094 
1095 public:
1096  bool isSymmetric() const { return issymmetric_; }
1097 
1098 
1105  n_(A.getNumberOfColumns()),
1106  issymmetric_(true),
1107  d_(n_),
1108  e_(n_),
1109  V_(n_, n_),
1110  H_(),
1111  D_(n_, n_),
1112  ort_(),
1113  cdivr(), cdivi()
1114  {
1115  if (n_ > INT_MAX)
1116  throw Exception("EigenValue: can only be computed for matrices <= " + TextTools::toString(INT_MAX));
1117  for (size_t j = 0; (j < n_) && issymmetric_; j++)
1118  {
1119  for (size_t i = 0; (i < n_) && issymmetric_; i++)
1120  {
1121  issymmetric_ = (A(i, j) == A(j, i));
1122  }
1123  }
1124 
1125  if (issymmetric_)
1126  {
1127  for (size_t i = 0; i < n_; i++)
1128  {
1129  for (size_t j = 0; j < n_; j++)
1130  {
1131  V_(i, j) = A(i, j);
1132  }
1133  }
1134 
1135  // Tridiagonalize.
1136  tred2();
1137 
1138  // Diagonalize.
1139  tql2();
1140  }
1141  else
1142  {
1143  H_.resize(n_, n_);
1144  ort_.resize(n_);
1145 
1146  for (size_t j = 0; j < n_; j++)
1147  {
1148  for (size_t i = 0; i < n_; i++)
1149  {
1150  H_(i, j) = A(i, j);
1151  }
1152  }
1153 
1154  // Reduce to Hessenberg form.
1155  orthes();
1156 
1157  // Reduce Hessenberg to real Schur form.
1158  hqr2();
1159  }
1160  }
1161 
1162 
1168  const RowMatrix<Real>& getV() const { return V_; }
1169 
1175  const std::vector<Real>& getRealEigenValues() const { return d_; }
1176 
1182  const std::vector<Real>& getImagEigenValues() const { return e_; }
1183 
1217  const RowMatrix<Real>& getD() const
1218  {
1219  for (size_t i = 0; i < n_; i++)
1220  {
1221  for (size_t j = 0; j < n_; j++)
1222  {
1223  D_(i, j) = 0.0;
1224  }
1225  D_(i, i) = d_[i];
1226  if (e_[i] > 0)
1227  {
1228  D_(i, i + 1) = e_[i];
1229  }
1230  else if (e_[i] < 0)
1231  {
1232  D_(i, i - 1) = e_[i];
1233  }
1234  }
1235  return D_;
1236  }
1237 };
1238 } // end of namespace bpp.
1239 #endif // BPP_NUMERIC_MATRIX_EIGENVALUE_H
#define TOST(i)
Definition: EigenValue.h:46
Computes eigenvalues and eigenvectors of a real (non-complex) matrix.
Definition: EigenValue.h:107
bool isSymmetric() const
Definition: EigenValue.h:1096
void tql2()
Symmetric tridiagonal QL algorithm.
Definition: EigenValue.h:303
EigenValue(const Matrix< Real > &A)
Check for symmetry, then construct the eigenvalue decomposition.
Definition: EigenValue.h:1104
size_t n_
Row and column dimension (square matrix).
Definition: EigenValue.h:112
const RowMatrix< Real > & getV() const
Return the eigenvector matrix.
Definition: EigenValue.h:1168
const RowMatrix< Real > & getD() const
Computes the block diagonal eigenvalue matrix.
Definition: EigenValue.h:1217
std::vector< Real > ort_
Working storage for nonsymmetric algorithm.
Definition: EigenValue.h:153
bool issymmetric_
Tell if the matrix is symmetric.
Definition: EigenValue.h:117
const std::vector< Real > & getImagEigenValues() const
Return the imaginary parts of the eigenvalues in parameter e.
Definition: EigenValue.h:1182
RowMatrix< Real > H_
Matrix for internal storage of nonsymmetric Hessenberg form.
Definition: EigenValue.h:138
RowMatrix< Real > D_
Matrix for internal storage of eigen values in a matrix form.
Definition: EigenValue.h:146
const std::vector< Real > & getRealEigenValues() const
Return the real parts of the eigenvalues.
Definition: EigenValue.h:1175
void cdiv(Real xr, Real xi, Real yr, Real yi)
Definition: EigenValue.h:550
RowMatrix< Real > V_
Array for internal storage of eigenvectors.
Definition: EigenValue.h:131
std::vector< Real > d_
Definition: EigenValue.h:124
void tred2()
Symmetric Householder reduction to tridiagonal form.
Definition: EigenValue.h:163
void orthes()
Nonsymmetric reduction to Hessenberg form.
Definition: EigenValue.h:442
std::vector< Real > e_
Definition: EigenValue.h:125
Exception base class. Overload exception constructor (to control the exceptions mechanism)....
Definition: Exceptions.h:59
The matrix template interface.
Definition: Matrix.h:61
void resize(size_t nRows, size_t nCols)
Resize the matrix.
Definition: Matrix.h:213
std::string toString(T t)
General template method to convert to a string.
Definition: TextTools.h:153