Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
PatternSearch.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_OPTIMIZER_HJ_PATTERN_SEARCH_HH
14#define OPTIMIST_OPTIMIZER_HJ_PATTERN_SEARCH_HH
15
16#include "Optimist/Optimizer.hh"
17
18namespace Optimist {
19 namespace Optimizer {
20
21 /*\
22 | ____ _ _ ____ _
23 | | _ \ __ _| |_| |_ ___ _ __ _ __ / ___| ___ __ _ _ __ ___| |__
24 | | |_) / _` | __| __/ _ \ '__| '_ \\___ \ / _ \/ _` | '__/ __| '_ \
25 | | __/ (_| | |_| || __/ | | | | |___) | __/ (_| | | | (__| | | |
26 | |_| \__,_|\__|\__\___|_| |_| |_|____/ \___|\__,_|_| \___|_| |_|
27 |
28 \*/
29
36 template <typename Real, Integer N>
38 : public Optimizer<Real, N, PatternSearch<Real, N>, true> {
39 public:
40 static constexpr bool RequiresFunction{true};
41 static constexpr bool RequiresFirstDerivative{false};
42 static constexpr bool RequiresSecondDerivative{false};
43
44 using typename Optimizer<Real, N, PatternSearch<Real, N>, true>::Vector;
45 using typename Optimizer<Real, N, PatternSearch<Real, N>, true>::Matrix;
46
47 using Simplex = std::vector<Vector>;
48
49 private:
50 Real m_rho{0.9}; // stencil step decreasing factor (must be 0 < rho < 1)
51 Real m_h{0.1};
52 bool m_stencil_failure{false}; // stencil failure flag - used to shrink
53 // h, stencil_failure = true means failure
54
55 public:
60
65 constexpr std::string name_impl() const {
66 return "PatternSearch";
67 }
68
69 void set_max_num_stagnation(integer nstg) {
70 UTILS_ASSERT(nstg > 0,
71 "set_max_num_stagnation({}) argument must be >0\n",
72 nstg);
73 m_max_num_stagnation = nstg;
74 }
75
76 // SEARCH This method call the explore method on the first
77 // iteration and then continue to call explore until a stencil
78 // fails. In the case of a stencil failure, it tries once to go
79 // back of half a step along the search direction by setting x_center
80 // equal to the base point x_best.
81 // If the stencil fails again, it exits the while loop and stencil_failure
82 // is set to zero in order to signal that a reduction of h is necessary.
83 void search() {
84 ++m_iteration_count; // augment counter
85
86 this->best_nearby();
87
88 while (m_stencil_failure) {
89 // reduce the scale
90 m_h *= m_rho;
91 this->best_nearby();
92 if (m_h <= m_tolerance)
93 return;
94 if (m_fun_evaluation_count >= m_max_fun_evaluation)
95 return;
96 }
97
98 search_dir.noalias() = x_best - x_old; // Compute search direction
99
100 // Continue exploring until stencil failure or exceed of
101 Real lambda = 1;
102 Real max_der = 0;
103 while (m_fun_evaluation_count < m_max_fun_evaluation && lambda > 0.1) {
104 x_new.noalias() = x_best + lambda * search_dir;
105 Real new_f = eval_function(x_new);
106 if (new_f < f_best - (0.25 * lambda) * max_der) {
107 Real der = (f_best - new_f) / lambda;
108 if (der > max_der)
109 max_der = der;
110 x_best.noalias() = x_new;
111 f_best = new_f;
112 // lambda *= 2;
113 }
114 lambda *= 0.5;
115 }
116 }
117
118 // This method explore all points on the stencil center at
119 // x_temporary = x_center and updates the current iteration x to the
120 // current best point x_current_best. If the current best point
121 // x_current_best is worse than the base point x_best, the current
122 // iteration x will remain constant (x = x_best) and stencil failure flag
123 // stencil_failure will be set to zero.
124 void best_nearby() {
125 /*
126 */
127 // Initialize
128 m_stencil_failure = true;
129
130 // Cycle on all stencil directions
131
132 for (integer j = 0; j < N; ++j) {
133 Real s_dirh = search_sign(j) * m_h;
134 m_p.noalias() = x_best;
135 m_p(j) += s_dirh;
136 Real fp = eval_function(m_p);
137 if (fp >= f_best) {
138 m_p1.noalias() = x_best;
139 m_p1(j) -= s_dirh; // try the opposite direction
140 Real fp1 = eval_function(m_p1);
141 if (fp1 < fp) {
142 m_p.noalias() = m_p1;
143 fp = fp1;
144 // change priority of search direction to the opposite verse
145 search_sign(j) = -search_sign(j);
146 }
147 }
148 // Update temporary and current best point before checking
149 // the remaining directions j
150 if (fp < f_best) {
151 x_best.noalias() = m_p; // move temporary point
152 f_best = fp; // new current best point
153 m_stencil_failure = false; // update stencil failure flag
154 }
155 }
156 }
157
168 template <typename FunctionLambda>
169 bool solve_impl(FunctionLambda &&function,
170 const Vector &x_ini,
171 Vector &x_sol) {
172 // Reset internal variables
173 this->reset_counters();
174 this->m_stencil_failure = false;
175
176 // Print header
177 if (this->m_verbose) {
178 this->header();
179 }
180
181 // Set initial iteration
182 Vector x_best(x_ini);
183 Real f_best;
184 bool success{
185 this->evaluate_function(std::forward<FunctionLambda>(function),
186 x_best,
187 f_best)};
188 UTILS_ASSERT(success,
189 "Optimist::Optimizer::PatternSearch::solve(...): "
190 "function evaluation failed at the initial point.");
191 search_sign
192 .setOnes(); // First direction will be positive for each direction
193 this->m_h = h;
194
195 // Algorithm iterations
196 integer stagnations{0};
197 for (this->m_iterations = 0;
198 this->m_iterations < this->m_max_iterations;
199 ++this->m_iterations) {
200 x_old = x_best;
201 f_old = f_best;
202
203 this->search();
204 if (this->m_stencil_failure) {
205 break;
206 }
207
208 // Check convergence
209 if (this->m_verbose) {
210 this->info(residuals);
211 }
212 if (this->m_h < this->m_tolerance) {
213 this->m_converged = true;
214 break;
215 }
216
217 // Reduce the scale
218 this->m_h *= this->m_rho;
219
220 // Check for stagnation
221 if (f_old <= f_best) {
222 ++stagnations;
223 if (stagnations > this->m_max_stagnations) {
224 break;
225 }
226 } else {
227 stagnations = 0;
228 }
229 }
230
231 // Print bottom
232 if (this->m_verbose) {
233 this->bottom();
234 }
235
236 // Convergence data
237 x_sol = return this->m_converged;
238 }
239
240 }; // class PatternSearch
241
242 } // namespace Optimizer
243
244} // namespace Optimist
245
246#endif // OPTIMIST_OPTIMIZER_HJ_PATTERN_SEARCH_HH
Class container for the multi-dimensional optimizer.
Definition Optimizer.hh:46
static constexpr bool RequiresFunction
Definition PatternSearch.hh:40
std::vector< Vector > Simplex
Definition PatternSearch.hh:47
bool m_stencil_failure
Definition PatternSearch.hh:52
Real m_rho
Definition PatternSearch.hh:50
void search()
Definition PatternSearch.hh:83
void set_max_num_stagnation(integer nstg)
Definition PatternSearch.hh:69
static constexpr bool RequiresSecondDerivative
Definition PatternSearch.hh:42
constexpr std::string name_impl() const
Definition PatternSearch.hh:65
void best_nearby()
Definition PatternSearch.hh:124
static constexpr bool RequiresFirstDerivative
Definition PatternSearch.hh:41
Real m_h
Definition PatternSearch.hh:51
PatternSearch()
Definition PatternSearch.hh:59
bool solve_impl(FunctionLambda &&function, const Vector &x_ini, Vector &x_sol)
Definition PatternSearch.hh:169
void info(Scalar residuals, const std::string &notes="-")
Definition SolverBase.hh:1232
bool evaluate_function(FunctionLambda &&function, const Real &x, TypeTrait< Real >::Scalar &out)
Definition SolverBase.hh:1040
Integer m_max_iterations
Definition SolverBase.hh:121
void reset_counters()
Definition SolverBase.hh:1022
Integer m_iterations
Definition SolverBase.hh:120
Namespace for the Optimist library.
Definition Optimist.hh:90