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 = 20;
45 void operator()(CallbackEvent t_event)
override;
49 [[nodiscard]]
bool with_integer_columns()
const {
return m_integer_columns; }
51 void set_integer_columns(
bool t_value) { m_integer_columns = t_value; }
53 void set_time_limit(
double t_time_limit) { m_time_limit = std::max(0., t_time_limit); }
55 void set_iteration_limit(
unsigned int t_iteration_limit) { m_iteration_limit = t_iteration_limit; }
57 void set_max_depth(
unsigned int t_max_depth) { m_max_depth = t_max_depth; }
59 void set_frequency(
unsigned int t_frequency) { m_frequency = t_frequency; }
68 IntegerMaster& with_integer_columns(
bool t_value);
70 IntegerMaster& with_time_limit(
double t_time_limit);
72 IntegerMaster& with_iteration_limit(
unsigned int t_iteration_limit);
74 IntegerMaster& with_max_depth(
unsigned int t_max_depth);
76 IntegerMaster& with_frequency(
unsigned int t_frequency);
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)
89template<
class NodeInfoT>
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.");
96 auto* result =
new Strategy(*m_optimizer_factory);
98 if (m_integer_columns.has_value()) {
99 result->set_integer_columns(m_integer_columns.value());
102 if (m_time_limit.has_value()) {
103 result->set_time_limit(m_time_limit.value());
106 if (m_iteration_limit.has_value()) {
107 result->set_iteration_limit(m_iteration_limit.value());
110 if (m_max_depth.has_value()){
111 result->set_max_depth(m_max_depth.value());
114 if (m_frequency.has_value()) {
115 result->set_frequency(m_frequency.value());
121template<
class NodeInfoT>
122idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_optimizer(
const OptimizerFactory &t_optimizer) {
124 if (m_optimizer_factory) {
125 throw Exception(
"A solver has already been given.");
128 m_optimizer_factory.reset(t_optimizer.clone());
133template<
class NodeInfoT>
134idol::BranchAndBoundCallbackFactory<NodeInfoT> *idol::Heuristics::IntegerMaster<NodeInfoT>::clone()
const {
135 return new IntegerMaster(*
this);
138template<
class NodeInfoT>
139idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_integer_columns(
bool t_value) {
140 m_integer_columns = t_value;
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;
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;
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;
162template<
class NodeInfoT>
163idol::Heuristics::IntegerMaster<NodeInfoT> &idol::Heuristics::IntegerMaster<NodeInfoT>::with_frequency(
unsigned int t_frequency) {
164 m_frequency = t_frequency;
168template<
class NodeInfoT>
169idol::Heuristics::IntegerMaster<NodeInfoT>::Strategy::Strategy(
const OptimizerFactory &t_optimizer)
170 : m_optimizer_factory(t_optimizer.clone()) {
174template<
class NodeInfoT>
177 if (t_event != InvalidSolution) {
181 if (m_max_depth < this->
node().level()) {
185 if ( this->node_count() % m_frequency != 0) {
190 const auto& dantzig_wolfe_optimizer =
relaxation.optimizer().template as<Optimizers::DantzigWolfeDecomposition>();
192 const auto& formulation = dantzig_wolfe_optimizer.formulation();
193 const unsigned int n_sub_problems = formulation.n_sub_problems();
195 std::unique_ptr<Model> integer_master_new(
relaxation.clone());
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);
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);
215 dw.set_master_optimizer_factory(*m_optimizer_factory);
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()));
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());
226 integer_master_new->optimize();
228 const int status = integer_master_new->get_status();
230 if (status != Optimal && status != Feasible) {
234 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