OffsetArrays.jl icon indicating copy to clipboard operation
OffsetArrays.jl copied to clipboard

Concatenation of 3D OffsetArrays fails if their axes do not start at 1

Open algrosso opened this issue 7 years ago • 7 comments

I try to hcat an OffsetArray with indices (0:-1, 0:-1,0:1) and size=(0,0,2) with another OffsetArray with indices (0:-1,0:15,0:1) and size(0,16,2) and I get the error ERROR: BoundsError: attempt to access 0×16×2 Array{Int8,3} at index [1:0, 0:15, 1:2]

julia> form=OffsetArray(reshape(zeros(Int8,0),0,0,2),0:-1,0:-1,0:1)
julia> exp=OffsetArray(reshape(zeros(Int8,0),0,16,2),0:-1,0:15,0:1)
julia> hcat(form,exp) Error!!

julia> hcat(form,exp)
ERROR: BoundsError: attempt to access 0×16×2 Array{Int8,3} at index [1:0, 0:15, 1:2]
Stacktrace:
 [1] throw_boundserror(::Array{Int8,3}, ::Tuple{UnitRange{Int64},UnitRange{Int64},UnitRange{Int64}}) at ./abstractarray.jl:484
 [2] checkbounds at ./abstractarray.jl:449 [inlined]
 [3] _setindex! at ./multidimensional.jl:638 [inlined]
 [4] setindex! at ./abstractarray.jl:998 [inlined]
 [5] __cat(::Array{Int8,3}, ::Tuple{Int64,Int64,Int64}, ::Tuple{Bool,Bool}, ::OffsetArray{Int8,3,Array{Int8,3}}, ::Vararg{OffsetArray{Int8,3,Array{Int8,3}},N} where N) at ./abstractarray.jl:1379
 [6] _cat_t(::Val{2}, ::Type, ::OffsetArray{Int8,3,Array{Int8,3}}, ::Vararg{OffsetArray{Int8,3,Array{Int8,3}},N} where N) at ./abstractarray.jl:1361
 [7] #cat_t#99(::Val{2}, ::Function, ::Type{Int8}, ::OffsetArray{Int8,3,Array{Int8,3}}, ::Vararg{OffsetArray{Int8,3,Array{Int8,3}},N} where N) at ./abstractarray.jl:1353
 [8] (::getfield(Base, Symbol("#kw##cat_t")))(::NamedTuple{(:dims,),Tuple{Val{2}}}, ::typeof(Base.cat_t), ::Type{Int8}, ::OffsetArray{Int8,3,Array{Int8,3}}, ::Vararg{OffsetArray{Int8,3,Array{Int8,3}},N} where N) at ./none:0
 [9] _cat at ./abstractarray.jl:1481 [inlined]
 [10] #cat#100 at ./abstractarray.jl:1480 [inlined]
 [11] #cat at ./none:0 [inlined]
 [12] hcat(::OffsetArray{Int8,3,Array{Int8,3}}, ::OffsetArray{Int8,3,Array{Int8,3}}) at ./abstractarray.jl:1489
 [13] top-level scope at none:0

However if I try with arrays with regular indices

julia> form=reshape(zeros(Int8,0),0,0,2)
julia> exp=reshape(zeros(Int8,0),0,16,2)
juilia> hcat(form,exp) works!!!

Thanks

algrosso avatar Dec 18 '18 11:12 algrosso

Also

julia> hcat(zeros(2, 1:1, 2), zeros(2, 2:3, 2))
ERROR: BoundsError: attempt to access 2×3×2 Array{Float64,3} at index [1:2, 3:4, 1:2]

julia> vcat(zeros(1:1, 2, 2), zeros(2:3, 2, 2))
ERROR: BoundsError: attempt to access 3×2×2 Array{Float64,3} at index [3:4, 1:2, 1:2]

but this works

