From 9e3fd742a20536a529a3cf4ed4bbc5befd88076a Mon Sep 17 00:00:00 2001 From: Gleb Belov Date: Thu, 8 Dec 2022 13:49:13 +1100 Subject: [PATCH] Prepare MOSEK cones #192 Some general API extensions towards quadratic cones --- include/mp/flat/constr_base.h | 12 ++++++++++ include/mp/flat/constr_general.h | 8 +++++++ include/mp/flat/constr_keeper.h | 2 ++ include/mp/flat/converter.h | 16 +++++++++++-- include/mp/flat/redef/MIP/mul.h | 38 +++++++++++++++++++++++++++--- include/mp/flat/redef/redef_base.h | 9 +++++++ 6 files changed, 80 insertions(+), 5 deletions(-) diff --git a/include/mp/flat/constr_base.h b/include/mp/flat/constr_base.h index c5de1381c..b16fc1d72 100644 --- a/include/mp/flat/constr_base.h +++ b/include/mp/flat/constr_base.h @@ -92,6 +92,8 @@ template using ParamArray0 = ParamArrayN; /// Fixed parameter array of 1 double using DblParamArray1 = ParamArrayN; +/// Variable-length parameter array +using DblParamArray = std::vector; /// A functional constraint with given arguments /// and further info as parameters @@ -261,6 +263,16 @@ class ConditionalConstraint : #define DEF_CONDITIONAL_CONSTRAINT_WRAPPER(Name, StaticConName) \ using Name = ConditionalConstraint< StaticConName > +//////////////////////////////////////////////////////////////////////// +/// STATIC CONSTRAINTS +/// Workaround: defining as functional constraint (result unused) +/// Could be solved by a mix-in parent +#define DEF_STATIC_CONSTR(Name, Args, Descr) \ + DEF_LOGICAL_FUNC_CONSTR(Name, Args, Descr) +#define DEF_STATIC_CONSTR_WITH_PRM(Name, Args, Params, Descr) \ + DEF_LOGICAL_FUNC_CONSTR_WITH_PRM(Name, Args, Params, Descr) + + } // namespace mp #endif // BASIC_CONSTR_H diff --git a/include/mp/flat/constr_general.h b/include/mp/flat/constr_general.h index 3d04fcc19..d6fc1ecda 100644 --- a/include/mp/flat/constr_general.h +++ b/include/mp/flat/constr_general.h @@ -188,6 +188,14 @@ using ComplementarityLinear = ComplementarityConstraint; /// Typedef ComplementarityQuadRange using ComplementarityQuadratic = ComplementarityConstraint; +/// Quadratic cone +DEF_STATIC_CONSTR_WITH_PRM( QuadraticConeConstraint, VarArray, DblParamArray, + "Quadratic cone x1 >= sqrt(x2^2 + ...)) with factors " + "applied to the squared arguments, aka MOSEK 10 affine cones"); +/// Rotated quadratic cone +DEF_STATIC_CONSTR_WITH_PRM( RotatedQuadraticConeConstraint, VarArray, DblParamArray, + "Rotated quadratic cone x1*x2 >= sqrt(x3^2 + ...)) with factors " + "applied to the squared arguments, aka MOSEK 10 affine cones"); } // namespace mp diff --git a/include/mp/flat/constr_keeper.h b/include/mp/flat/constr_keeper.h index 7e3241b0e..1db1fded9 100644 --- a/include/mp/flat/constr_keeper.h +++ b/include/mp/flat/constr_keeper.h @@ -429,6 +429,8 @@ class ConstraintKeeper : public BasicConstraintKeeper { if (!cons_[i].IsBridged()) { try { // Try to convert all but allow failure ConvertConstraint(cons_[i], i); + } catch (const ConstraintConversionGracefulFailure& ) { + /// nothing } catch (const ConstraintConversionFailure& ccf) { GetConverter().AddWarning( ccf.key(), ccf.message() ); } diff --git a/include/mp/flat/converter.h b/include/mp/flat/converter.h index f3d667a41..0f1714e37 100644 --- a/include/mp/flat/converter.h +++ b/include/mp/flat/converter.h @@ -231,6 +231,14 @@ class FlatConverter : MP_DISPATCH(Convert(con, i)); } + /// Query if a constraint type + /// is natively accepted by the solver. + /// The parameter is only needed for type. + template + ConstraintAcceptanceLevel GetConstraintAcceptance(Con* ) const { + return GET_CONST_CONSTRAINT_KEEPER(Con).GetChosenAcceptanceLevel(); + } + /// Query if the constraint type /// can be converted. /// This method should not be redefined; @@ -738,10 +746,10 @@ class FlatConverter : bool IfPreproEqBinVar() const { return MPCD( CanPreprocess(options_.preprocessEqualityBvar_) ); } - /// Whether we pass quad obj terms + /// Whether we pass quad obj terms to the solver without linearization bool IfPassQuadObj() const { return options_.passQuadObj_; } - /// Whether we pass quad con terms + /// Whether we pass quad con terms to the solver without linearization bool IfPassQuadCon() const { return options_.passQuadCon_; } /// Whether to quadratize pow(..., const_pos_int). @@ -882,6 +890,10 @@ class FlatConverter : ComplementarityLinear, "acc:compl acc:compllin") STORE_CONSTRAINT_TYPE__NO_MAP( ComplementarityQuadratic, "acc:complquad") + STORE_CONSTRAINT_TYPE__NO_MAP( + QuadraticConeConstraint, "acc:quadcone") + STORE_CONSTRAINT_TYPE__NO_MAP( + RotatedQuadraticConeConstraint, "acc:rotatedquadcone") ////////////////////// Default map accessors ///////////////////////// diff --git a/include/mp/flat/redef/MIP/mul.h b/include/mp/flat/redef/MIP/mul.h index d04060ea7..debe7afed 100644 --- a/include/mp/flat/redef/MIP/mul.h +++ b/include/mp/flat/redef/MIP/mul.h @@ -27,18 +27,50 @@ class QCConverter_MIP : /// Check whether the constraint /// needs to be converted despite being accepted by ModelAPI. bool IfNeedsConversion(const ItemType& , int ) { - return !GetMC().IfPassQuadCon(); + return IfCvtAcceptsQPCones() || + !GetMC().IfPassQuadCon(); } /// Conversion - void Convert(const ItemType& qc, int ) { - LinearizeQPTerms(qc); + void Convert(const ItemType& qc, int i) { + if (IfCvtAcceptsQPCones() && // conex accepted + GetMC().IfPassQuadCon()) // passing quadratic to solver, incl. cones + TryConvertToCone(qc, i); + else + LinearizeQPTerms(qc); } protected: using Base::GetMC; + bool IfCvtAcceptsQPCones() { + return + GetMC().GetConstraintAcceptance((QuadraticConeConstraint*)nullptr) || + GetMC().GetConstraintAcceptance((RotatedQuadraticConeConstraint*)nullptr); + } + + void TryConvertToCone(const ItemType& qc, int ) { + if (!TryQuadCone(qc) && !TryRotatedQuadCone(qc)) + throw ConstraintConversionGracefulFailure(); + } + + bool TryQuadCone(const ItemType& qc) { + if (GetMC().GetConstraintAcceptance( + (QuadraticConeConstraint*)nullptr)) { + return true; + } + return false; + } + + bool TryRotatedQuadCone(const ItemType& qc) { + if (GetMC().GetConstraintAcceptance( + (RotatedQuadraticConeConstraint*)nullptr)) { + return true; + } + return false; + } + void LinearizeQPTerms(const ItemType& qc) { const auto& body = qc.GetBody(); // Copy lin terms diff --git a/include/mp/flat/redef/redef_base.h b/include/mp/flat/redef/redef_base.h index 087087308..9e3c3a4e5 100644 --- a/include/mp/flat/redef/redef_base.h +++ b/include/mp/flat/redef/redef_base.h @@ -24,6 +24,8 @@ class BasicItemConverter { return false; } + /// Access const ModelConverter + const ModelConverter& GetMC() const { return mdl_cvt_; } /// Access ModelConverter ModelConverter& GetMC() { return mdl_cvt_; } @@ -127,6 +129,13 @@ class ConstraintConversionFailure { }; +/// Graceful constraint conversion failure - no warnings +class ConstraintConversionGracefulFailure { +public: + ConstraintConversionGracefulFailure() { } +}; + + } // namespace mp #endif // REDEF_BASE_H