Indexing assignment to arrays

The documentation for indexing assignment in the Julia manual says that:

If any index I_k selects more than one location, then the right hand side X must be an array with the same shape as the result of indexing A[I_1, I_2, ..., I_n] or a vector with the same number of elements. The value in location I_1[i_1], I_2[i_2], ..., I_n[i_n] of A is overwritten with the value X[I_1, I_2, ..., I_n] , converting if necessary.

However, I am not sure if this is a bug, but the behavior in 1.5.3 seems to be slightly different. Consider the following definitions:

julia> A = zeros(10, 10); #10 x 10 Array{T, 2}
                                                                   
julia> b = ones(100); #100 element Array{T, 1}
                                                                   
julia> s = zeros(1, 100); #1 x 100 Array{T, 2}
                                                                   
julia> t = zeros(100, 1); # 100 x 1 Array{T, 2}

Now as documented,

julia> A[:, :] = b # works as documented

fills A with ones. The behavior with s and t, however, is a bit puzzling. Neither of them are vectors. However,

julia> A[:, :] = s

fills A with zeros, even though this behavior does not seem to be documented in the quote from the “Indexing assignment” section reproduced above, as s neither has the same dimensions as A, nor is it a “vector”. Indeed,

julia> A[:, :] = t

raises precisely this error:

ERROR: DimensionMismatch("tried to assign 100Ă—1 array to 10Ă—10 destination")

So my question is the following: is it due to a documented feature that the assignment with s above works, but the one with t fails?

Julia version: 1.5.3

Broadcasting “recycles” values along singleton indices. Perhaps this example will help:

julia> A = collect(reshape(1:9, 3, 3))
3Ă—3 Matrix{Int64}:
 1  4  7
 2  5  8
 3  6  9

julia> s = collect(reshape(1:3, 1, 3))
1Ă—3 Matrix{Int64}:
 1  2  3

julia> A .= s
3Ă—3 Matrix{Int64}:
 1  2  3
 1  2  3
 1  2  3

The broadcasting rules do not apply to the examples in the question, since all the arrays (A, s, t, b) have the same number of elements. Thus, there is no opportunity or reason for “recycling” entries.

The same behavior as described in the question also happens with arrays constructed from reshape objects though:

julia> A = collect(reshape(1:9, 3, 3))
3Ă—3 Array{Int64,2}:
 1  4  7
 2  5  8
 3  6  9

julia> s = collect(reshape(10:18, 1, 9))
1Ă—9 Array{Int64,2}:
 10  11  12  13  14  15  16  17  18

julia> A[:, :] = s
1Ă—9 Array{Int64,2}:
 10  11  12  13  14  15  16  17  18

julia> A
3Ă—3 Array{Int64,2}:
 10  13  16
 11  14  17
 12  15  18

julia> t = collect(reshape(20:28, 9, 1))
9Ă—1 Array{Int64,2}:
 20
 21
 22
 23
 24
 25
 26
 27
 28

julia> A[:, :] = t
ERROR: DimensionMismatch("tried to assign 9Ă—1 array to 3Ă—3 destination")

So again, assigning a 1 x 9 array (s in the example) into A[:, :], when A is a 3 x 3 Array{T, 2} works, but assigning a 9 x 1 array (t in the example) doesn’t. My interpretation of the quote from the documentation is that neither should work (since neither is a vector, and neither is 3 x 3), but I just want to check if there is something else in the language that allows one but not the other.

3 Likes

Indeed you are right — I was imagining dots where there weren’t any.

I think that according to the comment here, A[:, :] = t above could be allowed.

Please consider opening an issue about this.

2 Likes

Thanks. We now have an issue. :slight_smile:

2 Likes