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