5#ifndef GRAMODS_MISC_NELDERMEAD
6#define GRAMODS_MISC_NELDERMEAD
8#include <gmMisc/config.hh>
9#include <gmCore/Console.hh>
17template<
class TYPE_OUT,
class TYPE_IN>
20 NelderMead(std::function<TYPE_OUT(
const TYPE_IN &X)> F) : function(F) {}
22 TYPE_IN solve(
const std::vector<TYPE_IN> &X0,
size_t &iterations);
24 std::function<TYPE_OUT(
const TYPE_IN &X)> function;
25 TYPE_OUT epsilon = std::numeric_limits<TYPE_OUT>::epsilon();
31 std::function<TYPE_IN(
const std::vector<std::pair<TYPE_OUT, TYPE_IN>> &F_X)>
33 [](
const std::vector<std::pair<TYPE_OUT, TYPE_IN>> &F_X) -> TYPE_IN {
34 auto factor = 1.f / (F_X.size() - 1.f);
35 TYPE_IN Xm = F_X.front().second * factor;
36 for (
size_t idx = 1; idx < F_X.size() - 1; idx++) {
37 Xm = Xm + F_X[idx].second * factor;
45 std::function<TYPE_IN(
const TYPE_IN &Xm,
const TYPE_IN &Xn)> func_reflect =
46 [](
const TYPE_IN &Xm,
const TYPE_IN Xn) -> TYPE_IN {
53 std::function<TYPE_IN(
const TYPE_IN &XA,
const TYPE_IN &XB)> func_mean =
54 [](
const TYPE_IN &XA,
const TYPE_IN XB) -> TYPE_IN {
55 return XA * 0.5f + XB * 0.5f;
59template<
class TYPE_OUT,
class TYPE_IN>
60TYPE_IN NelderMead<TYPE_OUT, TYPE_IN>::solve(
const std::vector<TYPE_IN> &X0,
63 const size_t N = X0.size();
67 std::vector<std::pair<TYPE_OUT, TYPE_IN>> F_X;
69 for (
const auto &X : X0) F_X.push_back({function(X), X});
72 size_t count_reflect = 0;
73 size_t count_expand = 0;
74 size_t count_contract_in = 0;
75 size_t count_contract_out = 0;
76 size_t count_shrink = 0;
80 if (iterations > 0 && iteration > iterations) {
82 "Termination by iteration limits ("
83 << iterations <<
") after "
84 << count_reflect <<
" reflect, "
85 << count_expand <<
" expand, "
86 << count_contract_in <<
"/"
87 << count_contract_out <<
" contract in/out, and "
88 << count_shrink <<
" shrink.");
89 return F_X.front().second;
93 std::sort(F_X.begin(),
95 [](
const std::pair<TYPE_OUT, TYPE_IN> &a,
96 const std::pair<TYPE_OUT, TYPE_IN> &b) {
97 return a.first < b.first;
101 TYPE_IN Xm = func_midpoint(F_X);
104 TYPE_IN Xr = func_reflect(Xm, F_X.back().second);
105 TYPE_OUT Fr = function(Xr);
107 if (F_X.front().first <= Fr && Fr < F_X[N - 2].first) {
109 F_X.push_back({Fr, Xr});
111 GM_DBG3(
"NelderMead",
"Reflect (" << Fr <<
")");
117 if (Fr < F_X.front().first) {
119 TYPE_IN Xe = func_reflect(Xr, Xm);
120 TYPE_OUT Fe = function(Xe);
122 TYPE_IN Xn = Fe < Fr ? Xe : Xr;
123 TYPE_OUT Fn = Fe < Fr ? Fe : Fr;
126 F_X.push_back({Fn, Xn});
128 GM_DBG3(
"NelderMead",
"Expand (" << Fn <<
")");
135 if (Fr < F_X.back().first) {
136 TYPE_IN Xc = func_mean(Xr, Xm);
137 TYPE_OUT Fc = function(Xc);
141 F_X.push_back({Fc, Xc});
143 GM_DBG3(
"NelderMead",
"Contract inside (" << Fc <<
")");
148 TYPE_IN Xc = func_mean(Xm, F_X.back().second);
149 TYPE_OUT Fc = function(Xc);
150 if (Fc < F_X.back().first) {
153 F_X.push_back({Fc, Xc});
155 GM_DBG3(
"NelderMead",
"Contract outside (" << Fc <<
")");
156 ++count_contract_out;
162 for (
size_t i = 1; i < N; i++) {
163 F_X[i].second = func_mean(F_X.front().second, F_X[i].second);
164 F_X[i].first = function(F_X[i].second);
167 GM_DBG3(
"NelderMead",
168 "Shrink (" << F_X.front().first <<
"/" << F_X.back().first <<
")");
170 for (
size_t idx = 1; idx < N; ++idx) {
171 if (std::fabs(F_X[0].first - F_X[idx].first) <=
172 (1 + std::fabs(F_X[0].first) + std::fabs(F_X[idx].first)) * epsilon) {
173 iterations = iteration;
174 GM_DBG1(
"NelderMead",
175 "Termination by precision after "
176 << count_reflect <<
" reflect, "
177 << count_expand <<
" expand, "
178 << count_contract_in <<
"/"
179 << count_contract_out <<
" contract in/out, and "
180 << count_shrink <<
" shrink.");
181 return F_X[0].second;
Definition NelderMead.hh:18
Standard exception for invalid arguments in a call to a function or object.
Definition InvalidArgument.hh:15