Loading...
Searching...
No Matches
IntegerMaster.h
1//
2// Created by henri on 30/03/23.
3//
4
5#ifndef IDOL_INTEGERMASTER_H
6#define IDOL_INTEGERMASTER_H
7
8#include "idol/mixed-integer/optimizers/branch-and-bound/nodes/DefaultNodeInfo.h"
9#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/BranchAndBoundCallbackFactory.h"
10#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/BranchAndBoundCallback.h"
11#include "idol/mixed-integer/optimizers/dantzig-wolfe/Optimizers_DantzigWolfeDecomposition.h"
12
13namespace idol::Heuristics {
14 template<class NodeInfoT> class IntegerMaster;
15}
16
17template<class NodeInfoT = idol::DefaultNodeInfo>
19 std::unique_ptr<OptimizerFactory> m_optimizer_factory;
20
21 std::optional<bool> m_integer_columns;
22
23 std::optional<double> m_time_limit;
24 std::optional<unsigned int> m_iteration_limit;
25 std::optional<unsigned int> m_max_depth;
26 std::optional<unsigned int> m_frequency;
27
28 IntegerMaster(const IntegerMaster& t_src);
29public:
30 IntegerMaster() = default;
31
32 IntegerMaster(IntegerMaster&&) noexcept = default;
33
34 IntegerMaster& operator=(const IntegerMaster&) = delete;
35 IntegerMaster& operator=(IntegerMaster&&) noexcept = default;
36
37 class Strategy : public BranchAndBoundCallback<NodeInfoT> {
38 std::unique_ptr<OptimizerFactory> m_optimizer_factory;
39 bool m_integer_columns = true;
40 double m_time_limit = std::numeric_limits<double>::max();
41 unsigned int m_iteration_limit = std::numeric_limits<unsigned int>::max();
42 unsigned int m_max_depth = 1000;
43 unsigned int m_frequency = 20;
44 protected:
45 void operator()(CallbackEvent t_event) override;
46 public:
47 explicit Strategy(const OptimizerFactory& t_optimizer);
48
49 [[nodiscard]] bool with_integer_columns() const { return m_integer_columns; }
50
51 void set_integer_columns(bool t_value) { m_integer_columns = t_value; }
52
53 void set_time_limit(double t_time_limit) { m_time_limit = std::max(0., t_time_limit); }
54
55 void set_iteration_limit(unsigned int t_iteration_limit) { m_iteration_limit = t_iteration_limit; }
56
57 void set_max_depth(unsigned int t_max_depth) { m_max_depth = t_max_depth; }
58
59 void set_frequency(unsigned int t_frequency) { m_frequency = t_frequency; }
60 };
61
62 BranchAndBoundCallback<NodeInfoT> *operator()() override;
63
64 [[nodiscard]] BranchAndBoundCallbackFactory<NodeInfoT> *clone() const override;
65
66 IntegerMaster& with_optimizer(const OptimizerFactory& t_optimizer);
67
68 IntegerMaster& with_integer_columns(bool t_value);
69
70 IntegerMaster& with_time_limit(double t_time_limit);
71
72 IntegerMaster& with_iteration_limit(unsigned int t_iteration_limit);
73
74 IntegerMaster& with_max_depth(unsigned int t_max_depth);
75
76 IntegerMaster& with_frequency(unsigned int t_frequency);
77};
78
79template<class NodeInfoT>
80idol::Heuristics::IntegerMaster<NodeInfoT>::IntegerMaster(const IntegerMaster& t_src)
81 : m_optimizer_factory(t_src.m_optimizer_factory ? t_src.m_optimizer_factory->clone() : nullptr),
82 m_integer_columns(t_src.m_integer_columns),
83 m_time_limit(t_src.m_time_limit),
84 m_iteration_limit(t_src.m_time_limit),
85 m_max_depth(t_src.m_max_depth),
86 m_frequency(t_src.m_frequency)
87{}
88
89template<class NodeInfoT>
90idol::BranchAndBoundCallback<NodeInfoT> *idol::Heuristics::IntegerMaster<NodeInfoT>::operator()() {
91
92 if (!m_optimizer_factory) {
93 throw Exception("No solver was given to solve the integer master problem, please call IntegerMaster.rst::with_osi_interface to configure.");
94 }
95
96 auto* result = new Strategy(*m_optimizer_factory);
97
98 if (m_integer_columns.has_value()) {
99 result->set_integer_columns(m_integer_columns.value());
100 }
101
102 if (m_time_limit.has_value()) {
103 result->set_time_limit(m_time_limit.value());
104 }
105
106 if (m_iteration_limit.has_value()) {
107 result->set_iteration_limit(m_iteration_limit.value());
108 }
109
110 if (m_max_depth.has_value()){
111 result->set_max_depth(m_max_depth.value());
112 }
113
114 if (m_frequency.has_value()) {
115 result->set_frequency(m_frequency.value());
116 }
117
118 return result;
119}
120
121template<class NodeInfoT>
122idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_optimizer(const OptimizerFactory &t_optimizer) {
123
124 if (m_optimizer_factory) {
125 throw Exception("A solver has already been given.");
126 }
127
128 m_optimizer_factory.reset(t_optimizer.clone());
129
130 return *this;
131}
132
133template<class NodeInfoT>
134idol::BranchAndBoundCallbackFactory<NodeInfoT> *idol::Heuristics::IntegerMaster<NodeInfoT>::clone() const {
135 return new IntegerMaster(*this);
136}
137
138template<class NodeInfoT>
139idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_integer_columns(bool t_value) {
140 m_integer_columns = t_value;
141 return *this;
142}
143
144template<class NodeInfoT>
145idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_time_limit(double t_time_limit) {
146 m_time_limit = t_time_limit;
147 return *this;
148}
149
150template<class NodeInfoT>
151idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_iteration_limit(unsigned int t_iteration_limit) {
152 m_iteration_limit = t_iteration_limit;
153 return *this;
154}
155
156template<class NodeInfoT>
157idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_max_depth(unsigned int t_max_depth) {
158 m_max_depth = t_max_depth;
159 return *this;
160}
161
162template<class NodeInfoT>
163idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_frequency(unsigned int t_frequency) {
164 m_frequency = t_frequency;
165 return *this;
166}
167
168template<class NodeInfoT>
169idol::Heuristics::IntegerMaster<NodeInfoT>::Strategy::Strategy(const OptimizerFactory &t_optimizer)
170 : m_optimizer_factory(t_optimizer.clone()) {
171
172}
173
174template<class NodeInfoT>
176
177 if (t_event != InvalidSolution) {
178 return;
179 }
180
181 if (m_max_depth < this->node().level()) {
182 return;
183 }
184
185 if ( this->node_count() % m_frequency != 0) {
186 return;
187 }
188
189 const auto& relaxation = this->relaxation();
190 const auto& dantzig_wolfe_optimizer = relaxation.optimizer().template as<Optimizers::DantzigWolfeDecomposition>();
191 const auto& original_model = this->original_model();
192 const auto& formulation = dantzig_wolfe_optimizer.formulation();
193 const unsigned int n_sub_problems = formulation.n_sub_problems();
194
195 std::unique_ptr<Model> integer_master_new(relaxation.clone());
196 auto& dw = integer_master_new->optimizer().as<Optimizers::DantzigWolfeDecomposition>();
197
198 // Here, we add all columns currently present in the relaxation
199 for (unsigned int k = 0 ; k < n_sub_problems ; ++k) {
200 for (const auto& [var, col] : formulation.present_generators(k)) {
201 dw.formulation().generate_column(k, col);
202 }
203 }
204
205 // Set integers
206 if (m_integer_columns) {
207 for (unsigned int i = 0 ; i < n_sub_problems ; ++i) {
208 for (const auto &[alpha, generator]: dw.formulation().present_generators(i)) {
209 dw.formulation().master().set_var_type(alpha, Binary);
210 }
211 }
212 }
213
214 // Use different master optimizer
215 dw.set_master_optimizer_factory(*m_optimizer_factory);
216
217 // Set parameters
218 dw.set_param_logs(false);
219 dw.set_param_iteration_limit(0);
220 dw.set_param_time_limit(std::min(m_time_limit, relaxation.optimizer().get_remaining_time()));
221
222 // Set bound limit if there is a current incumbent
223 auto& branch_and_bound = this->original_model().optimizer().template as<Optimizers::BranchAndBound<NodeInfoT>>();;
224 dw.set_param_best_bound_stop(branch_and_bound.get_best_obj());
225
226 integer_master_new->optimize();
227
228 const int status = integer_master_new->get_status();
229
230 if (status != Optimal && status != Feasible) {
231 return;
232 }
233
234 auto* info = new NodeInfoT();
235 info->save(original_model, *integer_master_new);
236 this->submit_heuristic_solution(info);
237
238}
239
240#endif //IDOL_INTEGERMASTER_H
void submit_heuristic_solution(NodeInfoT *t_info)
const Node< NodeInfoT > & node() const
void operator()(CallbackEvent t_event) override