In order to reduce the size of my variable, I wish to define a JuMP model with a CartesianIndex.
I have tried the following code, but I keep getting problems dealing with the CartesianIndex when using the variable:
using JuMP, Cbc, IterTools
Random.seed!(3)
N = 10
cost = rand(1:4, N, N)
# reducing size using an index
idx = findall(cost .< 2)
# size reduce from 100 to 22 variables
model = Model(with_optimizer(Cbc.Optimizer));
@variable(model, x[idx], Bin);
# constraint to have only sum(x) = 1 over each row
for i in 1:N
# creating a second CartesianIndex to select row i, then intersect with the 22 indices of x
cart_idx = CartesianIndex.(collect(product(i,1:N)))
cart_idx = intersect(cart_idx, idx)
@constraint(model, sum(x[cart_idx]) == 1)
# ERROR: KeyError: key CartesianIndex{2}[CartesianIndex(1, 5), CartesianIndex(1, 6)] not found
end
The last line of code in the loop throws the error:
ERROR: KeyError: key CartesianIndex{2}[CartesianIndex(1, 5), CartesianIndex(1, 6)] not found
Is it possible to use CartesianIndex with a JuMP variable, and how to fix the issue above?
The next version of JuMP will throw an error if you attempt to construct a DenseAxisArray using CartesianIndices. They are not intended for that purpose.
You should use an alternative approach:
Option 1
using JuMP, IterTools
Random.seed!(3)
N = 10
cost = rand(1:4, N, N)
model = Model()
@variable(model, x[i=1:N, j=1:N; cost[i, j] < 2], Bin)
@constraint(
model,
[ii=1:N],
sum(x[i, j] for (i, j) in eachindex(x) if ii == i) == 1,
)
Option 2
using JuMP, IterTools
Random.seed!(3)
N = 10
cost = rand(1:4, N, N)
S = [(i, j) for i in 1:N, j in 1:N if cost[i, j] < 2]
model = Model()
@variable(model, x[S], Bin)
@constraint(model, [ii=1:N], sum(x[i, j] for (i, j) in S if ii == i) == 1)
Prior post:
I think there are a few bugs relating to cartesian indices in JuMP:
julia> model = Model()
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: NO_OPTIMIZER
Solver name: No optimizer attached.
julia> S = CartesianIndex.([2, 4])
2-element Vector{CartesianIndex{1}}:
CartesianIndex(2,)
CartesianIndex(4,)
julia> @variable(model, x[S])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
Dimension 1, CartesianIndex{1}[CartesianIndex(2,), CartesianIndex(4,)]
And data, a 2-element Vector{VariableRef}:
x[CartesianIndex(2,)]
x[CartesianIndex(4,)]
julia> x[CartesianIndex(2,)]
x[CartesianIndex(4,)]
julia> x[CartesianIndex(1,)]
x[CartesianIndex(2,)]
julia> x[CartesianIndex(4,)]
ERROR: BoundsError: attempt to access 2-element Vector{VariableRef} at index [4]
Stacktrace:
[1] getindex
@ ./array.jl:801 [inlined]
[2] getindex
@ ./multidimensional.jl:637 [inlined]
[3] getindex(A::JuMP.Containers.DenseAxisArray{VariableRef, 1, Tuple{Vector{CartesianIndex{1}}}, Tuple{JuMP.Containers._AxisLookup{Dict{CartesianIndex{1}, Int64}}}}, idx::CartesianIndex{1})
@ JuMP.Containers ~/.julia/packages/JuMP/2IF9U/src/Containers/DenseAxisArray.jl:323
[4] top-level scope
@ REPL[42]:1
It seems that if we have cartesian indices as keys, we should look them up via the key, not via the typical cartesian index.
Edit: I opened an issue https://github.com/jump-dev/JuMP.jl/issues/2825