CompetingClocks
Fast, composable samplers for stochastic discrete-event simulation. This package gives your simulation or simulation framework statistical features like common random numbers, likelihood tracking, and first-class support for non-Exponential distributions.
This isn't a simulation framework. It's a component you can use to sample event times for simulation or to calculate the likelihood of a sample path for statistical estimation.
- Simulations of chemical reactions.
- Queueing theory models of networks, production, and computation.
- Epidemiological models of disease spread among individuals.
- Vector-addition systems.
- Generalized stochastic Petri nets.
- Generalized semi-Markov Processes.

Implementation Based on
- P. J. Haas, Stochastic Petri Nets: Modelling, Stability, Simulation. in Springer Series in Operations Research. New York, NY: Springer-Verlag New York, Inc, 2002. doi: 10.1007/b97265.
- D. F. Anderson and T. G. Kurtz, Stochastic Analysis of Biochemical Systems. Springer International Publishing AG Switzerland, 2015.
- Continuous-time, discrete-event simulation from counting processes, by Andrew Dolgert, 2016.
Version History
- v0.3.0 (2026-07) - Split fire! from enable! for correctness.
- v0.2.0 (2025-12) - Likelihood calculation, variance reduction.
- v0.1.0 (2024-06) - Initial release of samplers.
Usage
The library provides you with samplers. Each sampler has the same interface. Here, a distribution is a Distributions.ContinuousUnivariateDistribution, RNG is a random number generator, the key is some identifier (maybe an integer, tuple, or pair) for the event, and an enabling time is a zero-time for the given distribution.
enable!(sampler, key, distribution, enabling_time)- to start the clock on when an event will fire next.disable!(sampler, key)- to turn off an event so it can't fire.next(sampler)- to ask this library who could fire next, and it return a (time, key).fire!(sampler, key, time)- choose which event happens at what time.
When NOT to use Competing Clocks
- Need ODE coupling? If a firing rate is coupled to a continuously-evolving ODE state, it's easier to stay within SciML and JumpProcesses.jl. Fixed delays are supported here via Dirac distributions (see delayed reactions); coupling a full ODE state to a firing time is future work, tracked in issue #45.
- Want high-level frameworks? Try Agents.jl or ConcurrentSim.jl — or the frameworks built on this package: ChronoSim.jl for discrete-event simulation and Quarton.jl for queueing theory.
You do not have to leave for a pure-exponential or chemical-kinetics model. You should be able to write your simulation once, expressively, whether or not every clock is exponential, and a hazard-rate-only interface is rarely the fastest way to sample a distribution. The pointer to JumpProcesses.jl above is for users who need ODE coupling or the rest of the SciML ecosystem, not a suggestion that exponential clocks belong elsewhere.
CompetingClocks.jl is for:
- Building a simulation framework with
- General distributions (Weibull, Gamma, etc.),
- Likelihood calculations or rare events, or
- Variance reduction.
- Advanced work in reliability models, disease models, queueing models.