Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
NelderMead.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco and Enrico Bertolazzi. *
3 * *
4 * The Optimist project is distributed under the BSD 2-Clause License. *
5 * *
6 * Davide Stocco Enrico Bertolazzi *
7 * University of Trento University of Trento *
8 * davide.stocco@unitn.it enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#pragma once
12
13#ifndef OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
14#define OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
15
16#include "Optimist/Optimizer.hh"
17
18namespace Optimist {
19 namespace Optimizer {
20
21 /*\
22 | _ _ _ _ __ __ _
23 | | \ | | ___| | __| | ___ _ __| \/ | ___ __ _ __| |
24 | | \| |/ _ \ |/ _` |/ _ \ '__| |\/| |/ _ \/ _` |/ _` |
25 | | |\ | __/ | (_| | __/ | | | | | __/ (_| | (_| |
26 | |_| \_|\___|_|\__,_|\___|_| |_| |_|\___|\__,_|\__,_|
27 |
28 \*/
29
35 template <typename Vector>
36 requires TypeTrait<Vector>::IsEigen &&
37 (!TypeTrait<Vector>::IsFixed || TypeTrait<Vector>::Dimension > 0)
38 class NelderMead : public Optimizer<Vector, NelderMead<Vector>> {
39 public:
40 static constexpr bool RequiresFunction{true};
41 static constexpr bool RequiresFirstDerivative{false};
42 static constexpr bool RequiresSecondDerivative{false};
43
45 using Scalar = typename Vector::Scalar;
46
47 using Costs = std::conditional_t<
48 VectorTrait::IsFixed,
49 Eigen::Vector<Scalar, VectorTrait::Dimension + 1>,
50 std::conditional_t<VectorTrait::IsDynamic,
51 Eigen::Vector<Scalar, Eigen::Dynamic>,
52 Eigen::SparseVector<Scalar>>>;
53 using MatrixX = std::conditional_t<
54 VectorTrait::IsFixed,
55 Eigen::Matrix<Scalar, VectorTrait::Dimension, VectorTrait::Dimension>,
56 std::conditional_t<
57 VectorTrait::IsDynamic,
58 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>,
59 Eigen::SparseMatrix<Scalar>>>;
60 using Simplex = std::conditional_t<
61 VectorTrait::IsFixed,
62 Eigen::Matrix<Scalar,
63 VectorTrait::Dimension,
64 VectorTrait::Dimension + 1>,
65 std::conditional_t<
66 VectorTrait::IsDynamic,
67 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>,
68 Eigen::SparseMatrix<Scalar>>>;
69 using MatrixD = std::conditional_t<
70 VectorTrait::IsFixed,
71 Eigen::Matrix<Scalar,
72 VectorTrait::Dimension + 1,
73 VectorTrait::Dimension + 1>,
74 std::conditional_t<
75 VectorTrait::IsDynamic,
76 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>,
77 Eigen::SparseMatrix<Scalar>>>;
78 using Factorization = std::conditional_t<VectorTrait::IsSparse,
79 Eigen::SparseLU<Simplex>,
80 Eigen::FullPivLU<Simplex>>;
81
83
84
87 using Move = enum class Move : Integer {
88 INITIALIZE = 0,
89 REFLECT = 1,
90 EXPAND_E = 2,
91 EXPAND_R = 3,
92 CONTRACT_O = 4,
93 CONTRACT_I = 5,
94 SHRINK = 6,
95 RESTART = 7
96 };
97
101 using Method = enum class Method : Integer {
102 STANDARD = 0,
103 SPENDLEY = 1
104 };
105
106 private:
107 // Solver parameters
108 Method m_method{Method::STANDARD};
115 std::sqrt(this->m_tolerance)};
116
117 // Internal variables
121
125
129 Vector m_f_work;
131 Vector m_p_sum;
132
133 // Factorization m_lu; /**< LU decomposition. */
134
135 Vector m_p_r;
136 Vector m_p_e;
137 Vector m_p_c;
138
141
142 public:
147
153 this->delta(delta);
154 }
155
160 constexpr std::string name_impl() const {
161 return "NelderMead";
162 }
163
168 Method method() const {
169 return this->m_method;
170 }
171
176 void method(const Method t_method) {
177 this->m_method = t_method;
178 }
179
184 Scalar delta() const {
185 return this->m_delta;
186 }
187
192 void delta(const Scalar t_delta) {
193 OPTIMIST_ASSERT(t_delta > 0,
194 "Optimist::Optimizer::NelderMead::delta(...): invalid "
195 "input detected.");
196 this->m_delta = t_delta;
197 }
198
203 Scalar rho() const {
204 return this->m_rho;
205 }
206
211 void rho(const Scalar t_rho) {
212 OPTIMIST_ASSERT(t_rho > 0,
213 "Optimist::Optimizer::NelderMead::rho(...): invalid "
214 "input detected.");
215 this->m_rho = t_rho;
216 }
217
222 Scalar chi() const {
223 return this->m_chi;
224 }
225
230 void chi(const Scalar t_chi) {
231 OPTIMIST_ASSERT(t_chi > 1,
232 "Optimist::Optimizer::NelderMead::chi(...): invalid "
233 "input detected.");
234 this->m_chi = t_chi;
235 }
236
241 Scalar gamma() const {
242 return this->m_gamma;
243 }
244
249 void gamma(const Scalar t_gamma) {
250 OPTIMIST_ASSERT(t_gamma > 0 && t_gamma < 1,
251 "Optimist::Optimizer::NelderMead::gamma(...): invalid "
252 "input detected.");
253 this->m_gamma = t_gamma;
254 }
255
260 Scalar sigma() const {
261 return this->m_sigma;
262 }
263
268 void sigma(const Scalar t_sigma) {
269 OPTIMIST_ASSERT(t_sigma > 0 && t_sigma < 1,
270 "Optimist::Optimizer::NelderMead::sigma(...): invalid "
271 "input detected.");
272 this->m_sigma = t_sigma;
273 }
274
280 return this->m_volume_tolerance;
281 }
282
287 void volume_tolerance(const Scalar t_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;
293 }
294
306 template <typename FunctionLambda>
307 bool solve_impl(FunctionLambda &&function,
308 const Vector &x_ini,
309 Vector &x_sol) {
310#define CMD "Optimist::Optimizer::NelderMead::solve_impl(...): "
311
312 // Precompute constants
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;
317 }
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);
322
323 // Initialize internal variables
324 if constexpr (VectorTrait::IsFixed) {
325 this->m_p.setZero();
326 this->m_dist.setZero();
327 this->m_f.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);
344 this->m_p.setZero();
345 this->m_dist.setZero();
346 this->m_f.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);
372 }
373
374 // Initialize simplex
375 if (this->m_method == Method::STANDARD) {
376 this->diamond(std::forward<FunctionLambda>(function),
377 x_ini,
378 this->m_delta);
379 } else if (this->m_method == Method::SPENDLEY) {
380 this->spendley(std::forward<FunctionLambda>(function),
381 x_ini,
382 this->m_delta);
383 } else {
384 OPTIMIST_ERROR(CMD "invalid method detected.");
385 }
386
387 // Reset internal variables
388 this->reset_counters();
389
390 // Print header
391 if (this->m_verbose) {
392 this->header();
393 }
394
395 this->dist_init();
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);
399 }
400
401 // Algorithm iterations
402 Move move{Move::INITIALIZE};
403 for (this->m_iterations = 1;
404 this->m_iterations <= this->m_max_iterations;
405 ++this->m_iterations) {
406 // Determine which point is the highest (worst), next-highest, and
407 // lowest (best).
408 this->m_low = 0;
409 this->m_mid = 1;
410 this->m_high = 2;
411 if (this->m_f(this->m_low) > this->m_f(this->m_mid)) {
412 std::swap(this->m_low, this->m_mid);
413 }
414 if (this->m_f(this->m_low) > this->m_f(this->m_high)) {
415 std::swap(this->m_low, this->m_high);
416 }
417 if (this->m_f(this->m_mid) > this->m_f(this->m_high)) {
418 std::swap(this->m_mid, this->m_high);
419 }
420 for (Integer i{3}; i <= this->m_dim; ++i) {
421 if (this->m_f(i) < this->m_f(this->m_low)) {
422 this->m_low = i; // New minima
423 } else if (this->m_f(i) > this->m_f(this->m_high)) {
424 this->m_mid = this->m_high;
425 this->m_high = i;
426 } else if (this->m_f(i) > this->m_f(this->m_mid)) {
427 this->m_mid = i;
428 }
429 }
430
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)};
434
435 // Compute the fractional range from highest to lowest and return if
436 // satisfactory
437 Scalar rtol{std::abs(f_high - f_low) /
438 (std::abs(f_low) + this->m_tolerance)};
439
440 if (this->m_verbose) {
441 std::string move_str;
442 switch (move) {
443 case Move::INITIALIZE:
444 move_str = "Initialize";
445 break;
446 case Move::REFLECT:
447 move_str = "Reflect";
448 break;
449 case Move::EXPAND_E:
450 move_str = "Expand";
451 break;
452 case Move::EXPAND_R:
453 move_str = "Expand (reflection)";
454 break;
455 case Move::CONTRACT_O:
456 move_str = "Contract (outside)";
457 break;
458 case Move::CONTRACT_I:
459 move_str = "Contract (inside)";
460 break;
461 case Move::SHRINK:
462 move_str = "Shrink";
463 break;
464 case Move::RESTART:
465 move_str = "Restart";
466 break;
467 default:
468 move_str = "Unknown";
469 break;
470 }
471 this->info(rtol, move_str);
472 }
473 if (rtol < this->m_tolerance ||
474 this->m_diameter < this->m_tolerance) {
475 this->m_converged = true;
476 break;
477 }
478
479 Scalar ratio{
480 std::pow(this->m_simplex_volume / this->m_regular_simplex_volume,
481 1.0 / this->m_dim) /
482 this->m_diameter};
483 if (ratio <= this->m_volume_tolerance) {
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);
492 } else {
493 OPTIMIST_ERROR(CMD "invalid method detected.");
494 }
495 this->dist_init();
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);
499 }
500 move = Move::RESTART;
501 continue;
502 }
503
504 // Begin a new iteration: first extrapolate by a factor alpha
505 // (default: −1 a reflection) through the face of the simplex across
506 // from the high point, i.e., reflect the simplex from the high point
507 Scalar f_r{
508 this->reflect(std::forward<FunctionLambda>(function), this->m_p_r)};
509 if (f_r < f_low) {
510 Scalar f_e{this->expand(std::forward<FunctionLambda>(function),
511 this->m_p_e)};
512 if (f_e < f_r) {
513 move = Move::EXPAND_E;
514 this->replace_point(f_e, this->m_p_e, this->m_high);
515 } else {
516 move = Move::EXPAND_R;
517 this->replace_point(f_r, this->m_p_r, this->m_high);
518 }
519 } else if (f_r < f_mid) {
520 move = Move::REFLECT;
521 this->replace_point(f_r, this->m_p_r, this->m_high);
522 } else if (f_r < f_high) {
523 Scalar f_c{this->outside(std::forward<FunctionLambda>(function),
524 this->m_p_c)};
525 if (f_c < f_r) {
526 move = Move::CONTRACT_O;
527 this->replace_point(f_c, this->m_p_c, this->m_high);
528 } else {
529 move = Move::REFLECT;
530 this->replace_point(f_r, this->m_p_r, this->m_high);
531 }
532 } else {
533 Scalar f_c{this->inside(std::forward<FunctionLambda>(function),
534 this->m_p_c)};
535 if (f_c < f_high) {
536 move = Move::CONTRACT_I;
537 this->replace_point(f_c, this->m_p_c, this->m_high);
538 } else {
539 move = Move::SHRINK;
540 this->shrink(std::forward<FunctionLambda>(function));
541 }
542 }
543 }
544
545 // Print bottom
546 if (this->m_verbose) {
547 this->bottom();
548 }
549
550 // Convergence data
551 x_sol = this->m_p.col(this->m_low);
552 return this->m_converged;
553
554#undef CMD
555 }
556
557 private:
564 void replace_point(const Scalar f, const Vector &p, const Integer j) {
565 this->m_f(j) = f;
566 this->m_p_sum += p - this->m_p.col(j);
567 this->m_p.col(j).noalias() = p;
568 this->dist_update(j);
569 }
570
578 template <typename FunctionLambda>
579 void spendley(FunctionLambda &&function,
580 const Vector x,
581 const Scalar delta) {
582#define CMD "Optimist::Optimizer::NelderMead::spendley(...): "
583
584 Scalar const t1{std::sqrt(static_cast<Scalar>(this->m_dim + 1)) - 1.0};
585 const Scalar t2{static_cast<Scalar>(this->m_dim) *
586 std::sqrt(static_cast<Scalar>(2))};
587 const Scalar p{delta * (this->m_dim + t1) / t2};
588 const Scalar q{delta * t1 / t2};
589 bool success;
590 for (Integer i{0}; i < this->m_dim; ++i) {
591 this->m_p(i, 0) = x(i);
592 }
593 success =
594 this->evaluate_function(std::forward<FunctionLambda>(function),
595 this->m_p.col(0),
596 this->m_f(0));
597 OPTIMIST_ASSERT(success,
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;
602 success =
603 this->evaluate_function(std::forward<FunctionLambda>(function),
604 this->m_p.col(i + 1),
605 this->m_f(i + 1));
606 OPTIMIST_ASSERT(success,
607 CMD "function evaluation failed at simplex point "
608 << i + 1 << ".");
609 }
610
611#undef CMD
612 }
613
621 template <typename FunctionLambda>
622 void diamond(FunctionLambda &&function,
623 const Vector x,
624 const Scalar delta) {
625#define CMD "Optimist::Optimizer::NelderMead::diamond(...): "
626
627 bool success;
628 for (Integer i{0}; i < this->m_dim; ++i) {
629 this->m_p.row(i).setConstant(x(i));
630 }
631 success =
632 this->evaluate_function(std::forward<FunctionLambda>(function),
633 x,
634 this->m_f(0));
635 OPTIMIST_ASSERT(success,
636 CMD "function evaluation failed at the initial point.");
637 for (Integer i{0}; i < this->m_dim; ++i) {
638 Scalar f_p, f_m;
639 this->m_p(i, i + 1) = x(i) + delta;
640 success =
641 this->evaluate_function(std::forward<FunctionLambda>(function),
642 this->m_p.col(i + 1),
643 f_p);
644 OPTIMIST_ASSERT(success,
645 CMD "function evaluation failed at simplex point "
646 << i + 1 << ".");
647 this->m_p(i, i + 1) = x(i) - delta;
648 success =
649 this->evaluate_function(std::forward<FunctionLambda>(function),
650 this->m_p.col(i + 1),
651 f_m);
652 OPTIMIST_ASSERT(success,
653 CMD "function evaluation failed at simplex point "
654 << i + 1 << ".");
655 if (f_p < f_m) {
656 this->m_f(i + 1) = f_p;
657 this->m_p(i, i + 1) = x(i) + delta;
658 } else {
659 this->m_f(i + 1) = f_m;
660 }
661 }
662
663#undef CMD
664 }
665
671 Integer j{0};
672 for (Integer i{0}; i <= this->m_dim; ++i) {
673 if (i != k) {
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);
677 ++j;
678 }
679 }
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;
683 }
684
688 void dist_init() {
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);
694 }
695 }
696 this->m_diameter = this->m_dist.maxCoeff();
697 this->simplex_volume(0);
698 }
699
705 for (Integer i{0}; i <= this->m_dim; ++i) {
706 if (i != j) {
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);
709 }
710 }
711 this->m_diameter = this->m_dist.maxCoeff();
712 this->simplex_volume(this->m_low);
713 }
714
720 template <typename FunctionLambda>
721 void shrink(FunctionLambda &&function) {
722#define CMD "Optimist::Optimizer::NelderMead::shrink(...): "
723
724 bool success;
725 const Scalar c_1{static_cast<Scalar>(1.0) - this->m_sigma},
726 c_2{this->m_sigma};
727 for (Integer i{0}; i <= this->m_dim; ++i) {
728 if (i != this->m_low) {
729 this->m_p.col(i) =
730 c_1 * this->m_p.col(i) + c_2 * this->m_p.col(this->m_low);
731 success =
732 this->evaluate_function(std::forward<FunctionLambda>(function),
733 this->m_p.col(i),
734 this->m_f(i));
736 success,
737 CMD "function evaluation failed at simplex point " << i << ".");
738 }
739 }
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);
743 }
744 this->m_dist *= c_1;
745 this->m_diameter *= c_1;
746 this->m_simplex_volume *=
747 std::pow(c_1, static_cast<Scalar>(this->m_dim));
748#undef CMD
749 }
750
761 template <typename FunctionLambda>
762 Scalar extrapolate(FunctionLambda &&function,
763 const Scalar alpha,
764 const Integer j,
765 Vector &p) {
766 // Extrapolates by a factor alpha through the face of the simplex
767 // across from the high point.
768 //
769 // pface = (sum(p)-pfrom)/N
770 // pcenter = sum(p)/(N+1);
771 // pe = pface + alpha*(pface-pfrom)
772 // = pface*(1+alpha)-pfrom*alpha
773 // = (sum(p)-pfrom)/N*(1+alpha)-pfrom*alpha
774 // = sum(p)/N*(1+alpha)-pfrom*(alpha+(1+alpha)/N)
775 // = sum(p)/(N+1) * (1+alpha)*((N+1)/N) -
776 // pfrom*[1/N+alpha*(N+1)/N] = pcenter * (1+alpha)*((N+1)/N) -
777 // pfrom*(1/N-(N+1)/N+(1+alpha)*(N+1)/N) = pcenter *
778 // (1+alpha)*((N+1)/N) - pfrom*(-1+(1+alpha)*(N+1)/N)
779 //
780 // let beta = (1+alpha)*((N+1)/N);
781 //
782 // pe = pcenter * beta + pfrom * (1-beta)
783
784#define CMD "Optimist::Optimizer::NelderMead::extrapolate(...): "
785
786 Scalar const beta_1{(1.0 + alpha) / static_cast<Scalar>(this->m_n)};
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);
789 Scalar f;
790 bool success{
791 this->evaluate_function(std::forward<FunctionLambda>(function),
792 p,
793 f)};
794 OPTIMIST_ASSERT(success,
795 CMD "function evaluation failed during extrapolation.");
796 return f;
797
798#undef CMD
799 }
800
808 template <typename FunctionLambda>
809 Scalar reflect(FunctionLambda &&function, Vector &p) {
810 return this->extrapolate(std::forward<FunctionLambda>(function),
811 this->m_rho,
812 this->m_high,
813 p);
814 }
815
823 template <typename FunctionLambda>
824 Scalar expand(FunctionLambda &&function, Vector &p) {
825 return this->extrapolate(std::forward<FunctionLambda>(function),
826 this->m_rho * this->m_chi,
827 this->m_high,
828 p);
829 }
830
838 template <typename FunctionLambda>
839 Scalar outside(FunctionLambda &&function, Vector &p) {
840 return this->extrapolate(std::forward<FunctionLambda>(function),
841 this->m_rho * this->m_gamma,
842 this->m_high,
843 p);
844 }
845
853 template <typename FunctionLambda>
854 Scalar inside(FunctionLambda &&function, Vector &p) {
855 return this->extrapolate(std::forward<FunctionLambda>(function),
856 -this->m_gamma,
857 this->m_high,
858 p);
859 }
860
861 }; // class NelderMead
862
863 } // namespace Optimizer
864
865} // namespace Optimist
866
867#endif // OPTIMIST_OPTIMIZER_NELDER_MEAD_HH
#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
#define CMD
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
void info(Scalar residuals, const std::string &notes="-")
Definition SolverBase.hh:1230
bool evaluate_function(FunctionLambda &&function, const Vector &x, TypeTrait< Vector >::Scalar &out)
Definition SolverBase.hh:1040
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