I’m not sure if I understand LinearIndices
and CartesianIndices
correctly, but I think they provide a mapping between those index types, and are inverses of each other?
This seems to be the case for normal 1-based indices, but fails for non-1-based indices:
Julia-1.1.1> CI = CartesianIndices((0:5, 0:3))
6×4 CartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
CartesianIndex(0, 0) CartesianIndex(0, 1) CartesianIndex(0, 2) CartesianIndex(0, 3)
CartesianIndex(1, 0) CartesianIndex(1, 1) CartesianIndex(1, 2) CartesianIndex(1, 3)
CartesianIndex(2, 0) CartesianIndex(2, 1) CartesianIndex(2, 2) CartesianIndex(2, 3)
CartesianIndex(3, 0) CartesianIndex(3, 1) CartesianIndex(3, 2) CartesianIndex(3, 3)
CartesianIndex(4, 0) CartesianIndex(4, 1) CartesianIndex(4, 2) CartesianIndex(4, 3)
CartesianIndex(5, 0) CartesianIndex(5, 1) CartesianIndex(5, 2) CartesianIndex(5, 3)
Julia-1.1.1> LI = LinearIndices(CI)
6×4 LinearIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
1 7 13 19
2 8 14 20
3 9 15 21
4 10 16 22
5 11 17 23
6 12 18 24
Julia-1.1.1> CI[1]
CartesianIndex(0, 0)
Julia-1.1.1> LI[0, 0]
ERROR: BoundsError: attempt to access 6×4 LinearIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}} at index [0, 0]
Stacktrace:
[1] throw_boundserror(::LinearIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}, ::Tuple{Int64,Int64}) at .\abstractarray.jl:484
[2] checkbounds at .\abstractarray.jl:449 [inlined]
[3] _getindex at .\abstractarray.jl:949 [inlined]
[4] getindex(::LinearIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}, ::Int64, ::Int64) at .\abstractarray.jl:927
[5] top-level scope at none:0
Is this the intended behavior?
In an effort to understand this better, I went down a rabbit hole into the labyrinth of array indexing and nearly didn’t come out.
However, specializing these functions for LinearIndices
seems to give the behavior I expected:
function Base.checkbounds(::Type{Bool}, A::LinearIndices, I...)
Base.@_inline_meta
Base.checkbounds_indices(Bool, A.indices, I)
end
function Base._sub2ind(A::LinearIndices, I...)
Base.@_inline_meta
Base._sub2ind(A.indices, I...)
end
Julia-1.1.1> CI[1]
CartesianIndex(0, 0)
Julia-1.1.1> LI[0, 0]
1
Julia-1.1.1> CI[20]
CartesianIndex(1, 3)
Julia-1.1.1> LI[1, 3]
20
Can anyone comment on this?