Skip to content

Commit a5fc77c

Browse files
authored
[Bridges] add IndicatorSetMapBridge (#1958)
1 parent 18e3d1b commit a5fc77c

File tree

4 files changed

+251
-0
lines changed

4 files changed

+251
-0
lines changed

docs/src/submodules/Bridges/list_of_bridges.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ Bridges.Constraint.SquareBridge
5050
Bridges.Constraint.RootDetBridge
5151
Bridges.Constraint.LogDetBridge
5252
Bridges.Constraint.IndicatorActiveOnFalseBridge
53+
Bridges.Constraint.IndicatorGreaterToLessThanBridge
54+
Bridges.Constraint.IndicatorLessToGreaterThanBridge
5355
Bridges.Constraint.IndicatorSOS1Bridge
5456
Bridges.Constraint.SemiToBinaryBridge
5557
Bridges.Constraint.ZeroOneBridge

src/Bridges/Constraint/Constraint.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ include("bridges/functionize.jl")
3232
include("bridges/geomean_to_relentr.jl")
3333
include("bridges/geomean.jl")
3434
include("bridges/indicator_activate_on_zero.jl")
35+
include("bridges/indicator_flipsign.jl")
3536
include("bridges/indicator_sos.jl")
3637
include("bridges/interval.jl")
3738
include("bridges/ltgt_to_interval.jl")
@@ -100,6 +101,8 @@ function add_all_bridges(bridged_model, ::Type{T}) where {T}
100101
MOI.Bridges.add_bridge(bridged_model, RSOCtoPSDBridge{T})
101102
MOI.Bridges.add_bridge(bridged_model, IndicatorActiveOnFalseBridge{T})
102103
MOI.Bridges.add_bridge(bridged_model, IndicatorSOS1Bridge{T})
104+
MOI.Bridges.add_bridge(bridged_model, IndicatorLessToGreaterThanBridge{T})
105+
MOI.Bridges.add_bridge(bridged_model, IndicatorGreaterToLessThanBridge{T})
103106
MOI.Bridges.add_bridge(bridged_model, SemiToBinaryBridge{T})
104107
MOI.Bridges.add_bridge(bridged_model, ZeroOneBridge{T})
105108
# Constraint programming bridges
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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+
IndicatorSetMapBridge{T,A,S1,S2} <: Bridges.Constraint.AbstractBridge
9+
10+
`IndicatorSetMapBridge` implements the following reformulations:
11+
12+
* ``z \\implies {f(x) \\ge l}`` into ``z \\implies {-f(x) \\le -l}``
13+
* ``z \\implies {f(x) \\le u}`` into ``z \\implies {-f(x) \\ge -u}``
14+
15+
## Source node
16+
17+
`IndicatorSetMapBridge` supports:
18+
19+
* [`MOI.VectorAffineFunction{T}`](@ref) in [`MOI.Indicator{A,S1}`](@ref)
20+
21+
## Target nodes
22+
23+
`IndicatorSetMapBridge` creates:
24+
25+
* [`MOI.VectorAffineFunction{T}`](@ref) in [`MOI.Indicator{A,S2}`](@ref)
26+
"""
27+
struct IndicatorSetMapBridge{T,B,S1,S2,A} <: AbstractBridge
28+
ci::MOI.ConstraintIndex{MOI.VectorAffineFunction{T},MOI.Indicator{A,S2}}
29+
end
30+
31+
function bridge_constraint(
32+
::Type{IndicatorSetMapBridge{T,B,S1,S2,A}},
33+
model::MOI.ModelLike,
34+
func::MOI.VectorAffineFunction{T},
35+
s::MOI.Indicator{A,S1},
36+
) where {T,B,S1,S2,A}
37+
f = MOI.Utilities.eachscalar(func)
38+
f2 = MOI.Bridges.map_function(B, f[2])
39+
g = MOI.Utilities.operate(vcat, T, f[1], f2)
40+
s2 = MOI.Bridges.map_set(B, s.set)
41+
ci = MOI.add_constraint(model, g, MOI.Indicator{A}(s2))
42+
return IndicatorSetMapBridge{T,B,S1,S2,A}(ci)
43+
end
44+
45+
function MOI.supports_constraint(
46+
::Type{<:IndicatorSetMapBridge{T,B,S1,S2}},
47+
::Type{MOI.VectorAffineFunction{T}},
48+
::Type{MOI.Indicator{A,S1}},
49+
) where {T,B,S1,S2,A}
50+
return true
51+
end
52+
53+
function MOI.Bridges.added_constrained_variable_types(
54+
::Type{<:IndicatorSetMapBridge},
55+
)
56+
return Tuple{Type}[]
57+
end
58+
59+
function MOI.Bridges.added_constraint_types(
60+
::Type{IndicatorSetMapBridge{T,B,S1,S2,A}},
61+
) where {T,B,S1,S2,A}
62+
return Tuple{Type,Type}[(MOI.VectorAffineFunction{T}, MOI.Indicator{A,S2})]
63+
end
64+
65+
function concrete_bridge_type(
66+
::Type{<:IndicatorSetMapBridge{T,B,S1,S2}},
67+
::Type{MOI.VectorAffineFunction{T}},
68+
::Type{MOI.Indicator{A,S1}},
69+
) where {T,B,S1,S2,A}
70+
return IndicatorSetMapBridge{T,B,S1,S2,A}
71+
end
72+
73+
function MOI.delete(model::MOI.ModelLike, bridge::IndicatorSetMapBridge)
74+
MOI.delete(model, bridge.ci)
75+
return
76+
end
77+
78+
function MOI.get(
79+
model::MOI.ModelLike,
80+
attr::MOI.ConstraintSet,
81+
bridge::IndicatorSetMapBridge{T,B,S1,S2,A},
82+
) where {T,B,S1,S2,A}
83+
set = MOI.get(model, attr, bridge.ci)
84+
return MOI.Indicator{A}(MOI.Bridges.inverse_map_set(B, set.set))
85+
end
86+
87+
function MOI.get(
88+
model::MOI.ModelLike,
89+
attr::MOI.ConstraintFunction,
90+
bridge::IndicatorSetMapBridge{T,B},
91+
) where {T,B}
92+
func = MOI.get(model, attr, bridge.ci)
93+
f = MOI.Utilities.eachscalar(func)
94+
f2 = MOI.Bridges.inverse_map_function(B, f[2])
95+
return MOI.Utilities.operate(vcat, T, f[1], f2)
96+
end
97+
98+
function MOI.get(
99+
::IndicatorSetMapBridge{T,B,S1,S2,A},
100+
::MOI.NumberOfConstraints{MOI.VectorAffineFunction{T},MOI.Indicator{A,S2}},
101+
)::Int64 where {T,B,S1,S2,A}
102+
return 1
103+
end
104+
105+
function MOI.get(
106+
bridge::IndicatorSetMapBridge{T,B,S1,S2,A},
107+
::MOI.ListOfConstraintIndices{
108+
MOI.VectorAffineFunction{T},
109+
MOI.Indicator{A,S2},
110+
},
111+
) where {T,B,S1,S2,A}
112+
return [bridge.ci]
113+
end
114+
115+
"""
116+
IndicatorGreaterToLessThanBridge{T,A} <: Bridges.Constraint.AbstractBridge
117+
118+
`IndicatorGreaterToLessThanBridge` implements the following reformulation:
119+
120+
* ``z \\implies {f(x) \\ge l}`` into ``z \\implies {-f(x) \\le -l}``
121+
122+
## Source node
123+
124+
`IndicatorGreaterToLessThanBridge` supports:
125+
126+
* [`MOI.VectorAffineFunction{T}`](@ref) in
127+
[`MOI.Indicator{A,MOI.GreaterThan{T}}`](@ref)
128+
129+
## Target nodes
130+
131+
`IndicatorGreaterToLessThanBridge` creates:
132+
133+
* [`MOI.VectorAffineFunction{T}`](@ref) in
134+
[`MOI.Indicator{A,MOI.LessThan{T}}`](@ref)
135+
"""
136+
const IndicatorGreaterToLessThanBridge{T,A} = IndicatorSetMapBridge{
137+
T,
138+
MOI.Bridges.Constraint.GreaterToLessBridge{
139+
T,
140+
MOI.ScalarAffineFunction{T},
141+
MOI.ScalarAffineFunction{T},
142+
},
143+
MOI.GreaterThan{T},
144+
MOI.LessThan{T},
145+
A,
146+
}
147+
148+
const IndicatorGreaterToLessThan{T,OT<:MOI.ModelLike} =
149+
SingleBridgeOptimizer{IndicatorGreaterToLessThanBridge{T},OT}
150+
151+
"""
152+
IndicatorLessToGreaterThanBridge{T,A} <: Bridges.Constraint.AbstractBridge
153+
154+
`IndicatorLessToGreaterThanBridge` implements the following reformulations:
155+
156+
* ``z \\implies {f(x) \\le u}`` into ``z \\implies {-f(x) \\ge -u}``
157+
158+
## Source node
159+
160+
`IndicatorLessToGreaterThanBridge` supports:
161+
162+
* [`MOI.VectorAffineFunction{T}`](@ref) in
163+
[`MOI.Indicator{A,MOI.LessThan{T}}`](@ref)
164+
165+
## Target nodes
166+
167+
`IndicatorLessToGreaterThanBridge` creates:
168+
169+
* [`MOI.VectorAffineFunction{T}`](@ref) in
170+
[`MOI.Indicator{A,MOI.GreaterThan{T}}`](@ref)
171+
"""
172+
const IndicatorLessToGreaterThanBridge{T,A} = IndicatorSetMapBridge{
173+
T,
174+
MOI.Bridges.Constraint.LessToGreaterBridge{
175+
T,
176+
MOI.ScalarAffineFunction{T},
177+
MOI.ScalarAffineFunction{T},
178+
},
179+
MOI.LessThan{T},
180+
MOI.GreaterThan{T},
181+
A,
182+
}
183+
184+
const IndicatorLessToGreaterThan{T,OT<:MOI.ModelLike} =
185+
SingleBridgeOptimizer{IndicatorLessToGreaterThanBridge{T},OT}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 TestConstraintIndicatorFlipSign
8+
9+
using Test
10+
11+
using MathOptInterface
12+
const MOI = MathOptInterface
13+
14+
function runtests()
15+
for name in names(@__MODULE__; all = true)
16+
if startswith("$(name)", "test_")
17+
@testset "$(name)" begin
18+
getfield(@__MODULE__, name)()
19+
end
20+
end
21+
end
22+
return
23+
end
24+
25+
function test_runtests_lesstogreaterthan()
26+
MOI.Bridges.runtests(
27+
MOI.Bridges.Constraint.IndicatorLessToGreaterThanBridge,
28+
"""
29+
variables: x, z
30+
[z, 2.0 * x] in Indicator{ACTIVATE_ON_ONE}(LessThan(2.0))
31+
z in ZeroOne()
32+
""",
33+
"""
34+
variables: x, z
35+
[z, -2.0 * x] in Indicator{ACTIVATE_ON_ONE}(GreaterThan(-2.0))
36+
z in ZeroOne()
37+
""",
38+
)
39+
return
40+
end
41+
42+
function test_runtests_greatertolessthann()
43+
MOI.Bridges.runtests(
44+
MOI.Bridges.Constraint.IndicatorGreaterToLessThanBridge,
45+
"""
46+
variables: x, z
47+
[z, 2.0 * x] in Indicator{ACTIVATE_ON_ONE}(GreaterThan(2.0))
48+
z in ZeroOne()
49+
""",
50+
"""
51+
variables: x, z
52+
[z, -2.0 * x] in Indicator{ACTIVATE_ON_ONE}(LessThan(-2.0))
53+
z in ZeroOne()
54+
""",
55+
)
56+
return
57+
end
58+
59+
end # module
60+
61+
TestConstraintIndicatorFlipSign.runtests()

0 commit comments

Comments
 (0)