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>
18
19 template<class NodeInfoT>
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 [[nodiscard]] unsigned int node_count() const;
65
66 void terminate();
67
68 SideEffectRegistry operator()(
70 CallbackEvent t_event,
71 const Node<NodeInfoT>& t_current_node,
72 Model *t_relaxation) override;
73
74 void add_callback(BranchAndBoundCallback<NodeInfoT> *t_cb) override;
75
76 void initialize(Optimizers::BranchAndBound<NodeInfoT>* t_parent) override;
77
78 void log_after_termination() override;
79};
80
81template<class NodeInfoT>
82void idol::BranchAndBoundCallbackI<NodeInfoT>::add_local_variable_branching(const idol::Var &t_var, CtrType t_type, double t_rhs) {
83 m_node->info().add_branching_variable(t_var, t_type, t_rhs);
84 m_registry->n_added_local_variable_branching++;
85}
86
87template<class NodeInfoT>
88void idol::BranchAndBoundCallbackI<NodeInfoT>::terminate() {
89 m_parent->terminate();
90}
91
92template<class NodeInfoT>
93double idol::BranchAndBoundCallbackI<NodeInfoT>::best_obj() const {
94 return m_parent->get_best_obj();
95}
96
97template <class NodeInfoT>
98unsigned int idol::BranchAndBoundCallbackI<NodeInfoT>::node_count() const {
99 return m_parent->n_solved_nodes();
100}
101
102template<class NodeInfoT>
103double idol::BranchAndBoundCallbackI<NodeInfoT>::best_bound() const {
104 return m_parent->get_best_bound();
105}
106
107template<class NodeInfoT>
108void idol::BranchAndBoundCallbackI<NodeInfoT>::log_after_termination() {
109
110 if (m_callbacks.empty()) {
111 return;
112 }
113
114 std::cout << "Callbacks:" << std::endl;
115
116 for (auto& ptr_to_cb : m_callbacks) {
117 ptr_to_cb->log_after_termination();
118 }
119
120 std::cout << std::endl;
121
122}
123
124template<class NodeInfoT>
125const idol::SideEffectRegistry &idol::BranchAndBoundCallbackI<NodeInfoT>::side_effect_registry() const {
126 if (!m_registry) {
127 throw Exception("No side effect registry was found");
128 }
129 return *m_registry;
130}
131
132template<class NodeInfoT>
133const idol::Timer &idol::BranchAndBoundCallbackI<NodeInfoT>::time() const {
134 return m_parent->time();
135}
136
137template<class NodeInfoT>
139public:
140 virtual ~BranchAndBoundCallback() = default;
141protected:
142
146 virtual void initialize() {}
147
152 virtual void operator()(CallbackEvent t_event) = 0;
153
154 virtual void log_after_termination() {}
155
160 void add_user_cut(const TempCtr& t_cut);
161
166 void add_lazy_cut(const TempCtr& t_cut);
167
168 void add_local_variable_branching(const Var &t_var, CtrType t_type, double t_rhs);
169
174 [[nodiscard]] const Node<NodeInfoT>& node() const;
175
180 [[nodiscard]] const Model& relaxation() const;
181
186 [[nodiscard]] const Model& original_model() const;
187
195 void submit_heuristic_solution(NodeInfoT* t_info);
196
203 void submit_bound(double t_bound);
204
209 [[nodiscard]] const SideEffectRegistry& side_effect_registry() const;
210
211 [[nodiscard]] const Timer& time() const;
212
213 [[nodiscard]] double best_bound() const;
214
215 [[nodiscard]] double best_obj() const;
216
217 [[nodiscard]] unsigned int node_count() const;
218
219 void terminate();
220private:
221 BranchAndBoundCallbackI<NodeInfoT>* m_interface = nullptr;
222
223 void throw_if_no_interface() const;
224
225 friend class BranchAndBoundCallbackI<NodeInfoT>;
226};
227
228template<class NodeInfoT>
229void idol::BranchAndBoundCallback<NodeInfoT>::add_local_variable_branching(const Var &t_var, CtrType t_type, double t_rhs) {
230 throw_if_no_interface();
231 m_interface->add_local_variable_branching(t_var, t_type, t_rhs);
232}
233
234template<class NodeInfoT>
235double idol::BranchAndBoundCallback<NodeInfoT>::best_obj() const {
236 throw_if_no_interface();
237 return m_interface->best_obj();
238}
239
240template <class NodeInfoT>
241unsigned int idol::BranchAndBoundCallback<NodeInfoT>::node_count() const {
242 throw_if_no_interface();
243 return m_interface->node_count();
244}
245
246template<class NodeInfoT>
247double idol::BranchAndBoundCallback<NodeInfoT>::best_bound() const {
248 throw_if_no_interface();
249 return m_interface->best_bound();
250}
251
252template<class NodeInfoT>
253void idol::BranchAndBoundCallback<NodeInfoT>::terminate() {
254 throw_if_no_interface();
255 m_interface->terminate();
256}
257
258template<class NodeInfoT>
260 throw_if_no_interface();
261 return m_interface->side_effect_registry();
262}
263
264template<class NodeInfoT>
265const idol::Timer &idol::BranchAndBoundCallback<NodeInfoT>::time() const {
266 throw_if_no_interface();
267 return m_interface->time();
268}
269
270template<class NodeInfoT>
272 throw_if_no_interface();
273 m_interface->submit_bound(t_bound);
274}
275
276template<class NodeInfoT>
278 throw_if_no_interface();
279 m_interface->submit_heuristic_solution(t_info);
280}
281
282template<class NodeInfoT>
284 throw_if_no_interface();
285 return m_interface->original_model();
286}
287
288template<class NodeInfoT>
290 throw_if_no_interface();
291 return m_interface->relaxation();
292}
293
294template<class NodeInfoT>
296 throw_if_no_interface();
297 return m_interface->node();
298}
299
300template<class NodeInfoT>
302 throw_if_no_interface();
303 m_interface->add_lazy_cut(t_cut);
304}
305
306template<class NodeInfoT>
308 throw_if_no_interface();
309 m_interface->add_user_cut(t_cut);
310}
311
312template<class NodeInfoT>
313void idol::BranchAndBoundCallback<NodeInfoT>::throw_if_no_interface() const {
314 if (!m_interface) {
315 throw Exception("No interface was found.");
316 }
317}
318
319template<class NodeInfoT>
321idol::BranchAndBoundCallbackI<NodeInfoT>::operator()(Optimizers::BranchAndBound<NodeInfoT> *t_parent,
322 CallbackEvent t_event,
323 const Node<NodeInfoT> &t_current_node,
324 Model *t_relaxation) {
325 SideEffectRegistry result;
326
327 m_parent = t_parent;
328 m_node = t_current_node;
329 m_relaxation = t_relaxation;
330 m_registry = &result;
331
332 for (auto &cb: m_callbacks) {
333 cb->m_interface = this;
334 cb->operator()(t_event);
335 cb->m_interface = nullptr;
336 }
337
338 m_parent = nullptr;
339 m_node.reset();
340 m_relaxation = nullptr;
341 m_registry = nullptr;
342
343 return result;
344}
345
346template<class NodeInfoT>
347void idol::BranchAndBoundCallbackI<NodeInfoT>::add_callback(BranchAndBoundCallback<NodeInfoT> *t_cb) {
348 m_callbacks.emplace_back(t_cb);
349}
350
351template<class NodeInfoT>
352void idol::BranchAndBoundCallbackI<NodeInfoT>::initialize(Optimizers::BranchAndBound<NodeInfoT>* t_parent) {
353
354 m_parent = t_parent;
355
356 for (auto& ptr_callback : m_callbacks) {
357 ptr_callback->m_interface = this;
358 ptr_callback->initialize();
359 ptr_callback->m_interface = nullptr;
360 }
361
362 m_parent = nullptr;
363
364}
365
366template<class NodeInfoT>
367void idol::BranchAndBoundCallbackI<NodeInfoT>::submit_bound(double t_bound) {
368 if (!m_parent) {
369 throw Exception("submit_bound is not accessible in this context.");
370 }
371 m_parent->submit_lower_bound(t_bound);
372}
373
374template<class NodeInfoT>
375void idol::BranchAndBoundCallbackI<NodeInfoT>::submit_heuristic_solution(NodeInfoT *t_info) {
376 if (!m_parent) {
377 throw Exception("submit_heuristic_solution is not accessible in this context.");
378 }
379 m_parent->submit_heuristic_solution(t_info);
380}
381
382template<class NodeInfoT>
383const idol::Model &idol::BranchAndBoundCallbackI<NodeInfoT>::original_model() const {
384 if (!m_parent) {
385 throw Exception("original_model is not accessible in this context.");
386 }
387 return m_parent->parent();
388}
389
390template<class NodeInfoT>
391const idol::Model &idol::BranchAndBoundCallbackI<NodeInfoT>::relaxation() const {
392 if (!m_relaxation) {
393 throw Exception("relaxation is not accessible in this context.");
394 }
395 return *m_relaxation;
396}
397
398template<class NodeInfoT>
399const idol::Node<NodeInfoT> &idol::BranchAndBoundCallbackI<NodeInfoT>::node() const {
400 if (!m_node) {
401 throw Exception("node is not accessible in this context.");
402 }
403 return *m_node;
404}
405
406template<class NodeInfoT>
407void idol::BranchAndBoundCallbackI<NodeInfoT>::add_lazy_cut(const TempCtr &t_cut) {
408 m_parent->add_lazy_cut(t_cut);
409 ++m_registry->n_added_lazy_cuts;
410}
411
412template<class NodeInfoT>
413void idol::BranchAndBoundCallbackI<NodeInfoT>::add_user_cut(const TempCtr &t_cut) {
414 m_registry->n_added_user_cuts += m_parent->add_user_cut(t_cut);;
415}
416
417#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)