53 double w = x, v = x, fw = fx, fv = fx;
54 double d = c - a, e = d;
58 auto tolerance = [epsilon](
double point) {
return epsilon * (1 + std::fabs(point)); };
60 const double tol = tolerance(x);
63 bool acceptParabolicU =
false;
64 if (x != w && x != v && w != v && fx != fw && fx != fv && fw != fv) {
67 u = parabolicMinimum<RealType>(x, v, w, fx, fv, fw);
69 u = parabolicMinimum<RealType>(v, x, w, fv, fx, fw);
71 u = parabolicMinimum<RealType>(v, w, x, fv, fw, fx);
74 u = parabolicMinimum<RealType>(x, w, v, fx, fv, fw);
76 u = parabolicMinimum<RealType>(w, x, v, fw, fx, fv);
78 u = parabolicMinimum<RealType>(w, v, x, fw, fv, fx);
80 double absumx = std::fabs(u - x);
81 if (u >= a + tol && u <= c - tol && absumx < 0.5 * g) {
82 acceptParabolicU =
true;
87 if (!acceptParabolicU) {
89 if (x < 0.5 * (c + a)) {
98 if (std::fabs(u - x) < tol) {
99 u = x + ((u >= x) ? tol : -tol);
102 double fu = funPtr(u);
119 if (fu <= fw || w == x) {
124 }
else if (fu <= fv || v == x || v == w) {
129 }
while (0.49 * (c - a) > tolerance(x));
143bool findMin(
const std::function<
double(RealType)> &funPtr, RealType closePoint, RealType &root,
144 long double epsilon = 1e-8)
148 static constexpr int L = 100;
149 double a = closePoint, fa = funPtr(a);
150 double b = a + 1.0, fb = funPtr(b);
158 double u = parabolicMinimum<RealType>(a, b, c, fa, fb, fc);
160 double fu, uLim = c + L * cmb;
161 if (u < c && u > b) {
164 abc = std::make_tuple(b, u, c);
165 return findMin(funPtr, abc, fu, root, epsilon);
168 abc = std::make_tuple(a, b, u);
169 return findMin(funPtr, abc, fb, root, epsilon);
173 }
else if (u > c && u < uLim) {
179 fb = fc, fc = fu, fu = funPtr(u);
181 }
else if (u > uLim) {
195 abc = std::make_tuple(a, b, c);
196 return findMin(funPtr, abc, fb, root, epsilon);
207 double u = parabolicMinimum<RealType>(a, b, c, fa, fb, fc);
209 double fu, uLim = a - L * bma;
210 if (u < b && u > a) {
213 abc = std::make_tuple(a, u, b);
214 return findMin(funPtr, abc, fu, root, epsilon);
217 abc = std::make_tuple(u, b, c);
218 return findMin(funPtr, abc, fb, root, epsilon);
222 }
else if (u < a && u > uLim) {
228 fb = fa, fa = fu, fu = funPtr(u);
230 }
else if (u < uLim) {
244 abc = std::make_tuple(a, b, c);
245 return findMin(funPtr, abc, fb, root, epsilon);
275 const std::size_t n = start.size();
276 const Real dimension =
static_cast<Real
>(std::max<std::size_t>(n, 1));
277 const Real reflection = 1, expansion = 1 + 2 / dimension, contraction = Real(0.75) - 1 / (2 * dimension),
278 shrinkage = 1 - 1 / dimension;
279 std::vector<std::vector<Real>> simplex(n + 1, start);
280 for (std::size_t i = 0; i < n; ++i)
281 simplex[i + 1][i] = (start[i] != 0) ? start[i] * Real(1.05) : Real(0.00025);
282 std::vector<Real> values(n + 1);
283 for (std::size_t i = 0; i <= n; ++i)
284 values[i] = f(std::span<const Real>(simplex[i]));
286 std::vector<std::size_t> order(n + 1);
287 auto point = [n](
const std::vector<Real> &from,
const std::vector<Real> &to, Real t) {
288 std::vector<Real> x(n);
289 for (std::size_t j = 0; j < n; ++j)
290 x[j] = from[j] + t * (to[j] - from[j]);
295 std::iota(order.begin(), order.end(), 0);
296 std::sort(order.begin(), order.end(),
297 [&values](std::size_t i, std::size_t j) { return values[i] < values[j]; });
298 const std::size_t best = order.front(), worst = order.back(), secondWorst = order[n > 0 ? n - 1 : 0];
300 Real valueSpread = 0, pointSpread = 0, scale = 0;
301 for (std::size_t i = 0; i <= n; ++i) {
302 valueSpread = std::max(valueSpread, std::fabs(values[i] - values[best]));
303 for (std::size_t j = 0; j < n; ++j) {
304 pointSpread = std::max(pointSpread, std::fabs(simplex[i][j] - simplex[best][j]));
305 scale = std::max(scale, std::fabs(simplex[best][j]));
308 if (valueSpread <= tolerance * (std::fabs(values[best]) + tolerance) &&
309 pointSpread <= tolerance * (scale + 1)) {
314 std::vector<Real> centroid(n, 0);
315 for (std::size_t i : order) {
318 for (std::size_t j = 0; j < n; ++j)
319 centroid[j] += simplex[i][j] / dimension;
321 std::vector<Real> reflected = point(centroid, simplex[worst], -reflection);
322 Real reflectedValue = f(std::span<const Real>(reflected));
323 if (reflectedValue < values[best]) {
324 std::vector<Real> expanded = point(centroid, simplex[worst], -reflection * expansion);
325 Real expandedValue = f(std::span<const Real>(expanded));
326 if (expandedValue < reflectedValue) {
327 simplex[worst] = expanded;
328 values[worst] = expandedValue;
330 simplex[worst] = reflected;
331 values[worst] = reflectedValue;
335 if (reflectedValue < values[secondWorst]) {
336 simplex[worst] = reflected;
337 values[worst] = reflectedValue;
340 const bool outside = reflectedValue < values[worst];
341 std::vector<Real> contracted =
342 outside ? point(centroid, reflected, contraction) : point(centroid, simplex[worst], contraction);
343 Real contractedValue = f(std::span<const Real>(contracted));
344 if (contractedValue < (outside ? reflectedValue : values[worst])) {
345 simplex[worst] = contracted;
346 values[worst] = contractedValue;
349 for (std::size_t i = 0; i <= n; ++i) {
352 simplex[i] = point(simplex[best], simplex[i], shrinkage);
353 values[i] = f(std::span<const Real>(simplex[i]));
356 std::size_t best = std::min_element(values.begin(), values.end()) - values.begin();
357 result.
x = simplex[best];
358 result.
value = values[best];
392 const Real h0 = std::sqrt(std::sqrt(std::numeric_limits<Real>::epsilon()));
393 const std::size_t n = x.size();
394 std::vector<Real> steps(n);
395 for (std::size_t i = 0; i < n; ++i)
396 steps[i] = h0 * std::max<Real>(std::fabs(x[i]), 1);
398 std::vector<std::vector<Real>> hessian(n, std::vector<Real>(n));
399 std::vector<Real> y = x;
400 const Real center = f(std::span<const Real>(x));
401 for (std::size_t i = 0; i < n; ++i) {
402 y[i] = x[i] + steps[i];
403 const Real up = f(std::span<const Real>(y));
404 y[i] = x[i] - steps[i];
405 const Real down = f(std::span<const Real>(y));
407 hessian[i][i] = (up - 2 * center + down) / (steps[i] * steps[i]);
409 for (std::size_t j = 0; j < i; ++j) {
410 y[i] = x[i] + steps[i];
411 y[j] = x[j] + steps[j];
412 const Real upUp = f(std::span<const Real>(y));
413 y[j] = x[j] - steps[j];
414 const Real upDown = f(std::span<const Real>(y));
415 y[i] = x[i] - steps[i];
416 const Real downDown = f(std::span<const Real>(y));
417 y[j] = x[j] + steps[j];
418 const Real downUp = f(std::span<const Real>(y));
421 hessian[i][j] = hessian[j][i] = (upUp - upDown - downUp + downDown) / (4 * steps[i] * steps[j]);
439 const std::size_t n = start.size();
440 auto setIdentity = [n](std::vector<std::vector<Real>> &matrix) {
441 for (
auto &row : matrix)
442 std::fill(row.begin(), row.end(), Real{0});
443 for (std::size_t i = 0; i < n; ++i)
446 auto dot = [](
const std::vector<Real> &u,
const std::vector<Real> &v) {
447 return std::inner_product(u.begin(), u.end(), v.begin(), Real(0));
449 std::vector<std::vector<Real>> H(n, std::vector<Real>(n));
451 std::vector<Real> x = std::move(start);
452 Real value = f(std::span<const Real>(x));
453 std::vector<Real> gradient = numericalGradient<Real>(f, x);
457 for (Real g : gradient)
458 largest = std::max(largest, std::fabs(g));
459 if (largest <= tolerance * std::max<Real>(1, std::fabs(value))) {
463 std::vector<Real> direction(n, 0);
464 for (std::size_t i = 0; i < n; ++i)
465 for (std::size_t j = 0; j < n; ++j)
466 direction[i] -= H[i][j] * gradient[j];
467 Real slope = dot(gradient, direction);
470 for (std::size_t i = 0; i < n; ++i)
471 direction[i] = -gradient[i];
472 slope = -dot(gradient, gradient);
474 Real step = 1, newValue = value;
475 std::vector<Real> next(n);
476 for (
int k = 0; k < 60; ++k, step /= 2) {
477 for (std::size_t i = 0; i < n; ++i)
478 next[i] = x[i] + step * direction[i];
479 newValue = f(std::span<const Real>(next));
480 if (newValue <= value + Real(1e-4) * step * slope)
483 if (!(newValue < value)) {
487 std::vector<Real> newGradient = numericalGradient<Real>(f, next);
488 std::vector<Real> s(n), y(n);
489 for (std::size_t i = 0; i < n; ++i) {
490 s[i] = next[i] - x[i];
491 y[i] = newGradient[i] - gradient[i];
493 const Real sy = dot(s, y);
496 const Real rho = 1 / sy;
497 std::vector<Real> Hy(n, 0);
498 for (std::size_t i = 0; i < n; ++i)
499 for (std::size_t j = 0; j < n; ++j)
500 Hy[i] += H[i][j] * y[j];
501 const Real yHy = dot(y, Hy);
502 for (std::size_t i = 0; i < n; ++i)
503 for (std::size_t j = 0; j < n; ++j)
504 H[i][j] += rho * ((1 + rho * yHy) * s[i] * s[j] - Hy[i] * s[j] - s[i] * Hy[j]);
508 gradient = std::move(newGradient);
510 result.
x = std::move(x);
511 result.
value = value;