Skip to content

Commit d87a543

Browse files
committed
Add Bridges.Constraint.NormSpecialCaseBridge
1 parent 089bb06 commit d87a543

File tree

6 files changed

+247
-42
lines changed

6 files changed

+247
-42
lines changed

docs/src/submodules/Bridges/list_of_bridges.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Bridges.Constraint.RSOCtoPSDBridge
4242
Bridges.Constraint.NormInfinityBridge
4343
Bridges.Constraint.NormOneBridge
4444
Bridges.Constraint.NormToPowerBridge
45+
Bridges.Constraint.NormSpecialCaseBridge
4546
Bridges.Constraint.GeoMeantoRelEntrBridge
4647
Bridges.Constraint.GeoMeanToPowerBridge
4748
Bridges.Constraint.GeoMeanBridge

src/Bridges/Constraint/Constraint.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ include("bridges/ltgt_to_interval.jl")
4040
include("bridges/norm_infinity.jl")
4141
include("bridges/norm_one.jl")
4242
include("bridges/norm_to_power.jl")
43+
include("bridges/norm_special_case.jl")
4344
include("bridges/norm_spec_nuc_to_psd.jl")
4445
include("bridges/number_conversion.jl")
4546
include("bridges/quad_to_soc.jl")
@@ -95,6 +96,7 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
9596
MOI.Bridges.add_bridge(bridged_model, GeoMeanBridge{T})
9697
MOI.Bridges.add_bridge(bridged_model, GeoMeanToPowerBridge{T})
9798
MOI.Bridges.add_bridge(bridged_model, NormToPowerBridge{T})
99+
MOI.Bridges.add_bridge(bridged_model, NormSpecialCaseBridge{T})
98100
MOI.Bridges.add_bridge(bridged_model, RelativeEntropyBridge{T})
99101
MOI.Bridges.add_bridge(bridged_model, NormSpectralBridge{T})
100102
MOI.Bridges.add_bridge(bridged_model, NormNuclearBridge{T})
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Copyright (c) 2017: Miles Lubin and contributors
2+
# Copyright (c) 2017: Google Inc.
3+
#
4+
# Use of this source code is governed by an MIT-style license that can be found
5+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6+
7+
"""
8+
NormSpecialCaseBridge{T,F} <: Bridges.Constraint.AbstractBridge
9+
10+
`NormSpecialCaseBridge` implements the following reformulations:
11+
12+
* ``(t, x) in NormOneCone(d)`` into ``(t, x) in NormCone(1, d)``
13+
* ``(t, x) in SecondOrderCone(d)`` into ``(t, x) in NormCone(2, d)``
14+
* ``(t, x) in NormInfinityCone(d)`` into ``(t, x) in NormCone(Inf, d)``
15+
16+
## Source node
17+
18+
`NormSpecialCaseBridge` supports:
19+
20+
* `F` in [`MOI.NormOneCone`](@ref)
21+
* `F` in [`MOI.NormInfinityCone`](@ref)
22+
* `F` in [`MOI.SecondOrderCone`](@ref)
23+
24+
## Target nodes
25+
26+
`NormSpecialCaseBridge` creates:
27+
28+
* `F` in [`MOI.NormCone`](@ref)
29+
"""
30+
struct NormSpecialCaseBridge{T,F} <: AbstractBridge
31+
constraint::MOI.ConstraintIndex{F,MOI.NormCone}
32+
end
33+
34+
const NormSpecialCase{T,OT<:MOI.ModelLike} =
35+
SingleBridgeOptimizer{NormSpecialCaseBridge{T},OT}
36+
37+
function bridge_constraint(
38+
::Type{NormSpecialCaseBridge{T,F}},
39+
model::MOI.ModelLike,
40+
f::F,
41+
s::Union{MOI.NormOneCone,MOI.SecondOrderCone,MOI.NormInfinityCone},
42+
) where {T,F}
43+
ci = MOI.add_constraint(model, f, MOI.NormCone(s))
44+
return NormSpecialCaseBridge{T,F}(ci)
45+
end
46+
47+
function MOI.supports_constraint(
48+
::Type{NormSpecialCaseBridge{T}},
49+
::Type{<:MOI.AbstractVectorFunction},
50+
::Type{<:Union{MOI.NormOneCone,MOI.SecondOrderCone,MOI.NormInfinityCone}},
51+
) where {T}
52+
return true
53+
end
54+
55+
function concrete_bridge_type(
56+
::Type{<:NormSpecialCaseBridge{T}},
57+
F::Type{<:MOI.AbstractVectorFunction},
58+
::Type{<:Union{MOI.NormOneCone,MOI.SecondOrderCone,MOI.NormInfinityCone}},
59+
) where {T}
60+
return NormSpecialCaseBridge{T,F}
61+
end
62+
63+
function MOI.Bridges.added_constrained_variable_types(
64+
::Type{<:NormSpecialCaseBridge},
65+
)
66+
return Tuple{Type}[]
67+
end
68+
69+
function MOI.Bridges.added_constraint_types(
70+
::Type{NormSpecialCaseBridge{T,F}},
71+
) where {T,F}
72+
return Tuple{Type,Type}[(F, MOI.NormCone)]
73+
end
74+
75+
MOI.get(::NormSpecialCaseBridge, ::MOI.NumberOfVariables)::Int64 = 0
76+
77+
function MOI.get(::NormSpecialCaseBridge, ::MOI.ListOfVariableIndices)
78+
return MOI.VariableIndex[]
79+
end
80+
81+
function MOI.get(
82+
bridge::NormSpecialCaseBridge{T,F},
83+
::MOI.NumberOfConstraints{F,MOI.NormCone},
84+
)::Int64 where {T,F}
85+
return 1
86+
end
87+
88+
function MOI.get(
89+
bridge::NormSpecialCaseBridge{T,F},
90+
::MOI.ListOfConstraintIndices{F,MOI.NormCone},
91+
) where {T,F}
92+
return [bridge.constraint]
93+
end
94+
95+
function MOI.delete(model::MOI.ModelLike, bridge::NormSpecialCaseBridge)
96+
MOI.delete(model, bridge.constraint)
97+
return
98+
end
99+
100+
function MOI.get(
101+
model::MOI.ModelLike,
102+
::MOI.ConstraintFunction,
103+
bridge::NormSpecialCaseBridge,
104+
)
105+
return MOI.get(model, MOI.ConstraintFunction(), bridge.constraint)
106+
end
107+
108+
function MOI.get(
109+
model::MOI.ModelLike,
110+
::MOI.ConstraintSet,
111+
bridge::NormSpecialCaseBridge,
112+
)
113+
set = MOI.get(model, MOI.ConstraintSet(), bridge.constraint)
114+
d = MOI.dimension(set)
115+
if set.p == 1
116+
return MOI.NormOneCone(d)
117+
elseif set.p == 2
118+
return MOI.SecondOrderCone(d)
119+
else
120+
@assert set.p == Inf
121+
return MOI.NormInfinityCone(d)
122+
end
123+
end

