5#ifndef IDOL_INTEGERMASTER_H
6#define IDOL_INTEGERMASTER_H
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"
13namespace idol::Heuristics {
17template<
class NodeInfoT =
idol::DefaultNodeInfo>
19 std::unique_ptr<OptimizerFactory> m_optimizer_factory;
21 std::optional<bool> m_integer_columns;
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;
28 IntegerMaster(
const IntegerMaster& t_src);
30 IntegerMaster() =
default;
32 IntegerMaster(IntegerMaster&&)
noexcept =
default;
34 IntegerMaster& operator=(
const IntegerMaster&) =
delete;
35 IntegerMaster& operator=(IntegerMaster&&)
noexcept =
default;
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 = 1;
44 unsigned int m_n_relevant_calls = 0;
46 void operator()(CallbackEvent t_event)
override;
50 [[nodiscard]]
bool with_integer_columns()
const {
return m_integer_columns; }
52 void set_integer_columns(
bool t_value) { m_integer_columns = t_value; }
54 void set_time_limit(
double t_time_limit) { m_time_limit = std::max(0., t_time_limit); }
56 void set_iteration_limit(
unsigned int t_iteration_limit) { m_iteration_limit = t_iteration_limit; }
58 void set_max_depth(
unsigned int t_max_depth) { m_max_depth = t_max_depth; }
60 void set_frequency(
unsigned int t_frequency) { m_frequency = t_frequency; }
69 IntegerMaster& with_integer_columns(
bool t_value);
71 IntegerMaster& with_time_limit(
double t_time_limit);
73 IntegerMaster& with_iteration_limit(
unsigned int t_iteration_limit);
75 IntegerMaster& with_max_depth(
unsigned int t_max_depth);
77 IntegerMaster& with_frequency(
unsigned int t_frequency);
80template<
class NodeInfoT>
81idol::Heuristics::IntegerMaster<NodeInfoT>::IntegerMaster(
const IntegerMaster& t_src)
82 : m_optimizer_factory(t_src.m_optimizer_factory ? t_src.m_optimizer_factory->clone() : nullptr),
83 m_integer_columns(t_src.m_integer_columns),
84 m_time_limit(t_src.m_time_limit),
85 m_iteration_limit(t_src.m_time_limit),
86 m_max_depth(t_src.m_max_depth),
87 m_frequency(t_src.m_frequency)
90template<
class NodeInfoT>
93 if (!m_optimizer_factory) {
94 throw Exception(
"No solver was given to solve the integer master problem, please call IntegerMaster.rst::with_osi_interface to configure.");
97 auto* result =
new Strategy(*m_optimizer_factory);
99 if (m_integer_columns.has_value()) {
100 result->set_integer_columns(m_integer_columns.value());
103 if (m_time_limit.has_value()) {
104 result->set_time_limit(m_time_limit.value());
107 if (m_iteration_limit.has_value()) {
108 result->set_iteration_limit(m_iteration_limit.value());
111 if (m_max_depth.has_value()){
112 result->set_max_depth(m_max_depth.value());
115 if (m_frequency.has_value()) {
116 result->set_frequency(m_frequency.value());
122template<
class NodeInfoT>
123idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_optimizer(
const OptimizerFactory &t_optimizer) {
125 if (m_optimizer_factory) {
126 throw Exception(
"A solver has already been given.");
129 m_optimizer_factory.reset(t_optimizer.clone());
134template<
class NodeInfoT>
135idol::BranchAndBoundCallbackFactory<NodeInfoT> *idol::Heuristics::IntegerMaster<NodeInfoT>::clone()
const {
136 return new IntegerMaster(*
this);
139template<
class NodeInfoT>
140idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_integer_columns(
bool t_value) {
141 m_integer_columns = t_value;
145template<
class NodeInfoT>
146idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_time_limit(
double t_time_limit) {
147 m_time_limit = t_time_limit;
151template<
class NodeInfoT>
152idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_iteration_limit(
unsigned int t_iteration_limit) {
153 m_iteration_limit = t_iteration_limit;
157template<
class NodeInfoT>
158idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_max_depth(
unsigned int t_max_depth) {
159 m_max_depth = t_max_depth;
163template<
class NodeInfoT>
164idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_frequency(
unsigned int t_frequency) {
165 m_frequency = t_frequency;
169template<
class NodeInfoT>
170idol::Heuristics::IntegerMaster<NodeInfoT>::Strategy::Strategy(
const OptimizerFactory &t_optimizer)
171 : m_optimizer_factory(t_optimizer.clone()) {
175template<
class NodeInfoT>
178 if (t_event != InvalidSolution) {
182 if (m_max_depth < this->
node().level()) {
186 unsigned int n_relevant_calls = m_n_relevant_calls++;
188 if ( n_relevant_calls % m_frequency != 0) {
193 const auto& dantzig_wolfe_optimizer =
relaxation.optimizer().template as<Optimizers::DantzigWolfeDecomposition>();
195 const auto& formulation = dantzig_wolfe_optimizer.formulation();
196 const unsigned int n_sub_problems = formulation.n_sub_problems();
198 std::unique_ptr<Model> integer_master_new(
relaxation.clone());
202 for (
unsigned int k = 0 ; k < n_sub_problems ; ++k) {
203 for (
const auto& [var, col] : formulation.present_generators(k)) {
204 dw.formulation().generate_column(k, col);
209 if (m_integer_columns) {
210 for (
unsigned int i = 0 ; i < n_sub_problems ; ++i) {
211 for (
const auto &[alpha, generator]: dw.formulation().present_generators(i)) {
212 dw.formulation().master().set_var_type(alpha, Binary);
218 dw.set_master_optimizer_factory(*m_optimizer_factory);
221 dw.set_param_logs(
false);
222 dw.set_param_iteration_limit(0);
223 dw.set_param_time_limit(std::min(m_time_limit,
relaxation.optimizer().get_remaining_time()));
226 auto& branch_and_bound = this->
original_model().optimizer().template as<Optimizers::BranchAndBound<NodeInfoT>>();;
227 dw.set_param_best_bound_stop(branch_and_bound.get_best_obj());
229 integer_master_new->optimize();
231 const int status = integer_master_new->get_status();
233 if (status != Optimal && status != Feasible) {
237 auto* info =
new NodeInfoT();
void submit_heuristic_solution(NodeInfoT *t_info)
const Model & relaxation() const
const Node< NodeInfoT > & node() const
const Model & original_model() const
void operator()(CallbackEvent t_event) override