13namespace Stroika::Foundation::Math::Optimization::DownhillSimplexMinimization {
20 template <
typename FLOAT_TYPE>
21 Characters::String Options<FLOAT_TYPE>::ToString ()
const
23 Characters::StringBuilder sb;
26 sb <<
"Max-Iterations: "sv << fMaxIterations <<
","sv;
28 if (fNoImprovementThreshold) {
29 sb <<
"No-Improvement-Threshold: "sv << fNoImprovementThreshold;
40 template <
typename FLOAT_TYPE>
41 Characters::String Results<FLOAT_TYPE>::ToString ()
const
43 Characters::StringBuilder sb;
45 sb <<
"Optimized-Parameters: "sv << fOptimizedParameters <<
","sv;
46 sb <<
"Score: "sv << fScore <<
","sv;
47 sb <<
"Iteration-Count: "sv << fIterationCount;
58 using Containers::Sequence;
59 using namespace LinearAlgebra;
62 template <
typename FLOAT_TYPE>
63 Results<FLOAT_TYPE> nelder_mead_by_fchollet (
const TargetFunction<FLOAT_TYPE>& f,
const LinearAlgebra::Vector<FLOAT_TYPE>& x_start,
64 FLOAT_TYPE step = 0.1, FLOAT_TYPE no_improve_thr = 10e-6,
65 unsigned int no_improv_break = 10,
unsigned int max_iter = 0, FLOAT_TYPE alpha = 1,
66 FLOAT_TYPE gamma = 2, FLOAT_TYPE rho = -0.5, FLOAT_TYPE sigma = 0.5)
69 size_t dim = x_start.GetDimension ();
70 FLOAT_TYPE prev_best = f (x_start.GetItems ());
71 unsigned int no_improv = 0;
72 struct PartialResultType_ {
73 Sequence<FLOAT_TYPE> fResults;
78 vector<PartialResultType_> res{PartialResultType_{x_start.GetItems (), prev_best}};
79 for (
size_t i = 0; i != dim; ++i) {
80 Vector<FLOAT_TYPE> x = x_start;
82 FLOAT_TYPE score{f (x.GetItems ())};
83 res.push_back (PartialResultType_{x.GetItems (), score});
87 unsigned int iters = 0;
89 sort (res.begin (), res.end (), [] (
auto l,
auto r) { return l.fScore < r.fScore; });
90 FLOAT_TYPE best = res[0].fScore;
93 if (max_iter and iters >= max_iter) {
94 return Results<FLOAT_TYPE>{res[0].fResults, res[0].fScore, iters};
98#if Stroika_Foundation_Math_Optimization_DownhillSimplexMinimization_USE_NOISY_TRACE_IN_THIS_MODULE_
99 DbgTrace (
"...best so far (iteration {}): {}"_f, iters, best);
102 if (best < prev_best - no_improve_thr) {
109 if (no_improv >= no_improv_break) {
110 return Results<FLOAT_TYPE>{res[0].fResults, res[0].fScore, iters};
114 Vector<FLOAT_TYPE> x0{dim, 0.0};
116 auto removeLast = [] (
decltype (res) v) {
118 for (
auto i = v.begin (); i != v.end () and i + 1 != v.end (); ++i) {
123 for (
const PartialResultType_& tup : removeLast (res)) {
124 for (
size_t i = 0; i < x0.GetDimension (); ++i) {
125 FLOAT_TYPE c = Sequence<FLOAT_TYPE>{tup.fResults}[i];
126 x0[i] += c / (res.size () - 1);
132 Vector<FLOAT_TYPE> xr = x0 + alpha * (x0 - Vector<FLOAT_TYPE>{res[res.size () - 1].fResults});
133 FLOAT_TYPE rscore = f (xr.GetItems ());
135 if (res[0].fScore <= rscore and rscore < res[res.size () - 2].fScore) {
136 res[res.size () - 1] = PartialResultType_{xr.GetItems (), rscore};
143 if (rscore < res[0].fScore) {
144 Vector<FLOAT_TYPE> xe = x0 + gamma * (x0 - Vector<FLOAT_TYPE>{res[res.size () - 1].fResults});
145 FLOAT_TYPE escore = f (xe.GetItems ());
146 if (escore < rscore) {
147 res[res.size () - 1] = PartialResultType_{xe.GetItems (), escore};
150 res[res.size () - 1] = PartialResultType_{xr.GetItems (), rscore};
158 Vector<FLOAT_TYPE> xc = x0 + rho * (x0 - Vector<FLOAT_TYPE>{res[res.size () - 1].fResults});
159 FLOAT_TYPE cscore = f (xc.GetItems ());
160 if (cscore < res[res.size () - 1].fScore) {
161 res[res.size () - 1] = PartialResultType_{xc.GetItems (), cscore};
168 Vector<FLOAT_TYPE> x1 = res[0].fResults;
169 vector<PartialResultType_> nres;
170 for (
const PartialResultType_& tup : res) {
171 Vector<FLOAT_TYPE> redx = x1 + sigma * (Vector<FLOAT_TYPE>{tup.fResults} - x1);
172 FLOAT_TYPE score = f (redx.GetItems ());
173 res.push_back (PartialResultType_{redx.GetItems (), score});
179 return Results<FLOAT_TYPE>{};
182 template <
typename FLOAT_TYPE>
186#if Stroika_Foundation_Math_Optimization_DownhillSimplexMinimization_USE_NOISY_TRACE_IN_THIS_MODULE_
187 Debug::TraceContextBumper ctx{
"Optimization::DownhillSimplexMinimization::Run",
"initialValues={}, options={}"_f, initialValues, options};
190 FLOAT_TYPE step = 0.1;
191 FLOAT_TYPE no_improve_thr = options.fNoImprovementThreshold.value_or (10e-6);
192 unsigned int no_improv_break = 10;
193 unsigned int max_iter = options.fMaxIterations.value_or (0);
194 results = PRIVATE_::nelder_mead_by_fchollet<FLOAT_TYPE> (function2Minimize, initialValues, step, no_improve_thr, no_improv_break, max_iter);
195#if Stroika_Foundation_Math_Optimization_DownhillSimplexMinimization_USE_NOISY_TRACE_IN_THIS_MODULE_
196 DbgTrace (
"returns: {}"_f, results);
#define AssertNotReached()
Results< FLOAT_TYPE > Run(const TargetFunction< FLOAT_TYPE > &function2Minimize, const Sequence< FLOAT_TYPE > &initialValues, const Options< FLOAT_TYPE > &options=Options< FLOAT_TYPE >{})
Downhill Simplex Minimization, AKA Nelder-Mead algorithm, to compute minimization.
A generalization of a vector: a container whose elements are keyed by the natural numbers.