OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
FComplexEigen.h
Go to the documentation of this file.
1 #ifndef CLASSIC_FComplexEigen_HH
2 #define CLASSIC_FComplexEigen_HH
3 
4 // ------------------------------------------------------------------------
5 // $RCSfile: FComplexEigen.h,v $
6 // ------------------------------------------------------------------------
7 // $Revision: 1.1.1.1 $
8 // ------------------------------------------------------------------------
9 // Copyright: see Copyright.readme
10 // ------------------------------------------------------------------------
11 //
12 // Class: FComplexEigen
13 //
14 // ------------------------------------------------------------------------
15 // Class category: FixedAlgebra
16 // ------------------------------------------------------------------------
17 //
18 // $Date: 2000/03/27 09:32:36 $
19 // $Author: fci $
20 //
21 // ------------------------------------------------------------------------
22 
23 #include "FixedAlgebra/FMatrix.h"
24 #include "FixedAlgebra/FVector.h"
25 #include <cmath>
26 #include <complex>
27 
28 using std::complex;
29 using std::abs;
30 using std::conj;
31 using std::imag;
32 using std::norm;
33 using std::real;
34 using std::swap;
35 
36 
37 // Class FComplexEigen
38 // ------------------------------------------------------------------------
40 // Translated to FORTRAN by Burton S. Garbov, ANL
41 // Adapted March 1997 by F. Christoph Iselin, CERN, SL/AP
42 // Changed to template December 1998 by F. Christoph Iselin, CERN, SL/AP
43 
44 template <int N>
46 
47 public:
48 
50  // Find eigenvalues for matrix [b]M[/b].
51  // If [b]vec[/b] is true, the eigenvectors are also computed.
52  FComplexEigen(const FMatrix<complex<double>, N, N> &M, bool vec = false);
53 
54  FComplexEigen();
57 
59  // Return eigenvalues as complex vector.
60  const FVector<complex<double>, N> &eigenValues() const;
61 
63  // Return eigenvectors as a complex matrix.
64  const FMatrix<complex<double>, N, N> &eigenVectors() const;
65 
66 private:
67 
68  // Not implemented.
69  void operator=(const FComplexEigen &);
70 
71  // Used by eigenvalue and eigenvector routines
72  static void balance(FMatrix<complex<double>, N, N> &,
73  int &low, int &high, double scale[N]);
74 
75  void balbak(int low, int high, const double scale[N]);
76 
77  static void exchange(FMatrix<complex<double>, N, N> &,
78  int j, int m, int low, int high);
79 
80  int hqr(FMatrix<complex<double>, N, N> &, int low, int high);
81 
82  int hqr2(FMatrix<complex<double>, N, N> &, int low, int high,
83  complex<double> ort[N]);
84 
85  static void orthes(FMatrix<complex<double>, N, N> &, int low,
86  int high, complex<double> ort[N]);
87 
88  // Representation of the eigenvalues and eigenvectors.
91 };
92 
93 
94 // Implementation.
95 // ------------------------------------------------------------------------
96 
98 #include "Utilities/SizeError.h"
99 #include <algorithm>
100 #include <cmath>
101 
102 
103 namespace {
104  inline double abssum(complex<double> a) {
105  return std::abs(real(a)) + std::abs(imag(a));
106  }
107 };
108 
109 
110 template <int N>
112  lambda(), vectors()
113 {}
114 
115 
116 template <int N>
118  lambda(rhs.lambda), vectors(rhs.vectors)
119 {}
120 
121 
122 template <int N>
123 FComplexEigen<N>::FComplexEigen(const FMatrix<complex<double>, N, N> &M,
124  bool vec):
125  lambda(), vectors() {
126  for(int i = 0; i < N; ++i) vectors(i, i) = 1.0;
127  FMatrix<complex<double>, N, N> copy(M);
128 
129  int low, upp;
130  double scale[N];
131  balance(copy, low, upp, scale);
132 
133  complex<double> ort[N];
134  orthes(copy, low, upp, ort);
135 
136  if(vec) {
137  if(hqr2(copy, low, upp, ort) != 0) {
138  throw EigenvalueError("FComplexEigen::FComplexEigen()",
139  "Unable to find all eigenvalues.");
140  } else {
141  balbak(low, upp, scale);
142  }
143  } else {
144  if(hqr(copy, low, upp) != 0) {
145  throw EigenvalueError("FComplexEigen::FComplexEigen()",
146  "Unable to find all eigenvalues.");
147  }
148  }
149 }
150 
151 
152 template <int N>
154 
155 }
156 
157 
158 template <int N>
160  return lambda;
161 }
162 
163 
164 template <int N>
166  return vectors;
167 }
168 
169 
170 template <int N>
171 void FComplexEigen<N>::balance(FMatrix<complex<double>, N, N> &copy, int &low,
172  int &upp, double scale[N])
173 // This subroutine is a translation of the Algol procedure "cbalance",
174 // a complex version of "balance",
175 // Num. Math. 13, 293-304(1969) by Parlett and Reinsch.
176 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, 315-326(1971).
177 //
178 // This subroutine balances a complex matrix and isolates eigenvalues
179 // whenever possible.
180 //
181 // On input:
182 // copy Contains the complex<double> matrix to be balanced.
183 //
184 // On output:
185 // copy Contains the balanced matrix.
186 //
187 // low, upp Are two integers such that A[i][j] is zero if:
188 // (1) i is greater than j and
189 // (2) j = 0, ..., low - 1 or i = upp + 1, ..., N - 1.
190 //
191 // scale Contains information determining the permutations and
192 // scaling factors used.
193 //
194 // Suppose that the principal submatrix in rows low through upp has
195 // been balanced, that p[j] denotes the index interchanged with j
196 // during the permutation step, and that the elements of the diagonal
197 // matrix used are denoted by d[i,j]. Then
198 // scale[j] = p[j], for j = 0, ..., low - 1
199 // = d[j,j] j = low, ..., upp
200 // = p[j] j = upp + 1, ..., N - 1.
201 // The order in which the interchanges are made is N - 1 to upp + 1,
202 // then 0 to low - 1.
203 //
204 // Arithmetic is complex<double> throughout.
205 //
206 {
207  low = 0;
208  upp = N - 1;
209 
210  // Search for rows isolating an eigenvalue and push them down.
211  for(int j = upp; ; j--) {
212  for(int i = 0; i <= upp; i++) {
213  if(i != j && copy[j][i] != 0.0) goto next_row;
214  }
215 
216  // Column "j" qualifies for exchange.
217  exchange(copy, j, upp, low, upp);
218  scale[upp] = double(j);
219  j = --upp;
220 
221  // Restart search for next column.
222 next_row:
223  if(j == 0) break;
224  }
225 
226  // Search for columns isolating an eigenvalue and push them left.
227  for(int j = low; ; j++) {
228  for(int i = low; i <= upp; i++) {
229  if(i != j && copy[i][j] != 0.0) goto next_column;
230  }
231 
232  // Column "j" qualifies for exchange.
233  exchange(copy, j, low, low, upp);
234  scale[low] = double(j);
235  j = ++low;
236 
237  // Restart search for next column.
238 next_column:
239  if(j == upp) break;
240  }
241 
242  // Initialize scale factors.
243  for(int i = low; i <= upp; i++) scale[i] = 1.0;
244 
245  // Now balance the submatrix in rows low to upp.
246  const double radix = 16.;
247  const double b2 = radix * radix;
248  bool noconv;
249 
250  // Iterative loop for norm reduction.
251  do {
252  noconv = false;
253 
254  for(int i = low; i <= upp; i++) {
255  double c = 0.0;
256  double r = 0.0;
257 
258  for(int j = low; j <= upp; j++) {
259  if(j != i) {
260  c = c + abssum(copy[j][i]);
261  r = r + abssum(copy[i][j]);
262  }
263  }
264 
265  // Guard against zero c or r due to underflow/
266  if(c != 0.0 && r != 0.0) {
267  double g = r / radix;
268  double f = 1.0;
269  double s = c + r;
270 
271  while(c < g) {
272  f *= radix;
273  c *= b2;
274  }
275 
276  g = r * radix;
277 
278  while(c >= g) {
279  f /= radix;
280  c /= b2;
281  }
282 
283  // Now balance/
284  if((c + r) / f < s * .95) {
285  g = 1.0 / f;
286  scale[i] *= f;
287  noconv = true;
288  for(int j = low; j <= N; j++) copy[i][j] *= g;
289  for(int j = 1; j <= upp; j++) copy[j][i] *= f;
290  }
291  }
292  }
293  } while(noconv);
294 
295  return;
296 }
297 
298 
299 template <int N>
300 void FComplexEigen<N>::balbak(int low, int upp, const double scale[N])
301 // This subroutine is a translation of the Algol procedure cbabk2,
302 // a complex<double> version of balbak,
303 // Num. Math. 13, 293-304(1969) by Parlett and Reinsch.
304 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, 315-326(1971).
305 //
306 // It forms the eigenvectors of a complex general matrix by back
307 // transforming those of the corresponding balanced matrix determined
308 // by "balance".
309 //
310 // On input:
311 // vectors Contains the eigenvectors to be back transformed.
312 //
313 // low, upp Are integers determined by "balance".
314 //
315 // scale Contains information determining the permutations
316 // and scaling factors used by "balance".
317 //
318 // On output:
319 // vectors Contains the the transformed eigenvectors.
320 // Adapted March 1997 by F. Christoph Iselin, CERN, SL/AP
321 {
322  // Apply scale factors found by "balance" to rows low, ..., upp.
323  if(upp != low) {
324  for(int i = low; i <= upp; i++) {
325  double s = scale[i];
326  for(int j = 0; j < N; j++) vectors[i][j] *= s;
327  }
328  }
329 
330  // Exchange rows which were interchanged by "balance".
331  // for i = low-1 step -1 until 0, upp+1 step 1 until n-1 do
332  for(int i = low; i-- > 0;) {
333  int k = int(scale[i]);
334  if(k != i) vectors.swapRows(k, i);
335  }
336 
337  for(int i = upp + 1; i < N; i++) {
338  int k = int(scale[i]);
339  if(k != i) vectors.swapRows(k, i);
340  }
341 
342  return;
343 }
344 
345 
346 template <int N>
348 (FMatrix<complex<double>, N, N> &copy, int j, int m, int low, int upp) {
349  if(j != m) {
350  for(int i = 0; i <= upp; i++) swap(copy[i][j], copy[i][m]);
351  for(int i = low; i <= N; i++) swap(copy[j][i], copy[m][i]);
352  }
353 }
354 
355 
356 template <int N>
357 int FComplexEigen<N>::hqr(FMatrix<complex<double>, N, N> &h,
358  int low, int upp)
359 // This subroutine is a translation of a unitary analogue of the
360 // Algol procedure comlr, Num. Math. 12, 369-376(1968) by Martin
361 // and Wilkinson.
362 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, 396-403(1971).
363 // the unitary analogue substitutes the QR algorithm of Francis
364 // (Comp. Jour. 4, 332-345(1962)) for the LR algorithm.
365 //
366 // This subroutine finds the eigenvalues of a complex
367 // upper Hessenberg matrix by the QR method.
368 //
369 // On input:
370 // h Contains the complex<double> upper Hessenberg matrix.
371 // Its lower triangles below the subdiagonal contain
372 // information about the unitary transformations used in
373 // the reduction by orthes, if performed.
374 //
375 // low, upp Are integers determined by the balancing subroutine "balance".
376 // if "balance" has not been used, set low=1, upp=n.
377 //
378 // On output:
379 // h The upper Hessenberg portion has been destroyed.
380 // Therefore, it must be saved before calling hqr
381 // if subsequent calculation of eigenvectors is to be performed.
382 //
383 // lambda Contains the eigenvalues. If an error exit is made,
384 // the eigenvalues should be correct for indices ierr,...,n.
385 //
386 // The return value is
387 // zero For normal return,
388 // j+1 If the limit of 30n iterations is exhausted
389 // while the j-th eigenvalue is being sought.
390 {
391  complex<double> s, x, y, z;
392 
393  // Create real subdiagonal elements.
394  for(int i = low + 1; i <= upp; i++) {
395  if(imag(h[i][i-1]) != 0.0) {
396  double norm = std::abs(h[i][i-1]);
397  y = h[i][i-1] / norm;
398  h[i][i-1] = complex<double>(norm, 0.0);
399  for(int j = i; j <= upp; j++) h[i][j] = conj(y) * h[i][j];
400  int ll = (upp <= i) ? upp : (i + 1);
401  for(int j = low; j <= ll; j++) h[j][i] = y * h[j][i];
402  }
403  }
404 
405  // Store roots isolated by "balance".
406  for(int i = 0; i < N; i++) {
407  if(i < low || i < upp) lambda[i] = h[i][i];
408  }
409 
410  // Search for eigenvalues,
411  complex<double> t = 0.0;
412  int itn = N * 30;
413 
414  for(int en = upp + 1; en-- > low;) {
415  int its = 0;
416 
417  // Look for single small sub-diagonal element.
418  while(true) {
419  int l;
420  for(l = en; l > low; l--) {
421  double tst1, tst2;
422  tst1 = abssum(h[l-1][l-1]) + abssum(h[l][l]);
423  tst2 = tst1 + std::abs(real(h[l][l-1]));
424  if(tst2 == tst1) break;
425  }
426 
427  // Form shift.
428  if(l == en) break;
429 
430  // Set error -- all eigenvalues have not converged after 30n iterations.
431  if(itn == 0) return (en + 1);
432 
433  if(its != 10 && its != 20) {
434  s = h[en][en];
435  x = h[en-1][en] * real(h[en][en-1]);
436 
437  if(x != 0.0) {
438  y = (h[en-1][en-1] - s) / 2.0;
439  z = sqrt(y * y + x);
440 
441  if(real(y) * real(z) + imag(y) * imag(z) < 0.0)
442  z = - z;
443 
444  x /= (y + z);
445  s -= x;
446  }
447  } else {
448  // Form exceptional shift.
449  s = std::abs(real(h[en][en-1])) + std::abs(real(h[en-1][en-2]));
450  }
451 
452  for(int i = low; i <= en; i++) h[i][i] -= s;
453  t += s;
454  its++;
455  itn--;
456 
457  // Reduce to triangle (rows).
458  for(int i = l + 1; i <= en; i++) {
459  double sr = real(h[i][i-1]);
460  double norm = hypot(std::abs(h[i-1][i-1]), sr);
461  lambda[i-1] = x = h[i-1][i-1] / norm;
462  h[i-1][i-1] = norm;
463  double fi = sr / norm;
464  h[i][i-1] = complex<double>(0.0, fi);
465 
466  for(int j = i; j <= en; j++) {
467  y = h[i-1][j];
468  z = h[i][j];
469  h[i-1][j] = conj(x) * y + fi * z;
470  h[i][j] = x * z - fi * y;
471  }
472  }
473 
474  double si = imag(h[en][en]);
475 
476  if(si != 0.0) {
477  double norm = std::abs(h[en][en]);
478  s = h[en][en] / norm;
479  h[en][en] = norm;
480  }
481 
482  // Inverse operation (columns).
483  for(int j = l + 1; j <= en; j++) {
484  double fi = imag(h[j][j-1]);
485  x = lambda[j-1];
486 
487  for(int i = l; i < j; i++) {
488  y = h[i][j-1];
489  z = h[i][j];
490  h[i][j-1] = x * y + fi * z;
491  h[i][j] = conj(x) * z - fi * y;
492  }
493 
494  double yr = real(h[j][j-1]);
495  z = h[j][j];
496  h[j][j-1] = real(x) * yr + fi * real(z);
497  h[j][j] = conj(x) * z - fi * yr;
498  }
499 
500  if(si != 0.0) {
501  for(int i = l; i <= en; i++) h[i][en] *= s;
502  }
503  }
504 
505  // A root found.
506  lambda[en] = h[en][en] + t;
507  }
508 
509  // All eigenvalues have been found.
510  return 0;
511 }
512 
513 
514 template <int N>
515 int FComplexEigen<N>::hqr2(FMatrix<complex<double>, N, N> &h, int low,
516  int upp, complex<double> ort[N])
517 // This subroutine is a translation of a unitary analogue of the
518 // Algol procedure comlr2, Num. Math. 16, 181-204(1970) by Peters
519 // and Wilkinson.
520 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, 372-395(1971).
521 // the unitary analogue substitutes the QR algorithm of Francis
522 // (Comp. Jour. 4, 332-345(1962)) for the LR algorithm.
523 //
524 // This subroutine finds the eigenvalues and eigenvectors
525 // of a complex<double> upper Hessenberg matrix by the qr
526 // method. The eigenvectors of a complex<double> general matrix
527 // can also be found if orthes has been used to reduce
528 // this general matrix to Hessenberg form.
529 //
530 // On input:
531 // h Contains the complex<double> upper Hessenberg matrix.
532 // Its lower triangle below the subdiagonal contains further
533 // information about the transformations which were used in the
534 // reduction by orthes, if performed. If the eigenvectors of
535 // the Hessenberg matrix are desired, these elements may be
536 // arbitrary.
537 //
538 // low, upp Are integers determined by the balancing subroutine "balance".
539 // If "balance" has not been used, set low=1, upp=n.
540 //
541 // ort Contains information about the unitary transformations
542 // used in the reduction by orthes, if performed.
543 // Only elements low through upp are used. If the eigenvectors
544 // of the Hessenberg matrix are desired, set ort(j) to zero for
545 // these elements.
546 //
547 // On output:
548 // ort And the upper Hessenberg portion of h have been destroyed.
549 //
550 // lambda Contains the eigenvalues. if an error exit is made,
551 // the eigenvalues should be correct for indices ierr,...,n.
552 //
553 // vectors Contains the eigenvectors. The eigenvectors are unnormalized.
554 // If an error exit is made, none of the eigenvectors has been
555 // found.
556 //
557 // The return value is
558 // zero For normal return,
559 // j+1 If the limit of 30n iterations is exhausted
560 // while the j-th eigenvalue is being sought.
561 {
562  complex<double> s, x, y, z;
563 
564  // Form the matrix of accumulated transformations from the information
565  // left by "orthes".
566  for(int i = upp - 1; i > low; i--) {
567  if(ort[i] != 0.0 && h[i][i-1] != 0.0) {
568  // Norm below is negative of h formed in orthes
569  double norm = real(h[i][i-1]) * real(ort[i]) +
570  imag(h[i][i-1]) * imag(ort[i]);
571 
572  for(int k = i + 1; k <= upp; k++) ort[k] = h[k][i-1];
573 
574  for(int j = i; j <= upp; j++) {
575  s = 0.0;
576  for(int k = i; k <= upp; k++) s += conj(ort[k]) * vectors[k][j];
577  s /= norm;
578  for(int k = i; k <= upp; k++) vectors[k][j] += s * ort[k];
579  }
580  }
581  }
582 
583  // Create real subdiagonal elements.
584  for(int i = low + 1; i <= upp; i++) {
585  if(imag(h[i][i-1]) != 0.0) {
586  double norm = std::abs(h[i][i-1]);
587  y = h[i][i-1] / norm;
588  h[i][i-1] = norm;
589  for(int j = i; j < N; j++) h[i][j] = conj(y) * h[i][j];
590  int ll = (upp <= i) ? upp : (i + 1);
591  for(int j = 0; j <= ll; j++) h[j][i] = y * h[j][i];
592  for(int j = low; j <= upp; j++) vectors[j][i] = y * vectors[j][i];
593  }
594  }
595 
596  // Store roots isolated by "balance".
597  for(int i = 0; i < N; i++) {
598  if(i < low || i > upp) lambda[i] = h[i][i];
599  }
600 
601  complex<double> t = 0.0;
602  int itn = N * 30;
603 
604  // Search for eigenvalues.
605  for(int en = upp + 1; en-- > low;) {
606  int its = 0;
607 
608  // Look for single small sub-diagonal element.
609  while(true) {
610  int l;
611  for(l = en; l > low; l--) {
612  double tst1, tst2;
613  tst1 = abssum(h[l-1][l-1]) + abssum(h[l][l]);
614  tst2 = tst1 + std::abs(real(h[l][l-1]));
615  if(tst2 == tst1) break;
616  }
617 
618  if(l == en) break;
619 
620  // Set error -- all eigenvalues have not converged after 30n iterations.
621  if(itn == 0) return (en + 1);
622 
623  if(its != 10 && its != 20) {
624  // Form shift.
625  s = h[en][en];
626  x = h[en-1][en] * real(h[en][en-1]);
627 
628  if(x != 0.0) {
629  y = (h[en-1][en-1] - s) / 2.0;
630  z = sqrt(y * y + x);
631 
632  if(real(y) * real(z) + imag(y) * imag(z) < 0.0)
633  z = - z;
634 
635  x /= (y + z);
636  s -= x;
637  }
638  } else {
639  // Form exceptional shift.
640  s = std::abs(real(h[en][en-1])) + std::abs(real(h[en-1][en-2]));
641  }
642 
643  for(int i = low; i <= en; i++) h[i][i] -= s;
644  t += s;
645  its++;
646  itn--;
647 
648  // Reduce to triangle (rows).
649  for(int i = l + 1; i <= en; i++) {
650  double sr = real(h[i][i-1]);
651  double norm = hypot(std::abs(h[i-1][i-1]), sr);
652  lambda[i-1] = x = h[i-1][i-1] / norm;
653  h[i-1][i-1] = norm;
654  double fi = sr / norm;
655  h[i][i-1] = complex<double>(0.0, fi);
656 
657  for(int j = i; j < N; j++) {
658  y = h[i-1][j];
659  z = h[i][j];
660  h[i-1][j] = conj(x) * y + fi * z;
661  h[i][j] = x * z - fi * y;
662  }
663  }
664 
665  double si = imag(h[en][en]);
666 
667  if(si != 0.0) {
668  double norm = std::abs(h[en][en]);
669  s = h[en][en] / norm;
670  h[en][en] = norm;
671  for(int j = en + 1; j < N; j++) h[en][j] *= conj(s);
672  }
673 
674  // Inverse operation (columns).
675  for(int j = l + 1; j <= en; j++) {
676  x = lambda[j-1];
677  double fi = imag(h[j][j-1]);
678 
679  for(int i = 0; i < j; i++) {
680  y = h[i][j-1];
681  z = h[i][j];
682  h[i][j-1] = x * y + fi * z;
683  h[i][j] = conj(x) * z - fi * y;
684  }
685 
686  double yr = real(h[j][j-1]);
687  z = h[j][j];
688  h[j][j-1] = real(x) * yr + fi * real(z);
689  h[j][j] = conj(x) * z - fi * yr;
690 
691  for(int i = low; i <= upp; i++) {
692  y = vectors[i][j-1];
693  z = vectors[i][j];
694  vectors[i][j-1] = x * y + fi * z;
695  vectors[i][j] = conj(x) * z - fi * y;
696  }
697  }
698 
699  if(si != 0.0) {
700  for(int i = 0; i <= en; i++) h[i][en] *= s;
701  for(int i = low; i <= upp; i++) vectors[i][en] *= s;
702  }
703  }
704 
705  // A root found.
706  h[en][en] += t;
707  lambda[en] = h[en][en];
708  }
709 
710  // All roots found.
711  // Backsubstitute to find vectors of upper triangular form.
712  double norm = 0.0;
713 
714  for(int i = 0; i < N; i++) {
715  for(int j = i; j < N; j++) {
716  double temp = abssum(h[i][j]);
717  if(temp > norm) norm = temp;
718  }
719  }
720 
721  if(N == 1 || norm == 0.0) return 0;
722 
723  for(int en = N - 1; en > 0; en--) {
724  x = lambda[en];
725  h[en][en] = 1.0;
726 
727  for(int i = en; i-- > 0;) {
728  z = 0.0;
729  for(int j = i + 1; j <= en; j++) z += h[i][j] * h[j][en];
730  y = x - lambda[i];
731 
732  if(y == 0.0) {
733  double tst1 = norm;
734  double tst2;
735 
736  do {
737  tst1 *= .01;
738  tst2 = norm + tst1;
739  } while(tst2 > norm);
740 
741  y = tst1;
742  }
743 
744  h[i][en] = z / y;
745 
746  // Overflow control.
747  double temp = abssum(h[i][en]);
748 
749  if(temp != 0.0) {
750  double tst1 = temp;
751  double tst2 = tst1 + 1.0 / tst1;
752 
753  if(tst2 <= tst1) {
754  for(int j = i; j <= en; j++) h[j][en] /= temp;
755  }
756  }
757  }
758  }
759 
760  // End backsubstitution; vectors of isolated roots.
761  for(int i = 0; i < N; i++) {
762  if(i < low || i > upp) {
763  for(int j = i; j <= N; j++) vectors[i][j] = h[i][j];
764  }
765  }
766 
767  // Multiply by transformation matrix to give vectors of original full matrix.
768  for(int j = N; j-- > low;) {
769  int m = (j < upp) ? j : upp;
770 
771  for(int i = low; i <= upp; i++) {
772  z = 0.0;
773  for(int k = low; k <= m; k++) z += vectors[i][k] * h[k][j];
774  vectors[i][j] = z;
775  }
776  }
777 
778  return 0;
779 }
780 
781 
782 template <int N>
783 void FComplexEigen<N>::orthes(FMatrix<complex<double>, N, N> &copy, int low,
784  int upp, complex<double> ort[N])
785 // This subroutine is a translation of a complex<double> analogue of
786 // the Algol procedure orthes, Num. Math. 12, 349-368(1968)
787 // by Martin and Wilkinson.
788 // Handbook for Auto. Comp., Vol.ii-Linear Algebra, 339-358(1971).
789 //
790 // Given a complex<double> general matrix, this subroutine
791 // reduces a submatrix situated in rows and columns
792 // low through upp to upper Hessenberg form by
793 // unitary similarity transformations.
794 //
795 // On input:
796 // copy Contains the complex<double> input matrix.
797 //
798 // low, upp Are integers determined by the balancing subroutine "balance".
799 // if "balance" has not been used, set low=1, upp=n.
800 //
801 // On output:
802 // copy Contains the Hessenberg matrix. Information about the
803 // unitary transformations used in the reduction is stored in
804 // the remaining triangles under the Hessenberg matrix.
805 //
806 // ort Contains further information about the transformations.
807 // Only elements low through upp are used.
808 {
809  for(int m = low + 1; m < upp; m++) {
810  double h = 0.0;
811  ort[m] = 0.0;
812  double scale = 0.0;
813 
814  // Scale column (Algol tol then not needed).
815  for(int i = m; i <= upp; i++) scale += abssum(copy[i][m-1]);
816 
817  if(scale != 0.0) {
818  for(int i = upp + 1; i-- > m;) {
819  ort[i] = copy[i][m-1] / scale;
820  h += norm(ort[i]);
821  }
822 
823  double g = sqrt(h);
824  double f = std::abs(ort[m]);
825 
826  if(f != 0.0) {
827  h += f * g;
828  g /= f;
829  ort[m] *= (g + 1.0);
830  } else {
831  ort[m] = g;
832  copy[m][m-1] = scale;
833  }
834 
835  // Form (I - (u*ut)/h) * A.
836  for(int j = m; j < N; j++) {
837  complex<double> f = 0.0;
838  for(int i = upp + 1; i-- > m;) f += conj(ort[i]) * copy[i][j];
839  f /= h;
840  for(int i = m; i <= upp; i++) copy[i][j] -= f * ort[i];
841  }
842 
843  // Form (I - (u*ut)/h) * A * (I - (u*ut)/h).
844  for(int i = 0; i <= upp; i++) {
845  complex<double> f = 0.0;
846  for(int j = upp + 1; j-- > m;) f += ort[j] * copy[i][j];
847  f /= h;
848  for(int j = m; j <= upp; j++) copy[i][j] -= f * conj(ort[j]);
849  }
850 
851  ort[m] *= scale;
852  copy[m][m-1] = - g * copy[m][m-1];
853  }
854  }
855 }
856 
857 #endif // CLASSIC_FComplexEigen_HH
int hqr2(FMatrix< complex< double >, N, N > &, int low, int high, complex< double > ort[N])
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
static void orthes(FMatrix< complex< double >, N, N > &, int low, int high, complex< double > ort[N])
MMatrix< m_complex > complex(MMatrix< double > real)
Definition: MMatrix.cpp:407
A templated representation for matrices.
Definition: IdealMapper.h:26
int hqr(FMatrix< complex< double >, N, N > &, int low, int high)
A templated representation for vectors.
Definition: PartBunchBase.h:26
FMatrix< complex< double >, N, N > vectors
Definition: FComplexEigen.h:90
FLieGenerator< T, N > real(const FLieGenerator< std::complex< T >, N > &)
Take real part of a complex generator.
void balbak(int low, int high, const double scale[N])
m_complex conj(const m_complex &c)
Definition: MVector.h:105
constexpr double c
The velocity of light in m/s.
Definition: Physics.h:52
static void balance(FMatrix< complex< double >, N, N > &, int &low, int &high, double scale[N])
const FVector< complex< double >, N > & eigenValues() const
Get eigenvalues.
Eigenvalue error exception.
Tps< T > sqrt(const Tps< T > &x)
Square root.
Definition: TpsMath.h:91
Definition: Vec.h:21
Eigenvalues and eigenvectors for a complex general matrix.
Definition: FComplexEigen.h:45
const FMatrix< complex< double >, N, N > & eigenVectors() const
Get eigenvectors.
static void exchange(FMatrix< complex< double >, N, N > &, int j, int m, int low, int high)
void operator=(const FComplexEigen &)
FLieGenerator< T, N > imag(const FLieGenerator< std::complex< T >, N > &)
Take imaginary part of a complex generator.
FVector< complex< double >, N > lambda
Definition: FComplexEigen.h:89