bpp-core  2.2.0
EigenValue.h
Go to the documentation of this file.
1 //
2 // File: EigenValue.h
3 // Created by: Julien Dutheil
4 // Created on: Tue Apr 7 16:24 2004
5 //
6 
7 /*
8 Copyright or © or Copr. Bio++ Development Team, (November 17, 2004)
9 
10 This software is a computer program whose purpose is to provide classes
11 for numerical calculus. This file is part of the Bio++ project.
12 
13 This software is governed by the CeCILL license under French law and
14 abiding by the rules of distribution of free software. You can use,
15 modify and/ or redistribute the software under the terms of the CeCILL
16 license as circulated by CEA, CNRS and INRIA at the following URL
17 "http://www.cecill.info".
18 
19 As a counterpart to the access to the source code and rights to copy,
20 modify and redistribute granted by the license, users are provided only
21 with a limited warranty and the software's author, the holder of the
22 economic rights, and the successive licensors have only limited
23 liability.
24 
25 In this respect, the user's attention is drawn to the risks associated
26 with loading, using, modifying and/or developing or reproducing the
27 software by the user in light of its specific status of free software,
28 that may mean that it is complicated to manipulate, and that also
29 therefore means that it is reserved for developers and experienced
30 professionals having in-depth computer knowledge. Users are therefore
31 encouraged to load and test the software's suitability as regards their
32 requirements in conditions enabling the security of their systems and/or
33 data to be ensured and, more generally, to use and operate it in the
34 same conditions as regards security.
35 
36 The fact that you are presently reading this means that you have had
37 knowledge of the CeCILL license and that you accept its terms.
38 */
39 
40 
41 
42 #ifndef _EIGENVALUE_H_
43 #define _EIGENVALUE_H_
44 #define TOST(i) static_cast<size_t>(i)
45 
46 #include <algorithm>
47 // for min(), max() below
48 
49 #include <cmath>
50 // for abs() below
51 #include <climits>
52 
53 #include "Matrix.h"
54 #include "../NumTools.h"
55 
56 namespace bpp
57 {
58 
104 template <class Real>
106 {
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 = 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 = 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  }
641  else if (l == n-1)
642  {
643  w = H_(TOST(n),TOST(n-1)) * H_(TOST(n-1),TOST(n));
644  p = (H_(TOST(n-1),TOST(n-1)) - H_(TOST(n),TOST(n))) / 2.0;
645  q = p * p + w;
646  z = sqrt(NumTools::abs<Real>(q));
647  H_(TOST(n),TOST(n)) = H_(TOST(n),TOST(n)) + exshift;
648  H_(TOST(n-1),TOST(n-1)) = H_(TOST(n-1),TOST(n-1)) + exshift;
649  x = H_(TOST(n),TOST(n));
650 
651  // Real pair
652 
653  if (q >= 0)
654  {
655  if (p >= 0)
656  {
657  z = p + z;
658  }
659  else
660  {
661  z = p - z;
662  }
663  d_[TOST(n - 1)] = x + z;
664  d_[TOST(n)] = d_[TOST(n - 1)];
665  if (z != 0.0)
666  {
667  d_[TOST(n)] = x - w / z;
668  }
669  e_[TOST(n - 1)] = 0.0;
670  e_[TOST(n)] = 0.0;
671  x = H_(TOST(n),TOST(n-1));
672  s = NumTools::abs<Real>(x) + NumTools::abs<Real>(z);
673  p = x / s;
674  q = z / s;
675  r = sqrt(p * p+q * q);
676  p = p / r;
677  q = q / r;
678 
679  // Row modification
680 
681  for (int j = n-1; j < nn; j++)
682  {
683  z = H_(TOST(n-1),TOST(j));
684  H_(TOST(n-1),TOST(j)) = q * z + p * H_(TOST(n),TOST(j));
685  H_(TOST(n),TOST(j)) = q * H_(TOST(n),TOST(j)) - p * z;
686  }
687 
688  // Column modification
689 
690  for (int i = 0; i <= n; i++)
691  {
692  z = H_(TOST(i),TOST(n-1));
693  H_(TOST(i),TOST(n-1)) = q * z + p * H_(TOST(i),TOST(n));
694  H_(TOST(i),TOST(n)) = q * H_(TOST(i),TOST(n)) - p * z;
695  }
696 
697  // Accumulate transformations
698 
699  for (int i = low; i <= high; i++)
700  {
701  z = V_(TOST(i),TOST(n-1));
702  V_(TOST(i),TOST(n-1)) = q * z + p * V_(TOST(i),TOST(n));
703  V_(TOST(i),TOST(n)) = q * V_(TOST(i),TOST(n)) - p * z;
704  }
705 
706  // Complex pair
707 
708  }
709  else
710  {
711  d_[TOST(n - 1)] = x + p;
712  d_[TOST(n)] = x + p;
713  e_[TOST(n-1)] = z;
714  e_[TOST(n)] = -z;
715  }
716  n = n - 2;
717  iter = 0;
718 
719  // No convergence yet
720 
721  }
722  else
723  {
724  // Form shift
725 
726  x = H_(TOST(n),TOST(n));
727  y = 0.0;
728  w = 0.0;
729  if (l < n)
730  {
731  y = H_(TOST(n-1),TOST(n-1));
732  w = H_(TOST(n),TOST(n-1)) * H_(TOST(n-1),TOST(n));
733  }
734 
735  // Wilkinson's original ad hoc shift
736 
737  if (iter == 10)
738  {
739  exshift += x;
740  for (int i = low; i <= n; i++)
741  {
742  H_(TOST(i),TOST(i)) -= x;
743  }
744  s = NumTools::abs<Real>(H_(TOST(n),TOST(n-1))) + NumTools::abs<Real>(H_(TOST(n-1),TOST(n-2)));
745  x = y = 0.75 * s;
746  w = -0.4375 * s * s;
747  }
748 
749  // MATLAB's new ad hoc shift
750  if (iter == 30)
751  {
752  s = (y - x) / 2.0;
753  s = s * s + w;
754  if (s > 0)
755  {
756  s = sqrt(s);
757  if (y < x)
758  {
759  s = -s;
760  }
761  s = x - w / ((y - x) / 2.0 + s);
762  for (int i = low; i <= n; i++)
763  {
764  H_(TOST(i),TOST(i)) -= s;
765  }
766  exshift += s;
767  x = y = w = 0.964;
768  }
769  }
770 
771  iter = iter + 1; // (Could check iteration count here.)
772 
773  // Look for two consecutive small sub-diagonal elements
774 
775  int m = n-2;
776  while (m >= l)
777  {
778  z = H_(TOST(m),TOST(m));
779  r = x - z;
780  s = y - z;
781  p = (r * s - w) / H_(TOST(m+1),TOST(m)) + H_(TOST(m),TOST(m+1));
782  q = H_(TOST(m+1),TOST(m+1)) - z - r - s;
783  r = H_(TOST(m+2),TOST(m+1));
784  s = NumTools::abs<Real>(p) + NumTools::abs<Real>(q) + NumTools::abs<Real>(r);
785  p = p / s;
786  q = q / s;
787  r = r / s;
788  if (m == l)
789  {
790  break;
791  }
792  if (NumTools::abs<Real>(H_(TOST(m),TOST(m-1))) * (NumTools::abs<Real>(q) + NumTools::abs<Real>(r)) <
793  eps * (NumTools::abs<Real>(p) * (NumTools::abs<Real>(H_(TOST(m-1),TOST(m-1))) + NumTools::abs<Real>(z) +
794  NumTools::abs<Real>(H_(TOST(m+1),TOST(m+1))))))
795  {
796  break;
797  }
798  m--;
799  }
800 
801  for (int i = m+2; i <= n; i++)
802  {
803  H_(TOST(i),TOST(i-2)) = 0.0;
804  if (i > m+2)
805  {
806  H_(TOST(i),TOST(i-3)) = 0.0;
807  }
808  }
809 
810  // Double QR step involving rows l:n and columns m:n
811 
812  for (int k = m; k <= n-1; k++)
813  {
814  int notlast = (k != n-1);
815  if (k != m)
816  {
817  p = H_(TOST(k),TOST(k-1));
818  q = H_(TOST(k+1),TOST(k-1));
819  r = (notlast ? H_(TOST(k+2),TOST(k-1)) : 0.0);
820  x = NumTools::abs<Real>(p) + NumTools::abs<Real>(q) + NumTools::abs<Real>(r);
821  if (x != 0.0)
822  {
823  p = p / x;
824  q = q / x;
825  r = r / x;
826  }
827  }
828  if (x == 0.0)
829  {
830  break;
831  }
832  s = sqrt(p * p + q * q + r * r);
833  if (p < 0)
834  {
835  s = -s;
836  }
837  if (s != 0)
838  {
839  if (k != m)
840  {
841  H_(TOST(k),TOST(k-1)) = -s * x;
842  }
843  else if (l != m)
844  {
845  H_(TOST(k),TOST(k-1)) = -H_(TOST(k),TOST(k-1));
846  }
847  p = p + s;
848  x = p / s;
849  y = q / s;
850  z = r / s;
851  q = q / p;
852  r = r / p;
853 
854  // Row modification
855 
856  for (int j = k; j < nn; j++)
857  {
858  p = H_(TOST(k),TOST(j)) + q * H_(TOST(k+1),TOST(j));
859  if (notlast)
860  {
861  p = p + r * H_(TOST(k+2),TOST(j));
862  H_(TOST(k+2),TOST(j)) = H_(TOST(k+2),TOST(j)) - p * z;
863  }
864  H_(TOST(k),TOST(j)) = H_(TOST(k),TOST(j)) - p * x;
865  H_(TOST(k+1),TOST(j)) = H_(TOST(k+1),TOST(j)) - p * y;
866  }
867 
868  // Column modification
869 
870  for (int i = 0; i <= std::min(n,k+3); i++)
871  {
872  p = x * H_(TOST(i),TOST(k)) + y * H_(TOST(i),TOST(k+1));
873  if (notlast)
874  {
875  p = p + z * H_(TOST(i),TOST(k+2));
876  H_(TOST(i),TOST(k+2)) = H_(TOST(i),TOST(k+2)) - p * r;
877  }
878  H_(TOST(i),TOST(k)) = H_(TOST(i),TOST(k)) - p;
879  H_(TOST(i),TOST(k+1)) = H_(TOST(i),TOST(k+1)) - p * q;
880  }
881 
882  // Accumulate transformations
883 
884  for (int i = low; i <= high; i++)
885  {
886  p = x * V_(TOST(i),TOST(k)) + y * V_(TOST(i),TOST(k+1));
887  if (notlast)
888  {
889  p = p + z * V_(TOST(i),TOST(k+2));
890  V_(TOST(i),TOST(k+2)) = V_(TOST(i),TOST(k+2)) - p * r;
891  }
892  V_(TOST(i),TOST(k)) = V_(TOST(i),TOST(k)) - p;
893  V_(TOST(i),TOST(k+1)) = V_(TOST(i),TOST(k+1)) - p * q;
894  }
895  } // (s != 0)
896  } // k loop
897  } // check convergence
898  } // while (n >= low)
899 
900  // Backsubstitute to find vectors of upper triangular form
901 
902  if (norm == 0.0)
903  {
904  return;
905  }
906 
907  for (n = nn-1; n >= 0; n--)
908  {
909  p = d_[TOST(n)];
910  q = e_[TOST(n)];
911 
912  // Real vector
913 
914  if (q == 0)
915  {
916  int l = n;
917  H_(TOST(n),TOST(n)) = 1.0;
918  for (int i = n-1; i >= 0; i--)
919  {
920  w = H_(TOST(i),TOST(i)) - p;
921  r = 0.0;
922  for (int j = l; j <= n; j++)
923  {
924  r = r + H_(TOST(i),TOST(j)) * H_(TOST(j),TOST(n));
925  }
926  if (e_[TOST(i)] < 0.0)
927  {
928  z = w;
929  s = r;
930  }
931  else
932  {
933  l = i;
934  if (e_[TOST(i)] == 0.0)
935  {
936  if (w != 0.0)
937  {
938  H_(TOST(i),TOST(n)) = -r / w;
939  }
940  else
941  {
942  H_(TOST(i),TOST(n)) = -r / (eps * norm);
943  }
944 
945  // Solve real equations
946 
947  }
948  else
949  {
950  x = H_(TOST(i),TOST(i+1));
951  y = H_(TOST(i+1),TOST(i));
952  q = (d_[TOST(i)] - p) * (d_[TOST(i)] - p) + e_[TOST(i)] * e_[TOST(i)];
953  t = (x * s - z * r) / q;
954  H_(TOST(i),TOST(n)) = t;
955  if (NumTools::abs<Real>(x) > NumTools::abs<Real>(z))
956  {
957  H_(TOST(i+1),TOST(n)) = (-r - w * t) / x;
958  }
959  else
960  {
961  H_(TOST(i+1),TOST(n)) = (-s - y * t) / z;
962  }
963  }
964 
965  // Overflow control
966 
967  t = NumTools::abs<Real>(H_(TOST(i),TOST(n)));
968  if ((eps * t) * t > 1)
969  {
970  for (int j = i; j <= n; j++)
971  {
972  H_(TOST(j),TOST(n)) = H_(TOST(j),TOST(n)) / t;
973  }
974  }
975  }
976  }
977 
978  // Complex vector
979 
980  }
981  else if (q < 0)
982  {
983  int l = n-1;
984 
985  // Last vector component imaginary so matrix is triangular
986 
987  if (NumTools::abs<Real>(H_(TOST(n),TOST(n-1))) > NumTools::abs<Real>(H_(TOST(n-1),TOST(n))))
988  {
989  H_(TOST(n-1),TOST(n-1)) = q / H_(TOST(n),TOST(n-1));
990  H_(TOST(n-1),TOST(n)) = -(H_(TOST(n),TOST(n)) - p) / H_(TOST(n),TOST(n-1));
991  }
992  else
993  {
994  cdiv(0.0,-H_(TOST(n-1),TOST(n)),H_(TOST(n-1),TOST(n-1))-p,q);
995  H_(TOST(n-1),TOST(n-1)) = cdivr;
996  H_(TOST(n-1),TOST(n)) = cdivi;
997  }
998  H_(TOST(n),TOST(n-1)) = 0.0;
999  H_(TOST(n),TOST(n)) = 1.0;
1000  for (int i = n-2; i >= 0; i--)
1001  {
1002  Real ra,sa,vr,vi;
1003  ra = 0.0;
1004  sa = 0.0;
1005  for (int j = l; j <= n; j++)
1006  {
1007  ra = ra + H_(TOST(i),TOST(j)) * H_(TOST(j),TOST(n-1));
1008  sa = sa + H_(TOST(i),TOST(j)) * H_(TOST(j),TOST(n));
1009  }
1010  w = H_(TOST(i),TOST(i)) - p;
1011 
1012  if (e_[TOST(i)] < 0.0)
1013  {
1014  z = w;
1015  r = ra;
1016  s = sa;
1017  }
1018  else
1019  {
1020  l = i;
1021  if (e_[TOST(i)] == 0)
1022  {
1023  cdiv(-ra,-sa,w,q);
1024  H_(TOST(i),TOST(n-1)) = cdivr;
1025  H_(TOST(i),TOST(n)) = cdivi;
1026  }
1027  else
1028  {
1029  // Solve complex equations
1030 
1031  x = H_(TOST(i),TOST(i+1));
1032  y = H_(TOST(i+1),TOST(i));
1033  vr = (d_[TOST(i)] - p) * (d_[TOST(i)] - p) + e_[TOST(i)] * e_[TOST(i)] - q * q;
1034  vi = (d_[TOST(i)] - p) * 2.0 * q;
1035  if ((vr == 0.0) && (vi == 0.0))
1036  {
1037  vr = eps * norm * (NumTools::abs<Real>(w) + NumTools::abs<Real>(q) +
1038  NumTools::abs<Real>(x) + NumTools::abs<Real>(y) + NumTools::abs<Real>(z));
1039  }
1040  cdiv(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);
1041  H_(TOST(i),TOST(n-1)) = cdivr;
1042  H_(TOST(i),TOST(n)) = cdivi;
1043  if (NumTools::abs<Real>(x) > (NumTools::abs<Real>(z) + NumTools::abs<Real>(q)))
1044  {
1045  H_(TOST(i+1),TOST(n-1)) = (-ra - w * H_(TOST(i),TOST(n-1)) + q * H_(TOST(i),TOST(n))) / x;
1046  H_(TOST(i+1),TOST(n)) = (-sa - w * H_(TOST(i),TOST(n)) - q * H_(TOST(i),TOST(n-1))) / x;
1047  }
1048  else
1049  {
1050  cdiv(-r-y*H_(TOST(i),TOST(n-1)),-s-y*H_(TOST(i),TOST(n)),z,q);
1051  H_(TOST(i+1),TOST(n-1)) = cdivr;
1052  H_(TOST(i+1),TOST(n)) = cdivi;
1053  }
1054  }
1055 
1056  // Overflow control
1057  t = std::max(NumTools::abs<Real>(H_(TOST(i),TOST(n-1))),NumTools::abs<Real>(H_(TOST(i),TOST(n))));
1058  if ((eps * t) * t > 1)
1059  {
1060  for (int j = i; j <= n; j++)
1061  {
1062  H_(TOST(j),TOST(n-1)) = H_(TOST(j),TOST(n-1)) / t;
1063  H_(TOST(j),TOST(n)) = H_(TOST(j),TOST(n)) / t;
1064  }
1065  }
1066  }
1067  }
1068  }
1069  }
1070 
1071  // Vectors of isolated roots
1072 
1073  for (int i = 0; i < nn; i++)
1074  {
1075  if (i < low || i > high)
1076  {
1077  for (int j = i; j < nn; j++)
1078  {
1079  V_(TOST(i),TOST(j)) = H_(TOST(i),TOST(j));
1080  }
1081  }
1082  }
1083 
1084  // Back transformation to get eigenvectors of original matrix
1085 
1086  for (int j = nn-1; j >= low; j--)
1087  {
1088  for (int i = low; i <= high; i++)
1089  {
1090  z = 0.0;
1091  for (int k = low; k <= std::min(j,high); k++)
1092  {
1093  z = z + V_(TOST(i),TOST(k)) * H_(TOST(k),TOST(j));
1094  }
1095  V_(TOST(i),TOST(j)) = z;
1096  }
1097  }
1098  }
1099 
1100  public:
1101 
1102  bool isSymmetric() const { return issymmetric_; }
1103 
1104 
1111  n_(A.getNumberOfColumns()),
1112  issymmetric_(true),
1113  d_(n_),
1114  e_(n_),
1115  V_(n_,n_),
1116  H_(),
1117  D_(n_, n_),
1118  ort_(),
1119  cdivr(), cdivi()
1120  {
1121  if (n_ > INT_MAX)
1122  throw Exception("EigenValue: can only be computed for matrices <= " + TextTools::toString(INT_MAX));
1123  for (size_t j = 0; (j < n_) && issymmetric_; j++)
1124  {
1125  for (size_t i = 0; (i < n_) && issymmetric_; i++)
1126  {
1127  issymmetric_ = (A(i,j) == A(j,i));
1128  }
1129  }
1130 
1131  if (issymmetric_)
1132  {
1133  for (size_t i = 0; i < n_; i++)
1134  {
1135  for (size_t j = 0; j < n_; j++)
1136  {
1137  V_(i,j) = A(i,j);
1138  }
1139  }
1140 
1141  // Tridiagonalize.
1142  tred2();
1143 
1144  // Diagonalize.
1145  tql2();
1146  }
1147  else
1148  {
1149  H_.resize(n_,n_);
1150  ort_.resize(n_);
1151 
1152  for (size_t j = 0; j < n_; j++)
1153  {
1154  for (size_t i = 0; i < n_; i++)
1155  {
1156  H_(i,j) = A(i,j);
1157  }
1158  }
1159 
1160  // Reduce to Hessenberg form.
1161  orthes();
1162 
1163  // Reduce Hessenberg to real Schur form.
1164  hqr2();
1165  }
1166  }
1167 
1168 
1174  const RowMatrix<Real>& getV() const { return V_; }
1175 
1181  const std::vector<Real>& getRealEigenValues() const { return d_; }
1182 
1188  const std::vector<Real>& getImagEigenValues() const { return e_; }
1189 
1223  const RowMatrix<Real>& getD() const
1224  {
1225  for (size_t i = 0; i < n_; i++)
1226  {
1227  for (size_t j = 0; j < n_; j++)
1228  {
1229  D_(i,j) = 0.0;
1230  }
1231  D_(i,i) = d_[i];
1232  if (e_[i] > 0)
1233  {
1234  D_(i,i+1) = e_[i];
1235  }
1236  else if (e_[i] < 0)
1237  {
1238  D_(i,i-1) = e_[i];
1239  }
1240  }
1241  return D_;
1242  }
1243 };
1244 
1245 } //end of namespace bpp.
1246 
1247 #endif //_EIGENVALUE_H_
1248 
The matrix template interface.
Definition: Matrix.h:58
bool isSymmetric() const
Definition: EigenValue.h:1102
std::vector< Real > ort_
Working storage for nonsymmetric algorithm.
Definition: EigenValue.h:153
RowMatrix< Real > V_
Array for internal storage of eigenvectors.
Definition: EigenValue.h:131
#define TOST(i)
Definition: EigenValue.h:44
This class allows to perform a correspondence analysis.
static std::string toString(T t)
General template method to convert to a string.
Definition: TextTools.h:189
std::vector< Real > d_
Definition: EigenValue.h:124
const RowMatrix< Real > & getD() const
Computes the block diagonal eigenvalue matrix.
Definition: EigenValue.h:1223
const RowMatrix< Real > & getV() const
Return the eigenvector matrix.
Definition: EigenValue.h:1174
void orthes()
Nonsymmetric reduction to Hessenberg form.
Definition: EigenValue.h:442
void resize(size_t nRows, size_t nCols)
Resize the matrix.
Definition: Matrix.h:208
Computes eigenvalues and eigenvectors of a real (non-complex) matrix.
Definition: EigenValue.h:105
const std::vector< Real > & getImagEigenValues() const
Return the imaginary parts of the eigenvalues in parameter e.
Definition: EigenValue.h:1188
Exception base class.
Definition: Exceptions.h:57
void tql2()
Symmetric tridiagonal QL algorithm.
Definition: EigenValue.h:303
const std::vector< Real > & getRealEigenValues() const
Return the real parts of the eigenvalues.
Definition: EigenValue.h:1181
EigenValue(const Matrix< Real > &A)
Check for symmetry, then construct the eigenvalue decomposition.
Definition: EigenValue.h:1110
bool issymmetric_
Tell if the matrix is symmetric.
Definition: EigenValue.h:117
RowMatrix< Real > D_
Matrix for internal storage of eigen values in a matrix form.
Definition: EigenValue.h:146
std::vector< Real > e_
Definition: EigenValue.h:125
void tred2()
Symmetric Householder reduction to tridiagonal form.
Definition: EigenValue.h:163
size_t n_
Row and column dimension (square matrix).
Definition: EigenValue.h:112
void cdiv(Real xr, Real xi, Real yr, Real yi)
Definition: EigenValue.h:550
RowMatrix< Real > H_
Matrix for internal storage of nonsymmetric Hessenberg form.
Definition: EigenValue.h:138