Skip to content

Commit bca8480

Browse files
authored
[Bridges] fix CountAtLeastToCountBelongsBridge (#1926)
1 parent 63a489d commit bca8480

File tree

2 files changed

+43
-35
lines changed

2 files changed

+43
-35
lines changed

src/Bridges/Constraint/bridges/count_at_least.jl

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
1212
* ``x \\in \\textsf{CountAtLeast}(n, d, set)`` to
1313
``(n_i, x_{d_i}) \\in \\textsf{CountBelongs}(1+d)``
14-
and ``\\sum\\limits n_i \\ge n``
14+
and ``n_i \\ge n``
1515
1616
## Source node
1717
@@ -27,7 +27,7 @@ where `F` is [`MOI.VectorOfVariables`](@ref) or
2727
`CountAtLeastToCountBelongsBridge` creates:
2828
2929
* `F` in [`MOI.CountBelongs`](@ref)
30-
* [`MOI.ScalarAffineFunction{T}`](@ref) in [`MOI.GreaterThan{T}`](@ref)
30+
* [`MOI.VariableIndex`](@ref) in [`MOI.GreaterThan{T}`](@ref)
3131
"""
3232
mutable struct CountAtLeastToCountBelongsBridge{
3333
T,
@@ -37,7 +37,19 @@ mutable struct CountAtLeastToCountBelongsBridge{
3737
s::MOI.CountAtLeast
3838
variables::Vector{MOI.VariableIndex}
3939
ci::Vector{MOI.ConstraintIndex{F,MOI.CountBelongs}}
40-
count::MOI.ConstraintIndex{MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}}
40+
# We need an explicit inner constructor to avoid the unbound type parameter
41+
# T (it doesn't appear in the fields).
42+
function CountAtLeastToCountBelongsBridge{T}(
43+
f::Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}},
44+
s::MOI.CountAtLeast,
45+
) where {T}
46+
return new{T,typeof(f)}(
47+
f,
48+
s,
49+
MOI.VariableIndex[],
50+
MOI.ConstraintIndex{typeof(f),MOI.CountBelongs}[],
51+
)
52+
end
4153
end
4254

4355
const CountAtLeastToCountBelongs{T,OT<:MOI.ModelLike} =
@@ -50,25 +62,21 @@ function bridge_constraint(
5062
s::MOI.CountAtLeast,
5163
) where {T,F<:Union{MOI.VectorOfVariables,MOI.VectorAffineFunction{T}}}
5264
x = collect(MOI.Utilities.eachscalar(f))
53-
variables = MOI.VariableIndex[]
54-
cis = MOI.ConstraintIndex{F,MOI.CountBelongs}[]
55-
count_f = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm{T}[], zero(T))
65+
bridge = CountAtLeastToCountBelongsBridge{T}(f, s)
5666
offset = 0
5767
for p in s.partitions
5868
indices = offset .+ (1:p)
59-
y = MOI.add_variable(model)
60-
push!(variables, y)
61-
push!(count_f.terms, MOI.ScalarAffineTerm(one(T), y))
69+
y, _ = MOI.add_constrained_variable(model, MOI.GreaterThan(T(s.n)))
70+
push!(bridge.variables, y)
6271
ci = MOI.add_constraint(
6372
model,
6473
MOI.Utilities.operate(vcat, T, y, x[indices]...),
6574
MOI.CountBelongs(1 + p, s.set),
6675
)
67-
push!(cis, ci)
76+
push!(bridge.ci, ci)
6877
offset += p
6978
end
70-
count = MOI.add_constraint(model, count_f, MOI.GreaterThan(T(s.n)))
71-
return CountAtLeastToCountBelongsBridge{T,F}(f, s, variables, cis, count)
79+
return bridge
7280
end
7381

7482
function MOI.supports_constraint(
@@ -80,18 +88,15 @@ function MOI.supports_constraint(
8088
end
8189

8290
function MOI.Bridges.added_constrained_variable_types(
83-
::Type{<:CountAtLeastToCountBelongsBridge},
84-
)
85-
return Tuple{Type}[]
91+
::Type{<:CountAtLeastToCountBelongsBridge{T}},
92+
) where {T}
93+
return Tuple{Type}[(MOI.GreaterThan{T},)]
8694
end
8795

8896
function MOI.Bridges.added_constraint_types(
8997
::Type{CountAtLeastToCountBelongsBridge{T,F}},
9098
) where {T,F}
91-
return Tuple{Type,Type}[
92-
(F, MOI.CountBelongs),
93-
(MOI.ScalarAffineFunction{T}, MOI.GreaterThan{T}),
94-
]
99+
return Tuple{Type,Type}[(F, MOI.CountBelongs)]
95100
end
96101

97102
function concrete_bridge_type(
@@ -125,7 +130,6 @@ function MOI.delete(
125130
for ci in bridge.ci
126131
MOI.delete(model, ci)
127132
end
128-
MOI.delete(model, bridge.count)
129133
for x in bridge.variables
130134
MOI.delete(model, x)
131135
end
@@ -161,18 +165,18 @@ function MOI.get(
161165
end
162166

163167
function MOI.get(
164-
::CountAtLeastToCountBelongsBridge{T,F},
165-
::MOI.NumberOfConstraints{MOI.ScalarAffineFunction{T},MOI.GreaterThan{T}},
166-
)::Int64 where {T,F}
167-
return 1
168+
bridge::CountAtLeastToCountBelongsBridge{T},
169+
::MOI.NumberOfConstraints{MOI.VariableIndex,MOI.GreaterThan{T}},
170+
)::Int64 where {T}
171+
return length(bridge.variables)
168172
end
169173

170174
function MOI.get(
171-
bridge::CountAtLeastToCountBelongsBridge{T,F},
172-
::MOI.ListOfConstraintIndices{
173-
MOI.ScalarAffineFunction{T},
174-
MOI.GreaterThan{T},
175-
},
176-
) where {T,F}
177-
return [bridge.count]
175+
bridge::CountAtLeastToCountBelongsBridge{T},
176+
::MOI.ListOfConstraintIndices{MOI.VariableIndex,MOI.GreaterThan{T}},
177+
) where {T}
178+
return [
179+
MOI.ConstraintIndex{MOI.VariableIndex,MOI.GreaterThan{T}}(x.value) for
180+
x in bridge.variables
181+
]
178182
end

test/Bridges/Constraint/count_at_least.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,19 @@ function test_runtests_VectorOfVariables()
3030
[a, b, b, c] in CountAtLeast(1, [2, 2], Set([3]))
3131
a in Interval(1.0, 3.0)
3232
b in Interval(1.0, 3.0)
33-
c in Interval(1.0, 3.0)
33+
c >= 1.0
34+
c <= 3.0
3435
""",
3536
"""
3637
variables: a, b, c, y1, y2
3738
[y1, a, b] in CountBelongs(3, Set([3]))
3839
[y2, b, c] in CountBelongs(3, Set([3]))
39-
y1 + y2 >= 1.0
40+
y1 >= 1.0
41+
y2 >= 1.0
4042
a in Interval(1.0, 3.0)
4143
b in Interval(1.0, 3.0)
42-
c in Interval(1.0, 3.0)
44+
c >= 1.0
45+
c <= 3.0
4346
""",
4447
)
4548
return
@@ -59,7 +62,8 @@ function test_runtests_VectorAffineFunction()
5962
variables: a, b, c, y1, y2
6063
[y1, 1.0 * a, b + 1.0] in CountBelongs(3, Set([3]))
6164
[y2, 1.0 * b, 1.0 * c] in CountBelongs(3, Set([3]))
62-
y1 + y2 >= 1.0
65+
y1 >= 1.0
66+
y2 >= 1.0
6367
a in Interval(1.0, 3.0)
6468
b in Interval(1.0, 3.0)
6569
c in Interval(1.0, 3.0)

0 commit comments

Comments
 (0)