Exactly, that would probably solve the problem with GG. Also, this function is type stable:
f = (un, p) -> begin
X(t) = un(t; idxs = 1)
T = p.T
K = p.K
# the following block is given by the user
(X(T) > K) * X(T)
end
@code_warntype f(sol.u[1], params)
Variables
#self#::Core.Compiler.Const(var"#178#179"(), false)
un#3252::DiffEqBase.RODESolution{Float64,2,Array{Array{Float64,1},1},Nothing,Nothing,Array{Float64,1},DiffEqNoiseProcess.NoiseProcess{Float64,2,Float64,Array{Float64,1},Array{Float64,1},Array{Array{Float64,1},1},typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_DIST),typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_BRIDGE),true,DataStructures.Stack{Tuple{Float64,Array{Float64,1},Array{Float64,1}}},ResettableStacks.ResettableStack{Tuple{Float64,Array{Float64,1},Array{Float64,1}},true},DiffEqNoiseProcess.RSWM{:RSwM3,Float64},RandomNumbers.Xorshifts.Xoroshiro128Plus},DiffEqBase.SDEProblem{Array{Float64,1},Tuple{Float64,Float64},true,NamedTuple{(:tspan, :X₀, :μ, :σ, :μX, :σX),Tuple{Tuple{Float64,Float64},Float64,Float64,Float64,var"#120#125"{Float64},var"#121#126"{Float64}}},Nothing,DiffEqBase.SDEFunction{true,UniversalMonteCarlo.var"#2883#2884",UniversalMonteCarlo.var"#2885#2886",LinearAlgebra.UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},UniversalMonteCarlo.var"#2885#2886",Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},Nothing},StochasticDiffEq.SRIW1,StochasticDiffEq.LinearInterpolationData{Array{Array{Float64,1},1},Array{Float64,1}},DiffEqBase.DEStats}
p#3253::NamedTuple{(:T, :K, :r),Tuple{Float64,Float64,Float64}}
val::Float64
X::var"#X#180"{DiffEqBase.RODESolution{Float64,2,Array{Array{Float64,1},1},Nothing,Nothing,Array{Float64,1},DiffEqNoiseProcess.NoiseProcess{Float64,2,Float64,Array{Float64,1},Array{Float64,1},Array{Array{Float64,1},1},typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_DIST),typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_BRIDGE),true,DataStructures.Stack{Tuple{Float64,Array{Float64,1},Array{Float64,1}}},ResettableStacks.ResettableStack{Tuple{Float64,Array{Float64,1},Array{Float64,1}},true},DiffEqNoiseProcess.RSWM{:RSwM3,Float64},RandomNumbers.Xorshifts.Xoroshiro128Plus},DiffEqBase.SDEProblem{Array{Float64,1},Tuple{Float64,Float64},true,NamedTuple{(:tspan, :X₀, :μ, :σ, :μX, :σX),Tuple{Tuple{Float64,Float64},Float64,Float64,Float64,var"#120#125"{Float64},var"#121#126"{Float64}}},Nothing,DiffEqBase.SDEFunction{true,UniversalMonteCarlo.var"#2883#2884",UniversalMonteCarlo.var"#2885#2886",LinearAlgebra.UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},UniversalMonteCarlo.var"#2885#2886",Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},Nothing},StochasticDiffEq.SRIW1,StochasticDiffEq.LinearInterpolationData{Array{Array{Float64,1},1},Array{Float64,1}},DiffEqBase.DEStats}}
T::Float64
K::Float64
r::Float64
pv::Float64
Body::Float64
1 ─ $(Expr(:inbounds, true))
│ %2 = Main.:(var"#X#180")::Core.Compiler.Const(var"#X#180", false)
│ %3 = Core.typeof(un#3252)::Core.Compiler.Const(DiffEqBase.RODESolution{Float64,2,Array{Array{Float64,1},1},Nothing,Nothing,Array{Float64,1},DiffEqNoiseProcess.NoiseProcess{Float64,2,Float64,Array{Float64,1},Array{Float64,1},Array{Array{Float64,1},1},typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_DIST),typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_BRIDGE),true,DataStructures.Stack{Tuple{Float64,Array{Float64,1},Array{Float64,1}}},ResettableStacks.ResettableStack{Tuple{Float64,Array{Float64,1},Array{Float64,1}},true},DiffEqNoiseProcess.RSWM{:RSwM3,Float64},RandomNumbers.Xorshifts.Xoroshiro128Plus},DiffEqBase.SDEProblem{Array{Float64,1},Tuple{Float64,Float64},true,NamedTuple{(:tspan, :X₀, :μ, :σ, :μX, :σX),Tuple{Tuple{Float64,Float64},Float64,Float64,Float64,var"#120#125"{Float64},var"#121#126"{Float64}}},Nothing,DiffEqBase.SDEFunction{true,UniversalMonteCarlo.var"#2883#2884",UniversalMonteCarlo.var"#2885#2886",LinearAlgebra.UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},UniversalMonteCarlo.var"#2885#2886",Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},Nothing},StochasticDiffEq.SRIW1,StochasticDiffEq.LinearInterpolationData{Array{Array{Float64,1},1},Array{Float64,1}},DiffEqBase.DEStats}, false)
│ %4 = Core.apply_type(%2, %3)::Core.Compiler.Const(var"#X#180"{DiffEqBase.RODESolution{Float64,2,Array{Array{Float64,1},1},Nothing,Nothing,Array{Float64,1},DiffEqNoiseProcess.NoiseProcess{Float64,2,Float64,Array{Float64,1},Array{Float64,1},Array{Array{Float64,1},1},typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_DIST),typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_BRIDGE),true,DataStructures.Stack{Tuple{Float64,Array{Float64,1},Array{Float64,1}}},ResettableStacks.ResettableStack{Tuple{Float64,Array{Float64,1},Array{Float64,1}},true},DiffEqNoiseProcess.RSWM{:RSwM3,Float64},RandomNumbers.Xorshifts.Xoroshiro128Plus},DiffEqBase.SDEProblem{Array{Float64,1},Tuple{Float64,Float64},true,NamedTuple{(:tspan, :X₀, :μ, :σ, :μX, :σX),Tuple{Tuple{Float64,Float64},Float64,Float64,Float64,var"#120#125"{Float64},var"#121#126"{Float64}}},Nothing,DiffEqBase.SDEFunction{true,UniversalMonteCarlo.var"#2883#2884",UniversalMonteCarlo.var"#2885#2886",LinearAlgebra.UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},UniversalMonteCarlo.var"#2885#2886",Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},Nothing},StochasticDiffEq.SRIW1,StochasticDiffEq.LinearInterpolationData{Array{Array{Float64,1},1},Array{Float64,1}},DiffEqBase.DEStats}}, false)
│ (X = %new(%4, un#3252))
│ (T = Base.getproperty(p#3253, :T))
│ (K = Base.getproperty(p#3253, :K))
│ (r = Base.getproperty(p#3253, :r))
│ %9 = -r::Float64
│ %10 = (%9 * T)::Float64
│ %11 = Main.exp(%10)::Float64
│ %12 = (X)(T)::Float64
│ %13 = (%12 > K)::Bool
│ %14 = (X)(T)::Float64
│ %15 = (%11 * %13 * %14)::Float64
│ (pv = %15)
│ (val = %15)
│ $(Expr(:inbounds, :pop))
│ val
└── return pv
However, I am using the following scheme:
function getclosure(un::unType, idx::Int64) where unType
return t -> un(t; idxs = idx)
end
g = (un, p) -> begin
X = getclosure(un, 1)
T = p.T
K = p.K
# the following block is given by the user
(X(T) > K) * X(T)
end
@code_warntype g(sol.u[1], params)
Variables
#self#::Core.Compiler.Const(var"#184#185"(), false)
un#3256::DiffEqBase.RODESolution{Float64,2,Array{Array{Float64,1},1},Nothing,Nothing,Array{Float64,1},DiffEqNoiseProcess.NoiseProcess{Float64,2,Float64,Array{Float64,1},Array{Float64,1},Array{Array{Float64,1},1},typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_DIST),typeof(DiffEqNoiseProcess.INPLACE_WHITE_NOISE_BRIDGE),true,DataStructures.Stack{Tuple{Float64,Array{Float64,1},Array{Float64,1}}},ResettableStacks.ResettableStack{Tuple{Float64,Array{Float64,1},Array{Float64,1}},true},DiffEqNoiseProcess.RSWM{:RSwM3,Float64},RandomNumbers.Xorshifts.Xoroshiro128Plus},DiffEqBase.SDEProblem{Array{Float64,1},Tuple{Float64,Float64},true,NamedTuple{(:tspan, :X₀, :μ, :σ, :μX, :σX),Tuple{Tuple{Float64,Float64},Float64,Float64,Float64,var"#120#125"{Float64},var"#121#126"{Float64}}},Nothing,DiffEqBase.SDEFunction{true,UniversalMonteCarlo.var"#2883#2884",UniversalMonteCarlo.var"#2885#2886",LinearAlgebra.UniformScaling{Bool},Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing},UniversalMonteCarlo.var"#2885#2886",Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},Nothing},StochasticDiffEq.SRIW1,StochasticDiffEq.LinearInterpolationData{Array{Array{Float64,1},1},Array{Float64,1}},DiffEqBase.DEStats}
p#3257::NamedTuple{(:T, :K, :r),Tuple{Float64,Float64,Float64}}
X::Any
T::Float64
K::Float64
r::Float64
pv::Any
Body::Any
1 ─ (X = Main.process_closure(un#3256, 1))
│ (T = Base.getproperty(p#3257, :T))
│ (K = Base.getproperty(p#3257, :K))
│ (r = Base.getproperty(p#3257, :r))
│ %5 = -r::Float64
│ %6 = (%5 * T)::Float64
│ %7 = Main.exp(%6)::Float64
│ %8 = (X)(T)::Any
│ %9 = (%8 > K)::Any
│ %10 = (X)(T)::Any
│ (pv = %7 * %9 * %10)
└── return pv
Which is not type stable but gives better performance than the previous case! I cannot figure that out! For example, running the function f
(first case) for 10^5
trajectories gives:
141.667 ms (482515 allocations: 11.18 MiB)
while running the function g
(second case) for the same amount of trajectories gives:
108.782 ms (444500 allocations: 9.09 MiB)
I don’t get why these two cases are different in the first place, why one of them is type stable and the other one not and why the faster case is the type unstable…
Lastly, as you suggested, using GG works. However, this same input runs much slower if the function is evaluated using GG, instead of using just eval and invokelatest. For example, the example above gives:
815.524 ms (1017902 allocations: 40.64 MiB)
I have seen this similar behavior when using ModelingToolkit for solving ODEProblems with Val{false}
when generating a Julia function.
Any ideas regarding the performance issue for the first two cases?
Thanks!