Skip to content

Commit

Permalink
add update rules
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Sep 19, 2024
1 parent 38aa73b commit 2d0f716
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 27 deletions.
10 changes: 6 additions & 4 deletions examples/bilevel-optimization/padm.example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <idol/optimizers/mixed-integer-optimization/wrappers/Gurobi/Gurobi.h>
#include "idol/optimizers/mixed-integer-optimization/padm/PADM.h"
#include "idol/optimizers/mixed-integer-optimization/padm/SubProblem.h"
#include "idol/optimizers/mixed-integer-optimization/padm/PenaltyUpdates.h"

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

Expand Down Expand Up @@ -41,15 +42,16 @@ int main(int t_argc, const char** t_argv) {
var.set(decomposition, var.id() == delta.id());
}

Annotation<Ctr, bool> penalize(env, "penalize");
Annotation<Ctr, bool> penalized_constraints(env, "penalized_constraints");
for (const auto& ctr : single_level.ctrs()) {
ctr.set(penalize, true);
ctr.set(penalized_constraints, true);
}

single_level.use(
PADM(decomposition)
.with_penalization(penalize)
PADM(decomposition, penalized_constraints)
.with_default_sub_problem_spec(ADM::SubProblem().with_optimizer(Gurobi()))
.with_penalty_update(PenaltyUpdates::Additive(1))
.with_rescaling(true, 1e3)
);

single_level.optimize();
Expand Down
2 changes: 2 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ add_library(idol STATIC
include/idol/optimizers/mixed-integer-optimization/padm/Formulation.h
include/idol/optimizers/mixed-integer-optimization/padm/SubProblem.cpp
include/idol/optimizers/mixed-integer-optimization/padm/SubProblem.h
include/idol/optimizers/mixed-integer-optimization/padm/PenaltyUpdates.cpp
include/idol/optimizers/mixed-integer-optimization/padm/PenaltyUpdates.h
)

find_package(OpenMP REQUIRED)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ const idol::Model &idol::ADM::Formulation::sub_problem(const idol::Var &t_var) c
}

