Conditional sum in constraint

Dear all, the piece of code below works well with Jump until Ver 0.20.6, newer version of JuMP give to to me the error

LoadError: KeyError: key (1, 1, 2, 1) not found

The BRANCH set is a sparse set indicating the network topology of a power system, while TInBUS is a subset of BUS where generation is present. I’m using Julia 1.6.0. Any hint kn how to modify to make it work?

Thanks
Fabrizio

for h=1:hmax
    for r in BUS
        if r in keys(TInBUS)
            @constraint(
            MyMod,
            sum(pt[j,h] for j in TInBUS[r]) - nodeload[r,h] ==
            sum(p_flow[(l,k,m,h)] for (l,k,m) in BRANCH if r == m) -
            sum(p_flow[(l,k,m,h)] for (l,k,m) in BRANCH if r == k)
            )
        else 
            @constraint(
            MyMod,
            - nodeload[r,h] ==
            sum(p_flow[(l,k,m,h)] for (l,k,m) in BRANCH if r == m) -
            sum(p_flow[(l,k,m,h)] for (l,k,m) in BRANCH if r == k)
            )
        end
    end
end

Hi Fabrizio,

to make it easier to help you, try to format the code you post. You can do so using Markdown, in particular by putting your code between triple backticks ```… ```. see e.g. here for a reference

This helps other people to quicker parse your problem.

Also, it’s usually helpful to paste the full stacktrace, not just the error.

1 Like

On your particular problem:
It seems like it’s probably p_flow that doesn’t have a key (1, 1, 2, 1).

You can get the keys of p_flow via

keys(p_flow)

to check.

1 Like

Hi, thanks for the answer. Below the full stacktrace. Indeed one of the two p_flow (“in” or “out” of the node “r”) does not have the key depending on how is oriented, but the trick “if r==m” and “if r==k” in the sum(.) worked just fine before updating JuMP to ver >0.20.6

Any other hint?

Regards,
Fabrizio

Stacktrace:
[1] getindex(::JuMP.Containers._AxisLookup{Dict{NTuple{4,Int64},Int64}}, ::Tuple{Int32,Int32,Int32,Int64}) at C:\Users\Fabrizio.julia\packages\JuMP\klrjG\src\Containers\DenseAxisArray.jl:18
[2] _getindex_recurse(::Tuple{JuMP.Containers._AxisLookup{Dict{NTuple{4,Int64},Int64}}}, ::Tuple{Tuple{Int32,Int32,Int32,Int64}}, ::getfield(JuMP.Containers, Symbol("##8#10"))) at C:\Users\Fabrizio.julia\packages\JuMP\klrjG\src\Containers\DenseAxisArray.jl:250
[3] to_index(::JuMP.Containers.DenseAxisArray{VariableRef,1,Tuple{Array{NTuple{4,Int64},2}},Tuple{JuMP.Containers._AxisLookup{Dict{NTuple{4,Int64},Int64}}}}, ::Tuple{Tuple{Int32,Int32,Int32,Int64}}) at C:\Users\Fabrizio.julia\packages\JuMP\klrjG\src\Containers\DenseAxisArray.jl:259
[4] getindex(::JuMP.Containers.DenseAxisArray{VariableRef,1,Tuple{Array{NTuple{4,Int64},2}},Tuple{JuMP.Containers._AxisLookup{Dict{NTuple{4,Int64},Int64}}}}, ::Tuple{Int32,Int32,Int32,Int64}) at C:\Users\Fabrizio.julia\packages\JuMP\klrjG\src\Containers\DenseAxisArray.jl:266
[5] MyNetworkcns(::Model, ::Array{Tuple{Int32,Int32,Int32},1}, ::Array{Int64,1}, ::Int64, ::Array{Float64,1}, ::Bool, ::String, ::Bool, ::Int64, ::Bool, ::Bool) at C:\Users\Fabrizio.julia\packages\MutableArithmetics\0Y9ZS\src\rewrite.jl:279
[6] SolveMyProblem(::String, ::Int64, ::Float64, ::Int64, ::Int64, ::Array{Float64,2}, ::Array{Tuple{Int32,Int32,Int32},1}, ::Array{Int64,1}, ::Array{Float64,1}, ::Bool, ::String, ::Int64, ::Bool) at C:\DATI\Codici_Sorgente\ProgrammiJulia\UCOTS_20211106_newJump\UCOTS.jl:584
[7] top-level scope at none:0
[8] include at .\boot.jl:326 [inlined]
[9] include_relative(::Module, ::String) at .\loading.jl:1038
[10] include(::Module, ::String) at .\sysimg.jl:29
[11] include(::String) at .\client.jl:403
[12] top-level scope at none:0

