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_SCALAR_ROOT_FINDER_VARONA4_HH
14#define OPTIMIST_SCALAR_ROOT_FINDER_VARONA4_HH
15
17
18namespace Optimist
19{
20 namespace ScalarRootFinder
21 {
22
23 /*\
24 | __ __ _ _
25 | \ \ / /_ _ _ __ ___ _ __ __ _| || |
26 | \ \ / / _` | '__/ _ \| '_ \ / _` | || |_
27 | \ V / (_| | | | (_) | | | | (_| |__ _|
28 | \_/ \__,_|_| \___/|_| |_|\__,_| |_|
29 |
30 \*/
31
39 template <typename Real>
40 class Varona : public ScalarRootFinder<Real, 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 // Function types
50 using Method = enum class Method : Integer {ORDER_4 = 41, ORDER_8 = 8, ORDER_16 = 16, ORDER_32 = 32};
54
55 private:
56 Method m_method{Method::ORDER_4};
57
58 public:
59
63 Varona() {}
64
69 std::string name_impl() const
70 {
71 std::ostringstream os;
72 os << "Varona";
73 if (this->m_method == Method::ORDER_4) {os << "4";}
74 else if (this->m_method == Method::ORDER_8) {os << "8";}
75 else if (this->m_method == Method::ORDER_16) {os << "16";}
76 else if (this->m_method == Method::ORDER_32) {os << "32";}
77 else {os << "UNKNOWN";}
78 return os.str();
79 }
80
85 Method method() const {return this->m_method;}
86
91 void method(Method t_method) {this->m_method = t_method;}
92
96 void enable_4th_order_method() {this->m_method = Method::ORDER_4;}
97
101 void enable_8th_order_method() {this->m_method = Method::ORDER_8;}
102
106 void enable_16th_order_method() {this->m_method = Method::ORDER_16;}
107
111 void enable_32th_order_method() {this->m_method = Method::ORDER_32;}
112
117 void set_method(Method t_method) {this->m_method = t_method;}
118
127 bool solve_impl(FunctionWrapper function, FirstDerivativeWrapper first_derivative, Real x_ini,
128 Real & x_sol)
129 {
130 #define CMD "Optimist::ScalarRootFinder::Varona::solve(...): "
131
132 // Setup internal variables
133 this->reset();
134
135 // Print header
136 if (this->m_verbose) {this->header();}
137
138 // Initialize variables
139 bool damped;
140 Real residuals, step_norm;
141 Real x_old, x_new, function_old, function_new, step_old, step_new;
142 Real first_derivative_old;
143
144 // Set initial iteration
145 x_old = x_ini;
146 this->evaluate_function(function, x_old, function_old);
147
148 // Algorithm iterations
149 Real tolerance_residuals{this->m_tolerance};
150 Real tolerance_step_norm{this->m_tolerance * this->m_tolerance};
151 for (this->m_iterations = static_cast<Integer>(1); this->m_iterations < this->m_max_iterations; ++this->m_iterations)
152 {
153 // Store trace
154 this->store_trace(x_old);
155
156 // Evaluate first derivative
157 this->evaluate_first_derivative(first_derivative, x_old, first_derivative_old);
158
159 // Calculate step
160 if (std::abs(first_derivative_old) < EPSILON_LOW) {
161 OPTIMIST_WARNING( CMD "singular first derivative detected.");
162 first_derivative_old = (first_derivative_old > 0.0) ? EPSILON_LOW : -EPSILON_LOW;
163 }
164
165 this->compute_step(function, x_old, function_old, first_derivative_old, step_old);
166
167 // Check convergence
168 residuals = std::abs(function_old);
169 step_norm = std::abs(step_old);
170 if (this->m_verbose) {this->info(residuals);}
171 if (residuals < tolerance_residuals || step_norm < tolerance_step_norm) {
172 this->m_converged = true;
173 break;
174 }
175
176 if (this->m_damped) {
177 // Relax the iteration process
178 damped = this->damp(function, x_old, function_old, step_old, x_new, function_new, step_new);
179 OPTIMIST_ASSERT_WARNING(damped, CMD "damping failed.");
180 } else {
181 // Update point
182 x_new = x_old + step_old;
183 this->evaluate_function(function, x_new, function_new);
184 }
185
186 // Update internal variables
187 x_old = x_new;
188 function_old = function_new;
189 step_old = step_new;
190 }
191
192 // Print bottom
193 if (this->m_verbose) {this->bottom();}
194
195 // Convergence data
196 x_sol = x_old;
197 return this->m_converged;
198
199 #undef CMD
200 }
201
202 protected:
203
212 void compute_step(FunctionWrapper function, Real x_old, Real function_old, Real first_derivative_old,
213 Real & step_old)
214 {
215 Real function_y, function_z, function_w, function_h, step_tmp, t, s, u, v;
216 Real tolerance_residuals{this->m_tolerance};
217 //Real tolerance_step_norm{this->m_tolerance * this->m_tolerance};
218
219 // Base step
220 step_old = -function_old/first_derivative_old;
221
222 // Order 4 step
223 if (this->m_method == Method::ORDER_4 || this->m_method == Method::ORDER_8 ||
224 this->m_method == Method::ORDER_16 || this->m_method == Method::ORDER_32) {
225 this->evaluate_function(function, x_old+step_old, function_y);
226 if (std::abs(function_y) < tolerance_residuals) {return;}
227 t = function_y/function_old;
228 step_tmp = this->Q(t) * (function_y/first_derivative_old);
229 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
230 else {return;}
231 }
232
233 // Order 8 step (continued order 4)
234 if (this->m_method == Method::ORDER_8 || this->m_method == Method::ORDER_16 ||
235 this->m_method == Method::ORDER_32) {
236 this->evaluate_function(function, x_old+step_old, function_z);
237 if (std::abs(function_z) < tolerance_residuals) {return;}
238 s = function_z/function_y;
239 step_tmp = this->W(t, s) * (function_z/first_derivative_old);
240 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
241 else {return;}
242 }
243
244 // Order 16 step (continued order 8)
245 if (this->m_method == Method::ORDER_16 || this->m_method == Method::ORDER_32) {
246 this->evaluate_function(function, x_old+step_old, function_w);
247 if (std::abs(function_w) < tolerance_residuals) {return;}
248 u = function_w/function_z;
249 step_tmp = this->H(t, s, u) * (function_w/first_derivative_old);
250 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
251 else {return;}
252 }
253
254 // Order 32 step (continued order 16)
255 if (this->m_method == Method::ORDER_32) {
256 this->evaluate_function(function, x_old+step_old, function_h);
257 if (std::abs(function_h) < tolerance_residuals) {return;}
258 v = (function_h/function_w);
259 step_tmp = this->J(t, s, u, v) * (function_h/first_derivative_old);
260 if (std::isfinite(step_tmp)) {step_old -= step_tmp;}
261 else {return;}
262 }
263
264 OPTIMIST_ASSERT(std::isfinite(step_old),
265 "Optimist::ScalarRootFinder::Varona::compute_step(...): step is not finite.");
266 }
267
273 static Real Q(Real t) {return 1.0 + 2.0*t;}
274
281 static Real W(Real t, Real s) {return t*t*(1.0 - 4.0*t) + (4.0*s + 2.0)*t + s + 1.0;}
282
290 static Real H(Real t, Real s, Real u) {
291 Real t1{t*t};
292 Real t2{t1*t1};
293 Real t8{s*s};
294 Real t17{s*t8};
295 Real t23{2.0*u};
296 return
297 ((8.0*u + 6.0*t2 + 4.0)*s -
298 (6.0*t8 + 4.0*(s + u + 1.0))*t1 +
299 2.0*t8 - 4.0*t17 + t23 + 2.0)*t +
300 t1*(t8 + s + u + 1.0) +
301 (1.0 - 3.0*t2 + t23)*s +
302 u - t17 + 1.0;
303 }
304
313 static Real J(Real t, Real s, Real u, Real v) {
314 Real t1{s*s};
315 Real t2{t1*t1};
316 Real t17{t*t};
317 Real t22{u*u};
318 Real t32{t17*t17};
319 Real t34{t*t32};
320 Real t37{t*t17};
321 Real t46{1.0 + v};
322 Real t65{u + 1.0 + v};
323 Real t76{(-2.0*t22 + u + 4.0*v + 2.0)*u};
324 return
325 (-1.0 + 2.0*t)*(2.0 + 5.0*t)*u*t*t2 +
326 (4.0*t + 1.0)*u*s*t2 +
327 (u*t22 - 2.0*u*v - u - v - 1.0)*(4.0*t17 + 3.0*t + 1.0)*( - 1.0 + t) -
328 8.0*(t22*(t17/2.0 - 1.0/4.0) + u*(t17*t32 - 5.0/8.0*t34 - 3.0/4.0*t32 +
329 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 +
330 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) -
331 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 +
332 t76 + 4.0*(1.0 + v + t76)*t)*s;
333 }
334
335 }; // class Varona
336
337 } // namespace ScalarRootFinder
338
339} // namespace Optimist
340
341#endif // OPTIMIST_SCALAR_ROOT_FINDER_VARONA4_HH
#define OPTIMIST_WARNING(MSG)
Definition Optimist.hh:52
#define OPTIMIST_ASSERT_WARNING(COND, MSG)
Definition Optimist.hh:60
#define OPTIMIST_BASIC_CONSTANTS(Real)
Definition Optimist.hh:70
#define OPTIMIST_ASSERT(COND, MSG)
Definition Optimist.hh:43
#define CMD
typename ScalarRootFinder< Real, Varona< Real > >::SecondDerivativeWrapper SecondDerivativeWrapper
Definition Varona.hh:53
void enable_8th_order_method()
Definition Varona.hh:101
void set_method(Method t_method)
Definition Varona.hh:117
Varona()
Definition Varona.hh:63
static constexpr bool requires_second_derivative
Definition Varona.hh:45
typename ScalarRootFinder< Real, Varona< Real > >::FunctionWrapper FunctionWrapper
Definition Varona.hh:51
Method m_method
Definition Varona.hh:56
void enable_32th_order_method()
Definition Varona.hh:111
static constexpr bool requires_function
Definition Varona.hh:43
void enable_16th_order_method()
Definition Varona.hh:106
enum class Method :Integer {ORDER_4=41, ORDER_8=8, ORDER_16=16, ORDER_32=32} Method
Definition Varona.hh:50
bool solve_impl(FunctionWrapper function, FirstDerivativeWrapper first_derivative, Real x_ini, Real &x_sol)
Definition Varona.hh:127
Method method() const
Definition Varona.hh:85
static Real J(Real t, Real s, Real u, Real v)
Definition Varona.hh:313
void method(Method t_method)
Definition Varona.hh:91
static Real H(Real t, Real s, Real u)
Definition Varona.hh:290
typename ScalarRootFinder< Real, Varona< Real > >::FirstDerivativeWrapper FirstDerivativeWrapper
Definition Varona.hh:52
static Real Q(Real t)
Definition Varona.hh:273
void compute_step(FunctionWrapper function, Real x_old, Real function_old, Real first_derivative_old, Real &step_old)
Definition Varona.hh:212
std::string name_impl() const
Definition Varona.hh:69
static constexpr bool requires_first_derivative
Definition Varona.hh:44
void enable_4th_order_method()
Definition Varona.hh:96
static Real W(Real t, Real s)
Definition Varona.hh:281
void store_trace(const InputType &x)
Definition Solver.hh:750
void header()
Definition Solver.hh:799
void reset()
Definition Solver.hh:693
bool damp(FunctionWrapper function, InputType const &x_old, InputType const &function_old, InputType const &step_old, InputType &x_new, InputType &function_new, InputType &step_new)
Definition Solver.hh:763
void evaluate_first_derivative(FirstDerivativeWrapper function, const InputType &x, FirstDerivativeType &out)
Definition Solver.hh:724
void bottom()
Definition Solver.hh:829
void evaluate_function(FunctionWrapper function, const InputType &x, OutputType &out)
Definition Solver.hh:710
void info(Real residuals, std::string const &notes="-")
Definition Solver.hh:853
Integer m_iterations
Definition Solver.hh:85
Integer m_max_iterations
Definition Solver.hh:86
Namespace for the Optimist library.
Definition Optimist.hh:87
OPTIMIST_DEFAULT_INTEGER_TYPE Integer
The Integer type as used for the API.
Definition Optimist.hh:95