julia> hcat(zeros(2, 1:1, 2), zeros(2, 1:2, 2))
2×3×2 Array{Float64,3}:
[:, :, 1] =
 0.0  0.0  0.0
 0.0  0.0  0.0

[:, :, 2] =
 0.0  0.0  0.0
 0.0  0.0  0.0

Evidently the concatenations try to index into an Array with offset indices, which fails if the axes do not start at 1.

jishnub avatar Sep 09 '20 19:09 jishnub

Perhaps this should be fixed in Base?

jishnub avatar Sep 09 '20 19:09 jishnub

cat is a rough one. You can see that even CatIndices, dedicated to solving this problem, has never gotten around to figuring out a general solution. Doesn't mean it's not possible of course.

The key problem, I think, is that cat lives in an "arrays are just lists, or lists-of-lists" world, and offset axes live in a world of "arrays are function-approximations over positions." Those two are not always compatible. In the offset-axes world, cat only makes sense if the arrays are already "neighbors," but that implies a completely different axis condition than the one that Base's cat uses.

timholy avatar Sep 09 '20 20:09 timholy

I agree, this is something that I was thinking of as well. However Base.cat appears to ignore indices altogether for arrays <3D, so it might be worthwhile seeking consistency?

julia> hcat(zeros(2, 1:2), ones(2, 10:11))
2×4 Array{Float64,2}:
 0.0  0.0  1.0  1.0
 0.0  0.0  1.0  1.0

julia> hcat(zeros(2, 1:2), ones(2, -5:-4))
2×4 Array{Float64,2}:
 0.0  0.0  1.0  1.0
 0.0  0.0  1.0  1.0

Even the OP works if the third dimension is stripped

julia> form = OffsetArray(reshape(zeros(Int8,0), 0, 0), 0:-1, 0:-1)
0×0 OffsetArray(::Array{Int8,2}, 0:-1, 0:-1) with eltype Int8 with indices 0:-1×0:-1

julia> exp = OffsetArray(reshape(zeros(Int8,0), 0, 16), 0:-1, 0:15)
0×16 OffsetArray(::Array{Int8,2}, 0:-1, 0:15) with eltype Int8 with indices 0:-1×0:15

julia> hcat(form, exp)
0×16 Array{Int8,2}

jishnub avatar Sep 10 '20 05:09 jishnub

Fair enough, if cat just ignores all index values and treats arrays as lists, that is indeed consistent. :+1:

timholy avatar Sep 10 '20 09:09 timholy

Repost from https://github.com/JuliaLang/julia/issues/37628

1d case vcat(zeros(2:3), zeros(4:5)) doesn't work, either.

julia> vcat(zeros(2:3), zeros(4:5))
ERROR: ArgumentError: offset arrays are not supported but got an array with index other than 1
Stacktrace:
 [1] require_one_based_indexing
   @ ./abstractarray.jl:89 [inlined]
 [2] setindex!
   @ ./array.jl:855 [inlined]
 [3] _typed_vcat(#unused#::Type{Float64}, V::Tuple{OffsetVector{Float64, Vector{Float64}}, OffsetVector{Float64, Vector{Float64}}})
   @ Base ./abstractarray.jl:1450
 [4] typed_vcat
   @ ./abstractarray.jl:1518 [inlined]
 [5] vcat(::OffsetVector{Float64, Vector{Float64}}, ::OffsetVector{Float64, Vector{Float64}})
   @ Base ./abstractarray.jl:1433
 [6] top-level scope
   @ REPL[36]:1

johnnychen94 avatar Sep 17 '20 13:09 johnnychen94

One possible fairly straightforward rule would be drop all special indices along the direction of concatenation, and keep them when orthogonal.

Thus hcat(zeros(-1:1), ones(-1:1)) would have axes (-1:1, OneTo(2)) (and would demand that axes(z,1) == axes(o,1), I guess, not just size), but vcat of the same would have (OneTo(6),).

Would this rule have weird consequences?

mcabbott avatar Sep 18 '20 19:09 mcabbott