Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
Varona.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco, Mattia Piazza and Enrico Bertolazzi. *
3 * *
4 * The Optimist project is distributed under the BSD 2-Clause License. *
5 * *
6 * Davide Stocco Mattia Piazza Enrico Bertolazzi *
7 * University of Trento University of Trento University of Trento *
8 * davide.stocco@unitn.it mattia.piazza@unitn.it enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#pragma once
12
13#ifndef OPTIMIST_ROOTFINDER_VARONA4_HH
14#define OPTIMIST_ROOTFINDER_VARONA4_HH
15
17
18namespace Optimist
19{
20 namespace RootFinder
21 {
22
23 /*\
24 | __ __ _ _
25 | \ \ / /_ _ _ __ ___ _ __ __ _| || |
26 | \ \ / / _` | '__/ _ \| '_ \ / _` | || |_
27 | \ V / (_| | | | (_) | | | | (_| |__ _|
28 | \_/ \__,_|_| \___/|_| |_|\__,_| |_|
29 |
30 \*/
31
39 template <typename Real>
40 class Varona : public RootFinder<Real, 1, Varona<Real>>
41 {
42 public:
43 static constexpr bool requires_function{true};
44 static constexpr bool requires_first_derivative{true};
45 static constexpr bool requires_second_derivative{false};
46
48
49
52 using Method = enum class Method : Integer {ORDER_4 = 41, ORDER_8 = 8, ORDER_16 = 16, ORDER_32 = 32};
53
54 private:
55 Method m_method{Method::ORDER_4};
56
57 public:
58
62 Varona() {}
63
68 std::string name_impl() const
69 {
70 std::ostringstream os;
71 os << "Varona";
72 if (this->m_method == Method::ORDER_4) {os << "4";}
73 else if (this->m_method == Method::ORDER_8) {os << "8";}
74 else if (this->m_method == Method::ORDER_16) {os << "16";}
75 else if (this->m_method == Method::ORDER_32) {os << "32";}
76 else {os << "UNKNOWN";}
77 return os.str();
78 }
79
84 Method method() const {return this->m_method;}
85
90 void method(Method t_method) {this->m_method = t_method;}
91
95 void enable_4th_order_method() {this->m_method = Method::ORDER_4;}
96
100 void enable_8th_order_method() {this->m_method = Method::ORDER_8;}
101
105 void enable_16th_order_method() {this->m_method = Method::ORDER_16;}
106
110 void enable_32th_order_method() {this->m_method = Method::ORDER_32;}
111
116 void set_method(Method t_method) {this->m_method = t_method;}
117
128 template <typename FunctionLambda, typename FirstDerivativeLambda>
129 bool solve_impl(FunctionLambda && function, FirstDerivativeLambda && first_derivative, Real x_ini,
130 Real & x_sol)
131 {
132 #define CMD "Optimist::RootFinder::Varona::solve(...): "
133
134 // Setup internal variables
135 this->reset();
136
137 // Print header
138 if (this->m_verbose) {this->header();}
139
140 // Initialize variables
141 bool damped, success;
142 Real residuals, step_norm;
143 Real x_old, x_new, function_old, function_new, step_old, step_new;
144 Real first_derivative_old;
145
146 // Set initial iteration
147 x_old = x_ini;
148 success = this->evaluate_function(std::forward<FunctionLambda>(function), x_old, function_old);
150 CMD "function evaluation failed at the initial point.");
151
152 // Algorithm iterations
153 Real tolerance_residuals{this->m_tolerance};
154 Real tolerance_step_norm{this->m_tolerance * this->m_tolerance};
155 for (this->m_iterations = 1; this->m_iterations < this->m_max_iterations; ++this->m_iterations)
156 {
157 // Store trace
158 this->store_trace(x_old);
159
160 // Evaluate first derivative
161 success = this->evaluate_first_derivative(std::forward<FirstDerivativeLambda>(first_derivative), x_old, first_derivative_old);
163 CMD "first derivative evaluation failed at iteration " << this->m_iterations << ".");
164
165 // Calculate step
166 if (std::abs(first_derivative_old) < EPSILON_LOW) {
167 OPTIMIST_WARNING( CMD "singular first derivative detected.");
168 first_derivative_old = (first_derivative_old > 0.0) ? EPSILON_LOW : -EPSILON_LOW;
169 }
170
171 this->compute_step(std::forward<FunctionLambda>(function), x_old, function_old, first_derivative_old, step_old);
172
173 // Check convergence
174 residuals = std::abs(function_old);
175 step_norm = std::abs(step_old);
176 if (this->m_verbose) {this->info(residuals);}
177 if (residuals < tolerance_residuals || step_norm < tolerance_step_norm) {
178 this->m_converged = true;
179 break;
180 }
181
182 if (this->m_damped) {
183 // Relax the iteration process
184 damped = this->damp(std::forward<FunctionLambda>(function), x_old, function_old, step_old, x_new, function_new, step_new);
185 OPTIMIST_ASSERT_WARNING(damped, CMD "damping failed.");
186 } else {
187 // Update point
188 x_new = x_old + step_old;
189 success = this->evaluate_function(std::forward<FunctionLambda>(function), x_new, function_new);
191 CMD "function evaluation failed at iteration " << this->m_iterations << ".");
192 }
193
194 // Update internal variables
195 x_old = x_new;
196 function_old = function_new;
197 step_old = step_new;
198 }
199
200 // Print bottom
201 if (this->m_verbose) {this->bottom();}
202
203 // Convergence data
204 x_sol = x_old;
205 return this->m_converged;
206
207 #undef CMD
208 }
209
210 protected:
211
220 template <typename FunctionLambda>
221 void compute_step(FunctionLambda && function, Real x_old, Real function_old, Real first_derivative_old,
222 Real & step_old)
223 {
224 #define CMD "Optimist::RootFinder::Varona::compute_step(...): "
225
226 bool success;
227 Real function_y, function_z, function_w, function_h, step_tmp, t, s, u, v;
228 Real tolerance_residuals{this->m_tolerance};
229
230 // Base step
231 step_old = -function_old/first_derivative_old;
232
233 // Order 4 step
234 if (this->m_method == Method::ORDER_4 || this->m_method == Method::ORDER_8 ||
235 this->m_method == Method::ORDER_16 || this->m_method == Method::ORDER_32) {
236 success = this->evaluate_function(std::forward<FunctionLambda>(function), x_old+step_old, function_y);
238 CMD "function evaluation failed during order 4 step.");
239 if (std::abs(function_y) < tolerance_residuals) {return;}
240 t = function_y/function_old;
241 step_tmp = this->Q(t) * (function_y/first_derivative_old);
242 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
243 else {return;}
244 }
245
246 // Order 8 step (continued order 4)
247 if (this->m_method == Method::ORDER_8 || this->m_method == Method::ORDER_16 ||
248 this->m_method == Method::ORDER_32) {
249 success = this->evaluate_function(std::forward<FunctionLambda>(function), x_old+step_old, function_z);
251 CMD "function evaluation failed during order 8 step.");
252 if (std::abs(function_z) < tolerance_residuals) {return;}
253 s = function_z/function_y;
254 step_tmp = this->W(t, s) * (function_z/first_derivative_old);
255 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
256 else {return;}
257 }
258
259 // Order 16 step (continued order 8)
260 if (this->m_method == Method::ORDER_16 || this->m_method == Method::ORDER_32) {
261 success = this->evaluate_function(std::forward<FunctionLambda>(function), x_old+step_old, function_w);
263 CMD "function evaluation failed during order 16 step.");
264 if (std::abs(function_w) < tolerance_residuals) {return;}
265 u = function_w/function_z;
266 step_tmp = this->H(t, s, u) * (function_w/first_derivative_old);
267 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
268 else {return;}
269 }
270
271 // Order 32 step (continued order 16)
272 if (this->m_method == Method::ORDER_32) {
273 success = this->evaluate_function(std::forward<FunctionLambda>(function), x_old+step_old, function_h);
275 CMD "function evaluation failed during order 32 step.");
276 if (std::abs(function_h) < tolerance_residuals) {return;}
277 v = (function_h/function_w);
278 step_tmp = this->J(t, s, u, v) * (function_h/first_derivative_old);
279 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
280 else {return;}
281 }
282
283 OPTIMIST_ASSERT(std::isfinite(step_old),
284 CMD "step is not finite.");
285
286 #undef CMD
287 }
288
294 static Real Q(Real t) {return 1.0 + 2.0*t;}
295
302 static Real W(Real t, Real s) {return t*t*(1.0 - 4.0*t) + (4.0*s + 2.0)*t + s + 1.0;}
303
311 static Real H(Real t, Real s, Real u) {
312 Real t1{t*t};
313 Real t2{t1*t1};
314 Real t8{s*s};
315 Real t17{s*t8};
316 Real t23{2.0*u};
317 return
318 ((8.0*u + 6.0*t2 + 4.0)*s -
319 (6.0*t8 + 4.0*(s + u + 1.0))*t1 +
320 2.0*t8 - 4.0*t17 + t23 + 2.0)*t +
321 t1*(t8 + s + u + 1.0) +
322 (1.0 - 3.0*t2 + t23)*s +
323 u - t17 + 1.0;
324 }
325
334 static Real J(Real t, Real s, Real u, Real v) {
335 Real t1{s*s};
336 Real t2{t1*t1};
337 Real t17{t*t};
338 Real t22{u*u};
339 Real t32{t17*t17};
340 Real t34{t*t32};
341 Real t37{t*t17};
342 Real t46{1.0 + v};
343 Real t65{u + 1.0 + v};
344 Real t76{(-2.0*t22 + u + 4.0*v + 2.0)*u};
345 return
346 (-1.0 + 2.0*t)*(2.0 + 5.0*t)*u*t*t2 +
347 (4.0*t + 1.0)*u*s*t2 +
348 (u*t22 - 2.0*u*v - u - v - 1.0)*(4.0*t17 + 3.0*t + 1.0)*( - 1.0 + t) -
349 8.0*(t22*(t17/2.0 - 1.0/4.0) + u*(t17*t32 - 5.0/8.0*t34 - 3.0/4.0*t32 +
350 3.0/8.0*t37 + 3.0/4.0*t17 - t/8.0 - 1.0/4.0) + 3.0/4.0*t46*(t + 1.0/2.0)*(t - 2.0/3.0))*t*t1 +
351 4.0*(t22*( - 3.0/2.0*t - 1.0/4.0) + u*(t34 - t32 - 3.0/2.0*t37 + t17/4.0 - t - 1.0/4.0) -
352 t46*(t + 1.0/4.0))*s*t1 + (1.0 + v + t65*t17 - 4.0*t65*t37 - 3.0*t65*t32 + 6.0*t65*t34 +
353 t76 + 4.0*(1.0 + v + t76)*t)*s;
354 }
355
356 }; // class Varona
357
358 } // namespace RootFinder
359
360} // namespace Optimist
361
362#endif // OPTIMIST_ROOTFINDER_VARONA4_HH
#define OPTIMIST_WARNING(MSG)
Definition Optimist.hh:53
#define OPTIMIST_ASSERT_WARNING(COND, MSG)
Definition Optimist.hh:61
#define OPTIMIST_BASIC_CONSTANTS(Real)
Definition Optimist.hh:71
#define OPTIMIST_ASSERT(COND, MSG)
Definition Optimist.hh:44
#define CMD
void method(Method t_method)
Definition Varona.hh:90
static constexpr bool requires_second_derivative
Definition Varona.hh:45
enum class Method :Integer {ORDER_4=41, ORDER_8=8, ORDER_16=16, ORDER_32=32} Method
Definition Varona.hh:52
Varona()
Definition Varona.hh:62
static Real W(Real t, Real s)
Definition Varona.hh:302
void enable_8th_order_method()
Definition Varona.hh:100
bool solve_impl(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, Real x_ini, Real &x_sol)
Definition Varona.hh:129
void enable_4th_order_method()
Definition Varona.hh:95
void compute_step(FunctionLambda &&function, Real x_old, Real function_old, Real first_derivative_old, Real &step_old)
Definition Varona.hh:221
static constexpr bool requires_function
Definition Varona.hh:43
static Real Q(Real t)
Definition Varona.hh:294
static constexpr bool requires_first_derivative
Definition Varona.hh:44
Method m_method
Definition Varona.hh:55
static Real J(Real t, Real s, Real u, Real v)
Definition Varona.hh:334
Method method() const
Definition Varona.hh:84
void enable_16th_order_method()
Definition Varona.hh:105
static Real H(Real t, Real s, Real u)
Definition Varona.hh:311
void set_method(Method t_method)
Definition Varona.hh:116
void enable_32th_order_method()
Definition Varona.hh:110
std::string name_impl() const
Definition Varona.hh:68
void info(Real residuals, std::string const &notes="-")
Definition SolverBase.hh:924
bool damp(FunctionLambda &&function, InputType const &x_old, InputType const &function_old, InputType const &step_old, InputType &x_new, InputType &function_new, InputType &step_new)
Definition SolverBase.hh:828
Integer m_max_iterations
Definition SolverBase.hh:85
void store_trace(InputType const &x)
Definition SolverBase.hh:813
bool evaluate_function(FunctionLambda &&function, InputType const &x, OutputType &out)
Definition SolverBase.hh:768
bool evaluate_first_derivative(FirstDerivativeLambda &&function, InputType const &x, FirstDerivativeType &out)
Definition SolverBase.hh:785
Namespace for the Optimist library.
Definition Optimist.hh:88
OPTIMIST_DEFAULT_INTEGER_TYPE Integer
The Integer type as used for the API.
Definition Optimist.hh:96