# Iterating through JuMP variables

**URL:** <https://discourse.julialang.org/t/iterating-through-jump-variables/96816>\
**Category:** Optimization (Mathematical)\
**Tags:** question, jump\
**Created:** [March 30, 2023, 1:32am UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816 "2023-03-30T01:32:50Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![math\_opt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/math_opt/32/25317_2.png) [@math\_opt](https://discourse.julialang.org/u/math_opt)\
**Post date:** [March 30, 2023, 1:32am UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816/1 "2023-03-30T01:32:50Z")

</div>

I am doing some trivial checks on the variable values output by my optimization model, and I was wondering what is the correct way to iterate through a `JuMP` variable. For example, if my model has a variable `x[2:9, 10:15]`, what is the best way to check whether each of the variable values is binary? I wanted to write a generic function that would check this irrespective of what exactly my variable indices are, for which, I thought I can simply write a for loop which calls `size(value.(x),1)` and `size(value.(x),2)`, and I can step through each element. But I guess `size` does not work on `SparseAxisArray`.

Also, what could be done if my second indices is a function of the first one? For example, `x[i=2:3, j=1:2*i]`. In this case, how to iterate through each element? I guess `eachindex` works for this case, but I am not sure that’s the best way to do it.

Any help here is appreciated. Thanks!

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [March 30, 2023, 3:18am UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816/2 "2023-03-30T03:18:57Z")

</div>

You have a few options:

```julia
julia> model = Model();

julia> @variable(model, x[2:9, 10:15])
2-dimensional DenseAxisArray{VariableRef,2,...} with index sets:
    Dimension 1, 2:9
    Dimension 2, 10:15
And data, a 8×6 Matrix{VariableRef}:
 x[2,10] x[2,11] x[2,12] x[2,13] x[2,14] x[2,15]
 x[3,10] x[3,11] x[3,12] x[3,13] x[3,14] x[3,15]
 x[4,10] x[4,11] x[4,12] x[4,13] x[4,14] x[4,15]
 x[5,10] x[5,11] x[5,12] x[5,13] x[5,14] x[5,15]
 x[6,10] x[6,11] x[6,12] x[6,13] x[6,14] x[6,15]
 x[7,10] x[7,11] x[7,12] x[7,13] x[7,14] x[7,15]
 x[8,10] x[8,11] x[8,12] x[8,13] x[8,14] x[8,15]
 x[9,10] x[9,11] x[9,12] x[9,13] x[9,14] x[9,15]

julia> is_binary.(x)
2-dimensional DenseAxisArray{Bool,2,...} with index sets:
    Dimension 1, 2:9
    Dimension 2, 10:15
And data, a 8×6 Matrix{Bool}:
 0 0 0 0 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0
 0 0 0 0 0 0

julia> any(is_binary.(x))
false

julia> @variable(model, y[i=2:3, j=1:2*i])
JuMP.Containers.SparseAxisArray{VariableRef, 2, Tuple{Int64, Int64}} with 10 entries:
  [2, 1] = y[2,1]
  [2, 2] = y[2,2]
  [2, 3] = y[2,3]
  [2, 4] = y[2,4]
  [3, 1] = y[3,1]
  [3, 2] = y[3,2]
  [3, 3] = y[3,3]
  [3, 4] = y[3,4]
  [3, 5] = y[3,5]
  [3, 6] = y[3,6]

julia> is_binary.(y)
JuMP.Containers.SparseAxisArray{Bool, 2, Tuple{Int64, Int64}} with 10 entries:
  [2, 1] = false
  [2, 2] = false
  [2, 3] = false
  [2, 4] = false
  [3, 1] = false
  [3, 2] = false
  [3, 3] = false
  [3, 4] = false
  [3, 5] = false
  [3, 6] = false

julia> any(is_binary.(y))
false

julia> all(.!is_binary.(y))
true

julia> for i in eachindex(x)
       @show i, x[i], is_binary(x[i])
       end
(i, x[i], is_binary(x[i])) = (CartesianIndex(1, 1), x[2,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(2, 1), x[3,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(3, 1), x[4,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(4, 1), x[5,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(5, 1), x[6,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(6, 1), x[7,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(7, 1), x[8,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(8, 1), x[9,10], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(1, 2), x[2,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(2, 2), x[3,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(3, 2), x[4,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(4, 2), x[5,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(5, 2), x[6,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(6, 2), x[7,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(7, 2), x[8,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(8, 2), x[9,11], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(1, 3), x[2,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(2, 3), x[3,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(3, 3), x[4,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(4, 3), x[5,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(5, 3), x[6,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(6, 3), x[7,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(7, 3), x[8,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(8, 3), x[9,12], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(1, 4), x[2,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(2, 4), x[3,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(3, 4), x[4,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(4, 4), x[5,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(5, 4), x[6,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(6, 4), x[7,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(7, 4), x[8,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(8, 4), x[9,13], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(1, 5), x[2,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(2, 5), x[3,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(3, 5), x[4,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(4, 5), x[5,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(5, 5), x[6,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(6, 5), x[7,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(7, 5), x[8,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(8, 5), x[9,14], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(1, 6), x[2,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(2, 6), x[3,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(3, 6), x[4,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(4, 6), x[5,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(5, 6), x[6,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(6, 6), x[7,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(7, 6), x[8,15], false)
(i, x[i], is_binary(x[i])) = (CartesianIndex(8, 6), x[9,15], false)

julia> for i in eachindex(y)
       @show i, y[i], is_binary(y[i])
       end
(i, y[i], is_binary(y[i])) = ((2, 4), y[2,4], false)
(i, y[i], is_binary(y[i])) = ((3, 2), y[3,2], false)
(i, y[i], is_binary(y[i])) = ((3, 1), y[3,1], false)
(i, y[i], is_binary(y[i])) = ((3, 3), y[3,3], false)
(i, y[i], is_binary(y[i])) = ((3, 6), y[3,6], false)
(i, y[i], is_binary(y[i])) = ((2, 2), y[2,2], false)
(i, y[i], is_binary(y[i])) = ((2, 1), y[2,1], false)
(i, y[i], is_binary(y[i])) = ((3, 4), y[3,4], false)
(i, y[i], is_binary(y[i])) = ((2, 3), y[2,3], false)
(i, y[i], is_binary(y[i])) = ((3, 5), y[3,5], false)

```

The documentation describes different ways of working with containers: [Containers · JuMP](https://jump.dev/JuMP.jl/stable/manual/containers/#DenseAxisArray)

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [March 30, 2023, 3:50am UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816/3 "2023-03-30T03:50:49Z")

</div>

Also worth reading through the [Variables](https://jump.dev/JuMP.jl/stable/reference/variables/#VariableAPI) API documentation.

---

<div class="post-metadata">

**Author:** ![math\_opt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/math_opt/32/25317_2.png) [@math\_opt](https://discourse.julialang.org/u/math_opt)\
**Post date:** [March 30, 2023, 4:27am UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816/4 "2023-03-30T04:27:57Z")

</div>

Hi @odow,

Thanks for the reply. But maybe I was not very clear in what I wanted to do. I don’t want to check whether the variables are constrained to be binary or not. I want to check whether the values they eventually take are binary or not. For example:

```julia
using JuMP
using Gurobi

model = Model(Gurobi.Optimizer)

@variable(model, 0 <= x[1:3, 1:5] <=1)
@variable(model, 0<=y[i=2:4,j=2*i]<=1)

@constraint(model, [i=1:2, j=2:4], x[i,j] + y[j,2*j] >= 0.5)

@objective(model, Min, sum(x[i,j] for i in 1:3, j in 1:5) + sum(y[i,2*i] for i in 2:4))

optimize!(model)

```

Now, I want to check whether the values `x` and `y` take are binary or not (within some tolerance).  
To check that, I do:

```julia
function is_var_value_0_or_1(var; tol=1e-5)
    for (n,k) in eachindex(var)
        if !isapprox(var[n,k], 0.0, atol = tol) && !isapprox(var[n,k], 1.0, atol = tol)
            return false
        end
    end
    return true
end

```

For `x`:

```julia
is_var_value_0_or_1(value.(x)) # Should return true
# Throws the following error:
# ERROR: BoundsError: attempt to access Int64 at index [2]

```

For `y`, it works fine:

```julia
is_var_value_0_or_1(value.(y))
# Returns false

```

I want to write a generic function `is_var_value_0_or_1` (I know it’s terrible naming!) that takes in the data structure containing the variable values (and figures out its dimensions) and returns `true` if they are either 0 or 1, otherwise `false`.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [March 30, 2023, 11:37pm UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816/5 "2023-03-30T23:37:35Z")

</div>

You’re approaching this from the wrong direction. Instead of writing a function that works over a container of JuMP variables, write a function that works for a single variable, then broadcast over that. So something like (I didn’t run the code, so there might by typos, etc):

```julia
function is_var_value_0_or_1(x::Real; kwargs...)
    return isapprox(x, 0; kwargs...) || isapprox(x, 1; kwargs...)
end

all(is_var_value_0_or_1.(value.(x); atol = 1e-5))

function is_var_value_0_or_1(x::VariableRef; kwargs...)
    return is_var_value_0_or_1(value(x); kwargs...)
end

all(is_var_value_0_or_1.(x; atol = 1e-5))

function is_var_value_0_or_1(x::AbstractArray{VariableRef}; kwargs...)
    return all(is_var_value_0_or_1.(x; kwargs...))
end

is_var_value_0_or_1(x; atol = 1e-5)

```

---

<div class="post-metadata">

**Author:** ![math\_opt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/math_opt/32/25317_2.png) [@math\_opt](https://discourse.julialang.org/u/math_opt)\
**Post date:** [March 31, 2023, 8:33pm UTC](https://discourse.julialang.org/t/iterating-through-jump-variables/96816/6 "2023-03-31T20:33:01Z")

</div>

Wow. I was making it unnecessarily complicated. Thanks for pointing me in the right direction! 🙂
