25 #include "absl/strings/str_cat.h"
26 #include "absl/types/span.h"
29 #include "scip/cons_linear.h"
31 #include "scip/pub_cons.h"
32 #include "scip/scip.h"
33 #include "scip/scip_cons.h"
34 #include "scip/scip_cut.h"
35 #include "scip/scip_general.h"
36 #include "scip/scip_lp.h"
37 #include "scip/scip_param.h"
38 #include "scip/scip_prob.h"
39 #include "scip/scip_sol.h"
40 #include "scip/scip_solvingstats.h"
41 #include "scip/scip_tree.h"
42 #include "scip/scipdefplugins.h"
43 #include "scip/struct_cons.h"
44 #include "scip/struct_tree.h"
45 #include "scip/struct_var.h"
46 #include "scip/type_cons.h"
47 #include "scip/type_lp.h"
48 #include "scip/type_result.h"
49 #include "scip/type_retcode.h"
50 #include "scip/type_scip.h"
51 #include "scip/type_sol.h"
52 #include "scip/type_tree.h"
53 #include "scip/type_var.h"
56 std::unique_ptr<operations_research::internal::ScipCallbackRunner>
runner;
66 int ScipNumVars(SCIP* scip) {
return SCIPgetNOrigVars(scip); }
68 SCIP_VAR* ScipGetVar(SCIP* scip,
int var_index) {
69 DCHECK_GE(var_index, 0);
70 DCHECK_LT(var_index, ScipNumVars(scip));
71 return SCIPgetOrigVars(scip)[var_index];
77 SCIP* scip, SCIP_SOL* solution,
bool is_pseudo_solution)
80 is_pseudo_solution_(is_pseudo_solution) {}
84 return SCIPgetSolVal(scip_, solution_, ScipGetVar(scip_, variable->
index()));
88 return SCIPgetNNodes(scip_);
92 return SCIPgetCurrentNode(scip_)->number;
103 double a_times_x = 0;
105 a_times_x += coef_pair.second *
context.VariableValue(coef_pair.first);
109 return violation > 0;
120 absl::Span<SCIP_CONS*> constraints,
124 for (SCIP_CONS* constraint : constraints) {
125 SCIP_CONSDATA* consdata = SCIPconsGetData(constraint);
126 CHECK(consdata !=
nullptr);
127 std::vector<CallbackRangeConstraint> user_suggested_constraints;
129 user_suggested_constraints =
132 user_suggested_constraints =
135 int num_constraints_added = 0;
137 user_suggested_constraints) {
139 user_suggested_constraint.range)) {
142 num_constraints_added++;
144 if (user_suggested_constraint.is_cut) {
145 SCIP_ROW*
row =
nullptr;
146 constexpr
bool kModifiable =
false;
147 constexpr
bool kRemovable =
true;
149 scip, &
row, constraint, user_suggested_constraint.name.c_str(),
150 user_suggested_constraint.range.lower_bound(),
151 user_suggested_constraint.range.upper_bound(),
152 user_suggested_constraint.local, kModifiable, kRemovable)));
154 for (
const auto& coef_pair :
155 user_suggested_constraint.range.linear_expr().terms()) {
158 SCIP_VAR*
var = ScipGetVar(scip, coef_pair.first->index());
159 const double coef = coef_pair.second;
163 SCIP_Bool infeasible;
164 constexpr
bool kForceCut =
false;
179 std::vector<SCIP_VAR*> vars;
180 std::vector<double> coefs;
181 for (
const auto& coef_pair :
182 user_suggested_constraint.range.linear_expr().terms()) {
185 vars.push_back(ScipGetVar(scip, coef_pair.first->index()));
186 coefs.push_back(coef_pair.second);
189 const int num_vars = vars.size();
190 SCIP_CONS* scip_cons;
194 scip, &scip_cons, user_suggested_constraint.name.c_str(), num_vars,
195 vars.data(), coefs.data(),
196 user_suggested_constraint.range.lower_bound(),
197 user_suggested_constraint.range.upper_bound(),
true,
199 true, user_suggested_constraint.local,
202 if (user_suggested_constraint.local) {
203 CHECK_OK(
SCIP_TO_STATUS(SCIPaddConsLocal(scip, scip_cons,
nullptr)));
223 int nconss,
int nusefulconss, SCIP_SOL* sol,
224 bool is_pseudo_solution)
227 context(scip, sol, is_pseudo_solution),
230 absl::MakeSpan(conss, nconss).subspan(nusefulconss)) {
243 CHECK(scip !=
nullptr);
244 SCIP_CONSHDLRDATA* scip_handler_data = SCIPconshdlrGetData(conshdlr);
245 CHECK(scip_handler_data !=
nullptr);
246 delete scip_handler_data;
247 SCIPconshdlrSetData(conshdlr,
nullptr);
252 VLOG(3) <<
"DeleteC";
253 CHECK(consdata !=
nullptr);
254 CHECK(*consdata !=
nullptr);
256 cons->consdata =
nullptr;
261 VLOG(3) <<
"EnforceC";
263 nusefulconss,
nullptr,
false);
268 if (separation_result ==
274 switch (separation_result) {
276 *result = SCIP_CONSADDED;
279 *result = SCIP_SEPARATED;
282 *result = SCIP_FEASIBLE;
289 VLOG(3) <<
"SeparateLpC";
291 nusefulconss,
nullptr,
false);
296 if (separation_result ==
302 switch (separation_result) {
304 *result = SCIP_CONSADDED;
307 *result = SCIP_SEPARATED;
310 *result = SCIP_DIDNOTFIND;
317 VLOG(3) <<
"SeparatePrimalC";
319 nusefulconss, sol,
false);
324 if (separation_result ==
330 switch (separation_result) {
332 *result = SCIP_CONSADDED;
335 LOG(ERROR) <<
"Cutting planes cannot be added on integer solutions, "
336 "treating as a constraint.";
337 *result = SCIP_CONSADDED;
340 *result = SCIP_DIDNOTFIND;
347 VLOG(3) <<
"CheckFeasibilityC";
352 SCIP_CONSDATA* consdata = SCIPconsGetData(constraint);
353 CHECK(consdata !=
nullptr);
356 *result = SCIP_INFEASIBLE;
360 *result = SCIP_FEASIBLE;
364 VLOG(3) <<
"EnforcePseudoSolutionC";
368 nusefulconss,
nullptr,
true);
373 if (separation_result ==
379 switch (separation_result) {
381 *result = SCIP_CONSADDED;
384 LOG(ERROR) <<
"Cutting planes cannot be added on pseudo solutions, "
385 "treating as a constraint.";
386 *result = SCIP_CONSADDED;
389 *result = SCIP_FEASIBLE;
403 const int num_vars = operations_research::ScipNumVars(scip);
404 for (
int i = 0; i < num_vars; ++i) {
405 SCIP_VAR*
var = operations_research::ScipGetVar(scip, i);
406 SCIP_CALL(SCIPaddVarLocksType(scip,
var, locktype, nlockspos + nlocksneg,
407 nlockspos + nlocksneg));
418 std::unique_ptr<ScipCallbackRunner> runner, SCIP* scip) {
419 SCIP_CONSHDLR* c_scip_handler;
420 SCIP_CONSHDLRDATA* scip_handler_data =
new SCIP_CONSHDLRDATA;
421 scip_handler_data->runner = std::move(runner);
424 scip, &c_scip_handler, description.
name.c_str(),
428 CheckFeasibilityC, VariableRoundingLockC, scip_handler_data)));
429 CHECK(c_scip_handler !=
nullptr);
431 scip, c_scip_handler, SeparateLpC, SeparatePrimalSolutionC,
435 SCIPsetConshdlrFree(scip, c_scip_handler, ConstraintHandlerFreeC)));
437 SCIPsetConshdlrDelete(scip, c_scip_handler, ConstraintHandlerDeleteC)));
441 const std::string& constraint_name,
442 void* constraint_data,
444 SCIP_CONSHDLR* conshdlr = SCIPfindConshdlr(scip, handler_name.c_str());
445 CHECK(conshdlr !=
nullptr)
446 <<
"Constraint handler " << handler_name <<
" not registered with scip.";
448 consdata->
data = constraint_data;
449 SCIP_CONS* constraint =
nullptr;
451 scip, &constraint, constraint_name.c_str(), conshdlr, consdata,
455 CHECK(constraint !=
nullptr);
const absl::flat_hash_map< const MPVariable *, double > & terms() const
An expression of the form:
double upper_bound() const
double lower_bound() const
const LinearExpr & linear_expr() const
The class for variables of a Mathematical Programming (MP) model.
int index() const
Returns the index of the variable in the MPSolver::variables_.
double VariableValue(const MPVariable *variable) const
ScipConstraintHandlerContext(SCIP *scip, SCIP_SOL *solution, bool is_pseudo_solution)
int64_t CurrentNodeId() const
int64_t NumNodesProcessed() const
virtual bool IntegerSolutionFeasible(const ScipConstraintHandlerContext &context, void *constraint)=0
virtual std::vector< CallbackRangeConstraint > SeparateFractionalSolution(const ScipConstraintHandlerContext &context, void *constraint)=0
virtual std::vector< CallbackRangeConstraint > SeparateIntegerSolution(const ScipConstraintHandlerContext &context, void *constraint)=0
GurobiMPCallbackContext * context
void AddConstraintHandlerImpl(const ScipConstraintHandlerDescription &description, std::unique_ptr< ScipCallbackRunner > runner, SCIP *scip)
void AddCallbackConstraintImpl(SCIP *scip, const std::string &handler_name, const std::string &constraint_name, void *constraint_data, const ScipCallbackConstraintOptions &options)
Collection of objects used to extend the Constraint Solver library.
bool LinearConstraintIsViolated(const ScipConstraintHandlerContext &context, const LinearRange &constraint)
ScipSeparationResult RunSeparation(internal::ScipCallbackRunner *runner, const ScipConstraintHandlerContext &context, absl::Span< SCIP_CONS * > constraints, bool is_integral)
static SCIP_DECL_CONSLOCK(VariableRoundingLockC)
static SCIP_DECL_CONSFREE(ConstraintHandlerFreeC)
destructor of constraint handler to free user data (called when SCIP is exiting)
static SCIP_DECL_CONSSEPASOL(SeparatePrimalSolutionC)
static SCIP_DECL_CONSENFOPS(EnforcePseudoSolutionC)
static SCIP_DECL_CONSSEPALP(SeparateLpC)
static SCIP_DECL_CONSENFOLP(EnforceLpC)
static SCIP_DECL_CONSDELETE(ConstraintHandlerDeleteC)
static SCIP_DECL_CONSCHECK(CheckFeasibilityC)
#define SCIP_TO_STATUS(x)
std::unique_ptr< operations_research::internal::ScipCallbackRunner > runner
internal::ScipCallbackRunner * callback_runner
absl::Span< SCIP_CONS * > unlikely_useful_constraints
CallbackSetup(SCIP *scip, SCIP_CONSHDLR *scip_handler, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, bool is_pseudo_solution)
absl::Span< SCIP_CONS * > useful_constraints
SCIP_CONSHDLRDATA * scip_handler_data
ScipConstraintHandlerContext context
int feasibility_check_priority
#define VLOG(verboselevel)