# Reducing model building time

**URL:** https://discourse.julialang.org/t/reducing-model-building-time/97069
**Category:** Optimization (Mathematical)
**Tags:** question, jump
**Created:** [April 4, 2023, 4:00pm UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069 "2023-04-04T16:00:29Z")
**Posts on this page:** 9
**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: [April 4, 2023, 4:00pm UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/1 "2023-04-04T16:00:29Z")

</div>

Is there a difference in the time taken to build the JuMP model if I use `for` loops for defining variables/constraints. For example:

```julia
using JuMP
model = Model()

@variable(model, x[i in 1:7, j in 1:10] >= 0)
@constraint(model, [i in 2:6, j in 3:7], x[i,j] + x[j,i] >= 10)

```

Now, instead, if I do the following:

```julia
using JuMP
model = Model()
for i in 1:7
    for j in 1:10
        @variable(model, x[i,j] >= 0)
    end
end

for i in 2:6
    for j in 3:7
        @constraint(model, x[i,j] + x[j,i] >= 10)
    end
end

```

Although the first method is more succinct, is it always better than defining variables/constraint using `for` loops (or the other way round)? For small models, I understand there is practically no difference, but how do the two methods differ for large models. I obviously have a large model and want to make sure that the model building time is reduced.

Also, is one method better than the other if I have conditions in the variable/constraint definition? For example, something like `x[i=1:4; mod(i, 2)==0]`. Is it better (or worse) to use a for loop in this case?

---

<div class="post-metadata">

### Author: ![NiclasMattsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niclasmattsson/32/21988_2.png) [@NiclasMattsson](https://discourse.julialang.org/u/NiclasMattsson)
#### Post date: [April 4, 2023, 4:44pm UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/2 "2023-04-04T16:44:41Z")

</div>

I don’t think there’s any significant difference between the two versions for large models, at least as written, but I’ll leave the final word on this to the JuMP devs. In your second example though, an explicit for loop could be better when you have something like this: `x[i in 1:1000, j in 1:1000, k in 1:1000; demanding_computation(k)==0]`. That’s because it unrolls to something like this…

```julia
for i in 1:1000, j in 1:1000, k in 1:1000
    if demanding_computation(k) == 0
        @variable(model, x[i,j,k])
    end
end

```

Then it should be clear that this is better…

```julia
for k in 1:1000
    if demanding_computation(k) == 0
        for i in 1:1000, j in 1:1000
            @variable(model, x[i,j,k])
        end
    end
end

```

