Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Nov 14, 2023
2 parents 6ac5b05 + 52013a9 commit e6a040f
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 33 deletions.
2 changes: 1 addition & 1 deletion examples/knapsack.example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ using namespace idol;

int main(int t_argc, const char** t_argv) {

const auto instance = Problems::KP::read_instance("facility.data.txt");
const auto instance = Problems::KP::read_instance("knapsack.data.txt");

const auto n_items = instance.n_items();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ void idol::Optimizers::BranchAndBound<NodeVarInfoT>::solve(TreeNode& t_node) con

idol_Log(Debug, "Node " << t_node.id() << " has been solved.");

t_node.info().save(*this, parent(), *m_relaxation);
t_node.info().save(parent(), *m_relaxation);

m_branching_rule->on_node_solved(t_node);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "idol/optimizers/branch-and-bound/nodes/Node.h"
#include "idol/optimizers/Logger.h"
#include <list>

namespace idol {
namespace Optimizers {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,16 @@ class idol::NodeVarInfo {

void set_primal_solution(Solution::Primal t_primal_solution) { m_primal_solution = std::move(t_primal_solution); }

virtual void save(const Optimizers::BranchAndBound<NodeVarInfo>& t_parent, const Model& t_original_formulation, const Model& t_model);
virtual void save(const Model& t_original_formulation, const Model& t_model);

[[nodiscard]] virtual NodeVarInfo* create_child() const;

void set_local_lower_bound(const Var& t_var, double t_lb);

void set_local_upper_bound(const Var& t_var, double t_ub);

bool has_branching_decision() const { return m_branching_decision.has_value(); }

[[nodiscard]] const BranchingDecision& branching_decision() const { return m_branching_decision.value(); }

static NodeVarUpdator<NodeVarInfo>* create_updator(Model& t_relaxation);
Expand Down
31 changes: 20 additions & 11 deletions lib/include/idol/optimizers/branch-and-bound/nodes/NodeVarUpdator.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ class idol::NodeVarUpdator : public NodeUpdator<NodeVarInfoT> {
void apply_local_updates(const Node<NodeVarInfoT> &t_node) override;

void clear_local_updates() override;

protected:
Model& relaxation() { return m_relaxation; }

const Model& relaxation() const { return m_relaxation; }
};

template<class NodeT>
Expand Down Expand Up @@ -83,17 +88,21 @@ void idol::NodeVarUpdator<NodeVarInfoT>::apply_local_updates(const idol::Node<No
return;
}

const auto& branching_decision = t_node.info().branching_decision();

switch (branching_decision.type) {
case LessOrEqual:
apply_local_update(branching_decision, m_changed_upper_bounds, t_changed_upper_bounds);
break;
case GreaterOrEqual:
apply_local_update(branching_decision, m_changed_lower_bounds, t_changed_lower_bounds);
break;
default:
throw Exception("Branching on equality constraints is not implemented.");
if (t_node.info().has_branching_decision()) {

const auto &branching_decision = t_node.info().branching_decision();

switch (branching_decision.type) {
case LessOrEqual:
apply_local_update(branching_decision, m_changed_upper_bounds, t_changed_upper_bounds);
break;
case GreaterOrEqual:
apply_local_update(branching_decision, m_changed_lower_bounds, t_changed_lower_bounds);
break;
default:
throw Exception("Branching on equality constraints is not implemented.");
}

}

apply_local_updates(t_node.parent(), t_changed_lower_bounds, t_changed_upper_bounds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ namespace idol {
}

class idol::DantzigWolfeDecomposition : public OptimizerFactoryWithDefaultParameters<DantzigWolfeDecomposition> {
Annotation<Ctr, unsigned int> m_decomposition;
Annotation<Ctr, unsigned int> m_ctr_decomposition;
std::optional<Annotation<Var, unsigned int>> m_var_decomposition;
std::unique_ptr<OptimizerFactory> m_master_optimizer_factory;
std::unique_ptr<DantzigWolfe::InfeasibilityStrategyFactory> m_infeasibility_strategy;
std::unique_ptr<DantzigWolfe::DualPriceSmoothingStabilization> m_dual_price_smoothing_stabilization;
Expand All @@ -35,6 +36,9 @@ class idol::DantzigWolfeDecomposition : public OptimizerFactoryWithDefaultParame
public:
explicit DantzigWolfeDecomposition(Annotation<Ctr, unsigned int> t_decomposition);

DantzigWolfeDecomposition(Annotation<Ctr, unsigned int> t_ctr_decomposition,
Annotation<Var, unsigned int> t_var_decomposition);

DantzigWolfeDecomposition(const DantzigWolfeDecomposition& t_src);

Optimizer *operator()(const Model &t_model) const override;
Expand Down
10 changes: 9 additions & 1 deletion lib/include/idol/optimizers/dantzig-wolfe/Formulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ class idol::DantzigWolfe::Formulation {
void apply_sub_problem_bound_on_master(bool t_is_lb, const idol::Var &t_var, unsigned int t_sub_problem_id, double t_value);
LinExpr<Var> reformulate_sub_problem_variable(const Var &t_var, unsigned int t_sub_problem_id);
public:
Formulation(const Model& t_original_formulation, Annotation<Ctr, unsigned int> t_decomposition);
Formulation(const Model& t_original_formulation, const Annotation<Ctr, unsigned int>& t_decomposition);

Formulation(const Model& t_original_formulation,
Annotation<Ctr, unsigned int> t_ctr_decomposition,
Annotation<Var, unsigned int> t_var_decomposition);

Model& master() { return m_master; }
const Model& master() const { return m_master; }
Expand All @@ -62,6 +66,10 @@ class idol::DantzigWolfe::Formulation {
Model& get_model(const Ctr& t_ctr);
const Model& get_model(const Ctr& t_ctr) const;

const Annotation<Ctr, unsigned int>& decomposition_by_constraint() const { return m_decomposition_by_ctr; }

const Annotation<Var, unsigned int>& decomposition_by_variable() const { return m_decomposition_by_var; }

const GeneratorPool<Var>& column_pool(unsigned int t_sub_problem_id) const { return m_pools[t_sub_problem_id]; }

unsigned int n_sub_problems() const { return m_sub_problems.size(); }
Expand Down
3 changes: 1 addition & 2 deletions lib/src/optimizers/branch-and-bound/nodes/NodeVarInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ idol::NodeVarInfo::create_updator(idol::Model &t_relaxation) {
return new NodeVarUpdator<NodeVarInfo>(t_relaxation);
}

void idol::NodeVarInfo::save(const Optimizers::BranchAndBound<NodeVarInfo>& t_parent,
const idol::Model &t_original_formulation,
void idol::NodeVarInfo::save(const idol::Model &t_original_formulation,
const idol::Model &t_model) {

const auto status = t_model.get_status();
Expand Down
1 change: 0 additions & 1 deletion lib/src/optimizers/dantzig-wolfe/ColumnGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ void idol::Optimizers::DantzigWolfeDecomposition::ColumnGeneration::enrich_maste
if (m_current_iteration_is_using_farkas && !at_least_one_column_have_been_generated) {
m_status = Infeasible;
m_reason = Proved;
std::cout << "HERE" << std::endl;
m_is_terminated = true;
return;
}
Expand Down
32 changes: 25 additions & 7 deletions lib/src/optimizers/dantzig-wolfe/DantzigWolfeDecomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Created by henri on 31.10.23.
//
#include <memory>
#include <utility>

#include "idol/optimizers/dantzig-wolfe/DantzigWolfeDecomposition.h"
#include "idol/optimizers/dantzig-wolfe/Formulation.h"
Expand All @@ -15,11 +16,21 @@ idol::OptimizerFactory *idol::DantzigWolfeDecomposition::clone() const {
}

idol::DantzigWolfeDecomposition::DantzigWolfeDecomposition(idol::Annotation<idol::Ctr, unsigned int> t_decomposition)
: m_decomposition(std::move(t_decomposition)) {}
: m_ctr_decomposition(std::move(t_decomposition)) {}

idol::DantzigWolfeDecomposition::DantzigWolfeDecomposition(
idol::Annotation<idol::Ctr, unsigned int> t_ctr_decomposition,
idol::Annotation<idol::Var, unsigned int> t_var_decomposition)
: m_ctr_decomposition(std::move(t_ctr_decomposition)),
m_var_decomposition(std::move(t_var_decomposition))
{

}

idol::DantzigWolfeDecomposition::DantzigWolfeDecomposition(const DantzigWolfeDecomposition& t_src)
: OptimizerFactoryWithDefaultParameters<DantzigWolfeDecomposition>(t_src),
m_decomposition(t_src.m_decomposition),
m_ctr_decomposition(t_src.m_ctr_decomposition),
m_var_decomposition(t_src.m_var_decomposition),
m_master_optimizer_factory(t_src.m_master_optimizer_factory ? t_src.m_master_optimizer_factory->clone() : nullptr),
m_dual_price_smoothing_stabilization(t_src.m_dual_price_smoothing_stabilization ? t_src.m_dual_price_smoothing_stabilization->clone() : nullptr),
m_max_parallel_sub_problems(t_src.m_max_parallel_sub_problems),
Expand All @@ -37,11 +48,19 @@ idol::Optimizer *idol::DantzigWolfeDecomposition::operator()(const Model &t_mode
throw Exception("No optimizer for master has been configured.");
}

DantzigWolfe::Formulation dantzig_wolfe_formulation(t_model, m_decomposition);
std::unique_ptr<DantzigWolfe::Formulation> dantzig_wolfe_formulation;
if (m_var_decomposition.has_value()) {
dantzig_wolfe_formulation = std::make_unique<DantzigWolfe::Formulation>(t_model,
m_ctr_decomposition,
m_var_decomposition.value());
} else {
dantzig_wolfe_formulation = std::make_unique<DantzigWolfe::Formulation>(t_model,
m_ctr_decomposition);
}

auto sub_problems_specifications = create_sub_problems_specifications(dantzig_wolfe_formulation);
auto sub_problems_specifications = create_sub_problems_specifications(*dantzig_wolfe_formulation);

add_aggregation_constraints(dantzig_wolfe_formulation, sub_problems_specifications);
add_aggregation_constraints(*dantzig_wolfe_formulation, sub_problems_specifications);

std::unique_ptr<DantzigWolfe::InfeasibilityStrategyFactory> default_strategy;
if (!m_infeasibility_strategy) {
Expand All @@ -62,7 +81,7 @@ idol::Optimizer *idol::DantzigWolfeDecomposition::operator()(const Model &t_mode
const bool remove_infeasible_column = m_use_infeasible_column_removal_when_branching.has_value() ? m_use_infeasible_column_removal_when_branching.value() : use_hard_branching;

return new Optimizers::DantzigWolfeDecomposition(t_model,
std::move(dantzig_wolfe_formulation),
std::move(*dantzig_wolfe_formulation),
*m_master_optimizer_factory,
m_dual_price_smoothing_stabilization ? *m_dual_price_smoothing_stabilization : *dual_price_smoothing,
m_max_parallel_sub_problems.has_value() ? m_max_parallel_sub_problems.value() : 1,
Expand Down Expand Up @@ -236,4 +255,3 @@ idol::DantzigWolfeDecomposition &idol::DantzigWolfeDecomposition::with_infeasibl

return *this;
}

42 changes: 35 additions & 7 deletions lib/src/optimizers/dantzig-wolfe/Formulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
#include "idol/modeling/objects/Env.h"
#include "idol/modeling/expressions/operations/operators.h"

idol::DantzigWolfe::Formulation::Formulation(const Model &t_original_formulation,
Annotation<Ctr, unsigned int> t_decomposition)
: m_decomposition_by_ctr(std::move(t_decomposition)),
m_decomposition_by_var(t_original_formulation.env(), m_decomposition_by_ctr.name(), MasterId),
idol::DantzigWolfe::Formulation::Formulation(const idol::Model &t_original_formulation,
idol::Annotation<idol::Ctr, unsigned int> t_ctr_decomposition,
idol::Annotation<idol::Var, unsigned int> t_var_decomposition)
: m_decomposition_by_ctr(std::move(t_ctr_decomposition)),
m_decomposition_by_var(std::move(t_var_decomposition)),
m_master(t_original_formulation.env())
{

Expand All @@ -29,6 +30,14 @@ idol::DantzigWolfe::Formulation::Formulation(const Model &t_original_formulation

}

idol::DantzigWolfe::Formulation::Formulation(const Model &t_original_formulation,
const Annotation<Ctr, unsigned int>& t_decomposition)
: Formulation(t_original_formulation,
t_decomposition,
Annotation<Var, unsigned int>(t_original_formulation.env(), t_decomposition.name(), MasterId)) {

}

unsigned int idol::DantzigWolfe::Formulation::compute_n_sub_problems(const Model& t_original_formulation) {

std::optional<unsigned int> n_sub_problems;
Expand All @@ -52,6 +61,25 @@ unsigned int idol::DantzigWolfe::Formulation::compute_n_sub_problems(const Model

}

for (const auto& var : t_original_formulation.vars()) {

const unsigned int sub_problem_id = var.get(m_decomposition_by_var);

if (sub_problem_id == MasterId) {
continue;
}

if (!n_sub_problems.has_value()) {
n_sub_problems = sub_problem_id;
continue;
}

if (sub_problem_id >= n_sub_problems.value()) {
n_sub_problems = sub_problem_id;
}

}

return n_sub_problems.has_value() ? ++n_sub_problems.value() : 0; // ++ because indices start at 0
}

Expand Down Expand Up @@ -650,12 +678,12 @@ void idol::DantzigWolfe::Formulation::remove(const idol::Ctr &t_ctr) {

const auto sub_problem_id = t_ctr.get(m_decomposition_by_ctr);

if (sub_problem_id != MasterId) {
m_sub_problems[sub_problem_id].remove(t_ctr);
if (sub_problem_id == MasterId) {
m_master.remove(t_ctr);
return;
}

m_master.remove(t_ctr);
m_sub_problems[sub_problem_id].remove(t_ctr);
m_generation_patterns[sub_problem_id].linear().set(t_ctr, 0.);

}
Expand Down

0 comments on commit e6a040f

Please sign in to comment.