Possible type instability in `BVP.BVProblem()` and `BVP.solve()`
This issue originates from a Julia Discourse thread:
https://discourse.julialang.org/t/boundaryvaluediffeq-jl-reducing-allocations/136255
I noticed what appears to be type instability in both `BVP.BVProblem()` and `BVP.solve()`, which may affect solver performance.
## Minimal reproducible example
```julia
import BoundaryValueDiffEq as BVP
using Cthulhu
function distribution_fun_test!(dydt::AbstractVector{T}, y::AbstractVector{T}, p::Any,
t::Float64) where {T<:Real}
y1, y2, y3, y4 = y
dydt[1] = 0.001 * y2
dydt[2] = 10 * y1
dydt[3] = -0.03 * y2 + 0.0001 * y4
dydt[4] = 10 * y3
uptake = 0.1 * y3 / (1000 * y3 + 1)
dydt[3] += uptake
end
function distribution_bc_test!(residual::AbstractVector{}, u::Any, p::Any, t::Vector{Float64})
residual[1] = (u[4, end] - 0.001)
residual[2] = u[1, end]
residual[3] = -u[3, end]
residual[4] = u[1, 1]
end
function test_solve()
L = 100.0
mesh_size = 500
tspan::Tuple{Float64, Float64} = (0.0, Float64(L))
y_initial::Vector{Float64} = [1, 0.001 / 0.03, 1, 0.001]
bvp_problem = BVP.BVProblem(
distribution_fun_test!,
distribution_bc_test!,
y_initial,
tspan,
)
@time BVP.solve(bvp_problem, BVP.MIRK5(); adaptive = false, dt = Float64(L / mesh_size))
@time BVP.solve(bvp_problem, BVP.MIRK5(); adaptive = false, dt = Float64(L / mesh_size))
end
@descend test_solve()
```
## Output
```julia
> @descend test_solve()
test_solve() @ Main REPL[5]:1
1 function test_solve()::Any
2 L::Core.Const(100.0) = 100.0::Core.Const(100.0)
3 mesh_size::Core.Const(500) = 500::Core.Const(500)
4 (tspan::Core.Const((0.0, 100.0))::Tuple{Float64, Float64})::Core.Const(true) = (0.0, Float64(L::Core.Const(100.0))::Core.Const(100.0))::Core.Const((0.0, 100.0))
6
6 (y_initial::Vector{Float64}::Vector{Float64})::Core.Const(true) = [1, (0.001/0.03)::Core.Const(0.03333333333333333), 1, 0.001]::Vector{Float64}
8
8 bvp_problem::Any = BVP.BVProblem::Type{SciMLBase.BVProblem}(distribution_fun_test!::Core.Const(Main.distribution_fun_test!),
9 distribution_bc_test!::Core.Const(Main.distribution_bc_test!),
10 y_initial::Vector{Float64}, tspan::Core.Const((0.0, 100.0)))::Any
11
12 @time BVP.solve::Core.Const(CommonSolve.solve)(bvp_problem::Any, BVP.MIRK5::Type{BoundaryValueDiffEqMIRK.MIRK5}()::Core.Const(MIRK5(jac_alg = BVPJacobianAlgorithm(), defect_threshold = 0.1, max_num_subintervals = 3000)); adaptive = false, dt=Float64((L::Core.Const(100.0)/mesh_size::Core.Const(500))::Float64)::Tuple{Any, Float64, Int64, Float64, Base.GC_Diff, Int64, Float64, Float64}::NamedTuple{(:value, :time, :bytes, :gctime, :gcstats, :lock_conflicts, :compile_time, :recompile_time), <:Tuple{Any, Float64, Int64, Float64, Base.GC_Diff, Int64, Float64, Float64}})::Any
13 @time BVP.solve::Core.Const(CommonSolve.solve)(bvp_problem::Any, BVP.MIRK5::Type{BoundaryValueDiffEqMIRK.MIRK5}()::Core.Const(MIRK5(jac_alg = BVPJacobianAlgorithm(), defect_threshold = 0.1, max_num_subintervals = 3000)); adaptive = false, dt=Float64((L::Core.Const(100.0)/mesh_size::Core.Const(500))::Float64)::Tuple{Any, Float64, Int64, Float64, Base.GC_Diff, Int64, Float64, Float64}::NamedTuple{(:value, :time, :bytes, :gctime, :gcstats, :lock_conflicts, :compile_time, :recompile_time), <:Tuple{Any, Float64, Int64, Float64, Base.GC_Diff, Int64, Float64, Float64}})::Any
14 end
```
## Observation
From the `@descend` output:
* `bvp_problem` is inferred as `Any`
* `test_solve()` is inferred as returning `Any`
* consequently, the return value of `BVP.solve(...)` is reckoned to be `Any`
This suggests that `BVP.BVProblem()` and `BVP.solve()` may be type-unstable in this case.
Since this can introduce additional allocations and hurt performance, I thought it would be worth reporting.
## Environment
* Ubuntu 25.10
* Julia 1.12.5
0 条评论