Fix SDE/RODE algorithm ambiguity in OrdinaryDiffEqCore extension#567
Conversation
OrdinaryDiffEqCore now defines __init with:
Union{OrdinaryDiffEqAlgorithm, DAEAlgorithm, StochasticDiffEqAlgorithm, StochasticDiffEqRODEAlgorithm}
This causes an ambiguity with JumpProcesses' __init(::AbstractJumpProblem, ::DEAlgorithm).
The fix adds StochasticDiffEqAlgorithm and StochasticDiffEqRODEAlgorithm to the
extension's Union type to match the exact signature from OrdinaryDiffEqCore.
|
@ChrisRackauckas I thought StochasticDiffEq handled init for SDEs + jumps and JumpProcesses only handled ODEs + jumps or pure jumps? |
|
(Note I handled the ambiguity error with OrdinaryDiffEqCore previously.) |
|
No this is right. Since they are both the same init now it should just delegate to jump here, and then in the jump init it will delegate down to the problem. ODE's init is now involved even in SDEs, so it's not separate like that anymore. They are the same integrator. |
|
But doesn't https://github.com/SciML/OrdinaryDiffEq.jl/blob/6359ecae94193ca2d9ee407ee5de9653aae1e708/lib/StochasticDiffEqCore/src/solve.jl#L92 already handle a JumpProblem with an SDE algorithm? Why add a dispatch for the AbstractJumpProblem case here. It won't ever actually get called for JumpProblem over SDEProblem would it (since the StochasticDiffEqCore version is more specific). |
|
I think in practice this will never actually be called for jumps + SDEs, but I don't think it hurts either so I'll merge it. |
|
No this is the one that actually needs to get called so this gives it higher precedence. The SDE init handles regular jumps for some algorithms, like tau leaping, directly, but delegates here for the building of the irregular jump callbacks. The SDE init assumes that the irregular jump callbacks are already generated. So this needs to have higher precedence so that it does this to build the irregular jumps (ignores the regular jumps) and tag them to the SDE problem and then goes into the SDE init which handles the other jumps. If https://github.com/SciML/OrdinaryDiffEq.jl/blob/6359ecae94193ca2d9ee407ee5de9653aae1e708/lib/StochasticDiffEqCore/src/solve.jl#L92-L98 takes precedence, i.e. if the prob is split there into two dispatches, then it would go straight to the SDE part and ignore the irregular jumps. So this dispatch should be called given the other one is union SDE and jump and this is not, and this change makes it unambiguously a stricter dispatch. |
|
With the latest StochasticDiffEq (6.100) the following using StochasticDiffEq, JumpProcesses
# SDE: dX = -X dt + 0.1 dW
f(u, p, t) = -u
g(u, p, t) = 0.1
# Constant rate jump
rate(u, p, t) = 1.0
affect!(integrator) = (integrator.u += 0.5)
crj = ConstantRateJump(rate, affect!)
sde_prob = SDEProblem(f, g, 1.0, (0.0, 1.0))
jprob = JumpProblem(sde_prob, Direct(), crj)
# Check which __init is called
m = which(DiffEqBase.__init, (typeof(jprob), typeof(EM())))
println("Dispatches to: ", m.module, " in ", m.file)gives A print statement added to the |
|
Is that with this PR? And that version that is dispatching there, are the integrator.ops.callbacks missing the jump callbacks? |
|
No because the __sde_init adds the callbacks itself. |
|
I spawned an agent to step through it. I thought I had a call first to the jump library to add the callbacks, but if the StochasticDiffEq code is adding the callbacks then it should split the prob there. |
|
The right test is to look at the integrator object and see if the path has the jump callback made once: if SDE and this both do it, you'll double the jump callback so the length of integrator.opts.callbacks should be a good test for if this is done correctly. |
Callback duplication test resultsFollowing Chris's suggestion to check Test setup
ResultsBoth tests pass — no duplication of jump callbacks. The full test suite (52 callback tests) passes cleanly. Commit: 42e4102 Note: As @isaacsas observed, for SDE algorithms the dispatch currently goes through StochasticDiffEq's |
Adds a regression test for PR SciML#567 that checks integrator.opts.callback to ensure jump callbacks appear exactly once when using SDE algorithms with JumpProblems. Tests both ConstantRateJump (discrete callback) and VariableRateJump (continuous callback) with EM() solver. Co-Authored-By: Chris Rackauckas <[email protected]> Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
…duplication-test Add test for SDE+jump callback duplication (PR #567 follow-up)
Summary
OrdinaryDiffEqCore now defines
__initwith a Union that includes all four algorithm types:OrdinaryDiffEqAlgorithmDAEAlgorithmStochasticDiffEqAlgorithmStochasticDiffEqRODEAlgorithmThis creates an ambiguity with JumpProcesses'
__init(::AbstractJumpProblem, ::DEAlgorithm)when calling with aJumpProblemand any of these algorithm types.The Error
The error (seen in CI for PR #565):
Fix
Update the extension to include
StochasticDiffEqAlgorithmandStochasticDiffEqRODEAlgorithmin the Union type, matching the exact signature from OrdinaryDiffEqCore. This makes the extension method more specific than both ambiguous candidates.cc @isaacsas @ChrisRackauckas