Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
Halley.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#pragma once
12
13#ifndef OPTIMIST_ROOTFINDER_HALLEY_HH
14#define OPTIMIST_ROOTFINDER_HALLEY_HH
15
17
18namespace Optimist {
19 namespace RootFinder {
20
21 /*\
22 | _ _ _ _
23 | | | | | __ _| | | ___ _ _
24 | | |_| |/ _` | | |/ _ \ | | |
25 | | _ | (_| | | | __/ |_| |
26 | |_| |_|\__,_|_|_|\___|\__, |
27 | |___/
28 \*/
29
37 template <typename Scalar>
38 class Halley : public RootFinder<Scalar, Halley<Scalar>> {
39 public:
40 static constexpr bool RequiresFunction{true};
41 static constexpr bool RequiresFirstDerivative{true};
42 static constexpr bool RequiresSecondDerivative{true};
43
45
46
49 Halley() {}
50
55 constexpr std::string name_impl() const {
56 return "Halley";
57 }
58
72 template <typename FunctionLambda,
73 typename FirstDerivativeLambda,
74 typename SecondDerivativeLambda>
75 bool solve_impl(FunctionLambda &&function,
76 FirstDerivativeLambda &&first_derivative,
77 SecondDerivativeLambda &&second_derivative,
78 Scalar x_ini,
79 Scalar &x_sol) {
80#define CMD "Optimist::RootFinder::Halley::solve(...): "
81
82 // Reset internal variables
83 this->reset_counters();
84
85 // Print header
86 if (this->m_verbose) {
87 this->header();
88 }
89
90 // Initialize variables
91 bool damped, success;
92 Scalar residuals, step_norm;
93 Scalar x_old, x_new, function_old, function_new, step_old, step_new;
94 Scalar first_derivative_old, second_derivative_old;
95
96 // Set initial iteration
97 x_old = x_ini;
98 success =
99 this->evaluate_function(std::forward<FunctionLambda>(function),
100 x_old,
101 function_old);
102 OPTIMIST_ASSERT(success,
103 CMD "function evaluation failed at the initial point.");
104
105 // Algorithm iterations
106 Scalar tolerance_residuals{this->m_tolerance};
107 Scalar tolerance_step_norm{this->m_tolerance * this->m_tolerance};
108 for (this->m_iterations = 1;
109 this->m_iterations < this->m_max_iterations;
110 ++this->m_iterations) {
111 // Evaluate derivatives
112 success = this->evaluate_first_derivative(
113 std::forward<FirstDerivativeLambda>(first_derivative),
114 x_old,
115 first_derivative_old);
116 OPTIMIST_ASSERT(success,
117 CMD "first derivative evaluation failed at iteration "
118 << this->m_iterations << ".");
119 success = this->evaluate_second_derivative(
120 std::forward<SecondDerivativeLambda>(second_derivative),
121 x_old,
122 second_derivative_old);
124 success,
125 CMD "second derivative evaluation failed at iteration "
126 << this->m_iterations << ".");
127
128 // Calculate step
129 if (std::abs(first_derivative_old) < Halley::SQRT_EPSILON) {
131 "close-to-singular first derivative detected.");
132 first_derivative_old = (first_derivative_old > 0)
133 ? Halley::SQRT_EPSILON
134 : -Halley::SQRT_EPSILON;
135 }
136 if (std::abs(second_derivative_old) < Halley::SQRT_EPSILON) {
138 "close-to-singular second derivative detected.");
139 second_derivative_old = (second_derivative_old > 0)
140 ? Halley::SQRT_EPSILON
141 : -Halley::SQRT_EPSILON;
142 }
143 step_old =
144 -(function_old / first_derivative_old) /
145 (1.0 - (function_old * second_derivative_old) /
146 (2.0 * first_derivative_old * first_derivative_old));
148 std::isfinite(step_old),
149 CMD "step " << this->m_iterations << " is not finite.");
150
151 // Check convergence
152 residuals = std::abs(function_old);
153 step_norm = std::abs(step_old);
154 if (this->m_verbose) {
155 this->info(residuals);
156 }
157 if (residuals < tolerance_residuals ||
158 step_norm < tolerance_step_norm) {
159 this->m_converged = true;
160 break;
161 }
162
163 if (this->m_damped) {
164 // Relax the iteration process
165 damped = this->damp(std::forward<FunctionLambda>(function),
166 x_old,
167 function_old,
168 step_old,
169 x_new,
170 function_new,
171 step_new);
172 OPTIMIST_ASSERT_WARNING(damped, CMD "damping failed.");
173 } else {
174 // Update point
175 x_new = x_old + step_old;
176 success =
177 this->evaluate_function(std::forward<FunctionLambda>(function),
178 x_new,
179 function_new);
180 OPTIMIST_ASSERT(success,
181 CMD "function evaluation failed at iteration "
182 << this->m_iterations << ".");
183 }
184
185 // Update internal variables
186 x_old = x_new;
187 function_old = function_new;
188 step_old = step_new;
189 }
190
191 // Print bottom
192 if (this->m_verbose) {
193 this->bottom();
194 }
195
196 // Convergence data
197 x_sol = x_old;
198 return this->m_converged;
199
200#undef CMD
201 }
202
203 }; // class Halley
204
205 } // namespace RootFinder
206
207} // namespace Optimist
208
209#endif // OPTIMIST_ROOTFINDER_HALLEY_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
bool solve_impl(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, SecondDerivativeLambda &&second_derivative, Scalar x_ini, Scalar &x_sol)
Definition Halley.hh:75
static constexpr bool RequiresFunction
Definition Halley.hh:40
static constexpr bool RequiresFirstDerivative
Definition Halley.hh:41
constexpr std::string name_impl() const
Definition Halley.hh:55
Halley()
Definition Halley.hh:49
static constexpr bool RequiresSecondDerivative
Definition Halley.hh:42
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
bool evaluate_second_derivative(SecondDerivativeLambda &&function, const Scalar &x, SecondDerivative &out)
Definition SolverBase.hh:1082
Integer m_max_iterations
Definition SolverBase.hh:121
Scalar m_tolerance
Definition SolverBase.hh:128
void reset_counters()
Definition SolverBase.hh:1022
Integer m_iterations
Definition SolverBase.hh:120
Namespace for the Optimist library.
Definition Optimist.hh:89