Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/Utilities/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,36 @@ function substitute_variables(
return MOI.ScalarNonlinearFunction(f.head, new_args)
end

function substitute_variables(
variable_map::F,
f::MOI.VectorOfVariables,
) where {F<:Function}
variables = MOI.VariableIndex[]
for (i, x) in enumerate(f.variables)
y = variable_map(x)
try
push!(variables, convert(MOI.VariableIndex, y))
catch err
@assert err isa InexactError
error(
"""
Cannot substitute variables in the `VectorOfVariables` \
function because the result is not representable as a \
`VectorOfVariables` function.

The variable `$x` in index `$i` is mapped to the expression \
`$y`, not directly to another `VariableIndex`.

Note that variables constrained on creation can be used in a \
`VectorOfVariables` function only when their bridge maps each \
one directly to another variable, without a transformation.
""",
)
end
end
return MOI.VectorOfVariables(variables)
end

function substitute_variables(
variable_map::F,
f::MOI.VectorAffineFunction{T},
Expand Down
26 changes: 26 additions & 0 deletions test/Utilities/test_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,32 @@ function test_substitute_variables()
return
end

function test_substitute_variables_vector_of_variables()
w, x, y, z = MOI.VariableIndex.(1:4)
f1 = MOI.VectorOfVariables([w, x])
f2 = MOI.VectorOfVariables([y, z])
v_map = Dict(w => y, x => z)
@test MOI.Utilities.substitute_variables(v -> v_map[v], f1) == f2
@test_throws(
ErrorException(
"""
Cannot substitute variables in the `VectorOfVariables` function \
because the result is not representable as a `VectorOfVariables` \
function.

The variable `$w` in index `1` is mapped to the expression \
`$(2.0 * w)`, not directly to another `VariableIndex`.

Note that variables constrained on creation can be used in a \
`VectorOfVariables` function only when their bridge maps each \
one directly to another variable, without a transformation.
""",
),
MOI.Utilities.substitute_variables(vi -> 2.0 * vi, f1),
)
return
end

function test_substitute_variables_vector_nonlinear_function()
model = MOI.Utilities.UniversalFallback(MOI.Utilities.Model{Float64}())
x = MOI.add_variable(model)
Expand Down
Loading