Public API
Documentation for the exported, public interface of ComposableTuringIDModels.
Index
ComposableTuringIDModels.ARComposableTuringIDModels.AbstractComposableModelComposableTuringIDModels.AbstractInfectionModelComposableTuringIDModels.AbstractLatentModelComposableTuringIDModels.AbstractObservationErrorModelComposableTuringIDModels.AbstractObservationModelComposableTuringIDModels.AbstractPriorModelComposableTuringIDModels.AggregateComposableTuringIDModels.AscertainmentComposableTuringIDModels.BinomialErrorComposableTuringIDModels.BroadcastLatentModelComposableTuringIDModels.BroadcastPriorComposableTuringIDModels.CatalystODEParamsComposableTuringIDModels.CombineLatentModelsComposableTuringIDModels.ConcatLatentModelsComposableTuringIDModels.DiffLatentModelComposableTuringIDModels.DirectInfectionsComposableTuringIDModels.DirectSampleComposableTuringIDModels.ExpGrowthRateComposableTuringIDModels.FixedInterceptComposableTuringIDModels.HalfNormalComposableTuringIDModels.HierarchicalNormalComposableTuringIDModels.IDDataComposableTuringIDModels.IDMethodComposableTuringIDModels.IDModelComposableTuringIDModels.IDObservablesComposableTuringIDModels.IDProblemComposableTuringIDModels.IIDComposableTuringIDModels.InterceptComposableTuringIDModels.LatentDelayComposableTuringIDModels.MAComposableTuringIDModels.ManyPathfinderComposableTuringIDModels.NUTSamplerComposableTuringIDModels.NegativeBinomialErrorComposableTuringIDModels.NormalErrorComposableTuringIDModels.NullComposableTuringIDModels.ODEProcessComposableTuringIDModels.PoissonErrorComposableTuringIDModels.PrefixLatentModelComposableTuringIDModels.PrefixObservationModelComposableTuringIDModels.RandomWalkComposableTuringIDModels.RecordExpectedLatentComposableTuringIDModels.RecordExpectedObsComposableTuringIDModels.RenewalComposableTuringIDModels.RepeatBlockComposableTuringIDModels.RepeatEachComposableTuringIDModels.ReportTriangleComposableTuringIDModels.ReportingCDFComposableTuringIDModels.ReportingPMFComposableTuringIDModels.ReportingTriangleComposableTuringIDModels.RightTruncateComposableTuringIDModels.SEIRParamsComposableTuringIDModels.SIRParamsComposableTuringIDModels.SafeNegativeBinomialComposableTuringIDModels.SafePoissonComposableTuringIDModels.SplitComposableTuringIDModels.StrataMapComposableTuringIDModels.TransformLatentModelComposableTuringIDModels.TransformObservationModelComposableTuringIDModels.NegativeBinomialMeanClustComposableTuringIDModels.R_to_rComposableTuringIDModels.accumulate_scanComposableTuringIDModels.apply_methodComposableTuringIDModels.arimaComposableTuringIDModels.armaComposableTuringIDModels.as_priorComposableTuringIDModels.as_turing_modelComposableTuringIDModels.ascertainment_dayofweekComposableTuringIDModels.broadcast_dayofweekComposableTuringIDModels.broadcast_nComposableTuringIDModels.broadcast_ruleComposableTuringIDModels.broadcast_weeklyComposableTuringIDModels.condition_modelComposableTuringIDModels.define_y_tComposableTuringIDModels.equal_dimensionsComposableTuringIDModels.expected_RtComposableTuringIDModels.generate_observation_error_priorsComposableTuringIDModels.generated_observablesComposableTuringIDModels.get_param_arrayComposableTuringIDModels.get_stateComposableTuringIDModels.implements_infection_interfaceComposableTuringIDModels.implements_latent_interfaceComposableTuringIDModels.implements_observation_interfaceComposableTuringIDModels.implements_prior_interfaceComposableTuringIDModels.manypathfinderComposableTuringIDModels.observation_errorComposableTuringIDModels.r_to_RComposableTuringIDModels.spread_draws
ComposableTuringIDModels.AR Type
An autoregressive AR(p) latent process.
with damping coefficients damp_prior, initial conditions from init_prior, and innovations from the error model ϵ_t. The order p is the length of the damping/initial priors.
Examples
using ComposableTuringIDModels, Distributions
ar = AR()
mdl = as_turing_model(ar, 10)
rand(mdl)ComposableTuringIDModels.AbstractComposableModel Type
The single light supertype for every model component in ComposableTuringIDModels.
Unlike the deep abstract hierarchy used by the original EpiAware package, the prototype keeps a shallow tree: one root supertype, and directly beneath it a small set of role supertypes — AbstractLatentModel, AbstractInfectionModel, AbstractObservationModel (and AbstractObservationErrorModel under the last) — that encode the role a component plays. There is no deeper AbstractTuring* tree and there are no per-concept generate_* functions; dispatch happens on the concrete struct inside the single generic as_turing_model.
Encoding the role in the type lets the composer and manipulators constrain their component slots, so passing a wrong-role component (e.g. an observation model where a latent model is expected) fails at construction rather than at sampling. See AbstractLatentModel and its siblings for the interface each role's as_turing_model must satisfy.
ComposableTuringIDModels.AbstractInfectionModel Type
Supertype for infection process models.
An infection model maps a series length n to a path of unobserved infections I_t. It owns its own latent (parameter) process internally — generating, e.g., a (log) reproduction number or growth-rate path — and maps that to infections, so no external latent path is threaded in. Its role interface is
as_turing_model(model::AbstractInfectionModel, n) # ⇒ (; I_t, Z_t)where the returned named tuple carries the infection path I_t and the model's internal latent draw Z_t (the (log) nothing for models with no exposable latent such as ODEProcess). Exposing Z_t keeps the latent recoverable as a generated quantity downstream.
Members include DirectInfections, ExpGrowthRate, Renewal and ODEProcess. Only Renewal carries a generation interval (IDData); the others take a transformation directly.
ComposableTuringIDModels.AbstractLatentModel Type
Supertype for latent process models.
A latent model maps a series length n to a length-n latent path. Its role interface is
as_turing_model(model::AbstractLatentModel, n) # ⇒ a length-`n` latent pathLatent modifiers and manipulators (e.g. DiffLatentModel, CombineLatentModels, BroadcastLatentModel) are themselves AbstractLatentModels: wrapping a latent model yields another latent model, so they compose freely. Their inner-model slots are typed AbstractLatentModel, so only latent components can be wrapped.
A latent model also satisfies the AbstractPriorModel contract (same as_turing_model(m, n) ⇒ length-n signature), so AbstractLatentModel <: AbstractPriorModel and any latent model can be used directly as a prior.
ComposableTuringIDModels.AbstractObservationErrorModel Type
Internal supertype shared by simple observation-error models (Poisson, negative binomial).
It exists only so that the generic observation-error as_turing_model loop — which is identical across error families — can be written once and dispatch the family-specific pieces (observation_error and generate_observation_error_priors) on the concrete type. It is the error sub-role of AbstractObservationModel; the prototype keeps no deeper hierarchy than this.
ComposableTuringIDModels.AbstractObservationModel Type
Supertype for observation models.
An observation model maps a path of expected observations Y_t to observed counts y_t. Its role interface is
as_turing_model(model::AbstractObservationModel, y_t, Y_t) # ⇒ observed counts y_ty_t === missing triggers prior/predictive simulation; a concrete y_t conditions the model on data. Observation modifiers (e.g. LatentDelay, Ascertainment, Aggregate) are themselves AbstractObservationModels: wrapping an observation model yields another observation model. Their inner-model slots are typed AbstractObservationModel, so only observation components can be wrapped.
AbstractObservationErrorModel is the sub-role for the simple error families (Poisson, negative binomial).
ComposableTuringIDModels.AbstractPriorModel Type
Supertype for prior models — a parameter prior expressed as a length-n submodel rather than a bare Distribution.
A prior model maps a length n to a length-n vector of parameter values via the same as_turing_model protocol every other component speaks:
as_turing_model(prior::AbstractPriorModel, n) # ⇒ a length-`n` vectorThe default wrapper BroadcastPrior turns a plain Distribution (the common case) into exactly this, and as_prior coerces a user-supplied Distribution / vector of Distributions into the wrapper so constructors keep accepting bare distributions. Because every AbstractLatentModel already satisfies as_turing_model(m, n) ⇒ length-n, latent models are prior models: AbstractLatentModel <: AbstractPriorModel, so a prior slot accepts a latent model (e.g. a RandomWalk for a time-varying parameter) wherever it accepts a distribution wrapper. A genuinely scalar parameter uses n == 1 and reads the element with only(...), keeping the chain as small as a bare ~ dist.
This is the foundation for issue #37 (priors as submodels); the migration of the existing components' prior fields to this role is a separate, coordinated change.
sourceComposableTuringIDModels.Aggregate Type
Aggregate the expected observations of an underlying model over reporting windows.
Each entry of aggregation gives the window length to sum over at the corresponding (broadcast) time point, and present (derived as aggregation .!= 0) marks the time points that are reported. The aggregation and presence vectors are broadcast to the observation length with RepeatEach, the expected observations are summed over each window, the inner model is applied to the present windows, and the predictions are scattered back into a full-length vector (zeros elsewhere).
Arguments
ag: theAggregatemodel.y_t: the observed series (ormissingwhen simulating predictively).Y_t: the expected-observation series.
Examples
using ComposableTuringIDModels
obs = Aggregate(PoissonError(), [0, 0, 0, 0, 0, 0, 7])
mdl = as_turing_model(obs, missing, fill(10.0, 14))
rand(mdl)Fields
model: the underlying observation model applied to the aggregated windows.aggregation: the per-period window lengths (0marks an unreported point).present: the boolean presence mask (aggregation .!= 0).
ComposableTuringIDModels.Ascertainment Type
Scale the expected observations of an underlying observation model by a latent ascertainment process.
A latent model generates a length-length(Y_t) series which is combined with the expected observations Y_t through transform before being passed to the inner observation model. The default transform applies a multiplicative effect on the exponential scale ((Y_t, x) -> xexpy.(Y_t, x)), so a latent value x multiplies the expected observation by exp(x). The latent model is wrapped in a PrefixLatentModel (with prefix latent_prefix) unless the prefix is the empty string.
Arguments
obs_model: theAscertainmentmodel.y_t: the observed series (ormissingwhen simulating predictively).Y_t: the expected-observation series.
Examples
using ComposableTuringIDModels, Distributions
obs = Ascertainment(PoissonError(), FixedIntercept(0.1))
mdl = as_turing_model(obs, missing, fill(10.0, 5))
rand(mdl)Fields
model: the underlying observation model the ascertained expected observations are passed to.latent_model: the latent model generating the ascertainment effect (prefix-wrapped unlesslatent_prefixis empty).transform: the function(Y_t, x)combining expected observations with the latent effect.latent_prefix: the prefix applied to the latent model's variables.
ComposableTuringIDModels.BinomialError Type
A binomial observation-error model: the observed successes are binomially distributed about a per-time-point number of trials N and a success probability supplied by the expected series.
Unlike the count error families (PoissonError, NegativeBinomialError) — whose expected series Y_t is an expected count — the expected series passed to BinomialError is the success probability
The number-of-trials N comes from the data
A binomial likelihood needs a number of trials per time point, N_t. N is known data (it is not inferred), so — like the observed successes — it is supplied through the observation data y_t, not stored on the model. The BinomialError struct carries no data.
The observation data is a NamedTuple with a y field (the observed successes) and an N field (the number of trials):
y_t = (y = observed_successes, N = trials)where N is a scalar Integer (the same trials at every time point) or an AbstractVector{<:Integer} (per-time-point trials). To simulate, pass y = missing while still supplying N, e.g. y_t = (y = missing, N = fill(20, n)).
This follows the same NamedTuple-data pattern as a Split stream: the shared define_y_t hook unpacks the y field that every error model scores, and BinomialError additionally reads the N field it needs.
Examples
using ComposableTuringIDModels
be = BinomialError()
# 20 trials per time point; the expected series is a success probability.
mdl = as_turing_model(be, (y = missing, N = fill(20, 10)), fill(0.3, 10))
rand(mdl)ComposableTuringIDModels.BroadcastLatentModel Type
Broadcast a shorter latent process to length n under a broadcast rule.
The inner model is generated over the length the rule requires (broadcast_n), then expanded to length n (broadcast_rule).
Arguments
model: theBroadcastLatentModel.n: the length of the broadcasted series to generate.
Examples
using ComposableTuringIDModels
each = BroadcastLatentModel(RandomWalk(), 7, RepeatEach())
rand(as_turing_model(each, 10))Fields
model: the underlying latent model.period: the broadcast period.broadcast_rule: theAbstractBroadcastRuleapplied.
ComposableTuringIDModels.BroadcastPrior Type
Default AbstractPriorModel wrapper: turn a plain Distribution (or a vector of Distributions) into a length-n prior submodel.
This is the drop-in replacement for a bare-Distribution prior field. It has two modes, dispatching on what it wraps:
A single
Distribution— repeat-one. One value is drawn and repeated to lengthn:as_turing_model(BroadcastPrior(d), n)samples a singleθ ~ dand returnsfill(θ, n). A single global coefficient stays a single random variable — it is not silently turned intoni.i.d. draws. For a genuinely scalar parameter usen == 1and read the element withonly(...), so the chain stays as small as a bare~ dist.A vector of
Distributions — one i.i.d. draw per element. The length is fixed by the vector (nmust match). A homogeneous vector usesfilldistand a heterogeneous onearraydist— reproducing the eager_expand_disthelper, but as a submodel. This is the explicit way to ask fornindependent draws.
Because BroadcastPrior is itself an AbstractPriorModel, anything richer a user writes (a partially-pooled prior, a time-varying prior wrapping a RandomWalk) drops into the same prior slot with no struct changes.
Fields
dist: aDistribution, or aVector{<:Distribution}.
Examples
using ComposableTuringIDModels, Distributions
# scalar parameter: length-1, read back with `only`
only(as_turing_model(BroadcastPrior(Normal()), 1)())ComposableTuringIDModels.CatalystODEParams Type
Declarative, model-agnostic ODE parameter component built from any Catalyst ReactionSystem, usable as the parameter component of an ODEProcess in place of the hand-coded SIRParams / SEIRParams.
You declare a reaction network and give priors for its initial conditions and rate parameters; Catalyst + ModelingToolkit generate the ODE system and a symbolic Jacobian (jac = true), so there is no hand-written vector field or Jacobian to keep in sync, and nothing here is specialised to a particular compartmental model. Construct it for an SIR network, an SEIR network, or any other network the same way — only the reactions change.
Sampling and problem rebuilding are symbolic: as_turing_model samples each supplied prior into a flat Turing variable named after its species / parameter symbol (e.g. β, S) and returns symbolic symbol => value maps, which remake places into the problem by name. There is no positional-index bookkeeping, so species / parameter ordering inside the compiled problem is never assumed. Index the resulting solution symbolically too, with the network's own handles: sol2infs = sol -> sol[rn.I, :].
Optional extension
The constructor and sampling logic load only when Catalyst and ModelingToolkit are present (using ComposableTuringIDModels, Catalyst, ModelingToolkit). The heavy symbolic stack stays out of the default install; the hand-coded models remain the zero-latency default. Constructing a CatalystODEParams before loading Catalyst raises an informative error.
Arguments
rn: theCatalystReactionSystem(e.g. from@reaction_network).
Keyword Arguments
tspan: the ODE solution time span.u0_priors: the initial conditions, as symbolic-handle ⇒ spec pairs ([rn.S => Beta(...), rn.R => 0.0, ...]). Each spec is either aDistribution(sampled, as a flat variable named after the species) or a plainReal(a fixed initial value, not sampled). Every species ofrnmust appear.p_priors: the rate parameters, as symbolic-handle ⇒ spec pairs ([rn.β => LogNormal(...), ...]), each aDistribution(sampled) or a fixedReal. Every parameter ofrnmust appear.
Fields
prob: theODEProblembuilt fromrn(auto symbolic Jacobian).u0_specs: per-species specs (symbolic handle, flat name, prior-or-fixed).p_specs: per-parameter specs (symbolic handle, flat name, prior-or-fixed).
Examples
using ComposableTuringIDModels, Catalyst, ModelingToolkit, OrdinaryDiffEq, Distributions
sir = @reaction_network begin
β, S + I --> 2I
γ, I --> R
end
params = CatalystODEParams(sir;
tspan = (0.0, 30.0),
u0_priors = [sir.S => Beta(99, 1), sir.I => Beta(1, 99), sir.R => 0.0],
p_priors = [sir.β => LogNormal(log(0.3), 0.1), sir.γ => LogNormal(log(0.1), 0.1)])
process = ODEProcess(params = params, sol2infs = sol -> sol[sir.I, :])ComposableTuringIDModels.CombineLatentModels Type
Combine several latent models of the same length by summing their outputs.
Each component is generated over the full length n and the results are added. When a non-empty prefix is supplied for a component it is wrapped in a PrefixLatentModel so its variables stay distinct.
Arguments
latent_models: theCombineLatentModelscollection.n: the length of the latent series to generate.
Examples
using ComposableTuringIDModels, Distributions
combined = CombineLatentModels([Intercept(Normal(2, 0.2)), AR()])
rand(as_turing_model(combined, 10))Fields
models: the vector of latent models (prefix-wrapped where a prefix is set).prefixes: the vector of prefixes, one per model.
ComposableTuringIDModels.ConcatLatentModels Type
Concatenate several latent models along time into one length-n series.
The length n is partitioned across the component models by dimension_adaptor (default equal_dimensions); each component generates its own segment and the segments are concatenated.
Arguments
latent_models: theConcatLatentModelscollection.n: the total length of the latent series to generate.
Examples
using ComposableTuringIDModels, Distributions
combined = ConcatLatentModels([Intercept(Normal(2, 0.2)), AR()])
rand(as_turing_model(combined, 10))Fields
models: the vector of latent models (prefix-wrapped where a prefix is set).no_models: the number of models in the collection.dimension_adaptor: maps(n, no_models)to a vector of segment lengths.prefixes: the vector of prefixes, one per model.
ComposableTuringIDModels.DiffLatentModel Type
Model a latent process as a d-fold differenced version of an inner process.
If model, then
and cumsum d times. The d initial terms are inferred from init_prior; d equals the length of init_priors.
Composing DiffLatentModel over an AR gives an ARIMA-style latent process.
Examples
using ComposableTuringIDModels, Distributions
diff = DiffLatentModel(; model = RandomWalk(), init_priors = [Normal(), Normal()])
mdl = as_turing_model(diff, 10)
rand(mdl)ComposableTuringIDModels.DirectInfections Type
Model unobserved infections as a direct transformation of an internally generated latent path.
where the latent model Z supplies transformation, and the unconstrained initial infections initialisation_prior. The latent process is generated inside the model rather than threaded in from outside, so as_turing_model takes only the series length n and returns the named tuple (; I_t, Z_t).
This model carries no generation interval — it never uses one — so it takes a transformation directly instead of an IDData object.
Fields
Z: the latent process model (anAbstractLatentModel) generating. transformation: the link mapping the unconstrained sum to non-negative infections (defaultexp).initialisation_prior: the prior for the unconstrained initial infections.
Examples
using ComposableTuringIDModels, Distributions
inf = DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal())
mdl = as_turing_model(inf, 10)
rand(mdl)ComposableTuringIDModels.DirectSample Type
Direct sampling from a model's prior (no MCMC).
apply_method(model, ::DirectSample) samples the prior: with an integer n_samples it draws that many times with Turing.Prior() (returning a chain), and with nothing it draws once with rand (returning a NamedTuple).
Fields
n_samples: number of prior draws, ornothingfor a singleranddraw.
ComposableTuringIDModels.ExpGrowthRate Type
Model unobserved infections via an internally generated time-varying exponential growth rate.
where the latent model rt supplies the (log) growth rates transformation, and the unconstrained initial infections initialisation_prior. The growth-rate process is generated inside the model, so as_turing_model takes only the series length n and returns the named tuple (; I_t, Z_t) with Z_t the growth-rate path.
This model carries no generation interval — it never uses one — so it takes a transformation directly instead of an IDData object.
Fields
rt: the latent process model (anAbstractLatentModel) generating the growth-rate path.transformation: the link mapping the unconstrained cumulative sum to non-negative infections (default: numerically equivalent toexp, implemented viaLogExpFunctions.xexpyfor numerical stability).initialisation_prior: prior for the unconstrained initial infections.
Examples
using ComposableTuringIDModels, Distributions
egr = ExpGrowthRate(; rt = RandomWalk(), initialisation_prior = Normal())
rand(as_turing_model(egr, 10))ComposableTuringIDModels.FixedIntercept Type
A fixed (non-sampled) intercept broadcast to a length-n latent process.
ComposableTuringIDModels.HalfNormal Type
A half-normal prior distribution parameterised by its mean μ.
so that
Examples
using ComposableTuringIDModels, Distributions
hn = HalfNormal(1.0)
nothing
# outputComposableTuringIDModels.HierarchicalNormal Type
A non-centred hierarchical normal latent process.
Fields
mean: the mean of the normal process.std_prior: the prior distribution for the standard deviation. add_mean: flag controlling whethermeanis added (false whenmean == 0).
Examples
using ComposableTuringIDModels, Distributions
hn = HierarchicalNormal()
mdl = as_turing_model(hn, 10)
rand(mdl)ComposableTuringIDModels.IDData Type
Epidemiological data shared by infection models: a discrete generation interval and a transformation linking the unconstrained and constrained domains.
Constructors
IDData(gen_int, transformation)— from a discrete generation interval vector (must be non-negative and sum to 1) and a transformation function.IDData(; gen_distribution, D_gen, Δd = 1.0, transformation = exp)— discretise a continuous generation-interval distribution via double-interval censoring (CensoredDistributions.jl).
Fields
gen_int: the discrete generation interval vector.len_gen_int: the length of the discrete generation interval.transformation: the transformation between unconstrained and constrained domains.
Examples
using ComposableTuringIDModels
data = IDData([0.2, 0.3, 0.5], exp)ComposableTuringIDModels.IDMethod Type
Combine a sequence of optimisation pre-steps with a sampler.
apply_method(model, ::IDMethod) runs each pre_sampler_steps entry in turn, threading the result into the next step and finally into the sampler (e.g. using a ManyPathfinder result to initialise a NUTSampler).
Fields
pre_sampler_steps: optimisation pre-steps (e.g. Pathfinder).sampler: the sampler run last (e.g. NUTS).
ComposableTuringIDModels.IDModel Type
A composed epidemiological model linking an infection process and an observation model.
The infection process owns its own latent (parameter) process internally — it is no longer a separate top-level component — so a composed model is just two parts: infections, then observations.
Sampling as_turing_model(model, y_t, n) runs the two stages as submodels:
The returned generated quantities are (; generated_y_t, expected_y_t, I_t, Z_t). generated_y_t is the observation model's sampled y_t (the observed-or-simulated series, or a NamedTuple of streams for a Split); expected_y_t is its pre-error expected series (the uniform observation return contract). Z_t is the infection model's internal latent draw (e.g. the (log) nothing for infection models with no exposable latent (e.g. ODEProcess). Pass y_t = missing to simulate from the prior, or a data vector to condition.
Fields
infection_model: the infection process model generating (and its internal latent ).observation_model: the observation model mapping to .
Examples
using ComposableTuringIDModels, Distributions
model = IDModel(
DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal()),
PoissonError())
mdl = as_turing_model(model, missing, 20)
rand(mdl)ComposableTuringIDModels.IDObservables Type
Container for the outputs of an inference run: the model, the data, the posterior samples, and any generated quantities.
Fields
model: the model that was sampled.data: the data the model was conditioned on.samples: the posterior samples (or optimiser result).generated: generated quantities, ormissingif not computed.
ComposableTuringIDModels.IDProblem Type
A full epidemiological inference problem: an infection process, an observation model, and a time span. The latent (parameter) process is owned by the infection model, so it is not a separate slot here.
as_turing_model(problem, data) assembles the corresponding IDModel over tspan and conditions it on data.y_t.
Arguments
idproblem: theIDProblem.data: a value with ay_tfield holding the observations (ormissing).
Examples
using ComposableTuringIDModels, Distributions
data = IDData([0.2, 0.3, 0.5], exp)
problem = IDProblem(
infection = DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal()),
observation_model = PoissonError(),
tspan = (1, 20))
rand(as_turing_model(problem, (; y_t = missing)))Fields
infection: the infection process model.observation_model: the observation model.tspan: the(first, last)time span of the series.
ComposableTuringIDModels.IID Type
Model a latent process ϵ_t.
Examples
using ComposableTuringIDModels, Distributions
model = IID(Normal(0, 1))
mdl = as_turing_model(model, 10)
rand(mdl)ComposableTuringIDModels.Intercept Type
Broadcast a single sampled intercept value to a length-n latent process.
The field intercept_prior sets the prior distribution the intercept is drawn from.
Examples
using ComposableTuringIDModels, Distributions
int = Intercept(Normal(0, 1))
mdl = as_turing_model(int, 10)
rand(mdl)ComposableTuringIDModels.LatentDelay Type
Apply a reporting delay to an underlying observation model.
The expected observations are convolved with the (reversed) delay PMF before being passed to the wrapped model. LatentDelay shortens the expected observation vector by the length of the delay PMF to avoid fitting to partially observed data.
Constructors
LatentDelay(model, pmf)— from a delay PMF (non-negative, sums to 1).LatentDelay(model, distribution; D, Δd)— discretise a continuous delay distribution via double-interval censoring (CensoredDistributions.jl).
Fields
model: the wrapped observation model the delayed expected observations are passed to.rev_pmf: the reversed delay PMF convolved with the expected observations.
Examples
using ComposableTuringIDModels, Distributions
obs = LatentDelay(NegativeBinomialError(), truncated(Normal(5.0, 2.0), 0.0, Inf))
mdl = as_turing_model(obs, missing, fill(10, 30))
mdl()ComposableTuringIDModels.MA Type
A moving-average MA(q) latent process.
with coefficients θ and innovations from the error model ϵ_t. The order q is the length of the coefficient prior.
Examples
using ComposableTuringIDModels, Distributions
ma = MA()
mdl = as_turing_model(ma, 10)
rand(mdl)ComposableTuringIDModels.ManyPathfinder Type
Variational pre-sampler that runs Pathfinder several times and keeps the best run.
Fields
ndraws: draws per Pathfinder run.nruns: number of Pathfinder runs.maxiters: optimiser iterations per run.max_tries: extra tries if all runs fail.
ComposableTuringIDModels.NUTSampler Type
NUTS sampling method for a DynamicPPL.Model.
Fields
target_acceptance: target acceptance rate.adtype: automatic-differentiation backend.mcmc_parallel: MCMC parallelisation strategy.nchains: number of chains.max_depth: NUTS tree-depth limit.Δ_max: divergence threshold.init_ϵ: initial step size (0.0lets NUTS find one).ndraws: total draws.metricT: HMC metric type.nadapts: adaptation steps (-1uses the Turing default).
ComposableTuringIDModels.NegativeBinomialError Type
A negative-binomial observation-error model with an inferred cluster factor.
The field cluster_factor_prior sets the prior distribution for the cluster factor that is sampled and used to parameterise the negative-binomial error.
Examples
using ComposableTuringIDModels, Distributions
nb = NegativeBinomialError()
mdl = as_turing_model(nb, missing, fill(10, 10))
rand(mdl)ComposableTuringIDModels.NegativeBinomialMeanClust Function
Construct a SafeNegativeBinomial from a mean μ and cluster factor α using the variance relationship
Arguments
μ: the mean of the distribution.α: the cluster factor relating mean and variance.
Examples
using ComposableTuringIDModels
NegativeBinomialMeanClust(10.0, 0.1)ComposableTuringIDModels.NormalError Type
A normal (Gaussian) observation-error model with an inferred standard deviation.
Unlike PoissonError and NegativeBinomialError, which model count observations, NormalError models continuous observations: each observed value is normally distributed about its expected value,
with the standard deviation std_prior. It is the minimal non-count observation error, useful for already-aggregated or transformed quantities (e.g. log-incidence, prevalence proportions, wastewater concentrations) where a Gaussian likelihood is appropriate.
The field std_prior sets the prior distribution for
Examples
using ComposableTuringIDModels, Distributions
ne = NormalError()
mdl = as_turing_model(ne, missing, fill(10.0, 10))
rand(mdl)ComposableTuringIDModels.Null Type
A null latent model that generates nothing (no latent variables).
Examples
using ComposableTuringIDModels
null = Null()
mdl = as_turing_model(null, 10)
isnothing(mdl())
# output
trueComposableTuringIDModels.ODEProcess Type
An infection process defined by solving an ODE.
ODEProcess combines a parameter struct (params, e.g. SIRParams or SEIRParams, whose as_turing_model samples (u0, p)) with a solver, extra solver_options, and a sol2infs link mapping the ODE solution to a latent-infection series. The compartmental dynamics are fully determined by the sampled ODE parameters, so the model carries no separate latent as_turing_model samples the parameters, solves the ODE, and returns (; I_t, Z_t) with Z_t = nothing (no exposable latent path).
Arguments
infection: theODEProcess.n: the requested series length; passed through to the parameter model (the ODE dimension is fixed, sonis otherwise unused —nothingis also accepted).
Examples
using ComposableTuringIDModels, OrdinaryDiffEq, Distributions, LogExpFunctions
sirparams = SIRParams(
tspan = (0.0, 100.0),
infectiousness = LogNormal(log(0.3), 0.05),
recovery_rate = LogNormal(log(0.1), 0.05),
initial_prop_infected = Beta(1, 99))
N = 1000.0
sir_process = ODEProcess(
params = sirparams,
sol2infs = sol -> softplus.(N .* sol[2, :]),
solver_options = Dict(:saveat => 1.0))
as_turing_model(sir_process, nothing)()Fields
params: the ODE parameter model (anAbstractLatentModel, e.g.SIRParams/SEIRParams, whoseas_turing_modelsamples(u0, p)).solver: the ODE solver (defaultAutoVern7(Rodas5P())).sol2infs: link mapping the ODE solution to an infection series.solver_options: extra options passed tosolve(aDictorNamedTuple).
ComposableTuringIDModels.PoissonError Type
A Poisson observation-error model.
Examples
using ComposableTuringIDModels
poi = PoissonError()
mdl = as_turing_model(poi, missing, fill(10, 10))
rand(mdl)
nothing
# outputComposableTuringIDModels.PrefixLatentModel Type
Wrap an inner latent model so its sampled variables are prefixed with prefix.
This replaces the original prefix_submodel helper: the inner model is prefixed with DynamicPPL.prefix before being sampled as a submodel, so its variables appear as prefix.varname.
Arguments
model: the inner latent model.n: the length of the latent series to generate.
Examples
using ComposableTuringIDModels
pm = PrefixLatentModel(; model = HierarchicalNormal(), prefix = "Test")
rand(as_turing_model(pm, 10))Fields
model: the latent model to prefix.prefix: the string prefix applied to the inner model's variables.
ComposableTuringIDModels.PrefixObservationModel Type
Wrap an inner observation model so its sampled variables are prefixed with prefix.
This replaces the original prefix_submodel helper for observation models: the inner model is prefixed with DynamicPPL.prefix before being sampled as a submodel, so its variables appear as prefix.varname.
Arguments
observation_model: thePrefixObservationModel.y_t: the observed series (ormissingwhen simulating predictively).Y_t: the expected-observation series.
Examples
using ComposableTuringIDModels
pm = PrefixObservationModel(; model = PoissonError(), prefix = "Test")
mdl = as_turing_model(pm, missing, fill(10.0, 5))
rand(mdl)Fields
model: the inner observation model to prefix.prefix: the string prefix applied to the inner model's variables.
ComposableTuringIDModels.R_to_r Function
Approximate the exponential growth rate r implied by a reproduction number R₀ and discrete generation interval w.
Solves r initial guess refined with newton_steps Newton iterations.
Arguments
R₀: the reproduction number.w: the discrete generation interval weights (or aRenewalmodel, whose generation interval is used).
Keyword Arguments
newton_steps: number of Newton refinement steps (default2).Δd: generation-interval discretisation width (default1.0).
Examples
using ComposableTuringIDModels
R_to_r(1.5, [0.2, 0.3, 0.5])ComposableTuringIDModels.RandomWalk Type
Model the latent process
where init_prior and the increments ϵ_t (a HierarchicalNormal by default, giving an inferred step standard deviation).
Examples
using ComposableTuringIDModels, Distributions
rw = RandomWalk()
mdl = as_turing_model(rw, 10)
rand(mdl)ComposableTuringIDModels.RecordExpectedLatent Type
Record the inner latent vector as a tracked generated quantity (exp_latent).
Arguments
model: the inner latent model whose output is recorded.n: the length of the latent series to generate.
Examples
using ComposableTuringIDModels
rm = RecordExpectedLatent(FixedIntercept(0.1))
rand(as_turing_model(rm, 1))Fields
model: the latent model whose expected latent vector is recorded.
ComposableTuringIDModels.RecordExpectedObs Type
Record the expected observations as a tracked generated quantity (exp_y_t).
The expected observations Y_t are tracked via the := syntax before the inner model is applied unchanged, so the expected observations are available in the returned chain alongside the inner model's variables.
Arguments
model: theRecordExpectedObsmodel.y_t: the observed series (ormissingwhen simulating predictively).Y_t: the expected-observation series.
Examples
using ComposableTuringIDModels
obs = RecordExpectedObs(PoissonError())
mdl = as_turing_model(obs, missing, fill(10.0, 5))
rand(mdl)Fields
model: the inner observation model whose expected observations are recorded.
ComposableTuringIDModels.Renewal Type
Model unobserved infections via a time-varying renewal process driven by an internally generated (log) reproduction number.
where the latent model rt supplies the (log) reproduction number data.transformation, as_turing_model takes only the series length n and returns the named tuple (; I_t, Z_t) with Z_t the (log)
Renewal is the one infection model that needs a generation interval, so it alone keeps an IDData object.
Fields
data: theIDDataobject (generation interval + transformation).rt: the latent process model (anAbstractLatentModel) generating the (log) reproduction number.initialisation_prior: prior for the unconstrained initial infections.recurrent_step: the renewal accumulation step (anAbstractConstantRenewalStep).
Examples
using ComposableTuringIDModels, Distributions
data = IDData([0.2, 0.3, 0.5], exp)
renewal = Renewal(data; rt = RandomWalk(), initialisation_prior = Normal())
rand(as_turing_model(renewal, 20))ComposableTuringIDModels.RepeatBlock Type
Broadcast rule that repeats the latent process in blocks of length period (e.g. a piecewise-constant weekly process).
Examples
using ComposableTuringIDModels
broadcast_rule(RepeatBlock(), [1, 2, 3, 4, 5], 10, 2)ComposableTuringIDModels.RepeatEach Type
Broadcast rule that repeats the latent process at each position within a period (e.g. a fixed day-of-week effect).
Examples
using ComposableTuringIDModels
broadcast_rule(RepeatEach(), [1, 2], 10, 2)ComposableTuringIDModels.ReportTriangle Type
A 2D reporting-triangle observation model (epinowcast-style nowcasting), the joint counterpart to the RightTruncate marginal.
ReportTriangle consumes the expected eventual totals Y_t = μ_t (per reference day, the same quantity the infection pipeline produces) together with a reporting-delay PMF p drawn from a submodel, expands them to per-cell expected means μ_{t,d} = μ_t · p[d + 1], and scores only the observed cells of a ReportingTriangle (t + d ≤ now) under a per-cell count error model. The not-yet-reported cells are never sampled. Because the model's Y_t stays the eventual total, the nowcast of the eventual total is just Y_t read out as a generated quantity (and the completed triangle is μ_{t,d} over all d).
The delay PMF is supplied as a composable submodel delay_model — mirroring how RightTruncate takes a ReportingCDF — sampled with to_submodel(..., false) inside the model. The default ReportingPMF wraps a fixed PMF (the fixed-delay, independent-cell variant: each observed cell is an independent Poisson / negative-binomial draw about its mean, via the per-cell AbstractObservationErrorModel supplied as error_model). Because the delay is a submodel, an estimated / time-varying delay — and the multinomial-split parameterisation — are the seams this grows from (a later phase of the nowcasting design).
The default PMF is built with the same released-CD double_interval_censored + pdf discretisation path that LatentDelay / IDData use, so the triangle's per-cell means and the right-truncation nowcast share one delay kernel.
Constructors
ReportTriangle(error_model, delay_model)— from a delay submodel producing the PMF (e.g. aReportingPMF);Dmaxis read from it.ReportTriangle(error_model, pmf::AbstractVector)— wrap a precomputed delay PMF (non-negative, sums to 1) in the defaultReportingPMF.ReportTriangle(error_model, distribution; D, Δd)— discretise a continuous reporting-delay distribution via double-interval censoring (CensoredDistributions.jl) into aReportingPMF, exactly asLatentDelay.
The y_t data contract
The observation data is a ReportingTriangle, built through the shared define_y_t hook from either a matrix or a long-form table:
y_t = define_y_t(obs, N, Y_t) # from a count matrix
y_t = define_y_t(obs, reports, Y_t; now = now) # from (reference, delay, count) rowsPass y_t = missing to simulate: ReportTriangle builds a fully observed triangle (now = n + Dmax) of missing cells and fills them predictively.
Fields
error_model: the per-cell count-error model (e.g.PoissonError,NegativeBinomialError).delay_model: the delay submodel producing the reporting-delay PMFp(delays0 … Dmax); cell(t, d)has expected meanY_t[t] · p[d + 1]. The defaultReportingPMFholds a fixed PMF.
Examples
using ComposableTuringIDModels, Distributions
obs = ReportTriangle(PoissonError(), truncated(Normal(2.0, 1.0), 0.0, Inf))
# Simulate a triangle for 15 reference days of expected total 50.
sim = as_turing_model(obs, missing, fill(50.0, 15))()
sim.observedComposableTuringIDModels.ReportingCDF Type
A composable reporting-completeness component: a Distribution (or a precomputed vector) turned into the cumulative reporting proportion by age, for use as the correction submodel of RightTruncate.
Given a series length n, sampling as_turing_model(c::ReportingCDF, n) returns a length-n vector F where F[a + 1] is the fraction of a reference day's eventual total reported within a days (a = 0, 1, …, n - 1), in [0, 1]. Reference days older than the reporting delay's support are fully reported (F = 1), so the vector is padded with ones to length n. The CDF built from a delay distribution is non-decreasing, but ReportingCDF does not require monotonicity — a precomputed curve may be non-monotonic, so an over-/under-reporting correction that recovers can be expressed.
It is the fixed-delay default used by RightTruncate: the completeness is precomputed once and held constant. Because the correction is supplied to RightTruncate as a submodel, a user can instead pass any latent component that produces a length-n completeness curve — a flexible non-parametric CDF, or even a non-monotonic correction — without changing RightTruncate.
Constructors
ReportingCDF(distribution; D, Δd)— discretise a continuous reporting-delay distribution via double-interval censoring (CensoredDistributions.jl) and take the cumulative sum of the resulting PMF, exactly the released-CD pathLatentDelay/IDDatause.ReportingCDF(cdf)— from a precomputed completeness vector by age (in[0, 1]; need not be monotonic).
Examples
using ComposableTuringIDModels, Distributions
c = ReportingCDF(truncated(Normal(5.0, 2.0), 0.0, Inf))
as_turing_model(c, 10)()Fields
cdf: the reporting-completeness curve by age (cdf[a + 1]), in[0, 1](need not be monotonic). Padded with ones up to the requested length when shorter.
ComposableTuringIDModels.ReportingPMF Type
A composable reporting-delay PMF component: a Distribution (or a precomputed vector) turned into the reporting-delay PMF p (delays 0 … Dmax), for use as the delay submodel of ReportTriangle.
Sampling as_turing_model(c::ReportingPMF, n) returns the length-(Dmax + 1) PMF (the argument n is the role-interface series length and is ignored — the PMF is indexed by delay, not reference day). The PMF is non-negative and sums to one; Dmax = length(pmf) - 1.
It is the fixed-delay default used by ReportTriangle: the PMF is precomputed once and held constant. Because the delay is supplied to ReportTriangle as a submodel — mirroring how RightTruncate takes a ReportingCDF — a user can instead pass any latent component producing the delay PMF, the seam an estimated / time-varying delay grows from.
Constructors
ReportingPMF(distribution; D, Δd)— discretise a continuous reporting-delay distribution via double-interval censoring (CensoredDistributions.jl), exactly the released-CD pathLatentDelay/IDDatause.ReportingPMF(pmf)— from a precomputed delay PMF (non-negative, sums to 1).
Examples
using ComposableTuringIDModels, Distributions
c = ReportingPMF(truncated(Normal(2.0, 1.0), 0.0, Inf))
as_turing_model(c, 10)()Fields
pmf: the reporting-delay PMFp(delays0 … Dmax, non-negative, sums to 1);Dmax = length(pmf) - 1.
ComposableTuringIDModels.ReportingTriangle Type
A reporting triangle: the reference-date × reporting-delay count matrix with the not-yet-reported cells masked off.
counts[t, d + 1] is the number of events with reference day t first reported at delay d = 0, 1, …, Dmax. A cell is observed at the present time now iff t + d ≤ now; the remaining lower-right cells have not yet been reported and are masked out by observed. This is the native object of epinowcast-style nowcasting: it keeps the full joint reference-day × delay structure rather than collapsing it to a per-reference-day observed-so-far total (the marginal that RightTruncate conditions on — see the consistency note below).
Build one with define_y_t from either a dense matrix or a long-form table of (reference, delay, count) rows; pass it as the y_t data to a ReportTriangle observation model.
Consistency with right-truncation (CDF-scaling)
Summing the observed cells of reference day t (delays d = 0 … now − t) gives Σ_d counts[t, d+1], the observed-so-far total — which in expectation is μ_t · F[(now − t) + 1], exactly the CDF-scaled expected observed-so-far that RightTruncate conditions on. So the observed row-sums of the triangle are the marginal of the joint model; the triangle additionally models how that total is split across delays.
Fields
counts: theN[t, d+1]count matrix (reference day × delay). Unobserved cells are ignored byReportTriangle; they may holdmissing,0, or any placeholder.observed: the boolean mask of reported cells (t + d ≤ now).Dmax: the maximum reporting delay (the number of delay columns isDmax + 1, delays0 … Dmax).
Examples
using ComposableTuringIDModels
# A 4 × 3 matrix (reference days 1..4, delays 0..2); now = 4.
N = [10 5 2; 12 6 3; 14 7 4; 16 8 5]
rt = define_y_t(ReportTriangle(PoissonError(), [0.5, 0.3, 0.2]), N, fill(20.0, 4))
rt.observedComposableTuringIDModels.RightTruncate Type
Correct an underlying observation model for right-truncation (not-yet-reported counts), the EpiNow2-style CDF-scaling nowcast.
The infection → expected-observation pipeline produces t. At the present time now (taken to be the last reference day, now = n) a reference day of age Y_t remains the eventual total (so the nowcast of the eventual total is just Y_t read out as a generated quantity).
The modifier mirrors Ascertainment: it wraps an inner observation model, draws a length-n correction series from a submodel, transforms the expected-observation vector, and delegates via to_submodel(..., false). The correction cdf_model is any component producing a length-n completeness curve F (by age). The default is a fixed ReportingCDF built from a reporting delay distribution (the released-CD case), but because the correction is a submodel a user can supply a flexible non-parametric CDF — or even a non-monotonic correction — without changing RightTruncate.
The completeness is indexed by age: the most recent reference day (t = n, age 0) is scaled by F[1] and the oldest (t = 1, age n - 1) by F[n], so the age-indexed series is reversed onto the reference-day axis. A fully-reported correction (all ones) leaves the inner model unchanged.
This is the fixed-delay variant. An estimated / time-varying delay (a latent correction with sampled parameters) is a planned follow-up, and is exactly the submodel slot generalising to it.
Constructors
RightTruncate(model, cdf_model)— from an inner observation model and a correction component (a latent-role submodel producing the length-ncompleteness curve, e.g. aReportingCDF).RightTruncate(model, distribution; D, Δd)— wrap a continuous reporting-delay distribution in the defaultReportingCDF(the released-CD path).RightTruncate(model, cdf::AbstractVector)— wrap a precomputed completeness vector in a fixedReportingCDF.
Arguments
obs_model: theRightTruncatemodel.y_t: the observed-so-far series (ormissingwhen simulating predictively).Y_t: the expected eventual-total series.
Examples
using ComposableTuringIDModels, Distributions
obs = RightTruncate(NegativeBinomialError(), truncated(Normal(5.0, 2.0), 0.0, Inf))
mdl = as_turing_model(obs, missing, fill(100.0, 30))
rand(mdl)Fields
model: the inner observation-error model the corrected expected observations are passed to.cdf_model: the correction submodel producing the length-nreporting completeness curve (by age).
ComposableTuringIDModels.SEIRParams Type
SEIR compartmental model parameters and priors, usable as the latent component of an ODEProcess.
The sampled initial infected proportion is split between the exposed and infectious compartments using the constant-incidence equilibrium proportions
Arguments
params: theSEIRParamsstruct.n: unused size argument; accepted for the commonas_turing_modelsignature.
Keyword Arguments
tspan: the ODE solution time span.infectiousness: prior for .incubation_rate: prior for .recovery_rate: prior for .initial_prop_infected: prior for the initial infected proportion.
Examples
using ComposableTuringIDModels, OrdinaryDiffEq, Distributions
seirparams = SEIRParams(
tspan = (0.0, 30.0),
infectiousness = LogNormal(log(0.3), 0.05),
incubation_rate = LogNormal(log(0.1), 0.05),
recovery_rate = LogNormal(log(0.1), 0.05),
initial_prop_infected = Beta(1, 99))
rand(as_turing_model(seirparams, nothing))Fields
prob: theODEProbleminstance for the SEIR model.infectiousness: prior for .incubation_rate: prior for .recovery_rate: prior for .initial_prop_infected: prior for the initial infected proportion.
ComposableTuringIDModels.SIRParams Type
SIR compartmental model parameters and priors, usable as the latent component of an ODEProcess.
Arguments
params: theSIRParamsstruct.n: unused size argument (the ODE dimension is fixed); accepted for the commonas_turing_modelsignature.
Keyword Arguments
tspan: the ODE solution time span.infectiousness: prior for .recovery_rate: prior for .initial_prop_infected: prior for the initial infected proportion.
Examples
using ComposableTuringIDModels, OrdinaryDiffEq, Distributions
sirparams = SIRParams(
tspan = (0.0, 30.0),
infectiousness = LogNormal(log(0.3), 0.05),
recovery_rate = LogNormal(log(0.1), 0.05),
initial_prop_infected = Beta(1, 99))
rand(as_turing_model(sirparams, nothing))Fields
prob: theODEProbleminstance for the SIR model.infectiousness: prior for .recovery_rate: prior for .initial_prop_infected: prior for the initial infected proportion.
ComposableTuringIDModels.SafeNegativeBinomial Type
A negative binomial distribution parameterised by (r, p) that avoids InexactError at very large means.
The package uses a mean/cluster-factor parameterisation when constructing this distribution from an expected count (see NegativeBinomialMeanClust).
Examples
using ComposableTuringIDModels, Distributions
bigμ = exp(48.0)
σ² = bigμ + 0.05 * bigμ^2
p = bigμ / σ²
r = bigμ * p / (1 - p)
d = SafeNegativeBinomial(r, p)
logpdf(d, 100)
nothing
# outputComposableTuringIDModels.SafePoisson Type
A Poisson distribution parameterised by its mean λ that avoids InexactError for very large means.
Examples
using ComposableTuringIDModels, Distributions
d = SafePoisson(exp(48.0))
logpdf(d, 100)
nothing
# outputComposableTuringIDModels.Split Type
Split one expected series into several named observation streams — the single observation-composition construct for parallel, cascade, and data-driven strata composition.
Each stream is a full AbstractObservationModel (a bare error family or a delay / ascertainment / truncation pipeline). Split feeds every stream the expected series arriving at the point where it sits in the pipeline and automatically prefixes each stream's sampled variables with its name (via DynamicPPL.prefix), so no manual prefix layer is needed. The uniform (; y_t, expected) return contract exposes each stream's pre-error expected series so streams can thread on one another.
Composition by placement
Split is itself an observation model consuming an expected series, so where it sits chooses the composition:
Parallel — placed high, on infections: every stream observes the same
(cases and deaths each a delayed, ascertained fraction of the same infections).IDModel(inf, Split((cases = …, deaths = …))).Cascade — placed low, inside a stream's pipeline: the shared upstream layers run first and
Splitbranches on their expected output, so a later stream is observed downstream of an earlier one. For deaths as a delayed fraction of the expected reported cases, share the case delay then split:LatentDelay(Split((cases = leaf, deaths = pipeline)), case_delay).Data-driven strata — built from a single template model: the number and names of streams come from the data at model-build time (one per entry of the
y_tNamedTuple), and aStrataMapmaps infection strata onto observation streams.
The threaded quantity is always a stream's expected (pre-error) series, never its realised noisy draw; observing a downstream stream off another's sampled counts is out of scope.
Data contract
y_t is a NamedTuple of observed series keyed by stream name (or missing to simulate). The return value is (; y_t, expected), each a NamedTuple of per-stream series. When Split is nested inside another modifier the incoming missing reaches it as a shared placeholder; the explicit stream names let it still fan out.
The incoming expected series may be a single vector (broadcast to every stream), a per-stream NamedTuple, an inf_strata × time matrix (one stream per row), or a StrataMap.
Constructors
Split(streams::NamedTuple)— explicit named streams.Split(template::AbstractObservationModel)— a data-driven strata split replicating the template once pery_tentry.Split(template::AbstractObservationModel, map::AbstractMatrix)— a strata split that projects the incoming expected series (aninf_strata × timematrix, or a single vector treated as one infection stratum) onto the observation streams through theobs_strata × inf_strataweightmap. This is the composed-model form of aStrataMap: the strata come from the infection process at run time, soIDModel(infection, Split(template, map))maps infections onto streams end-to-end.
Examples
using ComposableTuringIDModels, Distributions
# Parallel: cases and deaths, each a delayed fraction of the SAME infections.
parallel = Split((
cases = LatentDelay(NegativeBinomialError(), [0.4, 0.3, 0.2, 0.1]),
deaths = LatentDelay(NegativeBinomialError(), [0.1, 0.2, 0.3, 0.4])))
rand(as_turing_model(parallel, (cases = missing, deaths = missing), fill(100.0, 12)))
# Cascade: share the case delay, then split so deaths sit downstream of cases.
cascade = LatentDelay(
Split((
cases = PoissonError(),
deaths = LatentDelay(
Ascertainment(PoissonError(), FixedIntercept(log(0.1))),
[0.2, 0.3, 0.5]))),
[0.5, 0.3, 0.2])
rand(as_turing_model(cascade, (cases = missing, deaths = missing), fill(100.0, 12)))Fields
streams: a NamedTuple of per-stream models, or a single strata template.names: the stream names, ornothingin strata mode (names come from data).map: anobs_strata × inf_strataweight matrix projecting infection strata onto streams, ornothingwhen the incoming expected series is used directly.
ComposableTuringIDModels.StrataMap Type
A strata mapping supplied as the expected series to a Split: project a multi-stratum expected series onto observation streams through a (possibly weighted) linear map.
strata is an inf_strata × time matrix of per-infection-stratum expected series; map is an obs_strata × inf_strata weight matrix. Stream k receives map covers the one-to-one (map = I), many-to-one (an aggregation row), and many-to-many (a general weight matrix) infection→observation mappings. The stream count is size(map, 1), read from the data at model-build time.
Fields
strata: theinf_strata × timeexpected series (per infection stratum).map: theobs_strata × inf_strataweight matrix.
Examples
using ComposableTuringIDModels
M = [10.0 10.0 10.0 10.0 10.0; 4.0 4.0 4.0 4.0 4.0]
W = [1.0 0.0; 0.0 1.0; 1.0 1.0] # stratum 1, stratum 2, and their sum
sm = StrataMap(M, W)
size(sm.map, 1) # 3 observation streamsComposableTuringIDModels.TransformLatentModel Type
Apply a transformation function to the output of an inner latent model.
Arguments
model: the inner latent model whose output is transformed.n: the length of the latent series to generate.
Examples
using ComposableTuringIDModels, Distributions
trans = TransformLatentModel(Intercept(Normal(2, 0.2)), x -> exp.(x))
rand(as_turing_model(trans, 5))Fields
model: the latent model to transform.transform: the transformation function applied to the latent vector.
ComposableTuringIDModels.TransformObservationModel Type
Apply a transformation function to the expected observations before passing them to an inner observation model.
The expected observations Y_t are mapped through transform and the result is passed to the inner model. The default transform applies a softplus (x -> log1pexp.(x)), keeping the transformed expected observations positive.
Arguments
obs: theTransformObservationModel.y_t: the observed series (ormissingwhen simulating predictively).Y_t: the expected-observation series.
Examples
using ComposableTuringIDModels
obs = TransformObservationModel(PoissonError(), x -> x .* 2)
mdl = as_turing_model(obs, missing, fill(10.0, 5))
rand(mdl)Fields
model: the inner observation model the transformed expected observations are passed to.transform: the transformation applied to the expected observations.
ComposableTuringIDModels.accumulate_scan Function
Apply an AbstractAccumulationStep across an input sequence in a single pass.
This is an optimised accumulate-based replacement for an explicit for loop. acc_step is a callable step (state, ϵ) -> new_state, initial_state seeds the scan, and ϵ_t is the driving sequence. The returned value is assembled by get_state from the accumulated states.
Arguments
acc_step: anAbstractAccumulationStep, a callable(state, ϵ) -> new_stateapplied at each element of the sequence.initial_state: the seed state passed toaccumulateasinit.ϵ_t: the driving sequence accumulated over.
Examples
using ComposableTuringIDModels
accumulate_scan(ComposableTuringIDModels.RWStep(), 0.0, [1.0, 2.0, 3.0])ComposableTuringIDModels.apply_method Function
Condition a model by fixing some parameters and conditioning on others, then run an inference method.
Arguments
idproblem: theIDProblem(or aDynamicPPL.Model).method: the inference method (a sampler or anIDMethod).data: the data to condition on (with ay_tfield).
Keyword Arguments
fix_parameters: aNamedTupleof parameters to fix.condition_parameters: aNamedTupleof parameters to condition on.kwargs...: forwarded to the inference method.
Examples
using ComposableTuringIDModels, Distributions
problem = IDProblem(
infection = DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal()),
observation_model = PoissonError(),
tspan = (1, 20))
y = rand(as_turing_model(problem, (; y_t = missing)))
nothingComposableTuringIDModels.arima Function
Build an ARIMA(p, d, q) latent process: an arma wrapped in a d-fold DiffLatentModel.
Arguments
ar_init: prior(s) for the AR initial conditions.diff_init: prior(s) for the differencing initial conditions (setsd).damp: prior(s) for the AR damping coefficients.θ: prior(s) for the MA coefficients.ϵ_t: the innovation model (defaultHierarchicalNormal).
Examples
using ComposableTuringIDModels, Distributions
model = arima()
rand(as_turing_model(model, 10))ComposableTuringIDModels.arma Function
Build an ARMA(p, q) latent process: an AR whose innovation model is an MA.
Arguments
init: prior(s) for the AR initial conditions.damp: prior(s) for the AR damping coefficients.θ: prior(s) for the MA coefficients.ϵ_t: the innovation model (defaultHierarchicalNormal).
Examples
using ComposableTuringIDModels, Distributions
model = arma(; θ = [truncated(Normal(0.0, 0.02), -1, 1)],
damp = [truncated(Normal(0.0, 0.02), 0, 1)])
rand(as_turing_model(model, 10))ComposableTuringIDModels.as_prior Function
Coerce a user-supplied prior into an AbstractPriorModel.
This is the seam that keeps constructors ergonomic: a prior field is typed ::AbstractPriorModel and the constructor calls as_prior on whatever the user passed, so a bare Distribution (or a vector of them) is wrapped in a BroadcastPrior while a prior submodel — including any AbstractLatentModel, e.g. RandomWalk() for a time-varying parameter — is accepted unchanged.
Arguments
p: anAbstractPriorModel, aDistribution, or aVector{<:Distribution}.
Examples
using ComposableTuringIDModels, Distributions
as_prior(Normal()) # a BroadcastPrior
as_prior(RandomWalk()) # a latent model is already a prior modelComposableTuringIDModels.as_turing_model Function
Construct a DynamicPPL.Model from an ComposableTuringIDModels model component.
as_turing_model is the single generic entry point of the prototype. Every concrete model struct implements exactly one
@model function as_turing_model(m::MyModel, args...; kwargs...)
...
endmethod, and components are composed by sampling submodels of one another:
z ~ to_submodel(as_turing_model(inner_model, n), false)The trailing false to to_submodel disables automatic variable prefixing so that parameter names stay flat unless prefixing is explicitly requested.
The fallback method below errors with a clear message when a struct does not yet implement as_turing_model, which keeps the public surface honest while the prototype grows.
Arguments
model: anComposableTuringIDModelsmodel component (a subtype ofAbstractComposableModel).args...: positional arguments forwarded to the component's method, such as the series lengthn(latent models) or the expected/observed series (infection and observation models).kwargs...: keyword arguments forwarded to the component's method.
Examples
using ComposableTuringIDModels, Distributions
turing_model = as_turing_model(RandomWalk(), 10)
rand(turing_model)Generate observations from an observation-error model.
Supports missing observations (y_t === missing, simulating predictively) and expected-observation vectors Y_t shorter than y_t (the expected values are aligned to the last length(Y_t) entries). Expected values are nudged by a tiny constant to avoid degenerate error distributions.
The error family supplies generate_observation_error_priors (sampled as a submodel) and observation_error (the per-time-point distribution).
Returns the uniform (; y_t, expected) tuple: y_t is the observed (or simulated) counts and expected is the pre-error series. Exposing expected lets a Split thread one stream's expectation into another.
ComposableTuringIDModels.ascertainment_dayofweek Function
Build an Ascertainment model for a day-of-week reporting effect.
The latent model is wrapped with broadcast_dayofweek so a 7-day effect is broadcast across the expected-observation series, and combined multiplicatively with the expected observations by default.
Arguments
model: the underlying observation model.
Keyword Arguments
latent_model: the latent model broadcast over the week (defaultHierarchicalNormal()).transform: the function(x, y)combining expected observations with the broadcast effect (default(x, y) -> x .* y).latent_prefix: the prefix applied to the latent model's variables (default"DayofWeek").
Examples
using ComposableTuringIDModels
obs = ascertainment_dayofweek(PoissonError())
mdl = as_turing_model(obs, missing, fill(10.0, 14))
rand(mdl)ComposableTuringIDModels.broadcast_dayofweek Function
Build a BroadcastLatentModel for a day-of-week effect: a transformed inner model repeated across a 7-day period.
Arguments
model: the inner latent model.link: link applied before broadcasting (defaultx -> 7 * softmax(x), constraining the week effects to sum to 7).
Examples
using ComposableTuringIDModels
broadcast_dayofweek(RandomWalk())ComposableTuringIDModels.broadcast_n Function
Length of the inner series an AbstractBroadcastRule needs to produce a length-n broadcasted series. Each rule implements its own method.
Arguments
rule: theAbstractBroadcastRule.n: the length of the broadcasted output series.period: the broadcast period.
Examples
using ComposableTuringIDModels
broadcast_n(RepeatEach(), 10, 7), broadcast_n(RepeatBlock(), 10, 7)ComposableTuringIDModels.broadcast_rule Function
Expand an inner latent series to length n under an AbstractBroadcastRule. Each rule implements its own method.
Arguments
rule: theAbstractBroadcastRule.latent: the inner latent series to expand.n: the length of the broadcasted output series.period: the broadcast period.
Examples
using ComposableTuringIDModels
broadcast_rule(RepeatEach(), [1, 2], 5, 2)ComposableTuringIDModels.broadcast_weekly Function
Build a BroadcastLatentModel for a piecewise-constant weekly process.
Arguments
model: the inner latent model.
Examples
using ComposableTuringIDModels
broadcast_weekly(RandomWalk())ComposableTuringIDModels.condition_model Function
Condition a DynamicPPL.Model by fixing some parameters and conditioning on others.
condition_model(model, fix_parameters, condition_parameters)equals condition(fix(model, fix_parameters), condition_parameters). Either named tuple may be empty.
Arguments
model: theDynamicPPL.Modelto fix and condition.fix_parameters: a named tuple of parameters to fix to constant values.condition_parameters: a named tuple of parameters to condition on data.
Examples
using ComposableTuringIDModels, Distributions
m = as_turing_model(RandomWalk(), 10)
condition_model(m, (rw_init = 0.0,), NamedTuple())ComposableTuringIDModels.define_y_t Function
Unpack the observed count series an observation-error model scores from the data y_t, dispatching on the model type.
The default method covers every count family (Poisson, negative binomial) and the Gaussian family: it accepts a plain observation vector, a missing (replaced by a length-Y_t vector of missing for predictive simulation), or a NamedTuple carrying the counts in a y field alongside any extra per-time-point data (a model that needs more than the counts — e.g. BinomialError, which also needs the number of trials — reads those extra fields itself). This keeps the simple case ergonomic (a plain vector just works) while letting a model opt into a richer NamedTuple data contract.
Arguments
obs_model: the observation-error model.y_t: the observed data — a vector,missing, or aNamedTuple.Y_t: the expected-observation series (used to size amissingseries).
Examples
using ComposableTuringIDModels
# A plain vector passes through; a NamedTuple's `y` field is unpacked.
define_y_t(PoissonError(), [1, 2, 3], fill(10.0, 3)),
define_y_t(PoissonError(), (y = [1, 2, 3],), fill(10.0, 3))Build the ReportingTriangle data a ReportTriangle scores.
Dispatched on ReportTriangle as the triangle method of the shared define_y_t data-unpacking hook (the vector / NamedTuple methods serve the per-time-point error families). It accepts:
a
ReportingTriangle— returned unchanged (already built);a dense matrix
N[t, d+1]— the present time defaults tonow = size(N, 1)(the last reference day), masking cell(t, d)observed ifft + d ≤ now;a long-form table of
(reference, delay, count)rows (anyTables.jltable, e.g. aDataFrame) — accumulated into the matrix, withnowsupplied as a keyword;missing— a fully observed triangle ofmissingcells for predictive simulation (now = n + Dmax, so every delay of every reference day is reported).
Arguments
obs_model: theReportTrianglemodel (fixesDmax).y_t: the raw data — aReportingTriangle, a matrix, a long-form table, ormissing.Y_t: the expected eventual-total series (its lengthnsets the number of reference days when sizing amissingtriangle).
Keyword Arguments
now: the present time used for thet + d ≤ nowmask. Defaults to the number of reference days for a matrix, and is required for a long-form table.reference,delay,count: the column names in a long-form table (defaults:reference,:delay,:count).
Examples
using ComposableTuringIDModels
obs = ReportTriangle(PoissonError(), [0.5, 0.3, 0.2]) # Dmax = 2
N = [10 5 2; 12 6 3; 14 7 4] # 3 reference days
define_y_t(obs, N, fill(20.0, 3)).observedComposableTuringIDModels.equal_dimensions Function
Partition n elements into m segments of as-equal-as-possible length.
Each segment gets floor(n / m), and the n mod m leftover elements are handed out one apiece to the leading segments. The segment lengths therefore always sum to exactly n (differing by at most one), which is required by ConcatLatentModels's @assert sum(dims) == n check. This is the default dimension_adaptor for ConcatLatentModels.
Arguments
n: the total number of elements.m: the number of segments.
Examples
using ComposableTuringIDModels
ComposableTuringIDModels.equal_dimensions(10, 3)ComposableTuringIDModels.expected_Rt Function
Expected reproduction number IDData generation interval and an infection series.
Arguments
data: theIDDataholding the generation interval.infections: the infection series (longer than the generation interval).
Examples
using ComposableTuringIDModels
data = IDData([0.2, 0.3, 0.5], exp)
expected_Rt(data, [100.0, 200, 300, 400, 500])ComposableTuringIDModels.generate_observation_error_priors Function
Generate the priors required by an observation-error model. Returns a named tuple consumed by observation_error. The default is an empty tuple.
Arguments
obs_model: the observation-error model whose priors are generated.y_t: the observed series (ormissingwhen simulating predictively).Y_t: the expected-observation series.
Examples
using ComposableTuringIDModels
m = generate_observation_error_priors(NegativeBinomialError(), missing, fill(10.0, 5))
rand(m)ComposableTuringIDModels.generated_observables Function
Wrap a model, data, and inference solution into an IDObservables.
When solution is an MCMC Chains, the model is re-run over the draws with DynamicPPL.returned to recover the model's returned generated quantities (e.g. (; generated_y_t, expected_y_t, I_t, Z_t)) per sample, stored in the generated field. For any other solution (an optimiser result, a prior draw, …) there are no per-draw generated quantities, so generated is missing.
Arguments
model: the model that was sampled (a conditionedDynamicPPL.Model).data: the data the model was conditioned on.solution: the inference solution (samples or optimiser result).
Examples
using ComposableTuringIDModels, Distributions
m = as_turing_model(
IDModel(
DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal()),
PoissonError()), missing, 10)
generated_observables(m, (; y_t = missing), rand(m))ComposableTuringIDModels.get_param_array Function
Reshape an MCMCChains.Chains object into a (draws × chains) array of per-sample NamedTuples.
Arguments
chn: theChainsobject.
Examples
using ComposableTuringIDModels
nothingComposableTuringIDModels.get_state Function
Assemble the final sequence from the raw output of accumulate_scan.
The default method prepends initial_state to the last element of each accumulated state. Step structs whose state is a named tuple (e.g. the MA and LatentDelay steps) override this method to extract the relevant field.
Arguments
acc_step: theAbstractAccumulationStepused in the scan; the method dispatches on its concrete type.initial_state: the seed state used byaccumulate_scan.state: the raw accumulated output produced byaccumulate.
Examples
using ComposableTuringIDModels
accumulate_scan(ComposableTuringIDModels.RWStep(), 0.0, [1.0, 2.0, 3.0])ComposableTuringIDModels.implements_infection_interface Function
Check that model satisfies the AbstractInfectionModel interface: it is an infection model and as_turing_model(model, n) returns a DynamicPPL.Model.
The infection model owns its latent process internally, so the construction check passes only a series length n (no external latent path).
Arguments
model: the component to check.
Keyword Arguments
n: the infection series length used for the construction check (default10).
Examples
using ComposableTuringIDModels, Distributions
implements_infection_interface(
DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal()))ComposableTuringIDModels.implements_latent_interface Function
Check that model satisfies the AbstractLatentModel interface: it is a latent model and as_turing_model(model, n) returns a DynamicPPL.Model.
Arguments
model: the component to check.
Keyword Arguments
n: the latent series length used for the construction check (default10).
Examples
using ComposableTuringIDModels
implements_latent_interface(RandomWalk())ComposableTuringIDModels.implements_observation_interface Function
Check that model satisfies the AbstractObservationModel interface: it is an observation model and as_turing_model(model, y_t, Y_t) returns a DynamicPPL.Model.
Arguments
model: the component to check.
Keyword Arguments
y_t: the observed series for the construction check (defaultmissing, i.e. predictive simulation).Y_t: the expected-observation series (defaultfill(10.0, 10)).
Examples
using ComposableTuringIDModels
implements_observation_interface(PoissonError())ComposableTuringIDModels.implements_prior_interface Function
Check that model satisfies the AbstractPriorModel interface: it is a prior model and as_turing_model(model, n) returns a DynamicPPL.Model.
Every AbstractLatentModel is also an AbstractPriorModel, so this holds for latent models (a latent process used directly as a prior) as well as for the BroadcastPrior wrapper and any bespoke prior submodel.
Arguments
model: the component to check.
Keyword Arguments
n: the prior length used for the construction check (default10).
Examples
using ComposableTuringIDModels, Distributions
implements_prior_interface(BroadcastPrior(Normal()))ComposableTuringIDModels.manypathfinder Function
Run Pathfinder several times and return the run with the largest ELBO estimate.
Arguments
mdl: theDynamicPPL.Modelto fit.ndraws: draws per Pathfinder run.
Keyword Arguments
nruns: number of Pathfinder runs (default4).maxiters: optimiser iterations per run (default50).max_tries: extra tries if all runs fail (default100).kwargs...: forwarded topathfinder.
Examples
using ComposableTuringIDModels, Distributions
m = as_turing_model(
IDModel(
DirectInfections(; Z = RandomWalk(), initialisation_prior = Normal()),
PoissonError()), fill(10, 10), 10)
nothingComposableTuringIDModels.observation_error Function
The per-time-point observation-error distribution given an expected value and the sampled priors. Each error family implements its own method.
Arguments
obs_model: the observation-error model.Y_t: the expected observation at a single time point.additional positional arguments: any sampled priors produced by
generate_observation_error_priorsfor the family (e.g. the squared cluster factor forNegativeBinomialError).
Examples
using ComposableTuringIDModels
observation_error(PoissonError(), 10.0)ComposableTuringIDModels.r_to_R Function
Reproduction number implied by an exponential growth rate r and discrete generation interval w:
Arguments
r: the exponential growth rate.w: the discrete generation interval weights.
Examples
using ComposableTuringIDModels
r_to_R(0.1, [0.2, 0.3, 0.5])ComposableTuringIDModels.spread_draws Function
Convert an MCMCChains.Chains object to a tidy DataFrame (one row per draw, with draw, chain, and iteration columns).
Arguments
chn: theChainsobject to convert.
Examples
using ComposableTuringIDModels
nothing