diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aac940c..53032785 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,3 +146,13 @@ INSTALL(TARGETS ${INSTALL_TARGETS} RUNTIME DESTINATION ${RUNTIME_INSTALL_DIR} ) INSTALL(EXPORT fatropConfig NAMESPACE fatrop:: DESTINATION cmake) + +# create an option for compiling the tests +option(BUILD_TESTS "Build tests" OFF) +# if the option is set to ON, add the tests directory +if(BUILD_TESTS) + enable_testing() + add_subdirectory(unittest) +endif() + + diff --git a/README.md b/README.md index 248b0a03..fb3af808 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ The main features of the solver are: ## Disclaimer -At this moment the easiest way to get specify fatrop problems is by using the [rockit](https://gitlab.kuleuven.be/meco-software/rockit) interface. See [Install rockit with Fatropy interface](#install-rockit-with-fatropy-interface) for installation instructions. The fatrop-rockit-plugin is not very stable yet, and still under development. Apart form the rockit interface, we are working on a ocp specification framework, especially developed for specifying Fatrop problems. An example is available in the **specification** branch, spectool/example.cpp. +At this moment the easiest way to get specify fatrop problems is by using the [rockit](https://gitlab.kuleuven.be/meco-software/rockit) interface. See [Install rockit with Fatropy interface](#install-rockit-with-fatropy-interface) for installation instructions. The fatrop-rockit-plugin is not very stable yet, and still under development. Apart form the rockit interface, we are working on a ocp specification framework, especially developed for specifying Fatrop problems. The spectool has several advantages over the rockit interface: - it supports fatrop problems in all its generality. For example: multi-stage problems are not supported by the fatrop-rockit-interface diff --git a/fatrop/CMakeLists.txt b/fatrop/CMakeLists.txt index d46d3cd1..65396e4c 100644 --- a/fatrop/CMakeLists.txt +++ b/fatrop/CMakeLists.txt @@ -27,6 +27,7 @@ auxiliary/FatropVector.hpp auxiliary/FatropVector.cpp auxiliary/LinearAlgebra.hpp auxiliary/LinearAlgebra.cpp function_evaluation/FunctionEvaluation.hpp function_evaluation/FunctionEvaluation.cpp ocp/OCPAbstract.hpp ocp/OCPAbstract.cpp +ocp/OCPApplication.hpp ocp/OCPApplication.cpp ocp/StageOCPApplication.hpp ocp/StageOCPApplication.cpp ocp/OCPAdapter.hpp ocp/OCPAdapter.cpp ocp/StageOCP.hpp ocp/StageOCP.cpp diff --git a/fatrop/auxiliary/Common.hpp b/fatrop/auxiliary/Common.hpp index 637eb50e..5115120d 100644 --- a/fatrop/auxiliary/Common.hpp +++ b/fatrop/auxiliary/Common.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef COMMONINCLUDED -#define COMMONINCLUDED +#ifndef __fatrop_auxiliary_common_hpp__ +#define __fatrop_auxiliary_common_hpp__ #include #if DEBUG #define DBGASSERT(assertion) assert(assertion); @@ -31,4 +31,4 @@ namespace fatrop bool CompareLessEqual(double lhs, double rhs); bool CompareLessEqual(double lhs, double rhs, double ref); } // namespace fatrop -#endif // COMMONINCLUDED \ No newline at end of file +#endif // __fatrop_auxiliary_common_hpp__ \ No newline at end of file diff --git a/fatrop/auxiliary/DynamicLib.hpp b/fatrop/auxiliary/DynamicLib.hpp index b7683f2e..15329027 100644 --- a/fatrop/auxiliary/DynamicLib.hpp +++ b/fatrop/auxiliary/DynamicLib.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef DYNAMICLIBINCLUDED -#define DYNAMICLIBINCLUDED +#ifndef __fatrop_auxiliary_DynamicLib_hpp__ +#define __fatrop_auxiliary_DynamicLib_hpp__ #include #include namespace fatrop @@ -31,4 +31,4 @@ namespace fatrop }; }; // namespace fatrop -#endif // DYNAMICLIBINCLUDED \ No newline at end of file +#endif // __fatrop_auxiliary_DynamicLib_hpp__ \ No newline at end of file diff --git a/fatrop/auxiliary/FatropOptions.hpp b/fatrop/auxiliary/FatropOptions.hpp index 1b1d6f61..d8ef9732 100644 --- a/fatrop/auxiliary/FatropOptions.hpp +++ b/fatrop/auxiliary/FatropOptions.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPOPTIONSINCLUDED -#define FATROPOPTIONSINCLUDED +#ifndef __fatrop_auxiliary_fatropoptions_hpp__ +#define __fatrop_auxiliary_fatropoptions_hpp__ #include namespace fatrop { @@ -65,4 +65,4 @@ namespace fatrop double upper_bound_; }; } // namespace fatrop -#endif \ No newline at end of file +#endif // __fatrop_auxiliary_fatropoptions_hpp__ \ No newline at end of file diff --git a/fatrop/auxiliary/FatropVector.hpp b/fatrop/auxiliary/FatropVector.hpp index 69acc43e..6e281797 100644 --- a/fatrop/auxiliary/FatropVector.hpp +++ b/fatrop/auxiliary/FatropVector.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROP_VECTOR_INCLUDED -#define FATROP_VECTOR_INCLUDED +#ifndef __fatrop_auxiliary_FatropVector_hpp__ +#define __fatrop_auxiliary_FatropVector_hpp__ #include #include #include @@ -140,4 +140,4 @@ namespace fatrop } } // namespace fatrop -#endif // FATROP_VECTOR_INCLUDED +#endif // __fatrop_auxiliary_FatropVector_hpp__ diff --git a/fatrop/auxiliary/LinearAlgebra.hpp b/fatrop/auxiliary/LinearAlgebra.hpp index 858625c2..b781b819 100644 --- a/fatrop/auxiliary/LinearAlgebra.hpp +++ b/fatrop/auxiliary/LinearAlgebra.hpp @@ -22,8 +22,8 @@ * This file contains some interface classes for use in linear algebra. * */ -#ifndef FATROP_LA_INCLUDED -#define FATROP_LA_INCLUDED +#ifndef __fatrop_auxiliary_LinearAlgebra_hpp__ +#define __fatrop_auxiliary_LinearAlgebra_hpp__ #include #include "fatrop/auxiliary/Common.hpp" @@ -85,4 +85,4 @@ namespace fatrop }; } // namespace fatrop -#endif // FATROP_LA_INCLUDED \ No newline at end of file +#endif // __fatrop_auxiliary_LinearAlgebra_hpp__ \ No newline at end of file diff --git a/fatrop/auxiliary/VectorUtils.hpp b/fatrop/auxiliary/VectorUtils.hpp index 3a784698..53ffcd60 100644 --- a/fatrop/auxiliary/VectorUtils.hpp +++ b/fatrop/auxiliary/VectorUtils.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPAUXILIARYINCLUDED -#define FATROPAUXILIARYINCLUDED +#ifndef __fatrop_auxiliary_VectorUtils_hpp__ +#define __fatrop_auxiliary_VectorUtils_hpp__ #include #include "FatropVector.hpp" #include "fatrop/auxiliary/Common.hpp" @@ -51,4 +51,4 @@ namespace fatrop return res; } }; // namespace fatrop -#endif // FATROPAUXINCLUDED \ No newline at end of file +#endif // __fatrop_auxiliary_VectorUtils_hpp__ \ No newline at end of file diff --git a/fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp b/fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp index 79fe4c63..11bcb228 100644 --- a/fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp +++ b/fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROP_BLASFEO_INCLUDED -#define FATROP_BLASFEO_INCLUDED +#ifndef __fatrop_blasfeo_wrapper_LinearAlgebraBlasfeo_hpp__ +#define __fatrop_blasfeo_wrapper_LinearAlgebraBlasfeo_hpp__ // macros extern "C" @@ -124,7 +124,9 @@ void blasfeo_ref_dtrsm_rlnn_copy(int m, int n, double alpha, struct MAT *sA, int #include extern "C" { +#ifndef NOMINMAX #define NOMINMAX +#endif #include } #include "fatrop/auxiliary/LinearAlgebra.hpp" @@ -491,4 +493,4 @@ namespace fatrop void fatrop_dtrsv_unu(const fatrop_int m, const fatrop_int n, blasfeo_dmat *sA, const fatrop_int ai, const fatrop_int aj, blasfeo_dvec *sx, const fatrop_int xi, blasfeo_dvec *sz, const fatrop_int zi); void fatrop_dtrsv_utu(const fatrop_int m, blasfeo_dmat *sA, const fatrop_int ai, const fatrop_int aj, blasfeo_dvec *sx, const fatrop_int xi, blasfeo_dvec *sz, const fatrop_int zi); } // namespace fatrop -#endif // FATROP_BLASFEO_INCLUDED +#endif // __fatrop_blasfeo_wrapper_LinearAlgebraBlasfeo_hpp__ diff --git a/fatrop/fatrop.hpp b/fatrop/fatrop.hpp index 1e75d9a9..05956fbe 100644 --- a/fatrop/fatrop.hpp +++ b/fatrop/fatrop.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROP_INCLUDED -#define FATROP_INCLUDED +#ifndef __fatrop_fatrop_hpp__ +#define __fatrop_fatrop_hpp__ #include "fatrop/ocp/StageOCPApplication.hpp" // #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" // #include "fatrop/ocp/OCPKKT.hpp" @@ -36,4 +36,4 @@ // #include "fatrop/ocp/FatropOCPBuilder.hpp" // #include "SparseSolvers/InterfaceMUMPS.hpp" -#endif //FATROP_INCLUDED \ No newline at end of file +#endif //__fatrop_fatrop_hpp__ \ No newline at end of file diff --git a/fatrop/function_evaluation/CasadiCodegen.hpp b/fatrop/function_evaluation/CasadiCodegen.hpp index 4a8ea7dd..ab8b5ae8 100644 --- a/fatrop/function_evaluation/CasadiCodegen.hpp +++ b/fatrop/function_evaluation/CasadiCodegen.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef CASADICODEGENINCLUDED -#define CASADICODEGENINCLUDED +#ifndef __fatrop_function_evaluation_CasadiCodegen_hpp__ +#define __fatrop_function_evaluation_CasadiCodegen_hpp__ #include #include #include @@ -101,4 +101,4 @@ namespace fatrop } // fatrop -#endif // CASADICODEGENINCLUDED \ No newline at end of file +#endif // __fatrop_function_evaluation_CasadiCodegen_hpp__ \ No newline at end of file diff --git a/fatrop/function_evaluation/FunctionEvaluation.hpp b/fatrop/function_evaluation/FunctionEvaluation.hpp index 0abb4efc..a34c9f36 100644 --- a/fatrop/function_evaluation/FunctionEvaluation.hpp +++ b/fatrop/function_evaluation/FunctionEvaluation.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FUNCTIONEVALUATIONINCLUDED -#define FUNCTIONEVALUATIONINCLUDED +#ifndef __fatrop_function_evaluation_FunctionEvaluation_hpp__ +#define __fatrop_function_evaluation_FunctionEvaluation_hpp__ #include #include #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" @@ -57,4 +57,4 @@ namespace fatrop ~EvalBase(){}; }; }; // namespace fatrop -#endif // FUNCTIONEVALUATIONINCLUDED +#endif // __fatrop_function_evaluation_FunctionEvaluation_hpp__ diff --git a/fatrop/ocp/CasadiCApiUserdataWrap.cpp b/fatrop/ocp/CasadiCApiUserdataWrap.cpp index 70fb9b17..d6dce254 100644 --- a/fatrop/ocp/CasadiCApiUserdataWrap.cpp +++ b/fatrop/ocp/CasadiCApiUserdataWrap.cpp @@ -2,6 +2,7 @@ #include #include "fatrop/ocp/StageOCPApplication.hpp" #include "fatrop/ocp/OCPDims.hpp" +#include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" // c++ stuff here namespace fatrop { diff --git a/fatrop/ocp/DuInfEvaluator.hpp b/fatrop/ocp/DuInfEvaluator.hpp index 96c112c5..090c3125 100644 --- a/fatrop/ocp/DuInfEvaluator.hpp +++ b/fatrop/ocp/DuInfEvaluator.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef DUINFEVALINCLUDED -#define DUINFEVALINCLUDED +#ifndef __fatrop_function_evaluation_DuInfEvaluator_hpp__ +#define __fatrop_function_evaluation_DuInfEvaluator_hpp__ #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "OCPKKT.hpp" #include "fatrop/auxiliary/Common.hpp" @@ -35,4 +35,4 @@ namespace fatrop FatropVecBF &du_inf); }; } -#endif // DUINFEVALINCLUDED \ No newline at end of file +#endif // __fatrop_function_evaluation_DuInfEvaluator_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/FatropOCP.cpp b/fatrop/ocp/FatropOCP.cpp index 34210311..2e5e3563 100644 --- a/fatrop/ocp/FatropOCP.cpp +++ b/fatrop/ocp/FatropOCP.cpp @@ -45,8 +45,6 @@ FatropOCP::FatropOCP( lam_test(nlpdims_.neqs, 1), delta_s_test(nlpdims_.nineqs, 1), lsscaler_(dims_) { - options_->register_option(BooleanOption("iterative_refinement_SOC", "Use iterative refinement for SOC", &it_ref, true)); - options_->register_option(BooleanOption("ls_scaling", "Use automatic scaling for linear system", &ls_scaling, true)); } int FatropOCP::eval_lag_hess( double obj_scale, @@ -358,4 +356,10 @@ void FatropOCP::finalize() void FatropOCP::reset() { ocp_->reset(); -} \ No newline at end of file +} +void FatropOCP::update_options(const FatropOptions &options) +{ + it_ref = options.iterative_refinement_SOC.get(); + ls_scaling = options.ls_scaling.get(); + ls_ -> update_options(options); +}; \ No newline at end of file diff --git a/fatrop/ocp/FatropOCP.hpp b/fatrop/ocp/FatropOCP.hpp index 280fea2d..168968da 100644 --- a/fatrop/ocp/FatropOCP.hpp +++ b/fatrop/ocp/FatropOCP.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPALGINCLUDED -#define OCPALGINCLUDED +#ifndef __fatrop_ocp_FatropOCP_hpp__ +#define __fatrop_ocp_FatropOCP_hpp__ #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "fatrop/templates/NLPAlg.hpp" #include "OCPKKT.hpp" @@ -117,6 +117,7 @@ namespace fatrop NLPDims get_nlp_dims() const override; void finalize() override; void reset() override; + void update_options(const FatropOptions& options) override; public: std::shared_ptr ocp_; @@ -158,4 +159,4 @@ namespace fatrop OCPLSScaler lsscaler_; }; } // namespace fatrop -#endif // OCPALGINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_FatropOCP_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/FatropOCPBuilder.hpp b/fatrop/ocp/FatropOCPBuilder.hpp index bbd986b1..e3f55049 100644 --- a/fatrop/ocp/FatropOCPBuilder.hpp +++ b/fatrop/ocp/FatropOCPBuilder.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPOCPBUILDERINCLUDED -#define FATROPOCPBUILDERINCLUDED +#ifndef __fatrop_ocp_FatropOCPBuilder_hpp__ +#define __fatrop_ocp_FatropOCPBuilder_hpp__ #include "fatrop/ocp/OCP.hpp" #include "fatrop/ocp/FatropOCP.hpp" #include "fatrop/ocp/OCPAbstract.hpp" @@ -49,4 +49,4 @@ namespace fatrop }; } -#endif // !OCPALGBUILDERINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_FatropOCPBuilder_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/FatropOCPResto.hpp b/fatrop/ocp/FatropOCPResto.hpp index 3386a0af..70e30086 100644 --- a/fatrop/ocp/FatropOCPResto.hpp +++ b/fatrop/ocp/FatropOCPResto.hpp @@ -9,8 +9,6 @@ namespace fatrop public: FatropOCPResto(const std::shared_ptr &orig, const std::shared_ptr &opts) : orig_(orig), orig_dims_(orig->get_nlp_dims()), lower_(orig_dims_.nineqs), upper_(orig_dims_.nineqs), x_start_(orig_dims_.nvars), s_start_(orig_dims_.nineqs), x_tmp_(orig_dims_.nvars), s_tmp_(orig_dims_.nineqs), upper_bounded_(orig_dims_.nineqs), lower_bounded_(orig_dims_.nineqs), slack_dummy_(orig_dims_.nineqs), sigma_dummy_(orig_dims_.nineqs), gradb_dummy_(orig_dims_.nineqs), zl_dummy_(orig_dims_.nineqs), zu_dummy_(orig_dims_.nineqs), sigma_cache_(orig_dims_.nineqs * 3), gradb_cache_(orig_dims_.nineqs * 3) { - opts->register_option(DoubleOption::lower_bounded("resto_rho", "Resto L1 penalty parameter", &rho, 1000., 0.0)); - opts->register_option(DoubleOption::lower_bounded("resto_xi", "Resto xi parameter", &xi, 1., 0.0)); auto lower_v = lower_[0]; auto upper_v = upper_[0]; orig_->get_bounds(lower_v, upper_v); @@ -275,6 +273,11 @@ namespace fatrop { orig_->reset(); }; + void update_options(const FatropOptions &options) override + { + rho = options.resto_rho.get(); + xi = options.resto_xi.get(); + }; std::shared_ptr orig_; NLPDims orig_dims_; NLPDims this_dims_; diff --git a/fatrop/ocp/OCP.hpp b/fatrop/ocp/OCP.hpp index 5c824c2b..faa2d4cd 100644 --- a/fatrop/ocp/OCP.hpp +++ b/fatrop/ocp/OCP.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPINCLUDED -#define OCPINCLUDED +#ifndef __fatrop_ocp_OCP_hpp__ +#define __fatrop_ocp_OCP_hpp__ #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "OCPDims.hpp" #include "fatrop/ocp/OCPKKT.hpp" @@ -79,4 +79,4 @@ namespace fatrop virtual void get_solution(const std::shared_ptr &fatropdata, std::vector &u, std::vector &x) = 0; }; } // namespace fatrop -#endif // OCPINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCP_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPAbstract.hpp b/fatrop/ocp/OCPAbstract.hpp index da4eed50..36864464 100644 --- a/fatrop/ocp/OCPAbstract.hpp +++ b/fatrop/ocp/OCPAbstract.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPTEMPLATEINCLUDED -#define OCPTEMPLATEINCLUDED +#ifndef __fatrop_ocp_OCPAbstract_hpp__ +#define __fatrop_ocp_OCPAbstract_hpp__ #include "fatrop/ocp/OCPKKT.hpp" #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "fatrop/auxiliary/FatropVector.hpp" @@ -251,4 +251,4 @@ namespace fatrop } }; }; // namespace fatrop -#endif // OCPTEMPLATEINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPAbstract_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPAdapter.hpp b/fatrop/ocp/OCPAdapter.hpp index c54674f2..1b8391ed 100644 --- a/fatrop/ocp/OCPAdapter.hpp +++ b/fatrop/ocp/OCPAdapter.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPEVALUATORINCLUDED -#define OCPEVALUATORINCLUDED +#ifndef __fatrop_ocp_OCPAdapter_hpp__ +#define __fatrop_ocp_OCPAdapter_hpp__ #include "OCPKKT.hpp" #include "OCPAbstract.hpp" #include "fatrop/solver/FatropData.hpp" @@ -194,4 +194,4 @@ namespace fatrop }; } // namespace fatrop -#endif // OCPEVALUATORINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPAdapter_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPApplication.cpp b/fatrop/ocp/OCPApplication.cpp new file mode 100644 index 00000000..88af83e9 --- /dev/null +++ b/fatrop/ocp/OCPApplication.cpp @@ -0,0 +1,195 @@ +#include "fatrop/ocp/OCPApplication.hpp" +#include "fatrop/solver/AlgBuilder.hpp" +#include "fatrop/ocp/OCPAdapter.hpp" +#include "fatrop/ocp/FatropOCP.hpp" +#include "fatrop/ocp/FatropOCPResto.hpp" +#include "fatrop/ocp/FatropOCPBuilder.hpp" +#include "fatrop/solver/FatropAlg.hpp" +#include "fatrop/ocp/OCPAbstract.hpp" +#include "fatrop/json/json.h" +#include "fatrop/auxiliary/Common.hpp" +#include "fatrop/solver/NLPL1.hpp" +using namespace fatrop; +using namespace std; +NLPApplication::NLPApplication() : fatropoptions_(make_shared()), dirty(true), options_registry(make_shared(*fatropoptions_.get())) +{ + if (printer_ == nullptr) + { + printer_ = std::make_shared(); + } +} + +void NLPApplication::build(const shared_ptr &nlp, const shared_ptr &nlp_resto) +{ + // keep nlp around for getting nlpdims + nlp_ = nlp; + // check if prebuilt option "inequality_handling" is in prebuilt options + if (fatropoptions_->inequality_handling.get() == "pd_ip") + { + } + else if(fatropoptions_->inequality_handling.get() == "L1_pen") + { + nlp_ = std::make_shared(nlp, fatropoptions_); + } + else + { + throw std::runtime_error("Unknown inequality handling method: " + fatropoptions_->inequality_handling.get()); + } + std::shared_ptr fatropdata_resto; + algbuilder = std::make_shared(); + algbuilder -> set_printer(printer_); + algbuilder -> build_fatrop_algorithm_objects(nlp_, nlp_resto, fatropoptions_, fatropdata_, fatropdata_resto, journaller_); + printer_ -> print_level() = fatropoptions_->print_level.get(); + // fatropoptions_->register_option(IntegerOption::un_bounded("print_level", "prfatrop_fatrop_int level", &printer_->print_level(), 10)); + fatropalg_ = algbuilder -> build_algorithm(); + dirty = false; +} + +fatrop_int NLPApplication::optimize() const +{ + assert(!dirty); + // update options + algbuilder -> update_options(*fatropoptions_); + // solve optimization problem + fatrop_int ret = fatropalg_->optimize(); + return ret; +} +// TODO: make this protected and use last_solution instead and choose other name +const FatropVecBF &NLPApplication::last_solution_primal() const +{ + assert(!dirty); + return fatropdata_->x_curr; +} +FatropVecBF &NLPApplication::initial_guess_primal() const +{ + assert(!dirty); + return fatropdata_->x_initial; +} +FatropStats NLPApplication::get_stats() const +{ + return fatropalg_->get_stats(); +} +NLPDims NLPApplication::get_nlp_dims() +{ + return nlp_->get_nlp_dims(); +} +const FatropVecBF &NLPApplication::last_solution_dual() const +{ + return fatropdata_->lam_curr; +} +const FatropVecBF &NLPApplication::last_solution_zL() const +{ + return fatropdata_->zL_curr; +} +const FatropVecBF &NLPApplication::last_solution_zU() const +{ + return fatropdata_->zU_curr; +} +FatropVecBF &NLPApplication::initial_guess_dual() const +{ + return fatropdata_->lam_init; +} +FatropVecBF &NLPApplication::initial_guess_zL() const +{ + return fatropdata_->zL_init; +} +FatropVecBF &NLPApplication::initial_guess_zU() const +{ + return fatropdata_->zU_init; +} +template +void NLPApplication::set_option(const string &option_name, T value) +{ + options_registry->set(option_name, value); +} +template void NLPApplication::set_option(const string &, int); +template void NLPApplication::set_option(const string &, double); +template void NLPApplication::set_option(const string &, bool); +template void NLPApplication::set_option(const string &, string); +template void NLPApplication::set_option(const string &, const string&); + +void NLPApplication::set_initial(const FatropSolution &initial_guess) const +{ + initial_guess_primal() = initial_guess.sol_primal_; + initial_guess_dual() = initial_guess.sol_dual_; + initial_guess_zL() = initial_guess.sol_zL_; + initial_guess_zU() = initial_guess.sol_zU_; +} +void NLPApplication::set_initial(const std::vector &initial_guess_primal_) const +{ + initial_guess_primal() = initial_guess_primal_; +} +const FatropOptions &NLPApplication::get_options() const +{ + return *fatropoptions_; +} + +// TODO move this class to a separate file +OCPAbstractApplication::OCPAbstractApplication(const shared_ptr &ocp) +{ + adapter = make_shared(ocp, fatropoptions_); + ocp_ = adapter; +} + +void OCPApplication::build() +{ + // keep the adapter around for accessing the parameters for samplers and parameter setters + shared_ptr nlp_resto(make_shared(FatropOCPBuilder(ocp_, fatropoptions_, printer_).build(ocp_), fatropoptions_)); + shared_ptr nlp(FatropOCPBuilder(ocp_, fatropoptions_, printer_).build(ocp_)); + NLPApplication::build(nlp, nlp_resto); + dirty = false; +} +void OCPAbstractApplication::set_params(const std::vector &global_params, const std::vector &stage_params) +{ + adapter->set_parameters(stage_params, global_params); +} + +vector &OCPAbstractApplication::global_parameters() +{ + assert(!dirty); + return adapter->get_global_parameters_vec(); +} +vector &OCPAbstractApplication::stage_parameters() +{ + assert(!dirty); + return adapter->get_stage_parameters_vec(); +} + + +OCPApplication::OCPApplication(const std::shared_ptr &ocp):ocp_(ocp) +{ + +} +OCPApplication::OCPApplication():ocp_(nullptr) +{ + +} +void OCPApplication::set_initial(vector &initial_u, vector &initial_x) +{ + assert(!dirty); + ocp_->set_initial_sol_guess(fatropdata_, initial_u, initial_x); +} +OCPDims OCPApplication::get_ocp_dims() +{ + return ocp_->get_ocp_dims(); +} + +FatropSolution::FatropSolution(){}; +void FatropSolution::set_dims(const NLPDims &dims) +{ + sol_primal_.resize(dims.nvars); + sol_dual_.resize(dims.neqs); + sol_zL_.resize(dims.nineqs); + sol_zU_.resize(dims.nineqs); +}; +void FatropSolution::set_solution(const FatropVecBF &sol_primal, const FatropVecBF &sol_dual, const FatropVecBF &sol_zL, const FatropVecBF &sol_zU) +{ + sol_primal.block(0, sol_primal_.size()).copyto(sol_primal_); + sol_dual.block(0, sol_dual_.size()).copyto(sol_dual_); + sol_zL.block(0, sol_zL_.size()).copyto(sol_zL_); + sol_zU.block(0,sol_zU_.size()).copyto(sol_zU_); +}; +void FatropSolution::set_primal_solution(const FatropVecBF &sol) +{ + sol.block(0, sol_primal_.size()).copyto(sol_primal_); +} \ No newline at end of file diff --git a/fatrop/ocp/OCPApplication.hpp b/fatrop/ocp/OCPApplication.hpp new file mode 100644 index 00000000..b43967fd --- /dev/null +++ b/fatrop/ocp/OCPApplication.hpp @@ -0,0 +1,140 @@ +/* + * Fatrop - A fast trajectory optimization solver + * Copyright (C) 2022 - 2024 Lander Vanroye, KU Leuven. All rights reserved. + * + * This file is part of Fatrop. + * + * Fatrop is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Fatrop is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Fatrop. If not, see . */ +#ifndef __fatrop_ocp_OCPApplication_hpp__ +#define __fatrop_ocp_OCPApplication_hpp__ +#include "fatrop/solver/FatropStats.hpp" +#include "fatrop/ocp/StageOCPExpressions.hpp" +#include +#include +#include +#include + +namespace fatrop +{ + // forward declarations to hide the implementation details + class Journaller; + class FatropAlg; + class StageOCP; + class NLPDims; + class FatropVecBF; + class FatropNLP; + class FatropOptions; + class FatropData; + class OCPAdapter; + class FatropPrinter; + class OCPAbstract; + class OCPDims; + class OCP; + class AlgBuilder; + class FatropOptionsRegistry; + class FatropSolution + { + public: + // void GetPrimalSolution(vector &result); + // defautl copy constructor + FatropSolution(const FatropSolution &other) = default; + const std::vector &primal_solution() { return sol_primal_; }; + + protected: + FatropSolution(); + void set_dims(const NLPDims &dims); + void set_primal_solution(const FatropVecBF &sol); + void set_solution(const FatropVecBF &sol_primal, const FatropVecBF &sol_dual, const FatropVecBF &sol_zL, const FatropVecBF &sol_zU); + + protected: + std::vector sol_primal_; + std::vector sol_dual_; + std::vector sol_zL_; + std::vector sol_zU_; + friend class NLPApplication; + }; + // TODO move this class to a separate file + class NLPApplication + { + public: + NLPApplication(); + + protected: + void build(const std::shared_ptr &nlp, const std::shared_ptr &nlp_resto); + + public: + fatrop_int optimize() const; + // TODO: make this protected and use last_solution instead and choose other name + const FatropVecBF &last_solution_primal() const; + const FatropVecBF &last_solution_dual() const; + const FatropVecBF &last_solution_zL() const; + const FatropVecBF &last_solution_zU() const; + FatropVecBF &initial_guess_primal() const; + FatropVecBF &initial_guess_dual() const; + FatropVecBF &initial_guess_zL() const; + FatropVecBF &initial_guess_zU() const; + FatropStats get_stats() const; + NLPDims get_nlp_dims(); + template + void set_option(const std::string &option_name, T value); + + public: + void set_initial(const FatropSolution &initial_guess) const; + void set_initial(const std::vector &initial_guess_primal_) const; + const FatropOptions &get_options() const; + + protected: + std::shared_ptr fatropoptions_; + std::shared_ptr fatropdata_; + std::shared_ptr nlp_; + bool dirty = true; + std::shared_ptr printer_; + friend class OcpSolverDriver; + + private: + const std::shared_ptr ocp_; + std::shared_ptr journaller_; + std::shared_ptr fatropalg_; + std::shared_ptr algbuilder; + std::shared_ptr options_registry; + }; + + class OCPApplication : public NLPApplication + { + public: + OCPApplication(const std::shared_ptr &ocp); + OCPApplication(); + void build(); + public: + using NLPApplication::set_initial; + void set_initial(std::vector &initial_u, std::vector &initial_x); + OCPDims get_ocp_dims(); + std::shared_ptr ocp_; + }; + + class OCPAbstractApplication : public OCPApplication + { + public: + OCPAbstractApplication(const std::shared_ptr &ocp); + void set_params(const std::vector &global_params, const std::vector &stage_params); + + protected: + std::shared_ptr adapter; + + protected: + std::vector &global_parameters(); + std::vector &stage_parameters(); + }; +} +#endif // __fatrop_ocp_OCPApplication_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPCInterface.h b/fatrop/ocp/OCPCInterface.h index 84de5c56..711f1f31 100644 --- a/fatrop/ocp/OCPCInterface.h +++ b/fatrop/ocp/OCPCInterface.h @@ -17,8 +17,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPCINTERFACEINCLUDED -#define OCPCINTERFACEINCLUDED +#ifndef __fatrop_ocp_OCPCInterface_hpp__ +#define __fatrop_ocp_OCPCInterface_hpp__ #ifdef __cplusplus extern "C" { @@ -286,4 +286,4 @@ FATROP_SYMBOL_EXPORT void fatrop_ocp_c_destroy(struct FatropOcpCSolver*); } // extern "C" #endif -#endif // OCPCINTERFACEINCLUDED +#endif // __fatrop_ocp_OCPAbstract_hpp__ diff --git a/fatrop/ocp/OCPDims.hpp b/fatrop/ocp/OCPDims.hpp index 57dd7d47..7b2d0f6c 100644 --- a/fatrop/ocp/OCPDims.hpp +++ b/fatrop/ocp/OCPDims.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROP_OCPDIMS_INCLUDED -#define FATROP_OCPDIMS_INCLUDED +#ifndef __fatrop_ocp_OCPDims_hpp__ +#define __fatrop_ocp_OCPDims_hpp__ #include "fatrop/auxiliary/FatropVector.hpp" #include "fatrop/auxiliary/Common.hpp" #include "fatrop/templates/NLPAlg.hpp" @@ -57,4 +57,4 @@ namespace fatrop const fatrop_int n_stage_params_tot; }; } // namespace fatrop -#endif // FATROP_OCPDIMS_INCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPDims_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPInitializer.hpp b/fatrop/ocp/OCPInitializer.hpp index 632bb45a..0f429576 100644 --- a/fatrop/ocp/OCPInitializer.hpp +++ b/fatrop/ocp/OCPInitializer.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPINITIALIZERINCLUDED -#define OCPINITIALIZERINCLUDED +#ifndef __fatrop_ocp_OCPInitializer_hpp__ +#define __fatrop_ocp_OCPInitializer_hpp__ #include "OCPKKT.hpp" #include "fatrop/auxiliary/Common.hpp" #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" @@ -38,4 +38,4 @@ namespace fatrop FatropVecBF &s); }; } // namespace fatrop -#endif // OCPINITIALIZERINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPInitializer_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPKKT.hpp b/fatrop/ocp/OCPKKT.hpp index a13eb617..6d2b7023 100644 --- a/fatrop/ocp/OCPKKT.hpp +++ b/fatrop/ocp/OCPKKT.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROP_OCP_KKT_INCLUDED -#define FATROP_OCP_KKT_INCLUDED +#ifndef __fatrop_ocp_OCPKKT_hpp__ +#define __fatrop_ocp_OCPKKT_hpp__ #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "OCPDims.hpp" #include "fatrop/auxiliary/VectorUtils.hpp" @@ -66,4 +66,4 @@ namespace fatrop }; } // namespace fatrop -#endif // FATROP_OCP_KKT_INCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPKKT_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPLSRiccati.cpp b/fatrop/ocp/OCPLSRiccati.cpp index 80d95ec6..865ac94e 100644 --- a/fatrop/ocp/OCPLSRiccati.cpp +++ b/fatrop/ocp/OCPLSRiccati.cpp @@ -85,14 +85,6 @@ OCPLSRiccati::OCPLSRiccati(const OCPDims &dims, const shared_ptr options_(options), printer_(printer) { - options_->register_option(BooleanOption("linsol_iterative_refinement", "iterative ref", &it_ref, true)); - options_->register_option(BooleanOption("linsol_perturbed_mode", "linear solver perturbed mode", &perturbed_mode, false)); - options_->register_option(BooleanOption("linsol_diagnostic", "linear solver diagnostic mode", &diagnostic, false)); - options_->register_option(DoubleOption::lower_bounded("linsol_perturbed_mode_param", "linear solver perturbed mode param", &perturbed_mode_param, 1e-6, 0.)); - options_->register_option(IntegerOption::lower_bounded("linsol_min_it_ref", "minimum number of iterative refinement steps", &min_it_ref, 0, 0)); - options_->register_option(IntegerOption::lower_bounded("linsol_max_it_ref", "maximum number of iterative refinement steps", &max_it_ref, 5, 0)); - options_->register_option(DoubleOption::lower_bounded("linsol_min_it_acc", "stopping criterion for iterative refinement procedure", &it_ref_acc, 1e-8, 0.)); - options_->register_option(DoubleOption::lower_bounded("linsol_lu_fact_tol", "pivoting tolerance parameter for lu fact", &lu_fact_tol, 1e-5, 0.)); }; fatrop_int OCPLSRiccati::solve_pd_sys( OCPKKTMemory *OCP, @@ -1728,4 +1720,16 @@ fatrop_int OCPLSRiccati::solve_rhs_degenerate( } } return 0; -}; \ No newline at end of file +}; + +void OCPLSRiccati::update_options(const FatropOptions& options) +{ + it_ref = options.linsol_iterative_refinement.get(); + perturbed_mode = options.linsol_perturbed_mode.get(); + diagnostic = options.linsol_diagnostic.get(); + perturbed_mode_param = options.linsol_perturbed_mode_param.get(); + min_it_ref = options.linsol_min_it_ref.get(); + max_it_ref = options.linsol_max_it_ref.get(); + it_ref_acc = options.linsol_min_it_acc.get(); + lu_fact_tol = options.linsol_lu_fact_tol.get(); +} \ No newline at end of file diff --git a/fatrop/ocp/OCPLSRiccati.hpp b/fatrop/ocp/OCPLSRiccati.hpp index aeee3d73..83145824 100644 --- a/fatrop/ocp/OCPLSRiccati.hpp +++ b/fatrop/ocp/OCPLSRiccati.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef OCPLSRICCATIINCLUDED -#define OCPLSRICCATIINCLUDED +#ifndef __fatrop_ocp_OCPLSRiccati_hpp__ +#define __fatrop_ocp_OCPLSRiccati_hpp__ #include "OCPKKT.hpp" #include "OCPLinearSolver.hpp" #include "fatrop/solver/FatropPrinter.hpp" @@ -123,6 +123,7 @@ namespace fatrop const FatropVecBF &rhs_g, const FatropVecBF &rhs_g_ineq, const FatropVecBF &rhs_gradb); + void update_options(const FatropOptions &options) override; FatropMemoryMatBF Ppt; FatropMemoryMatBF Hh; FatropMemoryMatBF AL; @@ -195,4 +196,4 @@ namespace fatrop bool diagnostic = false; }; }; // namespace -#endif // OCPLSRICCATIINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPLSRiccati_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPLinearSolver.hpp b/fatrop/ocp/OCPLinearSolver.hpp index ff062814..125b6eca 100644 --- a/fatrop/ocp/OCPLinearSolver.hpp +++ b/fatrop/ocp/OCPLinearSolver.hpp @@ -16,13 +16,16 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef NLPLSINCLUDED -#define NLPLSINCLUDED +#ifndef __fatrop_ocp_OCPLinearSolver_hpp__ +#define __fatrop_ocp_OCPLinearSolver_hpp__ #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "OCPKKT.hpp" #include "fatrop/auxiliary/Common.hpp" namespace fatrop { + // forward declaration + class FatropOptions; + class OCPLinearSolver { public: @@ -69,7 +72,8 @@ namespace fatrop const FatropVecBF &rhs_g, const FatropVecBF &rhs_g_ineq, const FatropVecBF &rhs_gradb) = 0; + virtual void update_options(const FatropOptions &options) = 0; }; } // namespace fatrop -#endif // NLPLSINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPLinearSolver_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPNoScaling.hpp b/fatrop/ocp/OCPNoScaling.hpp index 2f88d350..9e1861f8 100644 --- a/fatrop/ocp/OCPNoScaling.hpp +++ b/fatrop/ocp/OCPNoScaling.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef NOSCALINGMETHODINCLUDED -#define NOSCALINGMETHODINCLUDED +#ifndef __fatrop_ocp_OCPNoScaling_hpp__ +#define __fatrop_ocp_OCPNoScaling_hpp__ #include "fatrop/solver/FatropData.hpp" #include "fatrop/templates/NLPAlg.hpp" #include "fatrop/solver/AlgStrategy.hpp" @@ -39,4 +39,4 @@ namespace fatrop }; } // namespace fatrop -#endif // !SCALINGMETHODINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPNoScaling_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/OCPScalingMethod.hpp b/fatrop/ocp/OCPScalingMethod.hpp index 5ed458ac..965e2a61 100644 --- a/fatrop/ocp/OCPScalingMethod.hpp +++ b/fatrop/ocp/OCPScalingMethod.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef SCALINGMETHODINCLUDED -#define SCALINGMETHODINCLUDED +#ifndef __fatrop_ocp_OCPScalingMethod_hpp__ +#define __fatrop_ocp_OCPScalingMethod_hpp__ #include "fatrop/solver/FatropData.hpp" #include "fatrop/templates/NLPAlg.hpp" #include "fatrop/solver/AlgStrategy.hpp" @@ -39,4 +39,4 @@ namespace fatrop }; } // namespace fatrop -#endif // !SCALINGMETHODINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_OCPScalingMethod_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/StageOCP.hpp b/fatrop/ocp/StageOCP.hpp index 9e2c6e96..75b7dff1 100644 --- a/fatrop/ocp/StageOCP.hpp +++ b/fatrop/ocp/StageOCP.hpp @@ -18,8 +18,8 @@ * along with Fatrop. If not, see . */ // Basic OCP template: initial and terminal constraints eq constraints, Function evaluation provided by Casadi CodeGen -#ifndef OCPTEMPLATEBASICINCLUDED -#define OCPTEMPLATEBASICINCLUDED +#ifndef __fatrop_ocp_StageOCP_hpp__ +#define __fatrop_ocp_StageOCP_hpp__ #include "OCPAbstract.hpp" #include #include @@ -404,7 +404,7 @@ namespace fatrop } }; } -#endif // OCPTEMPLATEBASICINCLUDED +#endif // __fatrop_ocp_StageOCP_hpp__ // class SingleStageOCPAbstract // { diff --git a/fatrop/ocp/StageOCPApplication.cpp b/fatrop/ocp/StageOCPApplication.cpp index e75ebf1a..520bb152 100644 --- a/fatrop/ocp/StageOCPApplication.cpp +++ b/fatrop/ocp/StageOCPApplication.cpp @@ -30,187 +30,6 @@ #include "fatrop/solver/NLPL1.hpp" using namespace fatrop; using namespace std; -NLPApplication::NLPApplication() : fatropoptions_(make_shared()), dirty(true) -{ - if (printer_ == nullptr) - { - printer_ = std::make_shared(); - } -} - -void NLPApplication::build(const shared_ptr &nlp, const shared_ptr &nlp_resto) -{ - // keep nlp around for getting nlpdims - nlp_ = nlp; - // check if prebuilt option "inequality_handling" is in prebuilt options - if (fatropoptions_->prebuilt_string.find("inequality_handling") == fatropoptions_->prebuilt_string.end()) - { - fatropoptions_ ->prebuilt_set("inequality_handling", "pd_ip"); - } - if(fatropoptions_->prebuilt_string["inequality_handling"] == "L1_pen") - { - nlp_ = std::make_shared(nlp, fatropoptions_); - } - std::shared_ptr fatropdata_resto; - AlgBuilder algbuilder; - algbuilder.set_printer(printer_); - algbuilder.build_fatrop_algorithm_objects(nlp_, nlp_resto, fatropoptions_, fatropdata_, fatropdata_resto, journaller_); - fatropoptions_->register_option(IntegerOption::un_bounded("print_level", "prfatrop_fatrop_int level", &printer_->print_level(), 10)); - fatropalg_ = algbuilder.build_algorithm(); - dirty = false; -} - -fatrop_int NLPApplication::optimize() const -{ - assert(!dirty); - fatrop_int ret = fatropalg_->optimize(); - return ret; -} -// TODO: make this protected and use last_solution instead and choose other name -const FatropVecBF &NLPApplication::last_solution_primal() const -{ - assert(!dirty); - return fatropdata_->x_curr; -} -FatropVecBF &NLPApplication::initial_guess_primal() const -{ - assert(!dirty); - return fatropdata_->x_initial; -} -FatropStats NLPApplication::get_stats() const -{ - return fatropalg_->get_stats(); -} -NLPDims NLPApplication::get_nlp_dims() -{ - return nlp_->get_nlp_dims(); -} -const FatropVecBF &NLPApplication::last_solution_dual() const -{ - return fatropdata_->lam_curr; -} -const FatropVecBF &NLPApplication::last_solution_zL() const -{ - return fatropdata_->zL_curr; -} -const FatropVecBF &NLPApplication::last_solution_zU() const -{ - return fatropdata_->zU_curr; -} -FatropVecBF &NLPApplication::initial_guess_dual() const -{ - return fatropdata_->lam_init; -} -FatropVecBF &NLPApplication::initial_guess_zL() const -{ - return fatropdata_->zL_init; -} -FatropVecBF &NLPApplication::initial_guess_zU() const -{ - return fatropdata_->zU_init; -} -template -void NLPApplication::set_option(const string &option_name, T value) -{ - // check if application is built - if(dirty) - fatropoptions_->prebuilt_set(option_name, value); - else - fatropoptions_->set(option_name, value); -} -template void NLPApplication::set_option(const string &, int); -template void NLPApplication::set_option(const string &, double); -template void NLPApplication::set_option(const string &, bool); -template void NLPApplication::set_option(const string &, string); - -void NLPApplication::set_initial(const FatropSolution &initial_guess) const -{ - initial_guess_primal() = initial_guess.sol_primal_; - initial_guess_dual() = initial_guess.sol_dual_; - initial_guess_zL() = initial_guess.sol_zL_; - initial_guess_zU() = initial_guess.sol_zU_; -} -void NLPApplication::set_initial(const std::vector &initial_guess_primal_) const -{ - initial_guess_primal() = initial_guess_primal_; -} -const FatropOptions &NLPApplication::get_options() const -{ - return *fatropoptions_; -} - -// TODO move this class to a separate file -OCPAbstractApplication::OCPAbstractApplication(const shared_ptr &ocp) -{ - adapter = make_shared(ocp, fatropoptions_); - ocp_ = adapter; -} - -void OCPApplication::build() -{ - // keep the adapter around for accessing the parameters for samplers and parameter setters - shared_ptr nlp_resto(make_shared(FatropOCPBuilder(ocp_, fatropoptions_, printer_).build(ocp_), fatropoptions_)); - shared_ptr nlp(FatropOCPBuilder(ocp_, fatropoptions_, printer_).build(ocp_)); - NLPApplication::build(nlp, nlp_resto); - dirty = false; -} -void OCPAbstractApplication::set_params(const std::vector &global_params, const std::vector &stage_params) -{ - adapter->set_parameters(stage_params, global_params); -} - -vector &OCPAbstractApplication::global_parameters() -{ - assert(!dirty); - return adapter->get_global_parameters_vec(); -} -vector &OCPAbstractApplication::stage_parameters() -{ - assert(!dirty); - return adapter->get_stage_parameters_vec(); -} - - -OCPApplication::OCPApplication(const std::shared_ptr &ocp):ocp_(ocp) -{ - -} -OCPApplication::OCPApplication():ocp_(nullptr) -{ - -} -void OCPApplication::set_initial(vector &initial_u, vector &initial_x) -{ - assert(!dirty); - ocp_->set_initial_sol_guess(fatropdata_, initial_u, initial_x); -} -OCPDims OCPApplication::get_ocp_dims() -{ - return ocp_->get_ocp_dims(); -} - -FatropSolution::FatropSolution(){}; -void FatropSolution::set_dims(const NLPDims &dims) -{ - sol_primal_.resize(dims.nvars); - sol_dual_.resize(dims.neqs); - sol_zL_.resize(dims.nineqs); - sol_zU_.resize(dims.nineqs); -}; -void FatropSolution::set_solution(const FatropVecBF &sol_primal, const FatropVecBF &sol_dual, const FatropVecBF &sol_zL, const FatropVecBF &sol_zU) -{ - sol_primal.block(0, sol_primal_.size()).copyto(sol_primal_); - sol_dual.block(0, sol_dual_.size()).copyto(sol_dual_); - sol_zL.block(0, sol_zL_.size()).copyto(sol_zL_); - sol_zU.block(0,sol_zU_.size()).copyto(sol_zU_); -}; -void FatropSolution::set_primal_solution(const FatropVecBF &sol) -{ - sol.block(0, sol_primal_.size()).copyto(sol_primal_); -} -// StageOCPApplicationAbstract::StageOCPApplicationAbstract(const shared_ptr &ocp) : OCPApplication(ocp) -// { -// } StageOCPSolution::StageOCPSolution(const shared_ptr &app) { set_dims(app->get_ocp_dims()); diff --git a/fatrop/ocp/StageOCPApplication.hpp b/fatrop/ocp/StageOCPApplication.hpp index 3092d277..23c3d0fd 100644 --- a/fatrop/ocp/StageOCPApplication.hpp +++ b/fatrop/ocp/StageOCPApplication.hpp @@ -16,125 +16,11 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef BASICOCPAPPLICATIONINCLUDED -#define BASICOCPAPPLICATIONINCLUDED -#include "fatrop/solver/FatropStats.hpp" -#include "fatrop/solver/FatropAlg.hpp" -#include "fatrop/ocp/StageOCPExpressions.hpp" -#include -#include -#include -#include - +#ifndef __fatrop_ocp_StageOCPApplication_hpp__ +#define __fatrop_ocp_StageOCPApplication_hpp__ +#include "OCPApplication.hpp" namespace fatrop { - // forward declarations to hide the implementation details - class Journaller; - class FatropAlg; - class StageOCP; - class NLPDims; - class FatropVecBF; - class FatropNLP; - class FatropOptions; - class FatropData; - class OCPAdapter; - class FatropPrinter; - class OCPAbstract; - class OCPDims; - class OCP; - class FatropSolution - { - public: - // void GetPrimalSolution(vector &result); - // defautl copy constructor - FatropSolution(const FatropSolution &other) = default; - const std::vector &primal_solution() { return sol_primal_; }; - - protected: - FatropSolution(); - void set_dims(const NLPDims &dims); - void set_primal_solution(const FatropVecBF &sol); - void set_solution(const FatropVecBF &sol_primal, const FatropVecBF &sol_dual, const FatropVecBF &sol_zL, const FatropVecBF &sol_zU); - - protected: - std::vector sol_primal_; - std::vector sol_dual_; - std::vector sol_zL_; - std::vector sol_zU_; - friend class NLPApplication; - }; - // TODO move this class to a separate file - class NLPApplication - { - public: - NLPApplication(); - - protected: - void build(const std::shared_ptr &nlp, const std::shared_ptr &nlp_resto); - - public: - fatrop_int optimize() const; - // TODO: make this protected and use last_solution instead and choose other name - const FatropVecBF &last_solution_primal() const; - const FatropVecBF &last_solution_dual() const; - const FatropVecBF &last_solution_zL() const; - const FatropVecBF &last_solution_zU() const; - FatropVecBF &initial_guess_primal() const; - FatropVecBF &initial_guess_dual() const; - FatropVecBF &initial_guess_zL() const; - FatropVecBF &initial_guess_zU() const; - FatropStats get_stats() const; - NLPDims get_nlp_dims(); - template - void set_option(const std::string &option_name, T value); - - public: - void set_initial(const FatropSolution &initial_guess) const; - void set_initial(const std::vector &initial_guess_primal_) const; - const FatropOptions &get_options() const; - - protected: - std::shared_ptr fatropoptions_; - std::shared_ptr fatropdata_; - std::shared_ptr nlp_; - bool dirty = true; - std::shared_ptr printer_; - friend class OcpSolverDriver; - - private: - const std::shared_ptr ocp_; - std::shared_ptr journaller_; - std::shared_ptr fatropalg_; - }; - - class OCPApplication : public NLPApplication - { - public: - OCPApplication(const std::shared_ptr &ocp); - OCPApplication(); - void build(); - public: - using NLPApplication::set_initial; - void set_initial(std::vector &initial_u, std::vector &initial_x); - OCPDims get_ocp_dims(); - std::shared_ptr ocp_; - }; - - // TODO move this class to a separate file - class OCPAbstractApplication : public OCPApplication - { - public: - OCPAbstractApplication(const std::shared_ptr &ocp); - void set_params(const std::vector &global_params, const std::vector &stage_params); - - protected: - std::shared_ptr adapter; - - protected: - std::vector &global_parameters(); - std::vector &stage_parameters(); - }; - struct StageOCPSolution : public FatropSolution { public: @@ -239,4 +125,4 @@ namespace fatrop static StageOCPApplication from_rockit_interface(const std::string &functions, const std::string &json_spec_file); }; } -#endif // BASICOCPAPPLICATIONINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_StageOCPApplication_hpp__ \ No newline at end of file diff --git a/fatrop/ocp/StageOCPExpressions.hpp b/fatrop/ocp/StageOCPExpressions.hpp index 21690ea8..2e2742fb 100644 --- a/fatrop/ocp/StageOCPExpressions.hpp +++ b/fatrop/ocp/StageOCPExpressions.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef BASICOCPSAMPLERSINCLUDED -#define BASICOCPSAMPLERSINCLUDED +#ifndef __fatrop_ocp_StageOCPExpressions_hpp__ +#define __fatrop_ocp_StageOCPExpressions_hpp__ #include #include #include @@ -179,4 +179,4 @@ namespace fatrop } // namespace fatrop -#endif // BASICOCPSAMPLERSINCLUDED \ No newline at end of file +#endif // __fatrop_ocp_StageOCPExpressions_hpp__ \ No newline at end of file diff --git a/fatrop/solver/AlgBuilder.hpp b/fatrop/solver/AlgBuilder.hpp index d7a2f257..498dc9ed 100644 --- a/fatrop/solver/AlgBuilder.hpp +++ b/fatrop/solver/AlgBuilder.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef ALBBUILDERINCLUDED -#define ALBBUILDERINCLUDED +#ifndef __fatrop_solver_AlgBuilder_hpp__ +#define __fatrop_solver_AlgBuilder_hpp__ // #include "NLPAlg.hpp" #include "FatropAlg.hpp" #include "fatrop/auxiliary/Common.hpp" @@ -26,8 +26,8 @@ namespace fatrop class AlgBuilder { public: - void build_fatrop_algorithm_objects(const std::shared_ptr &nlp,const std::shared_ptr &nlp_resto, - const std::shared_ptr &fatropparams, + void build_fatrop_algorithm_objects(const std::shared_ptr &nlp, const std::shared_ptr &nlp_resto, + const std::shared_ptr &fatropoptions, std::shared_ptr &fatropdata, std::shared_ptr &fatropdata_resto, std::shared_ptr &journaller) { @@ -35,15 +35,15 @@ namespace fatrop { fatropprinter_ = std::make_shared(); } - fatropdata = std::make_shared(nlp->get_nlp_dims(), fatropparams, fatropprinter_); - fatropdata_resto = std::make_shared(nlp_resto->get_nlp_dims(), fatropparams, fatropprinter_); - journaller = std::make_shared(fatropparams->maxiter + 1, fatropprinter_); + fatropdata = std::make_shared(nlp->get_nlp_dims(), fatropoptions, fatropprinter_); + fatropdata_resto = std::make_shared(nlp_resto->get_nlp_dims(), fatropoptions, fatropprinter_); + journaller = std::make_shared(fatropoptions->max_iter.get() + 1, fatropprinter_); fatropdata_ = fatropdata; // keep this around for building the algorithm fatropdata_resto_ = fatropdata_resto; journaller_ = journaller; nlp_ = nlp; nlp_resto_ = nlp_resto; - fatropoptions_ = fatropparams; + fatropoptions_ = fatropoptions; } void set_printer(const std::shared_ptr &printer) { @@ -51,17 +51,31 @@ namespace fatrop } std::shared_ptr build_algorithm() { - // TODO unsafe if maxiter is changed during application - std::shared_ptr filter = std::make_shared(fatropoptions_->maxiter + 1); - std::shared_ptr linesearch = std::make_shared(fatropoptions_, nlp_, fatropdata_, filter, journaller_, fatropprinter_); - std::shared_ptr filter_resto = std::make_shared(fatropoptions_->maxiter + 1); - std::shared_ptr linesearch_resto = std::make_shared(fatropoptions_, nlp_resto_, fatropdata_resto_, filter_resto, journaller_, fatropprinter_); - std::shared_ptr orig_alg = std::make_shared(nlp_, fatropdata_, fatropoptions_, filter, linesearch, journaller_, fatropprinter_, nullptr, nullptr, false); - std::shared_ptr resto_alg = std::make_shared(nlp_resto_, fatropdata_resto_, fatropoptions_, filter_resto, linesearch_resto, journaller_, fatropprinter_, orig_alg, nullptr, true); - orig_alg-> set_resto_alg(resto_alg); - return orig_alg; + filter_ = std::make_shared(fatropoptions_->max_iter.get() + 1); + linesearch_ = std::make_shared(fatropoptions_, nlp_, fatropdata_, filter_, journaller_, fatropprinter_); + filter_resto_ = std::make_shared(fatropoptions_->max_iter.get() + 1); + linesearch_resto_ = std::make_shared(fatropoptions_, nlp_resto_, fatropdata_resto_, filter_resto_, journaller_, fatropprinter_); + orig_alg_ = std::make_shared(nlp_, fatropdata_, fatropoptions_, filter_, linesearch_, journaller_, fatropprinter_, nullptr, nullptr, false); + resto_alg_ = std::make_shared(nlp_resto_, fatropdata_resto_, fatropoptions_, filter_resto_, linesearch_resto_, journaller_, fatropprinter_, orig_alg_, nullptr, true); + orig_alg_->set_resto_alg(resto_alg_); + return orig_alg_; } + void update_options(const FatropOptions& options) + { + nlp_ -> update_options(options); + nlp_resto_ -> update_options(options); + fatropdata_ -> update_options(options); + fatropdata_resto_ -> update_options(options); + filter_ -> reserve(options.max_iter.get() + 1); + linesearch_ -> update_options(options); + filter_resto_ -> reserve(options.max_iter.get() + 1); + linesearch_resto_ -> update_options(options); + orig_alg_ -> update_options(options); + resto_alg_ -> update_options(options); + fatropprinter_ -> print_level() = options.print_level.get(); + }; + private: std::shared_ptr nlp_; std::shared_ptr nlp_resto_; @@ -70,7 +84,13 @@ namespace fatrop std::shared_ptr fatropdata_resto_; std::shared_ptr journaller_; std::shared_ptr fatropprinter_; + std::shared_ptr filter_; + std::shared_ptr linesearch_; + std::shared_ptr filter_resto_; + std::shared_ptr linesearch_resto_; + std::shared_ptr orig_alg_; + std::shared_ptr resto_alg_; }; }; -#endif // ALBBUILDERINCLUDED \ No newline at end of file +#endif // __fatrop_solver_AlgBuilder_hpp__ \ No newline at end of file diff --git a/fatrop/solver/FatropAlg.cpp b/fatrop/solver/FatropAlg.cpp index 7d9d53d8..6480eda0 100644 --- a/fatrop/solver/FatropAlg.cpp +++ b/fatrop/solver/FatropAlg.cpp @@ -28,7 +28,7 @@ FatropAlg::FatropAlg( const shared_ptr &linesearch, const shared_ptr &journaller, const shared_ptr &printer, - const shared_ptr&orig_, const shared_ptr&resto_alg_, bool resto_problem) + const shared_ptr &orig_, const shared_ptr &resto_alg_, bool resto_problem) : fatropnlp_(fatropnlp), fatropdata_(fatropdata), fatropoptions_(fatropparams), @@ -38,48 +38,30 @@ FatropAlg::FatropAlg( printer_(printer), orig_(orig_), resto_alg_(resto_alg_), resto_problem_(resto_problem) { - fatropoptions_->register_option(DoubleOption::lower_bounded("tol", "tolerance", &tol, 1e-8, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("acceptable_tol", "acceptable tolerance", &acceptable_tol, 1e-6, 0.0)); - fatropoptions_->register_option(IntegerOption::lower_bounded("max_watchdog_steps", "maximum number of watchdog steps", &max_watchdog_steps, 4, 0)); - fatropoptions_->register_option(IntegerOption::lower_bounded("acceptable_iter", "acceptable iter", &acceptable_iter, 15, 0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("lammax", "lammax", &lammax, 1e3, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("mu_init", "mu_init", &mu0, 1e2, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("kappa_eta", "kappa_eta", &kappa_eta, 10.0, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("kappa_mu", "kappa_mu", &kappa_mu, 0.2, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("theta_mu", "theta_mu", &theta_mu, 1.5, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("delta_w0", "delta_w0", &delta_w0, 1e-4, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("delta_wmin", "delta_wmin", &delta_wmin, 1e-20, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("kappa_wmin", "kappa_wmin", &kappa_wmin, 1.0 / 3.0, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("kappa_wplus", "kappa_wplus", &kappa_wplus, 8.0, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("kappa_wplusem", "kappa_wplusem", &kappa_wplusem, 100.0, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("delta_c_stripe", "delta_c_stripe", &delta_c_stripe, 1e-6, 0.0)); - fatropoptions_->register_option(DoubleOption::lower_bounded("kappa_c", "kappa_c", &kappa_c, 0.25, 0.0)); - fatropoptions_->register_option(BooleanOption("warm_start_init_point", "warm_start_init_point", &warm_start_init_point, false)); - fatropoptions_->register_option(DoubleOption::lower_bounded("theta_min", "theta_min", &theta_min, 1e-4, 0.0)); - fatropoptions_->register_option(BooleanOption("recalc_y", "recalc_y", &recalc_y, false)); - fatropoptions_->register_option(DoubleOption::lower_bounded("recalc_y_feas_tol", "recalc_y_feas_tol", &recalc_y_feas_tol, 1e-6, 0.0)); initialize(); fatropnlp_->get_initial_sol_guess(fatropdata_->x_initial); fatropnlp->get_bounds(fatropdata->s_lower_orig, fatropdata->s_upper_orig); - fatropdata_->init_bounds(); } void FatropAlg::initialize() { - maxiter = fatropoptions_->maxiter; - kappa_d = fatropoptions_->kappa_d; + // maxiter = fatropoptions_->max_iter; + // kappa_d = fatropoptions_->kappa_d; fatropdata_->initialize(); linesearch_->initialize(); } void FatropAlg::reset() { filter_->reset(); - if(!resto_problem_) fatropdata_->reset(); + fatropdata_->init_bounds(); + if (!resto_problem_) + fatropdata_->reset(); fatropdata_->reset_caches(); journaller_->reset(); fatropnlp_->reset(); linesearch_->reset(); stats = FatropStats(); - if(!resto_problem_) start_iter_ = 0; + if (!resto_problem_) + start_iter_ = 0; } void FatropAlg::set_bounds(const vector &lower, const vector &upper) { @@ -117,8 +99,9 @@ fatrop_int FatropAlg::optimize() fatropnlp_->pre_solve(fatropdata_->x_curr, fatropdata_->s_curr); eval_constr_jac(); // todo twice evaluation eval_obj_grad_curr(); - if(!resto_problem_) fatropnlp_->initialize_slacks(mu0, - fatropdata_->s_curr); + if (!resto_problem_) + fatropnlp_->initialize_slacks(mu0, + fatropdata_->s_curr); if (!resto_problem_ && warm_start_init_point) { fatropdata_->warmstart_dual(); @@ -194,7 +177,7 @@ fatrop_int FatropAlg::optimize() { no_acceptable_steps = 0; } - if(resto_problem_ && resto_stop_crit()) + if (resto_problem_ && resto_stop_crit()) { return 100; } @@ -223,7 +206,8 @@ fatrop_int FatropAlg::optimize() { stats.print(printer_->level(1)); } - if(resto_problem_) return 2; + if (resto_problem_) + return 2; printer_->level(1) << "found solution" << endl; return 0; } @@ -233,8 +217,10 @@ fatrop_int FatropAlg::optimize() { mu = MAX(mu_min, MIN(kappa_mu * mu, pow(mu, theta_mu))); fatropnlp_->update_mu(mu); - if(resto_problem_) fatropdata_->obj_curr = eval_objective_curr(); - if(resto_problem_) eval_obj_grad_curr(); + if (resto_problem_) + fatropdata_->obj_curr = eval_objective_curr(); + if (resto_problem_) + eval_obj_grad_curr(); filter_reseted = 0; filter_->reset(); no_no_full_steps_bc_filter = 0; @@ -340,10 +326,15 @@ fatrop_int FatropAlg::optimize() if (ls == 0) { // if already in resto phase: solver failed - if(resto_problem_) return 1; + if (resto_problem_) + return 1; // prepare for restoration phase int resto_res = start_resto_alg(mu, iter_count_); - if(resto_res != 100){stats.return_flag =1;return 1;} + if (resto_res != 100) + { + stats.return_flag = 1; + return 1; + } else { return_from_resto_alg(mu); @@ -518,13 +509,13 @@ fatrop_int FatropAlg::start_resto_alg(double mu, int iter) mu = std::max(mu, fatropdata_->constr_viol_max_curr()); resto_alg_->mu0 = mu; // set the starting iteration number - resto_alg_->start_iter_ = iter+1; + resto_alg_->start_iter_ = iter + 1; // initialize primal variables resto_alg_->fatropdata_->x_curr.copy(fatropdata_->x_curr); // initialize the first part of the slack variables resto_alg_->fatropdata_->s_curr.block(0, fatropdata_->n_ineqs).copy(fatropdata_->s_curr); // set n and p variables to zero - resto_alg_->fatropdata_->s_curr.block(fatropdata_-> n_ineqs, 2*fatropdata_->n_ineqs) = 0.; + resto_alg_->fatropdata_->s_curr.block(fatropdata_->n_ineqs, 2 * fatropdata_->n_ineqs) = 0.; // evaluate the constraint jacobian of resto_alg // the constraint jacobian is required for the slack initialization (todo: make this more efficient) resto_alg_->eval_constr_jac(); @@ -544,6 +535,32 @@ fatrop_int FatropAlg::start_resto_alg(double mu, int iter) return resto_alg_->optimize(); } +void FatropAlg::update_options(const FatropOptions &options) +{ + maxiter = options.max_iter.get(); + kappa_d = options.kappa_d.get(); + tol = options.tol.get(); + acceptable_tol = options.acceptable_tol.get(); + max_watchdog_steps = options.max_watchdog_steps.get(); + acceptable_iter = options.acceptable_iter.get(); + lammax = options.lammax.get(); + mu0 = options.mu_init.get(); + kappa_eta = options.kappa_eta.get(); + kappa_mu = options.kappa_mu.get(); + theta_mu = options.theta_mu.get(); + delta_w0 = options.delta_w0.get(); + delta_wmin = options.delta_wmin.get(); + kappa_wmin = options.kappa_wmin.get(); + kappa_wplus = options.kappa_wplus.get(); + kappa_wplusem = options.kappa_wplusem.get(); + delta_c_stripe = options.delta_c_stripe.get(); + kappa_c = options.kappa_c.get(); + warm_start_init_point = options.warm_start_init_point.get(); + theta_min = options.theta_min.get(); + recalc_y = options.recalc_y.get(); + recalc_y_feas_tol = options.recalc_y_feas_tol.get(); +}; + fatrop_int FatropAlg::return_from_resto_alg(double mu) { // compute delta x diff --git a/fatrop/solver/FatropAlg.hpp b/fatrop/solver/FatropAlg.hpp index 36384409..706c8f55 100644 --- a/fatrop/solver/FatropAlg.hpp +++ b/fatrop/solver/FatropAlg.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPALGINCLUDED -#define FATROPALGINCLUDED +#ifndef __fatrop_solver_FatropAlg_hpp__ +#define __fatrop_solver_FatropAlg_hpp__ #include "fatrop/templates/NLPAlg.hpp" #include "FatropData.hpp" #include "Filter.hpp" @@ -90,6 +90,8 @@ namespace fatrop resto_alg_ = resto_alg; }; + void update_options(const FatropOptions &options); + private: double lammax; double mu0; @@ -118,4 +120,4 @@ namespace fatrop fatrop_int iter_count_ = 0; }; } // namespace fatrop -#endif // FATROPALGINCLUDED \ No newline at end of file +#endif // __fatrop_solver_FatropAlg_hpp__ \ No newline at end of file diff --git a/fatrop/solver/FatropData.cpp b/fatrop/solver/FatropData.cpp index 8389196a..a3215107 100644 --- a/fatrop/solver/FatropData.cpp +++ b/fatrop/solver/FatropData.cpp @@ -134,20 +134,14 @@ FatropData::FatropData(const NLPDims &nlpdims, const shared_ptr & printer_(printer) { initialize(); - params->register_option(DoubleOption::lower_bounded("warm_start_mult_bound_push", "warm_start_mult_bound_push", &warm_start_mult_bound_push, 1e-2, 0.0)); - params->register_option(DoubleOption::lower_bounded("smax", "smax", &smax, 100.0, 0.0)); - params->register_option(DoubleOption::lower_bounded("bound_push", "kappa1", &kappa1, 1e-2, 0.0)); - params->register_option(DoubleOption::lower_bounded("bound_frac", "kappa2", &kappa2, 1e-2, 0.0)); - params->register_option(DoubleOption::lower_bounded("kappa_sigma", "kappa_sigma", &kappa_sigma, 1e10, 0.0)); - params->register_option(DoubleOption::lower_bounded("bound_relax_factor", "bound_relax_factor", &bound_relax_factor, 1e-8, 0.0)); - params->register_option(DoubleOption::lower_bounded("constr_viol_tol", "constr_viol_tol", &constr_viol_tol, 1e-4, 0.0)); } void FatropData::initialize() { - kappa_d = params->kappa_d; + // kappa_d = params->kappa_d; } fatrop_int FatropData::reset() { + init_bounds(); VEC *lower_bound_p = (VEC *)s_lower; VEC *upper_bound_p = (VEC *)s_upper; VEC *zL_p = (VEC *)zL_curr; @@ -615,7 +609,7 @@ void FatropData::set_bounds(const vector &lowerin, const vector { s_lower_orig = lowerin; s_upper_orig = upperin; - init_bounds(); + // init_bounds(); } void FatropData::init_bounds() { @@ -781,5 +775,17 @@ bool FatropData::small_step_size() } return true; } +void FatropData::update_options(const FatropOptions& options) +{ + warm_start_mult_bound_push = options.warm_start_mult_bound_push.get(); + smax = options.smax.get(); + kappa1 = options.bound_push.get(); + kappa2 = options.bound_frac.get(); + kappa_sigma = options.kappa_sigma.get(); + bound_relax_factor = options.bound_relax_factor.get(); + constr_viol_tol = options.constr_viol_tol.get(); + kappa_d = options.kappa_d.get(); + +} // void FatropData::B \ No newline at end of file diff --git a/fatrop/solver/FatropData.hpp b/fatrop/solver/FatropData.hpp index 98ce84f0..fbd7659a 100644 --- a/fatrop/solver/FatropData.hpp +++ b/fatrop/solver/FatropData.hpp @@ -18,8 +18,8 @@ * along with Fatrop. If not, see . */ // solver data -#ifndef FATROPDATAINCLUDED -#define FATROPDATAINCLUDED +#ifndef __fatrop_solver_FatropData_hpp__ +#define __fatrop_solver_FatropData_hpp__ #include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" #include "fatrop/templates/NLPAlg.hpp" #include "fatrop/auxiliary/Common.hpp" @@ -79,6 +79,7 @@ namespace fatrop void compute_primal_dual_residu(); void init_bounds(); bool small_step_size(); + void update_options(const FatropOptions &options); const NLPDims nlpdims; @@ -185,4 +186,4 @@ namespace fatrop double warm_start_mult_bound_push; }; } -#endif // FATROPDATAINCLUDED \ No newline at end of file +#endif // __fatrop_solver_FatropData_hpp__ \ No newline at end of file diff --git a/fatrop/solver/FatropOptions.cpp b/fatrop/solver/FatropOptions.cpp index 6bd24ec1..fa4f688a 100644 --- a/fatrop/solver/FatropOptions.cpp +++ b/fatrop/solver/FatropOptions.cpp @@ -16,260 +16,146 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#include "fatrop/solver/FatropOptions.hpp" +#include "FatropOptions.hpp" using namespace fatrop; -using namespace std; -template -Option::Option(const string &name, const string &description, T *value, T default_value) : name_(name), description_(description), value(value), default_value_(default_value){}; -template -void Option::set(const T &new_value) const -{ - *value = new_value; -} -template -void Option::set_default() const -{ - *value = default_value_; -} - -template -NumberOption::NumberOption(const string &name, const string &description, T *value, T default_value, bool lower_bound_inclusive, T lower_bound, bool upper_bound_inclusive, T upper_bound) : Option(name, description, value, default_value), lower_bound_inclusive_(lower_bound_inclusive), lower_bound_(lower_bound), upper_bound_inclusive_(upper_bound_inclusive), upper_bound_(upper_bound){}; -template -NumberOption NumberOption::lower_bounded(const string &name, const string &description, T *value, T default_value, T lower_bound) -{ - return NumberOption(name, description, value, default_value, true, lower_bound, false, 0.0); -}; -template -NumberOption NumberOption::upper_bounded(const string &name, const string &description, T *value, T default_value, T upper_bound) -{ - return NumberOption(name, description, value, default_value, false, 0.0, true, upper_bound); -}; -template -NumberOption NumberOption::un_bounded(const string &name, const string &description, T *value, T default_value) -{ - return NumberOption(name, description, value, default_value, false, 0.0, false, 0.0); -}; -template -NumberOption NumberOption::box_bounded(const string &name, const string &description, T *value, T default_value, T lower_bound, T upper_bound) -{ - return NumberOption(name, description, value, default_value, true, lower_bound, true, upper_bound); -}; -template -void NumberOption::set(const T &new_value) const -{ - // check if new value is in bounds - if (lower_bound_inclusive_ && new_value < lower_bound_) - { - throw runtime_error("Option " + this->name_ + " is out of bounds"); - } - if (upper_bound_inclusive_ && new_value > upper_bound_) - { - throw runtime_error("Option " + this->name_ + " is out of bounds"); - } - *(this->value) = new_value; -}; - -FatropOptions::FatropOptions() -{ - register_option(IntegerOption::box_bounded("max_iter", "maximum number of iterations", &maxiter, 1000, 0, maxiter)); - register_option(DoubleOption::lower_bounded("kappa_d", "kappa_d", &kappa_d, 1e-5, 0.0)); -}; - -bool FatropOptions::has_option(const std::string &option_name) const -{ - if (numeric_options.find(option_name) != numeric_options.end()) - { - return true; - } - if (integer_options.find(option_name) != integer_options.end()) - { - return true; - } - if (boolean_options.find(option_name) != boolean_options.end()) - { - return true; - } - if (string_options.find(option_name) != string_options.end()) - { - return true; - } - return false; -} -template -void FatropOptions::set(const string &option_name, T value) const -{ - if (numeric_options.find(option_name) != numeric_options.end()) - { - if constexpr (std::is_floating_point::value) - { - for (auto &el : numeric_options.at(option_name)) - el.set(value); - } - else - { - throw std::runtime_error("Option " + option_name + " of type double"); - } - } - else if (integer_options.find(option_name) != integer_options.end()) - { - if constexpr (std::is_integral::value) - { - for (auto &el : integer_options.at(option_name)) - el.set(value); - } - else if constexpr (std::is_floating_point::value) - { - if ((int)value == value) - { - for (auto &el : integer_options.at(option_name)) - el.set(value); - } - else - { - throw std::runtime_error("Option " + option_name + " of type int"); - } - } - else - { - throw std::runtime_error("Option " + option_name + " of type int"); - } - } - else if (boolean_options.find(option_name) != boolean_options.end()) - { - if constexpr (std::is_same::value) - { - for (auto &el : boolean_options.at(option_name)) - el.set(value); - } - else if constexpr (std::is_integral::value || std::is_floating_point::value) - { - if (value == 0) - { - for (auto &el : boolean_options.at(option_name)) - el.set(value); - } - else if (value == 1) - { - for (auto &el : boolean_options.at(option_name)) - el.set(value); - } - else - { - throw std::runtime_error("Option " + option_name + " of type bool can only convert integer value 0 or 1 to bool, got " + to_string(value)); - } - } - else - { - throw std::runtime_error("Option " + option_name + " of type bool"); - } +// void OptionBase::set(const OptionValueVariant &value) +// { +// switch (value.type) +// { +// case OptionType::INT: +// set(*static_cast(value.value)); +// break; +// case OptionType::DOUBLE: +// set(*static_cast(value.value)); +// break; +// case OptionType::BOOL: +// set(*static_cast(value.value)); +// break; +// case OptionType::STRING: +// set(std::string(static_cast(value.value))); +// break; +// default: +// throw std::invalid_argument("Invalid type for option " + name); +// } +// } +void BoolOption::set(const std::string &value) +{ + if (value == "yes") + { + Option::set_value(true); + } + else if (value == "no") + { + Option::set_value(false); } else { - throw std::runtime_error("Option " + option_name + " not found"); + throw std::invalid_argument("Invalid string value for boolean option, should be 'yes' or 'no'"); } } template -void FatropOptions::prebuilt_set(const string &option_name, T value) +NumericOption NumericOption::lower_bounded(const std::string &name, const std::string &description, const T &default_value, const T &lower_bound, bool requires_reinitialization) { - if constexpr (std::is_integral::value || std::is_floating_point::value) - { - prebuilt_double[option_name] = value; - } - if constexpr (std::is_same::value) - { - prebuilt_string[option_name] = value; - } + return NumericOption(name, description, default_value, true, lower_bound, false, 0, requires_reinitialization); } - -void FatropOptions::register_option(const DoubleOption &option) +template +NumericOption NumericOption::upper_bounded(const std::string &name, const std::string &description, const T &default_value, const T &upper_bound, bool requires_reinitialization) { - numeric_options[option.name_].push_back(option); - option.set_default(); - // check if available in prebuilt options - if (prebuilt_double.find(option.name_) != prebuilt_double.end()) - { - option.set(prebuilt_double[option.name_]); - } - else - { - prebuilt_set(option.name_, option.default_value_); - } + return NumericOption(name, description, default_value, false, 0, true, upper_bound, requires_reinitialization); } -void FatropOptions::register_option(const IntegerOption &option) +template +NumericOption NumericOption::bounded(const std::string &name, const std::string &description, const T &default_value, const T &lower_bound, const T &upper_bound, bool requires_reinitialization) { - integer_options[option.name_].push_back(option); - option.set_default(); - // check if available in prebuilt options - if (prebuilt_double.find(option.name_) != prebuilt_double.end()) - { - option.set(prebuilt_double[option.name_]); - } - else - { - prebuilt_set(option.name_, option.default_value_); - } + return NumericOption(name, description, default_value, true, lower_bound, true, upper_bound, requires_reinitialization); } -void FatropOptions::register_option(const BooleanOption &option) +template +void NumericOption::set(T value_in) { - boolean_options[option.name_].push_back(option); - option.set_default(); - // check if available in prebuilt options - if (prebuilt_double.find(option.name_) != prebuilt_double.end()) + if ((is_lower_bounded && (value_in < lower_bound)) || (is_upper_bounded && (value_in > upper_bound))) { - option.set(prebuilt_double[option.name_]); - } - else - { - prebuilt_set(option.name_, option.default_value_); + throw std::invalid_argument("Value out of bounds"); } + Option::set_value(value_in); } +// instantiate the template for int and double +template class NumericOption; +template class NumericOption; -void FatropOptions::register_option(const StringOption &option) -{ - string_options[option.name_].push_back(option); - option.set_default(); - // check if available in prebuilt options - if (prebuilt_string.find(option.name_) != prebuilt_string.end()) - { - option.set(prebuilt_string[option.name_]); +FatropOptionsRegistry::FatropOptionsRegistry(FatropOptions &options) +{ + // register all options + OptionBase *all_options[] = { + &options.max_iter, + &options.print_level, + &options.tol, + &options.acceptable_tol, + &options.max_watchdog_steps, + &options.acceptable_iter, + &options.lammax, + &options.mu_init, + &options.kappa_eta, + &options.kappa_mu, + &options.theta_mu, + &options.delta_w0, + &options.delta_wmin, + &options.kappa_wmin, + &options.kappa_wplus, + &options.kappa_wplusem, + &options.delta_c_stripe, + &options.kappa_c, + &options.warm_start_init_point, + &options.theta_min, + &options.recalc_y, + &options.recalc_y_feas_tol, + &options.inequality_handling, + &options.kappa_d, + &options.accept_every_trial_step, + &options.s_phi, + &options.delta, + &options.s_theta, + &options.gamma_theta, + &options.gamma_phi, + &options.eta_phi, + &options.gamma_alpha, + &options.max_soc, + &options.linsol_iterative_refinement, + &options.linsol_perturbed_mode, + &options.linsol_diagnostic, + &options.linsol_perturbed_mode_param, + &options.linsol_min_it_ref, + &options.linsol_max_it_ref, + &options.linsol_min_it_acc, + &options.linsol_lu_fact_tol, + &options.iterative_refinement_SOC, + &options.ls_scaling, + &options.warm_start_mult_bound_push, + &options.smax, + &options.bound_push, + &options.bound_frac, + &options.kappa_sigma, + &options.bound_relax_factor, + &options.constr_viol_tol}; + for (auto option : all_options) + { + this->options[option->name] = option; } } -auto operator<<(std::ostream &os, const FatropOptions &m) -> std::ostream & +template +void FatropOptionsRegistry::set(const std::string &name, T value) { - os << "Numeric options :" << std::endl; - { - for (auto const &x : m.numeric_options) - { - os << " " << x.first << " : " << *x.second.at(0).value << std::endl; - } - } - os << "Integer options :" << std::endl; - { - for (auto const &x : m.integer_options) - { - os << " " << x.first << " : " << *x.second.at(0).value << std::endl; - } - } - os << "Boolean options :" << std::endl; + if (options.find(name) == options.end()) { - for (auto const &x : m.boolean_options) - { - os << " " << x.first << " : " << *x.second.at(0).value << std::endl; - } + throw std::invalid_argument("Option with name " + name + " not found"); } - return os; + options[name]->set(value); } -template class fatrop::NumberOption; -template class fatrop::NumberOption; -template class fatrop::Option; -template class fatrop::Option; -template void FatropOptions::set(const string &, double) const; -template void FatropOptions::set(const string &, int) const; -template void FatropOptions::set(const string &, bool) const; -template void FatropOptions::set(const string &, std::string) const; -template void FatropOptions::prebuilt_set(const string &, double); -template void FatropOptions::prebuilt_set(const string &, int); -template void FatropOptions::prebuilt_set(const string &, bool); -template void FatropOptions::prebuilt_set(const string &, std::string); \ No newline at end of file + +template void FatropOptionsRegistry::set(const std::string &, int); +template void FatropOptionsRegistry::set(const std::string &, double); +template void FatropOptionsRegistry::set(const std::string &, bool); +template void FatropOptionsRegistry::set(const std::string &, std::string); +template void FatropOptionsRegistry::set(const std::string &, const std::string&); +// template void FatropOptionsRegistry::set(const std::string &, OptionValueVariant); +// template void FatropOptionsRegistry::set(const std::string &, const OptionValueVariant&); \ No newline at end of file diff --git a/fatrop/solver/FatropOptions.hpp b/fatrop/solver/FatropOptions.hpp index 01ee9e3d..9d806fa1 100644 --- a/fatrop/solver/FatropOptions.hpp +++ b/fatrop/solver/FatropOptions.hpp @@ -16,80 +16,260 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPPARAMSINCLUDED -#define FATROPPARAMSINCLUDED -#include -#include -#include +#ifndef __fatrop_solver_FatropOptions_hpp__ +#define __fatrop_solver_FatropOptions_hpp__ #include -#include -#include "fatrop/auxiliary/Common.hpp" +#include +#include +#include +#include +#include + namespace fatrop { - template - struct Option + /** + * @enum OptionType + * + * Enum that defines the different types of options supported by the system. + */ + enum OptionType + { + INT, ///< Represents an integer option. + DOUBLE, ///< Represents a double-precision floating-point option. + BOOL, ///< Represents a boolean option. + STRING ///< Represents a string option. + }; + // // forward declaration + // struct OptionValueVariant; + + /** + * @class OptionBase + * + * Base class for different option types. Provides a generic interface + * for managing option values of various types. + */ + class OptionBase { public: - Option(){}; - Option(const std::string &name, const std::string &description, T *value, T default_value); - void set(const T &new_value) const; - void set_default() const; - std::string name_; - std::string description_; - T *value = NULL; - T default_value_; + OptionBase(const std::string &name, const std::string &description, bool requires_reinitialization) : name(name), description(description), requires_reinitialization(requires_reinitialization) {} + virtual void set(int value) { throw std::invalid_argument("Invalid type for option " + name); }; + virtual void set(double value) { throw std::invalid_argument("Invalid type for option " + name); }; + virtual void set(const std::string &value) { throw std::invalid_argument("Invalid type " + name); }; + virtual void set(bool value) { throw std::invalid_argument("Invalid type " + name); }; + std::string name; /// < The name of the option. + std::string description; // < The description of the option. + bool requires_reinitialization; /// < wether changing the option requires reinitialization of the solver's algorithmic objects. Reinitialization can require dynamic memory allocation. }; + /** + * @class Option + * + * Templated class that holds a value of type T and provides methods + * to set and get that value. Inherits from OptionBase. + * + * @tparam T The type of the option (e.g., int, double, std::string). + */ + template + class Option : public OptionBase + { + public: + /** + * @brief Constructor that initializes the option with a name, description, and default value. + * @param name The name of the option. + * @param description The description of the option. + * @param default_value The default value of the option. + */ + Option(const ::std::string &name, const std::string &description, const T &default_value, bool requires_reinitialization) : OptionBase(name, description, requires_reinitialization), value(default_value) {} + void set_value(T value_in) { this->value = value_in; } + const T &get() const { return value; } + private: + T value; + }; + /** + * @class BoolOption + * + * A subclass of Option for handling boolean options. Allows setting + * values using either a boolean or a string ("yes"/"no"). + */ + class BoolOption : public Option + { + public: + BoolOption(const std::string &name, const std::string &description, bool default_value, bool requires_reinitialization) : Option(name, description, default_value, requires_reinitialization) {} + void set(bool value) { Option::set_value(value); } + void set(const std::string &value); + }; + + /** + * @class NumericOption + * + * A subclass of Option that handles numeric options, such as int or double, + * with the ability to enforce lower and/or upper bounds. + * + * @tparam T The numeric type of the option (e.g., int, double). + */ template - struct NumberOption: public Option + class NumericOption : public Option { public: - // DoubleOption operator=(const DoubleOption &other) = default; - NumberOption(){}; - NumberOption(const std::string &name, const std::string &description, T *value, T default_value, bool lower_bound_inclusive, T lower_bound, bool upper_bound_inclusive, T upper_bound); - static NumberOption lower_bounded(const std::string &name, const std::string &description, T *value, T default_value, T lower_bound); - static NumberOption upper_bounded(const std::string &name, const std::string &description, T *value, T default_value, T upper_bound); - static NumberOption un_bounded(const std::string &name, const std::string &description, T *value, T default_value); - static NumberOption box_bounded(const std::string &name, const std::string &description, T *value, T default_value, T lower_bound, T upper_bound); - void set(const T &new_value) const; - bool lower_bound_inclusive_; - T lower_bound_; - bool upper_bound_inclusive_; - T upper_bound_; + /** + * @brief Creates a lower-bounded numeric option. + * @param name The name of the option. + * @param description The description of the option. + * @param default_value The default value of the option. + * @param lower_bound The lower bound for the option value. + * @return A new NumericOption with the lower bound. + */ + static NumericOption lower_bounded(const std::string &name, const std::string &description, const T &default_value, const T &lower_bound, bool requires_reinitialization); + /** + * @brief Creates an upper-bounded numeric option. + * @param name The name of the option. + * @param description The description of the option. + * @param default_value The default value of the option. + * @param upper_bound The upper bound for the option value. + * @return A new NumericOption with the upper bound. + */ + static NumericOption upper_bounded(const std::string &name, const std::string &description, const T &default_value, const T &upper_bound, bool requires_reinitialization); + /** + * @brief Creates a bounded numeric option with both lower and upper bounds. + * @param name The name of the option. + * @param description The description of the option. + * @param default_value The default value of the option. + * @param lower_bound The lower bound for the option value. + * @param upper_bound The upper bound for the option value. + * @return A new NumericOption with both bounds. + */ + static NumericOption bounded(const std::string &name, const std::string &description, const T &default_value, const T &lower_bound, const T &upper_bound, bool requires_reinitialization); + void set(T value_in); + + private: + /** + * @brief Constructor that initializes a numeric option with bounds. + * @param name The name of the option. + * @param description The description of the option. + * @param default_value The default value of the option. + * @param lower_bounded Whether the option has a lower bound. + * @param lower_bound The lower bound. + * @param upper_bounded Whether the option has an upper bound. + * @param upper_bound The upper bound. + */ + NumericOption(const std::string &name, const std::string &description, const T &default_value, bool lower_bounded, const T &lower_bound, bool upper_bounded, const T &upper_bound, bool requires_reinitialization) : Option(name, description, default_value, requires_reinitialization), is_lower_bounded(lower_bounded), lower_bound(lower_bound), is_upper_bounded(upper_bounded), upper_bound(upper_bound) {} + bool is_lower_bounded; ///< Whether the option has a lower bound. + T lower_bound; ///< The lower bound for the option value. + bool is_upper_bounded; ///< Whether the option has an upper bound. + T upper_bound; ///< The upper bound for the option value. }; - // define Numeric option as Option - typedef NumberOption DoubleOption; - typedef NumberOption IntegerOption; + + typedef NumericOption IntOption; + typedef NumericOption DoubleOption; typedef Option StringOption; - typedef Option BooleanOption; + typedef BoolOption BoolOption; - class FatropOptions + /** + * @struct FatropOptions + * + * Contains the configuration settings for the system. + * It is optimized for fast look-up performance, + * as these options are accessed each time the Fatrop algorithm is executed. + */ + struct FatropOptions + { + // print options + IntOption print_level = IntOption::lower_bounded("print_level", "fatrop print level", 10, 0, false); + // fatrop algorithm options + IntOption max_iter = IntOption::lower_bounded("max_iter", "maximum number of iterations", 1000, 0, true); + DoubleOption tol = DoubleOption::lower_bounded("tol", "tolerance", 1e-8, 0.0, false); + DoubleOption acceptable_tol = DoubleOption::lower_bounded("acceptable_tol", "acceptable tolerance", 1e-6, 0.0, false); + IntOption max_watchdog_steps = IntOption::lower_bounded("max_watchdog_steps", "maximum number of watchdog steps", 4, 0, false); + IntOption acceptable_iter = IntOption::lower_bounded("acceptable_iter", "acceptable iter", 15, 0, false); + DoubleOption lammax = DoubleOption::lower_bounded("lammax", "lammax", 1e3, 0.0, false); + DoubleOption mu_init = DoubleOption::lower_bounded("mu_init", "mu_init", 1e2, 0.0, false); + DoubleOption kappa_eta = DoubleOption::lower_bounded("kappa_eta", "kappa_eta", 10.0, 0.0, false); + DoubleOption kappa_mu = DoubleOption::lower_bounded("kappa_mu", "kappa_mu", 0.2, 0.0, false); + DoubleOption theta_mu = DoubleOption::lower_bounded("theta_mu", "theta_mu", 1.5, 0.0, false); + DoubleOption delta_w0 = DoubleOption::lower_bounded("delta_w0", "delta_w0", 1e-4, 0.0, false); + DoubleOption delta_wmin = DoubleOption::lower_bounded("delta_wmin", "delta_wmin", 1e-20, 0.0, false); + DoubleOption kappa_wmin = DoubleOption::lower_bounded("kappa_wmin", "kappa_wmin", 1.0 / 3.0, 0.0, false); + DoubleOption kappa_wplus = DoubleOption::lower_bounded("kappa_wplus", "kappa_wplus", 8.0, 0.0, false); + DoubleOption kappa_wplusem = DoubleOption::lower_bounded("kappa_wplusem", "kappa_wplusem", 100.0, 0.0, false); + DoubleOption delta_c_stripe = DoubleOption::lower_bounded("delta_c_stripe", "delta_c_stripe", 1e-6, 0.0, false); + DoubleOption kappa_c = DoubleOption::lower_bounded("kappa_c", "kappa_c", 0.25, 0.0, false); + BoolOption warm_start_init_point = BoolOption("warm_start_init_point", "warm_start_init_point", false, false); + DoubleOption theta_min = DoubleOption::lower_bounded("theta_min", "theta_min", 1e-4, 0.0, false); + BoolOption recalc_y = BoolOption("recalc_y", "recalc_y", false, false); + DoubleOption recalc_y_feas_tol = DoubleOption::lower_bounded("recalc_y_feas_tol", "recalc_y_feas_tol", 1e-6, 0.0, false); + StringOption inequality_handling = StringOption("inequality_handling", "inequality_handling", "pd_ip", true); + DoubleOption kappa_d = DoubleOption::lower_bounded("kappa_d", "kappa_d", 1e-5, 0.0, false); + // line search options + BoolOption accept_every_trial_step = BoolOption("accept_every_trial_step", "accept every trial step", false, false); + DoubleOption s_phi = DoubleOption::lower_bounded("s_phi", "s_phi", 2.3, 0.0, false); + DoubleOption delta = DoubleOption::lower_bounded("delta", "delta", 1.0, 0.0, false); + DoubleOption s_theta = DoubleOption::lower_bounded("s_theta", "s_theta", 1.1, 0.0, false); + DoubleOption gamma_theta = DoubleOption::lower_bounded("gamma_theta", "gamma_theta", 1e-5, 0.0, false); + DoubleOption gamma_phi = DoubleOption::lower_bounded("gamma_phi", "gamma_phi", 1e-8, 0.0, false); + DoubleOption eta_phi = DoubleOption::lower_bounded("eta_phi", "eta_phi", 1e-8, 0.0, false); + DoubleOption gamma_alpha = DoubleOption::lower_bounded("gamma_alpha", "gamma_alpha", 0.05, 0.0, false); + IntOption max_soc = IntOption::lower_bounded("max_soc", "max_soc", 2, 0, false); + // linear solver options + BoolOption linsol_iterative_refinement = BoolOption("linsol_iterative_refinement", "iterative ref", true, false); + BoolOption linsol_perturbed_mode = BoolOption("linsol_perturbed_mode", "linear solver perturbed mode", false, false); + BoolOption linsol_diagnostic = BoolOption("linsol_diagnostic", "linear solver diagnostic mode", false, false); + DoubleOption linsol_perturbed_mode_param = DoubleOption::lower_bounded("linsol_perturbed_mode_param", "linear solver perturbed mode param", 1e-6, 0., false); + IntOption linsol_min_it_ref = IntOption::lower_bounded("linsol_min_it_ref", "minimum number of iterative refinement steps", 0, 0, false); + IntOption linsol_max_it_ref = IntOption::lower_bounded("linsol_max_it_ref", "maximum number of iterative refinement steps", 5, 0, false); + DoubleOption linsol_min_it_acc = DoubleOption::lower_bounded("linsol_min_it_acc", "stopping criterion for iterative refinement procedure", 1e-8, 0., false); + DoubleOption linsol_lu_fact_tol = DoubleOption::lower_bounded("linsol_lu_fact_tol", "pivoting tolerance parameter for lu fact", 1e-5, 0., false); + BoolOption iterative_refinement_SOC = BoolOption("iterative_refinement_SOC", "Use iterative refinement for SOC", true, false); + BoolOption ls_scaling = BoolOption("ls_scaling", "Use automatic scaling for linear system", true, false); + // fatrop data options + DoubleOption warm_start_mult_bound_push = DoubleOption::lower_bounded("warm_start_mult_bound_push", "warm_start_mult_bound_push", 1e-2, 0.0, false); + DoubleOption smax = DoubleOption::lower_bounded("smax", "smax", 100.0, 0.0, false); + DoubleOption bound_push = DoubleOption::lower_bounded("bound_push", "kappa1", 1e-2, 0.0, false); + DoubleOption bound_frac = DoubleOption::lower_bounded("bound_frac", "kappa2", 1e-2, 0.0, false); + DoubleOption kappa_sigma = DoubleOption::lower_bounded("kappa_sigma", "kappa_sigma", 1e10, 0.0, false); + DoubleOption bound_relax_factor = DoubleOption::lower_bounded("bound_relax_factor", "bound_relax_factor", 1e-8, 0.0, false); + DoubleOption constr_viol_tol = DoubleOption::lower_bounded("constr_viol_tol", "constr_viol_tol", 1e-4, 0.0, false); + // restoration phase options + DoubleOption resto_rho = DoubleOption::lower_bounded("resto_rho", "Resto L1 penalty parameter", 1000., 0.0, false); + DoubleOption resto_xi = DoubleOption::lower_bounded("resto_xi", "Resto xi parameter", 1., 0.0, false); + }; + + // /** + // * @struct OptionValueVariant + // * + // * A structure used to hold a value of different types (int, double, string) + // * and identify its type. This structure is used to pass values to options. + // */ + // struct OptionValueVariant + // { + // OptionValueVariant(int value_in) : type(OptionType::INT), value(malloc(sizeof(int))) { *static_cast(value) = value_in; } + // OptionValueVariant(double value_in) : type(OptionType::DOUBLE), value(malloc(sizeof(double))) { *static_cast(value) = value_in; } + // OptionValueVariant(bool value_in) : type(OptionType::BOOL), value(malloc(sizeof(bool))) { *static_cast(value) = value_in; } + // OptionValueVariant(const std::string &value_in) : type(OptionType::STRING), value(malloc((value_in.size()+1)*sizeof(char))) { std::strcpy(static_cast(value), value_in.c_str()); } + // OptionValueVariant(const char *value_in) : type(OptionType::STRING), value(malloc((std::strlen(value_in)+1)*sizeof(char))) { std::strcpy(static_cast(value), value_in); } + // ~OptionValueVariant() { free(value); } + // OptionType type; + // void *value; + // }; + + /** + * @class FatropOptionsRegistry + * + * A class that manages a collection of options (FatropOptions). + * Provides a way to set option values dynamically. + */ + class FatropOptionsRegistry { public: - FatropOptions(); - // the following options are shared between different algorithm components: - int maxiter = 1000; // TODO this value cannot be changed to a value larger than the one used for building the solver - double kappa_d = 1e-5; + FatropOptionsRegistry(FatropOptions &options); + // T can be int, double, bool, string, or an OptionValueVariant template - void set(const std::string &option_name, T value) const; - template - void prebuilt_set(const std::string &option_name, T value); + void set(const std::string &name, T value); public: - bool has_option(const std::string &option_name) const; - void register_option(const DoubleOption &option); - void register_option(const IntegerOption &option); - void register_option(const BooleanOption &option); - void register_option(const StringOption &option); - friend auto operator<<(std::ostream &os, const FatropOptions &m) -> std::ostream &; - std::map> numeric_options; - std::map> integer_options; - std::map> boolean_options; - std::map> string_options; - std::map prebuilt_string; - std::map prebuilt_double; + std::unordered_map options; }; -} // namespace fatrop -#endif // FatropOptions \ No newline at end of file +}; + +#endif // __fatrop_solver_FatropOptions_hpp__ \ No newline at end of file diff --git a/fatrop/solver/FatropPrinter.hpp b/fatrop/solver/FatropPrinter.hpp index de97b02c..5cb11f70 100644 --- a/fatrop/solver/FatropPrinter.hpp +++ b/fatrop/solver/FatropPrinter.hpp @@ -17,8 +17,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ #define PRIORITY1 PrintPriority<1>() -#ifndef FATROPPRINTERINCLUDED -#define FATROPPRINTERINCLUDED +#ifndef __fatrop_solver_FatropPrinter_hpp__ +#define __fatrop_solver_FatropPrinter_hpp__ #include #include #include @@ -62,4 +62,4 @@ namespace fatrop }; } // namespace fatrop -#endif // FATROPITERATIONDATAINCLUDED \ No newline at end of file +#endif // __fatrop_solver_FatropPrinter_hpp__ \ No newline at end of file diff --git a/fatrop/solver/FatropStats.hpp b/fatrop/solver/FatropStats.hpp index 65e30c86..c972cfaa 100644 --- a/fatrop/solver/FatropStats.hpp +++ b/fatrop/solver/FatropStats.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPSTATSINCLUDED -#define FATROPSTATSINCLUDED +#ifndef __fatrop_solver_FatropStats_hpp__ +#define __fatrop_solver_FatropStats_hpp__ #include namespace fatrop { @@ -60,4 +60,4 @@ namespace fatrop } }; } // namespace fatrop -#endif // FATROPSTATSINCLUDED \ No newline at end of file +#endif // __fatrop_solver_FatropStats_hpp__ \ No newline at end of file diff --git a/fatrop/solver/Filter.cpp b/fatrop/solver/Filter.cpp index 27424ded..abda3cf2 100644 --- a/fatrop/solver/Filter.cpp +++ b/fatrop/solver/Filter.cpp @@ -52,4 +52,4 @@ bool Filter::is_acceptable(const FilterData &fdin) const void Filter::reset() { filterdata_.resize(0); -} \ No newline at end of file +} diff --git a/fatrop/solver/Filter.hpp b/fatrop/solver/Filter.hpp index 0b5b7472..8c31b1ad 100644 --- a/fatrop/solver/Filter.hpp +++ b/fatrop/solver/Filter.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FILTERINCLUDED -#define FILTERINCLUDED +#ifndef __fatrop_solver_Filter_hpp__ +#define __fatrop_solver_Filter_hpp__ #include "vector" #include "fatrop/auxiliary/Common.hpp" namespace fatrop @@ -45,10 +45,15 @@ namespace fatrop { return filterdata_.size(); } + void reserve(const fatrop_int size) + { + + filterdata_.reserve(size); + } private: std::vector filterdata_; }; } // namespace fatrop -#endif // FILTERINCLUDED \ No newline at end of file +#endif // __fatrop_solver_Filter_hpp__ \ No newline at end of file diff --git a/fatrop/solver/IterationData.hpp b/fatrop/solver/IterationData.hpp index c2566907..0302ac60 100644 --- a/fatrop/solver/IterationData.hpp +++ b/fatrop/solver/IterationData.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef FATROPITERATIONDATAINCLUDED -#define FATROPITERATIONDATAINCLUDED +#ifndef __fatrop_solver_IterationData_hpp__ +#define __fatrop_solver_IterationData_hpp__ #include #include #include @@ -53,4 +53,4 @@ namespace fatrop std::shared_ptr printer_; }; } // namespace fatrop -#endif // FATROPITERATIONDATAINCLUDED \ No newline at end of file +#endif // __fatrop_solver_FatropPrinter_hpp__ \ No newline at end of file diff --git a/fatrop/solver/LineSearch.cpp b/fatrop/solver/LineSearch.cpp index d3a275ab..0a0aae7c 100644 --- a/fatrop/solver/LineSearch.cpp +++ b/fatrop/solver/LineSearch.cpp @@ -103,15 +103,6 @@ BackTrackingLineSearch::BackTrackingLineSearch( : LineSearch(fatropparams, nlp, fatropdata, printer), filter_(filter), journaller_(journaller) { initialize(); - fatrop_params_->register_option(BooleanOption("accept_every_trial_step", "accept every trial step", &accept_every_trial_step, false)); - fatrop_params_->register_option(DoubleOption::lower_bounded("s_phi", "s_phi", &s_phi, 2.3, 0.0)); - fatrop_params_->register_option(DoubleOption::lower_bounded("delta", "delta", &delta, 1.0, 0.0)); - fatrop_params_->register_option(DoubleOption::lower_bounded("s_theta", "s_theta", &s_theta, 1.1, 0.0)); - fatrop_params_->register_option(DoubleOption::lower_bounded("gamma_theta", "gamma_theta", &gamma_theta, 1e-5, 0.0)); - fatrop_params_->register_option(DoubleOption::lower_bounded("gamma_phi", "gamma_phi", &gamma_phi, 1e-8, 0.0)); - fatrop_params_->register_option(DoubleOption::lower_bounded("eta_phi", "eta_phi", &eta_phi, 1e-8, 0.0)); - fatrop_params_->register_option(DoubleOption::lower_bounded("gamma_alpha", "gamma_alpha", &gamma_alpha, 0.05, 0.0)); - fatrop_params_->register_option(IntegerOption::lower_bounded("max_soc", "max_soc", &max_soc, 2, 0)); }; void BackTrackingLineSearch::initialize() { @@ -291,4 +282,17 @@ LineSearchInfo BackTrackingLineSearch::find_acceptable_trial_point(double mu, bo } res.ls = 0; return res; -}; \ No newline at end of file +}; + +void BackTrackingLineSearch::update_options(const FatropOptions &options) +{ + accept_every_trial_step = options.accept_every_trial_step.get(); + s_phi = options.s_phi.get(); + delta = options.delta.get(); + s_theta = options.s_theta.get(); + gamma_theta = options.gamma_theta.get(); + gamma_phi = options.gamma_phi.get(); + eta_phi = options.eta_phi.get(); + gamma_alpha = options.gamma_alpha.get(); + max_soc = options.max_soc.get(); +} \ No newline at end of file diff --git a/fatrop/solver/LineSearch.hpp b/fatrop/solver/LineSearch.hpp index 39040dc9..ef484abd 100644 --- a/fatrop/solver/LineSearch.hpp +++ b/fatrop/solver/LineSearch.hpp @@ -16,8 +16,8 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef LINESEARCHINCLUDED -#define LINESEARCHINCLUDED +#ifndef __fatrop_solver_LineSearch_hpp__ +#define __fatrop_solver_LineSearch_hpp__ #include "AlgStrategy.hpp" #include "IterationData.hpp" #include "fatrop/templates/NLPAlg.hpp" @@ -50,6 +50,7 @@ namespace fatrop virtual fatrop_int initialize_second_order_correction() const; virtual fatrop_int exit_second_order_correction() const; virtual fatrop_int compute_second_order_correction(double alpha) const; + virtual void update_options(const FatropOptions &options) = 0; std::shared_ptr fatropnlp_; std::shared_ptr fatropdata_; std::shared_ptr printer_; @@ -69,6 +70,7 @@ namespace fatrop const std::shared_ptr &filter, const std::shared_ptr &journaller, const std::shared_ptr &printer); void initialize(); + void update_options(const FatropOptions &options) override; LineSearchInfo find_acceptable_trial_point(double mu, bool small_sd, bool from_backup); std::shared_ptr filter_; std::shared_ptr journaller_; @@ -83,4 +85,4 @@ namespace fatrop fatrop_int max_soc; }; } // namespace fatrop -#endif // LINESEARCHINCLUDED \ No newline at end of file +#endif // __fatrop_solver_LineSearch_hpp__ \ No newline at end of file diff --git a/fatrop/solver/NLPL1.hpp b/fatrop/solver/NLPL1.hpp index 0fa0736c..774569f7 100644 --- a/fatrop/solver/NLPL1.hpp +++ b/fatrop/solver/NLPL1.hpp @@ -9,7 +9,6 @@ namespace fatrop public: NLPL1(const std::shared_ptr &orig, const std::shared_ptr& opts) : orig_(orig), orig_dims_(orig->get_nlp_dims()), lower_(orig_dims_.nineqs), upper_(orig_dims_.nineqs), upper_bounded_(orig_dims_.nineqs), lower_bounded_(orig_dims_.nineqs), slack_dummy_(orig_dims_.nineqs), sigma_dummy_(orig_dims_.nineqs), gradb_dummy_(orig_dims_.nineqs), zl_dummy_(orig_dims_.nineqs), zu_dummy_(orig_dims_.nineqs), sigma_cache_(orig_dims_.nineqs * 3), gradb_cache_(orig_dims_.nineqs * 3) { - opts -> register_option(DoubleOption::lower_bounded("L1_rho", "L1 penalty parameter", &rho, 1e4, 0.0)); auto lower_v = lower_[0]; auto upper_v = upper_[0]; orig_->get_bounds(lower_v, upper_v); @@ -242,6 +241,11 @@ namespace fatrop orig_->get_initial_sol_guess(initial); return 0; } + void update_options(const FatropOptions & options) override + { + orig_->update_options(options); + rho = options.resto_rho.get(); + } std::shared_ptr orig_; NLPDims orig_dims_; NLPDims this_dims_; diff --git a/fatrop/spectool/solver_interfaces/fatrop/fatrop_function.hpp b/fatrop/spectool/solver_interfaces/fatrop/fatrop_function.hpp index 1395f679..9bda883c 100644 --- a/fatrop/spectool/solver_interfaces/fatrop/fatrop_function.hpp +++ b/fatrop/spectool/solver_interfaces/fatrop/fatrop_function.hpp @@ -6,6 +6,7 @@ #include "fatrop/ocp/StageOCPApplication.hpp" #include "fatrop/ocp/OCPDims.hpp" #include "fatrop/ocp/CasadiCApiUserdataWrap.hpp" +#include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" namespace fatrop { namespace spectool diff --git a/fatrop/templates/NLPAlg.hpp b/fatrop/templates/NLPAlg.hpp index d22e376b..25af8e73 100644 --- a/fatrop/templates/NLPAlg.hpp +++ b/fatrop/templates/NLPAlg.hpp @@ -16,12 +16,15 @@ * * You should have received a copy of the GNU Lesser General Public License * along with Fatrop. If not, see . */ -#ifndef NLPINCLUDED -#define NLPINCLUDED -#include "fatrop/blasfeo_wrapper/LinearAlgebraBlasfeo.hpp" +#ifndef __fatrop_templates_NLPAlg_hpp__ +#define __fatrop_templates_NLPAlg_hpp__ #include "fatrop/auxiliary/Common.hpp" namespace fatrop { + // forward declarations + class FatropVecBF; + class FatropOptions; + struct NLPDims { fatrop_int nvars; @@ -99,6 +102,7 @@ namespace fatrop virtual void finalize(){}; virtual void reset(){}; virtual void update_mu(double mu){}; + virtual void update_options(const FatropOptions& options) = 0; }; } // namespace fatrop -#endif // NLPINCLUDED \ No newline at end of file +#endif // __fatrop_templates_NLPAlg_hpp__ \ No newline at end of file diff --git a/fatropy/src/fatropy.cpp b/fatropy/src/fatropy.cpp index 83803ac3..e002c14d 100644 --- a/fatropy/src/fatropy.cpp +++ b/fatropy/src/fatropy.cpp @@ -91,7 +91,10 @@ PYBIND11_MODULE(_fatropy, m) py::class_(m, "StageOCPApplication") .def(py::init &>()) .def("optimize", &fatrop::StageOCPApplication::optimize) + .def("set_option", &fatrop::StageOCPApplication::set_option) + .def("set_option", &fatrop::StageOCPApplication::set_option) .def("set_option", &fatrop::StageOCPApplication::set_option) + .def("set_option", &fatrop::StageOCPApplication::set_option) .def("last_solution", &fatrop::StageOCPApplication::last_solution) .def("get_expression", &fatrop::StageOCPApplication::get_expression) // .def("set_initial", [](fatrop::NLPApplication& app, const fatrop::FatropSolution &initial_guess){return app.set_initial(initial_guess);}, py::const_) diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt new file mode 100644 index 00000000..7a621c69 --- /dev/null +++ b/unittest/CMakeLists.txt @@ -0,0 +1,6 @@ +find_package(GTest REQUIRED) +include_directories(${GTEST_INCLUDE_DIRS}) + +add_executable(FatropOptionsTests FatropOptionsTests.cpp) +target_link_libraries(FatropOptionsTests fatrop) +target_link_libraries(FatropOptionsTests ${GTEST_LIBRARIES}) \ No newline at end of file diff --git a/unittest/FatropOptionsTests.cpp b/unittest/FatropOptionsTests.cpp new file mode 100644 index 00000000..c7a38948 --- /dev/null +++ b/unittest/FatropOptionsTests.cpp @@ -0,0 +1,87 @@ +#include +#include +#include "fatrop/solver/FatropOptions.hpp" // Replace with the actual file name containing your code + +namespace fatrop { + +// Test OptionBase and derived classes functionality +class OptionTests : public ::testing::Test { +protected: + FatropOptions options; // Create an instance of FatropOptions to test + FatropOptionsRegistry registry{options}; // Create the registry with the options +}; + +// Test valid setting for IntOption +TEST_F(OptionTests, TestSetIntOption) { + int new_value(200); // An int value to set + registry.set("max_iter", new_value); + + EXPECT_EQ(options.max_iter.get(), 200); // Validate the value was set correctly +} + +// Test valid setting for DoubleOption +TEST_F(OptionTests, TestSetDoubleOption) { + double new_value(1e-5); // A double value to set + registry.set("tol", new_value); + + EXPECT_EQ(options.tol.get(), 1e-5); // Validate the value was set correctly +} + +// Test valid setting for BoolOption with "yes" +TEST_F(OptionTests, TestSetBoolOptionYes) { + std::string new_value("yes"); + registry.set("recalc_y", new_value); + + EXPECT_TRUE(options.recalc_y.get()); // Validate the boolean value was set to true +} + +// Test valid setting for BoolOption with "no" +TEST_F(OptionTests, TestSetBoolOptionNo) { + std::string new_value("no"); + registry.set("recalc_y", new_value); + + EXPECT_FALSE(options.recalc_y.get()); // Validate the boolean value was set to false +} + +// Test setting out-of-bounds value for IntOption (lower bound) +TEST_F(OptionTests, TestSetIntOptionOutOfBoundsLower) { + int new_value(-1); // Invalid value (out of bounds for max_iter) + + EXPECT_THROW(registry.set("max_iter", new_value), std::invalid_argument); // Should throw an exception +} + +// Test setting out-of-bounds value for DoubleOption (lower bound) +TEST_F(OptionTests, TestSetDoubleOptionOutOfBoundsLower) { + double new_value(-1e-7); // Invalid value (out of bounds for tol) + + EXPECT_THROW(registry.set("tol", new_value), std::invalid_argument); // Should throw an exception +} + +// Test setting invalid type (wrong type, e.g. string for IntOption) +TEST_F(OptionTests, TestSetInvalidTypeForIntOption) { + std::string new_value("wrong type"); // Invalid type (string instead of int) + + EXPECT_THROW(registry.set("max_iter", new_value), std::invalid_argument); // Should throw an exception +} + +// Test setting invalid string value for BoolOption +TEST_F(OptionTests, TestSetInvalidStringForBoolOption) { + std::string new_value("maybe"); // Invalid string for a boolean option + + EXPECT_THROW(registry.set("recalc_y", new_value), std::invalid_argument); // Should throw an exception +} + +// Test setting value for an option that doesn't exist +TEST_F(OptionTests, TestSetNonExistentOption) { + int new_value(42); // Arbitrary value + + EXPECT_THROW(registry.set("non_existent_option", new_value), std::invalid_argument); // Should throw an exception +} + +} // namespace fatrop + +// Main function to run the tests +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}