version 0.4.1
linearsolver.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
9#pragma once
10#include <memory>
11#include <type_traits>
12#include <variant>
13
14#include <dune/common/exceptions.hh>
15
16#include <Eigen/Core>
17#include <Eigen/SparseCore>
18
20namespace Ikarus {
21
28MAKE_ENUM(SolverTypeTag, none, si_ConjugateGradient, si_LeastSquaresConjugateGradient, si_BiCGSTAB, sd_SimplicialLLT,
29 sd_SimplicialLDLT, sd_SparseLU, sd_SparseQR, sd_CholmodSupernodalLLT, sd_UmfPackLU, sd_SuperLU,
30 d_PartialPivLU, d_FullPivLU, d_HouseholderQR, d_ColPivHouseholderQR, d_FullPivHouseholderQR,
31 d_CompleteOrthogonalDecomposition, d_LLT, d_LDLT);
32
37enum class MatrixTypeTag
38{
39 Dense,
40 Sparse
41};
42
49template <typename ST = double>
51{
52public:
53 using ScalarType = ST;
54 using SparseMatrixType = Eigen::SparseMatrix<ScalarType>;
55 using DenseMatrixType = Eigen::MatrixX<ScalarType>;
56
58
63 explicit LinearSolverTemplate(const SolverTypeTag& solverTypeTag);
64
69
70 friend void swap(LinearSolverTemplate& lhs, LinearSolverTemplate& rhs) noexcept {
71 std::swap(lhs.solverimpl_, rhs.solverimpl_);
72 std::swap(lhs.solverTypeTag_, rhs.solverTypeTag_);
73 }
80 LinearSolverTemplate tmp(other);
81 swap(*this, tmp);
82 return *this;
83 }
84
89 LinearSolverTemplate(const LinearSolverTemplate& other) { *this = LinearSolverTemplate(other.solverTypeTag_); }
94 LinearSolverTemplate(LinearSolverTemplate&& other) noexcept = default;
101
102private:
103 struct SolverBase
104 {
105 virtual ~SolverBase() = default;
106 virtual void analyzePattern(const DenseMatrixType&) const {}
107 virtual void analyzePattern(const SparseMatrixType&) = 0;
108 virtual void factorize(const DenseMatrixType&) = 0;
109 virtual void factorize(const SparseMatrixType&) = 0;
110 virtual void compute(const SparseMatrixType&) = 0;
111 virtual void compute(const DenseMatrixType&) = 0;
112 virtual void solve(Eigen::VectorX<ScalarType>& x, const Eigen::VectorX<ScalarType>&) const = 0;
113 virtual void solve(Eigen::MatrixX2<ScalarType>& x, const Eigen::MatrixX2<ScalarType>&) const = 0;
114 virtual void solve(Eigen::MatrixX3<ScalarType>& x, const Eigen::MatrixX3<ScalarType>&) const = 0;
115 virtual void solve(Eigen::MatrixX<ScalarType>& x, const Eigen::MatrixX<ScalarType>&) const = 0;
116 };
117
118 template <typename Solver>
119 struct SolverImpl : public SolverBase
120 {
121 using SolverBase::analyzePattern; // forward use of analyzePattern(DenseMatrixType)
122
123 void analyzePattern(const SparseMatrixType& A) final {
124 if constexpr (requires(Solver sol) { sol.analyzePattern(A); })
125 solver.analyzePattern(A);
126 }
127
128 void factorize(const SparseMatrixType& A) final {
129 if constexpr (requires(Solver sol) { sol.factorize(A); })
130 solver.factorize(A);
131 }
132
133 // Dense Solvers do not have a factorize method therefore
134 // our interface we just call compute for dense matrices
135 void factorize(const DenseMatrixType& A) final {
136 if constexpr (requires(Solver sol) { sol.compute(A); } && std::is_base_of_v<Eigen::SolverBase<Solver>, Solver>)
137 solver.compute(A);
138 }
139 void compute(const SparseMatrixType& A) final {
140 if constexpr (std::is_base_of_v<Eigen::SparseSolverBase<Solver>, Solver>)
141 solver.compute(A);
142 else
143 DUNE_THROW(Dune::NotImplemented, "This solver does not support solving with sparse matrices.");
144 }
145
146 void compute(const DenseMatrixType& A) final {
147 if constexpr (std::is_base_of_v<Eigen::SolverBase<Solver>, Solver>)
148 solver.compute(A);
149 else
150 DUNE_THROW(Dune::NotImplemented, "This solver does not support solving with dense matrices.");
151 }
152
153 void solve(Eigen::VectorX<ScalarType>& x, const Eigen::VectorX<ScalarType>& b) const final { x = solver.solve(b); }
154
155 void solve(Eigen::MatrixX2<ScalarType>& x, const Eigen::MatrixX2<ScalarType>& b) const final {
156 x = solver.solve(b);
157 }
158
159 void solve(Eigen::MatrixX3<ScalarType>& x, const Eigen::MatrixX3<ScalarType>& b) const final {
160 x = solver.solve(b);
161 }
162
163 void solve(Eigen::MatrixX<ScalarType>& x, const Eigen::MatrixX<ScalarType>& b) const final { x = solver.solve(b); }
164
165 Solver solver;
166 };
167
168 std::unique_ptr<SolverBase> solverimpl_;
169 SolverTypeTag solverTypeTag_{SolverTypeTag::none};
170
171public:
178 template <typename MatrixType>
179 requires std::is_same_v<MatrixType, DenseMatrixType> || std::is_same_v<MatrixType, SparseMatrixType>
180 inline LinearSolverTemplate& compute(const MatrixType& A) {
181 solverimpl_->compute(A);
182 return *this;
183 }
184
190 template <typename MatrixType>
191 requires std::is_same_v<MatrixType, DenseMatrixType> || std::is_same_v<MatrixType, SparseMatrixType>
192 inline void analyzePattern(const MatrixType& A) {
193 solverimpl_->analyzePattern(A);
194 }
195
201 template <typename MatrixType>
202 requires std::is_same_v<MatrixType, DenseMatrixType> || std::is_same_v<MatrixType, SparseMatrixType>
203 inline void factorize(const MatrixType& A) {
204 solverimpl_->factorize(A);
205 }
206
212 void solve(Eigen::VectorX<ScalarType>& x, const Eigen::VectorX<ScalarType>& b) { solverimpl_->solve(x, b); }
213
219 void solve(Eigen::MatrixX3<ScalarType>& x, const Eigen::MatrixX3<ScalarType>& b) { solverimpl_->solve(x, b); }
225 void solve(Eigen::MatrixX2<ScalarType>& x, const Eigen::MatrixX2<ScalarType>& b) { solverimpl_->solve(x, b); }
226
232 void solve(Eigen::MatrixX<ScalarType>& x, const Eigen::MatrixX<ScalarType>& b) { solverimpl_->solve(x, b); }
233};
234
236extern template class LinearSolverTemplate<double>;
237} // namespace Ikarus
Implementation of the make enum macro.
#define MAKE_ENUM(type,...)
Macro to create an enumeration with a string conversion function.The macro creates an enum class with...
Definition: makeenum.hh:40
Definition: assemblermanipulatorbuildingblocks.hh:22
MatrixTypeTag
Enumeration representing different matrix types (Dense or Sparse).
Definition: linearsolver.hh:38
SolverTypeTag
Enumeration representing different solver types.
Definition: linearsolver.hh:31
A type-erased class which wraps most of the linear solvers available in Eigen.
Definition: linearsolver.hh:51
friend void swap(LinearSolverTemplate &lhs, LinearSolverTemplate &rhs) noexcept
Definition: linearsolver.hh:70
LinearSolverTemplate & compute(const MatrixType &A)
Compute the factorization of the matrix.
Definition: linearsolver.hh:180
LinearSolverTemplate(const SolverTypeTag &solverTypeTag)
Constructor for LinearSolverTemplate.
LinearSolverTemplate & operator=(LinearSolverTemplate &&other) noexcept=default
Move assignment operator.
LinearSolverTemplate(const LinearSolverTemplate &other)
Copy constructor.
Definition: linearsolver.hh:89
void solve(Eigen::MatrixX3< ScalarType > &x, const Eigen::MatrixX3< ScalarType > &b)
Solve the linear system for a n times 3 matrix.
Definition: linearsolver.hh:219
~LinearSolverTemplate()=default
Destructor for LinearSolverTemplate.
void solve(Eigen::MatrixX< ScalarType > &x, const Eigen::MatrixX< ScalarType > &b)
Solve the linear system for a n times n matrix.
Definition: linearsolver.hh:232
void analyzePattern(const MatrixType &A)
Analyze the pattern of the matrix.
Definition: linearsolver.hh:192
LinearSolverTemplate(LinearSolverTemplate &&other) noexcept=default
Move constructor.
Eigen::MatrixX< ScalarType > DenseMatrixType
Definition: linearsolver.hh:55
LinearSolverTemplate & operator=(const LinearSolverTemplate &other)
Copy assignment operator.
Definition: linearsolver.hh:79
ST ScalarType
Definition: linearsolver.hh:53
Eigen::SparseMatrix< ScalarType > SparseMatrixType
Definition: linearsolver.hh:54
void factorize(const MatrixType &A)
Factorize the matrix.
Definition: linearsolver.hh:203
void solve(Eigen::VectorX< ScalarType > &x, const Eigen::VectorX< ScalarType > &b)
Solve the linear system for a vector.
Definition: linearsolver.hh:212
void solve(Eigen::MatrixX2< ScalarType > &x, const Eigen::MatrixX2< ScalarType > &b)
Solve the linear system for a n times 2 matrix.
Definition: linearsolver.hh:225