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