idol
A C++ Framework for Optimization
Loading...
Searching...
No Matches
BranchAndBoundCallback.h
1//
2// Created by henri on 12/04/23.
3//
4
5#ifndef IDOL_BRANCHANDBOUNDCALLBACK_H
6#define IDOL_BRANCHANDBOUNDCALLBACK_H
7
8#include "idol/mixed-integer/optimizers/callbacks/Callback.h"
9#include "idol/mixed-integer/optimizers/branch-and-bound/nodes/Node.h"
10#include "idol/mixed-integer/optimizers/branch-and-bound/Optimizers_BranchAndBound.h"
11#include "AbstractBranchAndBoundCallbackI.h"
12#include "CallbackAsBranchAndBoundCallback.h"
13
14namespace idol {
15
16 template<class NodeInfoT>
17 class BranchAndBoundCallback;
18
19 template<class NodeInfoT>
20 class BranchAndBoundCallbackI;
21
22}
26template<class NodeInfoT>
28 friend class BranchAndBoundCallback<NodeInfoT>;
29
30 std::list<std::unique_ptr<BranchAndBoundCallback<NodeInfoT>>> m_callbacks;
31
32 Optimizers::BranchAndBound<NodeInfoT>* m_parent = nullptr;
33 std::optional<Node<NodeInfoT>> m_node;
34 Model* m_relaxation = nullptr;
35 SideEffectRegistry* m_registry = nullptr;
36
37public:
38 virtual ~BranchAndBoundCallbackI() = default;
39protected:
40 void add_user_cut(const TempCtr &t_cut);
41
42 void add_lazy_cut(const TempCtr &t_cut);
43
44 void add_local_variable_branching(const idol::Var &t_var, CtrType t_type, double t_rhs);
45
46 [[nodiscard]] const Node<NodeInfoT>& node() const;
47
48 [[nodiscard]] const Model& relaxation() const;
49
50 [[nodiscard]] const Model& original_model() const;
51
52 [[nodiscard]] const Timer& time() const;
53
54 [[nodiscard]] const SideEffectRegistry& side_effect_registry() const;
55
56 void submit_heuristic_solution(NodeInfoT* t_info);
57
58 void submit_bound(double t_bound);
59
60 [[nodiscard]] double best_bound() const;
61
62 [[nodiscard]] double best_obj() const;
63
64 void terminate();
65
66 SideEffectRegistry operator()(
68 CallbackEvent t_event,
69 const Node<NodeInfoT>& t_current_node,
70 Model *t_relaxation) override;
71
72 void add_callback(BranchAndBoundCallback<NodeInfoT> *t_cb) override;
73
74 void initialize(Optimizers::BranchAndBound<NodeInfoT>* t_parent) override;
75
76 void log_after_termination() override;
77};
78
79template<class NodeInfoT>
80void idol::BranchAndBoundCallbackI<NodeInfoT>::add_local_variable_branching(const idol::Var &t_var, CtrType t_type, double t_rhs) {
81 m_node->info().add_branching_variable(t_var, t_type, t_rhs);
82 m_registry->n_added_local_variable_branching++;
83}
84
85template<class NodeInfoT>
87 m_parent->terminate();
88}
89
90template<class NodeInfoT>
92 return m_parent->get_best_obj();
93}
94
95template<class NodeInfoT>
97 return m_parent->get_best_bound();
98}
99
100template<class NodeInfoT>
102
103 if (m_callbacks.empty()) {
104 return;
105 }
106
107 std::cout << "Callbacks:" << std::endl;
108
109 for (auto& ptr_to_cb : m_callbacks) {
110 ptr_to_cb->log_after_termination();
111 }
112
113 std::cout << std::endl;
114
115}
116
117template<class NodeInfoT>
119 if (!m_registry) {
120 throw Exception("No side effect registry was found");
121 }
122 return *m_registry;
123}
124
125template<class NodeInfoT>
127 return m_parent->time();
128}
129
130template<class NodeInfoT>
132public:
133 virtual ~BranchAndBoundCallback() = default;
134protected:
135
139 virtual void initialize() {}
140
145 virtual void operator()(CallbackEvent t_event) = 0;
146
147 virtual void log_after_termination() {}
148
153 void add_user_cut(const TempCtr& t_cut);
154
159 void add_lazy_cut(const TempCtr& t_cut);
160
161 void add_local_variable_branching(const Var &t_var, CtrType t_type, double t_rhs);
162
167 [[nodiscard]] const Node<NodeInfoT>& node() const;
168
173 [[nodiscard]] const Model& relaxation() const;
174
179 [[nodiscard]] const Model& original_model() const;
180
188 void submit_heuristic_solution(NodeInfoT* t_info);
189
196 void submit_bound(double t_bound);
197
203
204 [[nodiscard]] const Timer& time() const;
205
206 double best_bound() const;
207
208 double best_obj() const;
209
210 void terminate();
211private:
212 BranchAndBoundCallbackI<NodeInfoT>* m_interface = nullptr;
213
214 void throw_if_no_interface() const;
215
216 friend class BranchAndBoundCallbackI<NodeInfoT>;
217};
218
219template<class NodeInfoT>
220void idol::BranchAndBoundCallback<NodeInfoT>::add_local_variable_branching(const Var &t_var, CtrType t_type, double t_rhs) {
221 throw_if_no_interface();
222 m_interface->add_local_variable_branching(t_var, t_type, t_rhs);
223}
224
225template<class NodeInfoT>
227 throw_if_no_interface();
228 return m_interface->best_obj();
229}
230
231template<class NodeInfoT>
233 throw_if_no_interface();
234 return m_interface->best_bound();
235}
236
237template<class NodeInfoT>
239 throw_if_no_interface();
240 m_interface->terminate();
241}
242
243template<class NodeInfoT>
245 throw_if_no_interface();
246 return m_interface->side_effect_registry();
247}
248
249template<class NodeInfoT>
251 throw_if_no_interface();
252 return m_interface->time();
253}
254
255template<class NodeInfoT>
257 throw_if_no_interface();
258 m_interface->submit_bound(t_bound);
259}
260
261template<class NodeInfoT>
263 throw_if_no_interface();
264 m_interface->submit_heuristic_solution(t_info);
265}
266
267template<class NodeInfoT>
269 throw_if_no_interface();
270 return m_interface->original_model();
271}
272
273template<class NodeInfoT>
275 throw_if_no_interface();
276 return m_interface->relaxation();
277}
278
279template<class NodeInfoT>
281 throw_if_no_interface();
282 return m_interface->node();
283}
284
285template<class NodeInfoT>
287 throw_if_no_interface();
288 m_interface->add_lazy_cut(t_cut);
289}
290
291template<class NodeInfoT>
293 throw_if_no_interface();
294 m_interface->add_user_cut(t_cut);
295}
296
297template<class NodeInfoT>
299 if (!m_interface) {
300 throw Exception("No interface was found.");
301 }
302}
303
304template<class NodeInfoT>
306idol::BranchAndBoundCallbackI<NodeInfoT>::operator()(Optimizers::BranchAndBound<NodeInfoT> *t_parent,
307 CallbackEvent t_event,
308 const Node<NodeInfoT> &t_current_node,
309 Model *t_relaxation) {
310 SideEffectRegistry result;
311
312 m_parent = t_parent;
313 m_node = t_current_node;
314 m_relaxation = t_relaxation;
315 m_registry = &result;
316
317 for (auto &cb: m_callbacks) {
318 cb->m_interface = this;
319 cb->operator()(t_event);
320 cb->m_interface = nullptr;
321 }
322
323 m_parent = nullptr;
324 m_node.reset();
325 m_relaxation = nullptr;
326 m_registry = nullptr;
327
328 return result;
329}
330
331template<class NodeInfoT>
332void idol::BranchAndBoundCallbackI<NodeInfoT>::add_callback(BranchAndBoundCallback<NodeInfoT> *t_cb) {
333 m_callbacks.emplace_back(t_cb);
334}
335
336template<class NodeInfoT>
337void idol::BranchAndBoundCallbackI<NodeInfoT>::initialize(Optimizers::BranchAndBound<NodeInfoT>* t_parent) {
338
339 m_parent = t_parent;
340
341 for (auto& ptr_callback : m_callbacks) {
342 ptr_callback->m_interface = this;
343 ptr_callback->initialize();
344 ptr_callback->m_interface = nullptr;
345 }
346
347 m_parent = nullptr;
348
349}
350
351template<class NodeInfoT>
353 if (!m_parent) {
354 throw Exception("submit_bound is not accessible in this context.");
355 }
356 m_parent->submit_lower_bound(t_bound);
357}
358
359template<class NodeInfoT>
361 if (!m_parent) {
362 throw Exception("submit_heuristic_solution is not accessible in this context.");
363 }
364 m_parent->submit_heuristic_solution(t_info);
365}
366
367template<class NodeInfoT>
369 if (!m_parent) {
370 throw Exception("original_model is not accessible in this context.");
371 }
372 return m_parent->parent();
373}
374
375template<class NodeInfoT>
377 if (!m_relaxation) {
378 throw Exception("relaxation is not accessible in this context.");
379 }
380 return *m_relaxation;
381}
382
383template<class NodeInfoT>
385 if (!m_node) {
386 throw Exception("node is not accessible in this context.");
387 }
388 return *m_node;
389}
390
391template<class NodeInfoT>
393 m_relaxation->add_ctr(t_cut);
394 ++m_registry->n_added_lazy_cuts;
395}
396
397template<class NodeInfoT>
399 m_relaxation->add_ctr(t_cut);
400 ++m_registry->n_added_user_cuts;
401}
402
403#endif //IDOL_BRANCHANDBOUNDCALLBACK_H
virtual void operator()(CallbackEvent t_event)=0
void submit_heuristic_solution(NodeInfoT *t_info)
void add_user_cut(const TempCtr &t_cut)
const SideEffectRegistry & side_effect_registry() const
const Node< NodeInfoT > & node() const
void add_lazy_cut(const TempCtr &t_cut)