diff --git a/dev/main.cpp b/dev/main.cpp index 488e363d..1908afa5 100644 --- a/dev/main.cpp +++ b/dev/main.cpp @@ -4,6 +4,8 @@ #include "idol/mixed-integer/modeling/models/Model.h" #include "idol/mixed-integer/modeling/objects/Env.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" +#include using namespace idol; @@ -11,11 +13,10 @@ int main(int t_argc, const char** t_argv) { Env env; Model model(env, Model::Storage::RowOriented); - const auto x = model.add_vars(Dim<1>(10), 0., 1., Continuous, "x"); + const auto x = model.add_vars(Dim<1>(10), 0., 1., Continuous, 1, "x"); - Column col; - col.set_obj(1.); - model.add_var(0, 10, Continuous, col); + LinExpr col; + model.add_var(0, 10, Continuous, 1, col); for (unsigned int i = 0; i < 9; ++i) { model.add_ctr(x[i] + x[i+1] >= 0.5); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index eda15caa..4ecddd61 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -14,10 +14,6 @@ add_library(idol STATIC include/idol/general/utils/Set.h include/idol/general/utils/exceptions/NotImplemented.h include/idol/mixed-integer/modeling/expressions/LinExpr.h - include/idol/mixed-integer/modeling/matrix/Row.h - src/mixed-integer/modeling/matrix/Row.cpp - src/mixed-integer/modeling/matrix/Column.cpp - include/idol/mixed-integer/modeling/matrix/Column.h src/mixed-integer/problems/generalized-assignment-problem/GAP_Instance.cpp include/idol/mixed-integer/problems/knapsack-problem/KP_Instance.h src/mixed-integer/problems/knapsack-problem/KP_Instance.cpp @@ -38,7 +34,6 @@ add_library(idol STATIC include/idol/mixed-integer/problems/helpers/distances.h include/idol/mixed-integer/problems/helpers/parse_delimited.h include/idol/mixed-integer/modeling/expressions/operations/operators_utils.h - include/idol/mixed-integer/modeling/expressions/QuadExpr.h include/idol/mixed-integer/modeling/models/Model.h include/idol/mixed-integer/modeling/objects/Env.h include/idol/mixed-integer/modeling/variables/Var.h @@ -231,6 +226,7 @@ add_library(idol STATIC include/idol/general/utils/SparseVector.h include/idol/general/utils/sort.h include/idol/general/utils/Point.h + src/mixed-integer/modeling/variables/VarVersion.cpp ) find_package(OpenMP REQUIRED) diff --git a/lib/include/idol/bilevel/optimizers/wrappers/MibS/MibSCallbackI.h b/lib/include/idol/bilevel/optimizers/wrappers/MibS/MibSCallbackI.h index ba73f7ba..24256b03 100644 --- a/lib/include/idol/bilevel/optimizers/wrappers/MibS/MibSCallbackI.h +++ b/lib/include/idol/bilevel/optimizers/wrappers/MibS/MibSCallbackI.h @@ -8,6 +8,7 @@ #include #include #include "idol/mixed-integer/optimizers/callbacks/Callback.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" #include "impl_MibSFromAPI.h" namespace idol { @@ -96,11 +97,11 @@ class idol::MibSCallbackI : public CallbackI { for (const auto& cut : m_cuts) { - const auto& row = cut.row(); - const double rhs = row.rhs(); + const auto& row = cut.lhs(); + const double rhs = cut.rhs(); CoinPackedVector lhs; - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : row) { const unsigned int index = model.get_var_index(var); lhs.insert(index, constant); } diff --git a/lib/include/idol/general/linear-algebra/to_rotated_quadratic_cone.h b/lib/include/idol/general/linear-algebra/to_rotated_quadratic_cone.h index 74d262e2..9297f47b 100644 --- a/lib/include/idol/general/linear-algebra/to_rotated_quadratic_cone.h +++ b/lib/include/idol/general/linear-algebra/to_rotated_quadratic_cone.h @@ -7,12 +7,12 @@ #ifdef IDOL_USE_EIGEN -#include "idol/mixed-integer/modeling/expressions/QuadExpr.h" #include "idol/mixed-integer/modeling/expressions/LinExpr.h" #include "SquareMatrix.h" namespace idol { + /* static std::list> to_rotated_quadratic_cone(const QuadExpr &t_expr) { // Create index mapping @@ -113,7 +113,7 @@ namespace idol { return result; } - + */ } #endif diff --git a/lib/include/idol/mixed-integer/modeling/constraints/CtrVersion.h b/lib/include/idol/mixed-integer/modeling/constraints/CtrVersion.h index 9e724bf5..1eed8e8e 100644 --- a/lib/include/idol/mixed-integer/modeling/constraints/CtrVersion.h +++ b/lib/include/idol/mixed-integer/modeling/constraints/CtrVersion.h @@ -5,21 +5,57 @@ #ifndef IDOL_CTRVERSION_H #define IDOL_CTRVERSION_H -#include "TempCtr.h" #include "idol/mixed-integer/modeling/objects/Version.h" +#include "idol/mixed-integer/modeling/expressions/LinExpr.h" +#include "idol/mixed-integer/modeling/Types.h" namespace idol { class CtrVersion; } -class idol::CtrVersion : public Version, public TempCtr { +class idol::CtrVersion : public Version { + std::unique_ptr> m_lhs; + CtrType m_type; + double m_rhs = 0.; public: - CtrVersion(unsigned int t_index, TempCtr&& t_temp_ctr) : Version(t_index), TempCtr(std::move(t_temp_ctr)) {} - CtrVersion(unsigned int t_index, const TempCtr& t_temp_ctr) : Version(t_index), TempCtr(t_temp_ctr) {} + CtrVersion(unsigned int t_index, LinExpr&& t_lhs, CtrType t_type, double t_rhs) + : Version(t_index), + m_lhs(std::make_unique>(std::move(t_lhs))), + m_type(t_type), + m_rhs(t_rhs) + {} - using TempCtr::has_row; - using TempCtr::reset_row; - using TempCtr::set_row; + CtrVersion(unsigned int t_index, CtrType t_type, double t_rhs) + : Version(t_index), + m_type(t_type), + m_rhs(t_rhs) + {} + + CtrVersion(const CtrVersion& t_src) + : Version(t_src), + m_lhs(t_src.m_lhs ? std::make_unique>(*t_src.m_lhs) : nullptr), + m_type(t_src.m_type), + m_rhs(t_src.m_rhs) {} + + double rhs() const { return m_rhs; } + + void set_rhs(double t_rhs) { m_rhs = t_rhs; } + + CtrType type() const { return m_type; } + + void set_type(CtrType t_type) { m_type = t_type; } + + LinExpr& lhs() { return *m_lhs; } + + const LinExpr& lhs() const { return *m_lhs; } + + void set_row(LinExpr&& t_row) { m_lhs = std::make_unique>(std::move(t_row)); } + + bool has_row() const { return m_lhs != nullptr; } + + void set_row(const LinExpr& t_row) { m_lhs = std::make_unique>(t_row); } + + void reset_row() { m_lhs.reset(); } }; #endif //IDOL_CTRVERSION_H diff --git a/lib/include/idol/mixed-integer/modeling/constraints/TempCtr.h b/lib/include/idol/mixed-integer/modeling/constraints/TempCtr.h index faae7cf0..717d3125 100644 --- a/lib/include/idol/mixed-integer/modeling/constraints/TempCtr.h +++ b/lib/include/idol/mixed-integer/modeling/constraints/TempCtr.h @@ -5,8 +5,9 @@ #ifndef OPTIMIZE_TEMPCTR_H #define OPTIMIZE_TEMPCTR_H -#include "idol/mixed-integer/modeling/matrix/Row.h" #include +#include +#include namespace idol { @@ -37,12 +38,9 @@ namespace idol { * ``` */ class idol::TempCtr { - std::unique_ptr m_row; + LinExpr m_lhs; CtrType m_type = LessOrEqual; -protected: - void set_row(Row&& t_row) { m_row = std::make_unique(std::move(t_row)); } - bool has_row() const { return (bool) m_row; } - void reset_row() { m_row.reset(); } + double m_rhs = 0.; public: /** * Default constructor. @@ -58,13 +56,13 @@ class idol::TempCtr { * @param t_row The desired row. * @param t_type The desired constraint type. */ - TempCtr(Row&& t_row, CtrType t_type) : m_row(std::make_unique(std::move(t_row))), m_type(t_type) {} + TempCtr(LinExpr&& t_lhs, CtrType t_type, double t_rhs) : m_lhs(std::move(t_lhs)), m_rhs(t_rhs), m_type(t_type) {} /** * Copy constructor. * @param t_src The object to copy. */ - TempCtr(const TempCtr& t_src) : m_row(t_src.m_row ? std::make_unique(*t_src.m_row) : std::unique_ptr()), m_type(t_src.m_type) {} + TempCtr(const TempCtr& t_src) = default; /** * Move constructor. @@ -84,17 +82,11 @@ class idol::TempCtr { */ TempCtr& operator=(TempCtr&& t_src) noexcept = default; - /** - * Returns the row of the temporary constraint (see Row). - * @return The row of the temporary constraint. - */ - [[nodiscard]] const Row& row() const { return *m_row; } + LinExpr& lhs() { return m_lhs; } - /** - * Returns the row of the temporary constraint (see Row). - * @return The row of the temporary constraint. - */ - Row& row() { return *m_row; } + const LinExpr& lhs() const { return m_lhs; } + + void set_lhs(LinExpr&& t_lhs) { m_lhs = std::move(t_lhs); } /** * Returns the temporary constraint type. @@ -102,6 +94,12 @@ class idol::TempCtr { */ [[nodiscard]] CtrType type() const { return m_type; } + double rhs() const { return m_rhs; } + + double& rhs() { return m_rhs; } + + void set_rhs(double t_rhs) { m_rhs = t_rhs; } + /** * Sets the type of the temporary constraint. * @param t_type the desired type. @@ -113,11 +111,6 @@ class idol::TempCtr { m_type = t_type; } - /** - * Returns true if the temporary constraint is violated by the given solution, false otherwise. - * @param t_solution The solution to check. - */ - [[nodiscard]] bool is_violated(const PrimalPoint& t_solution) const; }; idol::TempCtr operator<=(idol::Expr&& t_lhs, idol::Expr&& t_rhs); diff --git a/lib/include/idol/mixed-integer/modeling/expressions/Expr.h b/lib/include/idol/mixed-integer/modeling/expressions/Expr.h index e8685cf5..410754d0 100644 --- a/lib/include/idol/mixed-integer/modeling/expressions/Expr.h +++ b/lib/include/idol/mixed-integer/modeling/expressions/Expr.h @@ -6,23 +6,18 @@ #define IDOL_EXPR_H #include "LinExpr.h" -#include "QuadExpr.h" #include "idol/general/numericals.h" namespace idol { - namespace impl { - template - class Expr; - } + class Var; template class Expr; } -template -class idol::impl::Expr { +template +class idol::Expr { LinExpr m_linear; - QuadExpr m_quadratic; double m_constant = 0.; public: Expr(); @@ -30,9 +25,6 @@ class idol::impl::Expr { Expr(const Key1& t_var); // NOLINT(google-explicit-constructor) Expr(LinExpr&& t_expr); // NOLINT(google-explicit-constructor) Expr(const LinExpr& t_expr); // NOLINT(google-explicit-constructor) - Expr(QuadExpr&& t_expr); // NOLINT(google-explicit-constructor) - Expr(const QuadExpr& t_expr); // NOLINT(google-explicit-constructor) - Expr(const LinExpr& t_lin_expr, const QuadExpr& t_quad_expr, double t_constant); virtual ~Expr() = default; @@ -50,154 +42,86 @@ class idol::impl::Expr { LinExpr& linear() { return m_linear; } [[nodiscard]] const LinExpr& linear() const { return m_linear; } - QuadExpr& quadratic() { return m_quadratic; } - const QuadExpr& quadratic() const { return m_quadratic; } - double& constant() { return m_constant; } - double constant() const { return m_constant; } - - [[nodiscard]] bool is_zero() const { return std::abs(constant()) < Tolerance::Sparsity && linear().empty() && quadratic().empty(); } + [[nodiscard]] double constant() const { return m_constant; } - /* - void round(); - - [[nodiscard]] double gcd() const; - */ + [[nodiscard]] bool is_zero() const { return std::abs(constant()) < Tolerance::Sparsity && linear().empty(); } void clear() { constant() = 0; m_linear.clear(); - m_quadratic.clear(); } }; -/* -template -double idol::impl::Expr::gcd() const { - return std::gcd((long) m_constant->value(),std::gcd(m_linear.gcd(), m_quadratic.gcd())); -} - template -void idol::impl::Expr::round() { - const double val = m_constant->value(); - m_constant->set_value(std::round(val)); - m_linear.round(); - m_quadratic.round(); -} -*/ - -template -idol::impl::Expr::Expr() { +idol::Expr::Expr() { } template -idol::impl::Expr::Expr(double t_constant) : m_constant(t_constant) { +idol::Expr::Expr(double t_constant) : m_constant(t_constant) { } template -idol::impl::Expr::Expr(const Key1 &t_var) : m_linear(t_var) { +idol::Expr::Expr(const Key1 &t_var) : m_linear(t_var) { } template -idol::impl::Expr::Expr(LinExpr &&t_expr) : m_linear(std::move(t_expr)) { +idol::Expr::Expr(LinExpr &&t_expr) : m_linear(std::move(t_expr)) { } template -idol::impl::Expr::Expr(const LinExpr &t_expr) : m_linear(t_expr) { +idol::Expr::Expr(const LinExpr &t_expr) : m_linear(t_expr) { } template -idol::impl::Expr::Expr(QuadExpr &&t_expr) : m_quadratic(std::move(t_expr)) { - -} - -template -idol::impl::Expr::Expr(const QuadExpr &t_expr) : m_quadratic(t_expr) { - -} - -template -idol::impl::Expr::Expr(const LinExpr &t_lin_expr, const QuadExpr &t_quad_expr, double t_constant) - : m_linear(t_lin_expr), - m_quadratic(t_quad_expr), - m_constant(t_constant) { - -} - -template -idol::impl::Expr::Expr(const Expr &t_src) +idol::Expr::Expr(const Expr &t_src) : m_linear(t_src.m_linear), - m_quadratic(t_src.m_quadratic), m_constant(t_src.m_constant) { } template -idol::impl::Expr &idol::impl::Expr::operator=(const Expr &t_rhs) { +idol::Expr &idol::Expr::operator=(const Expr &t_rhs) { if (this == &t_rhs) { return *this; } m_linear = t_rhs.m_linear; - m_quadratic = t_rhs.m_quadratic; m_constant = t_rhs.m_constant; return *this; } template -idol::impl::Expr &idol::impl::Expr::operator+=(const impl::Expr &t_rhs) { +idol::Expr &idol::Expr::operator+=(const Expr &t_rhs) { m_linear += t_rhs.m_linear; - m_quadratic += t_rhs.m_quadratic; m_constant += t_rhs.m_constant; return *this; } template -idol::impl::Expr &idol::impl::Expr::operator-=(const impl::Expr &t_rhs) { +idol::Expr &idol::Expr::operator-=(const Expr &t_rhs) { m_linear -= t_rhs.m_linear; - m_quadratic -= t_rhs.m_quadratic; m_constant -= t_rhs.m_constant; return *this; } template -idol::impl::Expr &idol::impl::Expr::operator*=(double t_rhs) { +idol::Expr &idol::Expr::operator*=(double t_rhs) { m_linear *= t_rhs; - m_quadratic *= t_rhs; m_constant *= t_rhs; return *this; } template -idol::impl::Expr &idol::impl::Expr::operator/=(double t_rhs) { +idol::Expr &idol::Expr::operator/=(double t_rhs) { m_linear /= t_rhs; - m_quadratic /= t_rhs; m_constant /= t_rhs; return *this; } -template -class idol::Expr : public impl::Expr { -public: - Expr() = default; - Expr(double t_num) : impl::Expr(t_num) {} // NOLINT(google-explicit-constructor) - Expr(const Key1& t_var) : impl::Expr(t_var) {} // NOLINT(google-explicit-constructor) - Expr(LinExpr&& t_expr) : impl::Expr(std::move(t_expr)) {} // NOLINT(google-explicit-constructor) - Expr(const LinExpr& t_expr) : impl::Expr(t_expr) {} // NOLINT(google-explicit-constructor) - Expr(QuadExpr&& t_expr) : impl::Expr(std::move(t_expr)) {} // NOLINT(google-explicit-constructor) - Expr(const QuadExpr& t_expr) : impl::Expr(t_expr) {} // NOLINT(google-explicit-constructor) - Expr(const LinExpr& t_lin_expr, const QuadExpr& t_quad_expr, double t_constant) : impl::Expr(t_lin_expr, t_quad_expr, t_constant) {} - - Expr(const Expr& t_src) = default; - Expr(Expr&&) noexcept = default; - - Expr& operator=(const Expr& t_rhs) = default; - Expr& operator=(Expr&&) noexcept = default; -}; - namespace idol { template @@ -205,16 +129,8 @@ namespace idol { if (std::abs(t_expr.constant()) < Tolerance::Sparsity) { - if (t_expr.linear().empty()) { - return t_os << t_expr.quadratic(); - } - t_os << t_expr.linear(); - if (!t_expr.quadratic().empty()) { - return t_os << " + " << t_expr.quadratic(); - } - return t_os; } @@ -224,10 +140,6 @@ namespace idol { t_os << " + " << t_expr.linear(); } - if (!t_expr.quadratic().empty()) { - t_os << " + " << t_expr.quadratic(); - } - return t_os; } diff --git a/lib/include/idol/mixed-integer/modeling/expressions/LinExpr.h b/lib/include/idol/mixed-integer/modeling/expressions/LinExpr.h index c9f9cffe..4f9920cd 100644 --- a/lib/include/idol/mixed-integer/modeling/expressions/LinExpr.h +++ b/lib/include/idol/mixed-integer/modeling/expressions/LinExpr.h @@ -7,7 +7,6 @@ #include "idol/general/utils/SparseVector.h" #include "idol/general/utils/IteratorForward.h" -#include "idol/mixed-integer/modeling/variables/Var.h" #include "idol/general/utils/exceptions/Exception.h" #include #include @@ -16,6 +15,8 @@ #include namespace idol { + class Var; + template class LinExpr; } diff --git a/lib/include/idol/mixed-integer/modeling/expressions/QuadExpr.h b/lib/include/idol/mixed-integer/modeling/expressions/QuadExpr.h deleted file mode 100644 index 82a3275f..00000000 --- a/lib/include/idol/mixed-integer/modeling/expressions/QuadExpr.h +++ /dev/null @@ -1,85 +0,0 @@ -// -// Created by henri on 21/11/22. -// - -#ifndef IDOL_QUADEXPR_H -#define IDOL_QUADEXPR_H - -#include "idol/general/utils/Pair.h" - -namespace idol { - template - class QuadExpr; -} - -template -class idol::QuadExpr : public SparseVector, double> { -public: - QuadExpr() = default; - QuadExpr(const Key1& t_a, const Key2& t_b); - QuadExpr(double t_factor, const Key1& t_a, const Key2& t_b); - - QuadExpr(const QuadExpr&) = default; - QuadExpr(QuadExpr&&) noexcept = default; - - QuadExpr& operator=(const QuadExpr&) = default; - QuadExpr& operator=(QuadExpr&&) noexcept = default; - - virtual ~QuadExpr() = default; - - void set(const Key1& t_a, const Key2& t_b, double t_coefficient); - - double get(const Key1& t_a, const Key2& t_b) const; -}; - -template -idol::QuadExpr::QuadExpr(const Key1 &t_a, const Key2 &t_b) - : SparseVector, double>( - { {t_a, t_b} }, - { 1. }, - SparseVector, double>::SortingCriteria::Index, - true) { - -} - -template -idol::QuadExpr::QuadExpr(double t_factor, const Key1 &t_a, const Key2 &t_b) - : SparseVector, double>( - { {t_a, t_b} }, - { t_factor }, - SparseVector, double>::SortingCriteria::Index, - true - ) { - -} - -template -void idol::QuadExpr::set(const Key1 &t_a, const Key2& t_b, double t_coefficient) { - return SparseVector, double>::set({ t_a, t_b }, std::move(t_coefficient)); -} - -template -double idol::QuadExpr::get(const Key1 &t_a, const Key2 &t_b) const { - return SparseVector, double>::get({ t_a, t_b }); -} - -namespace idol { - template - std::ostream& operator<<(std::ostream& t_os, const QuadExpr& t_expr) { - - if (t_expr.empty()) { - return t_os << "0"; - } - - unsigned int i = 0; - t_os << t_expr.value_at(i) << " " << t_expr.index_at(i) << " + "; - ++i; - for (unsigned int n = t_expr.size() ; i < n ; ++i) { - t_os << t_expr.value_at(i) << " " << t_expr.index_at(i) << " + "; - } - - return t_os; - } -} - -#endif //IDOL_QUADEXPR_H diff --git a/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Ctr.h b/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Ctr.h index 85476100..85fe9cf3 100644 --- a/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Ctr.h +++ b/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Ctr.h @@ -32,20 +32,6 @@ namespace idol { idol::LinExpr operator*(const idol::Ctr &t_ctr, const idol::Constant &t_constant); - idol::QuadExpr operator*(const idol::Ctr &t_var1, const idol::Ctr &t_var2); - - idol::QuadExpr operator*(const idol::LinExpr &t_lin_expr, const idol::Ctr &t_var); - - idol::QuadExpr operator*(const idol::Ctr &t_var, const idol::LinExpr &t_lin_expr); - - idol::QuadExpr operator*(double t_num, idol::QuadExpr &&t_quad_expr); - - idol::QuadExpr operator*(double t_num, const idol::QuadExpr &t_quad_expr); - - idol::QuadExpr operator*(idol::QuadExpr &&t_quad_expr, double t_num); - - idol::QuadExpr operator*(const idol::QuadExpr &t_quad_expr, double t_num); - idol::Expr operator*(double t_num, idol::Expr &&t_expr); idol::Expr operator*(double t_num, const idol::Expr &t_expr); diff --git a/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Var.h b/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Var.h index bdd2edbd..239f03f3 100644 --- a/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Var.h +++ b/lib/include/idol/mixed-integer/modeling/expressions/operations/operators_Var.h @@ -31,20 +31,6 @@ namespace idol { idol::LinExpr operator*(const idol::Var &t_var, double t_constant); - idol::QuadExpr operator*(const idol::Var &t_var1, const idol::Var &t_var2); - - idol::QuadExpr operator*(const idol::LinExpr &t_lin_expr, const idol::Var &t_var); - - idol::QuadExpr operator*(const idol::Var &t_var, const idol::LinExpr &t_lin_expr); - - idol::QuadExpr operator*(double t_num, idol::QuadExpr &&t_quad_expr); - - idol::QuadExpr operator*(double t_num, const idol::QuadExpr &t_quad_expr); - - idol::QuadExpr operator*(idol::QuadExpr &&t_quad_expr, double t_num); - - idol::QuadExpr operator*(const idol::QuadExpr &t_quad_expr, double t_num); - idol::Expr operator*(double t_num, idol::Expr &&t_expr); idol::Expr operator*(double t_num, const idol::Expr &t_expr); @@ -81,18 +67,6 @@ namespace idol { idol::LinExpr operator+(const idol::LinExpr &t_a, const idol::LinExpr &t_b); - idol::Expr operator+(double t_term, idol::QuadExpr &&t_quad_expr); - - idol::Expr operator+(idol::QuadExpr &&t_quad_expr, double t_term); - - idol::QuadExpr operator+(idol::QuadExpr &&t_a, const idol::QuadExpr &t_b); - - idol::QuadExpr operator+(const idol::QuadExpr &t_a, idol::QuadExpr &&t_b); - - idol::QuadExpr operator+(idol::QuadExpr &&t_a, idol::QuadExpr &&t_b); - - idol::QuadExpr operator+(const idol::QuadExpr &t_a, const idol::QuadExpr &t_b); - idol::Expr operator+(const idol::Expr &t_a, idol::Expr &&t_b); idol::Expr operator+(idol::Expr &&t_a, const idol::Expr &t_b); @@ -115,10 +89,6 @@ namespace idol { idol::LinExpr operator-(const idol::LinExpr &t_a, const idol::LinExpr &t_b); - idol::QuadExpr operator-(idol::QuadExpr &&t_a, const idol::QuadExpr &t_b); - - idol::QuadExpr operator-(const idol::QuadExpr &t_a, const idol::QuadExpr &t_b); - idol::Expr operator-(idol::Expr &&t_a, const idol::Expr &t_b); idol::Expr operator-(const idol::Expr &t_a, const idol::Expr &t_b); diff --git a/lib/include/idol/mixed-integer/modeling/matrix/Column.h b/lib/include/idol/mixed-integer/modeling/matrix/Column.h deleted file mode 100644 index 393bff50..00000000 --- a/lib/include/idol/mixed-integer/modeling/matrix/Column.h +++ /dev/null @@ -1,231 +0,0 @@ -// -// Created by henri on 04/10/22. -// - -#ifndef OPTIMIZE_COLUMN_H -#define OPTIMIZE_COLUMN_H - -#include -#include "idol/mixed-integer/modeling/expressions/Expr.h" -#include "idol/mixed-integer/modeling/constraints/Ctr.h" - -namespace idol { - - namespace impl { - class Column; - } - - class Column; - -} - -class idol::impl::Column { - ::idol::Expr m_impl; - ::idol::LinExpr m_obj_quad; -protected: - ::idol::Expr& impl() { return m_impl; } -public: - Column() = default; - Column(double t_obj) : m_impl(t_obj) {} // NOLINT(google-explicit-constructor) - - Column(const Column& t_src) = default; - Column(Column&& t_src) noexcept = default; - - Column& operator=(const Column& t_src) = default; - Column& operator=(Column&& t_src) noexcept = default; - - /** - * Returns the (linear) objective coefficient of the column. - * - * For instance, a model's variable `x` with column whose objective is `2` implies that the model has a term in the - * objective function which is `2 * x`. - * @return The (linear) objective coefficient of the column - */ - double& obj() { return m_impl.constant(); } - - /** - * Returns the (linear) objective coefficient of the column. - * For instance, a model's variable `x` with column whose objective is `2` implies that the model has a term in the - * objective function which is `2 * x`. - * @return The (linear) objective coefficient of the column - */ - [[nodiscard]] double obj() const { return m_impl.constant(); } - - /** - * Returns the (quadratic) objective coefficient of the column. - * - * For instance, a model's variable `x` with column whose objective is `2 * y` implies that the model has a term in the - * objective function which is `2 * y * x`. - * @return The (quadratic) objective coefficient of the column - */ - ::idol::LinExpr& obj_quadratic() { return m_obj_quad; } - - /** - * Returns the (quadratic) objective coefficient of the column. - * - * For instance, a model's variable `x` with column whose objective is `2 * y` implies that the model has a term in the - * objective function which is `2 * y * x`. - * @return The (quadratic) objective coefficient of the column - */ - [[nodiscard]] const ::idol::LinExpr& obj_quadratic() const { return m_obj_quad; } - - /** - * Returns the (linear) components of the column. - * - * For instance, a model's variable `x` with a column having a component `{ constraint, 2 }` implies that the model - * has a constraint `constraint` with a term `2 * x`. - * @return The (linear) components of the column. - */ - LinExpr& linear() { return m_impl.linear(); } - - /** - * Returns the (linear) components of the column. - * - * For instance, a model's variable `x` with a column having a component `{ constraint, 2 }` implies that the model - * has a constraint `constraint` with a term `2 * x`. - * @return The (linear) components of the column. - */ - [[nodiscard]] const LinExpr& linear() const { return m_impl.linear(); } - - /** - * Returns the (quadratic) components of the column. - * - * For instance, a model's variable `x` with a column having a component `{ constraint, 2 * y }` implies that the model - * has a constraint `constraint` with a term `2 * y * x`. - * @return The (quadratic) components of the column. - */ - QuadExpr& quadratic() { return m_impl.quadratic(); } - - /** - * Returns the (quadratic) components of the column. - * - * For instance, a model's variable `x` with a column having a component `{ constraint, 2 * y }` implies that the model - * has a constraint `constraint` with a term `2 * y * x`. - * @return The (quadratic) components of the column. - */ - [[nodiscard]] const QuadExpr& quadratic() const { return m_impl.quadratic(); } - - /** - * Sets the (linear) components of the column. - * @param t_lin_expr The (linear) components of the column - */ - void set_linear(LinExpr&& t_lin_expr) { m_impl.linear() = std::move(t_lin_expr); } - - /** - * Sets the (linear) components of the column. - * @param t_lin_expr The (linear) components of the column - */ - void set_linear(const LinExpr& t_lin_expr) { m_impl.linear() = t_lin_expr; } - - /** - * Sets the (quadratic) components of the column. - * @param t_lin_expr The (quadratic) components of the column - */ - void set_quadratic(QuadExpr&& t_quad_expr) { m_impl.quadratic() = std::move(t_quad_expr); } - - /** - * Sets the (quadratic) components of the column. - * @param t_lin_expr The (quadratic) components of the column - */ - void set_quadratic(const QuadExpr& t_quad_expr) { m_impl.quadratic() = t_quad_expr; } - - /** - * Sets the (linear) objective coefficient. - * @param t_obj The (linear) objective coefficient - */ - void set_obj(double t_obj) { m_impl.constant() = t_obj; } - - /** - * Adds the objective and components of `t_rhs` to the objective and components of the column. - * @param t_rhs the right hand-side - * @return *this - */ - Column& operator+=(const Column& t_rhs) { m_impl += t_rhs.m_impl; return *this; } - - /** - * Subtracts the objective and components of `t_rhs` to the objective and components of the column. - * @param t_rhs the right hand-side - * @return *this - */ - Column& operator-=(const Column& t_rhs) { m_impl -= t_rhs.m_impl; return *this; } - - /** - * Multiplies the objective and components of the column by a given factor. - * @param t_rhs the right hand-side - * @return *this - */ - Column& operator*=(double t_rhs) { m_impl *= t_rhs; return *this; } -}; - -/** - * Column modeling-old object. - * - * This class is used to represent an optimization model's column. It is made of an objective coefficient and a set of - * `{ Ctr, Constant }` - * pairs representing the coefficient (`Constant`) of the column in each row (`Ctr`). Such pairs are called components. - */ -class idol::Column : public impl::Column { -public: - /** - * Default constructor. - * - * Creates an empty column. - */ - Column() = default; - - /** - * Constructor. - * - * Creates a new column with no components and on objective coefficient equal to `t_obj` - * @param t_obj The objective coefficient - */ - Column(double t_obj) : impl::Column(t_obj) {} // NOLINT(google-explicit-constructor) - - /** - * Copy constructor. - * @param t_src The object to be copied - */ - Column(const Column& t_src) = default; - - /** - * Move constructor. - * @param t_src The object to be moved - */ - Column(Column&& t_src) noexcept = default; - - /** - * Copy-assignment operator - * @param t_src The object to copy - * @return *this - */ - Column& operator=(const Column& t_src) = default; - - /** - * Move-assignment operator - * @param t_src The object to move - * @return *this - */ - Column& operator=(Column&& t_src) noexcept = default; - - /** - * Represents an empty column - */ - static const Column EmptyColumn; -}; - -namespace idol { - - static std::ostream &operator<<(std::ostream& t_os, const idol::Column& t_column) { - - t_os << "[Obj: " << t_column.obj() << "]\n"; - - for (const auto& [ctr, constant] : t_column.linear()) { - t_os << '[' << ctr.name() << ": " << constant << "]\n"; - } - - return t_os; - } - -} - -#endif //OPTIMIZE_COLUMN_H diff --git a/lib/include/idol/mixed-integer/modeling/matrix/Row.h b/lib/include/idol/mixed-integer/modeling/matrix/Row.h deleted file mode 100644 index 9353fdf0..00000000 --- a/lib/include/idol/mixed-integer/modeling/matrix/Row.h +++ /dev/null @@ -1,260 +0,0 @@ -// -// Created by henri on 04/10/22. -// - -#ifndef OPTIMIZE_ROW_H -#define OPTIMIZE_ROW_H - -#include -#include "idol/mixed-integer/modeling/expressions/Expr.h" -#include "idol/general/utils/Point.h" - -namespace idol { - - namespace impl { - class Row; - } - - class Row; - -} - -class idol::impl::Row { - ::idol::Expr m_impl; -protected: - ::idol::Expr& impl() { return m_impl; } -public: - Row() = default; - Row(::idol::Expr&& t_lhs, ::idol::Expr&& t_rhs); - Row(::idol::Expr&& t_lhs, const ::idol::Expr& t_rhs); - Row(const ::idol::Expr& t_lhs, ::idol::Expr&& t_rhs); - Row(const ::idol::Expr& t_lhs, const ::idol::Expr& t_rhs); - - Row(const Row& t_src) = default; - Row(Row&& t_src) noexcept = default; - - Row& operator=(const Row& t_src) = default; - Row& operator=(Row&& t_src) noexcept = default; - - /** - * Returns the right hand-side of the row. - * @return The right hand-side of the row. - */ - [[nodiscard]] double rhs() const { return m_impl.constant(); } - - /** - * Returns the linear part of the left hand-side of the row. - * @return The linear part of the left hand-side of the row. - */ - LinExpr& linear() { return m_impl.linear(); } - - /** - * Returns the linear part of the left hand-side of the row. - * @return The linear part of the left hand-side of the row. - */ - [[nodiscard]] const LinExpr& linear() const { return m_impl.linear(); } - - /** - * Returns the quadratic part of the left hand-side of the row. - * @return The quadratic part of the left hand-side of the row. - */ - QuadExpr& quadratic() { return m_impl.quadratic(); } - - /** - * Returns the quadratic part of the left hand-side of the row. - * @return The quadratic part of the left hand-side of the row. - */ - [[nodiscard]] const QuadExpr& quadratic() const { return m_impl.quadratic(); } - - /** - * Sets the linear part of the left hand-side of the row. - * @param t_lin_expr The new linear part of the right hand-side. - */ - void set_linear(LinExpr&& t_lin_expr) { m_impl.linear() = std::move(t_lin_expr); } - - /** - * Sets the linear part of the left hand-side of the row. - * @param t_lin_expr The new linear part of the right hand-side. - */ - void set_linear(const LinExpr& t_lin_expr) { m_impl.linear() = t_lin_expr; } - - /** - * Sets the quadratic part of the left hand-side of the row. - * @param t_lin_expr The new quadratic part of the right hand-side. - */ - void set_quadratic(QuadExpr&& t_quad_expr) { m_impl.quadratic() = std::move(t_quad_expr); } - - /** - * Sets the quadratic part of the left hand-side of the row. - * @param t_lin_expr The new quadratic part of the right hand-side. - */ - void set_quadratic(const QuadExpr& t_quad_expr) { m_impl.quadratic() = t_quad_expr; } - - /** - * Sets the right hand-side of the row. - * @param t_rhs The new right hand-side of the row. - */ - void set_rhs(double t_rhs) { m_impl.constant() = t_rhs; } - - /** - * Adds another row to the row (both the left and right hand-sides are added). - * @param t_rhs The row to add. - * @return *this - */ - Row& operator+=(const Row& t_rhs) { m_impl += t_rhs.m_impl; return *this; } - - /** - * Subtracts another row to the row (both the left and right hand-sides are subtracted). - * @param t_rhs The row to subtarct. - * @return *this - */ - Row& operator-=(const Row& t_rhs) { m_impl -= t_rhs.m_impl; return *this; } - - /** - * Multiplies all the entries of the row by a given factor (both the left and right hand-sides are multiplied). - * @param t_rhs The factor used for multiplication. - * @return *this - */ - Row& operator*=(double t_rhs) { m_impl *= t_rhs; return *this; } - - Row& operator/=(double t_rhs) { m_impl /= t_rhs; return *this; } - -}; - -/** - * Row modeling-old object. - * - * This class is used to represent an optimization model's row. It is made of a right hand-side and a set of `{ Var, Constant }` - * pairs representing the coefficient (`Constant`) of the row in each column (`Var`). Such pairs are called left hand-side terms. - * - * The whole left hand-side is stored as an `Expr` while the whole right hand-side is stored as a `Constant`. - * - * **Example**: - * ```cpp - * auto constraint = model.add_ctr(x + y <= 1.); - * const auto& row = model.get_ctr_row(constraint); // Row(x + y, 1.) - * ``` - */ -class idol::Row : public impl::Row { -public: - /* - * Default constructor. - * - * Creates an empty row. - */ - Row() = default; - - /** - * Constructor. - * - * Creates a new row with a left hand-side `t_lhs` and a right hand-side `t_rhs`. - * @param t_lhs The left hand-side. - * @param t_rhs The right hand-side. - */ - Row(Expr&& t_lhs, Expr&& t_rhs) : impl::Row(std::move(t_lhs), std::move(t_rhs)) {} - - /** - * Constructor. - * - * Creates a new row with a left hand-side `t_lhs` and a right hand-side `t_rhs`. - * @param t_lhs The left hand-side. - * @param t_rhs The right hand-side. - */ - Row(Expr&& t_lhs, const Expr& t_rhs) : impl::Row(std::move(t_lhs), t_rhs) {} - - /** - * Constructor. - * - * Creates a new row with a left hand-side `t_lhs` and a right hand-side `t_rhs`. - * @param t_lhs The left hand-side. - * @param t_rhs The right hand-side. - */ - Row(const Expr& t_lhs, Expr&& t_rhs) : impl::Row(t_lhs, std::move(t_rhs)) {} - - /** - * Constructor. - * - * Creates a new row with a left hand-side `t_lhs` and a right hand-side `t_rhs`. - * @param t_lhs The left hand-side. - * @param t_rhs The right hand-side. - */ - Row(const Expr& t_lhs, const Expr& t_rhs) : impl::Row(t_lhs, t_rhs) {} - - /** - * Copy constructor. - * @param t_src The row to copy. - */ - Row(const Row& t_src) = default; - - /** - * Move constructor. - * @param t_src The row to move. - */ - Row(Row&& t_src) noexcept = default; - - /** - * Copy-assignment operator. - * @param t_src The row to copy. - * @return *this - */ - Row& operator=(const Row& t_src) = default; - - /** - * Move-assignment operator. - * @param t_src The row to move. - * @return *this - */ - Row& operator=(Row&& t_src) noexcept = default; - - /** - * Returns the value of the row if the value of each variable is taken in `t_primals`, i.e., the difference between - * the left and the right hand-side. - * - * If parameters are encountered, an exception is thrown. - * @param t_primals The primal values. - * @return The value of the row. - */ - double value(const PrimalPoint& t_primals) const; - - /** - * Returns true if the point stored in `t_primals` violates the constraint formed by the row and a constraint type - * `t_type` with tolerance `t_tolerance`. - * @param t_primals The primal values. - * @param t_type The type of the constraint. - * @param t_tolerance The tolerance for feasibility. - * @return True if the given point violates the row. - */ - bool is_violated(const PrimalPoint& t_primals, CtrType t_type, double t_tolerance = Tolerance::Feasibility) const; - - /** - * Represents an empty row. - */ - static const Row EmptyRow; -}; - -namespace idol { - - static std::ostream &operator<<(std::ostream &t_os, const Row &t_row) { - - t_os << '['; - - if (t_row.linear().empty()) { - - t_os << t_row.quadratic(); - - } else { - - t_os << t_row.linear(); - - if (!t_row.quadratic().empty()) { - t_os << " + " << t_row.quadratic(); - } - - } - - return t_os << "] [" << t_row.rhs() << ']'; - } - -} - -#endif //OPTIMIZE_ROW_H diff --git a/lib/include/idol/mixed-integer/modeling/models/Model.h b/lib/include/idol/mixed-integer/modeling/models/Model.h index fce7c427..3acbc41e 100644 --- a/lib/include/idol/mixed-integer/modeling/models/Model.h +++ b/lib/include/idol/mixed-integer/modeling/models/Model.h @@ -29,7 +29,6 @@ namespace idol { static const unsigned int MasterId = std::numeric_limits::max(); class Env; - class Column; class TempCtr; class Model; @@ -64,7 +63,6 @@ class idol::Model { Model(const Model& t_src); template void throw_if_unknown_object(const LinExpr& t_expr); - template void throw_if_unknown_object(const QuadExpr& t_expr); void add_column_to_rows(const Var& t_var); void add_row_to_columns(const Ctr& t_ctr); void build_row(const Ctr& t_ctr); @@ -101,10 +99,11 @@ class idol::Model { * @param t_lb the lower bound in the model * @param t_ub the upper bound in the model * @param t_type the type in the model + * @param t_obj the objective coefficient in the model * @param t_name the name of the variable * @return the created variable */ - Var add_var(double t_lb, double t_ub, VarType t_type, std::string t_name = ""); + Var add_var(double t_lb, double t_ub, VarType t_type, double t_obj = 0., std::string t_name = ""); /** * Creates a new decision variable in the model and returns it. @@ -118,11 +117,12 @@ class idol::Model { * @param t_lb the lower bound in the model * @param t_ub the upper bound in the model * @param t_type the type in the model + * @param t_obj the objective coefficient in the model * @param t_column the column in the model * @param t_name the name of the variable * @return the created variable */ - Var add_var(double t_lb, double t_ub, VarType t_type, Column t_column, std::string t_name = ""); + Var add_var(double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr t_column, std::string t_name = ""); /** * Creates multiple decision variables in the model and returns them. @@ -146,7 +146,7 @@ class idol::Model { * @param t_name the base name for the variables (variables are then named by a combination of this name and indices) * @return the create variables */ - template Vector add_vars(Dim t_dim, double t_lb, double t_ub, VarType t_type, const std::string& t_name = ""); + template Vector add_vars(Dim t_dim, double t_lb, double t_ub, VarType t_type, double t_obj = 0., const std::string& t_name = ""); /** * Adds an existing variable to the model. @@ -258,12 +258,13 @@ class idol::Model { * ```cpp * auto constraint = model.add_ctr(Row(x[0] + 2 * x[1], 1.5), LessOrEqual); * ``` - * @param t_row the row of the constraint in the model + * @param t_lhs the left-hand side of the constraint in the model * @param t_type the type of the constraint in the model + * @param t_rhs the right-hand side of the constraint in the model * @param t_name the name of the constraint * @return the created constraint */ - Ctr add_ctr(Row&& t_row, CtrType t_type, std::string t_name = ""); + Ctr add_ctr(LinExpr&& t_lhs, CtrType t_type, double t_rhs, std::string t_name = ""); /** * Creates multiple constraints in the model and returns them. @@ -281,11 +282,11 @@ class idol::Model { * @tparam N the number of dimensions for the indices * @param t_dim the dimensions for the indices * @param t_type the type of the constraints in the model - * @param t_constant the right hand-side of the constraints in the model + * @param t_rhs the right hand-side of the constraints in the model * @param t_name the base name for the constraints (constraints are then named by a combination of this name and indices) * @return the created constraints */ - template Vector add_ctrs(Dim t_dim, CtrType t_type, double t_constant, const std::string& t_name = ""); + template Vector add_ctrs(Dim t_dim, CtrType t_type, double t_rhs, const std::string& t_name = ""); /** * Adds an existing variable to the model. @@ -825,6 +826,8 @@ class idol::Model { */ [[nodiscard]] CtrType get_ctr_type(const Ctr& t_ctr) const; + double get_ctr_rhs(const Ctr& t_ctr) const; + /** * Returns the row of the constraint in the model. * @@ -839,7 +842,7 @@ class idol::Model { * @param t_ctr the constraint * @return the constraint's row */ - [[nodiscard]] const Row& get_ctr_row(const Ctr& t_ctr) const; + [[nodiscard]] LinExpr get_ctr_row(const Ctr& t_ctr) const; /** * Returns the dual value of a constraint @@ -913,7 +916,7 @@ class idol::Model { * @param t_ctr the constraint * @param t_row the constraint's row */ - void set_ctr_row(const Ctr& t_ctr, const Row& t_row); + void set_ctr_row(const Ctr& t_ctr, const LinExpr& t_row); /** * Sets a constraint's row. @@ -930,7 +933,7 @@ class idol::Model { * @param t_ctr the constraint * @param t_row the constraint's row */ - void set_ctr_row(const Ctr& t_ctr, Row&& t_row); + void set_ctr_row(const Ctr& t_ctr, LinExpr&& t_row); /** * Returns the current index of the variable in the model. @@ -1052,7 +1055,9 @@ class idol::Model { * @param t_var the variable * @return the variable's column */ - [[nodiscard]] const Column& get_var_column(const Var& t_var) const; + [[nodiscard]] const LinExpr& get_var_column(const Var& t_var) const; + + [[nodiscard]] double get_var_obj(const Var& t_var) const; /** * Sets a variable's type in the model. @@ -1120,7 +1125,7 @@ class idol::Model { * @param t_var the variable * @param t_column the variable's column */ - void set_var_column(const Var& t_var, const Column& t_column); + void set_var_column(const Var& t_var, const LinExpr& t_column); /** * Sets a variable's column in the model. @@ -1137,7 +1142,7 @@ class idol::Model { * @param t_var the variable * @param t_column the variable's column */ - void set_var_column(const Var& t_var, Column&& t_column); + void set_var_column(const Var& t_var, LinExpr&& t_column); /** * Returns the number of available primal solutions. @@ -1220,15 +1225,15 @@ void idol::Model::add_vector(const Vector &t_vector) { } template -idol::Vector idol::Model::add_vars(Dim t_dim, double t_lb, double t_ub, VarType t_type, const std::string& t_name) { - auto result = Var::make_vector(m_env, t_dim, t_lb, t_ub, t_type, t_name); +idol::Vector idol::Model::add_vars(Dim t_dim, double t_lb, double t_ub, VarType t_type, double t_obj, const std::string& t_name) { + auto result = Var::make_vector(m_env, t_dim, t_lb, t_ub, t_type, t_obj, t_name); add_vector(result); return result; } template -idol::Vector idol::Model::add_ctrs(Dim t_dim, CtrType t_type, double t_constant, const std::string &t_name) { - auto result = Ctr::make_vector(m_env, t_dim, t_type, t_constant, t_name); +idol::Vector idol::Model::add_ctrs(Dim t_dim, CtrType t_type, double t_rhs, const std::string &t_name) { + auto result = Ctr::make_vector(m_env, t_dim, t_type, t_rhs, t_name); add_vector(result); return result; } @@ -1372,21 +1377,13 @@ namespace idol { for (const auto &ctr: t_model.ctrs()) { - const auto &row = t_model.get_ctr_row(ctr); - const auto &linear = row.linear(); - const auto &quadratic = row.quadratic(); + const auto linear = t_model.get_ctr_row(ctr); + const double rhs = t_model.get_ctr_rhs(ctr); const auto type = t_model.get_ctr_type(ctr); stream << '\t' << ctr << ": "; - if (linear.empty()) { - stream << quadratic; - } else { - stream << linear; - if (!quadratic.empty()) { - stream << " + " << quadratic; - } - } + stream << linear; switch (type) { case LessOrEqual: @@ -1402,7 +1399,7 @@ namespace idol { stream << " ?undefined? "; } - stream << row.rhs() << std::endl; + stream << rhs << std::endl; } std::list generals, binaries; diff --git a/lib/include/idol/mixed-integer/modeling/objects/Env.h b/lib/include/idol/mixed-integer/modeling/objects/Env.h index a26d3cf2..df90c8ec 100644 --- a/lib/include/idol/mixed-integer/modeling/objects/Env.h +++ b/lib/include/idol/mixed-integer/modeling/objects/Env.h @@ -9,6 +9,7 @@ #include "idol/mixed-integer/modeling/variables/Var.h" #include "idol/mixed-integer/modeling/variables/VarVersion.h" +#include "idol/mixed-integer/modeling/variables/TempVar.h" #include "Versions.h" #include "ObjectId.h" #include "idol/mixed-integer/modeling/annotations/impl_Annotation.h" @@ -99,8 +100,8 @@ class idol::impl::Env { return create(std::move(t_name), "x", m_variables, std::move(t_temp_var)); } - ObjectId create_ctr(std::string t_name, TempCtr&& t_temp_ctr) { - return create(std::move(t_name), "c", m_constraints, std::move(t_temp_ctr)); + ObjectId create_ctr(std::string t_name, LinExpr&& t_lhs, CtrType t_type, double t_rhs) { + return create(std::move(t_name), "c", m_constraints, std::move(t_lhs), t_type, t_rhs); } public: diff --git a/lib/include/idol/mixed-integer/modeling/variables/TempVar.h b/lib/include/idol/mixed-integer/modeling/variables/TempVar.h index 74b69094..b42ef080 100644 --- a/lib/include/idol/mixed-integer/modeling/variables/TempVar.h +++ b/lib/include/idol/mixed-integer/modeling/variables/TempVar.h @@ -5,7 +5,9 @@ #ifndef OPTIMIZE_TEMPVAR_H #define OPTIMIZE_TEMPVAR_H -#include "idol/mixed-integer/modeling/matrix/Column.h" +#include "idol/mixed-integer/modeling/expressions/LinExpr.h" +#include "idol/mixed-integer/modeling/constraints/Ctr.h" +#include "idol/mixed-integer/modeling/Types.h" namespace idol { class TempVar; @@ -30,11 +32,8 @@ class idol::TempVar { double m_lb = 0.; double m_ub = Inf; VarType m_type = Continuous; - std::unique_ptr m_column; -protected: - void set_column(Column&& t_column) { m_column = std::make_unique(std::move(t_column)); } - bool has_column() const { return (bool) m_column; } - void reset_column() { m_column.reset(); } + double m_obj = 0.; + LinExpr m_column; public: /** * Default constructor. @@ -52,7 +51,7 @@ class idol::TempVar { * @param t_type The desired variable type. * @param t_column The desired column. */ - TempVar(double t_lb, double t_ub, VarType t_type, Column&& t_column) : m_lb(t_lb), m_ub(t_ub), m_type(t_type), m_column(std::make_unique(std::move(t_column))) {} + TempVar(double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr&& t_column) : m_lb(t_lb), m_ub(t_ub), m_type(t_type), m_obj(t_obj), m_column(std::move(t_column)) {} /** * Copy constructor. @@ -64,7 +63,7 @@ class idol::TempVar { * Move constructor. * @param t_src The object to move. */ - TempVar(const TempVar& t_src) : m_lb(t_src.m_lb), m_ub(t_src.m_ub), m_type(t_src.m_type), m_column(t_src.m_column ? std::make_unique(*t_src.m_column) : std::unique_ptr()) {} + TempVar(const TempVar& t_src) : m_lb(t_src.m_lb), m_ub(t_src.m_ub), m_type(t_src.m_type), m_obj(t_src.m_obj), m_column(t_src.m_column) {} /** * Copy-assignment operator. @@ -82,13 +81,13 @@ class idol::TempVar { * Returns the column of the temporary variable (see `Column`). * @return The column of the temporary variable. */ - [[nodiscard]] const Column& column() const { return *m_column; } + [[nodiscard]] const LinExpr& column() const { return m_column; } /** * Returns the column of the temporary variable (see `Column`). * @return The column of the temporary variable. */ - Column& column() { return *m_column; } + LinExpr& column() { return m_column; } /** * Returns the lower bound of the temporary variable. @@ -130,6 +129,10 @@ class idol::TempVar { } m_type = t_type; } + + double obj() const { return m_obj; } + + void set_obj(double t_obj) { m_obj = t_obj; } }; #endif //OPTIMIZE_TEMPVAR_H diff --git a/lib/include/idol/mixed-integer/modeling/variables/Var.h b/lib/include/idol/mixed-integer/modeling/variables/Var.h index 64cd4e39..5a84ba6c 100644 --- a/lib/include/idol/mixed-integer/modeling/variables/Var.h +++ b/lib/include/idol/mixed-integer/modeling/variables/Var.h @@ -7,12 +7,12 @@ #include "idol/mixed-integer/modeling/objects/Object.h" #include "idol/mixed-integer/modeling/Types.h" +#include "idol/mixed-integer/modeling/expressions/LinExpr.h" namespace idol { class Env; class VarVersion; - class Column; template class Versions; @@ -54,7 +54,7 @@ class idol::Var : public Object { * @param t_type The type for the default version of the variable. * @param t_name The given name of the variable. */ - Var(Env& t_env, double t_lb, double t_ub, VarType t_type, std::string t_name = ""); + Var(Env& t_env, double t_lb, double t_ub, VarType t_type, double t_obj = 0., std::string t_name = ""); /** * Constructor. @@ -69,7 +69,7 @@ class idol::Var : public Object { * @param t_column The column for the default version of the variable. * @param t_name The given name of the variable. */ - Var(Env& t_env, double t_lb, double t_ub, VarType t_type, Column&& t_column, std::string t_name = ""); + Var(Env& t_env, double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr&& t_column, std::string t_name = ""); /** * Constructor. @@ -84,7 +84,7 @@ class idol::Var : public Object { * @param t_column The column for the default version of the variable. * @param t_name The given name of the variable. */ - Var(Env& t_env, double t_lb, double t_ub, VarType t_type, const Column& t_column, std::string t_name = ""); + Var(Env& t_env, double t_lb, double t_ub, VarType t_type, double t_obj, const LinExpr& t_column, std::string t_name = ""); Var(const Var&) = default; Var(Var&&) = default; @@ -116,9 +116,9 @@ class idol::Var : public Object { * @return A (nested) vector of variables. */ template - static Vector make_vector(Env& t_env, const Dim& t_dim, double t_lb, double t_ub, VarType t_type, const std::string& t_name = "") { + static Vector make_vector(Env& t_env, const Dim& t_dim, double t_lb, double t_ub, VarType t_type, double t_obj, const std::string& t_name = "") { return impl::create_many(t_dim, t_name.empty() ? "Var" : t_name, [&](const std::string& t_name_i) { - return Var(t_env, t_lb, t_ub, t_type, t_name_i); + return Var(t_env, t_lb, t_ub, t_type, t_obj, t_name_i); }); } }; diff --git a/lib/include/idol/mixed-integer/modeling/variables/VarVersion.h b/lib/include/idol/mixed-integer/modeling/variables/VarVersion.h index d34c08ed..51783902 100644 --- a/lib/include/idol/mixed-integer/modeling/variables/VarVersion.h +++ b/lib/include/idol/mixed-integer/modeling/variables/VarVersion.h @@ -5,23 +5,57 @@ #ifndef IDOL_VARVERSION_H #define IDOL_VARVERSION_H -#include "idol/mixed-integer/modeling/matrix/Column.h" #include "idol/mixed-integer/modeling/objects/Version.h" -#include "TempVar.h" +#include "idol/mixed-integer/modeling/expressions/LinExpr.h" +#include "idol/mixed-integer/modeling/constraints/Ctr.h" namespace idol { + class TempVar; class VarVersion; } -class idol::VarVersion : public Version, public TempVar { +class idol::VarVersion : public Version { + double m_lb; + double m_ub; + VarType m_type; + double m_obj; + std::unique_ptr> m_column; public: - VarVersion(unsigned int t_index, double t_lb, double t_ub, VarType t_type, Column&& t_column) : Version(t_index), TempVar(t_lb, t_ub, t_type, std::move(t_column)) {} - VarVersion(unsigned int t_index, TempVar&& t_temp_var) : Version(t_index), TempVar(std::move(t_temp_var)) {} - VarVersion(unsigned int t_index, const TempVar& t_temp_var) : Version(t_index), TempVar(t_temp_var) {} + VarVersion(unsigned int t_index, double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr&& t_column); + VarVersion(unsigned int t_index, TempVar&& t_temp_var); + VarVersion(unsigned int t_index, const TempVar& t_temp_var); + + VarVersion(const VarVersion& t_other); + VarVersion(VarVersion&& t_other) noexcept = default; + + double lb() const { return m_lb; } + + void set_lb(double t_lb) { m_lb = t_lb; } + + double ub() const { return m_ub; } + + void set_ub(double t_ub) { m_ub = t_ub; } + + VarType type() const { return m_type; } + + void set_type(VarType t_type) { m_type = t_type; } + + double obj() const { return m_obj; } + + void set_obj(double t_obj) { m_obj = t_obj; } + + LinExpr& column() { return *m_column; } + + const LinExpr& column() const { return *m_column; } + + void set_column(LinExpr&& t_column) { m_column = std::make_unique>(std::move(t_column)); } + + bool has_column() const { return m_column != nullptr; } + + void set_column(const LinExpr& t_column) { m_column = std::make_unique>(t_column); } + + void reset_column() { m_column.reset(); } - using TempVar::has_column; - using TempVar::reset_column; - using TempVar::set_column; }; #endif //IDOL_VARVERSION_H diff --git a/lib/include/idol/mixed-integer/optimizers/branch-and-bound/Optimizers_BranchAndBound.h b/lib/include/idol/mixed-integer/optimizers/branch-and-bound/Optimizers_BranchAndBound.h index dff5cddd..12256cc9 100644 --- a/lib/include/idol/mixed-integer/optimizers/branch-and-bound/Optimizers_BranchAndBound.h +++ b/lib/include/idol/mixed-integer/optimizers/branch-and-bound/Optimizers_BranchAndBound.h @@ -222,7 +222,7 @@ void idol::Optimizers::BranchAndBound::update_ctr_type(const Ctr &t_c template void idol::Optimizers::BranchAndBound::update_ctr_rhs(const Ctr &t_ctr) { - m_relaxation->set_ctr_rhs(t_ctr, parent().get_ctr_row(t_ctr).rhs()); + m_relaxation->set_ctr_rhs(t_ctr, parent().get_ctr_rhs(t_ctr)); } template @@ -242,7 +242,7 @@ void idol::Optimizers::BranchAndBound::update_var_ub(const Var &t_var template void idol::Optimizers::BranchAndBound::update_var_obj(const Var &t_var) { - m_relaxation->set_var_obj(t_var, parent().get_var_column(t_var).obj()); + m_relaxation->set_var_obj(t_var, parent().get_var_obj(t_var)); } template diff --git a/lib/include/idol/mixed-integer/optimizers/callbacks/cutting-planes/CutSeparation.h b/lib/include/idol/mixed-integer/optimizers/callbacks/cutting-planes/CutSeparation.h index a7064169..b47b5891 100644 --- a/lib/include/idol/mixed-integer/optimizers/callbacks/cutting-planes/CutSeparation.h +++ b/lib/include/idol/mixed-integer/optimizers/callbacks/cutting-planes/CutSeparation.h @@ -7,6 +7,7 @@ #include "idol/mixed-integer/modeling/models/Model.h" #include "idol/mixed-integer/optimizers/callbacks/Callback.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" namespace idol::impl { class CutSeparation; 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 b9770c71..9beb6db4 100644 --- a/lib/include/idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h +++ b/lib/include/idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h @@ -21,7 +21,7 @@ class idol::DantzigWolfe::Formulation { 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; @@ -36,8 +36,8 @@ class idol::DantzigWolfe::Formulation { void initialize_present_generators(unsigned int t_n_sub_problems); void dispatch_variables(const Model& t_original_formulation); void dispatch_constraints(const Model& t_original_formulation); - void dispatch_linking_constraint(const Ctr& t_original_ctr, const Row& t_row, CtrType t_type); - std::pair, std::vector> decompose_expression(const LinExpr &t_linear, const QuadExpr& t_quadratic); + void dispatch_linking_constraint(const Ctr& t_original_ctr, const LinExpr& t_row, CtrType t_type); + std::pair, std::vector> decompose_expression(const LinExpr &t_linear /*, const QuadExpr& t_quadratic */); void dispatch_objective_function(const Model& t_original_formulation); bool is_feasible(const PrimalPoint& t_primal, unsigned int t_sub_problem_id); @@ -97,9 +97,9 @@ class idol::DantzigWolfe::Formulation { void clean_up(unsigned int t_sub_problem_id, double t_ratio); - void add(const Var& t_var, double t_lb, double t_ub, VarType t_type, const Column& t_column); + void add(const Var& t_var, double t_lb, double t_ub, VarType t_type, const LinExpr& t_column); - void add(const Ctr& t_ctr, CtrType t_type, const Row& t_row); + void add(const Ctr& t_ctr, CtrType t_type, const LinExpr& t_row); void remove(const Var& t_var); diff --git a/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h b/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h index 2f681b50..6b5abd28 100644 --- a/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h +++ b/lib/include/idol/mixed-integer/optimizers/padm/Formulation.h @@ -81,7 +81,7 @@ class idol::ADM::Formulation { void dispatch_ctr(const Model& t_src_model, const Ctr& t_ctr, unsigned int t_sub_problem_id); void dispatch_obj(const Model& t_src_model); void dispatch_obj(const Model& t_src_model, unsigned int t_sub_problem_id); - std::pair, bool> dispatch(const Model& t_src_model, const LinExpr& t_lin_expr, const QuadExpr& t_quad_expr, unsigned int t_sub_problem_id); + std::pair, bool> dispatch(const Model& t_src_model, const LinExpr& t_lin_expr, /* const QuadExpr& t_quad_expr, */ unsigned int t_sub_problem_id); Var get_or_create_l1_var(const Ctr& t_ctr); void set_penalty_in_all_sub_problems(const Var& t_var, double t_value); void update_penalty_parameters_independently(const std::vector& t_primals, PenaltyUpdate& t_penalty_update); diff --git a/lib/src/bilevel/modeling/write_to_file.cpp b/lib/src/bilevel/modeling/write_to_file.cpp index 84c9f8f9..fe8f4dce 100644 --- a/lib/src/bilevel/modeling/write_to_file.cpp +++ b/lib/src/bilevel/modeling/write_to_file.cpp @@ -144,8 +144,9 @@ void MpsWriter::write() { const auto add_row_entries = [&](const Var& t_var) { const auto& column = m_model.get_var_column(t_var); - add_entry(t_var.name(), "OBJ", column.obj()); - for (const auto& [ctr, constant] : column.linear()) { + const double obj = m_model.get_var_obj(t_var); + add_entry(t_var.name(), "OBJ", obj); + for (const auto& [ctr, constant] : column) { add_entry(t_var.name(), ctr.name(), constant); } }; @@ -165,7 +166,7 @@ void MpsWriter::write() { file << "RHS\n"; for (const auto& ctr : m_model.ctrs()) { - file << " RHS " << std::setw(10) << ctr.name() << ' ' << m_model.get_ctr_row(ctr).rhs() << '\n'; + file << " RHS " << std::setw(10) << ctr.name() << ' ' << m_model.get_ctr_rhs(ctr) << '\n'; } file << "BOUNDS\n"; diff --git a/lib/src/bilevel/optimizers/wrappers/MibS/impl_MibSFromAPI.cpp b/lib/src/bilevel/optimizers/wrappers/MibS/impl_MibSFromAPI.cpp index 38642f7c..0ae20c0e 100644 --- a/lib/src/bilevel/optimizers/wrappers/MibS/impl_MibSFromAPI.cpp +++ b/lib/src/bilevel/optimizers/wrappers/MibS/impl_MibSFromAPI.cpp @@ -288,11 +288,7 @@ idol::impl::MibSFromAPI::parse_constraints() { const auto& row = m_model.get_ctr_row(ctr); const auto type = m_model.get_ctr_type(ctr); - const auto rhs = row.rhs(); - - if (!row.quadratic().empty()) { - throw Exception("Only linear constraints are allowed in MibS."); - } + const auto rhs = m_model.get_ctr_rhs(ctr); switch (type) { case LessOrEqual: @@ -334,11 +330,7 @@ CoinPackedMatrix idol::impl::MibSFromAPI::parse_matrix() { const auto& col = m_model.get_var_column(var); - if (!col.quadratic().empty()) { - throw Exception("Only linear constraints are allowed in MibS."); - } - - const auto& lin = col.linear(); + const auto& lin = col; CoinPackedVector vector; vector.reserve((int) lin.size()); @@ -366,7 +358,7 @@ std::vector idol::impl::MibSFromAPI::parse_objective() { for (const auto& var : m_model.vars()) { - const double coefficient = m_model.get_var_column(var).obj(); + const double coefficient = m_model.get_var_obj(var); result.emplace_back(coefficient); } diff --git a/lib/src/mixed-integer/modeling/annotations/impl_Annotation.cpp b/lib/src/mixed-integer/modeling/annotations/impl_Annotation.cpp index 758a8166..033f45d1 100644 --- a/lib/src/mixed-integer/modeling/annotations/impl_Annotation.cpp +++ b/lib/src/mixed-integer/modeling/annotations/impl_Annotation.cpp @@ -3,6 +3,8 @@ // #include "idol/mixed-integer/modeling/annotations/impl_Annotation.h" +#include "idol/mixed-integer/modeling/variables/TempVar.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" #include "idol/mixed-integer/modeling/objects/Env.h" idol::impl::Annotation::Annotation(::idol::Env &t_env, bool t_is_var_annotation, std::string &&t_name) diff --git a/lib/src/mixed-integer/modeling/constraints/Ctr.cpp b/lib/src/mixed-integer/modeling/constraints/Ctr.cpp index f2607a66..124e79c3 100644 --- a/lib/src/mixed-integer/modeling/constraints/Ctr.cpp +++ b/lib/src/mixed-integer/modeling/constraints/Ctr.cpp @@ -2,9 +2,11 @@ // Created by henri on 30/01/23. // #include "idol/mixed-integer/modeling/constraints/Ctr.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" #include "idol/mixed-integer/modeling/objects/Env.h" -idol::Ctr::Ctr(Env &t_env, TempCtr &&t_temp_ctr, std::string t_name) : Object(t_env.create_ctr(std::move(t_name), std::move(t_temp_ctr))) { +idol::Ctr::Ctr(Env &t_env, TempCtr &&t_temp_ctr, std::string t_name) + : Object(t_env.create_ctr(std::move(t_name), std::move(t_temp_ctr.lhs()), t_temp_ctr.type(), t_temp_ctr.rhs())) { } @@ -13,6 +15,6 @@ idol::Ctr::Ctr(Env &t_env, const TempCtr &t_temp_ctr, std::string t_name) : Ctr( } idol::Ctr::Ctr(idol::Env &t_env, idol::CtrType t_type, double t_constant, std::string t_name) - : Ctr(t_env, TempCtr(Row(0, t_constant), t_type), std::move(t_name)) { + : Ctr(t_env, TempCtr(LinExpr(), t_type, t_constant), std::move(t_name)) { } diff --git a/lib/src/mixed-integer/modeling/constraints/TempCtr.cpp b/lib/src/mixed-integer/modeling/constraints/TempCtr.cpp index 765ddfff..ae36c60c 100644 --- a/lib/src/mixed-integer/modeling/constraints/TempCtr.cpp +++ b/lib/src/mixed-integer/modeling/constraints/TempCtr.cpp @@ -3,12 +3,14 @@ // #include "idol/mixed-integer/modeling/constraints/TempCtr.h" #include "idol/general/utils/Point.h" -#include "idol/mixed-integer/modeling/expressions/LinExpr.h" +#include "idol/mixed-integer/modeling/expressions/Expr.h" using namespace idol; TempCtr operator<=(Expr&& t_lhs, Expr&& t_rhs) { - return { Row(std::move(t_lhs), std::move(t_rhs)), LessOrEqual }; + auto diff = std::move(t_lhs); + diff -= t_rhs; + return { std::move(diff.linear()), LessOrEqual, diff.constant() }; } TempCtr operator<=(const Expr& t_lhs, Expr&& t_rhs) { return Expr(t_lhs) <= std::move(t_rhs); } @@ -16,7 +18,9 @@ TempCtr operator<=(Expr&& t_lhs, const Expr& t_rhs) { return std::move TempCtr operator<=(const Expr& t_lhs, const Expr& t_rhs) { return Expr(t_lhs) <= Expr(t_rhs); } TempCtr operator>=(Expr&& t_lhs, Expr&& t_rhs) { - return { Row(std::move(t_lhs), std::move(t_rhs)), GreaterOrEqual }; + auto diff = std::move(t_lhs); + diff -= t_rhs; + return { std::move(diff.linear()), GreaterOrEqual, diff.constant() }; } TempCtr operator>=(const Expr& t_lhs, Expr&& t_rhs) { return Expr(t_lhs) >= std::move(t_rhs); } @@ -24,33 +28,21 @@ TempCtr operator>=(Expr&& t_lhs, const Expr& t_rhs) { return std::move TempCtr operator>=(const Expr& t_lhs, const Expr& t_rhs) { return Expr(t_lhs) >= Expr(t_rhs); } TempCtr operator==(Expr&& t_lhs, Expr&& t_rhs) { - return { Row(std::move(t_lhs), std::move(t_rhs)), Equal }; + auto diff = std::move(t_lhs); + diff -= t_rhs; + return { std::move(diff.linear()), Equal, diff.constant() }; } TempCtr operator==(const Expr& t_lhs, Expr&& t_rhs) { return Expr(t_lhs) == std::move(t_rhs); } TempCtr operator==(Expr&& t_lhs, const Expr& t_rhs) { return std::move(t_lhs) == Expr(t_rhs); } TempCtr operator==(const Expr& t_lhs, const Expr& t_rhs) { return Expr(t_lhs) == Expr(t_rhs); } -bool TempCtr::is_violated(const PrimalPoint &t_solution) const { - const double rhs = m_row->rhs(); - double lhs = 0.; - for (const auto& [var, coeff] : m_row->linear()) { - lhs += coeff * t_solution.get(var); - } - switch (m_type) { - case LessOrEqual: return lhs > rhs; - case GreaterOrEqual: return lhs < rhs; - default:; - } - return equals(lhs, rhs, Tolerance::Feasibility); -} - std::ostream &idol::operator<<(std::ostream& t_os, const TempCtr& t_temp_ctr) { - t_os << t_temp_ctr.row().linear(); + t_os << t_temp_ctr.lhs(); switch (t_temp_ctr.type()) { case LessOrEqual: t_os << " <= "; break; case GreaterOrEqual: t_os << " >= "; break; case Equal: t_os << " == "; break; } - return t_os << t_temp_ctr.row().rhs(); + return t_os << t_temp_ctr.rhs(); } diff --git a/lib/src/mixed-integer/modeling/expressions/operations/operators_Ctr.cpp b/lib/src/mixed-integer/modeling/expressions/operations/operators_Ctr.cpp index dc17e74d..e35a9e90 100644 --- a/lib/src/mixed-integer/modeling/expressions/operations/operators_Ctr.cpp +++ b/lib/src/mixed-integer/modeling/expressions/operations/operators_Ctr.cpp @@ -34,44 +34,6 @@ LinExpr idol::operator*(const LinExpr& t_lin_expr, double t_num) { return t_num * LinExpr(t_lin_expr); } - -QuadExpr idol::operator*(const LinExpr& t_lin_expr, const Ctr& t_var) { - QuadExpr result; - - for (auto&& [var, constant] : t_lin_expr) { - result.set(var, t_var, constant); - } - - return result; -} - -QuadExpr idol::operator*(const Ctr& t_var, const LinExpr& t_lin_expr) { - return t_lin_expr * t_var; -} - -QuadExpr idol::operator*(const Ctr& t_var1, const Ctr& t_var2) { - return { t_var1, t_var2 }; -} - -QuadExpr idol::operator*(double t_num, QuadExpr&& t_quad_expr) { - QuadExpr result(std::move(t_quad_expr)); - result *= t_num; - return result; -} - -QuadExpr idol::operator*(double t_num, const QuadExpr& t_quad_expr) { - return t_num * QuadExpr(t_quad_expr); -} - -QuadExpr idol::operator*(QuadExpr&& t_quad_expr, double t_num) { - return t_num * std::move(t_quad_expr); -} - -QuadExpr idol::operator*(const QuadExpr& t_quad_expr, double t_num) { - return t_num * t_quad_expr; -} - - /* ADDITION */ LinExpr idol::operator+(LinExpr&& t_lin_expr) { diff --git a/lib/src/mixed-integer/modeling/expressions/operations/operators_Var.cpp b/lib/src/mixed-integer/modeling/expressions/operations/operators_Var.cpp index b223390d..2a4444a7 100644 --- a/lib/src/mixed-integer/modeling/expressions/operations/operators_Var.cpp +++ b/lib/src/mixed-integer/modeling/expressions/operations/operators_Var.cpp @@ -2,6 +2,7 @@ // Created by henri on 26/10/22. // #include "idol/mixed-integer/modeling/expressions/operations/operators_Var.h" +#include "idol/mixed-integer/modeling/variables/Var.h" using namespace idol; @@ -33,42 +34,6 @@ LinExpr idol::operator*(const LinExpr& t_lin_expr, double t_num) { return t_num * LinExpr(t_lin_expr); } -QuadExpr idol::operator*(const LinExpr& t_lin_expr, const Var& t_var) { - QuadExpr result; - - for (auto&& [var, constant] : t_lin_expr) { - result.set(var, t_var, constant); - } - - return result; -} - -QuadExpr idol::operator*(const Var& t_var, const LinExpr& t_lin_expr) { - return t_lin_expr * t_var; -} - -QuadExpr idol::operator*(const Var& t_var1, const Var& t_var2) { - return { t_var1, t_var2 }; -} - -QuadExpr idol::operator*(double t_num, QuadExpr&& t_quad_expr) { - QuadExpr result(std::move(t_quad_expr)); - result *= t_num; - return result; -} - -QuadExpr idol::operator*(double t_num, const QuadExpr& t_quad_expr) { - return t_num * QuadExpr(t_quad_expr); -} - -QuadExpr idol::operator*(QuadExpr&& t_quad_expr, double t_num) { - return t_num * std::move(t_quad_expr); -} - -QuadExpr idol::operator*(const QuadExpr& t_quad_expr, double t_num) { - return t_num * t_quad_expr; -} - Expr idol::operator*(double t_num, Expr&& t_expr) { Expr result(std::move(t_expr)); result *= t_num; @@ -151,46 +116,9 @@ LinExpr idol::operator+(const LinExpr& t_a, const LinExpr& t_b) { return LinExpr(t_a) + t_b; } -idol::Expr idol::operator+(double t_term, idol::QuadExpr &&t_quad_expr) { - Expr result(std::move(t_quad_expr)); - result.constant() += t_term; - return result; -} - -idol::Expr idol::operator+(idol::QuadExpr &&t_quad_expr, double t_term) { - Expr result(std::move(t_quad_expr)); - result.constant() += t_term; - return result; -} - -QuadExpr idol::operator+(QuadExpr&& t_a, const QuadExpr& t_b) { - QuadExpr result(std::move(t_a)); - result += t_b; - return result; -} - -QuadExpr idol::operator+(const QuadExpr& t_a, QuadExpr&& t_b) { - return std::move(t_b) + t_a; -} - -QuadExpr idol::operator+(QuadExpr&& t_a, QuadExpr&& t_b) { - if (t_a.size() < t_b.size()) { - return std::move(t_b) + t_a; - } - return std::move(t_a) + t_b; -} - -QuadExpr idol::operator+(const QuadExpr& t_a, const QuadExpr& t_b) { - if (t_a.size() < t_b.size()) { - return QuadExpr(t_b) + t_a; - } - return QuadExpr(t_a) + t_b; -} - Expr idol::operator+(const Expr& t_a, Expr&& t_b) { Expr result(std::move(t_b)); result.linear() += t_a.linear(); - result.quadratic() += t_a.quadratic(); result.constant() += t_a.constant(); return result; } @@ -241,16 +169,6 @@ LinExpr idol::operator-(const LinExpr& t_a, const LinExpr& t_b) { return LinExpr(t_a) - t_b; } -QuadExpr idol::operator-(QuadExpr&& t_a, const QuadExpr& t_b) { - QuadExpr result(std::move(t_a)); - result -= t_b; - return result; -} - -QuadExpr idol::operator-(const QuadExpr& t_a, const QuadExpr& t_b) { - return QuadExpr(t_a) - t_b; -} - Expr idol::operator-(Expr&& t_a, const Expr& t_b) { Expr result(std::move(t_a)); result -= t_b; diff --git a/lib/src/mixed-integer/modeling/matrix/Column.cpp b/lib/src/mixed-integer/modeling/matrix/Column.cpp deleted file mode 100644 index fbc43753..00000000 --- a/lib/src/mixed-integer/modeling/matrix/Column.cpp +++ /dev/null @@ -1,7 +0,0 @@ -// -// Created by henri on 04/10/22. -// -#include "idol/mixed-integer/modeling/matrix/Column.h" -#include "idol/mixed-integer/modeling/expressions/operations/operators_Ctr.h" - -const idol::Column idol::Column::EmptyColumn; diff --git a/lib/src/mixed-integer/modeling/matrix/Row.cpp b/lib/src/mixed-integer/modeling/matrix/Row.cpp deleted file mode 100644 index 8d89e938..00000000 --- a/lib/src/mixed-integer/modeling/matrix/Row.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// -// Created by henri on 04/10/22. -// -#include "idol/mixed-integer/modeling/matrix/Row.h" -#include "idol/mixed-integer/modeling/expressions/operations/operators.h" -#include "idol/general/utils/Point.h" - -#include - -const idol::Row idol::Row::EmptyRow; - -double idol::Row::value(const idol::PrimalPoint &t_primals) const { - - double result = -rhs(); - - for (const auto& [var, constant] : linear()) { - result += constant * t_primals.get(var); - } - - for (const auto& [vars, constant] : quadratic()) { - result += constant * t_primals.get(vars.first) * t_primals.get(vars.second); - } - - return result; -} - -bool idol::Row::is_violated(const idol::PrimalPoint &t_primals, idol::CtrType t_type, double t_tolerance) const { - - const double value = this->value(t_primals); - - if (t_type == LessOrEqual) { - return value > t_tolerance; - } - - if (t_type == GreaterOrEqual) { - return value < -t_tolerance; - } - - return !equals(value, 0, t_tolerance); -} - -idol::impl::Row::Row(::idol::Expr &&t_lhs, ::idol::Expr &&t_rhs) - : m_impl( - std::move(t_lhs.linear()) - t_rhs.linear(), - std::move(t_lhs.quadratic()) - t_rhs.quadratic(), - t_rhs.constant() - t_lhs.constant() - ) { - -} - -idol::impl::Row::Row(::idol::Expr &&t_lhs, const ::idol::Expr &t_rhs) - : m_impl( - std::move(t_lhs.linear()) - t_rhs.linear(), - std::move(t_lhs.quadratic()) - t_rhs.quadratic(), - t_rhs.constant() - t_lhs.constant() - ) { - -} - -idol::impl::Row::Row(const ::idol::Expr &t_lhs, ::idol::Expr &&t_rhs) - : m_impl( - t_lhs.linear() - t_rhs.linear(), - t_lhs.quadratic() - t_rhs.quadratic(), - t_rhs.constant() - t_lhs.constant() - ) { - -} - -idol::impl::Row::Row(const ::idol::Expr &t_lhs, const ::idol::Expr &t_rhs) - : m_impl( - t_lhs.linear() - t_rhs.linear(), - t_lhs.quadratic() - t_rhs.quadratic(), - t_rhs.constant() - t_lhs.constant() - ) { - -} diff --git a/lib/src/mixed-integer/modeling/models/KKT.cpp b/lib/src/mixed-integer/modeling/models/KKT.cpp index 0b346183..bbc44eec 100644 --- a/lib/src/mixed-integer/modeling/models/KKT.cpp +++ b/lib/src/mixed-integer/modeling/models/KKT.cpp @@ -4,6 +4,8 @@ #include "idol/mixed-integer/modeling/models/KKT.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" +#include "idol/mixed-integer/modeling/variables/TempVar.h" idol::Reformulators::KKT::KKT(const idol::Model &t_src_model, const idol::Bilevel::LowerLevelDescription &t_lower_level_description) @@ -22,14 +24,14 @@ void idol::Reformulators::KKT::add_primal_variables(idol::Model &t_destination) for (const auto& var : m_src_model.vars()) { if (m_description.is_follower(var)) { - t_destination.add(var, TempVar(-Inf, Inf, Continuous, Column())); + t_destination.add(var, TempVar(-Inf, Inf, Continuous, 0., LinExpr())); continue; } const auto lb = m_src_model.get_var_lb(var); const auto ub = m_src_model.get_var_ub(var); const auto type = m_src_model.get_var_type(var); - t_destination.add(var, TempVar(lb, ub, type, Column())); + t_destination.add(var, TempVar(lb, ub, type, 0., LinExpr())); } } @@ -39,7 +41,7 @@ void idol::Reformulators::KKT::add_primal_constraints(Model &t_destination) cons for (const auto& ctr : m_src_model.ctrs()) { const auto& row = m_src_model.get_ctr_row(ctr); const auto type = m_src_model.get_ctr_type(ctr); - t_destination.add(ctr, TempCtr(Row(row), type)); + t_destination.add(ctr, TempCtr(LinExpr(row), type, 0.)); } for (const auto& var : m_src_model.vars()) { @@ -84,7 +86,7 @@ void idol::Reformulators::KKT::create_dual_variables_for_constraints() { case GreaterOrEqual: lb = 0; ub = Inf; break; } - m_dual_variables_for_constraints[index] = Var(env, lb, ub, Continuous, "dual_" + ctr.name()); + m_dual_variables_for_constraints[index] = Var(env, lb, ub, Continuous, 0., "dual_" + ctr.name()); } @@ -107,11 +109,11 @@ void idol::Reformulators::KKT::create_dual_variables_for_bounds() { const auto index = m_src_model.get_var_index(var); if (!is_pos_inf(ub)) { - m_dual_variables_for_upper_bounds[index] = Var(env, -Inf, 0, Continuous, "dual_ub_" + var.name()); + m_dual_variables_for_upper_bounds[index] = Var(env, -Inf, 0, Continuous, 0., "dual_ub_" + var.name()); } if (!is_neg_inf(lb)) { - m_dual_variables_for_lower_bounds[index] = Var(env, 0, Inf, Continuous, "dual_lb_" + var.name()); + m_dual_variables_for_lower_bounds[index] = Var(env, 0, Inf, Continuous, 0., "dual_lb_" + var.name()); } } @@ -164,7 +166,7 @@ void idol::Reformulators::KKT::create_dual_constraint(const idol::Var &t_var) { Expr expr; - for (const auto& [ctr, constant] : col.linear()) { + for (const auto& [ctr, constant] : col) { if (m_description.is_leader(ctr)) { continue; @@ -176,6 +178,7 @@ void idol::Reformulators::KKT::create_dual_constraint(const idol::Var &t_var) { } + /* for (const auto& [pair, constant] : col.quadratic()) { const auto& ctr = pair.first; @@ -190,6 +193,7 @@ void idol::Reformulators::KKT::create_dual_constraint(const idol::Var &t_var) { expr += constant * dual_var * var; } + */ if (const auto dual_var = m_dual_variables_for_lower_bounds[index]; dual_var.has_value()) { expr += dual_var.value(); @@ -207,6 +211,9 @@ void idol::Reformulators::KKT::create_dual_constraint(const idol::Var &t_var) { void idol::Reformulators::KKT::create_complementarity_constraints() { + throw Exception("Complementarity constraints lead to quadratic constraints, which are not supported by the current implementation."); + + /* m_complementarity_constraints.resize(m_src_model.ctrs().size()); auto& env = m_src_model.env(); @@ -225,22 +232,20 @@ void idol::Reformulators::KKT::create_complementarity_constraints() { const auto index = m_src_model.get_ctr_index(ctr); const auto& dual_var = *m_dual_variables_for_constraints[index]; const auto& row = m_src_model.get_ctr_row(ctr); - - if (!row.quadratic().empty()) { - //throw Exception("Cannot write complementarity constraints for quadratic constraints."); - } + const double rhs = m_src_model.get_ctr_rhs(ctr); Expr expr; - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : row) { expr += constant * var * dual_var; } - expr -= row.rhs() * dual_var; + expr -= rhs * dual_var; m_complementarity_constraints[index] = Ctr(env, expr == 0, "complementarity_" + ctr.name()); } + */ } @@ -276,6 +281,9 @@ void idol::Reformulators::KKT::add_strong_duality_constraint(idol::Model &t_dest void idol::Reformulators::KKT::create_dual_objective() { + throw Exception("The dual objective leads to quadratic constraints, which are not supported by the current implementation."); + + /* for (const auto& ctr : m_src_model.ctrs()) { if (m_description.is_leader(ctr)) { @@ -285,15 +293,16 @@ void idol::Reformulators::KKT::create_dual_objective() { const auto index = m_src_model.get_ctr_index(ctr); const auto& dual_var = *m_dual_variables_for_constraints[index]; const auto& row = m_src_model.get_ctr_row(ctr); + const double rhs = m_src_model.get_ctr_rhs(ctr); - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : row) { if (m_description.is_follower(var)) { continue; } m_dual_objective -= constant * var * dual_var; } - m_dual_objective += row.rhs() * dual_var; + m_dual_objective += rhs * dual_var; } @@ -318,7 +327,7 @@ void idol::Reformulators::KKT::create_dual_objective() { } } - + */ } void idol::Reformulators::KKT::add_kkt_reformulation(idol::Model &t_destination) const { diff --git a/lib/src/mixed-integer/modeling/models/Model.cpp b/lib/src/mixed-integer/modeling/models/Model.cpp index a5a8655d..27e4e515 100644 --- a/lib/src/mixed-integer/modeling/models/Model.cpp +++ b/lib/src/mixed-integer/modeling/models/Model.cpp @@ -4,6 +4,7 @@ #include "idol/mixed-integer/modeling/models/Model.h" #include "idol/mixed-integer/modeling/objects/Env.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" idol::Model::Model(Env &t_env, Storage t_storage) : m_env(t_env), m_id(t_env.create_model_id()), m_storage(t_storage) {} @@ -46,9 +47,7 @@ void idol::Model::add(const Var &t_var, TempVar t_temp_var) { // TODO sort and reduce by index in the model - throw_if_unknown_object(t_temp_var.column().obj_quadratic()); - throw_if_unknown_object(t_temp_var.column().linear()); - throw_if_unknown_object(t_temp_var.column().quadratic()); + throw_if_unknown_object(t_temp_var.column()); m_env.create_version(*this, t_var, @@ -56,6 +55,7 @@ void idol::Model::add(const Var &t_var, TempVar t_temp_var) { t_temp_var.lb(), t_temp_var.ub(), t_temp_var.type(), + t_temp_var.obj(), std::move(t_temp_var.column()) ); @@ -66,7 +66,7 @@ void idol::Model::add(const Var &t_var, TempVar t_temp_var) { } const auto& column = get_var_column(t_var); - m_objective += column.obj() * t_var + t_var * column.obj_quadratic(); + m_objective += t_temp_var.obj() * t_var; if (m_storage == ColumnOriented && !m_has_minor_representation) { return; @@ -84,22 +84,13 @@ void idol::Model::add_column_to_rows(const idol::Var &t_var) { const auto& column = get_var_column(t_var); - for (const auto& [ctr, constant] : column.linear()) { + for (const auto& [ctr, constant] : column) { auto& version = m_env.version(*this, ctr); if (version.has_row()) { - version.row().linear().push_back(t_var, constant); + version.lhs().push_back(t_var, constant); } } - for (const auto& [pair, constant] : column.quadratic()) { - - auto& version = m_env.version(*this, pair.first); - if (version.has_row()) { - version.row().quadratic().push_back({ pair.second, t_var }, constant); - } - - } - } void idol::Model::add(const Var &t_var) { @@ -108,7 +99,8 @@ void idol::Model::add(const Var &t_var) { default_version.lb(), default_version.ub(), default_version.type(), - Column(default_version.column()) + default_version.obj(), + LinExpr(default_version.column()) )); } @@ -144,18 +136,21 @@ void idol::Model::remove(const Ctr &t_ctr) { void idol::Model::add(const Ctr &t_ctr, TempCtr t_temp_ctr) { - throw_if_unknown_object(t_temp_ctr.row().linear()); - throw_if_unknown_object(t_temp_ctr.row().quadratic()); + throw_if_unknown_object(t_temp_ctr.lhs()); - m_env.create_version(*this, t_ctr, m_constraints.size(), std::move(t_temp_ctr)); + m_env.create_version(*this, + t_ctr, + m_constraints.size(), + std::move(t_temp_ctr.lhs()), + t_temp_ctr.type(), + t_temp_ctr.rhs()); m_constraints.emplace_back(t_ctr); if (has_optimizer()) { optimizer().add(t_ctr); } - const auto& row = get_ctr_row(t_ctr); - m_rhs += row.rhs() * t_ctr; + const auto& lhs = get_ctr_row(t_ctr); if (m_storage == RowOriented && !m_has_minor_representation) { return; @@ -171,36 +166,25 @@ void idol::Model::add(const Ctr &t_ctr, TempCtr t_temp_ctr) { void idol::Model::add_row_to_columns(const idol::Ctr &t_ctr) { - const auto& row = get_ctr_row(t_ctr); + const auto& lhs = get_ctr_row(t_ctr); - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : lhs) { auto& version = m_env.version(*this, var); if (version.has_column()) { - version.column().linear().push_back(t_ctr, constant); - } - } - - for (const auto& [pair, constant] : row.quadratic()) { - - auto& version1 = m_env.version(*this, pair.first); - if (version1.has_column()) { - version1.column().quadratic().push_back({ t_ctr, pair.second }, constant); - } - - auto& version2 = m_env.version(*this, pair.second); - if (version2.has_column()) { - version2.column().quadratic().push_back({ t_ctr, pair.first }, constant); + version.column().push_back(t_ctr, constant); } - } } void idol::Model::add(const Ctr &t_ctr) { const auto& default_version = m_env[t_ctr]; - add(t_ctr, TempCtr( - Row(default_version.row()), - default_version.type()) + add(t_ctr, + TempCtr( + LinExpr(default_version.lhs()), + default_version.type(), + default_version.rhs() + ) ); } @@ -217,10 +201,13 @@ const idol::LinExpr &idol::Model::get_rhs_expr() const { } double idol::Model::get_mat_coeff(const Ctr &t_ctr, const Var &t_var) const { - return m_env.version(*this, t_ctr).row().linear().get(t_var); + if (m_storage == Storage::ColumnOriented) { + return m_env.version(*this, t_var).column().get(t_ctr); + } + return m_env.version(*this, t_ctr).lhs().get(t_var); } -const idol::Row &idol::Model::get_ctr_row(const Ctr &t_ctr) const { +idol::LinExpr idol::Model::get_ctr_row(const Ctr &t_ctr) const { auto& version = m_env.version(*this, t_ctr); if (!version.has_row()) { @@ -228,7 +215,7 @@ const idol::Row &idol::Model::get_ctr_row(const Ctr &t_ctr) const { m_has_minor_representation = true; } - return version.row(); + return version.lhs(); } idol::CtrType idol::Model::get_ctr_type(const Ctr &t_ctr) const { @@ -247,7 +234,7 @@ double idol::Model::get_var_ub(const Var &t_var) const { return m_env.version(*this, t_var).ub(); } -const idol::Column &idol::Model::get_var_column(const Var &t_var) const { +const idol::LinExpr &idol::Model::get_var_column(const Var &t_var) const { auto& version = m_env.version(*this, t_var); if (!version.has_column()) { @@ -280,30 +267,63 @@ idol::Model* idol::Model::clone() const { idol::Model::Model(const Model& t_src) : Model(t_src.m_env) { + /** + * TODO: here, it would be more efficient to directly copy the data from the source model + * To do this, we need to add a method to the Env + */ + reserve_vars(t_src.vars().size()); reserve_ctrs(t_src.ctrs().size()); - for (const auto& var : t_src.vars()) { - add(var, TempVar( - t_src.get_var_lb(var), - t_src.get_var_ub(var), - t_src.get_var_type(var), - Column() - )); - } + m_storage = t_src.m_storage; - for (const auto& ctr : t_src.ctrs()) { - add(ctr, TempCtr( - Row(t_src.get_ctr_row(ctr)), - t_src.get_ctr_type(ctr) - )); - } + if (t_src.m_storage == Both || t_src.m_storage == RowOriented) { - set_obj_sense(t_src.get_obj_sense()); - set_obj_expr(t_src.get_obj_expr()); + for (const auto& var : t_src.vars()) { + add(var, TempVar( + t_src.get_var_lb(var), + t_src.get_var_ub(var), + t_src.get_var_type(var), + t_src.get_var_obj(var), + LinExpr() + )); + } - // TODO set storage to initial value - throw Exception("Model. Work in progress..."); + for (const auto& ctr : t_src.ctrs()) { + add(ctr, TempCtr( + t_src.get_ctr_row(ctr), + t_src.get_ctr_type(ctr), + t_src.get_ctr_rhs(ctr) + )); + } + + set_obj_sense(t_src.get_obj_sense()); + set_obj_expr(t_src.get_obj_expr()); + + } else { + + for (const auto& ctr : t_src.ctrs()) { + add(ctr, TempCtr( + LinExpr(), + t_src.get_ctr_type(ctr), + t_src.get_ctr_rhs(ctr) + )); + } + + for (const auto& var : t_src.vars()) { + add(var, TempVar( + t_src.get_var_lb(var), + t_src.get_var_ub(var), + t_src.get_var_type(var), + t_src.get_var_obj(var), + LinExpr(t_src.get_var_column(var)) + )); + } + + set_obj_sense(t_src.get_obj_sense()); + set_obj_expr(t_src.get_obj_expr()); + + } if (t_src.m_optimizer_factory) { use(*t_src.m_optimizer_factory); @@ -390,8 +410,9 @@ void idol::Model::set_obj_expr(const Expr &t_objective) { void idol::Model::set_obj_expr(Expr &&t_objective) { - //replace_objective(Expr(t_objective)); - throw Exception("Model. Work in progress..."); + throw_if_unknown_object(t_objective.linear()); + + m_objective = std::move(t_objective); if (has_optimizer()) { optimizer().update_obj(); @@ -405,6 +426,8 @@ void idol::Model::set_rhs_expr(const LinExpr &t_rhs) { void idol::Model::set_rhs_expr(LinExpr &&t_rhs) { + throw_if_unknown_object(t_rhs); + //replace_right_handside(LinExpr(t_rhs)); throw Exception("Model. Work in progress..."); @@ -459,12 +482,13 @@ void idol::Model::set_ctr_type(const Ctr &t_ctr, CtrType t_type) { } -void idol::Model::set_ctr_row(const Ctr &t_ctr, const Row &t_row) { - set_ctr_row(t_ctr, Row(t_row)); +void idol::Model::set_ctr_row(const Ctr &t_ctr, const LinExpr &t_row) { + set_ctr_row(t_ctr, LinExpr(t_row)); } -void idol::Model::set_ctr_row(const Ctr &t_ctr, Row &&t_row) { +void idol::Model::set_ctr_row(const Ctr &t_ctr, LinExpr &&t_row) { + /* Row old_row; // TODO: Do this properly @@ -476,16 +500,17 @@ void idol::Model::set_ctr_row(const Ctr &t_ctr, Row &&t_row) { } } - + */ throw Exception("Model. Work in progress..."); //remove_row_from_columns(t_ctr); - m_env.version(*this, t_ctr).row() = std::move(t_row); + //m_env.version(*this, t_ctr).row() = std::move(t_row); throw Exception("Model. Work in progress..."); //add_row_to_columns(t_ctr); // TODO: Do this properly + /* if (has_optimizer()) { optimizer().update(); @@ -494,13 +519,13 @@ void idol::Model::set_ctr_row(const Ctr &t_ctr, Row &&t_row) { optimizer().update_mat_coeff(t_ctr, var); } - for (const auto& [var, constant] : get_ctr_row(t_ctr).linear()) { + for (const auto& [var, constant] : get_ctr_row(t_ctr)) { optimizer().update_mat_coeff(t_ctr, var); } optimizer().update_ctr_rhs(t_ctr); } - + */ } void idol::Model::set_var_type(const Var &t_var, VarType t_type) { @@ -544,11 +569,11 @@ void idol::Model::set_var_obj(const Var &t_var, double t_obj) { } -void idol::Model::set_var_column(const Var &t_var, const Column &t_column) { - set_var_column(t_var, Column(t_column)); +void idol::Model::set_var_column(const Var &t_var, const LinExpr &t_column) { + set_var_column(t_var, LinExpr(t_column)); } -void idol::Model::set_var_column(const Var &t_var, Column &&t_column) { +void idol::Model::set_var_column(const Var &t_var, LinExpr &&t_column) { throw Exception("Model. Work in progress..."); //remove_column_from_rows(t_var); @@ -564,18 +589,18 @@ void idol::Model::set_var_column(const Var &t_var, Column &&t_column) { } -idol::Var idol::Model::add_var(double t_lb, double t_ub, VarType t_type, std::string t_name) { - return add_var(t_lb, t_ub, t_type, Column(), std::move(t_name)); +idol::Var idol::Model::add_var(double t_lb, double t_ub, VarType t_type, double t_obj, std::string t_name) { + return add_var(t_lb, t_ub, t_type, t_obj, LinExpr(), std::move(t_name)); } -idol::Var idol::Model::add_var(double t_lb, double t_ub, VarType t_type, Column t_column, std::string t_name) { - Var result(m_env, t_lb, t_ub, t_type, std::move(t_column), std::move(t_name)); +idol::Var idol::Model::add_var(double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr t_column, std::string t_name) { + Var result(m_env, t_lb, t_ub, t_type, t_obj, std::move(t_column), std::move(t_name)); add(result); return result; } -idol::Ctr idol::Model::add_ctr(Row &&t_row, CtrType t_type, std::string t_name) { - return add_ctr(TempCtr(std::move(t_row), t_type), std::move(t_name)); +idol::Ctr idol::Model::add_ctr(LinExpr &&t_row, CtrType t_type, double t_rhs, std::string t_name) { + return add_ctr(TempCtr(std::move(t_row), t_type, t_rhs), std::move(t_name)); } idol::Ctr idol::Model::add_ctr(TempCtr t_temp_ctr, std::string t_name) { @@ -622,58 +647,33 @@ double idol::Model::get_var_reduced_cost(const idol::Var &t_var) const { void idol::Model::build_row(const idol::Ctr &t_ctr) { - Row row; + LinExpr lhs; for (const auto& var : vars()) { const auto& column = get_var_column(var); - const double value = column.linear().get(t_ctr); - row.linear().push_back(var, value); - if (!row.quadratic().empty()) { - throw Exception("Building a row with quadratic terms is not implemented."); - } + const double value = column.get(t_ctr); + lhs.push_back(var, value); } - row.set_rhs(m_rhs.get(t_ctr)); - row.linear().sparsify(); - row.quadratic().sparsify(); + lhs.sparsify(); - m_env.version(*this, t_ctr).set_row(std::move(row)); + m_env.version(*this, t_ctr).set_row(std::move(lhs)); } void idol::Model::build_column(const idol::Var &t_var) { - Column column; + LinExpr column; for (const auto& ctr : ctrs()) { - const auto& row = get_ctr_row(ctr); - column.linear().push_back(ctr, row.linear().get(t_var)); - if (!column.quadratic().empty()) { - throw Exception("Building a column with quadratic terms is not implemented."); - } - } - column.set_obj(m_objective.linear().get(t_var)); - if (!column.obj_quadratic().empty()) { - throw Exception("Building a column with quadratic terms is not implemented."); + const auto& lhs = get_ctr_row(ctr); + column.push_back(ctr, lhs.get(t_var)); } - column.linear().sparsify(); - column.quadratic().sparsify(); + column.sparsify(); m_env.version(*this, t_var).set_column(std::move(column)); } -template -void idol::Model::throw_if_unknown_object(const idol::QuadExpr &t_expr) { - for (const auto& [pair, constant] : t_expr) { - if (!has(pair.first)) { - throw Exception("Object " + pair.first.name() + " is not part of the model."); - } - if (!has(pair.second)) { - throw Exception("Object " + pair.second.name() + " is not part of the model."); - } - } -} - template void idol::Model::throw_if_unknown_object(const idol::LinExpr &t_expr) { for (const auto& [obj, constant] : t_expr) { @@ -713,7 +713,7 @@ void idol::Model::dump(std::ostream &t_os) const { for (const auto& var : vars()) { auto& version = m_env.version(*this, var); if (version.has_column()) { - const auto& linear = version.column().linear(); + const auto& linear = version.column(); if (linear.has_index(ctr)) { t_os << std::setw(cell_width) << linear.get(ctr); } else { @@ -741,7 +741,7 @@ void idol::Model::dump(std::ostream &t_os) const { for (const auto& var : vars()) { auto& version = m_env.version(*this, ctr); if (version.has_row()) { - const auto& linear = version.row().linear(); + const auto& linear = version.lhs(); if (linear.has_index(var)) { t_os << std::setw(cell_width) << linear.get(var); } else { @@ -830,3 +830,11 @@ void idol::Model::build_columns() { } } } + +double idol::Model::get_var_obj(const idol::Var &t_var) const { + return get_obj_expr().linear().get(t_var); +} + +double idol::Model::get_ctr_rhs(const idol::Ctr &t_ctr) const { + return get_rhs_expr().get(t_ctr); +} diff --git a/lib/src/mixed-integer/modeling/variables/Var.cpp b/lib/src/mixed-integer/modeling/variables/Var.cpp index e54a5df4..af86cc2d 100644 --- a/lib/src/mixed-integer/modeling/variables/Var.cpp +++ b/lib/src/mixed-integer/modeling/variables/Var.cpp @@ -4,17 +4,17 @@ #include "idol/mixed-integer/modeling/variables/Var.h" #include "idol/mixed-integer/modeling/objects/Env.h" -idol::Var::Var(Env &t_env, double t_lb, double t_ub, VarType t_type, Column &&t_column, std::string t_name) - : Object(t_env.create_var(std::move(t_name), TempVar(t_lb, t_ub, t_type, std::move(t_column)))) { +idol::Var::Var(Env &t_env, double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr &&t_column, std::string t_name) + : Object(t_env.create_var(std::move(t_name), TempVar(t_lb, t_ub, t_type, t_obj, std::move(t_column)))) { } -idol::Var::Var(Env &t_env, double t_lb, double t_ub, VarType t_type, std::string t_name) - : Var(t_env, t_lb, t_ub, t_type, Column(0.), std::move(t_name)) { +idol::Var::Var(Env &t_env, double t_lb, double t_ub, VarType t_type, double t_obj, std::string t_name) + : Var(t_env, t_lb, t_ub, t_type, t_obj, LinExpr(), std::move(t_name)) { } -idol::Var::Var(Env &t_env, double t_lb, double t_ub, VarType t_type, const Column &t_column, std::string t_name) - : Var(t_env, t_lb, t_ub, t_type, Column(t_column), std::move(t_name)) { +idol::Var::Var(Env &t_env, double t_lb, double t_ub, VarType t_type, double t_obj, const LinExpr &t_column, std::string t_name) + : Var(t_env, t_lb, t_ub, t_type, t_obj, LinExpr(t_column), std::move(t_name)) { } diff --git a/lib/src/mixed-integer/modeling/variables/VarVersion.cpp b/lib/src/mixed-integer/modeling/variables/VarVersion.cpp new file mode 100644 index 00000000..40e236c7 --- /dev/null +++ b/lib/src/mixed-integer/modeling/variables/VarVersion.cpp @@ -0,0 +1,47 @@ +// +// Created by henri on 28.10.24. +// +#include "idol/mixed-integer/modeling/variables/VarVersion.h" +#include "idol/mixed-integer/modeling/variables/TempVar.h" + +idol::VarVersion::VarVersion(unsigned int t_index, double t_lb, double t_ub, VarType t_type, double t_obj, LinExpr &&t_column) + : Version(t_index), + m_lb(t_lb), + m_ub(t_ub), + m_type(t_type), + m_obj(t_obj), + m_column(std::make_unique>(std::move(t_column))) { + +} + +idol::VarVersion::VarVersion(unsigned int t_index, idol::TempVar &&t_temp_var) + : VarVersion( + t_index, + t_temp_var.lb(), + t_temp_var.ub(), + t_temp_var.type(), + t_temp_var.obj(), + std::move(t_temp_var.column())) { + +} + +idol::VarVersion::VarVersion(unsigned int t_index, const idol::TempVar &t_temp_var) + : VarVersion( + t_index, + t_temp_var.lb(), + t_temp_var.ub(), + t_temp_var.type(), + t_temp_var.obj(), + LinExpr(t_temp_var.column())) { + +} + +idol::VarVersion::VarVersion(const idol::VarVersion &t_other) + : Version(t_other), + m_lb(t_other.m_lb), + m_ub(t_other.m_ub), + m_type(t_other.m_type), + m_obj(t_other.m_obj), + m_column(t_other.m_column ? std::make_unique>(*t_other.m_column) : nullptr) { + +} diff --git a/lib/src/mixed-integer/optimizers/callbacks/CutSeparation.cpp b/lib/src/mixed-integer/optimizers/callbacks/CutSeparation.cpp index 12f65b57..95bb9c0e 100644 --- a/lib/src/mixed-integer/optimizers/callbacks/CutSeparation.cpp +++ b/lib/src/mixed-integer/optimizers/callbacks/CutSeparation.cpp @@ -12,10 +12,6 @@ idol::impl::CutSeparation::CutSeparation(CallbackEvent t_triggering_event, m_separation_problem(t_separation_problem), m_cut(std::move(t_cut)) { - if (!m_cut.row().quadratic().empty()) { - throw Exception("Adding non-linear cut is not available."); - } - if (m_cut.type() == Equal) { throw Exception("Separating equality constraints is not available."); } diff --git a/lib/src/mixed-integer/optimizers/callbacks/heuristics/LocalBranching.cpp b/lib/src/mixed-integer/optimizers/callbacks/heuristics/LocalBranching.cpp index 1e39c440..ea2ca404 100644 --- a/lib/src/mixed-integer/optimizers/callbacks/heuristics/LocalBranching.cpp +++ b/lib/src/mixed-integer/optimizers/callbacks/heuristics/LocalBranching.cpp @@ -4,6 +4,7 @@ #include "idol/mixed-integer/optimizers/callbacks/heuristics/LocalBranching.h" #include "idol/mixed-integer/modeling/models/Model.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" idol::Heuristics::LocalBranching::LocalBranching(const LocalBranching& t_src) : m_optimizer_factory(t_src.m_optimizer_factory->clone()), diff --git a/lib/src/mixed-integer/optimizers/callbacks/heuristics/SimpleRounding.cpp b/lib/src/mixed-integer/optimizers/callbacks/heuristics/SimpleRounding.cpp index a2f514fe..ba5ccf89 100644 --- a/lib/src/mixed-integer/optimizers/callbacks/heuristics/SimpleRounding.cpp +++ b/lib/src/mixed-integer/optimizers/callbacks/heuristics/SimpleRounding.cpp @@ -24,12 +24,8 @@ void idol::Heuristics::SimpleRounding::Strategy::operator()(CallbackEvent t_even const auto& column = model.get_var_column(var); - if (!column.quadratic().empty()) { - throw Exception("SimpleRounding for quadratic problems is not implemented."); - } - std::optional is_trivially_up_roundable; // The name assumes <= constraints - for (const auto& [ctr, coefficient] : column.linear()) { + for (const auto& [ctr, coefficient] : column) { const auto type = model.get_ctr_type(ctr); diff --git a/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp b/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp index a5154842..31167dfa 100644 --- a/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp +++ b/lib/src/mixed-integer/optimizers/dantzig-wolfe/Formulation.cpp @@ -6,6 +6,7 @@ #include "idol/mixed-integer/optimizers/dantzig-wolfe/Formulation.h" #include "idol/mixed-integer/modeling/objects/Env.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" idol::DantzigWolfe::Formulation::Formulation(const idol::Model &t_original_formulation, idol::Annotation t_ctr_decomposition, @@ -104,14 +105,16 @@ void idol::DantzigWolfe::Formulation::set_decomposition_by_var(const Model& t_or const auto &row = t_original_formulation.get_ctr_row(ctr); - for (const auto &[var, constant]: row.linear()) { + for (const auto &[var, constant]: row) { set_decomposition_by_var(var, sub_problem_id); } + /* for (const auto &[vars, constant]: row.quadratic()) { set_decomposition_by_var(vars.first, sub_problem_id); set_decomposition_by_var(vars.second, sub_problem_id); } + */ } @@ -130,7 +133,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); } @@ -160,7 +163,7 @@ void idol::DantzigWolfe::Formulation::dispatch_variables(const Model& t_original continue; } - model.add(var, TempVar(lb, ub, type, Column())); + model.add(var, TempVar(lb, ub, type, 0., LinExpr())); } @@ -181,7 +184,7 @@ void idol::DantzigWolfe::Formulation::dispatch_constraints(const idol::Model &t_ if (sub_problem_id == MasterId) { dispatch_linking_constraint(ctr, row, type); } else { - m_sub_problems[sub_problem_id].add(ctr, TempCtr(Row(row), type)); + m_sub_problems[sub_problem_id].add(ctr, TempCtr(LinExpr(row), type, 0)); } } @@ -189,7 +192,7 @@ void idol::DantzigWolfe::Formulation::dispatch_constraints(const idol::Model &t_ } void idol::DantzigWolfe::Formulation::dispatch_linking_constraint(const idol::Ctr &t_original_ctr, - const idol::Row &t_row, + const idol::LinExpr &t_row, idol::CtrType t_type) { throw Exception("TODO: Was using Constant"); /* @@ -207,7 +210,7 @@ void idol::DantzigWolfe::Formulation::dispatch_linking_constraint(const idol::Ct } std::pair, std::vector> -idol::DantzigWolfe::Formulation::decompose_expression(const LinExpr &t_linear, const QuadExpr& t_quadratic) { +idol::DantzigWolfe::Formulation::decompose_expression(const LinExpr &t_linear /*, const QuadExpr& t_quadratic */) { const unsigned int n_sub_problems = m_sub_problems.size(); @@ -227,6 +230,7 @@ idol::DantzigWolfe::Formulation::decompose_expression(const LinExpr &t_line } + /* for (const auto& [vars, constant] : t_quadratic) { const unsigned int sub_problem_id1 = vars.first.get(m_decomposition_by_var); @@ -244,6 +248,7 @@ idol::DantzigWolfe::Formulation::decompose_expression(const LinExpr &t_line sub_problem_parts[sub_problem_id1] += constant * (!vars.first * !vars.second); } + */ return std::make_pair( std::move(master_part), @@ -302,7 +307,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].linear().set(lower, 1); + m_generation_patterns[t_sub_problem_id].set(lower, 1); } @@ -310,7 +315,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].linear().set(upper, 1); + m_generation_patterns[t_sub_problem_id].set(upper, 1); } @@ -447,6 +452,8 @@ double idol::DantzigWolfe::Formulation::get_original_space_var_primal(const idol void idol::DantzigWolfe::Formulation::update_var_lb(const idol::Var &t_var, double t_lb, bool t_hard, bool t_remove_infeasible_columns) { + throw Exception("TODO: Was using Row::is_violated"); + /* const unsigned int sub_problem_id = t_var.get(m_decomposition_by_var); if (sub_problem_id == MasterId) { @@ -466,11 +473,13 @@ void idol::DantzigWolfe::Formulation::update_var_lb(const idol::Var &t_var, doub } apply_sub_problem_bound_on_master(true, t_var, sub_problem_id, t_lb); - + */ } void idol::DantzigWolfe::Formulation::update_var_ub(const idol::Var &t_var, double t_ub, bool t_hard, bool t_remove_infeasible_columns) { + throw Exception("TODO: Was using Row::is_violated"); + /* const unsigned int sub_problem_id = t_var.get(m_decomposition_by_var); if (sub_problem_id == MasterId) { @@ -490,7 +499,7 @@ void idol::DantzigWolfe::Formulation::update_var_ub(const idol::Var &t_var, doub } apply_sub_problem_bound_on_master(false, t_var, sub_problem_id, t_ub); - + */ } void idol::DantzigWolfe::Formulation::apply_sub_problem_bound_on_master(bool t_is_lb, @@ -640,8 +649,10 @@ void idol::DantzigWolfe::Formulation::add(const idol::Var &t_var, double t_lb, double t_ub, idol::VarType t_type, - const idol::Column &t_column) { + const idol::LinExpr &t_column) { + throw Exception("TODO Was using Column::obj"); + /* const auto sub_problem_id = t_var.get(m_decomposition_by_var); if (sub_problem_id == MasterId) { @@ -650,10 +661,10 @@ void idol::DantzigWolfe::Formulation::add(const idol::Var &t_var, } m_sub_problems[sub_problem_id].add(t_var, TempVar(t_lb, t_ub, t_type, Column(t_column))); - + */ } -void idol::DantzigWolfe::Formulation::add(const idol::Ctr &t_ctr, idol::CtrType t_type, const idol::Row &t_row) { +void idol::DantzigWolfe::Formulation::add(const idol::Ctr &t_ctr, idol::CtrType t_type, const idol::LinExpr &t_row) { throw Exception("TODO: Was using Constant"); /* @@ -710,7 +721,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].linear().set(t_ctr, 0.); + m_generation_patterns[sub_problem_id].set(t_ctr, 0.); } @@ -758,6 +769,8 @@ void idol::DantzigWolfe::Formulation::load_columns_from_pool() { bool idol::DantzigWolfe::Formulation::is_feasible(const idol::PrimalPoint &t_primal, unsigned int t_sub_problem_id) { + throw Exception("TODO: Was using Row::is_violated"); + /* const auto& model = m_sub_problems[t_sub_problem_id]; // Check bounds @@ -788,6 +801,7 @@ idol::DantzigWolfe::Formulation::is_feasible(const idol::PrimalPoint &t_primal, } return true; + */ } void idol::DantzigWolfe::Formulation::add_sub_problem() { diff --git a/lib/src/mixed-integer/optimizers/dantzig-wolfe/Optimizers_DantzigWolfeDecomposition.cpp b/lib/src/mixed-integer/optimizers/dantzig-wolfe/Optimizers_DantzigWolfeDecomposition.cpp index 86aaabaf..e76418a8 100644 --- a/lib/src/mixed-integer/optimizers/dantzig-wolfe/Optimizers_DantzigWolfeDecomposition.cpp +++ b/lib/src/mixed-integer/optimizers/dantzig-wolfe/Optimizers_DantzigWolfeDecomposition.cpp @@ -89,10 +89,13 @@ void idol::Optimizers::DantzigWolfeDecomposition::add(const idol::Var &t_var) { } void idol::Optimizers::DantzigWolfeDecomposition::add(const idol::Ctr &t_ctr) { + throw Exception("Work in progress: was using Row"); + /* const auto& parent = this->parent(); const auto type = parent.get_ctr_type(t_ctr); const auto& row = parent.get_ctr_row(t_ctr); m_formulation.add(t_ctr, type, row); + */ } void idol::Optimizers::DantzigWolfeDecomposition::remove(const idol::Var &t_var) { @@ -209,7 +212,7 @@ void idol::Optimizers::DantzigWolfeDecomposition::update_var_ub(const idol::Var } void idol::Optimizers::DantzigWolfeDecomposition::update_var_obj(const idol::Var &t_var) { - m_formulation.update_var_obj(t_var, parent().get_var_column(t_var).obj()); + m_formulation.update_var_obj(t_var, parent().get_var_obj(t_var)); } double idol::Optimizers::DantzigWolfeDecomposition::get_var_reduced_cost(const idol::Var &t_var) const { diff --git a/lib/src/mixed-integer/optimizers/dantzig-wolfe/infeasibility-strategies/ArtificialCosts.cpp b/lib/src/mixed-integer/optimizers/dantzig-wolfe/infeasibility-strategies/ArtificialCosts.cpp index b19595b3..ef073ed6 100644 --- a/lib/src/mixed-integer/optimizers/dantzig-wolfe/infeasibility-strategies/ArtificialCosts.cpp +++ b/lib/src/mixed-integer/optimizers/dantzig-wolfe/infeasibility-strategies/ArtificialCosts.cpp @@ -118,9 +118,9 @@ void idol::DantzigWolfe::ArtificialCosts::Strategy::create_artificial_variables( auto& master = t_formulation.master(); const auto add_artificial_variable = [&](const Ctr& t_ctr, double t_coeff) { - Column column(m_initial_costs); - column.linear().set(t_ctr, t_coeff); - auto var = master.add_var(0., Inf, Continuous, std::move(column)); + LinExpr column; + column.set(t_ctr, t_coeff); + auto var = master.add_var(0., Inf, Continuous, m_initial_costs, std::move(column)); m_artificial_variables.emplace_back(var); return var; }; @@ -184,7 +184,7 @@ void idol::DantzigWolfe::ArtificialCosts::Strategy::update_objective_function( for (const auto& var : m_artificial_variables) { if (!equals(t_primal_values.get(var), 0., Tolerance::Feasibility)) { - const double current_cost = master.get_var_column(var).obj(); + const double current_cost = master.get_var_obj(var); master.set_var_obj(var, m_update_factor * current_cost); } } diff --git a/lib/src/mixed-integer/optimizers/padm/Formulation.cpp b/lib/src/mixed-integer/optimizers/padm/Formulation.cpp index f895b822..d99ea4ab 100644 --- a/lib/src/mixed-integer/optimizers/padm/Formulation.cpp +++ b/lib/src/mixed-integer/optimizers/padm/Formulation.cpp @@ -6,6 +6,8 @@ #include "idol/mixed-integer/modeling/objects/Versions.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" #include "idol/mixed-integer/optimizers/padm/PenaltyUpdates.h" +#include "idol/mixed-integer/modeling/variables/TempVar.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" #include @@ -89,13 +91,13 @@ void idol::ADM::Formulation::dispatch_vars(const idol::Model &t_src_model) { if (sub_problem_id == -1) { for (unsigned int i = 0 ; i < n_sub_problems ; ++i) { - m_sub_problems[i].add(var, TempVar(lb, ub, type, Column())); + m_sub_problems[i].add(var, TempVar(lb, ub, type, 0.,LinExpr())); } continue; } - m_sub_problems[sub_problem_id].add(var, TempVar(lb, ub, type, Column())); + m_sub_problems[sub_problem_id].add(var, TempVar(lb, ub, type, 0., LinExpr())); } @@ -116,12 +118,13 @@ void idol::ADM::Formulation::dispatch_ctrs(const idol::Model &t_src_model) { void idol::ADM::Formulation::dispatch_ctr(const idol::Model &t_src_model, const idol::Ctr &t_ctr, unsigned int t_sub_problem_id) { const auto& row = t_src_model.get_ctr_row(t_ctr); + 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.linear(), row.quadratic(), t_sub_problem_id); - pattern.constant() -= row.rhs(); + auto [pattern, is_pure] = dispatch(t_src_model, row, /* row.quadratic(), */ t_sub_problem_id); + pattern.constant() -= rhs; - if (pattern.linear().empty() && pattern.quadratic().empty()) { + if (pattern.linear().empty()) { return; } @@ -139,8 +142,8 @@ void idol::ADM::Formulation::dispatch_ctr(const idol::Model &t_src_model, const switch (type) { case Equal: { auto var = add_l1_var(0); - auto var_minus = model.add_var(0, Inf, Continuous, var.name() + "_minus"); - auto var_plus = model.add_var(0, Inf, Continuous, var.name() + "_plus"); + auto var_minus = model.add_var(0, Inf, Continuous, 0., var.name() + "_minus"); + auto var_plus = model.add_var(0, Inf, Continuous, 0., var.name() + "_plus"); model.add_ctr(var == var_plus + var_minus); pattern.linear() += var_plus - var_minus; break; @@ -155,9 +158,9 @@ void idol::ADM::Formulation::dispatch_ctr(const idol::Model &t_src_model, const } if (is_pure) { - m_sub_problems[t_sub_problem_id].add(t_ctr, TempCtr(Row(std::move(pattern), 0), type)); + m_sub_problems[t_sub_problem_id].add(t_ctr, TempCtr(std::move(pattern.linear()), type, 0)); } else { - m_sub_problems[t_sub_problem_id].add(t_ctr, TempCtr(Row(), type)); + m_sub_problems[t_sub_problem_id].add(t_ctr, TempCtr(LinExpr(), type, 0)); m_constraint_patterns[t_sub_problem_id].emplace_back(t_ctr, std::move(pattern)); } @@ -176,7 +179,7 @@ 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, + // const idol::QuadExpr &t_quad_expr, unsigned int t_sub_problem_id) { throw Exception("TODO: Was using Constant"); @@ -239,10 +242,10 @@ void idol::ADM::Formulation::dispatch_obj(const Model &t_src_model, unsigned int t_sub_problem_id) { const auto& obj = t_src_model.get_obj_expr(); - auto [pattern, is_pure] = dispatch(t_src_model, obj.linear(), obj.quadratic(), t_sub_problem_id); + auto [pattern, is_pure] = dispatch(t_src_model, obj.linear() /*, obj.quadratic() */, t_sub_problem_id); pattern += obj.constant(); - if (pattern.linear().empty() && pattern.quadratic().empty()) { + if (pattern.linear().empty()) { return; } @@ -267,11 +270,8 @@ void idol::ADM::Formulation::fix_sub_problem(unsigned int t_sub_problem_id, lhs += fix(coefficient, t_primals) * var; } - for (const auto& [vars, coefficient] : pattern.quadratic()) { - lhs += fix(coefficient, t_primals) * vars.first * vars.second; - } - - m_sub_problems[t_sub_problem_id].set_ctr_row(ctr, Row(std::move(lhs), 0)); + m_sub_problems[t_sub_problem_id].set_ctr_row(ctr, LinExpr(std::move(lhs.linear()))); + m_sub_problems[t_sub_problem_id].set_ctr_rhs(ctr, -lhs.constant()); } // Objective @@ -283,9 +283,6 @@ void idol::ADM::Formulation::fix_sub_problem(unsigned int t_sub_problem_id, obj += fix(coefficient, t_primals) * var; } - for (const auto& [vars, coefficient] : obj_pattern.quadratic()) { - obj += fix(coefficient, t_primals) * vars.first * vars.second; - } m_sub_problems[t_sub_problem_id].set_obj_expr(std::move(obj)); } @@ -348,7 +345,7 @@ idol::ADM::Formulation::update_penalty_parameters(const std::vector if (const double val = t_primals[i].get(var); val > max) { max = val; argmax = i; - penalty = m_sub_problems[i].get_var_column(var).obj(); + penalty = m_sub_problems[i].get_var_obj(var); } } @@ -386,7 +383,7 @@ idol::Var idol::ADM::Formulation::get_or_create_l1_var(const idol::Ctr &t_ctr) { } auto& env = m_sub_problems.front().env(); - Var var (env, 0, Inf, Continuous, Column(), "l1_norm_" + t_ctr.name()); + Var var (env, 0, Inf, Continuous, 0., LinExpr(), "l1_norm_" + t_ctr.name()); m_l1_vars.emplace_hint(it, t_ctr, var); return var; @@ -426,7 +423,7 @@ void idol::ADM::Formulation::update_penalty_parameters_independently(const std:: for (const auto& var : m_l1_vars_in_sub_problem[i]) { - const double current_penalty = model.get_var_column(var).obj(); + const double current_penalty = model.get_var_obj(var); if (t_primals[i].get(var) > 1e-4) { model.set_var_obj(var, t_penalty_update(current_penalty)); diff --git a/lib/src/mixed-integer/optimizers/padm/Optimizers_PADM.cpp b/lib/src/mixed-integer/optimizers/padm/Optimizers_PADM.cpp index 2b2a2ab5..a4939afa 100644 --- a/lib/src/mixed-integer/optimizers/padm/Optimizers_PADM.cpp +++ b/lib/src/mixed-integer/optimizers/padm/Optimizers_PADM.cpp @@ -428,9 +428,11 @@ void idol::Optimizers::PADM::compute_objective_value() { result += constant * get_var_primal(var); } + /* for (const auto& [vars, constant] : obj.quadratic()) { result += constant * get_var_primal(vars.first) * get_var_primal(vars.second); } + */ set_best_obj(result); diff --git a/lib/src/mixed-integer/optimizers/wrappers/GLPK/Optimizers_GLPK.cpp b/lib/src/mixed-integer/optimizers/wrappers/GLPK/Optimizers_GLPK.cpp index 1468e145..d39d9b08 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/GLPK/Optimizers_GLPK.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/GLPK/Optimizers_GLPK.cpp @@ -27,10 +27,6 @@ void idol::Optimizers::GLPK::hook_build() { const auto& objective = parent().get_obj_expr(); - if (!objective.quadratic().empty()) { - throw Exception("GLPK is not available as an SOCP solver."); - } - hook_update_objective_sense(); set_objective_as_updated(); set_rhs_as_updated(); @@ -91,24 +87,21 @@ int idol::Optimizers::GLPK::hook_add(const Var &t_var, bool t_add_column) { const double lb = parent().get_var_lb(t_var); const double ub = parent().get_var_ub(t_var); const auto& column = parent().get_var_column(t_var); + const double obj = parent().get_var_obj(t_var); const auto type = parent().get_var_type(t_var); - set_var_attr(index, type, lb, ub, column.obj()); + set_var_attr(index, type, lb, ub, obj); glp_set_col_name(m_model, index, t_var.name().c_str()); if (t_add_column) { - if (!column.quadratic().empty()) { - throw Exception("GLPK cannot handle quadratic expressions."); - } - - const auto n = (int) column.linear().size(); + const auto n = (int) column.size(); auto* coefficients = new double[n+1]; auto* indices = new int[n+1]; int i = 1; - for (const auto& [ctr, constant] : column.linear()) { + for (const auto& [ctr, constant] : column) { indices[i] = lazy(ctr).impl(); coefficients[i] = constant; ++i; @@ -147,23 +140,19 @@ int idol::Optimizers::GLPK::hook_add(const Ctr &t_ctr) { } const auto& row = parent().get_ctr_row(t_ctr); - const double rhs = row.rhs(); + const double rhs = parent().get_ctr_rhs(t_ctr); const auto type = parent().get_ctr_type(t_ctr); - if (!row.quadratic().empty()) { - throw Exception("GLPK cannot handle quadratic expressions."); - } - set_ctr_attr(index, type, rhs); glp_set_row_name(m_model, index, t_ctr.name().c_str()); - const auto n = (int) row.linear().size(); + const auto n = (int) row.size(); auto* coefficients = new double[n+1]; auto* indices = new int[n+1]; int i = 1; - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : row) { indices[i] = lazy(var).impl(); coefficients[i] = constant; ++i; @@ -196,7 +185,7 @@ void idol::Optimizers::GLPK::hook_update(const Var &t_var) { const double lb = model.get_var_lb(t_var); const double ub = model.get_var_ub(t_var); const int type = model.get_var_type(t_var); - const double obj = model.get_var_column(t_var).obj(); + const double obj = model.get_var_obj(t_var); set_var_attr(impl, type, lb, ub, obj); @@ -206,7 +195,7 @@ void idol::Optimizers::GLPK::hook_update(const Ctr &t_ctr) { const auto& model = parent(); auto& impl = lazy(t_ctr).impl(); - const auto& rhs = model.get_ctr_row(t_ctr).rhs(); + const auto& rhs = model.get_ctr_rhs(t_ctr); const auto type = model.get_ctr_type(t_ctr); set_ctr_attr(impl, type, rhs); @@ -217,12 +206,8 @@ void idol::Optimizers::GLPK::hook_update_objective() { const auto& model = parent(); - if (!model.get_obj_expr().quadratic().empty()) { - throw Exception("GLPK cannot handle quadratic expressions."); - } - for (const auto& var : model.vars()) { - const auto& obj = model.get_var_column(var).obj(); + const double obj = model.get_var_obj(var); glp_set_obj_coef(m_model, lazy(var).impl(), obj); } @@ -423,7 +408,7 @@ void idol::Optimizers::GLPK::compute_farkas_certificate() { for (const auto& ctr : model.ctrs()) { const double dual = glp_get_row_dual(m_model, lazy(ctr).impl()); m_farkas_certificate->set(ctr, dual); - objective_value += dual * model.get_ctr_row(ctr).rhs(); + objective_value += dual * model.get_ctr_rhs(ctr); } m_farkas_certificate->set_objective_value(objective_value); @@ -547,8 +532,7 @@ void idol::Optimizers::GLPK::compute_unbounded_ray() { const int type = model.get_var_type(var); const double lb = model.get_var_lb(var); const double ub = model.get_var_ub(var); - const auto& column = model.get_var_column(var); - const double obj = column.obj(); + const double obj = model.get_var_obj(var); set_var_attr(index, type, lb, ub, obj); } @@ -557,7 +541,7 @@ void idol::Optimizers::GLPK::compute_unbounded_ray() { const int index = lazy(ctr).impl(); const int type = model.get_ctr_type(ctr); const auto& row = model.get_ctr_row(ctr); - const double rhs = row.rhs(); + const double rhs = model.get_ctr_rhs(ctr); set_ctr_attr(index, type, rhs); } @@ -727,7 +711,7 @@ idol::Model idol::Optimizers::GLPK::read_from_glpk(idol::Env &t_env, glp_prob *t } const std::string name = glp_get_col_name(t_model, j); - result.add_var(lb, ub, type, Column(obj),name); + result.add_var(lb, ub, type, obj, LinExpr(),name); } for (int i = 1 ; i <= n_constraints ; ++i) { @@ -757,7 +741,7 @@ idol::Model idol::Optimizers::GLPK::read_from_glpk(idol::Env &t_env, glp_prob *t auto* coefficients = new double[nz+1]; glp_get_mat_row(t_model, i, indices, coefficients); - Expr lhs; + LinExpr lhs; for (int k = 1 ; k <= nz ; ++k) { const unsigned int var_index = indices[k] - 1; const double coefficient = coefficients[k]; @@ -767,7 +751,7 @@ idol::Model idol::Optimizers::GLPK::read_from_glpk(idol::Env &t_env, glp_prob *t delete[] indices; delete[] coefficients; - result.add_ctr(TempCtr(Row(std::move(lhs), rhs), type), name); + result.add_ctr(std::move(lhs), type, rhs, name); } if (glp_get_obj_dir(t_model) == GLP_MAX) { diff --git a/lib/src/mixed-integer/optimizers/wrappers/Gurobi/GurobiCallbackI.cpp b/lib/src/mixed-integer/optimizers/wrappers/Gurobi/GurobiCallbackI.cpp index e57a284a..70faf125 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/Gurobi/GurobiCallbackI.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/Gurobi/GurobiCallbackI.cpp @@ -47,16 +47,12 @@ void idol::GurobiCallbackI::add_user_cut(const TempCtr &t_user_cut) { GRBTempConstr idol::GurobiCallbackI::gurobi_temp_constr(const TempCtr &t_temp_ctr) { - const auto& row = t_temp_ctr.row(); - const auto& rhs = m_parent.gurobi_numeric(row.rhs()); // NOLINT(readability-static-accessed-through-instance) - - if (!row.quadratic().empty()) { - throw Exception("Cannot add quadratic cuts in Gurobi."); - } + const auto& row = t_temp_ctr.lhs(); + const auto& rhs = m_parent.gurobi_numeric(t_temp_ctr.rhs()); // NOLINT(readability-static-accessed-through-instance) GRBLinExpr lhs; - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : row) { lhs += m_parent.lazy(var).impl() * constant; // NOLINT(readability-static-accessed-through-instance) } 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 f2006d6d..d3ed0089 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.cpp @@ -109,11 +109,9 @@ void idol::Optimizers::Gurobi::hook_build() { const auto& model = parent(); const auto& objective = model.get_obj_expr(); - if (objective.quadratic().empty()) { - hook_update_objective_sense(); - update_objective_constant(); - set_objective_as_updated(); - } + hook_update_objective_sense(); + update_objective_constant(); + set_objective_as_updated(); set_rhs_as_updated(); @@ -125,14 +123,14 @@ GRBVar idol::Optimizers::Gurobi::hook_add(const Var& t_var, bool t_add_column) { const auto& column = model.get_var_column(t_var); const auto lb = model.get_var_lb(t_var); const auto ub = model.get_var_ub(t_var); - const auto objective = column.obj(); + const auto objective = model.get_var_obj(t_var); const auto type = gurobi_var_type(model.get_var_type(t_var)); const auto& name = t_var.name(); GRBColumn col; if (t_add_column) { - for (const auto& [ctr, constant] : column.linear()) { + for (const auto& [ctr, constant] : column) { auto& impl = lazy(ctr).impl(); @@ -144,9 +142,6 @@ GRBVar idol::Optimizers::Gurobi::hook_add(const Var& t_var, bool t_add_column) { } - if (!column.quadratic().empty()) { - throw Exception("Cannot add column with quadratic terms."); - } } GUROBI_CATCH(return m_model.addVar(lb, ub, objective, type, col, name);) @@ -157,27 +152,13 @@ std::variant idol::Optimizers::Gurobi::hook_add(const Ctr const auto& model = parent(); const auto& row = model.get_ctr_row(t_ctr); const auto type = gurobi_ctr_type(model.get_ctr_type(t_ctr)); - const auto rhs = row.rhs(); + const auto rhs = model.get_ctr_rhs(t_ctr); const auto& name = t_ctr.name(); - - if (row.quadratic().empty()) { - - GRBLinExpr expr = 0.; - for (const auto &[var, constant]: row.linear()) { - expr += constant * lazy(var).impl(); - } - GUROBI_CATCH(return m_model.addConstr(expr, type, rhs, name);) - - } - GRBQuadExpr expr = 0.; - for (const auto &[var, constant]: row.linear()) { + for (const auto &[var, constant]: row) { expr.addTerm(constant, lazy(var).impl()); } - for (const auto& [vars, constant] : row.quadratic()) { - expr.addTerm(constant, lazy(vars.first).impl(), lazy(vars.second).impl()); - } GUROBI_CATCH(return m_model.addQConstr(expr, type, rhs, name);) } @@ -189,7 +170,7 @@ void idol::Optimizers::Gurobi::hook_update(const Var& t_var) { const double lb = model.get_var_lb(t_var); const double ub = model.get_var_ub(t_var); const int type = model.get_var_type(t_var); - const double obj = model.get_var_column(t_var).obj(); + const double obj = model.get_var_obj(t_var); impl.set(GRB_DoubleAttr_LB, gurobi_numeric(lb)); impl.set(GRB_DoubleAttr_UB, gurobi_numeric(ub)); @@ -206,7 +187,7 @@ void idol::Optimizers::Gurobi::hook_update(const Ctr& t_ctr) { if (std::holds_alternative(impl)) { auto& linear_impl = std::get(impl); - const auto& rhs = model.get_ctr_row(t_ctr).rhs(); + const auto& rhs = model.get_ctr_rhs(t_ctr); const auto type = model.get_ctr_type(t_ctr); linear_impl.set(GRB_DoubleAttr_RHS, gurobi_numeric(rhs)); @@ -230,20 +211,7 @@ void idol::Optimizers::Gurobi::hook_update_objective() { linear_expr += gurobi_numeric(constant) * lazy(var).impl(); } - if (objective.quadratic().empty()) { - m_model.setObjective(linear_expr, sense); - return; - } - - GRBQuadExpr quadratic_expr; - - for (const auto& [vars, constant] : objective.quadratic()) { - quadratic_expr.addTerm(gurobi_numeric(constant), lazy(vars.first).impl(), lazy(vars.second).impl()); - } - - m_model.setObjective(linear_expr + quadratic_expr, sense); - - + m_model.setObjective(linear_expr, sense); } void idol::Optimizers::Gurobi::hook_update_rhs() { @@ -253,7 +221,7 @@ void idol::Optimizers::Gurobi::hook_update_rhs() { for (const auto& ctr : model.ctrs()) { auto& impl = lazy(ctr).impl(); if (std::holds_alternative(impl)) { - const auto& rhs = model.get_ctr_row(ctr).rhs(); + const auto& rhs = model.get_ctr_rhs(ctr); std::get(impl).set(GRB_DoubleAttr_RHS, gurobi_numeric(rhs)); } else { std::cout << "Warning: Updating RHS on an SOCP constraint was skipped" << std::endl; @@ -526,9 +494,10 @@ idol::Model idol::Optimizers::Gurobi::read_from_file(idol::Env &t_env, const std const auto& var = model->getVar(j); const double lb = var.get(GRB_DoubleAttr_LB); const double ub = var.get(GRB_DoubleAttr_UB); + const double obj = var.get(GRB_DoubleAttr_Obj); VarType type = idol_var_type(var.get(GRB_CharAttr_VType)); - result.add_var(lb, ub, type, var.get(GRB_StringAttr_VarName)); + result.add_var(lb, ub, type, obj, var.get(GRB_StringAttr_VarName)); } const auto parse_linear = [&](const GRBLinExpr& t_lin_expr) { @@ -542,6 +511,7 @@ idol::Model idol::Optimizers::Gurobi::read_from_file(idol::Env &t_env, const std return result_; }; + /* const auto parse_quadratic = [&](const GRBQuadExpr& t_quad_expr) { Expr result_ = parse_linear(t_quad_expr.getLinExpr()); @@ -553,6 +523,7 @@ idol::Model idol::Optimizers::Gurobi::read_from_file(idol::Env &t_env, const std return result_; }; + */ const auto add_ctr = [&]( const auto& t_lhs, @@ -581,6 +552,7 @@ idol::Model idol::Optimizers::Gurobi::read_from_file(idol::Env &t_env, const std add_ctr(lhs, rhs, type, name); } + /* for (unsigned int i = 0 ; i < n_quad_ctrs ; ++i) { const auto& ctr = model->getQConstrs()[i]; @@ -593,12 +565,13 @@ idol::Model idol::Optimizers::Gurobi::read_from_file(idol::Env &t_env, const std add_ctr(lhs, rhs, type, name); } + */ const auto sense = model->get(GRB_IntAttr_ModelSense); result.set_obj_sense(idol_obj_sense(sense)); const auto& objective = model->getObjective(); - result.set_obj_expr(parse_quadratic(objective)); + result.set_obj_expr(parse_linear((GRBLinExpr&) objective)); return std::move(result); } diff --git a/lib/src/mixed-integer/optimizers/wrappers/HiGHS/Optimizers_HiGHS.cpp b/lib/src/mixed-integer/optimizers/wrappers/HiGHS/Optimizers_HiGHS.cpp index c668f981..3a123f45 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/HiGHS/Optimizers_HiGHS.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/HiGHS/Optimizers_HiGHS.cpp @@ -19,10 +19,6 @@ void idol::Optimizers::HiGHS::hook_build() { const auto& objective = parent().get_obj_expr(); - if (!objective.quadratic().empty()) { - throw Exception("HiGHS is not available as an SOCP solver."); - } - hook_update_objective_sense(); update_objective_constant(); set_objective_as_updated(); @@ -79,6 +75,7 @@ int idol::Optimizers::HiGHS::hook_add(const Var &t_var, bool t_add_column) { double lb = parent().get_var_lb(t_var); double ub = parent().get_var_ub(t_var); + double obj = parent().get_var_obj(t_var); const auto& column = parent().get_var_column(t_var); const auto type = parent().get_var_type(t_var); @@ -87,7 +84,7 @@ int idol::Optimizers::HiGHS::hook_add(const Var &t_var, bool t_add_column) { if (t_add_column) { - const auto& column_linear = column.linear(); + const auto& column_linear = column; unsigned int n_coefficients = column_linear.size(); auto* ctr_indices = new int[n_coefficients]; @@ -101,7 +98,7 @@ int idol::Optimizers::HiGHS::hook_add(const Var &t_var, bool t_add_column) { ++i; } - m_model.addCol(column.obj(), + m_model.addCol(obj, lb, ub, (int) n_coefficients, @@ -112,7 +109,7 @@ int idol::Optimizers::HiGHS::hook_add(const Var &t_var, bool t_add_column) { delete[] ctr_coefficients; } else { - m_model.addCol(column.obj(), + m_model.addCol(obj, lb, ub, 0, @@ -148,16 +145,15 @@ int idol::Optimizers::HiGHS::hook_add(const Ctr &t_ctr) { const int index = (int) m_model.getNumRow(); const auto& row = parent().get_ctr_row(t_ctr); - const auto& row_linear = row.linear(); - const double rhs = row.rhs(); + const double rhs = parent().get_ctr_rhs(t_ctr); const auto type = parent().get_ctr_type(t_ctr); - unsigned int n_coefficients = row_linear.size(); + unsigned int n_coefficients = row.size(); auto* var_indices = new int[n_coefficients]; auto* var_coefficients = new double[n_coefficients]; unsigned int i = 0; - for (const auto& [var, constant] : row.linear()) { + for (const auto& [var, constant] : row) { int ctr_index = lazy(var).impl(); var_indices[i] = ctr_index; var_coefficients[i] = constant; @@ -216,7 +212,7 @@ void idol::Optimizers::HiGHS::hook_update(const Var &t_var) { const double lb = model.get_var_lb(t_var); const double ub = model.get_var_ub(t_var); const int type = model.get_var_type(t_var); - const double obj = model.get_var_column(t_var).obj(); + const double obj = model.get_var_obj(t_var); set_var_attr(impl, type, lb, ub, obj); @@ -226,7 +222,7 @@ void idol::Optimizers::HiGHS::hook_update(const Ctr &t_ctr) { const auto& model = parent(); auto& impl = lazy(t_ctr).impl(); - const auto& rhs = model.get_ctr_row(t_ctr).rhs(); + const auto& rhs = model.get_ctr_rhs(t_ctr); const auto type = model.get_ctr_type(t_ctr); set_ctr_attr(impl, type, rhs); @@ -237,7 +233,7 @@ void idol::Optimizers::HiGHS::hook_update_objective() { const auto& model = parent(); for (const auto& var : model.vars()) { - const auto& obj = model.get_var_column(var).obj(); + const auto& obj = model.get_var_obj(var); m_model.changeColCost(lazy(var).impl(), obj); } diff --git a/lib/src/mixed-integer/optimizers/wrappers/Mosek/Optimizers_Mosek.cpp b/lib/src/mixed-integer/optimizers/wrappers/Mosek/Optimizers_Mosek.cpp index 16c7b447..62f090ec 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/Mosek/Optimizers_Mosek.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/Mosek/Optimizers_Mosek.cpp @@ -29,10 +29,6 @@ void idol::Optimizers::Mosek::hook_build() { const auto& objective = parent().get_obj_expr(); - if (!objective.quadratic().empty()) { - throw Exception("Handling quadratic objective is not implemented."); - } - set_rhs_as_updated(); } @@ -134,14 +130,15 @@ idol::MosekVar idol::Optimizers::Mosek::hook_add(const Var &t_var, bool t_add_co const double lb = parent().get_var_lb(t_var); const double ub = parent().get_var_ub(t_var); + const double obj = parent().get_var_obj(t_var); const auto& column = parent().get_var_column(t_var); const auto type = parent().get_var_type(t_var); - set_var_attr(result, type, lb, ub, column.obj()); + set_var_attr(result, type, lb, ub, obj); if (t_add_column) { - for (const auto& [ctr, constant] : column.linear()) { + for (const auto& [ctr, constant] : column) { lazy(ctr).impl().constraint->index(0)->update( mosek::fusion::Expr::mul(constant, result.variable->index(0)), result.variable->index(0) @@ -172,7 +169,6 @@ mosek::fusion::Expression::t idol::Optimizers::Mosek::to_mosek_expression(const } mosek::fusion::Expression::t idol::Optimizers::Mosek::to_mosek_expression(const Expr &t_expr) const { - assert(t_expr.quadratic().empty()); return mosek::fusion::Expr::add( t_expr.constant(), to_mosek_expression(t_expr.linear()) @@ -187,7 +183,9 @@ idol::MosekCtr idol::Optimizers::Mosek::hook_add(const Ctr &t_ctr) { const int type = model.get_ctr_type(t_ctr); const auto& row = model.get_ctr_row(t_ctr); + const double rhs = model.get_ctr_rhs(t_ctr); + /* if (!row.quadratic().empty()) { #ifdef IDOL_USE_EIGEN @@ -200,7 +198,7 @@ idol::MosekCtr idol::Optimizers::Mosek::hook_add(const Ctr &t_ctr) { auto it = rq_cone_expr.begin(); - if (!row.linear().empty() || std::abs(row.rhs()) >= Tolerance::Sparsity) { + if (!row.linear().empty() || std::abs(rhs) >= Tolerance::Sparsity) { const auto& head1 = *it; ++it; @@ -213,22 +211,22 @@ idol::MosekCtr idol::Optimizers::Mosek::hook_add(const Ctr &t_ctr) { expression = mosek::fusion::Expr::vstack( std::move(expression), mosek::fusion::Expr::constTerm(.5), - to_mosek_expression(sign * row.rhs() - sign * row.linear()) + to_mosek_expression(sign * rhs - sign * row.linear()) ); } else if (row.linear().empty()) { // Here, we have a constraint of the form x^T Q x - 2yz <= b \iff 2 * .5 * y * z >= xQx + sqrt(b)^2 - std::cout << "Warning: Assuming \"" << head1 << " >= 0\" when converting quadratic constraint to Mosek expression." << std::endl; - std::cout << "Warning: Assuming \"" << head2 << " >= 0\" when converting quadratic constraint to Mosek expression." << std::endl; + std::cerr << "Warning: Assuming \"" << head1 << " >= 0\" when converting quadratic constraint to Mosek expression." << std::endl; + std::cerr << "Warning: Assuming \"" << head2 << " >= 0\" when converting quadratic constraint to Mosek expression." << std::endl; - if (sign * row.rhs() >= 0) { + if (sign * rhs >= 0) { throw Exception("Non-convex constraint was found."); } expression = mosek::fusion::Expr::vstack( to_mosek_expression(head1), to_mosek_expression(head2), - std::sqrt(-sign * row.rhs()) + std::sqrt(-sign * rhs) ); } else { @@ -244,7 +242,7 @@ idol::MosekCtr idol::Optimizers::Mosek::hook_add(const Ctr &t_ctr) { ); } - result.constraint = m_model->constraint(/* t_ctr.name(), */ std::move(expression), mosek::fusion::Domain::inRotatedQCone()); + result.constraint = m_model->constraint(std::move(expression), mosek::fusion::Domain::inRotatedQCone()); return result; #else @@ -253,9 +251,11 @@ idol::MosekCtr idol::Optimizers::Mosek::hook_add(const Ctr &t_ctr) { } + */ + // Build expression - auto expr = to_mosek_expression(row.linear()); - expr = mosek::fusion::Expr::add(std::move(expr), -row.rhs()); + auto expr = to_mosek_expression(row); + expr = mosek::fusion::Expr::add(std::move(expr), -rhs); // Set constraint type switch (type) { @@ -293,7 +293,7 @@ void idol::Optimizers::Mosek::hook_update(const Var &t_var) { const double lb = model.get_var_lb(t_var); const double ub = model.get_var_ub(t_var); const int type = model.get_var_type(t_var); - const double obj = model.get_var_column(t_var).obj(); + const double obj = model.get_var_obj(t_var); set_var_attr(impl, type, lb, ub, obj); @@ -301,10 +301,10 @@ void idol::Optimizers::Mosek::hook_update(const Var &t_var) { void idol::Optimizers::Mosek::hook_update(const Ctr &t_ctr) { - const auto& row = parent().get_ctr_row(t_ctr); + const double rhs = parent().get_ctr_rhs(t_ctr); - auto rhs = std::make_shared>(monty::shape(1), -row.rhs()); - lazy(t_ctr).impl().constraint->index(0)->update(rhs); + auto msk_rhs = std::make_shared>(monty::shape(1), -rhs); + lazy(t_ctr).impl().constraint->index(0)->update(msk_rhs); } diff --git a/lib/src/mixed-integer/optimizers/wrappers/Osi/Optimizers_Osi.cpp b/lib/src/mixed-integer/optimizers/wrappers/Osi/Optimizers_Osi.cpp index e45bae25..85467664 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/Osi/Optimizers_Osi.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/Osi/Optimizers_Osi.cpp @@ -177,10 +177,6 @@ void idol::Optimizers::Osi::hook_build() { const auto& objective = parent().get_obj_expr(); - if (!objective.quadratic().empty()) { - throw Exception("Osi is not available as an SOCP solver."); - } - hook_update_objective_sense(); set_objective_as_updated(); set_rhs_as_updated(); @@ -214,6 +210,7 @@ int idol::Optimizers::Osi::hook_add(const idol::Var &t_var, bool t_add_column) { double lb = parent().get_var_lb(t_var); double ub = parent().get_var_ub(t_var); + const double obj = parent().get_var_obj(t_var); const auto& column = parent().get_var_column(t_var); const auto type = parent().get_var_type(t_var); @@ -221,11 +218,7 @@ int idol::Optimizers::Osi::hook_add(const idol::Var &t_var, bool t_add_column) { if (t_add_column) { - if (!column.quadratic().empty()) { - throw Exception("Osi cannot handle quadratic expressions."); - } - - for (const auto& [ctr, constant] : column.linear()) { + for (const auto& [ctr, constant] : column) { const int ctr_index = lazy(ctr).impl(); const double coefficient = constant; vector.insert(ctr_index, coefficient); @@ -238,7 +231,7 @@ int idol::Optimizers::Osi::hook_add(const idol::Var &t_var, bool t_add_column) { ub = std::min(1., ub); } - m_solver_interface->addCol(vector, lb, ub, column.obj(), t_var.name()); + m_solver_interface->addCol(vector, lb, ub, obj, t_var.name()); if (type == Binary || type == Integer) { m_solver_interface->setInteger(index); @@ -252,15 +245,11 @@ int idol::Optimizers::Osi::hook_add(const idol::Ctr &t_ctr) { const int index = m_solver_interface->getNumRows(); const auto& row = parent().get_ctr_row(t_ctr); - const double rhs = row.rhs(); + const double rhs = parent().get_ctr_rhs(t_ctr); const auto type = parent().get_ctr_type(t_ctr); - if (!row.quadratic().empty()) { - throw Exception("Osi cannot handle quadratic expressions."); - } - CoinPackedVector vector; - for (const auto& [var, coeff] : row.linear()) { + for (const auto& [var, coeff] : row) { const int var_index = lazy(var).impl(); const double coefficient = coeff; vector.insert(var_index, coefficient); @@ -298,7 +287,7 @@ void idol::Optimizers::Osi::hook_update(const idol::Var &t_var) { double lb = model.get_var_lb(t_var); double ub = model.get_var_ub(t_var); const int type = model.get_var_type(t_var); - const double obj = model.get_var_column(t_var).obj(); + const double obj = model.get_var_obj(t_var); if (type == Binary) { lb = std::max(0., lb); @@ -326,7 +315,7 @@ void idol::Optimizers::Osi::hook_update(const idol::Ctr &t_ctr) { const auto& model = parent(); auto& impl = lazy(t_ctr).impl(); - const auto& rhs = model.get_ctr_row(t_ctr).rhs(); + const auto& rhs = model.get_ctr_rhs(t_ctr); const auto type = model.get_ctr_type(t_ctr); double lb = -Inf, ub = Inf; @@ -344,16 +333,12 @@ void idol::Optimizers::Osi::hook_update_objective() { const auto& parent = this->parent(); - if (!parent.get_obj_expr().quadratic().empty()) { - throw Exception("Osi is not available as an SOCP solver."); - } - const unsigned int n_variables = parent.vars().size(); auto* coefficients = new double[n_variables]; for (const auto& var : parent.vars()) { const unsigned int index = lazy(var).impl(); - coefficients[index] = parent.get_var_column(var).obj(); + coefficients[index] = parent.get_var_obj(var); } m_solver_interface->setObjective(coefficients); diff --git a/lib/src/mixed-integer/optimizers/wrappers/Osi/OsiIdolSolverInterface.cpp b/lib/src/mixed-integer/optimizers/wrappers/Osi/OsiIdolSolverInterface.cpp index c7fb9696..99e70aa7 100644 --- a/lib/src/mixed-integer/optimizers/wrappers/Osi/OsiIdolSolverInterface.cpp +++ b/lib/src/mixed-integer/optimizers/wrappers/Osi/OsiIdolSolverInterface.cpp @@ -10,6 +10,7 @@ #include #include "idol/mixed-integer/optimizers/wrappers/Osi/OsiIdolSolverInterface.h" #include "idol/mixed-integer/modeling/expressions/operations/operators.h" +#include "idol/mixed-integer/modeling/constraints/TempCtr.h" #define OSI_IDOL_DEBUG std::cout << __FUNCTION__ << std::endl; @@ -206,7 +207,7 @@ const double *OsiIdolSolverInterface::getRowLower() const { m_row_lower = new double[n_rows]; for (int i = 0 ; i < n_rows ; ++i) { const auto ctr = m_model.get_ctr_by_index(i); - const auto rhs = m_model.get_ctr_row(ctr).rhs(); + const auto rhs = m_model.get_ctr_rhs(ctr); const auto type = m_model.get_ctr_type(ctr); switch (type) { case idol::LessOrEqual: @@ -231,7 +232,7 @@ const double *OsiIdolSolverInterface::getRowUpper() const { m_row_upper = new double[n_rows]; for (int i = 0 ; i < n_rows ; ++i) { const auto ctr = m_model.get_ctr_by_index(i); - const auto rhs = m_model.get_ctr_row(ctr).rhs(); + const auto rhs = m_model.get_ctr_rhs(ctr); const auto type = m_model.get_ctr_type(ctr); switch (type) { case idol::LessOrEqual: @@ -256,7 +257,7 @@ const double *OsiIdolSolverInterface::getObjCoefficients() const { m_col_obj = new double[n_cols]; for (int i = 0 ; i < n_cols ; ++i) { const auto var = m_model.get_var_by_index(i); - m_col_obj[i] = m_model.get_var_column(var).obj(); + m_col_obj[i] = m_model.get_var_obj(var); } } return m_col_obj; @@ -287,7 +288,7 @@ const CoinPackedMatrix *OsiIdolSolverInterface::getMatrixByRow() const { const auto &row = m_model.get_ctr_row(ctr); CoinPackedVector row_vector; - for (const auto &[var, constant]: row.linear()) { + for (const auto &[var, constant]: row) { const int index = (int) m_model.get_var_index(var); row_vector.insert(index, constant); } @@ -314,7 +315,7 @@ const CoinPackedMatrix *OsiIdolSolverInterface::getMatrixByCol() const { const auto &column = m_model.get_var_column(var); CoinPackedVector col_vector; - for (const auto &[ctr, constant]: column.linear()) { + for (const auto &[ctr, constant]: column) { const int index = (int) m_model.get_ctr_index(ctr); col_vector.insert(index, constant); } @@ -556,15 +557,15 @@ void OsiIdolSolverInterface::addCol(const CoinPackedVectorBase &vec, const doubl const auto* indices = vec.getIndices(); const auto* values = vec.getElements(); - idol::Column column(obj); + idol::LinExpr column; for (unsigned int i = 0, n = vec.getNumElements() ; i < n ; ++i) { const int index = indices[i]; const double value = values[i]; const auto& ctr = m_model.get_ctr_by_index(index); - column.linear().set(ctr, value); + column.set(ctr, value); } - m_model.add_var(collb, colub, idol::Continuous, std::move(column)); + m_model.add_var(collb, colub, idol::Continuous, obj, std::move(column)); std::cout << "WARNING: adding column relying on potentially wrong indices..." << std::endl; } @@ -601,15 +602,15 @@ void OsiIdolSolverInterface::addRow(const CoinPackedVectorBase &vec, const doubl throw idol::Exception("Range constraints are not implemented."); } - idol::Expr lhs; + idol::LinExpr lhs; for (unsigned int i = 0, n = vec.getNumElements() ; i < n ; ++i) { const int index = indices[i]; const double value = values[i]; const auto& var = m_model.get_var_by_index(index); - lhs.linear().set(var, value); + lhs += value * var; } - m_model.add_ctr(idol::TempCtr(idol::Row(std::move(lhs), rhs), type)); + m_model.add_ctr(idol::TempCtr(std::move(lhs), type, rhs)); // TODO: this can be handled more efficiently for the matrix (i.e., just add the row) delete[] m_row_sense; m_row_sense = nullptr; @@ -722,19 +723,19 @@ void OsiIdolSolverInterface::loadProblem(const CoinPackedMatrix &matrix, } else { throw idol::Exception("OsiIdolSolverInterface: Unknown sense."); } - m_model.add_ctr(idol::Row(0, rowrhs[i]), type); + m_model.add_ctr(idol::LinExpr(), type, rowrhs[i]); } for (int i = 0 ; i < n_cols ; ++i) { - idol::Column column(obj[i]); + idol::LinExpr column; const CoinShallowPackedVector& col = matrix.getVector(i); for (int j = 0 ; j < col.getNumElements() ; ++j) { const int row = col.getIndices()[j]; const double value = col.getElements()[j]; const auto& ctr = m_model.get_ctr_by_index(row); - column.linear().set(ctr, value); + column.set(ctr, value); } - m_model.add_var(collb[i], colub[i], idol::Continuous, std::move(column)); + m_model.add_var(collb[i], colub[i], idol::Continuous, obj[i], std::move(column)); } } diff --git a/tests/branch-and-bound/knapsack.cpp b/tests/branch-and-bound/knapsack.cpp index 7b8eb1df..52d001e6 100644 --- a/tests/branch-and-bound/knapsack.cpp +++ b/tests/branch-and-bound/knapsack.cpp @@ -63,7 +63,7 @@ TEMPLATE_LIST_TEST_CASE("Solve Knapsack Problem instances with different node se const auto instance = read_instance("../data/knapsack-problem/" + filename); const unsigned int n_items = instance.n_items(); - auto x = Var::make_vector(env, Dim<1>(n_items), 0., 1., Binary, "x"); + auto x = Var::make_vector(env, Dim<1>(n_items), 0., 1., Binary, 0., "x"); Ctr c(env, idol_Sum(j, Range(n_items), instance.weight(j) * x[j]) <= instance.capacity()); Model model(env); diff --git a/tests/modeling/Model.add-by-column.cpp b/tests/modeling/Model.add-by-column.cpp index 29767487..8b825298 100644 --- a/tests/modeling/Model.add-by-column.cpp +++ b/tests/modeling/Model.add-by-column.cpp @@ -22,13 +22,12 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { WHEN("Adding a variable by column (linear only)") { - Column column; - column.set_obj(100); - column.linear().set(c[0], 101); - column.linear().set(c[1], 102); - column.linear().set(c[2], 103); + LinExpr column; + column.set(c[0], 101); + column.set(c[1], 102); + column.set(c[2], 103); - Var var(env, 0., 1, Continuous, column); + Var var(env, 0., 1, Continuous, 100, column); model.add(var); THEN("The number of variables should be one") { @@ -40,7 +39,7 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { } AND_THEN("The column objective should have been added to the model's variable objective") { - CHECK(model.get_var_column(var).obj() == 100_a); + CHECK(model.get_var_obj(var) == 100_a); } AND_THEN("The column objective should have been added to the model's objective") { @@ -48,15 +47,15 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { } AND_THEN("The column coefficients should have been added to the model's variable column") { - CHECK(model.get_var_column(var).linear().get(c[0]) == 101_a); - CHECK(model.get_var_column(var).linear().get(c[1]) == 102_a); - CHECK(model.get_var_column(var).linear().get(c[2]) == 103_a); + CHECK(model.get_var_column(var).get(c[0]) == 101_a); + CHECK(model.get_var_column(var).get(c[1]) == 102_a); + CHECK(model.get_var_column(var).get(c[2]) == 103_a); } AND_THEN("The column coefficients should have been added to the model's constraints' rows") { - CHECK(model.get_ctr_row(c[0]).linear().get(var) == 101_a); - CHECK(model.get_ctr_row(c[1]).linear().get(var) == 102_a); - CHECK(model.get_ctr_row(c[2]).linear().get(var) == 103_a); + CHECK(model.get_ctr_row(c[0]).get(var) == 101_a); + CHECK(model.get_ctr_row(c[1]).get(var) == 102_a); + CHECK(model.get_ctr_row(c[2]).get(var) == 103_a); } AND_WHEN("The objective coefficient of that variable is changed in the model (nonzero)") { @@ -68,7 +67,7 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { } AND_THEN("The variable's objective coefficient should be updated") { - CHECK(model.get_var_column(var).obj() == 1_a); + CHECK(model.get_var_obj(var) == 1_a); } } @@ -77,11 +76,11 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { model.set_mat_coeff(c[0], var, 1); THEN("The model's constraint's row should be updated") { - CHECK(model.get_ctr_row(c[0]).linear().get(var) == 1_a); + CHECK(model.get_ctr_row(c[0]).get(var) == 1_a); } AND_THEN("The model's variable's column should be updated") { - CHECK(model.get_var_column(var).linear().get(c[0]) == 1_a); + CHECK(model.get_var_column(var).get(c[0]) == 1_a); } } @@ -95,7 +94,7 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { } AND_THEN("The model's variable's column's objective coefficient should be zero") { - CHECK(model.get_var_column(var).obj() == 0_a); + CHECK(model.get_var_obj(var) == 0_a); } } @@ -105,11 +104,11 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { model.set_mat_coeff(c[0], var, 0); THEN("The model's constraint's row should be empty") { - CHECK(model.get_ctr_row(c[0]).linear().empty()); + CHECK(model.get_ctr_row(c[0]).empty()); } AND_THEN("The model's variable's column's coefficient should be zero") { - CHECK(model.get_var_column(var).linear().get(c[0]) == 0_a); + CHECK(model.get_var_column(var).get(c[0]) == 0_a); } } @@ -135,15 +134,15 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { } AND_THEN("The model's constraints should be empty") { - CHECK(model.get_ctr_row(c[0]).linear().empty()); - CHECK(model.get_ctr_row(c[1]).linear().empty()); - CHECK(model.get_ctr_row(c[2]).linear().empty()); + CHECK(model.get_ctr_row(c[0]).empty()); + CHECK(model.get_ctr_row(c[1]).empty()); + CHECK(model.get_ctr_row(c[2]).empty()); } AND_THEN("The variable's coefficients in the model's constraints should be zero") { - CHECK(model.get_ctr_row(c[0]).linear().get(var) == 0_a); - CHECK(model.get_ctr_row(c[1]).linear().get(var) == 0_a); - CHECK(model.get_ctr_row(c[2]).linear().get(var) == 0_a); + CHECK(model.get_ctr_row(c[0]).get(var) == 0_a); + CHECK(model.get_ctr_row(c[1]).get(var) == 0_a); + CHECK(model.get_ctr_row(c[2]).get(var) == 0_a); } } @@ -156,16 +155,16 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { auto c = Ctr::make_vector(env, Dim<1>(3), LessOrEqual, 0.); model.add_vector(c); - auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous); + auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous, 0.); model.add_vector(x); WHEN("Adding a variable by column (linear and quadratic)") { - Column column; - column.set_obj(100); - column.linear().set(c[0], 101); - column.linear().set(c[1], 102); - column.linear().set(c[2], 103); + LinExpr column; + column.set(c[0], 101); + column.set(c[1], 102); + column.set(c[2], 103); + /* column.quadratic().set(c[0], x[0], 104); column.quadratic().set(c[0], x[1], 105); column.quadratic().set(c[0], x[2], 106); @@ -175,8 +174,9 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { column.quadratic().set(c[2], x[0], 110); column.quadratic().set(c[2], x[1], 111); column.quadratic().set(c[2], x[2], 112); + */ - Var var(env, 0., 1., Continuous, column); + Var var(env, 0., 1., Continuous, 100, column); model.add(var); THEN("The number of variables should increase by one") { @@ -186,10 +186,11 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { // OBJECTIVE check model's objective and variable's objective AND_THEN("The column coefficients should have been added to the model's variable column") { - CHECK(model.get_var_column(var).linear().get(c[0]) == 101_a); - CHECK(model.get_var_column(var).linear().get(c[1]) == 102_a); - CHECK(model.get_var_column(var).linear().get(c[2]) == 103_a); + CHECK(model.get_var_column(var).get(c[0]) == 101_a); + CHECK(model.get_var_column(var).get(c[1]) == 102_a); + CHECK(model.get_var_column(var).get(c[2]) == 103_a); + /* CHECK(model.get_var_column(var).quadratic().get(c[0], x[0]) == 104_a); CHECK(model.get_var_column(var).quadratic().get(c[0], x[1]) == 105_a); CHECK(model.get_var_column(var).quadratic().get(c[0], x[2]) == 106_a); @@ -201,13 +202,15 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { CHECK(model.get_var_column(var).quadratic().get(c[2], x[0]) == 110_a); CHECK(model.get_var_column(var).quadratic().get(c[2], x[1]) == 111_a); CHECK(model.get_var_column(var).quadratic().get(c[2], x[2]) == 112_a); + */ } AND_THEN("The column coefficients should have been added to the model's constraints' rows") { - CHECK(model.get_ctr_row(c[0]).linear().get(var) == 101_a); - CHECK(model.get_ctr_row(c[1]).linear().get(var) == 102_a); - CHECK(model.get_ctr_row(c[2]).linear().get(var) == 103_a); + CHECK(model.get_ctr_row(c[0]).get(var) == 101_a); + CHECK(model.get_ctr_row(c[1]).get(var) == 102_a); + CHECK(model.get_ctr_row(c[2]).get(var) == 103_a); + /* CHECK(model.get_ctr_row(c[0]).quadratic().get(var, x[0]) == 104_a); CHECK(model.get_ctr_row(c[0]).quadratic().get(var, x[1]) == 105_a); CHECK(model.get_ctr_row(c[0]).quadratic().get(var, x[2]) == 106_a); @@ -219,6 +222,7 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { CHECK(model.get_ctr_row(c[2]).quadratic().get(var, x[0]) == 110_a); CHECK(model.get_ctr_row(c[2]).quadratic().get(var, x[1]) == 111_a); CHECK(model.get_ctr_row(c[2]).quadratic().get(var, x[2]) == 112_a); + */ } AND_WHEN("The variable is removed") { @@ -235,27 +239,31 @@ SCENARIO("Model: Add a variable by column", "[unit][modeling-old][Model]") { AND_THEN("The model's objective should be empty") { CHECK(model.get_obj_expr().linear().empty()); - CHECK(model.get_obj_expr().quadratic().empty()); + //CHECK(model.get_obj_expr().quadratic().empty()); } AND_THEN("The model's constraints should be empty") { - CHECK(model.get_ctr_row(c[0]).linear().empty()); - CHECK(model.get_ctr_row(c[1]).linear().empty()); - CHECK(model.get_ctr_row(c[2]).linear().empty()); + CHECK(model.get_ctr_row(c[0]).empty()); + CHECK(model.get_ctr_row(c[1]).empty()); + CHECK(model.get_ctr_row(c[2]).empty()); + /* CHECK(model.get_ctr_row(c[0]).quadratic().empty()); CHECK(model.get_ctr_row(c[1]).quadratic().empty()); CHECK(model.get_ctr_row(c[2]).quadratic().empty()); + */ } AND_THEN("The variable's coefficients in the model's constraints should be zero") { - CHECK(model.get_ctr_row(c[0]).linear().get(var) == 0_a); - CHECK(model.get_ctr_row(c[1]).linear().get(var) == 0_a); - CHECK(model.get_ctr_row(c[2]).linear().get(var) == 0_a); + CHECK(model.get_ctr_row(c[0]).get(var) == 0_a); + CHECK(model.get_ctr_row(c[1]).get(var) == 0_a); + CHECK(model.get_ctr_row(c[2]).get(var) == 0_a); + /* CHECK(model.get_ctr_row(c[0]).quadratic().get(var, x[0]) == 0_a); CHECK(model.get_ctr_row(c[1]).quadratic().get(var, x[1]) == 0_a); CHECK(model.get_ctr_row(c[2]).quadratic().get(var, x[2]) == 0_a); + */ } } diff --git a/tests/modeling/Model.add-by-row.cpp b/tests/modeling/Model.add-by-row.cpp index cd749be2..f5dcd362 100644 --- a/tests/modeling/Model.add-by-row.cpp +++ b/tests/modeling/Model.add-by-row.cpp @@ -14,24 +14,25 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { GIVEN("An initial model with some variables and no constraint") { - auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous); + auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous, 0.); model.add_vector(x); WHEN("Adding a constraint by row (linear and quadratic)") { - Row row; - row.set_rhs(100); - row.linear().set(x[0], 101); - row.linear().set(x[1], 102); - row.linear().set(x[2], 103); + LinExpr row; + row.set(x[0], 101); + row.set(x[1], 102); + row.set(x[2], 103); + /* row.quadratic().set(x[0], x[0], 104); row.quadratic().set(x[0], x[1], 105); row.quadratic().set(x[0], x[2], 106); row.quadratic().set(x[1], x[1], 107); row.quadratic().set(x[1], x[2], 108); row.quadratic().set(x[2], x[2], 109); + */ - Ctr ctr(env, TempCtr(std::move(row), LessOrEqual)); + Ctr ctr(env, TempCtr(std::move(row), LessOrEqual, 100)); model.add(ctr); THEN("The number of constraints should be one") { @@ -51,37 +52,39 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { } AND_THEN("The row rhs should have been added to the model's constraint's rhs") { - CHECK(model.get_ctr_row(ctr).rhs() == 100_a); + CHECK(model.get_ctr_rhs(ctr) == 100_a); } AND_THEN("The row coefficients should have been added to the model's constraints' coefficients") { - CHECK(model.get_ctr_row(ctr).linear().get(x[0]) == 101_a); - CHECK(model.get_ctr_row(ctr).linear().get(x[1]) == 102_a); - CHECK(model.get_ctr_row(ctr).linear().get(x[2]) == 103_a); + CHECK(model.get_ctr_row(ctr).get(x[0]) == 101_a); + CHECK(model.get_ctr_row(ctr).get(x[1]) == 102_a); + CHECK(model.get_ctr_row(ctr).get(x[2]) == 103_a); + /* CHECK(model.get_ctr_row(ctr).quadratic().get(x[0], x[0]) == 104_a); CHECK(model.get_ctr_row(ctr).quadratic().get(x[0], x[1]) == 105_a); CHECK(model.get_ctr_row(ctr).quadratic().get(x[0], x[2]) == 106_a); CHECK(model.get_ctr_row(ctr).quadratic().get(x[1], x[1]) == 107_a); CHECK(model.get_ctr_row(ctr).quadratic().get(x[1], x[2]) == 108_a); CHECK(model.get_ctr_row(ctr).quadratic().get(x[2], x[2]) == 109_a); + */ } AND_THEN("The row coefficients should have been added to the model's variables' coefficients") { - CHECK(model.get_var_column(x[0]).linear().get(ctr) == 101_a); - CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[0]) == 104_a); - CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[1]) == 105_a); - CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[2]) == 106_a); - - CHECK(model.get_var_column(x[1]).linear().get(ctr) == 102_a); - CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[0]) == 105_a); - CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[1]) == 107_a); - CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[2]) == 108_a); - - CHECK(model.get_var_column(x[2]).linear().get(ctr) == 103_a); - CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[0]) == 106_a); - CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[1]) == 108_a); - CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[2]) == 109_a); + CHECK(model.get_var_column(x[0]).get(ctr) == 101_a); + //CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[0]) == 104_a); + //CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[1]) == 105_a); + //CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[2]) == 106_a); + + CHECK(model.get_var_column(x[1]).get(ctr) == 102_a); + //CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[0]) == 105_a); + //CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[1]) == 107_a); + //CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[2]) == 108_a); + + CHECK(model.get_var_column(x[2]).get(ctr) == 103_a); + //CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[0]) == 106_a); + //CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[1]) == 108_a); + //CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[2]) == 109_a); } AND_WHEN("The rhs of that constraint in changed int the model (nonzero)") { @@ -93,7 +96,7 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { } AND_THEN("The constraint's rhs should be updated") { - CHECK(model.get_ctr_row(ctr).rhs() == 1_a); + CHECK(model.get_ctr_rhs(ctr) == 1_a); } } @@ -103,11 +106,11 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { model.set_mat_coeff(ctr, x[0], 1); THEN("The model's constraint's row should be updated") { - CHECK(model.get_ctr_row(ctr).linear().get(x[0]) == 1_a); + CHECK(model.get_ctr_row(ctr).get(x[0]) == 1_a); } AND_THEN("The model's variable's column should be updated") { - CHECK(model.get_var_column(x[0]).linear().get(ctr) == 1_a); + CHECK(model.get_var_column(x[0]).get(ctr) == 1_a); } } @@ -121,7 +124,7 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { } AND_THEN("The model's constraint's row's rhs should be zero") { - CHECK(model.get_ctr_row(ctr).rhs() == 0_a); + CHECK(model.get_ctr_rhs(ctr) == 0_a); } } @@ -132,11 +135,11 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { model.set_mat_coeff(ctr, x[0], 0); THEN("The model's constraint's row should be empty") { - CHECK(model.get_ctr_row(ctr).linear().get(x[0]) == 0_a); + CHECK(model.get_ctr_row(ctr).get(x[0]) == 0_a); } AND_THEN("The model's variable's column's coefficient should be zero") { - CHECK(model.get_var_column(x[0]).linear().get(ctr) == 0_a); + CHECK(model.get_var_column(x[0]).get(ctr) == 0_a); } } @@ -162,31 +165,31 @@ SCENARIO("Model: Add a constraint by row", "[unit][modeling-old][Model]") { } AND_THEN("The model's columns should be empty") { - CHECK(model.get_var_column(x[0]).linear().empty()); - CHECK(model.get_var_column(x[0]).quadratic().empty()); + CHECK(model.get_var_column(x[0]).empty()); + //CHECK(model.get_var_column(x[0]).quadratic().empty()); - CHECK(model.get_var_column(x[1]).linear().empty()); - CHECK(model.get_var_column(x[1]).quadratic().empty()); + CHECK(model.get_var_column(x[1]).empty()); + //CHECK(model.get_var_column(x[1]).quadratic().empty()); - CHECK(model.get_var_column(x[2]).linear().empty()); - CHECK(model.get_var_column(x[2]).quadratic().empty()); + CHECK(model.get_var_column(x[2]).empty()); + //CHECK(model.get_var_column(x[2]).quadratic().empty()); } AND_THEN("The constraint's coefficients in the model's variables should be zero") { - CHECK(model.get_var_column(x[0]).linear().get(ctr) == 0_a); - CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[0]) == 0_a); - CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[1]) == 0_a); - CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[2]) == 0_a); - - CHECK(model.get_var_column(x[1]).linear().get(ctr) == 0_a); - CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[0]) == 0_a); - CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[1]) == 0_a); - CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[2]) == 0_a); - - CHECK(model.get_var_column(x[2]).linear().get(ctr) == 0_a); - CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[0]) == 0_a); - CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[1]) == 0_a); - CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[2]) == 0_a); + CHECK(model.get_var_column(x[0]).get(ctr) == 0_a); + //CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[0]) == 0_a); + //CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[1]) == 0_a); + //CHECK(model.get_var_column(x[0]).quadratic().get(ctr, x[2]) == 0_a); + + CHECK(model.get_var_column(x[1]).get(ctr) == 0_a); + //CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[0]) == 0_a); + //CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[1]) == 0_a); + //CHECK(model.get_var_column(x[1]).quadratic().get(ctr, x[2]) == 0_a); + + CHECK(model.get_var_column(x[2]).get(ctr) == 0_a); + //CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[0]) == 0_a); + //CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[1]) == 0_a); + //CHECK(model.get_var_column(x[2]).quadratic().get(ctr, x[2]) == 0_a); } } diff --git a/tests/modeling/Model.update-variable.cpp b/tests/modeling/Model.update-variable.cpp index b7dbe772..5982e723 100644 --- a/tests/modeling/Model.update-variable.cpp +++ b/tests/modeling/Model.update-variable.cpp @@ -19,18 +19,18 @@ SCENARIO("Model: Update a variable", "[unit][modeling-old][Model]") { WHEN("Adding a continuous variable with infinite lower and upper bound and no objective function") { - Var x(env, -Inf, Inf, Continuous, "x"); + Var x(env, -Inf, Inf, Continuous, 0.,"x"); model.add(x); THEN("The variabe's objective coefficient should be zero") { - CHECK(std::abs(model.get_var_column(x).obj()) <= Tolerance::Sparsity); + CHECK(std::abs(model.get_var_obj(x)) <= Tolerance::Sparsity); } AND_THEN("The model's objective should not contain a non-zero coefficient x") { auto objective = model.get_obj_expr(); CHECK(objective.linear().empty()); - CHECK(objective.quadratic().empty()); + //CHECK(objective.quadratic().empty()); CHECK(objective.constant() == 0_a); CHECK(objective.is_zero()); } @@ -74,7 +74,7 @@ SCENARIO("Model: Update a variable", "[unit][modeling-old][Model]") { model.set_var_obj(x, 1); THEN("The variable's objective coefficient should be 1") { - CHECK(model.get_var_column(x).obj() == 1_a); + CHECK(model.get_var_obj(x) == 1_a); } THEN("The model's objective should have a coefficient for x of 1") { diff --git a/tests/modeling/QuadExpr.rotated-cone.cpp b/tests/modeling/QuadExpr.rotated-cone.cpp index ca194110..45b0b132 100644 --- a/tests/modeling/QuadExpr.rotated-cone.cpp +++ b/tests/modeling/QuadExpr.rotated-cone.cpp @@ -12,6 +12,7 @@ using namespace idol; #include "idol/general/linear-algebra/to_rotated_quadratic_cone.h" +/* double eval(const LinExpr& t_expr, const PrimalPoint& t_primal) { double result = 0; for (const auto& [var, constant] : t_expr) { @@ -31,12 +32,13 @@ double eval(const QuadExpr& t_expr, const PrimalPoint& t_primal) { double eval(const Expr& t_expr, const PrimalPoint& t_primal) { return t_expr.constant() + eval(t_expr.linear(), t_primal) + eval(t_expr.quadratic(), t_primal); } +*/ TEST_CASE("QuadExpr: rotated cone expression", "[unit][modeling-old][QuadExpr]") { - + /* Env env; - auto x = Var::make_vector<1>(env, Dim<1>(4), 0., Inf, Continuous, "x"); + auto x = Var::make_vector<1>(env, Dim<1>(4), 0., Inf, Continuous, 0., "x"); std::vector> quadratic_expressions = { x[0] * x[0] + x[1] * x[1], @@ -95,7 +97,7 @@ TEST_CASE("QuadExpr: rotated cone expression", "[unit][modeling-old][QuadExpr]") } } - + */ } #endif \ No newline at end of file diff --git a/tests/wrappers/Gurobi/Gurobi.create-constraint-with-backend.cpp b/tests/wrappers/Gurobi/Gurobi.create-constraint-with-backend.cpp index 62ffc952..26f299b6 100644 --- a/tests/wrappers/Gurobi/Gurobi.create-constraint-with-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.create-constraint-with-backend.cpp @@ -2,6 +2,7 @@ // Created by henri on 31/01/23. // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -123,7 +124,7 @@ SCENARIO("Gurobi: Create a constraint with backend", "[unit][backend][Gurobi]") const auto& backend = ((const Model &) model).optimizer().as(); - auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous); + auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous, 0.); model.add_vector(x); WHEN("A <=-constraint (rhs=1) is added with a Row") { diff --git a/tests/wrappers/Gurobi/Gurobi.create-constraint-without-backend.cpp b/tests/wrappers/Gurobi/Gurobi.create-constraint-without-backend.cpp index 9d9eac39..4db2db3d 100644 --- a/tests/wrappers/Gurobi/Gurobi.create-constraint-without-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.create-constraint-without-backend.cpp @@ -2,6 +2,7 @@ // Created by henri on 31/01/23. // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -127,7 +128,7 @@ SCENARIO("Gurobi: Create a constraint without backend", "[unit][backend][Gurobi] Env env; Model model(env); - auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous); + auto x = Var::make_vector(env, Dim<1>(3), 0., 1., Continuous, 0.); model.add_vector(x); WHEN("A <=-constraint (rhs=1) is added with a Row") { diff --git a/tests/wrappers/Gurobi/Gurobi.create-variable-and-constraint-with-backend.cpp b/tests/wrappers/Gurobi/Gurobi.create-variable-and-constraint-with-backend.cpp index 1e77dbb0..0cca474f 100644 --- a/tests/wrappers/Gurobi/Gurobi.create-variable-and-constraint-with-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.create-variable-and-constraint-with-backend.cpp @@ -3,6 +3,7 @@ // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -22,7 +23,7 @@ SCENARIO("Gurobi: Create variables and constraints intertwined with backend", "[ const auto& backend = ((const Model &) model).optimizer().as(); - Var y(env, 0., 1., Continuous, "y"); + Var y(env, 0., 1., Continuous, 0., "y"); model.add(y); Ctr c1(env, y >= 2, "c1"); @@ -32,7 +33,7 @@ SCENARIO("Gurobi: Create variables and constraints intertwined with backend", "[ WHEN("A variable x and constraint c2 (2y + x <= 10) are added to the model and the variable appears in the constraint") { - Var x(env, 0., 1., Continuous, "x"); + Var x(env, 0., 1., Continuous, 0., "x"); model.add(x); Ctr c2(env, 2 * y + x <= 10, "c2"); @@ -77,10 +78,10 @@ SCENARIO("Gurobi: Create variables and constraints intertwined with backend", "[ Ctr c2(env, LessOrEqual, 10, "c"); model.add(c2); - Column column; - column.linear().set(c2, 1); + LinExpr column; + column.set(c2, 1); - Var x(env, 0., 1., Continuous, std::move(column), "x"); + Var x(env, 0., 1., Continuous, 0., std::move(column), "x"); model.add(x); WHEN("Model::update_objective() is called") { diff --git a/tests/wrappers/Gurobi/Gurobi.create-variable-with-backend.cpp b/tests/wrappers/Gurobi/Gurobi.create-variable-with-backend.cpp index c39a86e7..7012bedd 100644 --- a/tests/wrappers/Gurobi/Gurobi.create-variable-with-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.create-variable-with-backend.cpp @@ -3,6 +3,7 @@ // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -24,7 +25,7 @@ SCENARIO("Gurobi: Create a variable with backend", "[unit][backend][Gurobi]") { WHEN("A continuous variable (lb=-15,ub=15) is added to the model") { - Var x(env, -15, 30, Continuous, "x"); + Var x(env, -15, 30, Continuous, 0., "x"); model.add(x); model.update(); @@ -58,7 +59,7 @@ SCENARIO("Gurobi: Create a variable with backend", "[unit][backend][Gurobi]") { WHEN("An integer variable (lb=-inf,ub=inf) is added to the model") { - Var x(env, -Inf, Inf, Integer, "x"); + Var x(env, -Inf, Inf, Integer, 0., "x"); model.add(x); model.update(); @@ -92,7 +93,7 @@ SCENARIO("Gurobi: Create a variable with backend", "[unit][backend][Gurobi]") { WHEN("A binary variable (lb=1,ub=1) is added to the model") { - Var x(env, 1, 1, Binary, "x"); + Var x(env, 1, 1, Binary, 0., "x"); model.add(x); model.update(); @@ -140,12 +141,12 @@ SCENARIO("Gurobi: Create a variable with backend", "[unit][backend][Gurobi]") { WHEN("A continuous variable (lb=0,ub=inf) is added with a Column") { - Column column(1); - column.linear().set(c[0], 0); - column.linear().set(c[1], 1); - column.linear().set(c[2], 2); + LinExpr column; + column.set(c[0], 0); + column.set(c[1], 1); + column.set(c[2], 2); - Var x(env, 0, Inf, Continuous, std::move(column), "x"); + Var x(env, 0, Inf, Continuous, 1., std::move(column), "x"); model.add(x); model.update(); diff --git a/tests/wrappers/Gurobi/Gurobi.create-variable-without-backend.cpp b/tests/wrappers/Gurobi/Gurobi.create-variable-without-backend.cpp index f9cb68dd..e0c0530c 100644 --- a/tests/wrappers/Gurobi/Gurobi.create-variable-without-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.create-variable-without-backend.cpp @@ -3,6 +3,7 @@ // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -20,7 +21,7 @@ SCENARIO("Gurobi: Create a variable without backend", "[unit][backend][Gurobi]") WHEN("A continuous variable (lb=-15,ub=15) is added to the model") { - Var x(env, -15, 30, Continuous, "x"); + Var x(env, -15, 30, Continuous, 0., "x"); model.add(x); model.use(Gurobi()); @@ -58,7 +59,7 @@ SCENARIO("Gurobi: Create a variable without backend", "[unit][backend][Gurobi]") WHEN("An integer variable (lb=-inf,ub=inf) is added to the model") { - Var x(env, -Inf, Inf, Integer, "x"); + Var x(env, -Inf, Inf, Integer, 0., "x"); model.add(x); model.use(Gurobi()); @@ -96,7 +97,7 @@ SCENARIO("Gurobi: Create a variable without backend", "[unit][backend][Gurobi]") WHEN("A binary variable (lb=1,ub=1) is added to the model") { - Var x(env, 1, 1, Binary, "x"); + Var x(env, 1, 1, Binary, 0., "x"); model.add(x); model.use(Gurobi()); @@ -144,12 +145,12 @@ SCENARIO("Gurobi: Create a variable without backend", "[unit][backend][Gurobi]") WHEN("A continuous variable (lb=0,ub=inf) is added with a Column") { - Column column(1); - column.linear().set(c[0], 0); - column.linear().set(c[1], 1); - column.linear().set(c[2], 2); + LinExpr column; + column.set(c[0], 0); + column.set(c[1], 1); + column.set(c[2], 2); - Var x(env, 0, Inf, Continuous, std::move(column), "x"); + Var x(env, 0, Inf, Continuous, 1., std::move(column), "x"); model.add(x); model.use(Gurobi()); diff --git a/tests/wrappers/Gurobi/Gurobi.update-constraint-with-backend.cpp b/tests/wrappers/Gurobi/Gurobi.update-constraint-with-backend.cpp index 2f60393a..090004d8 100644 --- a/tests/wrappers/Gurobi/Gurobi.update-constraint-with-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.update-constraint-with-backend.cpp @@ -3,6 +3,7 @@ // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include diff --git a/tests/wrappers/Gurobi/Gurobi.update-objective-with-backend.cpp b/tests/wrappers/Gurobi/Gurobi.update-objective-with-backend.cpp index 634e62e2..5020bed4 100644 --- a/tests/wrappers/Gurobi/Gurobi.update-objective-with-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.update-objective-with-backend.cpp @@ -3,6 +3,7 @@ // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -17,8 +18,8 @@ SCENARIO("Gurobi: Update objective with backend", "[unit][backend][Gurobi]") { Env env; - Var x(env, 0., 1., Continuous, "x"); - Var y(env, 0., 1., Continuous, "y"); + Var x(env, 0., 1., Continuous, 0., "x"); + Var y(env, 0., 1., Continuous, 0., "y"); Model model(env); model.add(x); diff --git a/tests/wrappers/Gurobi/Gurobi.update-variable-with-backend.cpp b/tests/wrappers/Gurobi/Gurobi.update-variable-with-backend.cpp index 3b48eeee..491d0645 100644 --- a/tests/wrappers/Gurobi/Gurobi.update-variable-with-backend.cpp +++ b/tests/wrappers/Gurobi/Gurobi.update-variable-with-backend.cpp @@ -3,6 +3,7 @@ // #include "idol/mixed-integer/optimizers/wrappers/Gurobi/Gurobi.h" +#include "idol/mixed-integer/optimizers/wrappers/Gurobi/Optimizers_Gurobi.h" #include #include @@ -24,7 +25,7 @@ SCENARIO("Gurobi: Update a variable with backend", "[unit][backend][Gurobi]") { WHEN("A continuous variable (lb=0,ub=1) is added") { - Var x(env, 0., 1., Continuous, "x"); + Var x(env, 0., 1., Continuous, 0., "x"); model.add(x); WHEN("The variable is removed before Model::update_objective() is called") { diff --git a/tests/wrappers/all/toy_lp.cpp b/tests/wrappers/all/toy_lp.cpp index 46d7ceb9..5fc89df0 100644 --- a/tests/wrappers/all/toy_lp.cpp +++ b/tests/wrappers/all/toy_lp.cpp @@ -18,8 +18,8 @@ TEST_CASE("Solving small LPs") { WHEN("A bounded and feasible LP is solved") { // Example taken from http://lpsolve.sourceforge.net/5.5/formulate.htm#Construct%20the%20model%20from%20a%20Programming%20Language - Var x(env, 0, Inf, Continuous, "x"); - Var y(env, 0, Inf, Continuous, "y"); + Var x(env, 0, Inf, Continuous, 0., "x"); + Var y(env, 0, Inf, Continuous, 0., "y"); Ctr c1(env, 120 * x + 210 * y <= 15000); Ctr c2(env, 110 * x + 30 * y <= 4000); @@ -74,8 +74,8 @@ TEST_CASE("Solving small LPs") { WHEN("An unbounded LP is solved") { - Var x(env, 0, Inf, Continuous, "x"); - Var y(env, 0, Inf, Continuous, "y"); + Var x(env, 0, Inf, Continuous, 0., "x"); + Var y(env, 0, Inf, Continuous, 0., "y"); Ctr c1(env, x - 2 * y <= 1); Ctr c2(env, -2 * x + y <= 1); @@ -122,9 +122,9 @@ TEST_CASE("Solving small LPs") { WHEN("An infeasible LP is solved") { - Var u(env, 0., Inf, Continuous, "u"); - Var v(env, 0., Inf, Continuous, "v"); - Var w(env, 0., Inf, Continuous, "w"); + Var u(env, 0., Inf, Continuous, 0., "u"); + Var v(env, 0., Inf, Continuous, 0., "v"); + Var w(env, 0., Inf, Continuous, 0., "w"); Ctr c1(env, u + -2 * v + -1 * w >= 3); Ctr c2(env, -2 * u + v + -1 * w >= 2); auto objective = u + v - 2 * w; diff --git a/tests/wrappers/all/toy_milp.cpp b/tests/wrappers/all/toy_milp.cpp index 16acb1c5..4c76f93f 100644 --- a/tests/wrappers/all/toy_milp.cpp +++ b/tests/wrappers/all/toy_milp.cpp @@ -20,9 +20,9 @@ TEST_CASE("Solving small MIPs") { AND_WHEN("The root node is integer feasible") { // Taken from https://www.gurobi.com/documentation/9.5/examples/mip1_cpp_cpp.html#subsubsection:mip1_c++.cpp - Var x(env, 0., 1., Binary, "x"); - Var y(env, 0., 1., Binary, "y"); - Var z(env, 0., 1., Binary, "z"); + Var x(env, 0., 1., Binary, 0., "x"); + Var y(env, 0., 1., Binary, 0., "y"); + Var z(env, 0., 1., Binary, 0., "z"); Ctr c1(env, x + 2 * y + 3 * z <= 4); Ctr c2(env, x + y >= 1); auto objective = -x - y - 2 * z; @@ -62,9 +62,9 @@ TEST_CASE("Solving small MIPs") { AND_WHEN("The root not is not integer feasible") { - Var x(env, 0., 1., Binary, "x"); - Var y(env, 0., 1., Binary, "y"); - Var z(env, 0., 1., Binary, "z"); + Var x(env, 0., 1., Binary, 0., "x"); + Var y(env, 0., 1., Binary, 0., "y"); + Var z(env, 0., 1., Binary, 0., "z"); Ctr c1(env, x + 2 * y + 2.5 * z <= 4); Ctr c2(env, x + y >= 1); auto objective = -x - y - 2 * z; @@ -109,7 +109,7 @@ TEST_CASE("Solving small MIPs") { WHEN("The root node is infeasible") { - Var x(env, 0., 1., Binary, "x"); + Var x(env, 0., 1., Binary, 0., "x"); Ctr c1(env, x >= 1); Ctr c2(env, x <= 0); @@ -138,7 +138,7 @@ TEST_CASE("Solving small MIPs") { AND_WHEN("The root node is feasible") { - Var x(env, 0., 1., Binary, "x"); + Var x(env, 0., 1., Binary, 0., "x"); Ctr c1(env, x >= .1); Ctr c2(env, x <= .9); @@ -174,7 +174,7 @@ TEST_CASE("Solving small MIPs") { AND_WHEN("An unbounded MILP is solved") { - Var x(env, -Inf, Inf, Integer, "x"); + Var x(env, -Inf, Inf, Integer, 0., "x"); Model model(env); model.add(x); model.set_obj_expr(-x);