Coverage Report

Created: 2024-10-11 06:23

/builds/MusicScience37Projects/numerical-analysis/numerical-collection-cpp/include/num_collect/roots/newton_raphson.h
Line
Count
Source (jump to first uncovered line)
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