26 #include "gurobi_interface.hpp"
27 #include "casadi/core/casadi_misc.hpp"
28 #include "casadi/core/nlp_tools.hpp"
33 int CASADI_CONIC_GUROBI_EXPORT
36 plugin->name =
"gurobi";
38 plugin->version = CASADI_VERSION;
43 int ret = gurobi_adaptor_load(buffer,
sizeof(buffer));
45 casadi_warning(
"Failed to load Gurobi adaptor: " + std::string(buffer) +
".");
58 const std::map<std::string, Sparsity>& st)
70 "Type of variables: [CONTINUOUS|binary|integer|semicont|semiint]"}},
73 "Options to be passed to gurobi."}},
76 "Definition of SOS groups by indices."}},
79 "Weights corresponding to SOS entries."}},
82 "Specify 1 or 2 for each SOS group."}}
91 std::vector<std::string> vtype;
93 std::vector< std::vector<casadi_int> > sos_groups;
94 std::vector< std::vector<double> > sos_weights;
95 std::vector<casadi_int> sos_types;
98 for (
auto&& op : opts) {
99 if (op.first==
"vtype") {
101 }
else if (op.first==
"gurobi") {
103 }
else if (op.first==
"sos_groups") {
104 sos_groups = op.second.to_int_vector_vector();
105 }
else if (op.first==
"sos_weights") {
106 sos_weights = op.second.to_double_vector_vector();
107 }
else if (op.first==
"sos_types") {
108 sos_types = op.second.to_int_vector();
117 if (!sos_weights.empty())
123 if (!vtype.empty()) {
124 casadi_assert(vtype.size()==
nx_,
"Option 'vtype' has wrong length");
126 for (casadi_int i=0; i<
nx_; ++i) {
127 if (vtype[i]==
"continuous") {
128 vtype_[i] = GRB_CONTINUOUS;
129 }
else if (vtype[i]==
"binary") {
131 }
else if (vtype[i]==
"integer") {
133 }
else if (vtype[i]==
"semicont") {
135 }
else if (vtype[i]==
"semiint") {
138 casadi_error(
"No such variable type: " + vtype[i]);
158 casadi_int flag = GRBloadenv(&m->env,
nullptr);
159 casadi_assert(!flag && m->env,
"Failed to create GUROBI environment. Flag: " +
str(flag)
160 +
":" + GRBgeterrormsg(m->env));
169 m->add_stat(
"preprocessing");
170 m->add_stat(
"solver");
171 m->add_stat(
"postprocessing");
183 case GRB_INF_OR_UNBD:
184 return "INF_OR_UNBD";
189 case GRB_ITERATION_LIMIT:
190 return "ITERATION_LIMIT";
195 case GRB_SOLUTION_LIMIT:
196 return "SOLUTION_LIMIT";
197 case GRB_INTERRUPTED:
198 return "INTERRUPTED";
210 solve(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
215 m->fstats.at(
"preprocessing").tic();
218 m->return_status = -1;
245 int *ind=
reinterpret_cast<int*
>(iw); iw+=sm.
indval_size;
246 int *ind2=
reinterpret_cast<int*
>(iw); iw+=
nx_;
247 char *vtypes=
reinterpret_cast<char*
>(iw); iw+=
nx_;
250 GRBmodel *model =
nullptr;
252 casadi_int flag = GRBnewmodel(m->env, &model,
name_.c_str(), 0,
253 nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
254 casadi_assert(!flag, GRBgeterrormsg(m->env));
257 for (casadi_int i=0; i<
nx_; ++i) {
259 double lb = lbx ? lbx[i] : 0., ub = ubx ? ubx[i] : 0.;
260 if (isinf(lb)) lb = -GRB_INFINITY;
261 if (isinf(ub)) ub = GRB_INFINITY;
270 vtype = lb==0 && ub==1 ? GRB_BINARY : GRB_INTEGER;
273 vtype = GRB_CONTINUOUS;
278 flag = GRBaddvar(model, 0,
nullptr,
nullptr, g ? g[i] : 0., lb, ub, vtype,
nullptr);
279 casadi_assert(!flag, GRBgeterrormsg(m->env));
282 GRBupdatemodel(model);
283 for (casadi_int i=0; i<
nx_; ++i) {
285 if (vtypes[i] != GRB_CONTINUOUS) {
286 flag = GRBsetdblattrelement(model,
"Start", i, x0[i]);
287 casadi_assert(!flag, GRBgeterrormsg(m->env));
295 for (casadi_int i=0;i<sm.
r.size()-1;++i) {
296 for (casadi_int k=0;k<sm.
r[i+1]-sm.
r[i]-1;++k) {
297 flag = GRBaddvar(model, 0,
nullptr,
nullptr, 0, -GRB_INFINITY, GRB_INFINITY,
298 GRB_CONTINUOUS,
nullptr);
299 casadi_assert(!flag, GRBgeterrormsg(m->env));
301 flag = GRBaddvar(model, 0,
nullptr,
nullptr, 0, 0, GRB_INFINITY, GRB_CONTINUOUS,
nullptr);
302 casadi_assert(!flag, GRBgeterrormsg(m->env));
305 flag = GRBupdatemodel(model);
306 casadi_assert(!flag, GRBgeterrormsg(m->env));
310 for (
int i=0; i<
nx_; ++i) {
313 casadi_int numqnz = H_colind[1]-H_colind[0];
314 for (casadi_int k=0;k<numqnz;++k) ind[k]=H_row[k];
331 flag = GRBaddqpterms(model, numqnz, ind, ind2, val);
332 casadi_assert(!flag, GRBgeterrormsg(m->env));
335 std::vector<char> constraint_type(
na_);
339 const casadi_int *AT_colind=sm.
AT.
colind(), *AT_row=sm.
AT.
row();
340 for (casadi_int i=0; i<
na_; ++i) {
342 double lb = lba ? lba[i] : 0., ub = uba ? uba[i] : 0.;
344 casadi_int numnz = 0;
346 for (casadi_int k=AT_colind[i]; k<AT_colind[i+1]; ++k) {
347 casadi_int j = AT_row[k];
355 constraint_type[i] = 1;
359 constraint_type[i] = 0;
363 flag = GRBaddconstr(model, numnz, ind, val, GRB_LESS_EQUAL, ub,
nullptr);
364 casadi_assert(!flag, GRBgeterrormsg(m->env));
370 flag = GRBaddconstr(model, numnz, ind, val, GRB_GREATER_EQUAL, lb,
nullptr);
371 casadi_assert(!flag, GRBgeterrormsg(m->env));
375 flag = GRBaddconstr(model, numnz, ind, val, GRB_EQUAL, lb,
nullptr);
376 casadi_assert(!flag, GRBgeterrormsg(m->env));
380 flag = GRBaddrangeconstr(model, numnz, ind, val, lb, ub,
nullptr);
381 casadi_assert(!flag, GRBgeterrormsg(m->env));
386 std::vector<double>
pi(npi);
389 if (!m->sos_ind.empty()) {
390 flag = GRBaddsos(model, m->sos_beg.size()-1, m->sos_ind.size(),
393 casadi_assert(!flag, GRBgeterrormsg(m->env));
398 const casadi_int* colind = sp.
colind();
399 const casadi_int* row = sp.
row();
400 const casadi_int* data = sm.
map_Q.
ptr();
403 for (casadi_int i=0; i<sp.
size2(); ++i) {
405 casadi_int numnz = 0;
407 for (casadi_int k=colind[i]; k<colind[i+1]; ++k) {
408 casadi_int j = row[k];
411 val[numnz] = (q && j<
nx_) ? q[data[k]] : -1;
417 double bound = sm.
map_P[i]==-1 ? 0 : -p[sm.
map_P[i]];
419 flag = GRBaddconstr(model, numnz, ind, val, GRB_EQUAL, bound,
nullptr);
420 casadi_assert(!flag, GRBgeterrormsg(m->env));
424 for (casadi_int i=0; i<sm.
r.size()-1; ++i) {
425 casadi_int block_size = sm.
r[i+1]-sm.
r[i];
428 for (casadi_int j=0;j<block_size;++j) {
429 ind[j] =
nx_ + sm.
r[i] + j;
430 val[j] = j<block_size-1 ? 1 : -1;
433 flag = GRBaddqconstr(model, 0,
nullptr,
nullptr,
434 block_size, ind, ind, val,
435 GRB_LESS_EQUAL, 0,
nullptr);
436 casadi_assert(!flag, GRBgeterrormsg(m->env));
440 for (
auto && op :
opts_) {
441 int ret = GRBgetparamtype(m->env, op.first.c_str());
444 casadi_error(
"Parameter '" + op.first +
"' unknown to Gurobi.");
447 flag = GRBsetintparam(GRBgetenv(model), op.first.c_str(), op.second);
451 flag = GRBsetdblparam(GRBgetenv(model), op.first.c_str(), op.second);
455 std::string s = op.second;
456 flag = GRBsetstrparam(GRBgetenv(model), op.first.c_str(), s.c_str());
460 casadi_error(
"Not implememented : " +
str(ret));
462 casadi_assert(!flag, GRBgeterrormsg(m->env));
465 m->fstats.at(
"preprocessing").toc();
466 m->fstats.at(
"solver").tic();
469 flag = GRBoptimize(model);
470 casadi_assert(!flag, GRBgeterrormsg(m->env));
472 m->fstats.at(
"solver").toc();
473 m->fstats.at(
"postprocessing").tic();
476 flag = GRBgetintattr(model,
"Status", &optimstatus);
477 casadi_assert(!flag, GRBgeterrormsg(m->env));
480 " (" << optimstatus <<
")" << std::endl;
482 m->return_status = optimstatus;
483 m->d_qp.success = optimstatus==GRB_OPTIMAL;
484 if (optimstatus==GRB_ITERATION_LIMIT || optimstatus==GRB_TIME_LIMIT
485 || optimstatus==GRB_NODE_LIMIT || optimstatus==GRB_SOLUTION_LIMIT)
490 flag = GRBgetdblattr(model,
"ObjVal", cost);
496 flag = GRBgetdblattrarray(model,
"X", 0,
nx_, x);
500 flag = GRBgetdblattrarray(model,
"RC", 0,
nx_, lam_x);
505 flag = GRBgetdblattrarray(model,
"Pi", 0, npi,
get_ptr(
pi));
510 for (casadi_int i=0;i<
na_;++i) {
511 if (constraint_type[i]==0) {
513 }
else if (constraint_type[i]==1) {
521 flag = GRBgetintattr(model, GRB_INT_ATTR_SOLCOUNT, &(m->pool_sol_nr));
522 if (!flag && m->pool_sol_nr > 0) {
523 m->pool_obj_vals = std::vector<double>(m->pool_sol_nr,
casadi::nan);
524 for (
int idx = 0; idx < m->pool_sol_nr; ++idx) {
525 std::vector<double> x_pool(
nx_);
527 flag = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, idx);
528 if (!flag) flag = GRBgetdblattr(model, GRB_DBL_ATTR_POOLOBJVAL, &(m->pool_obj_vals[idx]));
529 if (!flag) flag = GRBgetdblattrarray(model, GRB_DBL_ATTR_XN, 0,
nx_,
get_ptr(x_pool));
533 std::fill(x_pool.begin(), x_pool.end(),
casadi::nan);
536 m->pool_solutions.push_back(x_pool);
542 m->fstats.at(
"postprocessing").toc();
546 if (model) GRBfreemodel(model);
557 stats[
"pool_sol_nr"] = m->pool_sol_nr;
558 stats[
"pool_obj_val"] = m->pool_obj_vals;
559 stats[
"pool_solutions"] = m->pool_solutions;
568 if (this->
env) GRBfreeenv(this->
env);
572 s.
version(
"GurobiInterface", 1);
584 s.
version(
"GurobiInterface", 1);
static const Options options_
Options.
casadi_int nx_
Number of decision variables.
int init_mem(void *mem) const override
Initalize memory block.
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
virtual void check_inputs(const double *lbx, const double *ubx, const double *lba, const double *uba) const
Check if the numerical values of the supplied bounds make sense.
Sparsity H_
Problem structure.
void init(const Dict &opts) override
Initialize.
void deserialize(DeserializingStream &s, SDPToSOCPMem &m)
std::vector< bool > discrete_
Options.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Dict get_stats(void *mem) const override
Get all statistics.
void sdp_to_socp_init(SDPToSOCPMem &mem) const
SDP to SOCP conversion initialization.
void serialize(SerializingStream &s, const SDPToSOCPMem &m) const
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.
bool inputs_check_
Errors are thrown if numerical values of inputs look bad.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
std::vector< int > sos_ind_
Dict get_stats(void *mem) const override
Get all statistics.
GurobiInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new Solver.
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
std::vector< int > sos_types_
~GurobiInterface() override
Destructor.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
std::vector< int > sos_beg_
std::vector< char > vtype_
void init(const Dict &opts) override
Initialize.
Dict opts_
Gurobi options.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
SDPToSOCPMem sdp_to_socp_mem_
SDP to SOCP conversion memory.
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
static const std::string meta_doc
A documentation string.
static const Options options_
Options.
int init_mem(void *mem) const override
Initalize memory block.
std::vector< double > sos_weights_
const Sparsity & sparsity() const
Const access the sparsity - reference to data member.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
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 size2() const
Get the number of columns.
const casadi_int * row() const
Get a reference to row-vector,.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
int CASADI_CONIC_GUROBI_EXPORT casadi_register_conic_gurobi(Conic::Plugin *plugin)
@ CONIC_UBA
dense, (nc x 1)
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
@ CONIC_G
The vector g: dense, (n x 1)
@ CONIC_Q
The matrix Q: sparse symmetric, (np^2 x n)
@ CONIC_LBA
dense, (nc x 1)
@ CONIC_UBX
dense, (n x 1)
@ CONIC_LBX
dense, (n x 1)
@ CONIC_P
The matrix P: sparse symmetric, (np x np)
int to_int(casadi_int rhs)
void flatten_nested_vector(const std::vector< std::vector< T > > &nested, std::vector< S > &flat)
Flatten a nested std::vector tot a single flattened vector.
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
void casadi_fill(T1 *x, casadi_int n, T1 alpha)
FILL: x <- alpha.
const char * return_status_string(Bonmin::TMINLP::SolverReturn status)
std::string str(const T &v)
String representation, any type.
void check_sos(casadi_int nx, const std::vector< std::vector< T > > &groups, std::vector< std::vector< double > > &weights, std::vector< casadi_int > &types)
Check sos structure and generate defaults.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
const double nan
Not a number.
void casadi_scal(casadi_int n, T1 alpha, T1 *x)
SCAL: x <- alpha*x.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
void CASADI_CONIC_GUROBI_EXPORT casadi_load_conic_gurobi()
const double pi
Define pi.
@ CONIC_X
The primal solution.
@ CONIC_LAM_A
The dual solution corresponding to linear bounds.
@ CONIC_COST
The optimal cost.
@ CONIC_LAM_X
The dual solution corresponding to simple bounds.
SDP to SOCP conversion memory.
std::vector< casadi_int > r
std::vector< casadi_int > A_mapping
std::vector< casadi_int > map_P
~GurobiMemory()
Destructor.
GurobiMemory()
Constructor.
Options metadata for a class.