Assignment of values to a subset of a subset of indices of an array

Why does the following give different results?

a = zeros(Float32, 10)
b = rand(Float32,10)
ind1 = [3,4,6,9]
ind2 = [2,3,4]
julia> a[ind1[ind2]] .= mean(b[ind1[ind2]])
3-element view(::Vector{Float32}, [4, 6, 9]) with eltype Float32:
 -0.45284092
 -0.45284092
 -0.45284092

julia> a'
1×10 adjoint(::Vector{Float32}) with eltype Float32:
 0.0  0.0  0.0  -0.452841  0.0  -0.452841  0.0  0.0  -0.452841  0.0

versus:

julia> a[ind1][ind2] .= mean(b[ind1][ind2])
3-element view(::Vector{Float32}, [2, 3, 4]) with eltype Float32:
 -0.45284092
 -0.45284092
 -0.45284092

julia> a'
1×10 adjoint(::Vector{Float32}) with eltype Float32:
 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0

In other words, why can we index like b[ind1][ind2] to get a correct series of values (using Int64 indices, not BitVectors) but a value cannot be written to a[ind1][ind2]? Should it not result in a warning if such assignment is done incorrectly?

The problem is that:

  • a[ind1[ind2]] first allocates a temporary array _temp1 = ind1[ind2], and then an array a[_temp1], so you’re mutating a, whereas
  • a[ind1][ind2] first creates a temporary array _temp2 = a[ind1] and then another array _temp2[ind2], so you’re not mutating a, you’re mutating _temp2.
Meta.@lower MWE
julia> begin
           a = 1:10
           b = 1:10
           ind1 = [3,4,6,9]
           ind2 = [2,3,4]
       end;

julia> Meta.@lower a[ind1[ind2]]
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ %1 = a
│   %2 = Base.getindex(ind1, ind2)
│   %3 = Base.getindex(%1, %2)
└──      return %3
))))

julia> Meta.@lower b[ind1][ind2]
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ %1 = Base.getindex(b, ind1)
│   %2 = Base.getindex(%1, ind2)
└──      return %2
))))

Side note: When trying to debug these things it’s useful to simplify your working example. e.g. not using rand and mean, just presenting the indexing problem.

4 Likes

Thanks for the clear explanation and the Meta.@lower example. I can see now that _temp2 has no notion of the location in a anymore, just the values. It all makes sense.

1 Like

You may want to mark @savq’s answer as the solution.