<T>LAPACK 0.1.1
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
lahqz.hpp
Go to the documentation of this file.
1
5//
6// Copyright (c) 2021-2023, University of Colorado Denver. All rights reserved.
7//
8// This file is part of <T>LAPACK.
9// <T>LAPACK is free software: you can redistribute it and/or modify it under
10// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
11
12#ifndef TLAPACK_LAHQZ_HH
13#define TLAPACK_LAHQZ_HH
14
16
18#include "tlapack/blas/rot.hpp"
19#include "tlapack/blas/rotg.hpp"
24
25namespace tlapack {
26
57template <TLAPACK_CSMATRIX matrix_t,
58 TLAPACK_VECTOR alpha_t,
59 TLAPACK_VECTOR beta_t>
60int lahqz(bool want_s,
61 bool want_q,
62 bool want_z,
65 matrix_t& A,
66 matrix_t& B,
68 beta_t& beta,
69 matrix_t& Q,
70 matrix_t& Z)
71{
72 using TA = type_t<matrix_t>;
73 using real_t = real_type<TA>;
74 using idx_t = size_type<matrix_t>;
76
77 // Functor
79
80 // constants
81 const real_t zero(0);
82 const real_t one(1);
83 const real_t eps = ulp<real_t>();
85 const idx_t non_convergence_limit = 10;
86
87 const idx_t n = ncols(A);
88 const idx_t nh = ihi - ilo;
89
90 // check arguments
91 tlapack_check_false(n != nrows(A));
92 tlapack_check_false(n != ncols(B));
93 tlapack_check_false(n != nrows(B));
94 tlapack_check_false((idx_t)size(alpha) != n);
95 tlapack_check_false((idx_t)size(beta) != n);
96 if (want_q) {
97 tlapack_check_false((n != ncols(Q)) or (n != nrows(Q)));
98 }
99 if (want_z) {
100 tlapack_check_false((n != ncols(Z)) or (n != nrows(Z)));
101 }
102
103 // quick return
104 if (nh <= 0) return 0;
105 if (nh == 1) {
106 alpha[ilo] = A(ilo, ilo);
107 beta[ilo] = B(ilo, ilo);
108 }
109
110 // itmax is the total number of QR iterations allowed.
111 // For most matrices, 3 shifts per eigenvalue is enough, so
112 // we set itmax to 30 times nh as a safe limit.
113 const idx_t itmax = 30 * std::max<idx_t>(10, nh);
114
115 // k_defl counts the number of iterations since a deflation
116 idx_t k_defl = 0;
117
118 // istop is the end of the active subblock.
119 // As more and more eigenvalues converge, it eventually
120 // becomes ilo+1 and the loop ends.
121 idx_t istop = ihi;
122 // istart is the start of the active subblock. Either
123 // istart = ilo, or H(istart, istart-1) = 0. This means
124 // that we can treat this subblock separately.
125 idx_t istart = ilo;
126
127 // Norm of B, used for checking infinite eigenvalues
128 const real_t bnorm =
129 lange(FROB_NORM, slice(B, range(ilo, ihi), range(ilo, ihi)));
130
131 // Used to calculate the exceptional shift
132 TA eshift = (TA)0.;
133
134 // Local workspace
135 TA v_[3];
136 auto v = new_3_vector(v_);
137
138 for (idx_t iter = 0; iter <= itmax; ++iter) {
139 if (iter == itmax) {
140 // The QZ algorithm failed to converge, return with error.
142 istop,
143 "The QZ algorithm failed to compute all the eigenvalues"
144 " in a total of 30 iterations per eigenvalue. Elements"
145 " i:ihi of alpha and beta contain those eigenvalues which have "
146 "been successfully computed.");
147 return istop;
148 }
149
150 if (istart + 1 >= istop) {
151 if (istart + 1 == istop) {
154 }
155 // All eigenvalues have been found, exit and return 0.
156 break;
157 }
158
159 // Determine range to apply rotations
160 idx_t istart_m;
161 idx_t istop_m;
162 if (!want_s) {
164 istop_m = istop;
165 }
166 else {
167 istart_m = 0;
168 istop_m = n;
169 }
170
171 // Check if active subblock has split
172 for (idx_t i = istop - 1; i > istart; --i) {
173 if (abs1(A(i, i - 1)) <= small_num) {
174 // A(i,i-1) is negligible, take i as new istart.
175 A(i, i - 1) = zero;
176 istart = i;
177 break;
178 }
179
180 real_t tst = abs1(A(i - 1, i - 1)) + abs1(A(i, i));
181 if (tst == zero) {
182 if (i >= ilo + 2) {
183 tst = tst + abs(A(i - 1, i - 2));
184 }
185 if (i < ihi) {
186 tst = tst + abs(A(i + 1, i));
187 }
188 }
189 if (abs1(A(i, i - 1)) <= eps * tst) {
190 //
191 // The elementwise deflation test has passed
192 // The following performs second deflation test due
193 // to Steel, Vandebril and Langou (2023). It has better
194 // mathematical foundation and improves accuracy in some
195 // examples.
196 //
197 // The test is |A(i,i-1)|*|A(i-1,i)*B(i,i) - A(i,i)*B(i-1,i)| <=
198 // eps*|A(i,i)|*|A(i-1,i-1)*B(i,i)-A(i,i)*B(i-1,i-1)|.
199 // The multiplications might overflow so we do some scaling
200 // first.
201 //
202 const real_t tst1 =
203 abs1(B(i, i) * A(i - 1, i) - A(i, i) * B(i - 1, i));
204 const real_t tst2 =
205 abs1(B(i, i) * A(i - 1, i - 1) - A(i, i) * B(i - 1, i - 1));
206 real_t ab = max(abs1(A(i, i - 1)), tst1);
207 real_t ba = min(abs1(A(i, i - 1)), tst1);
208 real_t aa = max(abs1(A(i, i)), tst2);
209 real_t bb = min(abs1(A(i, i)), tst2);
210 real_t s = aa + ab;
211 if (ba * (ab / s) <= max(small_num, eps * (bb * (aa / s)))) {
212 // A(i,i-1) is negligible, take i as new istart.
213 A(i, i - 1) = zero;
214 istart = i;
215 break;
216 }
217 }
218 }
219
220 // check for infinite eigenvalues
221 for (idx_t i = istart; i < istop; ++i) {
222 if (abs1(B(i, i)) <= max(small_num, eps * bnorm)) {
223 // B(i,i) is negligible, so B is singular, i.e. (A,B) has an
224 // infinite eigenvalue. Move it to the top to be deflated
225 B(i, i) = zero;
226
227 real_t c;
228 TA s;
229 for (idx_t j = i; j > istart; j--) {
230 rotg(B(j - 1, j), B(j - 1, j - 1), c, s);
231 B(j - 1, j - 1) = zero;
232 // Apply rotation from the right
233 {
234 auto b1 = slice(B, range(istart_m, j - 1), j);
235 auto b2 = slice(B, range(istart_m, j - 1), j - 1);
236 rot(b1, b2, c, s);
237
238 auto a1 = slice(A, range(istart_m, min(j + 2, n)), j);
239 auto a2 =
240 slice(A, range(istart_m, min(j + 2, n)), j - 1);
241 rot(a1, a2, c, s);
242
243 if (want_z) {
244 auto z1 = col(Z, j);
245 auto z2 = col(Z, j - 1);
246 rot(z1, z2, c, s);
247 }
248 }
249 // Remove fill-in in A
250 if (j < istop - 1) {
251 rotg(A(j, j - 1), A(j + 1, j - 1), c, s);
252 A(j + 1, j - 1) = zero;
253
254 auto a1 = slice(A, j, range(j, istop_m));
255 auto a2 = slice(A, j + 1, range(j, istop_m));
256 rot(a1, a2, c, s);
257 auto b1 = slice(B, j, range(j + 1, istop_m));
258 auto b2 = slice(B, j + 1, range(j + 1, istop_m));
259 rot(b1, b2, c, s);
260
261 if (want_q) {
262 auto q1 = col(Q, j);
263 auto q2 = col(Q, j + 1);
264 rot(q1, q2, c, conj(s));
265 }
266 }
267 }
268
269 if (istart + 1 < istop) {
270 rotg(A(istart, istart), A(istart + 1, istart), c, s);
271 A(istart + 1, istart) = zero;
272
273 auto a1 = slice(A, istart, range(istart + 1, istop_m));
274 auto a2 = slice(A, istart + 1, range(istart + 1, istop_m));
275 rot(a1, a2, c, s);
276 auto b1 = slice(B, istart, range(istart + 1, istop_m));
277 auto b2 = slice(B, istart + 1, range(istart + 1, istop_m));
278 rot(b1, b2, c, s);
279
280 if (want_q) {
281 auto q1 = col(Q, istart);
282 auto q2 = col(Q, istart + 1);
283 rot(q1, q2, c, conj(s));
284 }
285 }
287 beta[istart] = zero;
288 istart = istart + 1;
289 }
290 }
291
292 if (istart == istop) {
293 istop = istop - 1;
294 istart = ilo;
295 continue;
296 }
297 // Check if 1x1 block has split off
298 if (istart + 1 == istop) {
299 k_defl = 0;
300 // Normalize the block, make sure B(istart, istart) is real and
301 // positive
302 if constexpr (is_real<TA>) {
303 if (B(istart, istart) < 0.) {
304 for (idx_t i = istart_m; i <= istart; ++i) {
305 B(i, istart) = -B(i, istart);
306 A(i, istart) = -A(i, istart);
307 }
308 if (want_z) {
309 for (idx_t i = 0; i < n; ++i) {
310 Z(i, istart) = -Z(i, istart);
311 }
312 }
313 }
314 }
315 else {
316 real_t absB = abs(B(istart, istart));
317 if (absB > small_num and (imag(B(istart, istart)) != zero or
318 real(B(istart, istart)) < zero)) {
319 TA scal = conj(B(istart, istart) / absB);
320 for (idx_t i = istart_m; i <= istart; ++i) {
321 B(i, istart) = scal * B(i, istart);
322 A(i, istart) = scal * A(i, istart);
323 }
324 if (want_z) {
325 for (idx_t i = 0; i < n; ++i) {
326 Z(i, istart) = scal * Z(i, istart);
327 }
328 }
329 B(istart, istart) = absB;
330 }
331 else {
332 B(istart, istart) = zero;
333 }
334 }
337 istop = istart;
338 istart = ilo;
339 continue;
340 }
341 // Check if 2x2 block has split off
342 if constexpr (is_real<TA>) {
343 if (istart + 2 == istop) {
344 // 2x2 block, normalize the block
345 auto A22 = slice(A, range(istart, istop), range(istart, istop));
346 auto B22 = slice(B, range(istart, istop), range(istart, istop));
348 beta[istart], beta[istart + 1]);
349 // Only split off the block if the eigenvalues are imaginary
350 if (imag(alpha[istart]) != zero) {
351 // Standardize, that is, rotate so that
352 // ( B11 0 )
353 // B = ( ) with B11 non-negative
354 // ( 0 B22 )
355 TA ssmin, ssmax, csl, snl, csr, snr;
356 svd22(B22(0, 0), B22(0, 1), B22(1, 1), ssmin, ssmax, csl,
357 snl, csr, snr);
358
359 if (ssmax < (TA)0) {
360 csr = -csr;
361 snr = -snr;
362 ssmin = -ssmin;
363 ssmax = -ssmax;
364 }
365
366 B22(0, 0) = ssmax;
367 B22(1, 1) = ssmin;
368 B22(0, 1) = (TA)0;
369
370 // Apply rotations to A
371 auto a1l = slice(A, istart, range(istart, istop_m));
372 auto a2l = slice(A, istart + 1, range(istart, istop_m));
373 rot(a1l, a2l, csl, snl);
374 auto a1r = slice(A, range(istart_m, istop), istart);
375 auto a2r = slice(A, range(istart_m, istop), istart + 1);
376 rot(a1r, a2r, csr, snr);
377 // Apply rotations to B
378 if (istart + 2 < n) {
379 auto b1l = slice(B, istart, range(istart + 2, istop_m));
380 auto b2l =
381 slice(B, istart + 1, range(istart + 2, istop_m));
382 rot(b1l, b2l, csl, snl);
383 }
384 auto b1r = slice(B, range(istart_m, istart), istart);
385 auto b2r = slice(B, range(istart_m, istart), istart + 1);
386 rot(b1r, b2r, csr, snr);
387
388 // Apply rotation to Q
389 if (want_q) {
390 auto q1 = col(Q, istart);
391 auto q2 = col(Q, istart + 1);
392 rot(q1, q2, csl, snl);
393 }
394
395 // Apply rotation to Z
396 if (want_z) {
397 auto z1 = col(Z, istart);
398 auto z2 = col(Z, istart + 1);
399 rot(z1, z2, csr, snr);
400 }
401
402 k_defl = 0;
403 istop = istart;
404 istart = ilo;
405 continue;
406 }
407 }
408 }
409
410 // Determine shift
411 k_defl = k_defl + 1;
412
415 TA beta1;
416 TA beta2;
417 if (k_defl % non_convergence_limit == 0) {
418 // Exceptional shift
419 if (k_defl % 2 * non_convergence_limit == 0 or istop < 2)
420 eshift += A(istop - 1, istop - 1) / B(istop - 1, istop - 1);
421 else
422 eshift += A(istop - 2, istop - 2) / B(istop - 2, istop - 2);
423
424 shift1 = eshift;
425 shift2 = eshift;
426 beta1 = one;
427 beta2 = one;
428 }
429 else {
430 // Wilkinson shift
431 auto A22 =
432 slice(A, range(istop - 2, istop), range(istop - 2, istop));
433 auto B22 =
434 slice(B, range(istop - 2, istop), range(istop - 2, istop));
436 }
437
438 // We have already checked whether the subblock has split.
439 // If it has split, we can introduce any shift at the top of the new
440 // subblock. Now that we know the specific shift, we can also check
441 // whether we can introduce that shift somewhere else in the subblock.
442 idx_t istart2 = istart;
443 TA t1;
444 if (istart + 3 < istop) {
445 for (idx_t i = istop - 3; i > istart; --i) {
446 auto H = slice(A, range{i, i + 3}, range{i, i + 3});
447 auto T = slice(B, range{i, i + 3}, range{i, i + 3});
450 v[0] = t1;
451 const TA refsum =
452 conj(v[0]) * A(i, i - 1) + conj(v[1]) * A(i + 1, i - 1);
453 if (abs1(A(i + 1, i - 1) - refsum * v[1]) +
454 abs1(refsum * v[2]) <=
455 eps * (abs1(A(i, i - 1)) + abs1(A(i, i + 1)) +
456 abs1(A(i + 1, i + 2)))) {
457 istart2 = i;
458 break;
459 }
460 }
461 }
462
463 // All the preparations are done, we can apply an implicit QZ
464 // iteration
465 for (idx_t i = istart2; i < istop - 2; ++i) {
466 if (i == istart2) {
467 // This is the first iteration, calculate a reflector to
468 // introduce the shift
469 auto H = slice(A, range{i, i + 3}, range{i, i + 3});
470 auto T = slice(B, range{i, i + 3}, range{i, i + 3});
473 if (i > istart) {
474 A(i, i - 1) = A(i, i - 1) * (one - conj(t1));
475 }
476 }
477 else {
478 // Calculate a reflector to move the bulge one position
479 v[0] = A(i, i - 1);
480 v[1] = A(i + 1, i - 1);
481 v[2] = A(i + 2, i - 1);
483 A(i, i - 1) = v[0];
484 A(i + 1, i - 1) = zero;
485 A(i + 2, i - 1) = zero;
486 }
487
488 // The following code applies the reflector we have just calculated.
489 // We write this out instead of using larf because a direct loop is
490 // more efficient for small reflectors.
491 {
492 t1 = conj(t1);
493 const TA v2 = v[1];
494 const TA t2 = t1 * v2;
495 const TA v3 = v[2];
496 const TA t3 = t1 * v[2];
497 TA sum;
498
499 // Apply reflector from the left to A
500 for (idx_t j = i; j < istop_m; ++j) {
501 sum = A(i, j) + conj(v2) * A(i + 1, j) +
502 conj(v3) * A(i + 2, j);
503 A(i, j) = A(i, j) - sum * t1;
504 A(i + 1, j) = A(i + 1, j) - sum * t2;
505 A(i + 2, j) = A(i + 2, j) - sum * t3;
506 }
507 // Apply reflector from the left to B
508 for (idx_t j = i; j < istop_m; ++j) {
509 sum = B(i, j) + conj(v2) * B(i + 1, j) +
510 conj(v3) * B(i + 2, j);
511 B(i, j) = B(i, j) - sum * t1;
512 B(i + 1, j) = B(i + 1, j) - sum * t2;
513 B(i + 2, j) = B(i + 2, j) - sum * t3;
514 }
515 if (want_q) {
516 // Apply reflector to Q from the right
517 for (idx_t j = 0; j < n; ++j) {
518 sum = Q(j, i) + v2 * Q(j, i + 1) + v3 * Q(j, i + 2);
519 Q(j, i) = Q(j, i) - sum * conj(t1);
520 Q(j, i + 1) = Q(j, i + 1) - sum * conj(t2);
521 Q(j, i + 2) = Q(j, i + 2) - sum * conj(t3);
522 }
523 }
524 }
525
526 // Remove fill-in from B using an inverse reflector
527 auto T = slice(B, range{i + 1, i + 3}, range{i, i + 3});
528 inv_house3(T, v, t1);
529
530 // The following code applies the reflector we have just calculated.
531 // We write this out instead of using larf because a direct loop is
532 // more efficient for small reflectors.
533 {
534 t1 = conj(t1);
535 const TA v2 = v[1];
536 const TA t2 = t1 * v2;
537 const TA v3 = v[2];
538 const TA t3 = t1 * v[2];
539 TA sum;
540
541 // Apply reflector from the right to B
542 for (idx_t j = istart_m; j < i + 3; ++j) {
543 sum = B(j, i) + v2 * B(j, i + 1) + v3 * B(j, i + 2);
544 B(j, i) = B(j, i) - sum * conj(t1);
545 B(j, i + 1) = B(j, i + 1) - sum * conj(t2);
546 B(j, i + 2) = B(j, i + 2) - sum * conj(t3);
547 }
548 B(i + 1, i) = (TA)0;
549 B(i + 2, i) = (TA)0;
550 // Apply reflector from the right to A
551 for (idx_t j = istart_m; j < min(i + 4, istop); ++j) {
552 sum = A(j, i) + v2 * A(j, i + 1) + v3 * A(j, i + 2);
553 A(j, i) = A(j, i) - sum * conj(t1);
554 A(j, i + 1) = A(j, i + 1) - sum * conj(t2);
555 A(j, i + 2) = A(j, i + 2) - sum * conj(t3);
556 }
557 if (want_z) {
558 // Apply reflector to Z from the right
559 for (idx_t j = 0; j < n; ++j) {
560 sum = Z(j, i) + v2 * Z(j, i + 1) + v3 * Z(j, i + 2);
561 Z(j, i) = Z(j, i) - sum * conj(t1);
562 Z(j, i + 1) = Z(j, i + 1) - sum * conj(t2);
563 Z(j, i + 2) = Z(j, i + 2) - sum * conj(t3);
564 }
565 }
566 }
567 }
568 // Handle the final 2x2 block separately using a 2x2 rotation instead
569 // of a 3x3 reflector.
570 {
571 idx_t i = istop - 2;
572
573 real_t c2;
574 TA s2;
575
576 if (i == istart2) {
577 auto H = slice(A, range{i, i + 2}, range{i, i + 2});
578 auto T = slice(B, range{i, i + 2}, range{i, i + 2});
579 auto x = slice(v, range{0, 2});
581
582 rotg(x[0], x[1], c2, s2);
583
584 if (i > istart) {
585 A(i, i - 1) = A(i, i - 1) * c2;
586 }
587 }
588 else {
589 rotg(A(i, i - 1), A(i + 1, i - 1), c2, s2);
590 A(i + 1, i - 1) = zero;
591 }
592
593 // Apply rotation from the left
594 {
595 auto a1 = slice(A, i, range{i, istop_m});
596 auto a2 = slice(A, i + 1, range{i, istop_m});
597 rot(a1, a2, c2, s2);
598 auto b1 = slice(B, i, range{i, istop_m});
599 auto b2 = slice(B, i + 1, range{i, istop_m});
600 rot(b1, b2, c2, s2);
601 if (want_q) {
602 auto q1 = col(Q, i);
603 auto q2 = col(Q, i + 1);
604 rot(q1, q2, c2, conj(s2));
605 }
606 }
607
608 // Remove fill-in from B
609 rotg(B(i + 1, i + 1), B(i + 1, i), c2, s2);
610 s2 = -s2;
611 B(i + 1, i) = (TA)0.;
612
613 // Apply rotation from the right
614 {
615 auto b1 = slice(B, range{istart_m, i + 1}, i);
616 auto b2 = slice(B, range{istart_m, i + 1}, i + 1);
617 rot(b1, b2, c2, conj(s2));
618 auto a1 = slice(A, range{istart_m, min(i + 4, ihi)}, i);
619 auto a2 = slice(A, range{istart_m, min(i + 4, ihi)}, i + 1);
620 rot(a1, a2, c2, conj(s2));
621 if (want_z) {
622 auto z1 = col(Z, i);
623 auto z2 = col(Z, i + 1);
624 rot(z1, z2, c2, conj(s2));
625 }
626 }
627 }
628 }
629
630 return 0;
631}
632
633} // namespace tlapack
634
635#endif // TLAPACK_LAHQZ_HH
constexpr internal::FrobNorm FROB_NORM
Frobenius norm of matrices.
Definition types.hpp:342
constexpr internal::Forward FORWARD
Forward direction.
Definition types.hpp:376
constexpr internal::ColumnwiseStorage COLUMNWISE_STORAGE
Columnwise storage.
Definition types.hpp:409
constexpr real_type< T > real(const T &x) noexcept
Extends std::real() to real datatypes.
Definition utils.hpp:71
constexpr T conj(const T &x) noexcept
Extends std::conj() to real datatypes.
Definition utils.hpp:100
constexpr real_type< T > abs1(const T &x)
1-norm absolute value, |Re(x)| + |Im(x)|
Definition utils.hpp:133
constexpr real_type< T > imag(const T &x) noexcept
Extends std::imag() to real datatypes.
Definition utils.hpp:86
#define TLAPACK_CSMATRIX
Macro for tlapack::concepts::ConstructableAndSliceableMatrix compatible with C++17.
Definition concepts.hpp:961
#define TLAPACK_VECTOR
Macro for tlapack::concepts::Vector compatible with C++17.
Definition concepts.hpp:906
auto lange(norm_t normType, const matrix_t &A)
Calculates the norm of a matrix.
Definition lange.hpp:38
void svd22(const T &f, const T &g, const T &h, T &ssmin, T &ssmax, T &csl, T &snl, T &csr, T &snr)
Computes the singular value decomposition of a 2-by-2 real triangular matrix.
Definition svd22.hpp:55
void larfg(storage_t storeMode, type_t< vector_t > &alpha, vector_t &x, type_t< vector_t > &tau)
Generates a elementary Householder reflection.
Definition larfg.hpp:73
void inv_house3(const matrix_t &A, vector_t &v, type_t< vector_t > &tau)
Inv_house calculates a reflector to reduce the first column in a 2x3 matrix A from the right to zero.
Definition inv_house3.hpp:44
int lahqz_shiftcolumn(const matrix_t &A, const matrix_t &B, vector_t &v, complex_type< type_t< matrix_t > > s1, complex_type< type_t< matrix_t > > s2, type_t< matrix_t > beta1, type_t< matrix_t > beta2)
Given a 2-by-2 or 3-by-3 matrix pencil (A,B), lahqz_shiftcolumn calculates a multiple of the product:...
Definition lahqz_shiftcolumn.hpp:56
int lahqz(bool want_s, bool want_q, bool want_z, size_type< matrix_t > ilo, size_type< matrix_t > ihi, matrix_t &A, matrix_t &B, alpha_t &alpha, beta_t &beta, matrix_t &Q, matrix_t &Z)
lahqz computes the eigenvalues of a matrix pair (H,T), where H is an upper Hessenberg matrix and T is...
Definition lahqz.hpp:60
void rotg(T &a, T &b, T &c, T &s)
Construct plane rotation that eliminates b, such that:
Definition rotg.hpp:39
void rot(vectorX_t &x, vectorY_t &y, const c_type &c, const s_type &s)
Apply plane rotation:
Definition rot.hpp:44
void scal(const alpha_t &alpha, vector_t &x)
Scale vector by constant, .
Definition scal.hpp:30
#define tlapack_error(info, detailedInfo)
Error handler.
Definition exceptionHandling.hpp:142
#define tlapack_check_false(cond)
Throw an error if cond is true.
Definition exceptionHandling.hpp:113
void lahqz_eig22(const A_t &A, const B_t &B, complex_type< T > &alpha1, complex_type< T > &alpha2, T &beta1, T &beta2)
Computes the generalized eigenvalues of a 2x2 pencil (A,B) with B upper triangular.
Definition lahqz_eig22.hpp:35
typename traits::real_type_traits< Types..., int >::type real_type
The common real type of the list of types.
Definition scalar_type_traits.hpp:113