25 #include "uno_interface.hpp"
26 #include "casadi/core/casadi_misc.hpp"
27 #include "casadi/core/casadi_interrupt.hpp"
28 #include "casadi/core/code_generator.hpp"
30 #include <uno_runtime_str.h>
38 int CASADI_NLPSOL_UNO_EXPORT
43 plugin->version = CASADI_VERSION;
65 "Options to be passed to UNO"}}
77 casadi_uno_free_mem<double>(&
d_uno);
90 for (
auto&& op : opts) {
91 if (op.first ==
"uno") opts_ = op.second;
103 {
"triu:hess:gamma:x:x"},
104 {{
"gamma", {
"f",
"g"}}});
106 casadi_assert(hesslag_sp_.is_triu(),
"Hessian must be upper triangular");
111 final_options[
"is_diff_in"] = std::vector<bool>{
true,
false,
false,
false};
112 final_options[
"is_diff_out"] = std::vector<bool>{
true};
114 func_opts[
"final_options"] = final_options;
116 {
"grad:gamma:x"}, {{
"gamma", {
"f",
"g"}}}, func_opts);
120 auto jr = jacg_sp_.get_row(), jc = jacg_sp_.get_col();
121 auto hr = hesslag_sp_.get_row(), hc = hesslag_sp_.get_col();
122 jacobian_row_indices_.assign(jr.begin(), jr.end());
123 jacobian_column_indices_.assign(jc.begin(), jc.end());
124 hessian_row_indices_.assign(hr.begin(), hr.end());
125 hessian_column_indices_.assign(hc.begin(), hc.end());
128 placeholder_lb_g_.assign(
ng_, -std::numeric_limits<double>::infinity());
129 placeholder_ub_g_.assign(
ng_, std::numeric_limits<double>::infinity());
134 void UnoInterface::set_uno_prob() {
136 p_uno_.
sp_a = jacg_sp_;
137 p_uno_.
sp_h = hesslag_sp_;
138 p_uno_.
jac_row = jacobian_row_indices_.data();
139 p_uno_.
jac_col = jacobian_column_indices_.data();
140 p_uno_.
n_jac =
static_cast<uno_int
>(jacobian_row_indices_.size());
141 p_uno_.
hess_row = hessian_row_indices_.data();
142 p_uno_.
hess_col = hessian_column_indices_.data();
143 p_uno_.
n_hess =
static_cast<uno_int
>(hessian_row_indices_.size());
144 p_uno_.
obj_cb = &casadi_uno_obj_wrapper<double>;
145 p_uno_.
obj_grad_cb = &casadi_uno_obj_grad_wrapper<double>;
146 p_uno_.
constr_cb = &casadi_uno_constr_wrapper<double>;
147 p_uno_.
jac_cb = &casadi_uno_jac_wrapper<double>;
148 p_uno_.
hess_cb = &casadi_uno_hess_wrapper<double>;
149 p_uno_.
hess_prod_cb = &casadi_uno_hess_prod_wrapper<double>;
160 uno_set_solver_bool_option(solver, name.c_str(), value.
to_bool());
161 }
else if (value.
is_int()) {
162 uno_set_solver_integer_option(solver, name.c_str(),
static_cast<uno_int
>(value.
to_int()));
164 uno_set_solver_double_option(solver, name.c_str(), value.
to_double());
166 uno_set_solver_string_option(solver, name.c_str(), value.
to_string().c_str());
168 casadi_assert(
false,
"Unsupported UNO option type for " + name);
176 for (
auto&& op : casadi_options) {
177 if (op.first ==
"preset") {
178 uno_set_solver_preset(solver, op.second.to_string().c_str());
182 for (
auto&& op : casadi_options) {
183 if (op.first !=
"preset")
set_uno_option(solver, op.first, op.second);
188 const double* lower_mult,
const double* upper_mult,
const double* constraint_mult,
189 double,
double,
double,
double,
void* user_data) {
190 constexpr uno_int CONTINUE = 1;
191 constexpr uno_int TERMINATE = 0;
192 auto* m =
static_cast<UnoMemory*
>(user_data);
194 if (
self.fcallback_.is_null())
return CONTINUE;
196 auto* d_nlp = &m->d_nlp;
198 for (casadi_int i = 0; i <
self.nx_; ++i) {
200 d_nlp->lam[i] = lower_mult[i] + upper_mult[i];
203 casadi_copy(constraint_mult,
self.ng_, d_nlp->lam +
self.nx_);
205 std::fill_n(m->arg,
self.fcallback_.n_in(),
nullptr);
209 std::fill_n(m->res,
self.fcallback_.n_out(),
nullptr);
210 double ret_double = 0;
211 m->res[0] = &ret_double;
213 self.fcallback_(m->arg, m->res, m->iw, m->w, 0);
216 }
catch (std::exception& ex) {
217 casadi_warning(std::string(
"intermediate_callback: ") + ex.what());
218 return self.iteration_callback_ignore_errors_ ? CONTINUE : TERMINATE;
220 return static_cast<casadi_int
>(ret_double) ? TERMINATE : CONTINUE;
228 uno_int uno_major, uno_minor, uno_patch;
229 uno_get_version(&uno_major, &uno_minor, &uno_patch);
230 casadi_message(
"Using Uno v" +
str(uno_major) +
"." +
str(uno_minor) +
"." +
str(uno_patch));
233 m->d_uno.prob = &p_uno_;
234 casadi_uno_init_mem<double>(&m->d_uno);
235 casadi_uno_init_model<double>(&m->d_uno,
236 placeholder_lb_g_.data(), placeholder_ub_g_.data());
246 casadi_int*& iw,
double*& w)
const {
254 m->d_uno.nlp.
prob = &p_uno_.
nlp;
258 m->d_nlp.oracle->m =
static_cast<void*
>(m);
259 m->d_uno.nlp.oracle = m->d_nlp.oracle;
264 case UNO_FEASIBLE_KKT_POINT:
return "Converged with feasible KKT point";
265 case UNO_FEASIBLE_FJ_POINT:
return "Converged with feasible FJ point";
266 case UNO_INFEASIBLE_STATIONARY_POINT:
return "Converged with infeasible stationary point";
267 case UNO_FEASIBLE_SMALL_STEP:
return "Terminated with feasible small step";
268 case UNO_INFEASIBLE_SMALL_STEP:
return "Terminated with infeasible small step";
269 case UNO_UNBOUNDED:
return "Terminated with unbounded problem";
270 case UNO_NOT_OPTIMAL:
return "Terminated with not optimal point";
271 default:
return "Terminated with an unknown status";
278 casadi_uno_solve<double>(&m->d_uno);
280 m->success = m->d_uno.success;
281 m->unified_return_status =
static_cast<UnifiedReturnStatus>(m->d_uno.unified_return_status);
290 stats[
"iter_count"] =
static_cast<casadi_int
>(m->d_uno.iter_count);
291 stats[
"primal_infeasbility"] = m->d_uno.primal_infeasibility;
292 stats[
"stationarity"] = m->d_uno.stationarity;
293 stats[
"complementarity"] = m->d_uno.complementarity;
300 s.
pack(
"UnoInterface::jacg_sp", jacg_sp_);
301 s.
pack(
"UnoInterface::hesslag_sp", hesslag_sp_);
302 s.
pack(
"UnoInterface::opts", opts_);
307 s.
unpack(
"UnoInterface::jacg_sp", jacg_sp_);
308 s.
unpack(
"UnoInterface::hesslag_sp", hesslag_sp_);
309 s.
unpack(
"UnoInterface::opts", opts_);
312 jacobian_row_indices_.assign(jr.begin(), jr.end());
313 jacobian_column_indices_.assign(jc.begin(), jc.end());
314 hessian_row_indices_.assign(hr.begin(), hr.end());
315 hessian_column_indices_.assign(hc.begin(), hc.end());
316 placeholder_lb_g_.assign(
ng_, -std::numeric_limits<double>::infinity());
317 placeholder_ub_g_.assign(
ng_, std::numeric_limits<double>::infinity());
324 g.
local(
"d",
"struct casadi_uno_data*");
330 g.
local(
"p",
"static struct casadi_uno_prob");
332 g <<
"d->prob = &p;\n";
339 g <<
"casadi_uno_init_mem(d);\n";
340 g <<
"casadi_uno_init_model(d, "
341 << g.
constant(placeholder_lb_g_) <<
", "
342 << g.
constant(placeholder_ub_g_) <<
");\n";
346 for (
auto&& kv : opts_) {
347 if (kv.first ==
"preset") {
348 g <<
"uno_set_solver_preset(d->solver, \"" << kv.second.to_string() <<
"\");\n";
351 for (
auto&& kv : opts_) {
352 const std::string& key = kv.first;
353 if (key ==
"preset") {
355 }
else if (kv.second.is_bool()) {
356 g <<
"uno_set_solver_bool_option(d->solver, \"" << key <<
"\", "
357 << (kv.second.to_bool() ?
"1" :
"0") <<
");\n";
358 }
else if (kv.second.is_int()) {
359 g <<
"uno_set_solver_integer_option(d->solver, \"" << key <<
"\", "
360 << kv.second.to_int() <<
");\n";
361 }
else if (kv.second.is_double()) {
362 g <<
"uno_set_solver_double_option(d->solver, \"" << key <<
"\", "
363 << g.
constant(kv.second.to_double()) <<
");\n";
364 }
else if (kv.second.is_string()) {
365 g <<
"uno_set_solver_string_option(d->solver, \"" << key <<
"\", \""
366 << kv.second.to_string() <<
"\");\n";
368 casadi_error(
"Unsupported uno option type for '" + key +
"'");
375 g <<
"casadi_uno_free_mem(&" +
codegen_mem(g) +
");\n";
399 const std::vector<uno_int>& v) {
401 g <<
"p." << name <<
" = 0;\n";
404 g << g.
array(
"static const int",
"p_" + name, v.size(),
406 g <<
"p." << name <<
" = p_" << name <<
";\n";
409 void UnoInterface::set_uno_prob(CodeGenerator& g)
const {
410 g <<
"p.sp_a = " << g.
sparsity(jacg_sp_) <<
";\n";
411 g <<
"p.sp_h = " << g.sparsity(hesslag_sp_) <<
";\n";
414 g <<
"p.n_jac = " << jacobian_row_indices_.size() <<
";\n";
417 g <<
"p.n_hess = " << hessian_row_indices_.size() <<
";\n";
420 g.setup_callback(
"p.nlp_grad_f",
get_function(
"nlp_grad_f"));
421 g.setup_callback(
"p.nlp_jac_g",
get_function(
"nlp_jac_g"));
422 g.setup_callback(
"p.nlp_hess_l",
get_function(
"nlp_hess_l"));
423 g.setup_callback(
"p.fwd1_nlp_grad_l",
get_function(
"fwd1_nlp_grad_l"));
424 g <<
"p.obj_cb = &casadi_uno_obj_wrapper;\n";
425 g <<
"p.obj_grad_cb = &casadi_uno_obj_grad_wrapper;\n";
426 g <<
"p.constr_cb = &casadi_uno_constr_wrapper;\n";
427 g <<
"p.jac_cb = &casadi_uno_jac_wrapper;\n";
428 g <<
"p.hess_cb = &casadi_uno_hess_wrapper;\n";
429 g <<
"p.hess_prod_cb = &casadi_uno_hess_prod_wrapper;\n";
436 g.
local(
"d",
"struct casadi_uno_data*");
439 g <<
"casadi_uno_set_work(d, &arg, &res, &iw, &w);\n";
440 g <<
"casadi_oracle_set_work(&d->d_oracle, &arg, &res, &iw, &w);\n";
441 g <<
"casadi_uno_solve(d);\n";
447 g <<
"return d->unified_return_status;\n";
Helper class for C code generation.
std::string add_dependency(const Function &f)
Add a function dependency.
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
static std::string array(const std::string &type, const std::string &name, casadi_int len, const std::string &def=std::string())
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
std::string sanitize_source(const std::string &src, const std::vector< std::string > &inst, bool add_shorthand=true)
Sanitize source files for codegen.
void add_include(const std::string &new_include, bool relative_path=false, const std::string &use_ifdef=std::string())
Add an include file optionally using a relative path "..." instead of an absolute path <....
std::string initializer(const std::vector< T > &v)
Print an initializer.
std::string sparsity(const Sparsity &sp, bool canonical=true)
std::stringstream auxiliaries
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
std::string codegen_mem(CodeGenerator &g, const std::string &index="mem") const
Get thread-local memory object.
Function self() const
Get a public class instance.
const Sparsity & sparsity_out(casadi_int ind) const
Get sparsity of a given output.
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
bool is_string() const
Check if a particular type.
std::string to_string() const
Convert to a type.
bool is_bool() const
Check if a particular type.
double to_double() const
Convert to a type.
bool is_double() const
Check if a particular type.
casadi_int to_int() const
Convert to a type.
bool to_bool() const
Convert to a type.
bool is_int() const
Check if a particular type.
NLP solver storage class.
void codegen_post_solve(CodeGenerator &g, const std::string &d_nlp) const
Dict get_stats(void *mem) const override
Get all statistics.
static const Options options_
Options.
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
void init(const Dict &opts) override
Initialize.
casadi_int ng_
Number of constraints.
void codegen_setup_per_call(CodeGenerator &g, const std::string &d_nlp) const
int init_mem(void *mem) const override
Initalize memory block.
void codegen_setup_constants(CodeGenerator &g, const std::string &d_nlp, const std::string &p_nlp, const std::string &d_oracle) const
casadi_nlpsol_prob< double > p_nlp_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
Function create_function(const Function &oracle, const std::string &fname, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const Function::AuxOut &aux=Function::AuxOut(), const Dict &opts=Dict())
Function create_forward(const std::string &fname, casadi_int nfwd)
std::vector< std::string > get_function() const override
Get list of dependency functions.
bool has_function(const std::string &fname) const override
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool error_on_fail_
Throw an exception on failure?
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
std::vector< casadi_int > get_col() const
Get the column for each non-zero entry.
std::vector< casadi_int > get_row() const
Get the row for each non-zero entry.
UnoInterface(const std::string &name, const Function &nlp)
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
static Nlpsol * creator(const std::string &name, const Function &nlp)
void codegen_init_mem(CodeGenerator &g) const override
Codegen decref for init_mem.
static ProtoFunction * deserialize(DeserializingStream &s)
int solve(void *mem) const override
Dict get_stats(void *mem) const override
Get all statistics.
int init_mem(void *mem) const override
Initalize memory block.
void free_mem(void *mem) const override
Free memory block.
void codegen_free_mem(CodeGenerator &g) const override
Codegen for free_mem.
static const std::string meta_doc
void init(const Dict &opts) override
Initialize.
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
static const Options options_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static void codegen_int_array(CodeGenerator &g, const std::string &name, const std::vector< uno_int > &v)
@ NLPSOL_X
Decision variables at the optimal solution (nx x 1)
@ NLPSOL_LAM_G
Lagrange multipliers for bounds on G at the solution (ng x 1)
@ NLPSOL_LAM_X
Lagrange multipliers for bounds on X at the solution (nx x 1)
static void set_uno_option(void *solver, const std::string &name, const GenericType &value)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
const char * return_status_string(Bonmin::TMINLP::SolverReturn status)
int CASADI_NLPSOL_UNO_EXPORT casadi_register_nlpsol_uno(Nlpsol::Plugin *plugin)
void CASADI_NLPSOL_UNO_EXPORT casadi_load_nlpsol_uno()
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
static uno_int casadi_uno_term_cb_cpp(uno_int, uno_int, const double *primals, const double *lower_mult, const double *upper_mult, const double *constraint_mult, double, double, double, double, void *user_data)
static void insert_casadi_options(void *solver, Dict opts)
Options metadata for a class.
static Dict sanitize(const Dict &opts, bool top_level=true)
Sanitize a options dictionary.
const char * return_status
UnoMemory(const UnoInterface &uno_interface)
casadi_uno_data< double > d_uno
const casadi_nlpsol_prob< T1 > * prob
casadi_nlpsol_data< T1 > nlp
uno_lagrangian_hessian_operator_callback hess_prod_cb
OracleCallback nlp_grad_f
uno_lagrangian_hessian_callback hess_cb
OracleCallback nlp_hess_l
uno_constraints_callback constr_cb
casadi_nlpsol_prob< T1 > nlp
uno_objective_callback obj_cb
OracleCallback fwd1_nlp_grad_l
uno_constraints_jacobian_callback jac_cb
uno_objective_gradient_callback obj_grad_cb