diff --git a/include/mp/flat/constr_algebraic.h b/include/mp/flat/constr_algebraic.h index 34aa3564c..96f7339b2 100644 --- a/include/mp/flat/constr_algebraic.h +++ b/include/mp/flat/constr_algebraic.h @@ -145,10 +145,18 @@ template class AlgConRhs { static constexpr const char* kind_str_[] = { "LT", "LE", "EQ", "GE", "GT" }; + static constexpr const char* kind_cmp_[] = + { "<", "<=", "==", ">=", ">" }; public: /// name static std::string GetTypeName() { return std::string("Rhs") + kind_str_[kind_+2]; } + /// Comparison name as string + static const char* GetCmpName() + { return kind_str_[kind_+2]; } + /// Comparison operator as string + static const char* GetCmpStr() + { return kind_cmp_[kind_+2]; } /// Constructor AlgConRhs(double r) : rhs_(r) { } /// Kind @@ -227,6 +235,28 @@ using QuadConGE = QuadConRhs< 1>; /// Quadratic constraint c'x+x`Qx > d using QuadConGT = QuadConRhs< 2>; + +/// Write an algebraic constraint +template +inline void WriteJSON(JSONW jw, + const AlgebraicConstraint& algc) { + WriteJSON(jw["body"], algc.GetBody()); + WriteJSON(jw["rhs_or_range"], algc.GetRhsOrRange()); +} + +/// Write alg con range +inline void WriteJSON(JSONW jw, + const AlgConRange& acr) { + jw << acr.lb() << acr.ub(); +} + +/// Write alg con rhs +template +inline void WriteJSON(JSONW jw, + const AlgConRhs& acrhs) { + jw << acrhs.GetCmpName() << acrhs.rhs(); +} + } // namespace mp #endif // CONSTRAINTS_ALGEBRAIC_H diff --git a/include/mp/flat/constr_base.h b/include/mp/flat/constr_base.h index af94db1ce..a5e73cfb2 100644 --- a/include/mp/flat/constr_base.h +++ b/include/mp/flat/constr_base.h @@ -182,6 +182,16 @@ class CustomFunctionalConstraint : }; +/// Write a CustomFunctionalConstraint<> +template +inline void WriteJSON(JW jw, + const CustomFunctionalConstraint& cfc) { + jw["res_var"] = cfc.GetResultVar(); + WriteJSON(jw["args"], cfc.GetArguments()); + WriteJSON(jw["params"], cfc.GetParameters()); +} + + /// Dummy template: compute result of functional constraint. /// Should be implemented for proper functional specializations, /// but has no sense for conic constraints, for example. @@ -336,6 +346,15 @@ class ConditionalConstraint : } }; +/// Write a CondCon +template +inline void WriteJSON(JW jw, + const ConditionalConstraint& condc) { + jw["res_var"] = condc.GetResultVar(); + WriteJSON(jw["con"], condc.GetConstraint()); +} + + //////////////////////////////////////////////////////////////////////// /// Args is the argument type, e.g., array of variables, or an expression /// Params is the parameter type, e.g., array of numbers. Can be empty diff --git a/include/mp/flat/constr_functional.h b/include/mp/flat/constr_functional.h index 1790f6568..e24c62b00 100644 --- a/include/mp/flat/constr_functional.h +++ b/include/mp/flat/constr_functional.h @@ -215,6 +215,15 @@ class LinearFunctionalConstraint : } }; + +/// Write a LinFuncCon +inline void WriteJSON(JSONW jw, + const LinearFunctionalConstraint& lfc) { + jw["res_var"] = lfc.GetResultVar(); + WriteJSON(jw["expr"], lfc.GetAffineExpr()); +} + + //////////////////////////////////////////////////////////////////////// /// Quadratic Functional Constraint: r = quad_expr class QuadraticFunctionalConstraint : @@ -267,6 +276,14 @@ class QuadraticFunctionalConstraint : }; +/// Write a QuadrFuncCon +inline void WriteJSON(JSONW jw, + const QuadraticFunctionalConstraint& qfc) { + jw["res_var"] = qfc.GetResultVar(); + WriteJSON(jw["expr"], qfc.GetQuadExpr()); +} + + //////////////////////////////////////////////////////////////////////// /// AMPL represents PWL by a list of slopes /// and breakpoints between them, assuming (X0,Y0) is on the line @@ -375,6 +392,16 @@ class PLConParams { DEF_NUMERIC_FUNC_CONSTR_WITH_PRM( PLConstraint, VarArray1, PLConParams, "r = piecewise_linear(x)"); + +/// Write PLConParams +inline void WriteJSON(JSONW jw, + const PLConParams& plp) { + const auto& p = plp.GetPLPoints(); + jw["pl_x"] = p.x_; + jw["pl_y"] = p.y_; +} + + } // namespace mp #endif // CONSTRAINTS_FUNCTIONAL_H diff --git a/include/mp/flat/constr_general.h b/include/mp/flat/constr_general.h index 4c5a86ff4..e3ce1d9cf 100644 --- a/include/mp/flat/constr_general.h +++ b/include/mp/flat/constr_general.h @@ -79,6 +79,16 @@ using IndicatorConstraintQuadEQ = IndicatorConstraint; using IndicatorConstraintQuadGE = IndicatorConstraint; +/// Write an indicator constraint +template +inline void WriteJSON(JSONW jw, + const IndicatorConstraint& ic) { + jw["bin_var"] = ic.get_binary_var(); + jw["bin_val"] = ic.get_binary_value(); + WriteJSON(jw["con"], ic.get_constraint()); +} + + /// Unary encoding. /// Currently a dummy constraint just to build /// the reformulation graph. @@ -222,18 +232,13 @@ using SOS2Constraint = SOS_1or2_Constraint<2>; /// Write a SOS1, SOS2 constraint -template -inline void WriteJSON(Writer& wrt, const SOS_1or2_Constraint& sos) { - wrt.write("{} ", '{'); - wrt.write("\"sos_type\": {}, ", sos.get_sos_type()); - wrt.write("\"vars\": "); - WriteJSONVec(wrt, sos.get_vars()); - wrt.write(", \"weights\": "); - WriteJSONVec(wrt, sos.get_weights()); +template +inline void WriteJSON(JSONW jw, const SOS_1or2_Constraint& sos) { + jw["SOS_type"] = sos.get_sos_type(); + jw["vars"] = sos.get_vars(); + jw["weights"] = sos.get_weights(); auto bnds = sos.get_sum_of_vars_range(); - wrt.write(", \"sum_of_vars_range\": [{}, {}]", - bnds.lb_, bnds.ub_); - wrt.write(" {}", '}'); + jw["sum_of_vars_range"] << bnds.lb_ << bnds.ub_; } //////////////////////////////////////////////////////////////////////// @@ -291,6 +296,16 @@ using ComplementarityLinear = ComplementarityConstraint; /// Typedef ComplementarityQuadRange using ComplementarityQuadratic = ComplementarityConstraint; + +/// Write a ComplementarityCon +template +inline void WriteJSON(JSONW jw, + const ComplementarityConstraint& cc) { + WriteJSON(jw["expr"], cc.GetExpression()); + jw["compl_var"] = cc.GetVariable(); +} + + /// Quadratic cone DEF_STATIC_CONSTR_WITH_PRM( QuadraticConeConstraint, VarArray, DblParamArray, "Quadratic cone p1*x1 >= sqrt((p2*x2)^2 + ...))," diff --git a/include/mp/flat/constr_keeper.h b/include/mp/flat/constr_keeper.h index 00f6b3337..a92becea7 100644 --- a/include/mp/flat/constr_keeper.h +++ b/include/mp/flat/constr_keeper.h @@ -884,8 +884,7 @@ class ConstraintKeeper final jw["CON_TYPE"] = GetShortTypeName(); jw["index"] = i_con; jw["depth"] = cnt.GetDepth(); - // wrt.write("\"data\": "); - // WriteJSON(wrt, cnt.con_); + WriteJSON(jw["data"], cnt.con_); } wrt.write("\n"); // EOL GetLogger()->Append(wrt); diff --git a/include/mp/flat/converter_model.h b/include/mp/flat/converter_model.h index b7046f8ef..4c08eadca 100644 --- a/include/mp/flat/converter_model.h +++ b/include/mp/flat/converter_model.h @@ -74,7 +74,7 @@ class FlatModel fmt::MemoryWriter wrt; { MiniJSONWriter jw(wrt); - jw["VAR_INDEX"] = i+i_start; + jw["VAR_index"] = i+i_start; jw["bounds"] << lbs[i] << ubs[i]; jw["type"] = (int)types[i]; jw["is_from_nl"] = (int)is_var_original(i); @@ -238,13 +238,10 @@ class FlatModel fmt::MemoryWriter wrt; { MiniJSONWriter jw(wrt); - jw["OBJ_INDEX"] = i_obj; + jw["OBJECTIVE_index"] = i_obj; jw["sense"] = (int)obj.obj_sense(); - wrt.write("\"qp_terms\": "); - WriteJSON(wrt, obj.GetQPTerms()); - wrt.write("\"lin_terms\": "); - WriteJSON(wrt, obj.GetLinTerms()); - wrt.write(" {}\n", '}'); // with EOL + WriteJSON(jw["qp_terms"], obj.GetQPTerms()); + WriteJSON(jw["lin_terms"], obj.GetLinTerms()); } wrt.write("\n"); // EOL GetFileAppender().Append(wrt); diff --git a/include/mp/flat/expr_affine.h b/include/mp/flat/expr_affine.h index dbbad883b..262d7db2f 100644 --- a/include/mp/flat/expr_affine.h +++ b/include/mp/flat/expr_affine.h @@ -155,6 +155,10 @@ class LinTerms { std::vector vars_; }; +/// Specialize +template <> +void WriteJSON(JSONW jw, const LinTerms& qt); + /// Typedef AffineExpr using AffineExpr = AlgebraicExpression; diff --git a/include/mp/flat/expr_algebraic.h b/include/mp/flat/expr_algebraic.h index 4ce007984..5f147ac13 100644 --- a/include/mp/flat/expr_algebraic.h +++ b/include/mp/flat/expr_algebraic.h @@ -9,6 +9,7 @@ #include #include +#include "mp/util-json-write.hpp" #include "mp/arrayref.h" namespace mp { @@ -112,13 +113,23 @@ class AlgebraicExpression : public Body { }; /// Very general template to write -/// a JSON representation of anything +/// a JSON-like representation of anything template -void WriteJSON(Writer& , const Obj& ); +void WriteJSON(Writer w, const Obj& o) { + w = o; // default: assume assignable +} // unless WriteJSON is specialized for Obj + +/// Specialize our JSON writer +using JSONW = MiniJSONWriter; + +/// Write an AlgebraicExpression +template +inline void WriteJSON(JSONW jw, + const AlgebraicExpression& ale) { + WriteJSON(jw["body"], ale.GetBody()); + jw["const_term"] = ale.constant_term(); +} -/// Write JSON string of a vector -template -void WriteJSONVec(Writer& wrt, const Vec& vec); } // namespace mp diff --git a/include/mp/flat/expr_quadratic.h b/include/mp/flat/expr_quadratic.h index 014fc0718..2e9be94a4 100644 --- a/include/mp/flat/expr_quadratic.h +++ b/include/mp/flat/expr_quadratic.h @@ -131,6 +131,9 @@ class QuadTerms { std::vector vars2_; }; +/// Specialize +template <> +void WriteJSON(JSONW jw, const QuadTerms& qt); //////////////////////////////////////////////////////////////////////// /// Quadratic and linear terms. @@ -229,6 +232,10 @@ class QuadAndLinTerms : bool operator==(const QuadAndLinTerms& qlc) const { return equals(qlc); } }; +/// Specialize +template <> +void WriteJSON(JSONW jw, const QuadAndLinTerms& qt); + /// Typedef QuadraticExpr using QuadraticExpr = AlgebraicExpression; diff --git a/include/mp/util-json-write.h b/include/mp/util-json-write.h index 10ce0660d..b8f2a8020 100644 --- a/include/mp/util-json-write.h +++ b/include/mp/util-json-write.h @@ -65,24 +65,34 @@ class MiniJSONWriter { /// operator<<: make/ensure *this an array /// and write \a val a new element. /// + /// Equivalent: `++(*this) = val; return *this;` + /// /// @param val: scalar, tuple or container. - /// For non-supported types, define global method - /// Serialize(MiniJSONWriter& , const YourType& ). + /// For non-supported types, + /// write elements manually into + /// `auto jw_child = ++jw;`, + /// or define, e.g., + /// `Serialize(MiniJSONWriter , const YourType& )`, + /// to be used as follows: + /// `Serialize(++jw, obj[5]);` + /// (instead of `jw << obj[5]`.) /// /// @return *this. template - Node& operator<<(const Value& val) { - EnsureArray(); - InsertElementSeparator(); - Write(val); - return *this; - } + Node& operator<<(const Value& val) + { ++(*this) = val; return *this; } /// operator=: write \a val as a whole. /// /// @param val: scalar, tuple or container. - /// For non-supported types, define global method - /// Serialize(MiniJSONWriter& , const YourType& ). + /// For non-supported types, + /// write elements manually into + /// `auto jw_child = jw["data"];`, + /// or define, e.g., + /// `Serialize(MiniJSONWriter , const YourType& )`, + /// to be used as follows: + /// `Serialize(jw["data"], obj_data);` + /// (instead of `jw["data"] = obj_data`.) /// /// @note Can be called only once on a single node. template @@ -155,6 +165,7 @@ class MiniJSONWriter { int> = 0> // C++17 void DoWrite(Arithmetic v) { DoWriteScalar(v); } + /// Write a container template ()))> > diff --git a/include/mp/valcvt.h b/include/mp/valcvt.h index 3d60b868f..21fe98b8e 100644 --- a/include/mp/valcvt.h +++ b/include/mp/valcvt.h @@ -206,7 +206,7 @@ class ValuePresolverImpl : public BasicValuePresolver { void WriteNodes(JSON jw, const std::vector& nodes) { for (size_t i=0; iGetName()] = (int)nd; else diff --git a/src/std_constr.cc b/src/std_constr.cc index fbf79f987..b223aa348 100644 --- a/src/std_constr.cc +++ b/src/std_constr.cc @@ -46,37 +46,23 @@ void QuadTerms::sort_terms() { } } -template -void WriteJSONVec(Writer& wrt, const Vec& vec) { - wrt.write("{} ", '['); - for (size_t i=0; i +void WriteJSON(JSONW jw, const QuadTerms& qt) { + jw["coefs"] = qt.coefs(); + jw["vars1"] = qt.vars1(); + jw["vars2"] = qt.vars2(); } template <> -void WriteJSON(fmt::MemoryWriter& wrt, const QuadTerms& qt) { - wrt.write("{} ", '{'); - wrt.write("\"coefs\": "); - WriteJSONVec(wrt, qt.coefs()); - wrt.write(", \"vars1\": "); - WriteJSONVec(wrt, qt.vars1()); - wrt.write(", \"vars2\": "); - WriteJSONVec(wrt, qt.vars2()); - wrt.write(" {}", '}'); +void WriteJSON(JSONW jw, const LinTerms& qt) { + jw["coefs"] = qt.coefs(); + jw["vars"] = qt.vars(); } template <> -void WriteJSON(fmt::MemoryWriter& wrt, const LinTerms& qt) { - wrt.write("{} ", '{'); - wrt.write("\"coefs\": "); - WriteJSONVec(wrt, qt.coefs()); - wrt.write(", \"vars\": "); - WriteJSONVec(wrt, qt.vars()); - wrt.write(" {}", '}'); +void WriteJSON(JSONW jw, const QuadAndLinTerms& qlt) { + WriteJSON(jw["qp_terms"], qlt.GetQPTerms()); + WriteJSON(jw["lin_terms"], qlt.GetLinTerms()); } } // namespace mp