Apologizes for the relatively long minimal example.
I want to write an efficient broadcasting which is able to sum results from different objects. As an example, suppose I want to compute the sum of periodic functions, as in this example:
abstract type Periodic{S <: Real} end
struct Sine{S} <: Periodic{S}
a::S
ω::S
φ::S
end
Base.broadcastable(f::Sine) = Base.RefValue(f)
compute(h::Sine, x::Real) = h.a * sin(h.ω*x + h.φ)
struct Tophat{S} <: Periodic{S}
a::S
ω::S
φ::S
end
Base.broadcastable(h::Tophat) = Base.RefValue(h)
compute(h::Tophat, x::Real) = h.a * round(cos.(h.ω*x/2 + h.φ)^2)
struct Periodicsum{S}
f::Vector{Periodic{S}}
name::String
end
Base.broadcastable(hs::Periodicsum) = Base.RefValue(hs)
function compute(hs::Periodicsum, x::S) where {S}
ℓ = length(hs.f)
result = zero(S)
for n ∈ 1:ℓ
result += compute(hs.f[n], x)
end
result
end
function Base.broadcasted(::typeof(compute), hs::Periodicsum, xs::Array{S}) where {S}
ℓ = length(hs.f)
result = Broadcast.Broadcasted(compute, (Base.RefValue(hs.f[1]), xs))
for n ∈ 2:ℓ
@inbounds result = Broadcast.Broadcasted(+, (result, Broadcast.Broadcasted(compute, (Base.RefValue(hs.f[n]), xs))))
end
result
end
h1 = Sine(2.0, 1.3, 2.7)
h2 = Tophat(1.2, 2.4, 0.6)
hs = Periodicsum([h1, h2], "test")
So, essentially, I have two kind of periodic functions, Sine and Tophat, and a container represented by the Periodicsum object. Calling compute will return the value of the periodic function or of the sum of periodic functions at a given point.
My problem is that a broadcast call to compute on a Periodicsum returns Any as an inferred static type, leading to potentially un-specialized code:
julia> @code_warntype compute.(hs, rand(100))
Variables
#self#::Core.Const(var"##dotfunction#258#2"())
x1::Periodicsum{Float64}
x2::Vector{Float64}
Body::Any
1 ─ %1 = Base.broadcasted(Main.compute, x1, x2)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, F, Args} where {F, Args<:Tuple}
│ %2 = Base.materialize(%1)::Any
└── return %2
As far as I understand, this is due to the fact that the length of the array hs.f is no known at compile time: hence the Broadcast.Broadcasted object cannot be built with stable type.
Is there any possible cure for this issue? Note that it is probably not wise to use tuples for hs.f, since in principle I might have to use hundreds of periodic functions in a Periodicsum.