Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
NewtonRaphson.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco and Enrico Bertolazzi. *
3 * *
4 * The Optimist project is distributed under the BSD 2-Clause License. *
5 * *
6 * Davide Stocco Enrico Bertolazzi *
7 * University of Trento University of Trento *
8 * davide.stocco@unitn.it enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#ifndef OPTIMIST_ROOTFINDER_NEWTONRAPHSON_HH
12#define OPTIMIST_ROOTFINDER_NEWTONRAPHSON_HH
13
15
16namespace Optimist {
17 namespace RootFinder {
18
19 /*\
20 | _ _ _ ____ _
21 | | \ | | _____ _| |_ ___ _ __ | _ \ __ _ _ __ | |__ ___ ___ _
22 __
23 | | \| |/ _ \ \ /\ / / __/ _ \| '_ \| |_) / _` | '_ \| '_ \/ __|/ _ \| '_
24 \ | | |\ | __/\ V V /| || (_) | | | | _ < (_| | |_) | | | \__ \ (_) | |
25 | | | |_| \_|\___| \_/\_/ \__\___/|_| |_|_| \_\__,_| .__/|_|
26 |_|___/\___/|_| |_| | |_|
27 \*/
28
36 template <typename Scalar>
37 class NewtonRaphson : public RootFinder<Scalar, NewtonRaphson<Scalar>> {
38 public:
39 static constexpr bool RequiresFunction{true};
40 static constexpr bool RequiresFirstDerivative{true};
41 static constexpr bool RequiresSecondDerivative{false};
42
44
45
49
54 constexpr std::string name_impl() const {
55 return "NewtonRaphson";
56 }
57
69 template <typename FunctionLambda, typename FirstDerivativeLambda>
70 bool solve_impl(FunctionLambda &&function,
71 FirstDerivativeLambda &&first_derivative,
72 Scalar x_ini,
73 Scalar &x_sol) {
74#define CMD "Optimist::RootFinder::NewtonRaphson::solve(...): "
75
76 // Reset internal variables
77 this->reset_counters();
78
79 // Print header
80 if (this->m_verbose) {
81 this->header();
82 }
83
84 // Initialize variables
85 bool damped, success;
86 Scalar residuals, step_norm;
87 Scalar x_old, x_new, function_old, function_new, step_old, step_new;
88 Scalar first_derivative_old;
89
90 // Set initial iteration
91 x_old = x_ini;
92 success =
93 this->evaluate_function(std::forward<FunctionLambda>(function),
94 x_old,
95 function_old);
96 OPTIMIST_ASSERT(success,
97 CMD "function evaluation failed at the initial point.");
98
99 // Algorithm iterations
100 Scalar tolerance_residuals{this->m_tolerance};
101 Scalar tolerance_step_norm{this->m_tolerance * this->m_tolerance};
102 for (this->m_iterations = 1;
103 this->m_iterations < this->m_max_iterations;
104 ++this->m_iterations) {
105 // Evaluate first derivative
106 success = this->evaluate_first_derivative(
107 std::forward<FirstDerivativeLambda>(first_derivative),
108 x_old,
109 first_derivative_old);
110 OPTIMIST_ASSERT(success,
111 CMD "first derivative evaluation failed at iteration "
112 << this->m_iterations << ".");
113
114 // Calculate step
115 if (std::abs(first_derivative_old) < NewtonRaphson::SQRT_EPSILON) {
117 "close-to-singular first derivative detected.");
118 first_derivative_old = (first_derivative_old > 0)
119 ? NewtonRaphson::SQRT_EPSILON
120 : -NewtonRaphson::SQRT_EPSILON;
121 }
122 step_old = -function_old / first_derivative_old;
124 std::isfinite(step_old),
125 CMD "step " << this->m_iterations << " is not finite.");
126
127 // Check convergence
128 residuals = std::abs(function_old);
129 step_norm = std::abs(step_old);
130 if (this->m_verbose) {
131 this->info(residuals);
132 }
133 if (residuals < tolerance_residuals ||
134 step_norm < tolerance_step_norm) {
135 this->m_converged = true;
136 break;
137 }
138
139 if (this->m_damped) {
140 // Relax the iteration process
141 damped = this->damp(std::forward<FunctionLambda>(function),
142 x_old,
143 function_old,
144 step_old,
145 x_new,
146 function_new,
147 step_new);
148 OPTIMIST_ASSERT_WARNING(damped, CMD "damping failed.");
149 } else {
150 // Update point
151 x_new = x_old + step_old;
152 success =
153 this->evaluate_function(std::forward<FunctionLambda>(function),
154 x_new,
155 function_new);
156 OPTIMIST_ASSERT(success,
157 CMD "function evaluation failed at iteration "
158 << this->m_iterations << ".");
159 }
160
161 // Update internal variables
162 x_old = x_new;
163 function_old = function_new;
164 step_old = step_new;
165 }
166
167 // Print bottom
168 if (this->m_verbose) {
169 this->bottom();
170 }
171
172 // Convergence data
173 x_sol = x_old;
174 return this->m_converged;
175
176#undef CMD
177 }
178
179 }; // class NewtonRaphson
180
181 } // namespace RootFinder
182
183} // namespace Optimist
184
185#endif // OPTIMIST_ROOTFINDER_NEWTONRAPHSON_HH
#define OPTIMIST_WARNING(MSG)
Definition Optimist.hh:55
#define OPTIMIST_BASIC_CONSTANTS(Scalar)
Definition Optimist.hh:69
#define OPTIMIST_ASSERT_WARNING(COND, MSG)
Definition Optimist.hh:61
#define OPTIMIST_ASSERT(COND, MSG)
Definition Optimist.hh:47
#define CMD
static constexpr bool RequiresFunction
Definition NewtonRaphson.hh:39
constexpr std::string name_impl() const
Definition NewtonRaphson.hh:54
static constexpr bool RequiresSecondDerivative
Definition NewtonRaphson.hh:41
NewtonRaphson()
Definition NewtonRaphson.hh:48
bool solve_impl(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, Scalar x_ini, Scalar &x_sol)
Definition NewtonRaphson.hh:70
static constexpr bool RequiresFirstDerivative
Definition NewtonRaphson.hh:40
typename TypeTrait< Scalar >::Scalar Scalar
Definition RootFinder.hh:53
bool damp(FunctionLambda &&function, const Scalar &x_old, const Scalar &function_old, const Scalar &step_old, Scalar &x_new, Scalar &function_new, Scalar &step_new)
Definition SolverBase.hh:1109
void info(Scalar residuals, const std::string &notes="-")
Definition SolverBase.hh:1230
bool evaluate_function(FunctionLambda &&function, const Scalar &x, Scalar &out)
Definition SolverBase.hh:1040
bool evaluate_first_derivative(FirstDerivativeLambda &&function, const Scalar &x, FirstDerivative &out)
Definition SolverBase.hh:1061
Namespace for multi-dimensional root-finding algorithms.
Definition RootFinder.hh:23
Namespace for the Optimist library.
Definition Optimist.hh:89