How to loop over the variables of a JuMP model?

Hi,
I hope my question is not already answered somewhere else, I couldn’t find it.
Here is the beginning of a MWE (I actually have many more variables and bigger sets):

using JuMP, Gurobi
model = Model(Gurobi.Optimizer)
set_silent(model)
I = 1:5
J = 1:10
K = 8:20
@variables(model, begin
    a[i=I, j=J]
    b[j=J]
    c[i=I, k=K]
end)

At the end, I have a solution with results that I wish to process. How can I loop over the variables without calling them explicitly ? Is it possible to call for some results vector/container/…, where results[1] contains my variable a ?
Currently, I store the results in dictionaries or dataframes this way:

dict_output= OrderedDict{String, Any}() 
dict_output["a"]=value.(model[:a])
dict_output["b"]=value.(model[:b])
dict_output["c"]=value.(model[:c])

My main goal is to process the results differently, depending on their dimensions.

Thank you in advance

It depends what you want.

all_variables(model) gives you a vector of every variable, so perhaps:

dict_output = Dict(x => value(x) for x in all_variables(model))

Or you might want:

dict_output = Dict(
    k => value.(v) for (k, v) in object_dictionary(model)
)

You’re also free to create your own data structure:

@variables(model, begin
    a[i=I, j=J]
    b[j=J]
    c[i=I, k=K]
end)
results = Dict("a" => a, "b" => b, "c" => c)
dict_output = Dict(k => value.(v) for (k, v) in results)

You’re not limited to using only the functions defined by JuMP.

1 Like

I can deal with object_dictionary. Many thanks !
Btw, is there a way to distinguish variables from constraints or expressions ?

1 Like

Btw, is there a way to distinguish variables from constraints or expressions ?

It’s always useful to remember that JuMP variables and constraints are normal Julia types. So you can use non-JuMP functions to manipulate them. For example, you might do:

dict_output = Dict{Symbol,Any}()
for (k, v) in object_dictionary(model)
    if v isa VariableRef
        dict_output[k] = value(v)
    elseif v isa AbstractArray{VariableRef}
        dict_output[k] = value.(v)
    else
        # skip. probably a constraint or an expressionn
    end
end

or perhaps even

function add_output(dict_output, k, v::VariableRef)
    dict_output[k] = value(v)
end

function add_output(dict_output, k, v::AbstractArray{VariableRef})
    dict_output[k] = value.(v)
end

function add_output(dict_output, k, v::Any)
    @info "Skipping key = $k of type $(typeof(v))"
end

dict_output = Dict{Symbol,Any}()
for (k, v) in object_dictionary(model)
    add_output(dict_output, k, v)
end
1 Like

Yes, indeed. Thank you for the examples !

1 Like