26 #include "ccopt_interface.hpp"
27 #include <ccopt_runtime_str.h>
29 #include "casadi/core/casadi_misc.hpp"
30 #include "../../core/global_options.hpp"
31 #include "../../core/casadi_interrupt.hpp"
32 #include "../../core/convexify.hpp"
45 int CASADI_NLPSOL_CCOPT_EXPORT
48 plugin->name =
"ccopt";
50 plugin->version = CASADI_VERSION;
73 "Options to be passed to ccopt relaxation algorithm"}},
76 "Options to be passed to madnlp"}},
77 {
"convexify_strategy",
79 "NONE|regularize|eigen-reflect|eigen-clip. "
80 "Strategy to convexify the Lagrange Hessian before passing it to the solver."}},
83 "When using a convexification strategy, make sure that "
84 "the smallest eigenvalue is at least this (default: 1e-7)."}},
87 "List of complementary constraints on simple bounds. "
88 "Pair (i, j) encodes complementarity between the bounds on variable i and variable j."}},
91 "Type of cc pairs (default: 0). "}},
97 for (
const auto& kv : opts) {
98 switch (kv.second.getType()) {
103 ret[prefix + kv.first] = kv.second;
111 casadi_int struct_cnt=0;
114 std::string convexify_strategy =
"none";
115 double convexify_margin = 1e-7;
116 casadi_int max_iter_eig = 200;
117 std::vector< std::vector<casadi_int> > cc_pairs;
118 std::vector<casadi_int> cc_types;
125 for (
auto&& op : opts) {
126 if (op.first==
"convexify_strategy") {
127 convexify_strategy = op.second.to_string();
128 }
else if (op.first==
"convexify_margin") {
129 convexify_margin = op.second;
130 }
else if (op.first==
"max_iter") {
131 max_iter_eig = op.second;
132 }
else if (op.first==
"madnlp") {
134 }
else if (op.first==
"ccopt") {
136 }
else if (op.first==
"cc_pairs") {
137 cc_pairs = op.second;
138 }
else if (op.first==
"cc_types") {
139 cc_types = op.second;
145 if (cc_types.empty()) {
146 cc_types.resize(cc_pairs.size(), 0);
148 casadi_assert(cc_pairs.size()==cc_types.size(),
149 "Options 'cc_pairs' and 'cc_types' must have the same length.");
150 for (
auto && e : cc_types) {
155 for (
auto && e : cc_pairs) {
156 casadi_assert(e.size()==2,
"Complementary constraints must come in pairs.");
157 casadi_assert(e[0]>=0,
"Invalid index.");
158 casadi_assert(e[1]>=0,
"Invalid index.");
159 bool first_is_var = (*type == 0 || *type == 1);
160 bool second_is_var = (*type == 0 || *type == 2);
161 casadi_int n_first = first_is_var ?
nx_ :
ng_;
162 casadi_int n_second = second_is_var ?
nx_ :
ng_;
163 casadi_assert(e[0]<n_first,
"Invalid index for first slot of cc_pair "
164 "(type " +
str(*type) +
", limit " +
str(n_first) +
").");
165 casadi_assert(e[1]<n_second,
"Invalid index for second slot of cc_pair "
166 "(type " +
str(*type) +
", limit " +
str(n_second) +
").");
173 auto hessian_approximation =
opts_.find(
"hessian_approximation");
174 if (hessian_approximation!=
opts_.end()) {
194 {
"tril:hess:gamma:x:x"}, {{
"gamma", {
"f",
"g"}}});
199 if (convexify_strategy!=
"none") {
202 opts[
"strategy"] = convexify_strategy;
203 opts[
"margin"] = convexify_margin;
204 opts[
"max_iter_eig"] = max_iter_eig;
220 std::vector<char*> _argv = {};
223 int argc = _argv.size();
224 char** argv =
reinterpret_cast<char**
>(_argv.data());
233 libmad_create_options_dict(&(m->d.nlp_opts));
234 for (
const auto& kv :
opts_) {
235 switch (kv.second.getType()) {
237 libmad_set_double_option(m->d.nlp_opts, kv.first.c_str(), kv.second);
240 libmad_set_int64_option(m->d.nlp_opts, kv.first.c_str(), kv.second.to_int());
244 std::string s = kv.second.to_string();
245 libmad_set_string_option(m->d.nlp_opts, kv.first.c_str(), s.c_str());
249 libmad_set_bool_option(m->d.nlp_opts, kv.first.c_str(), kv.second.to_bool());
252 casadi_error(
"Unknown option type.");
256 libmad_create_options_dict(&(m->d.mpcc_opts));
258 switch (kv.second.getType()) {
260 libmad_set_double_option(m->d.mpcc_opts, kv.first.c_str(), kv.second);
263 libmad_set_int64_option(m->d.mpcc_opts, kv.first.c_str(), kv.second.to_int());
267 std::string s = kv.second.to_string();
268 libmad_set_string_option(m->d.mpcc_opts, kv.first.c_str(), s.c_str());
272 libmad_set_bool_option(m->d.mpcc_opts, kv.first.c_str(), kv.second.to_bool());
275 casadi_error(
"Unknown option type.");
283 casadi_ccopt_init_mem(&m->d);
290 casadi_ccopt_free_mem(&m->d);
296 casadi_int*& iw,
double*& w)
const {
303 m->d.
nlp = &m->d_nlp;
305 casadi_ccopt_set_work(&m->d, &arg, &res, &iw, &w);
307 m->d.nlp->oracle->m =
static_cast<void*
>(m);
313 int ret = casadi_ccopt_presolve(&m->d);
315 ret = casadi_ccopt_solve(&m->d);
318 m->success = m->d.success;
327 libmad_int iter, status;
328 double primal_feas, dual_feas, cc_feas, total_wall_time;
329 std::vector<libmad_real> multipliers_x1, multipliers_x2;
330 multipliers_x1.resize(
ind_cc1_.size());
331 multipliers_x2.resize(
ind_cc2_.size());
332 ccopt_relaxation_get_iters(m->d.stats, &iter);
333 ccopt_relaxation_get_total_wall_time(m->d.stats, &total_wall_time);
334 ccopt_relaxation_get_status(m->d.stats, &status);
335 ccopt_relaxation_get_dual_feas(m->d.stats, &dual_feas);
336 ccopt_relaxation_get_primal_feas(m->d.stats, &primal_feas);
337 ccopt_relaxation_get_cc_feas(m->d.stats, &cc_feas);
338 ccopt_relaxation_get_multipliers_x1(m->d.stats, multipliers_x1.data());
339 ccopt_relaxation_get_multipliers_x2(m->d.stats, multipliers_x2.data());
341 stats[
"iter_count"] =
static_cast<casadi_int
>(iter);
343 ccopt[
"dual_feas"] = dual_feas;
344 ccopt[
"cc_feas"] = cc_feas;
345 ccopt[
"primal_feas"] = primal_feas;
346 ccopt[
"status"] =
static_cast<casadi_int
>(status);
347 ccopt[
"multipliers_x1"] = multipliers_x1;
348 ccopt[
"multipliers_x2"] = multipliers_x2;
349 ccopt[
"total_wall_time"] = total_wall_time;
350 stats[
"ccopt"] = ccopt;
369 casadi_ccopt_setup(&p_);
373 const std::string& field)
const {
374 g <<
"libmad_create_options_dict(&(" +
codegen_mem(g) +
"." + field +
"));\n";
375 for (
const auto& kv : dict) {
376 switch (kv.second.getType()) {
378 g <<
"libmad_set_double_option(" +
codegen_mem(g) +
"." + field +
", \""
379 + kv.first +
"\", " +
str(kv.second) +
");\n";
382 g <<
"libmad_set_int64_option(" +
codegen_mem(g) +
"." + field +
", \""
383 + kv.first +
"\", " +
str(kv.second) +
");\n";
387 std::string s = kv.second.to_string();
388 g <<
"libmad_set_string_option(" +
codegen_mem(g) +
"." + field +
", \""
389 + kv.first +
"\", \"" + s +
"\");\n";
393 g <<
"libmad_set_bool_option(" +
codegen_mem(g) +
"." + field +
", \""
394 + kv.first +
"\", " +
str(kv.second) +
");\n";
397 casadi_error(
"Unknown option type.");
411 g <<
"casadi_ccopt_init_mem(&" +
codegen_mem(g) +
");\n";
417 g <<
"casadi_ccopt_free_mem(&" +
codegen_mem(g) +
");\n";
444 g.
local(
"d",
"struct casadi_ccopt_data*");
446 g.
local(
"p",
"struct casadi_ccopt_prob");
449 g <<
"casadi_ccopt_set_work(d, &arg, &res, &iw, &w);\n";
450 g <<
"casadi_oracle_set_work(d->nlp->oracle, &arg, &res, &iw, &w);\n";
451 g <<
"casadi_ccopt_presolve(d);\n";
453 g <<
"casadi_ccopt_solve(d);\n";
458 g <<
"return d->unified_return_status;\n";
466 casadi_error(
"Empty sparsity pattern not supported in CCOPT C interface");
468 g <<
"d->nlp = &d_nlp;\n";
469 g <<
"d->prob = &p;\n";
470 g <<
"p.nlp = &p_nlp;\n";
482 g <<
"p.sp_h = 0;\n";
485 g <<
"casadi_ccopt_setup(&p);\n";
489 s.
version(
"MadmpecInterface", 1);
504 s.
version(
"MadmpecInterface", 1);
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.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
void setup_callback(const std::string &s, const Function &f)
Setup a callback.
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 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.
static Sparsity setup(ConvexifyData &d, const Sparsity &H, const Dict &opts=Dict(), bool inplace=true)
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
std::string codegen_mem(CodeGenerator &g, const std::string &index="mem") const
Get thread-local memory object.
size_t sz_res() const
Get required length of res field.
size_t sz_w() const
Get required length of w field.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
size_t sz_arg() const
Get required length of arg field.
size_t sz_iw() const
Get required length of iw field.
bool exact_hessian_
Exact Hessian?
std::vector< libmad_int > cctypes_
ConvexifyData convexify_data_
Data for convexification.
MadmpecInterface(const std::string &name, const Function &nlp)
Dict opts_
All CCOPT options.
void init(const Dict &opts) override
Initialize.
void codegen_free_mem(CodeGenerator &g) const override
Codegen free_mem.
int init_mem(void *mem) const override
Initalize memory block.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
static Nlpsol * creator(const std::string &name, const Function &nlp)
Create a new NLP Solver.
~MadmpecInterface() override
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
Dict get_stats(void *mem) const override
Get all statistics.
std::vector< libmad_int > ind_cc1_
Complementarity.
void codegen_init_mem(CodeGenerator &g) const override
Codegen alloc_mem.
static const Options options_
Options.
void codegen_options(CodeGenerator &g, const Dict &dict, const std::string &field) const
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static const std::string meta_doc
A documentation string.
bool convexify_
convexify?
int solve(void *mem) const override
void free_mem(void *mem) const override
Free memory block.
std::vector< libmad_int > ind_cc2_
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
NLP solver storage class.
void codegen_body_exit(CodeGenerator &g) const override
Generate code for the function body.
Dict get_stats(void *mem) const override
Get all statistics.
static const Options options_
Options.
void codegen_body_enter(CodeGenerator &g) const override
Generate code for the function body.
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.
int init_mem(void *mem) const override
Initalize memory block.
casadi_nlpsol_prob< double > p_nlp_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
casadi_int nx_
Number of variables.
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())
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.
casadi_int size1() const
Get the number of rows.
bool is_tril(bool strictly=false) const
Is lower triangular?
casadi_int nnz() const
Get the number of (structural) non-zeros.
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
void flatten_opts(Dict &ret, const Dict &opts, const std::string &prefix)
void CASADI_NLPSOL_CCOPT_EXPORT casadi_load_nlpsol_ccopt()
int CASADI_NLPSOL_CCOPT_EXPORT casadi_register_nlpsol_ccopt(Nlpsol::Plugin *plugin)
Options metadata for a class.
OracleCallback nlp_grad_f
OracleCallback nlp_hess_l
const casadi_nlpsol_prob< T1 > * nlp