Add variables in a container

Hello,
I’ve found a workaround to my problem but I wonder if there is a better way to solve it.
This is what I do:

using JuMP
model = JuMP.Model()
n = 10
@variable(model, -5 <= x0 <= 5, Int)
@variable(model, -5 <= x[1:n] <= 5, Int)
...
n += 1
push!(model.obj_dict[:x], @variable(model, base_name="x["*string(n)*"]", lower_bound=-5, upper_bound=5, integer=true))

What I would like is having @variable(model, -5 <= x[0:n] <= 5, Int) instead of x0 and x[1:n] but I didn’t find a way to push! into x with this writing.

Thank you
Rémi Garcia

You shouldn’t touch internal fields of the JuMP model like obj_dict, but otherwise this is correct. You can push to x if it remains in scope, or to model[:x] otherwise.

You can only push if the container is an Array (i.e., it has indices 1:n). If it’s a DenseAxisArray (e.g., with indices 0:n) or a SparseAxisArray, then this won’t work.

Thanks. I didn’t find this usage (model[:x]) in docs. I looked in Variables and Constraints sections. It might be useful to add this there. I found obj_dict with auto-completion.

Thanks for the precision. That’s what I though but I hoped there was a better workaround than my separated 0. For a given variable, if the indices are not overlapping is it an option to add auto-push in JuMP? In order to make this kind of code works:

using JuMP
model = JuMP.Model()
@variable(model, -5 <= x[0:5] <= 5, Int)
@variable(model, -5 <= x[6:12] <= 5, Int)

or

for i in 1:7
    @variable(model, x[i], lower_bound=foo(i))
end

Maybe with a parameter like force_same_name=true?

The model[:x] syntax is discussed in this section of the docs: http://www.juliaopt.org/JuMP.jl/v0.21.1/variables/#What-is-a-JuMP-variable?-1.

We might be able to do something like this. Could you open an issue with a feature request?

1 Like

I read that and… missed it. Should have double checked. Sorry.

Ok, I’ll open an issue for it. Thanks!

I found a second workaround, more viable for me:

using JuMP
model = JuMP.Model()
n = 10
@variable(model, [0:n], base_name="x", lower_bound=-5, upper_bound=5, integer=true))
@constraint(model, [i in 0:n], variable_by_name(model, "x["*string(i)*"]") <= foo(i))
...
n += 1
@variable(model, [n], base_name="x", lower_bound=-5, upper_bound=5, integer=true))
@constraint(model, variable_by_name(model, "x["*string(n)*"]") <= foo(n))

There is a drawback: the code becomes unreadable… This can be improved with x = [i => variable_by_name(model, "x["*string(i)*"]") for i in 0:n] before @constraint calls. Yet I’m not totally satisfied. I will open the issue tomorrow morning (in France).

You don’t have to use JuMP types as containers. See:

using JuMP
model = Model()
n = 10
x = Dict(
    i => @variable(model, base_name = "x_$(i)")
    for i = 0:n
)

n += 1
x[n] = @variable(model, base_name = "x_$I")
@constraint(model, x[n] <= foo(n))
2 Likes

This is great! I opened an issue (JuMP.jl#2200) but this does exactly what I needed. Thanks a lot.