Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
gscip_event_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 event handlers, which are described at
15// https://www.scipopt.org/doc/html/EVENT.php.
16#ifndef OR_TOOLS_GSCIP_GSCIP_EVENT_HANDLER_H_
17#define OR_TOOLS_GSCIP_GSCIP_EVENT_HANDLER_H_
18
19#include <string>
20#include <vector>
21
22#include "absl/status/status.h"
23#include "scip/type_event.h"
24
25namespace operations_research {
26
27class GScip;
28
30 // For the first two members below, the SCIP constraint handler
31 // property name is provided. See
32 // https://www.scipopt.org/doc/html/EVENT.php#EVENTHDLR_PROPERTIES for
33 // details.
34
35 // See CONSHDLR_NAME in SCIP documentation above.
36 std::string name;
37
38 // See CONSHDLR_DESC in SCIP documentation above.
39 std::string description;
40};
41
42// Passed by value. This is a lightweight interface to the callback context and
43// the underlying problem. It's preferred for callbacks to use the context
44// object to query information rather than using the raw SCIP pointer, because
45// the context object can be set up to do this in a safe way.
47 public:
49 : gscip_(gscip), event_type_(event_type) {}
50
51 GScip* gscip() const { return gscip_; }
52
53 // This is always an atomic event type, not a mask (i.e., one of the events
54 // defined as a bitwise OR).
55 SCIP_EVENTTYPE event_type() const { return event_type_; }
56
57 // TODO(user): Support additional properties that might need to be
58 // queried within an event handler.
59
60 private:
61 GScip* const gscip_;
62 const SCIP_EVENTTYPE event_type_;
63};
64
65// Inherit from this to implement the callback and override Init() to call
66// CatchEvent() for the events you want to listen to.
67//
68// Usage:
69//
70// class MyHandler : public GScipEventHandler {
71// public:
72// MyHandler()
73// : GScipEventHandler({
74// .name = "my handler", .description = "something"}) {}
75//
76// SCIP_RETCODE Init(GScip* const gscip) override {
77// SCIP_CALL(CatchEvent(SCIP_EVENTTYPE_SOLFOUND));
78// return SCIP_OKAY;
79// }
80//
81// SCIP_RETCODE Execute(const GScipEventHandlerContext context) override {
82// ...
83// return SCIP_OKAY;
84// }
85// };
86//
87// std::unique_ptr<GScip> gscip = ...;
88//
89// MyHandler handler;
90// handler.Register(gscip.get());
91//
92class GScipEventHandler {
93 public:
94 explicit GScipEventHandler(const GScipEventHandlerDescription& description)
95 : description_(description) {}
96
97 GScipEventHandler(const GScipEventHandler&) = delete;
100 virtual ~GScipEventHandler() = default;
102 // Registers this event handler to the given GScip.
103 //
104 // This function returns an internal Status error if this handler has already
105 // been registered.
106 //
107 // The given GScip won't own this handler but will keep a pointer to it that
108 // will be used during the solve.
109 absl::Status Register(GScip* gscip);
110
111 // Initialization of the event handler. Called after the problem was
112 // transformed.
113 //
114 // The implementation should use the CatchEvent() method to register to global
115 // events.
116 //
117 // Return SCIP_OKAY, or use SCIP_CALL macro to wraps SCIP calls to properly
118 // propagate errors.
119 virtual SCIP_RETCODE Init(GScip* gscip) { return SCIP_OKAY; }
121 // Called when a caught event is emitted.
122 //
123 // Return SCIP_OKAY, or use SCIP_CALL macro to wraps SCIP calls to properly
124 // propagate errors.
125 virtual SCIP_RETCODE Execute(GScipEventHandlerContext context) {
126 return SCIP_OKAY;
127 }
128
129 // Deinitialization of the event handler.
130 //
131 // Called before the transformed problem is freed and after all the events
132 // specified in CatchEvent() have been dropped (thus there is no need to
133 // implement this function to drop these events since this would have already
134 // been done).
135 //
136 // Return SCIP_OKAY, or use SCIP_CALL macro to wraps SCIP calls to properly
137 // propagate errors.
138 virtual SCIP_RETCODE Exit(GScip* gscip) { return SCIP_OKAY; }
140 protected:
141 // Catches a global event (i.e. not a variable or row dependent one) based on
142 // the input event_type mask.
143 //
144 // This method must only be called after the problem is transformed; typically
145 // it is called in the Init() virtual method.
146 //
147 // Caught events will be automatically dropped when the handler will be called
148 // on EXIT (before calling the corresponding Exit() member function).
149 //
150 // See scip/type_event.h for the list of possible events. This function
151 // corresponds to SCIPcatchEvent().
152 //
153 // TODO(user): Support Var and Row events.
154 //
155 // TODO(user): Support registering events in the EVENTINITSOL
156 // callback, which would cause them to be trapped only after presolve.
157 SCIP_RETCODE CatchEvent(SCIP_EVENTTYPE event_type);
158
159 private:
160 struct CaughtEvent {
161 CaughtEvent(const SCIP_EVENTTYPE event_type, const int filter_pos)
162 : event_type(event_type), filter_pos(filter_pos) {}
163
164 // The event_type mask for this catch.
165 SCIP_EVENTTYPE event_type;
166
167 // The key used by SCIP to identify this catch with SCIPdropEvent(). Using
168 // this key prevents SCIP from having to do a look up to find the catch and
169 // helps when there are duplicates.
170 //
171 // It is the index of the data associated to the catch in the array SCIP
172 // uses as storage (this index is stable, even after other catch added
173 // previously are removed, since SCIP maintains a free-list of removed items
174 // instead of renumbering all elements).
175 int filter_pos;
176 };
177
178 // Calls SCIPdropEvent() for all events in caught_events_ and clear this
179 // collection.
180 //
181 // This is not a member function since it needs to be visible to the SCIP Exit
182 // callback function.
183 friend SCIP_RETCODE DropAllEvents(GScipEventHandler& handler);
184
185 const GScipEventHandlerDescription description_;
186
187 // Pointer to GScip set by Register();
188 GScip* gscip_ = nullptr;
189
190 // Pointer to the event handler registered on SCIP.
191 SCIP_EVENTHDLR* event_handler_ = nullptr;
192
193 // Caught events via CatchEvent().
194 std::vector<CaughtEvent> caught_events_;
195};
196
197} // namespace operations_research
198
199#endif // OR_TOOLS_GSCIP_GSCIP_EVENT_HANDLER_H_
GScipEventHandlerContext(GScip *gscip, SCIP_EVENTTYPE event_type)
friend SCIP_RETCODE DropAllEvents(GScipEventHandler &handler)
SCIP_RETCODE CatchEvent(SCIP_EVENTTYPE event_type)
GScipEventHandler & operator=(const GScipEventHandler &)=delete
virtual SCIP_RETCODE Init(GScip *gscip)
GScipEventHandler(const GScipEventHandlerDescription &description)
virtual SCIP_RETCODE Execute(GScipEventHandlerContext context)
virtual SCIP_RETCODE Exit(GScip *gscip)
GurobiMPCallbackContext * context
In SWIG mode, we don't want anything besides these top-level includes.
std::string name
See CONSHDLR_NAME in SCIP documentation above.
std::string description
See CONSHDLR_DESC in SCIP documentation above.