diff --git a/docs/src/background/duality.md b/docs/src/background/duality.md index 1042e2b5eb..602fdad25f 100644 --- a/docs/src/background/duality.md +++ b/docs/src/background/duality.md @@ -113,7 +113,9 @@ and similarly, the dual is: The scalar product is different from the canonical one for the sets [`PositiveSemidefiniteConeTriangle`](@ref), [`LogDetConeTriangle`](@ref), -[`RootDetConeTriangle`](@ref). +[`RootDetConeTriangle`](@ref), +[`FrobeniusProductPostiviveSemidefiniteConeTriangle`](@ref) and +[`LinearMatrixInequalityConeTriangle`](@ref). If the set ``C_i`` of the section [Duality](@ref) is one of these three cones, then the rows of the matrix ``A_i`` corresponding to off-diagonal entries are diff --git a/docs/src/manual/standard_form.md b/docs/src/manual/standard_form.md index 2d8855e21a..88ff9b3cab 100644 --- a/docs/src/manual/standard_form.md +++ b/docs/src/manual/standard_form.md @@ -98,7 +98,8 @@ The matrix-valued set types implemented in MathOptInterface.jl are: | [`NormSpectralCone(r, c)`](@ref MathOptInterface.NormSpectralCone) | ``\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sigma_1(X), X \mbox{ is a } r\times c\mbox{ matrix} \}`` | [`NormNuclearCone(r, c)`](@ref MathOptInterface.NormNuclearCone) | ``\{ (t, X) \in \mathbb{R}^{1 + r \times c} : t \ge \sum_i \sigma_i(X), X \mbox{ is a } r\times c\mbox{ matrix} \}`` | | [`HermitianPositiveSemidefiniteConeTriangle(d)`](@ref MathOptInterface.HermitianPositiveSemidefiniteConeTriangle) | The cone of Hermitian positive semidefinite matrices, with -`side_dimension` rows and columns. | +| [`FrobeniusProductPostiviveSemidefiniteConeTriangle(d, A)`](@ref MathOptInterface.FrobeniusProductPostiviveSemidefiniteConeTriangle) | The cone of positive semidefinite matrices, with `side_dimension` rows and columns and their Frobenius inner product with the matrices in `A`. | +| [`LinearMatrixInequalityConeTriangle(d, A)`](@ref MathOptInterface.LinearMatrixInequalityConeTriangle) | The cone of vector `y` and symmetric `C`, with `side_dimension` rows and columns such that ``\sum_i y_i A_i + C`` is positive semidefinite. | Some of these cones can take two forms: `XXXConeTriangle` and `XXXConeSquare`. diff --git a/docs/src/reference/standard_form.md b/docs/src/reference/standard_form.md index e4f77fe341..6c4325850a 100644 --- a/docs/src/reference/standard_form.md +++ b/docs/src/reference/standard_form.md @@ -152,4 +152,6 @@ LogDetConeTriangle LogDetConeSquare RootDetConeTriangle RootDetConeSquare +FrobeniusProductPostiviveSemidefiniteConeTriangle +LinearMatrixInequalityConeTriangle ``` diff --git a/src/Bridges/bridge.jl b/src/Bridges/bridge.jl index 69a7a3abd4..22b25cefca 100644 --- a/src/Bridges/bridge.jl +++ b/src/Bridges/bridge.jl @@ -283,3 +283,24 @@ If you implement this method, you must also implement [`needs_final_touch`](@ref). """ function final_touch end + +""" + struct FirstBridge <: MOI.AbstractConstraintAttribute end + +Returns the first bridge used to bridge the constraint. + +!!! warning + The indices of the bridge correspond to internal indices and may not + correspond to indices of the model this attribute is got from. +""" +struct FirstBridge <: MOI.AbstractConstraintAttribute end + +MOI.is_set_by_optimize(::FirstBridge) = true +MOI.get(::MOI.ModelLike, ::FirstBridge, b::MOI.Bridges.AbstractBridge) = b +function MOI.Utilities.map_indices( + ::Function, + ::FirstBridge, + b::MOI.Bridges.AbstractBridge, +) + return b +end diff --git a/src/Utilities/model.jl b/src/Utilities/model.jl index 128c9b20d0..5f69dafee2 100644 --- a/src/Utilities/model.jl +++ b/src/Utilities/model.jl @@ -795,6 +795,8 @@ const LessThanIndicatorZero{T} = MOI.ScaledPositiveSemidefiniteConeTriangle, MOI.RootDetConeTriangle, MOI.RootDetConeSquare, + MOI.FrobeniusProductPostiviveSemidefiniteConeTriangle, + MOI.LinearMatrixInequalityConeTriangle, MOI.LogDetConeTriangle, MOI.LogDetConeSquare, MOI.AllDifferent, diff --git a/src/Utilities/results.jl b/src/Utilities/results.jl index e693a7b7ee..ca12811e97 100644 --- a/src/Utilities/results.jl +++ b/src/Utilities/results.jl @@ -500,11 +500,7 @@ end Return the scalar product between a vector `x` of the set `set` and a vector `y` of the dual of the set `s`. """ -function set_dot( - x::AbstractVector, - y::AbstractVector, - set::MOI.AbstractVectorSet, -) +function set_dot(x::AbstractVector, y::AbstractVector, ::MOI.AbstractVectorSet) return dot(x, y) end @@ -514,7 +510,7 @@ end Return the scalar product between a number `x` of the set `set` and a number `y` of the dual of the set `s`. """ -set_dot(x, y, set::MOI.AbstractScalarSet) = dot(x, y) +set_dot(x, y, ::MOI.AbstractScalarSet) = dot(x, y) function triangle_dot( x::AbstractVector{S}, @@ -575,13 +571,26 @@ function set_dot( return x[1] * y[1] + x[2] * y[2] + triangle_dot(x, y, set.side_dimension, 2) end +function set_dot( + x::AbstractVector, + y::AbstractVector, + set::Union{ + MOI.FrobeniusProductPostiviveSemidefiniteConeTriangle, + MOI.LinearMatrixInequalityConeTriangle, + }, +) + m = length(set.matrices) + return LinearAlgebra.dot(view(x, 1:m), view(y, 1:m)) + + triangle_dot(x, y, set.side_dimension, m) +end + """ dot_coefficients(a::AbstractVector, set::AbstractVectorSet) Return the vector `b` such that for all vector `x` of the set `set`, `set_dot(b, x, set)` is equal to `dot(a, x)`. """ -function dot_coefficients(a::AbstractVector, set::MOI.AbstractVectorSet) +function dot_coefficients(a::AbstractVector, ::MOI.AbstractVectorSet) return a end @@ -633,3 +642,15 @@ function dot_coefficients(a::AbstractVector, set::MOI.LogDetConeTriangle) triangle_coefficients!(b, set.side_dimension, 2) return b end + +function set_dot( + a::AbstractVector, + set::Union{ + MOI.FrobeniusProductPostiviveSemidefiniteConeTriangle, + MOI.LinearMatrixInequalityConeTriangle, + }, +) + b = copy(a) + triangle_coefficients!(b, set.side_dimension, length(set.matrices)) + return b +end diff --git a/src/sets.jl b/src/sets.jl index ce2e25479a..852b58e648 100644 --- a/src/sets.jl +++ b/src/sets.jl @@ -880,7 +880,7 @@ MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInte """ struct ExponentialCone <: AbstractVectorSet end -dual_set(s::ExponentialCone) = DualExponentialCone() +dual_set(::ExponentialCone) = DualExponentialCone() dual_set_type(::Type{ExponentialCone}) = DualExponentialCone dimension(::ExponentialCone) = 3 @@ -906,7 +906,7 @@ MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInte """ struct DualExponentialCone <: AbstractVectorSet end -dual_set(s::DualExponentialCone) = ExponentialCone() +dual_set(::DualExponentialCone) = ExponentialCone() dual_set_type(::Type{DualExponentialCone}) = ExponentialCone dimension(::DualExponentialCone) = 3 @@ -1735,6 +1735,61 @@ function triangular_form(set::RootDetConeSquare) return RootDetConeTriangle(set.side_dimension) end +""" + FrobeniusProductPostiviveSemidefiniteConeTriangle{M}(side_dimension::Int, matrices::Vector{M}) + +Given `m` symmetric matrices `A_1`, ..., `A_m` given in `matrices`, the frobenius inner +product of positive semidefinite matrices is the convex cone: +``\\{ ((\\langle A_1, X \\rangle, ..., \\langle A_m, X \\rangle, X) \\in \\mathbb{R}^{m + d(d+1)/2} : X \\text{ postive semidefinite} \\}``, +where the matrix `X` is represented in the same symmetric packed format as in +the [`PositiveSemidefiniteConeTriangle`](@ref). +""" +struct FrobeniusProductPostiviveSemidefiniteConeTriangle{M} <: AbstractVectorSet + side_dimension::Int + matrices::Vector{M} +end + +function dimension(s::FrobeniusProductPostiviveSemidefiniteConeTriangle) + return length(s.matrices) + s.side_dimension^2 +end + +function dual_set(s::FrobeniusProductPostiviveSemidefiniteConeTriangle) + return LinearMatrixInequalityConeTriangle(s.side_dimension, s.matrices) +end + +function dual_set_type( + ::Type{FrobeniusProductPostiviveSemidefiniteConeTriangle{M}}, +) where {M} + return LinearMatrixInequalityConeTriangle +end + +""" + LinearMatrixInequalityConeTriangle{M}(side_dimension::Int, matrices::Vector{M}) + +Given `m` symmetric matrices `A_1`, ..., `A_m` given in `matrices`, the linear +matrix inequality cone is the convex cone: +``\\{ ((y, C) \\in \\mathbb{R}^{m + d(d+1)/2} : \\sum_{i=1}^m y_i A_i + C \\text{ postive semidefinite} \\}``, +where the matrix `C` is represented in the same symmetric packed format as in +the [`PositiveSemidefiniteConeTriangle`](@ref). +""" +struct LinearMatrixInequalityConeTriangle{M} <: AbstractVectorSet + side_dimension::Int + matrices::Vector{M} +end + +dimension(s::LinearMatrixInequalityConeTriangle) = length(s.matrices) + s.side_dimension^2 + +function dual_set(s::LinearMatrixInequalityConeTriangle) + return FrobeniusProductPostiviveSemidefiniteConeTriangle( + s.side_dimension, + s.matrices, + ) +end + +function dual_set_type(::Type{LinearMatrixInequalityConeTriangle{M}}) where {M} + return FrobeniusProductPostiviveSemidefiniteConeTriangle +end + """ SOS1{T<:Real}(weights::Vector{T})