numerics
Loading...
Searching...
No Matches
cg.cpp
Go to the documentation of this file.
3#include <cmath>
4#include <stdexcept>
5
6namespace num {
7
8SolverResult cg(const Matrix& A, const Vector& b, Vector& x,
9 real tol, idx max_iter, Backend backend) {
10 idx n = b.size();
11 if (A.rows() != n || A.cols() != n || x.size() != n)
12 throw std::invalid_argument("Dimension mismatch in CG solver");
13
14 // GPU path: transfer all data to device first
15 if (backend == Backend::gpu) {
16 const_cast<Matrix&>(A).to_gpu();
17 const_cast<Vector&>(b).to_gpu();
18 x.to_gpu();
19 }
20
21 Vector r(n), p(n), Ap(n);
22 if (backend == Backend::gpu) { r.to_gpu(); p.to_gpu(); Ap.to_gpu(); }
23
24 matvec(A, x, r, backend);
25 if (backend == Backend::gpu) {
26 scale(r, -1.0, backend);
27 axpy(1.0, b, r, backend);
28 cuda::to_device(p.gpu_data(), r.gpu_data(), n);
29 } else {
30 for (idx i = 0; i < n; ++i) r[i] = b[i] - r[i];
31 for (idx i = 0; i < n; ++i) p[i] = r[i];
32 }
33
34 real rsold = dot(r, r, backend);
35 SolverResult result{0, std::sqrt(rsold), false};
36
37 for (idx iter = 0; iter < max_iter; ++iter) {
39 matvec(A, p, Ap, backend);
40
41 real pAp = dot(p, Ap, backend);
42 if (std::abs(pAp) < 1e-15) break;
43 real alpha = rsold / pAp;
44
45 axpy(alpha, p, x, backend);
46 axpy(-alpha, Ap, r, backend);
47
48 real rsnew = dot(r, r, backend);
49 result.residual = std::sqrt(rsnew);
50
51 if (result.residual < tol) {
52 result.converged = true;
53 break;
54 }
55
56 real beta = rsnew / rsold;
57 scale(p, beta, backend);
58 axpy(1.0, r, p, backend);
59 rsold = rsnew;
60 }
61
62 if (backend == Backend::gpu) x.to_cpu();
63 return result;
64}
65
68 idx n = b.size();
69 Vector r(n), p(n), Ap(n);
70
71 matvec_fn(x, r);
72 for (idx i = 0; i < n; ++i) r[i] = b[i] - r[i];
73 for (idx i = 0; i < n; ++i) p[i] = r[i];
74
76 SolverResult result{0, std::sqrt(rsold), false};
77
78 for (idx iter = 0; iter < max_iter; ++iter) {
80 matvec_fn(p, Ap);
81
82 real pAp = dot(p, Ap, Backend::seq);
83 if (std::abs(pAp) < 1e-15) break;
84 real alpha = rsold / pAp;
85
86 axpy(alpha, p, x, Backend::seq);
88
90 result.residual = std::sqrt(rsnew);
91 if (result.residual < tol) { result.converged = true; break; }
92
93 real beta = rsnew / rsold;
95 axpy(1.0, r, p, Backend::seq);
96 rsold = rsnew;
97 }
98 return result;
99}
100
101} // namespace num
Conjugate gradient solvers (dense and matrix-free)
constexpr idx size() const noexcept
Definition vector.hpp:77
Dense row-major matrix with optional GPU storage.
Definition matrix.hpp:12
CUDA kernel wrappers.
void to_device(real *dst, const real *src, idx n)
Copy host to device.
double real
Definition types.hpp:10
Backend
Selects which backend handles a linalg operation.
Definition policy.hpp:19
@ gpu
CUDA – custom kernels or cuBLAS.
@ seq
Naive textbook loops – always available.
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 scale(Vector &v, real alpha, Backend b=default_backend)
v *= alpha
Definition vector.cpp:27
real dot(const Vector &x, const Vector &y, Backend b=default_backend)
dot product
Definition vector.cpp:57
constexpr real e
Definition math.hpp:41
void axpy(real alpha, const Vector &x, Vector &y, Backend b=default_backend)
y += alpha * x
Definition vector.cpp:46
SolverResult cg_matfree(MatVecFn matvec, const Vector &b, Vector &x, real tol=1e-6, idx max_iter=1000)
Matrix-free conjugate gradient for Ax = b where A is SPD.
Definition cg.cpp:66
SolverResult cg(const Matrix &A, const Vector &b, Vector &x, real tol=1e-10, idx max_iter=1000, Backend backend=default_backend)
Conjugate gradient solver for Ax = b.
Definition cg.cpp:8
std::function< void(const Vector &, Vector &)> MatVecFn
Callable type for matrix-free matvec: computes y = A*x.
Definition cg.hpp:13
idx iterations
Number of iterations performed.