Composable probabilistic models can lower barriers to rigorous infectious disease modelling

And a change of mind about the backend

Sam Abbott

London School of Hygiene & Tropical Medicine

14 August 2026

Talk plan

  • What modelling evidence has to be, and why we rarely manage all of it
  • Chaining models loses information, joint models cannot be taken apart
  • Parts validated on their own, then fitted together
  • One replication, a common EpiNow2 configuration in three hours
  • Why the backend is the part I am least sure about
  • Whether JAX is the way forward, and whether Julia is the place

samabbott.co.uk/JuliaCon2026/composable

JuliaCon 2026, Muschel — N3, Friday 14 August 2026, 16:45.

The gap: timely, rigorous, and collaborative evidence

  • Chris Whitty, then Chief Scientific Adviser and later Chief Medical Officer for England, set out what modelling evidence has to be to inform policy effectively
  • It has to be timely, rigorous, and collaborative
  • Most of what we build manages two of the three

Whitty 2015 editorial on academic papers and health policy

The gap: COVID-19 showed what is possible

  • COVID-19 models integrated cases, prevalence, severity, and hospital occupancy for policy
  • Fitting all the data and processes together provided evidence that supported policy decisions
  • They required expertise across multiple domains and long development timelines

Birrell et al. (2025), doi:10.1093/jrsssa/qnaf030

Results from the England COVID-19 joint model

The gap: flexibility for new contexts

  • In 2022 mpox spread internationally through sexual contact networks, and the response needed modelling quickly
  • The COVID-19 models were not adapted to it. New single-source models were built instead
  • A different contact structure and different behaviour needed explicit representation

Endo et al. (2022), doi:10.1126/science.add4507

Results from the 2022 mpox sexual contact network model

The gap: integrating diverse data

  • Cross-sectional viral loads carry information about epidemic dynamics
  • They are not in most policy models, even where they are already collected
  • Adding a data source to an existing model means rebuilding it

Hay et al. (2021), doi:10.1126/science.abh0635

Title of the Hay et al. 2021 viral load paper

The gap: multi-model efforts

  • Multi-model efforts combine forecasts from several teams, and can improve predictive accuracy
  • The teams rarely collaborate on model components
  • Common components would let a difference in results be attributed to an assumption rather than an implementation

The US COVID-19 Forecast Hub dataset. Cramer et al. (2022), doi:10.1038/s41597-022-01517-w

Title of the Cramer et al. 2022 Forecast Hub dataset paper

Analysing data and processes separately

  • The ONS COVID-19 Infection Survey tested over four million swabs from more than 150,000 households at a cost above £500 million
  • Modellers outside saw the published prevalence, not the swabs
  • Prevalence fed incidence, incidence fed \(R_t\), and those fed variant transmissibility and severity
  • Uncertainty was approximated at each step and assumptions were inherited unchecked

Four panels of the survey chain fitted as one model

Prevalence (A), incidence (B), antibody prevalence (C) and \(R_t\) (D) fitted together as one model instead. Abbott and Funk (2022), doi:10.1101/2022.03.29.22273101. Survey figures from the paper’s introduction

Analysing all data and processes together

  • Lison et al. found biases at each step of a chain, in date imputation and in the nowcasting count model
  • Those biases carried into \(R_t\). Fitting the steps together avoided them
  • Joint models are difficult to develop within policy timelines, and need expertise across several domains

Lison et al. (2024), doi:10.1371/journal.pcbi.1012021

Title of the Lison et al. 2024 paper

The \(R_t\) estimation ecosystem

  • At least seven packages estimate \(R_t\) by renewal in Stan. Only two of them share any component, and I wrote both
  • The wastewater \(R_t\) tools make different choices about how much of the sampling to represent, and share nothing
  • Shared parts do exist. primarycensored is one, and uptake outside my own packages is thin
  • The unit of reuse is the whole model, not the epidemiology underneath

The two sharing a component are EpiNow2 and epinowcast, both vendoring primarycensored.stan · epiforecasts.io/EpiNow2

The EpiNow2 package README, one of the seven

Can composable modelling help?

