/builds/MusicScience37Projects/numerical-analysis/numerical-collection-cpp/include/num_collect/roots/newton_raphson.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2021 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 | | */ |
16 | | /*! |
17 | | * \file |
18 | | * \brief Definition of newton_raphson class. |
19 | | */ |
20 | | #pragma once |
21 | | |
22 | | #include <cmath> |
23 | | #include <limits> |
24 | | #include <type_traits> |
25 | | |
26 | | #include <Eigen/LU> |
27 | | |
28 | | #include "num_collect/base/exception.h" |
29 | | #include "num_collect/base/index_type.h" |
30 | | #include "num_collect/logging/iterations/iteration_logger.h" |
31 | | #include "num_collect/logging/log_tag_view.h" |
32 | | #include "num_collect/logging/logging_macros.h" |
33 | | #include "num_collect/roots/concepts/differentiable_function.h" |
34 | | #include "num_collect/roots/concepts/multi_variate_differentiable_function.h" |
35 | | #include "num_collect/roots/concepts/single_variate_differentiable_function.h" |
36 | | #include "num_collect/roots/function_root_finder_base.h" |
37 | | |
38 | | namespace num_collect::roots { |
39 | | |
40 | | //! Tag of newton_raphson. |
41 | | constexpr auto newton_raphson_tag = |
42 | | logging::log_tag_view("num_collect::roots::newton_raphson"); |
43 | | |
44 | | /*! |
45 | | * \brief Class of Newton-Raphson method. |
46 | | * |
47 | | * \tparam Function Type of the function of equation. |
48 | | */ |
49 | | template <concepts::differentiable_function Function> |
50 | | class newton_raphson; |
51 | | |
52 | | /*! |
53 | | * \brief Class of Newton-Raphson method. |
54 | | * |
55 | | * This version is used when variable type is a floating-point number type. |
56 | | * |
57 | | * \tparam Function Type of the function of equation. |
58 | | */ |
59 | | template <concepts::single_variate_differentiable_function Function> |
60 | | class newton_raphson<Function> |
61 | | : public function_root_finder_base<newton_raphson<Function>, Function> { |
62 | | public: |
63 | | //! Type of this object. |
64 | | using this_type = newton_raphson<Function>; |
65 | | |
66 | | //! Type of base class. |
67 | | using base_type = |
68 | | function_root_finder_base<newton_raphson<Function>, Function>; |
69 | | |
70 | | using typename base_type::function_type; |
71 | | using typename base_type::variable_type; |
72 | | |
73 | | static_assert( |
74 | | std::is_same_v<variable_type, typename function_type::jacobian_type>); |
75 | | |
76 | | /*! |
77 | | * \brief Constructor. |
78 | | * |
79 | | * \param[in] function Function of equation. |
80 | | */ |
81 | | explicit newton_raphson(const function_type& function = function_type()) |
82 | 83 | : base_type(newton_raphson_tag, function) {} _ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEEC2ERKS5_ Line | Count | Source | 82 | 46 | : base_type(newton_raphson_tag, function) {} |
_ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEEC2ERKS5_ Line | Count | Source | 82 | 34 | : base_type(newton_raphson_tag, function) {} |
_ZN11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEEC2ERKS4_ Line | Count | Source | 82 | 3 | : base_type(newton_raphson_tag, function) {} |
|
83 | | |
84 | | /*! |
85 | | * \brief Initialize. |
86 | | * |
87 | | * \param[in] variable Initial variable. |
88 | | */ |
89 | 587 | void init(const variable_type& variable) { |
90 | 587 | variable_ = variable; |
91 | 587 | last_change_ = std::numeric_limits<variable_type>::infinity(); |
92 | 587 | iterations_ = 0; |
93 | 587 | evaluations_ = 0; |
94 | | |
95 | 587 | function().evaluate_on(variable_); |
96 | 587 | ++evaluations_; |
97 | 587 | using std::abs; |
98 | 587 | value_norm_ = abs(function().value()); |
99 | 587 | } _ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE4initERKd Line | Count | Source | 89 | 304 | void init(const variable_type& variable) { | 90 | 304 | variable_ = variable; | 91 | 304 | last_change_ = std::numeric_limits<variable_type>::infinity(); | 92 | 304 | iterations_ = 0; | 93 | 304 | evaluations_ = 0; | 94 | | | 95 | 304 | function().evaluate_on(variable_); | 96 | 304 | ++evaluations_; | 97 | 304 | using std::abs; | 98 | 304 | value_norm_ = abs(function().value()); | 99 | 304 | } |
_ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE4initERKf Line | Count | Source | 89 | 280 | void init(const variable_type& variable) { | 90 | 280 | variable_ = variable; | 91 | 280 | last_change_ = std::numeric_limits<variable_type>::infinity(); | 92 | 280 | iterations_ = 0; | 93 | 280 | evaluations_ = 0; | 94 | | | 95 | 280 | function().evaluate_on(variable_); | 96 | 280 | ++evaluations_; | 97 | 280 | using std::abs; | 98 | 280 | value_norm_ = abs(function().value()); | 99 | 280 | } |
_ZN11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE4initERKd Line | Count | Source | 89 | 3 | void init(const variable_type& variable) { | 90 | 3 | variable_ = variable; | 91 | 3 | last_change_ = std::numeric_limits<variable_type>::infinity(); | 92 | 3 | iterations_ = 0; | 93 | 3 | evaluations_ = 0; | 94 | | | 95 | 3 | function().evaluate_on(variable_); | 96 | 3 | ++evaluations_; | 97 | 3 | using std::abs; | 98 | 3 | value_norm_ = abs(function().value()); | 99 | 3 | } |
|
100 | | |
101 | | //! \copydoc function_root_finder_base::iterate |
102 | 1.10k | void iterate() { |
103 | 1.10k | change_ = -function().value() / function().jacobian(); |
104 | 1.10k | variable_ += change_; |
105 | | |
106 | 1.10k | function().evaluate_on(variable_); |
107 | 1.10k | ++evaluations_; |
108 | 1.10k | ++iterations_; |
109 | 1.10k | using std::abs; |
110 | 1.10k | last_change_ = abs(change_); |
111 | 1.10k | value_norm_ = abs(function().value()); |
112 | 1.10k | } _ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE7iterateEv Line | Count | Source | 102 | 766 | void iterate() { | 103 | 766 | change_ = -function().value() / function().jacobian(); | 104 | 766 | variable_ += change_; | 105 | | | 106 | 766 | function().evaluate_on(variable_); | 107 | 766 | ++evaluations_; | 108 | 766 | ++iterations_; | 109 | 766 | using std::abs; | 110 | 766 | last_change_ = abs(change_); | 111 | 766 | value_norm_ = abs(function().value()); | 112 | 766 | } |
_ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE7iterateEv Line | Count | Source | 102 | 332 | void iterate() { | 103 | 332 | change_ = -function().value() / function().jacobian(); | 104 | 332 | variable_ += change_; | 105 | | | 106 | 332 | function().evaluate_on(variable_); | 107 | 332 | ++evaluations_; | 108 | 332 | ++iterations_; | 109 | 332 | using std::abs; | 110 | 332 | last_change_ = abs(change_); | 111 | 332 | value_norm_ = abs(function().value()); | 112 | 332 | } |
_ZN11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE7iterateEv Line | Count | Source | 102 | 5 | void iterate() { | 103 | 5 | change_ = -function().value() / function().jacobian(); | 104 | 5 | variable_ += change_; | 105 | | | 106 | 5 | function().evaluate_on(variable_); | 107 | 5 | ++evaluations_; | 108 | 5 | ++iterations_; | 109 | 5 | using std::abs; | 110 | 5 | last_change_ = abs(change_); | 111 | 5 | value_norm_ = abs(function().value()); | 112 | 5 | } |
|
113 | | |
114 | | //! \copydoc num_collect::base::iterative_solver_base::is_stop_criteria_satisfied |
115 | 1.68k | [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool { |
116 | 1.68k | return (iterations() > max_iterations_) || |
117 | 1.68k | (last_change() < tol_last_change_) || |
118 | 1.68k | (value_norm() < tol_value_norm_); |
119 | 1.68k | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE26is_stop_criteria_satisfiedEv Line | Count | Source | 115 | 1.07k | [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool { | 116 | 1.07k | return (iterations() > max_iterations_) || | 117 | 1.07k | (last_change() < tol_last_change_) || | 118 | 1.07k | (value_norm() < tol_value_norm_); | 119 | 1.07k | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE26is_stop_criteria_satisfiedEv Line | Count | Source | 115 | 612 | [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool { | 116 | 612 | return (iterations() > max_iterations_) || | 117 | 612 | (last_change() < tol_last_change_) || | 118 | 612 | (value_norm() < tol_value_norm_); | 119 | 612 | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE26is_stop_criteria_satisfiedEv Line | Count | Source | 115 | 5 | [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool { | 116 | 5 | return (iterations() > max_iterations_) || | 117 | 5 | (last_change() < tol_last_change_) || | 118 | 5 | (value_norm() < tol_value_norm_); | 119 | 5 | } |
|
120 | | |
121 | | //! \copydoc num_collect::base::iterative_solver_base::configure_iteration_logger |
122 | | void configure_iteration_logger( |
123 | | logging::iterations::iteration_logger<this_type>& iteration_logger) |
124 | 77 | const { |
125 | 77 | iteration_logger.template append<index_type>( |
126 | 77 | "Iter.", &this_type::iterations); |
127 | 77 | iteration_logger.template append<index_type>( |
128 | 77 | "Eval.", &this_type::evaluations); |
129 | 77 | iteration_logger.template append<variable_type>( |
130 | 77 | "Value", &this_type::value_norm); |
131 | 77 | iteration_logger.template append<variable_type>( |
132 | 77 | "Change", &this_type::last_change); |
133 | 77 | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE26configure_iteration_loggerERNS_7logging10iterations16iteration_loggerIS6_EE Line | Count | Source | 124 | 44 | const { | 125 | 44 | iteration_logger.template append<index_type>( | 126 | 44 | "Iter.", &this_type::iterations); | 127 | 44 | iteration_logger.template append<index_type>( | 128 | 44 | "Eval.", &this_type::evaluations); | 129 | 44 | iteration_logger.template append<variable_type>( | 130 | 44 | "Value", &this_type::value_norm); | 131 | 44 | iteration_logger.template append<variable_type>( | 132 | 44 | "Change", &this_type::last_change); | 133 | 44 | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE26configure_iteration_loggerERNS_7logging10iterations16iteration_loggerIS6_EE Line | Count | Source | 124 | 32 | const { | 125 | 32 | iteration_logger.template append<index_type>( | 126 | 32 | "Iter.", &this_type::iterations); | 127 | 32 | iteration_logger.template append<index_type>( | 128 | 32 | "Eval.", &this_type::evaluations); | 129 | 32 | iteration_logger.template append<variable_type>( | 130 | 32 | "Value", &this_type::value_norm); | 131 | 32 | iteration_logger.template append<variable_type>( | 132 | 32 | "Change", &this_type::last_change); | 133 | 32 | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE26configure_iteration_loggerERNS_7logging10iterations16iteration_loggerIS5_EE Line | Count | Source | 124 | 1 | const { | 125 | 1 | iteration_logger.template append<index_type>( | 126 | 1 | "Iter.", &this_type::iterations); | 127 | 1 | iteration_logger.template append<index_type>( | 128 | 1 | "Eval.", &this_type::evaluations); | 129 | 1 | iteration_logger.template append<variable_type>( | 130 | 1 | "Value", &this_type::value_norm); | 131 | 1 | iteration_logger.template append<variable_type>( | 132 | 1 | "Change", &this_type::last_change); | 133 | 1 | } |
|
134 | | |
135 | | using base_type::function; |
136 | | |
137 | | /*! |
138 | | * \brief Get current variable. |
139 | | * |
140 | | * \return Current variable. |
141 | | */ |
142 | 587 | [[nodiscard]] auto variable() const -> const variable_type& { |
143 | 587 | return variable_; |
144 | 587 | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE8variableEv Line | Count | Source | 142 | 304 | [[nodiscard]] auto variable() const -> const variable_type& { | 143 | 304 | return variable_; | 144 | 304 | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE8variableEv Line | Count | Source | 142 | 280 | [[nodiscard]] auto variable() const -> const variable_type& { | 143 | 280 | return variable_; | 144 | 280 | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE8variableEv Line | Count | Source | 142 | 3 | [[nodiscard]] auto variable() const -> const variable_type& { | 143 | 3 | return variable_; | 144 | 3 | } |
|
145 | | |
146 | | /*! |
147 | | * \brief Get current value. |
148 | | * |
149 | | * \return Current value. |
150 | | */ |
151 | | [[nodiscard]] auto value() const |
152 | | -> std::invoke_result_t<decltype(&function_type::value), |
153 | 1 | const function_type> { |
154 | 1 | return function().value(); |
155 | 1 | } |
156 | | |
157 | | /*! |
158 | | * \brief Get Jacobian matrix. |
159 | | * |
160 | | * \return Jacobian matrix. |
161 | | */ |
162 | | [[nodiscard]] auto jacobian() const |
163 | | -> std::invoke_result_t<decltype(&function_type::jacobian), |
164 | 1 | const function_type> { |
165 | 1 | return function().jacobian(); |
166 | 1 | } |
167 | | |
168 | | /*! |
169 | | * \brief Get the number of iterations. |
170 | | * |
171 | | * \return Number of iterations. |
172 | | */ |
173 | 2.86k | [[nodiscard]] auto iterations() const noexcept -> index_type { |
174 | 2.86k | return iterations_; |
175 | 2.86k | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE10iterationsEv Line | Count | Source | 173 | 1.67k | [[nodiscard]] auto iterations() const noexcept -> index_type { | 174 | 1.67k | return iterations_; | 175 | 1.67k | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE10iterationsEv Line | Count | Source | 173 | 1.17k | [[nodiscard]] auto iterations() const noexcept -> index_type { | 174 | 1.17k | return iterations_; | 175 | 1.17k | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE10iterationsEv Line | Count | Source | 173 | 10 | [[nodiscard]] auto iterations() const noexcept -> index_type { | 174 | 10 | return iterations_; | 175 | 10 | } |
|
176 | | |
177 | | /*! |
178 | | * \brief Get the number of function evaluations. |
179 | | * |
180 | | * \return Number of function evaluations. |
181 | | */ |
182 | 1.17k | [[nodiscard]] auto evaluations() const noexcept -> index_type { |
183 | 1.17k | return evaluations_; |
184 | 1.17k | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE11evaluationsEv Line | Count | Source | 182 | 608 | [[nodiscard]] auto evaluations() const noexcept -> index_type { | 183 | 608 | return evaluations_; | 184 | 608 | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE11evaluationsEv Line | Count | Source | 182 | 560 | [[nodiscard]] auto evaluations() const noexcept -> index_type { | 183 | 560 | return evaluations_; | 184 | 560 | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE11evaluationsEv Line | Count | Source | 182 | 4 | [[nodiscard]] auto evaluations() const noexcept -> index_type { | 183 | 4 | return evaluations_; | 184 | 4 | } |
|
185 | | |
186 | | /*! |
187 | | * \brief Get the last change of the variable. |
188 | | * |
189 | | * \return Last change of the variable. |
190 | | */ |
191 | 2.85k | [[nodiscard]] auto last_change() const noexcept -> variable_type { |
192 | 2.85k | return last_change_; |
193 | 2.85k | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE11last_changeEv Line | Count | Source | 191 | 1.67k | [[nodiscard]] auto last_change() const noexcept -> variable_type { | 192 | 1.67k | return last_change_; | 193 | 1.67k | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE11last_changeEv Line | Count | Source | 191 | 1.17k | [[nodiscard]] auto last_change() const noexcept -> variable_type { | 192 | 1.17k | return last_change_; | 193 | 1.17k | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE11last_changeEv Line | Count | Source | 191 | 9 | [[nodiscard]] auto last_change() const noexcept -> variable_type { | 192 | 9 | return last_change_; | 193 | 9 | } |
|
194 | | |
195 | | /*! |
196 | | * \brief Get the norm of function value. |
197 | | * |
198 | | * \return Norm of function value. |
199 | | */ |
200 | 2.76k | [[nodiscard]] auto value_norm() const noexcept -> variable_type { |
201 | 2.76k | return value_norm_; |
202 | 2.76k | } _ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE10value_normEv Line | Count | Source | 200 | 1.64k | [[nodiscard]] auto value_norm() const noexcept -> variable_type { | 201 | 1.64k | return value_norm_; | 202 | 1.64k | } |
_ZNK11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE10value_normEv Line | Count | Source | 200 | 1.11k | [[nodiscard]] auto value_norm() const noexcept -> variable_type { | 201 | 1.11k | return value_norm_; | 202 | 1.11k | } |
_ZNK11num_collect5roots14newton_raphsonIN16num_prob_collect5roots24cubic_root_test_functionEE10value_normEv Line | Count | Source | 200 | 8 | [[nodiscard]] auto value_norm() const noexcept -> variable_type { | 201 | 8 | return value_norm_; | 202 | 8 | } |
|
203 | | |
204 | | /*! |
205 | | * \brief Set maximum number of iterations. |
206 | | * |
207 | | * \param[in] val Value. |
208 | | * \return This. |
209 | | */ |
210 | | auto max_iterations(index_type val) -> this_type& { |
211 | | if (val <= 0) { |
212 | | NUM_COLLECT_LOG_AND_THROW(invalid_argument, |
213 | | "Maximum number of iterations must be a positive integer."); |
214 | | } |
215 | | max_iterations_ = val; |
216 | | return *this; |
217 | | } |
218 | | |
219 | | /*! |
220 | | * \brief Set tolerance of last change of the variable. |
221 | | * |
222 | | * \param[in] val Value. |
223 | | * \return This. |
224 | | */ |
225 | 80 | auto tol_last_change(const variable_type& val) -> this_type& { |
226 | 80 | if (val < static_cast<variable_type>(0)) { |
227 | 0 | NUM_COLLECT_LOG_AND_THROW(invalid_argument, |
228 | 0 | "Tolerance of last change of the variable must be a " |
229 | 0 | "non-negative value."); |
230 | 0 | } |
231 | 80 | tol_last_change_ = val; |
232 | 80 | return *this; |
233 | 80 | } _ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE15tol_last_changeERKd Line | Count | Source | 225 | 46 | auto tol_last_change(const variable_type& val) -> this_type& { | 226 | 46 | if (val < static_cast<variable_type>(0)) { | 227 | 0 | NUM_COLLECT_LOG_AND_THROW(invalid_argument, | 228 | 0 | "Tolerance of last change of the variable must be a " | 229 | 0 | "non-negative value."); | 230 | 0 | } | 231 | 46 | tol_last_change_ = val; | 232 | 46 | return *this; | 233 | 46 | } |
_ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE15tol_last_changeERKf Line | Count | Source | 225 | 34 | auto tol_last_change(const variable_type& val) -> this_type& { | 226 | 34 | if (val < static_cast<variable_type>(0)) { | 227 | 0 | NUM_COLLECT_LOG_AND_THROW(invalid_argument, | 228 | 0 | "Tolerance of last change of the variable must be a " | 229 | 0 | "non-negative value."); | 230 | 0 | } | 231 | 34 | tol_last_change_ = val; | 232 | 34 | return *this; | 233 | 34 | } |
|
234 | | |
235 | | /*! |
236 | | * \brief Set tolerance of the norm of function value. |
237 | | * |
238 | | * \param[in] val Value. |
239 | | * \return This. |
240 | | */ |
241 | 80 | auto tol_value_norm(const variable_type& val) -> this_type& { |
242 | 80 | if (val < static_cast<variable_type>(0)) { |
243 | 0 | NUM_COLLECT_LOG_AND_THROW(invalid_argument, |
244 | 0 | "Tolerance of the norm of function value must be a " |
245 | 0 | "non-negative value."); |
246 | 0 | } |
247 | 80 | tol_value_norm_ = val; |
248 | 80 | return *this; |
249 | 80 | } _ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIdEEE14tol_value_normERKd Line | Count | Source | 241 | 46 | auto tol_value_norm(const variable_type& val) -> this_type& { | 242 | 46 | if (val < static_cast<variable_type>(0)) { | 243 | 0 | NUM_COLLECT_LOG_AND_THROW(invalid_argument, | 244 | 0 | "Tolerance of the norm of function value must be a " | 245 | 0 | "non-negative value."); | 246 | 0 | } | 247 | 46 | tol_value_norm_ = val; | 248 | 46 | return *this; | 249 | 46 | } |
_ZN11num_collect5roots14newton_raphsonINS_9functions4impl19legendre_for_newtonIfEEE14tol_value_normERKf Line | Count | Source | 241 | 34 | auto tol_value_norm(const variable_type& val) -> this_type& { | 242 | 34 | if (val < static_cast<variable_type>(0)) { | 243 | 0 | NUM_COLLECT_LOG_AND_THROW(invalid_argument, | 244 | 0 | "Tolerance of the norm of function value must be a " | 245 | 0 | "non-negative value."); | 246 | 0 | } | 247 | 34 | tol_value_norm_ = val; | 248 | 34 | return *this; | 249 | 34 | } |
|
250 | | |
251 | | private: |
252 | | //! Variable. |
253 | | variable_type variable_{}; |
254 | | |
255 | | //! Change. |
256 | | variable_type change_{}; |
257 | | |
258 | | //! Number of iterations. |
259 | | index_type iterations_{}; |
260 | | |
261 | | //! Number of function evaluations. |
262 | | index_type evaluations_{}; |
263 | | |
264 | | //! Last change of the variable. |
265 | | variable_type last_change_{}; |
266 | | |
267 | | //! Norm of function value. |
268 | | variable_type value_norm_{}; |
269 | | |
270 | | //! Default maximum iterations. |
271 | | static constexpr index_type default_max_iterations = 1000; |
272 | | |
273 | | //! Maximum iterations. |
274 | | index_type max_iterations_{default_max_iterations}; |
275 | | |
276 | | //! Default tolerance of last change of the variable. |
277 | | static constexpr auto default_tol_last_change = |
278 | | static_cast<variable_type>(1e-6); |
279 | | |
280 | | //! Threshold of last change of the variable. |
281 | | variable_type tol_last_change_{default_tol_last_change}; |
282 | | |
283 | | //! Default tolerance of the norm of function value. |
284 | | static constexpr auto default_tol_value_norm = |
285 | | static_cast<variable_type>(1e-6); |
286 | | |
287 | | //! Threshold of the norm of function value. |
288 | | variable_type tol_value_norm_{default_tol_value_norm}; |
289 | | }; |
290 | | |
291 | | /*! |
292 | | * \brief Class of Newton-Raphson method. |
293 | | * |
294 | | * This version is used when variable type is Eigen's vector. |
295 | | * |
296 | | * \tparam Function Type of the function of equation. |
297 | | */ |
298 | | template <concepts::multi_variate_differentiable_function Function> |
299 | | class newton_raphson<Function> |
300 | | : public function_root_finder_base<newton_raphson<Function>, Function> { |
301 | | public: |
302 | | //! Type of this object. |
303 | | using this_type = newton_raphson<Function>; |
304 | | |
305 | | //! Type of base class. |
306 | | using base_type = |
307 | | function_root_finder_base<newton_raphson<Function>, Function>; |
308 | | |
309 | | using typename base_type::function_type; |
310 | | using typename base_type::variable_type; |
311 | | |
312 | | //! Type of scalars in variables. |
313 | | using scalar_type = typename variable_type::Scalar; |
314 | | |
315 | | //! Type of Jacobian matrices. |
316 | | using jacobian_type = typename function_type::jacobian_type; |
317 | | |
318 | | //! Type of solvers of Jacobian matrices. |
319 | | using jacobian_solver_type = |
320 | | Eigen::PartialPivLU<typename Function::jacobian_type>; |
321 | | |
322 | | /*! |
323 | | * \brief Constructor. |
324 | | * |
325 | | * \param[in] function Function of equation. |
326 | | */ |
327 | | explicit newton_raphson(const function_type& function = function_type()) |
328 | 3 | : base_type(newton_raphson_tag, function) {} |
329 | | |
330 | | /*! |
331 | | * \brief Initialize. |
332 | | * |
333 | | * \param[in] variable Initial variable. |
334 | | */ |
335 | 3 | void init(const variable_type& variable) { |
336 | 3 | variable_ = variable; |
337 | 3 | last_change_ = std::numeric_limits<scalar_type>::infinity(); |
338 | 3 | iterations_ = 0; |
339 | 3 | evaluations_ = 0; |
340 | | |
341 | 3 | function().evaluate_on(variable_); |
342 | 3 | ++evaluations_; |
343 | 3 | value_norm_ = function().value().norm(); |
344 | 3 | } |
345 | | |
346 | | //! \copydoc function_root_finder_base::iterate |
347 | 1.00k | void iterate() { |
348 | 1.00k | jacobian_solver_.compute(function().jacobian()); |
349 | 1.00k | change_ = -jacobian_solver_.solve(function().value()); |
350 | 1.00k | variable_ += change_; |
351 | | |
352 | 1.00k | function().evaluate_on(variable_); |
353 | 1.00k | ++evaluations_; |
354 | 1.00k | ++iterations_; |
355 | 1.00k | last_change_ = change_.norm(); |
356 | 1.00k | value_norm_ = function().value().norm(); |
357 | 1.00k | } |
358 | | |
359 | | //! \copydoc function_root_finder_base::is_stop_criteria_satisfied |
360 | 1.00k | [[nodiscard]] auto is_stop_criteria_satisfied() const -> bool { |
361 | 1.00k | return (iterations() > max_iterations_) || |
362 | 1.00k | (last_change() < tol_last_change_) || |
363 | 1.00k | (value_norm() < tol_value_norm_); |
364 | 1.00k | } |
365 | | |
366 | | //! \copydoc num_collect::base::iterative_solver_base::configure_iteration_logger |
367 | | void configure_iteration_logger( |
368 | | logging::iterations::iteration_logger<this_type>& iteration_logger) |
369 | 1 | const { |
370 | 1 | iteration_logger.template append<index_type>( |
371 | 1 | "Iter.", &this_type::iterations); |
372 | 1 | iteration_logger.template append<index_type>( |
373 | 1 | "Eval.", &this_type::evaluations); |
374 | 1 | iteration_logger.template append<scalar_type>( |
375 | 1 | "Value", &this_type::value_norm); |
376 | 1 | iteration_logger.template append<scalar_type>( |
377 | 1 | "Change", &this_type::last_change); |
378 | 1 | } |
379 | | |
380 | | using base_type::function; |
381 | | |
382 | | /*! |
383 | | * \brief Get current variable. |
384 | | * |
385 | | * \return Current variable. |
386 | | */ |
387 | 4 | [[nodiscard]] auto variable() const -> const variable_type& { |
388 | 4 | return variable_; |
389 | 4 | } |
390 | | |
391 | | /*! |
392 | | * \brief Get current value. |
393 | | * |
394 | | * \return Current value. |
395 | | */ |
396 | | [[nodiscard]] auto value() const |
397 | | -> std::invoke_result_t<decltype(&function_type::value), |
398 | 1 | const function_type> { |
399 | 1 | return function().value(); |
400 | 1 | } |
401 | | |
402 | | /*! |
403 | | * \brief Get Jacobian matrix. |
404 | | * |
405 | | * \return Jacobian matrix. |
406 | | */ |
407 | | [[nodiscard]] auto jacobian() const |
408 | | -> std::invoke_result_t<decltype(&function_type::jacobian), |
409 | 1 | const function_type> { |
410 | 1 | return function().jacobian(); |
411 | 1 | } |
412 | | |
413 | | /*! |
414 | | * \brief Get the number of iterations. |
415 | | * |
416 | | * \return Number of iterations. |
417 | | */ |
418 | 1.10k | [[nodiscard]] auto iterations() const noexcept -> index_type { |
419 | 1.10k | return iterations_; |
420 | 1.10k | } |
421 | | |
422 | | /*! |
423 | | * \brief Get the number of function evaluations. |
424 | | * |
425 | | * \return Number of function evaluations. |
426 | | */ |
427 | 104 | [[nodiscard]] auto evaluations() const noexcept -> index_type { |
428 | 104 | return evaluations_; |
429 | 104 | } |
430 | | |
431 | | /*! |
432 | | * \brief Get the last change of the variable. |
433 | | * |
434 | | * \return Last change of the variable. |
435 | | */ |
436 | 1.10k | [[nodiscard]] auto last_change() const noexcept -> scalar_type { |
437 | 1.10k | return last_change_; |
438 | 1.10k | } |
439 | | |
440 | | /*! |
441 | | * \brief Get the norm of function value. |
442 | | * |
443 | | * \return Norm of function value. |
444 | | */ |
445 | 1.10k | [[nodiscard]] auto value_norm() const noexcept -> scalar_type { |
446 | 1.10k | return value_norm_; |
447 | 1.10k | } |
448 | | |
449 | | /*! |
450 | | * \brief Set maximum number of iterations. |
451 | | * |
452 | | * \param[in] val Value. |
453 | | * \return This. |
454 | | */ |
455 | | auto max_iterations(index_type val) -> this_type& { |
456 | | if (val <= 0) { |
457 | | NUM_COLLECT_LOG_AND_THROW(invalid_argument, |
458 | | "Maximum number of iterations must be a positive integer."); |
459 | | } |
460 | | max_iterations_ = val; |
461 | | return *this; |
462 | | } |
463 | | |
464 | | /*! |
465 | | * \brief Set tolerance of last change of the variable. |
466 | | * |
467 | | * \param[in] val Value. |
468 | | * \return This. |
469 | | */ |
470 | | auto tol_last_change(const scalar_type& val) -> this_type& { |
471 | | if (val < static_cast<variable_type>(0)) { |
472 | | NUM_COLLECT_LOG_AND_THROW(invalid_argument, |
473 | | "Tolerance of last change of the variable must be a " |
474 | | "non-negative value."); |
475 | | } |
476 | | tol_last_change_ = val; |
477 | | return *this; |
478 | | } |
479 | | |
480 | | /*! |
481 | | * \brief Set tolerance of the norm of function value. |
482 | | * |
483 | | * \param[in] val Value. |
484 | | * \return This. |
485 | | */ |
486 | | auto tol_value_norm(const scalar_type& val) -> this_type& { |
487 | | if (val < static_cast<variable_type>(0)) { |
488 | | NUM_COLLECT_LOG_AND_THROW(invalid_argument, |
489 | | "Tolerance of the norm of function value must be a " |
490 | | "non-negative value."); |
491 | | } |
492 | | tol_value_norm_ = val; |
493 | | return *this; |
494 | | } |
495 | | |
496 | | private: |
497 | | //! Variable. |
498 | | variable_type variable_{}; |
499 | | |
500 | | //! Change. |
501 | | variable_type change_{}; |
502 | | |
503 | | //! Solver of Jacobian matrices. |
504 | | jacobian_solver_type jacobian_solver_{}; |
505 | | |
506 | | //! Number of iterations. |
507 | | index_type iterations_{}; |
508 | | |
509 | | //! Number of function evaluations. |
510 | | index_type evaluations_{}; |
511 | | |
512 | | //! Last change of the variable. |
513 | | scalar_type last_change_{}; |
514 | | |
515 | | //! Norm of function value. |
516 | | scalar_type value_norm_{}; |
517 | | |
518 | | //! Default maximum iterations. |
519 | | static constexpr index_type default_max_iterations = 1000; |
520 | | |
521 | | //! Maximum iterations. |
522 | | index_type max_iterations_{default_max_iterations}; |
523 | | |
524 | | //! Default tolerance of last change of the variable. |
525 | | static constexpr auto default_tol_last_change = |
526 | | static_cast<scalar_type>(1e-6); |
527 | | |
528 | | //! Threshold of last change of the variable. |
529 | | scalar_type tol_last_change_{default_tol_last_change}; |
530 | | |
531 | | //! Default tolerance of the norm of function value. |
532 | | static constexpr auto default_tol_value_norm = |
533 | | static_cast<scalar_type>(1e-6); |
534 | | |
535 | | //! Threshold of the norm of function value. |
536 | | scalar_type tol_value_norm_{default_tol_value_norm}; |
537 | | }; |
538 | | |
539 | | } // namespace num_collect::roots |