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