<T>LAPACK 0.1.2
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
lahqz_eig22.hpp
Go to the documentation of this file.
1
5//
6// Copyright (c) 2013-2022, 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_EIG22_HH__
13#define __TLAPACK_LAHQZ_EIG22_HH__
14
16
17namespace tlapack {
18
32template <TLAPACK_MATRIX A_t, TLAPACK_MATRIX B_t, TLAPACK_SCALAR T>
33void lahqz_eig22(const A_t& A,
34 const B_t& B,
37 T& beta1,
38 T& beta2)
39{
40 // Using
41 using TA = type_t<A_t>;
42 using real_t = real_type<TA>;
43
44 // Constants
45 const real_t zero(0);
46 const real_t half(0.5);
47 const real_t one(1);
48 const real_t two(2);
50 const real_t rtmin = sqrt(safmin);
51 const real_t rtmax = sqrt(safe_max<real_t>());
52 const real_t safmax = one / safmin;
53
54 //
55 // Scale A
56 //
58 std::max<real_t>(std::max<real_t>(abs1(A(0, 0)) + abs1(A(1, 0)),
59 abs1(A(0, 1)) + abs1(A(1, 1))),
60 safmin);
62 TA a00 = ascale * A(0, 0);
63 TA a01 = ascale * A(0, 1);
64 TA a10 = ascale * A(1, 0);
65 TA a11 = ascale * A(1, 1);
66 //
67 // If B is singular, deflate infinite eigenvalue
68 // Note, here we deviate from LAPACK, as LAPACK perturbs B
69 // to make it non-singular, but this removes the possibility
70 // for infinite eigenvalues
71 //
72 TA b00 = B(0, 0);
73 TA b01 = B(0, 1);
74 TA b11 = B(1, 1);
75 real_t bmin =
76 rtmin * std::max<real_t>(std::max<real_t>(abs1(b00), abs1(b01)),
77 std::max<real_t>(abs1(b11), rtmin));
78 if (abs1(b00) < bmin) {
79 b00 = zero;
80 // B(0,0) is zero, we can apply rotations to the left
81 // to make A(1,0) zero without perturbing the upper triangular
82 // structure of B
83 if (a10 != zero) {
84 real_t c;
85 TA s;
86 rotg(a00, a10, c, s);
87 a10 = zero;
88 TA temp = c * a01 + s * a11;
89 a11 = c * a11 - conj(s) * a01;
90 a01 = temp;
91 temp = c * b01 + s * b11;
92 b11 = c * b11 - conj(s) * b01;
93 b01 = temp;
94 }
95
96 // Apply scaling to the right of B to make B(1,1) real
97 if constexpr (is_complex<TA>) {
98 if (abs1(b11) < bmin) {
99 b11 = zero;
100 }
101 else {
102 TA scale = conj(b11) / abs(b11);
103 b01 *= scale;
104 b11 = abs(b11);
105 a01 *= scale;
106 a11 *= scale;
107 }
108 }
109
110 alpha1 = a00;
111 alpha2 = a11;
112 beta1 = zero;
113 beta2 = real(b11) * ascale;
114 return;
115 }
116
117 if (abs1(b11) < bmin) {
118 b11 = zero;
119 // B(1,1) is zero, we can apply rotations to the right
120 // to make A(1,0) zero without perturbing the upper triangular
121 // structure of B
122 if (a10 != zero) {
123 real_t c;
124 TA s;
125 rotg(a11, a10, c, s);
126 a10 = zero;
127 TA temp = c * a01 + s * a00;
128 a00 = c * a00 - conj(s) * a01;
129 a01 = temp;
130 temp = c * b01 + s * b00;
131 b00 = c * b00 - conj(s) * b01;
132 b01 = temp;
133 }
134
135 // Apply scaling to the right of B to make B(0,0) real
136 if constexpr (is_complex<TA>) {
137 if (abs1(b00) < bmin) {
138 b00 = zero;
139 }
140 else {
141 TA scale = conj(b00) / abs(b00);
142 b01 *= scale;
143 b00 = abs(b00);
144 a01 *= scale;
145 a00 *= scale;
146 }
147 }
148
149 alpha1 = a00;
150 alpha2 = a11;
151 beta1 = real(b00) * ascale;
152 beta2 = zero;
153 return;
154 }
155 //
156 // Scale B
157 //
158 real_t bnorm = std::max<real_t>(
159 std::max<real_t>(abs1(b00), abs1(b01) + abs1(b11)), safmin);
160 real_t bsize = std::max<real_t>(abs1(b00), abs1(b11));
162 b00 = bscale * b00;
163 b01 = bscale * b01;
164 b11 = bscale * b11;
165 //
166 // Compute larger eigenvalue by method described by C. van Loan
167 // ( AS is A shifted by -SHIFT*B )
168 // TODO: add specific reference, van Loan wrote a lot of things
169 //
170 TA binv00 = one / b00;
171 TA binv11 = one / b11;
172 TA s0 = a00 * binv00;
173 TA s1 = a11 * binv11;
174 TA as00, as01, as11, ss, abi11, pp, shift;
175 if (abs1(s0) <= abs1(s1)) {
176 as01 = a01 - s0 * b01;
177 as11 = a11 - s0 * b11;
178 ss = a10 * (binv00 * binv11);
179 abi11 = as11 * binv11 - ss * b01;
180 pp = half * abi11;
181 shift = s0;
182 }
183 else {
184 as01 = a01 - s1 * b01;
185 as00 = a00 - s1 * b00;
186 ss = a10 * (binv00 * binv11);
187 abi11 = -ss * b01;
188 pp = half * (as00 * binv00 + abi11);
189 shift = s1;
190 }
191 TA qq = ss * as01;
192 TA discr;
193 real_t r;
194 if (abs1(pp * rtmin) >= one) {
195 discr = (rtmin * pp) * (rtmin * pp) + qq * safmin;
196 r = sqrt(abs(discr)) * rtmax;
197 }
198 else {
199 if (abs1(pp * pp) + abs1(qq) <= safmin) {
200 discr = (rtmax * pp) * (rtmax * pp) + qq * safmax;
201 r = sqrt(abs(discr)) * rtmin;
202 }
203 else {
204 discr = pp * pp + qq;
205 r = sqrt(abs(discr));
206 }
207 }
208
209 if constexpr (is_complex<TA>) {
210 TA root = sqrt(discr);
211
212 TA mu_big;
213 if (abs1(pp + root) > abs1(pp - root)) {
214 mu_big = pp + root;
215 }
216 else {
217 mu_big = pp - root;
218 }
219 TA mu_small = -qq / mu_big;
220 alpha1 = shift + mu_big;
222 }
223 else {
224 //
225 // Real pencil, check if we have 2 real eigenvalues
226 // or a complex conjugate pair
227 //
228 if (discr >= zero or r == zero) {
229 // real eigenvalues
230 TA rpp = pp > zero ? r : -r;
231 TA sum = pp + rpp;
232 TA diff = pp - rpp;
233 TA wbig = shift + sum;
234 //
235 // Compute smaller eigenvalue
236 //
237 TA wsmall = shift + diff;
238 if (half * abs1(wbig) > max<real_t>(abs1(wsmall), safmin)) {
239 T wdet = (a00 * a11 - a01 * a10) * (binv00 * binv11);
240 wsmall = wdet / wbig;
241 }
242 //
243 // Choose (real) eigenvalue closest to 1,1 element of AB^{-1}
244 // For alpha1
245 //
246 if (pp > abi11) {
249 }
250 else {
253 }
254 }
255 else {
256 // complex conjugate eigenvalues
259 }
260 }
261 //
262 // Further scaling to avoid underflow and overflow in computing
263 // beta1 and overflow in computing w*B.
264 //
265 // This scale factor (WSCALE) is bounded from above using C1 and C2,
266 // and from below using C3 and C4.
267 // C1 implements the condition s A must never overflow.
268 // C2 implements the condition w B must never overflow.
269 // C3, with C2,
270 // implement the condition that s A - w B must never overflow.
271 // C4 implements the condition s should not underflow.
272 // C5 implements the condition max<real_t>(s,|w|) should be at least 2.
275 real_t c3 = bsize * safmin;
276 real_t c4;
277 if (ascale <= one and bsize <= one) {
279 }
280 else {
281 c4 = one;
282 }
283 real_t c5;
284 if (ascale <= one or bsize <= one) {
286 }
287 else {
288 c5 = one;
289 }
290 //
291 // Scale first eigenvalue
292 //
294 real_t fuzzy1 = one + real_t(1.0e-5);
295 real_t wsize =
297 max<real_t>(fuzzy1 * (wabs * c2 + c3),
299 if (wsize != one) {
301 if (wsize > one) {
304 }
305 else {
308 }
309 alpha1 = wscale * alpha1;
310 }
311 else {
312 beta1 = ascale * bsize;
313 beta2 = beta1;
314 }
315
316 wabs = abs1(alpha2);
317 wsize =
319 max<real_t>(fuzzy1 * (wabs * c2 + c3),
321 if (wsize != one) {
323 if (wsize > one) {
326 }
327 else {
330 }
331 alpha2 = wscale * alpha2;
332 }
333 else {
334 beta2 = ascale * bsize;
335 }
336}
337
338} // namespace tlapack
339
340#endif // __LAHQZ_EIG22_HH__
void rotg(T &a, T &b, T &c, T &s)
Construct plane rotation that eliminates b, such that:
Definition rotg.hpp:39
Sort the numbers in D in increasing order (if ID = 'I') or in decreasing order (if ID = 'D' ).
Definition arrayTraits.hpp:15
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
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
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:33