Access JuMP variables queried as string

If a user wants to know the variable values for a JuMP model that is not exposed to the user directly, what are the options? For example:

using JuMP
using HiGHS

#some arbitrary JuMP model
model = Model(HiGHS.Optimizer)
@variable(model, x[1:3, 1:5] >= 0)
@constraint(model, sum(x[i,i+2] for i in 1:3) >= 5)
@objective(model, Min, sum(sum(x[i,j] for i in 1:3) for j in 1:5))
optimize!(model)

#Just assume that the above model is not exposed to the user and one cannot use `value` function directly. The only way user can query a variable is through the following input command.
variable_of_interest = readline() #x or x[1,:] or x[2,4], etc. #basically a string

#Then, how to make the following function work?
function val_return(m::Model, variable_of_interest)
    # convert variable_of_interest to form where I can actually use it
    return variable_value
end
# if variable_of_interest = "x", then we return the entire matrix of values
# if variable_of_interest = "x[:,1]", then we return the vector of values
# if variable_of_interest = "x[1,3]", then we return the scalar value

How to make the val_return function work if the input argument is a string? I see that variable_by_name function in JuMP might be useful but it only acts on a single element, i.e variable_by_name(model, "x[1,3]") works but variable_by_name(model, "x") doesn’t. Any help is appreciated. Thanks!

I recommend writing your MWE to not use Gurobi given it is a commerical solver not everyone has access to.

I don’t currently have JuMP installed but I think model["x"] should work?
Its been a while

Unfortunately, it doesn’t. model[:x] works but again my input is a string.

convert the input to a symbol?

model[Symbol("x")]

This works only if the input is "x". If the user inputs "x[1,3]" or "x[:,2]", this would fail.

In that case, I guess you have to manually parse the string expression and separate any indexing from the variable name. It shouldn’t be too hard?

julia> Meta.parse("x[1,1]")
:(x[1, 1])

julia> Meta.parse("x[1,1]") |> dump
Expr
  head: Symbol ref
  args: Array{Any}((3,))
    1: Symbol x
    2: Int64 1
    3: Int64 1
1 Like

This looks useful. Thanks! I am not super familiar with parsing this way. Any links where I can read more about it? Especially for cases like "x[:,2]".

Neither am I :slight_smile:

If all you can ever expect to get in the string is x or x[inds...] you could split it up something like

ex = parse(input)
if ex isa Symbol
    model[ex]
else
    getindex(model[ex.args[1]], eval.(ex.args[2:end])...)
end

(untested)

1 Like

This works. Thanks! :slight_smile:

Please do not use eval. It is unsafe, and it may return incorrect solutions if called from within a function instead of the top-level.

See also julia - Adding constraints to jump model from dict - Stack Overflow

The real answer is that using a string is the wrong approach.

Do something like:

function val_return(model::Model, variable_of_interest::String)
    return value.(model[Symbol(variable_of_interest)])
end

which returns a Matrix{Float64} to the user. Then they can decide whether to call x[:, 1] or x[1, 3]. Don’t make them write Julia code in a string and try to evaluate it.

3 Likes

Makes sense. Thanks!

1 Like