Slicing and boolean indexing in multidimensional arrays

I’m curious why the following 3D array slicing works for the i index but not for the j index:

T = Array(reshape(1:2*3*4, 2,3,4))
i = zeros(Bool, 2,3)
i[1,2:3] .= 1
display(T[i,:])
j = zeros(Bool, 3,4)
j[1,2:3] .= 1
display(T[:,j])

when the seemingly-analogous operation on a 2D array works either way:

M = Array(reshape(1:4*5, 4,5))
k = zeros(Bool, 4)
k[2:3] .= 1
display(M[k,:])
l = zeros(Bool, 5)
l[2:3] .= 1
display(M[:,l])

I’m interested in both why it doesn’t work, and any suggestions for a reasonably-elegant work-around.

2 Likes

I have no idea why it does not work but a “reasonably elegant workaround” might be:

jj = findall(j)
T[:,jj]
2 Likes

This should be a bug in Base.to_indices, more specific

@inline to_indices(A, inds, I::Tuple{Union{Array{Bool,N}, BitArray{N}}}) where {N} =
    (_maybe_linear_logical_index(IndexStyle(A), A, I[1]),)

It should be something like

@inline to_indices(A, inds, I::Tuple{Union{Array{Bool,N}, BitArray{N}}}) where {N} =
    ndims(A) == N ? (_maybe_linear_logical_index(IndexStyle(A), A, I[1]),) : (to_index(A, I[1]),)

Thanks, this does meet my needs for a workaround at the moment.

This seems very relevant, but I don’t fully understand it. Could you elaborate a bit on how your proposed update works? Are you planning to submit a bug-report about this?

1 Like

On master, if IndexStyle(A) === IndexLinear(), Base.to_indices always transforms the last logical index into Base.LogicalIndex{Int}. Thus T[:,j] behaves as T[:,findall(vec(j))], which is always not correct.
The above change avoids the wrong optimization by adding a dimension check. I’ve open a PR to fix this.