13namespace Stroika::Foundation::Math::Optimization::DownhillSimplexMinimization {
20 template <
typename FLOAT_TYPE>
21 Characters::String Options<FLOAT_TYPE>::ToString ()
const
23 Characters::StringBuilder sb;
25 sb <<
"maxIterations: "sv << fMaxIterations <<
", "sv;
26 sb <<
"noImprovementThreshold: "sv << fNoImprovementThreshold;
36 template <
typename FLOAT_TYPE>
37 Characters::String Results<FLOAT_TYPE>::ToString ()
const
39 Characters::StringBuilder sb;
41 sb <<
"Optimized-Parameters: "sv << fOptimizedParameters <<
","sv;
42 sb <<
"Score: "sv << fScore <<
","sv;
43 sb <<
"Iteration-Count: "sv << fIterationCount;
54 using Containers::Sequence;
55 using namespace LinearAlgebra;
58 template <
typename FLOAT_TYPE>
59 Results<FLOAT_TYPE> nelder_mead_by_fchollet (
const TargetFunction<FLOAT_TYPE>& f,
const LinearAlgebra::Vector<FLOAT_TYPE>& x_start,
60 FLOAT_TYPE step = 0.1, FLOAT_TYPE no_improve_thr = 10e-6,
61 unsigned int no_improv_break = 10,
unsigned int max_iter = 0, FLOAT_TYPE alpha = 1,
62 FLOAT_TYPE gamma = 2, FLOAT_TYPE rho = -0.5, FLOAT_TYPE sigma = 0.5)
65 size_t dim = x_start.GetDimension ();
66 FLOAT_TYPE prev_best = f (x_start.GetItems ());
67 unsigned int no_improv = 0;
68 struct PartialResultType_ {
69 Sequence<FLOAT_TYPE> fResults;
74 vector<PartialResultType_> res{PartialResultType_{x_start.GetItems (), prev_best}};
75 for (
size_t i = 0; i != dim; ++i) {
76 Vector<FLOAT_TYPE> x = x_start;
78 FLOAT_TYPE score{f (x.GetItems ())};
79 res.push_back (PartialResultType_{x.GetItems (), score});
83 unsigned int iters = 0;
85 sort (res.begin (), res.end (), [] (
auto l,
auto r) { return l.fScore < r.fScore; });
86 FLOAT_TYPE best = res[0].fScore;
89 if (max_iter and iters >= max_iter) {
90 return Results<FLOAT_TYPE>{res[0].fResults, res[0].fScore, iters};
94#if Stroika_Foundation_Math_Optimization_DownhillSimplexMinimization_USE_NOISY_TRACE_IN_THIS_MODULE_
95 DbgTrace (
"...best so far (iteration {}): {}"_f, iters, best);
98 if (best < prev_best - no_improve_thr) {
105 if (no_improv >= no_improv_break) {
106 return Results<FLOAT_TYPE>{res[0].fResults, res[0].fScore, iters};
110 Vector<FLOAT_TYPE> x0{dim, 0.0};
112 auto removeLast = [] (
decltype (res) v) {
114 for (
auto i = v.begin (); i != v.end () and i + 1 != v.end (); ++i) {
119 for (
const PartialResultType_& tup : removeLast (res)) {
120 for (
size_t i = 0; i < x0.GetDimension (); ++i) {
121 FLOAT_TYPE c = Sequence<FLOAT_TYPE>{tup.fResults}[i];
122 x0[i] += c / (res.size () - 1);
128 Vector<FLOAT_TYPE> xr = x0 + alpha * (x0 - Vector<FLOAT_TYPE>{res[res.size () - 1].fResults});
129 FLOAT_TYPE rscore = f (xr.GetItems ());
131 if (res[0].fScore <= rscore and rscore < res[res.size () - 2].fScore) {
132 res[res.size () - 1] = PartialResultType_{xr.GetItems (), rscore};
139 if (rscore < res[0].fScore) {
140 Vector<FLOAT_TYPE> xe = x0 + gamma * (x0 - Vector<FLOAT_TYPE>{res[res.size () - 1].fResults});
141 FLOAT_TYPE escore = f (xe.GetItems ());
142 if (escore < rscore) {
143 res[res.size () - 1] = PartialResultType_{xe.GetItems (), escore};
146 res[res.size () - 1] = PartialResultType_{xr.GetItems (), rscore};
154 Vector<FLOAT_TYPE> xc = x0 + rho * (x0 - Vector<FLOAT_TYPE>{res[res.size () - 1].fResults});
155 FLOAT_TYPE cscore = f (xc.GetItems ());
156 if (cscore < res[res.size () - 1].fScore) {
157 res[res.size () - 1] = PartialResultType_{xc.GetItems (), cscore};
164 Vector<FLOAT_TYPE> x1 = res[0].fResults;
165 vector<PartialResultType_> nres;
166 for (
const PartialResultType_& tup : res) {
167 Vector<FLOAT_TYPE> redx = x1 + sigma * (Vector<FLOAT_TYPE>{tup.fResults} - x1);
168 FLOAT_TYPE score = f (redx.GetItems ());
169 res.push_back (PartialResultType_{redx.GetItems (), score});
175 return Results<FLOAT_TYPE>{};
178 template <
typename FLOAT_TYPE>
182#if Stroika_Foundation_Math_Optimization_DownhillSimplexMinimization_USE_NOISY_TRACE_IN_THIS_MODULE_
183 Debug::TraceContextBumper ctx{
"Optimization::DownhillSimplexMinimization::Run",
"initialValues={}, options={}"_f, initialValues, options};
186 FLOAT_TYPE step = 0.1;
187 FLOAT_TYPE no_improve_thr = options.fNoImprovementThreshold;
188 unsigned int no_improv_break = 10;
190 results = PRIVATE_::nelder_mead_by_fchollet<FLOAT_TYPE> (function2Minimize, initialValues, step, no_improve_thr, no_improv_break, max_iter);
191#if Stroika_Foundation_Math_Optimization_DownhillSimplexMinimization_USE_NOISY_TRACE_IN_THIS_MODULE_
192 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.
unsigned int fMaxIterations