Skip to content

Conversation

@ChrisRackauckas-Claude
Copy link
Contributor

Summary

This PR adds a new RSWM algorithm variant :RSwM0 that addresses the bias issue when using adaptive tau-leaping with compound Poisson processes that have state-dependent rates.

The Problem

When doing tau-leaping with post-hoc corrections (bridging/rejection), the standard RSwM algorithms (RSwM1/2/3) store rejected noise values for later reuse. This works correctly for Brownian motion because the noise is independent of the solution. However, for Poisson processes with state-dependent rates:

  1. A Poisson increment is generated with rate λ(X_n, t) for interval [t, t+dt]
  2. If the step is rejected, the bridge is used to get an increment for [t, t+dt/2]
  3. The "future" portion [t+dt/2, t+dt] is stored in the stack
  4. But this stored value was generated with rate λ(X_n, t), which may be incorrect for the new trajectory

As David Anderson notes in the referenced paper, you should use the Poisson bridge to pull back, but you shouldn't store the future value because it was generated with the wrong λ.

The Solution

  • Add :RSwM0 algorithm variant that uses bridging but discards future values
  • reject_step!: Uses bridging for interpolation but doesn't push to S₁/S₂ stacks
  • setup_next_step!: Always recalculates fresh noise (doesn't use stored values)
  • CompoundPoissonProcess now defaults to :RSwM0

Changes

  • src/rswm.jl: Add documentation for :RSwM0
  • src/noise_interfaces/noise_process_interface.jl: Handle :RSwM0 in reject_step! and setup_next_step!
  • src/compoundpoisson.jl: Default to RSWM(adaptivealg = :RSwM0), add rswm keyword argument

Behavior Comparison

Algorithm On Step Rejection On Next Step Setup
RSwM0 Uses bridging, discards future Recalculates fresh
RSwM1/2/3 Uses bridging, stores future Reuses stored values

Test Results

Original dW (dt=0.5, rate=[100,200]): [55.0, 91.0]
RSwM0 S₁ empty after reject: true  ← Future values discarded
RSwM3 S₁ length after reject: 1    ← Future values stored

Reference

Anderson, D.F. "Incorporating postleap checks in tau-leaping"
J. Chem. Phys. 128, 054103 (2008); https://doi.org/10.1063/1.2819665

Test plan

  • Verified CompoundPoissonProcess defaults to :RSwM0
  • Verified reject_step! with :RSwM0 keeps S₁ empty
  • Verified setup_next_step! with :RSwM0 recalculates fresh noise
  • Verified binomial thinning (bridging) works correctly
  • Verified users can override with rswm = RSWM(adaptivealg = :RSwM3) if desired

🤖 Generated with Claude Code

This adds a new RSWM algorithm variant `:RSwM0` that uses bridging for
rejected steps but discards future values instead of storing them in memory.

For tau-leaping with state-dependent rates, the rate λ is approximated as
constant over each step. When a step is rejected, storing the "future"
portion doesn't make sense because you don't know the correct λ anyway -
it's always an approximation. Recalculating fresh is more appropriate for
this use case than reusing values generated with the wrong rate.

Changes:
- Add :RSwM0 to RSWM with documentation
- Modify reject_step! to handle :RSwM0 (bridge but don't store)
- Modify setup_next_step! to handle :RSwM0 (always recalculate)
- Change CompoundPoissonProcess default to use :RSwM0
- Add rswm keyword argument to CompoundPoissonProcess constructors

Reference: Anderson, D.F. "Incorporating postleap checks in tau-leaping"
J. Chem. Phys. 128, 054103 (2008); https://doi.org/10.1063/1.2819665

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@ChrisRackauckas-Claude
Copy link
Contributor Author

Correction to PR description: The original description incorrectly stated that storing values "introduces bias."

The correct framing is: RSwM0 is also biased (as is tau-leaping in general). The point is that for tau-leaping with state-dependent rates, you don't know the correct λ anyway - it's always approximated as constant over each step. So storing values generated with the wrong rate doesn't make sense; recalculating fresh is more appropriate for this use case.

The code docstrings have been updated to reflect this correct understanding.

@ChrisRackauckas
Copy link
Member

@isaacsas this fixes the Anderson post-leap so now it should be complete, and implicit tau leaps are in StochasticDiffEq

@ChrisRackauckas ChrisRackauckas merged commit 1fe1499 into SciML:master Jan 13, 2026
14 checks passed
@isaacsas
Copy link
Member

But I guess Anderson's method would still be advantageous for applications requiring / benefiting from strong convergence? (Since it could be realized by pre-sampling one unit rate Poisson process for each reaction, and then just using the sampled paths to determine reaction counts for the tau-leaping simulation?) The method here is only really convergent in a weak sense right?

@ChrisRackauckas
Copy link
Member

This is Anderson's post-leap correction method, unless you're referencing some other Anderson method. The point I was mentioning before is that the method has a small but non-zero bias in both strong and weak convergence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants