Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
gscip_constraint_handler.h
Go to the documentation of this file.
1// Copyright 2010-2024 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// Provides a safe C++ interface for SCIP constraint handlers, which are
15// described at https://www.scipopt.org/doc/html/CONS.php. For instructions to
16// write a constraint handler, see the documentation of GScipConstraintHandler.
17// Examples can be found in gscip_constraint_handler_test.cc.
18#ifndef OR_TOOLS_GSCIP_GSCIP_CONSTRAINT_HANDLER_H_
19#define OR_TOOLS_GSCIP_GSCIP_CONSTRAINT_HANDLER_H_
20
21#include <cstdint>
22#include <memory>
23#include <string>
24#include <utility>
25#include <vector>
26
27#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "ortools/gscip/gscip.h"
31#include "scip/type_cons.h"
32#include "scip/type_sol.h"
33#include "scip/type_var.h"
34
35namespace operations_research {
36
37// Properties for the constraint handler. It is recommended to set priorities
38// and frequencies manually.
40 // For members below, the corresponding SCIP constraint handler property name
41 // is provided. See https://www.scipopt.org/doc/html/CONS.php#CONS_PROPERTIES
42 // for details.
43 //
44 // While it is recommended to set your own parameters, we provide a default
45 // set of parameters that has the following behavior:
46 // * Enforcement and feasibility checking is done right after enforcing
47 // integrality, but before any other constraint handlers. This implies that
48 // it is only performed on integer solutions by default.
49 // * Obsolete constraints are revisited every 100 nodes (eager frequency).
50 // This default follows the most common frequency in SCIP's existing
51 // constraint handlers.
52 // * If separation is used, it is run before all constraint handlers and at
53 // every node. Note however that all separators are always run before any
54 // constraint handler separation. A user may control separation frequency
55 // either by changing this parameter or implementing a check in the
56 // callback.
57
58 // Name of the constraint handler. See CONSHDLR_NAME in SCIP
59 // documentation above.
60 std::string name;
61
62 // Description of the constraint handler. See CONSHDLR_DESC in SCIP
63 // documentation above.
64 std::string description;
65
66 // Determines the order this constraint class is checked at each LP node. If
67 // negative, the enforcement is only performed on integer solutions. See
68 // CONSHDLR_ENFOPRIORITY in the SCIP documentation above. Only relevant if
69 // enforcement callbacks are implemented.
71
72 // Determines the order this constraint class runs in when testing solution
73 // feasibility. If negative, the feasibility check is only performed on
74 // integer solutions. See CONSHDLR_CHECKPRIORITY in the SCIP documentation
75 // above. Only relevant if check callback is implemented.
77
78 // Determines the order the separation from this constraint handler runs in
79 // the cut loop. Note that separators are run before constraint handlers.
80 // See CONSHDLR_SEPAPRIORITY in SCIP documentation above. Only relevant if
81 // separation callbacks are implemented.
82 int separation_priority = 3000000;
83
84 // Frequency for separating cuts. See CONSHDLR_SEPAFREQ in the SCIP
85 // documentation above. Only relevant if separation callbacks are implemented.
87
88 // Determines if this separator be delayed if another separator has already
89 // found a cut. See CONSHDLR_DELAYSEPA in the SCIP documentation above.
90 bool delay_separation = false;
91
92 // Frequency for using all instead of only the useful constraints in
93 // separation, propagation, and enforcement. For example, some constraints may
94 // be aged out by SCIP if they are not relevant for several iterations. See
95 // CONSHDLR_EAGERFREQ in SCIP documentation above.
96 int eager_frequency = 100;
97
98 // Indicates whether the constraint handler can be skipped if no constraints
99 // from this handler are present in the model. In most cases, this should be
100 // true. This should only be false for constraints that are not added
101 // explicitly as a constraint, such as integrality. See CONSHDLR_NEEDSCONS in
102 // SCIP documentation above.
103 bool needs_constraints = true;
104};
105
106// Advanced use only. Indicates that if a variable moves in this direction, it
107// can cause a constraint violation. `kBoth` is the safest option and always
108// valid, but it is the least flexible for SCIP.
110
111// Options passed to SCIP when adding a cut.
113 // Cut is only valid for the current subtree.
114 bool local = false;
115 // Cut is modifiable during node processing (subject to column generation).
116 bool modifiable = false;
117 // Cut can be removed from the LP due to aging or cleanup.
118 bool removable = true;
119 // Cut is forced to enter the LP.
120 bool force_cut = false;
121};
122
123// Options passed to SCIP when adding a lazy constraint.
125 // Cut is only valid for the current subtree.
126 bool local = false;
127 // Constraint is subject to aging.
128 bool dynamic = false;
129};
130
132 // A unique id within a run, assigned consecutively by order of creation. -1
133 // if no nodes have been created yet, or num_processed_nodes if
134 // search is over. See SCIPgetCurrentNode().
135 int64_t current_node_id = 0;
136
137 // The number of processed nodes in the current run (i.e. does not include
138 // nodes before a restart), including the focus node. See SCIPgetNNodes().
140
141 // The number of open nodes left in the current run. See SCIPgetNNodesLeft().
142 int64_t num_nodes_left = 0;
143
144 // The total number of processed nodes in all runs, including the focus node.
145 // If the solver restarts > 1 time, will be larger than
146 // num_processed_nodes, otherwise is equal. See SCIPgetNTotalNodes().
148
149 // The global primal bound on the problem. See SCIPgetPrimalBound().
150 double primal_bound = 0.0;
151
152 // The global dual bound on the problem. See SCIPgetDualBound().
153 double dual_bound = 0.0;
154
155 // The number of pivots taken by the primal simplex method. See
156 // SCIPgetNPrimalLPIterations().
158
159 // The number of pivots taken by the dual simplex method. See
160 // SCIPgetNDualLPIterations().
162
163 // The number of feasible solutions found that were at least as good as the
164 // cutoff limit. See SCIPgetNLimSolsFound().
166
167 // The number of rows in the current LP that were added as cuts. See
168 // SCIPgetNPoolCuts().
169 int32_t num_cuts_in_lp = 0;
170};
171
172// Interface to the callback context and underlying problem. Supports adding
173// cuts and lazy constraints, and setting bounds. Prefer to use this context to
174// query information instead of a raw SCIP pointer. Passed by value.
175// TODO(user): Add support for branching.
177 public:
178 // Construct the context for the given handler. Following SCIP convention, if
179 // SCIP_SOL is nullptr, then the current solution from the LP is used.
181 SCIP_CONSHDLR* current_handler,
182 SCIP_SOL* current_solution)
183 : gscip_(gscip),
184 stats_(stats),
185 current_handler_(current_handler),
186 current_solution_(current_solution) {}
187
188 GScip* gscip() { return gscip_; }
189
190 // Returns the current solution value of a variable. This may be for a given
191 // solution (e.g. in CONS_SEPASOL) or the current LP/pseudosolution (e.g. in
192 // CONS_SEPALP). Equivalent to calling SCIPgetSolVal.
193 double VariableValue(SCIP_VAR* variable) const;
194
195 // Adds a cut (row) to the SCIP separation storage.
196 //
197 // If this is called and succeeds, the callback result must be the one
198 // returned or a higher priority result. The result returned is either kCutOff
199 // (SCIP_CUTOFF) if SCIP determined that the cut results in infeasibility
200 // based on local bounds, or kSeparated (SCIP_SEPARATED) otherwise.
201 absl::StatusOr<GScipCallbackResult> AddCut(
202 const GScipLinearRange& range, const std::string& name,
203 const GScipCutOptions& options = GScipCutOptions());
204
205 // Adds a lazy constraint as a SCIP linear constraint. This is similar to
206 // adding it as a row (and it would be valid to add a lazy constraint with
207 // AddCut and proper options), but it is treated as a higher-level object and
208 // may affect other portions of SCIP such as propagation. This is a thin
209 // wrapper on GScip::AddLinearConstraint() with different defaults.
210 //
211 // If this is called and succeeds, the callback result must be kConsAdded
212 // (equivalent to SCIP_CONSADDED) or a higher priority result.
213 absl::Status AddLazyLinearConstraint(
214 const GScipLinearRange& range, const std::string& name,
216
217 // The functions below set variable bounds. If they are used to cut off a
218 // solution, then the callback result must be kReducedDomain
219 // (SCIP_REDUCEDDOM) or a higher priority result.
220
221 absl::Status SetLocalVarLb(SCIP_VAR* var, double value);
222 absl::Status SetLocalVarUb(SCIP_VAR* var, double value);
223 absl::Status SetGlobalVarLb(SCIP_VAR* var, double value);
224 absl::Status SetGlobalVarUb(SCIP_VAR* var, double value);
225
226 double LocalVarLb(SCIP_VAR* var) const;
227 double LocalVarUb(SCIP_VAR* var) const;
228 double GlobalVarLb(SCIP_VAR* var) const;
229 double GlobalVarUb(SCIP_VAR* var) const;
230
231 const GScipCallbackStats& stats() const { return *stats_; }
232
233 private:
234 GScip* gscip_;
235 const GScipCallbackStats* stats_;
236 SCIP_CONSHDLR* current_handler_;
237 SCIP_SOL* current_solution_;
238};
239
240// Constraint handler class. To implement a constraint handler, the user can
241// inherit this class and implement the desired callback functions. The
242// templated ConstraintData is the equivalent of SCIP's SCIP_CONSHDLRDATA, and
243// can hold the data needed for the constraint. To then use it, the function
244// Register must be called once, and AddCallbackConstraint must be called for
245// each constraint to be added in this constraint handler.
246//
247// There is a one-to-one mapping between relevant SCIP callback functions and
248// the functions in this class; see SCIP documentation for which types of
249// callbacks to use. Make sure to follow SCIP's rules (e.g. if implementing
250// enforcement, all enforcement and check callbacks must be implemented).
251//
252// For examples of usage, see gscip_constraint_handler_test.cc.
253//
254// Implementation details:
255//
256// * Default implementations: All callback functions have a default
257// implementation that returns "did not run" or "feasible" accordingly. For
258// rounding lock, the default implementation locks both directions.
259//
260// * Status errors: If the user returns an absl::Status error, then the solve is
261// interrupted via SCIPinterruptSolve(), and the status error is ultimately
262// returned by GScip::Solve() after SCIP completes the interruption. The
263// callback function returns SCIP_OKAY to SCIP except for internal errors. We
264// try to avoid returning SCIP_ERROR in the middle of a callback since SCIP
265// might not stay in a fully clean state (e.g. calling SCIPfree might hit an
266// assert).
267//
268// * Constraint priority: SCIP informs the callback which subset of constraints
269// are more likely to be violated. The callback is called on those constraints
270// first, and if the highest priority result is kDidNotFind, kDidNotRun, or
271// kFeasible, it is called for the remaining ones.
272//
273// Supported SCIP callback functions:
274// * SCIP_DECL_CONSENFOLP
275// * SCIP_DECL_CONSENFOPS
276// * SCIP_DECL_CONSCHECK
277// * SCIP_DECL_CONSLOCK
278// * SCIP_DECL_CONSSEPALP
279// * SCIP_DECL_CONSSEPASOL
280//
281// Used, but not customizable:
282// * SCIP_DECL_CONSFREE
283// * SCIP_DECL_CONSINIT
284// * SCIP_DECL_CONSDELETE
285template <typename ConstraintData>
287 public:
288 // Constructs a constraint handler that will be registered using the given
289 // properties. It is recommended to set priorities and frequencies manually in
290 // properties.
294
295 virtual ~GScipConstraintHandler() = default;
296
298 return properties_;
299 }
300
301 // Registers this constraint handler with GScip. If the handler has already
302 // been registered, returns an error.
303 absl::Status Register(GScip* gscip);
304
305 // Adds a callback constraint to the model. That is, it attaches to the
306 // constraint handler a constraint for the given constraint data.
307 //
308 // Warning: the user is responsible for ensuring that constraint_data outlives
309 // the returned constraint (e.g. until GScip is destroyed or
310 // GScip::delete_constraint() is invoked on the returned constraint).
311 //
312 // Note: it appears to be safe (from looking at the source and running asan)
313 // to free constraint_data before calling ~GScip(), but this is difficult to
314 // verify. Any other interaction with GScip after freeing the constraint_data
315 // seems very likely to cause memory corruption.
316 absl::StatusOr<SCIP_CONS*> AddCallbackConstraint(
317 GScip* gscip, const std::string& constraint_name,
318 const ConstraintData* constraint_data,
319 const GScipConstraintOptions& options = DefaultGScipConstraintOptions());
320
321 // Callback function called at SCIP's CONSENFOLP. Must check if an LP solution
322 // at a node is feasible, and if not, resolve the infeasibility if possible by
323 // branching, reducing variable domains, or separating the solution with a
324 // cutting plane. If properties_.enforcement_priority < 0, then this only acts
325 // on integer solutions.
326 //
327 // SCIP CONSENFOLP callback arguments:
328 // * solution_infeasible: solinfeasible in SCIP, indicates if the solution was
329 // already declared infeasible by a constraint handler.
330 //
331 // It is the user's responsibility to return a valid result for CONSENFOLP;
332 // see SCIP's documentation (e.g. type_cons.h).
333 virtual absl::StatusOr<GScipCallbackResult> EnforceLp(
335 const ConstraintData& constraint_data, bool solution_infeasible);
336
337 // Callback function called at SCIP's CONSENFOPS. Must check if a
338 // pseudosolution is feasible, and if not, resolve the infeasibility if
339 // possible by branching, reducing variable domains, or adding an additional
340 // constraint. Separating with a cutting plane is not possible since there is
341 // no corresponding LP (i.e. kSeparated cannot be returned). If
342 // properties_.enforcement_priority < 0, then this only acts on integer
343 // solutions.
344 //
345 // SCIP CONSENFOPS callback arguments:
346 // * solution_infeasible: solinfeasible in SCIP, indicates if the solution was
347 // already declared infeasible by a constraint handler.
348 // * objective_infeasible: objinfeasible in SCIP, indicates if the solution is
349 // infeasible due to violating objective bound.
350 //
351 // It is the user's responsibility to return a valid result for CONSENFOPS;
352 // see SCIP's documentation (e.g. type_cons.h).
353 virtual absl::StatusOr<GScipCallbackResult> EnforcePseudoSolution(
355 const ConstraintData& constraint_data, bool solution_infeasible,
356 bool objective_infeasible);
357
358 // Callback function called at SCIP's CONSCHECK. Must return true if the
359 // current solution stored in the context satisfies all constraints of the
360 // constraint handler, or false otherwise. If
361 // properties_.feasibility_check_priority < 0, then this only acts on integer
362 // solutions.
363 //
364 // SCIP CONSCHECK callback arguments:
365 // * check_integrality: checkintegrality in SCIP, indicates if integrality
366 // must be checked. Used to avoid redundant checks in cases where
367 // integrality is already checked or implicit.
368 // * check_lp_rows: checklprows in SCIP, indicates if the constraints
369 // represented by rows in the current LP must be checked. Used to avoid
370 // redundant checks in cases where row feasibility is already checked or
371 // implicit.
372 // * print_reason: printreason in SCIP, indicates if the reason for the
373 // violation should be printed.
374 // * check_completely: completely in SCIP, indicates if all violations should
375 // be checked.
376 virtual absl::StatusOr<bool> CheckIsFeasible(
378 const ConstraintData& constraint_data, bool check_integrality,
379 bool check_lp_rows, bool print_reason, bool check_completely);
380
381 // Callback function called at SCIP's CONSLOCK. Must return, for each
382 // variable, whether the constraint may be violated by decreasing and/or
383 // increasing the variable value. It is always safe to claim that both
384 // directions can violate the constraint, which is the default implementation,
385 // but it may affect SCIP's capabilities.
386 //
387 // SCIP CONSLOCK callback arguments:
388 // * lock_type_is_model: if locktype == SCIP_LOCKTYPE_MODEL in SCIP. If true,
389 // this callback is called for model constraints, otherwise it is called for
390 // conflict constraints.
391 //
392 // It is the user's responsibility to return a valid result for CONSLOCK; see
393 // SCIP's documentation (e.g. type_cons.h).
394 virtual std::vector<std::pair<SCIP_VAR*, RoundingLockDirection>> RoundingLock(
395 GScip* gscip, const ConstraintData& constraint_data,
396 bool lock_type_is_model);
397
398 // Callback function called at SCIP's CONSSEPALP. Separates all constraints of
399 // the constraint handler for LP solutions.
400 //
401 // It is the user's responsibility to return a valid result for CONSSEPALP;
402 // see SCIP's documentation (e.g. type_cons.h).
403 virtual absl::StatusOr<GScipCallbackResult> SeparateLp(
405 const ConstraintData& constraint_data);
406
407 // Callback function called at SCIP's CONSSEPASOL. Separates all constraints
408 // of the constraint handler for solutions that do not come from LP (e.g.
409 // relaxators and primal heuristics).
410 //
411 // It is the user's responsibility to return a valid result for CONSSEPASOL;
412 // see SCIP's documentation (e.g. type_cons.h).
413 virtual absl::StatusOr<GScipCallbackResult> SeparateSolution(
415 const ConstraintData& constraint_data);
416
417 // The functions below wrap each callback function to manage status.
418
420 const ConstraintData& constraint_data,
421 bool solution_infeasible);
422
425 const ConstraintData& constraint_data, bool solution_infeasible,
426 bool objective_infeasible);
427
429 const ConstraintData& constraint_data,
430 bool check_integrality,
431 bool check_lp_rows, bool print_reason,
432 bool check_completely);
433
435 const ConstraintData& constraint_data);
436
439 const ConstraintData& constraint_data);
440
441 private:
442 // If the result status is not OK, stores the status for GScip to later return
443 // to the user, and interrupts the solve. Otherwise, returns the result
444 // itself.
445 GScipCallbackResult HandleCallbackStatus(
446 absl::StatusOr<GScipCallbackResult> result,
448 GScipCallbackResult default_callback_result);
449
451};
452
454// Helpers for implementing callbacks
456
457// Enum with supported user-implementable callback functions in the SCIP
458// constraint handler. Non-user-implementable functions are not included here
459// (e.g. CONSFREE). Same order as in type_cons.h.
461 kSepaLp, // CONSSEPALP
462 kSepaSol, // CONSSEPASOL
463 kEnfoLp, // CONSENFOLP
464 // Unsupported: kEnfoRelax, // CONSENFORELAX
465 kEnfoPs, // CONSENFOPS
466 kConsCheck, // CONSCHECK
467 // Unsupported: kConsProp, // CONSPROP
468 // Unsupported: kConsPresol, // CONSPRESOL
469 // Unsupported: kConsResProp, // CONSRESPROP
470 kConsLock // CONSLOCK
471};
472
473// In callbacks, SCIP requires the first SCIP_RESULT in a priority list be
474// returned when multiple results are applicable. This is a unified order of the
475// priorities extracted from type_cons.h. The higher the result, the higher
476// priority it is.
477//
478// Larger number indicates higher priority in what should be returned.
481
482// Returns the GScipCallbackResult with larger priority, see
483// ConstraintHandlerResultPriority().
486 ConstraintHandlerCallbackType callback_type);
487
488namespace internal {
489
490// These classes implement a void pointer version of GScipConstraintHandler that
491// performs a conversion to the more user-friendly templated implementation with
492// ConstraintData. This parent class is needed as an untemplated version that
493// SCIP_ConshdlrData can store.
494class UntypedGScipConstraintHandler : public GScipConstraintHandler<void*> {
495 public:
499};
500
501template <typename ConstraintData>
502class UntypedGScipConstraintHandlerImpl : public UntypedGScipConstraintHandler {
503 public:
505 GScipConstraintHandler<ConstraintData>* constraint_handler)
507 actual_handler_(constraint_handler) {}
508
509 absl::StatusOr<GScipCallbackResult> EnforceLp(
510 GScipConstraintHandlerContext context, void* const& constraint_data,
511 bool solution_infeasible) override {
512 return actual_handler_->EnforceLp(
513 context, *static_cast<const ConstraintData*>(constraint_data),
514 solution_infeasible);
515 }
516
517 absl::StatusOr<GScipCallbackResult> EnforcePseudoSolution(
518 GScipConstraintHandlerContext context, void* const& constraint_data,
519 bool solution_infeasible, bool objective_infeasible) override {
520 return actual_handler_->EnforcePseudoSolution(
521 context, *static_cast<const ConstraintData*>(constraint_data),
522 solution_infeasible, objective_infeasible);
523 }
524
526 void* const& constraint_data,
527 bool check_integrality,
528 bool check_lp_rows, bool print_reason,
529 bool completely) override {
530 return actual_handler_->CheckIsFeasible(
531 context, *static_cast<const ConstraintData*>(constraint_data),
532 check_integrality, check_lp_rows, print_reason, completely);
533 }
534
535 std::vector<std::pair<SCIP_VAR*, RoundingLockDirection>> RoundingLock(
536 GScip* gscip, void* const& constraint_data,
537 bool lock_type_is_model) override {
538 return actual_handler_->RoundingLock(
539 gscip, *static_cast<const ConstraintData*>(constraint_data),
540 lock_type_is_model);
541 }
542
543 absl::StatusOr<GScipCallbackResult> SeparateLp(
545 void* const& constraint_data) override {
546 return actual_handler_->SeparateLp(
547 context, *static_cast<const ConstraintData*>(constraint_data));
548 }
549
550 absl::StatusOr<GScipCallbackResult> SeparateSolution(
552 void* const& constraint_data) override {
553 return actual_handler_->SeparateSolution(
554 context, *static_cast<const ConstraintData*>(constraint_data));
555 }
556
557 private:
559};
560
561absl::Status RegisterConstraintHandler(
562 GScip* gscip,
563 std::unique_ptr<UntypedGScipConstraintHandler> constraint_handler);
564
565absl::StatusOr<SCIP_CONS*> AddCallbackConstraint(
566 GScip* gscip, const std::string& handler_name,
567 const std::string& constraint_name, void* constraint_data,
568 const GScipConstraintOptions& options);
569
570} // namespace internal
571
572// Template implementations.
573
574template <typename ConstraintData>
575absl::Status GScipConstraintHandler<ConstraintData>::Register(GScip* gscip) {
577 gscip,
578 std::make_unique<
580}
581
582template <typename ConstraintData>
583absl::StatusOr<SCIP_CONS*>
585 GScip* gscip, const std::string& constraint_name,
586 const ConstraintData* constraint_data,
587 const GScipConstraintOptions& options) {
589 gscip, properties().name, constraint_name,
590 static_cast<void*>(const_cast<ConstraintData*>(constraint_data)),
591 options);
592}
593
594// Default callback implementations.
595
596template <typename ConstraintData>
597absl::StatusOr<GScipCallbackResult>
600 const ConstraintData& /*constraint_data*/, bool /*solution_infeasible*/) {
602}
603
604template <typename ConstraintData>
605absl::StatusOr<GScipCallbackResult>
608 const ConstraintData& /*constraint_data*/, bool /*solution_infeasible*/,
609 bool /*objective_infeasible*/) {
611}
612
613template <typename ConstraintData>
616 const ConstraintData& /*constraint_data*/, bool /*check_integrality*/,
617 bool /*check_lp_rows*/, bool /*print_reason*/, bool /*check_completely*/) {
618 return true;
619}
620
621template <typename ConstraintData>
622std::vector<std::pair<SCIP_VAR*, RoundingLockDirection>>
624 GScip* gscip, const ConstraintData& /*constraint_data*/,
625 bool /*lock_type_is_model*/) {
626 std::vector<std::pair<SCIP_VAR*, RoundingLockDirection>> result;
627 for (SCIP_VAR* var : gscip->variables()) {
628 result.push_back({var, RoundingLockDirection::kBoth});
629 }
630 return result;
631}
632
633template <typename ConstraintData>
634absl::StatusOr<GScipCallbackResult>
637 const ConstraintData& /*constraint_data*/) {
639}
640
641template <typename ConstraintData>
642absl::StatusOr<GScipCallbackResult>
645 const ConstraintData& /*constraint_data*/) {
647}
648
649// Internal functions to handle status.
650
651template <typename ConstraintData>
654 const absl::StatusOr<GScipCallbackResult> result,
656 const GScipCallbackResult default_callback_result) {
657 if (!result.ok()) {
658 context.gscip()->InterruptSolveFromCallbackOnCallbackError(result.status());
659 return default_callback_result;
660 }
661 return result.value();
662}
663
664template <typename ConstraintData>
666 GScipConstraintHandlerContext context,
667 const ConstraintData& constraint_data, bool solution_infeasible) {
668 return HandleCallbackStatus(
669 EnforceLp(context, constraint_data, solution_infeasible), context,
671}
672
673template <typename ConstraintData>
677 const ConstraintData& constraint_data, bool solution_infeasible,
678 bool objective_infeasible) {
679 return HandleCallbackStatus(
680 EnforcePseudoSolution(context, constraint_data, solution_infeasible,
681 objective_infeasible),
683}
684
685template <typename ConstraintData>
688 const ConstraintData& constraint_data, bool check_integrality,
689 bool check_lp_rows, bool print_reason, bool check_completely) {
690 const absl::StatusOr<bool> result =
691 CheckIsFeasible(context, constraint_data, check_integrality,
692 check_lp_rows, print_reason, check_completely);
693 if (!result.ok()) {
694 return HandleCallbackStatus(result.status(), context,
696 } else {
697 return HandleCallbackStatus(*result ? GScipCallbackResult::kFeasible
700 }
701}
702
703template <typename ConstraintData>
706 const ConstraintData& constraint_data) {
707 return HandleCallbackStatus(SeparateLp(context, constraint_data), context,
709}
710
711template <typename ConstraintData>
715 const ConstraintData& constraint_data) {
716 return HandleCallbackStatus(SeparateSolution(context, constraint_data),
718}
719
720} // namespace operations_research
721
722#endif // OR_TOOLS_GSCIP_GSCIP_CONSTRAINT_HANDLER_H_
absl::Status SetLocalVarLb(SCIP_VAR *var, double value)
GScipConstraintHandlerContext(GScip *gscip, const GScipCallbackStats *stats, SCIP_CONSHDLR *current_handler, SCIP_SOL *current_solution)
absl::StatusOr< GScipCallbackResult > AddCut(const GScipLinearRange &range, const std::string &name, const GScipCutOptions &options=GScipCutOptions())
absl::Status SetGlobalVarUb(SCIP_VAR *var, double value)
absl::Status AddLazyLinearConstraint(const GScipLinearRange &range, const std::string &name, const GScipLazyConstraintOptions &options=GScipLazyConstraintOptions())
absl::Status SetLocalVarUb(SCIP_VAR *var, double value)
absl::Status SetGlobalVarLb(SCIP_VAR *var, double value)
virtual std::vector< std::pair< SCIP_VAR *, RoundingLockDirection > > RoundingLock(GScip *gscip, const ConstraintData &constraint_data, bool lock_type_is_model)
GScipCallbackResult CallEnforcePseudoSolution(GScipConstraintHandlerContext context, const ConstraintData &constraint_data, bool solution_infeasible, bool objective_infeasible)
const GScipConstraintHandlerProperties & properties() const
virtual absl::StatusOr< GScipCallbackResult > SeparateSolution(GScipConstraintHandlerContext context, const ConstraintData &constraint_data)
virtual absl::StatusOr< GScipCallbackResult > EnforceLp(GScipConstraintHandlerContext context, const ConstraintData &constraint_data, bool solution_infeasible)
Default callback implementations.
GScipCallbackResult CallEnforceLp(GScipConstraintHandlerContext context, const ConstraintData &constraint_data, bool solution_infeasible)
The functions below wrap each callback function to manage status.
absl::Status Register(GScip *gscip)
Template implementations.
GScipCallbackResult CallCheckIsFeasible(GScipConstraintHandlerContext context, const ConstraintData &constraint_data, bool check_integrality, bool check_lp_rows, bool print_reason, bool check_completely)
absl::StatusOr< SCIP_CONS * > AddCallbackConstraint(GScip *gscip, const std::string &constraint_name, const ConstraintData *constraint_data, const GScipConstraintOptions &options=DefaultGScipConstraintOptions())
virtual absl::StatusOr< GScipCallbackResult > SeparateLp(GScipConstraintHandlerContext context, const ConstraintData &constraint_data)
virtual absl::StatusOr< GScipCallbackResult > EnforcePseudoSolution(GScipConstraintHandlerContext context, const ConstraintData &constraint_data, bool solution_infeasible, bool objective_infeasible)
virtual absl::StatusOr< bool > CheckIsFeasible(GScipConstraintHandlerContext context, const ConstraintData &constraint_data, bool check_integrality, bool check_lp_rows, bool print_reason, bool check_completely)
GScipCallbackResult CallSeparateLp(GScipConstraintHandlerContext context, const ConstraintData &constraint_data)
GScipCallbackResult CallSeparateSolution(GScipConstraintHandlerContext context, const ConstraintData &constraint_data)
GScipConstraintHandler(const GScipConstraintHandlerProperties &properties)
absl::StatusOr< bool > CheckIsFeasible(GScipConstraintHandlerContext context, void *const &constraint_data, bool check_integrality, bool check_lp_rows, bool print_reason, bool completely) override
absl::StatusOr< GScipCallbackResult > SeparateSolution(GScipConstraintHandlerContext context, void *const &constraint_data) override
absl::StatusOr< GScipCallbackResult > EnforceLp(GScipConstraintHandlerContext context, void *const &constraint_data, bool solution_infeasible) override
Default callback implementations.
UntypedGScipConstraintHandlerImpl(GScipConstraintHandler< ConstraintData > *constraint_handler)
absl::StatusOr< GScipCallbackResult > SeparateLp(GScipConstraintHandlerContext context, void *const &constraint_data) override
absl::StatusOr< GScipCallbackResult > EnforcePseudoSolution(GScipConstraintHandlerContext context, void *const &constraint_data, bool solution_infeasible, bool objective_infeasible) override
std::vector< std::pair< SCIP_VAR *, RoundingLockDirection > > RoundingLock(GScip *gscip, void *const &constraint_data, bool lock_type_is_model) override
UntypedGScipConstraintHandler(const GScipConstraintHandlerProperties &properties)
const std::string name
A name for logging purposes.
int64_t value
IntVar * var
GurobiMPCallbackContext * context
absl::StatusOr< SCIP_CONS * > AddCallbackConstraint(GScip *gscip, const std::string &handler_name, const std::string &constraint_name, void *constraint_data, const GScipConstraintOptions &options)
absl::Status RegisterConstraintHandler(GScip *gscip, std::unique_ptr< UntypedGScipConstraintHandler > constraint_handler)
In SWIG mode, we don't want anything besides these top-level includes.
const GScipConstraintOptions & DefaultGScipConstraintOptions()
Definition gscip.cc:292
int ConstraintHandlerResultPriority(const GScipCallbackResult result, const ConstraintHandlerCallbackType callback_type)
@ kEnfoPs
Unsupported: kEnfoRelax, ///< CONSENFORELAX.
GScipCallbackResult
Equivalent to type_result.h in SCIP.
GScipCallbackResult MergeConstraintHandlerResults(const GScipCallbackResult result1, const GScipCallbackResult result2, const ConstraintHandlerCallbackType callback_type)
const std::optional< Range > & range
Definition statistics.cc:37
double dual_bound
The global dual bound on the problem. See SCIPgetDualBound().
double primal_bound
The global primal bound on the problem. See SCIPgetPrimalBound().
int64_t num_nodes_left
The number of open nodes left in the current run. See SCIPgetNNodesLeft().
Options passed to SCIP when adding a cut.
bool local
Cut is only valid for the current subtree.
bool removable
Cut can be removed from the LP due to aging or cleanup.
bool force_cut
Cut is forced to enter the LP.
bool modifiable
Cut is modifiable during node processing (subject to column generation).
Options passed to SCIP when adding a lazy constraint.
bool local
Cut is only valid for the current subtree.