Skip to content

Commit

Permalink
add example for robust to deterministic
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Nov 28, 2024
1 parent 4683059 commit 7917bce
Show file tree
Hide file tree
Showing 15 changed files with 727 additions and 24 deletions.
88 changes: 87 additions & 1 deletion dev/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,85 @@
#include "idol/mixed-integer/modeling/models/KKT.h"
#include "idol/mixed-integer/problems/facility-location-problem/FLP_Instance.h"
#include "idol/robust/modeling/Description.h"
#include "idol/bilevel/modeling/Description.h"

using namespace idol;

Model make_deterministic(const Model& t_model, const Robust::Description& t_description) {

auto& env = t_model.env();
Model result(env);

for (const auto& var : t_model.vars()) {
const double lb = t_model.get_var_lb(var);
const double ub = t_model.get_var_ub(var);
const auto type = t_model.get_var_type(var);
result.add(var, TempVar(lb, ub, type, 0, LinExpr<Ctr>()));
}

for (const auto& ctr : t_model.ctrs()) {
const auto& row = t_model.get_ctr_row(ctr);
const auto rhs = t_model.get_ctr_rhs(ctr);
const auto type = t_model.get_ctr_type(ctr);

const auto& uncertain_mat_coeffs = t_description.uncertain_mat_coeffs(ctr);
const auto& uncertain_rhs = t_description.uncertain_rhs(ctr);

const bool has_lhs_uncertainty = !uncertain_mat_coeffs.is_zero(Tolerance::Sparsity);
const bool has_rhs_uncertainty = !uncertain_rhs.is_zero(Tolerance::Sparsity);

if (!has_lhs_uncertainty && !has_rhs_uncertainty) {
result.add(ctr, TempCtr(LinExpr(row), type, rhs));
continue;
}

if (type == Equal) {
throw Exception("Cannot make equality constraints deterministic.");
}

const auto& uncertainty_set = t_description.uncertainty_set();

QuadExpr<Var> objective = row;
for (const auto& [var, uncertain_coeff] : row) {
const auto& uncertain_mat_coeff = uncertain_mat_coeffs.get(var);
objective += uncertain_mat_coeff * var;
}
for (const auto& [var, uncertain_coeff] : uncertain_rhs) {
objective -= uncertain_coeff * var;
}

if (type == LessOrEqual) {
objective *= -1;
}

Reformulators::KKT kkt(uncertainty_set,
objective,
[&](const Var& t_var) { return uncertainty_set.has(t_var); },
[&](const Ctr& t_ctr) { return uncertainty_set.has(t_ctr); },
[&](const QCtr& t_qvar) { return uncertainty_set.has(t_qvar); }
);
kkt.set_prefix("robust_" + ctr.name() + "_");
kkt.add_dual_variables(result);
kkt.add_dual_constraints(result);

auto dual_objective = kkt.get_dual_obj_expr();
if (type == LessOrEqual) {
dual_objective *= -1;
}

assert(!dual_objective.has_quadratic());

result.add(ctr, TempCtr(
std::move(dual_objective.affine().linear()),
type,
-dual_objective.affine().constant())
);

}

return result;
}

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

