Rosetta
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
rgg.cc
Go to the documentation of this file.
2 
3 namespace numeric {
4 namespace linear_algebra {
5 
6 using namespace fem::major_types;
7 using fem::common;
8 
9 // double epslon( {{{1
10 
11 /// @brief Estimate unit roundoff in quantities of size x.
12 ///
13 /// This program should function properly on all systems satisfying the
14 /// following two assumptions:
15 ///
16 /// 1. The base used in representing floating point numbers is not a power of
17 /// three.
18 /// 2. The quantity a in statement 10 is represented to the accuracy used in
19 /// floating point variables that are stored in memory.
20 ///
21 /// The statement number 10 and the goto 10 are intended to force optimizing
22 /// compilers to generate code satisfying assumption 2. Under these
23 /// assumptions, it should be true that:
24 ///
25 /// - `a` is not exactly equal to four-thirds.
26 /// - `b` has a zero for its last bit or digit.
27 /// - `c` is not exactly equal to one.
28 /// - `eps` measures the separation of 1.0 from the next larger floating
29 /// point number.
30 ///
31 /// The developers of EISPACK would appreciate being informed about any systems
32 /// where these assumptions do not hold. This version dated 4/6/83. Fable was
33 /// used to convert the original source to C++.
34 
35 double epslon(
36  double const& x) {
37 
38  double return_value = fem::double0;
39  //double a = fem::double0;
40  double b;
41  double c;
42  double eps;
43 
44  double a = 4.0e0 / 3.0e0;
45  statement_10:
46  b = a - 1.0e0;
47  c = b + b + b;
48  eps = fem::dabs(c - 1.0e0);
49  if ( eps == 0.0e0 ) {
50  goto statement_10;
51  }
52  return_value = eps * fem::dabs(x);
53  return return_value;
54 }
55 
56 // void qzhes( {{{1
57 
58 /// @brief This subroutine is the first step of the QZ algorithm for solving
59 /// generalized matrix eigenvalue problems.
60 ///
61 /// This subroutine accepts a pair of real general matrices and reduces one of
62 /// them to upper Hessenberg form and the other to upper triangular form using
63 /// orthogonal transformations. it is usually followed by `qzit`, `qzval` and,
64 /// possibly, `qzvec`.
65 ///
66 /// @param[in] nm Must be set to the row dimension of two-dimensional array
67 /// parameters as declared in the calling program dimension statement.
68 ///
69 /// @param[in] n The order of the matrices.
70 ///
71 /// @param[in] a Contains a real general matrix.
72 ///
73 /// @param[in] b Contains a real general matrix.
74 ///
75 /// @param[in] matz Should be set to `true` if the right hand transformations
76 /// are to be accumulated for later use in computing eigenvectors, and to
77 /// `false` otherwise.
78 ///
79 /// @param[out] a Reduced to upper Hessenberg form. The elements below the
80 /// first subdiagonal have been set to zero.
81 ///
82 /// @param[out] b Reduced to upper triangular form. The elements below the
83 /// main diagonal have been set to zero.
84 ///
85 /// @param[out] z Contains the product of the right hand transformations if
86 /// matz has been set to `true`. Otherwise, `z` is not referenced.
87 ///
88 /// Reference: Siam J. Numer. Anal. 10, 241-256(1973) by Moler and Stewart.
89 ///
90 /// Questions and comments should be directed to Burton S. Garbow,
91 /// Mathematics and Computer Science Division, Argonne National Laboratory.
92 /// This version dated August 1983. Fable was used to convert the original
93 /// Fortran source into C++.
94 
95 void qzhes(
96  int const& nm,
97  int const& n,
98  arr_ref<double, 2> a,
99  arr_ref<double, 2> b,
100  bool const& matz,
101  arr_ref<double, 2> z) {
102 
103  a(dimension(nm, n));
104  b(dimension(nm, n));
105  z(dimension(nm, n));
106  int j = fem::int0;
107  int i = fem::int0;
108  int nm1 = fem::int0;
109  int l = fem::int0;
110  int l1 = fem::int0;
111  double s = fem::double0;
112  double r = fem::double0;
113  double rho = fem::double0;
114  double t = fem::double0;
115  int nm2 = fem::int0;
116  int k = fem::int0;
117  int nk1 = fem::int0;
118  int lb = fem::int0;
119  double u1 = fem::double0;
120  double u2 = fem::double0;
121  double v1 = fem::double0;
122  double v2 = fem::double0;
123 
124  //C .......... initialize z ..........
125  if ( !matz ) {
126  goto statement_10;
127  }
128 
129  FEM_DO_SAFE ( j, 1, n ) {
130  FEM_DO_SAFE ( i, 1, n ) {
131  z(i, j) = 0.0e0;
132  }
133  z(j, j) = 1.0e0;
134  }
135  //C .......... reduce b to upper triangular form ..........
136  statement_10:
137  if ( n <= 1 ) {
138  goto statement_170;
139  }
140  nm1 = n - 1;
141 
142  FEM_DO_SAFE ( l, 1, nm1 ) {
143  l1 = l + 1;
144  s = 0.0e0;
145 
146  FEM_DO_SAFE ( i, l1, n ) {
147  s += fem::dabs(b(i, l));
148  }
149 
150  if ( s == 0.0e0 ) {
151  goto statement_100;
152  }
153  s += fem::dabs(b(l, l));
154  r = 0.0e0;
155 
156  FEM_DO_SAFE ( i, l, n ) {
157  b(i, l) = b(i, l) / s;
158  r += fem::pow2(b(i, l));
159  }
160 
161  r = fem::dsign(fem::dsqrt(r), b(l, l));
162  b(l, l) += r;
163  rho = r * b(l, l);
164 
165  FEM_DO_SAFE ( j, l1, n ) {
166  t = 0.0e0;
167 
168  FEM_DO_SAFE ( i, l, n ) {
169  t += b(i, l) * b(i, j);
170  }
171 
172  t = -t / rho;
173 
174  FEM_DO_SAFE ( i, l, n ) {
175  b(i, j) += t * b(i, l);
176  }
177 
178  }
179 
180  FEM_DO_SAFE ( j, 1, n ) {
181  t = 0.0e0;
182 
183  FEM_DO_SAFE ( i, l, n ) {
184  t += b(i, l) * a(i, j);
185  }
186 
187  t = -t / rho;
188 
189  FEM_DO_SAFE ( i, l, n ) {
190  a(i, j) += t * b(i, l);
191  }
192 
193  }
194 
195  b(l, l) = -s * r;
196 
197  FEM_DO_SAFE ( i, l1, n ) {
198  b(i, l) = 0.0e0;
199  }
200 
201  statement_100:;
202  }
203  //C .......... reduce a to upper hessenberg form, while
204  //C keeping b triangular ..........
205  if ( n == 2 ) {
206  goto statement_170;
207  }
208  nm2 = n - 2;
209 
210  FEM_DO_SAFE ( k, 1, nm2 ) {
211  nk1 = nm1 - k;
212  //C .......... for l=n-1 step -1 until k+1 do -- ..........
213  FEM_DO_SAFE ( lb, 1, nk1 ) {
214  l = n - lb;
215  l1 = l + 1;
216  //C .......... zero a(l+1,k) ..........
217  s = fem::dabs(a(l, k)) + fem::dabs(a(l1, k));
218  if ( s == 0.0e0 ) {
219  goto statement_150;
220  }
221  u1 = a(l, k) / s;
222  u2 = a(l1, k) / s;
223  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
224  v1 = -(u1 + r) / r;
225  v2 = -u2 / r;
226  u2 = v2 / v1;
227 
228  FEM_DO_SAFE ( j, k, n ) {
229  t = a(l, j) + u2 * a(l1, j);
230  a(l, j) += t * v1;
231  a(l1, j) += t * v2;
232  }
233 
234  a(l1, k) = 0.0e0;
235 
236  FEM_DO_SAFE ( j, l, n ) {
237  t = b(l, j) + u2 * b(l1, j);
238  b(l, j) += t * v1;
239  b(l1, j) += t * v2;
240  }
241  //C .......... zero b(l+1,l) ..........
242  s = fem::dabs(b(l1, l1)) + fem::dabs(b(l1, l));
243  if ( s == 0.0e0 ) {
244  goto statement_150;
245  }
246  u1 = b(l1, l1) / s;
247  u2 = b(l1, l) / s;
248  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
249  v1 = -(u1 + r) / r;
250  v2 = -u2 / r;
251  u2 = v2 / v1;
252 
253  FEM_DO_SAFE ( i, 1, l1 ) {
254  t = b(i, l1) + u2 * b(i, l);
255  b(i, l1) += t * v1;
256  b(i, l) += t * v2;
257  }
258 
259  b(l1, l) = 0.0e0;
260 
261  FEM_DO_SAFE ( i, 1, n ) {
262  t = a(i, l1) + u2 * a(i, l);
263  a(i, l1) += t * v1;
264  a(i, l) += t * v2;
265  }
266 
267  if ( !matz ) {
268  goto statement_150;
269  }
270 
271  FEM_DO_SAFE ( i, 1, n ) {
272  t = z(i, l1) + u2 * z(i, l);
273  z(i, l1) += t * v1;
274  z(i, l) += t * v2;
275  }
276 
277  statement_150:;
278  }
279 
280  }
281 
282  statement_170:;
283 }
284 
285 // void qzit( {{{1
286 
287 /// @brief This subroutine is the second step of the QZ algorithm
288 /// for solving generalized matrix eigenvalue problems.
289 ///
290 /// This subroutine accepts a pair of real matrices, one of them
291 /// in upper Hessenberg form and the other in upper triangular form.
292 /// it reduces the Hessenberg matrix to quasi-triangular form using
293 /// orthogonal transformations while maintaining the triangular form
294 /// of the other matrix. It is usually preceded by `qzhes` and
295 /// followed by `qzval` and, possibly, `qzvec`.
296 ///
297 /// @param[in] nm Must be set to the row dimension of two-dimensional array
298 /// parameters as declared in the calling program dimension statement.
299 ///
300 /// @param[in] n The order of the matrices.
301 ///
302 /// @param[in] a Contains a real upper Hessenberg matrix.
303 ///
304 /// @param[in] b Contains a real upper triangular matrix.
305 ///
306 /// @param[in] eps1 A tolerance used to determine negligible elements. Zero or
307 /// negative values may be given, in which case an element will be neglected
308 /// only if it is less than roundoff error times the norm of its matrix. If
309 /// the input `eps1` is positive, then an element will be considered negligible
310 /// if it is less than `eps1` times the norm of its matrix. A positive value
311 /// of `eps1` may result in faster execution, but less accurate results.
312 ///
313 /// @param[in] matz Should be set to `true` if the right hand transformations
314 /// are to be accumulated for later use in computing eigenvectors, and to
315 /// `false` otherwise.
316 ///
317 /// @param[in] z Contains, if matz has been set to `true`, the transformation
318 /// matrix produced in the reduction by `qzhes`, if performed, or else the
319 /// identity matrix. if `matz` has been set to `false`, `z` is not referenced.
320 ///
321 /// @param[out] a Reduced to quasi-triangular form. The elements below the
322 /// first subdiagonal are still zero and no two consecutive subdiagonal
323 /// elements are nonzero.
324 ///
325 /// @param[out] b Still in upper triangular form, although its elements have
326 /// been altered. The location `b(n,1)` is used to store `eps1` times the norm
327 /// of `b` for later use by `qzval` and `qzvec`.
328 ///
329 /// @param[out] z Contains the product of the right hand transformations (for
330 /// both steps) if `matz` has been set to `true`.
331 ///
332 /// @param[out] ierr Set to zero for normal return, `j` if the limit of 30*n
333 /// iterations is exhausted while the j-th eigenvalue is being sought.
334 ///
335 /// Reference: Siam J. Numer. Anal. 10, 241-256(1973) by Moler and Stewart,
336 /// as modified in technical note NASA tn D-7305(1973) by Ward.
337 ///
338 /// Questions and comments should be directed to Burton S. Garbow,
339 /// Mathematics and Computer Science Division, Argonne National Laboratory.
340 /// This version dated August 1983. Fable was used to convert the original
341 /// Fortran source into C++.
342 
343 
344 void qzit(
345  int const& nm,
346  int const& n,
347  arr_ref<double, 2> a,
348  arr_ref<double, 2> b,
349  double const& eps1,
350  bool const& matz,
351  arr_ref<double, 2> z,
352  int& ierr) {
353 
354  a(dimension(nm, n));
355  b(dimension(nm, n));
356  z(dimension(nm, n));
357  //double anorm = fem::double0;
358  //double bnorm = fem::double0;
359  int i = fem::int0;
360  double ani = fem::double0;
361  double bni = fem::double0;
362  int j = fem::int0;
363  double ep = fem::double0;
364  double epsa = fem::double0;
365  double epsb = fem::double0;
366  int lor1 = fem::int0;
367  int enorn = fem::int0;
368  int en = fem::int0;
369  int itn = fem::int0;
370  int its = fem::int0;
371  int na = fem::int0;
372  int enm2 = fem::int0;
373  int ish = fem::int0;
374  int ll = fem::int0;
375  int lm1 = fem::int0;
376  int l = fem::int0;
377  int ld = fem::int0;
378  int l1 = fem::int0;
379  double b11 = fem::double0;
380  double s = fem::double0;
381  double u1 = fem::double0;
382  double u2 = fem::double0;
383  double r = fem::double0;
384  double v1 = fem::double0;
385  double v2 = fem::double0;
386  double t = fem::double0;
387  double a11 = fem::double0;
388  double a21 = fem::double0;
389  double b22 = fem::double0;
390  double b33 = fem::double0;
391  double b44 = fem::double0;
392  double a33 = fem::double0;
393  double a34 = fem::double0;
394  double a43 = fem::double0;
395  double a44 = fem::double0;
396  double b34 = fem::double0;
397  double sh = fem::double0;
398  double a1 = fem::double0;
399  double a2 = fem::double0;
400  double a12 = fem::double0;
401  double a22 = fem::double0;
402  double b12 = fem::double0;
403  double a3 = fem::double0;
404  int k = fem::int0;
405  bool notlas = fem::bool0;
406  int k1 = fem::int0;
407  int k2 = fem::int0;
408  int km1 = fem::int0;
409  double u3 = fem::double0;
410  double v3 = fem::double0;
411 
412  ierr = 0;
413  //C .......... compute epsa,epsb ..........
414  double anorm = 0.0e0;
415  double bnorm = 0.0e0;
416 
417  FEM_DO_SAFE ( i, 1, n ) {
418  ani = 0.0e0;
419  if ( i != 1 ) {
420  ani = fem::dabs(a(i, i - 1));
421  }
422  bni = 0.0e0;
423 
424  FEM_DO_SAFE ( j, i, n ) {
425  ani += fem::dabs(a(i, j));
426  bni += fem::dabs(b(i, j));
427  }
428 
429  if ( ani > anorm ) {
430  anorm = ani;
431  }
432  if ( bni > bnorm ) {
433  bnorm = bni;
434  }
435  }
436 
437  if ( anorm == 0.0e0 ) {
438  anorm = 1.0e0;
439  }
440  if ( bnorm == 0.0e0 ) {
441  bnorm = 1.0e0;
442  }
443  ep = eps1;
444  if ( ep > 0.0e0 ) {
445  goto statement_50;
446  }
447  //C .......... use roundoff level if eps1 is zero ..........
448  ep = epslon(1.0e0);
449  statement_50:
450  epsa = ep * anorm;
451  epsb = ep * bnorm;
452  //C .......... reduce a to quasi-triangular form, while
453  //C keeping b triangular ..........
454  lor1 = 1;
455  enorn = n;
456  en = n;
457  itn = 30 * n;
458  //C .......... begin qz step ..........
459  statement_60:
460  if ( en <= 2 ) {
461  goto statement_1001;
462  }
463  if ( !matz ) {
464  enorn = en;
465  }
466  its = 0;
467  na = en - 1;
468  enm2 = na - 1;
469  statement_70:
470  ish = 2;
471  //C .......... check for convergence or reducibility.
472  //C for l=en step -1 until 1 do -- ..........
473  FEM_DO_SAFE ( ll, 1, en ) {
474  lm1 = en - ll;
475  l = lm1 + 1;
476  if ( l == 1 ) {
477  goto statement_95;
478  }
479  if ( fem::dabs(a(l, lm1)) <= epsa ) {
480  goto statement_90;
481  }
482  }
483 
484  statement_90:
485  a(l, lm1) = 0.0e0;
486  if ( l < na ) {
487  goto statement_95;
488  }
489  //C .......... 1-by-1 or 2-by-2 block isolated ..........
490  en = lm1;
491  goto statement_60;
492  //C .......... check for small top of b ..........
493  statement_95:
494  ld = l;
495  statement_100:
496  l1 = l + 1;
497  b11 = b(l, l);
498  if ( fem::dabs(b11) > epsb ) {
499  goto statement_120;
500  }
501  b(l, l) = 0.0e0;
502  s = fem::dabs(a(l, l)) + fem::dabs(a(l1, l));
503  u1 = a(l, l) / s;
504  u2 = a(l1, l) / s;
505  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
506  v1 = -(u1 + r) / r;
507  v2 = -u2 / r;
508  u2 = v2 / v1;
509 
510  FEM_DO_SAFE ( j, l, enorn ) {
511  t = a(l, j) + u2 * a(l1, j);
512  a(l, j) += t * v1;
513  a(l1, j) += t * v2;
514  t = b(l, j) + u2 * b(l1, j);
515  b(l, j) += t * v1;
516  b(l1, j) += t * v2;
517  }
518 
519  if ( l != 1 ) {
520  a(l, lm1) = -a(l, lm1);
521  }
522  lm1 = l;
523  l = l1;
524  goto statement_90;
525  statement_120:
526  a11 = a(l, l) / b11;
527  a21 = a(l1, l) / b11;
528  if ( ish == 1 ) {
529  goto statement_140;
530  }
531  //C .......... iteration strategy ..........
532  if ( itn == 0 ) {
533  goto statement_1000;
534  }
535  if ( its == 10 ) {
536  goto statement_155;
537  }
538  //C .......... determine type of shift ..........
539  b22 = b(l1, l1);
540  if ( fem::dabs(b22) < epsb ) {
541  b22 = epsb;
542  }
543  b33 = b(na, na);
544  if ( fem::dabs(b33) < epsb ) {
545  b33 = epsb;
546  }
547  b44 = b(en, en);
548  if ( fem::dabs(b44) < epsb ) {
549  b44 = epsb;
550  }
551  a33 = a(na, na) / b33;
552  a34 = a(na, en) / b44;
553  a43 = a(en, na) / b33;
554  a44 = a(en, en) / b44;
555  b34 = b(na, en) / b44;
556  t = 0.5e0 * (a43 * b34 - a33 - a44);
557  r = t * t + a34 * a43 - a33 * a44;
558  if ( r < 0.0e0 ) {
559  goto statement_150;
560  }
561  //C .......... determine single shift zeroth column of a ..........
562  ish = 1;
563  r = fem::dsqrt(r);
564  sh = -t + r;
565  s = -t - r;
566  if ( fem::dabs(s - a44) < fem::dabs(sh - a44) ) {
567  sh = s;
568  }
569  //C .......... look for two consecutive small
570  //C sub-diagonal elements of a.
571  //C for l=en-2 step -1 until ld do -- ..........
572  FEM_DO_SAFE ( ll, ld, enm2 ) {
573  l = enm2 + ld - ll;
574  if ( l == ld ) {
575  goto statement_140;
576  }
577  lm1 = l - 1;
578  l1 = l + 1;
579  t = a(l, l);
580  if ( fem::dabs(b(l, l)) > epsb ) {
581  t = t - sh * b(l, l);
582  }
583  if ( fem::dabs(a(l, lm1)) <= fem::dabs(t / a(l1, l)) * epsa ) {
584  goto statement_100;
585  }
586  }
587 
588  statement_140:
589  a1 = a11 - sh;
590  a2 = a21;
591  if ( l != ld ) {
592  a(l, lm1) = -a(l, lm1);
593  }
594  goto statement_160;
595  //C .......... determine double shift zeroth column of a ..........
596  statement_150:
597  a12 = a(l, l1) / b22;
598  a22 = a(l1, l1) / b22;
599  b12 = b(l, l1) / b22;
600  a1 = ((a33 - a11) * (a44 - a11) - a34 * a43 + a43 * b34 * a11) /
601  a21 + a12 - a11 * b12;
602  a2 = (a22 - a11) - a21 * b12 - (a33 - a11) - (a44 - a11) + a43 * b34;
603  a3 = a(l1 + 1, l1) / b22;
604  goto statement_160;
605  //C .......... ad hoc shift ..........
606  statement_155:
607  a1 = 0.0e0;
608  a2 = 1.0e0;
609  a3 = 1.1605e0;
610  statement_160:
611  its++;
612  itn = itn - 1;
613  if ( !matz ) {
614  lor1 = ld;
615  }
616  //C .......... main loop ..........
617  FEM_DO_SAFE ( k, l, na ) {
618  notlas = k != na && ish == 2;
619  k1 = k + 1;
620  k2 = k + 2;
621  km1 = fem::max0(k - 1, l);
622  ll = fem::min0(en, k1 + ish);
623  if ( notlas ) {
624  goto statement_190;
625  }
626  //C .......... zero a(k+1,k-1) ..........
627  if ( k == l ) {
628  goto statement_170;
629  }
630  a1 = a(k, km1);
631  a2 = a(k1, km1);
632  statement_170:
633  s = fem::dabs(a1) + fem::dabs(a2);
634  if ( s == 0.0e0 ) {
635  goto statement_70;
636  }
637  u1 = a1 / s;
638  u2 = a2 / s;
639  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
640  v1 = -(u1 + r) / r;
641  v2 = -u2 / r;
642  u2 = v2 / v1;
643 
644  FEM_DO_SAFE ( j, km1, enorn ) {
645  t = a(k, j) + u2 * a(k1, j);
646  a(k, j) += t * v1;
647  a(k1, j) += t * v2;
648  t = b(k, j) + u2 * b(k1, j);
649  b(k, j) += t * v1;
650  b(k1, j) += t * v2;
651  }
652 
653  if ( k != l ) {
654  a(k1, km1) = 0.0e0;
655  }
656  goto statement_240;
657  //C .......... zero a(k+1,k-1) and a(k+2,k-1) ..........
658  statement_190:
659  if ( k == l ) {
660  goto statement_200;
661  }
662  a1 = a(k, km1);
663  a2 = a(k1, km1);
664  a3 = a(k2, km1);
665  statement_200:
666  s = fem::dabs(a1) + fem::dabs(a2) + fem::dabs(a3);
667  if ( s == 0.0e0 ) {
668  goto statement_260;
669  }
670  u1 = a1 / s;
671  u2 = a2 / s;
672  u3 = a3 / s;
673  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2 + u3 * u3), u1);
674  v1 = -(u1 + r) / r;
675  v2 = -u2 / r;
676  v3 = -u3 / r;
677  u2 = v2 / v1;
678  u3 = v3 / v1;
679 
680  FEM_DO_SAFE ( j, km1, enorn ) {
681  t = a(k, j) + u2 * a(k1, j) + u3 * a(k2, j);
682  a(k, j) += t * v1;
683  a(k1, j) += t * v2;
684  a(k2, j) += t * v3;
685  t = b(k, j) + u2 * b(k1, j) + u3 * b(k2, j);
686  b(k, j) += t * v1;
687  b(k1, j) += t * v2;
688  b(k2, j) += t * v3;
689  }
690 
691  if ( k == l ) {
692  goto statement_220;
693  }
694  a(k1, km1) = 0.0e0;
695  a(k2, km1) = 0.0e0;
696  //C .......... zero b(k+2,k+1) and b(k+2,k) ..........
697  statement_220:
698  s = fem::dabs(b(k2, k2)) + fem::dabs(b(k2, k1)) + fem::dabs(b(k2, k));
699  if ( s == 0.0e0 ) {
700  goto statement_240;
701  }
702  u1 = b(k2, k2) / s;
703  u2 = b(k2, k1) / s;
704  u3 = b(k2, k) / s;
705  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2 + u3 * u3), u1);
706  v1 = -(u1 + r) / r;
707  v2 = -u2 / r;
708  v3 = -u3 / r;
709  u2 = v2 / v1;
710  u3 = v3 / v1;
711 
712  FEM_DO_SAFE ( i, lor1, ll ) {
713  t = a(i, k2) + u2 * a(i, k1) + u3 * a(i, k);
714  a(i, k2) += t * v1;
715  a(i, k1) += t * v2;
716  a(i, k) += t * v3;
717  t = b(i, k2) + u2 * b(i, k1) + u3 * b(i, k);
718  b(i, k2) += t * v1;
719  b(i, k1) += t * v2;
720  b(i, k) += t * v3;
721  }
722 
723  b(k2, k) = 0.0e0;
724  b(k2, k1) = 0.0e0;
725  if ( !matz ) {
726  goto statement_240;
727  }
728 
729  FEM_DO_SAFE ( i, 1, n ) {
730  t = z(i, k2) + u2 * z(i, k1) + u3 * z(i, k);
731  z(i, k2) += t * v1;
732  z(i, k1) += t * v2;
733  z(i, k) += t * v3;
734  }
735  //C .......... zero b(k+1,k) ..........
736  statement_240:
737  s = fem::dabs(b(k1, k1)) + fem::dabs(b(k1, k));
738  if ( s == 0.0e0 ) {
739  goto statement_260;
740  }
741  u1 = b(k1, k1) / s;
742  u2 = b(k1, k) / s;
743  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
744  v1 = -(u1 + r) / r;
745  v2 = -u2 / r;
746  u2 = v2 / v1;
747 
748  FEM_DO_SAFE ( i, lor1, ll ) {
749  t = a(i, k1) + u2 * a(i, k);
750  a(i, k1) += t * v1;
751  a(i, k) += t * v2;
752  t = b(i, k1) + u2 * b(i, k);
753  b(i, k1) += t * v1;
754  b(i, k) += t * v2;
755  }
756 
757  b(k1, k) = 0.0e0;
758  if ( !matz ) {
759  goto statement_260;
760  }
761 
762  FEM_DO_SAFE ( i, 1, n ) {
763  t = z(i, k1) + u2 * z(i, k);
764  z(i, k1) += t * v1;
765  z(i, k) += t * v2;
766  }
767 
768  statement_260:;
769  }
770  //C .......... end qz step ..........
771  goto statement_70;
772  //C .......... set error -- all eigenvalues have not
773  //C converged after 30*n iterations ..........
774  statement_1000:
775  ierr = en;
776  //C .......... save epsb for use by qzval and qzvec ..........
777  statement_1001:
778  if ( n > 1 ) {
779  b(n, 1) = epsb;
780  }
781 }
782 
783 // void qzval( {{{1
784 
785 /// @brief This subroutine is the third step of the QZ algorithm
786 /// for solving generalized matrix eigenvalue problems,
787 ///
788 /// This subroutine accepts a pair of real matrices, one of them
789 /// in quasi-triangular form and the other in upper triangular form.
790 /// It reduces the quasi-triangular matrix further, so that any
791 /// remaining 2-by-2 blocks correspond to pairs of complex
792 /// eigenvalues, and returns quantities whose ratios give the
793 /// generalized eigenvalues. It is usually preceded by `qzhes`
794 /// and `qzit` and may be followed by `qzvec`.
795 ///
796 /// @param[in] nm Must be set to the row dimension of two-dimensional array
797 /// parameters as declared in the calling program dimension statement.
798 ///
799 /// @param[in] n The order of the matrices.
800 ///
801 /// @param[in] a Contains a real upper quasi-triangular matrix.
802 ///
803 /// @param[in] b Contains a real upper triangular matrix. In addition,
804 /// location `b(n,1)` contains the tolerance quantity `epsb` computed and saved
805 /// in `qzit`.
806 ///
807 /// @param[in] matz Should be set to `true` if the right hand transformations
808 /// are to be accumulated for later use in computing eigenvectors, and to
809 /// `false` otherwise.
810 ///
811 /// @param[in] z Contains, if `matz` has been set to `true`, the transformation
812 /// matrix produced in the reductions by `qzhes` and `qzit`, if performed, or
813 /// else the identity matrix. If `matz` has been set to `false`, `z` is not
814 /// referenced.
815 ///
816 /// @param[out] a Reduced further to a quasi-triangular matrix in which all
817 /// nonzero subdiagonal elements correspond to pairs of complex eigenvalues.
818 ///
819 /// @param[out] b Still in upper triangular form, although its elements have
820 /// been altered. `b(n,1)` is unaltered.
821 ///
822 /// @param[out] alfr,alfi Contain the real and imaginary parts of the diagonal
823 /// elements of the triangular matrix that would be obtained if a were reduced
824 /// completely to triangular form by unitary transformations. Non-zero values
825 /// of `alfi` occur in pairs, the first member positive and the second
826 /// negative.
827 ///
828 /// @param[out] beta Contains the diagonal elements of the corresponding `b`,
829 /// normalized to be real and non-negative. The generalized eigenvalues are
830 /// then the ratios \f$\frac{\mathrm{alfr} + i \times \mathrm{alfi}}
831 /// {\mathrm{beta}}\f$.
832 ///
833 /// @param[out] z Contains the product of the right hand transformations (for
834 /// all three steps) if `matz` has been set to `true`.
835 ///
836 /// Reference: Siam J. Numer. Anal. 10, 241-256(1973) by Moler and Stewart.
837 ///
838 /// Questions and comments should be directed to Burton S. Garbow,
839 /// Mathematics and Computer Science Division, Argonne National Laboratory.
840 /// This version dated August 1983. Fable was used to convert the original
841 /// Fortran source into C++.
842 
843 void qzval(
844  int const& nm,
845  int const& n,
846  arr_ref<double, 2> a,
847  arr_ref<double, 2> b,
848  arr_ref<double> alfr,
849  arr_ref<double> alfi,
850  arr_ref<double> beta,
851  bool const& matz,
852  arr_ref<double, 2> z) {
853 
854  a(dimension(nm, n));
855  b(dimension(nm, n));
856  alfr(dimension(n));
857  alfi(dimension(n));
858  beta(dimension(n));
859  z(dimension(nm, n));
860  //double epsb = fem::double0;
861  //int isw = fem::int0;
862  int nn = fem::int0;
863  int en = fem::int0;
864  int na = fem::int0;
865  double a1 = fem::double0;
866  double a2 = fem::double0;
867  double bn = fem::double0;
868  double an = fem::double0;
869  double a11 = fem::double0;
870  double a12 = fem::double0;
871  double a21 = fem::double0;
872  double a22 = fem::double0;
873  double b11 = fem::double0;
874  double b12 = fem::double0;
875  double b22 = fem::double0;
876  double e = fem::double0;
877  double ei = fem::double0;
878  double s = fem::double0;
879  double t = fem::double0;
880  double c = fem::double0;
881  double d = fem::double0;
882  double u1 = fem::double0;
883  double u2 = fem::double0;
884  double r = fem::double0;
885  double v1 = fem::double0;
886  double v2 = fem::double0;
887  int i = fem::int0;
888  int j = fem::int0;
889  double a11r = fem::double0;
890  double a11i = fem::double0;
891  double a12r = fem::double0;
892  double a12i = fem::double0;
893  double a22r = fem::double0;
894  double a22i = fem::double0;
895  double a1i = fem::double0;
896  double a2i = fem::double0;
897  double cz = fem::double0;
898  double szr = fem::double0;
899  double szi = fem::double0;
900  double cq = fem::double0;
901  double sqr = fem::double0;
902  double sqi = fem::double0;
903  double ssr = fem::double0;
904  double ssi = fem::double0;
905  double tr = fem::double0;
906  double ti = fem::double0;
907  double dr = fem::double0;
908  double di = fem::double0;
909 
910  double epsb = b(n, 1);
911  int isw = 1;
912  //C .......... find eigenvalues of quasi-triangular matrices.
913  //C for en=n step -1 until 1 do -- ..........
914  FEM_DO_SAFE ( nn, 1, n ) {
915  en = n + 1 - nn;
916  na = en - 1;
917  if ( isw == 2 ) {
918  goto statement_505;
919  }
920  if ( en == 1 ) {
921  goto statement_410;
922  }
923  if ( a(en, na) != 0.0e0 ) {
924  goto statement_420;
925  }
926  //C .......... 1-by-1 block, one real root ..........
927  statement_410:
928  alfr(en) = a(en, en);
929  if ( b(en, en) < 0.0e0 ) {
930  alfr(en) = -alfr(en);
931  }
932  beta(en) = fem::dabs(b(en, en));
933  alfi(en) = 0.0e0;
934  goto statement_510;
935  //C .......... 2-by-2 block ..........
936  statement_420:
937  if ( fem::dabs(b(na, na)) <= epsb ) {
938  goto statement_455;
939  }
940  if ( fem::dabs(b(en, en)) > epsb ) {
941  goto statement_430;
942  }
943  a1 = a(en, en);
944  a2 = a(en, na);
945  bn = 0.0e0;
946  goto statement_435;
947  statement_430:
948  an = fem::dabs(a(na, na)) + fem::dabs(a(na, en)) + fem::dabs(a(en,
949  na)) + fem::dabs(a(en, en));
950  bn = fem::dabs(b(na, na)) + fem::dabs(b(na, en)) + fem::dabs(b(en, en));
951  a11 = a(na, na) / an;
952  a12 = a(na, en) / an;
953  a21 = a(en, na) / an;
954  a22 = a(en, en) / an;
955  b11 = b(na, na) / bn;
956  b12 = b(na, en) / bn;
957  b22 = b(en, en) / bn;
958  e = a11 / b11;
959  ei = a22 / b22;
960  s = a21 / (b11 * b22);
961  t = (a22 - e * b22) / b22;
962  if ( fem::dabs(e) <= fem::dabs(ei) ) {
963  goto statement_431;
964  }
965  e = ei;
966  t = (a11 - e * b11) / b11;
967  statement_431:
968  c = 0.5e0 * (t - s * b12);
969  d = c * c + s * (a12 - e * b12);
970  if ( d < 0.0e0 ) {
971  goto statement_480;
972  }
973  //C .......... two real roots.
974  //C zero both a(en,na) and b(en,na) ..........
975  e += (c + fem::dsign(fem::dsqrt(d), c));
976  a11 = a11 - e * b11;
977  a12 = a12 - e * b12;
978  a22 = a22 - e * b22;
979  if ( fem::dabs(a11) + fem::dabs(a12) < fem::dabs(a21) + fem::dabs(a22) ) {
980  goto statement_432;
981  }
982  a1 = a12;
983  a2 = a11;
984  goto statement_435;
985  statement_432:
986  a1 = a22;
987  a2 = a21;
988  //C .......... choose and apply real z ..........
989  statement_435:
990  s = fem::dabs(a1) + fem::dabs(a2);
991  u1 = a1 / s;
992  u2 = a2 / s;
993  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
994  v1 = -(u1 + r) / r;
995  v2 = -u2 / r;
996  u2 = v2 / v1;
997 
998  FEM_DO_SAFE ( i, 1, en ) {
999  t = a(i, en) + u2 * a(i, na);
1000  a(i, en) += t * v1;
1001  a(i, na) += t * v2;
1002  t = b(i, en) + u2 * b(i, na);
1003  b(i, en) += t * v1;
1004  b(i, na) += t * v2;
1005  }
1006 
1007  if ( !matz ) {
1008  goto statement_450;
1009  }
1010 
1011  FEM_DO_SAFE ( i, 1, n ) {
1012  t = z(i, en) + u2 * z(i, na);
1013  z(i, en) += t * v1;
1014  z(i, na) += t * v2;
1015  }
1016 
1017  statement_450:
1018  if ( bn == 0.0e0 ) {
1019  goto statement_475;
1020  }
1021  if ( an < fem::dabs(e) * bn ) {
1022  goto statement_455;
1023  }
1024  a1 = b(na, na);
1025  a2 = b(en, na);
1026  goto statement_460;
1027  statement_455:
1028  a1 = a(na, na);
1029  a2 = a(en, na);
1030  //C .......... choose and apply real q ..........
1031  statement_460:
1032  s = fem::dabs(a1) + fem::dabs(a2);
1033  if ( s == 0.0e0 ) {
1034  goto statement_475;
1035  }
1036  u1 = a1 / s;
1037  u2 = a2 / s;
1038  r = fem::dsign(fem::dsqrt(u1 * u1 + u2 * u2), u1);
1039  v1 = -(u1 + r) / r;
1040  v2 = -u2 / r;
1041  u2 = v2 / v1;
1042 
1043  FEM_DO_SAFE ( j, na, n ) {
1044  t = a(na, j) + u2 * a(en, j);
1045  a(na, j) += t * v1;
1046  a(en, j) += t * v2;
1047  t = b(na, j) + u2 * b(en, j);
1048  b(na, j) += t * v1;
1049  b(en, j) += t * v2;
1050  }
1051 
1052  statement_475:
1053  a(en, na) = 0.0e0;
1054  b(en, na) = 0.0e0;
1055  alfr(na) = a(na, na);
1056  alfr(en) = a(en, en);
1057  if ( b(na, na) < 0.0e0 ) {
1058  alfr(na) = -alfr(na);
1059  }
1060  if ( b(en, en) < 0.0e0 ) {
1061  alfr(en) = -alfr(en);
1062  }
1063  beta(na) = fem::dabs(b(na, na));
1064  beta(en) = fem::dabs(b(en, en));
1065  alfi(en) = 0.0e0;
1066  alfi(na) = 0.0e0;
1067  goto statement_505;
1068  //C .......... two complex roots ..........
1069  statement_480:
1070  e += c;
1071  ei = fem::dsqrt(-d);
1072  a11r = a11 - e * b11;
1073  a11i = ei * b11;
1074  a12r = a12 - e * b12;
1075  a12i = ei * b12;
1076  a22r = a22 - e * b22;
1077  a22i = ei * b22;
1078  if ( fem::dabs(a11r) + fem::dabs(a11i) + fem::dabs(a12r) +
1079  fem::dabs(a12i) < fem::dabs(a21) + fem::dabs(a22r) +
1080  fem::dabs(a22i) ) {
1081  goto statement_482;
1082  }
1083  a1 = a12r;
1084  a1i = a12i;
1085  a2 = -a11r;
1086  a2i = -a11i;
1087  goto statement_485;
1088  statement_482:
1089  a1 = a22r;
1090  a1i = a22i;
1091  a2 = -a21;
1092  a2i = 0.0e0;
1093  //C .......... choose complex z ..........
1094  statement_485:
1095  cz = fem::dsqrt(a1 * a1 + a1i * a1i);
1096  if ( cz == 0.0e0 ) {
1097  goto statement_487;
1098  }
1099  szr = (a1 * a2 + a1i * a2i) / cz;
1100  szi = (a1 * a2i - a1i * a2) / cz;
1101  r = fem::dsqrt(cz * cz + szr * szr + szi * szi);
1102  cz = cz / r;
1103  szr = szr / r;
1104  szi = szi / r;
1105  goto statement_490;
1106  statement_487:
1107  szr = 1.0e0;
1108  szi = 0.0e0;
1109  statement_490:
1110  if ( an < (fem::dabs(e) + ei) * bn ) {
1111  goto statement_492;
1112  }
1113  a1 = cz * b11 + szr * b12;
1114  a1i = szi * b12;
1115  a2 = szr * b22;
1116  a2i = szi * b22;
1117  goto statement_495;
1118  statement_492:
1119  a1 = cz * a11 + szr * a12;
1120  a1i = szi * a12;
1121  a2 = cz * a21 + szr * a22;
1122  a2i = szi * a22;
1123  //C .......... choose complex q ..........
1124  statement_495:
1125  cq = fem::dsqrt(a1 * a1 + a1i * a1i);
1126  if ( cq == 0.0e0 ) {
1127  goto statement_497;
1128  }
1129  sqr = (a1 * a2 + a1i * a2i) / cq;
1130  sqi = (a1 * a2i - a1i * a2) / cq;
1131  r = fem::dsqrt(cq * cq + sqr * sqr + sqi * sqi);
1132  cq = cq / r;
1133  sqr = sqr / r;
1134  sqi = sqi / r;
1135  goto statement_500;
1136  statement_497:
1137  sqr = 1.0e0;
1138  sqi = 0.0e0;
1139  //C .......... compute diagonal elements that would result
1140  //C if transformations were applied ..........
1141  statement_500:
1142  ssr = sqr * szr + sqi * szi;
1143  ssi = sqr * szi - sqi * szr;
1144  i = 1;
1145  tr = cq * cz * a11 + cq * szr * a12 + sqr * cz * a21 + ssr * a22;
1146  ti = cq * szi * a12 - sqi * cz * a21 + ssi * a22;
1147  dr = cq * cz * b11 + cq * szr * b12 + ssr * b22;
1148  di = cq * szi * b12 + ssi * b22;
1149  goto statement_503;
1150  statement_502:
1151  i = 2;
1152  tr = ssr * a11 - sqr * cz * a12 - cq * szr * a21 + cq * cz * a22;
1153  ti = -ssi * a11 - sqi * cz * a12 + cq * szi * a21;
1154  dr = ssr * b11 - sqr * cz * b12 + cq * cz * b22;
1155  di = -ssi * b11 - sqi * cz * b12;
1156  statement_503:
1157  t = ti * dr - tr * di;
1158  j = na;
1159  if ( t < 0.0e0 ) {
1160  j = en;
1161  }
1162  r = fem::dsqrt(dr * dr + di * di);
1163  beta(j) = bn * r;
1164  alfr(j) = an * (tr * dr + ti * di) / r;
1165  alfi(j) = an * t / r;
1166  if ( i == 1 ) {
1167  goto statement_502;
1168  }
1169  statement_505:
1170  isw = 3 - isw;
1171  statement_510:;
1172  }
1173  b(n, 1) = epsb;
1174 
1175 }
1176 
1177 // void qzvec( {{{1
1178 
1179 /// @brief This subroutine is the optional fourth step of the QZ algorithm for
1180 /// solving generalized matrix eigenvalue problems.
1181 ///
1182 /// This subroutine accepts a pair of real matrices, one of them in
1183 /// quasi-triangular form (in which each 2-by-2 block corresponds to a pair of
1184 /// complex eigenvalues) and the other in upper triangular form. It computes
1185 /// the eigenvectors of the triangular problem and transforms the results back
1186 /// to the original coordinate system. It is usually preceded by `qzhes`,
1187 /// `qzit`, and `qzval`.
1188 ///
1189 /// @param[in] nm Must be set to the row dimension of two-dimensional array
1190 /// parameters as declared in the calling program dimension statement.
1191 ///
1192 /// @param[in] n The order of the matrices.
1193 ///
1194 /// @param[in] a Contains a real upper quasi-triangular matrix. Not altered by
1195 /// this subroutine. Its subdiagonal elements provide information about the
1196 /// storage of the complex eigenvectors.
1197 ///
1198 /// @param[in] b Contains a real upper triangular matrix. In addition,
1199 /// location `b(n,1)` contains the tolerance quantity `epsb` computed and saved
1200 /// in `qzit`.
1201 ///
1202 /// @param[in] alfr,alfi,beta Vectors with components whose ratios
1203 /// \f$\frac{\mathrm{alfr} + i \times \mathrm{alfi} } {\mathrm{beta}}\f$ are
1204 /// the generalized eigenvalues. They are usually obtained from `qzval`.
1205 ///
1206 /// @param[in] z Contains the transformation matrix produced in the reductions
1207 /// by `qzhes`, `qzit`, and `qzval`, if performed. If the eigenvectors of the
1208 /// triangular problem are desired, `z` must contain the identity matrix.
1209 ///
1210 /// @param[out] b Destroyed.
1211 ///
1212 /// @param[out] z Contains the real and imaginary parts of the eigenvectors.
1213 /// Each eigenvector is normalized so that the modulus of its largest component
1214 /// is 1.0.
1215 /// - if `alfi(i) == 0.0`, the i-th eigenvalue is real and the i-th column
1216 /// of z contains its eigenvector.
1217 /// - if `alfi(i) != 0.0`, the i-th eigenvalue is complex.
1218 /// - if `alfi(i) > 0.0`, the eigenvalue is the first of a complex pair and
1219 /// the i-th and (i+1)-th columns of `z` contain its eigenvector.
1220 /// - if `alfi(i) < 0.0`, the eigenvalue is the second of a complex pair
1221 /// and the (i-1)-th and i-th columns of z contain the conjugate of its
1222 /// eigenvector.
1223 ///
1224 /// Reference: Siam J. Numer. Anal. 10, 241-256(1973) by Moler and Stewart.
1225 ///
1226 /// Questions and comments should be directed to Burton S. Garbow,
1227 /// Mathematics and Computer Science Division, Argonne National Laboratory.
1228 /// This version dated August 1983. Fable was used to convert the original
1229 /// Fortran source into C++.
1230 
1231 
1232 void qzvec(
1233  int const& nm,
1234  int const& n,
1235  arr_cref<double, 2> a,
1236  arr_ref<double, 2> b,
1237  arr_cref<double> alfr,
1238  arr_cref<double> alfi,
1239  arr_cref<double> beta,
1240  arr_ref<double, 2> z) {
1241 
1242  a(dimension(nm, n));
1243  b(dimension(nm, n));
1244  alfr(dimension(n));
1245  alfi(dimension(n));
1246  beta(dimension(n));
1247  z(dimension(nm, n));
1248  //double epsb = fem::double0;
1249  //int isw = fem::int0;
1250  int nn = fem::int0;
1251  int en = fem::int0;
1252  int na = fem::int0;
1253  int m = fem::int0;
1254  double alfm = fem::double0;
1255  double betm = fem::double0;
1256  int ii = fem::int0;
1257  int i = fem::int0;
1258  double w = fem::double0;
1259  double r = fem::double0;
1260  int j = fem::int0;
1261  double zz = fem::double0;
1262  double s = fem::double0;
1263  double t = fem::double0;
1264  double x = fem::double0;
1265  double y = fem::double0;
1266  double q = fem::double0;
1267  double almr = fem::double0;
1268  double almi = fem::double0;
1269  int enm2 = fem::int0;
1270  double w1 = fem::double0;
1271  double ra = fem::double0;
1272  double sa = fem::double0;
1273  double x1 = fem::double0;
1274  double z1 = fem::double0;
1275  double tr = fem::double0;
1276  double ti = fem::double0;
1277  double dr = fem::double0;
1278  double di = fem::double0;
1279  double rr = fem::double0;
1280  double d = fem::double0;
1281  double t1 = fem::double0;
1282  double t2 = fem::double0;
1283  int jj = fem::int0;
1284  int k = fem::int0;
1285 
1286  double epsb = b(n, 1);
1287  int isw = 1;
1288  //C .......... for en=n step -1 until 1 do -- ..........
1289  FEM_DO_SAFE ( nn, 1, n ) {
1290  en = n + 1 - nn;
1291  na = en - 1;
1292  if ( isw == 2 ) {
1293  goto statement_795;
1294  }
1295  if ( alfi(en) != 0.0e0 ) {
1296  goto statement_710;
1297  }
1298  //C .......... real vector ..........
1299  m = en;
1300  b(en, en) = 1.0e0;
1301  if ( na == 0 ) {
1302  goto statement_800;
1303  }
1304  alfm = alfr(m);
1305  betm = beta(m);
1306  //C .......... for i=en-1 step -1 until 1 do -- ..........
1307  FEM_DO_SAFE ( ii, 1, na ) {
1308  i = en - ii;
1309  w = betm * a(i, i) - alfm * b(i, i);
1310  r = 0.0e0;
1311 
1312  FEM_DO_SAFE ( j, m, en ) {
1313  r += (betm * a(i, j) - alfm * b(i, j)) * b(j, en);
1314  }
1315 
1316  if ( i == 1 || isw == 2 ) {
1317  goto statement_630;
1318  }
1319  if ( betm * a(i, i - 1) == 0.0e0 ) {
1320  goto statement_630;
1321  }
1322  zz = w;
1323  s = r;
1324  goto statement_690;
1325  statement_630:
1326  m = i;
1327  if ( isw == 2 ) {
1328  goto statement_640;
1329  }
1330  //C .......... real 1-by-1 block ..........
1331  t = w;
1332  if ( w == 0.0e0 ) {
1333  t = epsb;
1334  }
1335  b(i, en) = -r / t;
1336  goto statement_700;
1337  //C .......... real 2-by-2 block ..........
1338  statement_640:
1339  x = betm * a(i, i + 1) - alfm * b(i, i + 1);
1340  y = betm * a(i + 1, i);
1341  q = w * zz - x * y;
1342  t = (x * s - zz * r) / q;
1343  b(i, en) = t;
1344  if ( fem::dabs(x) <= fem::dabs(zz) ) {
1345  goto statement_650;
1346  }
1347  b(i + 1, en) = (-r - w * t) / x;
1348  goto statement_690;
1349  statement_650:
1350  b(i + 1, en) = (-s - y * t) / zz;
1351  statement_690:
1352  isw = 3 - isw;
1353  statement_700:;
1354  }
1355  //C .......... end real vector ..........
1356  goto statement_800;
1357  //C .......... complex vector ..........
1358  statement_710:
1359  m = na;
1360  almr = alfr(m);
1361  almi = alfi(m);
1362  betm = beta(m);
1363  //C .......... last vector component chosen imaginary so that
1364  //C eigenvector matrix is triangular ..........
1365  y = betm * a(en, na);
1366  b(na, na) = -almi * b(en, en) / y;
1367  b(na, en) = (almr * b(en, en) - betm * a(en, en)) / y;
1368  b(en, na) = 0.0e0;
1369  b(en, en) = 1.0e0;
1370  enm2 = na - 1;
1371  if ( enm2 == 0 ) {
1372  goto statement_795;
1373  }
1374  //C .......... for i=en-2 step -1 until 1 do -- ..........
1375  FEM_DO_SAFE ( ii, 1, enm2 ) {
1376  i = na - ii;
1377  w = betm * a(i, i) - almr * b(i, i);
1378  w1 = -almi * b(i, i);
1379  ra = 0.0e0;
1380  sa = 0.0e0;
1381 
1382  FEM_DO_SAFE ( j, m, en ) {
1383  x = betm * a(i, j) - almr * b(i, j);
1384  x1 = -almi * b(i, j);
1385  ra += x * b(j, na) - x1 * b(j, en);
1386  sa += x * b(j, en) + x1 * b(j, na);
1387  }
1388 
1389  if ( i == 1 || isw == 2 ) {
1390  goto statement_770;
1391  }
1392  if ( betm * a(i, i - 1) == 0.0e0 ) {
1393  goto statement_770;
1394  }
1395  zz = w;
1396  z1 = w1;
1397  r = ra;
1398  s = sa;
1399  isw = 2;
1400  goto statement_790;
1401  statement_770:
1402  m = i;
1403  if ( isw == 2 ) {
1404  goto statement_780;
1405  }
1406  //C .......... complex 1-by-1 block ..........
1407  tr = -ra;
1408  ti = -sa;
1409  statement_773:
1410  dr = w;
1411  di = w1;
1412  //C .......... complex divide (t1,t2) = (tr,ti) / (dr,di) ..........
1413  statement_775:
1414  if ( fem::dabs(di) > fem::dabs(dr) ) {
1415  goto statement_777;
1416  }
1417  rr = di / dr;
1418  d = dr + di * rr;
1419  t1 = (tr + ti * rr) / d;
1420  t2 = (ti - tr * rr) / d;
1421  switch (isw) {
1422  case 1 : goto statement_787;
1423  case 2 : goto statement_782;
1424  default : break;
1425  }
1426  statement_777:
1427  rr = dr / di;
1428  d = dr * rr + di;
1429  t1 = (tr * rr + ti) / d;
1430  t2 = (ti * rr - tr) / d;
1431  switch (isw) {
1432  case 1 : goto statement_787;
1433  case 2 : goto statement_782;
1434  default : break;
1435  }
1436  //C .......... complex 2-by-2 block ..........
1437  statement_780:
1438  x = betm * a(i, i + 1) - almr * b(i, i + 1);
1439  x1 = -almi * b(i, i + 1);
1440  y = betm * a(i + 1, i);
1441  tr = y * ra - w * r + w1 * s;
1442  ti = y * sa - w * s - w1 * r;
1443  dr = w * zz - w1 * z1 - x * y;
1444  di = w * z1 + w1 * zz - x1 * y;
1445  if ( dr == 0.0e0 && di == 0.0e0 ) {
1446  dr = epsb;
1447  }
1448  goto statement_775;
1449  statement_782:
1450  b(i + 1, na) = t1;
1451  b(i + 1, en) = t2;
1452  isw = 1;
1453  if ( fem::dabs(y) > fem::dabs(w) + fem::dabs(w1) ) {
1454  goto statement_785;
1455  }
1456  tr = -ra - x * b(i + 1, na) + x1 * b(i + 1, en);
1457  ti = -sa - x * b(i + 1, en) - x1 * b(i + 1, na);
1458  goto statement_773;
1459  statement_785:
1460  t1 = (-r - zz * b(i + 1, na) + z1 * b(i + 1, en)) / y;
1461  t2 = (-s - zz * b(i + 1, en) - z1 * b(i + 1, na)) / y;
1462  statement_787:
1463  b(i, na) = t1;
1464  b(i, en) = t2;
1465  statement_790:;
1466  }
1467  //C .......... end complex vector ..........
1468  statement_795:
1469  isw = 3 - isw;
1470  statement_800:;
1471  }
1472  //C .......... end back substitution.
1473  //C transform to original coordinate system.
1474  //C for j=n step -1 until 1 do -- ..........
1475  FEM_DO_SAFE ( jj, 1, n ) {
1476  j = n + 1 - jj;
1477 
1478  FEM_DO_SAFE ( i, 1, n ) {
1479  zz = 0.0e0;
1480 
1481  FEM_DO_SAFE ( k, 1, j ) {
1482  zz += z(i, k) * b(k, j);
1483  }
1484 
1485  z(i, j) = zz;
1486  }
1487  }
1488  //C .......... normalize so that modulus of largest
1489  //C component of each vector is 1.
1490  //C (isw is 1 initially from before) ..........
1491  FEM_DO_SAFE ( j, 1, n ) {
1492  d = 0.0e0;
1493  if ( isw == 2 ) {
1494  goto statement_920;
1495  }
1496  if ( alfi(j) != 0.0e0 ) {
1497  goto statement_945;
1498  }
1499 
1500  FEM_DO_SAFE ( i, 1, n ) {
1501  if ( fem::dabs(z(i, j)) > d ) {
1502  d = fem::dabs(z(i, j));
1503  }
1504  }
1505 
1506  FEM_DO_SAFE ( i, 1, n ) {
1507  z(i, j) = z(i, j) / d;
1508  }
1509 
1510  goto statement_950;
1511 
1512  statement_920:
1513  FEM_DO_SAFE ( i, 1, n ) {
1514  r = fem::dabs(z(i, j - 1)) + fem::dabs(z(i, j));
1515  if ( r != 0.0e0 ) {
1516  r = r * fem::dsqrt(fem::pow2((z(i, j - 1) / r)) + fem::pow2((z(i,
1517  j) / r)));
1518  }
1519  if ( r > d ) {
1520  d = r;
1521  }
1522  }
1523 
1524  FEM_DO_SAFE ( i, 1, n ) {
1525  z(i, j - 1) = z(i, j - 1) / d;
1526  z(i, j) = z(i, j) / d;
1527  }
1528 
1529  statement_945:
1530  isw = 3 - isw;
1531  statement_950:;
1532  }
1533 
1534 }
1535 
1536 // void rgg( {{{1
1537 
1538 /// @brief This subroutine calls the recommended sequence of
1539 /// subroutines from the eigensystem subroutine package (EISPACK)
1540 /// to find the eigenvalues and eigenvectors (if desired)
1541 /// for the real general generalized eigenproblem \f$ Ax = \lambda Bx \f$.
1542 ///
1543 /// @param[in] nm Must be set to the row dimension of the two-dimensional
1544 /// array parameters as declared in the calling program dimension statement.
1545 ///
1546 /// @param[in] n The order of the matrices \f$A\f$ and \f$B\f$.
1547 ///
1548 /// @param[in] a A real general matrix.
1549 ///
1550 /// @param[in] b A real general matrix.
1551 ///
1552 /// @param[in] matz An integer variable set equal to zero if only eigenvalues
1553 /// are desired. otherwise it is set to any non-zero integer for both
1554 /// eigenvalues and eigenvectors.
1555 ///
1556 /// @param[out] alfr The real parts of the numerators of the eigenvalues.
1557 ///
1558 /// @param[out] alfi The imaginary parts of the numerators of the eigenvalues.
1559 ///
1560 /// @param[out] beta The denominators of the eigenvalues, which are thus given
1561 /// by the ratios \f$\frac{\mathrm{alfr} + i \times \mathrm{alfi}}
1562 /// {\mathrm{beta}}\f$. Complex conjugate pairs of eigenvalues appear
1563 /// consecutively with the eigenvalue having the positive imaginary part first.
1564 ///
1565 /// @param[out] z The real and imaginary parts of the eigenvectors if matz is
1566 /// not zero. If the j-th eigenvalue is real, the j-th column of z contains
1567 /// its eigenvector. If the j-th eigenvalue is complex with positive imaginary
1568 /// part, the j-th and (j+1)-th columns of z contain the real and imaginary
1569 /// parts of its eigenvector. The conjugate of this vector is the eigenvector
1570 /// for the conjugate eigenvalue.
1571 ///
1572 /// @param[out] ierr An integer output variable set equal to an error
1573 /// completion code described in the documentation for qzit. The normal
1574 /// completion code is zero.
1575 ///
1576 /// Questions and comments should be directed to Burton S. Garbow,
1577 /// Mathematics and Computer Science Division, Argonne National Laboratory.
1578 /// This version dated August 1983. Fable was used to convert the original
1579 /// Fortran source into C++.
1580 
1581 void rgg(
1582  int const& nm,
1583  int const& n,
1584  arr_ref<double, 2> a,
1585  arr_ref<double, 2> b,
1586  arr_ref<double> alfr,
1587  arr_ref<double> alfi,
1588  arr_ref<double> beta,
1589  int const& matz,
1590  arr_ref<double, 2> z,
1591  int& ierr) {
1592 
1593  a(dimension(nm, n));
1594  b(dimension(nm, n));
1595  alfr(dimension(n));
1596  alfi(dimension(n));
1597  beta(dimension(n));
1598  z(dimension(nm, n));
1599  bool tf = fem::bool0;
1600 
1601  if ( n <= nm ) {
1602  goto statement_10;
1603  }
1604  ierr = 10 * n;
1605  goto statement_50;
1606 
1607  statement_10:
1608  if ( matz != 0 ) {
1609  goto statement_20;
1610  }
1611  //C .......... find eigenvalues only ..........
1612  tf = false;
1613  qzhes(nm, n, a, b, tf, z);
1614  qzit(nm, n, a, b, 0.0e0, tf, z, ierr);
1615  qzval(nm, n, a, b, alfr, alfi, beta, tf, z);
1616  goto statement_50;
1617  //C .......... find both eigenvalues and eigenvectors ..........
1618  statement_20:
1619  tf = true;
1620  qzhes(nm, n, a, b, tf, z);
1621  qzit(nm, n, a, b, 0.0e0, tf, z, ierr);
1622  qzval(nm, n, a, b, alfr, alfi, beta, tf, z);
1623  if ( ierr != 0 ) {
1624  goto statement_50;
1625  }
1626  qzvec(nm, n, a, b, alfr, alfi, beta, z);
1627  statement_50:;
1628 }
1629 // }}}1
1630 
1631 } // namespace linear_algebra
1632 } // namespace numeric
Header file for the EISPACK rgg routine.
cmplx w(cmplx z, double relerr)
Definition: functions.cc:470
void qzhes(int const &nm, int const &n, arr_ref< double, 2 > a, arr_ref< double, 2 > b, bool const &matz, arr_ref< double, 2 > z)
This subroutine is the first step of the QZ algorithm for solving generalized matrix eigenvalue probl...
Definition: rgg.cc:95
def x
void qzval(int const &nm, int const &n, arr_ref< double, 2 > a, arr_ref< double, 2 > b, arr_ref< double > alfr, arr_ref< double > alfi, arr_ref< double > beta, bool const &matz, arr_ref< double, 2 > z)
This subroutine is the third step of the QZ algorithm for solving generalized matrix eigenvalue probl...
Definition: rgg.cc:843
void qzit(int const &nm, int const &n, arr_ref< double, 2 > a, arr_ref< double, 2 > b, double const &eps1, bool const &matz, arr_ref< double, 2 > z, int &ierr)
This subroutine is the second step of the QZ algorithm for solving generalized matrix eigenvalue prob...
Definition: rgg.cc:344
def z
void qzvec(int const &nm, int const &n, arr_cref< double, 2 > a, arr_ref< double, 2 > b, arr_cref< double > alfr, arr_cref< double > alfi, arr_cref< double > beta, arr_ref< double, 2 > z)
This subroutine is the optional fourth step of the QZ algorithm for solving generalized matrix eigenv...
Definition: rgg.cc:1232
THREAD_LOCAL basic::Tracer tr("struc_set_fragment_picker")
double epslon(double const &x)
Estimate unit roundoff in quantities of size x.
Definition: rgg.cc:35
void rgg(int const &nm, int const &n, arr_ref< double, 2 > a, arr_ref< double, 2 > b, arr_ref< double > alfr, arr_ref< double > alfi, arr_ref< double > beta, int const &matz, arr_ref< double, 2 > z, int &ierr)
This subroutine calls the recommended sequence of subroutines from the eigensystem subroutine package...
Definition: rgg.cc:1581
def y