Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
SolverBase.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco, Mattia Piazza and Enrico Bertolazzi. *
3 * *
4 * The Optimist project is distributed under the BSD 2-Clause License. *
5 * *
6 * Davide Stocco Mattia Piazza Enrico Bertolazzi *
7 * University of Trento University of Trento University of Trento *
8 * davide.stocco@unitn.it mattia.piazza@unitn.it enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#pragma once
12
13#ifndef OPTIMIST_SOLVER_HH
14#define OPTIMIST_SOLVER_HH
15
16#include "Optimist.hh"
17#include "Optimist/Function.hh"
18
19namespace Optimist
20{
21
22 /*\
23 | ____ _ ____
24 | / ___| ___ | |_ _____ _ __| __ ) __ _ ___ ___
25 | \___ \ / _ \| \ \ / / _ \ '__| _ \ / _` / __|/ _ \
26 | ___) | (_) | |\ V / __/ | | |_) | (_| \__ \ __/
27 | |____/ \___/|_| \_/ \___|_| |____/ \__,_|___/\___|
28 |
29 \*/
30
42 template <typename Real, Integer SolInDim, Integer SolOutDim, typename DerivedSolver, bool ForceEigen = false>
44 {
45 public:
46 // Fancy static assertions (just for fun, don't take it too seriously)
47 static_assert(SolInDim > 0 && SolOutDim > 0,
48 "Negative-dimensional optimization problem? Are you serious?");
49
51
52 // I/O types
53 using InputType = typename std::conditional_t<ForceEigen || (SolInDim > 1),
54 Eigen::Vector<Real, SolInDim>, Real>;
55 using OutputType = typename std::conditional_t<ForceEigen || (SolOutDim > 1),
56 Eigen::Vector<Real, SolOutDim>, Real>;
57
58 // Trace types
59 using TraceType = typename std::vector<InputType>;
60
61 // Derivative types
62 using FirstDerivativeType = std::conditional_t<ForceEigen || (SolInDim > 1) || (SolOutDim > 1),
63 Eigen::Matrix<Real, SolOutDim, SolInDim>, Real>;
64 using SecondDerivativeType = std::conditional_t<ForceEigen || (SolInDim > 1) || (SolOutDim > 1),
65 std::conditional_t<SolInDim == 1 || SolOutDim == 1, Eigen::Matrix<Real, SolInDim, SolInDim>,
66 std::vector<Eigen::Matrix<Real, SolInDim, SolInDim>>>, Real>;
67
68 protected:
69 // Bounds (may not be used)
72
73 // Evaluations
77
78 // Maximum allowed evaluations
82
83 // Iterations and relaxations
86 Real m_alpha{0.8};
89
90 // Settings
91 Real m_tolerance{EPSILON_LOW};
92 bool m_verbose{false};
93 bool m_damped{true};
94 std::ostream * m_ostream{&std::cout};
95
96 // Convergence output flag and trace
97 std::string m_task{"Undefined"};
98 bool m_converged{false};
100
101 public:
106 if constexpr (ForceEigen || SolInDim > 1) {
107 this->m_lower_bound.setConstant(-INFTY);
108 this->m_upper_bound.setConstant(INFTY);
109 } else {
110 this->m_lower_bound = -INFTY;
111 this->m_upper_bound = INFTY;
112 }
113 this->m_trace.reserve(this->m_max_iterations * this->m_max_relaxations);
114 }
115
123 template <typename FunctionLambda>
124 SolverBase(FunctionLambda && function, InputType const & x_ini, InputType & x_sol) : SolverBase() {
125 static_cast<const DerivedSolver *>(this)->solve_impl(
126 std::forward<FunctionLambda>(function),
127 x_ini, x_sol);
128 }
129
139 template <typename FunctionLambda, typename FirstDerivativeLambda>
140 SolverBase(FunctionLambda && function, FirstDerivativeLambda && first_derivative, InputType const & x_ini,
141 InputType & x_sol) : SolverBase()
142 {
143 static_cast<const DerivedSolver *>(this)->solve_impl(
144 std::forward<FunctionLambda>(function),
145 std::forward<FirstDerivativeLambda>(first_derivative),
146 x_ini, x_sol);
147 }
148
160 template <typename FunctionLambda, typename FirstDerivativeLambda, typename SecondDerivativeLambda>
161 SolverBase(FunctionLambda && function, FirstDerivativeLambda && first_derivative, SecondDerivativeLambda
162 && second_derivative, InputType const & x_ini, InputType & x_sol) : SolverBase()
163 {
164 static_cast<const DerivedSolver *>(this)->solve_impl(
165 std::forward<FunctionLambda>(function),
166 std::forward<FirstDerivativeLambda>(first_derivative),
167 std::forward<SecondDerivativeLambda>(second_derivative),
168 x_ini, x_sol);
169 }
170
175 InputType const & lower_bound() const {return this->m_lower_bound;}
176
181 void lower_bound(InputType const & t_lower_bound) {
182 #define CMD "Optimist::Solver::bounds(...): "
183
184 if constexpr (ForceEigen || SolInDim > 1) {
185 OPTIMIST_ASSERT((this->m_upper_bound - t_lower_bound).minCoeff() <= 0.0,
186 CMD "invalid or degenarate bounds detected.");
187 } else {
188 OPTIMIST_ASSERT(this->m_upper_bound > t_lower_bound,
189 CMD "invalid or degenarate bounds detected.");
190 }
191 this->m_lower_bound = t_lower_bound;
192
193 #undef CMD
194 }
195
200 InputType const & upper_bound() const {return this->m_upper_bound;}
201
206 void upper_bound(InputType const & t_upper_bound) {
207 #define CMD "Optimist::Solver::bounds(...): "
208
209 if constexpr (ForceEigen || SolInDim > 1) {
210 OPTIMIST_ASSERT((t_upper_bound - this->m_lower_bound).minCoeff() <= 0.0,
211 CMD "invalid or degenarate bounds detected.");
212 } else {
213 OPTIMIST_ASSERT(t_upper_bound > this->m_lower_bound,
214 CMD "invalid or degenarate bounds detected.");
215 }
216 this->m_upper_bound = t_upper_bound;
217
218 #undef CMD
219 }
220
226 void bounds(InputType const & t_lower_bound, InputType const & t_upper_bound)
227 {
228 #define CMD "Optimist::Solver::bounds(...): "
229
230 if constexpr (ForceEigen || SolInDim > 1) {
231 OPTIMIST_ASSERT((t_upper_bound - t_lower_bound).minCoeff() <= 0.0,
232 CMD "invalid or degenarate bounds detected.");
233 } else {
234 OPTIMIST_ASSERT(t_upper_bound > t_lower_bound,
235 CMD "invalid or degenarate bounds detected.");
236 }
237 this->m_lower_bound = t_lower_bound;
238 this->m_upper_bound = t_upper_bound;
239
240 #undef CMD
241 }
242
247 constexpr Integer input_dimension() const {return SolInDim;}
248
253 constexpr Integer output_dimension() const {return SolOutDim;}
254
260
265 void max_function_evaluations(Integer t_max_function_evaluations)
266 {
267 OPTIMIST_ASSERT(t_max_function_evaluations > 0,
268 "Optimist::Solver::max_function_evaluations(...): invalid input detected.");
269 this->m_max_function_evaluations = t_max_function_evaluations;
270 }
271
276 Integer max_function_evaluations() const {return this->m_max_function_evaluations;}
277
278 protected:
283 Integer first_derivative_evaluations() const {return this->m_first_derivative_evaluations;}
284
289 Integer max_first_derivative_evaluations() const {return this->m_max_first_derivative_evaluations;}
290
296 {
298 "Optimist::Solver::max_first_derivative_evaluations(...): invalid input detected.");
299 this->m_max_first_derivative_evaluations = first_derivative_evaluations;
300 }
301
306 Integer second_derivative_evaluations() const {return this->m_second_derivative_evaluations;}
307
312 Integer max_second_derivative_evaluations() const {return this->m_max_second_derivative_evaluations;}
313
319 {
321 "Optimist::Solver::max_second_derivative_evaluations(...): invalid input detected.");
322 this->m_max_second_derivative_evaluations = second_derivative_evaluations;
323 }
324
325 public:
329 Integer iterations() const {return this->m_iterations;}
330
335 Integer max_iterations() const {return this->max_iterations;}
336
341 void max_iterations(Integer t_max_iterations) {
342 OPTIMIST_ASSERT(t_max_iterations > 0,
343 "Optimist::Solver::max_iterations(...): invalid input detected.");
344 this->m_max_iterations = t_max_iterations;
345 }
346
351 Real alpha() const {return this->m_alpha;}
352
357 void alpha(Real t_alpha)
358 {
360 !std::isnan(t_alpha) && std::isfinite(t_alpha) && 0.0 <= t_alpha && t_alpha <= 1.0,
361 "Optimist::Solver::alpha(...): invalid input detected.");
362 this->m_alpha = t_alpha;
363 }
364
369 Integer relaxations() const {return this->m_relaxations;}
370
376
381 void max_relaxations(Integer t_max_relaxations)
382 {
383 OPTIMIST_ASSERT(t_max_relaxations > 0,
384 "Optimist::Solver::max_relaxations(...): invalid input detected.");
385 this->m_max_relaxations = t_max_relaxations;
386 }
387
392 Real tolerance() const {return this->m_tolerance;}
393
399 void tolerance(Real t_tolerance) {
400 OPTIMIST_ASSERT(!std::isnan(t_tolerance) && std::isfinite(t_tolerance) && t_tolerance > 0.0,
401 "Optimist::Solver::tolerance(...): invalid input detected.");
402 this->m_tolerance = t_tolerance;
403 }
404
409 void verbose_mode(bool t_verbose) {this->m_verbose = t_verbose;}
410
415 bool verbose_mode() const {return this->m_verbose;}
416
420 void enable_verbose_mode() {this->m_verbose = true;}
421
425 void disable_verbose_mode() {this->m_verbose = false;}
426
431 void damped_mode(bool t_damped) {this->m_damped = t_damped;}
432
437 bool damped_mode() const {return this->m_damped;}
438
442 void enable_damped_mode() {this->m_damped = true;}
443
447 void disable_damped_mode() {this->m_damped = false;}
448
453 std::string task() const {return this->m_task;}
454
459 void task(std::string t_task) {this->m_task = t_task;}
460
465 bool converged() const {return this->m_converged;}
466
471 const TraceType & trace() const {return this->m_trace;}
472
477 std::ostream & ostream() const {return *this->m_ostream;}
478
483 void ostream(std::ostream & t_ostream) {this->m_ostream = &t_ostream;}
484
493 template <typename FunctionLambda>
494 bool solve(FunctionLambda && function, InputType const & x_ini, InputType & x_sol)
495 {
496 #define CMD "Optimist::Solver::solve(...): "
497
498 static_assert(DerivedSolver::requires_function,
499 CMD "the solver requires a function.");
500 return static_cast<DerivedSolver *>(this)->solve(
501 std::forward<FunctionLambda>(function),
502 nullptr, nullptr, x_ini, x_sol);
503
504 #undef CMD
505 }
506
517 template <typename FunctionLambda, typename FirstDerivativeLambda>
518 bool solve(FunctionLambda && function, FirstDerivativeLambda && first_derivative, InputType const & x_ini,
519 InputType & x_sol)
520 {
521 #define CMD "Optimist::Solver::solve(...): "
522
523 static_assert(DerivedSolver::requires_function,
524 CMD "the solver requires a function.");
525 static_assert(DerivedSolver::requires_first_derivative,
526 CMD "the solver requires the first derivative.");
527 return static_cast<DerivedSolver *>(this)->solve(
528 std::forward<FunctionLambda>(function),
529 std::forward<FirstDerivativeLambda>(first_derivative),
530 nullptr, x_ini, x_sol);
531
532 #undef CMD
533 }
534
547 template <typename FunctionLambda, typename FirstDerivativeLambda, typename SecondDerivativeLambda>
548 bool solve(FunctionLambda && function, FirstDerivativeLambda && first_derivative, SecondDerivativeLambda
549 && second_derivative, InputType const & x_ini, InputType & x_sol)
550 {
551 #define CMD "Optimist::Solver::solve(...): "
552
553 static_assert(DerivedSolver::requires_function,
554 CMD "the solver requires the function.");
555 static_assert(DerivedSolver::requires_first_derivative,
556 CMD "the solver requires the first derivative.");
557 static_assert(DerivedSolver::requires_second_derivative,
558 CMD "the solver requires the second derivative.");
559 return static_cast<DerivedSolver *>(this)->solve(
560 std::forward<FunctionLambda>(function),
561 std::forward<FirstDerivativeLambda>(first_derivative),
562 std::forward<SecondDerivativeLambda>(second_derivative),
563 x_ini, x_sol);
564
565 #undef CMD
566 }
567
578 template <Integer FunInDim, Integer FunOutDim, typename DerivedFunction>
580 InputType const & x_ini, InputType & x_sol)
581 {
582 #define CMD "Optimist::Solver::rootfind(...): "
583
584 static_assert(SolInDim == FunInDim,
585 CMD "solver input dimension must be equal to the function input dimension.");
586 static_assert(SolOutDim == FunOutDim || SolOutDim == 1,
587 CMD "solver output dimension must be equal to the function output dimension or 1.");
588 static_assert(!(SolInDim == 1 && DerivedSolver::is_optimizer),
589 CMD "one-dimensional optimizers do not support root-finding problems.");
590 return this->solve(function, x_ini, x_sol, SolOutDim != FunOutDim || (SolInDim > 1 && SolOutDim == 1));
591
592 #undef CMD
593 }
594
605 template <Integer FunInDim, Integer FunOutDim, typename DerivedFunction>
607 InputType const & x_ini, InputType & x_sol)
608 {
609 #define CMD "Optimist::Solver::optimize(...): "
610
611 static_assert(SolInDim == FunInDim,
612 CMD "solver input dimension must be equal to the function input dimension.");
613 static_assert(SolOutDim == 1,
614 CMD "solver output dimension must be equal to the function output dimension or 1.");
615 static_assert(!(SolInDim == 1 && DerivedSolver::is_rootfinder),
616 CMD "one-dimensional root-finders do not support optimization problems.");
617 return this->solve(function, x_ini, x_sol, true);
618
619 #undef CMD
620 }
621
626 std::string name() const {return static_cast<const DerivedSolver *>(this)->name_impl();};
627
628 protected:
640 template <Integer FunInDim, Integer FunOutDim, typename DerivedFunction>
642 const & function, InputType const & x_ini, InputType & x_sol, bool is_optimization)
643 {
644 #define CMD "Optimist::Solver::solve(...): "
645
647
648 static_assert(SolInDim == FunInDim,
649 CMD "solver input dimension must be equal to the function input dimension.");
650 static_assert(SolOutDim == FunOutDim || SolOutDim == 1,
651 CMD "solver output dimension must be equal to the function output dimension or 1.");
652
653 // Lambda generators for function and derivatives
654 auto function_lambda = [&function, is_optimization] (InputType const & x, OutputType & out) -> bool
655 {
656 bool success{false};
657 typename FunctionType::OutputType f; success = function.evaluate(x, f);
658 OPTIMIST_ASSERT(success,
659 CMD "function evaluation failed during function computation.");
660
661 if (is_optimization) {
662 if constexpr (FunOutDim == 1) {out = 0.5*f*f;}
663 else if constexpr (SolOutDim != FunOutDim) {out = 0.5*f.squaredNorm();}
664 else {OPTIMIST_ERROR(CMD "optimization problem with inconsistent output in function.");}
665 } else {
666 if constexpr (SolOutDim == FunOutDim) {out = f;}
667 else {OPTIMIST_ERROR(CMD "root-finding problem with inconsistent output in function.");}
668 }
669 return success;
670 };
671
672 auto first_derivative_lambda = [&function, is_optimization, this] (InputType const & x,
673 FirstDerivativeType & out) -> bool
674 {
675 bool success{false};
676 typename FunctionType::FirstDerivativeType J; success = function.first_derivative(x, J);
677 OPTIMIST_ASSERT(success,
678 CMD "first derivative evaluation failed during first derivative computation.");
679
680 if (is_optimization) {
681 bool success{false};
682 typename FunctionType::OutputType f; success = function.evaluate(x, f);
683 OPTIMIST_ASSERT(success,
684 CMD "function evaluation failed during first derivative computation.");
686 if constexpr (FunInDim == 1 && FunOutDim == 1) {out = J*f;}
687 else if constexpr (SolOutDim != FunOutDim) {out = J.transpose()*f;}
688 else {OPTIMIST_ERROR(CMD "optimization problem inconsistent output in first derivative.");}
689 } else {
690 if constexpr (SolOutDim == FunOutDim) {out = J;}
691 else {OPTIMIST_ERROR(CMD "root-finding problem with inconsistent output in first derivative.");}
692 }
693 return success;
694 };
695
696 auto second_derivative_lambda = [&function, is_optimization, this] (InputType const & x,
697 SecondDerivativeType & out) -> bool
698 {
699 bool success{false};
700 typename FunctionType::SecondDerivativeType H; success = function.second_derivative(x, H);
701 OPTIMIST_ASSERT(success,
702 CMD "function evaluation failed during second derivative computation.");
703
704 if (is_optimization) {
705 typename FunctionType::OutputType f; success = function.evaluate(x, f);
707 OPTIMIST_ASSERT(success,
708 CMD "function evaluation failed during second derivative computation.");
709 typename FunctionType::FirstDerivativeType J; success = function.first_derivative(x, J);
710 this->m_first_derivative_evaluations++;
711 OPTIMIST_ASSERT(success,
712 CMD "first derivative evaluation failed during second derivative computation.");
713 if constexpr (FunInDim == 1 && FunOutDim == 1) {out = J*J + f*H;}
714 else if constexpr (SolOutDim != FunOutDim) {
715 out = J.transpose()*J;
716 for (Integer i{0}; i < static_cast<Integer>(H.size()); ++i) {out += f(i)*H[i];}
717 }
718 else {OPTIMIST_ERROR(CMD "optimization problem with inconsistent output in second derivative.");}
719 } else {
720 if constexpr (SolOutDim == FunOutDim) {out = H;}
721 else {OPTIMIST_ERROR(CMD "root-finding problem with inconsistent output in second derivative.");}
722 }
723 return success;
724 };
725
726 // Select solver method based on derivative requirements
727 if constexpr (DerivedSolver::requires_function && !DerivedSolver::requires_first_derivative &&
728 !DerivedSolver::requires_second_derivative) {
729 return static_cast<DerivedSolver *>(this)->solve(function_lambda, x_ini, x_sol);
730 } else if constexpr (DerivedSolver::requires_function && DerivedSolver::requires_first_derivative &&
731 !DerivedSolver::requires_second_derivative) {
732 return static_cast<DerivedSolver *>(this)->solve(function_lambda, first_derivative_lambda,
733 x_ini, x_sol);
734 } else if constexpr (DerivedSolver::requires_function && DerivedSolver::requires_first_derivative &&
735 DerivedSolver::requires_second_derivative) {
736 return static_cast<DerivedSolver *>(this)->solve(function_lambda, first_derivative_lambda,
737 second_derivative_lambda, x_ini, x_sol);
738 } else {
739 OPTIMIST_ERROR(CMD "no matching function signature found for the solver.");
740 }
741
742 #undef CMD
743 }
744
748 void reset()
749 {
750 this->m_function_evaluations = 0;
751 this->m_first_derivative_evaluations = 0;
752 this->m_second_derivative_evaluations = 0;
753 this->m_iterations = 0;
754 this->m_relaxations = 0;
755 this->m_converged = false;
756 this->m_trace.clear();
757 }
758
767 template <typename FunctionLambda>
768 bool evaluate_function(FunctionLambda && function, InputType const & x, OutputType & out)
769 {
770 OPTIMIST_ASSERT(this->m_function_evaluations < this->m_max_function_evaluations,
771 "Optimist::" << this-> name() << "::evaluate_function(...): maximum allowed function evaluations reached.");
773 return function(x, out);
774 }
775
784 template <typename FirstDerivativeLambda>
785 bool evaluate_first_derivative(FirstDerivativeLambda && function, InputType const & x, FirstDerivativeType & out)
786 {
787 OPTIMIST_ASSERT(this->m_first_derivative_evaluations < this->m_max_first_derivative_evaluations,
788 "Optimist::" << this-> name() << "::evaluate_first_derivative(...): maximum allowed first derivative evaluations reached.");
789 ++this->m_first_derivative_evaluations;
790 return function(x, out);
791 }
792
800 template <typename SecondDerivativeLambda>
801 bool evaluate_second_derivative(SecondDerivativeLambda && function, InputType const & x, SecondDerivativeType & out)
802 {
803 OPTIMIST_ASSERT(this->m_second_derivative_evaluations < this->m_max_second_derivative_evaluations,
804 "Optimist::" << this-> name() << "::evaluate_second_derivative(...): maximum allowed second derivative evaluations reached.");
805 ++this->m_second_derivative_evaluations;
806 return function(x, out);
807 }
808
813 void store_trace(InputType const & x) {this->m_trace.push_back(x);}
814
827 template <typename FunctionLambda>
828 bool damp(FunctionLambda && function, InputType const & x_old, InputType const & function_old,
829 InputType const & step_old, InputType & x_new, InputType & function_new, InputType & step_new)
830 {
831 #define CMD "Optimist::Solver::damp(...): "
832
833 Real step_norm_old, step_norm_new, residuals_old, residuals_new, tau{1.0};
834 for (this->m_relaxations = 0; this->m_relaxations < this->m_max_relaxations; ++this->m_relaxations)
835 {
836 // Update point
837 step_new = tau * step_old;
838 x_new = x_old + step_new;
839 bool success{this->evaluate_function(std::forward<FunctionLambda>(function), x_new, function_new)};
840 OPTIMIST_ASSERT(success,
841 CMD "function evaluation failed during damping.");
842
843 // Check relaxation
844 if constexpr (ForceEigen || (SolInDim > 1 && SolOutDim > 1)) {
845 residuals_old = function_old.norm();
846 residuals_new = function_new.norm();
847 step_norm_old = step_old.norm();
848 step_norm_new = step_new.norm();
849 } else {
850 residuals_old = std::abs(function_old);
851 residuals_new = std::abs(function_new);
852 step_norm_old = std::abs(step_old);
853 step_norm_new = std::abs(step_new);
854 }
855 if (residuals_new < residuals_old || step_norm_new < (Real(1.0)-tau/Real(2.0))*step_norm_old) {
856 return true;
857 } else {
858 tau *= this->m_alpha;
859 }
860 }
861 return false;
862
863 #undef CMD
864 }
865
870 void header()
871 {
872 std::string c_tl{table_top_left_corner()};
873 std::string c_tr{table_top_right_corner()};
874 std::string h_7{table_horizontal_line<7>()};
875 std::string h_14{table_horizontal_line<14>()};
876 std::string h_23{table_horizontal_line<23>()};
877 std::string h_78{table_horizontal_line<78>()};
878 std::string v_ll{table_vertical_line() + " "};
879 std::string v_rr{" " + table_vertical_line()};
880 std::string v_lc{" " + table_vertical_line() + " "};
881 std::string j_tt{table_top_junction()};
882 std::string j_cc{table_center_cross()};
883 std::string j_ll{table_left_junction()};
884 std::string j_rr{table_right_junction()};
885
886 *this->m_ostream
887 << c_tl << h_78 << c_tr << std::endl
888 << v_ll << "Solver:" << std::setw(69) << this->name() << v_rr << std::endl
889 << v_ll << "Task: " << std::setw(69) << this->task() << v_rr << std::endl
890 << j_ll << h_7 << j_tt << h_7 << j_tt << h_7 << j_tt << h_7 << j_tt << h_7 << j_tt << h_14 << j_tt << h_23 << j_rr << std::endl
891 << v_ll << "#Iter" << v_lc << " #f" << v_lc << " #Df" << v_lc << " #DDf" << v_lc << " #Rlx" << v_lc
892 << " ║f(x)║₂ " << v_lc << "Additional notes" << std::setw(9) << v_rr << std::endl
893 << j_ll << h_7 << j_cc << h_7 << j_cc << h_7 << j_cc << h_7 << j_cc << h_7 << j_cc << h_14 << j_cc << h_23 << j_rr << std::endl;
894 }
895
900 void bottom()
901 {
902 std::string c_bl{table_bottom_left_corner()};
903 std::string c_br{table_bottom_right_corner()};
904 std::string h_7{table_horizontal_line<7>()};
905 std::string h_14{table_horizontal_line<14>()};
906 std::string h_23{table_horizontal_line<23>()};
907 std::string h_78{table_horizontal_line<78>()};
908 std::string v_ll{table_vertical_line() + " "};
909 std::string v_rr{" " + table_vertical_line()};
910 std::string j_ll{table_left_junction()};
911 std::string j_rr{table_right_junction()};
912 std::string j_bb{table_bottom_junction()};
913
914 *this->m_ostream
915 << j_ll << h_7 << j_bb << h_7 << j_bb << h_7 << j_bb << h_7 << j_bb << h_7 << j_bb << h_14 << j_bb << h_23 << j_rr << std::endl
916 << v_ll << std::setw(40) << (this->m_converged ? "CONVERGED" : "NOT CONVERGED") << std::setw(40) << v_rr << std::endl
917 << c_bl << h_78 << c_br << std::endl;
918 }
919
924 void info(Real residuals, std::string const & notes = "-")
925 {
926 std::string v_rr{" " + table_vertical_line()};
927 std::string v_ll{table_vertical_line() + " "};
928 std::string v_lc{" " + table_vertical_line() + " "};
929
930 *this->m_ostream << v_ll
931 << std::setw(5) << this->m_iterations << v_lc
932 << std::setw(5) << this->m_function_evaluations << v_lc
933 << std::setw(5) << this->m_first_derivative_evaluations << v_lc
934 << std::setw(5) << this->m_second_derivative_evaluations << v_lc
935 << std::setw(5) << this->m_relaxations << v_lc
936 << std::setw(12) << std::scientific << std::setprecision(6) << residuals << v_lc
937 << notes << std::setw(25-notes.length()) << v_rr << std::endl;
938 }
939
940 }; // class Solver
941
942} // namespace Optimist
943
944#endif // OPTIMIST_SOLVER_HH
#define OPTIMIST_ERROR(MSG)
Definition Optimist.hh:34
#define OPTIMIST_BASIC_CONSTANTS(Real)
Definition Optimist.hh:71
#define OPTIMIST_ASSERT(COND, MSG)
Definition Optimist.hh:44
#define CMD
Class container for the generic function.
Definition Function.hh:43
bool second_derivative(const InputType &x, SecondDerivativeType &out) const
Definition Function.hh:108
bool first_derivative(const InputType &x, FirstDerivativeType &out) const
Definition Function.hh:97
bool evaluate(const InputType &x, OutputType &out) const
Definition Function.hh:86
Integer max_iterations() const
Definition SolverBase.hh:335
typename std::vector< InputType > TraceType
Definition SolverBase.hh:59
bool m_damped
Definition SolverBase.hh:93
bool evaluate_second_derivative(SecondDerivativeLambda &&function, InputType const &x, SecondDerivativeType &out)
Definition SolverBase.hh:801
void lower_bound(InputType const &t_lower_bound)
Definition SolverBase.hh:181
void max_second_derivative_evaluations(Integer second_derivative_evaluations)
Definition SolverBase.hh:318
void ostream(std::ostream &t_ostream)
Definition SolverBase.hh:483
bool converged() const
Definition SolverBase.hh:465
InputType const & upper_bound() const
Definition SolverBase.hh:200
void alpha(Real t_alpha)
Definition SolverBase.hh:357
Integer max_first_derivative_evaluations() const
Definition SolverBase.hh:289
void max_iterations(Integer t_max_iterations)
Definition SolverBase.hh:341
void info(Real residuals, std::string const &notes="-")
Definition SolverBase.hh:924
constexpr Integer output_dimension() const
Definition SolverBase.hh:253
const TraceType & trace() const
Definition SolverBase.hh:471
Integer m_iterations
Definition SolverBase.hh:84
Integer max_relaxations() const
Definition SolverBase.hh:375
typename std::conditional_t< ForceEigen||(SolOutDim > 1), Eigen::Vector< Real, SolOutDim >, Real > OutputType
Definition SolverBase.hh:55
Real alpha() const
Definition SolverBase.hh:351
bool damp(FunctionLambda &&function, InputType const &x_old, InputType const &function_old, InputType const &step_old, InputType &x_new, InputType &function_new, InputType &step_new)
Definition SolverBase.hh:828
Integer m_max_iterations
Definition SolverBase.hh:85
std::string task() const
Definition SolverBase.hh:453
void enable_damped_mode()
Definition SolverBase.hh:442
SolverBase(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, SecondDerivativeLambda &&second_derivative, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:161
Integer relaxations() const
Definition SolverBase.hh:369
SolverBase(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:140
void verbose_mode(bool t_verbose)
Definition SolverBase.hh:409
void store_trace(InputType const &x)
Definition SolverBase.hh:813
std::string name() const
Definition SolverBase.hh:626
void header()
Definition SolverBase.hh:870
Integer max_second_derivative_evaluations() const
Definition SolverBase.hh:312
Integer function_evaluations() const
Definition SolverBase.hh:259
Real tolerance() const
Definition SolverBase.hh:392
Integer iterations() const
Definition SolverBase.hh:329
bool solve(FunctionBase< Real, FunInDim, FunOutDim, DerivedFunction, ForceEigen &&FunOutDim==1 > const &function, InputType const &x_ini, InputType &x_sol, bool is_optimization)
Definition SolverBase.hh:641
void reset()
Definition SolverBase.hh:748
void max_relaxations(Integer t_max_relaxations)
Definition SolverBase.hh:381
std::ostream & ostream() const
Definition SolverBase.hh:477
void bounds(InputType const &t_lower_bound, InputType const &t_upper_bound)
Definition SolverBase.hh:226
bool solve(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:518
void damped_mode(bool t_damped)
Definition SolverBase.hh:431
SolverBase(FunctionLambda &&function, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:124
Integer m_max_first_derivative_evaluations
Definition SolverBase.hh:80
bool m_verbose
Definition SolverBase.hh:92
Integer m_max_second_derivative_evaluations
Definition SolverBase.hh:81
bool m_converged
Definition SolverBase.hh:98
bool solve(FunctionLambda &&function, FirstDerivativeLambda &&first_derivative, SecondDerivativeLambda &&second_derivative, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:548
Real m_alpha
Definition SolverBase.hh:86
InputType m_upper_bound
Definition SolverBase.hh:71
void enable_verbose_mode()
Definition SolverBase.hh:420
void disable_damped_mode()
Definition SolverBase.hh:447
constexpr Integer input_dimension() const
Definition SolverBase.hh:247
Integer max_function_evaluations() const
Definition SolverBase.hh:276
TraceType m_trace
Definition SolverBase.hh:99
bool verbose_mode() const
Definition SolverBase.hh:415
Integer second_derivative_evaluations() const
Definition SolverBase.hh:306
void upper_bound(InputType const &t_upper_bound)
Definition SolverBase.hh:206
InputType const & lower_bound() const
Definition SolverBase.hh:175
void bottom()
Definition SolverBase.hh:900
SolverBase()
Definition SolverBase.hh:105
std::ostream * m_ostream
Definition SolverBase.hh:94
bool evaluate_function(FunctionLambda &&function, InputType const &x, OutputType &out)
Definition SolverBase.hh:768
Integer m_function_evaluations
Definition SolverBase.hh:74
std::conditional_t< ForceEigen||(SolInDim > 1)||(SolOutDim > 1), std::conditional_t< SolInDim==1||SolOutDim==1, Eigen::Matrix< Real, SolInDim, SolInDim >, std::vector< Eigen::Matrix< Real, SolInDim, SolInDim > > >, Real > SecondDerivativeType
Definition SolverBase.hh:64
Integer m_first_derivative_evaluations
Definition SolverBase.hh:75
Integer m_relaxations
Definition SolverBase.hh:87
void max_first_derivative_evaluations(Integer first_derivative_evaluations)
Definition SolverBase.hh:295
Real m_tolerance
Definition SolverBase.hh:91
std::string m_task
Definition SolverBase.hh:97
bool rootfind(FunctionBase< Real, FunInDim, FunOutDim, DerivedFunction, ForceEigen &&FunOutDim==1 > const &function, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:579
bool damped_mode() const
Definition SolverBase.hh:437
typename std::conditional_t< ForceEigen||(SolInDim > 1), Eigen::Vector< Real, SolInDim >, Real > InputType
Definition SolverBase.hh:53
Integer m_second_derivative_evaluations
Definition SolverBase.hh:76
std::conditional_t< ForceEigen||(SolInDim > 1)||(SolOutDim > 1), Eigen::Matrix< Real, SolOutDim, SolInDim >, Real > FirstDerivativeType
Definition SolverBase.hh:62
bool optimize(FunctionBase< Real, FunInDim, FunOutDim, DerivedFunction, ForceEigen &&FunOutDim==1 > const &function, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:606
Integer m_max_relaxations
Definition SolverBase.hh:88
Integer first_derivative_evaluations() const
Definition SolverBase.hh:283
void disable_verbose_mode()
Definition SolverBase.hh:425
void tolerance(Real t_tolerance)
Definition SolverBase.hh:399
Integer m_max_function_evaluations
Definition SolverBase.hh:79
bool evaluate_first_derivative(FirstDerivativeLambda &&function, InputType const &x, FirstDerivativeType &out)
Definition SolverBase.hh:785
void max_function_evaluations(Integer t_max_function_evaluations)
Definition SolverBase.hh:265
void task(std::string t_task)
Definition SolverBase.hh:459
bool solve(FunctionLambda &&function, InputType const &x_ini, InputType &x_sol)
Definition SolverBase.hh:494
InputType m_lower_bound
Definition SolverBase.hh:70
Namespace for the Optimist library.
Definition Optimist.hh:88
static std::string table_vertical_line()
Retrieve the Unicode character for the vertical line of a table.
Definition Optimist.hh:174
static std::string table_bottom_right_corner()
Retrieve the Unicode character for the bottom-right corner of a table.
Definition Optimist.hh:120
static std::string table_top_left_corner()
Retrieve the Unicode character for the top-left corner of a table.
Definition Optimist.hh:102
static std::string table_bottom_left_corner()
Retrieve the Unicode character for the bottom-left corner of a table.
Definition Optimist.hh:114
OPTIMIST_DEFAULT_INTEGER_TYPE Integer
The Integer type as used for the API.
Definition Optimist.hh:96
static std::string table_center_cross()
Retrieve the Unicode character for the center cross of a table.
Definition Optimist.hh:150
static std::string table_bottom_junction()
Retrieve the Unicode character for the bottom junction of a table.
Definition Optimist.hh:144
static std::string table_top_junction()
Retrieve the Unicode character for the top junction of a table.
Definition Optimist.hh:138
static std::string table_top_right_corner()
Retrieve the Unicode character for the top-right corner of a table.
Definition Optimist.hh:108
static std::string table_horizontal_line()
Retrieve the Unicode character for the horizontal line of a table.
Definition Optimist.hh:156
static std::string table_right_junction()
Retrieve the Unicode character for the right junction of a table.
Definition Optimist.hh:132
static std::string table_left_junction()
Retrieve the Unicode character for the left junction of a table.
Definition Optimist.hh:126