numerics
Loading...
Searching...
No Matches
krylov.cpp
Go to the documentation of this file.
2#include "core/vector.hpp"
3#include <cmath>
4#include <algorithm>
5#include <stdexcept>
6#include <vector>
7
8namespace num {
9
10// Core restarted GMRES implementation (matrix-free)
13 if (x.size() != n || b.size() != n)
14 throw std::invalid_argument("Dimension mismatch in GMRES");
15
16 restart = std::min(restart, n);
17 SolverResult result{0, 0.0, false};
18
19 std::vector<Vector> V;
20 V.reserve(restart + 1);
21 std::vector<std::vector<real>> H(restart, std::vector<real>(restart + 1, 0.0));
22 std::vector<real> cs(restart, 0.0);
23 std::vector<real> sn(restart, 0.0);
24 std::vector<real> g(restart + 1, 0.0);
25
26 idx total_iters = 0;
27
28 while (total_iters < max_iter) {
29 Vector r(n);
30 matvec_fn(x, r);
31 for (idx i = 0; i < n; ++i) r[i] = b[i] - r[i];
32
33 real beta = 0.0;
34 for (idx i = 0; i < n; ++i) beta += r[i] * r[i];
35 beta = std::sqrt(beta);
36
37 result.residual = beta;
38 if (beta < tol) { result.converged = true; break; }
39
40 V.clear();
41 V.emplace_back(n);
42 for (idx i = 0; i < n; ++i) V[0][i] = r[i] / beta;
43
44 for (auto& col : H) std::fill(col.begin(), col.end(), 0.0);
45 std::fill(cs.begin(), cs.end(), 0.0);
46 std::fill(sn.begin(), sn.end(), 0.0);
47 std::fill(g.begin(), g.end(), 0.0);
48 g[0] = beta;
49
50 idx j = 0;
51 for (; j < restart && total_iters < max_iter; ++j, ++total_iters) {
52 result.iterations = total_iters + 1;
53
54 Vector w(n);
55 matvec_fn(V[j], w);
56
57 for (idx i = 0; i <= j; ++i) {
58 real h = 0.0;
59 for (idx k = 0; k < n; ++k) h += w[k] * V[i][k];
60 H[j][i] = h;
61 for (idx k = 0; k < n; ++k) w[k] -= h * V[i][k];
62 }
63 real h_next = 0.0;
64 for (idx k = 0; k < n; ++k) h_next += w[k] * w[k];
65 h_next = std::sqrt(h_next);
66 H[j][j + 1] = h_next;
67
68 if (h_next < 1e-15) { ++j; break; }
69
70 V.emplace_back(n);
71 for (idx k = 0; k < n; ++k) V[j + 1][k] = w[k] / h_next;
72
73 for (idx i = 0; i < j; ++i) {
74 real tmp = cs[i] * H[j][i] + sn[i] * H[j][i + 1];
75 H[j][i + 1] = -sn[i] * H[j][i] + cs[i] * H[j][i + 1];
76 H[j][i] = tmp;
77 }
78
79 real h0 = H[j][j], h1 = H[j][j + 1];
80 real denom = std::sqrt(h0 * h0 + h1 * h1);
81 if (denom < 1e-15) { cs[j] = 1.0; sn[j] = 0.0; }
82 else { cs[j] = h0 / denom; sn[j] = h1 / denom; }
83
84 H[j][j] = cs[j] * h0 + sn[j] * h1;
85 H[j][j + 1] = 0.0;
86
87 g[j + 1] = -sn[j] * g[j];
88 g[j] = cs[j] * g[j];
89
90 result.residual = std::abs(g[j + 1]);
91 if (result.residual < tol) { result.converged = true; ++j; break; }
92 }
93
94 idx m = j;
95 std::vector<real> y(m, 0.0);
96 for (idx i = m; i > 0; ) {
97 --i;
98 y[i] = g[i];
99 for (idx k = i + 1; k < m; ++k) y[i] -= H[k][i] * y[k];
100 y[i] /= H[i][i];
101 }
102
103 for (idx i = 0; i < m; ++i)
104 for (idx k = 0; k < n; ++k) x[k] += y[i] * V[i][k];
105
106 if (result.converged) break;
107 }
108
109 return result;
110}
111
112// Sparse overload
115 if (A.n_rows() != A.n_cols())
116 throw std::invalid_argument("GMRES requires a square matrix");
117 idx n = A.n_rows();
118 MatVecFn mv = [&](const Vector& in, Vector& out) {
119 out = Vector(n);
121 };
122 return gmres(mv, n, b, x, tol, max_iter, restart);
123}
124
125// Dense overload -- wraps the matrix-free core with a backend-parameterized matvec
127 real tol, idx max_iter, idx restart, Backend backend) {
128 if (A.rows() != A.cols())
129 throw std::invalid_argument("GMRES requires a square matrix");
130 idx n = A.rows();
131 MatVecFn mv = [&](const Vector& in, Vector& out) {
132 out = Vector(n);
133 matvec(A, in, out, backend);
134 };
135 return gmres(mv, n, b, x, tol, max_iter, restart);
136}
137
138} // namespace num
constexpr idx size() const noexcept
Definition vector.hpp:77
Dense row-major matrix with optional GPU storage.
Definition matrix.hpp:12
Sparse matrix in Compressed Sparse Row (CSR) format.
Definition sparse.hpp:15
Restarted GMRES – a Krylov subspace solver for general Ax = b.
double real
Definition types.hpp:10
Backend
Selects which backend handles a linalg operation.
Definition policy.hpp:19
real beta(real a, real b)
B(a, b) – beta function.
Definition math.hpp:242
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
std::size_t idx
Definition types.hpp:11
void matvec(const Matrix &A, const Vector &x, Vector &y, Backend b=default_backend)
y = A * x
Definition matrix.cpp:94
void sparse_matvec(const SparseMatrix &A, const Vector &x, Vector &y)
y = A * x
Definition sparse.cpp:110
SolverResult gmres(MatVecFn matvec, idx n, const Vector &b, Vector &x, real tol=1e-6, idx max_iter=1000, idx restart=30)
Restarted GMRES(restart) – matrix-free interface.
Definition krylov.cpp:11
constexpr real e
Definition math.hpp:41
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:122
std::function< void(const Vector &, Vector &)> MatVecFn
Callable type for matrix-free matvec: computes y = A*x.
Definition cg.hpp:13
Vector operations.