Skip to content

Commit 86d17e3

Browse files
authored
[Bridges] add ExponentialConeToScalarNonlinearFunctionBridge (#2587)
1 parent f88f78b commit 86d17e3

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed

src/Bridges/Constraint/Constraint.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
108108
MOI.Bridges.add_bridge(bridged_model, SOS1ToMILPBridge{T})
109109
MOI.Bridges.add_bridge(bridged_model, SOS2ToMILPBridge{T})
110110
MOI.Bridges.add_bridge(bridged_model, IndicatorToMILPBridge{T})
111+
112+
MOI.Bridges.add_bridge(
113+
bridged_model,
114+
ExponentialConeToScalarNonlinearFunctionBridge{T},
115+
)
111116
return
112117
end
113118

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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+
ExponentialConeToScalarNonlinearFunctionBridge{T,F} <:
9+
Bridges.Constraint.AbstractBridge
10+
11+
`ExponentialConeToScalarNonlinearFunctionBridge` implements the following
12+
reformulation:
13+
14+
* ``(x, y, z) \\in \\textsf{ExponentialCone}()`` to
15+
``y \\cdot exp(x / y)) - z \\le 0``, ``y \\ge 0``.
16+
17+
## Source node
18+
19+
`ExponentialConeToScalarNonlinearFunctionBridge` supports:
20+
21+
* `F` in [`MOI.ExponentialCone`](@ref)
22+
23+
## Target nodes
24+
25+
`ExponentialConeToScalarNonlinearFunctionBridge` creates:
26+
27+
* [`MOI.ScalarNonlinearFunction`](@ref) in [`MOI.LessThan{T}`](@ref)
28+
* [`MOI.ScalarAffineFunction`](@ref) in [`MOI.GreaterThan{T}`](@ref)
29+
"""
30+
mutable struct ExponentialConeToScalarNonlinearFunctionBridge{
31+
T,
32+
F<:Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}},
33+
} <: AbstractBridge
34+
f::F
35+
ci::MOI.ConstraintIndex{MOI.ScalarNonlinearFunction,MOI.LessThan{T}}
36+
ci_y::MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}}
37+
end
38+
39+
const ExponentialConeToScalarNonlinearFunction{T,OT<:MOI.ModelLike} =
40+
SingleBridgeOptimizer{ExponentialConeToScalarNonlinearFunctionBridge{T},OT}
41+
42+
function bridge_constraint(
43+
::Type{ExponentialConeToScalarNonlinearFunctionBridge{T,F}},
44+
model::MOI.ModelLike,
45+
f::F,
46+
s::MOI.ExponentialCone,
47+
) where {T,F<:Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}}}
48+
x, y, z = MOI.Utilities.scalarize(f)
49+
g_x_div_y = MOI.ScalarNonlinearFunction(:/, Any[x, y])
50+
g_exp_x_div_y = MOI.ScalarNonlinearFunction(:exp, Any[g_x_div_y])
51+
g = MOI.ScalarNonlinearFunction(
52+
:-,
53+
Any[MOI.ScalarNonlinearFunction(:*, Any[y, g_exp_x_div_y]), z],
54+
)
55+
ci = MOI.add_constraint(model, g, MOI.LessThan(zero(T)))
56+
# We add this as a constraint to avoid conflicting with existing variable
57+
# bounds, of which there can be at most one of.
58+
ci_y = MOI.add_constraint(model, one(T) * y, MOI.GreaterThan(zero(T)))
59+
return ExponentialConeToScalarNonlinearFunctionBridge{T,F}(f, ci, ci_y)
60+
end
61+
62+
function MOI.supports_constraint(
63+
::Type{<:ExponentialConeToScalarNonlinearFunctionBridge{T}},
64+
::Type{<:Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}}},
65+
::Type{MOI.ExponentialCone},
66+
) where {T}
67+
return true
68+
end
69+
70+
function MOI.Bridges.added_constrained_variable_types(
71+
::Type{ExponentialConeToScalarNonlinearFunctionBridge{T,F}},
72+
) where {T,F}
73+
return Tuple{Type}[]
74+
end
75+
76+
function MOI.Bridges.added_constraint_types(
77+
::Type{ExponentialConeToScalarNonlinearFunctionBridge{T,F}},
78+
) where {T,F}
79+
return Tuple{Type,Type}[
80+
(MOI.ScalarNonlinearFunction, MOI.LessThan{T}),
81+
(MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}),
82+
]
83+
end
84+
85+
function concrete_bridge_type(
86+
::Type{<:ExponentialConeToScalarNonlinearFunctionBridge{T}},
87+
::Type{F},
88+
::Type{MOI.ExponentialCone},
89+
) where {T,F<:Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}}}
90+
return ExponentialConeToScalarNonlinearFunctionBridge{T,F}
91+
end
92+
93+
function MOI.get(
94+
::MOI.ModelLike,
95+
::MOI.ConstraintFunction,
96+
bridge::ExponentialConeToScalarNonlinearFunctionBridge,
97+
)
98+
return copy(bridge.f)
99+
end
100+
101+
function MOI.get(
102+
::MOI.ModelLike,
103+
::MOI.ConstraintSet,
104+
::ExponentialConeToScalarNonlinearFunctionBridge,
105+
)
106+
return MOI.ExponentialCone()
107+
end
108+
109+
function MOI.delete(
110+
model::MOI.ModelLike,
111+
bridge::ExponentialConeToScalarNonlinearFunctionBridge,
112+
)
113+
MOI.delete(model, bridge.ci)
114+
MOI.delete(model, bridge.ci_y)
115+
return
116+
end
117+
118+
function MOI.get(
119+
::ExponentialConeToScalarNonlinearFunctionBridge,
120+
::MOI.NumberOfVariables,
121+
)::Int64
122+
return 0
123+
end
124+
125+
function MOI.get(
126+
::ExponentialConeToScalarNonlinearFunctionBridge,
127+
::MOI.ListOfVariableIndices,
128+
)::Vector{MOI.VariableIndex}
129+
return MOI.VariableIndex[]
130+
end
131+
132+
function MOI.get(
133+
::ExponentialConeToScalarNonlinearFunctionBridge{T},
134+
::MOI.NumberOfConstraints{MOI.ScalarNonlinearFunction,MOI.LessThan{T}},
135+
)::Int64 where {T}
136+
return 1
137+
end
138+
139+
function MOI.get(
140+
bridge::ExponentialConeToScalarNonlinearFunctionBridge{T},
141+
::MOI.ListOfConstraintIndices{MOI.ScalarNonlinearFunction,MOI.LessThan{T}},
142+
) where {T}
143+
return [bridge.ci]
144+
end
145+
146+
function MOI.get(
147+
::ExponentialConeToScalarNonlinearFunctionBridge{T},
148+
::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}},
149+
)::Int64 where {T}
150+
return 1
151+
end
152+
153+
function MOI.get(
154+
bridge::ExponentialConeToScalarNonlinearFunctionBridge{T},
155+
::MOI.ListOfConstraintIndices{
156+
MOI.ScalarAffineFunction{T},
157+
MOI.GreaterThan{T},
158+
},
159+
) where {T}
160+
return [bridge.ci_y]
161+
end

src/Utilities/parser.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ function _parsed_to_moi(model, s::Expr)
244244
return _parsed_scalar_to_moi(model, s.args[2])
245245
elseif Meta.isexpr(s, :call, 2) && s.args[1] == :VectorNonlinearFunction
246246
return _parsed_vector_to_moi(model, s.args[2])
247+
elseif Meta.isexpr(s, :call, 2) && s.args[1] == :esc
248+
return _parsed_to_moi(model, _parse_function(s.args[2], Float64))
247249
end
248250
args = Any[_parsed_to_moi(model, arg) for arg in s.args[2:end]]
249251
return MOI.ScalarNonlinearFunction(s.args[1], args)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 TestConstraintExponentialConeToScalarNonlinearFunctionBridge
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_VectorOfVariables()
25+
MOI.Bridges.runtests(
26+
MOI.Bridges.Constraint.ExponentialConeToScalarNonlinearFunctionBridge,
27+
"""
28+
variables: x, y, z
29+
[x, y, z] in ExponentialCone()
30+
""",
31+
"""
32+
variables: x, y, z
33+
ScalarNonlinearFunction(y * exp(x / y) - z) <= 0.0
34+
1.0 * y >= 0.0
35+
""",
36+
)
37+
return
38+
end
39+
40+
function test_runtests_VectorAffineFunction()
41+
MOI.Bridges.runtests(
42+
MOI.Bridges.Constraint.ExponentialConeToScalarNonlinearFunctionBridge,
43+
"""
44+
variables: x, y, z
45+
[1.0 * x, 2.0 * y, 3.0 * z + 1.0] in ExponentialCone()
46+
""",
47+
"""
48+
variables: x, y, z
49+
ScalarNonlinearFunction(esc(2.0 * y) * exp(esc(1.0 * x) / esc(2.0 * y)) - esc(3.0 * z + 1.0)) <= 0.0
50+
2.0 * y >= 0.0
51+
""",
52+
)
53+
return
54+
end
55+
56+
end # module
57+
58+
TestConstraintExponentialConeToScalarNonlinearFunctionBridge.runtests()

0 commit comments

Comments
 (0)