I solved the problem by simply changing the definition of BRANCH from

BRANCH = [(Int32(BrancheS[l].line), Int32(BrancheS[l].from), Int32(BrancheS[l].to)) for l=1:length(LINES)]

in to

BRANCH = [(BrancheS[l].line, BrancheS[l].from, BrancheS[l].to) for l=1:length(LINES)]

Hi @Fabrizio,

Can you provide a reproducible example that I can copy-and-paste?

Why did you have explicit Int32 casts? It seems like JuMP might be converting Int32 to Int64 somewhere.

Hi @odow,

a working example is quite difficult to extract for me and i don’t know why a former student did this explicit cast in the definition of the set BRANCH.

However maybe the problem was in the: “if r==m” or “if r==k” in the sum(.) below

sum(p_flow[(l,k,m,h)] for (l,k,m) in BRANCH if r == m)

If you take a look of the code posted previously the BUS is so defined:

BUS = collect(1:Int32(size(bus,1)))

and we iterate in the for loop “r in BUS”

the only thing i can stress is that there has been a change in the ver > 0.20.6 of JuMP

Current version

The current behavior seems correct. If your index sets are Int32, then you need to index with an Int32:

julia> using JuMP

julia> model = Model();

julia> S = Int32[1]
1-element Vector{Int32}:
 1

julia> @variable(model, x[S])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
    Dimension 1, Int32[1]
And data, a 1-element Vector{VariableRef}:
 x[1]

julia> x[1]
ERROR: KeyError: key 1 not found
Stacktrace:
 [1] getindex(#unused#::JuMP.Containers._AxisLookup{Dict{Int32, Int64}}, key::Int64)
   @ JuMP.Containers ~/.julia/dev/JuMP/src/Containers/DenseAxisArray.jl:18
 [2] _getindex_recurse(data::Tuple{JuMP.Containers._AxisLookup{Dict{Int32, Int64}}}, keys::Tuple{Int64}, condition::JuMP.Containers.var"#10#12")
   @ JuMP.Containers ~/.julia/dev/JuMP/src/Containers/DenseAxisArray.jl:299
 [3] to_index(A::JuMP.Containers.DenseAxisArray{VariableRef, 1, Tuple{Vector{Int32}}, Tuple{JuMP.Containers._AxisLookup{Dict{Int32, Int64}}}}, idx::Tuple{Int64})
   @ JuMP.Containers ~/.julia/dev/JuMP/src/Containers/DenseAxisArray.jl:308
 [4] getindex(A::JuMP.Containers.DenseAxisArray{VariableRef, 1, Tuple{Vector{Int32}}, Tuple{JuMP.Containers._AxisLookup{Dict{Int32, Int64}}}}, idx::Int64)
   @ JuMP.Containers ~/.julia/dev/JuMP/src/Containers/DenseAxisArray.jl:315
 [5] top-level scope
   @ REPL[18]:1

julia> x[Int32(1)]
x[1]

v0.21.6

It looks like JuMP 0.21.6 didn’t respect types like this, and automatically converted if needed:

julia> using JuMP

julia> model = Model();

julia> S = Int32[1]
1-element Vector{Int32}:
 1

julia> @variable(model, x[S])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
    Dimension 1, Int32[1]
And data, a 1-element Vector{VariableRef}:
 x[1]

julia> x[1]
x[1]

It’s a shame we broke existing code. But I’d regard this as a bug fix. I don’t know if we want to re-introduce the old behavior. The easiest fix for your code is probably just to delete all of the explicit Int32 casts.

thanks @odow for the explanation, and yes i don’t know if you want to treat as a bug fix, but it may be useful.

Regards,
Fabrizio