Skip to content

Commit 6ac4e6d

Browse files
authored
Merge pull request #850 from JuliaOpt/bl/nlp_var
Don't change order of variables when NLPBlock is used
2 parents 1fd2afe + 3ef0d90 commit 6ac4e6d

File tree

2 files changed

+59
-24
lines changed

2 files changed

+59
-24
lines changed

src/Utilities/copy.jl

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,21 @@ function pass_constraints(
267267
end
268268
end
269269

270+
function copy_free_variables(dest::MOI.ModelLike, idxmap::IndexMap, vis_src, copy_variables::Function)
271+
if length(vis_src) != length(keys(idxmap.varmap))
272+
vars = copy_variables(dest, length(vis_src) - length(idxmap.varmap))
273+
i = 1
274+
for vi in vis_src
275+
if !haskey(idxmap.varmap, vi)
276+
idxmap.varmap[vi] = vars[i]
277+
i += 1
278+
end
279+
end
280+
@assert i == length(vars) + 1
281+
@assert length(vis_src) == length(idxmap.varmap)
282+
end
283+
end
284+
270285
function default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike)
271286
Base.depwarn("default_copy_to(dest, src) is deprecated, use default_copy_to(dest, src, true) instead or default_copy_to(dest, src, false) if you do not want to copy names.", :default_copy_to)
272287
default_copy_to(dest, src, true)
@@ -292,24 +307,29 @@ function default_copy_to(dest::MOI.ModelLike, src::MOI.ModelLike, copy_names::Bo
292307
vector_of_variables_types = [S for (F, S) in constraint_types
293308
if F == MOI.VectorOfVariables]
294309

295-
vector_of_variables_not_added = [
296-
copy_vector_of_variables(dest, src, idxmap, S)
297-
for S in vector_of_variables_types
298-
]
299-
single_variable_not_added = [
300-
copy_single_variable(dest, src, idxmap, S)
301-
for S in single_variable_types
302-
]
303-
304-
if length(vis_src) != length(keys(idxmap.varmap))
305-
# Copy free variables
306-
variables_not_added = setdiff(Set(vis_src), keys(idxmap.varmap))
307-
vars = MOI.add_variables(dest, length(variables_not_added))
308-
for (vi, var) in zip(variables_not_added, vars)
309-
idxmap.varmap[vi] = var
310-
end
310+
# The `NLPBlock` assumes that the order of variables does not change (#849)
311+
if MOI.NLPBlock() in MOI.get(src, MOI.ListOfModelAttributesSet())
312+
vector_of_variables_not_added = [
313+
MOI.get(src, MOI.ListOfConstraintIndices{MOI.VectorOfVariables, S}())
314+
for S in vector_of_variables_types
315+
]
316+
single_variable_not_added = [
317+
MOI.get(src, MOI.ListOfConstraintIndices{MOI.SingleVariable, S}())
318+
for S in single_variable_types
319+
]
320+
else
321+
vector_of_variables_not_added = [
322+
copy_vector_of_variables(dest, src, idxmap, S)
323+
for S in vector_of_variables_types
324+
]
325+
single_variable_not_added = [
326+
copy_single_variable(dest, src, idxmap, S)
327+
for S in single_variable_types
328+
]
311329
end
312330

331+
copy_free_variables(dest, idxmap, vis_src, MOI.add_variables)
332+
313333
# Copy variable attributes
314334
pass_attributes(dest, src, copy_names, idxmap, vis_src)
315335

@@ -652,14 +672,7 @@ function allocate_load(dest::MOI.ModelLike, src::MOI.ModelLike, copy_names::Bool
652672
allocate_single_variable(dest, src, idxmap, S)
653673
end
654674

655-
if length(vis_src) != length(keys(idxmap.varmap))
656-
# Allocate free variables
657-
variables_not_added = setdiff(Set(vis_src), keys(idxmap.varmap))
658-
vars = allocate_variables(dest, length(variables_not_added))
659-
for (vi, var) in zip(variables_not_added, vars)
660-
idxmap.varmap[vi] = var
661-
end
662-
end
675+
copy_free_variables(dest, idxmap, vis_src, allocate_variables)
663676

664677
# Allocate variable attributes
665678
pass_attributes(dest, src, copy_names, idxmap, vis_src, allocate)

test/Utilities/copy.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,25 @@ end
5757
MOIT.failcopytestca(mock)
5858
MOIT.copytest(mock, MOIU.Model{Float64}())
5959
end
60+
61+
struct DummyEvaluator <: MOI.AbstractNLPEvaluator end
62+
63+
@testset "Create variables in same ordering when NLPBlock is used (#849)" begin
64+
model = MOIU.UniversalFallback(MOIU.Model{Float64}())
65+
a = MOI.add_variable(model)
66+
b, c = MOI.add_variables(model, 2)
67+
x, cx = MOI.add_constrained_variable(model, MOI.GreaterThan(0.0))
68+
y, cy = MOI.add_constrained_variables(model, MOI.Nonnegatives(1))
69+
nlp_data = MOI.NLPBlockData(
70+
[MOI.NLPBoundsPair(0.0, 1.0) for i in 1:5],
71+
DummyEvaluator(), false)
72+
MOI.set(model, MOI.NLPBlock(), nlp_data)
73+
copy = MOIU.UniversalFallback(MOIU.Model{Float64}())
74+
index_map = MOIU.default_copy_to(copy, model, true)
75+
for vi in [a, b, c, x, y[1]]
76+
@test index_map[vi] == vi
77+
end
78+
for ci in [cx, cy]
79+
@test index_map[ci] == ci
80+
end
81+
end

0 commit comments

Comments
 (0)