numerics 0.1.0
Loading...
Searching...
No Matches
lanczos.hpp
Go to the documentation of this file.
1/// @file eigen/lanczos.hpp
2/// @brief Lanczos eigensolver for symmetric operators.
3///
4/// Builds an orthonormal basis \f$Q_m\f$ such that
5/// \f$Q_m^T A Q_m = T_m\f$, with \f$T_m\f$ tridiagonal.
6/// @todo Add thick-restart Lanczos and selective reorthogonalization controls.
7#pragma once
8
9#include "core/matrix.hpp"
10#include "core/policy.hpp"
11#include "core/vector.hpp"
12#include "kernel/subspace.hpp"
15#include "core/concepts.hpp"
16#include <algorithm>
17#include <cmath>
18#include <stdexcept>
19
20namespace num {
21
28
29namespace detail {
30
31template<class Op>
34 idx k,
35 real tol,
36 idx max_steps,
37 Backend backend) {
38 (void)backend;
39 const idx n = A.rows();
40 if (A.cols() != n) {
41 throw std::invalid_argument("lanczos: operator must be square");
42 }
43 if (k == 0 || k > n) {
44 throw std::invalid_argument("lanczos: k must satisfy 0 < k <= n");
45 }
46
47 if (max_steps == 0) {
48 max_steps = std::min(3 * k, n);
49 }
50 max_steps = std::min(max_steps, n);
51
52 Matrix V(n, max_steps, 0.0);
53 Vector alpha(max_steps, 0.0);
54 Vector beta(max_steps, 0.0);
55
56 for (idx i = 0; i < n; ++i) {
57 V(i, 0) = (i == 0) ? 1.0 : 0.0;
58 }
59
60 idx steps = 0;
61
62 for (idx j = 0; j < max_steps; ++j) {
63 Vector vj(n);
64 for (idx i = 0; i < n; ++i) {
65 vj[i] = V(i, j);
66 }
67
68 Vector w(n, 0.0);
69 A.apply(vj, w);
70
71 const real a = dot(vj, w);
72 alpha[j] = a;
73
74 axpy(-a, vj, w);
75 if (j > 0) {
76 for (idx i = 0; i < n; ++i) {
77 w[i] -= beta[j - 1] * V(i, j - 1);
78 }
79 }
80
81 const real b = kernel::subspace::mgs_orthogonalize(V, j + 1, w);
82 ++steps;
83
84 if (b < real(1e-12)) {
85 break;
86 }
87
88 beta[j] = b;
89
90 if (j + 1 < max_steps) {
91 for (idx i = 0; i < n; ++i) {
92 V(i, j + 1) = w[i] / b;
93 }
94 }
95 }
96
97 const idx m = steps;
98 Matrix T(m, m, 0.0);
99 for (idx j = 0; j < m; ++j) {
100 T(j, j) = alpha[j];
101 if (j + 1 < m) {
102 T(j, j + 1) = beta[j];
103 T(j + 1, j) = beta[j];
104 }
105 }
106
107 EigenResult teig = eig_sym(T, tol * real(1e-2));
108 const idx nret = std::min(k, m);
109
110 Matrix ritz_vecs(n, nret, 0.0);
111 for (idx i = 0; i < nret; ++i) {
112 const idx ti = m - nret + i;
113 for (idx j = 0; j < m; ++j) {
114 const real coeff = teig.vectors(j, ti);
115 for (idx r = 0; r < n; ++r) {
116 ritz_vecs(r, i) += coeff * V(r, j);
117 }
118 }
119 }
120
121 Vector ritz_vals(nret);
122 for (idx i = 0; i < nret; ++i) {
123 ritz_vals[i] = teig.values[m - nret + i];
124 }
125
126 bool all_converged = true;
127 for (idx i = 0; i < nret; ++i) {
128 Vector u(n);
129 for (idx r = 0; r < n; ++r) {
130 u[r] = ritz_vecs(r, i);
131 }
132
133 Vector Au(n, 0.0);
134 A.apply(u, Au);
135
136 real res = 0;
137 const real lam = ritz_vals[i];
138 for (idx r = 0; r < n; ++r) {
139 const real d = Au[r] - lam * u[r];
140 res += d * d;
141 }
142 if (std::sqrt(res) > tol) {
143 all_converged = false;
144 break;
145 }
146 }
147
148 return {ritz_vals, ritz_vecs, steps, all_converged};
149}
150
151} // namespace detail
152
153/// @brief Operator Lanczos for a declared symmetric \f$y=A x\f$ adapter.
154template<class Op>
155 requires SymmetricLinearOperator<Op, Vector, Vector>
157 idx k,
158 real tol = 1e-10,
159 idx max_steps = 0,
160 Backend backend = Backend::seq) {
161 return detail::lanczos_operator_impl(A, k, tol, max_steps, backend);
162}
163
164LanczosResult lanczos(const Matrix& A,
165 idx k,
166 real tol = 1e-10,
167 idx max_steps = 0,
168 Backend backend = Backend::seq);
169
170LanczosResult lanczos(const SparseMatrix& A,
171 idx k,
172 real tol = 1e-10,
173 idx max_steps = 0,
174 Backend backend = Backend::seq);
175
176} // namespace num
Compile-time contract for the matrix-free product y = A*x.
Definition concepts.hpp:67
Storage and operator concepts for numerical routines.
Backend enum and default backend selection.
Full symmetric eigendecomposition via cyclic Jacobi sweeps.
Dense row-major matrix templated over scalar type T.
LanczosResult lanczos_operator_impl(const Op &A, idx k, real tol, idx max_steps, Backend backend)
Definition lanczos.hpp:33
real mgs_orthogonalize(const std::vector< Vector > &basis, Vector &v, std::vector< real > &h, idx k)
Modified Gram-Schmidt against basis[0..k-1].
Definition subspace.cpp:9
double real
Definition types.hpp:10
LanczosResult lanczos(const Op &A, idx k, real tol=1e-10, idx max_steps=0, Backend backend=Backend::seq)
Operator Lanczos for a declared symmetric adapter.
Definition lanczos.hpp:156
Backend
Definition policy.hpp:7
real beta(real a, real b)
B(a, b) – beta function.
Definition math.hpp:248
std::size_t idx
Definition types.hpp:11
BasicMatrix< real > Matrix
Double-precision dense matrix with full backend dispatch (CPU + GPU).
Definition matrix.hpp:127
real dot(const Vector &x, const Vector &y, Backend b=default_backend)
Compute .
Definition vector.cpp:65
constexpr real e
Definition math.hpp:44
void axpy(real alpha, const Vector &x, Vector &y, Backend b=default_backend)
Compute .
Definition vector.cpp:44
EigenResult eig_sym(const Matrix &A, real tol=1e-12, idx max_sweeps=100, Backend backend=lapack_backend)
Definition eig.cpp:11
Compressed Sparse Row (CSR) matrix and operations.
Symmetric eigendecomposition .
Subspace construction and orthogonalization kernels.
Dense vector storage and operations.