Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
FiniteDifferences.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_FINITE_DIFFERENCES_HH
14#define OPTIMIST_FINITE_DIFFERENCES_HH
15
16#include "Optimist.hh"
17
18namespace Optimist {
19
21
26 template<typename Real>
27 class Epsilon {
29 Real m_epsilon_1{std::sqrt(EPSILON)};
30 Real m_epsilon_2{std::pow(EPSILON, 0.75)};
31 Real m_epsilon_3{std::pow(EPSILON, 0.25)};
32 public:
33
35 Real epsilon_1(Real const v) const {return (std::abs(v) + 1.0)*this->m_epsilon_1;}
36
38 Real epsilon_2(Real const v) const {return (std::abs(v) + 1.0)*this->m_epsilon_2;}
39
41 Real epsilon_3(Real const v) const {return (std::abs(v) + 1.0)*this->m_epsilon_3;}
42 };
43
44
55 template<typename Real>
56 inline Real SideFiniteDifferences(Real const f_0, Real const f_1, Real const f_2, Real h_1,
57 Real h_2)
58 {
59 Real d_f_1{f_1 - f_0};
60 Real d_f_2{f_2 - f_0};
61 Real d_h{h_1 - h_2};
62 return ((h_1/h_2)*d_f_2 - (h_2/h_1)*d_f_1) / d_h;
63 }
64
74 template<typename Real>
75 inline Real CenteredFiniteDifferences(Real const f_l, Real const f_c, Real const f_r, Real h)
76 {
77 constexpr Real EPSILON{std::numeric_limits<Real>::epsilon()};
78 Real diff_r{(f_r-f_c)/h};
79 Real diff_l{(f_c-f_l)/h};
80 Real weight_r{std::abs(diff_r) + EPSILON};
81 Real weight_l{std::abs(diff_l) + EPSILON};
82 Real weight_max{std::max(weight_r, weight_l)};
83 weight_r = std::sqrt(weight_r/weight_max);
84 weight_l = std::sqrt(weight_l/weight_max);
85 return (diff_r*weight_l + diff_l*weight_r) / (weight_r+weight_l);
86 }
87
99 template<typename Vector, typename Real = typename Vector::Scalar>
100 inline Vector SideFiniteDifferences(Vector const & f_0, Vector const & f_1,
101 Vector const & f_2, Real h_1, Real h_2)
102 {
103 Real d_h{h_1-h_2}, t_1{-(h_2/h_1)/d_h}, t_2{(h_1/h_2)/d_h};
104 return t_1*(f_1-f_0) + t_2*(f_2-f_0);
105 }
106
117 template<typename Vector, typename Real = typename Vector::Scalar>
118 inline Vector CenteredFiniteDifferences(Vector const & f_l, Vector const & f_c, Vector const & f_r,
119 Real h)
120 {
121 constexpr Real EPSILON{std::numeric_limits<Real>::epsilon()};
122 Vector diff_r((f_r - f_c) / h);
123 Vector diff_l((f_c - f_l) / h);
124 Vector weight_r(diff_r.array().abs() + EPSILON);
125 Vector weight_l(diff_l.array().abs() + EPSILON);
126 Vector weight_max(weight_r.array().max(weight_l.array()));
127 weight_r = (weight_r.array()/weight_max.array()).sqrt();
128 weight_l = (weight_l.array()/weight_max.array()).sqrt();
129 return (diff_r.array()*weight_l.array() + diff_l.array()*weight_r.array()) / (weight_r.array()+weight_l.array());
130 }
131
142 template <typename Function, typename Vector, typename Real = typename Vector::Scalar>
143 bool Gradient(Vector const & x, Function && function, Vector & out)
144 {
145 Epsilon<Real> eps;
146 Real v_c{0.0};
147 if (!function(x, v_c) || !std::isfinite(v_c)) {return false;}
148 Eigen::Index dim_x{x.size()};
149 out.resize(dim_x);
150 out.setZero();
151 for (Eigen::Index i{0}; i < dim_x; ++i) {
152 Vector v_x(x);
153 Real tmp{x[i]}, h_1{eps.epsilon_1(tmp)}, h_2{eps.epsilon_2(tmp)};
154 v_x[i] = tmp + h_1; Real v_r{0.0}; bool is_finite_r{function(v_x, v_r) && std::isfinite(v_r)};
155 v_x[i] = tmp - h_1; Real v_l{0.0}; bool is_finite_l{function(v_x, v_l) && std::isfinite(v_l)};
156 Integer ic{(is_finite_r && is_finite_l) ? 0 : (is_finite_r ? 1 : (is_finite_l ? -1 : -2))};
157 switch (ic) {
158 case 0:
159 out[i] = CenteredFiniteDifferences(v_l, v_c, v_r, h_1);
160 break;
161 case 1: {
162 v_x[i] = tmp + h_2; Real v_rr{0.0}; bool is_finite_rr{function(v_x, v_rr) && std::isfinite(v_rr)};
163 out[i] = is_finite_rr ? SideFiniteDifferences(v_c, v_r, v_rr, h_1, h_2) : (v_r-v_c)/h_1;
164 break;
165 }
166 case -1: {
167 v_x[i] = tmp - h_2; Real v_ll{0.0}; bool is_finite_ll{function(v_x, v_ll) && std::isfinite(v_ll)};
168 out[i] = is_finite_ll ? SideFiniteDifferences(v_c, v_l, v_ll, -h_1, -h_2) : (v_c-v_l)/h_1;
169 break;
170 }
171 case -2: {
172 out[i] = 0.0;
173 return false;
174 }
175 }
176 }
177 return out.allFinite();
178 }
179
191 template <typename Function, typename Vector, typename Matrix, typename Real = typename Vector::Scalar>
192 bool Jacobian(Vector const & x, Function && function, Matrix & out)
193 {
194 Epsilon<Real> eps;
195 Vector v_c;
196 if (!function(x, v_c) || !v_c.allFinite()) {return false;}
197 Eigen::Index dim_x{x.size()};
198 out.resize(dim_x, dim_x);
199 out.setZero();
200 for (Eigen::Index j{0}; j < dim_x; ++j) {
201 Vector v_x(x);
202 Real tmp{x[j]}, h_1{eps.epsilon_1(tmp)}, h_2{eps.epsilon_2(tmp)};
203 v_x[j] = tmp + h_1; Vector v_r; bool is_finite_r{function(v_x, v_r) && v_r.allFinite()};
204 v_x[j] = tmp - h_1; Vector v_l; bool is_finite_l{function(v_x, v_l) && v_l.allFinite()};
205 Integer ic{(is_finite_r && is_finite_l) ? 0 : (is_finite_r ? 1 : (is_finite_l ? -1 : -2))};
206 switch (ic) {
207 case 0:
208 out.col(j) = CenteredFiniteDifferences(v_l, v_c, v_r, h_1);
209 break;
210 case 1: {
211 v_x[j] = tmp + h_2; Vector v_rr; bool is_finite_rr{function(v_x, v_rr) && v_rr.allFinite()};
212 out.col(j) = is_finite_rr ? SideFiniteDifferences(v_c, v_r, v_rr, h_1, h_2) : (v_r-v_c)/h_1;
213 break;
214 }
215 case -1: {
216 v_x[j] = tmp - h_2; Vector v_ll; bool is_finite_ll{function(v_x, v_ll) && v_ll.allFinite()};
217 out.col(j) = is_finite_ll ? SideFiniteDifferences(v_c, v_l, v_ll, -h_1, -h_2) : (v_c-v_l)/h_1;
218 break;
219 }
220 case -2: {
221 out.col(j).setZero();
222 return false;
223 }
224 }
225 }
226 return out.allFinite();
227 }
228
240 template <typename Function, typename Vector, typename Matrix, typename Real = typename Vector::Scalar>
241 bool Hessian(Vector const & x, Function && function, Matrix & out)
242 {
244 Eigen::Index dim_x{x.size()};
245 out.resize(dim_x, dim_x);
246 out.setZero();
247 Real fc{0.0};
248 if (!function(x, fc) || !std::isfinite(fc)) {return false;}
249 for (Eigen::Index j{0}; j < dim_x; ++j) {
250 Real tmp_j{x[j]}, h_j{eps.epsilon_3(tmp_j)};
251 Vector v_x(x);
252 v_x[j] = tmp_j + h_j; Real fp; if (!function(v_x, fp) || !std::isfinite(fp)) {return false;}
253 v_x[j] = tmp_j - h_j; Real fm; if (!function(v_x, fm) || !std::isfinite(fm)) {return false;}
254 out(j, j) = ((fp + fm) - 2.0 * fc) / (h_j * h_j);
255 for (Eigen::Index i{j + 1}; i < dim_x; ++i) {
256 Real tmp_i{x[i]}, h_i{eps.epsilon_3(tmp_i)};
257 v_x[i] = tmp_i + h_i;
258 v_x[j] = tmp_j + h_j; Real fpp; if (!function(v_x, fpp) || !std::isfinite(fpp)) {return false;}
259 v_x[i] = tmp_i - h_i; Real fmp; if (!function(v_x, fmp) || !std::isfinite(fmp)) {return false;}
260 v_x[j] = tmp_j - h_j; Real fmm; if (!function(v_x, fmm) || !std::isfinite(fmm)) {return false;}
261 v_x[i] = tmp_i + h_i; Real fpm; if (!function(v_x, fpm) || !std::isfinite(fpm)) {return false;}
262 Real h_ij{4.0 * h_i * h_j}, value{((fpp + fmm) - (fpm + fmp)) / h_ij};
263 out(j, i) = out(i, j) = value;
264 v_x[i] = tmp_i;
265 }
266 v_x[j] = tmp_j;
267 }
268 return out.allFinite();
269 }
270
271 } // namespace FiniteDifferences
272
273} // namespace Optimist
274
275#endif // OPTIMIST_FINITE_DIFFERENCES_HH
#define OPTIMIST_BASIC_CONSTANTS(Real)
Definition Optimist.hh:71
Definition FiniteDifferences.hh:27
Real m_epsilon_3
Definition FiniteDifferences.hh:31
Real m_epsilon_1
Definition FiniteDifferences.hh:29
Real epsilon_3(Real const v) const
Definition FiniteDifferences.hh:41
Real epsilon_2(Real const v) const
Definition FiniteDifferences.hh:38
Real m_epsilon_2
Definition FiniteDifferences.hh:30
Real epsilon_1(Real const v) const
Definition FiniteDifferences.hh:35
Class container for the vector-valued function.
Definition Function.hh:190
Definition FiniteDifferences.hh:20
bool Gradient(Vector const &x, Function &&function, Vector &out)
Definition FiniteDifferences.hh:143
Real SideFiniteDifferences(Real const f_0, Real const f_1, Real const f_2, Real h_1, Real h_2)
Definition FiniteDifferences.hh:56
bool Jacobian(Vector const &x, Function &&function, Matrix &out)
Definition FiniteDifferences.hh:192
bool Hessian(Vector const &x, Function &&function, Matrix &out)
Definition FiniteDifferences.hh:241
Real CenteredFiniteDifferences(Real const f_l, Real const f_c, Real const f_r, Real h)
Definition FiniteDifferences.hh:75
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