EllAlgo 1.6.13
Loading...
Searching...
No Matches
conjugate_gradient.hpp
Go to the documentation of this file.
1
10#ifndef CONJUGATE_GRADIENT_HPP
11#define CONJUGATE_GRADIENT_HPP
12
13#include <cmath>
14#include <stdexcept>
15#include <string>
16#include <utility>
17#include <vector>
18
19// GCC 13 with -Wall -Werror emits -Werror=alloc-size-larger-than= when a size_t
20// parameter is passed to std::vector constructor, because the compiler can't prove
21// the allocation won't exceed PTRDIFF_MAX. This is a false positive when sizes
22// are bounded by actual matrix dimensions at runtime.
23#if defined(__GNUC__) && !defined(__clang__)
24# pragma GCC diagnostic push
25# pragma GCC diagnostic ignored "-Walloc-size-larger-than="
26#endif
27
35class Vector0 {
36 public:
42 Vector0(size_t size) : data(size, 0.0) {}
43
49 Vector0(const std::vector<double>& v) : data(v) {}
50
57 double& operator[](size_t i) { return data[i]; }
58
65 const double& operator[](size_t i) const { return data[i]; }
66
72 size_t size() const { return data.size(); }
73
80 Vector0& operator+=(const Vector0& rhs) {
81 for (size_t i = 0; i < size(); ++i) data[i] += rhs[i];
82 return *this;
83 }
90 Vector0& operator-=(const Vector0& rhs) {
91 for (size_t i = 0; i < size(); ++i) data[i] -= rhs[i];
92 return *this;
93 }
100 Vector0& operator*=(double scalar) {
101 for (auto& val : data) val *= scalar;
102 return *this;
103 }
104
111 double dot(const Vector0& other) const {
112 double sum = 0.0;
113 for (size_t i = 0; i < size(); ++i) sum += data[i] * other[i];
114 return sum;
115 }
116
122 double norm() const { return std::sqrt(dot(*this)); }
123
124 private:
125 std::vector<double> data;
126};
127
135inline Vector0 operator+(Vector0 lhs, const Vector0& rhs) {
136 lhs += rhs;
137 return lhs;
138}
139
147inline Vector0 operator-(Vector0 lhs, const Vector0& rhs) {
148 lhs -= rhs;
149 return lhs;
150}
151
159inline Vector0 operator*(Vector0 v, double scalar) {
160 v *= scalar;
161 return v;
162}
163
171inline Vector0 operator*(double scalar, Vector0 v) { return std::move(v) * scalar; }
172
179class Matrix0 {
180 public:
187 Matrix0(size_t rows, size_t cols) : data(rows, std::vector<double>(cols, 0.0)) {}
188
195 std::vector<double>& operator[](size_t i) { return data[i]; }
196
203 const std::vector<double>& operator[](size_t i) const { return data[i]; }
204
210 size_t rows() const { return data.size(); }
211
217 size_t cols() const { return data[0].size(); }
218
225 Vector0 dot(const Vector0& v) const {
226 Vector0 result(rows());
227 for (size_t i = 0; i < rows(); ++i) {
228 for (size_t j = 0; j < cols(); ++j) {
229 result[i] += data[i][j] * v[j];
230 }
231 }
232 return result;
233 }
234
235 private:
236 std::vector<std::vector<double>> data;
237};
238
286template <typename Matrix0, typename Vector0>
287inline Vector0 conjugate_gradient(const Matrix0& A, const Vector0& b, const Vector0* x0 = nullptr,
288 double tol = 1e-5, int max_iter = 1000) {
289 size_t ndim = b.size();
290 Vector0 x_vector = x0 ? *x0 : Vector0(ndim);
291
292 Vector0 residual = b - A.dot(x_vector);
293 Vector0 director = residual;
294 double r_norm_sq = residual.dot(residual);
295
296 for (int i = 0; i < max_iter; ++i) {
297 Vector0 Ap = A.dot(director);
298 double alpha = r_norm_sq / director.dot(Ap);
299 x_vector += alpha * director;
300 residual -= alpha * Ap;
301 double r_norm_sq_new = residual.dot(residual);
302
303 if (std::sqrt(r_norm_sq_new) < tol) {
304 return x_vector;
305 }
306
307 double beta = r_norm_sq_new / r_norm_sq;
308 director = residual + beta * director;
309 r_norm_sq = r_norm_sq_new;
310 }
311
312 throw std::runtime_error("Conjugate Gradient did not converge after " + std::to_string(max_iter)
313 + " iterations");
314}
315
316#if defined(__GNUC__) && !defined(__clang__)
317# pragma GCC diagnostic pop
318#endif
319
320#endif // CONJUGATE_GRADIENT_HPP
double sum(const Arr &a)
Sum of all elements.
Definition arr.hpp:260
A simple matrix class for conjugate gradient calculations.
Definition conjugate_gradient.hpp:179
size_t cols() const
Get the number of columns.
Definition conjugate_gradient.hpp:217
const std::vector< double > & operator[](size_t i) const
Access row i of the matrix (const version)
Definition conjugate_gradient.hpp:203
Vector0 dot(const Vector0 &v) const
Multiply the matrix by a vector.
Definition conjugate_gradient.hpp:225
std::vector< double > & operator[](size_t i)
Access row i of the matrix.
Definition conjugate_gradient.hpp:195
size_t rows() const
Get the number of rows.
Definition conjugate_gradient.hpp:210
Matrix0(size_t rows, size_t cols)
Construct a new Matrix0 object.
Definition conjugate_gradient.hpp:187
A simple vector class for conjugate gradient calculations.
Definition conjugate_gradient.hpp:35
Vector0 & operator*=(double scalar)
Multiply this vector by a scalar.
Definition conjugate_gradient.hpp:100
const double & operator[](size_t i) const
Access element at index i (const version)
Definition conjugate_gradient.hpp:65
Vector0(size_t size)
Construct a new Vector0 object with given size.
Definition conjugate_gradient.hpp:42
double norm() const
Compute the L2 norm of the vector.
Definition conjugate_gradient.hpp:122
Vector0 & operator-=(const Vector0 &rhs)
Subtract another vector from this vector.
Definition conjugate_gradient.hpp:90
double & operator[](size_t i)
Access element at index i.
Definition conjugate_gradient.hpp:57
double dot(const Vector0 &other) const
Compute the dot product with another vector.
Definition conjugate_gradient.hpp:111
Vector0(const std::vector< double > &v)
Construct a new Vector0 from a std::vector.
Definition conjugate_gradient.hpp:49
size_t size() const
Get the size of the vector.
Definition conjugate_gradient.hpp:72
Vector0 & operator+=(const Vector0 &rhs)
Add another vector to this vector.
Definition conjugate_gradient.hpp:80
Vector0 operator+(Vector0 lhs, const Vector0 &rhs)
Element-wise vector addition.
Definition conjugate_gradient.hpp:135
Vector0 operator*(Vector0 v, double scalar)
Scalar-vector multiplication (vector * scalar)
Definition conjugate_gradient.hpp:159
Vector0 operator-(Vector0 lhs, const Vector0 &rhs)
Element-wise vector subtraction.
Definition conjugate_gradient.hpp:147
Vector0 conjugate_gradient(const Matrix0 &A, const Vector0 &b, const Vector0 *x0=nullptr, double tol=1e-5, int max_iter=1000)
Solve Ax = b using the conjugate gradient method.
Definition conjugate_gradient.hpp:287