What is the difference between variable definition in JuMP like these two ways

I got two difinition ways used in my JuMP model. And I encountered some trouble when I try to access their results using value function. A is a variable defined as @variable(M, A[i = 1:3, t = 1:24]) and B is like @variable(M, B[i in [1,2,3], t = 1:24]). When I access their values, A yields a matrix, while B gives a DenseAxisArray. This kind of difference cause some trouble when I try to record them in dataframes using Dataframe(value.(A/B), :auto). A is good to go while B throwed an error no method matching to_shape(::Tuple{Vector{Int64}}).

How could I avoid this without changes to model definition?

1 Like

The difference is that B defines a variable container whereas A does not. If you do not like to change your model definition, a (probably inefficient) workaround is to create an empty DataFrame and to fill it value by value, e.g., value(A[i,t]) / value(B[i,t]) packed into an appropriate loop.

1 Like

Thanks, it’s a viable solution. I checked JuMP’s documentation and found that B’s data could be accessed using Array(value.(B)) or just value.(B).data.

2 Likes

The trick is that JuMP cannot “see” that [1,2,3] is the same as 1:3. It has to assume that the first vector could contain arbitrary integers.

As a result, it builds a different type of container. You seem on the right track with the rest.

I would also look into the possibility of using the rowtable() function from JuMP.Containers which will work with the DenseAxisArray and can be used to initialize a dataframe directly:

using JuMP
using DataFrames
using HiGHS

M = Model(HiGHS.Optimizer)

@variable(M, B[i in [1,2,3], t = 1:24])
@objective(M, Min, 0)

optimize!(M)

df = DataFrame(Containers.rowtable(value, B))

It is also possible to specify the column names by using the header argument.

2 Likes