numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
algebraic_multigrid_solver.h
Go to the documentation of this file.
1/*
2 * Copyright 2024 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
20#pragma once
21
22#include <cmath>
23#include <cstddef>
24#include <deque>
25#include <vector>
26
27#include <Eigen/Cholesky>
28#include <Eigen/Core>
29
45
47
48template <base::concepts::sparse_matrix Matrix>
50
53 logging::log_tag_view("num_collect::linear::algebraic_multigrid_solver");
54
55namespace impl {
56
62template <base::concepts::sparse_matrix Matrix>
67
68} // namespace impl
69
76template <base::concepts::sparse_matrix Matrix>
78 : public iterative_solver_base<algebraic_multigrid_solver<Matrix>>,
81 "Complex matrices are not supported.");
82
83public:
86
89
90 using typename base_type::matrix_type;
91 using typename base_type::real_scalar_type;
92 using typename base_type::scalar_type;
93 using typename base_type::storage_index_type;
94
95protected:
96 using base_type::coeff;
97
98public:
104
110 void compute(const matrix_type& coeff) {
112
113 constexpr index_type smoother_iterations = 1;
114
115 // Initialization of the first layer.
117 this->logger(), "AMG layer size {} (first layer)", coeff.cols());
120 first_layer_.smoother.max_iterations(smoother_iterations);
121
122 // Initialization of the intermidiate layers.
123 intermidiate_layers_.clear();
124 const matrix_type* current_matrix = &coeff;
125 const matrix_type* current_prolongation =
127 index_type next_matrix_size = first_layer_.prolongation_matrix.cols();
128 while (next_matrix_size > maximum_directly_solved_matrix_size_) {
130 this->logger(), "AMG layer size {}", next_matrix_size);
131 intermidiate_layer_data& next_layer =
132 intermidiate_layers_.emplace_back();
133 next_layer.coeff_matrix = (*current_prolongation).transpose() *
134 (*current_matrix) * (*current_prolongation);
136 next_layer.prolongation_matrix, next_layer.coeff_matrix);
137 next_layer.smoother.compute(next_layer.coeff_matrix);
138 next_layer.smoother.max_iterations(smoother_iterations);
139
140 current_matrix = &next_layer.coeff_matrix;
141 current_prolongation = &next_layer.prolongation_matrix;
142 next_matrix_size = next_layer.prolongation_matrix.cols();
143 }
144
145 // Initialization of the final layer.
146 NUM_COLLECT_LOG_TRACE(this->logger(), "AMG layer size {} (final layer)",
147 next_matrix_size);
148 final_layer_.coeff_matrix = (*current_prolongation).transpose() *
149 (*current_matrix) * (*current_prolongation);
151
152 // Initialization of buffers.
153 residual_buffers_.resize(intermidiate_layers_.size() + 1U);
154 solution_buffers_.resize(intermidiate_layers_.size() + 1U);
155 for (std::size_t i = 0; i < intermidiate_layers_.size(); ++i) {
156 const index_type size = intermidiate_layers_[i].coeff_matrix.cols();
157 residual_buffers_[i] = dense_vector_type::Zero(size);
158 solution_buffers_[i] = dense_vector_type::Zero(size);
159 }
160 {
161 const index_type size = final_layer_.coeff_matrix.cols();
162 residual_buffers_.back() = dense_vector_type::Zero(size);
163 solution_buffers_.back() = dense_vector_type::Zero(size);
164 }
165 }
166
175 template <base::concepts::dense_vector_of<scalar_type> Right,
176 base::concepts::dense_vector_of<scalar_type> Solution>
177 void solve_vector_in_place(const Right& right, Solution& solution) const {
178 const auto& coeff_ref = coeff();
179
180 NUM_COLLECT_PRECONDITION(coeff_ref.rows() == coeff_ref.cols(),
181 this->logger(), "Coefficient matrix must be a square matrix.");
182 NUM_COLLECT_PRECONDITION(right.rows() == coeff_ref.cols(),
183 this->logger(),
184 "Right-hand-side vector must have the number of elements same as "
185 "the size of the coefficient matrix.");
186 NUM_COLLECT_PRECONDITION(solution.rows() == coeff_ref.cols(),
187 this->logger(),
188 "Solution vector must have the number of elements same as the size "
189 "of the coefficient matrix.");
190
191 iterations_ = 0;
193 while (iterations_ < max_iterations) {
194 iterate(right, solution);
195 ++iterations_;
196 using std::sqrt;
198 break;
199 }
200 }
201
203 "Solved a linear equation with {} iterations. (Residual rate: {})",
205 }
206
215 NUM_COLLECT_PRECONDITION(value > 0, this->logger(),
216 "The maximum size of matrices to solve directly must be a positive "
217 "integer.");
219 return *this;
220 }
221
227 [[nodiscard]] auto iterations() const noexcept -> index_type {
228 return iterations_;
229 }
230
238 [[nodiscard]] auto residual_rate() const noexcept -> scalar_type {
240 }
241
242private:
251 template <base::concepts::dense_vector_of<scalar_type> Right,
252 base::concepts::dense_vector_of<scalar_type> Solution>
253 void iterate(const Right& right, Solution& solution) const {
254 // First layer.
256 residual_buffers_.front() =
258 (right - coeff() * solution);
259
260 // Intermidiate layers.
261 for (std::size_t i = 0; i < intermidiate_layers_.size(); ++i) {
264 dense_vector_type::Zero(layer.coeff_matrix.cols());
267 residual_buffers_[i + 1U] = layer.prolongation_matrix.transpose() *
270 }
271
272 // Final layer.
273 solution_buffers_.back() =
275
276 // Intermidiate layers.
277 for (std::size_t i = intermidiate_layers_.size(); i > 0; --i) {
278 const intermidiate_layer_data& layer = intermidiate_layers_[i - 1U];
279 solution_buffers_[i - 1U] +=
282 residual_buffers_[i - 1U], solution_buffers_[i - 1U]);
283 }
284
285 // First layer.
286 solution +=
289 }
290
298 matrix_type& prolongation_matrix, const matrix_type& coeff_matrix) {
299 const auto connections = impl::amg::compute_strong_connection_list(
300 coeff_matrix, strong_coeff_rate_threshold_);
301 const auto transposed_connections = connections.transpose();
302 auto node_classification = impl::amg::build_first_coarse_grid_candidate(
303 connections, transposed_connections);
305 connections, transposed_connections, node_classification);
307 prolongation_matrix, transposed_connections, node_classification);
308 }
309
311 using dense_matrix_type = Eigen::MatrixX<scalar_type>;
312
314 using dense_vector_type = Eigen::VectorX<scalar_type>;
315
324
336
341
343 Eigen::LLT<dense_matrix_type> solver;
344 };
345
348
355 std::deque<intermidiate_layer_data> intermidiate_layers_{};
356
359
361 mutable std::vector<dense_vector_type> residual_buffers_{};
362
364 mutable std::vector<dense_vector_type> solution_buffers_{};
365
368
371 static_cast<real_scalar_type>(0.25);
372
376
379 500;
380
384};
385
386} // namespace num_collect::linear
Definition of build_first_coarse_grid_candidate function.
Class to solve linear equations using algebraic multigrid method ruge1987.
final_layer_data final_layer_
Data of the final layer.
std::vector< dense_vector_type > residual_buffers_
Buffers of residuals in layers except for the first layer.
real_scalar_type strong_coeff_rate_threshold_
Threshold of the rate of coefficients to determine strong connections.
Eigen::MatrixX< scalar_type > dense_matrix_type
Type of the dense matrix used in this algorithm.
auto maximum_directly_solved_matrix_size(index_type value) -> algebraic_multigrid_solver &
Set the maximum size of matrices to solve directly.
void solve_vector_in_place(const Right &right, Solution &solution) const
Iterate repeatedly until stop criterion is satisfied for a vector.
index_type maximum_directly_solved_matrix_size_
Maximum size of matrices to solve directly.
void compute_prolongation_matrix(matrix_type &prolongation_matrix, const matrix_type &coeff_matrix)
Compute prolongation matrix from a coefficient matrix.
void compute(const matrix_type &coeff)
Prepare to solve.
auto iterations() const noexcept -> index_type
Get the number of iterations.
Eigen::VectorX< scalar_type > dense_vector_type
Type of the dense vector used in this algorithm.
static constexpr index_type default_maximum_directly_solved_matrix_size
Default value of the maximum size of matrices to solve directly.
first_layer_data first_layer_
Data of the first layer.
static constexpr auto default_strong_coeff_rate_threshold
Default value of the threshold of the rate of coefficients to determine strong connections.
std::deque< intermidiate_layer_data > intermidiate_layers_
Data of the intermidiate layers.
void iterate(const Right &right, Solution &solution) const
Iterate once.
std::vector< dense_vector_type > solution_buffers_
Buffers of solutions in layers except for the first layer.
auto residual_rate() const noexcept -> scalar_type
Get the rate of the last residual.
auto compute(const matrix_type &coeff) -> algebraic_multigrid_solver< Matrix > &
auto max_iterations() const noexcept -> index_type
Get the maximum number of iterations.
Class to solve linear equations using symmetric successive over-relaxation using threads golub2013.
void solve_vector_in_place(const Right &right, Solution &solution) const
Iterate repeatedly until stop criterion is satisfied for a vector.
auto residual_rate() const noexcept -> scalar_type
Get the rate of the last residual.
Class of tags of logs without memory management.
Class to incorporate logging in algorithms.
logging_mixin(log_tag_view tag)
Constructor.
auto logger() const noexcept -> const num_collect::logging::logger &
Access to the logger.
Definition of compute_strong_connection_list function.
Definition of create_prolongation_matrix function.
Definition of dense_vector_of concept.
Definition of exceptions.
Definition of index_type type.
Definition of iterative_solver_base class.
Definition of log_tag_view class.
Definition of macros for logging.
#define NUM_COLLECT_LOG_SUMMARY(LOGGER,...)
Write a summary log.
#define NUM_COLLECT_LOG_TRACE(LOGGER,...)
Write a trace log.
Definition of logging_mixin class.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
void create_prolongation_matrix(Matrix &prolongation_matrix, const node_connection_list< typename Matrix::StorageIndex > &transposed_connections, const util::vector< node_layer > &node_classification)
Create a prolongation matrix.
void tune_coarse_grid_selection(const node_connection_list< StorageIndex > &connections, const node_connection_list< StorageIndex > &transposed_connections, util::vector< node_layer > &node_classification)
Tune a coarse grid to satisfy the condition for interpolation specified in ruge1987.
auto build_first_coarse_grid_candidate(const node_connection_list< StorageIndex > &connections, const node_connection_list< StorageIndex > &transposed_connections) -> util::vector< node_layer >
Build the first candidate of a coarse grid.
auto compute_strong_connection_list(const Matrix &matrix, typename Matrix::Scalar strong_coeff_rate_threshold) -> node_connection_list< typename Matrix::StorageIndex >
Compute a list of strong connections in a matrix ruge1987.
Namespace of solvers of linear equations.
constexpr auto algebraic_multigrid_solver_tag
Log tag for num_collect::linear::algebraic_multigrid_solver.
Definition of parallel_symmetric_successive_over_relaxation class.
Definition of NUM_COLLECT_PRECONDITION macro.
#define NUM_COLLECT_PRECONDITION(CONDITION,...)
Check whether a precondition is satisfied and throw an exception if not.
Definition of real_scalar concept.
Definition of sparse_matrix concept.
Eigen::LLT< dense_matrix_type > solver
Solver of the final coefficient matrix.
dense_matrix_type coeff_matrix
Coefficient matrix in this layer.
matrix_type prolongation_matrix
Prolongation matrix from the next layer.
parallel_symmetric_successive_over_relaxation< matrix_type > smoother
Smoother in this layer.
parallel_symmetric_successive_over_relaxation< matrix_type > smoother
Smoother in this layer.
Definition of tune_coarse_grid_selection function.