Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/apireference.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ AbstractVectorSet
Functions for getting properties of sets.
```@docs
dimension
dual_set
constant(s::EqualTo)
supports_dimension_update
update_dimension
Expand Down
52 changes: 52 additions & 0 deletions src/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ julia> dimension(PositiveSemidefiniteConeTriangle(2))
"""
function dimension end

"""
dual_set(s::AbstractSet)

Return the dual set of `s`, that is the dual cone of the set. This follows the
definition of duality discussed in [Duals](@ref).
See [Dual cone](https://en.wikipedia.org/wiki/Dual_cone_and_polar_cone) for more information.
If the dual cone is not defined it returns an error.

### Examples

```jldocstest
julia> dual_set(Reals(4))
Zeros(4)

julia> dual_set(SecondOrderCone(5))
SecondOrderCone(5)

julia> dual_set(ExponentialCone())
DualExponentialCone()
```
"""
function dual_set end

dual_set(s::AbstractSet) = error("Dual of $s is not implemented.")

"""
AbstractScalarSet

Expand Down Expand Up @@ -59,6 +84,8 @@ struct Reals <: AbstractVectorSet
dimension::Int
end

dual_set(s::Reals) = Zeros(dimension(s))

"""
Zeros(dimension)

Expand All @@ -68,6 +95,8 @@ struct Zeros <: AbstractVectorSet
dimension::Int
end

dual_set(s::Zeros) = Reals(dimension(s))

"""
Nonnegatives(dimension)

Expand All @@ -77,6 +106,8 @@ struct Nonnegatives <: AbstractVectorSet
dimension::Int
end

dual_set(s::Nonnegatives) = copy(s)

"""
Nonpositives(dimension)

Expand All @@ -86,6 +117,8 @@ struct Nonpositives <: AbstractVectorSet
dimension::Int
end

dual_set(s::Nonpositives) = copy(s)

"""
GreaterThan{T <: Real}(lower::T)

Expand Down Expand Up @@ -158,6 +191,8 @@ struct SecondOrderCone <: AbstractVectorSet
dimension::Int
end

dual_set(s::SecondOrderCone) = copy(s)

"""
RotatedSecondOrderCone(dimension)

Expand All @@ -167,6 +202,8 @@ struct RotatedSecondOrderCone <: AbstractVectorSet
dimension::Int
end

dual_set(s::RotatedSecondOrderCone) = copy(s)

"""
GeometricMeanCone(dimension)

Expand All @@ -183,13 +220,17 @@ The 3-dimensional exponential cone ``\\{ (x,y,z) \\in \\mathbb{R}^3 : y \\exp (x
"""
struct ExponentialCone <: AbstractVectorSet end

dual_set(s::ExponentialCone) = DualExponentialCone()

"""
DualExponentialCone()

The 3-dimensional dual exponential cone ``\\{ (u,v,w) \\in \\mathbb{R}^3 : -u \\exp (v/u) \\le \\exp(1) w, u < 0 \\}``.
"""
struct DualExponentialCone <: AbstractVectorSet end

dual_set(s::DualExponentialCone) = ExponentialCone()

"""
PowerCone{T <: Real}(exponent::T)

Expand All @@ -199,6 +240,8 @@ struct PowerCone{T <: Real} <: AbstractVectorSet
exponent::T
end

dual_set(s::PowerCone{T}) where T <: Real = DualPowerCone{T}(s.exponent)

"""
DualPowerCone{T <: Real}(exponent::T)

Expand All @@ -208,6 +251,8 @@ struct DualPowerCone{T <: Real} <: AbstractVectorSet
exponent::T
end

dual_set(s::DualPowerCone{T}) where T <: Real = PowerCone{T}(s.exponent)

dimension(s::Union{ExponentialCone, DualExponentialCone, PowerCone, DualPowerCone}) = 3

"""
Expand Down Expand Up @@ -383,6 +428,8 @@ struct PositiveSemidefiniteConeTriangle <: AbstractSymmetricMatrixSetTriangle
side_dimension::Int
end

dual_set(s::PositiveSemidefiniteConeTriangle) = copy(s)

"""
PositiveSemidefiniteConeSquare(side_dimension) <: AbstractSymmetricMatrixSetSquare

Expand Down Expand Up @@ -411,6 +458,11 @@ struct PositiveSemidefiniteConeSquare <: AbstractSymmetricMatrixSetSquare
side_dimension::Int
end

function dual_set(s::PositiveSemidefiniteConeSquare)
return error("""Dual of $s is not defined in MathOptInterface.
For more details see the comments in src/Bridges/Constraint/square.jl""")
end

triangular_form(::Type{PositiveSemidefiniteConeSquare}) = PositiveSemidefiniteConeTriangle

"""
Expand Down
71 changes: 70 additions & 1 deletion test/Utilities/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,75 @@ end
@test MOI.dimension(MOI.SOS2(collect(1:6))) === 6
end

@testset "Dual Set" begin
# Nonpositives
nonpositives3 = MOI.Nonpositives(3)
nonpositives4 = MOI.Nonpositives(4)
@test MOI.dual_set(nonpositives3) == nonpositives3
@test MOI.dual_set(nonpositives3) != nonpositives4
@test MOI.dual_set(nonpositives4) == nonpositives4
# Nonnegatives
nonnegatives3 = MOI.Nonnegatives(3)
nonnegatives4 = MOI.Nonnegatives(4)
@test MOI.dual_set(nonnegatives3) == nonnegatives3
@test MOI.dual_set(nonnegatives3) != nonnegatives4
@test MOI.dual_set(nonnegatives4) == nonnegatives4
# Zeros and Reals
zeros3 = MOI.Zeros(3)
zeros4 = MOI.Zeros(4)
reals3 = MOI.Reals(3)
reals4 = MOI.Reals(4)
@test MOI.dual_set(zeros3) == reals3
@test MOI.dual_set(reals3) == zeros3
@test MOI.dual_set(reals3) != zeros4
@test MOI.dual_set(zeros4) == reals4
@test MOI.dual_set(reals4) == zeros4
@test MOI.dual_set(zeros4) != reals3
#SOC
soc2 = MOI.SecondOrderCone(2)
soc3 = MOI.SecondOrderCone(3)
@test MOI.dual_set(soc2) == soc2
@test MOI.dual_set(soc2) != soc3
@test MOI.dual_set(soc3) == soc3
#RSOC
rsoc2 = MOI.RotatedSecondOrderCone(2)
rsoc3 = MOI.RotatedSecondOrderCone(3)
@test MOI.dual_set(rsoc2) == rsoc2
@test MOI.dual_set(rsoc2) != rsoc3
@test MOI.dual_set(rsoc3) == rsoc3
#PSDtriangle
psd2 = MOI.PositiveSemidefiniteConeTriangle(2)
psd3 = MOI.PositiveSemidefiniteConeTriangle(3)
@test MOI.dual_set(psd2) == psd2
@test MOI.dual_set(psd2) != psd3
@test MOI.dual_set(psd3) == psd3
# Exponential
exp = MOI.ExponentialCone()
dual_exp = MOI.DualExponentialCone()
@test MOI.dual_set(exp) == dual_exp
@test MOI.dual_set(exp) != exp
@test MOI.dual_set(dual_exp) == exp
@test MOI.dual_set(dual_exp) != dual_exp
# Power
pow03 = MOI.PowerCone(0.3)
pow04 = MOI.PowerCone(0.4)
dual_pow03 = MOI.DualPowerCone(0.3)
@test MOI.dual_set(pow03) == dual_pow03
@test MOI.dual_set(pow03) != pow03
@test MOI.dual_set(dual_pow03) == pow03
@test MOI.dual_set(dual_pow03) != pow04
@test MOI.dual_set(dual_pow03) != dual_pow03
# PSDSquare error
s = MOI.PositiveSemidefiniteConeSquare(4)
err = ErrorException("""Dual of $s is not defined in MathOptInterface.
For more details see the comments in src/Bridges/Constraint/square.jl""")
@test_throws err MOI.dual_set(MOI.PositiveSemidefiniteConeSquare(4))
# Not implemented
s = MOI.LogDetConeTriangle(4)
err = ErrorException("Dual of $s is not implemented.")
@test_throws err MOI.dual_set(MOI.LogDetConeTriangle(4))
end

@testset "Set dot" begin
vec = zeros(6)
@test MOIU.set_dot(vec, vec, MOI.SecondOrderCone(6)) == 0
Expand Down Expand Up @@ -114,4 +183,4 @@ end
@test MOIU. dot_coefficients(sp_vec, MOI.LogDetConeTriangle(3)) == sp_vec
sp_vec[5] = 1
@test MOIU.dot_coefficients(sp_vec, MOI.LogDetConeTriangle(3)) == sp_vec
end
end