Loading...
Searching...
No Matches
chebyshev.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "linalg/operator.hpp"
5#include "power_iteration.hpp"
6#include "solver.hpp"
7
9
10/// @brief Chebyshev accelerated Jacobi iterative solver for linear systems.
11///
12/// Computes (given an order \f$p \geq 1, \ p \in \mathbb{N}\f$)
13/// \f[
14/// x^{k+1} = x^k + \alpha_k \, D^{-1}(b - A x^k) + \beta_k \, d^k, \quad
15/// d^0 = 0
16/// \f]
17/// for \f$k = 0\f$ up to \f$k+1 = p\f$, where \f$D = \mathrm{diag}(A)\f$, and the coefficients \f$ \alpha_k \f$ and
18/// \f$ \beta_k \f$ are computed recursively from
19/// \f[
20/// \begin{aligned}
21/// \rho_0 &= \frac{\delta}{\theta}, \quad \\
22/// \rho_{k+1} &= (2(\theta/\delta) - \rho_k)^{-1}, \quad \\
23/// \alpha_0 &= \theta^{-1}, \\
24/// \alpha_k &= \frac{2 \, \rho_{k+1}}{\delta}, \quad \\
25/// \beta_0 &= 0, \\
26/// \beta_k &= \rho_{k+1} \rho_k, \\
27/// d_0 &= 0, \\
28/// d_k &= x^{k+1} - x^{k} = \alpha_k D^{-1}(b - A x^k) + \beta_k d_{k-1}
29/// \end{aligned}
30/// \f]
31/// with \f$ \theta = (\lambda_{\max} + \lambda_{\min})/2 \f$ and \f$ \delta = (\lambda_{\max} - \lambda_{\min})/2\f$ ,
32/// and \f$ \lambda_{\min}, \lambda_{\max} \f$ the eigenvalue bounds of \f$ D^{-1}A \f$.
33///
34/// The max eigenvalue \f$\lambda_{\max}\f$ is estimated before the first solve (or if requested via
35/// `refresh_max_eigenvalue_estimate_in_next_solve()`) applying a specified number of power iterations. A safety margin
36/// is added to hopefully ensure that the estimate is not too far off. The minimum eigenvalue is the obtained by scaling
37/// the maximum eigenvalue.
38///
39/// Each iteration executes \f$p\f$ matrix-vector products (plus some vector-vector operations).
40/// Setting the order \f$p = 1\f$ recovers the standard weighted Jacobi relaxation.
41/// If unsure, try low-order settings with \f$p = 2\f$ or \f$p = 3\f$.
42///
43/// The number of iterations repeats the entire process. For instance, setting the iterations \f$\text{it} = 10\f$ will
44/// perform \f$\text{it} \times p\f$ updates.
45///
46/// Satisfies the SolverLike concept (see solver.hpp).
47///
48/// @tparam OperatorT Operator type (must satisfy OperatorLike).
49template < OperatorLike OperatorT >
51{
52 public:
53 /// @brief Operator type to be solved.
54 using OperatorType = OperatorT;
55 /// @brief Solution vector type.
57 /// @brief Right-hand side vector type.
59
60 /// @brief Scalar type for computations.
61 using ScalarType = SolutionVectorType::ScalarType;
62
63 /// @brief Construct a Chebyshev accelerated Jacobi solver.
64 /// @param order Chebyshev order \f$p >= 1\f$. Equivalent to weighted Jacobi for \f$p = 1\f$.
65 /// @param inverse_diagonal Inverse of the diagonal of the operator (D^-1).
66 /// @param tmps Temporary vectors for workspace. We need 2 here.
67 /// @param iterations Number of Chebyshev iterations to perform.
68 /// @param max_ev_power_iterations Number of power iterations executed to estimate the max eigenvalue of ((D^-1)A).
69 /// An additional safety margin is added internally during the setup of the Chebyshev
70 /// solver.
72 const int order,
73 const SolutionVectorType& inverse_diagonal,
74 const std::vector< SolutionVectorType >& tmps,
75 const int iterations = 1,
76 const int max_ev_power_iterations = 50 )
77 : order_( order )
78 , inverse_diagonal_( inverse_diagonal )
79 , iterations_( iterations )
80 , tmps_( tmps )
81 , max_ev_power_iterations_( max_ev_power_iterations )
82 , need_max_ev_estimation_( true )
83 {
84 if ( order_ < 1 )
85 {
86 Kokkos::abort( "Chebyshev order must be at least 1." );
87 }
88
89 if ( tmps_.size() < 2 )
90 {
91 Kokkos::abort( "Chebyshev requires at least 2 tmp vectors." );
92 }
93 }
94
95 /// @brief Solve the linear system using the Chebyshev iteration.
96 /// Applies the update rule for the specified number of iterations.
97 /// @param A Operator (matrix).
98 /// @param x Solution vector (output).
99 /// @param b Right-hand side vector (input).
101 {
102 if ( need_max_ev_estimation_ )
103 {
104 estimate_max_eigenvalues( A );
105 need_max_ev_estimation_ = false;
106 }
107
108 auto& d = tmps_[0];
109 auto& z = tmps_[1];
110
111 const auto lambda_max = 1.5 * max_ev_estimate_;
112 const auto lambda_min = 0.1 * max_ev_estimate_;
113
114 const auto theta = 0.5 * ( lambda_max + lambda_min );
115 const auto delta = 0.5 * ( lambda_max - lambda_min );
116
117 const auto sigma = theta / delta;
118 auto rho = 1.0 / sigma;
119
120 for ( int iteration = 0; iteration < iterations_; ++iteration )
121 {
122 // r = b - A(x);
123 // z = M_inv(r);
124
125 apply( A, x, z );
126 lincomb( z, { 1.0, -1.0 }, { b, z } );
127 scale_in_place( z, inverse_diagonal_ );
128
129 // d = z / theta; // first Chebyshev direction
130 // x = x + d;
131
132 lincomb( d, { 1.0 / theta }, { z } );
133 lincomb( x, { 1.0, 1.0 }, { x, d } );
134
135 // cheby recurrence
136
137 for ( int i = 2; i <= order_; ++i )
138 {
139 const auto rho_new = 1.0 / ( 2.0 * sigma - rho );
140
141 const auto beta = rho_new * rho;
142 const auto alpha = 2.0 * rho_new / delta;
143
144 apply( A, x, z );
145 lincomb( z, { 1.0, -1.0 }, { b, z } );
146 scale_in_place( z, inverse_diagonal_ );
147
148 // d = alpha * z + beta * d;
149 // x = x + d;
150
151 lincomb( d, { alpha, beta }, { z, d } );
152 lincomb( x, { 1.0, 1.0 }, { x, d } );
153
154 rho = rho_new;
155 }
156 }
157 }
158
159 SolutionVectorType& get_inverse_diagonal() { return inverse_diagonal_; }
160
161 void refresh_max_eigenvalue_estimate_in_next_solve() { need_max_ev_estimation_ = true; }
162
163 private:
164 void estimate_max_eigenvalues( OperatorType& A )
165 {
166 DiagonallyScaledOperator< OperatorType > inv_diag_A( A, inverse_diagonal_ );
167 max_ev_estimate_ = solvers::power_iteration( inv_diag_A, tmps_[0], tmps_[1], max_ev_power_iterations_ );
168 }
169
170 int order_; ///< Order of the Chebyshev smoother.
171 SolutionVectorType inverse_diagonal_; ///< Inverse diagonal vector.
172 int iterations_; ///< Number of iterations.
173 std::vector< SolutionVectorType > tmps_; ///< Temporary workspace vectors.
174 int max_ev_power_iterations_; ///< Number of power iterations to estimate the max eigenvalue.
175 bool need_max_ev_estimation_; ///< If true, max eigenvalue is estimated in next solve call.
176 ScalarType max_ev_estimate_; ///< Estimate of the max eigenvalue of ((D^-1)A).
177};
178
179/// @brief Static assertion: Chebyshev satisfies SolverLike concept.
180static_assert( SolverLike< Chebyshev< linalg::detail::DummyConcreteOperator > > );
181
182} // namespace terra::linalg::solvers
Given some operator and a vector , this operator is equivalent to an operator defined as.
Definition diagonally_scaled_operator.hpp:16
Chebyshev accelerated Jacobi iterative solver for linear systems.
Definition chebyshev.hpp:51
void refresh_max_eigenvalue_estimate_in_next_solve()
Definition chebyshev.hpp:161
SrcOf< OperatorType > SolutionVectorType
Solution vector type.
Definition chebyshev.hpp:56
SolutionVectorType::ScalarType ScalarType
Scalar type for computations.
Definition chebyshev.hpp:61
Chebyshev(const int order, const SolutionVectorType &inverse_diagonal, const std::vector< SolutionVectorType > &tmps, const int iterations=1, const int max_ev_power_iterations=50)
Construct a Chebyshev accelerated Jacobi solver.
Definition chebyshev.hpp:71
void solve_impl(OperatorType &A, SolutionVectorType &x, const RHSVectorType &b)
Solve the linear system using the Chebyshev iteration. Applies the update rule for the specified numb...
Definition chebyshev.hpp:100
DstOf< OperatorType > RHSVectorType
Right-hand side vector type.
Definition chebyshev.hpp:58
OperatorT OperatorType
Operator type to be solved.
Definition chebyshev.hpp:54
SolutionVectorType & get_inverse_diagonal()
Definition chebyshev.hpp:159
Definition block_preconditioner_2x2.hpp:7
double power_iteration(OperatorT &op, SrcOf< OperatorT > &tmpIt, SrcOf< OperatorT > &tmpAux, const int iterations)
Power iteration to estimate the largest eigenvalue of a row-normalized operator D^{-1}A,...
Definition power_iteration.hpp:13
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
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 scale_in_place(Vector &y, const Vector &x)
Scale a vector in place with another vector. For each entry , computes .
Definition vector.hpp:137