Loading...
Searching...
No Matches
pcg.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "identity_solver.hpp"
8#include "util/table.hpp"
9
10#include <cmath>
11#include <limits>
12
13namespace terra::linalg::solvers {
14
15/// @brief Preconditioned Conjugate Gradient (PCG) iterative solver for symmetric positive definite linear systems.
16///
17/// See, e.g.,
18/// @code
19/// Elman, H. C., Silvester, D. J., & Wathen, A. J. (2014).
20/// Finite elements and fast iterative solvers: with applications in incompressible fluid dynamics.
21/// Oxford university press.
22/// @endcode
23///
24/// Satisfies the SolverLike concept (see solver.hpp).
25/// Supports optional preconditioning.
26/// @tparam OperatorT Operator type (must satisfy OperatorLike).
27/// @tparam PreconditionerT Preconditioner type (must satisfy SolverLike, defaults to IdentitySolver).
28template < OperatorLike OperatorT, SolverLike PreconditionerT = IdentitySolver< OperatorT > >
29class PCG
30{
31 public:
32 /// @brief Operator type to be solved.
33 using OperatorType = OperatorT;
34 /// @brief Solution vector type.
36 /// @brief Right-hand side vector type.
38 /// @brief Scalar type for computations.
39 using ScalarType = typename SolutionVectorType::ScalarType;
40
41 /// @brief Construct a PCG solver with default identity preconditioner.
42 /// @param params Iterative solver parameters.
43 /// @param statistics Shared pointer to statistics table.
44 /// @param tmps Temporary vectors for workspace. (At least 4 vectors are required.)
46 const std::shared_ptr< util::Table >& statistics,
47 const std::vector< SolutionVectorType >& tmps )
48 : PCG( params, statistics, tmps, IdentitySolver< OperatorT >() )
49 {}
50
51 /// @brief Construct a PCG solver with a custom preconditioner.
52 /// @param params Iterative solver parameters.
53 /// @param statistics Shared pointer to statistics table.
54 /// @param tmps Temporary vectors for workspace. (At least 4 vectors are required.)
55 /// @param preconditioner Preconditioner solver.
57 const std::shared_ptr< util::Table >& statistics,
58 const std::vector< SolutionVectorType >& tmps,
59 const PreconditionerT preconditioner )
60 : tag_( "pcg_solver" )
61 , params_( params )
62 , statistics_( statistics )
63 , tmps_( tmps )
64 , preconditioner_( preconditioner )
65 {
66 if ( tmps.size() < 4 )
67 {
68 throw std::runtime_error( "PCG: tmps.size() < 4. Need at least 4 tmp vectors." );
69 }
70 }
71
72 /// @brief Set a tag string for statistics output.
73 /// @param tag Tag string.
74 void set_tag( const std::string& tag ) { tag_ = tag; }
75
76 /// @brief Solve the linear system \f$ Ax = b \f$ using PCG.
77 /// Calls the iterative solver and updates statistics.
78 /// @param A Operator (matrix).
79 /// @param x Solution vector (output).
80 /// @param b Right-hand side vector (input).
82 {
83 auto& r_ = tmps_[0]; ///< Residual vector.
84 auto& p_ = tmps_[1]; ///< Search direction vector.
85 auto& ap_ = tmps_[2]; ///< Temporary vector for A*p.
86 auto& z_ = tmps_[3]; ///< Preconditioned residual vector.
87
88 apply( A, x, r_ );
89
90 lincomb( r_, { 1.0, -1.0 }, { b, r_ } );
91
92 solve( preconditioner_, A, z_, r_ );
93
94 assign( p_, z_ );
95
96 // TODO: should this be dot(z, z) instead or dot(r, r)?
97 const ScalarType initial_residual = std::sqrt( dot( r_, r_ ) );
98
99 if ( statistics_ )
100 {
101 statistics_->add_row(
102 { { "tag", tag_ },
103 { "iteration", 0 },
104 { "relative_residual", 1.0 },
105 { "absolute_residual", initial_residual } } );
106 }
107
108 if ( initial_residual < params_.absolute_residual_tolerance() )
109 {
110 return;
111 }
112
113 for ( int iteration = 1; iteration <= params_.max_iterations(); ++iteration )
114 {
115 const ScalarType alpha_num = dot( z_, r_ );
116
117 apply( A, p_, ap_ );
118 const ScalarType alpha_den = dot( ap_, p_ );
119
120 if ( std::abs( alpha_den ) < std::numeric_limits< ScalarType >::min() )
121 {
122 // Search direction is in or near the null space of A.
123 // Cannot make progress — break to avoid inf/NaN.
124 return;
125 }
126
127 const ScalarType alpha = alpha_num / alpha_den;
128
129 lincomb( x, { 1.0, alpha }, { x, p_ } );
130 lincomb( r_, { 1.0, -alpha }, { r_, ap_ } );
131
132 // TODO: is this the correct term for the residual check?
133 const ScalarType absolute_residual = std::sqrt( dot( r_, r_ ) );
134
135 const ScalarType relative_residual = absolute_residual / initial_residual;
136
137 if ( statistics_ )
138 {
139 statistics_->add_row(
140 { { "tag", tag_ },
141 { "iteration", iteration },
142 { "relative_residual", relative_residual },
143 { "absolute_residual", absolute_residual } } );
144 }
145
146 if ( relative_residual <= params_.relative_residual_tolerance() )
147 {
148 return;
149 }
150
151 if ( absolute_residual < params_.absolute_residual_tolerance() )
152 {
153 return;
154 }
155
156 solve( preconditioner_, A, z_, r_ );
157
158 const ScalarType beta_num = dot( z_, r_ );
159
160 if ( std::abs( alpha_num ) < std::numeric_limits< ScalarType >::min() )
161 {
162 return;
163 }
164
165 const ScalarType beta = beta_num / alpha_num;
166
167 lincomb( p_, { 1.0, beta }, { z_, p_ } );
168 }
169 }
170
171 private:
172 std::string tag_; ///< Tag for statistics output.
173
174 IterativeSolverParameters params_; ///< Solver parameters.
175
176 std::shared_ptr< util::Table > statistics_; ///< Statistics table.
177
178 std::vector< SolutionVectorType > tmps_; ///< Temporary workspace vectors.
179
180 PreconditionerT preconditioner_; ///< Preconditioner solver.
181};
182
183/// @brief Static assertion: PCG satisfies SolverLike concept.
184static_assert(
185 SolverLike<
186 PCG< linalg::detail::
187 DummyOperator< linalg::detail::DummyVector< double >, linalg::detail::DummyVector< double > > > > );
188
189} // namespace terra::linalg::solvers
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 Conjugate Gradient (PCG) iterative solver for symmetric positive definite linear syste...
Definition pcg.hpp:30
DstOf< OperatorType > RHSVectorType
Right-hand side vector type.
Definition pcg.hpp:37
SrcOf< OperatorType > SolutionVectorType
Solution vector type.
Definition pcg.hpp:35
void solve_impl(OperatorType &A, SolutionVectorType &x, const RHSVectorType &b)
Solve the linear system using PCG. Calls the iterative solver and updates statistics.
Definition pcg.hpp:81
void set_tag(const std::string &tag)
Set a tag string for statistics output.
Definition pcg.hpp:74
typename SolutionVectorType::ScalarType ScalarType
Scalar type for computations.
Definition pcg.hpp:39
PCG(const IterativeSolverParameters &params, const std::shared_ptr< util::Table > &statistics, const std::vector< SolutionVectorType > &tmps, const PreconditionerT preconditioner)
Construct a PCG solver with a custom preconditioner.
Definition pcg.hpp:56
OperatorT OperatorType
Operator type to be solved.
Definition pcg.hpp:33
PCG(const IterativeSolverParameters &params, const std::shared_ptr< util::Table > &statistics, const std::vector< SolutionVectorType > &tmps)
Construct a PCG solver with default identity preconditioner.
Definition pcg.hpp:45
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