From 0ea0b8fa96f20603233eb05baae9514e3fe5e35b Mon Sep 17 00:00:00 2001 From: Gleb Belov Date: Fri, 26 Apr 2024 19:09:13 +1000 Subject: [PATCH] 'acc:...' options, -c with expressions #237 --- CMakeLists.txt | 2 +- include/mp/flat/constr_base.h | 1 + include/mp/flat/constr_keeper.h | 150 ++++++--------- include/mp/flat/model_api_base.h | 1 - include/mp/flat/model_info.hpp | 6 - include/mp/valcvt-node.h | 20 +- src/mp/flat/std_constr.cc | 317 +++++++++++++++++++++++++++++++ src/std_constr.cc | 185 ------------------ 8 files changed, 383 insertions(+), 299 deletions(-) create mode 100644 src/mp/flat/std_constr.cc delete mode 100644 src/std_constr.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index afe47b405..b9cccca49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,11 +411,11 @@ set(MP_SOURCES ) add_prefix(MP_SOURCES src/ expr.cc expr-writer.h nl-reader.cc option.cc os.cc problem.cc rstparser.cc sol.cc solver.cc solver-c.h sp.h sp.cc - std_constr.cc utils_file.cc utils_string.cc utils_clock.cc) set(MP_FLAT_SOURCES ) add_prefix(MP_FLAT_SOURCES src/mp/flat/ + std_constr.cc encodings.cpp piecewise_linear.cpp) diff --git a/include/mp/flat/constr_base.h b/include/mp/flat/constr_base.h index ef4c9a8cc..30ec0af44 100644 --- a/include/mp/flat/constr_base.h +++ b/include/mp/flat/constr_base.h @@ -463,6 +463,7 @@ inline void WriteJSON(JW jw, struct Name ## Id { \ static constexpr const char* description() { return Descr; } \ static constexpr const char* GetTypeName() { return #Name; } \ + static constexpr const char* GetExprTypeName() { return #Name "Expression"; } \ }; \ using Name ## Constraint = CustomFunctionalConstraint; \ using Name ## Expression = ExprWrapper< Name ## Constraint > diff --git a/include/mp/flat/constr_keeper.h b/include/mp/flat/constr_keeper.h index 91a4c4299..36b4596c4 100644 --- a/include/mp/flat/constr_keeper.h +++ b/include/mp/flat/constr_keeper.h @@ -21,17 +21,11 @@ namespace mp { + /// Converters handling custom constraints should derive from class BasicFlatConverter; -static const mp::OptionValueInfo values_item_acceptance[] = { - { "0", "Not accepted natively, automatic redefinition will be attempted", 0}, - { "1", "Accepted but automatic redefinition will be used where possible", 1}, - { "2", "Accepted natively and preferred", 2} -}; - - /// Violation summary for a class of vars/cons/objs struct ViolSummary { /// Check if this violation should be counted. @@ -392,10 +386,13 @@ class BasicConstraintKeeper { /// Convert to use expressions virtual void ConvertWithExpressions(BasicFlatConverter& cvt) = 0; - /// Query (user-chosen, if sensible) constraint acceptance level - virtual ConstraintAcceptanceLevel GetChosenAcceptanceLevel() - const { - assert(0<=acceptance_level_); // has been initialized + /// Query (user-chosen, if sensible) constraint acceptance level. + /// This is "combined" for constraint or expression + virtual ConstraintAcceptanceLevel GetChosenAcceptanceLevel() const { + if (acceptance_level_<0) { // not initialized + std::array alv = {0, 1, 2, 1, 2}; + acceptance_level_ = alv.at(acc_level_item_); + } return ConstraintAcceptanceLevel(acceptance_level_); } @@ -409,6 +406,16 @@ class BasicConstraintKeeper { virtual ConstraintAcceptanceLevel GetModelAPIAcceptance( const BasicFlatModelAPI& ) const = 0; + /// ModelAPI's acceptance level for the expression type. + /// This should not be used directly, instead: + /// GetChosenAcceptanceLevelEXPR() + virtual ExpressionAcceptanceLevel GetModelAPIAcceptanceEXPR( + const BasicFlatModelAPI& ) const = 0; + + /// Acceptance level of the overall expression interface in the ModelAPI + virtual ExpressionAcceptanceLevel GetModelAPIAcceptance_EXPR_INTF( + const BasicFlatModelAPI& ba) const = 0; + /// Constraint type_info virtual const std::type_info& GetTypeInfo() const =0; @@ -456,73 +463,16 @@ class BasicConstraintKeeper { virtual const char* GetShortTypeName() const; /// See what options are available for this constraint: - /// whether it is accepted natively by ModelAPI and/or can be - /// converted by the Converter. + /// whether it is accepted natively by ModelAPI, + /// as flat constraint or expression. /// If both, add constraint acceptance option. /// @note This should be called before using the class. - virtual void ConsiderAcceptanceOptions( + void ConsiderAcceptanceOptions( BasicFlatConverter& cvt, const BasicFlatModelAPI& ma, Env& env) { - auto cancvt = IfConverterConverts(cvt); - SetChosenAcceptanceLevel( GetModelAPIAcceptance(ma) ); - bool optadded = true; - if (true || cancvt) { // Changing to show all native cons - if (ConstraintAcceptanceLevel::Recommended == - GetChosenAcceptanceLevel()) { - env.AddStoredOption(GetAcceptanceOptionNames(), - fmt::format( - "Solver acceptance level for '{}', " - "default 2:\n\n.. value-table::", - GetConstraintName()).c_str(), - GetAccLevRef(), values_item_acceptance); - } else - if (ConstraintAcceptanceLevel::AcceptedButNotRecommended == - GetChosenAcceptanceLevel()) { - env.AddStoredOption(GetAcceptanceOptionNames(), - fmt::format( - "Solver acceptance level for '{}', " - "default 1:\n\n.. value-table::", - GetConstraintName()).c_str(), - GetAccLevRef(), values_item_acceptance); - } else - optadded = false; - } else - optadded = false; - if (!optadded) // Still add as hidden option - env.AddStoredOption(GetAcceptanceOptionNames(), - "HIDDEN", - GetAccLevRef(), 0, 2); - // Description table - env.SetConstraintListHeader( - "List of flat constraints.\n" - "For each constraint the following are given:\n" - "\n" - " - name,\n" - " - convertibility into simpler forms,\n" - " - solver acceptance natively,\n" - " - driver option(s) to modify acceptance\n" - " (enabled if both convertible and accepted)."); - std::string con_descr = (cancvt) ? "Convertible" : "NonConvertible"; - con_descr += "; "; - if (ConstraintAcceptanceLevel::Recommended == - GetChosenAcceptanceLevel()) - con_descr += "NativeRecommended"; - else if (ConstraintAcceptanceLevel::AcceptedButNotRecommended == - GetChosenAcceptanceLevel()) - con_descr += "NativeAcceptedButNotRecommended"; - else - con_descr += "NotAccepted"; - con_descr += "; "; - con_descr += GetAcceptanceOptionNames(); - env.AddConstraintDescr(GetConstraintName(), con_descr); - } - - /// Set user preferred acceptance level - virtual void SetChosenAcceptanceLevel( - ConstraintAcceptanceLevel acc) { - acceptance_level_ = static_cast< - std::underlying_type_t >(acc); + DoAddAcceptanceOptions(cvt, ma, env); + DoPopulateConstraintList(cvt, ma, env); } /// Mark as bridged. Use index only. @@ -553,7 +503,14 @@ class BasicConstraintKeeper { } protected: - int& GetAccLevRef() { return acceptance_level_; } + void DoAddAcceptanceOptions( + BasicFlatConverter& cvt, + const BasicFlatModelAPI& ma, + Env& env); + void DoPopulateConstraintList( + BasicFlatConverter& cvt, + const BasicFlatModelAPI& ma, + Env& env); private: @@ -561,30 +518,12 @@ class BasicConstraintKeeper { const char* const constr_name_; const char* const solver_opt_nm_; mutable std::string type_name_short_; - int acceptance_level_ {-1}; + mutable int acceptance_level_ {-1}; // combined, for either con or expr + int acc_level_item_ {0}; // item, corresp. to the solver option 0..4 + mutable int acc_level_expr_ {-1}; // expression only BasicLogger* exporter_{}; }; -const char* -BasicConstraintKeeper::GetShortTypeName() const { - if (type_name_short_.empty()) { - std::string acc_opt = GetAcceptanceOptionNames(); - assert(acc_opt.size()); - auto word_end = std::min(acc_opt.find(' '), - acc_opt.size()); - auto colon_pos = acc_opt.find(':'); - if (colon_pos>word_end) - colon_pos = 0; - type_name_short_ = acc_opt.substr( - colon_pos, word_end-colon_pos); - for (auto& c: type_name_short_) - if (':'==c) - c = '_'; // Markdown - assert(type_name_short_.size()); - } - return type_name_short_.c_str(); -} - /// Full id of a constraint: CK + index /// This helper class is parameterized by the Keeper @@ -699,6 +638,9 @@ class ConstraintKeeper final /// Constraint type using ConstraintType = Constraint; + /// The corresponding flat expression type + using FlatExprType = ExprWrapper; + /// Expression type, or, if appropriate, constraint type name, /// e.g., 'Abs' const char* GetExprOrConstraintName() const override @@ -804,6 +746,22 @@ class ConstraintKeeper final AcceptanceLevel((Constraint*)nullptr); } + /// Acceptance level of the corresponding expression type in the ModelAPI + ExpressionAcceptanceLevel GetModelAPIAcceptanceEXPR( + const BasicFlatModelAPI& ba) const override { + return + static_cast( ba ). + AcceptanceLevel((FlatExprType*)nullptr); + } + + /// Acceptance level of the overall expression interface in the ModelAPI + ExpressionAcceptanceLevel GetModelAPIAcceptance_EXPR_INTF( + const BasicFlatModelAPI& ba) const override { + return + static_cast( ba ). + ExpressionInterfaceAcceptanceLevel(); + } + /// Constraint type_info const std::type_info& GetTypeInfo() const override { return typeid(ConstraintType); } @@ -893,7 +851,7 @@ class ConstraintKeeper final private: // Storing in the ExprWrapper, // so we can send (wrapper &) to ModelAPI::AddExpression(). - ExprWrapper con_; + FlatExprType con_; int depth_ = 0; bool is_bridged_ = false; bool is_unused_ = false; diff --git a/include/mp/flat/model_api_base.h b/include/mp/flat/model_api_base.h index fc80b3ed7..0e20bbfc5 100644 --- a/include/mp/flat/model_api_base.h +++ b/include/mp/flat/model_api_base.h @@ -96,7 +96,6 @@ static mp::ConstraintAcceptanceLevel \ #define ACCEPT_EXPRESSION(FlatExprType, level) \ static mp::ExpressionAcceptanceLevel \ AcceptanceLevel(const FlatExprType*) { \ - typename FlatExprType::FlatConType* pc{}; \ static_assert( std::is_same_v >, \ #FlatExprType \ diff --git a/include/mp/flat/model_info.hpp b/include/mp/flat/model_info.hpp index 534adf1e4..201896147 100644 --- a/include/mp/flat/model_info.hpp +++ b/include/mp/flat/model_info.hpp @@ -81,12 +81,6 @@ class FlatModelInfoImpl : public FlatModelInfo { int nUnfxIntVars_ = 0; }; - -/// FlatModelInfo factory -std::unique_ptr CreateFlatModelInfo() { - return std::unique_ptr{new FlatModelInfoImpl()}; -} - } // namespace mp #endif // MODEL_INFO_HPP diff --git a/include/mp/valcvt-node.h b/include/mp/valcvt-node.h index fca26fb3b..395e0b0bc 100644 --- a/include/mp/valcvt-node.h +++ b/include/mp/valcvt-node.h @@ -219,7 +219,7 @@ class ValueNode { /// Retrieve T, dummy version template - const T& GetVal(size_t ) const { return {}; } + const T& GetVal(size_t ) const { assert(false); return {}; } /// Set T, dummy version template @@ -337,32 +337,32 @@ class ValueNode { template <> -std::vector& ValueNode::GetValVec() { return vd_; } +inline std::vector& ValueNode::GetValVec() { return vd_; } template <> -std::vector& ValueNode::GetValVec() { return vi_; } +inline std::vector& ValueNode::GetValVec() { return vi_; } template <> -std::vector& ValueNode::GetValVec() { return vStr_; } +inline std::vector& ValueNode::GetValVec() { return vStr_; } template <> -const double& ValueNode::GetVal(size_t i) const { return GetDblRef(i); } +inline const double& ValueNode::GetVal(size_t i) const { return GetDblRef(i); } template <> -const int& ValueNode::GetVal(size_t i) const { return GetIntRef(i); } +inline const int& ValueNode::GetVal(size_t i) const { return GetIntRef(i); } template <> -const VCString& ValueNode::GetVal(size_t i) const +inline const VCString& ValueNode::GetVal(size_t i) const { return GetStr(i); } template <> -void ValueNode::SetVal(size_t i, double v) { SetDbl(i, v); } +inline void ValueNode::SetVal(size_t i, double v) { SetDbl(i, v); } template <> -void ValueNode::SetVal(size_t i, int v) { SetInt(i, v); } +inline void ValueNode::SetVal(size_t i, int v) { SetInt(i, v); } template <> -void ValueNode::SetVal(size_t i, VCString v) +inline void ValueNode::SetVal(size_t i, VCString v) { SetStr(i, std::move(v)); } diff --git a/src/mp/flat/std_constr.cc b/src/mp/flat/std_constr.cc new file mode 100644 index 000000000..d88d6d04e --- /dev/null +++ b/src/mp/flat/std_constr.cc @@ -0,0 +1,317 @@ +#include +#include +#include + +#include "mp/format.h" +#include "mp/common.h" + +#include "mp/flat/expr_quadratic.h" +#include "mp/flat/obj_std.h" +#include "mp/flat/constr_keeper.h" +#include "mp/flat/model_info.hpp" + +namespace mp { + +/// @todo Keep consistent with the \a ConstraintGroups enum. +static const char* const congroup_names[] += { + "Default", + "All", + "Algebraic", + "Linear", + "Quadratic", + "Conic", + "General", + "Piecewiselinear", + "SOS", + "SOS1", + "SOS2", + "Logical" +}; + +const char* ConGroupName(int cg) { + assert(0<=cg + && cg var_coef_map; + for (size_t i=0; i(a, b) : std::pair(b, a); + }; + std::map, double> var_coef_map; + for (int i=0; iword_end) + colon_pos = 0; + type_name_short_ = acc_opt.substr( + colon_pos, word_end-colon_pos); + for (auto& c: type_name_short_) + if (':'==c) + c = '_'; // Markdown + assert(type_name_short_.size()); + } + return type_name_short_.c_str(); +} + + +/// acceptance when constraint only +static const mp::OptionValueInfo values_con_acceptance[] = { + { "0", "Not accepted natively, automatic redefinition will be attempted", 0}, + { "1", "Accepted but automatic redefinition will be used where possible", 1}, + { "2", "Accepted natively and preferred", 2} +}; + +/// acceptance when expression only +static const mp::OptionValueInfo values_expr_acceptance[] = { + { "0", "Not accepted natively, automatic redefinition will be attempted", 0}, + { "3", "Accepted but automatic redefinition will be used where possible", 3}, + { "4", "Accepted natively and preferred", 4} +}; + +/// acceptance when both constraint and expression are possible +/// (ANY SOLVER DOING THIS? Ilog CP?) +static const mp::OptionValueInfo values_universal_acceptance[] = { + { "0", "Not accepted natively, automatic redefinition will be attempted", 0}, + { "1", "Accepted as constraint but automatic redefinition will be used where possible", 1}, + { "2", "Accepted as constraint natively and preferred", 2}, + { "3", "Accepted as expression but automatic redefinition will be used where possible", 3}, + { "4", "Accepted as expression natively and preferred", 4} +}; + + + +void BasicConstraintKeeper::DoAddAcceptanceOptions( + BasicFlatConverter& , + const BasicFlatModelAPI& ma, + Env& env) { + auto cal = GetModelAPIAcceptance(ma); + auto eal = GetModelAPIAcceptanceEXPR(ma); + auto eial = GetModelAPIAcceptance_EXPR_INTF(ma); + const bool conacc = (ConstraintAcceptanceLevel::NotAccepted != cal); + const bool expracc = (ExpressionAcceptanceLevel::NotAccepted != eal); + if (conacc) + acc_level_item_ + = std::underlying_type_t(cal); + // we prefer expressions, if ModelAPI recommends expression interface + if (expracc + && (!conacc || ExpressionAcceptanceLevel::Recommended == eial)) + acc_level_item_ + = std::underlying_type_t(cal) + + 2; + if (conacc && expracc) { + env.AddStoredOption(GetAcceptanceOptionNames(), + fmt::format( + "Solver acceptance level for '{}' as either constraint or expression, " + "default {}:\n\n.. value-table::", + GetConstraintName(), acc_level_item_).c_str(), + acc_level_item_, values_universal_acceptance); + } else + if (conacc) { + env.AddStoredOption(GetAcceptanceOptionNames(), + fmt::format( + "Solver acceptance level for '{}' as flat constraint, " + "default {}:\n\n.. value-table::", + GetConstraintName(), acc_level_item_).c_str(), + acc_level_item_, values_con_acceptance); + } else + if (expracc) { + env.AddStoredOption(GetAcceptanceOptionNames(), + fmt::format( + "Solver acceptance level for '{}' as expression, " + "default {}:\n\n.. value-table::", + GetConstraintName(), acc_level_item_).c_str(), + acc_level_item_, values_expr_acceptance); + } else { + env.AddStoredOption(GetAcceptanceOptionNames(), + "HIDDEN", + acc_level_item_, 0, 4); + } +} + +void BasicConstraintKeeper::DoPopulateConstraintList( + BasicFlatConverter& cvt, + const BasicFlatModelAPI& ma, + Env& env) { + auto cancvt = IfConverterConverts(cvt); + auto cal = GetModelAPIAcceptance(ma); + auto eal = GetModelAPIAcceptanceEXPR(ma); + // Description table + env.SetConstraintListHeader( + "List of flat constraints.\n" + "For each constraint the following are given:\n" + "\n" + " - name,\n" + " - convertibility into simpler forms,\n" + " - solver acceptance natively as flat constraint,\n" + " - solver acceptance natively as expression,\n" + " - driver option(s) to modify acceptance\n" + " (enabled if both convertible and accepted)."); + std::string con_descr = (cancvt) ? "Convertible" : "NonConvertible"; + con_descr += "; "; + const char * const acc_lev_nam[] = { + "NotAccepted", "NativeAcceptedButNotRecommended", "NativeRecommended" + }; + con_descr += acc_lev_nam[std::underlying_type_t(cal)]; + con_descr += "; "; + con_descr += acc_lev_nam[std::underlying_type_t(eal)]; + con_descr += "; "; + con_descr += GetAcceptanceOptionNames(); + env.AddConstraintDescr(GetConstraintName(), con_descr); +} + +template +void WriteVar(Writer& pr, const char* name, + double lb, double ub, var::Type ty) { + assert(*name); + pr << "var " << name; + if (!lb && 1.0==ub && var::INTEGER==ty) + pr << " binary"; + else if (lb==ub) + pr << " = " << lb; + else { + if (lb > -DBL_MAX) + pr << " >=" << lb; + if (ub < DBL_MAX) + pr << " <=" << ub; + if (var::INTEGER == ty) + pr << " integer"; + } +} + +void WriteModelItem(fmt::MemoryWriter& wrt, const LinTerms& lt, + const std::vector& vnam) { + for (int i=0; i<(int)lt.size(); ++i) { + auto coef = lt.coef(i); + bool ifpos = coef>=0.0; + if (i) { + wrt << (ifpos ? " + " : " - "); + } else { + if (!ifpos) + wrt << "-"; + } + auto abscoef = std::fabs(coef); + if (1.0 != abscoef) + wrt << abscoef << '*'; + wrt << vnam.at(lt.var(i)); + } +} + +void WriteModelItem(fmt::MemoryWriter& wrt, const QuadTerms& qt, + const std::vector& vnam) { + for (int i=0; i<(int)qt.size(); ++i) { + auto coef = qt.coef(i); + bool ifpos = coef>=0.0; + if (i) { + wrt << (qt.coef(i)>=0.0 ? " + " : " - "); + } else + if (!ifpos) + wrt << "-"; + auto abscoef = std::fabs(coef); + if (1.0 != abscoef) + wrt << abscoef << '*'; + if (qt.var1(i)==qt.var2(i)) + wrt << vnam.at(qt.var1(i)) << "^2"; + else + wrt << vnam.at(qt.var1(i)) + << '*' << vnam.at(qt.var2(i)); + } +} + +void WriteModelItem(fmt::MemoryWriter& wrt, const QuadAndLinTerms& qlt, + const std::vector& vnam) { + WriteModelItem(wrt, qlt.GetLinTerms(), vnam); + if (qlt.GetQPTerms().size()) { + if (qlt.GetLinTerms().size()) + wrt << " + "; + wrt << '('; + WriteModelItem(wrt, qlt.GetQPTerms(), vnam); + wrt << ')'; + } +} + +void WriteModelItem(fmt::MemoryWriter& wrt, const QuadraticObjective& obj, + const std::vector& vnam) { + wrt << (obj.obj_sense() ? "maximize " : "minimize "); + assert(obj.name() && *obj.name()); + wrt << obj.name() << ": "; + WriteModelItem(wrt, obj.GetLinTerms(), vnam); + if (obj.GetQPTerms().size()) { + if (obj.GetLinTerms().size()) + wrt << " + "; + wrt << '('; + WriteModelItem(wrt, obj.GetQPTerms(), vnam); + wrt << ')'; + } +} + +// Generate +template +void WriteVar(fmt::MemoryWriter& pr, const char* name, + double lb, double ub, var::Type ty); + +template <> +void WriteJSON(JSONW jw, const QuadTerms& qt) { + jw["coefs"] = qt.coefs(); + jw["vars1"] = qt.vars1(); + jw["vars2"] = qt.vars2(); +} + +template <> +void WriteJSON(JSONW jw, const LinTerms& qt) { + jw["coefs"] = qt.coefs(); + jw["vars"] = qt.vars(); +} + +template <> +void WriteJSON(JSONW jw, const QuadAndLinTerms& qlt) { + WriteJSON(jw["qp_terms"], qlt.GetQPTerms()); + WriteJSON(jw["lin_terms"], qlt.GetLinTerms()); +} + + +/// FlatModelInfo factory +std::unique_ptr CreateFlatModelInfo() { + return std::unique_ptr{new FlatModelInfoImpl()}; +} + +} // namespace mp diff --git a/src/std_constr.cc b/src/std_constr.cc deleted file mode 100644 index cedad374c..000000000 --- a/src/std_constr.cc +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include -#include - -#include "mp/format.h" -#include "mp/util-json-write.hpp" -#include "mp/common.h" - -#include "mp/flat/expr_quadratic.h" -#include "mp/flat/obj_std.h" -#include "mp/flat/model_info.hpp" - -namespace mp { - -/// @todo Keep consistent with the \a ConstraintGroups enum. -static const char* const congroup_names[] -= { - "Default", - "All", - "Algebraic", - "Linear", - "Quadratic", - "Conic", - "General", - "Piecewiselinear", - "SOS", - "SOS1", - "SOS2", - "Logical" -}; - -const char* ConGroupName(int cg) { - assert(0<=cg - && cg var_coef_map; - for (size_t i=0; i(a, b) : std::pair(b, a); - }; - std::map, double> var_coef_map; - for (int i=0; i -void WriteVar(Writer& pr, const char* name, - double lb, double ub, var::Type ty) { - assert(*name); - pr << "var " << name; - if (!lb && 1.0==ub && var::INTEGER==ty) - pr << " binary"; - else if (lb==ub) - pr << " = " << lb; - else { - if (lb > -DBL_MAX) - pr << " >=" << lb; - if (ub < DBL_MAX) - pr << " <=" << ub; - if (var::INTEGER == ty) - pr << " integer"; - } -} - -void WriteModelItem(fmt::MemoryWriter& wrt, const LinTerms& lt, - const std::vector& vnam) { - for (int i=0; i<(int)lt.size(); ++i) { - auto coef = lt.coef(i); - bool ifpos = coef>=0.0; - if (i) { - wrt << (ifpos ? " + " : " - "); - } else { - if (!ifpos) - wrt << "-"; - } - auto abscoef = std::fabs(coef); - if (1.0 != abscoef) - wrt << abscoef << '*'; - wrt << vnam.at(lt.var(i)); - } -} - -void WriteModelItem(fmt::MemoryWriter& wrt, const QuadTerms& qt, - const std::vector& vnam) { - for (int i=0; i<(int)qt.size(); ++i) { - auto coef = qt.coef(i); - bool ifpos = coef>=0.0; - if (i) { - wrt << (qt.coef(i)>=0.0 ? " + " : " - "); - } else - if (!ifpos) - wrt << "-"; - auto abscoef = std::fabs(coef); - if (1.0 != abscoef) - wrt << abscoef << '*'; - if (qt.var1(i)==qt.var2(i)) - wrt << vnam.at(qt.var1(i)) << "^2"; - else - wrt << vnam.at(qt.var1(i)) - << '*' << vnam.at(qt.var2(i)); - } -} - -void WriteModelItem(fmt::MemoryWriter& wrt, const QuadAndLinTerms& qlt, - const std::vector& vnam) { - WriteModelItem(wrt, qlt.GetLinTerms(), vnam); - if (qlt.GetQPTerms().size()) { - if (qlt.GetLinTerms().size()) - wrt << " + "; - wrt << '('; - WriteModelItem(wrt, qlt.GetQPTerms(), vnam); - wrt << ')'; - } -} - -void WriteModelItem(fmt::MemoryWriter& wrt, const QuadraticObjective& obj, - const std::vector& vnam) { - wrt << (obj.obj_sense() ? "maximize " : "minimize "); - assert(obj.name() && *obj.name()); - wrt << obj.name() << ": "; - WriteModelItem(wrt, obj.GetLinTerms(), vnam); - if (obj.GetQPTerms().size()) { - if (obj.GetLinTerms().size()) - wrt << " + "; - wrt << '('; - WriteModelItem(wrt, obj.GetQPTerms(), vnam); - wrt << ')'; - } -} - -// Generate -template -void WriteVar(fmt::MemoryWriter& pr, const char* name, - double lb, double ub, var::Type ty); - -template <> -void WriteJSON(JSONW jw, const QuadTerms& qt) { - jw["coefs"] = qt.coefs(); - jw["vars1"] = qt.vars1(); - jw["vars2"] = qt.vars2(); -} - -template <> -void WriteJSON(JSONW jw, const LinTerms& qt) { - jw["coefs"] = qt.coefs(); - jw["vars"] = qt.vars(); -} - -template <> -void WriteJSON(JSONW jw, const QuadAndLinTerms& qlt) { - WriteJSON(jw["qp_terms"], qlt.GetQPTerms()); - WriteJSON(jw["lin_terms"], qlt.GetLinTerms()); -} - -} // namespace mp