27#include "absl/base/attributes.h"
28#include "absl/cleanup/cleanup.h"
29#include "absl/flags/flag.h"
30#include "absl/status/status.h"
31#include "absl/strings/str_format.h"
32#include "absl/synchronization/mutex.h"
33#include "absl/time/time.h"
46#include "scip/cons_indicator.h"
47#include "scip/cons_linear.h"
49#include "scip/scip_cons.h"
50#include "scip/scip_copy.h"
51#include "scip/scip_general.h"
52#include "scip/scip_message.h"
53#include "scip/scip_numerics.h"
54#include "scip/scip_param.h"
55#include "scip/scip_prob.h"
56#include "scip/scip_sol.h"
57#include "scip/scip_solve.h"
58#include "scip/scip_solvingstats.h"
59#include "scip/scip_var.h"
60#include "scip/scipdefplugins.h"
61#include "scip/type_clock.h"
62#include "scip/type_cons.h"
63#include "scip/type_paramset.h"
64#include "scip/type_prob.h"
65#include "scip/type_retcode.h"
66#include "scip/type_scip.h"
67#include "scip/type_sol.h"
68#include "scip/type_stat.h"
69#include "scip/type_var.h"
72 "When true, emphasize search towards feasibility. This may or "
73 "may not result in speedups in some problems.");
93 std::atomic<bool>* interrupt)
override;
95 void Reset()
override;
107 double new_value,
double old_value)
override;
110 double coefficient)
override;
116 int64_t
nodes()
const override;
118 LOG(DFATAL) <<
"Basis status only available for continuous problems";
122 LOG(DFATAL) <<
"Basis status only available for continuous problems";
127 bool IsLP()
const override {
return false; }
128 bool IsMIP()
const override {
return true; }
135 return absl::StrFormat(
"SCIP %d.%d.%d [LP solver: %s]", SCIPmajorVersion(),
136 SCIPminorVersion(), SCIPtechVersion(),
137 SCIPlpiGetSolverName());
141 const absl::MutexLock lock(&hold_interruptions_mutex_);
142 if (scip_ ==
nullptr) {
143 LOG_IF(DFATAL, status_.ok()) <<
"scip_ is null is unexpected here, since "
144 "status_ did not report any error";
147 return SCIPinterruptSolve(scip_) == SCIP_OKAY;
180 void SetRelativeMipGap(
double value)
override;
181 void SetPrimalTolerance(
double value)
override;
182 void SetDualTolerance(
double value)
override;
183 void SetPresolveMode(
int presolve)
override;
184 void SetScalingMode(
int scaling)
override;
185 void SetLpAlgorithm(
int lp_algorithm)
override;
195 absl::Status SetNumThreads(
int num_threads)
override;
197 bool SetSolverSpecificParametersAsString(
198 const std::string& parameters)
override;
200 void SetUnsupportedIntegerParam(
207 void SetSolution(SCIP_SOL*
solution);
209 absl::Status CreateSCIP();
213 SCIP* DeleteSCIP(
bool return_scip =
false);
221 absl::Status status_;
224 std::vector<SCIP_VAR*> scip_variables_;
225 std::vector<SCIP_CONS*> scip_constraints_;
226 int current_solution_index_ = 0;
228 std::unique_ptr<ScipConstraintHandlerForMPCallback> scip_constraint_handler_;
230 EmptyStruct constraint_data_for_handler_;
231 bool branching_priority_reset_ =
false;
232 bool callback_reset_ =
false;
237 mutable absl::Mutex hold_interruptions_mutex_;
254 std::vector<CallbackRangeConstraint> SeparateSolution(
260#define RETURN_IF_ALREADY_IN_ERROR_STATE \
262 if (!status_.ok()) { \
263 VLOG_EVERY_N(1, 10) << "Early abort: SCIP is in error state."; \
268#define RETURN_AND_STORE_IF_SCIP_ERROR(x) \
270 status_ = SCIP_TO_STATUS(x); \
271 if (!status_.ok()) return; \
276 status_ = CreateSCIP();
283 const absl::MutexLock lock(&hold_interruptions_mutex_);
286 SCIP* old_scip = DeleteSCIP(
true);
287 const auto scip_deleter = absl::MakeCleanup(
288 [&old_scip]() { CHECK_EQ(SCIPfree(&old_scip), SCIP_OKAY); });
290 scip_constraint_handler_.reset();
294 status_ = CreateSCIP();
308absl::Status SCIPInterface::CreateSCIP() {
313 if (absl::GetFlag(FLAGS_scip_feasibility_emphasis)) {
324 SCIPsetIntParam(scip_,
"timing/clocktype", SCIP_CLOCKTYPE_WALL));
326 nullptr,
nullptr,
nullptr,
nullptr,
329 scip_,
maximize_ ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
330 return absl::OkStatus();
335SCIP* SCIPInterface::DeleteSCIP(
bool return_scip) {
340 CHECK(scip_ !=
nullptr);
341 for (
int i = 0; i < scip_variables_.size(); ++i) {
342 CHECK_EQ(SCIPreleaseVar(scip_, &scip_variables_[i]), SCIP_OKAY);
344 scip_variables_.clear();
345 for (
int j = 0; j < scip_constraints_.size(); ++j) {
346 CHECK_EQ(SCIPreleaseCons(scip_, &scip_constraints_[j]), SCIP_OKAY);
348 scip_constraints_.clear();
350 SCIP* old_scip = scip_;
353 CHECK_EQ(SCIPfree(&old_scip), SCIP_OKAY);
364 scip_, maximize ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE));
375 SCIPchgVarLb(scip_, scip_variables_[var_index], lb));
377 SCIPchgVarUb(scip_, scip_variables_[var_index], ub));
389#if (SCIP_VERSION >= 210)
390 SCIP_Bool infeasible =
false;
392 scip_, scip_variables_[var_index],
393 integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS, &infeasible));
396 scip_, scip_variables_[var_index],
397 integer ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS));
412 SCIPchgLhsLinear(scip_, scip_constraints_[index], lb));
414 SCIPchgRhsLinear(scip_, scip_constraints_[index], ub));
435 scip_, scip_constraints_[constraint->
index()],
436 scip_variables_[variable->
index()], new_value - old_value));
448 const int constraint_index = constraint->
index();
451 for (
const auto& entry : constraint->coefficients_) {
452 const int var_index = entry.first->index();
453 const double old_coef_value = entry.second;
458 SCIPaddCoefLinear(scip_, scip_constraints_[constraint_index],
459 scip_variables_[var_index], -old_coef_value));
479 for (
const auto& entry :
solver_->objective_->coefficients_) {
480 const int var_index = entry.first->index();
486 SCIPchgVarObj(scip_, scip_variables_[var_index], 0.0));
504 branching_priority_reset_ =
true;
521 int total_num_vars =
solver_->variables_.size();
529 SCIP_VAR* scip_var =
nullptr;
531 double tmp_obj_coef = 0.0;
533 scip_, &scip_var, var->
name().c_str(), var->
lb(), var->
ub(),
535 var->
integer() ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_CONTINUOUS,
true,
536 false,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr));
538 scip_variables_.push_back(scip_var);
540 if (branching_priority != 0) {
541 const int index = var->
index();
543 scip_, scip_variables_[index], branching_priority));
549 for (
const auto& entry : ct->coefficients_) {
550 const int var_index = entry.first->index();
556 SCIPaddCoefLinear(scip_, scip_constraints_[i],
557 scip_variables_[var_index], entry.second));
566 int total_num_rows =
solver_->constraints_.size();
570 int max_row_length = 0;
575 if (ct->coefficients_.size() > max_row_length) {
576 max_row_length = ct->coefficients_.size();
579 std::unique_ptr<SCIP_VAR*[]> vars(
new SCIP_VAR*[max_row_length]);
580 std::unique_ptr<double[]> coeffs(
new double[max_row_length]);
585 const int size = ct->coefficients_.size();
587 for (
const auto& entry : ct->coefficients_) {
588 const int var_index = entry.first->index();
590 vars[j] = scip_variables_[var_index];
591 coeffs[j] = entry.second;
594 SCIP_CONS* scip_constraint =
nullptr;
595 const bool is_lazy = ct->
is_lazy();
599 SCIP_VAR* ind_var = scip_variables_[ind_index];
602 SCIPgetNegatedVar(scip_, scip_variables_[ind_index], &ind_var));
605 if (ct->
ub() < std::numeric_limits<double>::infinity()) {
607 scip_, &scip_constraint, ct->
name().c_str(), ind_var, size,
608 vars.get(), coeffs.get(), ct->
ub(),
619 scip_constraints_.push_back(scip_constraint);
621 if (ct->
lb() > -std::numeric_limits<double>::infinity()) {
622 for (
int i = 0; i < size; ++i) {
626 scip_, &scip_constraint, ct->
name().c_str(), ind_var, size,
627 vars.get(), coeffs.get(), -ct->
lb(),
638 scip_constraints_.push_back(scip_constraint);
645 scip_, &scip_constraint, ct->
name().c_str(), size, vars.get(),
646 coeffs.get(), ct->
lb(), ct->
ub(),
658 scip_constraints_.push_back(scip_constraint);
669 for (
const auto& entry :
solver_->objective_->coefficients_) {
670 const int var_index = entry.first->index();
671 const double obj_coef = entry.second;
673 SCIPchgVarObj(scip_, scip_variables_[var_index], obj_coef));
678 scip_,
solver_->Objective().offset() - SCIPgetOrigObjoffset(scip_)));
681#define RETURN_ABNORMAL_IF_BAD_STATUS \
683 if (!status_.ok()) { \
684 LOG_IF(INFO, solver_->OutputIsEnabled()) \
685 << "Invalid SCIP status: " << status_; \
686 return result_status_ = MPSolver::ABNORMAL; \
690#define RETURN_ABNORMAL_IF_SCIP_ERROR(x) \
692 RETURN_ABNORMAL_IF_BAD_STATUS; \
693 status_ = SCIP_TO_STATUS(x); \
694 RETURN_ABNORMAL_IF_BAD_STATUS; \
711 branching_priority_reset_ || callback_reset_) {
713 branching_priority_reset_ =
false;
714 callback_reset_ =
false;
718 SCIPsetMessagehdlrQuiet(scip_,
quiet_);
721 if (
solver_->variables_.empty() &&
solver_->constraints_.empty()) {
730 VLOG(1) << absl::StrFormat(
"Model built in %s.",
732 if (scip_constraint_handler_ !=
nullptr) {
737 CHECK_EQ(scip_constraint_handler_->mp_callback(), callback_);
738 }
else if (callback_ !=
nullptr) {
739 scip_constraint_handler_ =
740 std::make_unique<ScipConstraintHandlerForMPCallback>(callback_);
744 "mp_solver_callback_constraint_for_scip",
745 &constraint_data_for_handler_,
750 if (
solver_->time_limit() != 0) {
751 VLOG(1) <<
"Setting time limit = " <<
solver_->time_limit() <<
" ms.";
753 SCIPsetRealParam(scip_,
"limits/time",
solver_->time_limit_in_secs()));
763 SetParameters(param);
764 solver_->SetSolverSpecificParametersAsString(
765 solver_->solver_specific_parameter_string_);
768 if (!
solver_->solution_hint_.empty()) {
770 bool is_solution_partial =
false;
771 const int num_vars =
solver_->variables_.size();
772 if (
solver_->solution_hint_.size() != num_vars) {
775 SCIPcreatePartialSol(scip_, &
solution,
nullptr));
776 is_solution_partial =
true;
783 for (
const std::pair<const MPVariable*, double>& p :
786 scip_,
solution, scip_variables_[p.first->index()], p.second));
789 if (!is_solution_partial) {
790 SCIP_Bool is_feasible;
795 VLOG(1) <<
"Solution hint is "
796 << (is_feasible ?
"FEASIBLE" :
"INFEASIBLE");
804 if (!is_solution_partial && SCIPisTransformed(scip_)) {
811 SCIPaddSolFree(scip_, &
solution, &is_stored));
818 ? SCIPsolveConcurrent(scip_)
820 VLOG(1) << absl::StrFormat(
"Solved in %s.",
822 current_solution_index_ = 0;
824 SCIP_SOL*
const solution = SCIPgetBestSol(scip_);
829 VLOG(1) <<
"No feasible solution found.";
833 SCIP_STATUS scip_status = SCIPgetStatus(scip_);
834 switch (scip_status) {
835 case SCIP_STATUS_OPTIMAL:
838 case SCIP_STATUS_GAPLIMIT:
842 case SCIP_STATUS_INFEASIBLE:
845 case SCIP_STATUS_UNBOUNDED:
848 case SCIP_STATUS_INFORUNBD:
856 }
else if (scip_status == SCIP_STATUS_TIMELIMIT ||
857 scip_status == SCIP_STATUS_TOTALNODELIMIT) {
871void SCIPInterface::SetSolution(SCIP_SOL*
solution) {
876 for (
int i = 0; i <
solver_->variables_.size(); ++i) {
878 const int var_index = var->
index();
880 SCIPgetSolVal(scip_,
solution, scip_variables_[var_index]);
882 VLOG(3) << var->
name() <<
"=" << val;
887 std::atomic<bool>* interrupt)
const {
889 if (
solver_->GetNumThreads() > 1)
return false;
892 if (interrupt !=
nullptr)
return false;
899 const bool log_error = request->enable_internal_solver_output();
904int SCIPInterface::SolutionCount() {
return SCIPgetNSols(scip_); }
911 if (current_solution_index_ + 1 >= SolutionCount()) {
914 current_solution_index_++;
915 SCIP_SOL** all_solutions = SCIPgetSols(scip_);
916 SetSolution(all_solutions[current_solution_index_]);
924 return SCIPgetNLPIterations(scip_);
933 return SCIPgetNTotalNodes(scip_);
941void SCIPInterface::SetRelativeMipGap(
double value) {
954 if (status_.ok()) status_ = status;
957void SCIPInterface::SetPrimalTolerance(
double value) {
960 SCIP_TO_STATUS(SCIPsetRealParam(scip_,
"numerics/feastol", value));
961 if (status_.ok()) status_ = status;
964void SCIPInterface::SetDualTolerance(
double value) {
966 SCIP_TO_STATUS(SCIPsetRealParam(scip_,
"numerics/dualfeastol", value));
967 if (status_.ok()) status_ = status;
970void SCIPInterface::SetPresolveMode(
int presolve) {
975 SCIP_TO_STATUS(SCIPsetIntParam(scip_,
"presolving/maxrounds", 0));
976 if (status_.ok()) status_ = status;
981 SCIP_TO_STATUS(SCIPsetIntParam(scip_,
"presolving/maxrounds", -1));
982 if (status_.ok()) status_ = status;
992void SCIPInterface::SetScalingMode(
int) {
999void SCIPInterface::SetLpAlgorithm(
int lp_algorithm) {
1001 switch (lp_algorithm) {
1004 SCIP_TO_STATUS(SCIPsetCharParam(scip_,
"lp/initalgorithm",
'd'));
1005 if (status_.ok()) status_ = status;
1010 SCIP_TO_STATUS(SCIPsetCharParam(scip_,
"lp/initalgorithm",
'p'));
1011 if (status_.ok()) status_ = status;
1017 SCIP_TO_STATUS(SCIPsetCharParam(scip_,
"lp/initalgorithm",
'p'));
1018 if (status_.ok()) status_ = status;
1029void SCIPInterface::SetUnsupportedIntegerParam(
1033 status_ = absl::InvalidArgumentError(absl::StrFormat(
1034 "Tried to set unsupported integer parameter %d", param));
1038void SCIPInterface::SetIntegerParamToUnsupportedValue(
1042 status_ = absl::InvalidArgumentError(absl::StrFormat(
1043 "Tried to set integer parameter %d to unsupported value %d", param,
1048absl::Status SCIPInterface::SetNumThreads(
int num_threads) {
1049 if (SetSolverSpecificParametersAsString(
1050 absl::StrFormat(
"parallel/maxnthreads = %d\n", num_threads))) {
1051 return absl::OkStatus();
1053 return absl::InternalError(
1054 "Could not set parallel/maxnthreads, which may "
1055 "indicate that SCIP API has changed.");
1058bool SCIPInterface::SetSolverSpecificParametersAsString(
1059 const std::string& parameters) {
1060 const absl::Status s =
1063 LOG(WARNING) <<
"Failed to set SCIP parameter string: " << parameters
1064 <<
", error is: " << s;
1072 bool at_integer_solution)
1073 : scip_context_(scip_context),
1074 at_integer_solution_(at_integer_solution) {}
1077 if (at_integer_solution_) {
1084 return !scip_context_->is_pseudo_solution();
1089 return scip_context_->VariableValue(variable);
1094 constraint.
is_cut =
true;
1095 constraint.
range = cutting_plane;
1096 constraint.
local =
false;
1097 constraints_added_.push_back(std::move(constraint));
1102 constraint.
is_cut =
false;
1103 constraint.
range = lazy_constraint;
1104 constraint.
local =
false;
1105 constraints_added_.push_back(std::move(constraint));
1109 const absl::flat_hash_map<const MPVariable*, double>&
solution)
override {
1110 LOG(FATAL) <<
"SuggestSolution() not currently supported for SCIP.";
1121 return std::max(int64_t{0}, scip_context_->NumNodesProcessed() - 1);
1125 return constraints_added_;
1130 bool at_integer_solution_;
1132 std::vector<CallbackRangeConstraint> constraints_added_;
1140std::vector<CallbackRangeConstraint>
1143 return SeparateSolution(context,
false);
1146std::vector<CallbackRangeConstraint>
1149 return SeparateSolution(context,
true);
1152std::vector<CallbackRangeConstraint>
1153ScipConstraintHandlerForMPCallback::SeparateSolution(
1155 const bool at_integer_solution) {
1158 return mp_context.constraints_added();
1162 if (callback_ !=
nullptr) {
1163 callback_reset_ =
true;
1165 callback_ = mp_callback;
1175#undef RETURN_AND_STORE_IF_SCIP_ERROR
1176#undef RETURN_IF_ALREADY_IN_ERROR_STATE
1177#undef RETURN_ABNORMAL_IF_BAD_STATUS
1178#undef RETURN_ABNORMAL_IF_SCIP_ERROR
absl::Duration GetDuration() const
void Start()
When Start() is called multiple times, only the most recent is used.
virtual void RunCallback(MPCallbackContext *callback_context)=0
bool is_lazy() const
Advanced usage: returns true if the constraint is "lazy" (see below).
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
const MPVariable * indicator_variable() const
const std::string & name() const
Returns the name of the constraint.
int index() const
Returns the index of the constraint in the MPSolver::constraints_.
bool indicator_value() const
void set_variable_as_extracted(int var_index, bool extracted)
bool CheckSolutionIsSynchronized() const
static constexpr int64_t kUnknownNumberOfIterations
friend class MPConstraint
To access the maximize_ bool and the MPSolver.
void InvalidateSolutionSynchronization()
void set_constraint_as_extracted(int ct_index, bool extracted)
void ResetExtractionInformation()
Resets the extraction information.
int last_variable_index_
Index in MPSolver::constraints_ of last variable extracted.
virtual void SetIntegerParamToUnsupportedValue(MPSolverParameters::IntegerParam param, int value)
Sets a supported integer parameter to an unsupported value.
int last_constraint_index_
Index in MPSolver::variables_ of last constraint extracted.
virtual void SetUnsupportedIntegerParam(MPSolverParameters::IntegerParam param)
Sets an unsupported integer parameter.
bool variable_is_extracted(int var_index) const
bool constraint_is_extracted(int ct_index) const
static constexpr int64_t kUnknownNumberOfNodes
void ExtractModel()
Extracts model stored in MPSolver.
double objective_value_
The value of the objective function.
double best_objective_bound_
The value of the best objective bound. Used only for MIP solvers.
bool maximize_
Optimization direction.
void SetMIPParameters(const MPSolverParameters ¶m)
Sets MIP specific parameters in the underlying solver.
MPSolverInterface(MPSolver *solver)
bool quiet_
Boolean indicator for the verbosity of the solver output.
void SetCommonParameters(const MPSolverParameters ¶m)
Sets parameters common to LP and MIP in the underlying solver.
bool CheckSolutionIsSynchronizedAndExists() const
Handy shortcut to do both checks above (it is often used).
MPSolver::ResultStatus result_status_
SynchronizationStatus sync_status_
Indicates whether the model and the solution are synchronized.
@ PRESOLVE_OFF
Presolve is off.
@ PRESOLVE_ON
Presolve is on.
@ BARRIER
Barrier algorithm.
IntegerParam
Enumeration of parameters that take integer or categorical values.
@ INCREMENTALITY
Advanced usage: incrementality from one solve to the next.
@ PRESOLVE
Advanced usage: presolve mode.
@ LP_ALGORITHM
Algorithm to solve linear programs.
@ SCALING
Advanced usage: enable or disable matrix scaling.
@ INCREMENTALITY_OFF
Start solve from scratch.
int GetIntegerParam(MPSolverParameters::IntegerParam param) const
Returns the value of an integer parameter.
@ FEASIBLE
feasible, or stopped by limit.
@ NOT_SOLVED
not been solved yet.
@ INFEASIBLE
proven infeasible.
@ UNBOUNDED
proven unbounded.
@ ABNORMAL
abnormal, i.e., error of some kind.
The class for variables of a Mathematical Programming (MP) model.
bool integer() const
Returns the integrality requirement of the variable.
double lb() const
Returns the lower bound.
double ub() const
Returns the upper bound.
const std::string & name() const
Returns the name of the variable.
int branching_priority() const
void set_solution_value(double value)
int index() const
Returns the index of the variable in the MPSolver::variables_.
void ExtractObjective() override
Extracts the objective.
bool InterruptSolve() override
void ExtractNewConstraints() override
Extracts the constraints that have not been extracted yet.
void AddVariable(MPVariable *var) override
Add a variable.
int64_t nodes() const override
double infinity() override
void SetObjectiveCoefficient(const MPVariable *variable, double coefficient) override
Cached.
void SetObjectiveOffset(double value) override
Cached.
void ExtractNewVariables() override
Extracts the variables that have not been extracted yet.
void * underlying_solver() override
Returns the underlying solver.
bool IsContinuous() const override
~SCIPInterface() override
int64_t iterations() const override
void SetVariableInteger(int var_index, bool integer) override
Modifies integrality of an extracted variable.
SCIPInterface(MPSolver *solver)
void ClearConstraint(MPConstraint *constraint) override
Not cached.
void SetCallback(MPCallback *mp_callback) override
MPCallback API.
void ClearObjective() override
Clear objective of all its terms.
MPSolver::ResultStatus Solve(const MPSolverParameters ¶m) override
void BranchingPriorityChangedForVariable(int var_index) override
void SetVariableBounds(int var_index, double lb, double ub) override
Modifies bounds of an extracted variable.
bool IsMIP() const override
Returns true if the problem is discrete and linear.
void SetCoefficient(MPConstraint *constraint, const MPVariable *variable, double new_value, double old_value) override
Changes a coefficient in a constraint.
void SetConstraintBounds(int row_index, double lb, double ub) override
Modify bounds of an extracted variable.
bool SupportsCallbacks() const override
void AddRowConstraint(MPConstraint *ct) override
Adds a linear constraint.
std::string SolverVersion() const override
Returns a string describing the underlying solver and its version.
MPSolver::BasisStatus row_status(int) const override
Returns the basis status of a row.
bool IsLP() const override
Returns true if the problem is continuous and linear.
bool SupportsDirectlySolveProto(std::atomic< bool > *interrupt) const override
bool NextSolution() override
MPSolutionResponse DirectlySolveProto(LazyMutableCopy< MPModelRequest > request, std::atomic< bool > *interrupt) override
void SetOptimizationDirection(bool maximize) override
Not cached.
bool AddIndicatorConstraint(MPConstraint *ct) override
MPSolver::BasisStatus column_status(int) const override
Returns the basis status of a constraint.
ScipConstraintHandler(const ScipConstraintHandlerDescription &description)
void AddLazyConstraint(const LinearRange &lazy_constraint) override
void AddCut(const LinearRange &cutting_plane) override
int64_t NumExploredNodes() override
MPCallbackEvent Event() override
bool CanQueryVariableValues() override
double VariableValue(const MPVariable *variable) override
ScipMPCallbackContext(const ScipConstraintHandlerContext *scip_context, bool at_integer_solution)
double SuggestSolution(const absl::flat_hash_map< const MPVariable *, double > &solution) override
const std::vector< CallbackRangeConstraint > & constraints_added()
In SWIG mode, we don't want anything besides these top-level includes.
void AddCallbackConstraint(SCIP *scip, ScipConstraintHandler< ConstraintData > *handler, const std::string &constraint_name, const ConstraintData *constraint_data, const ScipCallbackConstraintOptions &options)
constraint_data is not owned but held.
Select next search node to expand Select next item_i to add this new search node to the search Generate a new search node where item_i is not in the knapsack Check validity of this new partial solution(using propagators) - If valid
absl::StatusOr< MPSolutionResponse > ScipSolveProto(LazyMutableCopy< MPModelRequest > request)
@ kMipSolution
Called every time a new MIP incumbent is found.
@ kMipNode
Called once per pass of the cut loop inside each MIP node.
void RegisterConstraintHandler(ScipConstraintHandler< Constraint > *handler, SCIP *scip)
handler is not owned but held.
MPSolutionResponse ConvertStatusOrMPSolutionResponse(bool log_error, absl::StatusOr< MPSolutionResponse > response)
absl::Status LegacyScipSetSolverSpecificParameters(absl::string_view parameters, SCIP *scip)
MPSolverInterface * BuildSCIPInterface(MPSolver *const solver)
#define SCIP_TO_STATUS(x)
#define RETURN_IF_SCIP_ERROR(x)
ABSL_FLAG(bool, scip_feasibility_emphasis, false, "When true, emphasize search towards feasibility. This may or " "may not result in speedups in some problems.")
#define RETURN_IF_ALREADY_IN_ERROR_STATE
#define RETURN_ABNORMAL_IF_SCIP_ERROR(x)
#define RETURN_AND_STORE_IF_SCIP_ERROR(x)
#define RETURN_ABNORMAL_IF_BAD_STATUS