My general application of interest requires a vector of functions of the form f(x, y, p)
, for some known parameters p
. I put the functions in a Tuple
so that their types are known, and define for example the following struct:
struct Point{T,N}
x::T
y::T
F::Tuple{Vararg{Function,N}}
F_params::Tuple{Vararg{Union{Nothing, AbstractVector{T}}, N}}
end
The F_params
is given the type shown so that a user can provide a Tuple
with an element for each function, and either provide a vector of parameters or no parameters at all (nothing
). I need to have functions that take in a Point
as input, for example:
function TestFnc(pt::Point{T,N}) where {T,N}
res = 0.0
for (f, p) in zip(pt.F, pt.F_params)
res = res + f(pt.x, pt.y, p)
end
return res
end
F1 = (x, y, p) -> x^2 + y^2 - p[1]
F2 = (x, y, p) -> x*y
F3 = (x, y, p) -> x + y + p[2] - p[3]*p[1]
pβ = [1.0]; pβ = nothing; pβ = [1.0, 2.0, 3.0]
x = 0.2; y = 0.7
pt = Point(x, y, (F1, F2, F3), (pβ, pβ, pβ))
When I use these definitions, I get type instabilities according to @code_warntype
(see below). How can I improve my struct so that all types are properly inferred?
@code_warntype TestFnc(pt)
MethodInstance for TestFnc(::Point{Float64, 3})
from TestFnc(pt::Point{T, N}) where {T, N} in Main at c:\Users\licer\testjl.jl:7
Static Parameters
T = Float64
N = 3
Arguments
#self#::Core.Const(TestFnc)
pt::Point{Float64, 3}
Locals
@_3::Union{Nothing, Tuple{Tuple, Tuple}}
res::Any
@_5::Int64
p::Any
f::Any
Body::Any
1 β (res = 0.0)
β %2 = Base.getproperty(pt, :F)::Tuple{Function, Function, Function}
β %3 = Base.getproperty(pt, :F_params)::Tuple{Union{Nothing, AbstractVector{Float64}}, Union{Nothing, AbstractVector{Float64}}, Union{Nothing, AbstractVector{Float64}}}
β %4 = Main.zip(%2, %3)::Base.Iterators.Zip
β (@_3 = Base.iterate(%4))
β %6 = (@_3 === nothing)::Bool
β %7 = Base.not_int(%6)::Bool
βββ goto #4 if not %7
2 β %9 = @_3::Tuple{Tuple, Tuple}
β %10 = Core.getfield(%9, 1)::Tuple
β %11 = Base.indexed_iterate(%10, 1)::Core.PartialStruct(Tuple{Any, Int64}, Any[Any, Core.Const(2)])
β (f = Core.getfield(%11, 1))
β (@_5 = Core.getfield(%11, 2))
β %14 = Base.indexed_iterate(%10, 2, @_5::Core.Const(2))::Core.PartialStruct(Tuple{Any, Int64}, Any[Any, Core.Const(3)])
β (p = Core.getfield(%14, 1))
β %16 = Core.getfield(%9, 2)::Tuple
β %17 = res::Any
β %18 = Base.getproperty(pt, :x)::Float64
β %19 = Base.getproperty(pt, :y)::Float64
β %20 = (f)(%18, %19, p)::Any
β (res = %17 + %20)
β (@_3 = Base.iterate(%4, %16))
β %23 = (@_3 === nothing)::Bool
β %24 = Base.not_int(%23)::Bool
βββ goto #4 if not %24
3 β goto #2
4 β return res