Hello everyone,

I need to compute the same sum of scalar functions (constant, linear, Gaussian kernel…)

for a large number of different values. I would like to create a structure that will hold the sum of these functions to speed-up the computations

I have created an abstract type `ParamFcn`

for these scalar functions. Each function is then a subtype of `ParamFcn`

. For instance `rbf`

is the subtype for a Gaussian kernel parameterized by a mean `μ`

and std `σ`

.

I have created a subtype of `ParamFcn`

called `AddedParamFcn`

that holds a tuple of `ParamFcn`

to compute the sum of the scalar functions.

However, even for simple computations, this way of proceeding is actually slower than taking the sum of the different functions . See example. I would expect to get some speed-up with this approach since the the functions can be precomputed.

Should I use a Tuple to store the different ParamFcn functions, or can I create an `Array{ParamFcn,1}$ ( I don’t know how to implement this second option) since I know in advance the number of scalar functions.

What is a better way to implement this?

```
import Base: show, zero
# Type to hold 1D functions
abstract type ParamFcn end
# zero(::T) where {T <: ParamFcn} = T()
struct AddedParamFcn{T <: Tuple} <: ParamFcn
list::T
end
function show(io::IO, Σg::AddedParamFcn)
println(io, "AddedParamFcn:")
for g in Σg.list
println(io, " $g")
end
end
"""
g₁::ParamFcn + g₂::ParamFcn
Add the parameterized functions so that `(g₁ + g₂)(z) = g₁(z) + g₂(z)`.
"""
+(g::ParamFcn, Σg::AddedParamFcn) = AddedParamFcn((g, Σg.list...))
+(Σg::AddedParamFcn, g::ParamFcn) = AddedParamFcn((Σg.list..., g))
function +(Σg₁::AddedParamFcn, Σg₂::AddedParamFcn)
AddedParamFcn((Σg₁..., Σg₂...))
end
+(g::ParamFcn...) = AddedParamFcn(g)
(Σg::AddedParamFcn)(z) = mapreduce(g->g(z),+, Σg.list)
struct constant <:ParamFcn
end
const Cst = constant()
(C::constant)(z::T) where {T<:Real} = 1.0
struct linear <:ParamFcn
end
const Lin = linear()
(L::linear)(z::T) where {T<:Real} = z
# Gaussian Kernel
struct rbf <:ParamFcn
μ::Float64
σ::Float64
end
function show(io::IO, N::rbf)
println(io,"Gaussian kernel with mean $(N.μ) and std $(N.σ)")
end
(N::rbf)(z::T) where {T<:Real} = 1/(N.σ*√(2*π))*exp(-(0.5/N.σ^2)*(z-N.μ)^2)
struct ψ₀ <:ParamFcn
ξ₀::Float64
σ₀::Float64
end
function show(io::IO, F::ψ₀)
println(io,"ψ₀ function with mean $(F.ξ₀) and std $(F.σ₀)")
end
function (F::ψ₀)(z::T) where {T<:Real}
@assert F.σ₀ >= 0.0 "std must be >= 0"
Δ₀ = (1/(F.σ₀*√2))*(z-F.ξ₀)
return 0.5*((z-F.ξ₀)*(1-erf(Δ₀))-F.σ₀*√(2/π)*exp(-Δ₀^2))
end
```

Speed benchmark

```
function time_estim()
@btime begin
z= 0.0
for i=1:1000
z= randn()
1.0 + z + rbf(1.0,1.0)(z) + ψ₀(1.0,2.0)(z)
end
end
@btime U = Cst + Lin + rbf(1.0,1.0) + ψ₀(1.0, 2.0)
@btime begin
U = Cst + Lin + rbf(1.0,1.0) + ψ₀(1.0, 2.0);
z= 0
for i=1:1000
z= randn()
U(z)
end
end
end
time_estim()
```

32.604 μs (0 allocations: 0 bytes)

0.015 ns (0 allocations: 0 bytes)

33.814 μs (0 allocations: 0 bytes)