5#ifndef IDOL_BRANCHANDBOUNDCALLBACK_H
6#define IDOL_BRANCHANDBOUNDCALLBACK_H
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"
16 template<
class NodeInfoT>
19 template<
class NodeInfoT>
26template<
class NodeInfoT>
30 std::list<std::unique_ptr<BranchAndBoundCallback<NodeInfoT>>> m_callbacks;
33 std::optional<Node<NodeInfoT>> m_node;
34 Model* m_relaxation =
nullptr;
40 void add_user_cut(
const TempCtr &t_cut);
42 void add_lazy_cut(
const TempCtr &t_cut);
44 void add_local_variable_branching(
const idol::Var &t_var, CtrType t_type,
double t_rhs);
48 [[nodiscard]]
const Model& relaxation()
const;
50 [[nodiscard]]
const Model& original_model()
const;
52 [[nodiscard]]
const Timer& time()
const;
56 void submit_heuristic_solution(NodeInfoT* t_info);
58 void submit_bound(
double t_bound);
60 [[nodiscard]]
double best_bound()
const;
62 [[nodiscard]]
double best_obj()
const;
64 [[nodiscard]]
unsigned int node_count()
const;
70 CallbackEvent t_event,
72 Model *t_relaxation)
override;
78 void log_after_termination()
override;
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++;
87template<
class NodeInfoT>
88void idol::BranchAndBoundCallbackI<NodeInfoT>::terminate() {
89 m_parent->terminate();
92template<
class NodeInfoT>
93double idol::BranchAndBoundCallbackI<NodeInfoT>::best_obj()
const {
94 return m_parent->get_best_obj();
97template <
class NodeInfoT>
98unsigned int idol::BranchAndBoundCallbackI<NodeInfoT>::node_count()
const {
99 return m_parent->n_solved_nodes();
102template<
class NodeInfoT>
103double idol::BranchAndBoundCallbackI<NodeInfoT>::best_bound()
const {
104 return m_parent->get_best_bound();
107template<
class NodeInfoT>
108void idol::BranchAndBoundCallbackI<NodeInfoT>::log_after_termination() {
110 if (m_callbacks.empty()) {
114 std::cout <<
"Callbacks:" << std::endl;
116 for (
auto& ptr_to_cb : m_callbacks) {
117 ptr_to_cb->log_after_termination();
120 std::cout << std::endl;
124template<
class NodeInfoT>
127 throw Exception(
"No side effect registry was found");
132template<
class NodeInfoT>
133const idol::Timer &idol::BranchAndBoundCallbackI<NodeInfoT>::time()
const {
134 return m_parent->time();
137template<
class NodeInfoT>
154 virtual void log_after_termination() {}
168 void add_local_variable_branching(
const Var &t_var, CtrType t_type,
double t_rhs);
211 [[nodiscard]]
const Timer& time()
const;
213 [[nodiscard]]
double best_bound()
const;
215 [[nodiscard]]
double best_obj()
const;
217 [[nodiscard]]
unsigned int node_count()
const;
223 void throw_if_no_interface()
const;
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);
234template<
class NodeInfoT>
235double idol::BranchAndBoundCallback<NodeInfoT>::best_obj()
const {
236 throw_if_no_interface();
237 return m_interface->best_obj();
240template <
class NodeInfoT>
241unsigned int idol::BranchAndBoundCallback<NodeInfoT>::node_count()
const {
242 throw_if_no_interface();
243 return m_interface->node_count();
246template<
class NodeInfoT>
247double idol::BranchAndBoundCallback<NodeInfoT>::best_bound()
const {
248 throw_if_no_interface();
249 return m_interface->best_bound();
252template<
class NodeInfoT>
253void idol::BranchAndBoundCallback<NodeInfoT>::terminate() {
254 throw_if_no_interface();
255 m_interface->terminate();
258template<
class NodeInfoT>
260 throw_if_no_interface();
261 return m_interface->side_effect_registry();
264template<
class NodeInfoT>
265const idol::Timer &idol::BranchAndBoundCallback<NodeInfoT>::time()
const {
266 throw_if_no_interface();
267 return m_interface->time();
270template<
class NodeInfoT>
272 throw_if_no_interface();
273 m_interface->submit_bound(t_bound);
276template<
class NodeInfoT>
278 throw_if_no_interface();
279 m_interface->submit_heuristic_solution(t_info);
282template<
class NodeInfoT>
284 throw_if_no_interface();
285 return m_interface->original_model();
288template<
class NodeInfoT>
290 throw_if_no_interface();
291 return m_interface->relaxation();
294template<
class NodeInfoT>
296 throw_if_no_interface();
297 return m_interface->node();
300template<
class NodeInfoT>
302 throw_if_no_interface();
303 m_interface->add_lazy_cut(t_cut);
306template<
class NodeInfoT>
308 throw_if_no_interface();
309 m_interface->add_user_cut(t_cut);
312template<
class NodeInfoT>
313void idol::BranchAndBoundCallback<NodeInfoT>::throw_if_no_interface()
const {
315 throw Exception(
"No interface was found.");
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;
328 m_node = t_current_node;
329 m_relaxation = t_relaxation;
330 m_registry = &result;
332 for (
auto &cb: m_callbacks) {
333 cb->m_interface =
this;
334 cb->operator()(t_event);
335 cb->m_interface =
nullptr;
340 m_relaxation =
nullptr;
341 m_registry =
nullptr;
346template<
class NodeInfoT>
347void idol::BranchAndBoundCallbackI<NodeInfoT>::add_callback(BranchAndBoundCallback<NodeInfoT> *t_cb) {
348 m_callbacks.emplace_back(t_cb);
351template<
class NodeInfoT>
352void idol::BranchAndBoundCallbackI<NodeInfoT>::initialize(Optimizers::BranchAndBound<NodeInfoT>* t_parent) {
356 for (
auto& ptr_callback : m_callbacks) {
357 ptr_callback->m_interface =
this;
358 ptr_callback->initialize();
359 ptr_callback->m_interface =
nullptr;
366template<
class NodeInfoT>
367void idol::BranchAndBoundCallbackI<NodeInfoT>::submit_bound(
double t_bound) {
369 throw Exception(
"submit_bound is not accessible in this context.");
371 m_parent->submit_lower_bound(t_bound);
374template<
class NodeInfoT>
375void idol::BranchAndBoundCallbackI<NodeInfoT>::submit_heuristic_solution(NodeInfoT *t_info) {
377 throw Exception(
"submit_heuristic_solution is not accessible in this context.");
379 m_parent->submit_heuristic_solution(t_info);
382template<
class NodeInfoT>
383const idol::Model &idol::BranchAndBoundCallbackI<NodeInfoT>::original_model()
const {
385 throw Exception(
"original_model is not accessible in this context.");
387 return m_parent->parent();
390template<
class NodeInfoT>
391const idol::Model &idol::BranchAndBoundCallbackI<NodeInfoT>::relaxation()
const {
393 throw Exception(
"relaxation is not accessible in this context.");
395 return *m_relaxation;
398template<
class NodeInfoT>
401 throw Exception(
"node is not accessible in this context.");
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;
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);;
virtual void operator()(CallbackEvent t_event)=0
void submit_heuristic_solution(NodeInfoT *t_info)
void add_user_cut(const TempCtr &t_cut)
const Model & relaxation() const
const SideEffectRegistry & side_effect_registry() const
const Node< NodeInfoT > & node() const
void add_lazy_cut(const TempCtr &t_cut)
virtual void initialize()
void submit_bound(double t_bound)
const Model & original_model() const