See also [this section](https://jump.dev/JuMP.jl/stable/manual/variables/#Performance-considerations) of the JuMP manual.

---

<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: [April 4, 2023, 8:29pm UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/3 "2023-04-04T20:29:50Z")

</div>

@NiclasMattsson hit upon the major points.

Depending on the solver, one thing that can help is [Performance tips · JuMP](https://jump.dev/JuMP.jl/stable/tutorials/getting_started/performance_tips/#Disable-string-names).

Other than that, it’s usually a case that if your model takes a long time to build, it’s going to take an even longer time to solve.

---

<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: [April 4, 2023, 10:16pm UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/4 "2023-04-04T22:16:36Z")

</div>

Thanks @NiclasMattsson and @odow for the input on this.

---

<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: [April 5, 2023, 12:49am UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/5 "2023-04-05T00:49:35Z")

</div>

Hi @odow,  
Defining variables using for loop gives me the following error:

```julia
using JuMP
model = Model()
for k in 1:10
    if demanding_computation(k) == 0
        for i in 1:10, j in 1:10
            @variable(model, x[i,j,k])
        end
    end
end

```

This gives me the following error:

```julia
ERROR: An object of name x is already attached to this model. If this
    is intended, consider using the anonymous construction syntax, e.g.,
    `x = @variable(model, [1:N], ...)` where the name of the object does
    not appear inside the macro.

    Alternatively, use `unregister(model, :x)` to first unregister
    the existing name from the model. Note that this will not delete the
    object; it will just remove the reference at `model[:x]`.

```

Any way around this (I still want to use for loop)? 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: [April 5, 2023, 12:58am UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/6 "2023-04-05T00:58:44Z")

</div>

You cannot build a variable like this.

- [Variables · JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#variable_sparseaxisarrays)
- [Variables · JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#User-defined-containers)

It’s always useful to remember that JuMP is not a special part of Julia, so if you find yourself fighting the JuMP syntax, use a different datastructure.

I would do

```julia
using JuMP
model = Model()
add_k = [demanding_computation(k) for k in 1:10]
@variable(model, x[i=1:10, j=1:10, k=1:10; add_k[k]])

```

---

<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: [April 5, 2023, 2:09am UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/7 "2023-04-05T02:09:25Z")

</div>

Thanks. That makes sense. One last question:  
If I have a predefined set of indices like `indices = [[1,2,3], [4,5,6]]`, and I want to construct variables `x[1,2,3] and x[4,5,6]` out of it, I usually simply do:

```julia
using JuMP
model = Model()

@variable(model, x[indices] >= 0)

```

Although I get the correct indices, I get an extra parenthesis like `x[[1,2,3]]` and `x[[4,5,6]]`, which is expected because `@variable(model, x[indices] >=0)` is same as `@variable(model, x[i in indices])`, so each vector serve as a single index. I assume this is not an issue, but is there a way I can still get multiple indices, i.e., x[1,2,3] instead of x[[1,2,3]]?

(I can post this as a separate question if you feel it’s unrelated). 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: [April 5, 2023, 2:20am UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/8 "2023-04-05T02:20:44Z")

</div>

This is a slightly subtle question, in which the difference is a dense, one-dimensional array of variables with the keys `[1, 2, 3]` and `[4, 5, 6]`, and a sparse, three-dimensional array of variables with elements in positions `(1, 2, 3)` and `(4, 5, 6)`.

- See [Getting started with sets and indexing · JuMP](https://jump.dev/JuMP.jl/stable/tutorials/getting_started/getting_started_with_sets_and_indexing/#Sets-of-other-things)

This comes back to the data structure question. There’s no correct answer, it depends on your model, and _why_ you want that.

These three examples might be helpful:

```julia
julia> using JuMP

julia> indices = [[1,2,3], [4,5,6]]
2-element Vector{Vector{Int64}}:
 [1, 2, 3]
 [4, 5, 6]

julia> model = Model();

julia> @variable(model, x[indices])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
    Dimension 1, [[1, 2, 3], [4, 5, 6]]
And data, a 2-element Vector{VariableRef}:
 x[[1, 2, 3]]
 x[[4, 5, 6]]

julia> x[[1, 2, 3]]
x[[1, 2, 3]]

julia> x[indices[1]]
x[[1, 2, 3]]

julia> indices2 = [tuple(i...) for i in indices]
2-element Vector{Tuple{Int64, Int64, Int64}}:
 (1, 2, 3)
 (4, 5, 6)

julia> model = Model();

julia> @variable(model, x[indices2])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
    Dimension 1, [(1, 2, 3), (4, 5, 6)]
And data, a 2-element Vector{VariableRef}:
 x[(1, 2, 3)]
 x[(4, 5, 6)]

julia> x[(1, 2, 3)]
x[(1, 2, 3)]

julia> x[indices2[1]]
x[(1, 2, 3)]

julia> I, J, K = [sort(unique(getindex.(indices, i))) for i in 1:3]
3-element Vector{Vector{Int64}}:
 [1, 4]
 [2, 5]
 [3, 6]

julia> model = Model();

julia> @variable(model, x[i=I, j=J, k=K; [i, j, k] in indices])
JuMP.Containers.SparseAxisArray{VariableRef, 3, Tuple{Int64, Int64, Int64}} with 2 entries:
  [1, 2, 3] = x[1,2,3]
  [4, 5, 6] = x[4,5,6]

julia> x[1, 2, 3]
x[1,2,3]

```

The real answer is that if you’re building large-scale problems, pick a data structure that best suits the problem, not necessarily one that is provided by JuMP.

---

<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: [April 5, 2023, 3:09am UTC](https://discourse.julialang.org/t/reducing-model-building-time/97069/9 "2023-04-05T03:09:51Z")

</div>

Sounds good. Thanks for a very clear explanation!
