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
.