diff --git a/dev/main.cpp b/dev/main.cpp index 197d1619..91a4b9a5 100644 --- a/dev/main.cpp +++ b/dev/main.cpp @@ -23,145 +23,72 @@ #include "idol/mixed-integer/problems/facility-location-problem/FLP_Instance.h" #include "idol/robust/modeling/Description.h" #include "idol/bilevel/modeling/Description.h" +#include "idol/robust/optimizers/deterministic/Deterministic.h" +#include "idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.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())); - } - - 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 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; - const double Gamma = 3; - - // Generate parameters - const auto filename = "/home/henri/Research/idol/tests/data/facility-location-problem/instance_F10_C20__0.txt"; - // Read instance - const auto instance = idol::Problems::FLP::read_instance_1991_Cornuejols_et_al(filename); + const auto instance = Problems::FLP::read_instance_1991_Cornuejols_et_al("/home/henri/Research/idol/examples/robust/robust-facility-location.data.txt"); const unsigned int n_customers = instance.n_customers(); const unsigned int n_facilities = instance.n_facilities(); - // Make model - auto x = Var::make_vector(env, Dim<1>(n_facilities), 0., 1., Continuous, 0., "x"); - auto y = Var::make_vector(env, Dim<2>(n_facilities, n_customers), 0., 1., Continuous, 0., "y"); - + // Uncertainty set Model uncertainty_set(env); - 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); + const double Gamma = 0; + 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); - model.add_vector(x); - model.add_vector(y); + 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) { - model.add(Ctr(env, idol_Sum(j, Range(n_customers), instance.demand(j) * y[i][j]) <= instance.capacity(i) * x[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_rhs(c, -xi[j]); + } + } for (unsigned int j = 0 ; j < n_customers ; ++j) { - model.add(Ctr(env, idol_Sum(i, Range(n_facilities), y[i][j]) == 1)); + model.add_ctr(idol_Sum(i, Range(n_facilities), y[i][j]) >= 1); } - Robust::Description description(uncertainty_set); for (unsigned int i = 0 ; i < n_facilities ; ++i) { for (unsigned int j = 0 ; j < n_customers ; ++j) { - description.make_stage_var(y[i][j], 1); - auto activation = model.add_ctr(y[i][j] <= 1); - description.set_uncertain_rhs(activation, -xi[i]); + 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]))); - - std::cout << Robust::Description::View(model, description) << std::endl; + 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] + ) + ) + ); - auto deterministic = make_deterministic(model, description); + model.use(Gurobi()); + model.optimize(); - deterministic.use(Gurobi()); + std::cout << "Deterministic Problem has value: " << model.get_best_obj() << std::endl; - deterministic.optimize(); + model.use(Robust::AffineDecisionRule(description).with_deterministic_optimizer(Gurobi())); + model.optimize(); - std::cout << deterministic.get_status() << std::endl; - std::cout << deterministic.optimizer().time().count() << std::endl; - std::cout << save_primal(deterministic) << std::endl; + std::cout << "ADR Problem has value: " << model.get_best_obj() << std::endl; return 0; } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index cf57457d..830b2d52 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -233,6 +233,10 @@ add_library(idol STATIC src/robust/optimizers/deterministic/Deterministic.cpp include/idol/robust/optimizers/deterministic/Optimizers_Deterministic.h src/robust/optimizers/deterministic/Optimizers_Deterministic.cpp + include/idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.h + include/idol/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.h + src/robust/optimizers/affine-decision-rule/AffineDecisionRule.cpp + src/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.cpp ) find_package(OpenMP REQUIRED) diff --git a/lib/include/idol/general/optimizers/OptimizerWithLazyUpdates.h b/lib/include/idol/general/optimizers/OptimizerWithLazyUpdates.h index b04d82f4..b38b4c94 100644 --- a/lib/include/idol/general/optimizers/OptimizerWithLazyUpdates.h +++ b/lib/include/idol/general/optimizers/OptimizerWithLazyUpdates.h @@ -222,15 +222,20 @@ idol::OptimizerWithLazyUpdates::OptimizerWithLazy template void idol::OptimizerWithLazyUpdates::build() { - for (const auto& var : parent().vars()) { + const auto& parent = this->parent(); + + m_variables.reserve(parent.vars().size()); + for (const auto& var : parent.vars()) { add(var); } - for (const auto& ctr : parent().ctrs()) { + m_constraints.reserve(parent.ctrs().size()); + for (const auto& ctr : parent.ctrs()) { add(ctr); } - for (const auto& qctr : parent().qctrs()) { + m_qconstraints.reserve(parent.qctrs().size()); + for (const auto& qctr : parent.qctrs()) { add(qctr); } diff --git a/lib/include/idol/robust/modeling/Description.h b/lib/include/idol/robust/modeling/Description.h index 27ab355a..562304d4 100644 --- a/lib/include/idol/robust/modeling/Description.h +++ b/lib/include/idol/robust/modeling/Description.h @@ -25,9 +25,7 @@ class idol::Robust::Description { [[nodiscard]] const Annotation& stage_annotation() const; - void make_stage_var(const Var& t_var, unsigned int t_stage); - - void make_stage_ctr(const Ctr& t_ctr, unsigned int t_stage); + void set_stage(const Var& t_var, unsigned int t_stage); unsigned int stage(const Var& t_var) const; @@ -61,6 +59,14 @@ class idol::Robust::Description { m_uncertain_obj.set(t_var, t_obj); } + void set_uncertain_obj(LinExpr> t_obj) { + m_uncertain_obj = std::move(t_obj); + } + + void set_uncertain_rhs(LinExpr> t_rhs) { + m_uncertain_rhs = std::move(t_rhs); + } + class View { const Description& m_description; const Model& m_deterministic_model; diff --git a/lib/include/idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.h b/lib/include/idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.h new file mode 100644 index 00000000..edbb9506 --- /dev/null +++ b/lib/include/idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.h @@ -0,0 +1,43 @@ +// +// Created by henri on 28.11.24. +// + +#ifndef IDOL_AFFINEDECISIONRULE_H +#define IDOL_AFFINEDECISIONRULE_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 AffineDecisionRule; +} + +class idol::Robust::AffineDecisionRule : public OptimizerFactoryWithDefaultParameters { + const Robust::Description& m_description; + std::unique_ptr m_deterministic_optimizer; +public: + explicit AffineDecisionRule(const Robust::Description& t_description); + + AffineDecisionRule(const AffineDecisionRule& t_src); + + Optimizer *operator()(const Model &t_model) const override; + + [[nodiscard]] OptimizerFactory *clone() const override; + + AffineDecisionRule& with_deterministic_optimizer(const OptimizerFactory& t_deterministic_optimizer); + + struct Result { + + Model model; + std::vector> affine_decision_rules; + Robust::Description description; + + explicit Result(Model&& t_model, const Model& t_uncertainty_set) : model(std::move(t_model)), description(t_uncertainty_set) {} + }; + + static Result make_model(const Model& t_model, const Robust::Description& t_description); +}; + + +#endif //IDOL_AFFINEDECISIONRULE_H diff --git a/lib/include/idol/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.h b/lib/include/idol/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.h new file mode 100644 index 00000000..c823d5ef --- /dev/null +++ b/lib/include/idol/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.h @@ -0,0 +1,95 @@ +// +// Created by henri on 28.11.24. +// + +#ifndef IDOL_OPTIMIZERS_AFFINEDECISIONRULE_H +#define IDOL_OPTIMIZERS_AFFINEDECISIONRULE_H + +#include "idol/robust/modeling/Description.h" +#include "idol/general/optimizers/Algorithm.h" +#include "idol/general/optimizers/OptimizerFactory.h" +#include "idol/mixed-integer/modeling/models/Model.h" +#include "idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.h" + +namespace idol::Optimizers::Robust { + class AffineDecisionRule; +} + +class idol::Optimizers::Robust::AffineDecisionRule : public Algorithm { + const idol::Robust::Description& m_description; + std::unique_ptr m_deterministic_optimizer; + std::unique_ptr m_deterministic_model; + + void throw_if_no_deterministic_model() const; +public: + AffineDecisionRule(const Model& t_parent, const idol::Robust::Description& t_description, const OptimizerFactory& t_deterministic_optimizer); + + [[nodiscard]] std::string name() const override; + + [[nodiscard]] SolutionStatus get_status() const override; + + [[nodiscard]] SolutionReason get_reason() const override; + + [[nodiscard]] double get_best_obj() const override; + + [[nodiscard]] double get_best_bound() const override; + + [[nodiscard]] double get_var_primal(const Var &t_var) const override; + + [[nodiscard]] double get_var_reduced_cost(const Var &t_var) const override; + + [[nodiscard]] double get_var_ray(const Var &t_var) const override; + + [[nodiscard]] double get_ctr_dual(const Ctr &t_ctr) const override; + + [[nodiscard]] double get_ctr_farkas(const Ctr &t_ctr) const override; + + [[nodiscard]] unsigned int get_n_solutions() const override; + + [[nodiscard]] unsigned int get_solution_index() const override; + +protected: + void add(const Var &t_var) override; + + void add(const Ctr &t_ctr) override; + + void add(const QCtr &t_ctr) override; + + void remove(const Var &t_var) override; + + void remove(const Ctr &t_ctr) override; + + void remove(const QCtr &t_ctr) override; + + void update() override; + + void write(const std::string &t_name) override; + + void hook_optimize() override; + + void set_solution_index(unsigned int t_index) override; + + void update_obj_sense() override; + + void update_obj() override; + + void update_rhs() override; + + void update_obj_constant() override; + + void update_mat_coeff(const Ctr &t_ctr, const Var &t_var) override; + + void update_ctr_type(const Ctr &t_ctr) override; + + void update_ctr_rhs(const Ctr &t_ctr) override; + + void update_var_type(const Var &t_var) override; + + void update_var_lb(const Var &t_var) override; + + void update_var_ub(const Var &t_var) override; + + void update_var_obj(const Var &t_var) override; +}; + +#endif //IDOL_OPTIMIZERS_AFFINEDECISIONRULE_H diff --git a/lib/src/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.cpp b/lib/src/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.cpp index 006c0a5b..b04b0792 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.cpp @@ -153,9 +153,18 @@ GRBConstr idol::Optimizers::Gurobi::hook_add(const Ctr& t_ctr) { const auto& name = t_ctr.name(); GRBLinExpr expr = 0.; + const unsigned int n = row.size(); + auto* vars = new GRBVar[n]; + auto* vals = new double[n]; + unsigned int i = 0; for (const auto &[var, constant]: row) { - expr += constant * lazy(var).impl(); + vars[i] = lazy(var).impl(); + vals[i] = gurobi_numeric(constant); + ++i; } + expr.addTerms(vals, vars, (int) n); + delete[] vars; + delete[] vals; GUROBI_CATCH(return m_model.addConstr(expr, type, rhs, name);) } @@ -169,9 +178,18 @@ GRBQConstr idol::Optimizers::Gurobi::hook_add(const idol::QCtr &t_ctr) { GRBQuadExpr quad_expr = expr.affine().constant(); + const unsigned int n = expr.affine().linear().size(); + auto* vars = new GRBVar[n]; + auto* vals = new double[n]; + unsigned int i = 0; for (const auto& [var, constant]: expr.affine().linear()) { - quad_expr += constant * lazy(var).impl(); + vars[i] = lazy(var).impl(); + vals[i] = gurobi_numeric(constant); + ++i; } + quad_expr.addTerms(vals, vars, (int) n); + delete[] vars; + delete[] vals; for (const auto& [pair, constant]: expr) { quad_expr += constant * lazy(pair.first).impl() * lazy(pair.second).impl(); @@ -217,11 +235,31 @@ void idol::Optimizers::Gurobi::hook_update_objective() { GRBLinExpr linear_expr = gurobi_numeric(objective.affine().constant()); + const unsigned int n = objective.affine().linear().size(); + auto* vars = new GRBVar[n]; + auto* vals = new double[n]; + unsigned int i = 0; for (const auto& [var, constant] : objective.affine().linear()) { - linear_expr += gurobi_numeric(constant) * lazy(var).impl(); + vars[i] = lazy(var).impl(); + vals[i] = gurobi_numeric(constant); + ++i; } + linear_expr.addTerms(vals, vars, (int) n); + delete[] vars; + delete[] vals; + + if (!objective.has_quadratic()) { + m_model.setObjective(linear_expr, sense); + return; + } + + GRBQuadExpr quad_expr(linear_expr); + for (const auto& [pair, constant] : objective) { + quad_expr += gurobi_numeric(constant) * lazy(pair.first).impl() * lazy(pair.second).impl(); + } + + m_model.setObjective(quad_expr, sense); - m_model.setObjective(linear_expr, sense); } void idol::Optimizers::Gurobi::hook_update_rhs() { diff --git a/lib/src/robust/modeling/Description.cpp b/lib/src/robust/modeling/Description.cpp index 3a8e3e27..69eccce3 100644 --- a/lib/src/robust/modeling/Description.cpp +++ b/lib/src/robust/modeling/Description.cpp @@ -13,14 +13,10 @@ const idol::Annotation &idol::Robust::Description::stage_annotatio return *m_stages; } -void idol::Robust::Description::make_stage_var(const Var &t_var, unsigned int t_stage) { +void idol::Robust::Description::set_stage(const Var &t_var, unsigned int t_stage) { t_var.set(stage_annotation(), t_stage); } -void idol::Robust::Description::make_stage_ctr(const idol::Ctr &t_ctr, unsigned int t_stage) { - t_ctr.set(stage_annotation(), t_stage); -} - unsigned int idol::Robust::Description::stage(const idol::Var &t_var) const { if (!m_stages) { return 0; @@ -74,9 +70,11 @@ std::ostream &idol::operator<<(std::ostream &t_os, const idol::Robust::Descripti const auto& obj = model.get_obj_expr(); - stream << "Minimize\n" << obj.affine().constant() << " + "; + stream << "Minimize\n" << obj.affine().constant(); for (const auto& [var, constant] : obj.affine().linear()) { + stream << " + "; + const auto& uncertainty = description.uncertain_obj(var); if (uncertainty.is_zero(Tolerance::Sparsity)) { stream << constant; @@ -101,8 +99,15 @@ std::ostream &idol::operator<<(std::ostream &t_os, const idol::Robust::Descripti if (uncertain_mat_coeff.is_zero(Tolerance::Sparsity)) { stream << linear; } else { + bool first = true; for (const auto& [var, constant] : linear) { + if (first) { + first = false; + } else { + stream << " + "; + } + const auto& uncertainty = uncertain_mat_coeff.get(var); if (uncertainty.is_zero(Tolerance::Sparsity)) { stream << constant; diff --git a/lib/src/robust/optimizers/affine-decision-rule/AffineDecisionRule.cpp b/lib/src/robust/optimizers/affine-decision-rule/AffineDecisionRule.cpp new file mode 100644 index 00000000..27e1ce0c --- /dev/null +++ b/lib/src/robust/optimizers/affine-decision-rule/AffineDecisionRule.cpp @@ -0,0 +1,104 @@ +// +// Created by henri on 28.11.24. +// +#include "idol/robust/optimizers/affine-decision-rule/AffineDecisionRule.h" +#include "idol/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.h" +#include "idol/mixed-integer/modeling/expressions/operations/operators.h" + +idol::Robust::AffineDecisionRule::AffineDecisionRule(const idol::Robust::Description &t_description) : m_description(t_description) { + +} + +idol::Robust::AffineDecisionRule::AffineDecisionRule(const idol::Robust::AffineDecisionRule &t_src) + : OptimizerFactoryWithDefaultParameters(t_src), + m_description(t_src.m_description), + m_deterministic_optimizer(t_src.m_deterministic_optimizer->clone()) { + +} + +idol::OptimizerFactory *idol::Robust::AffineDecisionRule::clone() const { + return new AffineDecisionRule(*this); +} + +idol::Robust::AffineDecisionRule &idol::Robust::AffineDecisionRule::with_deterministic_optimizer( + const idol::OptimizerFactory &t_deterministic_optimizer) { + if (m_deterministic_optimizer) { + throw Exception("Deterministic optimizer has already been set."); + } + m_deterministic_optimizer.reset(t_deterministic_optimizer.clone()); + return *this; +} + +idol::Optimizer *idol::Robust::AffineDecisionRule::operator()(const idol::Model &t_model) const { + + if (!m_deterministic_optimizer) { + throw Exception("No deterministic optimizer has been set."); + } + + auto* result = new Optimizers::Robust::AffineDecisionRule(t_model, m_description, *m_deterministic_optimizer); + + handle_default_parameters(result); + + return result; +} + +idol::Robust::AffineDecisionRule::Result idol::Robust::AffineDecisionRule::make_model(const idol::Model &t_model, + const idol::Robust::Description &t_description) { + + if (t_description.uncertain_mat_coeffs().size() > 0) { + throw Exception("Cannot handle uncertain matrix coefficients."); + } + + auto& env = t_model.env(); + const auto& uncertainty_set = t_description.uncertainty_set(); + + Result result(t_model.copy(), uncertainty_set); + result.affine_decision_rules.reserve(t_model.vars().size()); + + // Create variables + for (const auto& var : t_model.vars()) { + + if (t_description.stage(var) == 0) { + result.affine_decision_rules.emplace_back(var); + continue; + } + + QuadExpr adr = var; + for (const auto& unc_var : uncertainty_set.vars()) { + const auto y_tilde = result.model.add_var(-Inf, Inf, Continuous, 0., "adr_" + var.name() + "_" + unc_var.name()); + adr += y_tilde * unc_var; + } + + result.affine_decision_rules.emplace_back(std::move(adr)); + } + + for (const auto& ctr : t_model.ctrs()) { + + const auto& row = t_model.get_ctr_row(ctr); + + for (const auto& [var, constant] : row) { + + if (t_description.stage(var) == 0) { + continue; + } + + const unsigned int index = t_model.get_var_index(var); + const auto& adr = result.affine_decision_rules[index]; + for (const auto& [pair, coefficient] : adr) { + if (uncertainty_set.has(pair.first)) { + result.description.set_uncertain_mat_coeff(ctr, pair.second, constant * coefficient * pair.first); + } else { + result.description.set_uncertain_mat_coeff(ctr, pair.first, constant * coefficient * pair.second); + } + } + + } + + } + + result.description.set_uncertain_obj(t_description.uncertain_obj()); + result.description.set_uncertain_rhs(t_description.uncertain_rhs()); + + return result; + +} diff --git a/lib/src/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.cpp b/lib/src/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.cpp new file mode 100644 index 00000000..6b8f7af5 --- /dev/null +++ b/lib/src/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.cpp @@ -0,0 +1,186 @@ +// +// Created by henri on 28.11.24. +// +#include "idol/robust/optimizers/affine-decision-rule/Optimizers_AffineDecisionRule.h" +#include "idol/robust/optimizers/deterministic/Deterministic.h" + +idol::Optimizers::Robust::AffineDecisionRule::AffineDecisionRule(const Model& t_parent, + const idol::Robust::Description &t_description, + const OptimizerFactory &t_deterministic_optimizer) + : Algorithm(t_parent), + m_description(t_description), + m_deterministic_optimizer(t_deterministic_optimizer.clone()) { + +} + +std::string idol::Optimizers::Robust::AffineDecisionRule::name() const { + return "deterministic"; +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_var_primal(const idol::Var &t_var) const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_var_primal(t_var); +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_var_reduced_cost(const idol::Var &t_var) const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_var_reduced_cost(t_var); +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_var_ray(const idol::Var &t_var) const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_var_ray(t_var); +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_ctr_dual(const idol::Ctr &t_ctr) const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_ctr_dual(t_ctr); +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_ctr_farkas(const idol::Ctr &t_ctr) const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_ctr_farkas(t_ctr); +} + +unsigned int idol::Optimizers::Robust::AffineDecisionRule::get_n_solutions() const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_n_solutions(); +} + +unsigned int idol::Optimizers::Robust::AffineDecisionRule::get_solution_index() const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_solution_index(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::add(const idol::Var &t_var) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::add(const idol::Ctr &t_ctr) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::add(const idol::QCtr &t_ctr) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::remove(const idol::Var &t_var) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::remove(const idol::Ctr &t_ctr) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::remove(const idol::QCtr &t_ctr) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update() { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::write(const std::string &t_name) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.write(t_name); +} + +void idol::Optimizers::Robust::AffineDecisionRule::hook_optimize() { + + if (!m_deterministic_model) { + + m_deterministic_model = std::make_unique( + idol::Robust::AffineDecisionRule::make_model(parent(), m_description) + ); + + m_deterministic_model->model.use( + idol::Robust::Deterministic(m_deterministic_model->description) + .with_deterministic_optimizer(*m_deterministic_optimizer) + ); + + } + + m_deterministic_model->model.optimize(); + +} + +void idol::Optimizers::Robust::AffineDecisionRule::set_solution_index(unsigned int t_index) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_solution_index(t_index); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_obj_sense() { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_obj() { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_rhs() { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_obj_constant() { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_obj_const(parent().get_obj_expr().affine().constant()); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_mat_coeff(const idol::Ctr &t_ctr, const idol::Var &t_var) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_ctr_type(const idol::Ctr &t_ctr) { + m_deterministic_model.reset(); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_ctr_rhs(const idol::Ctr &t_ctr) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_ctr_rhs(t_ctr, parent().get_ctr_rhs(t_ctr)); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_var_type(const idol::Var &t_var) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_var_type(t_var, parent().get_var_type(t_var)); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_var_lb(const idol::Var &t_var) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_var_lb(t_var, parent().get_var_lb(t_var)); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_var_ub(const idol::Var &t_var) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_var_ub(t_var, parent().get_var_ub(t_var)); +} + +void idol::Optimizers::Robust::AffineDecisionRule::update_var_obj(const idol::Var &t_var) { + throw_if_no_deterministic_model(); + m_deterministic_model->model.set_var_obj(t_var, parent().get_var_obj(t_var)); +} + +void idol::Optimizers::Robust::AffineDecisionRule::throw_if_no_deterministic_model() const { + if (!m_deterministic_optimizer) { + throw Exception("Not available."); + } +} + +idol::SolutionStatus idol::Optimizers::Robust::AffineDecisionRule::get_status() const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_status(); +} + +idol::SolutionReason idol::Optimizers::Robust::AffineDecisionRule::get_reason() const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_reason(); +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_best_obj() const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_best_obj(); +} + +double idol::Optimizers::Robust::AffineDecisionRule::get_best_bound() const { + throw_if_no_deterministic_model(); + return m_deterministic_model->model.get_best_bound(); +} diff --git a/lib/src/robust/optimizers/deterministic/Deterministic.cpp b/lib/src/robust/optimizers/deterministic/Deterministic.cpp index 96c10528..7bacce70 100644 --- a/lib/src/robust/optimizers/deterministic/Deterministic.cpp +++ b/lib/src/robust/optimizers/deterministic/Deterministic.cpp @@ -38,7 +38,8 @@ idol::Robust::Deterministic::with_deterministic_optimizer(const idol::OptimizerF } idol::Robust::Deterministic::Deterministic(const idol::Robust::Deterministic &t_src) - : m_description(t_src.m_description), + : OptimizerFactoryWithDefaultParameters(t_src), + m_description(t_src.m_description), m_deterministic_optimizer(t_src.m_deterministic_optimizer->clone()) { }