numerics 0.1.0
Loading...
Searching...
No Matches
krylov.hpp
Go to the documentation of this file.
1/// @file krylov.hpp
2/// @brief Restarted GMRES for general linear systems.
3///
4/// Minimizes \f$\|b-Ax_k\|_2\f$ over \f$x_0+\mathcal{K}_m(A,r_0)\f$ and
5/// restarts after \f$m=\texttt{restart}\f$ Arnoldi steps.
6#pragma once
7#include "core/matrix.hpp"
8#include "core/policy.hpp"
9#include "core/vector.hpp"
10#include "kernel/subspace.hpp"
14#include <algorithm>
15#include <cmath>
16#include <stdexcept>
17#include <vector>
18
19namespace num {
20
21/// @brief Operator GMRES for any \f$y=A x\f$ adapter.
22template<class Op>
23 requires operators::LinearOperator<Op, Vector, Vector>
24SolverResult gmres(const Op& A,
25 const Vector& b,
26 Vector& x,
27 real tol = 1e-6,
28 idx max_iter = 1000,
29 idx restart = 30) {
30 const idx n = b.size();
31 if (A.rows() != n || A.cols() != n || x.size() != n) {
32 throw std::invalid_argument("Dimension mismatch in operator GMRES solver");
33 }
34 if (restart <= 0) {
35 throw std::invalid_argument("GMRES restart must be positive");
36 }
37
38 restart = std::min(restart, n);
39 SolverResult result{0, 0.0, false};
40
41 std::vector<Vector> V;
42 V.reserve(restart + 1);
43 std::vector<std::vector<real>> H(restart, std::vector<real>(restart + 1, 0.0));
44 std::vector<real> cs(restart, 0.0);
45 std::vector<real> sn(restart, 0.0);
46 std::vector<real> g(restart + 1, 0.0);
47 Vector scratch(n);
48
49 idx total_iters = 0;
50
51 while (total_iters < max_iter) {
52 Vector r(n);
53 A.apply(x, r);
54 for (idx i = 0; i < n; ++i) {
55 r[i] = b[i] - r[i];
56 }
57
58 const real beta = norm(r);
59 result.residual = beta;
60 if (beta < tol) {
61 result.converged = true;
62 break;
63 }
64
65 V.clear();
66 V.emplace_back(n);
67 for (idx i = 0; i < n; ++i) {
68 V[0][i] = r[i] / beta;
69 }
70
71 for (auto& col : H) {
72 std::fill(col.begin(), col.end(), 0.0);
73 }
74 std::fill(cs.begin(), cs.end(), 0.0);
75 std::fill(sn.begin(), sn.end(), 0.0);
76 std::fill(g.begin(), g.end(), 0.0);
77 g[0] = beta;
78
79 idx j = 0;
80 for (; j < restart && total_iters < max_iter; ++j, ++total_iters) {
81 result.iterations = total_iters + 1;
82
83 A.apply(V[j], scratch);
84 const real h_next =
85 kernel::subspace::mgs_orthogonalize(V, scratch, H[j], j + 1);
86 H[j][j + 1] = h_next;
87
88 if (h_next > real(1e-15)) {
89 scale(scratch, real(1) / h_next);
90 V.push_back(scratch);
91 } else {
92 ++j;
93 break;
94 }
95
96 for (idx i = 0; i < j; ++i) {
97 real tmp = cs[i] * H[j][i] + sn[i] * H[j][i + 1];
98 H[j][i + 1] = -sn[i] * H[j][i] + cs[i] * H[j][i + 1];
99 H[j][i] = tmp;
100 }
101
102 real h0 = H[j][j], h1 = H[j][j + 1];
103 real denom = std::sqrt(h0 * h0 + h1 * h1);
104 if (denom < real(1e-15)) {
105 cs[j] = 1.0;
106 sn[j] = 0.0;
107 } else {
108 cs[j] = h0 / denom;
109 sn[j] = h1 / denom;
110 }
111
112 H[j][j] = cs[j] * h0 + sn[j] * h1;
113 H[j][j + 1] = 0.0;
114
115 g[j + 1] = -sn[j] * g[j];
116 g[j] = cs[j] * g[j];
117
118 result.residual = std::abs(g[j + 1]);
119 if (result.residual < tol) {
120 result.converged = true;
121 ++j;
122 break;
123 }
124 }
125
126 const idx m = j;
127 std::vector<real> y(m, 0.0);
128 for (idx i = m; i > 0;) {
129 --i;
130 y[i] = g[i];
131 for (idx k = i + 1; k < m; ++k) {
132 y[i] -= H[k][i] * y[k];
133 }
134 y[i] /= H[i][i];
135 }
136
137 for (idx i = 0; i < m; ++i) {
138 for (idx k = 0; k < n; ++k) {
139 x[k] += y[i] * V[i][k];
140 }
141 }
142
143 if (result.converged) {
144 break;
145 }
146 }
147
148 return result;
149}
150
151SolverResult gmres(const SparseMatrix& A,
152 const Vector& b,
153 Vector& x,
154 real tol = 1e-6,
155 idx max_iter = 1000,
156 idx restart = 30);
157
158SolverResult gmres(const Matrix& A,
159 const Vector& b,
160 Vector& x,
161 real tol = 1e-6,
162 idx max_iter = 1000,
163 idx restart = 30,
164 Backend backend = default_backend);
165
166} // namespace num
constexpr idx size() const noexcept
Definition vector.hpp:83
Backend enum and default backend selection.
Compressed Sparse Row (CSR) matrix and operations.
Dense row-major matrix templated over scalar type T.
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
Backend
Definition policy.hpp:7
SolverResult gmres(const Op &A, const Vector &b, Vector &x, real tol=1e-6, idx max_iter=1000, idx restart=30)
Operator GMRES for any adapter.
Definition krylov.hpp:24
real beta(real a, real b)
B(a, b) – beta function.
Definition math.hpp:248
std::size_t idx
Definition types.hpp:11
void scale(Vector &v, real alpha, Backend b=default_backend)
Compute .
Definition vector.cpp:15
BasicMatrix< real > Matrix
Double-precision dense matrix with full backend dispatch (CPU + GPU).
Definition matrix.hpp:127
constexpr real e
Definition math.hpp:44
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:129
real norm(const Vector &x, Backend b=default_backend)
Compute .
Definition vector.cpp:83
constexpr Backend default_backend
Definition policy.hpp:53
Umbrella include for operator concepts and adapters.
Common result type shared by all iterative solvers.
Subspace construction and orthogonalization kernels.
Dense vector storage and operations.