What is composable modelling?

Components can be reused across contexts and combined in different configurations whilst maintaining statistical rigour.

  • Components can be validated on their own, then combined into joint models that propagate uncertainty properly
  • Domain experts contribute specialised parts without understanding the whole system
  • Adding a data source means a new submodel rather than a rebuild
  • Domain-specific languages have done this in other fields, SpeedyWeather.jl for weather and HydroModels.jl for hydrology

Design considerations

  • Uncertainty and inference. Joint and staged inference that avoids the cascading biases, and automatic differentiation for fitting
  • Model structure. Components separated by process type, and models nested inside models
  • Workflow. One specification that is useful for simulation and for inference

Warning

These were developed by the authors and have not yet received broader community input.

Table 1 of the paper, requirements against motivating problems

Table 1 of the paper pairs each requirement with the problem that motivates it, under six themes. Three of the twelve are on the left. All twelve are at epiaware.org/approaches

The proof of concept is ComposableTuringIDModels.jl

  • A thin language for epidemiology over Turing.jl, which does the fitting
  • Three component families. Infection processes, latent processes, and observation models
  • Components carry their own priors, so domain expertise travels with the component
  • Model definitions do not know about the data, so one definition simulates and fits

Registered in General at v0.1.1, so ] add ComposableTuringIDModels works · github.com/EpiAware/ComposableTuringIDModels.jl · Abbott et al., Composable probabilistic models can lower barriers to rigorous infectious disease modelling, in CDC clearance

Four applications drawn as graphs over a band of shared parts

Four illustrative applications, not implementations. The incubation period model appears in all four and the latent infection model in three

What composition looks like

using ComposableTuringIDModels, Distributions, Turing, Accessors

ar2 = AR(;
  damp = [truncated(Normal(0.2, 0.2), 0, 1),
          truncated(Normal(0.1, 0.05), 0, 1)],
  ϵ_t = HierarchicalNormal(std = HalfNormal(0.1)))
ma1 = MA(;
  θ = [truncated(Normal(0.0, 0.2), -1, 1)],
  ϵ_t = HierarchicalNormal(std = HalfNormal(0.1)))

arma21 = @set ar2.ϵ_t = ma1
arima211 = DiffLatentModel(arma21, Normal(0, 0.2); d = 1)

mdl = IDModel(
  DirectInfections(; Z = arima211, initialisation = Normal()),
  PoissonError())
chain = sample(as_turing_model(mdl, cases, n), NUTS(), 1_000)

@set is Accessors.jl, not ours, and works because the components are plain immutable structs · Keywords track main. The paper’s artefact pins an earlier release, where these were damp_priors, θ_priors and std_prior

MA(1) inside AR(2) inside ARMA inside ARIMA, then Poisson

Note

AR was never told that MA exists.

Real-time nowcasting, one EpiNow2 configuration

  • Reuses the ARIMA(2,1,1) and the negative binomial from the worked example
  • broadcast_weekly wraps the ARIMA for piecewise constant weekly \(R_t\), and ascertainment_dayofweek adds day-of-week reporting
  • Two LatentDelay wrappers add the incubation period and the reporting delay
  • A to D validate each part on its own. E and F are the joint fit, recovering cases through the delays and \(R_t\) with them

Important

No component was edited. The replication took three hours.

Figures 2 and 4 of the paper. Replicating a common configuration of EpiNow2, real-time estimation accounting for reporting delays, right truncation and day-of-week effects. Abbott et al. (2020), doi:10.12688/wellcomeopenres.16006.2. Daily COVID-19 cases from Italy, February to June 2020, shipped with EpiNow2. One configuration replicated, not a benchmark against the package

The EpiNow2 configuration drawn as a graph of components

Six panels: prior checks on each part, then the joint fit

The backend is the part I am least sure about

  • Turing.jl gave us submodels, a choice of samplers, and the rest of Julia. The proof of concept exists because of it
  • Eleven breaking releases in nineteen months, v0.35.5 to v0.46.0. Our migration was one rename. The cost is the tracking
  • Large simulated counts error, and vectors mixing missing and observed values have to be handled by hand
  • Automatic differentiation is the part that decided it

