Boolean indexing does not work

Reading the documentation I see that boolean indexing is supposed to be the same as indexing with findall(...). However, it doesn’t look like this is correct:

A = randn(10, 20, 30)
mask = dropdims(sum(A, dims=3), dims=3) .> 0
A[findall(mask), :]  # gives the expected result
A[mask, :]  # raises BoundsError: attempt to access 10×20×30 Array{Float64,3} at index [Base.LogicalIndex(Bool[...]), Base.Slice(Base.OneTo(30))]

Do I overlook the correct way to do this?

This looks like a bug to me, in
checkindex(::Type{Bool}, inds::Tuple, I::Base.LogicalIndex) in Base at multidimensional.jl:542 (currently returns false, should instead check sizes). But the multi-dimensional boundschecking code is too byzantine for me to fix this right now.

The following difference between findall and logical indexing is probably intentional:

julia> A_=[1,2,3];b=[true,false,false,false]; A_[findall(b)];
julia> A_[b];
ERROR: BoundsError: ...

Edit: On the other hand, this might be intentional, cf https://github.com/JuliaLang/julia/pull/15431#issuecomment-215469927.

From the indexing docs - logical indexing segment

Similarly, indexing by a N -dimensional boolean array is effectively the same as indexing by the vector of CartesianIndex{N} s where its values are true . A logical index must be a vector of the same length as the dimension it indexes into (Single dimension only), or it must be the only index provided and match the size and dimensionality of the array it indexes into (Full size)…

We can adjust the array shape though, so this will work

reshape(A, 200,30)[mask[:], :]
> ~92x30 Array

Indeed, so it’s documented and not a bug. But anyway, very unintuitive, and would be better not to limit boolean indexing to single dimension.

Yes, this was intentionally disallowed to make space for this meaning — IIRC it had done something slightly different in the past. It can be added as a feature in 1.x.

2 Likes