Skip to content

Commit 85f23cd

Browse files
authored
Merge pull request #905 from JuliaOpt/bl/del_constr_vars_cachopt
Fix deletion of constrained variables for CachingOptimizer
2 parents 16aa12f + 0060461 commit 85f23cd

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

src/Test/UnitTests/variables.jl

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,86 @@ function delete_variables(model::MOI.ModelLike, config::TestConfig)
8888
end
8989
unittests["delete_variables"] = delete_variable
9090

91+
"""
92+
delete_nonnegative_variables(model::MOI.ModelLike, config::TestConfig)
93+
94+
Test adding, and then deleting, nonnegative variables.
95+
"""
96+
function delete_nonnegative_variables(model::MOI.ModelLike, config::TestConfig)
97+
MOI.empty!(model)
98+
@test MOI.is_empty(model)
99+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
100+
v, cv = MOI.add_constrained_variables(model, MOI.Nonnegatives(2))
101+
@test MOI.get(model, MOI.NumberOfVariables()) == 2
102+
MOI.delete(model, v)
103+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
104+
@test !MOI.is_valid(model, v[1])
105+
@test_throws MOI.InvalidIndex(v[1]) MOI.delete(model, v[1])
106+
@test !MOI.is_valid(model, v[2])
107+
@test_throws MOI.InvalidIndex(v[2]) MOI.delete(model, v[2])
108+
@test !MOI.is_valid(model, cv)
109+
v, cv = MOI.add_constrained_variables(model, MOI.Nonnegatives(1))
110+
@test MOI.get(model, MOI.NumberOfVariables()) == 1
111+
MOI.delete(model, v[1])
112+
@test !MOI.is_valid(model, v[1])
113+
@test_throws MOI.InvalidIndex(v[1]) MOI.delete(model, v[1])
114+
@test !MOI.is_valid(model, cv)
115+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
116+
end
117+
unittests["delete_nonnegative_variables"] = delete_nonnegative_variables
118+
119+
"""
120+
update_dimension_nonnegative_variables(model::MOI.ModelLike, config::TestConfig)
121+
122+
Test adding, and then deleting one by one, nonnegative variables.
123+
"""
124+
function update_dimension_nonnegative_variables(model::MOI.ModelLike, config::TestConfig)
125+
MOI.empty!(model)
126+
@test MOI.is_empty(model)
127+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
128+
v, cv = MOI.add_constrained_variables(model, MOI.Nonnegatives(2))
129+
@test MOI.get(model, MOI.NumberOfVariables()) == 2
130+
MOI.delete(model, v[1])
131+
@test !MOI.is_valid(model, v[1])
132+
@test_throws MOI.InvalidIndex(v[1]) MOI.delete(model, v[1])
133+
@test MOI.is_valid(model, cv)
134+
@test MOI.is_valid(model, v[2])
135+
@test MOI.get(model, MOI.ConstraintFunction(), cv) == MOI.VectorOfVariables([v[2]])
136+
@test MOI.get(model, MOI.ConstraintSet(), cv) == MOI.Nonnegatives(1)
137+
MOI.delete(model, v[2])
138+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
139+
@test !MOI.is_valid(model, v[1])
140+
@test_throws MOI.InvalidIndex(v[1]) MOI.delete(model, v[1])
141+
@test !MOI.is_valid(model, v[2])
142+
@test_throws MOI.InvalidIndex(v[2]) MOI.delete(model, v[2])
143+
@test !MOI.is_valid(model, cv)
144+
end
145+
unittests["update_dimension_nonnegative_variables"] = update_dimension_nonnegative_variables
146+
147+
"""
148+
delete_soc_variables(model::MOI.ModelLike, config::TestConfig)
149+
150+
Test adding, and then deleting, second-order cone variables.
151+
"""
152+
function delete_soc_variables(model::MOI.ModelLike, config::TestConfig)
153+
MOI.empty!(model)
154+
@test MOI.is_empty(model)
155+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
156+
v, cv = MOI.add_constrained_variables(model, MOI.SecondOrderCone(3))
157+
@test MOI.get(model, MOI.NumberOfVariables()) == 3
158+
MOI.delete(model, v)
159+
@test MOI.get(model, MOI.NumberOfVariables()) == 0
160+
@test !MOI.is_valid(model, v[1])
161+
@test_throws MOI.InvalidIndex(v[1]) MOI.delete(model, v[1])
162+
@test !MOI.is_valid(model, v[2])
163+
@test_throws MOI.InvalidIndex(v[2]) MOI.delete(model, v[2])
164+
@test !MOI.is_valid(model, cv)
165+
v, cv = MOI.add_constrained_variables(model, MOI.SecondOrderCone(3))
166+
@test MOI.get(model, MOI.NumberOfVariables()) == 3
167+
@test_throws MOI.DeleteNotAllowed MOI.delete(model, v[1])
168+
end
169+
unittests["delete_soc_variables"] = delete_soc_variables
170+
91171
"""
92172
getvariable(model::MOI.ModelLike, config::TestConfig)
93173

src/Utilities/cachingoptimizer.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,39 @@ function MOI.delete(m::CachingOptimizer, index::MOI.Index)
375375
MOI.delete(m.model_cache, index)
376376
end
377377

378+
function MOI.delete(m::CachingOptimizer, indices::Vector{<:MOI.Index})
379+
if m.state == ATTACHED_OPTIMIZER
380+
for index in indices
381+
if !MOI.is_valid(m, index)
382+
# The index thrown by m.model_cache would be xored
383+
throw(MOI.InvalidIndex(index))
384+
end
385+
end
386+
indices_optimizer = [m.model_to_optimizer_map[index] for index in indices]
387+
if m.mode == AUTOMATIC
388+
try
389+
MOI.delete(m.optimizer, indices_optimizer)
390+
catch err
391+
if err isa MOI.NotAllowedError
392+
reset_optimizer(m)
393+
else
394+
rethrow(err)
395+
end
396+
end
397+
else
398+
MOI.delete(m.optimizer, indices_optimizer)
399+
end
400+
end
401+
# The state may have changed in AUTOMATIC mode since reset_optimizer is
402+
# called in case the deletion is not supported
403+
if m.state == ATTACHED_OPTIMIZER
404+
for index in indices
405+
delete!(m.optimizer_to_model_map, m.model_to_optimizer_map[index])
406+
delete!(m.model_to_optimizer_map, index)
407+
end
408+
end
409+
MOI.delete(m.model_cache, indices)
410+
end
378411

379412
# TODO: add_constraints, transform
380413

0 commit comments

Comments
 (0)