Reputation: 113
I initialise two arrays of arrays using fill():
A = fill(Vector{Float32}(zeros(Float32, 4)), 3);
B = fill(Vector{Float32}(ones(Float32, 4)), 3);
When I then try to add two of the subarrays A[1]
, B[1]
and store it in-place in the first array A[1]
by
A[1] .+= B[1]
this results in all elements of A
to be changed:
3-element Vector{MVector{4, Float32}}:
[1.0, 1.0, 1.0, 1.0]
[1.0, 1.0, 1.0, 1.0]
[1.0, 1.0, 1.0, 1.0]
I found a workaround by initialising the arrays differently
A = Array{Vector{Float32},1}(undef, 3)
for x in 1:3
A[x] = zeros(Float32,4)
end
B = Array{Vector{Float32},1}(undef, 3)
for x in 1:3
B[x] = ones(Float32,4)
end
When I now do the same in-place addition, A
is (as expected)
3-element Vector{Vector{Float32}}:
[1.0, 1.0, 1.0, 1.0]
[0.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 0.0]
I suspect, that I do not fully understand what fill
does as it seems like that the broadcasting .+=
acts on the whole array of arrays and not the indexed subarray.
I am quite new to Julia, any help is appreciated. I work with the Julia version 1.9.2.
Upvotes: 1
Views: 38
Reputation: 2398
When you do A = fill(zeros(4), 3)
, you are taking the object zeros(4)
and making an Array
of that object with the dimensions specified.
It does not make 3
different zeros(4)
and make an Array
of them.
In your loop version that is exactly what you do, you make a new zeros(4)
each iteration and then slot it into the Array
. To see the difference, imagine you had written this:
A = Vector{Vector{Float32}}(undef, 3)
x = zeros(Float32, 4)
for i in 1:3
A[i] = x
end
Now you do your operation on the elements of A
:
A[1] .+= ones(Float32, 4)
All the elements of A
will change, because in fact there is really only one element, repeated 3 times:
julia> A
3-element Vector{Vector{Float32}}:
[1.0, 1.0, 1.0, 1.0]
[1.0, 1.0, 1.0, 1.0]
[1.0, 1.0, 1.0, 1.0]
Further, since A = [x, x, x]
you will also see your modification of A[1]
reflected in x
:
julia> x
4-element Vector{Float32}:
1.0
1.0
1.0
1.0
To do what you are trying to do in a concise way you could use list comprehensions:
A = [zeros(4) for _ in 1:3]
B = [ones(4) for _ in 1:3]
A[1] .+= B[1]
Usually it would be even better to use a Matrix
instead of a Vector{Vector}
. In this case you would have avoided this particular trap with the fill
method E.g.:
A = fill(0f0, 3, 4)
B = fill(1f0, 3, 4)
A[1, :] .+= B[1, :]
Would give you:
julia> A
3×4 Matrix{Float32}:
1.0 1.0 1.0 1.0
0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0
Upvotes: 2