OR-Tools  8.2
gurobi_proto_solver.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 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 <limits>
17 #include <memory>
18 #include <numeric>
19 #include <string>
20 #include <vector>
21 
22 #include "absl/status/status.h"
23 #include "absl/status/statusor.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/str_format.h"
26 #include "absl/strings/str_join.h"
27 #include "absl/strings/str_split.h"
28 #include "absl/types/optional.h"
29 #include "ortools/base/cleanup.h"
32 #include "ortools/linear_solver/linear_solver.pb.h"
35 
36 namespace operations_research {
37 
38 namespace {
39 constexpr int GRB_OK = 0;
40 
41 inline absl::Status GurobiCodeToUtilStatus(int error_code,
42  const char* source_file,
43  int source_line,
44  const char* statement,
45  GRBenv* const env) {
46  if (error_code == GRB_OK) return absl::OkStatus();
47  return absl::InvalidArgumentError(absl::StrFormat(
48  "Gurobi error code %d (file '%s', line %d) on '%s': %s", error_code,
49  source_file, source_line, statement, GRBgeterrormsg(env)));
50 }
51 
52 int AddIndicatorConstraint(const MPGeneralConstraintProto& gen_cst,
53  GRBmodel* gurobi_model,
54  std::vector<int>* tmp_variables,
55  std::vector<double>* tmp_coefficients) {
56  CHECK(gurobi_model != nullptr);
57  CHECK(tmp_variables != nullptr);
58  CHECK(tmp_coefficients != nullptr);
59 
60  const auto& ind_cst = gen_cst.indicator_constraint();
61  MPConstraintProto cst = ind_cst.constraint();
62  if (cst.lower_bound() > -std::numeric_limits<double>::infinity()) {
63  int status = GRBaddgenconstrIndicator(
64  gurobi_model, gen_cst.name().c_str(), ind_cst.var_index(),
65  ind_cst.var_value(), cst.var_index_size(),
66  cst.mutable_var_index()->mutable_data(),
67  cst.mutable_coefficient()->mutable_data(),
68  cst.upper_bound() == cst.lower_bound() ? GRB_EQUAL : GRB_GREATER_EQUAL,
69  cst.lower_bound());
70  if (status != GRB_OK) return status;
71  }
72  if (cst.upper_bound() < std::numeric_limits<double>::infinity() &&
73  cst.lower_bound() != cst.upper_bound()) {
74  return GRBaddgenconstrIndicator(gurobi_model, gen_cst.name().c_str(),
75  ind_cst.var_index(), ind_cst.var_value(),
76  cst.var_index_size(),
77  cst.mutable_var_index()->mutable_data(),
78  cst.mutable_coefficient()->mutable_data(),
79  GRB_LESS_EQUAL, cst.upper_bound());
80  }
81 
82  return GRB_OK;
83 }
84 
85 int AddSosConstraint(const MPSosConstraint& sos_cst, GRBmodel* gurobi_model,
86  std::vector<int>* tmp_variables,
87  std::vector<double>* tmp_weights) {
88  CHECK(gurobi_model != nullptr);
89  CHECK(tmp_variables != nullptr);
90  CHECK(tmp_weights != nullptr);
91 
92  tmp_variables->resize(sos_cst.var_index_size(), 0);
93  for (int v = 0; v < sos_cst.var_index_size(); ++v) {
94  (*tmp_variables)[v] = sos_cst.var_index(v);
95  }
96  tmp_weights->resize(sos_cst.var_index_size(), 0);
97  if (sos_cst.weight_size() == sos_cst.var_index_size()) {
98  for (int w = 0; w < sos_cst.weight_size(); ++w) {
99  (*tmp_weights)[w] = sos_cst.weight(w);
100  }
101  } else {
102  DCHECK_EQ(sos_cst.weight_size(), 0);
103  // Gurobi requires variable weights in their SOS constraints.
104  std::iota(tmp_weights->begin(), tmp_weights->end(), 1);
105  }
106 
107  std::vector<int> types = {sos_cst.type() == MPSosConstraint::SOS1_DEFAULT
108  ? GRB_SOS_TYPE1
109  : GRB_SOS_TYPE2};
110  std::vector<int> begins = {0};
111  return GRBaddsos(gurobi_model, /*numsos=*/1,
112  /*nummembers=*/sos_cst.var_index_size(),
113  /*types=*/types.data(),
114  /*beg=*/begins.data(), /*ind=*/tmp_variables->data(),
115  /*weight*/ tmp_weights->data());
116 }
117 
118 int AddQuadraticConstraint(const MPGeneralConstraintProto& gen_cst,
119  GRBmodel* gurobi_model) {
120  CHECK(gurobi_model != nullptr);
121  constexpr double kInfinity = std::numeric_limits<double>::infinity();
122 
123  CHECK(gen_cst.has_quadratic_constraint());
124  const MPQuadraticConstraint& quad_cst = gen_cst.quadratic_constraint();
125 
126  auto addqconstr = [](GRBmodel* gurobi_model, MPQuadraticConstraint quad_cst,
127  char sense, double rhs, const std::string& name) {
128  return GRBaddqconstr(
129  gurobi_model,
130  /*numlnz=*/quad_cst.var_index_size(),
131  /*lind=*/quad_cst.mutable_var_index()->mutable_data(),
132  /*lval=*/quad_cst.mutable_coefficient()->mutable_data(),
133  /*numqnz=*/quad_cst.qvar1_index_size(),
134  /*qrow=*/quad_cst.mutable_qvar1_index()->mutable_data(),
135  /*qcol=*/quad_cst.mutable_qvar2_index()->mutable_data(),
136  /*qval=*/quad_cst.mutable_qcoefficient()->mutable_data(),
137  /*sense=*/sense,
138  /*rhs=*/rhs,
139  /*QCname=*/name.c_str());
140  };
141 
142  if (quad_cst.has_lower_bound() && quad_cst.lower_bound() > -kInfinity) {
143  const int grb_status =
144  addqconstr(gurobi_model, gen_cst.quadratic_constraint(),
145  GRB_GREATER_EQUAL, quad_cst.lower_bound(),
146  gen_cst.has_name() ? gen_cst.name() + "_lb" : "");
147  if (grb_status != GRB_OK) return grb_status;
148  }
149  if (quad_cst.has_upper_bound() && quad_cst.upper_bound() < kInfinity) {
150  const int grb_status =
151  addqconstr(gurobi_model, gen_cst.quadratic_constraint(), GRB_LESS_EQUAL,
152  quad_cst.upper_bound(),
153  gen_cst.has_name() ? gen_cst.name() + "_ub" : "");
154  if (grb_status != GRB_OK) return grb_status;
155  }
156 
157  return GRB_OK;
158 }
159 
160 int AddAndConstraint(const MPGeneralConstraintProto& gen_cst,
161  GRBmodel* gurobi_model, std::vector<int>* tmp_variables) {
162  CHECK(gurobi_model != nullptr);
163  CHECK(tmp_variables != nullptr);
164 
165  auto and_cst = gen_cst.and_constraint();
166  return GRBaddgenconstrAnd(
167  gurobi_model,
168  /*name=*/gen_cst.name().c_str(),
169  /*resvar=*/and_cst.resultant_var_index(),
170  /*nvars=*/and_cst.var_index_size(),
171  /*vars=*/and_cst.mutable_var_index()->mutable_data());
172 }
173 
174 int AddOrConstraint(const MPGeneralConstraintProto& gen_cst,
175  GRBmodel* gurobi_model, std::vector<int>* tmp_variables) {
176  CHECK(gurobi_model != nullptr);
177  CHECK(tmp_variables != nullptr);
178 
179  auto or_cst = gen_cst.or_constraint();
180  return GRBaddgenconstrOr(gurobi_model,
181  /*name=*/gen_cst.name().c_str(),
182  /*resvar=*/or_cst.resultant_var_index(),
183  /*nvars=*/or_cst.var_index_size(),
184  /*vars=*/or_cst.mutable_var_index()->mutable_data());
185 }
186 
187 int AddMinConstraint(const MPGeneralConstraintProto& gen_cst,
188  GRBmodel* gurobi_model, std::vector<int>* tmp_variables) {
189  CHECK(gurobi_model != nullptr);
190  CHECK(tmp_variables != nullptr);
191 
192  auto min_cst = gen_cst.min_constraint();
193  return GRBaddgenconstrMin(
194  gurobi_model,
195  /*name=*/gen_cst.name().c_str(),
196  /*resvar=*/min_cst.resultant_var_index(),
197  /*nvars=*/min_cst.var_index_size(),
198  /*vars=*/min_cst.mutable_var_index()->mutable_data(),
199  /*constant=*/min_cst.has_constant()
200  ? min_cst.constant()
201  : std::numeric_limits<double>::infinity());
202 }
203 
204 int AddMaxConstraint(const MPGeneralConstraintProto& gen_cst,
205  GRBmodel* gurobi_model, std::vector<int>* tmp_variables) {
206  CHECK(gurobi_model != nullptr);
207  CHECK(tmp_variables != nullptr);
208 
209  auto max_cst = gen_cst.max_constraint();
210  return GRBaddgenconstrMax(
211  gurobi_model,
212  /*name=*/gen_cst.name().c_str(),
213  /*resvar=*/max_cst.resultant_var_index(),
214  /*nvars=*/max_cst.var_index_size(),
215  /*vars=*/max_cst.mutable_var_index()->mutable_data(),
216  /*constant=*/max_cst.has_constant()
217  ? max_cst.constant()
218  : -std::numeric_limits<double>::infinity());
219 }
220 } // namespace
221 
222 absl::Status SetSolverSpecificParameters(const std::string& parameters,
223  GRBenv* gurobi) {
224  if (parameters.empty()) return absl::OkStatus();
225  std::vector<std::string> error_messages;
226  for (absl::string_view line : absl::StrSplit(parameters, '\n')) {
227  // Comment tokens end at the next new-line, or the end of the string.
228  // The first character must be '#'
229  if (line[0] == '#') continue;
230  for (absl::string_view token :
231  absl::StrSplit(line, ',', absl::SkipWhitespace())) {
232  if (token.empty()) continue;
233  std::vector<std::string> key_value =
234  absl::StrSplit(token, absl::ByAnyChar(" ="), absl::SkipWhitespace());
235  // If one parameter fails, we keep processing the list of parameters.
236  if (key_value.size() != 2) {
237  const std::string current_message =
238  absl::StrCat("Cannot parse parameter '", token,
239  "'. Expected format is 'ParameterName value' or "
240  "'ParameterName=value'");
241  error_messages.push_back(current_message);
242  continue;
243  }
244  const int gurobi_code =
245  GRBsetparam(gurobi, key_value[0].c_str(), key_value[1].c_str());
246  if (gurobi_code != GRB_OK) {
247  const std::string current_message = absl::StrCat(
248  "Error setting parameter '", key_value[0], "' to value '",
249  key_value[1], "': ", GRBgeterrormsg(gurobi));
250  error_messages.push_back(current_message);
251  continue;
252  }
253  VLOG(2) << absl::StrCat("Set parameter '", key_value[0], "' to value '",
254  key_value[1]);
255  }
256  }
257 
258  if (error_messages.empty()) return absl::OkStatus();
259  return absl::InvalidArgumentError(absl::StrJoin(error_messages, "\n"));
260 }
261 
262 absl::StatusOr<MPSolutionResponse> GurobiSolveProto(
263  const MPModelRequest& request, GRBenv* gurobi_env) {
264  MPSolutionResponse response;
265  const absl::optional<LazyMutableCopy<MPModelProto>> optional_model =
267  if (!optional_model) return response;
268  const MPModelProto& model = optional_model->get();
269 
270  // We set `gurobi_env` to point to a new environment if no existing one is
271  // provided. We must make sure that we free this environment when we exit this
272  // function.
273  bool gurobi_env_was_created = false;
274  auto gurobi_env_deleter = absl::MakeCleanup([&]() {
275  if (gurobi_env_was_created && gurobi_env != nullptr) {
276  GRBfreeenv(gurobi_env);
277  }
278  });
279  if (gurobi_env == nullptr) {
280  // We activate the deletion of `gurobi_env` before making the call to
281  // `LoadGurobiEnvironment()` since this function still returns a non null
282  // value even when it fails.
283  gurobi_env_was_created = true;
285  }
286 
287  GRBmodel* gurobi_model = nullptr;
288  auto gurobi_model_deleter = absl::MakeCleanup([&]() {
289  const int error_code = GRBfreemodel(gurobi_model);
290  LOG_IF(DFATAL, error_code != GRB_OK)
291  << "GRBfreemodel failed with error " << error_code << ": "
292  << GRBgeterrormsg(gurobi_env);
293  });
294 
295 // `gurobi_env` references ther GRBenv argument.
296 #define RETURN_IF_GUROBI_ERROR(x) \
297  RETURN_IF_ERROR( \
298  GurobiCodeToUtilStatus(x, __FILE__, __LINE__, #x, gurobi_env));
299 
300  RETURN_IF_GUROBI_ERROR(GRBnewmodel(gurobi_env, &gurobi_model,
301  model.name().c_str(),
302  /*numvars=*/0,
303  /*obj=*/nullptr,
304  /*lb=*/nullptr,
305  /*ub=*/nullptr,
306  /*vtype=*/nullptr,
307  /*varnames=*/nullptr));
308 
309  if (request.has_solver_specific_parameters()) {
310  const auto parameters_status = SetSolverSpecificParameters(
311  request.solver_specific_parameters(), GRBgetenv(gurobi_model));
312  if (!parameters_status.ok()) {
313  response.set_status(MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS);
314  response.set_status_str(
315  std::string(parameters_status.message())); // NOLINT
316  return response;
317  }
318  }
319  if (request.solver_time_limit_seconds() > 0) {
322  request.solver_time_limit_seconds()));
323  }
326  request.enable_internal_solver_output()));
327 
328  const int variable_size = model.variable_size();
329  bool has_integer_variables = false;
330  {
331  std::vector<double> obj_coeffs(variable_size, 0);
332  std::vector<double> lb(variable_size);
333  std::vector<double> ub(variable_size);
334  std::vector<char> ctype(variable_size);
335  std::vector<const char*> varnames(variable_size);
336  for (int v = 0; v < variable_size; ++v) {
337  const MPVariableProto& variable = model.variable(v);
338  obj_coeffs[v] = variable.objective_coefficient();
339  lb[v] = variable.lower_bound();
340  ub[v] = variable.upper_bound();
341  ctype[v] = variable.is_integer() ? GRB_INTEGER : GRB_CONTINUOUS;
342  if (variable.is_integer()) has_integer_variables = true;
343  if (!variable.name().empty()) varnames[v] = variable.name().c_str();
344  }
345 
347  GRBaddvars(gurobi_model, variable_size, 0, nullptr, nullptr, nullptr,
348  /*obj=*/obj_coeffs.data(),
349  /*lb=*/lb.data(), /*ub=*/ub.data(), /*vtype=*/ctype.data(),
350  /*varnames=*/const_cast<char**>(varnames.data())));
351 
352  // Set solution hints if any.
353  for (int i = 0; i < model.solution_hint().var_index_size(); ++i) {
355  gurobi_model, GRB_DBL_ATTR_START, model.solution_hint().var_index(i),
356  model.solution_hint().var_value(i)));
357  }
358  }
359 
360  {
361  std::vector<int> ct_variables;
362  std::vector<double> ct_coefficients;
363  for (int c = 0; c < model.constraint_size(); ++c) {
364  const MPConstraintProto& constraint = model.constraint(c);
365  const int size = constraint.var_index_size();
366  ct_variables.resize(size, 0);
367  ct_coefficients.resize(size, 0);
368  for (int i = 0; i < size; ++i) {
369  ct_variables[i] = constraint.var_index(i);
370  ct_coefficients[i] = constraint.coefficient(i);
371  }
372  // Using GRBaddrangeconstr for constraints that don't require it adds
373  // a slack which is not always removed by presolve.
374  if (constraint.lower_bound() == constraint.upper_bound()) {
376  gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
377  /*cval=*/ct_coefficients.data(),
378  /*sense=*/GRB_EQUAL, /*rhs=*/constraint.lower_bound(),
379  /*constrname=*/constraint.name().c_str()));
380  } else if (constraint.lower_bound() ==
381  -std::numeric_limits<double>::infinity()) {
383  gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
384  /*cval=*/ct_coefficients.data(),
385  /*sense=*/GRB_LESS_EQUAL, /*rhs=*/constraint.upper_bound(),
386  /*constrname=*/constraint.name().c_str()));
387  } else if (constraint.upper_bound() ==
388  std::numeric_limits<double>::infinity()) {
390  gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
391  /*cval=*/ct_coefficients.data(),
392  /*sense=*/GRB_GREATER_EQUAL, /*rhs=*/constraint.lower_bound(),
393  /*constrname=*/constraint.name().c_str()));
394  } else {
396  gurobi_model, /*numnz=*/size, /*cind=*/ct_variables.data(),
397  /*cval=*/ct_coefficients.data(),
398  /*lower=*/constraint.lower_bound(),
399  /*upper=*/constraint.upper_bound(),
400  /*constrname=*/constraint.name().c_str()));
401  }
402  }
403 
404  for (const auto& gen_cst : model.general_constraint()) {
405  switch (gen_cst.general_constraint_case()) {
406  case MPGeneralConstraintProto::kIndicatorConstraint: {
407  RETURN_IF_GUROBI_ERROR(AddIndicatorConstraint(
408  gen_cst, gurobi_model, &ct_variables, &ct_coefficients));
409  break;
410  }
411  case MPGeneralConstraintProto::kSosConstraint: {
412  RETURN_IF_GUROBI_ERROR(AddSosConstraint(gen_cst.sos_constraint(),
413  gurobi_model, &ct_variables,
414  &ct_coefficients));
415  break;
416  }
417  case MPGeneralConstraintProto::kQuadraticConstraint: {
418  RETURN_IF_GUROBI_ERROR(AddQuadraticConstraint(gen_cst, gurobi_model));
419  break;
420  }
421  case MPGeneralConstraintProto::kAbsConstraint: {
423  gurobi_model,
424  /*name=*/gen_cst.name().c_str(),
425  /*resvar=*/gen_cst.abs_constraint().resultant_var_index(),
426  /*argvar=*/gen_cst.abs_constraint().var_index()));
427  break;
428  }
429  case MPGeneralConstraintProto::kAndConstraint: {
431  AddAndConstraint(gen_cst, gurobi_model, &ct_variables));
432  break;
433  }
434  case MPGeneralConstraintProto::kOrConstraint: {
436  AddOrConstraint(gen_cst, gurobi_model, &ct_variables));
437  break;
438  }
439  case MPGeneralConstraintProto::kMinConstraint: {
441  AddMinConstraint(gen_cst, gurobi_model, &ct_variables));
442  break;
443  }
444  case MPGeneralConstraintProto::kMaxConstraint: {
446  AddMaxConstraint(gen_cst, gurobi_model, &ct_variables));
447  break;
448  }
449  default:
450  return absl::UnimplementedError(
451  absl::StrFormat("General constraints of type %i not supported.",
452  gen_cst.general_constraint_case()));
453  }
454  }
455  }
456 
458  model.maximize() ? -1 : 1));
460  model.objective_offset()));
461  if (model.has_quadratic_objective()) {
462  MPQuadraticObjective qobj = model.quadratic_objective();
463  if (qobj.coefficient_size() > 0) {
465  GRBaddqpterms(gurobi_model, /*numqnz=*/qobj.coefficient_size(),
466  /*qrow=*/qobj.mutable_qvar1_index()->mutable_data(),
467  /*qcol=*/qobj.mutable_qvar2_index()->mutable_data(),
468  /*qval=*/qobj.mutable_coefficient()->mutable_data()));
469  }
470  }
471 
472  RETURN_IF_GUROBI_ERROR(GRBupdatemodel(gurobi_model));
473  RETURN_IF_GUROBI_ERROR(GRBoptimize(gurobi_model));
474 
475  int optimization_status = 0;
477  GRBgetintattr(gurobi_model, GRB_INT_ATTR_STATUS, &optimization_status));
478  int solution_count = 0;
480  GRBgetintattr(gurobi_model, GRB_INT_ATTR_SOLCOUNT, &solution_count));
481  switch (optimization_status) {
482  case GRB_OPTIMAL:
483  response.set_status(MPSOLVER_OPTIMAL);
484  break;
485  case GRB_INF_OR_UNBD:
486  DLOG(INFO) << "Gurobi solve returned GRB_INF_OR_UNBD, which we treat as "
487  "INFEASIBLE even though it may mean UNBOUNDED.";
488  response.set_status_str(
489  "The model may actually be unbounded: Gurobi returned "
490  "GRB_INF_OR_UNBD");
491  ABSL_FALLTHROUGH_INTENDED;
492  case GRB_INFEASIBLE:
493  response.set_status(MPSOLVER_INFEASIBLE);
494  break;
495  case GRB_UNBOUNDED:
496  response.set_status(MPSOLVER_UNBOUNDED);
497  break;
498  default: {
499  if (solution_count > 0) {
500  response.set_status(MPSOLVER_FEASIBLE);
501  } else {
502  response.set_status(MPSOLVER_NOT_SOLVED);
503  response.set_status_str(
504  absl::StrFormat("Gurobi status code %d", optimization_status));
505  }
506  break;
507  }
508  }
509 
510  if (solution_count > 0 && (response.status() == MPSOLVER_FEASIBLE ||
511  response.status() == MPSOLVER_OPTIMAL)) {
512  double objective_value = 0;
514  GRBgetdblattr(gurobi_model, GRB_DBL_ATTR_OBJVAL, &objective_value));
515  response.set_objective_value(objective_value);
516  double best_objective_bound = 0;
517  const int error = GRBgetdblattr(gurobi_model, GRB_DBL_ATTR_OBJBOUND,
518  &best_objective_bound);
519  if (response.status() == MPSOLVER_OPTIMAL &&
520  error == GRB_ERROR_DATA_NOT_AVAILABLE) {
521  // If the presolve deletes all variables, there's no best bound.
522  response.set_best_objective_bound(objective_value);
523  } else {
524  RETURN_IF_GUROBI_ERROR(error);
525  response.set_best_objective_bound(best_objective_bound);
526  }
527 
528  response.mutable_variable_value()->Resize(variable_size, 0);
530  GRBgetdblattrarray(gurobi_model, GRB_DBL_ATTR_X, 0, variable_size,
531  response.mutable_variable_value()->mutable_data()));
532  // NOTE, GurobiSolveProto() is exposed to external clients via MPSolver API,
533  // which assumes the solution values of integer variables are rounded to
534  // integer values.
535  for (int v = 0; v < variable_size; ++v) {
536  if (model.variable(v).is_integer()) {
537  (*response.mutable_variable_value())[v] =
538  std::round(response.variable_value(v));
539  }
540  }
541  if (!has_integer_variables && model.general_constraint_size() == 0) {
542  response.mutable_dual_value()->Resize(model.constraint_size(), 0);
544  gurobi_model, GRB_DBL_ATTR_PI, 0, model.constraint_size(),
545  response.mutable_dual_value()->mutable_data()));
546  }
547  }
548 #undef RETURN_IF_GUROBI_ERROR
549 
550  return response;
551 }
552 
553 } // namespace operations_research
#define LOG_IF(severity, condition)
Definition: base/logging.h:479
#define DLOG(severity)
Definition: base/logging.h:875
#define CHECK(condition)
Definition: base/logging.h:495
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:885
#define VLOG(verboselevel)
Definition: base/logging.h:978
SatParameters parameters
SharedResponseManager * response
const std::string name
#define GRB_DBL_ATTR_START
#define GRB_ERROR_DATA_NOT_AVAILABLE
#define GRB_INT_ATTR_MODELSENSE
struct _GRBenv GRBenv
#define GRB_GREATER_EQUAL
#define GRB_OPTIMAL
#define GRB_INTEGER
#define GRB_DBL_ATTR_PI
#define GRB_DBL_ATTR_OBJVAL
#define GRB_CONTINUOUS
#define GRB_SOS_TYPE1
struct _GRBmodel GRBmodel
#define GRB_DBL_ATTR_OBJCON
#define GRB_INF_OR_UNBD
#define GRB_DBL_ATTR_X
#define GRB_INFEASIBLE
#define GRB_EQUAL
#define GRB_SOS_TYPE2
#define GRB_UNBOUNDED
#define GRB_INT_ATTR_STATUS
#define GRB_LESS_EQUAL
#define GRB_INT_ATTR_SOLCOUNT
#define GRB_INT_PAR_OUTPUTFLAG
#define GRB_DBL_PAR_TIMELIMIT
#define GRB_DBL_ATTR_OBJBOUND
GRBmodel * model
#define RETURN_IF_GUROBI_ERROR(x)
const int INFO
Definition: log_severity.h:31
absl::Cleanup< absl::decay_t< Callback > > MakeCleanup(Callback &&callback)
Definition: cleanup.h:120
const double kInfinity
Definition: lp_types.h:83
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
std::function< int(GRBenv *, GRBmodel **, const char *, int numvars, double *, double *, double *, char *, char **)> GRBnewmodel
std::function< int(GRBmodel *model, const char *name, int resvar, int nvars, const int *vars, double constant)> GRBaddgenconstrMin
std::function< int(GRBmodel *model, int numnz, int *cind, double *cval, char sense, double rhs, const char *constrname)> GRBaddconstr
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
std::function< void(GRBenv *)> GRBfreeenv
std::function< char *(GRBenv *)> GRBgeterrormsg
std::function< int(GRBmodel *, const char *, int)> GRBsetintattr
std::function< int(GRBenv *env, const char *paramname, const char *value)> GRBsetparam
std::function< int(GRBmodel *model, const char *name, int resvar, int argvar)> GRBaddgenconstrAbs
std::function< int(GRBmodel *, const char *, int *)> GRBgetintattr
std::function< int(GRBenv *, const char *, double)> GRBsetdblparam
std::function< int(GRBmodel *, const char *, double)> GRBsetdblattr
std::function< int(GRBmodel *)> GRBoptimize
std::function< int(GRBmodel *)> GRBupdatemodel
std::function< int(GRBmodel *model, int numqnz, int *qrow, int *qcol, double *qval)> GRBaddqpterms
std::function< int(GRBmodel *model, const char *name, int resvar, int nvars, const int *vars, double constant)> GRBaddgenconstrMax
std::function< int(GRBmodel *)> GRBfreemodel
std::function< int(GRBmodel *, const char *, int, int, double *)> GRBgetdblattrarray
std::function< int(GRBmodel *, int, int, int *, int *, double *, double *, double *, double *, char *, char **)> GRBaddvars
std::function< int(GRBmodel *model, const char *name, int resvar, int nvars, const int *vars)> GRBaddgenconstrAnd
absl::Status SetSolverSpecificParameters(const std::string &parameters, GRBenv *gurobi)
absl::optional< LazyMutableCopy< MPModelProto > > ExtractValidMPModelOrPopulateResponseStatus(const MPModelRequest &request, MPSolutionResponse *response)
If the model is valid and non-empty, returns it (possibly after extracting the model_delta).
absl::StatusOr< MPSolutionResponse > GurobiSolveProto(const MPModelRequest &request, GRBenv *gurobi_env)
std::function< int(GRBmodel *model, const char *name, int resvar, int nvars, const int *vars)> GRBaddgenconstrOr
std::function< int(GRBmodel *, const char *, double *)> GRBgetdblattr
absl::Status LoadGurobiEnvironment(GRBenv **env)
std::function< int(GRBmodel *, const char *, int, double)> GRBsetdblattrelement
std::function< int(GRBmodel *model, int numsos, int nummembers, int *types, int *beg, int *ind, double *weight)> GRBaddsos
std::function< GRBenv *(GRBmodel *)> GRBgetenv
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
std::function< int(GRBmodel *, int, int *, double *, double, double, const char *)> GRBaddrangeconstr
std::function< int(GRBenv *, const char *, int)> GRBsetintparam
#define RETURN_IF_ERROR(expr)
Definition: status_macros.h:27