<T>LAPACK 0.1.2
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
trevc3.hpp
Go to the documentation of this file.
1
5//
6// Copyright (c) 2025, 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_TREVC_HH
13#define TLAPACK_TREVC_HH
14
16#include "tlapack/blas/asum.hpp"
17#include "tlapack/blas/gemv.hpp"
20
21namespace tlapack {
22
26struct Trevc3Opts {
27 // Size of the eigenvector blocks
28 size_t block_size = 64;
29 // Blocksize used in the backward and forward substitution
30 size_t block_size_solve = 64;
31};
32
33enum class HowMny : char {
34 All = 'A',
35 Back = 'B',
36 Select = 'S'
37};
38
53template <TLAPACK_SIDE side_t,
59 const HowMny howmny,
61 const matrix_T_t& T,
64 const Trevc3Opts& opts = {})
65{
66 using idx_t = size_type<matrix_T_t>;
67
68 const idx_t n = ncols(T);
69
70 // Space for single and double back/forward substitution
71 WorkInfo workinfo(n * 3);
72
73 // Space for blocked back/forward substitution
74 workinfo += WorkInfo(opts.block_size_solve + 1);
75
76 // Space to temporarily store eigenvector block
77 workinfo += WorkInfo(n, opts.block_size + 1);
78
79 // Space to store the backtransformed eigenvector block
80 if (howmny == HowMny::Back) {
81 workinfo += WorkInfo(n, opts.block_size + 1);
82 }
83
84 return workinfo;
85}
86
169template <TLAPACK_SIDE side_t,
177 const HowMny howmny,
179 const matrix_T_t& T,
182 rwork_t& rwork,
183 work_t& work,
184 const Trevc3Opts& opts = {})
185{
186 using idx_t = size_type<matrix_T_t>;
187 using TT = type_t<matrix_T_t>;
189 using real_t = real_type<TT>;
190
191 const idx_t n = nrows(T);
192 // Number of columns of Vl and Vr
193 // const idx_t mm = max(ncols(Vl), ncols(Vr));
194 idx_t mm;
195 if (side == Side::Both) {
196 mm = std::min<idx_t>(ncols(Vl), ncols(Vr));
197 }
198 else if (side == Side::Left) {
199 mm = ncols(Vl);
200 }
201 else {
202 mm = ncols(Vr);
203 }
204
205 // Quick return
206 if (n == 0) return 0;
207
208 idx_t m = 0; // Actual number of eigenvectors to compute
209 if (howmny == HowMny::Select) {
210 // Set m to the number of columns required to store the selected
211 // eigenvectors.
212 // If necessary, the array select is standardized for complex
213 // conjugate pairs so that select[j] is true and select[j+1] is false.
214 idx_t j = 0;
215 while (j < n) {
216 bool pair = false;
217 if (j < n - 1) {
218 if (T(j + 1, j) != TT(0)) {
219 pair = true;
220 }
221 }
222 if (!pair) {
223 if (select[j]) {
224 m++;
225 }
226 j++;
227 }
228 else {
229 if (select[j] || select[j + 1]) {
230 select[j] = true;
231 select[j + 1] = true;
232 m += 2;
233 }
234 j += 2;
235 }
236 }
237 }
238 else {
239 m = n;
240 }
241
242 // Make sure that the matrices Vl and Vr have enough space
243 tlapack_check(mm >= m);
244
245 const idx_t nb = opts.block_size; // Block size
246
247 auto [X, work2] = reshape(work, n, opts.block_size + 1);
248
249 auto [colN, rwork2] = reshape(rwork, n);
250
251 for (idx_t j = 0; j < n; ++j) {
252 auto itmax = iamax(slice(col(T, j), range(0, n)));
253 colN[j] = abs1(T(itmax, j));
254 }
255
256 if (side == Side::Right || side == Side::Both) {
257 //
258 // Compute right eigenvectors.
259 //
260 idx_t iVr = m - 1; // current column of Vr to store the eigenvector
261 for (idx_t ii = 0; ii < n;) {
262 idx_t i = n - 1 - ii;
263 // First eigenvector to compute within this block
264 idx_t i_start;
265 // Last eigenvector to compute within this block (inclusive)
266 idx_t i_end;
267
268 if (howmny == HowMny::Select) {
269 // Find the first eigenvalue with index <= i with select ==
270 // true
271 for (idx_t jj = 0; jj < i + 1; jj++) {
272 idx_t j = i - jj;
273 if (select[j]) {
274 i_end = j;
275 break;
276 }
277 }
278 // Find the last eigenvalue with index <= i_end with select ==
279 // true
280 i_start = 0;
281 for (idx_t jj = 0; jj < i_end + 1; jj++) {
282 idx_t j = i_end - jj;
283 if (jj >= nb) {
284 // Don't make the block too big
285 i_start = j + 1;
286 break;
287 }
288 bool pair = false;
289 if (!select[j]) {
290 i_start = j + 1;
291 break;
292 }
293 }
294 }
295 else {
296 i_end = i;
297 i_start = (i >= nb) ? i - nb + 1 : 0;
298 }
299
300 // Make sure we don't split 2x2 blocks
301 if (i_start > 0) {
302 if (T(i_start, i_start - 1) != TT(0)) {
303 i_start--;
304 }
305 }
306
307 // The true block size
308 idx_t nb2 = i_end - i_start + 1;
309
310 // Calculate the current block of eigenvectors of T
312 opts.block_size_solve);
313
314 // If required, backtransform the eigenvectors to the original
315 // matrix, otherwise copy them to Vr
316 if (howmny == HowMny::Back) {
317 auto Q_slice = slice(Vr, range(0, n), range(0, i_end + 1));
318 auto X_block = slice(X, range(0, i_end + 1), range(0, nb2));
319 auto [Qx, work3] = reshape(work2, n, nb2);
320
322 Qx);
323
324 auto Vr_block =
325 slice(Vr, range(0, n), range(i_start, i_end + 1));
327 }
328 else {
329 auto Vr_block =
330 slice(Vr, range(0, n), range(iVr - nb2 + 1, iVr + 1));
331 auto X_block = slice(X, range(0, n), range(0, nb2));
333 iVr -= nb2;
334 }
335
336 ii += nb2;
337 }
338 }
339
340 if (side == Side::Left || side == Side::Both) {
341 //
342 // Compute left eigenvectors.
343 //
344 idx_t iVl = 0;
345 for (idx_t i = 0; i < n;) {
346 // First eigenvector to compute within this block
347 idx_t i_start;
348 // Last eigenvector to compute within this block (inclusive)
349 idx_t i_end;
350
351 if (howmny == HowMny::Select) {
352 // Find the first eigenvalue with index <= i with select ==
353 // true
354 for (idx_t j = i; j < n; j++) {
355 if (select[j]) {
356 i_start = j;
357 break;
358 }
359 }
360 // Find the last eigenvalue with index <= i_end with select ==
361 // true
362 i_end = n - 1;
363 for (idx_t j = i_start + 1; j < n; j++) {
364 if (j > i_start + nb) {
365 // Don't make the block too big
366 i_end = j - 1;
367 break;
368 }
369 bool pair = false;
370 if (!select[j]) {
371 i_end = j - 1;
372 break;
373 }
374 }
375 }
376 else {
377 i_start = i;
378 i_end = min<idx_t>(n - 1, i + nb - 1);
379 }
380
381 // Make sure we don't split 2x2 blocks
382 if (i_end + 1 < n) {
383 if (T(i_end + 1, i_end) != TT(0)) {
384 i_end++;
385 }
386 }
387
388 // The true block size
389 idx_t nb2 = i_end - i_start + 1;
390
391 // Calculate the current block of eigenvectors of T
393 opts.block_size_solve);
394
395 // If required, backtransform the eigenvectors to the original
396 // matrix, otherwise copy them to Vl
397 if (howmny == HowMny::Back) {
398 auto Q_slice = slice(Vl, range(0, n), range(i_start, n));
399 auto X_block = slice(X, range(i_start, n), range(0, nb2));
400 auto [Qx, work3] = reshape(work2, n, nb2);
401
403 Qx);
404
405 auto Vl_block =
406 slice(Vl, range(0, n), range(i_start, i_end + 1));
408 }
409 else {
410 auto Vl_block = slice(Vl, range(0, n), range(iVl, iVl + nb2));
411 auto X_block = slice(X, range(0, n), range(0, nb2));
413 iVl += nb2;
414 }
415
416 i += nb2;
417 }
418 }
419
420 return 0;
421}
422
501template <TLAPACK_SIDE side_t,
507 const HowMny howmny,
509 const matrix_T_t& T,
512 const Trevc3Opts& opts = {})
513{
514 WorkInfo workinfo = trevc3_worksize(side, howmny, select, T, Vl, Vr, opts);
515
516 using TT = type_t<matrix_T_t>;
518 std::vector<TT> work_;
519 auto work = new_vector(work_, workinfo.m * workinfo.n);
520 std::vector<real_type<TT>> rwork_;
521 auto rwork = new_vector(rwork_, nrows(T));
522
523 return trevc3_work(side, howmny, select, T, Vl, Vr, rwork, work, opts);
524}
525} // namespace tlapack
526
527#endif // TLAPACK_TREVC_HH
#define TLAPACK_SIDE
Macro for tlapack::concepts::Side compatible with C++17.
Definition concepts.hpp:927
#define TLAPACK_WORKSPACE
Macro for tlapack::concepts::Workspace compatible with C++17.
Definition concepts.hpp:912
#define TLAPACK_VECTOR
Macro for tlapack::concepts::Vector compatible with C++17.
Definition concepts.hpp:906
#define TLAPACK_MATRIX
Macro for tlapack::concepts::Matrix compatible with C++17.
Definition concepts.hpp:896
void lacpy(uplo_t uplo, const matrixA_t &A, matrixB_t &B)
Copies a matrix from A to B.
Definition lacpy.hpp:38
size_type< vector_t > iamax(const vector_t &x, const IamaxOpts< abs_f > &opts)
Return .
Definition iamax.hpp:234
void gemm(Op transA, Op transB, const alpha_t &alpha, const matrixA_t &A, const matrixB_t &B, const beta_t &beta, matrixC_t &C)
General matrix-matrix multiply:
Definition gemm.hpp:61
#define tlapack_check(cond)
Throw an error if cond is false.
Definition exceptionHandling.hpp:98
WorkInfo trevc3_worksize(const side_t side, const HowMny howmny, select_t &select, const matrix_T_t &T, matrix_Vl_t &Vl, matrix_Vr_t &Vr, const Trevc3Opts &opts={})
Worspace query of TREVC3()
Definition trevc3.hpp:58
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
int trevc3_work(const side_t side, const HowMny howmny, select_t &select, const matrix_T_t &T, matrix_Vl_t &Vl, matrix_Vr_t &Vr, rwork_t &rwork, work_t &work, const Trevc3Opts &opts={})
TREVC3 computes some or all of the right and/or left eigenvectors of an upper quasi-triangular matrix...
Definition trevc3.hpp:176
@ Both
both sides
@ Right
right side
@ Left
left side
constexpr real_type< T > abs1(const T &x)
1-norm absolute value, |Re(x)| + |Im(x)|
Definition utils.hpp:133
HowMny
Definition trevc.hpp:23
@ Back
all eigenvectors, backtransformed by input matrix
@ All
all eigenvectors
@ Select
selected eigenvectors
@ NoTrans
no transpose
void trevc3_backsolve(const matrix_T_t &T, matrix_X_t &X, vector_colN_t &colN, work_t &work, size_type< matrix_T_t > ks, size_type< matrix_T_t > ke, size_type< matrix_T_t > blocksize)
Calculate the ks-th through ke-th (not inclusive) right eigenvector of T using a blocked backsubstitu...
Definition trevc3_backsolve.hpp:32
@ General
0 <= i <= m, 0 <= j <= n.
void trevc3_forwardsolve(const matrix_T_t &T, matrix_X_t &X, vector_colN_t &colN, work_t &work, size_type< matrix_T_t > ks, size_type< matrix_T_t > ke, size_type< matrix_T_t > blocksize)
Calculate the ks-th through ke-th (not inclusive) left eigenvector of T using a blocked backsubstitut...
Definition trevc3_forwardsolve.hpp:31
int trevc3(const side_t side, const HowMny howmny, select_t &select, const matrix_T_t &T, matrix_Vl_t &Vl, matrix_Vr_t &Vr, const Trevc3Opts &opts={})
TREVC3 computes some or all of the right and/or left eigenvectors of an upper quasi-triangular matrix...
Definition trevc3.hpp:506
Options struct for multishift_qr().
Definition trevc3.hpp:26
Output information in the workspace query.
Definition workspace.hpp:16