A C++ Framework for Optimization
Loading...
Searching...
No Matches
BranchAndBound.h
1//
2// Created by henri on 21/03/23.
3//
4
5#ifndef IDOL_BRANCHANDBOUND_H
6#define IDOL_BRANCHANDBOUND_H
7
8#include <memory>
9#include "idol/general/optimizers/OptimizerFactory.h"
10#include "Optimizers_BranchAndBound.h"
11#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/BranchAndBoundCallbackFactory.h"
12#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/BranchAndBoundCallback.h"
13#include "idol/mixed-integer/optimizers/branch-and-bound/callbacks/CallbackAsBranchAndBoundCallback.h"
14#include "idol/mixed-integer/optimizers/callbacks/CallbackFactory.h"
15#include "idol/mixed-integer/optimizers/branch-and-bound/nodes/DefaultNodeInfo.h"
16#include "idol/mixed-integer/optimizers/branch-and-bound/logs/Factory.h"
17#include "idol/mixed-integer/optimizers/branch-and-bound/logs/Info.h"
18
19namespace idol {
20 template<class NodeT>
21 class BranchAndBound;
22}
23
28template<class NodeT = idol::DefaultNodeInfo>
29class idol::BranchAndBound : public OptimizerFactoryWithDefaultParameters<BranchAndBound<NodeT>> {
30 std::unique_ptr<OptimizerFactory> m_relaxation_optimizer_factory;
31 std::unique_ptr<BranchingRuleFactory<NodeT>> m_branching_rule_factory;
32 std::unique_ptr<NodeSelectionRuleFactory<NodeT>> m_node_selection_rule_factory;
33 std::unique_ptr<Logs::BranchAndBound::Factory<NodeT>> m_logger_factory;
34 std::unique_ptr<NodeT> m_root_node_info;
35
36 std::list<std::unique_ptr<BranchAndBoundCallbackFactory<NodeT>>> m_callbacks;
37
38 std::optional<unsigned int> m_subtree_depth;
39 std::optional<unsigned int> m_log_frequency;
40public:
47 template<class ReturnT, class T> using only_if_has_Strategy = typename std::pair<typename T::template Strategy<NodeT>, ReturnT>::second_type;
48
57 BranchAndBound() = default;
58
63 BranchAndBound(const BranchAndBound& t_rhs);
64
78
79 void set_node_optimizer(const OptimizerFactory& t_node_optimizer);
80
81 BranchAndBound<NodeT>& operator+=(const OptimizerFactory& t_node_optimizer);
82
95
112 template<class BranchingRuleFactoryT>
113 only_if_has_Strategy<BranchAndBound<NodeT>&, BranchingRuleFactoryT> with_branching_rule(const BranchingRuleFactoryT& t_branching_rule);
114
126
143 template<class NodeSelectionRuleFactoryT>
144 only_if_has_Strategy<BranchAndBound<NodeT>&, NodeSelectionRuleFactoryT> with_node_selection_rule(const NodeSelectionRuleFactoryT& t_node_selection_rule);
145
146 BranchAndBound(BranchAndBound&&) noexcept = default;
147 BranchAndBound& operator=(const BranchAndBound&) = delete;
148 BranchAndBound& operator=(BranchAndBound&&) noexcept = delete;
149
150 Optimizer *operator()(const Model &t_model) const override;
151
152 [[nodiscard]] OptimizerFactory *clone() const override;
153
174 BranchAndBound<NodeT>& with_subtree_depth(unsigned int t_depth);
175
176 BranchAndBound<NodeT>& with_logger(const Logs::BranchAndBound::Factory<NodeT>& t_log_factory);
177
190 BranchAndBound<NodeT>& add_callback(const BranchAndBoundCallbackFactory<NodeT> & t_callback);
191
206 BranchAndBound<NodeT>& add_callback(const CallbackFactory& t_callback);
207
208 BranchAndBound<NodeT>& with_root_node_info(const NodeT& t_root_node_info);
209};
210
211template<class NodeT>
212void idol::BranchAndBound<NodeT>::set_node_optimizer(const idol::OptimizerFactory &t_node_optimizer) {
213 m_relaxation_optimizer_factory.reset(t_node_optimizer.clone());
214}
215
216template<class NodeT>
219
220 if (m_logger_factory) {
221 throw Exception("Logs have already been configured.");
222 }
223
224 m_logger_factory.reset(t_log_factory.clone());
225
226 return *this;
227}
228
229template<class NodeT>
231 return with_node_optimizer(t_node_optimizer);
232}
233
234template<class NodeT>
239
240template <class NodeT>
242
243 if (m_root_node_info) {
244 throw Exception("A root node info has already been given");
245 }
246
247 m_root_node_info.reset(t_root_node_info.clone());
248
249 return *this;
250}
251
252template<class NodeT>
254
255 m_callbacks.emplace_back(t_callback.clone());
256
257 return *this;
258}
259
260template<class NodeT>
262
263 if (m_subtree_depth.has_value()) {
264 throw Exception("A subtree depth has already been given");
265 }
266
267 m_subtree_depth = t_depth;
268
269 return *this;
270}
271
272template<class NodeT>
273template<class NodeSelectionRuleFactoryT>
274typename idol::BranchAndBound<NodeT>::template only_if_has_Strategy<idol::BranchAndBound<NodeT>&, NodeSelectionRuleFactoryT>
275idol::BranchAndBound<NodeT>::with_node_selection_rule(const NodeSelectionRuleFactoryT &t_node_selection_rule) {
276 return with_node_selection_rule(typename NodeSelectionRuleFactoryT::template Strategy<NodeT>(t_node_selection_rule));
277}
278
279template<class NodeT>
282
283 if (m_node_selection_rule_factory) {
284 throw Exception("A node selection rule has already been set.");
285 }
286
287 m_node_selection_rule_factory.reset(t_node_selection.clone());
288
289 return *this;
290}
291
292template<class NodeT>
293template<class BranchingRuleFactoryT>
294typename idol::BranchAndBound<NodeT>::template only_if_has_Strategy<idol::BranchAndBound<NodeT>&, BranchingRuleFactoryT>
295idol::BranchAndBound<NodeT>::with_branching_rule(const BranchingRuleFactoryT &t_branching_rule) {
296 return with_branching_rule(typename BranchingRuleFactoryT::template Strategy<NodeT>(t_branching_rule));
297}
298
299template<class NodeT>
301
302 if (m_branching_rule_factory) {
303 throw Exception("A branching rule has already been set.");
304 }
305
306 m_branching_rule_factory.reset(t_branching_rule.clone());
307
308 return *this;
309}
310
311template<class NodeT>
313
314 if (m_relaxation_optimizer_factory) {
315 throw Exception("A node solver has already been set.");
316 }
317
318 m_relaxation_optimizer_factory.reset(t_node_optimizer.clone());
319
320 return *this;
321}
322
323template<class NodeT>
325
327 m_relaxation_optimizer_factory(t_rhs.m_relaxation_optimizer_factory ? t_rhs.m_relaxation_optimizer_factory->clone() : nullptr),
328 m_branching_rule_factory(t_rhs.m_branching_rule_factory ? t_rhs.m_branching_rule_factory->clone() : nullptr),
329 m_node_selection_rule_factory(t_rhs.m_node_selection_rule_factory ? t_rhs.m_node_selection_rule_factory->clone() : nullptr),
330 m_subtree_depth(t_rhs.m_subtree_depth),
331 m_logger_factory(t_rhs.m_logger_factory ? t_rhs.m_logger_factory->clone() : nullptr),
332 m_root_node_info(t_rhs.m_root_node_info ? t_rhs.m_root_node_info->clone() : nullptr) {
333
334 for (auto& cb : t_rhs.m_callbacks) {
335 m_callbacks.emplace_back(cb->clone());
336 }
337
338}
339
340template<class NodeT>
342
343 if (!m_relaxation_optimizer_factory) {
344 throw Exception("No node solver has been given, please call BranchAndBound::with_node_optimizer to configure.");
345 }
346
347 if (!m_branching_rule_factory) {
348 throw Exception("No branching rule has been given, please call BranchAndBound::with_branching_rule to configure.");
349 }
350
351 if (!m_node_selection_rule_factory) {
352 throw Exception("No node selection rule has been given, please call BranchAndBound::with_node_selection_rule to configure.");
353 }
354
355 std::unique_ptr<Logs::BranchAndBound::Factory<NodeT>> default_logger_factory;
356 if (!m_logger_factory) {
357 default_logger_factory = std::make_unique<Logs::BranchAndBound::Info<NodeT>>();
358 }
359
360 auto* result = new Optimizers::BranchAndBound<NodeT>(t_model,
361 *m_relaxation_optimizer_factory,
362 *m_branching_rule_factory,
363 *m_node_selection_rule_factory,
365 m_logger_factory ? *m_logger_factory : *default_logger_factory);
366
367 this->handle_default_parameters(result);
368
369 if (m_root_node_info) {
370 result->set_root_node_info(*m_root_node_info);
371 }
372
373 if (m_subtree_depth) {
374 result->set_subtree_depth(m_subtree_depth.value());
375 }
376
377 for (auto& cb : m_callbacks) {
378 result->add_callback(cb->operator()());
379 }
380
381 return result;
382}
383
384template<class NodeT>
388
389namespace idol {
390 template<class NodeInfoT>
391 BranchAndBound<NodeInfoT> operator+(const BranchAndBound<NodeInfoT>& t_branch_and_bound, const OptimizerFactory& t_node_optimizer) {
392 BranchAndBound<NodeInfoT> result(t_branch_and_bound);
393 result += t_node_optimizer;
394 return result;
395 }
396}
397
398#endif //IDOL_BRANCHANDBOUND_H
only_if_has_Strategy< BranchAndBound< NodeT > &, BranchingRuleFactoryT > with_branching_rule(const BranchingRuleFactoryT &t_branching_rule)
BranchAndBound< NodeT > & with_branching_rule(const BranchingRuleFactory< NodeT > &t_branching_rule)
BranchAndBound< NodeT > & with_node_selection_rule(const NodeSelectionRuleFactory< NodeT > &t_node_selection)
BranchAndBound< NodeT > & with_node_optimizer(const OptimizerFactory &t_node_optimizer)
BranchAndBound< NodeT > & add_callback(const BranchAndBoundCallbackFactory< NodeT > &t_callback)
BranchAndBound()=default
OptimizerFactory * clone() const override
typename std::pair< typename T::template Strategy< NodeT >, ReturnT >::second_type only_if_has_Strategy
BranchAndBound< NodeT > & with_subtree_depth(unsigned int t_depth)
only_if_has_Strategy< BranchAndBound< NodeT > &, NodeSelectionRuleFactoryT > with_node_selection_rule(const NodeSelectionRuleFactoryT &t_node_selection_rule)
Optimizer * operator()(const Model &t_model) const override
virtual OptimizerFactory * clone() const =0