OR-Tools  8.0
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"
37 #include "scip/cons_indicator.h"
38 #include "scip/scip.h"
39 #include "scip/scip_prob.h"
40 #include "scip/scipdefplugins.h"
41 
42 DEFINE_bool(scip_feasibility_emphasis, false,
43  "When true, emphasize search towards feasibility. This may or "
44  "may not result in speedups in some problems.");
45 
46 namespace operations_research {
47 
49  public:
50  explicit SCIPInterface(MPSolver* solver);
51  ~SCIPInterface() override;
52 
53  void SetOptimizationDirection(bool maximize) override;
54  MPSolver::ResultStatus Solve(const MPSolverParameters& param) override;
55  absl::optional<MPSolutionResponse> DirectlySolveProto(
56  const MPModelRequest& request) override;
57  void Reset() override;
58 
59  void SetVariableBounds(int var_index, double lb, double ub) override;
60  void SetVariableInteger(int var_index, bool integer) override;
61  void SetConstraintBounds(int row_index, double lb, double ub) override;
62 
63  void AddRowConstraint(MPConstraint* ct) override;
64  bool AddIndicatorConstraint(MPConstraint* ct) override;
65  void AddVariable(MPVariable* var) override;
66  void SetCoefficient(MPConstraint* constraint, const MPVariable* variable,
67  double new_value, double old_value) override;
68  void ClearConstraint(MPConstraint* constraint) override;
69  void SetObjectiveCoefficient(const MPVariable* variable,
70  double coefficient) override;
71  void SetObjectiveOffset(double value) override;
72  void ClearObjective() override;
73  void BranchingPriorityChangedForVariable(int var_index) override;
74 
75  int64 iterations() const override;
76  int64 nodes() const override;
77  double best_objective_bound() const override;
78  MPSolver::BasisStatus row_status(int constraint_index) const override {
79  LOG(DFATAL) << "Basis status only available for continuous problems";
80  return MPSolver::FREE;
81  }
82  MPSolver::BasisStatus column_status(int variable_index) const override {
83  LOG(DFATAL) << "Basis status only available for continuous problems";
84  return MPSolver::FREE;
85  }
86 
87  bool IsContinuous() const override { return false; }
88  bool IsLP() const override { return false; }
89  bool IsMIP() const override { return true; }
90 
91  void ExtractNewVariables() override;
92  void ExtractNewConstraints() override;
93  void ExtractObjective() override;
94 
95  std::string SolverVersion() const override {
96  return absl::StrFormat("SCIP %d.%d.%d [LP solver: %s]", SCIPmajorVersion(),
97  SCIPminorVersion(), SCIPtechVersion(),
99  }
100 
101  bool InterruptSolve() override {
102  if (scip_ == nullptr) return true; // NOTE(user): Is this weird?
103  return SCIPinterruptSolve(scip_) == SCIP_OKAY;
104  }
105 
106  void* underlying_solver() override { return reinterpret_cast<void*>(scip_); }
107 
108  private:
109  void SetParameters(const MPSolverParameters& param) override;
110  void SetRelativeMipGap(double value) override;
111  void SetPrimalTolerance(double value) override;
112  void SetDualTolerance(double value) override;
113  void SetPresolveMode(int presolve) override;
114  void SetScalingMode(int scaling) override;
115  void SetLpAlgorithm(int lp_algorithm) override;
116 
117  // SCIP parameters allow to lower and upper bound the number of threads used
118  // (via "parallel/minnthreads" and "parallel/maxnthread", respectively). Here,
119  // we interpret "num_threads" to mean "parallel/maxnthreads", as this is what
120  // most clients probably want to do. To change "parallel/minnthreads" use
121  // SetSolverSpecificParametersAsString(). However, one must change
122  // "parallel/maxnthread" with SetNumThreads() because only this will inform
123  // the interface to run SCIPsolveConcurrent() instead of SCIPsolve() which is
124  // necessery to enable multi-threading.
125  absl::Status SetNumThreads(int num_threads) override;
126 
127  bool SetSolverSpecificParametersAsString(
128  const std::string& parameters) override;
129 
130  void SetUnsupportedIntegerParam(
131  MPSolverParameters::IntegerParam param) override;
132  void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param,
133  int value) override;
134  // Copy sol from SCIP to MPSolver.
135  void SetSolution(SCIP_SOL* solution);
136  absl::Status CreateSCIP();
137  void DeleteSCIP();
138 
139  // SCIP has many internal checks (many of which are numerical) that can fail
140  // during various phases: upon startup, when loading the model, when solving,
141  // etc. Often, the user is meant to stop at the first error, but since most
142  // of the linear solver interface API doesn't support "error reporting", we
143  // store a potential error status here.
144  // If this status isn't OK, then most operations will silently be cancelled.
145  absl::Status status_;
146 
147  SCIP* scip_;
148  std::vector<SCIP_VAR*> scip_variables_;
149  std::vector<SCIP_CONS*> scip_constraints_;
150  bool branching_priority_reset_ = false;
151 };
152 
154  : MPSolverInterface(solver), scip_(nullptr) {
155  status_ = CreateSCIP();
156 }
157 
158 SCIPInterface::~SCIPInterface() { DeleteSCIP(); }
159 
161  DeleteSCIP();
162  status_ = CreateSCIP();
164 }
165 
166 absl::Status SCIPInterface::CreateSCIP() {
167  RETURN_IF_SCIP_ERROR(SCIPcreate(&scip_));
168  RETURN_IF_SCIP_ERROR(SCIPincludeDefaultPlugins(scip_));
169  // Set the emphasis to enum SCIP_PARAMEMPHASIS_FEASIBILITY. Do not print
170  // the new parameter (quiet = true).
171  if (FLAGS_scip_feasibility_emphasis) {
172  RETURN_IF_SCIP_ERROR(SCIPsetEmphasis(scip_, SCIP_PARAMEMPHASIS_FEASIBILITY,
173  /*quiet=*/true));
174  }
175  // Default clock type. We use wall clock time because getting CPU user seconds
176  // involves calling times() which is very expensive.
177  // NOTE(user): Also, time limit based on CPU user seconds is *NOT* thread
178  // safe. We observed that different instances of SCIP running concurrently
179  // in different threads consume the time limit *together*. E.g., 2 threads
180  // running SCIP with time limit 10s each will both terminate after ~5s.
182  SCIPsetIntParam(scip_, "timing/clocktype", SCIP_CLOCKTYPE_WALL));
183  RETURN_IF_SCIP_ERROR(SCIPcreateProb(scip_, solver_->name_.c_str(), nullptr,
184  nullptr, nullptr, nullptr, nullptr,
185  nullptr, nullptr));
186  RETURN_IF_SCIP_ERROR(SCIPsetObjsense(
187  scip_, maximize_ ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
188  return absl::OkStatus();
189 }
190 
191 void SCIPInterface::DeleteSCIP() {
192  // NOTE(user): DeleteSCIP() shouldn't "give up" mid-stage if it fails, since
193  // it might be the user's chance to reset the solver to start fresh without
194  // errors. The current code isn't perfect, since some CHECKs() remain, but
195  // hopefully they'll never be triggered in practice.
196  CHECK(scip_ != nullptr);
197  for (int i = 0; i < scip_variables_.size(); ++i) {
198  CHECK_EQ(SCIPreleaseVar(scip_, &scip_variables_[i]), SCIP_OKAY);
199  }
200  scip_variables_.clear();
201  for (int j = 0; j < scip_constraints_.size(); ++j) {
202  CHECK_EQ(SCIPreleaseCons(scip_, &scip_constraints_[j]), SCIP_OKAY);
203  }
204  scip_constraints_.clear();
205  CHECK_EQ(SCIPfree(&scip_), SCIP_OKAY);
206  scip_ = nullptr;
207 }
208 
209 #define RETURN_IF_ALREADY_IN_ERROR_STATE \
210  do { \
211  if (!status_.ok()) { \
212  LOG_EVERY_N(INFO, 10) << "Early abort: SCIP is in error state."; \
213  return; \
214  } \
215  } while (false)
216 
217 #define RETURN_AND_STORE_IF_SCIP_ERROR(x) \
218  do { \
219  status_ = SCIP_TO_STATUS(x); \
220  if (!status_.ok()) return; \
221  } while (false)
222 
223 // Not cached.
227  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
228  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPsetObjsense(
229  scip_, maximize ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
230 }
231 
232 void SCIPInterface::SetVariableBounds(int var_index, double lb, double ub) {
235  if (variable_is_extracted(var_index)) {
236  // Not cached if the variable has been extracted.
237  DCHECK_LT(var_index, last_variable_index_);
238  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
240  SCIPchgVarLb(scip_, scip_variables_[var_index], lb));
242  SCIPchgVarUb(scip_, scip_variables_[var_index], ub));
243  } else {
245  }
246 }
247 
248 void SCIPInterface::SetVariableInteger(int var_index, bool integer) {
251  if (variable_is_extracted(var_index)) {
252  // Not cached if the variable has been extracted.
253  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
254 #if (SCIP_VERSION >= 210)
255  SCIP_Bool infeasible = false;
256  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarType(
257  scip_, scip_variables_[var_index],
258  integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS, &infeasible));
259 #else
260  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarType(
261  scip_, scip_variables_[var_index],
262  integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS));
263 #endif // SCIP_VERSION >= 210
264  } else {
266  }
267 }
268 
269 void SCIPInterface::SetConstraintBounds(int index, double lb, double ub) {
273  // Not cached if the row has been extracted.
274  DCHECK_LT(index, last_constraint_index_);
275  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
277  SCIPchgLhsLinear(scip_, scip_constraints_[index], lb));
279  SCIPchgRhsLinear(scip_, scip_constraints_[index], ub));
280  } else {
282  }
283 }
284 
286  const MPVariable* variable, double new_value,
287  double old_value) {
290  if (variable_is_extracted(variable->index()) &&
291  constraint_is_extracted(constraint->index())) {
292  // The modification of the coefficient for an extracted row and
293  // variable is not cached.
294  DCHECK_LT(constraint->index(), last_constraint_index_);
295  DCHECK_LT(variable->index(), last_variable_index_);
296  // SCIP does not allow to set a coefficient directly, so we add the
297  // difference between the new and the old value instead.
298  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
299  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCoefLinear(
300  scip_, scip_constraints_[constraint->index()],
301  scip_variables_[variable->index()], new_value - old_value));
302  } else {
303  // The modification of an unextracted row or variable is cached
304  // and handled in ExtractModel.
306  }
307 }
308 
309 // Not cached
313  const int constraint_index = constraint->index();
314  // Constraint may not have been extracted yet.
315  if (!constraint_is_extracted(constraint_index)) return;
316  for (const auto& entry : constraint->coefficients_) {
317  const int var_index = entry.first->index();
318  const double old_coef_value = entry.second;
319  DCHECK(variable_is_extracted(var_index));
320  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
321  // Set coefficient to zero by substracting the old coefficient value.
323  SCIPaddCoefLinear(scip_, scip_constraints_[constraint_index],
324  scip_variables_[var_index], -old_coef_value));
325  }
326 }
327 
328 // Cached
330  double coefficient) {
332 }
333 
334 // Cached
337 }
338 
339 // Clear objective of all its terms.
343 
345  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
346  // Clear linear terms
347  for (const auto& entry : solver_->objective_->coefficients_) {
348  const int var_index = entry.first->index();
349  // Variable may have not been extracted yet.
350  if (!variable_is_extracted(var_index)) {
351  DCHECK_NE(MODEL_SYNCHRONIZED, sync_status_);
352  } else {
354  SCIPchgVarObj(scip_, scip_variables_[var_index], 0.0));
355  }
356  }
357  // Note: we don't clear the objective offset here because it's not necessary
358  // (it's always reset anyway in ExtractObjective) and we sometimes run into
359  // crashes when clearing the whole model (see
360  // http://test/OCL:253365573:BASE:253566457:1560777456754:e181f4ab).
361  // It's not worth to spend time investigating this issue.
362 }
363 
365  // As of 2019-05, SCIP does not support setting branching priority for
366  // variables in models that have already been solved. Therefore, we force
367  // reset the model when setting the priority on an already extracted variable.
368  // Note that this is a more drastic step than merely changing the sync_status.
369  // This may be slightly conservative, as it is technically possible that
370  // the extraction has occurred without a call to Solve().
371  if (variable_is_extracted(var_index)) {
372  branching_priority_reset_ = true;
373  }
374 }
375 
378 }
379 
382  return true;
383 }
384 
386 
389  int total_num_vars = solver_->variables_.size();
390  if (total_num_vars > last_variable_index_) {
391  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
392  // Define new variables
393  for (int j = last_variable_index_; j < total_num_vars; ++j) {
394  MPVariable* const var = solver_->variables_[j];
395  DCHECK(!variable_is_extracted(j));
396  set_variable_as_extracted(j, true);
397  SCIP_VAR* scip_var = nullptr;
398  // The true objective coefficient will be set later in ExtractObjective.
399  double tmp_obj_coef = 0.0;
400  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateVar(
401  scip_, &scip_var, var->name().c_str(), var->lb(), var->ub(),
402  tmp_obj_coef,
403  var->integer() ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS, true,
404  false, nullptr, nullptr, nullptr, nullptr, nullptr));
405  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddVar(scip_, scip_var));
406  scip_variables_.push_back(scip_var);
407  const int branching_priority = var->branching_priority();
408  if (branching_priority != 0) {
409  const int index = var->index();
410  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPchgVarBranchPriority(
411  scip_, scip_variables_[index], branching_priority));
412  }
413  }
414  // Add new variables to existing constraints.
415  for (int i = 0; i < last_constraint_index_; i++) {
416  MPConstraint* const ct = solver_->constraints_[i];
417  for (const auto& entry : ct->coefficients_) {
418  const int var_index = entry.first->index();
419  DCHECK(variable_is_extracted(var_index));
420  if (var_index >= last_variable_index_) {
421  // The variable is new, so we know the previous coefficient
422  // value was 0 and we can directly add the coefficient.
424  SCIPaddCoefLinear(scip_, scip_constraints_[i],
425  scip_variables_[var_index], entry.second));
426  }
427  }
428  }
429  }
430 }
431 
434  int total_num_rows = solver_->constraints_.size();
435  if (last_constraint_index_ < total_num_rows) {
436  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
437  // Find the length of the longest row.
438  int max_row_length = 0;
439  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
440  MPConstraint* const ct = solver_->constraints_[i];
441  DCHECK(!constraint_is_extracted(i));
443  if (ct->coefficients_.size() > max_row_length) {
444  max_row_length = ct->coefficients_.size();
445  }
446  }
447  std::unique_ptr<SCIP_VAR*[]> vars(new SCIP_VAR*[max_row_length]);
448  std::unique_ptr<double[]> coeffs(new double[max_row_length]);
449  // Add each new constraint.
450  for (int i = last_constraint_index_; i < total_num_rows; ++i) {
451  MPConstraint* const ct = solver_->constraints_[i];
452  DCHECK(constraint_is_extracted(i));
453  const int size = ct->coefficients_.size();
454  int j = 0;
455  for (const auto& entry : ct->coefficients_) {
456  const int var_index = entry.first->index();
457  DCHECK(variable_is_extracted(var_index));
458  vars[j] = scip_variables_[var_index];
459  coeffs[j] = entry.second;
460  j++;
461  }
462  SCIP_CONS* scip_constraint = nullptr;
463  const bool is_lazy = ct->is_lazy();
464  if (ct->indicator_variable() != nullptr) {
465  const int ind_index = ct->indicator_variable()->index();
466  DCHECK(variable_is_extracted(ind_index));
467  SCIP_VAR* ind_var = scip_variables_[ind_index];
468  if (ct->indicator_value() == 0) {
470  SCIPgetNegatedVar(scip_, scip_variables_[ind_index], &ind_var));
471  }
472 
473  if (ct->ub() < std::numeric_limits<double>::infinity()) {
474  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsIndicator(
475  scip_, &scip_constraint, ct->name().c_str(), ind_var, size,
476  vars.get(), coeffs.get(), ct->ub(),
477  /*initial=*/!is_lazy,
478  /*separate=*/true,
479  /*enforce=*/true,
480  /*check=*/true,
481  /*propagate=*/true,
482  /*local=*/false,
483  /*dynamic=*/false,
484  /*removable=*/is_lazy,
485  /*stickingatnode=*/false));
486  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint));
487  scip_constraints_.push_back(scip_constraint);
488  }
489  if (ct->lb() > -std::numeric_limits<double>::infinity()) {
490  for (int i = 0; i < size; ++i) {
491  coeffs[i] *= -1;
492  }
493  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsIndicator(
494  scip_, &scip_constraint, ct->name().c_str(), ind_var, size,
495  vars.get(), coeffs.get(), -ct->lb(),
496  /*initial=*/!is_lazy,
497  /*separate=*/true,
498  /*enforce=*/true,
499  /*check=*/true,
500  /*propagate=*/true,
501  /*local=*/false,
502  /*dynamic=*/false,
503  /*removable=*/is_lazy,
504  /*stickingatnode=*/false));
505  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint));
506  scip_constraints_.push_back(scip_constraint);
507  }
508  } else {
509  // See
510  // http://scip.zib.de/doc/html/cons__linear_8h.php#aa7aed137a4130b35b168812414413481
511  // for an explanation of the parameters.
512  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPcreateConsLinear(
513  scip_, &scip_constraint, ct->name().c_str(), size, vars.get(),
514  coeffs.get(), ct->lb(), ct->ub(),
515  /*initial=*/!is_lazy,
516  /*separate=*/true,
517  /*enforce=*/true,
518  /*check=*/true,
519  /*propagate=*/true,
520  /*local=*/false,
521  /*modifiable=*/false,
522  /*dynamic=*/false,
523  /*removable=*/is_lazy,
524  /*stickingatnode=*/false));
525  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddCons(scip_, scip_constraint));
526  scip_constraints_.push_back(scip_constraint);
527  }
528  }
529  }
530 }
531 
534  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPfreeTransform(scip_));
535  // Linear objective: set objective coefficients for all variables (some might
536  // have been modified).
537  for (const auto& entry : solver_->objective_->coefficients_) {
538  const int var_index = entry.first->index();
539  const double obj_coef = entry.second;
541  SCIPchgVarObj(scip_, scip_variables_[var_index], obj_coef));
542  }
543 
544  // Constant term: change objective offset.
545  RETURN_AND_STORE_IF_SCIP_ERROR(SCIPaddOrigObjoffset(
546  scip_, solver_->Objective().offset() - SCIPgetOrigObjoffset(scip_)));
547 }
548 
549 #define RETURN_ABNORMAL_IF_BAD_STATUS \
550  do { \
551  if (!status_.ok()) { \
552  LOG_IF(INFO, solver_->OutputIsEnabled()) \
553  << "Invalid SCIP status: " << status_; \
554  return result_status_ = MPSolver::ABNORMAL; \
555  } \
556  } while (false)
557 
558 #define RETURN_ABNORMAL_IF_SCIP_ERROR(x) \
559  do { \
560  RETURN_ABNORMAL_IF_BAD_STATUS; \
561  status_ = SCIP_TO_STATUS(x); \
562  RETURN_ABNORMAL_IF_BAD_STATUS; \
563  } while (false);
564 
566  // "status_" may encode a variety of failure scenarios, many of which would
567  // correspond to another MPResultStatus than ABNORMAL, but since SCIP is a
568  // moving target, we use the most likely error code here (abnormalities,
569  // often numeric), and rely on the user enabling output to see more details.
571 
572  WallTimer timer;
573  timer.Start();
574 
575  // Note that SCIP does not provide any incrementality.
576  // TODO(user): Is that still true now (2018) ?
579  branching_priority_reset_) {
580  Reset();
581  branching_priority_reset_ = false;
582  }
583 
584  // Set log level.
585  SCIPsetMessagehdlrQuiet(scip_, quiet_);
586 
587  // Special case if the model is empty since SCIP expects a non-empty model.
588  if (solver_->variables_.empty() && solver_->constraints_.empty()) {
592  return result_status_;
593  }
594 
595  ExtractModel();
596  VLOG(1) << absl::StrFormat("Model built in %s.",
597  absl::FormatDuration(timer.GetDuration()));
598 
599  // Time limit.
600  if (solver_->time_limit() != 0) {
601  VLOG(1) << "Setting time limit = " << solver_->time_limit() << " ms.";
603  SCIPsetRealParam(scip_, "limits/time", solver_->time_limit_in_secs()));
604  } else {
605  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPresetParam(scip_, "limits/time"));
606  }
607 
608  // We first set our internal MPSolverParameters from param and then set any
609  // user specified internal solver, ie. SCIP, parameters via
610  // solver_specific_parameter_string_.
611  // Default MPSolverParameters can override custom parameters (for example for
612  // presolving) and therefore we apply MPSolverParameters first.
613  SetParameters(param);
615  solver_->solver_specific_parameter_string_);
616 
617  // Use the solution hint if any.
618  if (!solver_->solution_hint_.empty()) {
619  SCIP_SOL* solution;
620  bool is_solution_partial = false;
621  const int num_vars = solver_->variables_.size();
622  if (solver_->solution_hint_.size() != num_vars) {
623  // We start by creating an empty partial solution.
625  SCIPcreatePartialSol(scip_, &solution, nullptr));
626  is_solution_partial = true;
627  } else {
628  // We start by creating the all-zero solution.
629  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPcreateSol(scip_, &solution, nullptr));
630  }
631 
632  // Fill the other variables from the given solution hint.
633  for (const std::pair<const MPVariable*, double>& p :
634  solver_->solution_hint_) {
635  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPsetSolVal(
636  scip_, solution, scip_variables_[p.first->index()], p.second));
637  }
638 
639  if (!is_solution_partial) {
640  SCIP_Bool is_feasible;
641  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPcheckSol(
642  scip_, solution, /*printreason=*/false, /*completely=*/true,
643  /*checkbounds=*/true, /*checkintegrality=*/true, /*checklprows=*/true,
644  &is_feasible));
645  VLOG(1) << "Solution hint is "
646  << (is_feasible ? "FEASIBLE" : "INFEASIBLE");
647  }
648 
649  // TODO(user): I more or less copied this from the SCIPreadSol() code that
650  // reads a solution from a file. I am not sure what SCIPisTransformed() is
651  // or what is the difference between the try and add version. In any case
652  // this seems to always call SCIPaddSolFree() for now and it works.
653  SCIP_Bool is_stored;
654  if (!is_solution_partial && SCIPisTransformed(scip_)) {
655  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPtrySolFree(
656  scip_, &solution, /*printreason=*/false, /*completely=*/true,
657  /*checkbounds=*/true, /*checkintegrality=*/true, /*checklprows=*/true,
658  &is_stored));
659  } else {
661  SCIPaddSolFree(scip_, &solution, &is_stored));
662  }
663  }
664 
665  // Solve.
666  timer.Restart();
668  ? SCIPsolveConcurrent(scip_)
669  : SCIPsolve(scip_));
670  VLOG(1) << absl::StrFormat("Solved in %s.",
671  absl::FormatDuration(timer.GetDuration()));
672 
673  // Get the results.
674  SCIP_SOL* const solution = SCIPgetBestSol(scip_);
675  if (solution != nullptr) {
676  // If optimal or feasible solution is found.
677  SetSolution(solution);
678  } else {
679  VLOG(1) << "No feasible solution found.";
680  }
681 
682  // Check the status: optimal, infeasible, etc.
683  SCIP_STATUS scip_status = SCIPgetStatus(scip_);
684  switch (scip_status) {
685  case SCIP_STATUS_OPTIMAL:
687  break;
688  case SCIP_STATUS_GAPLIMIT:
689  // To be consistent with the other solvers.
691  break;
692  case SCIP_STATUS_INFEASIBLE:
694  break;
695  case SCIP_STATUS_UNBOUNDED:
697  break;
698  case SCIP_STATUS_INFORUNBD:
699  // TODO(user): We could introduce our own "infeasible or
700  // unbounded" status.
702  break;
703  default:
704  if (solution != nullptr) {
706  } else if (scip_status == SCIP_STATUS_TIMELIMIT ||
707  scip_status == SCIP_STATUS_TOTALNODELIMIT) {
709  } else {
711  }
712  break;
713  }
714 
715  RETURN_ABNORMAL_IF_SCIP_ERROR(SCIPresetParams(scip_));
716 
718  return result_status_;
719 }
720 
721 void SCIPInterface::SetSolution(SCIP_SOL* solution) {
722  objective_value_ = SCIPgetSolOrigObj(scip_, solution);
723  VLOG(1) << "objective=" << objective_value_;
724  for (int i = 0; i < solver_->variables_.size(); ++i) {
725  MPVariable* const var = solver_->variables_[i];
726  const int var_index = var->index();
727  const double val =
728  SCIPgetSolVal(scip_, solution, scip_variables_[var_index]);
729  var->set_solution_value(val);
730  VLOG(3) << var->name() << "=" << val;
731  }
732 }
733 
734 absl::optional<MPSolutionResponse> SCIPInterface::DirectlySolveProto(
735  const MPModelRequest& request) {
736  // ScipSolveProto doesn't solve concurrently.
737  if (solver_->GetNumThreads() > 1) return absl::nullopt;
738 
739  const auto status_or = ScipSolveProto(request);
740  if (status_or.ok()) return status_or.value();
741  // Special case: if something is not implemented yet, fall back to solving
742  // through MPSolver.
743  if (absl::IsUnimplemented(status_or.status())) return absl::nullopt;
744 
745  if (request.enable_internal_solver_output()) {
746  LOG(INFO) << "Invalid SCIP status: " << status_or.status();
747  }
748  MPSolutionResponse response;
749  response.set_status(MPSOLVER_NOT_SOLVED);
750  response.set_status_str(status_or.status().ToString());
751  return response;
752 }
753 
755  // NOTE(user): As of 2018-12 it doesn't run in the stubby server, and is
756  // a specialized call, so it's ok to crash if the status is broken.
758  return SCIPgetNLPIterations(scip_);
759 }
760 
762  // NOTE(user): Same story as iterations(): it's OK to crash here.
764  // This is the total number of nodes used in the solve, potentially across
765  // multiple branch-and-bound trees. Use limits/totalnodes (rather than
766  // limits/nodes) to control this value.
767  return SCIPgetNTotalNodes(scip_);
768 }
769 
771  // NOTE(user): Same story as iterations(): it's OK to crash here.
774  }
775  if (solver_->variables_.empty() && solver_->constraints_.empty()) {
776  // Special case for empty model.
777  return solver_->Objective().offset();
778  } else {
779  return SCIPgetDualbound(scip_);
780  }
781 }
782 
783 void SCIPInterface::SetParameters(const MPSolverParameters& param) {
784  SetCommonParameters(param);
785  SetMIPParameters(param);
786 }
787 
788 void SCIPInterface::SetRelativeMipGap(double value) {
789  // NOTE(user): We don't want to call RETURN_IF_ALREADY_IN_ERROR_STATE here,
790  // because even if the solver is in an error state, the user might be setting
791  // some parameters and then "restoring" the solver to a non-error state by
792  // calling Reset(), which should *not* reset the parameters.
793  // So we want the parameter-setting functions to be resistant to being in an
794  // error state, essentially. What we do is:
795  // - we call the parameter-setting function anyway (I'm assuming that SCIP
796  // won't crash even if we're in an error state. I did *not* verify this).
797  // - if that call yielded an error *and* we weren't already in an error state,
798  // set the state to that error we just got.
799  const auto status =
800  SCIP_TO_STATUS(SCIPsetRealParam(scip_, "limits/gap", value));
801  if (status_.ok()) status_ = status;
802 }
803 
804 void SCIPInterface::SetPrimalTolerance(double value) {
805  // SCIP automatically updates numerics/lpfeastol if the primal tolerance is
806  // tighter. Doing that it unconditionally logs this modification to stderr. By
807  // setting numerics/lpfeastol first we avoid this unwanted log.
808  // double current_lpfeastol = 0.0;
809  // CHECK_EQ(SCIP_OKAY,
810  // SCIPgetRealParam(scip_, "numerics/lpfeastol", &current_lpfeastol));
811  // if (value < current_lpfeastol) {
812  // // See the NOTE on SetRelativeMipGap().
813  // const auto status =
814  // SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/lpfeastol", value));
815  // if (status_.ok()) status_ = status;
816  // }
817  // See the NOTE on SetRelativeMipGap().
818  const auto status =
819  SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/feastol", value));
820  if (status_.ok()) status_ = status;
821 }
822 
823 void SCIPInterface::SetDualTolerance(double value) {
824  const auto status =
825  SCIP_TO_STATUS(SCIPsetRealParam(scip_, "numerics/dualfeastol", value));
826  if (status_.ok()) status_ = status;
827 }
828 
829 void SCIPInterface::SetPresolveMode(int presolve) {
830  // See the NOTE on SetRelativeMipGap().
831  switch (presolve) {
833  const auto status =
834  SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", 0));
835  if (status_.ok()) status_ = status;
836  return;
837  }
839  const auto status =
840  SCIP_TO_STATUS(SCIPsetIntParam(scip_, "presolving/maxrounds", -1));
841  if (status_.ok()) status_ = status;
842  return;
843  }
844  default: {
845  SetIntegerParamToUnsupportedValue(MPSolverParameters::PRESOLVE, presolve);
846  return;
847  }
848  }
849 }
850 
851 void SCIPInterface::SetScalingMode(int scaling) {
852  SetUnsupportedIntegerParam(MPSolverParameters::SCALING);
853 }
854 
855 // Only the root LP algorithm is set as setting the node LP to a
856 // non-default value rarely is beneficial. The node LP algorithm could
857 // be set as well with "lp/resolvealgorithm".
858 void SCIPInterface::SetLpAlgorithm(int lp_algorithm) {
859  // See the NOTE on SetRelativeMipGap().
860  switch (lp_algorithm) {
862  const auto status =
863  SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'd'));
864  if (status_.ok()) status_ = status;
865  return;
866  }
868  const auto status =
869  SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p'));
870  if (status_.ok()) status_ = status;
871  return;
872  }
874  // Barrier with crossover.
875  const auto status =
876  SCIP_TO_STATUS(SCIPsetCharParam(scip_, "lp/initalgorithm", 'p'));
877  if (status_.ok()) status_ = status;
878  return;
879  }
880  default: {
881  SetIntegerParamToUnsupportedValue(MPSolverParameters::LP_ALGORITHM,
882  lp_algorithm);
883  return;
884  }
885  }
886 }
887 
888 void SCIPInterface::SetUnsupportedIntegerParam(
891  if (status_.ok()) {
892  status_ = absl::InvalidArgumentError(absl::StrFormat(
893  "Tried to set unsupported integer parameter %d", param));
894  }
895 }
896 
897 void SCIPInterface::SetIntegerParamToUnsupportedValue(
900  if (status_.ok()) {
901  status_ = absl::InvalidArgumentError(absl::StrFormat(
902  "Tried to set integer parameter %d to unsupported value %d", param,
903  value));
904  }
905 }
906 
907 absl::Status SCIPInterface::SetNumThreads(int num_threads) {
908  if (SetSolverSpecificParametersAsString(
909  absl::StrFormat("parallel/maxnthreads = %d\n", num_threads))) {
910  return absl::OkStatus();
911  }
912  return absl::InternalError(
913  "Could not set parallel/maxnthreads, which may "
914  "indicate that SCIP API has changed.");
915 }
916 
917 bool SCIPInterface::SetSolverSpecificParametersAsString(
918  const std::string& parameters) {
919  const absl::Status s =
921  if (!s.ok()) {
922  LOG(WARNING) << "Failed to set SCIP parameter string: " << parameters
923  << ", error is: " << s;
924  }
925  return s.ok();
926 }
927 
929  return new SCIPInterface(solver);
930 }
931 
932 } // namespace operations_research
933 #endif // #if defined(USE_SCIP)
934 
935 #undef RETURN_AND_STORE_IF_SCIP_ERROR
936 #undef RETURN_IF_ALREADY_IN_ERROR_STATE
937 #undef RETURN_ABNORMAL_IF_BAD_STATUS
938 #undef RETURN_ABNORMAL_IF_SCIP_ERROR
operations_research::SCIPInterface::SetOptimizationDirection
void SetOptimizationDirection(bool maximize) override
Definition: scip_interface.cc:224
operations_research::MPSolverInterface::variable_is_extracted
bool variable_is_extracted(int var_index) const
Definition: linear_solver.h:1658
operations_research::SCIPInterface::SetVariableInteger
void SetVariableInteger(int var_index, bool integer) override
Definition: scip_interface.cc:248
var
IntVar * var
Definition: expr_array.cc:1858
operations_research::MPSolverParameters::GetIntegerParam
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
Definition: linear_solver.cc:1973
operations_research::MPSolverParameters::LP_ALGORITHM
@ LP_ALGORITHM
Algorithm to solve linear programs.
Definition: linear_solver.h:1381
response
SharedResponseManager * response
Definition: cp_model_solver.cc:2027
integral_types.h
operations_research::MPVariable
The class for variables of a Mathematical Programming (MP) model.
Definition: linear_solver.h:1050
operations_research::MPSolver
This mathematical programming (MP) solver class is the main class though which users build and solve ...
Definition: linear_solver.h:177
operations_research::MPSolverInterface::MUST_RELOAD
@ MUST_RELOAD
Definition: linear_solver.h:1519
operations_research::SCIPInterface::SetVariableBounds
void SetVariableBounds(int var_index, double lb, double ub) override
Definition: scip_interface.cc:232
operations_research::MPSolverParameters::PRESOLVE_OFF
@ PRESOLVE_OFF
Presolve is off.
Definition: linear_solver.h:1391
operations_research::SCIPInterface::ClearConstraint
void ClearConstraint(MPConstraint *constraint) override
Definition: scip_interface.cc:310
operations_research::MPSolverInterface::result_status_
MPSolver::ResultStatus result_status_
Definition: linear_solver.h:1723
operations_research::ScipSolveProto
absl::StatusOr< MPSolutionResponse > ScipSolveProto(const MPModelRequest &request)
Definition: scip_proto_solver.cc:740
operations_research::MPVariable::index
int index() const
Returns the index of the variable in the MPSolver::variables_.
Definition: linear_solver.h:1071
operations_research::SCIPInterface::ClearObjective
void ClearObjective() override
Definition: scip_interface.cc:340
linear_solver.pb.h
operations_research::MPConstraint
The class for constraints of a Mathematical Programming (MP) model.
Definition: linear_solver.h:1175
operations_research::SCIPInterface::SetCoefficient
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
Definition: scip_interface.cc:285
operations_research::SCIPInterface::IsMIP
bool IsMIP() const override
Definition: scip_interface.cc:89
operations_research::MPSolver::FEASIBLE
@ FEASIBLE
feasible, or stopped by limit.
Definition: linear_solver.h:429
operations_research::MPSolverInterface::objective_value_
double objective_value_
Definition: linear_solver.h:1733
scip_helper_macros.h
logging.h
operations_research::SCIPInterface::SCIPInterface
SCIPInterface(MPSolver *solver)
Definition: scip_interface.cc:153
operations_research::MPSolver::time_limit
int64 time_limit() const
Definition: linear_solver.h:777
operations_research::SCIPInterface::BranchingPriorityChangedForVariable
void BranchingPriorityChangedForVariable(int var_index) override
Definition: scip_interface.cc:364
operations_research::MPObjective::offset
double offset() const
Gets the constant term in the objective.
Definition: linear_solver.h:959
WallTimer::GetDuration
absl::Duration GetDuration() const
Definition: timer.h:48
value
int64 value
Definition: demon_profiler.cc:43
operations_research::MPSolverParameters::DUAL
@ DUAL
Dual simplex.
Definition: linear_solver.h:1399
operations_research::MPSolverInterface::set_variable_as_extracted
void set_variable_as_extracted(int var_index, bool extracted)
Definition: linear_solver.h:1661
operations_research::SCIPInterface::nodes
int64 nodes() const override
Definition: scip_interface.cc:761
operations_research::MPSolverInterface::MODEL_SYNCHRONIZED
@ MODEL_SYNCHRONIZED
Definition: linear_solver.h:1523
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::MPSolverParameters::SCALING
@ SCALING
Advanced usage: enable or disable matrix scaling.
Definition: linear_solver.h:1385
operations_research::SCIPInterface::best_objective_bound
double best_objective_bound() const override
Definition: scip_interface.cc:770
operations_research::MPSolverInterface::last_variable_index_
int last_variable_index_
Definition: linear_solver.h:1730
int64
int64_t int64
Definition: integral_types.h:34
operations_research::MPSolverParameters
This class stores parameter settings for LP and MIP solvers.
Definition: linear_solver.h:1358
operations_research::SCIPInterface::AddRowConstraint
void AddRowConstraint(MPConstraint *ct) override
Definition: scip_interface.cc:376
operations_research::MPSolverInterface::CheckSolutionIsSynchronized
bool CheckSolutionIsSynchronized() const
Definition: linear_solver.cc:1648
operations_research::SCIPInterface::ExtractObjective
void ExtractObjective() override
Definition: scip_interface.cc:532
operations_research::SCIPInterface::ExtractNewConstraints
void ExtractNewConstraints() override
Definition: scip_interface.cc:432
scip_proto_solver.h
operations_research::SCIPInterface::IsLP
bool IsLP() const override
Definition: scip_interface.cc:88
index
int index
Definition: pack.cc:508
operations_research::MPSolverParameters::INCREMENTALITY
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
Definition: linear_solver.h:1383
operations_research::MPSolverInterface::SetIntegerParamToUnsupportedValue
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
Definition: linear_solver.cc:1748
RETURN_IF_ALREADY_IN_ERROR_STATE
#define RETURN_IF_ALREADY_IN_ERROR_STATE
Definition: scip_interface.cc:209
operations_research::MPConstraint::index
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
Definition: linear_solver.h:1243
operations_research::SCIPInterface::SetObjectiveCoefficient
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
Definition: scip_interface.cc:329
operations_research::MPSolverInterface::SetCommonParameters
void SetCommonParameters(const MPSolverParameters &param)
Definition: linear_solver.cc:1707
operations_research::MPSolverInterface::ExtractModel
void ExtractModel()
Definition: linear_solver.cc:1612
WallTimer::Restart
void Restart()
Definition: timer.h:35
operations_research::SCIPInterface::~SCIPInterface
~SCIPInterface() override
Definition: scip_interface.cc:158
operations_research::BuildSCIPInterface
MPSolverInterface * BuildSCIPInterface(MPSolver *const solver)
Definition: scip_interface.cc:928
operations_research::MPSolverParameters::PRIMAL
@ PRIMAL
Primal simplex.
Definition: linear_solver.h:1401
timer.h
operations_research::MPSolverInterface::set_constraint_as_extracted
void set_constraint_as_extracted(int ct_index, bool extracted)
Definition: linear_solver.h:1667
operations_research::SCIPInterface::Solve
MPSolver::ResultStatus Solve(const MPSolverParameters &param) override
Definition: scip_interface.cc:565
operations_research::MPSolver::ABNORMAL
@ ABNORMAL
abnormal, i.e., error of some kind.
Definition: linear_solver.h:435
operations_research::MPSolverInterface::ResetExtractionInformation
void ResetExtractionInformation()
Definition: linear_solver.cc:1640
operations_research::MPSolverInterface::kUnknownNumberOfNodes
static constexpr int64 kUnknownNumberOfNodes
Definition: linear_solver.h:1534
operations_research::SCIPInterface
Definition: scip_interface.cc:48
RETURN_ABNORMAL_IF_BAD_STATUS
#define RETURN_ABNORMAL_IF_BAD_STATUS
Definition: scip_interface.cc:549
operations_research::MPSolverInterface::quiet_
bool quiet_
Definition: linear_solver.h:1736
RETURN_ABNORMAL_IF_SCIP_ERROR
#define RETURN_ABNORMAL_IF_SCIP_ERROR(x)
Definition: scip_interface.cc:558
SCIPlpiGetSolverName
const char * SCIPlpiGetSolverName(void)
gets name and version of LP solver
Definition: lpi_glop.cc:137
operations_research::MPSolverParameters::INCREMENTALITY_OFF
@ INCREMENTALITY_OFF
Start solve from scratch.
Definition: linear_solver.h:1409
operations_research::SCIPInterface::row_status
MPSolver::BasisStatus row_status(int constraint_index) const override
Definition: scip_interface.cc:78
operations_research::MPSolverInterface::maximize_
bool maximize_
Definition: linear_solver.h:1725
WallTimer
Definition: timer.h:23
status_macros.h
operations_research::SCIPInterface::SolverVersion
std::string SolverVersion() const override
Definition: scip_interface.cc:95
ct
const Constraint * ct
Definition: demon_profiler.cc:42
operations_research::SCIPInterface::IsContinuous
bool IsContinuous() const override
Definition: scip_interface.cc:87
operations_research::SCIPInterface::column_status
MPSolver::BasisStatus column_status(int variable_index) const override
Definition: scip_interface.cc:82
operations_research::MPSolverParameters::IntegerParam
IntegerParam
Enumeration of parameters that take integer or categorical values.
Definition: linear_solver.h:1377
operations_research::SCIPInterface::AddVariable
void AddVariable(MPVariable *var) override
Definition: scip_interface.cc:385
operations_research::MPSolverInterface::CheckBestObjectiveBoundExists
virtual bool CheckBestObjectiveBoundExists() const
Definition: linear_solver.cc:1672
RETURN_AND_STORE_IF_SCIP_ERROR
#define RETURN_AND_STORE_IF_SCIP_ERROR(x)
Definition: scip_interface.cc:217
operations_research::MPSOLVER_NOT_SOLVED
@ MPSOLVER_NOT_SOLVED
Definition: linear_solver.pb.h:234
operations_research::MPSolverInterface::SetMIPParameters
void SetMIPParameters(const MPSolverParameters &param)
Definition: linear_solver.cc:1728
operations_research::MPSolverInterface
Definition: linear_solver.h:1514
DEFINE_bool
DEFINE_bool(scip_feasibility_emphasis, false, "When true, emphasize search towards feasibility. This may or " "may not result in speedups in some problems.")
operations_research::MPSolverParameters::PRESOLVE
@ PRESOLVE
Advanced usage: presolve mode.
Definition: linear_solver.h:1379
operations_research::SCIPInterface::SetConstraintBounds
void SetConstraintBounds(int row_index, double lb, double ub) override
Definition: scip_interface.cc:269
operations_research::MPSolver::SetSolverSpecificParametersAsString
bool SetSolverSpecificParametersAsString(const std::string &parameters)
Advanced usage: pass solver specific parameters in text format.
Definition: linear_solver.cc:345
operations_research::MPSolver::Objective
const MPObjective & Objective() const
Returns the objective object.
Definition: linear_solver.h:414
operations_research::MPSolver::OPTIMAL
@ OPTIMAL
optimal.
Definition: linear_solver.h:427
operations_research::MPSolver::ResultStatus
ResultStatus
The status of solving the problem.
Definition: linear_solver.h:425
WallTimer::Start
void Start()
Definition: timer.h:31
coefficient
int64 coefficient
Definition: routing_search.cc:973
operations_research::MPSolver::FREE
@ FREE
Definition: linear_solver.h:641
operations_research::SCIPInterface::Reset
void Reset() override
Definition: scip_interface.cc:160
operations_research::MPSolverInterface::SetUnsupportedIntegerParam
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
Definition: linear_solver.cc:1739
operations_research::SCIPInterface::iterations
int64 iterations() const override
Definition: scip_interface.cc:754
SCIP_TO_STATUS
#define SCIP_TO_STATUS(x)
Definition: scip_helper_macros.h:39
operations_research::MPSolver::GetNumThreads
int GetNumThreads() const
Returns the number of threads to be used during solve.
Definition: linear_solver.h:608
operations_research::MPSolverParameters::BARRIER
@ BARRIER
Barrier algorithm.
Definition: linear_solver.h:1403
hash.h
linear_solver.h
operations_research::SCIPInterface::DirectlySolveProto
absl::optional< MPSolutionResponse > DirectlySolveProto(const MPModelRequest &request) override
Definition: scip_interface.cc:734
operations_research::SCIPInterface::SetObjectiveOffset
void SetObjectiveOffset(double value) override
Definition: scip_interface.cc:335
operations_research::MPSolver::time_limit_in_secs
double time_limit_in_secs() const
Definition: linear_solver.h:787
operations_research::MPSolverInterface::solver_
MPSolver *const solver_
Definition: linear_solver.h:1718
operations_research::SCIPInterface::AddIndicatorConstraint
bool AddIndicatorConstraint(MPConstraint *ct) override
Definition: scip_interface.cc:380
operations_research::ScipSetSolverSpecificParameters
absl::Status ScipSetSolverSpecificParameters(const std::string &parameters, SCIP *scip)
Definition: scip_proto_solver.cc:59
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:640
operations_research::MPSolverInterface::SOLUTION_SYNCHRONIZED
@ SOLUTION_SYNCHRONIZED
Definition: linear_solver.h:1526
operations_research::MPSolverInterface::constraint_is_extracted
bool constraint_is_extracted(int ct_index) const
Definition: linear_solver.h:1664
operations_research::MPSolverInterface::kUnknownNumberOfIterations
static constexpr int64 kUnknownNumberOfIterations
Definition: linear_solver.h:1531
operations_research::SCIPInterface::InterruptSolve
bool InterruptSolve() override
Definition: scip_interface.cc:101
operations_research::MPSolverInterface::last_constraint_index_
int last_constraint_index_
Definition: linear_solver.h:1728
operations_research::MPSolverParameters::PRESOLVE_ON
@ PRESOLVE_ON
Presolve is on.
Definition: linear_solver.h:1393
operations_research::SCIPInterface::ExtractNewVariables
void ExtractNewVariables() override
Definition: scip_interface.cc:387
operations_research::MPSolverInterface::trivial_worst_objective_bound
double trivial_worst_objective_bound() const
Definition: linear_solver.cc:1682
commandlineflags.h
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:107
operations_research::SCIPInterface::underlying_solver
void * underlying_solver() override
Definition: scip_interface.cc:106
operations_research::MPSolver::INFEASIBLE
@ INFEASIBLE
proven infeasible.
Definition: linear_solver.h:431
operations_research::MPSolverInterface::sync_status_
SynchronizationStatus sync_status_
Definition: linear_solver.h:1720
operations_research::MPSolverInterface::InvalidateSolutionSynchronization
void InvalidateSolutionSynchronization()
Definition: linear_solver.cc:1692
operations_research::MPSolver::UNBOUNDED
@ UNBOUNDED
proven unbounded.
Definition: linear_solver.h:433
operations_research::MPSolver::NOT_SOLVED
@ NOT_SOLVED
not been solved yet.
Definition: linear_solver.h:439