OR-Tools  8.1
scip_interface.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 
14 #if defined(USE_SCIP)
15 
16 #include <stddef.h>
17 
18 #include <algorithm>
19 #include <limits>
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 #include "absl/status/status.h"
25 #include "absl/strings/str_format.h"
26 #include "absl/types/optional.h"
28 #include "ortools/base/hash.h"
30 #include "ortools/base/logging.h"
32 #include "ortools/base/timer.h"
40 #include "scip/cons_indicator.h"
41 #include "scip/scip.h"
42 #include "scip/scip_param.h"
43 #include "scip/scip_prob.h"
44 #include "scip/scipdefplugins.h"
45 
46 ABSL_FLAG(bool, scip_feasibility_emphasis, false,
47  "When true, emphasize search towards feasibility. This may or "
48  "may not result in speedups in some problems.");
49 
50 namespace operations_research {
51 namespace {
52 // See the class ScipConstraintHandlerForMPCallback below.
53 struct EmptyStruct {};
54 } // namespace
55 
56 class ScipConstraintHandlerForMPCallback;
57 
59  public:
60  explicit SCIPInterface(MPSolver* solver);
61  ~SCIPInterface() override;
62 
63  void SetOptimizationDirection(bool maximize) override;
64  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
65  absl::optional<MPSolutionResponse> DirectlySolveProto(
66  const MPModelRequest& request) override;
67  void Reset() override;
68 
69  void SetVariableBounds(int var_index, double lb, double ub) override;
70  void SetVariableInteger(int var_index, bool integer) override;
71  void SetConstraintBounds(int row_index, double lb, double ub) override;
72 
73  void AddRowConstraint(MPConstraint* ct) override;
74  bool AddIndicatorConstraint(MPConstraint* ct) override;
75  void AddVariable(MPVariable* var) override;
76  void SetCoefficient(MPConstraint* constraint, const MPVariable* variable,
77  double new_value, double old_value) override;
78  void ClearConstraint(MPConstraint* constraint) override;
79  void SetObjectiveCoefficient(const MPVariable* variable,
80  double coefficient) override;
81  void SetObjectiveOffset(double value) override;
82  void ClearObjective() override;
83  void BranchingPriorityChangedForVariable(int var_index) override;
84 
85  int64 iterations() const override;
86  int64 nodes() const override;
87  MPSolver::BasisStatus row_status(int constraint_index) const override {
88  LOG(DFATAL) << "Basis status only available for continuous problems";
89  return MPSolver::FREE;
90  }
91  MPSolver::BasisStatus column_status(int variable_index) const override {
92  LOG(DFATAL) << "Basis status only available for continuous problems";
93  return MPSolver::FREE;
94  }
95 
96  bool IsContinuous() const override { return false; }
97  bool IsLP() const override { return false; }
98  bool IsMIP() const override { return true; }
99 
100  void ExtractNewVariables() override;
101  void ExtractNewConstraints() override;
102  void ExtractObjective() override;
103 
104  std::string SolverVersion() const override {
105  return absl::StrFormat("SCIP %d.%d.%d [LP solver: %s]", SCIPmajorVersion(),
106  SCIPminorVersion(), SCIPtechVersion(),
108  }
109 
110  bool InterruptSolve() override {
111  if (scip_ == nullptr) return true; // NOTE(user): Is this weird?
112  return SCIPinterruptSolve(scip_) == SCIP_OKAY;
113  }
114 
115  void* underlying_solver() override { return reinterpret_cast<void*>(scip_); }
116 
117  // MULTIPLE SOLUTIONS SUPPORT
118  // The default behavior of scip is to store the top incidentally generated
119  // integer solutions in the solution pool. The default maximum size is 100.
120  // This can be adjusted by setting the param limits/maxsol. There is no way
121  // to ensure that the pool will actually be full.
122  //
123  // You can also ask SCIP to enumerate all feasible solutions. Combined with
124  // an equality or inequality constraint on the objective (after solving once
125  // to find the optimal solution), you can use this to find all high quality
126  // solutions. See https://scip.zib.de/doc/html/COUNTER.php. This behavior is
127  // not supported directly through MPSolver, but in theory can be controlled
128  // entirely through scip parameters.
129  bool NextSolution() override;
130 
131  // CALLBACK SUPPORT:
132  // * We support MPSolver's callback API via MPCallback.
133  // See ./linear_solver_callback.h.
134  // * We also support SCIP's more general callback interface, built on
135  // 'constraint handlers'. See ./scip_callback.h and test, these are added
136  // directly to the underlying SCIP object, bypassing SCIPInterface.
137  // The former works by calling the latter. See go/scip-callbacks for
138  // a complete documentation of this design.
139 
140  // MPCallback API
141  void SetCallback(MPCallback* mp_callback) override;
142  bool SupportsCallbacks() const override { return true; }
143 
144  private:
145  void SetParameters(const MPSolverParameters& param) override;
146  void SetRelativeMipGap(double value) override;
147  void SetPrimalTolerance(double value) override;
148  void SetDualTolerance(double value) override;
149  void SetPresolveMode(int presolve) override;
150  void SetScalingMode(int scaling) override;
151  void SetLpAlgorithm(int lp_algorithm) override;
152 
153  // SCIP parameters allow to lower and upper bound the number of threads used
154  // (via "parallel/minnthreads" and "parallel/maxnthread", respectively). Here,
155  // we interpret "num_threads" to mean "parallel/maxnthreads", as this is what
156  // most clients probably want to do. To change "parallel/minnthreads" use
157  // SetSolverSpecificParametersAsString(). However, one must change
158  // "parallel/maxnthread" with SetNumThreads() because only this will inform
159  // the interface to run SCIPsolveConcurrent() instead of SCIPsolve() which is
160  // necessery to enable multi-threading.
161  absl::Status SetNumThreads(int num_threads) override;
162 
163  bool SetSolverSpecificParametersAsString(
164  const std::string& parameters) override;
165 
166  void SetUnsupportedIntegerParam(
167  MPSolverParameters::IntegerParam param) override;
168  void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param,
169  int value) override;
170  // How many solutions SCIP found.
171  int SolutionCount();
172  // Copy sol from SCIP to MPSolver.
173  void SetSolution(SCIP_SOL* solution);
174 
175  absl::Status CreateSCIP();
176  void DeleteSCIP();
177 
178  // SCIP has many internal checks (many of which are numerical) that can fail
179  // during various phases: upon startup, when loading the model, when solving,
180  // etc. Often, the user is meant to stop at the first error, but since most
181  // of the linear solver interface API doesn't support "error reporting", we
182  // store a potential error status here.
183  // If this status isn't OK, then most operations will silently be cancelled.
184  absl::Status status_;
185 
186  SCIP* scip_;
187  std::vector<SCIP_VAR*> scip_variables_;
188  std::vector<SCIP_CONS*> scip_constraints_;
189  int current_solution_index_ = 0;
190  MPCallback* callback_ = nullptr;
191  std::unique_ptr<ScipConstraintHandlerForMPCallback> scip_constraint_handler_;
192  // See ScipConstraintHandlerForMPCallback below.
193  EmptyStruct constraint_data_for_handler_;
194  bool branching_priority_reset_ = false;
195  bool callback_reset_ = false;
196 };
197 
199  : public ScipConstraintHandler<EmptyStruct> {
200  public:
201  explicit ScipConstraintHandlerForMPCallback(MPCallback* mp_callback);
202 
203  std::vector<CallbackRangeConstraint> SeparateFractionalSolution(
204  const ScipConstraintHandlerContext& context, const EmptyStruct&) override;
205 
206  std::vector<CallbackRangeConstraint> SeparateIntegerSolution(
207  const ScipConstraintHandlerContext& context, const EmptyStruct&) override;
208 
209  private:
210  std::vector<CallbackRangeConstraint> SeparateSolution(
212  const bool at_integer_solution);
213 
214  MPCallback* mp_callback_;
215 };
216 
218  : MPSolverInterface(solver), scip_(nullptr) {
219  status_ = CreateSCIP();
220 }
221 
222 SCIPInterface::~SCIPInterface() { DeleteSCIP(); }
223 
225  DeleteSCIP();
226  scip_constraint_handler_.reset();
227  status_ = CreateSCIP();
229 }
230 
231 absl::Status SCIPInterface::CreateSCIP() {
232  RETURN_IF_SCIP_ERROR(SCIPcreate(&scip_));
233  RETURN_IF_SCIP_ERROR(SCIPincludeDefaultPlugins(scip_));
234  // Set the emphasis to enum SCIP_PARAMEMPHASIS_FEASIBILITY. Do not print
235  // the new parameter (quiet = true).
236  if (absl::GetFlag(FLAGS_scip_feasibility_emphasis)) {
237  RETURN_IF_SCIP_ERROR(SCIPsetEmphasis(scip_, SCIP_PARAMEMPHASIS_FEASIBILITY,
238  /*quiet=*/true));
239  }
240  // Default clock type. We use wall clock time because getting CPU user seconds
241  // involves calling times() which is very expensive.
242  // NOTE(user): Also, time limit based on CPU user seconds is *NOT* thread
243  // safe. We observed that different instances of SCIP running concurrently
244  // in different threads consume the time limit *together*. E.g., 2 threads
245  // running SCIP with time limit 10s each will both terminate after ~5s.
247  SCIPsetIntParam(scip_, "timing/clocktype", SCIP_CLOCKTYPE_WALL));
248  RETURN_IF_SCIP_ERROR(SCIPcreateProb(scip_, solver_->name_.c_str(), nullptr,
249  nullptr, nullptr, nullptr, nullptr,
250  nullptr, nullptr));
251  RETURN_IF_SCIP_ERROR(SCIPsetObjsense(
252  scip_, maximize_ ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
253  return absl::OkStatus();
254 }
255 
256 void SCIPInterface::DeleteSCIP() {
257  // NOTE(user): DeleteSCIP() shouldn't "give up" mid-stage if it fails, since
258  // it might be the user's chance to reset the solver to start fresh without
259  // errors. The current code isn't perfect, since some CHECKs() remain, but
260  // hopefully they'll never be triggered in practice.
261  CHECK(scip_ != nullptr);
262  for (int i = 0; i < scip_variables_.size(); ++i) {
263  CHECK_EQ(SCIPreleaseVar(scip_, &scip_variables_[i]), SCIP_OKAY);
264  }
265  scip_variables_.clear();
266  for (int j = 0; j < scip_constraints_.size(); ++j) {
267  CHECK_EQ(SCIPreleaseCons(scip_, &scip_constraints_[j]), SCIP_OKAY);
268  }
269  scip_constraints_.clear();
270  CHECK_EQ(SCIPfree(&scip_), SCIP_OKAY);
271  scip_ = nullptr;
272 }
273 
274 #define RETURN_IF_ALREADY_IN_ERROR_STATE \
275  do { \
276  if (!status_.ok()) { \
277  VLOG_EVERY_N(1, 10) << "Early abort: SCIP is in error state."; \
278  return; \
279  } \
280  } while (false)
281 
282 #define RETURN_AND_STORE_IF_SCIP_ERROR(x) \
283  do { \
284  status_ = SCIP_TO_STATUS(x); \
285  if (!status_.ok()) return; \
286  } while (false)
287 
288 // Not cached.
292  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
293  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPsetObjsense(
294  scip_, maximize ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
295 }
296 
297 void SCIPInterface::SetVariableBounds(int var_index, double lb, double ub) {
300  if (variable_is_extracted(var_index)) {
301  // Not cached if the variable has been extracted.
302  DCHECK_LT(var_index, last_variable_index_);
303  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
305  SCIPchgVarLb(scip_, scip_variables_[var_index], lb));
307  SCIPchgVarUb(scip_, scip_variables_[var_index], ub));
308  } else {
310  }
311 }
312 
313 void SCIPInterface::SetVariableInteger(int var_index, bool integer) {
316  if (variable_is_extracted(var_index)) {
317  // Not cached if the variable has been extracted.
318  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
319 #if (SCIP_VERSION >= 210)
320  SCIP_Bool infeasible = false;
321  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarType(
322  scip_, scip_variables_[var_index],
323  integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS, &infeasible));
324 #else
325  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarType(
326  scip_, scip_variables_[var_index],
327  integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS));
328 #endif // SCIP_VERSION >= 210
329  } else {
331  }
332 }
333 
334 void SCIPInterface::SetConstraintBounds(int index, double lb, double ub) {
338  // Not cached if the row has been extracted.
340  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
342  SCIPchgLhsLinear(scip_, scip_constraints_[index], lb));
344  SCIPchgRhsLinear(scip_, scip_constraints_[index], ub));
345  } else {
347  }
348 }
349 
351  const MPVariable* variable, double new_value,
352  double old_value) {
355  if (variable_is_extracted(variable->index()) &&
356  constraint_is_extracted(constraint->index())) {
357  // The modification of the coefficient for an extracted row and
358  // variable is not cached.
359  DCHECK_LT(constraint->index(), last_constraint_index_);
360  DCHECK_LT(variable->index(), last_variable_index_);
361  // SCIP does not allow to set a coefficient directly, so we add the
362  // difference between the new and the old value instead.
363  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
364  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCoefLinear(
365  scip_, scip_constraints_[constraint->index()],
366  scip_variables_[variable->index()], new_value - old_value));
367  } else {
368  // The modification of an unextracted row or variable is cached
369  // and handled in ExtractModel.
371  }
372 }
373 
374 // Not cached
378  const int constraint_index = constraint->index();
379  // Constraint may not have been extracted yet.
380  if (!constraint_is_extracted(constraint_index)) return;
381  for (const auto& entry : constraint->coefficients_) {
382  const int var_index = entry.first->index();
383  const double old_coef_value = entry.second;
384  DCHECK(variable_is_extracted(var_index));
385  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
386  // Set coefficient to zero by subtracting the old coefficient value.
388  SCIPaddCoefLinear(scip_, scip_constraints_[constraint_index],
389  scip_variables_[var_index], -old_coef_value));
390  }
391 }
392 
393 // Cached
395  double coefficient) {
397 }
398 
399 // Cached
402 }
403 
404 // Clear objective of all its terms.
408 
410  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
411  // Clear linear terms
412  for (const auto& entry : solver_->objective_->coefficients_) {
413  const int var_index = entry.first->index();
414  // Variable may have not been extracted yet.
415  if (!variable_is_extracted(var_index)) {
417  } else {
419  SCIPchgVarObj(scip_, scip_variables_[var_index], 0.0));
420  }
421  }
422  // Note: we don't clear the objective offset here because it's not necessary
423  // (it's always reset anyway in ExtractObjective) and we sometimes run into
424  // crashes when clearing the whole model (see
425  // http://test/OCL:253365573:BASE:253566457:1560777456754:e181f4ab).
426  // It's not worth to spend time investigating this issue.
427 }
428 
430  // As of 2019-05, SCIP does not support setting branching priority for
431  // variables in models that have already been solved. Therefore, we force
432  // reset the model when setting the priority on an already extracted variable.
433  // Note that this is a more drastic step than merely changing the sync_status.
434  // This may be slightly conservative, as it is technically possible that
435  // the extraction has occurred without a call to Solve().
436  if (variable_is_extracted(var_index)) {
437  branching_priority_reset_ = true;
438  }
439 }
440 
443 }
444 
447  return true;
448 }
449 
451 
454  int total_num_vars = solver_->variables_.size();
455  if (total_num_vars > last_variable_index_) {
456  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
457  // Define new variables
458  for (int j = last_variable_index_; j < total_num_vars; ++j) {
459  MPVariable* const var = solver_->variables_[j];
461  set_variable_as_extracted(j, true);
462  SCIP_VAR* scip_var = nullptr;
463  // The true objective coefficient will be set later in ExtractObjective.
464  double tmp_obj_coef = 0.0;
465  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateVar(
466  scip_, &scip_var, var->name().c_str(), var->lb(), var->ub(),
467  tmp_obj_coef,
468  var->integer() ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS, true,
469  false, nullptr, nullptr, nullptr, nullptr, nullptr));
470  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddVar(scip_, scip_var));
471  scip_variables_.push_back(scip_var);
472  const int branching_priority = var->branching_priority();
473  if (branching_priority != 0) {
474  const int index = var->index();
475  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarBranchPriority(
476  scip_, scip_variables_[index], branching_priority));
477  }
478  }
479  // Add new variables to existing constraints.
480  for (int i = 0; i < last_constraint_index_; i++) {
481  MPConstraint* const ct = solver_->constraints_[i];
482  for (const auto& entry : ct->coefficients_) {
483  const int var_index = entry.first->index();
484  DCHECK(variable_is_extracted(var_index));
485  if (var_index >= last_variable_index_) {
486  // The variable is new, so we know the previous coefficient
487  // value was 0 and we can directly add the coefficient.
489  SCIPaddCoefLinear(scip_, scip_constraints_[i],
490  scip_variables_[var_index], entry.second));
491  }
492  }
493  }
494  }
495 }
496 
499  int total_num_rows = solver_->constraints_.size();
500  if (last_constraint_index_ < total_num_rows) {
501  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
502  // Find the length of the longest row.
503  int max_row_length = 0;
504  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
505  MPConstraint* const ct = solver_->constraints_[i];
508  if (ct->coefficients_.size() > max_row_length) {
509  max_row_length = ct->coefficients_.size();
510  }
511  }
512  std::unique_ptr<SCIP_VAR*[]> vars(new SCIP_VAR*[max_row_length]);
513  std::unique_ptr<double[]> coeffs(new double[max_row_length]);
514  // Add each new constraint.
515  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
516  MPConstraint* const ct = solver_->constraints_[i];
518  const int size = ct->coefficients_.size();
519  int j = 0;
520  for (const auto& entry : ct->coefficients_) {
521  const int var_index = entry.first->index();
522  DCHECK(variable_is_extracted(var_index));
523  vars[j] = scip_variables_[var_index];
524  coeffs[j] = entry.second;
525  j++;
526  }
527  SCIP_CONS* scip_constraint = nullptr;
528  const bool is_lazy = ct->is_lazy();
529  if (ct->indicator_variable() != nullptr) {
530  const int ind_index = ct->indicator_variable()->index();
531  DCHECK(variable_is_extracted(ind_index));
532  SCIP_VAR* ind_var = scip_variables_[ind_index];
533  if (ct->indicator_value() == 0) {
535  SCIPgetNegatedVar(scip_, scip_variables_[ind_index], &ind_var));
536  }
537 
538  if (ct->ub() < std::numeric_limits<double>::infinity()) {
539  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsIndicator(
540  scip_, &scip_constraint, ct->name().c_str(), ind_var, size,
541  vars.get(), coeffs.get(), ct->ub(),
542  /*initial=*/!is_lazy,
543  /*separate=*/true,
544  /*enforce=*/true,
545  /*check=*/true,
546  /*propagate=*/true,
547  /*local=*/false,
548  /*dynamic=*/false,
549  /*removable=*/is_lazy,
550  /*stickingatnode=*/false));
551  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint));
552  scip_constraints_.push_back(scip_constraint);
553  }
554  if (ct->lb() > -std::numeric_limits<double>::infinity()) {
555  for (int i = 0; i < size; ++i) {
556  coeffs[i] *= -1;
557  }
558  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsIndicator(
559  scip_, &scip_constraint, ct->name().c_str(), ind_var, size,
560  vars.get(), coeffs.get(), -ct->lb(),
561  /*initial=*/!is_lazy,
562  /*separate=*/true,
563  /*enforce=*/true,
564  /*check=*/true,
565  /*propagate=*/true,
566  /*local=*/false,
567  /*dynamic=*/false,
568  /*removable=*/is_lazy,
569  /*stickingatnode=*/false));
570  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint));
571  scip_constraints_.push_back(scip_constraint);
572  }
573  } else {
574  // See
575  // http://scip.zib.de/doc/html/cons__linear_8h.php#aa7aed137a4130b35b168812414413481
576  // for an explanation of the parameters.
577  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsLinear(
578  scip_, &scip_constraint, ct->name().c_str(), size, vars.get(),
579  coeffs.get(), ct->lb(), ct->ub(),
580  /*initial=*/!is_lazy,
581  /*separate=*/true,
582  /*enforce=*/true,
583  /*check=*/true,
584  /*propagate=*/true,
585  /*local=*/false,
586  /*modifiable=*/false,
587  /*dynamic=*/false,
588  /*removable=*/is_lazy,
589  /*stickingatnode=*/false));
590  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint));
591  scip_constraints_.push_back(scip_constraint);
592  }
593  }
594  }
595 }
596 
599  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
600  // Linear objective: set objective coefficients for all variables (some might
601  // have been modified).
602  for (const auto& entry : solver_->objective_->coefficients_) {
603  const int var_index = entry.first->index();
604  const double obj_coef = entry.second;
606  SCIPchgVarObj(scip_, scip_variables_[var_index], obj_coef));
607  }
608 
609  // Constant term: change objective offset.
610  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddOrigObjoffset(
611  scip_, solver_->Objective().offset() - SCIPgetOrigObjoffset(scip_)));
612 }
613 
614 #define RETURN_ABNORMAL_IF_BAD_STATUS \
615  do { \
616  if (!status_.ok()) { \
617  LOG_IF(INFO, solver_->OutputIsEnabled()) \
618  << "Invalid SCIP status: " << status_; \
619  return result_status_ = MPSolver::ABNORMAL; \
620  } \
621  } while (false)
622 
623 #define RETURN_ABNORMAL_IF_SCIP_ERROR(x) \
624  do { \
625  RETURN_ABNORMAL_IF_BAD_STATUS; \
626  status_ = SCIP_TO_STATUS(x); \
627  RETURN_ABNORMAL_IF_BAD_STATUS; \
628  } while (false);
629 
631  // "status_" may encode a variety of failure scenarios, many of which would
632  // correspond to another MPResultStatus than ABNORMAL, but since SCIP is a
633  // moving target, we use the most likely error code here (abnormalities,
634  // often numeric), and rely on the user enabling output to see more details.
636 
637  WallTimer timer;
638  timer.Start();
639 
640  // Note that SCIP does not provide any incrementality.
641  // TODO(user): Is that still true now (2018) ?
644  branching_priority_reset_ || callback_reset_) {
645  Reset();
646  branching_priority_reset_ = false;
647  callback_reset_ = false;
648  }
649 
650  // Set log level.
651  SCIPsetMessagehdlrQuiet(scip_, quiet_);
652 
653  // Special case if the model is empty since SCIP expects a non-empty model.
654  if (solver_->variables_.empty() && solver_->constraints_.empty()) {
659  return result_status_;
660  }
661 
662  ExtractModel();
663  VLOG(1) << absl::StrFormat("Model built in %s.",
664  absl::FormatDuration(timer.GetDuration()));
665  if (callback_ != nullptr) {
666  scip_constraint_handler_ =
667  absl::make_unique<ScipConstraintHandlerForMPCallback>(callback_);
668  RegisterConstraintHandler<EmptyStruct>(scip_constraint_handler_.get(),
669  scip_);
670  AddCallbackConstraint<EmptyStruct>(scip_, scip_constraint_handler_.get(),
671  "mp_solver_callback_constraint_for_scip",
672  &constraint_data_for_handler_,
674  }
675 
676  // Time limit.
677  if (solver_->time_limit() != 0) {
678  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
680  SCIPsetRealParam(scip_, "limits/time", solver_->time_limit_in_secs()));
681  } else {
682  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPresetParam(scip_, "limits/time"));
683  }
684 
685  // We first set our internal MPSolverParameters from param and then set any
686  // user specified internal solver, ie. SCIP, parameters via
687  // solver_specific_parameter_string_.
688  // Default MPSolverParameters can override custom parameters (for example for
689  // presolving) and therefore we apply MPSolverParameters first.
690  SetParameters(param);
692  solver_->solver_specific_parameter_string_);
693 
694  // Use the solution hint if any.
695  if (!solver_->solution_hint_.empty()) {
696  SCIP_SOL* solution;
697  bool is_solution_partial = false;
698  const int num_vars = solver_->variables_.size();
699  if (solver_->solution_hint_.size() != num_vars) {
700  // We start by creating an empty partial solution.
702  SCIPcreatePartialSol(scip_, &solution, nullptr));
703  is_solution_partial = true;
704  } else {
705  // We start by creating the all-zero solution.
706  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPcreateSol(scip_, &solution, nullptr));
707  }
708 
709  // Fill the other variables from the given solution hint.
710  for (const std::pair<const MPVariable*, double>& p :
711  solver_->solution_hint_) {
712  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPsetSolVal(
713  scip_, solution, scip_variables_[p.first->index()], p.second));
714  }
715 
716  if (!is_solution_partial) {
717  SCIP_Bool is_feasible;
718  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPcheckSol(
719  scip_, solution, /*printreason=*/false, /*completely=*/true,
720  /*checkbounds=*/true, /*checkintegrality=*/true, /*checklprows=*/true,
721  &is_feasible));
722  VLOG(1) << "Solution hint is "
723  << (is_feasible ? "FEASIBLE" : "INFEASIBLE");
724  }
725 
726  // TODO(user): I more or less copied this from the SCIPreadSol() code that
727  // reads a solution from a file. I am not sure what SCIPisTransformed() is
728  // or what is the difference between the try and add version. In any case
729  // this seems to always call SCIPaddSolFree() for now and it works.
730  SCIP_Bool is_stored;
731  if (!is_solution_partial && SCIPisTransformed(scip_)) {
732  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPtrySolFree(
733  scip_, &solution, /*printreason=*/false, /*completely=*/true,
734  /*checkbounds=*/true, /*checkintegrality=*/true, /*checklprows=*/true,
735  &is_stored));
736  } else {
738  SCIPaddSolFree(scip_, &solution, &is_stored));
739  }
740  }
741 
742  // Solve.
743  timer.Restart();
745  ? SCIPsolveConcurrent(scip_)
746  : SCIPsolve(scip_));
747  VLOG(1) << absl::StrFormat("Solved in %s.",
748  absl::FormatDuration(timer.GetDuration()));
749  current_solution_index_ = 0;
750  // Get the results.
751  SCIP_SOL* const solution = SCIPgetBestSol(scip_);
752  if (solution != nullptr) {
753  // If optimal or feasible solution is found.
754  SetSolution(solution);
755  } else {
756  VLOG(1) << "No feasible solution found.";
757  }
758 
759  // Check the status: optimal, infeasible, etc.
760  SCIP_STATUS scip_status = SCIPgetStatus(scip_);
761  switch (scip_status) {
762  case SCIP_STATUS_OPTIMAL:
764  break;
765  case SCIP_STATUS_GAPLIMIT:
766  // To be consistent with the other solvers.
768  break;
769  case SCIP_STATUS_INFEASIBLE:
771  break;
772  case SCIP_STATUS_UNBOUNDED:
774  break;
775  case SCIP_STATUS_INFORUNBD:
776  // TODO(user): We could introduce our own "infeasible or
777  // unbounded" status.
779  break;
780  default:
781  if (solution != nullptr) {
783  } else if (scip_status == SCIP_STATUS_TIMELIMIT ||
784  scip_status == SCIP_STATUS_TOTALNODELIMIT) {
786  } else {
788  }
789  break;
790  }
791 
792  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPresetParams(scip_));
793 
795  return result_status_;
796 }
797 
798 void SCIPInterface::SetSolution(SCIP_SOL* solution) {
799  objective_value_ = SCIPgetSolOrigObj(scip_, solution);
800  best_objective_bound_ = SCIPgetDualbound(scip_);
801  VLOG(1) << "objective=" << objective_value_
802  << ", bound=" << best_objective_bound_;
803  for (int i = 0; i < solver_->variables_.size(); ++i) {
804  MPVariable* const var = solver_->variables_[i];
805  const int var_index = var->index();
806  const double val =
807  SCIPgetSolVal(scip_, solution, scip_variables_[var_index]);
808  var->set_solution_value(val);
809  VLOG(3) << var->name() << "=" << val;
810  }
811 }
812 
813 absl::optional<MPSolutionResponse> SCIPInterface::DirectlySolveProto(
814  const MPModelRequest& request) {
815  // ScipSolveProto doesn't solve concurrently.
816  if (solver_->GetNumThreads() > 1) return absl::nullopt;
817 
818  const auto status_or = ScipSolveProto(request);
819  if (status_or.ok()) return status_or.value();
820  // Special case: if something is not implemented yet, fall back to solving
821  // through MPSolver.
822  if (absl::IsUnimplemented(status_or.status())) return absl::nullopt;
823 
824  if (request.enable_internal_solver_output()) {
825  LOG(INFO) << "Invalid SCIP status: " << status_or.status();
826  }
827  MPSolutionResponse response;
828  response.set_status(MPSOLVER_NOT_SOLVED);
829  response.set_status_str(status_or.status().ToString());
830  return response;
831 }
832 
833 int SCIPInterface::SolutionCount() { return SCIPgetNSols(scip_); }
834 
836  // Make sure we have successfully solved the problem and not modified it.
838  return false;
839  }
840  if (current_solution_index_ + 1 >= SolutionCount()) {
841  return false;
842  }
843  current_solution_index_++;
844  SCIP_SOL** all_solutions = SCIPgetSols(scip_);
845  SetSolution(all_solutions[current_solution_index_]);
846  return true;
847 }
848 
850  // NOTE(user): As of 2018-12 it doesn't run in the stubby server, and is
851  // a specialized call, so it's ok to crash if the status is broken.
853  return SCIPgetNLPIterations(scip_);
854 }
855 
857  // NOTE(user): Same story as iterations(): it's OK to crash here.
859  // This is the total number of nodes used in the solve, potentially across
860  // multiple branch-and-bound trees. Use limits/totalnodes (rather than
861  // limits/nodes) to control this value.
862  return SCIPgetNTotalNodes(scip_);
863 }
864 
865 void SCIPInterface::SetParameters(const MPSolverParameters& param) {
866  SetCommonParameters(param);
867  SetMIPParameters(param);
868 }
869 
870 void SCIPInterface::SetRelativeMipGap(double value) {
871  // NOTE(user): We don't want to call RETURN_IF_ALREADY_IN_ERROR_STATE here,
872  // because even if the solver is in an error state, the user might be setting
873  // some parameters and then "restoring" the solver to a non-error state by
874  // calling Reset(), which should *not* reset the parameters.
875  // So we want the parameter-setting functions to be resistant to being in an
876  // error state, essentially. What we do is:
877  // - we call the parameter-setting function anyway (I'm assuming that SCIP
878  // won't crash even if we're in an error state. I did *not* verify this).
879  // - if that call yielded an error *and* we weren't already in an error state,
880  // set the state to that error we just got.
881  const auto status =
882  SCIP_TO_STATUS(SCIPsetRealParam(scip_, "limits/gap", value));
883  if (status_.ok()) status_ = status;
884 }
885 
886 void SCIPInterface::SetPrimalTolerance(double value) {
887  // See the NOTE on SetRelativeMipGap().
888  const auto status =
889  SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/feastol", value));
890  if (status_.ok()) status_ = status;
891 }
892 
893 void SCIPInterface::SetDualTolerance(double value) {
894  const auto status =
895  SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/dualfeastol", value));
896  if (status_.ok()) status_ = status;
897 }
898 
899 void SCIPInterface::SetPresolveMode(int presolve) {
900  // See the NOTE on SetRelativeMipGap().
901  switch (presolve) {
903  const auto status =
904  SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", 0));
905  if (status_.ok()) status_ = status;
906  return;
907  }
909  const auto status =
910  SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", -1));
911  if (status_.ok()) status_ = status;
912  return;
913  }
914  default: {
915  SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, presolve);
916  return;
917  }
918  }
919 }
920 
921 void SCIPInterface::SetScalingMode(int scaling) {
922  SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
923 }
924 
925 // Only the root LP algorithm is set as setting the node LP to a
926 // non-default value rarely is beneficial. The node LP algorithm could
927 // be set as well with "lp/resolvealgorithm".
928 void SCIPInterface::SetLpAlgorithm(int lp_algorithm) {
929  // See the NOTE on SetRelativeMipGap().
930  switch (lp_algorithm) {
932  const auto status =
933  SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'd'));
934  if (status_.ok()) status_ = status;
935  return;
936  }
938  const auto status =
939  SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p'));
940  if (status_.ok()) status_ = status;
941  return;
942  }
944  // Barrier with crossover.
945  const auto status =
946  SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p'));
947  if (status_.ok()) status_ = status;
948  return;
949  }
950  default: {
951  SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
952  lp_algorithm);
953  return;
954  }
955  }
956 }
957 
958 void SCIPInterface::SetUnsupportedIntegerParam(
961  if (status_.ok()) {
962  status_ = absl::InvalidArgumentError(absl::StrFormat(
963  "Tried to set unsupported integer parameter %d", param));
964  }
965 }
966 
967 void SCIPInterface::SetIntegerParamToUnsupportedValue(
970  if (status_.ok()) {
971  status_ = absl::InvalidArgumentError(absl::StrFormat(
972  "Tried to set integer parameter %d to unsupported value %d", param,
973  value));
974  }
975 }
976 
977 absl::Status SCIPInterface::SetNumThreads(int num_threads) {
978  if (SetSolverSpecificParametersAsString(
979  absl::StrFormat("parallel/maxnthreads = %d\n", num_threads))) {
980  return absl::OkStatus();
981  }
982  return absl::InternalError(
983  "Could not set parallel/maxnthreads, which may "
984  "indicate that SCIP API has changed.");
985 }
986 
987 bool SCIPInterface::SetSolverSpecificParametersAsString(
988  const std::string& parameters) {
989  const absl::Status s =
991  if (!s.ok()) {
992  LOG(WARNING) << "Failed to set SCIP parameter string: " << parameters
993  << ", error is: " << s;
994  }
995  return s.ok();
996 }
997 
999  public:
1001  bool at_integer_solution)
1002  : scip_context_(scip_context),
1003  at_integer_solution_(at_integer_solution) {}
1004 
1005  MPCallbackEvent Event() override {
1006  if (at_integer_solution_) {
1007  return MPCallbackEvent::kMipSolution;
1008  }
1009  return MPCallbackEvent::kMipNode;
1010  }
1011 
1012  bool CanQueryVariableValues() override {
1013  return !scip_context_->is_pseudo_solution();
1014  }
1015 
1016  double VariableValue(const MPVariable* variable) override {
1018  return scip_context_->VariableValue(variable);
1019  }
1020 
1021  void AddCut(const LinearRange& cutting_plane) override {
1022  CallbackRangeConstraint constraint;
1023  constraint.is_cut = true;
1024  constraint.range = cutting_plane;
1025  constraint.local = false;
1026  constraints_added_.push_back(std::move(constraint));
1027  }
1028 
1029  void AddLazyConstraint(const LinearRange& lazy_constraint) override {
1030  CallbackRangeConstraint constraint;
1031  constraint.is_cut = false;
1032  constraint.range = lazy_constraint;
1033  constraint.local = false;
1034  constraints_added_.push_back(std::move(constraint));
1035  }
1036 
1038  const absl::flat_hash_map<const MPVariable*, double>& solution) override {
1039  LOG(FATAL) << "SuggestSolution() not currently supported for SCIP.";
1040  }
1041 
1043  // scip_context_->NumNodesProcessed() returns:
1044  // 0 before the root node is solved, e.g. if a heuristic finds a solution.
1045  // 1 at the root node
1046  // > 1 after the root node.
1047  // The NumExploredNodes spec requires that we return 0 at the root node,
1048  // (this is consistent with gurobi). Below is a bandaid to try and make the
1049  // behavior consistent, although some information is lost.
1050  return std::max(int64{0}, scip_context_->NumNodesProcessed() - 1);
1051  }
1052 
1053  const std::vector<CallbackRangeConstraint>& constraints_added() {
1054  return constraints_added_;
1055  }
1056 
1057  private:
1058  const ScipConstraintHandlerContext* scip_context_;
1059  bool at_integer_solution_;
1060  // second value of pair is true for cuts and false for lazy constraints.
1061  std::vector<CallbackRangeConstraint> constraints_added_;
1062 };
1063 
1065  MPCallback* mp_callback)
1066  : ScipConstraintHandler<EmptyStruct>(
1067  // MOE(begin-strip):
1068  {/*name=*/"mp_solver_constraint_handler",
1069  /*description=*/
1070  "A single constraint handler for all MPSolver models."}
1071  // MOE(end-strip-and-replace): ScipConstraintHandlerDescription()
1072  ),
1073  mp_callback_(mp_callback) {}
1074 
1075 std::vector<CallbackRangeConstraint>
1077  const ScipConstraintHandlerContext& context, const EmptyStruct&) {
1078  return SeparateSolution(context, /*at_integer_solution=*/false);
1079 }
1080 
1081 std::vector<CallbackRangeConstraint>
1083  const ScipConstraintHandlerContext& context, const EmptyStruct&) {
1084  return SeparateSolution(context, /*at_integer_solution=*/true);
1085 }
1086 
1087 std::vector<CallbackRangeConstraint>
1088 ScipConstraintHandlerForMPCallback::SeparateSolution(
1090  const bool at_integer_solution) {
1091  ScipMPCallbackContext mp_context(&context, at_integer_solution);
1092  mp_callback_->RunCallback(&mp_context);
1093  return mp_context.constraints_added();
1094 }
1095 
1097  if (callback_ != nullptr) {
1098  callback_reset_ = true;
1099  }
1100  callback_ = mp_callback;
1101 }
1102 
1104  return new SCIPInterface(solver);
1105 }
1106 
1107 } // namespace operations_research
1108 #endif // #if defined(USE_SCIP)
1109 
1110 #undef RETURN_AND_STORE_IF_SCIP_ERROR
1111 #undef RETURN_IF_ALREADY_IN_ERROR_STATE
1112 #undef RETURN_ABNORMAL_IF_BAD_STATUS
1113 #undef RETURN_ABNORMAL_IF_SCIP_ERROR
operations_research::ScipConstraintHandler
Definition: scip_callback.h:118
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::ScipConstraintHandlerForMPCallback::SeparateFractionalSolution
std::vector< CallbackRangeConstraint > SeparateFractionalSolution(const ScipConstraintHandlerContext &context, const EmptyStruct &) override
Definition: scip_interface.cc:1076
INFO
const int INFO
Definition: log_severity.h:31
operations_research::MPCallback
Definition: linear_solver_callback.h:140
operations_research::ScipMPCallbackContext::CanQueryVariableValues
bool CanQueryVariableValues() override
Definition: scip_interface.cc:1012
response
SharedResponseManager * response
Definition: cp_model_solver.cc:2105
operations_research::SCIPInterface::ExtractObjective
void ExtractObjective() override
Definition: scip_interface.cc:597
operations_research::SCIPInterface::IsContinuous
bool IsContinuous() const override
Definition: scip_interface.cc:96
integral_types.h
DCHECK_LT
#define DCHECK_LT(val1, val2)
Definition: base/logging.h:888
VLOG
#define VLOG(verboselevel)
Definition: base/logging.h:978
operations_research::CallbackRangeConstraint::is_cut
bool is_cut
Definition: scip_callback.h:111
max
int64 max
Definition: alldiff_cst.cc:139
operations_research::ScipSolveProto
absl::StatusOr< MPSolutionResponse > ScipSolveProto(const MPModelRequest &request)
Definition: scip_proto_solver.cc:657
operations_research::MPCallbackContext
Definition: linear_solver_callback.h:64
operations_research::SCIPInterface::SetObjectiveCoefficient
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
Definition: scip_interface.cc:394
operations_research::ScipCallbackConstraintOptions
Definition: scip_callback.h:165
LOG
#define LOG(severity)
Definition: base/logging.h:420
operations_research::LegacyScipSetSolverSpecificParameters
absl::Status LegacyScipSetSolverSpecificParameters(const std::string &parameters, SCIP *scip)
Definition: legacy_scip_params.cc:32
operations_research::MPCallback::RunCallback
virtual void RunCallback(MPCallbackContext *callback_context)=0
operations_research::SCIPInterface::ExtractNewVariables
void ExtractNewVariables() override
Definition: scip_interface.cc:452
linear_solver.pb.h
operations_research::MPSolver::OPTIMAL
@ OPTIMAL
optimal.
Definition: linear_solver.h:429
operations_research::MPSolverParameters::LP_ALGORITHM
@ LP_ALGORITHM
Algorithm to solve linear programs.
Definition: linear_solver.h:1383
FATAL
const int FATAL
Definition: log_severity.h:32
operations_research::SCIPInterface::ClearConstraint
void ClearConstraint(MPConstraint *constraint) override
Definition: scip_interface.cc:375
operations_research::MPVariable::index
int index() const
Returns the index of the variable in the MPSolver::variables_.
Definition: linear_solver.h:1073
operations_research::MPSolver::Objective
const MPObjective & Objective() const
Returns the objective object.
Definition: linear_solver.h:416
operations_research::MPSolver::UNBOUNDED
@ UNBOUNDED
proven unbounded.
Definition: linear_solver.h:435
operations_research::SCIPInterface::Reset
void Reset() override
Definition: scip_interface.cc:224
operations_research::ScipMPCallbackContext::AddLazyConstraint
void AddLazyConstraint(const LinearRange &lazy_constraint) override
Definition: scip_interface.cc:1029
scip_helper_macros.h
operations_research::SCIPInterface::SupportsCallbacks
bool SupportsCallbacks() const override
Definition: scip_interface.cc:142
logging.h
operations_research::MPSolverInterface::quiet_
bool quiet_
Definition: linear_solver.h:1735
operations_research::MPSolverInterface::last_constraint_index_
int last_constraint_index_
Definition: linear_solver.h:1724
operations_research::MPSolver
This mathematical programming (MP) solver class is the main class though which users build and solve ...
Definition: linear_solver.h:179
operations_research::SCIPInterface::SetVariableInteger
void SetVariableInteger(int var_index, bool integer) override
Definition: scip_interface.cc:313
operations_research::ScipConstraintHandlerContext::is_pseudo_solution
bool is_pseudo_solution() const
Definition: scip_callback.h:101
value
int64 value
Definition: demon_profiler.cc:43
operations_research::MPSolverInterface::MODEL_SYNCHRONIZED
@ MODEL_SYNCHRONIZED
Definition: linear_solver.h:1525
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
operations_research::MPObjective::offset
double offset() const
Gets the constant term in the objective.
Definition: linear_solver.h:961
operations_research::SCIPInterface::nodes
int64 nodes() const override
Definition: scip_interface.cc:856
operations_research::SCIPInterface::column_status
MPSolver::BasisStatus column_status(int variable_index) const override
Definition: scip_interface.cc:91
WARNING
const int WARNING
Definition: log_severity.h:31
operations_research::MPSolverInterface::InvalidateSolutionSynchronization
void InvalidateSolutionSynchronization()
Definition: linear_solver.cc:1718
operations_research::SCIPInterface
Definition: scip_interface.cc:58
operations_research::SCIPInterface::underlying_solver
void * underlying_solver() override
Definition: scip_interface.cc:115
operations_research::MPSolverInterface
Definition: linear_solver.h:1516
legacy_scip_params.h
operations_research::MPSolver::ABNORMAL
@ ABNORMAL
abnormal, i.e., error of some kind.
Definition: linear_solver.h:437
WallTimer::Restart
void Restart()
Definition: timer.h:35
int64
int64_t int64
Definition: integral_types.h:34
operations_research::MPConstraint::index
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
Definition: linear_solver.h:1245
operations_research::SCIPInterface::SetCallback
void SetCallback(MPCallback *mp_callback) override
Definition: scip_interface.cc:1096
scip_proto_solver.h
operations_research::SCIPInterface::SetObjectiveOffset
void SetObjectiveOffset(double value) override
Definition: scip_interface.cc:400
index
int index
Definition: pack.cc:508
operations_research::MPSolverParameters
This class stores parameter settings for LP and MIP solvers.
Definition: linear_solver.h:1360
operations_research::MPConstraint
The class for constraints of a Mathematical Programming (MP) model.
Definition: linear_solver.h:1177
context
GurobiMPCallbackContext * context
Definition: gurobi_interface.cc:509
operations_research::MPSolverInterface::constraint_is_extracted
bool constraint_is_extracted(int ct_index) const
Definition: linear_solver.h:1660
operations_research::ScipMPCallbackContext::AddCut
void AddCut(const LinearRange &cutting_plane) override
Definition: scip_interface.cc:1021
operations_research::ScipConstraintHandlerContext::VariableValue
double VariableValue(const MPVariable *variable) const
Definition: scip_callback.cc:75
operations_research::MPSolverParameters::PRESOLVE_ON
@ PRESOLVE_ON
Presolve is on.
Definition: linear_solver.h:1395
DCHECK_NE
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:886
RETURN_IF_ALREADY_IN_ERROR_STATE
#define RETURN_IF_ALREADY_IN_ERROR_STATE
Definition: scip_interface.cc:274
operations_research::SCIPInterface::AddIndicatorConstraint
bool AddIndicatorConstraint(MPConstraint *ct) override
Definition: scip_interface.cc:445
operations_research::MPSolverInterface::objective_value_
double objective_value_
Definition: linear_solver.h:1729
scip_callback.h
operations_research::MPSolverParameters::GetIntegerParam
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
Definition: linear_solver.cc:1999
WallTimer::Start
void Start()
Definition: timer.h:31
operations_research::MPSolverInterface::ResetExtractionInformation
void ResetExtractionInformation()
Definition: linear_solver.cc:1665
operations_research::MPCallbackEvent
MPCallbackEvent
Definition: linear_solver_callback.h:35
operations_research::MPSolverInterface::kUnknownNumberOfIterations
static constexpr int64 kUnknownNumberOfIterations
Definition: linear_solver.h:1533
operations_research::MPSolverInterface::solver_
MPSolver *const solver_
Definition: linear_solver.h:1714
operations_research::SCIPInterface::SetVariableBounds
void SetVariableBounds(int var_index, double lb, double ub) override
Definition: scip_interface.cc:297
operations_research::SCIPInterface::InterruptSolve
bool InterruptSolve() override
Definition: scip_interface.cc:110
operations_research::MPSolver::NOT_SOLVED
@ NOT_SOLVED
not been solved yet.
Definition: linear_solver.h:441
operations_research::BuildSCIPInterface
MPSolverInterface * BuildSCIPInterface(MPSolver *const solver)
Definition: scip_interface.cc:1103
operations_research::MPSolverInterface::kUnknownNumberOfNodes
static constexpr int64 kUnknownNumberOfNodes
Definition: linear_solver.h:1536
operations_research::MPSolver::SetSolverSpecificParametersAsString
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
Definition: linear_solver.cc:346
timer.h
operations_research::MPSolverParameters::PRESOLVE
@ PRESOLVE
Advanced usage: presolve mode.
Definition: linear_solver.h:1381
operations_research::MPSolver::FREE
@ FREE
Definition: linear_solver.h:643
operations_research::MPSolverInterface::SOLUTION_SYNCHRONIZED
@ SOLUTION_SYNCHRONIZED
Definition: linear_solver.h:1528
RETURN_ABNORMAL_IF_BAD_STATUS
#define RETURN_ABNORMAL_IF_BAD_STATUS
Definition: scip_interface.cc:614
RETURN_ABNORMAL_IF_SCIP_ERROR
#define RETURN_ABNORMAL_IF_SCIP_ERROR(x)
Definition: scip_interface.cc:623
SCIPlpiGetSolverName
const char * SCIPlpiGetSolverName(void)
gets name and version of LP solver
Definition: lpi_glop.cc:137
CHECK_EQ
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:697
operations_research::MPSolverInterface::SetIntegerParamToUnsupportedValue
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
Definition: linear_solver.cc:1774
operations_research::MPSolver::time_limit
int64 time_limit() const
Definition: linear_solver.h:779
operations_research::SCIPInterface::SetCoefficient
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
Definition: scip_interface.cc:350
operations_research::MPSolver::BasisStatus
BasisStatus
Advanced usage: possible basis status values for a variable and the slack variable of a linear constr...
Definition: linear_solver.h:642
operations_research::MPSolverInterface::CheckSolutionIsSynchronizedAndExists
bool CheckSolutionIsSynchronizedAndExists() const
Definition: linear_solver.h:1634
operations_research::SCIPInterface::Solve
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
Definition: scip_interface.cc:630
operations_research::SCIPInterface::SCIPInterface
SCIPInterface(MPSolver *solver)
Definition: scip_interface.cc:217
operations_research::SCIPInterface::AddRowConstraint
void AddRowConstraint(MPConstraint *ct) override
Definition: scip_interface.cc:441
status_macros.h
operations_research::ScipMPCallbackContext::SuggestSolution
double SuggestSolution(const absl::flat_hash_map< const MPVariable *, double > &solution) override
Definition: scip_interface.cc:1037
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::ScipConstraintHandlerContext::NumNodesProcessed
int64 NumNodesProcessed() const
Definition: scip_callback.cc:80
WallTimer
Definition: timer.h:23
operations_research::SCIPInterface::DirectlySolveProto
absl::optional< MPSolutionResponse > DirectlySolveProto(const MPModelRequest &request) override
Definition: scip_interface.cc:813
operations_research::SCIPInterface::~SCIPInterface
~SCIPInterface() override
Definition: scip_interface.cc:222
operations_research::ScipMPCallbackContext::VariableValue
double VariableValue(const MPVariable *variable) override
Definition: scip_interface.cc:1016
operations_research::MPSolverInterface::SetUnsupportedIntegerParam
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
Definition: linear_solver.cc:1765
operations_research::MPSolverParameters::INCREMENTALITY_OFF
@ INCREMENTALITY_OFF
Start solve from scratch.
Definition: linear_solver.h:1411
operations_research::MPSolverInterface::sync_status_
SynchronizationStatus sync_status_
Definition: linear_solver.h:1716
DCHECK
#define DCHECK(condition)
Definition: base/logging.h:884
operations_research::LinearRange
An expression of the form:
Definition: linear_expr.h:192
operations_research::SCIPInterface::IsMIP
bool IsMIP() const override
Definition: scip_interface.cc:98
RETURN_AND_STORE_IF_SCIP_ERROR
#define RETURN_AND_STORE_IF_SCIP_ERROR(x)
Definition: scip_interface.cc:282
operations_research::MPSolver::time_limit_in_secs
double time_limit_in_secs() const
Definition: linear_solver.h:789
operations_research::MPSOLVER_NOT_SOLVED
@ MPSOLVER_NOT_SOLVED
Definition: linear_solver.pb.h:233
operations_research::MPSolver::ResultStatus
ResultStatus
The status of solving the problem.
Definition: linear_solver.h:427
operations_research::MPSolverInterface::variable_is_extracted
bool variable_is_extracted(int var_index) const
Definition: linear_solver.h:1654
operations_research::ScipMPCallbackContext::Event
MPCallbackEvent Event() override
Definition: scip_interface.cc:1005
operations_research::ScipConstraintHandlerForMPCallback::SeparateIntegerSolution
std::vector< CallbackRangeConstraint > SeparateIntegerSolution(const ScipConstraintHandlerContext &context, const EmptyStruct &) override
Definition: scip_interface.cc:1082
operations_research::MPSolverInterface::ExtractModel
void ExtractModel()
Definition: linear_solver.cc:1637
operations_research::SCIPInterface::ClearObjective
void ClearObjective() override
Definition: scip_interface.cc:405
operations_research::MPSolverInterface::SetMIPParameters
void SetMIPParameters(const MPSolverParameters &param)
Definition: linear_solver.cc:1754
operations_research::ScipConstraintHandlerForMPCallback
Definition: scip_interface.cc:199
operations_research::ScipMPCallbackContext
Definition: scip_interface.cc:998
operations_research::ScipMPCallbackContext::ScipMPCallbackContext
ScipMPCallbackContext(const ScipConstraintHandlerContext *scip_context, bool at_integer_solution)
Definition: scip_interface.cc:1000
operations_research::MPSolverInterface::set_variable_as_extracted
void set_variable_as_extracted(int var_index, bool extracted)
Definition: linear_solver.h:1657
operations_research::MPSolverParameters::SCALING
@ SCALING
Advanced usage: enable or disable matrix scaling.
Definition: linear_solver.h:1387
coefficient
int64 coefficient
Definition: routing_search.cc:972
operations_research::MPSolverParameters::IntegerParam
IntegerParam
Enumeration of parameters that take integer or categorical values.
Definition: linear_solver.h:1379
operations_research::SCIPInterface::SetOptimizationDirection
void SetOptimizationDirection(bool maximize) override
Definition: scip_interface.cc:289
operations_research::SCIPInterface::row_status
MPSolver::BasisStatus row_status(int constraint_index) const override
Definition: scip_interface.cc:87
ABSL_FLAG
ABSL_FLAG(bool, scip_feasibility_emphasis, false, "When true, emphasize search towards feasibility. This may or " "may not result in speedups in some problems.")
operations_research::MPSolverInterface::last_variable_index_
int last_variable_index_
Definition: linear_solver.h:1726
SCIP_TO_STATUS
#define SCIP_TO_STATUS(x)
Definition: scip_helper_macros.h:39
operations_research::MPSolverParameters::INCREMENTALITY
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
Definition: linear_solver.h:1385
operations_research::CallbackRangeConstraint
Definition: scip_callback.h:109
operations_research::SCIPInterface::IsLP
bool IsLP() const override
Definition: scip_interface.cc:97
operations_research::MPVariable
The class for variables of a Mathematical Programming (MP) model.
Definition: linear_solver.h:1052
hash.h
linear_solver.h
A C++ wrapper that provides a simple and unified interface to several linear programming and mixed in...
operations_research::SCIPInterface::ExtractNewConstraints
void ExtractNewConstraints() override
Definition: scip_interface.cc:497
operations_research::SCIPInterface::AddVariable
void AddVariable(MPVariable *var) override
Definition: scip_interface.cc:450
operations_research::SCIPInterface::SolverVersion
std::string SolverVersion() const override
Definition: scip_interface.cc:104
operations_research::MPSolverInterface::SetCommonParameters
void SetCommonParameters(const MPSolverParameters &param)
Definition: linear_solver.cc:1733
WallTimer::GetDuration
absl::Duration GetDuration() const
Definition: timer.h:48
operations_research::ScipMPCallbackContext::NumExploredNodes
int64 NumExploredNodes() override
Definition: scip_interface.cc:1042
operations_research::MPSolver::INFEASIBLE
@ INFEASIBLE
proven infeasible.
Definition: linear_solver.h:433
operations_research::SCIPInterface::NextSolution
bool NextSolution() override
Definition: scip_interface.cc:835
operations_research::SCIPInterface::SetConstraintBounds
void SetConstraintBounds(int row_index, double lb, double ub) override
Definition: scip_interface.cc:334
linear_solver_callback.h
operations_research::MPSolverParameters::PRIMAL
@ PRIMAL
Primal simplex.
Definition: linear_solver.h:1403
operations_research::ScipConstraintHandlerForMPCallback::ScipConstraintHandlerForMPCallback
ScipConstraintHandlerForMPCallback(MPCallback *mp_callback)
Definition: scip_interface.cc:1064
operations_research::MPSolverParameters::PRESOLVE_OFF
@ PRESOLVE_OFF
Presolve is off.
Definition: linear_solver.h:1393
operations_research::SCIPInterface::iterations
int64 iterations() const override
Definition: scip_interface.cc:849
operations_research::MPSolverInterface::MUST_RELOAD
@ MUST_RELOAD
Definition: linear_solver.h:1521
operations_research::MPSolverInterface::CheckSolutionIsSynchronized
bool CheckSolutionIsSynchronized() const
Definition: linear_solver.cc:1673
operations_research::MPSolverInterface::result_status_
MPSolver::ResultStatus result_status_
Definition: linear_solver.h:1719
operations_research::CallbackRangeConstraint::range
LinearRange range
Definition: scip_callback.h:110
CHECK
#define CHECK(condition)
Definition: base/logging.h:495
operations_research::MPSolverInterface::maximize_
bool maximize_
Definition: linear_solver.h:1721
commandlineflags.h
operations_research::MPSolverInterface::set_constraint_as_extracted
void set_constraint_as_extracted(int ct_index, bool extracted)
Definition: linear_solver.h:1663
operations_research::MPSolver::GetNumThreads
int GetNumThreads() const
Returns the number of threads to be used during solve.
Definition: linear_solver.h:610
RETURN_IF_SCIP_ERROR
#define RETURN_IF_SCIP_ERROR(x)
Definition: scip_helper_macros.h:43
parameters
SatParameters parameters
Definition: cp_model_fz_solver.cc:108
operations_research::ScipMPCallbackContext::constraints_added
const std::vector< CallbackRangeConstraint > & constraints_added()
Definition: scip_interface.cc:1053
operations_research::MPSolverParameters::DUAL
@ DUAL
Dual simplex.
Definition: linear_solver.h:1401
operations_research::MPSolverParameters::BARRIER
@ BARRIER
Barrier algorithm.
Definition: linear_solver.h:1405
operations_research::MPSolver::FEASIBLE
@ FEASIBLE
feasible, or stopped by limit.
Definition: linear_solver.h:431
operations_research::SCIPInterface::BranchingPriorityChangedForVariable
void BranchingPriorityChangedForVariable(int var_index) override
Definition: scip_interface.cc:429
operations_research::MPSolverInterface::best_objective_bound_
double best_objective_bound_
Definition: linear_solver.h:1732
operations_research::ScipConstraintHandlerContext
Definition: scip_callback.h:82