Skip to content

Commit 57fc52c

Browse files
authored
Merge pull request #1002 from JuliaOpt/bl/dual_set_type
Add dual_set_type
2 parents e3cfaaf + 29e9ea2 commit 57fc52c

File tree

4 files changed

+146
-90
lines changed

4 files changed

+146
-90
lines changed

docs/src/apireference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ Functions for getting properties of sets.
310310
```@docs
311311
dimension
312312
dual_set
313+
dual_set_type
313314
constant(s::EqualTo)
314315
supports_dimension_update
315316
update_dimension

src/sets.jl

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,29 @@ function dual_set end
5757

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

60+
"""
61+
dual_set_type(S::Type{<:AbstractSet})
62+
63+
Return the type of dual set of sets of type `S`, as returned by
64+
[`dual_set`](@ref). If the dual cone is not defined it returns an error.
65+
66+
### Examples
67+
68+
```jldocstest
69+
julia> dual_set_type(Reals)
70+
Zeros
71+
72+
julia> dual_set_type(SecondOrderCone)
73+
SecondOrderCone
74+
75+
julia> dual_set_type(ExponentialCone)
76+
DualExponentialCone
77+
```
78+
"""
79+
function dual_set_type end
80+
81+
dual_set_type(S::Type{<:AbstractSet}) = error("Dual type of $S is not implemented.")
82+
6083
"""
6184
AbstractScalarSet
6285
@@ -87,6 +110,7 @@ struct Reals <: AbstractVectorSet
87110
end
88111

89112
dual_set(s::Reals) = Zeros(dimension(s))
113+
dual_set_type(::Type{Reals}) = Zeros
90114

91115
"""
92116
Zeros(dimension)
@@ -98,6 +122,7 @@ struct Zeros <: AbstractVectorSet
98122
end
99123

100124
dual_set(s::Zeros) = Reals(dimension(s))
125+
dual_set_type(::Type{Zeros}) = Reals
101126

102127
"""
103128
Nonnegatives(dimension)
@@ -109,6 +134,7 @@ struct Nonnegatives <: AbstractVectorSet
109134
end
110135

111136
dual_set(s::Nonnegatives) = copy(s)
137+
dual_set_type(::Type{Nonnegatives}) = Nonnegatives
112138

113139
"""
114140
Nonpositives(dimension)
@@ -120,6 +146,7 @@ struct Nonpositives <: AbstractVectorSet
120146
end
121147

122148
dual_set(s::Nonpositives) = copy(s)
149+
dual_set_type(::Type{Nonpositives}) = Nonpositives
123150

124151
"""
125152
GreaterThan{T <: Real}(lower::T)
@@ -198,6 +225,7 @@ struct NormInfinityCone <: AbstractVectorSet
198225
end
199226

200227
dual_set(s::NormInfinityCone) = NormOneCone(dimension(s))
228+
dual_set_type(::Type{NormInfinityCone}) = NormOneCone
201229

202230
"""
203231
NormOneCone(dimension)
@@ -209,6 +237,7 @@ struct NormOneCone <: AbstractVectorSet
209237
end
210238

211239
dual_set(s::NormOneCone) = NormInfinityCone(dimension(s))
240+
dual_set_type(::Type{NormOneCone}) = NormInfinityCone
212241

213242
"""
214243
SecondOrderCone(dimension)
@@ -220,6 +249,7 @@ struct SecondOrderCone <: AbstractVectorSet
220249
end
221250

222251
dual_set(s::SecondOrderCone) = copy(s)
252+
dual_set_type(::Type{SecondOrderCone}) = SecondOrderCone
223253

224254
"""
225255
RotatedSecondOrderCone(dimension)
@@ -231,6 +261,7 @@ struct RotatedSecondOrderCone <: AbstractVectorSet
231261
end
232262

233263
dual_set(s::RotatedSecondOrderCone) = copy(s)
264+
dual_set_type(::Type{RotatedSecondOrderCone}) = RotatedSecondOrderCone
234265

235266
"""
236267
GeometricMeanCone(dimension)
@@ -249,6 +280,7 @@ The 3-dimensional exponential cone ``\\{ (x,y,z) \\in \\mathbb{R}^3 : y \\exp (x
249280
struct ExponentialCone <: AbstractVectorSet end
250281

251282
dual_set(s::ExponentialCone) = DualExponentialCone()
283+
dual_set_type(::Type{ExponentialCone}) = DualExponentialCone
252284

253285
"""
254286
DualExponentialCone()
@@ -258,6 +290,7 @@ The 3-dimensional dual exponential cone ``\\{ (u,v,w) \\in \\mathbb{R}^3 : -u \\
258290
struct DualExponentialCone <: AbstractVectorSet end
259291

260292
dual_set(s::DualExponentialCone) = ExponentialCone()
293+
dual_set_type(::Type{DualExponentialCone}) = ExponentialCone
261294

262295
"""
263296
PowerCone{T <: Real}(exponent::T)
@@ -269,6 +302,7 @@ struct PowerCone{T <: Real} <: AbstractVectorSet
269302
end
270303

271304
dual_set(s::PowerCone{T}) where T <: Real = DualPowerCone{T}(s.exponent)
305+
dual_set_type(::Type{PowerCone{T}}) where T <: Real = DualPowerCone{T}
272306

273307
"""
274308
DualPowerCone{T <: Real}(exponent::T)
@@ -280,6 +314,7 @@ struct DualPowerCone{T <: Real} <: AbstractVectorSet
280314
end
281315

282316
dual_set(s::DualPowerCone{T}) where T <: Real = PowerCone{T}(s.exponent)
317+
dual_set_type(::Type{DualPowerCone{T}}) where T <: Real = PowerCone{T}
283318

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

@@ -308,6 +343,7 @@ struct NormSpectralCone <: AbstractVectorSet
308343
end
309344

310345
dual_set(s::NormSpectralCone) = NormNuclearCone(s.row_dim, s.column_dim)
346+
dual_set_type(::Type{NormSpectralCone}) = NormNuclearCone
311347

312348
"""
313349
NormNuclearCone(row_dim, column_dim)
@@ -321,6 +357,7 @@ struct NormNuclearCone <: AbstractVectorSet
321357
end
322358

323359
dual_set(s::NormNuclearCone) = NormSpectralCone(s.row_dim, s.column_dim)
360+
dual_set_type(::Type{NormNuclearCone}) = NormSpectralCone
324361

325362
dimension(s::Union{NormSpectralCone, NormNuclearCone}) = 1 + s.row_dim * s.column_dim
326363

@@ -498,6 +535,7 @@ struct PositiveSemidefiniteConeTriangle <: AbstractSymmetricMatrixSetTriangle
498535
end
499536

500537
dual_set(s::PositiveSemidefiniteConeTriangle) = copy(s)
538+
dual_set_type(::Type{PositiveSemidefiniteConeTriangle}) = PositiveSemidefiniteConeTriangle
501539

502540
"""
503541
PositiveSemidefiniteConeSquare(side_dimension) <: AbstractSymmetricMatrixSetSquare
@@ -527,9 +565,15 @@ struct PositiveSemidefiniteConeSquare <: AbstractSymmetricMatrixSetSquare
527565
side_dimension::Int
528566
end
529567

530-
function dual_set(s::PositiveSemidefiniteConeSquare)
531-
return error("""Dual of $s is not defined in MathOptInterface.
532-
For more details see the comments in src/Bridges/Constraint/square.jl""")
568+
function _dual_set_square_error()
569+
error("""Dual of `PositiveSemidefiniteConeSquare` is not defined in MathOptInterface.
570+
For more details see the comments in `src/Bridges/Constraint/square.jl`.""")
571+
end
572+
function dual_set(::PositiveSemidefiniteConeSquare)
573+
_dual_set_square_error()
574+
end
575+
function dual_set_type(::Type{PositiveSemidefiniteConeSquare})
576+
_dual_set_square_error()
533577
end
534578

535579
triangular_form(::Type{PositiveSemidefiniteConeSquare}) = PositiveSemidefiniteConeTriangle

test/Utilities/sets.jl

Lines changed: 0 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -57,93 +57,6 @@ end
5757
@test MOI.dimension(MOI.SOS2(collect(1:6))) === 6
5858
end
5959

60-
@testset "Dual Set" begin
61-
# Nonpositives
62-
nonpositives3 = MOI.Nonpositives(3)
63-
nonpositives4 = MOI.Nonpositives(4)
64-
@test MOI.dual_set(nonpositives3) == nonpositives3
65-
@test MOI.dual_set(nonpositives3) != nonpositives4
66-
@test MOI.dual_set(nonpositives4) == nonpositives4
67-
# Nonnegatives
68-
nonnegatives3 = MOI.Nonnegatives(3)
69-
nonnegatives4 = MOI.Nonnegatives(4)
70-
@test MOI.dual_set(nonnegatives3) == nonnegatives3
71-
@test MOI.dual_set(nonnegatives3) != nonnegatives4
72-
@test MOI.dual_set(nonnegatives4) == nonnegatives4
73-
# Zeros and Reals
74-
zeros3 = MOI.Zeros(3)
75-
zeros4 = MOI.Zeros(4)
76-
reals3 = MOI.Reals(3)
77-
reals4 = MOI.Reals(4)
78-
@test MOI.dual_set(zeros3) == reals3
79-
@test MOI.dual_set(reals3) == zeros3
80-
@test MOI.dual_set(reals3) != zeros4
81-
@test MOI.dual_set(zeros4) == reals4
82-
@test MOI.dual_set(reals4) == zeros4
83-
@test MOI.dual_set(zeros4) != reals3
84-
# Norm-1 and norm-∞ cones
85-
norminf2 = MOI.NormInfinityCone(2)
86-
norminf3 = MOI.NormInfinityCone(3)
87-
normone2 = MOI.NormOneCone(2)
88-
normone3 = MOI.NormOneCone(3)
89-
@test MOI.dual_set(norminf2) == normone2
90-
@test MOI.dual_set(normone2) == norminf2
91-
@test MOI.dual_set(norminf2) != normone3
92-
@test MOI.dual_set(normone2) != norminf3
93-
# SOC
94-
soc2 = MOI.SecondOrderCone(2)
95-
soc3 = MOI.SecondOrderCone(3)
96-
@test MOI.dual_set(soc2) == soc2
97-
@test MOI.dual_set(soc2) != soc3
98-
@test MOI.dual_set(soc3) == soc3
99-
# RSOC
100-
rsoc2 = MOI.RotatedSecondOrderCone(2)
101-
rsoc3 = MOI.RotatedSecondOrderCone(3)
102-
@test MOI.dual_set(rsoc2) == rsoc2
103-
@test MOI.dual_set(rsoc2) != rsoc3
104-
@test MOI.dual_set(rsoc3) == rsoc3
105-
# Norm-spectral and norm-nuclear cones
106-
normspec22 = MOI.NormSpectralCone(2, 2)
107-
normspec23 = MOI.NormSpectralCone(2, 3)
108-
normnuc22 = MOI.NormNuclearCone(2, 2)
109-
normnuc23 = MOI.NormNuclearCone(2, 3)
110-
@test MOI.dual_set(normspec23) == normnuc23
111-
@test MOI.dual_set(normnuc23) == normspec23
112-
@test MOI.dual_set(normspec22) != normnuc23
113-
@test MOI.dual_set(normnuc22) != normspec23
114-
# PSDtriangle
115-
psd2 = MOI.PositiveSemidefiniteConeTriangle(2)
116-
psd3 = MOI.PositiveSemidefiniteConeTriangle(3)
117-
@test MOI.dual_set(psd2) == psd2
118-
@test MOI.dual_set(psd2) != psd3
119-
@test MOI.dual_set(psd3) == psd3
120-
# Exponential
121-
exp = MOI.ExponentialCone()
122-
dual_exp = MOI.DualExponentialCone()
123-
@test MOI.dual_set(exp) == dual_exp
124-
@test MOI.dual_set(exp) != exp
125-
@test MOI.dual_set(dual_exp) == exp
126-
@test MOI.dual_set(dual_exp) != dual_exp
127-
# Power
128-
pow03 = MOI.PowerCone(0.3)
129-
pow04 = MOI.PowerCone(0.4)
130-
dual_pow03 = MOI.DualPowerCone(0.3)
131-
@test MOI.dual_set(pow03) == dual_pow03
132-
@test MOI.dual_set(pow03) != pow03
133-
@test MOI.dual_set(dual_pow03) == pow03
134-
@test MOI.dual_set(dual_pow03) != pow04
135-
@test MOI.dual_set(dual_pow03) != dual_pow03
136-
# PSDSquare error
137-
s = MOI.PositiveSemidefiniteConeSquare(4)
138-
err = ErrorException("""Dual of $s is not defined in MathOptInterface.
139-
For more details see the comments in src/Bridges/Constraint/square.jl""")
140-
@test_throws err MOI.dual_set(MOI.PositiveSemidefiniteConeSquare(4))
141-
# Not implemented
142-
s = MOI.LogDetConeTriangle(4)
143-
err = ErrorException("Dual of $s is not implemented.")
144-
@test_throws err MOI.dual_set(MOI.LogDetConeTriangle(4))
145-
end
146-
14760
@testset "Set dot" begin
14861
vec = zeros(6)
14962
@test MOIU.set_dot(vec, vec, MOI.SecondOrderCone(6)) == 0

test/sets.jl

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,102 @@ Base.copy(mlt::MutLessThan) = MutLessThan(Base.copy(mlt.upper))
9797
@test MOI.dimension(MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}(MOI.LessThan(1.0))) == 2
9898
@test MOI.dimension(MOI.Complements(5)) == 10
9999
end
100+
101+
@testset "Dual Set" begin
102+
function dual_set_test(set1, set2)
103+
@test MOI.dual_set(set1) == set2
104+
@test MOI.dual_set_type(typeof(set1)) == typeof(set2)
105+
@test MOI.dual_set(set2) == set1
106+
@test MOI.dual_set_type(typeof(set2)) == typeof(set1)
107+
end
108+
function self_dual_set_test(set)
109+
@test MOI.dual_set(set) == set
110+
@test MOI.dual_set_type(typeof(set)) == typeof(set)
111+
end
112+
# Nonpositives
113+
nonpositives3 = MOI.Nonpositives(3)
114+
nonpositives4 = MOI.Nonpositives(4)
115+
self_dual_set_test(nonpositives3)
116+
@test MOI.dual_set(nonpositives3) != nonpositives4
117+
self_dual_set_test(nonpositives4)
118+
# Nonnegatives
119+
nonnegatives3 = MOI.Nonnegatives(3)
120+
nonnegatives4 = MOI.Nonnegatives(4)
121+
self_dual_set_test(nonnegatives3)
122+
@test MOI.dual_set(nonnegatives3) != nonnegatives4
123+
self_dual_set_test(nonnegatives4)
124+
# Zeros and Reals
125+
zeros3 = MOI.Zeros(3)
126+
zeros4 = MOI.Zeros(4)
127+
reals3 = MOI.Reals(3)
128+
reals4 = MOI.Reals(4)
129+
dual_set_test(zeros3, reals3)
130+
@test MOI.dual_set(reals3) != zeros4
131+
dual_set_test(zeros4, reals4)
132+
@test MOI.dual_set(zeros4) != reals3
133+
# Norm-1 and norm-∞ cones
134+
norminf2 = MOI.NormInfinityCone(2)
135+
norminf3 = MOI.NormInfinityCone(3)
136+
normone2 = MOI.NormOneCone(2)
137+
normone3 = MOI.NormOneCone(3)
138+
dual_set_test(norminf2, normone2)
139+
dual_set_test(norminf3, normone3)
140+
@test MOI.dual_set(norminf2) != normone3
141+
@test MOI.dual_set(normone2) != norminf3
142+
# SOC
143+
soc2 = MOI.SecondOrderCone(2)
144+
soc3 = MOI.SecondOrderCone(3)
145+
self_dual_set_test(soc2)
146+
@test MOI.dual_set(soc2) != soc3
147+
self_dual_set_test(soc3)
148+
# RSOC
149+
rsoc2 = MOI.RotatedSecondOrderCone(2)
150+
rsoc3 = MOI.RotatedSecondOrderCone(3)
151+
self_dual_set_test(rsoc2)
152+
@test MOI.dual_set(rsoc2) != rsoc3
153+
self_dual_set_test(rsoc3)
154+
# Norm-spectral and norm-nuclear cones
155+
normspec22 = MOI.NormSpectralCone(2, 2)
156+
normspec23 = MOI.NormSpectralCone(2, 3)
157+
normnuc22 = MOI.NormNuclearCone(2, 2)
158+
normnuc23 = MOI.NormNuclearCone(2, 3)
159+
dual_set_test(normspec23, normnuc23)
160+
dual_set_test(normspec22, normnuc22)
161+
@test MOI.dual_set(normspec22) != normnuc23
162+
@test MOI.dual_set(normnuc22) != normspec23
163+
# PSDtriangle
164+
psd2 = MOI.PositiveSemidefiniteConeTriangle(2)
165+
psd3 = MOI.PositiveSemidefiniteConeTriangle(3)
166+
self_dual_set_test(psd2)
167+
@test MOI.dual_set(psd2) != psd3
168+
self_dual_set_test(psd3)
169+
# Exponential
170+
exp = MOI.ExponentialCone()
171+
dual_exp = MOI.DualExponentialCone()
172+
dual_set_test(exp, dual_exp)
173+
@test MOI.dual_set(exp) != exp
174+
dual_set_test(dual_exp, exp)
175+
@test MOI.dual_set(dual_exp) != dual_exp
176+
# Power
177+
pow03 = MOI.PowerCone(0.3)
178+
pow04 = MOI.PowerCone(0.4)
179+
dual_pow03 = MOI.DualPowerCone(0.3)
180+
dual_set_test(pow03, dual_pow03)
181+
@test MOI.dual_set(pow03) != pow03
182+
dual_set_test(dual_pow03, pow03)
183+
@test MOI.dual_set(dual_pow03) != pow04
184+
@test MOI.dual_set(dual_pow03) != dual_pow03
185+
# PSDSquare error
186+
s = MOI.PositiveSemidefiniteConeSquare(4)
187+
err = ErrorException("""Dual of `PositiveSemidefiniteConeSquare` is not defined in MathOptInterface.
188+
For more details see the comments in `src/Bridges/Constraint/square.jl`.""")
189+
@test_throws err MOI.dual_set(MOI.PositiveSemidefiniteConeSquare(4))
190+
@test_throws err MOI.dual_set_type(MOI.PositiveSemidefiniteConeSquare)
191+
# Not implemented
192+
s = MOI.LogDetConeTriangle(4)
193+
err = ErrorException("Dual of $s is not implemented.")
194+
@test_throws err MOI.dual_set(MOI.LogDetConeTriangle(4))
195+
err = ErrorException("Dual type of $(typeof(s)) is not implemented.")
196+
@test_throws err MOI.dual_set_type(MOI.LogDetConeTriangle)
197+
end
100198
end

0 commit comments

Comments
 (0)