From 280c2bcff6b3fd0c09b03bd814acc1d64707fc1a Mon Sep 17 00:00:00 2001 From: Wim Van Roy Date: Thu, 25 May 2023 15:17:50 +0200 Subject: [PATCH] Add change options to ipopt --- casadi/core/function.cpp | 6 +-- casadi/core/function_internal.cpp | 10 +++++ casadi/core/function_internal.hpp | 16 +++++-- casadi/core/nlpsol.cpp | 6 +++ casadi/core/nlpsol_impl.hpp | 4 ++ casadi/core/oracle_function.cpp | 6 +++ casadi/core/oracle_function.hpp | 3 ++ casadi/interfaces/ipopt/ipopt_interface.cpp | 50 +++++++++++++++++++++ casadi/interfaces/ipopt/ipopt_interface.hpp | 2 + 9 files changed, 96 insertions(+), 7 deletions(-) diff --git a/casadi/core/function.cpp b/casadi/core/function.cpp index 0a877d7ef6..d46f801d37 100644 --- a/casadi/core/function.cpp +++ b/casadi/core/function.cpp @@ -1115,11 +1115,9 @@ namespace casadi { void Function::change_option(const std::string& option_name, const GenericType& option_value) { try { - // Assert existance - if (!has_option(option_name)) - casadi_error("Option '" + option_name + "' does not exist"); // Call internal class - (*this)->change_option(option_name, option_value); + scoped_checkout mem(*this); + (*this)->change_option(memory(mem), option_name, option_value); } catch(std::exception& e) { THROW_ERROR("change_option", e.what()); } diff --git a/casadi/core/function_internal.cpp b/casadi/core/function_internal.cpp index dfeeec5884..21d2d0ff08 100644 --- a/casadi/core/function_internal.cpp +++ b/casadi/core/function_internal.cpp @@ -438,6 +438,11 @@ namespace casadi { } } + void FunctionInternal::change_option(void* mem, const std::string& option_name, + const GenericType& option_value) { + change_option(option_name, option_value); + } + void FunctionInternal::init(const Dict& opts) { // Call the initialization method of the base class ProtoFunction::init(opts); @@ -914,6 +919,11 @@ namespace casadi { } } + void ProtoFunction::change_option(void* mem, const std::string& option_name, + const GenericType& option_value) { + change_option(option_name, option_value); + } + std::vector FunctionInternal::get_free() const { casadi_assert_dev(!has_free()); return std::vector(); diff --git a/casadi/core/function_internal.hpp b/casadi/core/function_internal.hpp index eb8b9607d9..81f10ae75d 100644 --- a/casadi/core/function_internal.hpp +++ b/casadi/core/function_internal.hpp @@ -134,11 +134,20 @@ namespace casadi { \identifier{jj} */ bool has_option(const std::string &option_name) const; - /** \brief Change option after object creation for debugging + /** \brief Change option after object creation \identifier{jk} */ virtual void change_option(const std::string& option_name, const GenericType& option_value); + /** \brief Change options after object creation + + Internally changes the options of this function. + + \identifier{jk} */ + virtual void change_option(void* mem, + const std::string& option_name, + const GenericType& option_value); + /** \brief Initialize Initialize and make the object ready for setting arguments and evaluation. @@ -305,8 +314,9 @@ namespace casadi { /** \brief Change option after object creation for debugging \identifier{k5} */ - void change_option(const std::string& option_name, const GenericType& option_value) override; - + virtual void change_option(const std::string& option_name, const GenericType& option_value) override; + virtual void change_option(void* mem, const std::string& option_name, + const GenericType& option_value) override; /** \brief Initialize \identifier{k6} */ diff --git a/casadi/core/nlpsol.cpp b/casadi/core/nlpsol.cpp index ef10956343..8b682f6a45 100644 --- a/casadi/core/nlpsol.cpp +++ b/casadi/core/nlpsol.cpp @@ -1183,6 +1183,12 @@ namespace casadi { return Function(name, arg, res, inames, onames, options); } + void Nlpsol::change_option(void* mem, + const std::string& option_name, + const GenericType& option_value) { + OracleFunction::change_option(mem, option_name, option_value); + } + int Nlpsol::callback(NlpsolMemory* m) const { // Quick return if no callback function if (fcallback_.is_null()) return 0; diff --git a/casadi/core/nlpsol_impl.hpp b/casadi/core/nlpsol_impl.hpp index bf09ae4f4d..c8f2aaf657 100644 --- a/casadi/core/nlpsol_impl.hpp +++ b/casadi/core/nlpsol_impl.hpp @@ -247,6 +247,10 @@ namespace casadi { const Dict& opts) const override; ///@} + // Change option after object creation + void change_option(void* mem, const std::string& option_name, + const GenericType& option_value) override; + // Call the callback function int callback(NlpsolMemory* m) const; diff --git a/casadi/core/oracle_function.cpp b/casadi/core/oracle_function.cpp index 63ed0df217..ae2f192a40 100644 --- a/casadi/core/oracle_function.cpp +++ b/casadi/core/oracle_function.cpp @@ -431,6 +431,12 @@ Dict OracleFunction::get_stats(void *mem) const { return stats; } +void OracleFunction::change_option(void* mem, + const std::string& option_name, + const GenericType& option_value) { + FunctionInternal::change_option(option_name, option_value); +} + int OracleFunction::local_init_mem(void* mem) const { if (ProtoFunction::init_mem(mem)) return 1; if (!mem) return 1; diff --git a/casadi/core/oracle_function.hpp b/casadi/core/oracle_function.hpp index a653116bb8..aa5996e37a 100644 --- a/casadi/core/oracle_function.hpp +++ b/casadi/core/oracle_function.hpp @@ -230,6 +230,9 @@ namespace casadi { /// Get all statistics Dict get_stats(void* mem) const override; + virtual void change_option(void* mem, const std::string& option_name, + const GenericType& option_value) override; + /** \brief Serialize an object without type information \identifier{r} */ diff --git a/casadi/interfaces/ipopt/ipopt_interface.cpp b/casadi/interfaces/ipopt/ipopt_interface.cpp index d9df058dac..643391b58e 100644 --- a/casadi/interfaces/ipopt/ipopt_interface.cpp +++ b/casadi/interfaces/ipopt/ipopt_interface.cpp @@ -483,6 +483,56 @@ namespace casadi { return 0; } + void IpoptInterface:: + change_option(void* mem, const std::string& option_name, const GenericType& option_value) { + std::string option_name_ = option_name; + if (startswith(option_name_, "ipopt.")) { + option_name_ = option_name.substr(6); + } else { + return Nlpsol::change_option(mem, option_name, option_value); + } + + auto m = static_cast(mem); + Ipopt::SmartPtr *app = static_cast*>(m->app); + + auto regops = (*app)->RegOptions()->RegisteredOptionsList(); + + // There might be options with a resto prefix. + if (startswith(option_name_, "resto.")) { + option_name_ = option_name_.substr(6); + } + + // Find the option + auto regops_it = regops.find(option_name_); + if (regops_it==regops.end()) { + casadi_error("No such IPOPT option: " + option_name_); + } + + // Get the type + Ipopt::RegisteredOptionType ipopt_type = regops_it->second->Type(); + + // Pass to IPOPT + bool ret = true; + switch (ipopt_type) { + case Ipopt::OT_Number: + ret = (*app)->Options()->SetNumericValue(option_name_, option_value.to_double(), false); + break; + case Ipopt::OT_Integer: + ret = (*app)->Options()->SetIntegerValue(option_name_, option_value.to_int(), false); + break; + case Ipopt::OT_String: + ret = (*app)->Options()->SetStringValue(option_name_, option_value.to_string(), false); + break; + case Ipopt::OT_Unknown: + default: + casadi_error("Cannot handle option \"" + option_name + "\", ignored"); + } + + if (ret) { + casadi_error("Cannot handle option \"" + option_name + "\", ignored"); + } + } + bool IpoptInterface:: intermediate_callback(IpoptMemory* m, const double* x, const double* z_L, const double* z_U, const double* g, const double* lambda, double obj_value, int iter, diff --git a/casadi/interfaces/ipopt/ipopt_interface.hpp b/casadi/interfaces/ipopt/ipopt_interface.hpp index f0626f0343..f083dfece9 100644 --- a/casadi/interfaces/ipopt/ipopt_interface.hpp +++ b/casadi/interfaces/ipopt/ipopt_interface.hpp @@ -158,6 +158,8 @@ namespace casadi { /// All IPOPT options Dict opts_; + void change_option(void* mem, const std::string& option_name, const GenericType& option_value) override; + // Ipopt callback functions void finalize_solution(IpoptMemory* m, const double* x, const double* z_L, const double* z_U, const double* g, const double* lambda, double obj_value,