From ed72b0258cbc116142c4450e7e56a1087f5c4f02 Mon Sep 17 00:00:00 2001 From: Henri Lefebvre Date: Wed, 20 Nov 2024 16:23:15 +0100 Subject: [PATCH] introduce generation pattern --- dev/main.cpp | 12 ++-- lib/CMakeLists.txt | 1 + .../idol/general/utils/GenerationPattern.h | 59 +++++++++++++++++++ .../optimizers/dantzig-wolfe/Formulation.h | 8 +-- .../optimizers/padm/Formulation.h | 3 +- .../optimizers/dantzig-wolfe/Formulation.cpp | 36 +++++------ .../optimizers/padm/Formulation.cpp | 10 ++-- 7 files changed, 95 insertions(+), 34 deletions(-) create mode 100644 lib/include/idol/general/utils/GenerationPattern.h diff --git a/dev/main.cpp b/dev/main.cpp index 11f1e00b..27bcf49f 100644 --- a/dev/main.cpp +++ b/dev/main.cpp @@ -18,6 +18,7 @@ #include "idol/mixed-integer/optimizers/branch-and-bound/node-selection-rules/factories/BestBound.h" #include "idol/mixed-integer/optimizers/branch-and-bound/BranchAndBound.h" #include "idol/mixed-integer/modeling/expressions/QuadExpr.h" +#include "idol/general/utils/GenerationPattern.h" using namespace idol; @@ -28,13 +29,16 @@ int main(int t_argc, const char** t_argv) { const auto x = model.add_vars(Dim<1>(10), 0, 1, Binary, 1, "x"); - QuadExpr expr(2 * x[0] + 2); + Point point; + point.set(x[0], 5); - expr += x[0] * x[0]; + GenerationPattern pattern; + pattern.constant() += 2 + 2 * x[0]; - std::cout << expr << std::endl; + pattern.linear().set(x[1], x[0]); + pattern.linear().set(x[2], 10 * x[0] + 4); - std::cout << evaluate(expr, Point()) << std::endl; + std::cout << pattern(point) << std::endl; return 0; } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 224a6c66..53376210 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -226,6 +226,7 @@ add_library(idol STATIC src/mixed-integer/modeling/constraints/TempQCtr.cpp src/mixed-integer/modeling/constraints/QCtrVersion.cpp src/mixed-integer/modeling/constraints/QCtr.cpp + include/idol/general/utils/GenerationPattern.h ) find_package(OpenMP REQUIRED) diff --git a/lib/include/idol/general/utils/GenerationPattern.h b/lib/include/idol/general/utils/GenerationPattern.h new file mode 100644 index 00000000..a30d14a7 --- /dev/null +++ b/lib/include/idol/general/utils/GenerationPattern.h @@ -0,0 +1,59 @@ +// +// Created by henri on 20.11.24. +// + +#ifndef IDOL_GENERATIONPATTERN_H +#define IDOL_GENERATIONPATTERN_H + +#include "idol/mixed-integer/modeling/expressions/AffExpr.h" +#include "Point.h" +#include "idol/mixed-integer/modeling/expressions/operations/operators.h" + +namespace idol { + template class GenerationPattern; +} + +template +class idol::GenerationPattern { + using KeyT = std::conditional_t, Ctr, Var>; + idol::AffExpr m_constant; + SparseVector> m_linear; +public: + GenerationPattern() = default; + + GenerationPattern(idol::AffExpr t_constant, SparseVector> t_linear) + : m_constant(std::move(t_constant)), m_linear(std::move(t_linear)) {} + + auto& constant() { return m_constant; } + + const auto& constant() const { return m_constant; } + + auto& linear() { return m_linear; } + + const auto& linear() const { return m_linear; } + + double generate_constant(const Point& t_values) const { + return evaluate(m_constant, t_values); + } + + LinExpr generate_linear(const Point& t_values) const { + LinExpr result; + + for (const auto& [key, value] : m_linear) { + result += key * evaluate(value, t_values); + } + + return result; + } + + AffExpr operator()(const Point& t_values) const { + AffExpr result(generate_linear(t_values)); + result.constant() = generate_constant(t_values); + return result; + } + +}; + +#endif //IDOL_GENERATIONPATTERN_H diff --git a/lib/include/idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h b/lib/include/idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h index dc5173b3..10a77817 100644 --- a/lib/include/idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h +++ b/lib/include/idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h @@ -7,6 +7,7 @@ #include "idol/mixed-integer/modeling/models/Model.h" #include "idol/general/utils/GeneratorPool.h" +#include "idol/general/utils/GenerationPattern.h" #include "idol/general/utils/Map.h" namespace idol::DantzigWolfe { @@ -18,14 +19,9 @@ class idol::DantzigWolfe::Formulation { Annotation m_decomposition; - struct GenerationPattern { - AffExpr objective; - SparseVector> column; - }; - Model m_master; std::vector m_sub_problems; - std::vector m_generation_patterns; + std::vector> m_generation_patterns; std::vector> m_pools; std::vector m_present_generators; diff --git a/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h b/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h index b1c45715..4e642d30 100644 --- a/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h +++ b/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h @@ -67,8 +67,9 @@ class idol::ADM::Formulation { std::pair m_rescaling; std::vector m_sub_problems; - std::vector>> m_objective_patterns; + std::vector>> m_objective_patterns; std::vector>>> m_constraint_patterns; // as ctr: row <= 0 + std::vector>>> m_qconstraint_patterns; // as ctr: row <= 0 std::vector> m_l1_vars_in_sub_problem; Map m_l1_vars; diff --git a/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp b/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp index 59d3a3ff..75149b33 100644 --- a/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp +++ b/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp @@ -116,7 +116,7 @@ void idol::DantzigWolfe::Formulation::initialize_sub_problems(unsigned int t_n_s void idol::DantzigWolfe::Formulation::initialize_generation_patterns(unsigned int t_n_sub_problems) { - m_generation_patterns = std::vector(t_n_sub_problems); + m_generation_patterns = std::vector>(t_n_sub_problems); } @@ -187,7 +187,7 @@ void idol::DantzigWolfe::Formulation::dispatch_linking_constraint(const idol::Ct m_master.add(t_original_ctr, TempCtr(std::move(master_part), t_type, t_rhs)); for (unsigned int i = 0 ; i < n_sub_problems ; ++i) { - m_generation_patterns[i].column.set(t_original_ctr, std::move(sub_problem_parts[i])); + m_generation_patterns[i].linear().set(t_original_ctr, std::move(sub_problem_parts[i])); } } @@ -231,7 +231,7 @@ void idol::DantzigWolfe::Formulation::dispatch_objective_function(const idol::Mo m_master.set_obj_expr(AffExpr(std::move(master_part)) += objective.affine().constant()); for (unsigned int i = 0 ; i < n_subproblems ; ++i) { - m_generation_patterns[i].objective += std::move(sub_problem_parts[i]); + m_generation_patterns[i].constant() += std::move(sub_problem_parts[i]); } } @@ -266,7 +266,7 @@ void idol::DantzigWolfe::Formulation::add_aggregation_constraint(unsigned int t_ Ctr lower(env, GreaterOrEqual, t_lower_multiplicity); m_master.add(lower); - m_generation_patterns[t_sub_problem_id].column.set(lower, 1); + m_generation_patterns[t_sub_problem_id].linear().set(lower, 1); } @@ -274,7 +274,7 @@ void idol::DantzigWolfe::Formulation::add_aggregation_constraint(unsigned int t_ Ctr upper(env, LessOrEqual, t_upper_multiplicity); m_master.add(upper); - m_generation_patterns[t_sub_problem_id].column.set(upper, 1); + m_generation_patterns[t_sub_problem_id].linear().set(upper, 1); } @@ -283,11 +283,13 @@ void idol::DantzigWolfe::Formulation::add_aggregation_constraint(unsigned int t_ void idol::DantzigWolfe::Formulation::generate_column(unsigned int t_sub_problem_id, idol::PrimalPoint t_generator) { + auto generated = m_generation_patterns[t_sub_problem_id](t_generator); + auto alpha = m_master.add_var(0., Inf, Continuous, - evaluate(m_generation_patterns[t_sub_problem_id].objective, t_generator), - evaluate(m_generation_patterns[t_sub_problem_id].column, t_generator) + std::move(generated.constant()), + std::move(generated.linear()) ); auto& pool = m_pools[t_sub_problem_id]; @@ -306,11 +308,11 @@ double idol::DantzigWolfe::Formulation::compute_reduced_cost(unsigned int t_sub_ const auto generation_pattern = m_generation_patterns[t_sub_problem_id]; - for (const auto &[ctr, constant] : generation_pattern.column) { + for (const auto &[ctr, constant] : generation_pattern.linear()) { result += evaluate(constant, t_generator) * -t_master_dual.get(ctr); } - result += evaluate(generation_pattern.objective, t_generator); + result += evaluate(generation_pattern.constant(), t_generator); return result; @@ -324,12 +326,12 @@ void idol::DantzigWolfe::Formulation::update_sub_problem_objective(unsigned int const auto generation_pattern = m_generation_patterns[t_sub_problem_id]; - for (const auto &[ctr, constant] : generation_pattern.column) { + for (const auto &[ctr, constant] : generation_pattern.linear()) { objective += constant * -t_master_dual.get(ctr); } if (!t_use_farkas) { - objective += generation_pattern.objective; + objective += generation_pattern.constant(); } m_sub_problems[t_sub_problem_id].set_obj_expr(std::move(objective)); @@ -419,7 +421,7 @@ void idol::DantzigWolfe::Formulation::apply_sub_problem_bound_on_master(bool t_i Ctr bound_constraint(m_master.env(), Equal, 0); m_master.add(bound_constraint, TempCtr(LinExpr(expanded), type, t_value)); - m_generation_patterns[t_sub_problem_id].column.set(bound_constraint, t_var); + m_generation_patterns[t_sub_problem_id].linear().set(bound_constraint, t_var); applied_bounds.emplace(t_var, bound_constraint); @@ -474,7 +476,7 @@ void idol::DantzigWolfe::Formulation::update_obj(const idol::QuadExpr m_master.set_var_obj(var, evaluate(sub_problem_parts[i], generator)); } - m_generation_patterns[i].objective = std::move(sub_problem_parts[i]); + m_generation_patterns[i].constant() = std::move(sub_problem_parts[i]); } } @@ -594,7 +596,7 @@ void idol::DantzigWolfe::Formulation::remove(const idol::Var &t_var) { const auto sub_problem_id = t_var.get(m_decomposition); if (sub_problem_id != MasterId) { - m_generation_patterns[sub_problem_id].objective.linear().remove(t_var); + m_generation_patterns[sub_problem_id].constant().linear().remove(t_var); m_sub_problems[sub_problem_id].remove(t_var); return; } @@ -613,7 +615,7 @@ void idol::DantzigWolfe::Formulation::remove(const idol::Ctr &t_ctr) { } m_sub_problems[sub_problem_id].remove(t_ctr); - m_generation_patterns[sub_problem_id].column.remove(t_ctr); + m_generation_patterns[sub_problem_id].linear().remove(t_ctr); } @@ -642,8 +644,8 @@ void idol::DantzigWolfe::Formulation::load_columns_from_pool() { 0, Inf, Continuous, - evaluate(m_generation_patterns[sub_problem_id].objective, generator), - evaluate(m_generation_patterns[sub_problem_id].column, generator) + evaluate(m_generation_patterns[sub_problem_id].constant(), generator), + evaluate(m_generation_patterns[sub_problem_id].linear(), generator) )); m_present_generators[sub_problem_id].emplace_back(var, generator); diff --git a/lib/src/mixed-integer/optimizers/padm/Formulation.cpp b/lib/src/mixed-integer/optimizers/padm/Formulation.cpp index bfc2d022..d160f56d 100644 --- a/lib/src/mixed-integer/optimizers/padm/Formulation.cpp +++ b/lib/src/mixed-integer/optimizers/padm/Formulation.cpp @@ -121,7 +121,7 @@ void idol::ADM::Formulation::dispatch_ctr(const idol::Model &t_src_model, const const double rhs = t_src_model.get_ctr_rhs(t_ctr); const auto type = t_src_model.get_ctr_type(t_ctr); - auto [pattern, is_pure] = dispatch(t_src_model, row, /* row.quadratic(), */ t_sub_problem_id); + auto [pattern, is_pure] = dispatch(t_src_model, row, t_sub_problem_id); pattern.constant() -= rhs; if (pattern.linear().empty()) { @@ -179,11 +179,8 @@ idol::ADM::Formulation::dispatch_obj(const Model &t_src_model) { std::pair, bool> idol::ADM::Formulation::dispatch(const idol::Model &t_src_model, const idol::LinExpr &t_lin_expr, - // const idol::QuadExpr &t_quad_expr, unsigned int t_sub_problem_id) { - throw Exception("TODO: Was using Constant"); - /* bool is_pure = true; // true if the row only has variables from the same sub-problem const auto belongs_to_sub_problem = [&](const Var& t_var) { @@ -197,13 +194,14 @@ std::pair, bool> idol::ADM::Formulation::dispatch(const if (!belongs_to_sub_problem(var)) { is_pure = false; - pattern.constant() += coefficient * !var; + pattern += coefficient * var; continue; } pattern.linear() += coefficient * var; } + /* for (const auto& [var1, var2, constant] : t_quad_expr) { const unsigned int var1_sub_problem_id = var1.get(m_decomposition); @@ -230,12 +228,12 @@ std::pair, bool> idol::ADM::Formulation::dispatch(const pattern.quadratic() += constant * var1 * var2; } + */ return { std::move(pattern), is_pure }; - */ } void