<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"
24
25namespace tlapack {
26
72 class d_t,
73 class e_t,
76int steqr(bool want_z, d_t& d, e_t& e, matrix_t& Z)
77{
78 using idx_t = size_type<matrix_t>;
79 using T = type_t<matrix_t>;
80 using real_t = real_type<T>;
81
82 // constants
83 const real_t two(2);
84 const real_t one(1);
85 const real_t zero(0);
86 const idx_t n = size(d);
87
88 // Quick return if possible
89 if (n == 0) return 0;
90 if (n == 1) return 0;
91
92 // Determine the unit roundoff and over/underflow thresholds.
93 const real_t eps = ulp<real_t>();
94 const real_t eps2 = square(eps);
96
97 // Compute the eigenvalues and eigenvectors of the tridiagonal
98 // matrix.
99 const idx_t itmax = 30 * n;
100
101 // istart and istop determine the active block
102 idx_t istart = 0;
103 idx_t istop = n;
104
105 // Keep track of previous istart and istop to know when to change direction
106 idx_t istart_old = -1;
107 idx_t istop_old = -1;
108
109 // If true, chase bulges from top to bottom
110 // If false, chase bulges from bottom to top
111 // This variable is reevaluated for every new subblock
112 bool forwarddirection = true;
113
114 // Main loop
115 for (idx_t iter = 0; iter < itmax; iter++) {
116 if (iter == itmax) {
117 // The QR algorithm failed to converge, return with error.
118 return istop;
119 }
120
121 if (istop <= 1) {
122 // All eigenvalues have been found, exit and return 0.
123 break;
124 }
125
126 // Find active block
127 for (idx_t i = istop - 1; i > istart; --i) {
128 if (square(e[i - 1]) <=
129 (eps2 * abs(d[i - 1])) * abs(d[i]) + safmin) {
130 e[i - 1] = zero;
131 istart = i;
132 break;
133 }
134 }
135
136 // An eigenvalue has split off, reduce istop and start the loop again
137 if (istart == istop - 1) {
138 istop = istop - 1;
139 istart = 0;
140 continue;
141 }
142
143 // A 2x2 block has split off, handle separately
144 if (istart + 1 == istop - 1) {
145 real_t s1, s2;
146 if (want_z) {
147 real_t cs, sn;
148 laev2(d[istart], e[istart], d[istart + 1], s1, s2, cs, sn);
149
150 auto z1 = col(Z, istart);
151 auto z2 = col(Z, istart + 1);
152 rot(z1, z2, cs, sn);
153 }
154 else {
155 lae2(d[istart], e[istart], d[istart + 1], s1, s2);
156 }
157 d[istart] = s1;
158 d[istart + 1] = s2;
159 e[istart] = zero;
160
161 istop = istop - 2;
162 istart = 0;
163 continue;
164 }
165
166 // Choose between QL and QR iteration
167 if (istart >= istop_old or istop <= istart_old) {
168 forwarddirection = abs(d[istart]) > abs(d[istop - 1]);
169 }
172
173 if (forwarddirection) {
174 // QR iteration
175
176 // Form shift using last 2x2 block of the active matrix
177 real_t p = d[istop - 1];
178 real_t g = (d[istop - 2] - p) / (two * e[istop - 2]);
179 real_t r = lapy2(g, one);
180 g = d[istart] - p + e[istop - 2] / (real_t)(g + (sgn(g) * r));
181
182 real_t s = one;
183 real_t c = one;
184 p = zero;
185
186 // Chase bulge from top to bottom
187 for (idx_t i = istart; i < istop - 1; ++i) {
188 real_t f = s * e[i];
189 real_t b = c * e[i];
190 lartg(g, f, c, s, r);
191 if (i != istart) e[i - 1] = r;
192 g = d[i] - p;
193 r = (d[i + 1] - g) * s + two * c * b;
194 p = s * r;
195 d[i] = g + p;
196 g = c * r - b;
197 // If eigenvalues are desired, then apply rotations
198 if (want_z) {
199 auto z1 = col(Z, i);
200 auto z2 = col(Z, i + 1);
201 rot(z1, z2, c, s);
202 }
203 }
204 d[istop - 1] = d[istop - 1] - p;
205 e[istop - 2] = g;
206 }
207 else {
208 // QL iteration
209
210 // Form shift using last 2x2 block of the active matrix
211 real_t p = d[istart];
212 real_t g = (d[istart + 1] - p) / (two * e[istart]);
213 real_t r = lapy2(g, one);
214 g = d[istop - 1] - p + e[istart] / (real_t)(g + (sgn(g) * r));
215
216 real_t s = one;
217 real_t c = one;
218 p = zero;
219
220 // Chase bulge from bottom to top
221 for (idx_t i = istop - 1; i > istart; --i) {
222 real_t f = s * e[i - 1];
223 real_t b = c * e[i - 1];
224 lartg(g, f, c, s, r);
225 if (i != istop - 1) e[i] = r;
226 g = d[i] - p;
227 r = (d[i - 1] - g) * s + two * c * b;
228 p = s * r;
229 d[i] = g + p;
230 g = c * r - b;
231 // If eigenvalues are desired, then apply rotations
232 if (want_z) {
233 auto z1 = col(Z, i);
234 auto z2 = col(Z, i - 1);
235 rot(z1, z2, c, s);
236 }
237 }
238 d[istart] = d[istart] - p;
239 e[istart] = g;
240 }
241 }
242
243 // Order eigenvalues and eigenvectors
244 if (!want_z) {
245 // Use quick sort
246 lasrt('I', n, d);
247 }
248 else {
249 // Use selection sort to minize swaps of eigenvectors
250 for (idx_t i = 0; i < n - 1; ++i) {
251 idx_t k = i;
252 real_t p = d[i];
253 for (idx_t j = i + 1; j < n; ++j) {
254 if (d[j] < p) {
255 k = j;
256 p = d[j];
257 }
258 }
259 if (k != i) {
260 d[k] = d[i];
261 d[i] = p;
262 auto z1 = col(Z, i);
263 auto z2 = col(Z, k);
265 }
266 }
267 }
268
269 return 0;
270}
271
272} // namespace tlapack
273
274#endif // TLAPACK_STEQR_HH
#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 real symmetric tridiagonal matrix u...
Definition steqr.hpp:76
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 int sgn(const T &val)
Type-safe sgn function.
Definition utils.hpp:109