SparseArrays.jl icon indicating copy to clipboard operation
SparseArrays.jl copied to clipboard

allocation with v.*="x"on SparseArrays

Open dpinol opened this issue 2 years ago • 4 comments

The following code allocates 128 bytes in julia 1.9 & 1.10 (also in previous julia versions). However, when using dense vectors, it doesn't allocate.

using SparseArrays

const v=spzeros(10)
v[1]=4
f(v) = v.*=4
@allocated f(v)

Currently the workaround is using map!(f, v,v)

dpinol avatar Jul 07 '23 16:07 dpinol

Do note that another solution is nonzeros(v) .*= 4.

The culprit is that broadcast is only for unaliased vector (unalised refers to the left and right-hand side sharing memory, here both matrices are the same, so they naturally share vector) because it may or may not change the structure. map! on the other hand only works on the nonzero elements so it is safe to apply to aliased vector

using SparseArrays
function f(x, y)
    for i in 1:10000
        y .= x .* 1.1
        x .= y .* (1 / 1.1)
    end
    x
end
x = spzeros(10)
x[1] = 3
y = copy(x)
@time f(x, y)
@time f(x, y)

gives

  0.094615 seconds (271.80 k allocations: 18.823 MiB, 99.75% compilation time)
  0.000205 seconds

@ViralBShah we could optimize this for fixed sparse matrices, what do you think?

SobhanMP avatar Jul 18 '23 19:07 SobhanMP

I suppose that makes sense. @Wimmerer ?

ViralBShah avatar Jul 19 '23 02:07 ViralBShah

I'm not convinced we can't optimize this within the semantics of sparse broadcast.

rayegun avatar Jul 19 '23 15:07 rayegun

So we only trigger a copy if the structure changes or just do it inplace?

SobhanMP avatar Jul 19 '23 18:07 SobhanMP