void
idol::ADM::Formulation::update_penalty_parameters(const std::vector<Solution::Primal> &t_primals) {
idol::ADM::Formulation::update_penalty_parameters(const std::vector<Solution::Primal> &t_primals,
PenaltyUpdate& t_penalty_update) {

for (unsigned int i = 0, n_sub_problems = m_sub_problems.size() ; i < n_sub_problems ; ++i) {
auto& model = m_sub_problems[i];
Expand All @@ -301,7 +302,7 @@ idol::ADM::Formulation::update_penalty_parameters(const std::vector<Solution::Pr
}

if (t_primals[i].get(var) > 1e-4) {
model.set_var_obj(var, current_penalty + 1);
model.set_var_obj(var, t_penalty_update(current_penalty));
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define IDOL_ADM_FORMULATION_H

#include "idol/modeling/models/Model.h"
#include "PenaltyUpdates.h"

namespace idol::ADM {
class Formulation;
Expand Down Expand Up @@ -37,7 +38,7 @@ class idol::ADM::Formulation {

void fix_sub_problem(unsigned int t_sub_problem_id, const std::vector<Solution::Primal>& t_primals);

void update_penalty_parameters(const std::vector<Solution::Primal>& t_primals);
void update_penalty_parameters(const std::vector<Solution::Primal>& t_primals, PenaltyUpdate& t_penalty_update);
private:
Annotation<Var, unsigned int> m_decomposition;
std::optional<Annotation<Ctr, bool>> m_penalized_constraints;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@

#include "Optimizers_PADM.h"

#include <utility>

idol::Optimizers::PADM::PADM(const Model& t_model,
ADM::Formulation t_formulation,
std::vector<idol::ADM::SubProblem>&& t_sub_problem_specs)
std::vector<idol::ADM::SubProblem>&& t_sub_problem_specs,
std::pair<bool, double> t_rescaling,
PenaltyUpdate* t_penalty_update)
: Algorithm(t_model),
m_formulation(std::move(t_formulation)),
m_sub_problem_specs(std::move(t_sub_problem_specs)) {
m_sub_problem_specs(std::move(t_sub_problem_specs)),
m_rescaling(std::move(t_rescaling)),
m_penalty_update(t_penalty_update) {

}

Expand Down Expand Up @@ -201,7 +207,11 @@ void idol::Optimizers::PADM::run_inner_loop() {

void idol::Optimizers::PADM::update_penalty_parameters() {

m_formulation.update_penalty_parameters(m_last_solutions);
if (!m_formulation.has_penalized_constraints()) {
return;
}

m_formulation.update_penalty_parameters(m_last_solutions, *m_penalty_update);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "idol/optimizers/Algorithm.h"
#include "idol/optimizers/mixed-integer-optimization/padm/SubProblem.h"
#include "Formulation.h"
#include "PenaltyUpdates.h"

namespace idol::Optimizers {
class PADM;
Expand All @@ -17,7 +18,9 @@ class idol::Optimizers::PADM : public Algorithm {
public:
PADM(const Model& t_model,
ADM::Formulation t_formulation,
std::vector<idol::ADM::SubProblem>&& t_sub_problem_specs);
std::vector<idol::ADM::SubProblem>&& t_sub_problem_specs,
std::pair<bool, double> t_rescaling,
PenaltyUpdate* t_penalty_update);

std::string name() const override { return "PADM"; }

Expand Down Expand Up @@ -84,6 +87,8 @@ class idol::Optimizers::PADM : public Algorithm {
private:
ADM::Formulation m_formulation;
std::vector<idol::ADM::SubProblem> m_sub_problem_specs;
std::pair<bool, double> m_rescaling;
std::unique_ptr<PenaltyUpdate> m_penalty_update;
unsigned int m_max_inner_loop_iterations = 1000;

unsigned int m_outer_loop_iteration = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ idol::PADM::PADM(idol::Annotation<idol::Var, unsigned int> t_decomposition)

}

idol::PADM::PADM(idol::Annotation<idol::Var, unsigned int> t_decomposition,
idol::Annotation<idol::Ctr, bool> t_penalized_constraints)
: m_decomposition(t_decomposition),
m_penalized_constraints(t_penalized_constraints)
{

}

idol::PADM &idol::PADM::with_default_sub_problem_spec(idol::ADM::SubProblem t_sub_problem) {

if (m_default_sub_problem_spec) {
Expand All @@ -28,17 +36,27 @@ idol::Optimizer *idol::PADM::operator()(const idol::Model &t_model) const {
throw Exception("The decomposition has not been set.");
}

if (!m_penalized_constraints && (m_rescaling || m_penalty_update)) {
std::cout << "Warning: The penalized constraints have not been set. The rescaling and penalty update will be ignored." << std::endl;
}

ADM::Formulation formulation(t_model,
*m_decomposition,
m_penalized_constraints);

// create sub-problems specs
auto sub_problem_specs = create_sub_problem_specs(t_model, formulation);

auto* penalty_update = m_penalty_update ? m_penalty_update->clone() : nullptr;
if (m_penalized_constraints && !penalty_update) {
penalty_update = new PenaltyUpdates::Additive(1);
}

auto* result = new Optimizers::PADM(
t_model,
std::move(formulation),
std::move(sub_problem_specs)
std::move(sub_problem_specs),
m_rescaling ? *m_rescaling : std::make_pair(false, 0.),
penalty_update
);

handle_default_parameters(result);
Expand All @@ -50,18 +68,6 @@ idol::OptimizerFactory *idol::PADM::clone() const {
return new PADM(*this);
}

idol::PADM &
idol::PADM::with_penalization(const idol::Annotation<idol::Ctr, bool>& t_penalized_constraints) {

if (m_penalized_constraints) {
throw Exception("The penalized constraints have already been set.");
}

m_penalized_constraints = t_penalized_constraints;

return *this;
}

std::vector<idol::ADM::SubProblem>
idol::PADM::create_sub_problem_specs(const idol::Model &t_model,
const idol::ADM::Formulation &t_formulation) const {
Expand All @@ -76,3 +82,36 @@ idol::PADM::create_sub_problem_specs(const idol::Model &t_model,

return result;
}

idol::PADM &idol::PADM::with_rescaling(bool t_rescaling, double t_threshold) {

if (m_rescaling) {
throw Exception("The rescaling has already been set.");
}

m_rescaling = std::make_pair(t_rescaling, t_threshold);

return *this;
}

idol::PADM &idol::PADM::with_penalty_update(const idol::PenaltyUpdate &t_penalty_update) {

if (m_penalty_update) {
throw Exception("The penalty update has already been set.");
}

m_penalty_update.reset(t_penalty_update.clone());

return *this;
}

idol::PADM::PADM(const idol::PADM &t_src)
: OptimizerFactoryWithDefaultParameters<PADM>(t_src),
m_decomposition(t_src.m_decomposition),
m_penalized_constraints(t_src.m_penalized_constraints),
m_default_sub_problem_spec(t_src.m_default_sub_problem_spec),
m_sub_problem_specs(t_src.m_sub_problem_specs),
m_rescaling(t_src.m_rescaling),
m_penalty_update(t_src.m_penalty_update ? t_src.m_penalty_update->clone() : nullptr) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "idol/containers/Map.h"
#include "SubProblem.h"
#include "Formulation.h"
#include "PenaltyUpdates.h"
#include <optional>

namespace idol {
Expand All @@ -20,15 +21,19 @@ class idol::PADM : public OptimizerFactoryWithDefaultParameters<PADM> {
public:
explicit PADM(Annotation<Var, unsigned int> t_decomposition);

PADM(const PADM& t_src) = default;
PADM(Annotation<Var, unsigned int> t_decomposition, Annotation<Ctr, bool> t_penalized_constraints);

PADM(const PADM& t_src);
PADM(PADM&&) = default;

PADM& operator=(const PADM&) = default;
PADM& operator=(PADM&&) = default;

PADM& with_default_sub_problem_spec(ADM::SubProblem t_sub_problem);

PADM& with_penalization(const Annotation<Ctr, bool>& t_penalized_constraints);
PADM& with_rescaling(bool t_rescaling, double t_threshold);

PADM& with_penalty_update(const PenaltyUpdate& t_penalty_update);

Optimizer *operator()(const Model &t_model) const override;

Expand All @@ -39,6 +44,8 @@ class idol::PADM : public OptimizerFactoryWithDefaultParameters<PADM> {
std::optional<Annotation<Ctr, bool>> m_penalized_constraints;
std::optional<ADM::SubProblem> m_default_sub_problem_spec;
Map<unsigned int, ADM::SubProblem> m_sub_problem_specs;
std::optional<std::pair<bool, double>> m_rescaling;
std::unique_ptr<PenaltyUpdate> m_penalty_update;

std::vector<ADM::SubProblem> create_sub_problem_specs(const Model& t_model, const ADM::Formulation& t_formulation) const;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//
// Created by henri on 19.09.24.
//

#include "PenaltyUpdates.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// Created by henri on 19.09.24.
//

#ifndef IDOL_PENALTYUPDATES_H
#define IDOL_PENALTYUPDATES_H

namespace idol {
class PenaltyUpdate;

namespace PenaltyUpdates {
class Additive;
class Multiplicative;
}
}

class idol::PenaltyUpdate {
public:
virtual ~PenaltyUpdate() = default;

virtual double operator()(double t_current_penalty) = 0;

virtual PenaltyUpdate* clone() const = 0;
};

class idol::PenaltyUpdates::Additive : public PenaltyUpdate {
double m_increment;
public:
explicit Additive(double t_increment) : m_increment(t_increment) {}

double operator()(double t_current_penalty) override {
return t_current_penalty + m_increment;
}

PenaltyUpdate* clone() const override {
return new Additive(*this);
}
};

class idol::PenaltyUpdates::Multiplicative : public PenaltyUpdate {
double m_factor;
public:
explicit Multiplicative(double t_factor) : m_factor(t_factor) {}

double operator()(double t_current_penalty) override {
return t_current_penalty * m_factor;
}

PenaltyUpdate* clone() const override {
return new Multiplicative(*this);
}
};


#endif //IDOL_PENALTYUPDATES_H

0 comments on commit 2d0f716

Please sign in to comment.