15 throw std::invalid_argument(
"Dimension mismatch in GMRES");
17 restart = std::min(restart, n);
20 std::vector<Vector> V;
21 V.reserve(restart + 1);
22 std::vector<std::vector<real>> H(restart,
23 std::vector<real>(restart + 1, 0.0));
24 std::vector<real> cs(restart, 0.0);
25 std::vector<real> sn(restart, 0.0);
26 std::vector<real> g(restart + 1, 0.0);
30 [&](
const Vector& in,
Vector& out) { matvec_fn(in, out); }, n);
35 while (total_iters < max_iter) {
38 for (
idx i = 0; i < n; ++i)
42 for (
idx i = 0; i < n; ++i)
46 result.residual =
beta;
48 result.converged =
true;
54 for (
idx i = 0; i < n; ++i)
55 V[0][i] = r[i] /
beta;
58 std::fill(col.begin(), col.end(), 0.0);
59 std::fill(cs.begin(), cs.end(), 0.0);
60 std::fill(sn.begin(), sn.end(), 0.0);
61 std::fill(g.begin(), g.end(), 0.0);
65 for (; j < restart && total_iters < max_iter; ++j, ++total_iters) {
66 result.iterations = total_iters + 1;
69 A_op, V, H[j], j, scratch,
real(1
e-15));
76 for (
idx i = 0; i < j; ++i) {
77 real tmp = cs[i] * H[j][i] + sn[i] * H[j][i + 1];
78 H[j][i + 1] = -sn[i] * H[j][i] + cs[i] * H[j][i + 1];
82 real h0 = H[j][j], h1 = H[j][j + 1];
83 real denom = std::sqrt(h0 * h0 + h1 * h1);
92 H[j][j] = cs[j] * h0 + sn[j] * h1;
95 g[j + 1] = -sn[j] * g[j];
98 result.residual = std::abs(g[j + 1]);
99 if (result.residual < tol) {
100 result.converged =
true;
107 std::vector<real> y(m, 0.0);
108 for (
idx i = m; i > 0;) {
111 for (
idx k = i + 1; k < m; ++k)
112 y[i] -= H[k][i] * y[k];
116 for (
idx i = 0; i < m; ++i)
117 for (
idx k = 0; k < n; ++k)
118 x[k] += y[i] * V[i][k];
120 if (result.converged)
real arnoldi_step(const LinearOp &A, std::vector< Vector > &basis, std::vector< real > &h, idx k, Vector &scratch, real breakdown_tol=real(1e-14))
One Arnoldi step: expand the orthonormal basis by one vector.
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.