Coverage Report

Created: 2025-01-24 06:23

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