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"
32#include "ortools/linear_solver/linear_solver.pb.h"
35
36namespace operations_research {
37
38namespace {
39constexpr int GRB_OK = 0;
40
41inline 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
52int 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
85int 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
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
118int 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
160int 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
174int 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
187int 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
204int 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
222absl::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
262absl::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
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 &&
521 // If the presolve deletes all variables, there's no best bound.
522 response.set_best_objective_bound(objective_value);
523 } else {
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