# Allocations with closure and mul!

Hi! I have an issue with allocations using the `mul!` function and a closure:

``````using LinearAlgebra, Test

struct operator{T}
prod!
end

function operator(A :: AbstractArray{T}) where T
prod! = (res, u, α, β) -> mul!(res, A, u, α, β)
return operator{T}(prod!)
end

import LinearAlgebra.mul!

function mul!(res::Vector{T}, op::operator{T}, u::Vector{T}, α::T, β::T) where T
op.prod!(res, u, α, β)
end

function mul!(res::Vector{T}, op::operator{T}, u::Vector{T}) where T
op.prod!(res, u, one(T), zero(T))
end

function mul2!(res::Vector{T}, op::operator{T}, u::Vector{T}) where T
op.prod!(res, u, 2*one(T), 2*one(T))
end

function test_allocs()
n = 10
A = rand(n, n)
A_op1 = operator(A)
res1, u1, α1, β1 = rand(n), rand(n), 2.0, 2.0

### compile
A_op1.prod!(res1, u1, β1, α1)
mul!(res1, A_op1, u1, β1, α1)
mul!(res1, A, u1, α1, β1)
mul2!(res1, A_op1, u1)

### tests allocs
allocs1 = @allocated A_op1.prod!(res1, u1, α1, β1)
@test allocs1 == 16
allocs2 = @allocated mul!(res1, A_op1, u1, α1, β1)
@test allocs2 == 32
allocs3 = @allocated mul!(res1, A, u1, α1, β1)  # LinearAlgebra mul! function for matrices
@test allocs3 == 0
allocs4 = @allocated mul!(res1, A_op1, u1)
@test allocs4 == 0
allocs5 = @allocated mul2!(res1, A_op1, u1)
@test allocs5 == 0
end

test_allocs()
``````

All tests passed but I do not know how to remove the allocations for the first and second tests with my type `operator{T}`. Maybe it comes from `α` and `β` because when I removed them with the 3-args `mul!` and `mul2!` the allocations disappear, but I could not find a way to solve this problem. Does anybody know how I could fix this?

The field `prod!` of your `operator` type misses a type annotation and hence seems to be of `Any`. I assume you wanted to make this `prod!::T`.

1 Like

I do not think that this possible because I want `prod!` to be a closure (its type could be `Function` but it does not change the number of allocations). The `T` in `struct operator{T}` is only used to indicate that the closure should work with data of type `T`.

If you want to reserve `T` for data you can just add another type parameter to `operator` to make `prod!` type-stable:

``````struct operator{T,F}
prod!::F
end
operator{T}(prod!::F) where {T,F} = operator{T,F}(prod!)
``````

Thank you!