Copy. vs. deepcopy vs. .=

Despite many threads on this, I’m still confused. I want to avoid allocation but something is not working in my code. My setup is like the one below. Can someone explain the difference in this context,

 A = (rand(3),rand(3),rand(3))
 B = (rand(3),rand(3),rand(3))

option 1 works but I want to avoid it because it allocates:

B = deepcopy(A)

option 2 does not allocate but does not work:

copy!.(B,A)

neither does option 3:

map((b,a)-> b .= a, B, A)

you have a collection of collections, I believe option 3 works:

julia> @ballocated map((b,a)-> b .= a, B, A) setup = begin A = (rand(3),rand(3),rand(3)); B = (rand(3),rand(3),rand(3))end
0

but instead of map, you’re probably looking for foreach

julia> foreach(A,B) do a,b
           b .= a
       end

option 3 doesn’t, if I make a change to A later, then it also changes B. I don’t know why options 2 or 3 don’t work though. I missing something fundamental. I understand that it is a collection of collections, but I thought the map or broadcast would unwrap the outer collection and let me do an in-place copy on the arrays. It doesn’t seem so, and I am confused.

it does not:

julia> A = (rand(3),rand(3),rand(3))
([0.44064579753939914, 0.5513894805471519, 0.14531256392609548], [0.7632771815487763, 0.01759682471452173, 0.5437928857351825], [0.4404378190057092, 0.005535005026375717, 0.09501474232898721])

julia> B = (rand(3),rand(3),rand(3));

julia> B[1][1]
0.67551842978281

julia> map((b,a)-> b .= a, B, A);

julia> B[1][1]
0.44064579753939914

julia> A[1][1] = 0.0
0.0

julia> B[1][1]
0.44064579753939914

I think this does “work”, as you expect:

julia> A = (zeros(3),zeros(3),zeros(3))
([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0])

julia> B = (ones(3),ones(3),ones(3))
([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])

julia> copy!.(A,B)
([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])

julia> A
([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])

julia> B
([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])

julia> A[1][1] = 5.0
5.0

julia> A
([5.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])

julia> B
([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])

julia> @btime copy!.($A,$B)
  13.516 ns (0 allocations: 0 bytes)
([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0])
4 Likes

I believe there is a reassignment in another part of the code that is causing the problem. Thanks.

Yes, I’ve confirmed this was the problem. Thanks for the feedback.

1 Like