numerical-collection-cpp 0.10.0
A collection of algorithms in numerical analysis implemented in C++
Loading...
Searching...
No Matches
symmetric_successive_over_relaxation.h
Go to the documentation of this file.
1/*
2 * Copyright 2023 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
24#include <Eigen/Core>
25
34
35namespace num_collect::linear {
36
37template <base::concepts::sparse_matrix Matrix>
38class symmetric_successive_over_relaxation;
39
40namespace impl {
41
47template <base::concepts::sparse_matrix Matrix>
52
53} // namespace impl
54
61template <base::concepts::sparse_matrix Matrix>
63 : public iterative_solver_base<
64 symmetric_successive_over_relaxation<Matrix>> {
65 static_assert(Matrix::IsRowMajor == 1, "Row major matrix is required.");
67 "Complex matrices are not supported.");
68
69public:
71 using base_type =
73
74 using typename base_type::matrix_type;
75 using typename base_type::real_scalar_type;
76 using typename base_type::scalar_type;
77 using typename base_type::storage_index_type;
78
79protected:
80 using base_type::coeff;
81
82public:
84 using vector_type = Eigen::VectorX<scalar_type>;
85
90
96 void compute(const matrix_type& coeff) {
98 diag_ = coeff.diagonal();
99 inv_diag_ = diag_.cwiseInverse();
100 intermidiate_solution_.resize(coeff.cols());
101 NUM_COLLECT_PRECONDITION(inv_diag_.array().isFinite().all(),
102 "All diagonal elements of the coefficient matrix must not be "
103 "zero.");
104 }
105
114 template <base::concepts::dense_vector_of<scalar_type> Right,
115 base::concepts::dense_vector_of<scalar_type> Solution>
116 void solve_vector_in_place(const Right& right, Solution& solution) const {
117 const auto& coeff_ref = coeff();
118
119 NUM_COLLECT_PRECONDITION(coeff_ref.rows() == coeff_ref.cols(),
120 "Coefficient matrix must be a square matrix.");
121 NUM_COLLECT_PRECONDITION(right.rows() == coeff_ref.cols(),
122 "Right-hand-side vector must have the number of elements same as "
123 "the size of the coefficient matrix.");
124 NUM_COLLECT_PRECONDITION(solution.rows() == coeff_ref.cols(),
125 "Solution vector must have the number of elements same as the size "
126 "of the coefficient matrix.");
127
128 iterations_ = 0;
129 const scalar_type right_norm = right.squaredNorm();
131 while (iterations_ < max_iterations) {
132 iterate(coeff_ref, right, solution);
133 if (!std::isfinite(residual_)) {
135 "Failure in "
136 "symmetric_successive_over_relaxation.");
137 }
138 ++iterations_;
139 using std::sqrt;
140 residual_rate_ = sqrt(residual_ / right_norm);
142 break;
143 }
144 }
145 }
146
154 [[nodiscard]] auto iterations() const noexcept -> index_type {
155 return iterations_;
156 }
157
165 [[nodiscard]] auto residual_rate() const noexcept -> index_type {
166 return residual_rate_;
167 }
168
177 NUM_COLLECT_PRECONDITION(static_cast<scalar_type>(0) < val &&
178 val < static_cast<scalar_type>(2),
179 "Relaxation coefficient must be in the range (0, 2).");
180 relaxation_coeff_ = val;
181 return *this;
182 }
183
184private:
194 template <base::concepts::dense_vector_of<scalar_type> Right,
195 base::concepts::dense_vector_of<scalar_type> Solution>
196 void iterate(const matrix_type& coeff_ref, const Right& right,
197 Solution& solution) const {
198 const index_type size = coeff_ref.rows();
199 const scalar_type prev_sol_coeff =
200 static_cast<scalar_type>(1) - relaxation_coeff_;
201 residual_ = static_cast<scalar_type>(0);
202
203 // Forward update.
204 for (index_type i = 0; i < size; ++i) {
205 scalar_type numerator = right(i);
206 for (typename matrix_type::InnerIterator iter(coeff_ref, i); iter;
207 ++iter) {
208 if (iter.index() < i) {
209 numerator -=
210 iter.value() * intermidiate_solution_(iter.index());
211 } else if (iter.index() > i) {
212 numerator -= iter.value() * solution(iter.index());
213 }
214 }
215 const scalar_type row_residual = numerator - diag_(i) * solution(i);
217 relaxation_coeff_ * numerator * inv_diag_(i) +
218 prev_sol_coeff * solution(i);
219 residual_ += row_residual * row_residual;
220 }
221
222 // Backward update.
223 for (index_type i = size - 1; i >= 0; --i) {
224 scalar_type numerator = right(i);
225 for (typename matrix_type::InnerIterator iter(coeff_ref, i); iter;
226 ++iter) {
227 if (iter.index() < i) {
228 numerator -=
229 iter.value() * intermidiate_solution_(iter.index());
230 } else if (iter.index() > i) {
231 numerator -= iter.value() * solution(iter.index());
232 }
233 }
234 solution(i) = relaxation_coeff_ * numerator * inv_diag_(i) +
235 prev_sol_coeff * intermidiate_solution_(i);
236 }
237 }
238
241
244
247
250
253
256
259};
260
261} // namespace num_collect::linear
Class of exception on failure in algorithm.
Definition exception.h:93
auto compute(const matrix_type &coeff) -> symmetric_successive_over_relaxation< Matrix > &
Class to solve linear equations using symmetric successive over-relaxation golub2013.
void solve_vector_in_place(const Right &right, Solution &solution) const
Iterate repeatedly until stop criterion is satisfied for a vector.
auto iterations() const noexcept -> index_type
Get the number of iterations.
void iterate(const matrix_type &coeff_ref, const Right &right, Solution &solution) const
Iterate once.
auto relaxation_coeff(const scalar_type &val) -> symmetric_successive_over_relaxation &
Set the relaxation coefficient.
auto residual_rate() const noexcept -> index_type
Get the rate of the last residual.
Definition of dense_vector_of concept.
Definition of exceptions.
Definition of index_type type.
Definition of iterative_solver_base class.
Definition of macros for logging.
#define NUM_COLLECT_LOG_AND_THROW(EXCEPTION_TYPE,...)
Write an error log and throw an exception for an error.
std::ptrdiff_t index_type
Type of indices in this library.
Definition index_type.h:33
Namespace of solvers of linear equations.
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.