Loading...
Searching...
No Matches
LocalMIP.h
1//
2// Created by Henri on 27/03/2026.
3//
4
5#ifndef IDOL_LOCALMIP_H
6#define IDOL_LOCALMIP_H
7
8#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/BranchAndBoundCallbackFactory.h"
9#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/BranchAndBoundCallback.h"
10#include "idol/mixed-integer/optimizers/branch-and-bound/nodes/DefaultNodeInfo.h"
11
12namespace idol::Heuristics {
13 template<class> class LocalMIP;
14 namespace impl {
15 std::optional<PrimalPoint> call_local_mip(const Model& t_model, const PrimalPoint& t_primal_point, double t_time_limit);
16 }
17}
18
19template<class NodeInfoT = idol::DefaultNodeInfo>
21public:
22 class Strategy : public BranchAndBoundCallback<NodeInfoT> {
23 bool m_found_feasible_at_root_node = true;
24 unsigned int m_n_calls = 0;
25 unsigned int m_n_tries = 0;
26 unsigned int m_n_submitted_points = 0;
27 unsigned int m_frequency = 50;
28 protected:
29 void operator()(CallbackEvent t_event) override;
30 void log_after_termination() override;
31 };
32
33 BranchAndBoundCallback<NodeInfoT>* operator()() override;
34 BranchAndBoundCallbackFactory<NodeInfoT>* clone() const override;
35};
36
37template <class NodeInfoT>
39
40 if (t_event != InvalidSolution) {
41 return;
42 }
43
44 const bool is_root_node = this->node().id() == 0;
45
46 m_n_calls++;
47 if (!is_root_node) {
48 if (m_n_calls % m_frequency > 0 || !m_found_feasible_at_root_node) {
49 return;
50 }
51 }
52
53 const double relative_gap = idol::relative_gap(this->best_bound(), this->best_obj());
54
55 bool be_aggressive = false;
56 if (is_root_node || relative_gap > 1) {
57 be_aggressive = true;
58 }
59
60 const double time_used_to_solve_node = this->relaxation().optimizer().time().count();
61 const double factor_for_heuristic = be_aggressive ? 200 : 10;
62 const double heuristic_time_limit = std::min(this->original_model().optimizer().get_remaining_time(), factor_for_heuristic * time_used_to_solve_node);
63 auto point = impl::call_local_mip(this->original_model(), this->node().info().primal_solution(), heuristic_time_limit);
64 m_n_tries++;
65
66 if (!point) {
67
68 if (is_root_node) {
69 m_found_feasible_at_root_node = false;
70 }
71
72 if (m_n_submitted_points == 0) {
73 m_frequency *= 1.5;
74 }
75
76 return;
77 }
78
79 auto* info = new NodeInfoT();
80 info->set_primal_solution(*point);
81 this->submit_heuristic_solution(info);
82 m_n_submitted_points++;
83
84}
85
86template <class NodeInfoT>
87void idol::Heuristics::LocalMIP<NodeInfoT>::Strategy::log_after_termination() {
88
89 BranchAndBoundCallback<NodeInfoT>::log_after_termination();
90
91 std::cout << "Local-MIP Heuristic: Called " << m_n_tries << ", Found " << m_n_submitted_points << "." << std::endl;
92
93}
94
95template <class NodeInfoT>
96idol::BranchAndBoundCallback<NodeInfoT>* idol::Heuristics::LocalMIP<NodeInfoT>::operator()() {
97 return new Strategy();
98}
99
100template <class NodeInfoT>
101idol::BranchAndBoundCallbackFactory<NodeInfoT>* idol::Heuristics::LocalMIP<NodeInfoT>::clone() const {
102 return new LocalMIP(*this);
103}
104
105#endif //IDOL_LOCALMIP_H
void submit_heuristic_solution(NodeInfoT *t_info)
const Node< NodeInfoT > & node() const
void operator()(CallbackEvent t_event) override
Definition LocalMIP.h:38