Skip to content

Commit 59a8650

Browse files
authored
improve performance of internal semi-infintie variables (infiniteopt#359)
1 parent c64333f commit 59a8650

File tree

4 files changed

+77
-86
lines changed

4 files changed

+77
-86
lines changed

Diff for: src/TranscriptionOpt/measures.jl

+18-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,24 @@ function InfiniteOpt.add_semi_infinite_variable(
7474
# make the reference and map it to a transcription variable
7575
rvref = InfiniteOpt.GeneralVariableRef(inf_model, raw_index, InfiniteOpt.SemiInfiniteVariableIndex)
7676
push!(semi_infinite_vars, var)
77-
_set_semi_infinite_variable_mapping(backend, var, rvref, InfiniteOpt._index_type(ivref))
77+
if ivref.index_type != InfiniteOpt.ParameterFunctionIndex
78+
ivref_param_nums = InfiniteOpt._parameter_numbers(ivref)
79+
param_nums = var.parameter_nums
80+
supp_indices = support_index_iterator(backend, var.group_int_idxs)
81+
lookup_dict = Dict{Vector{Float64}, JuMP.VariableRef}()
82+
sizehint!(lookup_dict, length(supp_indices))
83+
for i in supp_indices
84+
raw_supp = index_to_support(backend, i)
85+
if any(!isnan(raw_supp[ivref_param_nums[k]]) && raw_supp[ivref_param_nums[k]] != v for (k, v) in eval_supps)
86+
continue
87+
end
88+
ivref_supp = [haskey(eval_supps, j) ? eval_supps[j] : raw_supp[k]
89+
for (j, k) in enumerate(ivref_param_nums)]
90+
supp = raw_supp[param_nums]
91+
lookup_dict[supp] = lookup_by_support(ivref, backend, ivref_supp)
92+
end
93+
data.infvar_lookup[rvref] = lookup_dict
94+
end
7895
data.semi_lookup[(ivref, eval_supps)] = rvref
7996
return rvref
8097
end

Diff for: src/TranscriptionOpt/transcribe.jl

+48-68
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ function transcribe_infinite_variables!(
139139
vrefs = Array{JuMP.VariableRef, length(dims)}(undef, dims...)
140140
supp_type = typeof(Tuple(ones(length(prefs)), prefs))
141141
supps = Array{supp_type, length(dims)}(undef, dims...)
142-
lookup_dict = Dict{Vector{Float64}, JuMP.VariableRef}()
142+
lookup_dict = sizehint!(Dict{Vector{Float64}, JuMP.VariableRef}(), length(vrefs))
143143
# create a variable for each support
144144
for i in supp_indices
145145
supp = index_to_support(backend, i)[param_nums]
@@ -190,7 +190,7 @@ function _transcribe_derivative_variable(dref, d, backend)
190190
vrefs = Array{JuMP.VariableRef, length(dims)}(undef, dims...)
191191
supp_type = typeof(Tuple(ones(length(prefs)), prefs))
192192
supps = Array{supp_type, length(dims)}(undef, dims...)
193-
lookup_dict = Dict{Vector{Float64}, JuMP.VariableRef}()
193+
lookup_dict = sizehint!(Dict{Vector{Float64}, JuMP.VariableRef}(), length(vrefs))
194194
# create a variable for each support
195195
for i in supp_indices
196196
supp = index_to_support(backend, i)[param_nums]
@@ -255,69 +255,6 @@ function transcribe_derivative_variables!(
255255
return
256256
end
257257

258-
# Setup the mapping for a given semi_infinite variable
259-
function _set_semi_infinite_variable_mapping(
260-
backend::TranscriptionBackend,
261-
var::InfiniteOpt.SemiInfiniteVariable,
262-
rvref::InfiniteOpt.GeneralVariableRef,
263-
index_type
264-
)
265-
param_nums = var.parameter_nums
266-
ivref = var.infinite_variable_ref
267-
ivref_param_nums = InfiniteOpt._parameter_numbers(ivref)
268-
eval_supps = var.eval_supports
269-
group_idxs = var.group_int_idxs
270-
prefs = InfiniteOpt.raw_parameter_refs(var)
271-
# prepare for iterating over its supports
272-
supp_indices = support_index_iterator(backend, group_idxs)
273-
dims = size(supp_indices)[group_idxs]
274-
vrefs = Array{JuMP.VariableRef, length(dims)}(undef, dims...)
275-
supp_type = typeof(Tuple(ones(length(prefs)), prefs))
276-
supps = Array{supp_type, length(dims)}(undef, dims...)
277-
lookup_dict = Dict{Vector{Float64}, JuMP.VariableRef}()
278-
valid_idxs = ones(Bool, dims...)
279-
# map a variable for each support
280-
for i in supp_indices
281-
raw_supp = index_to_support(backend, i)
282-
var_idx = i.I[group_idxs]
283-
# ensure this support is valid with the reduced restriction
284-
if any(!isnan(raw_supp[ivref_param_nums[k]]) && raw_supp[ivref_param_nums[k]] != v for (k, v) in eval_supps)
285-
valid_idxs[var_idx...] = false
286-
continue
287-
end
288-
# map to the current transcription variable
289-
supp = raw_supp[param_nums]
290-
ivref_supp = [haskey(eval_supps, j) ? eval_supps[j] : raw_supp[k]
291-
for (j, k) in enumerate(ivref_param_nums)]
292-
jump_vref = lookup_by_support(ivref, backend, ivref_supp)
293-
@inbounds vrefs[var_idx...] = jump_vref
294-
lookup_dict[supp] = jump_vref
295-
@inbounds supps[var_idx...] = Tuple(supp, prefs)
296-
end
297-
# truncate vrefs if any supports were skipped because of dependent parameter supps and save
298-
data = transcription_data(backend)
299-
if !all(valid_idxs)
300-
data.infvar_mappings[rvref] = vrefs[valid_idxs]
301-
data.infvar_supports[rvref] = supps[valid_idxs]
302-
data.valid_indices[rvref] = valid_idxs
303-
else
304-
data.infvar_mappings[rvref] = vrefs
305-
data.infvar_supports[rvref] = supps
306-
end
307-
data.infvar_lookup[rvref] = lookup_dict
308-
return
309-
end
310-
311-
# Empty mapping dispatch for infinite parameter functions
312-
function _set_semi_infinite_variable_mapping(
313-
backend::TranscriptionBackend,
314-
var::InfiniteOpt.SemiInfiniteVariable,
315-
rvref::InfiniteOpt.GeneralVariableRef,
316-
index_type::Type{InfiniteOpt.ParameterFunctionIndex}
317-
)
318-
return
319-
end
320-
321258
"""
322259
transcribe_semi_infinite_variables!(
323260
backend::TranscriptionBackend,
@@ -342,8 +279,51 @@ function transcribe_semi_infinite_variables!(
342279
var = object.variable
343280
rvref = InfiniteOpt.GeneralVariableRef(model, idx)
344281
# setup the mappings
345-
idx_type = InfiniteOpt._index_type(InfiniteOpt.infinite_variable_ref(rvref))
346-
_set_semi_infinite_variable_mapping(backend, var, rvref, idx_type)
282+
ivref = var.infinite_variable_ref
283+
if InfiniteOpt._index_type(ivref) != InfiniteOpt.ParameterFunctionIndex
284+
param_nums = var.parameter_nums
285+
ivref_param_nums = InfiniteOpt._parameter_numbers(ivref)
286+
eval_supps = var.eval_supports
287+
group_idxs = var.group_int_idxs
288+
prefs = InfiniteOpt.raw_parameter_refs(var)
289+
# prepare for iterating over its supports
290+
supp_indices = support_index_iterator(backend, group_idxs)
291+
dims = size(supp_indices)[group_idxs]
292+
vrefs = Array{JuMP.VariableRef, length(dims)}(undef, dims...)
293+
supp_type = typeof(Tuple(ones(length(prefs)), prefs))
294+
supps = Array{supp_type, length(dims)}(undef, dims...)
295+
lookup_dict = sizehint!(Dict{Vector{Float64}, JuMP.VariableRef}(), length(vrefs))
296+
valid_idxs = ones(Bool, dims...)
297+
# map a variable for each support
298+
for i in supp_indices
299+
raw_supp = index_to_support(backend, i)
300+
var_idx = i.I[group_idxs]
301+
# ensure this support is valid with the reduced restriction
302+
if any(!isnan(raw_supp[ivref_param_nums[k]]) && raw_supp[ivref_param_nums[k]] != v for (k, v) in eval_supps)
303+
valid_idxs[var_idx...] = false
304+
continue
305+
end
306+
# map to the current transcription variable
307+
supp = raw_supp[param_nums]
308+
ivref_supp = [haskey(eval_supps, j) ? eval_supps[j] : raw_supp[k]
309+
for (j, k) in enumerate(ivref_param_nums)]
310+
jump_vref = lookup_by_support(ivref, backend, ivref_supp)
311+
@inbounds vrefs[var_idx...] = jump_vref
312+
lookup_dict[supp] = jump_vref
313+
@inbounds supps[var_idx...] = Tuple(supp, prefs)
314+
end
315+
# truncate vrefs if any supports were skipped because of dependent parameter supps and save
316+
data = transcription_data(backend)
317+
if !all(valid_idxs)
318+
data.infvar_mappings[rvref] = vrefs[valid_idxs]
319+
data.infvar_supports[rvref] = supps[valid_idxs]
320+
data.valid_indices[rvref] = valid_idxs
321+
else
322+
data.infvar_mappings[rvref] = vrefs
323+
data.infvar_supports[rvref] = supps
324+
end
325+
data.infvar_lookup[rvref] = lookup_dict
326+
end
347327
end
348328
return
349329
end
@@ -570,7 +550,7 @@ function transcribe_measures!(
570550
exprs = Array{JuMP.AbstractJuMPScalar, length(dims)}(undef, dims...)
571551
supp_type = typeof(Tuple(ones(length(prefs)), prefs))
572552
supps = Array{supp_type, length(dims)}(undef, dims...)
573-
lookup_dict = Dict{Vector{Float64}, Int}()
553+
lookup_dict = sizehint!(Dict{Vector{Float64}, Int}(), length(exprs))
574554
# map a variable for each support
575555
for (lin_idx, i) in enumerate(supp_indices)
576556
raw_supp = index_to_support(backend, i)

Diff for: test/TranscriptionOpt/measure.jl

+10-6
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,18 @@
4949
vref = GeneralVariableRef(m, -1, SemiInfiniteVariableIndex)
5050
@test isequal(InfiniteOpt.add_semi_infinite_variable(tb, var), vref)
5151
@test isequal(data.semi_infinite_vars, [var])
52-
@test c in IOTO.transcription_variable(vref)
53-
@test d in IOTO.transcription_variable(vref)
54-
@test sort!(supports(vref)) == [([0., 0.], ), ([1., 1.], )]
52+
@test IOTO.transcription_expression(vref, tb, [1., 0., 0.]) == c
53+
@test IOTO.transcription_expression(vref, tb, [1., 1., 1.]) == d
5554
# add one that has already been added internally
5655
@test isequal(InfiniteOpt.add_semi_infinite_variable(tb, var), vref)
5756
@test isequal(data.semi_infinite_vars, [var])
58-
@test c in IOTO.transcription_variable(vref)
59-
@test d in IOTO.transcription_variable(vref)
60-
@test sort!(supports(vref)) == [([0., 0.], ), ([1., 1.], )]
57+
@test IOTO.transcription_expression(vref, tb, [1., 0., 0.]) == c
58+
@test IOTO.transcription_expression(vref, tb, [1., 1., 1.]) == d
59+
# test with partially evaluated dependent parameter group
60+
var2 = SemiInfiniteVariable(y, Dict(1 => 1., 2 => 1.0), [3], [2])
61+
vref = GeneralVariableRef(m, -2, SemiInfiniteVariableIndex)
62+
@test isequal(InfiniteOpt.add_semi_infinite_variable(tb, var2), vref)
63+
@test isequal(data.semi_infinite_vars, [var, var2])
64+
@test IOTO.transcription_expression(vref, tb, [1., 1., 1.]) == d
6165
end
6266
end

Diff for: test/TranscriptionOpt/transcribe.jl

+1-11
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,11 @@
116116
@test supports(dx) == [(0,), (1,)]
117117
@test supports(dy) == [(0, [0, 0]) (0, [1, 1]); (1, [0, 0]) (1, [1, 1])]
118118
end
119-
# test _set_semi_infinite_variable_mapping
120-
@testset "_set_semi_infinite_variable_mapping" begin
121-
var = SemiInfiniteVariable(y, Dict{Int, Float64}(1 => 0), [1, 2], [1])
122-
vref = GeneralVariableRef(m, -1, SemiInfiniteVariableIndex)
123-
@test IOTO._set_semi_infinite_variable_mapping(tb, var, vref, SemiInfiniteVariableIndex) isa Nothing
124-
@test IOTO.transcription_variable(vref) isa Vector{VariableRef}
125-
@test length(IOTO.transcription_data(tb).infvar_mappings) == 7
126-
@test IOTO.lookup_by_support(y, tb, [0., 0, 0]) == IOTO.lookup_by_support(vref, tb, [0., 0])
127-
@test IOTO._set_semi_infinite_variable_mapping(tb, var, vref, ParameterFunctionIndex) isa Nothing
128-
end
129119
# test transcribe_semi_infinite_variables!
130120
@testset "transcribe_semi_infinite_variables!" begin
131121
@test IOTO.transcribe_semi_infinite_variables!(tb, m) isa Nothing
132122
@test IOTO.transcription_variable(yrv) isa Vector{VariableRef}
133-
@test length(IOTO.transcription_data(tb).infvar_mappings) == 8
123+
@test length(IOTO.transcription_data(tb).infvar_mappings) == 7
134124
@test IOTO.lookup_by_support(y, tb, [1., 0., 0.]) == IOTO.lookup_by_support(yrv, tb, [1., 0])
135125
end
136126
# test _update_point_info

0 commit comments

Comments
 (0)