JuMP: filtering the output of JuMP.value.(x)

Is there a nice idiom for filtering all of the elements of a JuMP array of binaries that are set? Even with iterating over the elements of JuMP.value.(x) in a for-loop I don’t seem to be able to catch the indices in a useful format.

Thanks.

What do you mean by “set”?

The answer depends on the container of the JuMP variable.

Arrays:

using JuMP, GLPK
model = Model(with_optimizer(GLPK.Optimizer))
@variable(model, x[1:2, 1:2], Bin)
optimize!(model)
filter(k -> value(x[k]) > 0.5, keys(x))

Containers.DenseAxisArray:

using JuMP, GLPK
model = Model(with_optimizer(GLPK.Optimizer))
@variable(model, x[1:2, [:A, :B]], Bin)
optimize!(model)
# The following doesn't work for some reason
filter(k -> value(x[k]) > 0.5, keys(x))
# Here is a work-around
filter(k -> value(x[k]) > 0.5, collect(keys(x)))

Containers.SparseAxisArray:

using JuMP, GLPK
model = Model(with_optimizer(GLPK.Optimizer))
@variable(model, x[i=1:2, j=i:2], Bin)
optimize!(model)
# The following doesn't work: it appears to be a bug.
filter(k -> value(x[k]) > 0.5, keys(x))
# Here is a work-around
filter(k -> value(x[k]) > 0.5, collect(keys(x.data)))

I’ll open an issue in JuMP: Unify treatment of `keys` on JuMP containers. · Issue #1988 · jump-dev/JuMP.jl · GitHub

Sorry, that’s the electrical engineer coming out in me :wink:

Here’s what I got following your suggestions:

julia> typeof(x)
JuMP.Containers.DenseAxisArray{VariableRef,1,Tuple{Array{Tuple,1}},Tuple{Dict{Tuple,Int64}}}

julia> collect(keys(x))
ERROR: MethodError: Cannot `convert` an object of type JuMP.Containers.DenseAxisArrayKey{Tuple{Tuple{Int64,Int64}}} to an object of type JuMP.Containers.DenseAxisArrayKey{Tuple{Tuple}}
Closest candidates are:
  convert(::Type{S}, ::T< .....
    :

julia> keys(x)
JuMP.Containers.DenseAxisArrayKeys{Tuple{Array{Tuple,1}}}(Base.Iterators.ProductIterator{Tuple{Array{Tuple,1}}}((Tuple[(1, 4), (4, 1), (1, 10), (10, 1), (1, 12), (12, 1), (1, 14), (14, 1), (1, 18), (18, 1)  …  (45, 48), (48, 45), (45, 50), (50, 45), (46, 49), (49, 46), (47, 48), (48, 47), (47, 50), (50, 47)],)))
julia> filter(k -> value(x[k]) > 0.5, keys(x))
ERROR: MethodError: no method matching filter(::getfield(Main, Symbol("##1067#1068")), ::JuMP.Containers.DenseAxisArrayKeys{Tuple{Array{Tuple,1}}})
Closest candidates are:
  filter(::Any, ::Array{T,1} where T) at array.jl:2351
  filter(::Any, ::BitArray) at bitarray.jl:1710
  filter(::Any, ::AbstractArray) at array.jl:2312
  ...

Not sure if I’m doing something wrong here. Thanks.

Please provide a minimum working example. See: Please read: make it easier to help you

Do the ones above work for you?