OR-Tools  9.6
g_gurobi.cc
Go to the documentation of this file.
1 // Copyright 2010-2022 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 
15 
16 #include <memory>
17 #include <optional>
18 #include <string>
19 #include <string_view>
20 #include <utility>
21 #include <vector>
22 
23 #include "absl/status/status.h"
24 #include "absl/status/statusor.h"
25 #include "absl/strings/str_format.h"
26 #include "ortools/base/cleanup.h"
27 #include "ortools/base/logging.h"
32 #include "ortools/math_opt/solvers/gurobi.pb.h"
33 
35 
36 namespace {
37 constexpr int kGrbOk = 0;
38 
39 struct UserCallbackData {
41  absl::Status status = absl::OkStatus();
42  Gurobi* gurobi = nullptr;
43 };
44 
45 int GurobiCallback(GRBmodel* const model, void* const cbdata, const int where,
46  void* const usrdata) {
47  CHECK(usrdata != nullptr);
48  CHECK(model != nullptr);
49  auto user_cb_data = static_cast<UserCallbackData*>(usrdata);
50  CHECK_EQ(model, user_cb_data->gurobi->model());
51  // NOTE: if a previous callback failed, we never run the callback again.
52  if (!user_cb_data->status.ok()) {
53  return GRB_ERROR_CALLBACK;
54  }
55  const Gurobi::CallbackContext context(user_cb_data->gurobi, cbdata, where);
56  user_cb_data->status = user_cb_data->user_cb(context);
57  if (!user_cb_data->status.ok()) {
58  user_cb_data->gurobi->Terminate();
59  return GRB_ERROR_CALLBACK;
60  }
61  return kGrbOk;
62 }
63 
64 } // namespace
65 
66 void GurobiFreeEnv::operator()(GRBenv* const env) const {
67  if (env != nullptr) {
68  GRBfreeenv(env);
69  }
70 }
71 
72 absl::StatusOr<GRBenvUniquePtr> GurobiNewPrimaryEnv(
73  const std::optional<GurobiIsvKey>& isv_key) {
74  GRBenv* naked_primary_env = nullptr;
75  int err;
76  std::string_view init_env_method;
77  if (isv_key.has_value()) {
78  err = GRBisqp(&naked_primary_env, /*logfilename=*/
79  nullptr, isv_key->name.c_str(),
80  isv_key->application_name.c_str(), isv_key->expiration,
81  isv_key->key.c_str());
82  init_env_method = "GRBisqp()";
83  } else {
84  err = GRBloadenv(&naked_primary_env, /*logfilename=*/nullptr);
85  init_env_method = "GRBloadenv()";
86  }
87  if (err != kGrbOk) {
88  // Surprisingly, even when Gurobi fails to load the environment, it still
89  // creates one. Here we make sure to free it properly.
90  //
91  // We can also use it with GRBgeterrormsg() to get the associated error
92  // message that goes with the error and the contains additional data like
93  // the user, the host and the hostid.
94  const GRBenvUniquePtr primary_env(naked_primary_env);
96  << "failed to create Gurobi primary environment, " << init_env_method
97  << " returned the error (" << err
98  << "): " << GRBgeterrormsg(primary_env.get());
99  }
100  return GRBenvUniquePtr(naked_primary_env);
101 }
102 
103 absl::StatusOr<std::unique_ptr<Gurobi>> Gurobi::NewWithSharedPrimaryEnv(
104  GRBenv* const primary_env) {
105  CHECK(primary_env != nullptr);
106  return New(nullptr, primary_env);
107 }
108 
109 absl::StatusOr<std::unique_ptr<Gurobi>> Gurobi::New(
110  GRBenvUniquePtr primary_env) {
111  if (primary_env == nullptr) {
112  ASSIGN_OR_RETURN(primary_env, GurobiNewPrimaryEnv());
113  }
114  GRBenv* const raw_primary_env = primary_env.get();
115  return New(std::move(primary_env), raw_primary_env);
116 }
117 
118 Gurobi::Gurobi(GRBenvUniquePtr optional_owned_primary_env,
119  GRBmodel* const model, GRBenv* const model_env)
120  : owned_primary_env_(std::move(optional_owned_primary_env)),
121  gurobi_model_(ABSL_DIE_IF_NULL(model)),
122  model_env_(ABSL_DIE_IF_NULL(model_env)) {}
123 
124 absl::StatusOr<std::unique_ptr<Gurobi>> Gurobi::New(
125  GRBenvUniquePtr optional_owned_primary_env, GRBenv* const primary_env) {
126  CHECK(primary_env != nullptr);
127  GRBmodel* model = nullptr;
128  const int err = GRBnewmodel(primary_env, &model,
129  /*Pname=*/nullptr,
130  /*numvars=*/0,
131  /*obj=*/nullptr, /*lb=*/nullptr,
132  /*ub=*/nullptr, /*vtype=*/nullptr,
133  /*varnames=*/nullptr);
134  if (err != kGrbOk) {
136  << "Error creating gurobi model on GRBnewmodel(), error code: "
137  << err << " message: " << GRBgeterrormsg(primary_env);
138  }
139  CHECK(model != nullptr);
140  GRBenv* const model_env = GRBgetenv(model);
141 
142  if (VLOG_IS_ON(3)) {
143  int gurobi_major, gurobi_minor, gurobi_technical;
144  GRBversion(&gurobi_major, &gurobi_minor, &gurobi_technical);
145  VLOG(3) << absl::StrFormat(
146  "Successfully created model for Gurobi v%d.%d.%d (%s)", gurobi_major,
147  gurobi_minor, gurobi_technical, GRBplatform());
148  }
149  return absl::WrapUnique(
150  new Gurobi(std::move(optional_owned_primary_env), model, model_env));
151 }
152 
154  const int err = GRBfreemodel(gurobi_model_);
155  if (err != kGrbOk) {
156  LOG(ERROR) << "Error freeing gurobi model, code: " << err
157  << ", message: " << GRBgeterrormsg(model_env_);
158  }
159 }
160 
161 absl::Status Gurobi::ToStatus(const int grb_err, const absl::StatusCode code,
162  const absl::SourceLocation loc) const {
163  if (grb_err == kGrbOk) {
164  return absl::OkStatus();
165  }
166 
167  return util::StatusBuilder(code)
168  << "Gurobi error code: " << grb_err
169  << ", message: " << GRBgeterrormsg(model_env_);
170 }
171 
172 absl::Status Gurobi::AddVar(const double obj, const double lb, const double ub,
173  const char vtype, const std::string& name) {
174  return AddVar({}, {}, obj, lb, ub, vtype, name);
175 }
176 
177 absl::Status Gurobi::AddVar(const absl::Span<const int> vind,
178  const absl::Span<const double> vval,
179  const double obj, const double lb, const double ub,
180  const char vtype, const std::string& name) {
181  CHECK_EQ(vind.size(), vval.size());
182  const int numnz = static_cast<int>(vind.size());
183  return ToStatus(GRBaddvar(/*model=*/gurobi_model_, /*numnz=*/numnz,
184  /*vind=*/const_cast<int*>(vind.data()),
185  /*vval=*/const_cast<double*>(vval.data()),
186  /*obj=*/obj,
187  /*lb=*/lb,
188  /*ub=*/ub,
189  /*vtype=*/vtype,
190  /*varname=*/name.empty() ? nullptr : name.data()));
191 }
192 
193 absl::Status Gurobi::AddVars(const absl::Span<const double> obj,
194  const absl::Span<const double> lb,
195  const absl::Span<const double> ub,
196  const absl::Span<const char> vtype,
197  const absl::Span<const std::string> names) {
198  return AddVars({}, {}, {}, obj, lb, ub, vtype, names);
199 }
200 
201 absl::Status Gurobi::AddVars(const absl::Span<const int> vbegin,
202  const absl::Span<const int> vind,
203  const absl::Span<const double> vval,
204  const absl::Span<const double> obj,
205  const absl::Span<const double> lb,
206  const absl::Span<const double> ub,
207  const absl::Span<const char> vtype,
208  const absl::Span<const std::string> names) {
209  CHECK_EQ(vind.size(), vval.size());
210  const int num_vars = static_cast<int>(lb.size());
211  CHECK_EQ(ub.size(), num_vars);
212  CHECK_EQ(vtype.size(), num_vars);
213  double* c_obj = nullptr;
214  if (!obj.empty()) {
215  CHECK_EQ(obj.size(), num_vars);
216  c_obj = const_cast<double*>(obj.data());
217  }
218  if (!vbegin.empty()) {
219  CHECK_EQ(vbegin.size(), num_vars);
220  }
221  char** c_names = nullptr;
222  std::vector<char*> c_names_data;
223  if (!names.empty()) {
224  CHECK_EQ(num_vars, names.size());
225  for (const std::string& name : names) {
226  c_names_data.push_back(const_cast<char*>(name.c_str()));
227  }
228  c_names = c_names_data.data();
229  }
230  return ToStatus(GRBaddvars(/*model=*/gurobi_model_, /*numvars=*/num_vars,
231  /*numnz=*/vind.size(),
232  /*vbeg=*/const_cast<int*>(vbegin.data()),
233  /*vind=*/const_cast<int*>(vind.data()),
234  /*vval=*/const_cast<double*>(vval.data()),
235  /*obj=*/c_obj,
236  /*lb=*/const_cast<double*>(lb.data()),
237  /*ub=*/const_cast<double*>(ub.data()),
238  /*vtype=*/const_cast<char*>(vtype.data()),
239  /*varnames=*/c_names));
240 }
241 
242 absl::Status Gurobi::DelVars(const absl::Span<const int> ind) {
243  return ToStatus(
244  GRBdelvars(gurobi_model_, ind.size(), const_cast<int*>(ind.data())));
245 }
246 
247 absl::Status Gurobi::AddConstr(const char sense, const double rhs,
248  const std::string& name) {
249  return AddConstr({}, {}, sense, rhs, name);
250 }
251 
252 absl::Status Gurobi::AddConstr(const absl::Span<const int> cind,
253  const absl::Span<const double> cval,
254  const char sense, const double rhs,
255  const std::string& name) {
256  CHECK_EQ(cind.size(), cval.size());
257  const int numnz = static_cast<int>(cind.size());
258  return ToStatus(
259  GRBaddconstr(/*model=*/gurobi_model_, /*numnz=*/numnz,
260  /*cind=*/const_cast<int*>(cind.data()),
261  /*cval=*/const_cast<double*>(cval.data()),
262  /*sense=*/sense,
263  /*rhs=*/rhs,
264  /*constrname=*/name.empty() ? nullptr : name.data()));
265 }
266 
267 absl::Status Gurobi::AddConstrs(const absl::Span<const char> sense,
268  const absl::Span<const double> rhs,
269  const absl::Span<const std::string> names) {
270  const int num_cons = static_cast<int>(sense.size());
271  CHECK_EQ(rhs.size(), num_cons);
272  char** c_names = nullptr;
273  std::vector<char*> c_names_data;
274  if (!names.empty()) {
275  CHECK_EQ(num_cons, names.size());
276  for (const std::string& name : names) {
277  c_names_data.push_back(const_cast<char*>(name.c_str()));
278  }
279  c_names = c_names_data.data();
280  }
281  return ToStatus(GRBaddconstrs(
282  /*model=*/gurobi_model_,
283  /*numconstrs=*/num_cons,
284  /*numnz=*/0, /*cbeg=*/nullptr, /*cind=*/nullptr,
285  /*cval=*/nullptr, /*sense=*/const_cast<char*>(sense.data()),
286  /*rhs=*/const_cast<double*>(rhs.data()), /*constrnames=*/c_names));
287 }
288 
289 absl::Status Gurobi::DelConstrs(const absl::Span<const int> ind) {
290  return ToStatus(
291  GRBdelconstrs(gurobi_model_, ind.size(), const_cast<int*>(ind.data())));
292 }
293 
294 absl::Status Gurobi::AddQpTerms(const absl::Span<const int> qrow,
295  const absl::Span<const int> qcol,
296  const absl::Span<const double> qval) {
297  const int numqnz = static_cast<int>(qrow.size());
298  CHECK_EQ(qcol.size(), numqnz);
299  CHECK_EQ(qval.size(), numqnz);
300  return ToStatus(GRBaddqpterms(
301  gurobi_model_, numqnz, const_cast<int*>(qcol.data()),
302  const_cast<int*>(qrow.data()), const_cast<double*>(qval.data())));
303 }
304 
305 absl::Status Gurobi::DelQ() { return ToStatus(GRBdelq(gurobi_model_)); }
306 
307 absl::Status Gurobi::SetNthObjective(const int index, const int priority,
308  const double weight, const double abs_tol,
309  const double rel_tol,
310  const std::string& name,
311  const double constant,
312  const absl::Span<const int> lind,
313  const absl::Span<const double> lval) {
314  const int numlnz = static_cast<int>(lind.size());
315  CHECK_EQ(lval.size(), numlnz);
316  return ToStatus(GRBsetobjectiven(
317  /*model=*/gurobi_model_,
318  /*index=*/index,
319  /*priority=*/priority,
320  /*weight=*/weight,
321  /*abstol=*/abs_tol,
322  /*reltol=*/rel_tol,
323  /*name=*/const_cast<char*>(name.c_str()),
324  /*constant=*/constant,
325  /*lnz=*/numlnz,
326  /*lind=*/const_cast<int*>(lind.data()),
327  /*lval=*/const_cast<double*>(lval.data())));
328 }
329 
330 absl::Status Gurobi::AddQConstr(const absl::Span<const int> lind,
331  const absl::Span<const double> lval,
332  const absl::Span<const int> qrow,
333  const absl::Span<const int> qcol,
334  const absl::Span<const double> qval,
335  const char sense, const double rhs,
336  const std::string& name) {
337  const int numlnz = static_cast<int>(lind.size());
338  CHECK_EQ(lval.size(), numlnz);
339 
340  const int numqlnz = static_cast<int>(qrow.size());
341  CHECK_EQ(qcol.size(), numqlnz);
342  CHECK_EQ(qval.size(), numqlnz);
343 
344  return ToStatus(GRBaddqconstr(
345  /*model=*/gurobi_model_,
346  /*numlnz=*/numlnz,
347  /*lind=*/const_cast<int*>(lind.data()),
348  /*lval=*/const_cast<double*>(lval.data()),
349  /*numqlnz=*/numqlnz,
350  /*qrow=*/const_cast<int*>(qrow.data()),
351  /*qcol=*/const_cast<int*>(qcol.data()),
352  /*qval=*/const_cast<double*>(qval.data()),
353  /*sense=*/sense,
354  /*rhs=*/rhs,
355  /*constrname=*/const_cast<char*>(name.c_str())));
356 }
357 
358 absl::Status Gurobi::DelQConstrs(const absl::Span<const int> ind) {
359  return ToStatus(GRBdelqconstrs(gurobi_model_, static_cast<int>(ind.size()),
360  const_cast<int*>(ind.data())));
361 }
362 
363 absl::Status Gurobi::AddSos(const absl::Span<const int> types,
364  const absl::Span<const int> beg,
365  const absl::Span<const int> ind,
366  const absl::Span<const double> weight) {
367  const int num_sos = static_cast<int>(types.size());
368  CHECK_EQ(beg.size(), num_sos);
369 
370  const int num_members = static_cast<int>(ind.size());
371  CHECK_EQ(weight.size(), num_members);
372 
373  return ToStatus(GRBaddsos(/*model=*/gurobi_model_, /*numsos=*/num_sos,
374  /*nummembers=*/num_members,
375  /*types=*/const_cast<int*>(types.data()),
376  /*beg=*/const_cast<int*>(beg.data()),
377  /*ind=*/const_cast<int*>(ind.data()),
378  /*weight=*/const_cast<double*>(weight.data())));
379 }
380 
381 absl::Status Gurobi::DelSos(const absl::Span<const int> ind) {
382  return ToStatus(GRBdelsos(gurobi_model_, static_cast<int>(ind.size()),
383  const_cast<int*>(ind.data())));
384 }
385 
386 absl::Status Gurobi::AddIndicator(const std::string& name, const int binvar,
387  const int binval,
388  const absl::Span<const int> ind,
389  const absl::Span<const double> val,
390  const char sense, const double rhs) {
391  const int nvars = static_cast<int>(ind.size());
392  CHECK_EQ(val.size(), nvars);
393  return ToStatus(GRBaddgenconstrIndicator(
394  /*model=*/gurobi_model_, /*name=*/const_cast<char*>(name.c_str()),
395  /*binvar=*/binvar, /*binval=*/binval, /*nvars=*/nvars,
396  /*ind=*/const_cast<int*>(ind.data()),
397  /*val=*/const_cast<double*>(val.data()), /*sense=*/sense, /*rhs=*/rhs));
398 }
399 
400 absl::Status Gurobi::DelGenConstrs(const absl::Span<const int> ind) {
401  return ToStatus(GRBdelgenconstrs(gurobi_model_, static_cast<int>(ind.size()),
402  const_cast<int*>(ind.data())));
403 }
404 
405 absl::Status Gurobi::ChgCoeffs(const absl::Span<const int> cind,
406  const absl::Span<const int> vind,
407  const absl::Span<const double> val) {
408  const int num_changes = static_cast<int>(cind.size());
409  CHECK_EQ(vind.size(), num_changes);
410  CHECK_EQ(val.size(), num_changes);
411  return ToStatus(GRBchgcoeffs(
412  gurobi_model_, num_changes, const_cast<int*>(cind.data()),
413  const_cast<int*>(vind.data()), const_cast<double*>(val.data())));
414 }
415 
416 absl::StatusOr<int> Gurobi::GetNnz(const int first_var, const int num_vars) {
417  int nnz = 0;
418  RETURN_IF_ERROR(ToStatus(GRBgetvars(gurobi_model_, &nnz, nullptr, nullptr,
419  nullptr, first_var, num_vars)));
420  return nnz;
421 }
422 
423 absl::Status Gurobi::GetVars(const absl::Span<int> vbegin,
424  const absl::Span<int> vind,
425  const absl::Span<double> vval, const int first_var,
426  const int num_vars) {
427  CHECK_EQ(vbegin.size(), num_vars);
428  CHECK_EQ(vind.size(), vval.size());
429  int nnz = 0;
431  ToStatus(GRBgetvars(gurobi_model_, &nnz, vbegin.data(), vind.data(),
432  vval.data(), first_var, num_vars)));
433  CHECK_EQ(nnz, vind.size());
434  return absl::OkStatus();
435 }
436 
437 absl::StatusOr<Gurobi::SparseMat> Gurobi::GetVars(const int first_var,
438  const int num_vars) {
439  SparseMat result;
440  ASSIGN_OR_RETURN(const int nnz, GetNnz(first_var, num_vars));
441  result.begins.resize(num_vars);
442  result.inds.resize(nnz);
443  result.vals.resize(nnz);
444  int read_nnz = 0;
445  RETURN_IF_ERROR(ToStatus(
446  GRBgetvars(gurobi_model_, &read_nnz, result.begins.data(),
447  result.inds.data(), result.vals.data(), first_var, num_vars)));
448  CHECK_EQ(read_nnz, nnz);
449  return result;
450 }
451 
452 absl::Status Gurobi::UpdateModel() {
453  return ToStatus(GRBupdatemodel(gurobi_model_));
454 }
455 
456 absl::Status Gurobi::Optimize(Callback cb) {
457  bool needs_cb_cleanup = false;
458  UserCallbackData user_cb_data;
459  if (cb != nullptr) {
460  user_cb_data.user_cb = std::move(cb);
461  user_cb_data.gurobi = this;
462  RETURN_IF_ERROR(ToStatus(
463  GRBsetcallbackfunc(gurobi_model_, GurobiCallback, &user_cb_data)));
464  needs_cb_cleanup = true;
465  }
466 
467  // Failsafe to try and clear the callback if there is another error. We cannot
468  // raise an error in a destructor, we can only log it.
469  auto callback_cleanup = absl::MakeCleanup([&]() {
470  if (needs_cb_cleanup) {
471  int error = GRBsetcallbackfunc(gurobi_model_, nullptr, nullptr);
472  if (error != kGrbOk) {
473  LOG(ERROR) << "Error cleaning up callback";
474  }
475  }
476  });
477  absl::Status solve_status = ToStatus(GRBoptimize(gurobi_model_));
478  RETURN_IF_ERROR(user_cb_data.status) << "Error in Optimize callback.";
479  RETURN_IF_ERROR(solve_status);
480  if (needs_cb_cleanup) {
481  needs_cb_cleanup = false;
483  ToStatus(GRBsetcallbackfunc(gurobi_model_, nullptr, nullptr)));
484  }
485  return absl::OkStatus();
486 }
487 
488 bool Gurobi::IsAttrAvailable(const char* name) const {
489  return GRBisattravailable(gurobi_model_, name) > 0;
490 }
491 
492 absl::StatusOr<int> Gurobi::GetIntAttr(const char* const name) const {
493  int result;
494  RETURN_IF_ERROR(ToStatus(GRBgetintattr(gurobi_model_, name, &result)))
495  << "Error getting Gurobi int attribute: " << name;
496  return result;
497 }
498 
499 absl::StatusOr<double> Gurobi::GetDoubleAttr(const char* const name) const {
500  double result;
501  RETURN_IF_ERROR(ToStatus(GRBgetdblattr(gurobi_model_, name, &result)))
502  << "Error getting Gurobi double attribute: " << name;
503  return result;
504 }
505 
506 absl::StatusOr<std::string> Gurobi::GetStringAttr(
507  const char* const name) const {
508  // WARNING: if a string attribute is the empty string, we need to be careful,
509  // std::string(char*) cannot take a nullptr.
510  char* result = nullptr;
511  RETURN_IF_ERROR(ToStatus(GRBgetstrattr(gurobi_model_, name, &result)))
512  << "Error getting Gurobi string attribute: " << name;
513  if (result == nullptr) {
514  return std::string();
515  }
516  return std::string(result);
517 }
518 
519 absl::Status Gurobi::SetStringAttr(const char* const attr_name,
520  const std::string& value) {
521  return ToStatus(GRBsetstrattr(gurobi_model_, attr_name, value.c_str()));
522 }
523 
524 absl::Status Gurobi::SetIntAttr(const char* const attr_name, const int value) {
525  return ToStatus(GRBsetintattr(gurobi_model_, attr_name, value));
526 }
527 
528 absl::Status Gurobi::SetDoubleAttr(const char* const attr_name,
529  const double value) {
530  return ToStatus(GRBsetdblattr(gurobi_model_, attr_name, value));
531 }
532 
533 absl::Status Gurobi::SetIntAttrArray(const char* const name,
534  const absl::Span<const int> new_values) {
535  return ToStatus(GRBsetintattrarray(gurobi_model_, name, 0, new_values.size(),
536  const_cast<int*>(new_values.data())));
537 }
538 
540  const char* const name, const absl::Span<const double> new_values) {
541  return ToStatus(GRBsetdblattrarray(gurobi_model_, name, 0, new_values.size(),
542  const_cast<double*>(new_values.data())));
543 }
544 
545 absl::Status Gurobi::SetCharAttrArray(const char* const name,
546  const absl::Span<const char> new_values) {
547  return ToStatus(GRBsetcharattrarray(gurobi_model_, name, 0, new_values.size(),
548  const_cast<char*>(new_values.data())));
549 }
550 
551 absl::Status Gurobi::GetIntAttrArray(const char* const name,
552  const absl::Span<int> attr_out) const {
554  gurobi_model_, name, 0, attr_out.size(), attr_out.data())))
555  << "Error getting Gurobi int array attribute: " << name;
556  return absl::OkStatus();
557 }
558 
559 absl::StatusOr<std::vector<int>> Gurobi::GetIntAttrArray(const char* const name,
560  const int len) const {
561  std::vector<int> result(len);
562  RETURN_IF_ERROR(GetIntAttrArray(name, absl::MakeSpan(result)));
563  return result;
564 }
565 
567  const char* const name, const absl::Span<double> attr_out) const {
569  gurobi_model_, name, 0, attr_out.size(), attr_out.data())))
570  << "Error getting Gurobi double array attribute: " << name;
571  return absl::OkStatus();
572 }
573 
574 absl::StatusOr<std::vector<double>> Gurobi::GetDoubleAttrArray(
575  const char* const name, const int len) const {
576  std::vector<double> result(len);
577  RETURN_IF_ERROR(GetDoubleAttrArray(name, absl::MakeSpan(result)));
578  return result;
579 }
580 
581 absl::Status Gurobi::GetCharAttrArray(const char* const name,
582  const absl::Span<char> attr_out) const {
584  gurobi_model_, name, 0, attr_out.size(), attr_out.data())))
585  << "Error getting Gurobi char array attribute: " << name;
586  return absl::OkStatus();
587 }
588 
589 absl::StatusOr<std::vector<char>> Gurobi::GetCharAttrArray(
590  const char* const name, const int len) const {
591  std::vector<char> result(len);
592  RETURN_IF_ERROR(GetCharAttrArray(name, absl::MakeSpan(result)));
593  return result;
594 }
595 
596 absl::Status Gurobi::SetIntAttrList(const char* const name,
597  const absl::Span<const int> ind,
598  const absl::Span<const int> new_values) {
599  const int len = static_cast<int>(ind.size());
600  CHECK_EQ(new_values.size(), len);
601  return ToStatus(GRBsetintattrlist(gurobi_model_, name, len,
602  const_cast<int*>(ind.data()),
603  const_cast<int*>(new_values.data())));
604 }
605 
607  const char* const name, const absl::Span<const int> ind,
608  const absl::Span<const double> new_values) {
609  const int len = static_cast<int>(ind.size());
610  CHECK_EQ(new_values.size(), len);
611  return ToStatus(GRBsetdblattrlist(gurobi_model_, name, len,
612  const_cast<int*>(ind.data()),
613  const_cast<double*>(new_values.data())));
614 }
615 
616 absl::Status Gurobi::SetCharAttrList(const char* const name,
617  const absl::Span<const int> ind,
618  const absl::Span<const char> new_values) {
619  const int len = static_cast<int>(ind.size());
620  CHECK_EQ(new_values.size(), len);
621  return ToStatus(GRBsetcharattrlist(gurobi_model_, name, len,
622  const_cast<int*>(ind.data()),
623  const_cast<char*>(new_values.data())));
624 }
625 
626 absl::StatusOr<double> Gurobi::GetDoubleAttrElement(const char* const name,
627  const int element) const {
628  double value;
630  ToStatus(GRBgetdblattrelement(gurobi_model_, name, element, &value)));
631  return value;
632 }
633 
634 absl::Status Gurobi::SetDoubleAttrElement(const char* const name, int element,
635  double new_value) {
636  return ToStatus(
637  GRBsetdblattrelement(gurobi_model_, name, element, new_value));
638 }
639 
640 absl::StatusOr<char> Gurobi::GetCharAttrElement(const char* const name,
641  const int element) const {
642  char value;
644  ToStatus(GRBgetcharattrelement(gurobi_model_, name, element, &value)));
645  return value;
646 }
647 
648 absl::Status Gurobi::SetCharAttrElement(const char* const name,
649  const int element,
650  const char new_value) {
651  return ToStatus(
652  GRBsetcharattrelement(gurobi_model_, name, element, new_value));
653 }
654 
655 absl::Status Gurobi::SetParam(const char* const name,
656  const std::string& value) {
657  return ToStatus(GRBsetparam(model_env_, name, value.c_str()));
658 }
659 
660 absl::Status Gurobi::SetIntParam(const char* const name, const int value) {
661  return ToStatus(GRBsetintparam(model_env_, name, value));
662 }
663 
664 absl::Status Gurobi::SetDoubleParam(const char* const name,
665  const double value) {
666  return ToStatus(GRBsetdblparam(model_env_, name, value));
667 }
668 
669 absl::Status Gurobi::SetStringParam(const char* const name,
670  const std::string& value) {
671  return ToStatus(GRBsetstrparam(model_env_, name, value.c_str()));
672 }
673 
674 absl::StatusOr<int> Gurobi::GetIntParam(const char* const name) {
675  int result;
676  RETURN_IF_ERROR(ToStatus(GRBgetintparam(model_env_, name, &result)));
677  return result;
678 }
679 
680 absl::StatusOr<double> Gurobi::GetDoubleParam(const char* const name) {
681  double result;
682  RETURN_IF_ERROR(ToStatus(GRBgetdblparam(model_env_, name, &result)));
683  return result;
684 }
685 
686 absl::StatusOr<std::string> Gurobi::GetStringParam(const char* const name) {
687  std::vector<char> result(GRB_MAX_STRLEN);
688  RETURN_IF_ERROR(ToStatus(GRBgetstrparam(model_env_, name, result.data())));
689  return std::string(result.data());
690 }
691 
692 absl::Status Gurobi::ResetParameters() {
693  return ToStatus(GRBresetparams(model_env_));
694 }
695 
696 void Gurobi::Terminate() { GRBterminate(gurobi_model_); }
697 
699  void* const cb_data, const int where)
700  : gurobi_(ABSL_DIE_IF_NULL(gurobi)), cb_data_(cb_data), where_(where) {}
701 
702 absl::StatusOr<int> Gurobi::CallbackContext::CbGetInt(const int what) const {
703  int result;
704  RETURN_IF_ERROR(gurobi_->ToStatus(
705  GRBcbget(cb_data_, where_, what, static_cast<void*>(&result))));
706  return result;
707 }
708 
710  const int what) const {
711  double result;
712  RETURN_IF_ERROR(gurobi_->ToStatus(
713  GRBcbget(cb_data_, where_, what, static_cast<void*>(&result))));
714  return result;
715 }
716 
718  const int what, const absl::Span<double> result) const {
719  return gurobi_->ToStatus(
720  GRBcbget(cb_data_, where_, what, static_cast<void*>(result.data())));
721 }
722 
723 absl::StatusOr<std::string> Gurobi::CallbackContext::CbGetMessage() const {
724  char* result = nullptr;
725  RETURN_IF_ERROR(gurobi_->ToStatus(GRBcbget(
726  cb_data_, where_, GRB_CB_MSG_STRING, static_cast<void*>(&result))));
727  if (result == nullptr) {
728  return std::string();
729  }
730  return std::string(result);
731 }
732 
734  const absl::Span<const int> cutind, const absl::Span<const double> cutval,
735  const char cutsense, const double cutrhs) const {
736  const int cut_len = static_cast<int>(cutind.size());
737  CHECK_EQ(cutval.size(), cut_len);
738  return gurobi_->ToStatus(
739  GRBcbcut(cb_data_, cut_len, const_cast<int*>(cutind.data()),
740  const_cast<double*>(cutval.data()), cutsense, cutrhs));
741 }
742 
744  const absl::Span<const int> lazyind, const absl::Span<const double> lazyval,
745  const char lazysense, const double lazyrhs) const {
746  const int lazy_len = static_cast<int>(lazyind.size());
747  CHECK_EQ(lazyval.size(), lazy_len);
748  return gurobi_->ToStatus(
749  GRBcblazy(cb_data_, lazy_len, const_cast<int*>(lazyind.data()),
750  const_cast<double*>(lazyval.data()), lazysense, lazyrhs));
751 }
752 
753 absl::StatusOr<double> Gurobi::CallbackContext::CbSolution(
754  const absl::Span<const double> solution) const {
755  double result;
756  RETURN_IF_ERROR(gurobi_->ToStatus(
757  GRBcbsolution(cb_data_, const_cast<double*>(solution.data()), &result)));
758  return result;
759 }
760 
761 } // namespace operations_research::math_opt
#define ASSIGN_OR_RETURN(lhs, rexpr)
#define RETURN_IF_ERROR(expr)
absl::StatusOr< double > CbGetDouble(int what) const
Definition: g_gurobi.cc:709
absl::StatusOr< double > CbSolution(absl::Span< const double > solution) const
Definition: g_gurobi.cc:753
CallbackContext(Gurobi *gurobi, void *cb_data, int where)
Definition: g_gurobi.cc:698
absl::Status CbGetDoubleArray(int what, absl::Span< double > result) const
Definition: g_gurobi.cc:717
absl::Status CbCut(absl::Span< const int > cutind, absl::Span< const double > cutval, char cutsense, double cutrhs) const
Definition: g_gurobi.cc:733
absl::StatusOr< std::string > CbGetMessage() const
Definition: g_gurobi.cc:723
absl::StatusOr< int > CbGetInt(int what) const
Definition: g_gurobi.cc:702
absl::Status CbLazy(absl::Span< const int > lazyind, absl::Span< const double > lazyval, char lazysense, double lazyrhs) const
Definition: g_gurobi.cc:743
absl::Status AddConstr(char sense, double rhs, const std::string &name)
Definition: g_gurobi.cc:247
absl::Status GetVars(absl::Span< int > vbegin, absl::Span< int > vind, absl::Span< double > vval, int first_var, int num_vars)
Definition: g_gurobi.cc:423
absl::Status AddVar(double obj, double lb, double ub, char vtype, const std::string &name)
Definition: g_gurobi.cc:172
absl::Status GetIntAttrArray(const char *name, absl::Span< int > attr_out) const
Definition: g_gurobi.cc:551
absl::Status SetCharAttrElement(const char *name, int element, char new_value)
Definition: g_gurobi.cc:648
absl::Status DelQConstrs(const absl::Span< const int > ind)
Definition: g_gurobi.cc:358
absl::Status AddConstrs(absl::Span< const char > sense, absl::Span< const double > rhs, absl::Span< const std::string > names)
Definition: g_gurobi.cc:267
absl::StatusOr< double > GetDoubleAttrElement(const char *name, int element) const
Definition: g_gurobi.cc:626
absl::StatusOr< double > GetDoubleParam(const char *name)
Definition: g_gurobi.cc:680
absl::Status Optimize(Callback cb=nullptr)
Definition: g_gurobi.cc:456
absl::Status ChgCoeffs(absl::Span< const int > cind, absl::Span< const int > vind, absl::Span< const double > val)
Definition: g_gurobi.cc:405
absl::Status DelGenConstrs(absl::Span< const int > ind)
Definition: g_gurobi.cc:400
absl::StatusOr< int > GetIntParam(const char *name)
Definition: g_gurobi.cc:674
absl::Status SetDoubleAttr(const char *attr_name, double value)
Definition: g_gurobi.cc:528
absl::Status AddQpTerms(absl::Span< const int > qrow, absl::Span< const int > qcol, absl::Span< const double > qval)
Definition: g_gurobi.cc:294
absl::StatusOr< int > GetNnz(int first_var, int num_vars)
Definition: g_gurobi.cc:416
absl::Status SetDoubleParam(const char *name, double value)
Definition: g_gurobi.cc:664
std::function< absl::Status(const CallbackContext &)> Callback
Definition: g_gurobi.h:228
absl::Status AddIndicator(const std::string &name, int binvar, int binval, absl::Span< const int > ind, absl::Span< const double > val, char sense, double rhs)
Definition: g_gurobi.cc:386
absl::Status SetIntAttr(const char *attr_name, int value)
Definition: g_gurobi.cc:524
static absl::StatusOr< std::unique_ptr< Gurobi > > NewWithSharedPrimaryEnv(GRBenv *primary_env)
Definition: g_gurobi.cc:103
absl::StatusOr< std::string > GetStringParam(const char *name)
Definition: g_gurobi.cc:686
absl::Status SetDoubleAttrElement(const char *name, int element, double new_value)
Definition: g_gurobi.cc:634
absl::Status GetCharAttrArray(const char *name, absl::Span< char > attr_out) const
Definition: g_gurobi.cc:581
absl::Status SetCharAttrArray(const char *name, absl::Span< const char > new_values)
Definition: g_gurobi.cc:545
absl::StatusOr< int > GetIntAttr(const char *name) const
Definition: g_gurobi.cc:492
static absl::StatusOr< std::unique_ptr< Gurobi > > New(GRBenvUniquePtr primary_env=nullptr)
Definition: g_gurobi.cc:109
absl::Status DelVars(absl::Span< const int > ind)
Definition: g_gurobi.cc:242
absl::StatusOr< std::string > GetStringAttr(const char *name) const
Definition: g_gurobi.cc:506
absl::Status SetIntAttrList(const char *name, absl::Span< const int > ind, absl::Span< const int > new_values)
Definition: g_gurobi.cc:596
absl::Status GetDoubleAttrArray(const char *name, absl::Span< double > attr_out) const
Definition: g_gurobi.cc:566
absl::Status DelSos(absl::Span< const int > ind)
Definition: g_gurobi.cc:381
absl::Status SetDoubleAttrArray(const char *name, absl::Span< const double > new_values)
Definition: g_gurobi.cc:539
absl::Status SetParam(const char *name, const std::string &value)
Definition: g_gurobi.cc:655
bool IsAttrAvailable(const char *name) const
Definition: g_gurobi.cc:488
absl::Status SetDoubleAttrList(const char *name, absl::Span< const int > ind, absl::Span< const double > new_values)
Definition: g_gurobi.cc:606
absl::StatusOr< double > GetDoubleAttr(const char *name) const
Definition: g_gurobi.cc:499
absl::Status SetNthObjective(int index, int priority, double weight, double abs_tol, double rel_tol, const std::string &name, double constant, absl::Span< const int > lind, absl::Span< const double > lval)
Definition: g_gurobi.cc:307
absl::Status AddSos(absl::Span< const int > types, absl::Span< const int > beg, absl::Span< const int > ind, absl::Span< const double > weight)
Definition: g_gurobi.cc:363
absl::Status SetIntParam(const char *name, int value)
Definition: g_gurobi.cc:660
absl::Status SetIntAttrArray(const char *name, absl::Span< const int > new_values)
Definition: g_gurobi.cc:533
absl::Status SetStringParam(const char *name, const std::string &value)
Definition: g_gurobi.cc:669
absl::Status DelConstrs(absl::Span< const int > ind)
Definition: g_gurobi.cc:289
absl::Status SetStringAttr(const char *attr_name, const std::string &value)
Definition: g_gurobi.cc:519
absl::Status AddVars(absl::Span< const double > obj, absl::Span< const double > lb, absl::Span< const double > ub, absl::Span< const char > vtype, absl::Span< const std::string > names)
Definition: g_gurobi.cc:193
absl::StatusOr< char > GetCharAttrElement(const char *name, int element) const
Definition: g_gurobi.cc:640
absl::Status SetCharAttrList(const char *name, absl::Span< const int > ind, absl::Span< const char > new_values)
Definition: g_gurobi.cc:616
absl::Status AddQConstr(absl::Span< const int > lind, absl::Span< const double > lval, absl::Span< const int > qrow, absl::Span< const int > qcol, absl::Span< const double > qval, char sense, double rhs, const std::string &name)
Definition: g_gurobi.cc:330
const std::string name
int64_t value
#define GRB_ERROR_CALLBACK
Definition: environment.h:79
struct _GRBenv GRBenv
Definition: environment.h:32
#define GRB_CB_MSG_STRING
Definition: environment.h:402
#define GRB_MAX_STRLEN
Definition: environment.h:117
struct _GRBmodel GRBmodel
Definition: environment.h:31
absl::Status status
Definition: g_gurobi.cc:41
Gurobi::Callback user_cb
Definition: g_gurobi.cc:40
Gurobi * gurobi
Definition: g_gurobi.cc:42
GRBmodel * model
GurobiMPCallbackContext * context
int where
int index
absl::Cleanup< absl::decay_t< Callback > > MakeCleanup(Callback &&callback)
Definition: cleanup.h:125
absl::StatusOr< GRBenvUniquePtr > GurobiNewPrimaryEnv(const std::optional< GurobiIsvKey > &isv_key)
Definition: g_gurobi.cc:72
std::unique_ptr< GRBenv, GurobiFreeEnv > GRBenvUniquePtr
Definition: g_gurobi.h:69
std::function< int(GRBmodel *model, const char *attrname, int element, char *valueP)> GRBgetcharattrelement
Definition: environment.cc:73
std::function< int(GRBenv *env, const char *paramname, int *valueP)> GRBgetintparam
Definition: environment.cc:194
std::function< int(GRBmodel *model, int numnz, int *cind, double *cval, char sense, double rhs, const char *constrname)> GRBaddconstr
Definition: environment.cc:141
std::function< int(GRBmodel *model, const char *attrname, double *valueP)> GRBgetdblattr
Definition: environment.cc:87
std::function< int(GRBmodel *model, int numlnz, int *lind, double *lval, int numqnz, int *qrow, int *qcol, double *qval, char sense, double rhs, const char *QCname)> GRBaddqconstr
Definition: environment.cc:173
std::function< int(GRBmodel *model, const char *attrname, int len, int *ind, double *newvalues)> GRBsetdblattrlist
Definition: environment.cc:104
std::function< int(GRBmodel *model, int numnz, int *vind, double *vval, double obj, double lb, double ub, char vtype, const char *varname)> GRBaddvar
Definition: environment.cc:134
std::function< char *(void)> GRBplatform
Definition: environment.cc:215
std::function< int(GRBmodel *model, int len, int *ind)> GRBdelgenconstrs
Definition: environment.cc:180
std::function< void(int *majorP, int *minorP, int *technicalP)> GRBversion
Definition: environment.cc:213
std::function< int(GRBenv *env, const char *paramname, const char *value)> GRBsetparam
Definition: environment.cc:200
std::function< int(GRBmodel *model, const char *attrname, int newvalue)> GRBsetintattr
Definition: environment.cc:55
std::function< int(GRBenv *env, const char *paramname, char *valueP)> GRBgetstrparam
Definition: environment.cc:198
std::function< int(void *cbdata, int lazylen, const int *lazyind, const double *lazyval, char lazysense, double lazyrhs)> GRBcblazy
Definition: environment.cc:121
std::function< int(GRBmodel *model, const char *attrname, int first, int len, int *values)> GRBgetintattrarray
Definition: environment.cc:64
std::function< int(GRBmodel *model, int numconstrs, int numnz, int *cbeg, int *cind, double *cval, char *sense, double *rhs, char **constrnames)> GRBaddconstrs
Definition: environment.cc:145
std::function< int(GRBenv *env, const char *paramname, int value)> GRBsetintparam
Definition: environment.cc:202
std::function< int(void *cbdata, int where, int what, void *resultP)> GRBcbget
Definition: environment.cc:112
std::function< int(GRBmodel *model, int index, int priority, double weight, double abstol, double reltol, const char *name, double constant, int lnz, int *lind, double *lval)> GRBsetobjectiven
Definition: environment.cc:192
std::function< int(GRBmodel *model, const char *attrname, int first, int len, char *values)> GRBgetcharattrarray
Definition: environment.cc:79
std::function< int(GRBenv **envP, const char *logfilename)> GRBloadenv
Definition: environment.cc:209
std::function< int(GRBmodel *model, const char *attrname, int first, int len, double *newvalues)> GRBsetdblattrarray
Definition: environment.cc:101
std::function< int(GRBmodel *model)> GRBfreemodel
Definition: environment.cc:187
std::function< void(GRBmodel *model)> GRBterminate
Definition: environment.cc:188
std::function< int(GRBmodel *model, int numqnz, int *qrow, int *qcol, double *qval)> GRBaddqpterms
Definition: environment.cc:176
std::function< int(GRBenv *env, const char *paramname, double *valueP)> GRBgetdblparam
Definition: environment.cc:196
std::function< const char *(GRBenv *env)> GRBgeterrormsg
Definition: environment.cc:212
std::function< int(GRBmodel *model, int cnt, int *cind, int *vind, double *val)> GRBchgcoeffs
Definition: environment.cc:185
std::function< GRBenv *(GRBmodel *model)> GRBgetenv
Definition: environment.cc:210
std::function< int(GRBmodel *model, int len, int *ind)> GRBdelconstrs
Definition: environment.cc:178
std::function< int(GRBenv *env, const char *paramname, const char *value)> GRBsetstrparam
Definition: environment.cc:206
std::function< int(GRBmodel *model, const char *attrname, int element, double newvalue)> GRBsetdblattrelement
Definition: environment.cc:95
std::function< int(GRBenv *env)> GRBresetparams
Definition: environment.cc:207
std::function< int(GRBmodel *model, const char *attrname, int first, int len, double *values)> GRBgetdblattrarray
Definition: environment.cc:98
std::function< int(GRBmodel *model, int len, int *ind)> GRBdelqconstrs
Definition: environment.cc:182
std::function< int(GRBmodel *model)> GRBupdatemodel
Definition: environment.cc:186
std::function< int(GRBmodel *model)> GRBdelq
Definition: environment.cc:183
std::function< int(GRBmodel *model, const char *attrname, int element, char newvalue)> GRBsetcharattrelement
Definition: environment.cc:76
std::function< int(GRBmodel *model, const char *attrname, const char *newvalue)> GRBsetstrattr
Definition: environment.cc:108
std::function< int(GRBmodel *model, const char *attrname, int element, double *valueP)> GRBgetdblattrelement
Definition: environment.cc:92
std::function< int(GRBmodel *model, int len, int *ind)> GRBdelsos
Definition: environment.cc:179
std::function< int(void *cbdata, const double *solution, double *objvalP)> GRBcbsolution
Definition: environment.cc:115
std::function< int(GRBmodel *model, const char *attrname)> GRBisattravailable
Definition: environment.cc:50
std::function< int(GRBmodel *model)> GRBoptimize
Definition: environment.cc:125
std::function< int(GRBenv **, const char *, const char *, const char *, int, const char *)> GRBisqp
Definition: environment.cc:49
std::function< int(GRBmodel *model, int len, int *ind)> GRBdelvars
Definition: environment.cc:177
std::function< int(GRBmodel *model, const char *attrname, int len, int *ind, char *newvalues)> GRBsetcharattrlist
Definition: environment.cc:85
std::function< int(GRBmodel *model, const char *attrname, char **valueP)> GRBgetstrattr
Definition: environment.cc:106
std::function< int(GRBenv *env, GRBmodel **modelP, const char *Pname, int numvars, double *obj, double *lb, double *ub, char *vtype, char **varnames)> GRBnewmodel
Definition: environment.cc:130
std::function< void(GRBenv *env)> GRBfreeenv
Definition: environment.cc:211
std::function< int(GRBmodel *model, const char *attrname, int len, int *ind, int *newvalues)> GRBsetintattrlist
Definition: environment.cc:70
std::function< int(GRBmodel *model, int numsos, int nummembers, int *types, int *beg, int *ind, double *weight)> GRBaddsos
Definition: environment.cc:151
std::function< int(void *cbdata, int cutlen, const int *cutind, const double *cutval, char cutsense, double cutrhs)> GRBcbcut
Definition: environment.cc:118
std::function< int(GRBmodel *model, const char *attrname, double newvalue)> GRBsetdblattr
Definition: environment.cc:89
std::function< int(GRBmodel *model, const char *attrname, int first, int len, int *newvalues)> GRBsetintattrarray
Definition: environment.cc:67
std::function< int(GRBmodel *model, int(GUROBI_STDCALL *cb)(CB_ARGS), void *usrdata)> GRBsetcallbackfunc
Definition: environment.cc:111
std::function< int(GRBmodel *model, int *numnzP, int *vbeg, int *vind, double *vval, int start, int len)> GRBgetvars
Definition: environment.cc:124
std::function< int(GRBmodel *model, int numvars, int numnz, int *vbeg, int *vind, double *vval, double *obj, double *lb, double *ub, char *vtype, char **varnames)> GRBaddvars
Definition: environment.cc:138
std::function< int(GRBmodel *model, const char *attrname, int first, int len, char *newvalues)> GRBsetcharattrarray
Definition: environment.cc:82
std::function< int(GRBmodel *model, const char *name, int binvar, int binval, int nvars, const int *vars, const double *vals, char sense, double rhs)> GRBaddgenconstrIndicator
Definition: environment.cc:169
std::function< int(GRBmodel *model, const char *attrname, int *valueP)> GRBgetintattr
Definition: environment.cc:53
std::function< int(GRBenv *env, const char *paramname, double value)> GRBsetdblparam
Definition: environment.cc:204
StatusBuilder InvalidArgumentErrorBuilder()
int64_t weight
Definition: pack.cc:510
void operator()(GRBenv *const env) const
Definition: g_gurobi.cc:66
#define VLOG(verboselevel)
Definition: vlog.h:39
#define VLOG_IS_ON(verboselevel)
Definition: vlog_is_on.h:47