<T>LAPACK 0.1.2
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
steqr.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_STEQR_HH
13#define TLAPACK_STEQR_HH
14
18#include "tlapack/blas/rot.hpp"
19#include "tlapack/blas/swap.hpp"
23
24namespace tlapack {
25
53template <TLAPACK_SMATRIX matrix_t,
54 class d_t,
55 class e_t,
56 enable_if_t<is_same_v<type_t<d_t>, real_type<type_t<d_t>>>, int> = 0,
57 enable_if_t<is_same_v<type_t<e_t>, real_type<type_t<e_t>>>, int> = 0>
58int steqr(bool want_z, d_t& d, e_t& e, matrix_t& Z)
59{
60 using idx_t = size_type<matrix_t>;
61 using T = type_t<matrix_t>;
62 using real_t = real_type<T>;
63
64 // constants
65 const real_t two(2);
66 const real_t one(1);
67 const real_t zero(0);
68 const idx_t n = size(d);
69
70 // Quick return if possible
71 if (n == 0) return 0;
72 if (n == 1) {
73 if (want_z) Z(0, 0) = one;
74 return 0;
75 }
76
77 // Determine the unit roundoff and over/underflow thresholds.
78 const real_t eps = ulp<real_t>();
79 const real_t eps2 = square(eps);
81
82 // Compute the eigenvalues and eigenvectors of the tridiagonal
83 // matrix.
84 const idx_t itmax = 30 * n;
85
86 // istart and istop determine the active block
87 idx_t istart = 0;
88 idx_t istop = n;
89
90 // Keep track of previous istart and istop to know when to change direction
91 idx_t istart_old = -1;
92 idx_t istop_old = -1;
93
94 // If true, chase bulges from top to bottom
95 // If false chase bulges from bottom to top
96 // This variable is reevaluated for every new subblock
97 bool forwarddirection = true;
98
99 // Main loop
100 for (idx_t iter = 0; iter < itmax; iter++) {
101 if (iter == itmax) {
102 // The QR algorithm failed to converge, return with error.
103 return istop;
104 }
105
106 if (istop <= 1) {
107 // All eigenvalues have been found, exit and return 0.
108 break;
109 }
110
111 // Find active block
112 for (idx_t i = istop - 1; i > istart; --i) {
113 if (square(e[i - 1]) <=
114 (eps2 * abs(d[i - 1])) * abs(d[i]) + safmin) {
115 e[i - 1] = zero;
116 istart = i;
117 break;
118 }
119 }
120
121 // An eigenvalue has split off, reduce istop and start the loop again
122 if (istart == istop - 1) {
123 istop = istop - 1;
124 istart = 0;
125 continue;
126 }
127
128 // A 2x2 block has split off, handle separately
129 if (istart + 1 == istop - 1) {
130 real_t s1, s2;
131 if (want_z) {
132 real_t cs, sn;
133 laev2(d[istart], e[istart], d[istart + 1], s1, s2, cs, sn);
134
135 auto z1 = col(Z, istart);
136 auto z2 = col(Z, istart + 1);
137 rot(z1, z2, cs, sn);
138 }
139 else {
140 lae2(d[istart], e[istart], d[istart + 1], s1, s2);
141 }
142 d[istart] = s1;
143 d[istart + 1] = s2;
144 e[istart] = zero;
145
146 istop = istop - 2;
147 istart = 0;
148 continue;
149 }
150
151 // Choose betwwen QL and QR iteration
152 if (istart >= istop_old or istop <= istart_old) {
153 forwarddirection = abs(d[istart]) > abs(d[istop - 1]);
154 }
157
158 if (forwarddirection) {
159 // QR iteration
160
161 // Form shift using last 2x2 block of the active matrix
162 real_t p = d[istop - 1];
163 real_t g = (d[istop - 2] - p) / (two * e[istop - 2]);
164 real_t r = lapy2(g, one);
165 g = d[istart] - p + e[istop - 2] / (real_t)(g + (sgn(g) * r));
166
167 real_t s = one;
168 real_t c = one;
169 p = zero;
170
171 // Chase bulge from top to bottom
172 for (idx_t i = istart; i < istop - 1; ++i) {
173 real_t f = s * e[i];
174 real_t b = c * e[i];
175 lartg(g, f, c, s, r);
176 if (i != istart) e[i - 1] = r;
177 g = d[i] - p;
178 r = (d[i + 1] - g) * s + two * c * b;
179 p = s * r;
180 d[i] = g + p;
181 g = c * r - b;
182 // If eigenvalues are desired, then apply rotations
183 if (want_z) {
184 auto z1 = col(Z, i);
185 auto z2 = col(Z, i + 1);
186 rot(z1, z2, c, s);
187 }
188 }
189 d[istop - 1] = d[istop - 1] - p;
190 e[istop - 2] = g;
191 }
192 else {
193 // QL iteration
194
195 // Form shift using last 2x2 block of the active matrix
196 real_t p = d[istart];
197 real_t g = (d[istart + 1] - p) / (two * e[istart]);
198 real_t r = lapy2(g, one);
199 g = d[istop - 1] - p + e[istart] / (real_t)(g + (sgn(g) * r));
200
201 real_t s = one;
202 real_t c = one;
203 p = zero;
204
205 // Chase bulge from bottom to top
206 for (idx_t i = istop - 1; i > istart; --i) {
207 real_t f = s * e[i - 1];
208 real_t b = c * e[i - 1];
209 lartg(g, f, c, s, r);
210 if (i != istop - 1) e[i] = r;
211 g = d[i] - p;
212 r = (d[i - 1] - g) * s + two * c * b;
213 p = s * r;
214 d[i] = g + p;
215 g = c * r - b;
216 // If eigenvalues are desired, then apply rotations
217 if (want_z) {
218 auto z1 = col(Z, i);
219 auto z2 = col(Z, i - 1);
220 rot(z1, z2, c, s);
221 }
222 }
223 d[istart] = d[istart] - p;
224 e[istart] = g;
225 }
226 }
227
228 // Order eigenvalues and eigenvectors
229 if (!want_z) {
230 // Use quick sort
231 // TODO: implement quick sort
232 }
233 else {
234 // Use selection sort to minize swaps of eigenvectors
235 for (idx_t i = 0; i < n - 1; ++i) {
236 idx_t k = i;
237 real_t p = d[i];
238 for (idx_t j = i + 1; j < n; ++j) {
239 if (d[j] < p) {
240 k = j;
241 p = d[j];
242 }
243 }
244 if (k != i) {
245 d[k] = d[i];
246 d[i] = p;
247 auto z1 = col(Z, i);
248 auto z2 = col(Z, k);
250 }
251 }
252 }
253
254 return 0;
255}
256
257} // namespace tlapack
258
259#endif // TLAPACK_STEQR_HH
constexpr int sgn(const T &val)
Type-safe sgn function.
Definition utils.hpp:109
#define TLAPACK_SMATRIX
Macro for tlapack::concepts::SliceableMatrix compatible with C++17.
Definition concepts.hpp:899
real_type< TX, TY > lapy2(const TX &x, const TY &y)
Finds , taking care not to cause unnecessary overflow.
Definition lapy2.hpp:34
void laev2(T a, T b, T c, T &s1, T &s2, T &cs, T &sn)
Computes the eigenvalues and eigenvector of a real symmetric 2x2 matrix A [ a b ] [ b c ] On exit,...
Definition laev2.hpp:59
void lae2(T a, T b, T c, T &s1, T &s2)
Computes the eigenvalues of a real symmetric 2x2 matrix A [ a b ] [ b c ].
Definition lae2.hpp:49
void rot(vectorX_t &x, vectorY_t &y, const c_type &c, const s_type &s)
Apply plane rotation:
Definition rot.hpp:44
void swap(vectorX_t &x, vectorY_t &y)
Swap vectors, .
Definition swap.hpp:31
void lartg(const T &a, const T &b, real_type< T > &c, T &s, T &r)
Construct plane rotation that eliminates b, such that:
Definition lartg.hpp:38
int steqr(bool want_z, d_t &d, e_t &e, matrix_t &Z)
STEQR computes all eigenvalues and, optionally, eigenvectors of a hermitian tridiagonal matrix using ...
Definition steqr.hpp:58
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