From the Turing.jl documentation

“not all AD libraries in there are thoroughly tested on Turing models. Thus, it is possible that some of them will either error … or maybe even silently give incorrect results”

Release dates from the GitHub API, 2026-08-10 · v0.35.5 is the release the paper’s artefact pins · turinglang.org/docs/usage/automatic-differentiation · The two practical limits are in the paper’s discussion · We run six autodiff configurations in CI instead, which was the 14:30 talk in this room, samabbott.co.uk/JuliaCon2026/roadmap

The teams under this are small

  • A lot of the stack rests on very few people. The work itself is good
  • TuringLang/ADTests, the one public per-backend support table for a probabilistic programming stack, was archived in June
  • EpiAwareADTools.jl is where we keep our autodiff workarounds. We delete them when upstream ships a fix
  • Our own packages are the same shape, one or two people each
Commits, last six months Turing.jl DynamicPPL.jl
Human authors 29 72
One person 17 47

Commit counts from the GitHub API, 2026-08-10, main, human authors only, so 17 of 29 and 47 of 72 are per repository · DynamicPPL.jl is where most of the composition machinery lives · TuringLang/ADTests, archived 2026-06-15

So what is the composable unit?

  • A Distributions.jl distribution is already an interface the whole of Julia understands, so write the epidemiology as distributions and the probabilistic programming language becomes optional
  • CensoredDistributions.jl does not depend on Turing. Nothing in src/ mentions it
  • It reaches ConvolvedDistributions.jl through a package extension, and neither is a hard dependency of the other
# a serial interval, censored and truncated
si = double_interval_censored(
  convolve_distributions(generation_time, incubation);
  upper = 15, interval = 1)

typeof(si)
# IntervalCensored{Truncated{PrimaryCensored{Convolved{…}}}}

cdf(si, 5.0)   # 0.094

CensoredDistributions.jl v0.2.22, main, checked 2026-08-11. ConvolvedDistributions is a [weakdeps] entry carrying the extension CensoredDistributionsConvolvedDistributionsExt, and neither package is in the other’s [deps] · The type is the output of scripts/composable-composed-type.jl, run for this talk, with the parameter types dropped, and cdf needed no telling about it

How far does that go?

Piece of a model Is it a distribution?
Delay, censored and truncated Yes, today
Renewal process No
ARIMA latent process No
ODE No
The fitting layer No
  • So this is a direction, not a plan. It needs a way to write a time series as a distribution, and a way to fit one without a model macro
  • The fitting layer is what the probabilistic programming language was doing

Open issue CensoredDistributions.jl#749 says the joint fit is too slow, because reverse mode autodiff through cdf(Convolved(...)) costs too much per step · The delay side is written up in full at samabbott.co.uk/JuliaCon2026/delays

Is JAX the way forward, and is Julia the place?

  • In the paper I wrote that NumPyro and JAX are promising, with barriers for epidemiological modellers, and that I find them ugly. Taste is not an argument
  • JAX has one autodiff system, and everything is written against it
  • We test six configurations and cannot tell a user which one is safe for a model built from five packages
  • Multiple dispatch is why a composed delay is still a distribution. I do not know how to write that as cleanly anywhere else
  • The teams under Turing, under the autodiff backends, and under our own packages are all small

Important

I have argued myself into both answers.

The alternative approaches, including NumPyro and JAX, are in the paper’s discussion. The paper is in CDC clearance · The six autodiff configurations were the 14:30 talk in this room, samabbott.co.uk/JuliaCon2026/roadmap

Thank you

Important

Tell me what you would build this on, if not a probabilistic programming language.

  • Counter-examples. Where is practice already timely, rigorous, and collaborative? I would like to be shown the problem is smaller than I think
  • Other ways to compose. Category theory, symbolic approaches, or something I have not thought of
  • Build it in Julia. The infectious disease ecosystem here is small. If you are about to write a tool, come and find me first
  • The prompts that wrote these decks

Backup

What this does not do yet

Nobody outside the author team has built a model with this

Until somebody outside tries, the title is an argument rather than a result.

