1 
2 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
3 
4 /*
5  *  Main authors:
6  *     Gleb Belov <gleb.belov@monash.edu>
7  */
8 
9 /* This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
12 
13 #pragma once
14 
15 #include <minizinc/solver_config.hh>
16 #include <minizinc/solver_instance_base.hh>
17 #include <minizinc/solvers/MIP/MIP_wrap.hh>
18 
19 extern "C" {
20 #include <gurobi_c.h>  // need GUROBI_HOME defined
21 }
22 
23 class MIPGurobiWrapper : public MIPWrapper {
24   GRBenv* _env = nullptr;
25   GRBmodel* _model = nullptr;
26 #ifdef GUROBI_PLUGIN
27   void* _gurobiDll;
28 #endif
29   int _error;
30   std::string _gurobiBuffer;        // [GRB_MESSAGEBUFSIZE];
31   std::string _gurobiStatusBuffer;  // [GRB_MESSAGEBUFSIZE];
32 
33   std::vector<double> _x;
34 
35 public:
36   class FactoryOptions {
37   public:
38     bool processOption(int& i, std::vector<std::string>& argv,
39                        const std::string& workingDir = std::string());
40 
41     std::string gurobiDll;
42   };
43 
44   class Options : public MiniZinc::SolverInstanceBase::Options {
45   public:
46     int nMIPFocus = 0;
47     int nFreeSearch = 1;
48     int nThreads = 1;
49     std::string sExportModel;
50     int nTimeout1000 = -1;
51     int nTimeoutFeas1000 = -1;
52     int nSolLimit = -1;
53     int nSeed = -1;
54     double nWorkMemLimit = 0.5;
55     std::string sNodefileDir;
56     std::string sReadParams;
57     std::string sWriteParams;
58     std::vector<std::string> sConcurrentParamFiles;
59     bool flagIntermediate = false;
60 
61     double absGap = -1;
62     double relGap = 1e-8;
63     double feasTol = 1e-8;
64     double intTol = 1e-8;
65     double objDiff = 1.0;
66     int nonConvex = 2;
67 
68     std::unordered_map<std::string, std::string> extraParams;
69 
70     bool processOption(int& i, std::vector<std::string>& argv, const std::string& workingDir);
71     static void printHelp(std::ostream& os);
72   };
73 
74 private:
75   FactoryOptions& _factoryOptions;
76   Options* _options = nullptr;
77 
78 public:
79   // NOLINTNEXTLINE(readability-identifier-naming)
80   void(__stdcall* dll_GRBversion)(int*, int*, int*);
81 
82   // NOLINTNEXTLINE(readability-identifier-naming)
83   int(__stdcall* dll_GRBaddconstr)(GRBmodel* model, int numnz, int* cind, double* cval, char sense,
84                                    double rhs, const char* constrname);
85 
86   // NOLINTNEXTLINE(readability-identifier-naming)
87   int(__stdcall* dll_GRBaddgenconstrMin)(GRBmodel* model, const char* name, int resvar, int nvars,
88                                          const int* vars, double constant);
89 
90   // NOLINTNEXTLINE(readability-identifier-naming)
91   int(__stdcall* dll_GRBaddqconstr)(GRBmodel* model, int numlnz, int* lind, double* lval,
92                                     int numqnz, int* qrow, int* qcol, double* qval, char sense,
93                                     double rhs, const char* QCname);
94 
95   // NOLINTNEXTLINE(readability-identifier-naming)
96   int(__stdcall* dll_GRBaddgenconstrIndicator)(GRBmodel* model, const char* name, int binvar,
97                                                int binval, int nvars, const int* ind,
98                                                const double* val, char sense, double rhs);
99 
100   // NOLINTNEXTLINE(readability-identifier-naming)
101   int(__stdcall* dll_GRBaddvars)(GRBmodel* model, int numvars, int numnz, int* vbeg, int* vind,
102                                  double* vval, double* obj, double* lb, double* ub, char* vtype,
103                                  char** varnames);
104 
105   // NOLINTNEXTLINE(readability-identifier-naming)
106   int(__stdcall* dll_GRBcbcut)(void* cbdata, int cutlen, const int* cutind, const double* cutval,
107                                char cutsense, double cutrhs);
108 
109   // NOLINTNEXTLINE(readability-identifier-naming)
110   int(__stdcall* dll_GRBcbget)(void* cbdata, int where, int what, void* resultP);
111 
112   // NOLINTNEXTLINE(readability-identifier-naming)
113   int(__stdcall* dll_GRBcblazy)(void* cbdata, int lazylen, const int* lazyind,
114                                 const double* lazyval, char lazysense, double lazyrhs);
115 
116   // NOLINTNEXTLINE(readability-identifier-naming)
117   void(__stdcall* dll_GRBfreeenv)(GRBenv* env);
118 
119   // NOLINTNEXTLINE(readability-identifier-naming)
120   int(__stdcall* dll_GRBfreemodel)(GRBmodel* model);
121 
122   // NOLINTNEXTLINE(readability-identifier-naming)
123   int(__stdcall* dll_GRBgetdblattr)(GRBmodel* model, const char* attrname, double* valueP);
124 
125   // NOLINTNEXTLINE(readability-identifier-naming)
126   int(__stdcall* dll_GRBgetdblattrarray)(GRBmodel* model, const char* attrname, int first, int len,
127                                          double* values);
128 
129   // NOLINTNEXTLINE(readability-identifier-naming)
130   GRBenv*(__stdcall* dll_GRBgetenv)(GRBmodel* model);
131 
132   // NOLINTNEXTLINE(readability-identifier-naming)
133   const char*(__stdcall* dll_GRBgeterrormsg)(GRBenv* env);
134 
135   // NOLINTNEXTLINE(readability-identifier-naming)
136   int(__stdcall* dll_GRBgetintattr)(GRBmodel* model, const char* attrname, int* valueP);
137 
138   // NOLINTNEXTLINE(readability-identifier-naming)
139   int(__stdcall* dll_GRBloadenv)(GRBenv** envP, const char* logfilename);
140 
141   // NOLINTNEXTLINE(readability-identifier-naming)
142   GRBenv*(__stdcall* dll_GRBgetconcurrentenv)(GRBmodel* model, int num);
143 
144   // NOLINTNEXTLINE(readability-identifier-naming)
145   int(__stdcall* dll_GRBnewmodel)(GRBenv* env, GRBmodel** modelP, const char* Pname, int numvars,
146                                   double* obj, double* lb, double* ub, char* vtype,
147                                   char** varnames);
148 
149   // NOLINTNEXTLINE(readability-identifier-naming)
150   int(__stdcall* dll_GRBoptimize)(GRBmodel* model);
151 
152   // NOLINTNEXTLINE(readability-identifier-naming)
153   int(__stdcall* dll_GRBreadparams)(GRBenv* env, const char* filename);
154 
155   // NOLINTNEXTLINE(readability-identifier-naming)
156   int(__stdcall* dll_GRBsetcallbackfunc)(GRBmodel* model, int(__stdcall* cb)(CB_ARGS),
157                                          void* usrdata);
158 
159   // NOLINTNEXTLINE(readability-identifier-naming)
160   int(__stdcall* dll_GRBsetdblparam)(GRBenv* env, const char* paramname, double value);
161 
162   // NOLINTNEXTLINE(readability-identifier-naming)
163   int(__stdcall* dll_GRBsetintparam)(GRBenv* env, const char* paramname, int value);
164 
165   // NOLINTNEXTLINE(readability-identifier-naming)
166   int(__stdcall* dll_GRBsetintattr)(GRBmodel* model, const char* attrname, int newvalue);
167 
168   // NOLINTNEXTLINE(readability-identifier-naming)
169   int(__stdcall* dll_GRBsetdblattrelement)(GRBmodel* model, const char* attrname, int iv, double v);
170 
171   // NOLINTNEXTLINE(readability-identifier-naming)
172   int(__stdcall* dll_GRBsetintattrlist)(GRBmodel* model, const char* attrname, int len, int* ind,
173                                         int* newvalues);
174 
175   // NOLINTNEXTLINE(readability-identifier-naming)
176   int(__stdcall* dll_GRBsetdblattrlist)(GRBmodel* model, const char* attrname, int len, int* ind,
177                                         double* newvalues);
178 
179   // NOLINTNEXTLINE(readability-identifier-naming)
180   int(__stdcall* dll_GRBsetobjectiven)(GRBmodel* model, int index, int priority, double weight,
181                                        double abstol, double reltol, const char* name,
182                                        double constant, int lnz, int* lind, double* lval);
183 
184   // NOLINTNEXTLINE(readability-identifier-naming)
185   int(__stdcall* dll_GRBsetstrparam)(GRBenv* env, const char* paramname, const char* value);
186 
187   // NOLINTNEXTLINE(readability-identifier-naming)
188   void(__stdcall* dll_GRBterminate)(GRBmodel* model);
189 
190   // NOLINTNEXTLINE(readability-identifier-naming)
191   int(__stdcall* dll_GRBupdatemodel)(GRBmodel* model);
192 
193   // NOLINTNEXTLINE(readability-identifier-naming)
194   int(__stdcall* dll_GRBwrite)(GRBmodel* model, const char* filename);
195 
196   // NOLINTNEXTLINE(readability-identifier-naming)
197   int(__stdcall* dll_GRBwriteparams)(GRBenv* env, const char* filename);
198 
199   // NOLINTNEXTLINE(readability-identifier-naming)
200   int(__stdcall* dll_GRBgetintparam)(GRBenv* env, const char* paramname, int* valueP);
201 
202   // NOLINTNEXTLINE(readability-identifier-naming)
203   int(__stdcall* dll_GRBemptyenv)(GRBenv** envP);
204 
205   // NOLINTNEXTLINE(readability-identifier-naming)
206   int(__stdcall* dll_GRBgetnumparams)(GRBenv* env);
207 
208   // NOLINTNEXTLINE(readability-identifier-naming)
209   int(__stdcall* dll_GRBgetparamname)(GRBenv* env, int i, char** paramnameP);
210 
211   // NOLINTNEXTLINE(readability-identifier-naming)
212   int(__stdcall* dll_GRBgetparamtype)(GRBenv* env, const char* paramname);
213 
214   // NOLINTNEXTLINE(readability-identifier-naming)
215   int(__stdcall* dll_GRBgetintparaminfo)(GRBenv* env, const char* paramname, int* valueP, int* minP,
216                                          int* maxP, int* defP);
217 
218   // NOLINTNEXTLINE(readability-identifier-naming)
219   int(__stdcall* dll_GRBgetdblparaminfo)(GRBenv* env, const char* paramname, double* valueP,
220                                          double* minP, double* maxP, double* defP);
221 
222   // NOLINTNEXTLINE(readability-identifier-naming)
223   int(__stdcall* dll_GRBgetstrparaminfo)(GRBenv* env, const char* paramname, char* valueP,
224                                          char* defP);
225 
MIPGurobiWrapper(FactoryOptions & factoryOpt,Options * opt)226   MIPGurobiWrapper(FactoryOptions& factoryOpt, Options* opt)
227       : _factoryOptions(factoryOpt), _options(opt) {
228     if (opt != nullptr) {
229       openGUROBI();
230     }
231   }
~MIPGurobiWrapper()232   ~MIPGurobiWrapper() override { closeGUROBI(); }
233 
234   static std::string getDescription(FactoryOptions& factoryOpt,
235                                     MiniZinc::SolverInstanceBase::Options* opt = nullptr);
236   static std::string getVersion(FactoryOptions& factoryOpt,
237                                 MiniZinc::SolverInstanceBase::Options* opt = nullptr);
238   static std::string getId();
239   static std::string getName();
240   static std::vector<std::string> getTags();
241   static std::vector<std::string> getStdFlags();
242   static std::vector<std::string> getRequiredFlags(FactoryOptions& factoryOpt);
243   static std::vector<std::string> getFactoryFlags();
244 
245   static std::vector<MiniZinc::SolverConfig::ExtraFlag> getExtraFlags(FactoryOptions& factoryOpt);
246 
247   //       Statistics& getStatistics() { return _statistics; }
248 
249   //      IloConstraintArray *userCuts, *lazyConstraints;
250 
251   /// derived should overload and call the ancestor
252   //     virtual void cleanup();
253 
254   void checkDLL();
255   void openGUROBI();
256   void closeGUROBI();
257 
258   /// actual adding new variables to the solver
259   void doAddVars(size_t n, double* obj, double* lb, double* ub, VarType* vt,
260                  std::string* names) override;
261 
262   /// adding a linear constraint
263   void addRow(int nnz, int* rmatind, double* rmatval, LinConType sense, double rhs,
264               int mask = MaskConsType_Normal, const std::string& rowName = "") override;
265   void setVarBounds(int iVar, double lb, double ub) override;
266   void setVarLB(int iVar, double lb) override;
267   void setVarUB(int iVar, double ub) override;
268   /// Indicator constraint: x[iBVar]==bVal -> lin constr
269   void addIndicatorConstraint(int iBVar, int bVal, int nnz, int* rmatind, double* rmatval,
270                               LinConType sense, double rhs,
271                               const std::string& rowName = "") override;
272   void addMinimum(int iResultVar, int nnz, int* ind, const std::string& rowName = "") override;
273 
274   /// Times constraint: var[x]*var[y] == var[z]
275   void addTimes(int x, int y, int z, const std::string& rowName = "") override;
276 
277   int getFreeSearch() override;
278   bool addSearch(const std::vector<VarId>& vars, const std::vector<int>& pri) override;
279   bool addWarmStart(const std::vector<VarId>& vars, const std::vector<double>& vals) override;
280   bool defineMultipleObjectives(const MultipleObjectives& mo) override;
281 
282   int nRows = 0;  // to count rows in order tp notice lazy constraints
283   std::vector<int> nLazyIdx;
284   std::vector<int> nLazyValue;
285   /// adding an implication
286   //     virtual void addImpl() = 0;
287   void setObjSense(int s) override;  // +/-1 for max/min
288 
getInfBound()289   double getInfBound() override { return GRB_INFINITY; }
290 
getNCols()291   int getNCols() override {
292     dll_GRBupdatemodel(_model);
293     int cols;
294     _error = dll_GRBgetintattr(_model, GRB_INT_ATTR_NUMVARS, &cols);
295     return cols;
296   }
getNRows()297   int getNRows() override {
298     dll_GRBupdatemodel(_model);
299     int cols;
300     _error = dll_GRBgetintattr(_model, GRB_INT_ATTR_NUMCONSTRS, &cols);
301     return cols;
302   }
303 
304   //     void setObjUB(double ub) { objUB = ub; }
305   //     void addQPUniform(double c) { qpu = c; } // also sets problem type to MIQP unless c=0
306 
307   void solve() override;
308 
309   /// OUTPUT:
getValues()310   const double* getValues() override { return output.x; }
getObjValue()311   double getObjValue() override { return output.objVal; }
getBestBound()312   double getBestBound() override { return output.bestBound; }
getCPUTime()313   double getCPUTime() override { return output.dCPUTime; }
314 
getStatus()315   Status getStatus() override { return output.status; }
getStatusName()316   std::string getStatusName() override { return output.statusName; }
317 
getNNodes()318   int getNNodes() override { return output.nNodes; }
getNOpen()319   int getNOpen() override { return output.nOpenNodes; }
320 
321   //     virtual int getNNodes() = 0;
322   //     virtual double getTime() = 0;
323 
324 protected:
325   void wrapAssert(bool cond, const std::string& msg, bool fTerm = true);
326 
327   /// Need to consider the 100 status codes in GUROBI and change with every version? TODO
328   Status convertStatus(int gurobiStatus);
329 };
330