18 #include "absl/strings/str_cat.h"
19 #include "absl/types/span.h"
22 #include "scip/cons_linear.h"
24 #include "scip/pub_cons.h"
25 #include "scip/scip.h"
26 #include "scip/scip_cons.h"
27 #include "scip/scip_cut.h"
28 #include "scip/scip_general.h"
29 #include "scip/scip_lp.h"
30 #include "scip/scip_param.h"
31 #include "scip/scip_prob.h"
32 #include "scip/scip_sol.h"
33 #include "scip/scip_solvingstats.h"
34 #include "scip/scip_tree.h"
35 #include "scip/scipdefplugins.h"
36 #include "scip/struct_cons.h"
37 #include "scip/struct_tree.h"
38 #include "scip/struct_var.h"
39 #include "scip/type_cons.h"
40 #include "scip/type_lp.h"
41 #include "scip/type_result.h"
42 #include "scip/type_retcode.h"
43 #include "scip/type_scip.h"
44 #include "scip/type_sol.h"
45 #include "scip/type_tree.h"
46 #include "scip/type_var.h"
49 std::unique_ptr<operations_research::internal::ScipCallbackRunner>
runner;
59 int ScipNumVars(SCIP* scip) {
return SCIPgetNOrigVars(scip); }
61 SCIP_VAR* ScipGetVar(SCIP* scip,
int var_index) {
64 return SCIPgetOrigVars(scip)[var_index];
70 SCIP* scip, SCIP_SOL* solution,
bool is_pseudo_solution)
73 is_pseudo_solution_(is_pseudo_solution) {}
77 return SCIPgetSolVal(scip_, solution_, ScipGetVar(scip_, variable->
index()));
81 return SCIPgetNNodes(scip_);
85 return SCIPgetCurrentNode(scip_)->number;
98 a_times_x += coef_pair.second *
context.VariableValue(coef_pair.first);
102 return violation > 0;
113 absl::Span<SCIP_CONS*> constraints,
117 for (SCIP_CONS* constraint : constraints) {
118 SCIP_CONSDATA* consdata = SCIPconsGetData(constraint);
119 CHECK(consdata !=
nullptr);
120 std::vector<CallbackRangeConstraint> user_suggested_constraints;
122 user_suggested_constraints =
125 user_suggested_constraints =
128 int num_constraints_added = 0;
130 user_suggested_constraints) {
132 user_suggested_constraint.range)) {
135 num_constraints_added++;
137 if (user_suggested_constraint.is_cut) {
138 SCIP_ROW*
row =
nullptr;
139 constexpr
bool kModifiable =
false;
140 constexpr
bool kRemovable =
true;
142 scip, &
row, constraint, user_suggested_constraint.name.c_str(),
143 user_suggested_constraint.range.lower_bound(),
144 user_suggested_constraint.range.upper_bound(),
145 user_suggested_constraint.local, kModifiable, kRemovable)));
147 for (
const auto& coef_pair :
148 user_suggested_constraint.range.linear_expr().terms()) {
151 SCIP_VAR*
var = ScipGetVar(scip, coef_pair.first->index());
152 const double coef = coef_pair.second;
156 SCIP_Bool infeasible;
157 constexpr
bool kForceCut =
false;
164 if (result != ScipSeparationResult::kLazyConstraintAdded) {
168 result = ScipSeparationResult::kCuttingPlaneAdded;
172 std::vector<SCIP_VAR*> vars;
173 std::vector<double> coefs;
174 for (
const auto& coef_pair :
175 user_suggested_constraint.range.linear_expr().terms()) {
178 vars.push_back(ScipGetVar(scip, coef_pair.first->index()));
179 coefs.push_back(coef_pair.second);
182 const int num_vars = vars.size();
183 SCIP_CONS* scip_cons;
187 scip, &scip_cons, user_suggested_constraint.name.c_str(), num_vars,
188 vars.data(), coefs.data(),
189 user_suggested_constraint.range.lower_bound(),
190 user_suggested_constraint.range.upper_bound(),
true,
192 true, user_suggested_constraint.local,
195 if (user_suggested_constraint.local) {
201 result = ScipSeparationResult::kLazyConstraintAdded;
216 int nconss,
int nusefulconss, SCIP_SOL* sol,
217 bool is_pseudo_solution)
220 context(scip, sol, is_pseudo_solution),
223 absl::MakeSpan(conss, nconss).subspan(nusefulconss)) {
236 CHECK(scip !=
nullptr);
237 SCIP_CONSHDLRDATA* scip_handler_data = SCIPconshdlrGetData(conshdlr);
238 CHECK(scip_handler_data !=
nullptr);
239 delete scip_handler_data;
240 SCIPconshdlrSetData(conshdlr,
nullptr);
245 VLOG(3) <<
"DeleteC";
246 CHECK(consdata !=
nullptr);
247 CHECK(*consdata !=
nullptr);
249 cons->consdata =
nullptr;
254 VLOG(3) <<
"EnforceC";
256 nusefulconss,
nullptr,
false);
261 if (separation_result ==
267 switch (separation_result) {
268 case operations_research::ScipSeparationResult::kLazyConstraintAdded:
269 *result = SCIP_CONSADDED;
271 case operations_research::ScipSeparationResult::kCuttingPlaneAdded:
272 *result = SCIP_SEPARATED;
275 *result = SCIP_FEASIBLE;
282 VLOG(3) <<
"SeparateLpC";
284 nusefulconss,
nullptr,
false);
289 if (separation_result ==
295 switch (separation_result) {
296 case operations_research::ScipSeparationResult::kLazyConstraintAdded:
297 *result = SCIP_CONSADDED;
299 case operations_research::ScipSeparationResult::kCuttingPlaneAdded:
300 *result = SCIP_SEPARATED;
303 *result = SCIP_DIDNOTFIND;
310 VLOG(3) <<
"SeparatePrimalC";
312 nusefulconss, sol,
false);
317 if (separation_result ==
323 switch (separation_result) {
324 case operations_research::ScipSeparationResult::kLazyConstraintAdded:
325 *result = SCIP_CONSADDED;
327 case operations_research::ScipSeparationResult::kCuttingPlaneAdded:
328 LOG(
ERROR) <<
"Cutting planes cannot be added on integer solutions, "
329 "treating as a constraint.";
330 *result = SCIP_CONSADDED;
333 *result = SCIP_DIDNOTFIND;
340 VLOG(3) <<
"CheckFeasibilityC";
345 SCIP_CONSDATA* consdata = SCIPconsGetData(constraint);
346 CHECK(consdata !=
nullptr);
349 *result = SCIP_INFEASIBLE;
353 *result = SCIP_FEASIBLE;
357 VLOG(3) <<
"EnforcePseudoSolutionC";
361 nusefulconss,
nullptr,
true);
366 if (separation_result ==
372 switch (separation_result) {
373 case operations_research::ScipSeparationResult::kLazyConstraintAdded:
374 *result = SCIP_CONSADDED;
376 case operations_research::ScipSeparationResult::kCuttingPlaneAdded:
377 LOG(
ERROR) <<
"Cutting planes cannot be added on pseudo solutions, "
378 "treating as a constraint.";
379 *result = SCIP_CONSADDED;
382 *result = SCIP_FEASIBLE;
396 const int num_vars = operations_research::ScipNumVars(scip);
397 for (
int i = 0; i < num_vars; ++i) {
398 SCIP_VAR*
var = operations_research::ScipGetVar(scip, i);
399 SCIP_CALL(SCIPaddVarLocksType(scip,
var, locktype, nlockspos + nlocksneg,
400 nlockspos + nlocksneg));
411 std::unique_ptr<ScipCallbackRunner> runner, SCIP* scip) {
412 SCIP_CONSHDLR* c_scip_handler;
413 SCIP_CONSHDLRDATA* scip_handler_data =
new SCIP_CONSHDLRDATA;
414 scip_handler_data->runner = std::move(runner);
417 scip, &c_scip_handler, description.
name.c_str(),
421 CheckFeasibilityC, VariableRoundingLockC, scip_handler_data)));
422 CHECK(c_scip_handler !=
nullptr);
424 scip, c_scip_handler, SeparateLpC, SeparatePrimalSolutionC,
428 SCIPsetConshdlrFree(scip, c_scip_handler, ConstraintHandlerFreeC)));
430 SCIPsetConshdlrDelete(scip, c_scip_handler, ConstraintHandlerDeleteC)));
434 const std::string& constraint_name,
435 void* constraint_data,
437 SCIP_CONSHDLR* conshdlr = SCIPfindConshdlr(scip, handler_name.c_str());
438 CHECK(conshdlr !=
nullptr)
439 <<
"Constraint handler " << handler_name <<
" not registered with scip.";
441 consdata->
data = constraint_data;
442 SCIP_CONS* constraint =
nullptr;
444 scip, &constraint, constraint_name.c_str(), conshdlr, consdata,
448 CHECK(constraint !=
nullptr);
455 #endif // #if defined(USE_SCIP)