Skip to content

Commit

Permalink
add scenario
Browse files Browse the repository at this point in the history
  • Loading branch information
hlefebvr committed Dec 11, 2024
1 parent 129599d commit 7bc0073
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 11 deletions.
5 changes: 3 additions & 2 deletions dev/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ int main(int t_argc, const char** t_argv) {

// Uncertainty set
Model uncertainty_set(env);
const double Gamma = 0;
const double Gamma = 2;
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);

Expand All @@ -56,7 +56,7 @@ int main(int t_argc, const char** t_argv) {
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_rhs(c, -xi[j]);
description.set_uncertain_rhs(c, -instance.capacity(i) * xi[j]);
}

}
Expand All @@ -68,6 +68,7 @@ int main(int t_argc, const char** t_argv) {
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]);
description.set_stage(y[i][j], 1);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,25 @@ namespace idol::CCG {
class idol::CCG::Formulation {
const Model& m_parent;
const ::idol::Robust::Description &m_description;

Model m_master;
std::vector<Var> m_second_stage_variables;
std::vector<Ctr> m_second_stage_constraints;

unsigned int m_n_added_scenario = 0;
std::optional<Var> m_second_stage_epigraph;

void parse_variables();
void parse_objective();
void parse_constraints();
public:
Formulation(const Model& t_parent, const ::idol::Robust::Description &t_description);

Model& master() { return m_master; }

const Model& master() const { return m_master; }

void add_scenario_to_master(const Point<Var>& t_scenario);
};

#endif //IDOL_CCG_FORMULATION_H
4 changes: 2 additions & 2 deletions lib/src/bilevel/modeling/read_from_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void AuxParser::read_aux_file(const std::string &t_path_to_aux, const std::funct
if (read_tag(file, "@MPS", false) || read_tag(file, "@LP", false)) {
read_file(file, t_path_to_aux, t_read_model_from_file);
} else {
throw Exception("Parsing error: could not parse LP or MPS tags.");
throw Exception("Parsing error: could not parse_variables LP or MPS tags.");
}

file.close();
Expand Down Expand Up @@ -190,7 +190,7 @@ bool AuxParser::read_tag(std::ifstream &t_file, const std::string &t_tag, bool t
return false;
}

throw Exception("Parsing error, could not parse tag: " + t_tag);
throw Exception("Parsing error, could not parse_variables tag: " + t_tag);

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ idol::Model idol::Optimizers::GLPK::read_from_lp_file(idol::Env &t_env, const st
glp_prob* model = glp_create_prob();
auto result = glp_read_lp(model, NULL, t_filename.c_str());
if (result != 0) {
throw Exception("Could not parse MPS file.");
throw Exception("Could not parse_variables MPS file.");
}
return read_from_glpk(t_env, model);

Expand All @@ -779,7 +779,7 @@ idol::Model idol::Optimizers::GLPK::read_from_mps_file(idol::Env &t_env, const s
glp_prob *model = glp_create_prob();
auto result = glp_read_mps(model, use_fixed_format ? GLP_MPS_DECK : GLP_MPS_FILE, NULL, t_filename.c_str());
if (result != 0) {
throw Exception("Could not parse MPS file.");
throw Exception("Could not parse_variables MPS file.");
}
return read_from_glpk(t_env, model);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ idol::Problems::FLP::Instance idol::Problems::FLP::read_instance_2021_Cheng_et_a
auto data = parse_delimited(t_filename, '\t');

if (data[0][0] != "FacNum") {
throw Exception("Could not parse instance, missing header FacNum.");
throw Exception("Could not parse_variables instance, missing header FacNum.");
}

if (data[0][2] != "CustNum") {
throw Exception("Could not parse instance, missing header CustNum.");
throw Exception("Could not parse_variables instance, missing header CustNum.");
}

unsigned int n_facilities = std::stoul(data[0][1]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,147 @@
// Created by henri on 11.12.24.
//
#include <idol/robust/optimizers/column-and-constraint-generation/Formulation.h>
#include <idol/mixed-integer/modeling/variables/TempVar.h>
#include <idol/mixed-integer/modeling/expressions/operations/operators.h>

idol::CCG::Formulation::Formulation(const Model &t_parent, const ::idol::Robust::Description &t_description)
: m_parent(t_parent), m_description(t_description), m_master(t_parent.env()) {

idol::CCG::Formulation::Formulation(const idol::Model &t_parent, const ::idol::Robust::Description &t_description)
: m_parent(t_parent), m_description(t_description) {
parse_variables();
parse_objective();
parse_constraints();

}

void idol::CCG::Formulation::parse_variables() {

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

if (m_description.stage(var) > 0) {
m_second_stage_variables.emplace_back(var);
continue;
}

const double lb = m_parent.get_var_lb(var);
const double ub = m_parent.get_var_ub(var);
const auto type = m_parent.get_var_type(var);
const double obj = m_parent.get_var_obj(var);

m_master.add(var, TempVar(lb, ub, type, obj, LinExpr<Ctr>()));

}

}

void idol::CCG::Formulation::parse_objective() {

const auto& objective = m_parent.get_obj_expr();

if (!objective.has_quadratic()) {
return; // Because the objective has been added while parsing the variables
}

auto master_objective = m_master.get_obj_expr();

for (const auto& [pair, coeff] : objective) {

if (m_description.stage(pair.first) > 0) {
continue;
}

if (m_description.stage(pair.second) > 0) {
continue;
}

master_objective += coeff * pair.first * pair.second;

}

}

void idol::CCG::Formulation::parse_constraints() {

for (const auto& ctr : m_parent.ctrs()) {

const auto& row = m_parent.get_ctr_row(ctr);

const bool has_second_stage = std::any_of(row.begin(), row.end(), [this](const auto& term) {
return m_description.stage(term.first) > 0;
});

if (has_second_stage || !m_description.uncertain_mat_coeffs(ctr).empty()) {
m_second_stage_constraints.emplace_back(ctr);
continue;
}

const auto type = m_parent.get_ctr_type(ctr);
const double rhs = m_parent.get_ctr_rhs(ctr);

m_master.add(ctr, TempCtr(LinExpr(row), type, rhs));
}

}

void idol::CCG::Formulation::add_scenario_to_master(const idol::Point<idol::Var> &t_scenario) {

std::vector<std::optional<Var>> new_vars;
new_vars.resize(m_parent.vars().size());

// Add Variables
for (const auto& var : m_second_stage_variables) {

const double lb = m_parent.get_var_lb(var);
const double ub = m_parent.get_var_ub(var);
const auto type = m_parent.get_var_type(var);
const auto index = m_parent.get_var_index(var);

new_vars[index] = m_master.add_var(lb, ub, type, 0, var.name() + "_" + std::to_string(m_n_added_scenario));

}

// Add Constraints
for (const auto& ctr : m_second_stage_constraints) {

const auto& row = m_parent.get_ctr_row(ctr);
const auto type = m_parent.get_ctr_type(ctr);
double rhs = m_parent.get_ctr_rhs(ctr);

LinExpr<Var> new_row;
for (const auto& [var, coeff] : row) {

if (m_description.stage(var) == 0) {
new_row += coeff * var;
continue;
}

new_row += coeff * new_vars[m_parent.get_var_index(var)].value();
}

const auto uncertainties = m_description.uncertain_mat_coeffs(ctr);
for (const auto& [var, coeff] : uncertainties) {
new_row += evaluate(coeff, t_scenario) * new_vars[m_parent.get_var_index(var)].value();
}

rhs += evaluate(m_description.uncertain_rhs(ctr), t_scenario);

m_master.add_ctr(TempCtr(std::move(new_row), type, rhs), ctr.name() + "_" + std::to_string(m_n_added_scenario));

}

if (!m_second_stage_epigraph) {
m_second_stage_epigraph = m_master.add_var(-Inf, Inf, Continuous, 1, "second_stage_epigraph");
}

// Add Objective
LinExpr<Var> objective;
for (const auto& var : m_second_stage_variables) {
objective += m_parent.get_var_obj(var) * new_vars[m_parent.get_var_index(var)].value();
}
for (const auto& [var, coeff] : m_description.uncertain_obj()) {
objective += evaluate(coeff, t_scenario) * new_vars[m_parent.get_var_index(var)].value();
}

m_master.add_ctr(*m_second_stage_epigraph >= std::move(objective));

++m_n_added_scenario;
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void idol::Optimizers::Robust::ColumnAndConstraintGeneration::remove(const idol:
}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::update() {
throw Exception("Not implemented update");

}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::write(const std::string &t_name) {
Expand All @@ -78,6 +78,10 @@ void idol::Optimizers::Robust::ColumnAndConstraintGeneration::write(const std::s

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::hook_before_optimize() {
Optimizer::hook_before_optimize();

m_formulation = std::make_unique<CCG::Formulation>(parent(), m_description);
m_formulation->master().use(*m_master_optimizer);

}

void idol::Optimizers::Robust::ColumnAndConstraintGeneration::hook_optimize() {
Expand Down

0 comments on commit 7bc0073

Please sign in to comment.