Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
NelderMead.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_OPTIMIZER_NELDER_MEAD_HH
14#define OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
15
16#include "Optimist/Optimizer.hh"
17
18namespace Optimist
19{
20 namespace Optimizer
21 {
22
23 /*\
24 | _ _ _ _ __ __ _
25 | | \ | | ___| | __| | ___ _ __| \/ | ___ __ _ __| |
26 | | \| |/ _ \ |/ _` |/ _ \ '__| |\/| |/ _ \/ _` |/ _` |
27 | | |\ | __/ | (_| | __/ | | | | | __/ (_| | (_| |
28 | |_| \_|\___|_|\__,_|\___|_| |_| |_|\___|\__,_|\__,_|
29 |
30 \*/
31
32
41 template <typename Real, Integer N>
42 class NelderMead : public Optimizer<Real, N, NelderMead<Real, N>>
43 {
44 public:
45 static constexpr bool requires_function{true};
46 static constexpr bool requires_first_derivative{false};
47 static constexpr bool requires_second_derivative{false};
48
51
52 using Simplex = std::vector<Vector>;
53
54 private:
57 Real m_alpha{1.0};
58 Real m_gamma{2.0};
59 Real m_rho{0.5};
60 Real m_sigma{0.5};
61
62 public:
67 this->m_s.reserve(N+1);
68 }
69
74 std::string name_impl() const {return "NelderMead";}
75
81 void initialize(Vector const & x_ini, Real delta)
82 {
83 this->m_s.clear();
84 this->m_s.push_back(x_ini);
85 Vector x;
86 for (Integer i{0}; i < N; ++i) {
87 x = x_ini;
88 x(i) += delta;
89 this->m_s.push_back(x);
90 }
91 this->m_c = this->centroid();
92 }
93
99 {
100 return std::accumulate(this->m_s.begin(), this->m_s.end(), this->m_c) / N;
101 }
102
108 template <typename FunctionLambda>
109 void sort(FunctionLambda && function)
110 {
111 std::sort(this->m_s.begin(), this->m_s.end(),
112 [function, this] (Vector const & a, Vector const & b) {
113 Real function_a, function_b;
114 this->evaluate_function(std::forward<FunctionLambda>(function), a, function_a);
115 this->evaluate_function(std::forward<FunctionLambda>(function), b, function_b);
116 return function_a < function_b;
117 }
118 );
119 this->m_c = this->centroid();
120 }
121
127 {
128 return this->m_c + this->m_alpha * (this->m_c - this->m_s.back());
129 }
130
136 Vector expansion(Vector const & x) const
137 {
138 return this->m_c + this->m_gamma * (x - this->m_c);
139 }
140
147 {
148 return this->m_c + this->m_rho * (x - this->m_c);
149 }
150
156 {
157 return this->m_c + this->m_rho * (this->m_s.back() - this->m_c);
158 }
159
163 void shrink()
164 {
165 for (Integer i{1}; i < static_cast<Integer>(this->m_s.size()); ++i) {
166 this->m_s.at(i) = this->m_s.at(1) + this->m_sigma * (this->m_s.at(i) - this->m_s.at(1));
167 }
168 }
169
179 bool solve_impl(FunctionLambda && function, Vector const & x_ini, Vector & x_sol)
180 {
181 // Setup internal variables
182 this->reset();
183
184 // Print header
185 if (this->m_verbose) {this->header();}
186
187 // Initialize variables
188 Vector x_r, x_c, x_e, simplex_size;
189 Real function_x_r, function_x_1, function_x_last, function_x_e, function_x_c;
190
191 // Set initial iteration
192 this->initialize(x_ini, 100.0);
193
194 // Algorithm iterations
195 for (this->m_iterations = 1; this->m_iterations < this->m_max_iterations; ++this->m_iterations)
196 {
197 // Sort the simplex points based on the function values
198 this->sort(function);
199
200 // Store trace
201 this->store_trace(this->m_s.back());
202
203 // Compute the reflection point
204 x_r = this->reflection();
205 this->evaluate_function(std::forward<FunctionLambda>(function), x_r, function_x_r);
206 this->evaluate_function(std::forward<FunctionLambda>(function), this->m_s.at(1), function_x_1);
207 this->evaluate_function(std::forward<FunctionLambda>(function), this->m_s.back(), function_x_last);
208
209 if (function_x_1 <= function_x_r && function_x_r < function_x_last)
210 {
211 this->m_s.back() = x_r;
212 if (this->m_verbose) {this->info(function_x_1, "Reflection");}
213 }
214 else if (function_x_r < function_x_1)
215 {
216 // Expansion
217 x_e = this->expansion(x_r);
218 this->evaluate_function(std::forward<FunctionLambda>(function), x_e, function_x_e);
219 if (function_x_e < function_x_r) {
220 this->m_s.back() = x_e;
221 } else {
222 this->m_s.back() = x_r;
223 }
224 if (this->m_verbose) {this->info(function_x_1, "Expansion");}
225 }
226 else if (function_x_r < function_x_last)
227 {
228 // Outward contraction
229 x_c = this->outward_contraction(x_r);
230 this->evaluate_function(std::forward<FunctionLambda>(function), x_c, function_x_c);
231 if (function_x_c < function_x_r) {
232 this->m_s.back() = x_c;
233 } else {
234 this->shrink();
235 }
236 if (this->m_verbose) {this->info(function_x_1, "Outward contraction");}
237 }
238 else
239 {
240 // Inward contraction
241 x_c = this->inward_contraction();
242 this->evaluate_function(std::forward<FunctionLambda>(function), x_c, function_x_c);
243 if (function_x_c < function_x_last) {
244 this->m_s.back() = x_c;
245 } else {
246 this->shrink();
247 }
248 if (this->m_verbose) {this->info(function_x_1, "Inward contraction");}
249 }
250 simplex_size = this->m_s.back() - this->m_s.front();
251 if (simplex_size.norm() < this->m_tolerance) {
252 this->m_converged = true;
253 break;
254 }
255 }
256
257 // Print bottom
258 if (this->m_verbose) {this->bottom();}
259
260 // Convergence data
261 x_sol = this->m_s.at(0);
262 return this->m_converged;
263 }
264
265 }; // class NelderMead
266
267 } // namespace Optimizer
268
269} // namespace Optimist
270
271#endif // OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
bool solve_impl(FunctionLambda &&function, Vector const &x_ini, Vector &x_sol)
Definition NelderMead.hh:179
Vector inward_contraction() const
Definition NelderMead.hh:155
static constexpr bool requires_first_derivative
Definition NelderMead.hh:46
Vector expansion(Vector const &x) const
Computes the expansion point.
Definition NelderMead.hh:136
void initialize(Vector const &x_ini, Real delta)
Definition NelderMead.hh:81
Simplex m_s
Definition NelderMead.hh:55
Real m_gamma
Definition NelderMead.hh:58
std::string name_impl() const
Definition NelderMead.hh:74
Real m_sigma
Definition NelderMead.hh:60
Vector centroid() const
Definition NelderMead.hh:98
void sort(FunctionLambda &&function)
Definition NelderMead.hh:109
NelderMead()
Definition NelderMead.hh:66
Real m_alpha
Definition NelderMead.hh:57
Vector m_c
Definition NelderMead.hh:56
static constexpr bool requires_second_derivative
Definition NelderMead.hh:47
Vector outward_contraction(Vector const &x) const
Definition NelderMead.hh:146
Vector reflection() const
Computes the reflection point.
Definition NelderMead.hh:126
Real m_rho
Definition NelderMead.hh:59
std::vector< Vector > Simplex
Definition NelderMead.hh:52
static constexpr bool requires_function
Definition NelderMead.hh:45
void shrink()
Definition NelderMead.hh:163
Class container for the multi-dimensional optimizer.
Definition Optimizer.hh:47
typename SolverBase< Real, N, 1, NelderMead< Real, N >, false >::InputType Vector
Definition Optimizer.hh:60
typename SolverBase< Real, N, 1, NelderMead< Real, N >, false >::SecondDerivativeType Matrix
Definition Optimizer.hh:64
void info(Real residuals, std::string const &notes="-")
Definition SolverBase.hh:924
void store_trace(InputType const &x)
Definition SolverBase.hh:813
bool evaluate_function(FunctionLambda &&function, InputType const &x, OutputType &out)
Definition SolverBase.hh:768
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