# How to use elements of a N*M elements Vector of Vector for a constraint

Hi,

We have two sets `A = [1,2,...,N]` and `B = [1,2,...,M]`. There are two other sets `SA, SB` associated with `A` and `B`which are N-elements and M-elemets vector of vector.

``````A = [1:N]
B = [1:M]

SA =  [ [some stuff for 1] , [some stuff for 2] ,..., [[some stuff for N] ]
SB =  [ [some stuff for 1] , [some stuff for 2] ,..., [[some stuff for M] ]
``````

I’m interested in the intersection of things between `SA` and `SB` to later use them for a constraint.
Therefore I did the following:

``````AB  =  [(a,b) for a in A for b in B]
SAB = [ intersect( SA[a], SB[b]) for (a,b) in AB]

``````

This outputs N*M elements Vector of Vector. Until this point things are fine. Now I’d like to add a constrains to model that says:

``````sum( a in A , y[i, a, b]) <=  U*x[i,j,b]    for all b in B and i in SAB and j in SAB # where U is a constant
``````

Therefore I translate it like below:

``````@constraint(model, [(a,b) in AB, i in SAB[a,b], j in SAB[a,b]], sum( y[i,a,b] for a in A) <= U * x[i,j,b])
``````

But it return error like `KeyError: key (this, this, this) not found`. Next time I tried this

``````@constraint(model, [(b in B, i in SAB[a,b], j in SAB[a,b]], sum( y[i,a,b] for a in A) <= U * x[i,j,b])
``````

Altough I knew it’s incorrect, but the only issue is that I cannot say `i in SAB[a,b]` when I only use ` [(b in B, i in SAB[a,b], j in SAB[a,b]]` Right??

Basically, how we could do this? Sum over `b` while using elements of sahred vector like `SAB`?

You could instead try to collect the constraint indices into a separate vector first, and just work around this:

``````julia> constraint_index = Any[]
Any[]

julia> for (a,b) in AB, i in SAB[a,b], j in SAB[a,b]; push!(constraint_index, (;a,b,i,j)); end

julia> constraint_index
4-element Vector{Any}:
(a = 1, b = 4, i = 1, j = 1)
(a = 2, b = 1, i = 2, j = 2)
(a = 2, b = 3, i = 2, j = 2)
(a = 3, b = 4, i = 4, j = 4)
``````

If you don’t use the macro to parse the constraint indices, then using such an array of tuples seems like it’s easier:

``````julia> @constraint(model, c[(;a,b,i,j) in constraint_index], sum(y[i,a,b] for a in A) <= x[i,j,b])
1-dimensional DenseAxisArray{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}, ScalarShape},1,...} with index sets:
Dimension 1, Any[(a = 1, b = 4, i = 1, j = 1), (a = 2, b = 1, i = 2, j = 2), (a = 2, b = 3, i = 2, j = 2), (a = 3, b = 4, i = 4, j = 4)]
And data, a 4-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.LessThan{Float64}}, ScalarShape}}:
c[(a = 1, b = 4, i = 1, j = 1)] : y[1,1,4] + y[1,2,4] + y[1,3,4] - x[1,1,4] ≤ 0.0
c[(a = 2, b = 1, i = 2, j = 2)] : y[2,1,1] + y[2,2,1] + y[2,3,1] - x[2,2,1] ≤ 0.0
c[(a = 2, b = 3, i = 2, j = 2)] : y[2,1,3] + y[2,2,3] + y[2,3,3] - x[2,2,3] ≤ 0.0
c[(a = 3, b = 4, i = 4, j = 4)] : y[4,1,4] + y[4,2,4] + y[4,3,4] - x[4,4,4] ≤ 0.0

julia> c[(a=1,b=4,i=1,j=1)]
c[(a = 1, b = 4, i = 1, j = 1)] : y[1,1,4] + y[1,2,4] + y[1,3,4] - x[1,1,4] ≤ 0.0
``````

You can index into the vector of constraints by arbitrary tuples this way.

(I used some arbitrary arrays A,B,etc., I hope I understood your example.)

I’m really not sure that the macro is even intended to parse complex for-loops like that in the index set, I think it’s just trying to figure out the dimensions of an array and failing.

2 Likes

It’s hard to tell what’s going wrong without a reproducible example. For example, it’s not obvious what `SAB[a, b]` is. Isn’t `SAB` a vector? Do you mean `SAB = Dict((a, b) => intersect( SA[a], SB[b]) for (a,b) in AB)` and then `SAB[(a, b)]`?

But @ikirill’s suggestion of collating the indices is a good one. Don’t feel you need to be constrained by the helper syntax that JuMP provides. It’s a helper, but there are other ways if things are more complicated.

1 Like

Thanks @ikirill this is very fresh to me. Nice to learn that. I did try it but I still have key error. There’s something wrong that is very uncelar why!! But thanks a lot. It is very inetersting.

I guess, the issue is realted to the `sum` part (`sum(y[i,a,b] for a in A)`. When I ran the exact things as yours. It says: `KeyError: key (661, 15, 14) not found`. which is one of the combinations of `(i,a,b)`. I mean it seems when summing over `a in A` there are some `(i,a,b)` which did not form by `constraint_index`

Thank @odow. Yes. They are like this

``````AB = [(a,b) for a in A for b in B]
sAB = [intersect(SA[a], SB[b]) for (a,b) in AB)]
SAB = Dict(  AB .=> sAB)

``````

The question is harder to understand fully because you haven’t stated which indexing you’ve defined for `x` and `y`.

There are two scopes happening here, where the index `a` appears in two places: first, in `(a,b) in AB` and then inside the `sum( ... for a in A)`. I would say that you probably want to write this as

``````@constraint(model,
[(a,b) in AB, i in SAB[a,b], j in SAB[a,b]],
sum( y[i,aa,b] for aa in A if aa == a) <= U * x[i,j,b]
)
``````

A full minimal working example to test might look like this; you would help a lot by creating a similar one for future discussions:

``````using JuMP
model = JuMP.Model()

A = 1:4
B = 1:3
AB  =  [(a,b) for a in A for b in B]

SA = Dict([i => 10*i:10*(i+1) for i in A])
SB = Dict([i => [10*(i-1), 10*(i+2)] for i in B])
SAB = Dict((a, b) => intersect( SA[a], SB[b]) for (a,b) in AB)

SAB_vals = union(values(SAB)...)

@variable(model, x[i=SAB_vals, j=SAB_vals, b=B])
@variable(model, y[i=SAB_vals, a=A, b=B])

U = 7

@constraint(model,
[(a,b) in AB, i in SAB[a,b], j in SAB[a,b]],
sum( y[i,aa,b] for aa in A if aa == a) <= U * x[i,j,b]
)
``````
1 Like