I’m struggling to understand the in-place modification operator .= in Julia 1.0+ in the following examples,
julia> b = rand(1000, 1000)
julia> @time begin
Ham = zeros(1000, 1000)
for i in 1:100
global Ham .= Ham .+ b
end
println(Ham[1, 1])
end
96.71386850591365
0.092689 seconds (215 allocations: 7.634 MiB, 1.67% gc time)
julia> @time begin
Ham = zeros(1000, 1000)
for i in 1:100
global Ham .= Ham + b
end
println(Ham[1, 1])
end
96.71386850591365
0.199746 seconds (416 allocations: 770.580 MiB, 2.23% gc time)
julia> @time begin
Ham = zeros(1000, 1000)
for i in 1:100
global Ham = Ham + b
end
println(Ham[1, 1])
end
96.71386850591365
0.264974 seconds (215 allocations: 770.577 MiB, 31.54% gc time)
It seems that the second option Ham .= Ham + b still creates a tmp copy of Ham + b, and only pair .= it with .+ will we be able to avoid allocating the tmp copy. Why the implememtation/semantics did it in this way? What is wrong in implementing Ham .= Ham + b to have the same effect as Ham .= Ham .+ b?
Another problem I had is
julia> a = 1;
julia> a .= 1 .+ 1
ERROR: MethodError: no method matching copyto!(::Int64, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0},Tuple{},typeof(+),Tuple{Int64,Int64}})
Closest candidates are:
copyto!(::AbstractArray, ::Base.Broadcast.Broadcasted{#s617,Axes,F,Args} where Args<:Tuple where F where Axes where #s617<:Base.Broadcast.AbstractArrayStyle{0}) at broadcast.jl:848
copyto!(::AbstractArray, ::Base.Broadcast.Broadcasted) at broadcast.jl:842
copyto!(::AbstractArray, ::Any) at abstractarray.jl:720
Stacktrace:
[1] materialize!(::Int64, ::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0},Nothing,typeof(+),Tuple{Int64,Int64}}) at ./broadcast.jl:801
[2] top-level scope at REPL[22]:1
It seems to me .= in-place modification, by definition, need a to be mutable, for example an array instead of a primitive type Int here. However, what surprise me is the error information. What is the relationship between .= and copyto!?