1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "ortools/gurobi/environment.h"
15 
16 #include <mutex>
17 #include <string>
18 
19 #include "absl/status/status.h"
20 #include "absl/strings/match.h"
21 #include "absl/strings/str_cat.h"
22 #include "absl/strings/str_format.h"
23 #include "absl/strings/str_join.h"
24 #include "absl/synchronization/mutex.h"
25 #include "ortools/base/file.h"
26 #include "ortools/base/logging.h"
27 #include "ortools/base/status_macros.h"
28 
29 namespace operations_research {
30 
GurobiIsCorrectlyInstalled()31 bool GurobiIsCorrectlyInstalled() {
32   absl::StatusOr<GRBenv*> status = GetGurobiEnv();
33   if (!status.ok() || status.value() == nullptr) {
34     return false;
35   }
36 
37   GRBfreeenv(status.value());
38 
39   return true;
40 }
41 
42 // This was generated with the parse_header.py script.
43 // See the comment at the top of the script.
44 
45 // This is the 'define' section.
46 
47 std::function<int(GRBenv**, const char*, const char*, const char*, int,
48                   const char*)>
49     GRBisqp = nullptr;
50 std::function<int(GRBmodel* model, const char* attrname, int* datatypeP,
51                   int* sizeP, int* settableP)>
52     GRBgetattrinfo = nullptr;
53 std::function<int(GRBmodel* model, const char* attrname)> GRBisattravailable =
54     nullptr;
55 std::function<int(GRBmodel* model, const char* attrname, int* valueP)>
56     GRBgetintattr = nullptr;
57 std::function<int(GRBmodel* model, const char* attrname, int newvalue)>
58     GRBsetintattr = nullptr;
59 std::function<int(GRBmodel* model, const char* attrname, int element,
60                   int* valueP)>
61     GRBgetintattrelement = nullptr;
62 std::function<int(GRBmodel* model, const char* attrname, int element,
63                   int newvalue)>
64     GRBsetintattrelement = nullptr;
65 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
66                   int* values)>
67     GRBgetintattrarray = nullptr;
68 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
69                   int* newvalues)>
70     GRBsetintattrarray = nullptr;
71 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
72                   int* values)>
73     GRBgetintattrlist = nullptr;
74 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
75                   int* newvalues)>
76     GRBsetintattrlist = nullptr;
77 std::function<int(GRBmodel* model, const char* attrname, int element,
78                   char* valueP)>
79     GRBgetcharattrelement = nullptr;
80 std::function<int(GRBmodel* model, const char* attrname, int element,
81                   char newvalue)>
82     GRBsetcharattrelement = nullptr;
83 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
84                   char* values)>
85     GRBgetcharattrarray = nullptr;
86 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
87                   char* newvalues)>
88     GRBsetcharattrarray = nullptr;
89 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
90                   char* values)>
91     GRBgetcharattrlist = nullptr;
92 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
93                   char* newvalues)>
94     GRBsetcharattrlist = nullptr;
95 std::function<int(GRBmodel* model, const char* attrname, double* valueP)>
96     GRBgetdblattr = nullptr;
97 std::function<int(GRBmodel* model, const char* attrname, double newvalue)>
98     GRBsetdblattr = nullptr;
99 std::function<int(GRBmodel* model, const char* attrname, int element,
100                   double* valueP)>
101     GRBgetdblattrelement = nullptr;
102 std::function<int(GRBmodel* model, const char* attrname, int element,
103                   double newvalue)>
104     GRBsetdblattrelement = nullptr;
105 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
106                   double* values)>
107     GRBgetdblattrarray = nullptr;
108 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
109                   double* newvalues)>
110     GRBsetdblattrarray = nullptr;
111 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
112                   double* values)>
113     GRBgetdblattrlist = nullptr;
114 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
115                   double* newvalues)>
116     GRBsetdblattrlist = nullptr;
117 std::function<int(GRBmodel* model, const char* attrname, char** valueP)>
118     GRBgetstrattr = nullptr;
119 std::function<int(GRBmodel* model, const char* attrname, const char* newvalue)>
120     GRBsetstrattr = nullptr;
121 std::function<int(GRBmodel* model, const char* attrname, int element,
122                   char** valueP)>
123     GRBgetstrattrelement = nullptr;
124 std::function<int(GRBmodel* model, const char* attrname, int element,
125                   const char* newvalue)>
126     GRBsetstrattrelement = nullptr;
127 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
128                   char** values)>
129     GRBgetstrattrarray = nullptr;
130 std::function<int(GRBmodel* model, const char* attrname, int first, int len,
131                   char** newvalues)>
132     GRBsetstrattrarray = nullptr;
133 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
134                   char** values)>
135     GRBgetstrattrlist = nullptr;
136 std::function<int(GRBmodel* model, const char* attrname, int len, int* ind,
137                   char** newvalues)>
138     GRBsetstrattrlist = nullptr;
139 std::function<int(GRBmodel* model, int(GUROBI_STDCALL* cb)(CB_ARGS),
140                   void* usrdata)>
141     GRBsetcallbackfunc = nullptr;
142 std::function<int(GRBmodel* model, int(GUROBI_STDCALL** cbP)(CB_ARGS))>
143     GRBgetcallbackfunc = nullptr;
144 std::function<int(GRBmodel* model, int(GUROBI_STDCALL* cb)(char* msg))>
145     GRBsetlogcallbackfunc = nullptr;
146 std::function<int(GRBenv* env, int(GUROBI_STDCALL* cb)(char* msg))>
147     GRBsetlogcallbackfuncenv = nullptr;
148 std::function<int(void* cbdata, int where, int what, void* resultP)> GRBcbget =
149     nullptr;
150 std::function<int(void* cbdata, const char* paramname, const char* newvalue)>
151     GRBcbsetparam = nullptr;
152 std::function<int(void* cbdata, const double* solution, double* objvalP)>
153     GRBcbsolution = nullptr;
154 std::function<int(void* cbdata, int cutlen, const int* cutind,
155                   const double* cutval, char cutsense, double cutrhs)>
156     GRBcbcut = nullptr;
157 std::function<int(void* cbdata, int lazylen, const int* lazyind,
158                   const double* lazyval, char lazysense, double lazyrhs)>
159     GRBcblazy = nullptr;
160 std::function<int(GRBmodel* model, int constr, int var, double* valP)>
161     GRBgetcoeff = nullptr;
162 std::function<int(GRBmodel* model, int* numnzP, int* cbeg, int* cind,
163                   double* cval, int start, int len)>
164     GRBgetconstrs = nullptr;
165 std::function<int(GRBmodel* model, size_t* numnzP, size_t* cbeg, int* cind,
166                   double* cval, int start, int len)>
167     GRBXgetconstrs = nullptr;
168 std::function<int(GRBmodel* model, int* numnzP, int* vbeg, int* vind,
169                   double* vval, int start, int len)>
170     GRBgetvars = nullptr;
171 std::function<int(GRBmodel* model, size_t* numnzP, size_t* vbeg, int* vind,
172                   double* vval, int start, int len)>
173     GRBXgetvars = nullptr;
174 std::function<int(GRBmodel* model, int* nummembersP, int* sostype, int* beg,
175                   int* ind, double* weight, int start, int len)>
176     GRBgetsos = nullptr;
177 std::function<int(GRBmodel* model, int genconstr, int* resvarP, int* nvarsP,
178                   int* vars, double* constantP)>
179     GRBgetgenconstrMax = nullptr;
180 std::function<int(GRBmodel* model, int genconstr, int* resvarP, int* nvarsP,
181                   int* vars, double* constantP)>
182     GRBgetgenconstrMin = nullptr;
183 std::function<int(GRBmodel* model, int genconstr, int* resvarP, int* argvarP)>
184     GRBgetgenconstrAbs = nullptr;
185 std::function<int(GRBmodel* model, int genconstr, int* resvarP, int* nvarsP,
186                   int* vars)>
187     GRBgetgenconstrAnd = nullptr;
188 std::function<int(GRBmodel* model, int genconstr, int* resvarP, int* nvarsP,
189                   int* vars)>
190     GRBgetgenconstrOr = nullptr;
191 std::function<int(GRBmodel* model, int genconstr, int* binvarP, int* binvalP,
192                   int* nvarsP, int* vars, double* vals, char* senseP,
193                   double* rhsP)>
194     GRBgetgenconstrIndicator = nullptr;
195 std::function<int(GRBmodel* model, int* numqnzP, int* qrow, int* qcol,
196                   double* qval)>
197     GRBgetq = nullptr;
198 std::function<int(GRBmodel* model, int qconstr, int* numlnzP, int* lind,
199                   double* lval, int* numqnzP, int* qrow, int* qcol,
200                   double* qval)>
201     GRBgetqconstr = nullptr;
202 std::function<int(GRBmodel* model, const char* name, int* indexP)>
203     GRBgetvarbyname = nullptr;
204 std::function<int(GRBmodel* model, const char* name, int* indexP)>
205     GRBgetconstrbyname = nullptr;
206 std::function<int(GRBmodel* model, int var, int* pointsP, double* x, double* y)>
207     GRBgetpwlobj = nullptr;
208 std::function<int(GRBmodel* model)> GRBoptimize = nullptr;
209 std::function<int(GRBmodel* model)> GRBoptimizeasync = nullptr;
210 std::function<GRBmodel*(GRBmodel* model)> GRBcopymodel = nullptr;
211 std::function<GRBmodel*(GRBmodel* model)> GRBfixedmodel = nullptr;
212 std::function<int(GRBmodel* model, int relaxobjtype, int minrelax,
213                   double* lbpen, double* ubpen, double* rhspen,
214                   double* feasobjP)>
215     GRBfeasrelax = nullptr;
216 std::function<int(void* cbdata, int what, int* typeP, int* sizeP)>
217     GRBgetcbwhatinfo = nullptr;
218 std::function<GRBmodel*(GRBmodel* model)> GRBrelaxmodel = nullptr;
219 std::function<int(GRBmodel* model)> GRBconverttofixed = nullptr;
220 std::function<GRBmodel*(GRBmodel* model)> GRBpresolvemodel = nullptr;
221 std::function<GRBmodel*(GRBmodel* model)> GRBiismodel = nullptr;
222 std::function<GRBmodel*(GRBmodel* model)> GRBfeasibility = nullptr;
223 std::function<GRBmodel*(GRBmodel* model)> GRBlinearizemodel = nullptr;
224 std::function<int(GRBenv** envP, const char* logfilename,
225                   void*(GUROBI_STDCALL* malloccb)(MALLOCCB_ARGS),
226                   void*(GUROBI_STDCALL* calloccb)(CALLOCCB_ARGS),
227                   void*(GUROBI_STDCALL* realloccb)(REALLOCCB_ARGS),
228                   void(GUROBI_STDCALL* freecb)(FREECB_ARGS),
229                   int(GUROBI_STDCALL* threadcreatecb)(THREADCREATECB_ARGS),
230                   void(GUROBI_STDCALL* threadjoincb)(THREADJOINCB_ARGS),
231                   void* syscbusrdata)>
232     GRBloadenvsyscb = nullptr;
233 std::function<int(GRBenv* env, const char* filename, GRBmodel** modelP)>
234     GRBreadmodel = nullptr;
235 std::function<int(GRBmodel* model, const char* filename)> GRBread = nullptr;
236 std::function<int(GRBmodel* model, const char* filename)> GRBwrite = nullptr;
237 std::function<int(const char* filename)> GRBismodelfile = nullptr;
238 std::function<int(const char* filename)> GRBfiletype = nullptr;
239 std::function<int(const char* filename)> GRBisrecordfile = nullptr;
240 std::function<int(GRBenv* env, GRBmodel** modelP, const char* Pname,
241                   int numvars, double* obj, double* lb, double* ub, char* vtype,
242                   char** varnames)>
243     GRBnewmodel = nullptr;
244 std::function<int(GRBenv* env, GRBmodel** modelP, const char* Pname,
245                   int numvars, int numconstrs, int objsense, double objcon,
246                   double* obj, char* sense, double* rhs, int* vbeg, int* vlen,
247                   int* vind, double* vval, double* lb, double* ub, char* vtype,
248                   char** varnames, char** constrnames)>
249     GRBloadmodel = nullptr;
250 std::function<int(GRBenv* env, GRBmodel** modelP, const char* Pname,
251                   int numvars, int numconstrs, int objsense, double objcon,
252                   double* obj, char* sense, double* rhs, size_t* vbeg,
253                   int* vlen, int* vind, double* vval, double* lb, double* ub,
254                   char* vtype, char** varnames, char** constrnames)>
255     GRBXloadmodel = nullptr;
256 std::function<int(GRBmodel* model, int numnz, int* vind, double* vval,
257                   double obj, double lb, double ub, char vtype,
258                   const char* varname)>
259     GRBaddvar = nullptr;
260 std::function<int(GRBmodel* model, int numvars, int numnz, int* vbeg, int* vind,
261                   double* vval, double* obj, double* lb, double* ub,
262                   char* vtype, char** varnames)>
263     GRBaddvars = nullptr;
264 std::function<int(GRBmodel* model, int numvars, size_t numnz, size_t* vbeg,
265                   int* vind, double* vval, double* obj, double* lb, double* ub,
266                   char* vtype, char** varnames)>
267     GRBXaddvars = nullptr;
268 std::function<int(GRBmodel* model, int numnz, int* cind, double* cval,
269                   char sense, double rhs, const char* constrname)>
270     GRBaddconstr = nullptr;
271 std::function<int(GRBmodel* model, int numconstrs, int numnz, int* cbeg,
272                   int* cind, double* cval, char* sense, double* rhs,
273                   char** constrnames)>
274     GRBaddconstrs = nullptr;
275 std::function<int(GRBmodel* model, int numconstrs, size_t numnz, size_t* cbeg,
276                   int* cind, double* cval, char* sense, double* rhs,
277                   char** constrnames)>
278     GRBXaddconstrs = nullptr;
279 std::function<int(GRBmodel* model, int numnz, int* cind, double* cval,
280                   double lower, double upper, const char* constrname)>
281     GRBaddrangeconstr = nullptr;
282 std::function<int(GRBmodel* model, int numconstrs, int numnz, int* cbeg,
283                   int* cind, double* cval, double* lower, double* upper,
284                   char** constrnames)>
285     GRBaddrangeconstrs = nullptr;
286 std::function<int(GRBmodel* model, int numconstrs, size_t numnz, size_t* cbeg,
287                   int* cind, double* cval, double* lower, double* upper,
288                   char** constrnames)>
289     GRBXaddrangeconstrs = nullptr;
290 std::function<int(GRBmodel* model, int numsos, int nummembers, int* types,
291                   int* beg, int* ind, double* weight)>
292     GRBaddsos = nullptr;
293 std::function<int(GRBmodel* model, const char* name, int resvar, int nvars,
294                   const int* vars, double constant)>
295     GRBaddgenconstrMax = nullptr;
296 std::function<int(GRBmodel* model, const char* name, int resvar, int nvars,
297                   const int* vars, double constant)>
298     GRBaddgenconstrMin = nullptr;
299 std::function<int(GRBmodel* model, const char* name, int resvar, int argvar)>
300     GRBaddgenconstrAbs = nullptr;
301 std::function<int(GRBmodel* model, const char* name, int resvar, int nvars,
302                   const int* vars)>
303     GRBaddgenconstrAnd = nullptr;
304 std::function<int(GRBmodel* model, const char* name, int resvar, int nvars,
305                   const int* vars)>
306     GRBaddgenconstrOr = nullptr;
307 std::function<int(GRBmodel* lp, const char* name, int binvar, int binval,
308                   int nvars, const int* vars, const double* vals, char sense,
309                   double rhs)>
310     GRBaddgenconstrIndicator = nullptr;
311 std::function<int(GRBmodel* model, int numlnz, int* lind, double* lval,
312                   int numqnz, int* qrow, int* qcol, double* qval, char sense,
313                   double rhs, const char* QCname)>
314     GRBaddqconstr = nullptr;
315 std::function<int(GRBmodel* model, int nummembers, int* members)> GRBaddcone =
316     nullptr;
317 std::function<int(GRBmodel* model, int numqnz, int* qrow, int* qcol,
318                   double* qval)>
319     GRBaddqpterms = nullptr;
320 std::function<int(GRBmodel* model, int len, int* ind)> GRBdelvars = nullptr;
321 std::function<int(GRBmodel* model, int len, int* ind)> GRBdelconstrs = nullptr;
322 std::function<int(GRBmodel* model, int len, int* ind)> GRBdelsos = nullptr;
323 std::function<int(GRBmodel* model, int len, int* ind)> GRBdelgenconstrs =
324     nullptr;
325 std::function<int(GRBmodel* model, int len, int* ind)> GRBdelqconstrs = nullptr;
326 std::function<int(GRBmodel* model)> GRBdelq = nullptr;
327 std::function<int(GRBmodel* model, int cnt, int* cind, int* vind, double* val)>
328     GRBchgcoeffs = nullptr;
329 std::function<int(GRBmodel* model, size_t cnt, int* cind, int* vind,
330                   double* val)>
331     GRBXchgcoeffs = nullptr;
332 std::function<int(GRBmodel* model, int var, int points, double* x, double* y)>
333     GRBsetpwlobj = nullptr;
334 std::function<int(GRBmodel* model)> GRBupdatemodel = nullptr;
335 std::function<int(GRBmodel* model)> GRBresetmodel = nullptr;
336 std::function<int(GRBmodel* model)> GRBfreemodel = nullptr;
337 std::function<int(GRBmodel* model)> GRBcomputeIIS = nullptr;
338 std::function<int(GRBmodel* model, GRBsvec* b, GRBsvec* x)> GRBFSolve = nullptr;
339 std::function<int(GRBmodel* model, int j, GRBsvec* x)> GRBBinvColj = nullptr;
340 std::function<int(GRBmodel* model, int j, GRBsvec* x)> GRBBinvj = nullptr;
341 std::function<int(GRBmodel* model, GRBsvec* b, GRBsvec* x)> GRBBSolve = nullptr;
342 std::function<int(GRBmodel* model, int i, GRBsvec* x)> GRBBinvi = nullptr;
343 std::function<int(GRBmodel* model, int i, GRBsvec* x)> GRBBinvRowi = nullptr;
344 std::function<int(GRBmodel* model, int* bhead)> GRBgetBasisHead = nullptr;
345 std::function<int(GRBmodel* model, int num, int* cand, double* downobjbd,
346                   double* upobjbd, int* statusP)>
347     GRBstrongbranch = nullptr;
348 std::function<int(GRBmodel* model)> GRBcheckmodel = nullptr;
349 std::function<void(GRBmodel* model)> GRBsetsignal = nullptr;
350 std::function<void(GRBmodel* model)> GRBterminate = nullptr;
351 std::function<int(const char* filename)> GRBreplay = nullptr;
352 std::function<int(GRBmodel* model, int sense, double constant, int lnz,
353                   int* lind, double* lval, int qnz, int* qrow, int* qcol,
354                   double* qval)>
355     GRBsetobjective = nullptr;
356 std::function<int(GRBmodel* model, int index, int priority, double weight,
357                   double abstol, double reltol, const char* name,
358                   double constant, int lnz, int* lind, double* lval)>
359     GRBsetobjectiven = nullptr;
360 std::function<void(GRBenv* env, const char* message)> GRBmsg = nullptr;
361 std::function<int(GRBenv* env, FILE** logfileP)> GRBgetlogfile = nullptr;
362 std::function<int(GRBenv* env, FILE* logfile)> GRBsetlogfile = nullptr;
363 std::function<int(GRBenv* env, const char* paramname, int* valueP)>
364     GRBgetintparam = nullptr;
365 std::function<int(GRBenv* env, const char* paramname, double* valueP)>
366     GRBgetdblparam = nullptr;
367 std::function<int(GRBenv* env, const char* paramname, char* valueP)>
368     GRBgetstrparam = nullptr;
369 std::function<int(GRBenv* env, const char* paramname, int* valueP, int* minP,
370                   int* maxP, int* defP)>
371     GRBgetintparaminfo = nullptr;
372 std::function<int(GRBenv* env, const char* paramname, double* valueP,
373                   double* minP, double* maxP, double* defP)>
374     GRBgetdblparaminfo = nullptr;
375 std::function<int(GRBenv* env, const char* paramname, char* valueP, char* defP)>
376     GRBgetstrparaminfo = nullptr;
377 std::function<int(GRBenv* env, const char* paramname, const char* value)>
378     GRBsetparam = nullptr;
379 std::function<int(GRBenv* env, const char* paramname, int value)>
380     GRBsetintparam = nullptr;
381 std::function<int(GRBenv* env, const char* paramname, double value)>
382     GRBsetdblparam = nullptr;
383 std::function<int(GRBenv* env, const char* paramname, const char* value)>
384     GRBsetstrparam = nullptr;
385 std::function<int(GRBenv* env, const char* paramname)> GRBgetparamtype =
386     nullptr;
387 std::function<int(GRBenv* env)> GRBresetparams = nullptr;
388 std::function<int(GRBenv* dest, GRBenv* src)> GRBcopyparams = nullptr;
389 std::function<int(GRBenv* env, const char* filename)> GRBwriteparams = nullptr;
390 std::function<int(GRBenv* env, const char* filename)> GRBreadparams = nullptr;
391 std::function<int(GRBenv* env)> GRBgetnumparams = nullptr;
392 std::function<int(GRBenv* env, int i, char** paramnameP)> GRBgetparamname =
393     nullptr;
394 std::function<int(GRBmodel* model)> GRBgetnumattributes = nullptr;
395 std::function<int(GRBmodel* model, int i, char** attrnameP)> GRBgetattrname =
396     nullptr;
397 std::function<int(GRBenv** envP, const char* logfilename)> GRBloadenv = nullptr;
398 std::function<int(GRBenv** envP, const char* logfilename, int apitype,
399                   int major, int minor, int tech,
400                   int(GUROBI_STDCALL* cb)(CB_ARGS), void* usrdata)>
401     GRBloadenvadv = nullptr;
402 std::function<int(GRBenv** envP, const char* logfilename,
403                   const char* computeservers, int port, const char* password,
404                   int priority, double timeout)>
405     GRBloadclientenv = nullptr;
406 std::function<int(GRBenv** envP, const char* logfilename,
407                   const char* computeservers, int port, const char* password,
408                   int priority, double timeout, int apitype, int major,
409                   int minor, int tech, int(GUROBI_STDCALL* cb)(CB_ARGS),
410                   void* usrdata)>
411     GRBloadclientenvadv = nullptr;
412 std::function<int(GRBenv** envP, const char* logfilename, const char* accessID,
413                   const char* secretKey, const char* pool)>
414     GRBloadcloudenv = nullptr;
415 std::function<int(GRBenv** envP, const char* logfilename, const char* accessID,
416                   const char* secretKey, const char* pool, int apitype,
417                   int major, int minor, int tech,
418                   int(GUROBI_STDCALL* cb)(CB_ARGS), void* usrdata)>
419     GRBloadcloudenvadv = nullptr;
420 std::function<GRBenv*(GRBmodel* model)> GRBgetenv = nullptr;
421 std::function<GRBenv*(GRBmodel* model, int num)> GRBgetconcurrentenv = nullptr;
422 std::function<void(GRBmodel* model)> GRBdiscardconcurrentenvs = nullptr;
423 std::function<GRBenv*(GRBmodel* model, int num)> GRBgetmultiobjenv = nullptr;
424 std::function<void(GRBmodel* model)> GRBdiscardmultiobjenvs = nullptr;
425 std::function<void(GRBenv* env)> GRBreleaselicense = nullptr;
426 std::function<void(GRBenv* env)> GRBfreeenv = nullptr;
427 std::function<const char*(GRBenv* env)> GRBgeterrormsg = nullptr;
428 std::function<const char*(GRBmodel* model)> GRBgetmerrormsg = nullptr;
429 std::function<void(int* majorP, int* minorP, int* technicalP)> GRBversion =
430     nullptr;
431 std::function<char*(void)> GRBplatform = nullptr;
432 std::function<int(GRBmodel* model)> GRBtunemodel = nullptr;
433 std::function<int(int nummodels, GRBmodel** models, GRBmodel* ignore,
434                   GRBmodel* hint)>
435     GRBtunemodels = nullptr;
436 std::function<int(GRBmodel* model, int i)> GRBgettuneresult = nullptr;
437 std::function<int(GRBmodel* model, int i, char** logP)> GRBgettunelog = nullptr;
438 std::function<int(GRBmodel* model, GRBmodel* ignore, GRBmodel* hint)>
439     GRBtunemodeladv = nullptr;
440 std::function<int(GRBmodel* model)> GRBsync = nullptr;
441 
LoadGurobiFunctions(DynamicLibrary * gurobi_dynamic_library)442 void LoadGurobiFunctions(DynamicLibrary* gurobi_dynamic_library) {
443   // This was generated with the parse_header.py script.
444   // See the comment at the top of the script.
445 
446   // This is the 'assign' section.
447 
448   gurobi_dynamic_library->GetFunction(&GRBisqp, "GRBisqp");
449   gurobi_dynamic_library->GetFunction(&GRBgetattrinfo, "GRBgetattrinfo");
450   gurobi_dynamic_library->GetFunction(&GRBisattravailable,
451                                       "GRBisattravailable");
452   gurobi_dynamic_library->GetFunction(&GRBgetintattr, "GRBgetintattr");
453   gurobi_dynamic_library->GetFunction(&GRBsetintattr, "GRBsetintattr");
454   gurobi_dynamic_library->GetFunction(&GRBgetintattrelement,
455                                       "GRBgetintattrelement");
456   gurobi_dynamic_library->GetFunction(&GRBsetintattrelement,
457                                       "GRBsetintattrelement");
458   gurobi_dynamic_library->GetFunction(&GRBgetintattrarray,
459                                       "GRBgetintattrarray");
460   gurobi_dynamic_library->GetFunction(&GRBsetintattrarray,
461                                       "GRBsetintattrarray");
462   gurobi_dynamic_library->GetFunction(&GRBgetintattrlist, "GRBgetintattrlist");
463   gurobi_dynamic_library->GetFunction(&GRBsetintattrlist, "GRBsetintattrlist");
464   gurobi_dynamic_library->GetFunction(&GRBgetcharattrelement,
465                                       "GRBgetcharattrelement");
466   gurobi_dynamic_library->GetFunction(&GRBsetcharattrelement,
467                                       "GRBsetcharattrelement");
468   gurobi_dynamic_library->GetFunction(&GRBgetcharattrarray,
469                                       "GRBgetcharattrarray");
470   gurobi_dynamic_library->GetFunction(&GRBsetcharattrarray,
471                                       "GRBsetcharattrarray");
472   gurobi_dynamic_library->GetFunction(&GRBgetcharattrlist,
473                                       "GRBgetcharattrlist");
474   gurobi_dynamic_library->GetFunction(&GRBsetcharattrlist,
475                                       "GRBsetcharattrlist");
476   gurobi_dynamic_library->GetFunction(&GRBgetdblattr, "GRBgetdblattr");
477   gurobi_dynamic_library->GetFunction(&GRBsetdblattr, "GRBsetdblattr");
478   gurobi_dynamic_library->GetFunction(&GRBgetdblattrelement,
479                                       "GRBgetdblattrelement");
480   gurobi_dynamic_library->GetFunction(&GRBsetdblattrelement,
481                                       "GRBsetdblattrelement");
482   gurobi_dynamic_library->GetFunction(&GRBgetdblattrarray,
483                                       "GRBgetdblattrarray");
484   gurobi_dynamic_library->GetFunction(&GRBsetdblattrarray,
485                                       "GRBsetdblattrarray");
486   gurobi_dynamic_library->GetFunction(&GRBgetdblattrlist, "GRBgetdblattrlist");
487   gurobi_dynamic_library->GetFunction(&GRBsetdblattrlist, "GRBsetdblattrlist");
488   gurobi_dynamic_library->GetFunction(&GRBgetstrattr, "GRBgetstrattr");
489   gurobi_dynamic_library->GetFunction(&GRBsetstrattr, "GRBsetstrattr");
490   gurobi_dynamic_library->GetFunction(&GRBgetstrattrelement,
491                                       "GRBgetstrattrelement");
492   gurobi_dynamic_library->GetFunction(&GRBsetstrattrelement,
493                                       "GRBsetstrattrelement");
494   gurobi_dynamic_library->GetFunction(&GRBgetstrattrarray,
495                                       "GRBgetstrattrarray");
496   gurobi_dynamic_library->GetFunction(&GRBsetstrattrarray,
497                                       "GRBsetstrattrarray");
498   gurobi_dynamic_library->GetFunction(&GRBgetstrattrlist, "GRBgetstrattrlist");
499   gurobi_dynamic_library->GetFunction(&GRBsetstrattrlist, "GRBsetstrattrlist");
500   gurobi_dynamic_library->GetFunction(&GRBsetcallbackfunc,
501                                       "GRBsetcallbackfunc");
502   gurobi_dynamic_library->GetFunction(&GRBgetcallbackfunc,
503                                       "GRBgetcallbackfunc");
504   gurobi_dynamic_library->GetFunction(&GRBsetlogcallbackfunc,
505                                       "GRBsetlogcallbackfunc");
506   gurobi_dynamic_library->GetFunction(&GRBsetlogcallbackfuncenv,
507                                       "GRBsetlogcallbackfuncenv");
508   gurobi_dynamic_library->GetFunction(&GRBcbget, "GRBcbget");
509   gurobi_dynamic_library->GetFunction(&GRBcbsetparam, "GRBcbsetparam");
510   gurobi_dynamic_library->GetFunction(&GRBcbsolution, "GRBcbsolution");
511   gurobi_dynamic_library->GetFunction(&GRBcbcut, "GRBcbcut");
512   gurobi_dynamic_library->GetFunction(&GRBcblazy, "GRBcblazy");
513   gurobi_dynamic_library->GetFunction(&GRBgetcoeff, "GRBgetcoeff");
514   gurobi_dynamic_library->GetFunction(&GRBgetconstrs, "GRBgetconstrs");
515   gurobi_dynamic_library->GetFunction(&GRBXgetconstrs, "GRBXgetconstrs");
516   gurobi_dynamic_library->GetFunction(&GRBgetvars, "GRBgetvars");
517   gurobi_dynamic_library->GetFunction(&GRBXgetvars, "GRBXgetvars");
518   gurobi_dynamic_library->GetFunction(&GRBgetsos, "GRBgetsos");
519   gurobi_dynamic_library->GetFunction(&GRBgetgenconstrMax,
520                                       "GRBgetgenconstrMax");
521   gurobi_dynamic_library->GetFunction(&GRBgetgenconstrMin,
522                                       "GRBgetgenconstrMin");
523   gurobi_dynamic_library->GetFunction(&GRBgetgenconstrAbs,
524                                       "GRBgetgenconstrAbs");
525   gurobi_dynamic_library->GetFunction(&GRBgetgenconstrAnd,
526                                       "GRBgetgenconstrAnd");
527   gurobi_dynamic_library->GetFunction(&GRBgetgenconstrOr, "GRBgetgenconstrOr");
528   gurobi_dynamic_library->GetFunction(&GRBgetgenconstrIndicator,
529                                       "GRBgetgenconstrIndicator");
530   gurobi_dynamic_library->GetFunction(&GRBgetq, "GRBgetq");
531   gurobi_dynamic_library->GetFunction(&GRBgetqconstr, "GRBgetqconstr");
532   gurobi_dynamic_library->GetFunction(&GRBgetvarbyname, "GRBgetvarbyname");
533   gurobi_dynamic_library->GetFunction(&GRBgetconstrbyname,
534                                       "GRBgetconstrbyname");
535   gurobi_dynamic_library->GetFunction(&GRBgetpwlobj, "GRBgetpwlobj");
536   gurobi_dynamic_library->GetFunction(&GRBoptimize, "GRBoptimize");
537   gurobi_dynamic_library->GetFunction(&GRBoptimizeasync, "GRBoptimizeasync");
538   gurobi_dynamic_library->GetFunction(&GRBcopymodel, "GRBcopymodel");
539   gurobi_dynamic_library->GetFunction(&GRBfixedmodel, "GRBfixedmodel");
540   gurobi_dynamic_library->GetFunction(&GRBfeasrelax, "GRBfeasrelax");
541   gurobi_dynamic_library->GetFunction(&GRBgetcbwhatinfo, "GRBgetcbwhatinfo");
542   gurobi_dynamic_library->GetFunction(&GRBrelaxmodel, "GRBrelaxmodel");
543   gurobi_dynamic_library->GetFunction(&GRBconverttofixed, "GRBconverttofixed");
544   gurobi_dynamic_library->GetFunction(&GRBpresolvemodel, "GRBpresolvemodel");
545   gurobi_dynamic_library->GetFunction(&GRBiismodel, "GRBiismodel");
546   gurobi_dynamic_library->GetFunction(&GRBfeasibility, "GRBfeasibility");
547   gurobi_dynamic_library->GetFunction(&GRBlinearizemodel, "GRBlinearizemodel");
548   gurobi_dynamic_library->GetFunction(&GRBloadenvsyscb, "GRBloadenvsyscb");
549   gurobi_dynamic_library->GetFunction(&GRBreadmodel, "GRBreadmodel");
550   gurobi_dynamic_library->GetFunction(&GRBread, "GRBread");
551   gurobi_dynamic_library->GetFunction(&GRBwrite, "GRBwrite");
552   gurobi_dynamic_library->GetFunction(&GRBismodelfile, "GRBismodelfile");
553   gurobi_dynamic_library->GetFunction(&GRBfiletype, "GRBfiletype");
554   gurobi_dynamic_library->GetFunction(&GRBisrecordfile, "GRBisrecordfile");
555   gurobi_dynamic_library->GetFunction(&GRBnewmodel, "GRBnewmodel");
556   gurobi_dynamic_library->GetFunction(&GRBloadmodel, "GRBloadmodel");
557   gurobi_dynamic_library->GetFunction(&GRBXloadmodel, "GRBXloadmodel");
558   gurobi_dynamic_library->GetFunction(&GRBaddvar, "GRBaddvar");
559   gurobi_dynamic_library->GetFunction(&GRBaddvars, "GRBaddvars");
560   gurobi_dynamic_library->GetFunction(&GRBXaddvars, "GRBXaddvars");
561   gurobi_dynamic_library->GetFunction(&GRBaddconstr, "GRBaddconstr");
562   gurobi_dynamic_library->GetFunction(&GRBaddconstrs, "GRBaddconstrs");
563   gurobi_dynamic_library->GetFunction(&GRBXaddconstrs, "GRBXaddconstrs");
564   gurobi_dynamic_library->GetFunction(&GRBaddrangeconstr, "GRBaddrangeconstr");
565   gurobi_dynamic_library->GetFunction(&GRBaddrangeconstrs,
566                                       "GRBaddrangeconstrs");
567   gurobi_dynamic_library->GetFunction(&GRBXaddrangeconstrs,
568                                       "GRBXaddrangeconstrs");
569   gurobi_dynamic_library->GetFunction(&GRBaddsos, "GRBaddsos");
570   gurobi_dynamic_library->GetFunction(&GRBaddgenconstrMax,
571                                       "GRBaddgenconstrMax");
572   gurobi_dynamic_library->GetFunction(&GRBaddgenconstrMin,
573                                       "GRBaddgenconstrMin");
574   gurobi_dynamic_library->GetFunction(&GRBaddgenconstrAbs,
575                                       "GRBaddgenconstrAbs");
576   gurobi_dynamic_library->GetFunction(&GRBaddgenconstrAnd,
577                                       "GRBaddgenconstrAnd");
578   gurobi_dynamic_library->GetFunction(&GRBaddgenconstrOr, "GRBaddgenconstrOr");
579   gurobi_dynamic_library->GetFunction(&GRBaddgenconstrIndicator,
580                                       "GRBaddgenconstrIndicator");
581   gurobi_dynamic_library->GetFunction(&GRBaddqconstr, "GRBaddqconstr");
582   gurobi_dynamic_library->GetFunction(&GRBaddcone, "GRBaddcone");
583   gurobi_dynamic_library->GetFunction(&GRBaddqpterms, "GRBaddqpterms");
584   gurobi_dynamic_library->GetFunction(&GRBdelvars, "GRBdelvars");
585   gurobi_dynamic_library->GetFunction(&GRBdelconstrs, "GRBdelconstrs");
586   gurobi_dynamic_library->GetFunction(&GRBdelsos, "GRBdelsos");
587   gurobi_dynamic_library->GetFunction(&GRBdelgenconstrs, "GRBdelgenconstrs");
588   gurobi_dynamic_library->GetFunction(&GRBdelqconstrs, "GRBdelqconstrs");
589   gurobi_dynamic_library->GetFunction(&GRBdelq, "GRBdelq");
590   gurobi_dynamic_library->GetFunction(&GRBchgcoeffs, "GRBchgcoeffs");
591   gurobi_dynamic_library->GetFunction(&GRBXchgcoeffs, "GRBXchgcoeffs");
592   gurobi_dynamic_library->GetFunction(&GRBsetpwlobj, "GRBsetpwlobj");
593   gurobi_dynamic_library->GetFunction(&GRBupdatemodel, "GRBupdatemodel");
594   gurobi_dynamic_library->GetFunction(&GRBresetmodel, "GRBresetmodel");
595   gurobi_dynamic_library->GetFunction(&GRBfreemodel, "GRBfreemodel");
596   gurobi_dynamic_library->GetFunction(&GRBcomputeIIS, "GRBcomputeIIS");
597   gurobi_dynamic_library->GetFunction(&GRBFSolve, "GRBFSolve");
598   gurobi_dynamic_library->GetFunction(&GRBBinvColj, "GRBBinvColj");
599   gurobi_dynamic_library->GetFunction(&GRBBinvj, "GRBBinvj");
600   gurobi_dynamic_library->GetFunction(&GRBBSolve, "GRBBSolve");
601   gurobi_dynamic_library->GetFunction(&GRBBinvi, "GRBBinvi");
602   gurobi_dynamic_library->GetFunction(&GRBBinvRowi, "GRBBinvRowi");
603   gurobi_dynamic_library->GetFunction(&GRBgetBasisHead, "GRBgetBasisHead");
604   gurobi_dynamic_library->GetFunction(&GRBstrongbranch, "GRBstrongbranch");
605   gurobi_dynamic_library->GetFunction(&GRBcheckmodel, "GRBcheckmodel");
606   gurobi_dynamic_library->GetFunction(&GRBsetsignal, "GRBsetsignal");
607   gurobi_dynamic_library->GetFunction(&GRBterminate, "GRBterminate");
608   gurobi_dynamic_library->GetFunction(&GRBreplay, "GRBreplay");
609   gurobi_dynamic_library->GetFunction(&GRBsetobjective, "GRBsetobjective");
610   gurobi_dynamic_library->GetFunction(&GRBsetobjectiven, "GRBsetobjectiven");
611   gurobi_dynamic_library->GetFunction(&GRBmsg, "GRBmsg");
612   gurobi_dynamic_library->GetFunction(&GRBgetlogfile, "GRBgetlogfile");
613   gurobi_dynamic_library->GetFunction(&GRBsetlogfile, "GRBsetlogfile");
614   gurobi_dynamic_library->GetFunction(&GRBgetintparam, "GRBgetintparam");
615   gurobi_dynamic_library->GetFunction(&GRBgetdblparam, "GRBgetdblparam");
616   gurobi_dynamic_library->GetFunction(&GRBgetstrparam, "GRBgetstrparam");
617   gurobi_dynamic_library->GetFunction(&GRBgetintparaminfo,
618                                       "GRBgetintparaminfo");
619   gurobi_dynamic_library->GetFunction(&GRBgetdblparaminfo,
620                                       "GRBgetdblparaminfo");
621   gurobi_dynamic_library->GetFunction(&GRBgetstrparaminfo,
622                                       "GRBgetstrparaminfo");
623   gurobi_dynamic_library->GetFunction(&GRBsetparam, "GRBsetparam");
624   gurobi_dynamic_library->GetFunction(&GRBsetintparam, "GRBsetintparam");
625   gurobi_dynamic_library->GetFunction(&GRBsetdblparam, "GRBsetdblparam");
626   gurobi_dynamic_library->GetFunction(&GRBsetstrparam, "GRBsetstrparam");
627   gurobi_dynamic_library->GetFunction(&GRBgetparamtype, "GRBgetparamtype");
628   gurobi_dynamic_library->GetFunction(&GRBresetparams, "GRBresetparams");
629   gurobi_dynamic_library->GetFunction(&GRBcopyparams, "GRBcopyparams");
630   gurobi_dynamic_library->GetFunction(&GRBwriteparams, "GRBwriteparams");
631   gurobi_dynamic_library->GetFunction(&GRBreadparams, "GRBreadparams");
632   gurobi_dynamic_library->GetFunction(&GRBgetnumparams, "GRBgetnumparams");
633   gurobi_dynamic_library->GetFunction(&GRBgetparamname, "GRBgetparamname");
634   gurobi_dynamic_library->GetFunction(&GRBgetnumattributes,
635                                       "GRBgetnumattributes");
636   gurobi_dynamic_library->GetFunction(&GRBgetattrname, "GRBgetattrname");
637   gurobi_dynamic_library->GetFunction(&GRBloadenv, "GRBloadenv");
638   gurobi_dynamic_library->GetFunction(&GRBloadenvadv, "GRBloadenvadv");
639   gurobi_dynamic_library->GetFunction(&GRBloadclientenv, "GRBloadclientenv");
640   gurobi_dynamic_library->GetFunction(&GRBloadclientenvadv,
641                                       "GRBloadclientenvadv");
642   gurobi_dynamic_library->GetFunction(&GRBloadcloudenv, "GRBloadcloudenv");
643   gurobi_dynamic_library->GetFunction(&GRBloadcloudenvadv,
644                                       "GRBloadcloudenvadv");
645   gurobi_dynamic_library->GetFunction(&GRBgetenv, "GRBgetenv");
646   gurobi_dynamic_library->GetFunction(&GRBgetconcurrentenv,
647                                       "GRBgetconcurrentenv");
648   gurobi_dynamic_library->GetFunction(&GRBdiscardconcurrentenvs,
649                                       "GRBdiscardconcurrentenvs");
650   gurobi_dynamic_library->GetFunction(&GRBgetmultiobjenv, "GRBgetmultiobjenv");
651   gurobi_dynamic_library->GetFunction(&GRBdiscardmultiobjenvs,
652                                       "GRBdiscardmultiobjenvs");
653   gurobi_dynamic_library->GetFunction(&GRBreleaselicense, "GRBreleaselicense");
654   gurobi_dynamic_library->GetFunction(&GRBfreeenv, "GRBfreeenv");
655   gurobi_dynamic_library->GetFunction(&GRBgeterrormsg, "GRBgeterrormsg");
656   gurobi_dynamic_library->GetFunction(&GRBgetmerrormsg, "GRBgetmerrormsg");
657   gurobi_dynamic_library->GetFunction(&GRBversion, "GRBversion");
658   gurobi_dynamic_library->GetFunction(&GRBplatform, "GRBplatform");
659   gurobi_dynamic_library->GetFunction(&GRBtunemodel, "GRBtunemodel");
660   gurobi_dynamic_library->GetFunction(&GRBtunemodels, "GRBtunemodels");
661   gurobi_dynamic_library->GetFunction(&GRBgettuneresult, "GRBgettuneresult");
662   gurobi_dynamic_library->GetFunction(&GRBgettunelog, "GRBgettunelog");
663   gurobi_dynamic_library->GetFunction(&GRBtunemodeladv, "GRBtunemodeladv");
664   gurobi_dynamic_library->GetFunction(&GRBsync, "GRBsync");
665 }
666 
GurobiDynamicLibraryPotentialPaths()667 std::vector<std::string> GurobiDynamicLibraryPotentialPaths() {
668   std::vector<std::string> potential_paths;
669   const std::vector<std::string> kGurobiVersions = {
670       "951", "950", "911", "910", "903", "902", "811", "801", "752"};
671 
672   // Look for libraries pointed by GUROBI_HOME first.
673   const char* gurobi_home_from_env = getenv("GUROBI_HOME");
674   if (gurobi_home_from_env != nullptr) {
675     for (const std::string& version : kGurobiVersions) {
676       const std::string lib = version.substr(0, 2);
677 #if defined(_MSC_VER)  // Windows
678       potential_paths.push_back(
679           absl::StrCat(gurobi_home_from_env, "\\bin\\gurobi", lib, ".dll"));
680 #elif defined(__APPLE__)  // OS X
681       potential_paths.push_back(
682           absl::StrCat(gurobi_home_from_env, "/lib/libgurobi", lib, ".dylib"));
683 #elif defined(__GNUC__)   // Linux
684       potential_paths.push_back(
685           absl::StrCat(gurobi_home_from_env, "/lib/libgurobi", lib, ".so"));
686       potential_paths.push_back(
687           absl::StrCat(gurobi_home_from_env, "/lib64/libgurobi", lib, ".so"));
688 #else
689       LOG(ERROR) << "OS Not recognized by gurobi/environment.cc."
690                  << " You won't be able to use Gurobi.";
691 #endif
692     }
693   }
694 
695   // Search for canonical places.
696   for (const std::string& version : kGurobiVersions) {
697     const std::string lib = version.substr(0, 2);
698 #if defined(_MSC_VER)  // Windows
699     potential_paths.push_back(absl::StrCat("C:\\Program Files\\gurobi", version,
700                                            "\\win64\\bin\\gurobi", lib,
701                                            ".dll"));
702 #elif defined(__APPLE__)  // OS X
703     potential_paths.push_back(absl::StrCat(
704         "/Library/gurobi", version, "/mac64/lib/libgurobi", lib, ".dylib"));
705 #elif defined(__GNUC__)   // Linux
706     potential_paths.push_back(absl::StrCat(
707         "/opt/gurobi", version, "/linux64/lib/libgurobi", lib, ".so"));
708     potential_paths.push_back(absl::StrCat(
709         "/opt/gurobi", version, "/linux64/lib64/libgurobi", lib, ".so"));
710     potential_paths.push_back(
711         absl::StrCat("/opt/gurobi/linux64/lib/libgurobi", lib, ".so"));
712     potential_paths.push_back(
713         absl::StrCat("/opt/gurobi/linux64/lib64/libgurobi", lib, ".so"));
714 #else
715     LOG(ERROR) << "OS Not recognized by gurobi/environment.cc."
716                << " You won't be able to use Gurobi.";
717 #endif
718   }
719   return potential_paths;
720 }
721 
LoadGurobiDynamicLibrary(std::vector<std::string> potential_paths)722 absl::Status LoadGurobiDynamicLibrary(
723     std::vector<std::string> potential_paths) {
724   static std::once_flag gurobi_loading_done;
725   static absl::Status gurobi_load_status;
726   static DynamicLibrary gurobi_library;
727   static absl::Mutex mutex;
728 
729   absl::MutexLock lock(&mutex);
730 
731   std::call_once(gurobi_loading_done, [&potential_paths]() {
732     const std::vector<std::string> canonical_paths =
733         GurobiDynamicLibraryPotentialPaths();
734     potential_paths.insert(potential_paths.end(), canonical_paths.begin(),
735                            canonical_paths.end());
736     for (const std::string& path : potential_paths) {
737       if (gurobi_library.TryToLoad(path)) {
738         LOG(INFO) << "Found the Gurobi library in '" << path << ".";
739         break;
740       }
741     }
742 
743     if (gurobi_library.LibraryIsLoaded()) {
744       LoadGurobiFunctions(&gurobi_library);
745       gurobi_load_status = absl::OkStatus();
746     } else {
747       gurobi_load_status = absl::NotFoundError(absl::StrCat(
748           "Could not find the Gurobi shared library. Looked in: [",
749           absl::StrJoin(potential_paths, "', '"),
750           "]. If you know where it"
751           " is, pass the full path to 'LoadGurobiDynamicLibrary()'."));
752     }
753   });
754   return gurobi_load_status;
755 }
756 
GetGurobiEnv()757 absl::StatusOr<GRBenv*> GetGurobiEnv() {
758   RETURN_IF_ERROR(LoadGurobiDynamicLibrary({}));
759 
760   GRBenv* env = nullptr;
761 
762   if (GRBloadenv(&env, nullptr) != 0 || env == nullptr) {
763     return absl::FailedPreconditionError(
764         absl::StrCat("Found the Gurobi shared library, but could not create "
765                      "Gurobi environment: is Gurobi licensed on this machine?",
766                      GRBgeterrormsg(env)));
767   }
768   return env;
769 }
770 
771 }  // namespace operations_research
772