How to refer to a JuMP variable using a string when the model is defined in a module?

Hello, in a JuMP model I need to fix some variables, and these variables to fix are defined in a dictionary.

This works:

using JuMP, Ipopt
fvars   = Dict{String,Float64}("c" => 5)
m = Model(Ipopt.Optimizer)
# [...]
@variable(m, c) 
for (k,v) in fvars
    fix(eval(Symbol(k)), v; force = true)
end
# [...]

However if I wrap the model in a module I got an UndefVarError:

module Foo 
using JuMP, Ipopt
function foo()
    fvars   = Dict{String,Float64}("c" => 5)
    m = Model(Ipopt.Optimizer)
    # [...]
    @variable(m, c) 
    for (k,v) in fvars
        fix(eval(Symbol(k)), v; force = true)
    end
    # [...]
end
end

ERROR: UndefVarError: cnot defined inMain.Foo``

I guess the “eval” somehow happens too early, is there any workaround ?

Actually the issue was that the model was in a function, not much that it was embedded in a module…

I solved by using

global c = @variable(m, c)

but I guess if there is a better way, as this may kill the performances of my program (not much of the solving the optimization itself)…

First. Never use eval. It is always the wrong thing to do.

Either use variable_by_name, or, if the variable is registered, convert the string to a symbol and do model[Symbol(k)]:

using JuMP, Ipopt
function foo()
    fvars   = Dict{String,Float64}("c" => 5)
    m = Model(Ipopt.Optimizer)
    @variable(m, c) 
    for (k, v) in fvars
        # Option 1
        x = variable_by_name(m, k)
        fix(x, v; force = true)
        # Option 2
        x = m[Symbol(k)]
        fix(x, v; force = true)
    end
end

More generally, consider using some sort of data structure that you control:

using JuMP, Ipopt
function foo()
    fvars = Dict{String,Float64}("c" => 5)
    my_variables = Dict{String,VariableRef}()
    m = Model(Ipopt.Optimizer)
    my_variables["c"] = @variable(m, c)
    for (k, v) in fvars
        fix(my_variables[k], v; force = true)
    end
end
3 Likes

Thank you.

Just to notice that in my specific model, adding a constraint @constraint(m, x == v) is much faster than using fix.