src/sets.jl

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -668,48 +668,6 @@ end
668668
dual_set(s::NormOneCone) = NormInfinityCone(dimension(s))
669669
dual_set_type(::Type{NormOneCone}) = NormInfinityCone
670670

671-
"""
672-
NormCone(p::Float64, dimension::Int)
673-
674-
The ``\\ell_p``-norm cone ``\\{ (t,x) \\in \\mathbb{R}^{dimension} : t \\ge \\left(\\sum\\limits_i |x_i|^p\\right)^{\\frac{1}{p}} \\}``
675-
of dimension `dimension`.
676-
677-
The `dimension` must be at least `1`.
678-
679-
## Example
680-
681-
```jldoctest
682-
julia> import MathOptInterface as MOI
683-
684-
julia> model = MOI.Utilities.Model{Float64}()
685-
MOIU.Model{Float64}
686-
687-
julia> t = MOI.add_variable(model)
688-
MOI.VariableIndex(1)
689-
690-
julia> x = MOI.add_variables(model, 3);
691-
692-
julia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormCone(3, 4))
693-
MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormCone}(1)
694-
```
695-
"""
696-
struct NormCone <: AbstractVectorSet
697-
p::Float64
698-
dimension::Int
699-
700-
function NormCone(p::Real, dimension::Base.Integer)
701-
if !(dimension >= 1)
702-
throw(
703-
DimensionMismatch(
704-
"Dimension of NormCone must be >= 1, not " *
705-
"$(dimension).",
706-
),
707-
)
708-
end
709-
return new(convert(Float64, p), dimension)
710-
end
711-
end
712-
713671
"""
714672
SecondOrderCone(dimension::Int)
715673
@@ -804,6 +762,54 @@ end
804762
dual_set(s::RotatedSecondOrderCone) = copy(s)
805763
dual_set_type(::Type{RotatedSecondOrderCone}) = RotatedSecondOrderCone
806764

765+
"""
766+
NormCone(p::Float64, dimension::Int)
767+
768+
The ``\\ell_p``-norm cone ``\\{ (t,x) \\in \\mathbb{R}^{dimension} : t \\ge \\left(\\sum\\limits_i |x_i|^p\\right)^{\\frac{1}{p}} \\}``
769+
of dimension `dimension`.
770+
771+
The `dimension` must be at least `1`.
772+
773+
## Example
774+
775+
```jldoctest
776+
julia> import MathOptInterface as MOI
777+
778+
julia> model = MOI.Utilities.Model{Float64}()
779+
MOIU.Model{Float64}
780+
781+
julia> t = MOI.add_variable(model)
782+
MOI.VariableIndex(1)
783+
784+
julia> x = MOI.add_variables(model, 3);
785+
786+
julia> MOI.add_constraint(model, MOI.VectorOfVariables([t; x]), MOI.NormCone(3, 4))
787+
MathOptInterface.ConstraintIndex{MathOptInterface.VectorOfVariables, MathOptInterface.NormCone}(1)
788+
```
789+
"""
790+
struct NormCone <: AbstractVectorSet
791+
p::Float64
792+
dimension::Int
793+
794+
function NormCone(p::Real, dimension::Base.Integer)
795+
if !(dimension >= 1)
796+
throw(
797+
DimensionMismatch(
798+
"Dimension of NormCone must be >= 1, not " *
799+
"$(dimension).",
800+
),
801+
)
802+
elseif !(p >= 1)
803+
throw(ArgumentError("The p- argument to `NormCone` must be `>= 1`"))
804+
end
805+
return new(convert(Float64, p), dimension)
806+
end
807+
end
808+
809+
NormCone(set::NormOneCone) = NormCone(1, set.dimension)
810+
NormCone(set::SecondOrderCone) = NormCone(2, set.dimension)
811+
NormCone(set::NormInfinityCone) = NormCone(Inf, set.dimension)
812+
807813
"""
808814
GeometricMeanCone(dimension::Int)
809815
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright (c) 2017: Miles Lubin and contributors
2+
# Copyright (c) 2017: Google Inc.
3+
#
4+
# Use of this source code is governed by an MIT-style license that can be found
5+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
6+
7+
module TestConstraintNormSpecialCase
8+
9+
using Test
10+
11+
import MathOptInterface as MOI
12+
13+
function runtests()
14+
for name in names(@__MODULE__; all = true)
15+
if startswith("$(name)", "test_")
16+
@testset "$(name)" begin
17+
getfield(@__MODULE__, name)()
18+
end
19+
end
20+
end
21+
return
22+
end
23+
24+
function test_runtests_norm_1()
25+
MOI.Bridges.runtests(
26+
MOI.Bridges.Constraint.NormSpecialCaseBridge,
27+
"""
28+
variables: t, x1, x2, x3, x4
29+
[t, x1, x2, x3, x4] in NormOneCone(5)
30+
""",
31+
"""
32+
variables: t, x1, x2, x3, x4
33+
[t, x1, x2, x3, x4] in NormCone(1.0, 5)
34+
""",
35+
)
36+
return
37+
end
38+
39+
function test_runtests_norm_2()
40+
MOI.Bridges.runtests(
41+
MOI.Bridges.Constraint.NormSpecialCaseBridge,
42+
"""
43+
variables: t, x1, x2, x3, x4
44+
[t, x1, x2, x3, x4] in SecondOrderCone(5)
45+
""",
46+
"""
47+
variables: t, x1, x2, x3, x4
48+
[t, x1, x2, x3, x4] in NormCone(2.0, 5)
49+
""",
50+
)
51+
return
52+
end
53+
54+
function test_runtests_norm_inf()
55+
MOI.Bridges.runtests(
56+
MOI.Bridges.Constraint.NormSpecialCaseBridge,
57+
"""
58+
variables: t, x1, x2, x3, x4
59+
[t, x1, x2, x3, x4] in NormInfinityCone(5)
60+
""",
61+
"""
62+
variables: t, x1, x2, x3, x4
63+
[t, x1, x2, x3, x4] in NormCone(Inf, 5)
64+
""",
65+
)
66+
return
67+
end
68+
end # module
69+
70+
TestConstraintNormSpecialCase.runtests()

test/sets.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ function test_sets_DimensionMismatch()
167167
@test_throws DimensionMismatch MOI.CountAtLeast(1, [-1, 2], Set([1, 2]))
168168
@test_throws DimensionMismatch MOI.NormCone(4, 0)
169169
@test MOI.NormCone(4, 1) isa MOI.NormCone
170+
@test_throws ArgumentError MOI.NormCone(0.99, 0)
171+
@test_throws ArgumentError MOI.NormCone(0.5, 0)
172+
@test_throws ArgumentError MOI.NormCone(-2, 0)
170173
return
171174
end
172175

0 commit comments

Comments
 (0)