OR-Tools  9.1
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-7.0.1/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 
25 namespace 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-7.0.1/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:
92  explicit GScipEventHandler(const GScipEventHandlerDescription& description)
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.
119  virtual SCIP_RETCODE Execute(GScipEventHandlerContext context) {
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_
friend SCIP_RETCODE DropAllEvents(GScipEventHandler &handler)
virtual SCIP_RETCODE Exit(GScip *gscip)
virtual SCIP_RETCODE Execute(GScipEventHandlerContext context)
SCIP_RETCODE CatchEvent(SCIP_EVENTTYPE event_type)
Collection of objects used to extend the Constraint Solver library.
GScipEventHandler(const GScipEventHandlerDescription &description)
GurobiMPCallbackContext * context
GScipEventHandlerContext(GScip *gscip, SCIP_EVENTTYPE event_type)
virtual SCIP_RETCODE Init(GScip *gscip)