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/presolve/AbstractPresolver.h"
15#include "idol/mixed-integer/optimizers/callbacks/CallbackFactory.h"
16#include "idol/mixed-integer/optimizers/branch-and-bound/nodes/DefaultNodeInfo.h"
17#include "idol/mixed-integer/optimizers/branch-and-bound/logs/Factory.h"
18#include "idol/mixed-integer/optimizers/branch-and-bound/logs/Info.h"
19
20namespace idol {
21 template<class NodeT>
22 class BranchAndBound;
23}
24
29template<class NodeT = idol::DefaultNodeInfo>
30class idol::BranchAndBound : public OptimizerFactoryWithDefaultParameters<BranchAndBound<NodeT>> {
31 std::unique_ptr<OptimizerFactory> m_relaxation_optimizer_factory;
32 std::unique_ptr<BranchingRuleFactory<NodeT>> m_branching_rule_factory;
33 std::unique_ptr<NodeSelectionRuleFactory<NodeT>> m_node_selection_rule_factory;
34 std::unique_ptr<Logs::BranchAndBound::Factory<NodeT>> m_logger_factory;
35 std::unique_ptr<NodeT> m_root_node_info;
36
37 std::list<std::unique_ptr<Presolvers::AbstractPresolver>> m_presolvers;
38 std::list<std::unique_ptr<BranchAndBoundCallbackFactory<NodeT>>> m_callbacks;
39
40 std::optional<unsigned int> m_subtree_depth;
41 std::optional<unsigned int> m_log_frequency;
42protected:
43 [[nodiscard]] Optimizer *create(const Model &t_model) const override;
44public:
51 template<class ReturnT, class T> using only_if_has_Strategy = typename std::pair<typename T::template Strategy<NodeT>, ReturnT>::second_type;
52
61 BranchAndBound() = default;
62
67 BranchAndBound(const BranchAndBound& t_rhs);
68
82
83 void set_node_optimizer(const OptimizerFactory& t_node_optimizer);
84
85 BranchAndBound<NodeT>& operator+=(const OptimizerFactory& t_node_optimizer);
86
99
116 template<class BranchingRuleFactoryT>
117 only_if_has_Strategy<BranchAndBound<NodeT>&, BranchingRuleFactoryT> with_branching_rule(const BranchingRuleFactoryT& t_branching_rule);
118
130
147 template<class NodeSelectionRuleFactoryT>
148 only_if_has_Strategy<BranchAndBound<NodeT>&, NodeSelectionRuleFactoryT> with_node_selection_rule(const NodeSelectionRuleFactoryT& t_node_selection_rule);
149
150 BranchAndBound(BranchAndBound&&) noexcept = default;
151 BranchAndBound& operator=(const BranchAndBound&) = delete;
152 BranchAndBound& operator=(BranchAndBound&&) noexcept = delete;
153
154 [[nodiscard]] OptimizerFactory *clone() const override;
155
176 BranchAndBound<NodeT>& with_subtree_depth(unsigned int t_depth);
177
178 BranchAndBound<NodeT>& with_logger(const Logs::BranchAndBound::Factory<NodeT>& t_log_factory);
179
192 BranchAndBound<NodeT>& add_callback(const BranchAndBoundCallbackFactory<NodeT> & t_callback);
193
208 BranchAndBound<NodeT>& add_callback(const CallbackFactory& t_callback);
209
210 BranchAndBound<NodeT>& add_presolver(const Presolvers::AbstractPresolver& t_presolver);
211
212 BranchAndBound<NodeT>& with_root_node_info(const NodeT& t_root_node_info);
213};
214
215template<class NodeT>
216void idol::BranchAndBound<NodeT>::set_node_optimizer(const idol::OptimizerFactory &t_node_optimizer) {
217 m_relaxation_optimizer_factory.reset(t_node_optimizer.clone());
218}
219
220template<class NodeT>
222idol::BranchAndBound<NodeT>::with_logger(const typename idol::Logs::BranchAndBound::Factory<NodeT> &t_log_factory) {
223
224 if (m_logger_factory) {
225 throw Exception("Logs have already been configured.");
226 }
227
228 m_logger_factory.reset(t_log_factory.clone());
229
230 return *this;
231}
232
233template<class NodeT>
234idol::BranchAndBound<NodeT> &idol::BranchAndBound<NodeT>::operator+=(const idol::OptimizerFactory &t_node_optimizer) {
235 return with_node_optimizer(t_node_optimizer);
236}
237
238template<class NodeT>
239idol::BranchAndBound<NodeT> &
243
244template <class NodeT>
245idol::BranchAndBound<NodeT>& idol::BranchAndBound<NodeT>::add_presolver(const Presolvers::AbstractPresolver& t_presolver) {
246 m_presolvers.emplace_back(t_presolver.clone());
247 return *this;
248}
249
250template <class NodeT>
251idol::BranchAndBound<NodeT>& idol::BranchAndBound<NodeT>::with_root_node_info(const NodeT& t_root_node_info) {
252
253 if (m_root_node_info) {
254 throw Exception("A root node info has already been given");
255 }
256
257 m_root_node_info.reset(t_root_node_info.clone());
258
259 return *this;
260}
261
262template<class NodeT>
264
265 m_callbacks.emplace_back(t_callback.clone());
266
267 return *this;
268}
269
270template<class NodeT>
272
273 if (m_subtree_depth.has_value()) {
274 throw Exception("A subtree depth has already been given");
275 }
276
277 m_subtree_depth = t_depth;
278
279 return *this;
280}
281
282template<class NodeT>
283template<class NodeSelectionRuleFactoryT>
285idol::BranchAndBound<NodeT>::with_node_selection_rule(const NodeSelectionRuleFactoryT &t_node_selection_rule) {
286 return with_node_selection_rule(typename NodeSelectionRuleFactoryT::template Strategy<NodeT>(t_node_selection_rule));
287}
288
289template<class NodeT>
292
293 if (m_node_selection_rule_factory) {
294 throw Exception("A node selection rule has already been set.");
295 }
296
297 m_node_selection_rule_factory.reset(t_node_selection.clone());
298
299 return *this;
300}
301
302template<class NodeT>
303template<class BranchingRuleFactoryT>
305idol::BranchAndBound<NodeT>::with_branching_rule(const BranchingRuleFactoryT &t_branching_rule) {
306 return with_branching_rule(typename BranchingRuleFactoryT::template Strategy<NodeT>(t_branching_rule));
307}
308
309template<class NodeT>
311
312 if (m_branching_rule_factory) {
313 throw Exception("A branching rule has already been set.");
314 }
315
316 m_branching_rule_factory.reset(t_branching_rule.clone());
317
318 return *this;
319}
320
321template<class NodeT>
323
324 if (m_relaxation_optimizer_factory) {
325 throw Exception("A node solver has already been set.");
326 }
327
328 m_relaxation_optimizer_factory.reset(t_node_optimizer.clone());
329
330 return *this;
331}
332
333template<class NodeT>
335
337 m_relaxation_optimizer_factory(t_rhs.m_relaxation_optimizer_factory ? t_rhs.m_relaxation_optimizer_factory->clone() : nullptr),
338 m_branching_rule_factory(t_rhs.m_branching_rule_factory ? t_rhs.m_branching_rule_factory->clone() : nullptr),
339 m_node_selection_rule_factory(t_rhs.m_node_selection_rule_factory ? t_rhs.m_node_selection_rule_factory->clone() : nullptr),
340 m_subtree_depth(t_rhs.m_subtree_depth),
341 m_logger_factory(t_rhs.m_logger_factory ? t_rhs.m_logger_factory->clone() : nullptr),
342 m_root_node_info(t_rhs.m_root_node_info ? t_rhs.m_root_node_info->clone() : nullptr) {
343
344 for (auto& presolve : t_rhs.m_presolvers) {
345 m_presolvers.emplace_back(presolve->clone());
346 }
347
348 for (auto& cb : t_rhs.m_callbacks) {
349 m_callbacks.emplace_back(cb->clone());
350 }
351
352}
353
354template<class NodeT>
355idol::Optimizer *idol::BranchAndBound<NodeT>::create(const Model &t_model) const {
356
357 if (!m_relaxation_optimizer_factory) {
358 throw Exception("No node solver has been given, please call BranchAndBound::with_node_optimizer to configure.");
359 }
360
361 if (!m_branching_rule_factory) {
362 throw Exception("No branching rule has been given, please call BranchAndBound::with_branching_rule to configure.");
363 }
364
365 if (!m_node_selection_rule_factory) {
366 throw Exception("No node selection rule has been given, please call BranchAndBound::with_node_selection_rule to configure.");
367 }
368
369 std::unique_ptr<Logs::BranchAndBound::Factory<NodeT>> default_logger_factory;
370 if (!m_logger_factory) {
371 default_logger_factory = std::make_unique<Logs::BranchAndBound::Info<NodeT>>();
372 }
373
374 auto* result = new Optimizers::BranchAndBound<NodeT>(t_model,
375 *m_relaxation_optimizer_factory,
376 *m_branching_rule_factory,
377 *m_node_selection_rule_factory,
379 m_logger_factory ? *m_logger_factory : *default_logger_factory);
380
381 if (m_root_node_info) {
382 result->set_root_node_info(*m_root_node_info);
383 }
384
385 if (m_subtree_depth) {
386 result->set_subtree_depth(m_subtree_depth.value());
387 }
388
389 for (auto& presolver : m_presolvers) {
390 result->add_presolver(*presolver);
391 }
392
393 for (auto& cb : m_callbacks) {
394 result->add_callback(cb->operator()());
395 }
396
397 return result;
398}
399
400template<class NodeT>
401idol::OptimizerFactory *idol::BranchAndBound<NodeT>::clone() const {
402 return new BranchAndBound(*this);
403}
404
405namespace idol {
406 template<class NodeInfoT>
407 BranchAndBound<NodeInfoT> operator+(const BranchAndBound<NodeInfoT>& t_branch_and_bound, const OptimizerFactory& t_node_optimizer) {
408 BranchAndBound<NodeInfoT> result(t_branch_and_bound);
409 result += t_node_optimizer;
410 return result;
411 }
412}
413
414#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
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)