numerics 0.1.0
Loading...
Searching...
No Matches
preconditioner.hpp
Go to the documentation of this file.
1/// @file solvers/preconditioner.hpp
2/// @brief Preconditioner concept and diagonal preconditioners.
3/// @todo Add SSOR, incomplete Cholesky, ILU(0), and block-Jacobi
4/// preconditioners for sparse systems.
5#pragma once
6
7#include "core/matrix.hpp"
8#include "core/vector.hpp"
10#include <cmath>
11#include <concepts>
12#include <stdexcept>
13#include <utility>
14
15namespace num {
16
17template<class M>
18concept Preconditioner = requires(const M& M_op, const Vector& r, Vector& z) {
19 { M_op.rows() } -> std::convertible_to<idx>;
20 { M_op.cols() } -> std::convertible_to<idx>;
21 M_op.apply(r, z);
22};
23
25public:
26 explicit JacobiPreconditioner(Vector inv_diag)
27 : inv_diag_(std::move(inv_diag)) {}
28
29 [[nodiscard]] idx rows() const noexcept { return inv_diag_.size(); }
30 [[nodiscard]] idx cols() const noexcept { return inv_diag_.size(); }
31
32 void apply(const Vector& r, Vector& z) const {
33 const idx n = inv_diag_.size();
34 if (r.size() != n) {
35 throw std::invalid_argument("JacobiPreconditioner: dimension mismatch");
36 }
37 if (z.size() != n) {
38 z = Vector(n, 0.0);
39 }
40 for (idx i = 0; i < n; ++i) {
41 z[i] = inv_diag_[i] * r[i];
42 }
43 }
44
45private:
46 Vector inv_diag_;
47};
48
49[[nodiscard]] inline JacobiPreconditioner jacobi_preconditioner(const Matrix& A) {
50 if (A.rows() != A.cols()) {
51 throw std::invalid_argument("jacobi_preconditioner: matrix must be square");
52 }
53 Vector inv(A.rows());
54 for (idx i = 0; i < A.rows(); ++i) {
55 if (std::abs(A(i, i)) < real(1e-15)) {
56 throw std::invalid_argument("jacobi_preconditioner: zero diagonal");
57 }
58 inv[i] = real(1) / A(i, i);
59 }
60 return JacobiPreconditioner(std::move(inv));
61}
62
64 if (A.n_rows() != A.n_cols()) {
65 throw std::invalid_argument("jacobi_preconditioner: matrix must be square");
66 }
67 Vector inv(A.n_rows(), 0.0);
68 for (idx i = 0; i < A.n_rows(); ++i) {
69 const idx row_begin = A.row_ptr()[i];
70 const idx row_end = A.row_ptr()[i + 1];
71 for (idx p = row_begin; p < row_end; ++p) {
72 if (A.col_idx()[p] == i) {
73 inv[i] = A.values()[p];
74 break;
75 }
76 }
77 if (std::abs(inv[i]) < real(1e-15)) {
78 throw std::invalid_argument("jacobi_preconditioner: zero diagonal");
79 }
80 inv[i] = real(1) / inv[i];
81 }
82 return JacobiPreconditioner(std::move(inv));
83}
84
85} // namespace num
constexpr idx rows() const noexcept
Definition matrix.hpp:87
constexpr idx cols() const noexcept
Definition matrix.hpp:88
constexpr idx size() const noexcept
Definition vector.hpp:83
void apply(const Vector &r, Vector &z) const
idx rows() const noexcept
JacobiPreconditioner(Vector inv_diag)
idx cols() const noexcept
Sparse matrix in Compressed Sparse Row (CSR) format.
Definition sparse.hpp:17
idx n_cols() const
Definition sparse.hpp:36
const idx * row_ptr() const
Definition sparse.hpp:45
idx n_rows() const
Definition sparse.hpp:35
const idx * col_idx() const
Definition sparse.hpp:44
const real * values() const
Definition sparse.hpp:43
Dense row-major matrix templated over scalar type T.
double real
Definition types.hpp:10
std::size_t idx
Definition types.hpp:11
constexpr real e
Definition math.hpp:44
JacobiPreconditioner jacobi_preconditioner(const Matrix &A)
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:129
Compressed Sparse Row (CSR) matrix and operations.
Dense vector storage and operations.