Loading...
Searching...
No Matches
pminres.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "identity_solver.hpp"
8#include "util/table.hpp"
9
10namespace terra::linalg::solvers {
11
12/// @brief Preconditioned MINRES (PMINRES) iterative solver for symmetric indefinite linear systems.
13///
14/// See, e.g.,
15/// @code
16/// Elman, H. C., Silvester, D. J., & Wathen, A. J. (2014).
17/// Finite elements and fast iterative solvers: with applications in incompressible fluid dynamics.
18/// Oxford university press.
19/// @endcode
20///
21/// Satisfies the SolverLike concept (see solver.hpp).
22/// Supports optional preconditioning.
23/// @tparam OperatorT Operator type (must satisfy OperatorLike).
24/// @tparam PreconditionerT Preconditioner type (must satisfy SolverLike, defaults to IdentitySolver).
25template < OperatorLike OperatorT, SolverLike PreconditionerT = IdentitySolver< OperatorT > >
27{
28 public:
29 /// @brief Operator type to be solved.
30 using OperatorType = OperatorT;
31 /// @brief Solution vector type.
33 /// @brief Right-hand side vector type.
35 /// @brief Scalar type for computations.
36 using ScalarType = typename SolutionVectorType::ScalarType;
37
38 /// @brief Construct a PMINRES solver with default identity preconditioner.
39 /// @param params Iterative solver parameters.
40 /// @param statistics Shared pointer to statistics table.
41 /// @param tmp Temporary vectors for workspace.
43 const IterativeSolverParameters& params,
44 const std::shared_ptr< util::Table >& statistics,
45 const std::vector< SolutionVectorType >& tmp )
46 : PMINRES( params, statistics, tmp, IdentitySolver< OperatorT >() )
47 {}
48
49 /// @brief Construct a PMINRES solver with a custom preconditioner.
50 /// @param params Iterative solver parameters.
51 /// @param statistics Shared pointer to statistics table.
52 /// @param tmp Temporary vectors for workspace.
53 /// @param preconditioner Preconditioner solver.
55 const IterativeSolverParameters& params,
56 const std::shared_ptr< util::Table >& statistics,
57 const std::vector< SolutionVectorType >& tmp,
58 const PreconditionerT preconditioner )
59 : tag_( "pminres_solver" )
60 , params_( params )
61 , statistics_( statistics )
62 , tmp_( tmp )
63 , preconditioner_( preconditioner )
64 {}
65
66 /// @brief Set a tag string for statistics output.
67 /// @param tag Tag string.
68 void set_tag( const std::string& tag ) { tag_ = tag; }
69
70 /// @brief Solve the linear system \f$ Ax = b \f$ using PMINRES.
71 /// Calls the iterative solver and updates statistics.
72 /// @param A Operator (matrix).
73 /// @param x Solution vector (output).
74 /// @param b Right-hand side vector (input).
76 {
77 auto& az_ = tmp_[0]; ///< Temporary vector for A*z.
78 auto& v_j_minus_1_ = tmp_[1]; ///< Temporary vector for v_{j-1}.
79 auto& v_j_ = tmp_[2]; ///< Temporary vector for v_j.
80 auto& w_j_minus_1_ = tmp_[3]; ///< Temporary vector for w_{j-1}.
81 auto& w_j_ = tmp_[4]; ///< Temporary vector for w_j.
82 auto& z_j_plus_1_ = tmp_[5]; ///< Temporary vector for z_{j+1}.
83 auto& z_ = tmp_[6]; ///< Temporary vector for z.
84
85 assign( v_j_minus_1_, 0 );
86 assign( w_j_, 0 );
87 assign( w_j_minus_1_, 0 );
88
89 apply( A, x, v_j_ );
90 lincomb( v_j_, { 1.0, -1.0 }, { b, v_j_ } );
91
92 solve( preconditioner_, A, z_, v_j_ );
93
94 ScalarType gamma_j_minus_1 = 1.0;
95 ScalarType gamma_j = std::sqrt( dot( z_, v_j_ ) );
96
97 ScalarType eta = gamma_j;
98 ScalarType s_j_minus_1 = 0;
99 ScalarType s_j = 0;
100 ScalarType c_j_minus_1 = 1;
101 ScalarType c_j = 1;
102
103 const ScalarType initial_residual = gamma_j;
104
105 if ( statistics_ )
106 {
107 statistics_->add_row(
108 { { "tag", tag_ },
109 { "iteration", 0 },
110 { "relative_residual", 1.0 },
111 { "absolute_residual", initial_residual } } );
112 }
113
114 if ( initial_residual < params_.absolute_residual_tolerance() )
115 {
116 return;
117 }
118
119 for ( int iteration = 1; iteration <= params_.max_iterations(); ++iteration )
120 {
121 lincomb( z_, { 1.0 / gamma_j }, { z_ } );
122
123 apply( A, z_, az_ );
124
125 const ScalarType delta = dot( az_, z_ );
126
127 lincomb( v_j_minus_1_, { 1.0, -delta / gamma_j, -gamma_j / gamma_j_minus_1 }, { az_, v_j_, v_j_minus_1_ } );
128 swap( v_j_minus_1_, v_j_ );
129
130 assign( z_j_plus_1_, 0.0 );
131 solve( preconditioner_, A, z_j_plus_1_, v_j_ );
132
133 const ScalarType gamma_j_plus_1 = std::sqrt( dot( z_j_plus_1_, v_j_ ) );
134
135 const ScalarType alpha_0 = c_j * delta - c_j_minus_1 * s_j * gamma_j;
136 const ScalarType alpha_1 = std::sqrt( alpha_0 * alpha_0 + gamma_j_plus_1 * gamma_j_plus_1 );
137 const ScalarType alpha_2 = s_j * delta + c_j_minus_1 * c_j * gamma_j;
138 const ScalarType alpha_3 = s_j_minus_1 * gamma_j;
139
140 const ScalarType c_j_plus_1 = alpha_0 / alpha_1;
141 const ScalarType s_j_plus_1 = gamma_j_plus_1 / alpha_1;
142
143 lincomb(
144 w_j_minus_1_, { 1.0 / alpha_1, -alpha_3 / alpha_1, -alpha_2 / alpha_1 }, { z_, w_j_minus_1_, w_j_ } );
145 swap( w_j_minus_1_, w_j_ );
146
147 lincomb( x, { 1.0, c_j_plus_1 * eta }, { x, w_j_ } );
148
149 eta = -s_j_plus_1 * eta;
150
151 const ScalarType absolute_residual = std::abs( eta );
152 const ScalarType relative_residual = absolute_residual / initial_residual;
153
154 if ( statistics_ )
155 {
156 statistics_->add_row(
157 { { "tag", tag_ },
158 { "iteration", iteration },
159 { "relative_residual", relative_residual },
160 { "absolute_residual", absolute_residual } } );
161 }
162
163 if ( relative_residual <= params_.relative_residual_tolerance() )
164 {
165 return;
166 }
167
168 if ( absolute_residual < params_.absolute_residual_tolerance() )
169 {
170 return;
171 }
172
173 swap( z_, z_j_plus_1_ );
174
175 gamma_j_minus_1 = gamma_j;
176 gamma_j = gamma_j_plus_1;
177
178 c_j_minus_1 = c_j;
179 c_j = c_j_plus_1;
180
181 s_j_minus_1 = s_j;
182 s_j = s_j_plus_1;
183 }
184 }
185
186 private:
187 std::string tag_; ///< Tag for statistics output.
188
189 IterativeSolverParameters params_; ///< Solver parameters.
190
191 std::shared_ptr< util::Table > statistics_; ///< Statistics table.
192
193 std::vector< SolutionVectorType > tmp_; ///< Temporary workspace vectors.
194
195 PreconditionerT preconditioner_; ///< Preconditioner solver.
196};
197
198/// @brief Static assertion: PMINRES satisfies SolverLike concept.
199static_assert( SolverLike< PMINRES< linalg::detail::DummyOperator<
202
203} // namespace terra::linalg::solvers
Dummy operator for testing concepts. Implements apply_impl as a no-op.
Definition operator.hpp:167
Dummy vector class for concept checks and testing. Implements required vector operations as no-ops.
Definition vector.hpp:210
"Identity solver" for linear systems.
Definition identity_solver.hpp:21
Definition iterative_solver_info.hpp:7
double absolute_residual_tolerance() const
Definition iterative_solver_info.hpp:20
int max_iterations() const
Definition iterative_solver_info.hpp:18
double relative_residual_tolerance() const
Definition iterative_solver_info.hpp:19
Preconditioned MINRES (PMINRES) iterative solver for symmetric indefinite linear systems.
Definition pminres.hpp:27
PMINRES(const IterativeSolverParameters &params, const std::shared_ptr< util::Table > &statistics, const std::vector< SolutionVectorType > &tmp, const PreconditionerT preconditioner)
Construct a PMINRES solver with a custom preconditioner.
Definition pminres.hpp:54
typename SolutionVectorType::ScalarType ScalarType
Scalar type for computations.
Definition pminres.hpp:36
OperatorT OperatorType
Operator type to be solved.
Definition pminres.hpp:30
SrcOf< OperatorType > SolutionVectorType
Solution vector type.
Definition pminres.hpp:32
PMINRES(const IterativeSolverParameters &params, const std::shared_ptr< util::Table > &statistics, const std::vector< SolutionVectorType > &tmp)
Construct a PMINRES solver with default identity preconditioner.
Definition pminres.hpp:42
void solve_impl(OperatorType &A, SolutionVectorType &x, const RHSVectorType &b)
Solve the linear system using PMINRES. Calls the iterative solver and updates statistics.
Definition pminres.hpp:75
void set_tag(const std::string &tag)
Set a tag string for statistics output.
Definition pminres.hpp:68
DstOf< OperatorType > RHSVectorType
Right-hand side vector type.
Definition pminres.hpp:34
Definition block_preconditioner_2x2.hpp:7
void solve(Solver &solver, Operator &A, SolutionVector &x, const RHSVector &b)
Solve a linear system using the given solver and operator. Calls the solver's solve_impl method.
Definition solver.hpp:51
void lincomb(Vector &y, const std::vector< ScalarOf< Vector > > &c, const std::vector< Vector > &x, const ScalarOf< Vector > &c0)
Compute a linear combination of vectors. Implements: .
Definition vector.hpp:72
Operator::SrcVectorType SrcOf
Alias for the source vector type of an operator.
Definition operator.hpp:145
ScalarOf< Vector > dot(const Vector &y, const Vector &x)
Compute the dot product of two vectors. Implements: .
Definition vector.hpp:118
void apply(LinearForm &L, typename LinearForm::DstVectorType &dst)
Apply a linear form and write to a destination vector.
Definition linear_form.hpp:37
Operator::DstVectorType DstOf
Alias for the destination vector type of an operator.
Definition operator.hpp:149
void assign(Vector &y, const ScalarOf< Vector > &c0)
Assign a scalar value to a vector. Implements: .
Definition vector.hpp:97
void swap(Vector &x, Vector &y)
Swap the contents of two vectors. Exchanges the entries of and .
Definition vector.hpp:199