226 "nelder_mead requires transcendental arithmetic (it stops on tolerances)");
227 const std::size_t n = x0.size();
228 if (n == 0)
throw InputError(
"nelder_mead: no variables");
231 std::vector<std::vector<T>> v(n + 1, x0);
232 for (std::size_t j = 0; j < n; ++j) {
234 v[j + 1][j] =
opt.step_abs;
239 std::vector<T> fv(n + 1);
241 for (std::size_t i = 0; i <= n; ++i) {
246 std::vector<std::size_t> ord(n + 1);
251 for (
unsigned it = 0; it <
opt.max_iter; ++it) {
253 for (std::size_t i = 0; i <= n; ++i) ord[i] = i;
254 std::stable_sort(ord.begin(), ord.end(),
255 [&fv](std::size_t a, std::size_t b) { return fv[a] < fv[b]; });
257 const std::size_t best = ord[0];
258 const std::size_t worst = ord[n];
259 const std::size_t second = ord[n - 1];
263 for (std::size_t i = 0; i <= n; ++i) {
264 const T df =
num_abs(T(fv[i] - fv[best]));
265 if (df > fspread) fspread = df;
266 for (std::size_t j = 0; j < n; ++j) {
267 const T dx =
num_abs(T(v[i][j] - v[best][j]));
268 if (dx > xspread) xspread = dx;
271 if (fspread <=
opt.ftol && xspread <=
opt.xtol) {
275 if (evals >=
opt.max_eval)
break;
278 std::vector<T> c(n, zero);
279 for (std::size_t i = 0; i < n; ++i)
280 for (std::size_t j = 0; j < n; ++j) c[j] += v[ord[i]][j];
283 std::vector<T> xr(n);
284 for (std::size_t j = 0; j < n; ++j) xr[j] = c[j] +
opt.alpha * (c[j] - v[worst][j]);
289 std::vector<T> xe(n);
290 for (std::size_t j = 0; j < n; ++j) xe[j] = c[j] +
opt.gamma * (xr[j] - c[j]);
302 if (fr < fv[second]) {
310 if (fr < fv[worst]) {
311 std::vector<T> xc(n);
312 for (std::size_t j = 0; j < n; ++j) xc[j] = c[j] +
opt.rho * (xr[j] - c[j]);
322 std::vector<T> xc(n);
323 for (std::size_t j = 0; j < n; ++j) xc[j] = c[j] +
opt.rho * (v[worst][j] - c[j]);
326 if (fc < fv[worst]) {
335 for (std::size_t i = 0; i <= n; ++i) {
336 if (i == best)
continue;
337 for (std::size_t j = 0; j < n; ++j)
338 v[i][j] = v[best][j] +
opt.sigma * (v[i][j] - v[best][j]);
345 std::size_t best = 0;
346 for (std::size_t i = 1; i <= n; ++i)
347 if (fv[i] < fv[best]) best = i;
371 const std::vector<
Bound<T>>& bounds,
374 "nelder_mead_box requires transcendental arithmetic");
375 const std::size_t n = x0.size();
376 if (bounds.size() != n)
throw InputError(
"nelder_mead_box: one bound per variable is required");
377 for (std::size_t j = 0; j < n; ++j)
378 if (bounds[j].has_lo && bounds[j].has_hi && bounds[j].hi < bounds[j].lo)
379 throw InputError(
"nelder_mead_box: upper bound below lower bound");
382 std::vector<std::size_t> free_idx;
383 std::vector<T> xfix = x0;
384 for (std::size_t j = 0; j < n; ++j) {
385 if (bounds[j].has_lo && bounds[j].has_hi && bounds[j].hi == bounds[j].lo)
386 xfix[j] = bounds[j].lo;
388 free_idx.push_back(j);
390 if (free_idx.empty()) {
400 std::vector<T> u0(free_idx.size());
401 for (std::size_t k = 0; k < free_idx.size(); ++k)
402 u0[k] = nmdetail::transform(x0[free_idx[k]], bounds[free_idx[k]]);
404 const std::vector<std::size_t> idx = free_idx;
405 const std::vector<Bound<T>> bnd = bounds;
406 std::vector<T> xbuf = xfix;
407 auto expand = [idx, bnd, xbuf](
const std::vector<T>& u) {
408 std::vector<T> x = xbuf;
409 for (std::size_t k = 0; k < idx.size(); ++k)
410 x[idx[k]] = nmdetail::untransform(u[k], bnd[idx[k]]);
415 nelder_mead([f, expand](
const std::vector<T>& u) {
return f(expand(u)); }, u0,
opt);
NelderMeadResult< T > nelder_mead(F f, const std::vector< T > &x0, const NelderMeadOptions< T > &opt)
Unconstrained simplex minimization.
NelderMeadResult< T > nelder_mead_box(F f, const std::vector< T > &x0, const std::vector< Bound< T > > &bounds, const NelderMeadOptions< T > &opt)
Box-constrained simplex minimization by the transformation described in the header comment.