13#ifndef OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
14#define OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
35 template <
typename Vector>
36 requires TypeTrait<Vector>::IsEigen &&
37 (!TypeTrait<Vector>::IsFixed || TypeTrait<Vector>::Dimension > 0)
45 using Scalar =
typename Vector::Scalar;
47 using Costs = std::conditional_t<
49 Eigen::Vector<Scalar, VectorTrait::Dimension + 1>,
50 std::conditional_t<VectorTrait::IsDynamic,
51 Eigen::Vector<Scalar, Eigen::Dynamic>,
52 Eigen::SparseVector<Scalar>>>;
55 Eigen::Matrix<Scalar, VectorTrait::Dimension, VectorTrait::Dimension>,
57 VectorTrait::IsDynamic,
58 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>,
59 Eigen::SparseMatrix<Scalar>>>;
63 VectorTrait::Dimension,
64 VectorTrait::Dimension + 1>,
66 VectorTrait::IsDynamic,
67 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>,
68 Eigen::SparseMatrix<Scalar>>>;
72 VectorTrait::Dimension + 1,
73 VectorTrait::Dimension + 1>,
75 VectorTrait::IsDynamic,
76 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>,
77 Eigen::SparseMatrix<Scalar>>>;
79 Eigen::SparseLU<Simplex>,
80 Eigen::FullPivLU<Simplex>>;
169 return this->m_method;
177 this->m_method = t_method;
185 return this->m_delta;
194 "Optimist::Optimizer::NelderMead::delta(...): invalid "
196 this->m_delta = t_delta;
213 "Optimist::Optimizer::NelderMead::rho(...): invalid "
232 "Optimist::Optimizer::NelderMead::chi(...): invalid "
242 return this->m_gamma;
251 "Optimist::Optimizer::NelderMead::gamma(...): invalid "
253 this->m_gamma = t_gamma;
261 return this->m_sigma;
270 "Optimist::Optimizer::NelderMead::sigma(...): invalid "
272 this->m_sigma = t_sigma;
280 return this->m_volume_tolerance;
289 t_volume_tolerance > 0,
290 "Optimist::Optimizer::NelderMead::volume_tolerance(...): "
291 "invalid input detected.");
292 this->m_volume_tolerance = t_volume_tolerance;
306 template <
typename FunctionLambda>
310#define CMD "Optimist::Optimizer::NelderMead::solve_impl(...): "
313 this->m_dim = x_ini.size();
314 this->m_dim_factorial = 1;
315 for (
Integer i{2}; i <= this->m_dim + 1; ++i) {
316 this->m_dim_factorial *= i;
318 this->m_regular_simplex_volume =
319 (std::sqrt(
static_cast<Scalar>(this->m_dim + 1)) /
320 static_cast<Scalar>(this->m_dim_factorial)) /
321 std::pow(2.0,
static_cast<Scalar>(this->m_dim) / 2.0);
324 if constexpr (VectorTrait::IsFixed) {
326 this->m_dist.setZero();
328 this->m_f_work.setZero();
329 this->m_p_work.setZero();
330 this->m_p_sum.setZero();
331 this->m_p_r.setZero();
332 this->m_p_e.setZero();
333 this->m_p_c.setZero();
334 }
else if constexpr (VectorTrait::IsDynamic) {
335 this->m_p.resize(this->m_dim, this->m_dim + 1);
336 this->m_dist.resize(this->m_dim + 1, this->m_dim + 1);
337 this->m_f.resize(this->m_dim + 1);
338 this->m_f_work.resize(this->m_dim + 1);
339 this->m_p_work.resize(this->m_dim, this->m_dim + 1);
340 this->m_p_sum.resize(this->m_dim);
341 this->m_p_r.resize(this->m_dim);
342 this->m_p_e.resize(this->m_dim);
343 this->m_p_c.resize(this->m_dim);
345 this->m_dist.setZero();
347 this->m_f_work.setZero();
348 this->m_p_work.setZero();
349 this->m_p_sum.setZero();
350 this->m_p_r.setZero();
351 this->m_p_e.setZero();
352 this->m_p_c.setZero();
353 }
else if constexpr (VectorTrait::IsSparse) {
354 this->m_p.resize(this->m_dim, this->m_dim + 1);
355 this->m_dist.resize(this->m_dim + 1, this->m_dim + 1);
356 this->m_f.resize(this->m_dim + 1);
357 this->m_f_work.resize(this->m_dim + 1);
358 this->m_p_work.resize(this->m_dim, this->m_dim + 1);
359 this->m_p_sum.resize(this->m_dim);
360 this->m_p_r.resize(this->m_dim);
361 this->m_p_e.resize(this->m_dim);
362 this->m_p_c.resize(this->m_dim);
363 this->m_p.reserve(this->m_dim, this->m_dim + 1);
364 this->m_dist.reserve(this->m_dim + 1, this->m_dim + 1);
365 this->m_f.reserve(this->m_dim + 1);
366 this->m_f_work.reserve(this->m_dim + 1);
367 this->m_p_work.reserve(this->m_dim, this->m_dim + 1);
368 this->m_p_sum.reserve(this->m_dim);
369 this->m_p_r.reserve(this->m_dim);
370 this->m_p_e.reserve(this->m_dim);
371 this->m_p_c.reserve(this->m_dim);
375 if (this->m_method == Method::STANDARD) {
376 this->
diamond(std::forward<FunctionLambda>(function),
379 }
else if (this->m_method == Method::SPENDLEY) {
380 this->
spendley(std::forward<FunctionLambda>(function),
396 this->m_p_sum.noalias() = this->m_p.col(this->m_dim);
397 for (
Integer i{0}; i < this->m_dim; ++i) {
398 this->m_p_sum.noalias() += this->m_p.col(i);
402 Move move{Move::INITIALIZE};
411 if (this->m_f(this->m_low) > this->m_f(this->m_mid)) {
412 std::swap(this->m_low, this->m_mid);
414 if (this->m_f(this->m_low) > this->m_f(this->m_high)) {
415 std::swap(this->m_low, this->m_high);
417 if (this->m_f(this->m_mid) > this->m_f(this->m_high)) {
418 std::swap(this->m_mid, this->m_high);
420 for (
Integer i{3}; i <= this->m_dim; ++i) {
421 if (this->m_f(i) < this->m_f(this->m_low)) {
423 }
else if (this->m_f(i) > this->m_f(this->m_high)) {
424 this->m_mid = this->m_high;
426 }
else if (this->m_f(i) > this->m_f(this->m_mid)) {
431 Scalar f_low{this->m_f(this->m_low)};
432 Scalar f_mid{this->m_f(this->m_mid)};
433 Scalar f_high{this->m_f(this->m_high)};
437 Scalar rtol{std::abs(f_high - f_low) /
441 std::string move_str;
443 case Move::INITIALIZE:
444 move_str =
"Initialize";
447 move_str =
"Reflect";
453 move_str =
"Expand (reflection)";
455 case Move::CONTRACT_O:
456 move_str =
"Contract (outside)";
458 case Move::CONTRACT_I:
459 move_str =
"Contract (inside)";
465 move_str =
"Restart";
468 move_str =
"Unknown";
471 this->
info(rtol, move_str);
480 std::pow(this->m_simplex_volume / this->m_regular_simplex_volume,
484 if (this->m_method == Method::STANDARD) {
485 this->
diamond(std::forward<FunctionLambda>(function),
486 this->m_p.col(this->m_low),
487 this->m_diameter * this->m_volume_tolerance);
488 }
else if (this->m_method == Method::SPENDLEY) {
489 this->
spendley(std::forward<FunctionLambda>(function),
490 this->m_p.col(this->m_low),
491 this->m_diameter * this->m_volume_tolerance);
496 this->m_p_sum.noalias() = this->m_p.col(this->m_dim);
497 for (
Integer i{0}; i < this->m_dim; ++i) {
498 this->m_p_sum.noalias() += this->m_p.col(i);
500 move = Move::RESTART;
508 this->
reflect(std::forward<FunctionLambda>(function), this->m_p_r)};
510 Scalar f_e{this->
expand(std::forward<FunctionLambda>(function),
513 move = Move::EXPAND_E;
516 move = Move::EXPAND_R;
519 }
else if (f_r < f_mid) {
520 move = Move::REFLECT;
522 }
else if (f_r < f_high) {
523 Scalar f_c{this->
outside(std::forward<FunctionLambda>(function),
526 move = Move::CONTRACT_O;
529 move = Move::REFLECT;
533 Scalar f_c{this->
inside(std::forward<FunctionLambda>(function),
536 move = Move::CONTRACT_I;
540 this->
shrink(std::forward<FunctionLambda>(function));
551 x_sol = this->m_p.col(this->m_low);
566 this->m_p_sum += p - this->m_p.col(j);
567 this->m_p.col(j).noalias() = p;
578 template <
typename FunctionLambda>
582#define CMD "Optimist::Optimizer::NelderMead::spendley(...): "
584 Scalar const t1{std::sqrt(
static_cast<Scalar>(this->m_dim + 1)) - 1.0};
586 std::sqrt(
static_cast<Scalar>(2))};
590 for (
Integer i{0}; i < this->m_dim; ++i) {
591 this->m_p(i, 0) = x(i);
598 CMD "function evaluation failed at the initial point.");
599 for (
Integer i{0}; i < this->m_dim; ++i) {
600 this->m_p.col(i + 1) = this->m_p.col(0).array() + p;
601 this->m_p(i, i + 1) += q;
604 this->m_p.col(i + 1),
607 CMD "function evaluation failed at simplex point "
621 template <
typename FunctionLambda>
625#define CMD "Optimist::Optimizer::NelderMead::diamond(...): "
628 for (
Integer i{0}; i < this->m_dim; ++i) {
629 this->m_p.row(i).setConstant(x(i));
636 CMD "function evaluation failed at the initial point.");
637 for (
Integer i{0}; i < this->m_dim; ++i) {
639 this->m_p(i, i + 1) = x(i) +
delta;
642 this->m_p.col(i + 1),
645 CMD "function evaluation failed at simplex point "
647 this->m_p(i, i + 1) = x(i) -
delta;
650 this->m_p.col(i + 1),
653 CMD "function evaluation failed at simplex point "
656 this->m_f(i + 1) = f_p;
657 this->m_p(i, i + 1) = x(i) +
delta;
659 this->m_f(i + 1) = f_m;
672 for (
Integer i{0}; i <= this->m_dim; ++i) {
674 this->m_p_work.col(j).noalias() =
675 this->m_p.col(i) - this->m_p.col(k);
676 this->m_f_work(j) = this->m_f(i) - this->m_f(k);
680 this->m_lu.compute(this->m_p_work.transpose());
681 this->m_simplex_volume =
682 std::abs(this->m_lu.determinant()) / this->m_dim_factorial;
689 for (
Integer i{0}; i < this->m_dim; ++i) {
690 this->m_dist(i, i) = 0;
691 for (
Integer j{i + 1}; j <= this->m_dim; ++j) {
692 this->m_dist(i, j) = (this->m_p.col(i) - this->m_p.col(j)).norm();
693 this->m_dist(j, i) = this->m_dist(i, j);
696 this->m_diameter = this->m_dist.maxCoeff();
705 for (
Integer i{0}; i <= this->m_dim; ++i) {
707 this->m_dist(i, j) = (this->m_p.col(i) - this->m_p.col(j)).norm();
708 this->m_dist(j, i) = this->m_dist(i, j);
711 this->m_diameter = this->m_dist.maxCoeff();
720 template <
typename FunctionLambda>
722#define CMD "Optimist::Optimizer::NelderMead::shrink(...): "
725 const Scalar c_1{
static_cast<Scalar>(1.0) - this->m_sigma},
727 for (
Integer i{0}; i <= this->m_dim; ++i) {
728 if (i != this->m_low) {
730 c_1 * this->m_p.col(i) + c_2 * this->m_p.col(this->m_low);
737 CMD "function evaluation failed at simplex point " << i <<
".");
740 this->m_p_sum.noalias() = this->m_p.col(this->m_dim);
741 for (
Integer i{0}; i < this->m_dim; ++i) {
742 this->m_p_sum.noalias() += this->m_p.col(i);
745 this->m_diameter *= c_1;
746 this->m_simplex_volume *=
747 std::pow(c_1,
static_cast<Scalar>(this->m_dim));
761 template <
typename FunctionLambda>
784#define CMD "Optimist::Optimizer::NelderMead::extrapolate(...): "
787 const Scalar beta{(
static_cast<Scalar>(this->m_n) + 1.0) * beta_1};
788 p.noalias() = beta_1 * this->m_p_sum + (1.0 - beta) * this->m_p.col(j);
795 CMD "function evaluation failed during extrapolation.");
808 template <
typename FunctionLambda>
810 return this->
extrapolate(std::forward<FunctionLambda>(function),
823 template <
typename FunctionLambda>
825 return this->
extrapolate(std::forward<FunctionLambda>(function),
826 this->m_rho * this->m_chi,
838 template <
typename FunctionLambda>
840 return this->
extrapolate(std::forward<FunctionLambda>(function),
841 this->m_rho * this->m_gamma,
853 template <
typename FunctionLambda>
855 return this->
extrapolate(std::forward<FunctionLambda>(function),
#define OPTIMIST_ERROR(MSG)
Definition Optimist.hh:37
#define OPTIMIST_BASIC_CONSTANTS(Scalar)
Definition Optimist.hh:69
#define OPTIMIST_ASSERT(COND, MSG)
Definition Optimist.hh:47
void volume_tolerance(const Scalar t_volume_tolerance)
Definition NelderMead.hh:287
Vector m_f_work
Definition NelderMead.hh:129
void sigma(const Scalar t_sigma)
Definition NelderMead.hh:268
Scalar extrapolate(FunctionLambda &&function, const Scalar alpha, const Integer j, Vector &p)
Definition NelderMead.hh:762
Scalar delta() const
Definition NelderMead.hh:184
Vector m_p_r
Definition NelderMead.hh:135
void chi(const Scalar t_chi)
Definition NelderMead.hh:230
std::conditional_t< VectorTrait::IsFixed, Eigen::Matrix< Scalar, VectorTrait::Dimension, VectorTrait::Dimension+1 >, std::conditional_t< VectorTrait::IsDynamic, Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic >, Eigen::SparseMatrix< Scalar > > > Simplex
Definition NelderMead.hh:60
Scalar m_diameter
Definition NelderMead.hh:139
Costs m_f
Definition NelderMead.hh:126
void diamond(FunctionLambda &&function, const Vector x, const Scalar delta)
Definition NelderMead.hh:622
Scalar outside(FunctionLambda &&function, Vector &p)
Definition NelderMead.hh:839
Simplex m_p_work
Definition NelderMead.hh:130
Scalar sigma() const
Definition NelderMead.hh:260
Scalar m_volume_tolerance
Definition NelderMead.hh:114
void delta(const Scalar t_delta)
Definition NelderMead.hh:192
Scalar m_sigma
Definition NelderMead.hh:113
void rho(const Scalar t_rho)
Definition NelderMead.hh:211
std::conditional_t< VectorTrait::IsSparse, Eigen::SparseLU< Simplex >, Eigen::FullPivLU< Simplex > > Factorization
Definition NelderMead.hh:78
static constexpr bool RequiresFunction
Definition NelderMead.hh:40
Scalar m_rho
Definition NelderMead.hh:110
enum class Move :Integer { INITIALIZE=0, REFLECT=1, EXPAND_E=2, EXPAND_R=3, CONTRACT_O=4, CONTRACT_I=5, SHRINK=6, RESTART=7 } Move
Definition NelderMead.hh:87
static constexpr bool RequiresFirstDerivative
Definition NelderMead.hh:41
Integer m_low
Definition NelderMead.hh:122
Scalar m_simplex_volume
Definition NelderMead.hh:140
Scalar inside(FunctionLambda &&function, Vector &p)
Definition NelderMead.hh:854
Simplex m_p
Definition NelderMead.hh:127
void method(const Method t_method)
Definition NelderMead.hh:176
bool solve_impl(FunctionLambda &&function, const Vector &x_ini, Vector &x_sol)
Definition NelderMead.hh:307
constexpr std::string name_impl() const
Definition NelderMead.hh:160
TypeTrait< Vector > VectorTrait
Definition NelderMead.hh:44
Scalar gamma() const
Definition NelderMead.hh:241
Scalar reflect(FunctionLambda &&function, Vector &p)
Definition NelderMead.hh:809
Vector m_p_sum
Definition NelderMead.hh:131
Integer m_mid
Definition NelderMead.hh:123
Scalar chi() const
Definition NelderMead.hh:222
Scalar m_chi
Definition NelderMead.hh:111
static constexpr bool RequiresSecondDerivative
Definition NelderMead.hh:42
void gamma(const Scalar t_gamma)
Definition NelderMead.hh:249
Integer m_dim
Definition NelderMead.hh:118
Integer m_high
Definition NelderMead.hh:124
MatrixD m_dist
Definition NelderMead.hh:128
Scalar volume_tolerance() const
Definition NelderMead.hh:279
void dist_init()
Definition NelderMead.hh:688
NelderMead()
Definition NelderMead.hh:146
Vector m_p_c
Definition NelderMead.hh:137
void simplex_volume(Integer k)
Definition NelderMead.hh:670
Scalar m_regular_simplex_volume
Definition NelderMead.hh:120
std::conditional_t< VectorTrait::IsFixed, Eigen::Matrix< Scalar, VectorTrait::Dimension, VectorTrait::Dimension >, std::conditional_t< VectorTrait::IsDynamic, Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic >, Eigen::SparseMatrix< Scalar > > > MatrixX
Definition NelderMead.hh:53
std::conditional_t< VectorTrait::IsFixed, Eigen::Vector< Scalar, VectorTrait::Dimension+1 >, std::conditional_t< VectorTrait::IsDynamic, Eigen::Vector< Scalar, Eigen::Dynamic >, Eigen::SparseVector< Scalar > > > Costs
Definition NelderMead.hh:47
Scalar m_gamma
Definition NelderMead.hh:112
Scalar m_dim_factorial
Definition NelderMead.hh:119
typename Vector::Scalar Scalar
Definition NelderMead.hh:45
void dist_update(Integer j)
Definition NelderMead.hh:704
Scalar expand(FunctionLambda &&function, Vector &p)
Definition NelderMead.hh:824
void spendley(FunctionLambda &&function, const Vector x, const Scalar delta)
Definition NelderMead.hh:579
void replace_point(const Scalar f, const Vector &p, const Integer j)
Definition NelderMead.hh:564
Scalar rho() const
Definition NelderMead.hh:203
Vector m_p_e
Definition NelderMead.hh:136
std::conditional_t< VectorTrait::IsFixed, Eigen::Matrix< Scalar, VectorTrait::Dimension+1, VectorTrait::Dimension+1 >, std::conditional_t< VectorTrait::IsDynamic, Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic >, Eigen::SparseMatrix< Scalar > > > MatrixD
Definition NelderMead.hh:69
void shrink(FunctionLambda &&function)
Definition NelderMead.hh:721
Scalar m_delta
Definition NelderMead.hh:109
Method method() const
Definition NelderMead.hh:168
Method m_method
Definition NelderMead.hh:108
enum class Method :Integer { STANDARD=0, SPENDLEY=1 } Method
Definition NelderMead.hh:101
NelderMead(const Scalar delta)
Definition NelderMead.hh:152
Optimizer()
Definition Optimizer.hh:67
void info(Scalar residuals, const std::string ¬es="-")
Definition SolverBase.hh:1230
Scalar alpha() const
Definition SolverBase.hh:467
bool evaluate_function(FunctionLambda &&function, const Vector &x, TypeTrait< Vector >::Scalar &out)
Definition SolverBase.hh:1040
Integer m_max_iterations
Definition SolverBase.hh:121
Scalar m_tolerance
Definition SolverBase.hh:128
void header()
Definition SolverBase.hh:1168
void reset_counters()
Definition SolverBase.hh:1022
Integer m_iterations
Definition SolverBase.hh:120
bool m_verbose
Definition SolverBase.hh:130
bool m_converged
Definition SolverBase.hh:136
void bottom()
Definition SolverBase.hh:1204
Namespace for the Optimist library.
Definition Optimist.hh:89
OPTIMIST_DEFAULT_INTEGER_TYPE Integer
The Integer type as used for the API.
Definition Optimist.hh:97
Definition Optimist.hh:113