In the proof of concept

  • The component library stops at basic epidemiological patterns. No partial pooling, and no mapping between latent and observed states
  • Changing a component’s order does not update the priors that go with it. That stays manual
  • The abstraction layers have a runtime cost. We have not measured it properly

In the claim

  • The design considerations came from the authors and have had no community input

Note

EpiAwareR, Sebastian Funk’s prototype R interface, ran two of the three replications. That is the closest thing to outside use so far.

Reusing that AR(2) for South Korea

  • The first replication takes the AR(2) from the worked example, a renewal process with a discretised serial interval, and a negative binomial observation model
  • A to C are prior predictive checks on each part, D compares the continuous serial interval with its discretised form
  • E and F recover the paper’s finding. \(R_t\) in South Korea peaked near 10 and dropped below 1 in early March 2020

Replicating Mishra et al. (2020). Figure from the paper

Six panels: prior checks on each part, then the joint fit

Swap the infection process, keep the rest

  • The third replication drops the renewal process and uses an SIR model built with ODEProcess over the SciML solvers instead
  • Everything downstream is unchanged. A Poisson observation model, and a second version wrapping it in Ascertainment driven by an AR(1)
  • C shows both landing on the same posterior \(R_0\). E and F show the deterministic fit is the worse calibrated of the two

Important

The infection process changed and nothing downstream had to.

Replicating Chatzilena et al. (2019), doi:10.1016/j.epidem.2019.100367. An influenza outbreak in an English boarding school, 1978. Figure 5 of the paper. The paper’s text reads \(R_0 \approx 2\) off this panel. Panel C looks closer to 4 to me, and I have not resolved which is right

Six panels comparing a deterministic and a stochastic SIR fit

Other ways to compose models

Approach How it composes
AlgebraicJulia Formal compositional guarantees, and little support for probabilistic models
JuliaBUGS.jl, RxInfer.jl Models specified as graphs
ModelingToolkit.jl Acausal components, symbolically
Gen.jl Nested generative functions, at a lower level than Turing.jl

The paper’s discussion of alternative designs

Why keep the parts small

  • The component structure is what makes this tractable for a language model to assemble

This claim is in the paper’s discussion. It has not been tested.

Composable probabilistic models

What is composable modelling?

Components can be reused across contexts and combined in different configurations whilst maintaining statistical rigour.

  • Chaining models keeps you flexible and loses information. Uncertainty is approximated at each hand-off and assumptions are inherited unchecked
  • Joint models avoid that and produce something nobody can take apart. England’s COVID-19 models were not adapted to mpox in 2022
  • Composable components are validated on their own, then fitted together, and carry their own priors, so domain expertise travels with the component

Whitty (2015), doi:10.1186/s12916-015-0544-8 · Birrell et al. (2025), doi:10.1093/jrsssa/qnaf030 · Endo et al. (2022), doi:10.1126/science.add4507 · Lison et al. (2024), doi:10.1371/journal.pcbi.1012021

Four applications drawn as graphs over a band of shared parts

Four illustrative applications, not implementations. The incubation period model appears in all four, the latent infection model in three, and the band beneath is what those shared components are themselves made of. Figure 1 of the paper, which is in CDC clearance. The design considerations behind it are at epiaware.org/approaches

One EpiNow2 configuration, rebuilt out of parts

  • An ARIMA(2,1,1) latent process and a negative binomial observation model, both lifted unchanged from other applications
  • broadcast_weekly for weekly \(R_t\), day-of-week ascertainment around the observation model, and two LatentDelay wrappers for the incubation period and the reporting delay
  • A to D validate each part on its own. E and F are the joint fit, recovering cases through the delays and \(R_t\) with them

Important

Nothing here required editing a component that already existed. The replication took three hours.

One of three replications in the paper, alongside a renewal model of South Korea and an ODE model of influenza. Replicating EpiNow2 (Abbott et al., 2020). Figures from the paper, which is in CDC clearance. The prototype is ComposableTuringIDModels.jl

The EpiNow2 configuration drawn as a graph of components

Six panels: prior checks on each part, then the joint fit