Env env;
Expand All @@ -44,7 +120,7 @@ int main(int t_argc, const char** t_argv) {
auto y = Var::make_vector(env, Dim<2>(n_facilities, n_customers), 0., 1., Continuous, 0., "y");

Model uncertainty_set(env);
const auto xi = uncertainty_set.add_vars(Dim<1>(n_facilities), 0., 1., Binary, 0., "xi");
const auto xi = uncertainty_set.add_vars(Dim<1>(n_facilities), 0., 1., Continuous, 0., "xi");
uncertainty_set.add_ctr(idol_Sum(i, Range(n_facilities), xi[i]) <= Gamma);

Model model(env);
Expand Down Expand Up @@ -77,5 +153,15 @@ int main(int t_argc, const char** t_argv) {

std::cout << Robust::Description::View(model, description) << std::endl;

auto deterministic = make_deterministic(model, description);

deterministic.use(Gurobi());

deterministic.optimize();

std::cout << deterministic.get_status() << std::endl;
std::cout << deterministic.optimizer().time().count() << std::endl;
std::cout << save_primal(deterministic) << std::endl;

return 0;
}
4 changes: 3 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ function(ADD_EXAMPLE NAME)
target_link_libraries(example_${NAME} PRIVATE idol)
file(GLOB DATA_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${NAME}.data.*")
foreach(FILE ${DATA_FILES})
message(STATUS "Copying ${FILE}")
add_custom_command(TARGET example_${NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${FILE} $<TARGET_FILE_DIR:example_${NAME}>)
endforeach()
endfunction()

add_subdirectory(mixed-integer)
add_subdirectory(bilevel)
add_subdirectory(bilevel)
add_subdirectory(robust)
1 change: 1 addition & 0 deletions examples/robust/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_example(robust-facility-location)
41 changes: 41 additions & 0 deletions examples/robust/robust-facility-location.data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
10 20
109.6 131.484
169.498 103.513
24.7946 41.8319
150.331 156.535
140.651 128.462
68.8231 66.0825
5.40097 33.6793
123.19 113.974
118.503 152.262
27.5682 125.587
36.1992
5.60365
10.0339
20.1965
17.4686
35.8237
14.8866
2.75196
36.7471
2.76135
12.0892
16.2641
11.3815
8.96618
32.1548
13.7501
0.631599
26.9407
36.4762
10.0098
0.674345 0.377274 0.60077 0.725902 0.347025 0.648906 0.635155 0.607522 0.333549 0.300607 0.416598 0.628605 0.753687 0.644812 0.405533 0.152511 0.424802 0.261078 0.50283 0.403443
0.79483 0.0798539 0.347963 0.756363 0.654002 0.484362 0.663717 0.820894 0.220568 0.548021 0.218845 0.779403 0.804299 0.507375 0.592223 0.172742 0.63654 0.0894973 0.819295 0.712606
0.988408 0.473435 0.741449 1.02582 0.420089 0.859221 0.932609 0.913111 0.206479 0.606641 0.592807 0.943148 1.05883 0.871605 0.719628 0.296455 0.735305 0.405338 0.70923 0.472351
0.801213 0.930165 1.12413 0.970236 0.281743 1.11036 0.911725 0.579372 0.840547 0.467774 0.937797 0.721997 0.961574 1.08599 0.57822 0.70739 0.533045 0.812734 0.148052 0.238144
0.033511 0.742563 0.729705 0.21527 0.807152 0.579068 0.209073 0.232984 0.91811 0.384516 0.620859 0.0675881 0.187979 0.528276 0.248045 0.699975 0.263439 0.677736 0.632054 0.831136
0.379508 0.394834 0.402656 0.338167 0.703938 0.315728 0.243857 0.475284 0.607753 0.336413 0.270847 0.38184 0.381389 0.285442 0.271919 0.405371 0.331478 0.346229 0.681973 0.748633
1.01954 0.586318 0.852622 1.08059 0.340762 0.955962 0.989606 0.914744 0.331927 0.616543 0.693984 0.966318 1.10785 0.963435 0.742256 0.385068 0.74801 0.505968 0.654321 0.385256
0.124851 0.647767 0.637432 0.198938 0.766693 0.495492 0.15157 0.278676 0.831333 0.339767 0.525301 0.137635 0.200255 0.446836 0.203461 0.614955 0.238989 0.585824 0.629149 0.796432
0.822042 0.611747 0.850139 0.920143 0.113758 0.898665 0.836445 0.683577 0.462689 0.406345 0.66767 0.759121 0.93636 0.891583 0.542633 0.376275 0.534339 0.501362 0.400407 0.172095
0.728693 0.27883 0.523355 0.749647 0.439242 0.602651 0.655937 0.692852 0.235195 0.391798 0.348472 0.692708 0.785082 0.607712 0.47688 0.0436219 0.506139 0.16976 0.61561 0.497567
99 changes: 99 additions & 0 deletions examples/robust/robust-facility-location.example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// Created by henri on 28.11.24.
//
//
// Created by henri on 06/04/23.
//
#include <iostream>
#include "idol/modeling.h"
#include "idol/mixed-integer/problems/facility-location-problem/FLP_Instance.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/BranchAndBound.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/branching-rules/factories/PseudoCost.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/node-selection-rules/factories/BestEstimate.h"
#include "idol/mixed-integer/optimizers/wrappers/HiGHS/HiGHS.h"
#include "idol/mixed-integer/optimizers/wrappers/GLPK/GLPK.h"
#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/node-selection-rules/factories/BestBound.h"
#include "idol/mixed-integer/optimizers/branch-and-bound/branching-rules/factories/MostInfeasible.h"
#include "idol/mixed-integer/optimizers/callbacks/ReducedCostFixing.h"
#include "idol/robust/modeling/Description.h"
#include "idol/robust/optimizers/deterministic/Deterministic.h"

using namespace idol;

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

Env env;

// Read instance
const auto instance = Problems::FLP::read_instance_1991_Cornuejols_et_al("robust-facility-location.data.txt");
const unsigned int n_customers = instance.n_customers();
const unsigned int n_facilities = instance.n_facilities();

// Uncertainty set
Model uncertainty_set(env);
const double Gamma = 1;
const auto xi = uncertainty_set.add_vars(Dim<1>(n_customers), 0., 1., Continuous, 0., "xi");
uncertainty_set.add_ctr(idol_Sum(i, Range(n_customers), xi[i]) <= Gamma);

// Make model
Model model(env);
Robust::Description description(uncertainty_set);

auto x = model.add_vars(Dim<1>(n_facilities), 0., 1., Binary, 0., "x");
auto y = model.add_vars(Dim<2>(n_facilities, n_customers), 0., 1., Continuous, 0., "y");

for (unsigned int i = 0 ; i < n_facilities ; ++i) {

const auto c = model.add_ctr(idol_Sum(j, Range(n_customers), instance.demand(j) * y[i][j]) <= instance.capacity(i));

for (unsigned int j = 0 ; j < n_customers ; ++j) {
description.set_uncertain_mat_coeff(c, y[i][j], 0.2 * instance.demand(j) * xi[j]);
}

}

for (unsigned int j = 0 ; j < n_customers ; ++j) {
model.add_ctr(idol_Sum(i, Range(n_facilities), y[i][j]) == 1);
}

for (unsigned int i = 0 ; i < n_facilities ; ++i) {
for (unsigned int j = 0 ; j < n_customers ; ++j) {
model.add_ctr(y[i][j] <= x[i]);
}
}

model.set_obj_expr(idol_Sum(i, Range(n_facilities),
instance.fixed_cost(i) * x[i]
+ idol_Sum(j, Range(n_customers),
instance.per_unit_transportation_cost(i, j) *
instance.demand(j) *
y[i][j]
)
)
);

for (unsigned int i = 0 ; i < n_facilities ; ++i) {
for (unsigned int j = 0; j < n_customers; ++j) {
description.set_uncertain_obj(y[i][j], 0.2 * instance.per_unit_transportation_cost(i, j) * instance.demand(j) * xi[j]);
}
}

/*
* const auto deterministic_model = Robust::Deterministic::make_model(model, description);
* std::cout << Robust::Description::View(model, description) << std::endl;
*/

model.use(Gurobi());
model.optimize();
std::cout << "Deterministic Problem has value: " << model.get_best_obj() << std::endl;

model.use(
Robust::Deterministic(description)
.with_deterministic_optimizer(Gurobi().with_logs(false))
);
model.optimize();
std::cout << "Robust Problem has value: " << model.get_best_obj() << std::endl;

return 0;
}
4 changes: 4 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,10 @@ add_library(idol STATIC
include/idol/mixed-integer/optimizers/callbacks/ReducedCostFixing.h
include/idol/robust/modeling/Description.h
src/robust/modeling/Description.cpp
include/idol/robust/optimizers/deterministic/Deterministic.h
src/robust/optimizers/deterministic/Deterministic.cpp
include/idol/robust/optimizers/deterministic/Optimizers_Deterministic.h
src/robust/optimizers/deterministic/Optimizers_Deterministic.cpp
)

find_package(OpenMP REQUIRED)
Expand Down
6 changes: 3 additions & 3 deletions lib/include/idol/bilevel/modeling/Description.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Created by henri on 20.06.24.
//

#ifndef IDOL_DESCRIPTION_H
#define IDOL_DESCRIPTION_H
#ifndef IDOL_BILEVEL_DESCRIPTION_H
#define IDOL_BILEVEL_DESCRIPTION_H

#include <utility>

Expand Down Expand Up @@ -62,4 +62,4 @@ class idol::Bilevel::Description {
[[nodiscard]] bool is_follower(const QCtr& t_ctr) const { return t_ctr.get(m_lower_level) != MasterId; }
};

#endif //IDOL_DESCRIPTION_H
#endif //IDOL_BILEVEL_DESCRIPTION_H
4 changes: 3 additions & 1 deletion lib/include/idol/mixed-integer/modeling/models/KKT.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace idol {
class idol::Reformulators::KKT {
const Model& m_primal;
const QuadExpr<Var, double>& m_primal_objective;
std::string m_prefix;

std::function<bool(const Var&)> m_primal_variable_indicator;
std::function<bool(const Ctr&)> m_primal_constraint_indicator;
Expand Down Expand Up @@ -57,8 +58,9 @@ class idol::Reformulators::KKT {

KKT(const Model& t_high_point_relaxation, const Bilevel::Description& t_bilevel_description);

void set_prefix(std::string t_prefix) { m_prefix = std::move(t_prefix); }

const QuadExpr<Var, double>& get_dual_obj_expr() const { return m_dual_objective; }
[[nodiscard]] const QuadExpr<Var, double>& get_dual_obj_expr() const { return m_dual_objective; }

/**
* Adds the coupling variables and constraints to the destination model.
Expand Down
14 changes: 9 additions & 5 deletions lib/include/idol/robust/modeling/Description.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ namespace idol::Robust {
class idol::Robust::Description {
mutable std::optional<Annotation<unsigned int>> m_stages;
Map<Ctr, LinExpr<Var, LinExpr<Var>>> m_uncertain_mat_coeff;
Map<Ctr, LinExpr<Var>> m_uncertain_rhs;
Map<Var, LinExpr<Var>> m_uncertain_obj;
LinExpr<Ctr, LinExpr<Var>> m_uncertain_rhs;
LinExpr<Var, LinExpr<Var>> m_uncertain_obj;
const Model& m_uncertainty_set;
public:
explicit Description(const Model& t_uncertainty_set) : m_uncertainty_set(t_uncertainty_set) {}
Expand All @@ -35,7 +35,11 @@ class idol::Robust::Description {

const Model& uncertainty_set() const { return m_uncertainty_set; }

auto uncertain_coefficients() const { return ConstIteratorForward(m_uncertain_mat_coeff); }
auto uncertain_mat_coeffs() const { return ConstIteratorForward(m_uncertain_mat_coeff); }

auto uncertain_rhs() const { return m_uncertain_rhs; }

auto uncertain_obj() const { return m_uncertain_obj; }

const LinExpr<Var>& uncertain_mat_coeff(const Ctr& t_ctr, const Var& t_var) const;

Expand All @@ -50,11 +54,11 @@ class idol::Robust::Description {
}

void set_uncertain_rhs(const Ctr& t_ctr, const LinExpr<Var>& t_rhs) {
m_uncertain_rhs[t_ctr] = t_rhs;
m_uncertain_rhs.set(t_ctr, t_rhs);
}

void set_uncertain_obj(const Var& t_var, const LinExpr<Var>& t_obj) {
m_uncertain_obj[t_var] = t_obj;
m_uncertain_obj.set(t_var, t_obj);
}

class View {
Expand Down
33 changes: 33 additions & 0 deletions lib/include/idol/robust/optimizers/deterministic/Deterministic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Created by henri on 28.11.24.
//

#ifndef IDOL_DETERMINISTIC_H
#define IDOL_DETERMINISTIC_H

#include "idol/general/optimizers/OptimizerFactory.h"
#include "idol/robust/modeling/Description.h"
#include "idol/mixed-integer/modeling/models/Model.h"

namespace idol::Robust {
class Deterministic;
}

class idol::Robust::Deterministic : public OptimizerFactoryWithDefaultParameters<Deterministic> {
const Robust::Description& m_description;
std::unique_ptr<OptimizerFactory> m_deterministic_optimizer;
public:
explicit Deterministic(const Robust::Description& t_description);

Deterministic(const Deterministic& t_src);

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

[[nodiscard]] OptimizerFactory *clone() const override;

Deterministic& with_deterministic_optimizer(const OptimizerFactory& t_deterministic_optimizer);

static Model make_model(const Model& t_model, const Robust::Description& t_description);
};

#endif //IDOL_DETERMINISTIC_H
Loading

0 comments on commit 7917bce

Please sign in to comment.