Skip to content

Commit bf5bcc4

Browse files
committed
Refactor modfiyconstraint!(m,c,f) to set!(m,ConstraintFunction(),c,f)
1 parent 82dc333 commit bf5bcc4

File tree

9 files changed

+97
-27
lines changed

9 files changed

+97
-27
lines changed

src/Bridges/bridgeoptimizer.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,25 @@ function MOI.set!(b::AbstractBridgeOptimizer, ::MOI.ConstraintSet, constraint_in
244244
end
245245
end
246246

247+
function MOI.canset(b::AbstractBridgeOptimizer, ::MOI.ConstraintFunction, ::Type{C}) where C <: CI
248+
if isbridged(b, C)
249+
MOI.canset(b.bridged, MOI.ConstraintFunction(), C)
250+
# TODO(@blegat) is this necessary? How do I do it without types
251+
# && MOI.canset(b, MOIB.bridge(b, ci), change)
252+
else
253+
MOI.canset(b.model, MOI.ConstraintFunction(), C)
254+
end
255+
end
256+
function MOI.set!(b::AbstractBridgeOptimizer, ::MOI.ConstraintFunction, constraint_index::CI, func)
257+
# Note: we also under-type this function to avoid ambiguity
258+
if isbridged(b, typeof(constraint_index))
259+
MOI.set!(b, MOI.ConstraintFunction(), bridge(b, constraint_index), func)
260+
MOI.set!(b.bridged, MOI.ConstraintFunction(), constraint_index, func)
261+
else
262+
MOI.set!(b.model, MOI.ConstraintFunction(), constraint_index, func)
263+
end
264+
end
265+
247266
# Objective
248267
MOI.canmodifyobjective(b::AbstractBridgeOptimizer, ::Type{M}) where M<:MOI.AbstractFunctionModification = MOI.canmodifyobjective(b.model, M)
249268
MOI.modifyobjective!(b::AbstractBridgeOptimizer, change::MOI.AbstractFunctionModification) = MOI.modifyobjective!(b.model, change)

src/Bridges/intervalbridge.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,17 @@ end
5252

5353
# Constraints
5454
MOI.canmodifyconstraint(model::MOI.ModelLike, c::SplitIntervalBridge, change) = true
55-
function MOI.modifyconstraint!(model::MOI.ModelLike, c::SplitIntervalBridge, change::Union{MOI.ScalarAffineFunction, MOI.AbstractFunctionModification})
55+
function MOI.modifyconstraint!(model::MOI.ModelLike, c::SplitIntervalBridge, change::MOI.AbstractFunctionModification)
5656
MOI.modifyconstraint!(model, c.lower, change)
5757
MOI.modifyconstraint!(model, c.upper, change)
5858
end
5959

60+
MOI.canset(model::MOI.ModelLike, ::MOI.ConstraintFunction, ::Type{<:SplitIntervalBridge}) = true
61+
function MOI.set!(model::MOI.ModelLike, ::MOI.ConstraintFunction, c::SplitIntervalBridge, func::MOI.ScalarAffineFunction)
62+
MOI.set!(model, MOI.ConstraintFunction(), c.lower, func)
63+
MOI.set!(model, MOI.ConstraintFunction(), c.upper, func)
64+
end
65+
6066
MOI.canset(model::MOI.ModelLike, ::MOI.ConstraintSet, ::Type{<:SplitIntervalBridge}) = true
6167
function MOI.set!(model::MOI.ModelLike, ::MOI.ConstraintSet, c::SplitIntervalBridge, change::MOI.Interval)
6268
MOI.set!(model, MOI.ConstraintSet(), c.lower, MOI.GreaterThan(change.lower))

src/Utilities/cachingoptimizer.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,30 @@ function MOI.set!(m::CachingOptimizer, ::MOI.ConstraintSet, cindex::CI{F,S}, set
271271
return
272272
end
273273

274+
function MOI.canset(m::CachingOptimizer, ::MOI.ConstraintFunction, ::Type{C}) where C <: CI
275+
if !MOI.canset(m.model_cache, MOI.ConstraintFunction(), C)
276+
return false
277+
end
278+
if m.state == AttachedOptimizer && m.mode == Manual
279+
if !MOI.canset(m.optimizer, MOI.ConstraintFunction(), C)
280+
return false
281+
end
282+
end
283+
return true
284+
end
285+
function MOI.set!(m::CachingOptimizer, ::MOI.ConstraintFunction, cindex::CI{F,S}, func::F) where {F<:MOI.AbstractFunction, S<:MOI.AbstractSet}
286+
if (m.mode == Automatic && m.state == AttachedOptimizer &&
287+
!MOI.canset(m.optimizer, MOI.ConstraintFunction(), typeof(cindex)) )
288+
resetoptimizer!(m)
289+
end
290+
@assert MOI.canset(m, MOI.ConstraintFunction(), typeof(cindex))
291+
MOI.set!(m.model_cache, MOI.ConstraintFunction(), cindex, func)
292+
if m.state == AttachedOptimizer
293+
MOI.set!(m.optimizer, MOI.ConstraintFunction(), m.model_to_optimizer_map[cindex], func)
294+
end
295+
return
296+
end
297+
274298
function MOI.canmodifyobjective(m::CachingOptimizer, change)
275299
MOI.canmodifyobjective(m.model_cache, change) || return false
276300
if m.state == AttachedOptimizer && m.mode == Manual

src/Utilities/mockoptimizer.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ function MOI.set!(mock::MockOptimizer, ::MOI.ConstraintSet, c::CI{F,S}, set::S)
215215
MOI.set!(mock.inner_model, MOI.ConstraintSet(), xor_index(c), set)
216216
end
217217

218+
MOI.canset(mock::MockOptimizer, ::MOI.ConstraintFunction, ::Type{C}) where C <: CI = true
219+
function MOI.set!(mock::MockOptimizer, ::MOI.ConstraintFunction, c::CI{F,S}, func::F) where {F<:MOI.AbstractFunction, S<:MOI.AbstractSet}
220+
MOI.set!(mock.inner_model, MOI.ConstraintFunction(), xor_index(c), func)
221+
end
222+
218223
function MOI.canmodifyobjective(mock::MockOptimizer, change)
219224
MOI.canmodifyobjective(mock.inner_model, change)
220225
end

src/Utilities/model.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,10 @@ MOI.canmodifyconstraint(::AbstractModel, ::CI, ::Type{<:MOI.AbstractFunction}) =
257257
function MOI.modifyconstraint!(model::AbstractModel, ci::CI, change::MOI.AbstractFunction)
258258
_modifyconstraint!(model, ci, getconstrloc(model, ci), change)
259259
end
260-
# MOI.canset(::AbstractModel, ::MOI.ConstraintFunction, ::Type{<:CI}) = true
261-
# function MOI.set!(model::AbstractModel, ::MOI.ConstraintFunction, ci::CI, change::MOI.AbstractFunction)
262-
# _modifyconstraint!(model, ci, getconstrloc(model, ci), change)
263-
# end
260+
MOI.canset(::AbstractModel, ::MOI.ConstraintFunction, ::Type{<:CI}) = true
261+
function MOI.set!(model::AbstractModel, ::MOI.ConstraintFunction, ci::CI, change::MOI.AbstractFunction)
262+
_modifyconstraint!(model, ci, getconstrloc(model, ci), change)
263+
end
264264
MOI.canset(::AbstractModel, ::MOI.ConstraintSet, ::Type{<:CI}) = true
265265
function MOI.set!(model::AbstractModel, ::MOI.ConstraintSet, ci::CI, change::MOI.AbstractSet)
266266
_modifyconstraint!(model, ci, getconstrloc(model, ci), change)

src/Utilities/universalfallback.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ function MOI.set!(uf::UniversalFallback, ::MOI.ConstraintSet, ci::CI{F,S}, set::
162162
MOI.set!(uf.model, MOI.ConstraintSet(), ci, set)
163163
end
164164

165+
function MOI.canset(uf::UniversalFallback, ::MOI.ConstraintFunction, ::Type{C}) where C <: CI
166+
MOI.canset(uf.model, MOI.ConstraintFunction(), C)
167+
end
168+
function MOI.set!(uf::UniversalFallback, ::MOI.ConstraintFunction, ci::CI{F,S}, func::F) where F where S
169+
MOI.set!(uf.model, MOI.ConstraintFunction(), ci, func)
170+
end
165171

166172
# Objective
167173
MOI.canmodifyobjective(uf::UniversalFallback, ::Type{M}) where M<:MOI.AbstractFunctionModification = MOI.canmodifyobjective(uf.model, M)

src/constraints.jl

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ function addconstraints! end
4343
# default fallback
4444
addconstraints!(model::ModelLike, funcs, sets) = addconstraint!.(model, funcs, sets)
4545

46-
4746
"""
4847
canset(model::ModelLike, ::ConstraintSet, ::Type{ConstraintIndex{F,S}})::Bool
4948
@@ -84,43 +83,55 @@ end
8483
set_type(c::ConstraintIndex{F,S}) where {F, S} = S
8584

8685
"""
87-
## Modify Function
88-
89-
canmodifyconstraint(model::ModelLike, c::ConstraintIndex{F,S}, ::Type{F})::Bool
86+
canset(model::ModelLike, ::ConstraintFunction, ::Type{ConstraintIndex{F,S}})::Bool
9087
91-
Return a `Bool` indicating whether the function in constraint `c` can be replaced by another function of the same type `F` as the original function.
92-
93-
## Partial Modifications
88+
Return a `Bool` indicating whether the function in a constraint of type
89+
`F`-in-`S` can be replaced by another set of the same type `F` as the original
90+
function.
91+
"""
92+
canset(model::ModelLike, ::ConstraintFunction, type_of_function) = false
93+
# Note: the above method is deliberately under-typed to avoid method ambiguities
9494

95-
canmodifyconstraint(model::ModelLike, c::ConstraintIndex, ::Type{M})::Bool where M<:AbstractFunctionModification
95+
"""
96+
set!(model::ModelLike, ::ConstraintFunction, c::ConstraintIndex{F,S}, func::F)
9697
97-
Return a `Bool` indicating whether it is possible to apply a modification of type `M` to the function of constraint `c`.
98+
Replace the function in constraint `c` with `func`. `F` must match the original
99+
function type used to define the constraint.
98100
99101
### Examples
100102
103+
If `c` is a `ConstraintIndex{ScalarAffineFunction,S}` and `v1` and `v2` are
104+
`VariableIndex` objects,
105+
101106
```julia
102-
canmodifyconstraint(model, c, ScalarConstantChange{Float64})
107+
set!(model, ConstraintFunction(), c, ScalarAffineFunction([v1,v2],[1.0,2.0],5.0))
108+
set!(model, ConstraintFunction(), c, SingleVariable(v1)) # Error
103109
```
104110
"""
105-
function canmodifyconstraint end
106-
canmodifyconstraint(model::ModelLike, c::ConstraintIndex, change) = false
111+
function set!(model::ModelLike, ::ConstraintFunction, constraint_index, func)
112+
# note: we deliberately avoid typing the last two arguments to avoid
113+
# ambiguity errors. If solvers don't catch the case where the set is
114+
# different, it should still fall back to this method.
115+
throw(MethodError(set!, (model, ConstraintFunction(), constraint_index, func)))
116+
end
107117

108118
"""
109-
## Modify Function
119+
## Partial Modifications
110120
111-
modifyconstraint!(model::ModelLike, c::ConstraintIndex{F,S}, func::F)
121+
canmodifyconstraint(model::ModelLike, c::ConstraintIndex, ::Type{M})::Bool where M<:AbstractFunctionModification
112122
113-
Replace the function in constraint `c` with `func`. `F` must match the original function type used to define the constraint.
123+
Return a `Bool` indicating whether it is possible to apply a modification of type `M` to the function of constraint `c`.
114124
115125
### Examples
116126
117-
If `c` is a `ConstraintIndex{ScalarAffineFunction,S}` and `v1` and `v2` are `VariableIndex` objects,
118-
119127
```julia
120-
modifyconstraint!(model, c, ScalarAffineFunction([v1,v2],[1.0,2.0],5.0))
121-
modifyconstraint!(model, c, SingleVariable(v1)) # Error
128+
canmodifyconstraint(model, c, ScalarConstantChange{Float64})
122129
```
130+
"""
131+
function canmodifyconstraint end
132+
canmodifyconstraint(model::ModelLike, c::ConstraintIndex, change) = false
123133

134+
"""
124135
## Partial Modifications
125136
126137
modifyconstraint!(model::ModelLike, c::ConstraintIndex, change::AbstractFunctionModification)

test/bridge.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ end
167167
ci = first(MOI.get(bridgedmock, MOI.ListOfConstraintIndices{MOI.ScalarAffineFunction{Float64}, MOI.Interval{Float64}}()))
168168
@test MOI.canmodifyconstraint(bridgedmock, ci, MOI.ScalarAffineFunction{Float64})
169169
newf = MOI.ScalarAffineFunction(MOI.ScalarAffineTerm.([1.0, -1.0], MOI.get(bridgedmock, MOI.ListOfVariableIndices())), 0.0)
170-
MOI.modifyconstraint!(bridgedmock, ci, newf)
170+
MOI.set!(bridgedmock, MOI.ConstraintFunction(), ci, newf)
171171
@test MOI.canget(bridgedmock, MOI.ConstraintFunction(), typeof(ci))
172172
@test MOI.get(bridgedmock, MOI.ConstraintFunction(), ci) newf
173173
test_delete_bridge(bridgedmock, ci, 2, ((MOI.ScalarAffineFunction{Float64}, MOI.GreaterThan{Float64}, 0),

test/model.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ end
6262
f3 = MOIU.modifyfunction(f3, MOI.ScalarCoefficientChange(y, 2))
6363

6464
@test !(MOI.get(model, MOI.ConstraintFunction(), c1) f3)
65-
MOI.modifyconstraint!(model, c1, f3)
66-
# MOI.set!(model, MOI.ConstraintFunction(), c1, f3)
65+
MOI.set!(model, MOI.ConstraintFunction(), c1, f3)
6766
@test MOI.get(model, MOI.ConstraintFunction(), c1) f3
6867

6968
f4 = MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1, 1, 2], MOI.ScalarAffineTerm.([2, 4, 3], [x, y, y])), [5, 7])

0 commit comments

Comments
 (0)