# Fastest way to add many JuMP constraints

**URL:** <https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587>\
**Category:** Optimization (Mathematical)\
**Tags:** question, jump\
**Created:** [October 11, 2021, 9:02pm UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587 "2021-10-11T21:02:09Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![ZHEN\_LIN](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhen_lin/32/27672_2.png) [@ZHEN\_LIN](https://discourse.julialang.org/u/ZHEN_LIN)\
**Post date:** [October 11, 2021, 9:02pm UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/1 "2021-10-11T21:02:09Z")

</div>

What is the best way to add the following constraints in JuMP to minimize computation time? I need to solve similar models many times.

```julia
@constraint(model, [i = 1:n, j = 1:m], [t[i, j], 1, x[i, j]] in MOI.ExponentialCone())

```

Another way for example is to do for loops:

```julia
for j = 1:m
     for i = 1:n
         @constraint(model, [t[i, j], 1, x[i, j]] in MOI.ExponentialCone())
      end
end

```

How to do this without loops? For example, with vectors? Will vectorized codes be faster when `n` or `m` is large?

As a related question, I remember I have seen cases where adding constraints with vectorized codes can be much faster than simply doing for loops, but I also heard that for loops are actually considered to be more efficient than vectorized codes. I’m a bit confused about in general which way to follow.

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:** [October 11, 2021, 11:17pm UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/2 "2021-10-11T23:17:26Z")

</div>

The two approaches are the same.

> I need to solve similar models many times.

What parts are you changing? JuMP has efficient support for modifying some parts of the model, so you won’t need to rebuild everything from scratch.

What solver are you using?

---

<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:** [October 11, 2021, 11:21pm UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/3 "2021-10-11T23:21:13Z")

</div>

For background:  
The general Julia language approach is discussed [here](https://docs.julialang.org/en/v1/manual/functions/#man-vectorized):

> In Julia, vectorized functions are not required for performance, and indeed it is often beneficial to write your own loops (see Performance Tips), but they can still be convenient.

I believe [this advice](https://jump.dev/JuMP.jl/dev/manual/variables/#variable_sparseaxisarrays) is also relevant to constraint containers if you happen to also use a conditional condition in the indexing e.g `[i = 1:n, j = 1:m; a[i,j] > 0]`:

> Note that with many index dimensions and a large amount of sparsity, variable construction may be unnecessarily slow if the semi-colon syntax is naively applied. When using the semi-colon as a filter, JuMP iterates over _all_ indices and evaluates the conditional for each combination. When this is undesired, the recommended work-around is to work directly with a list of tuples or create a dictionary.

---

<div class="post-metadata">

**Author:** ![ZHEN\_LIN](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhen_lin/32/27672_2.png) [@ZHEN\_LIN](https://discourse.julialang.org/u/ZHEN_LIN)\
**Post date:** [October 12, 2021, 12:34am UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/4 "2021-10-12T00:34:37Z")

</div>

> [@odow](#):
>
> What parts are you changing? JuMP has efficient support for modifying some parts of the model, so you won’t need to rebuild everything from scratch.
> 
> What solver are you using?

Thanks! The form and coefficients in the objective do not change. Some of the constraints in the models are changing. For example, like the following (suppose `t, x, y` are the variables)

`@constraint(model, Ay .== b)`  
`@constraint(model, t .== Cy + d)`  
`@constraint(model, [i = 1:n, j = 1:m], [t[i, j], 1, x[i, j]] in MOI.ExponentialCone())`

Part of the coefficient matrix `A` is changing.

How do I rebuild the model faster?

Also, I use the solver `Mosek.Optimizer`. Or is there a faster solver for models with exponential cones?

---

<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:** [October 12, 2021, 12:45am UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/5 "2021-10-12T00:45:25Z")

</div>

Mosek is a good choice.

For your `t`, you may be better doing

```nohighlight
@expression(model, t, Cy .+ d)

```

This avoids having to create a whole new matrix of variables.

Some things to try are

```julia
model = direct_model(Mosek.Optimizer())
# or
model = Model(Mosek.Optimizer, bridge_constraints = false)

```

You can efficiently modify elements in the A matrix using `set_normalized_coefficient`: [Constraints · JuMP](https://jump.dev/JuMP.jl/stable/manual/constraints/#Modifying-a-variable-coefficient)

---

<div class="post-metadata">

**Author:** ![ZHEN\_LIN](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhen_lin/32/27672_2.png) [@ZHEN\_LIN](https://discourse.julialang.org/u/ZHEN_LIN)\
**Post date:** [October 12, 2021, 1:05am UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/6 "2021-10-12T01:05:07Z")

</div>

> [@odow](#):
>
> For your `t` , you may be better doing
> 
> ```julia
> @expression(model, t, Cy .+ d)
> 
> ```
> 
> This avoids having to create a whole new matrix of variables.

Thanks! Would it be better to do this for all the intermediate variables like `t` here? That is, change equality constraints to expressions if possible? For example,

```julia
@variable(model, t[1:dim1])
@variable(model, t2[1:dim2, 1:dim3]) 
@objective(model, Min, c' * t2 + dot(t2 , t2))
@constraint(model, t2 .== A * t .+ b)

```

Then it would be better to change

```julia
@variable(model, t2[1:dim2, 1:dim3]) 
@constraint(model, t2 .== A * t .+ b)

```

to

```julia
@expression(model, t2, A * t .+ b)

```

right?

Also, I sometimes see codes that put `dot(t2, t2)` to the constraint by introducting another variable ` t3 >= dot(t2, t2)`, but would this simply add additional variables and constraints, and make things slower?

---

<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:** [October 12, 2021, 3:08am UTC](https://discourse.julialang.org/t/fastest-way-to-add-many-jump-constraints/69587/7 "2021-10-12T03:08:43Z")

</div>

> [@ZHEN\_LIN](#):
>
> Would it be better to do this for all the intermediate variables like `t` here?

In most cases, yes. More variables means more work for the solver. (It’s possible to construct a case where more variables is faster, but a good rule of thumb is fewer variables = better.)

You’ll also end up with weird cases where `abs(t2 - (A * t .+ b)) > 0` because of tolerances (i.e., the equality doesn’t hold exactly, only approximately).

Usually adding single epigraph variables like `t3` is fine, and in some cases even encouraged.
