ConfigurableEpi API¶
Reference for the exported API of ConfigurableEpi, generated from docstrings and grouped by layer.
ConfigurableEpi.ConfigurableEpi — Module.
Configurable compartmental forecasting on AlgebraicEpiMech Petri nets. Four layers:
config.jl: the TOML-backedRunConfigand the two inference axes (filter×hyper).model/: everything that defines a model — priors, latent processes, the state layout, vector fields, the observation model, seasonality, ascertainment, weekday effects, initialisation — grouped into anEpiModel.inference/: the three engines built bybuild_inferenceand driven byfit_forecast!: UKF + Optimise, PF + Liu-West, EnKF + EKP.output/: forecast rolls, quantiles, backtest tables, routine sample output and data linkage.
Configuration¶
ConfigurableEpi.DEFAULT_JITTER_FLOOR_FRACTION — Constant.
Minimum Liu-West jitter variance per parameter as a fraction of the prior's unconstrained variance, so a collapsed cloud can re-expand rather than freeze.
ConfigurableEpi.CountInput — Type.
The observation scale. counts are already on the model's count scale. percent observations are percentages of a denominator series (all visits, say) whose annual volume is annual_rate_per_100 per 100 population; the runner converts them to counts with the location's population and the observation interval.
ConfigurableEpi.Durations — Type.
Mean durations in days. Erlang stage rates are n_stages / mean. Because observation is attached to the infection event, the reporting delay is the observation chain alone: (n_obs_stages - 1) * obs_progression (the terminal stage is the reset accumulator).
EKP(; n_ensemble, iterations, burnin_iterations, reopt_interval = 1, inflation = 0.0,
window_length = nothing, warm_start = true, threads = false) # [hyper.ekp]
Outer ensemble Kalman inversion of the static parameters, each candidate scored by a complete inner filter replay. burnin_iterations at the first origin, iterations when warm-starting from the previous ensemble. threads parallelises candidate replays (not together with filter.enkf.threads).
Augmented ensemble Kalman filter. inflation >= 1 multiplies the ensemble spread after each propagation; threads parallelises member propagation.
ConfigurableEpi.LiuWest — Type.
LiuWest(; discount = 0.95, jitter_floor_fraction = DEFAULT_JITTER_FLOOR_FRACTION,
forgetting_memory_days = Dict(), replay_on_revision = true) # [hyper.liu_west]
Learn static hyperparameters online in the particle cloud by the Liu-West shrink-jitter kernel. forgetting_memory_days (parameter => days) adds Kulhavý forgetting toward the prior, merged over the model's own defaults. replay_on_revision tells a backtest runner whether to rebuild the filter when already-assimilated data are revised.
ConfigurableEpi.NoDayOfWeekConfig — Type.
NoDayOfWeekConfig() # [day_of_week.none]
PluginDayOfWeekConfig(; window_days = 182, exclude_recent_days = 14, fit_policy = "per_origin")
LearnedDayOfWeekConfig() # [day_of_week.learned]
Weekday observation effect for daily counts: none, multipliers and per-weekday extra dispersion estimated from history (fit_policy is per_origin or first_vintage), or six zero-sum Helmert coordinates learned by Liu-West.
ConfigurableEpi.Optimise — Type.
Optimise(; reopt_interval = 1, maxiters = 50, maxiters_burnin = 300, window_length = nothing,
warm_start = true) # [hyper.optimise]
Maximise the filter's marginal log-posterior over data replays every reopt_interval origins. maxiters_burnin caps every optimiser stage on the first (and any cold-started) optimisation, maxiters on warm-started ones. window_length scores only the most recent observations from a rolling filter checkpoint. warm_start = false restarts from the configured values each time.
Bootstrap particle filter. threads parallelises particle propagation; a seeded run reproduces exactly for a fixed thread count.
ConfigurableEpi.PriorSpec — Type.
One parameter's prior as written in TOML; constraint is positive, unit_interval or unconstrained. build_prior turns it into an EKP ParameterDistribution.
ConfigurableEpi.RunConfig — Type.
One run's TOML: the [io] block, the forecast horizon and draw count, the observation cadence (step_days, burnin_observations, drop_recent_observations), the [input.<name>] scale, the inference axes [filter.<name>] and [hyper.<name>], the [epi.<submodel>] block (kept opaque for the submodel to parse with its own @option type) and [priors] overriding the submodel's defaults per key. origin_mode is sequential, independent or forked (PF + Liu-West only).
Per-run I/O labels: the reporting-triangle data path, the model_id and forecast_df output labels, the run loc, and the ordered locations of a joint multi-location model.
ConfigurableEpi.SeasonalityConfig — Type.
Transmission seasonality: mode is indoor_activity (empirical location curve scaled by kappa ∈ [0, 1], the seasonally forced share of transmission), cosine (learned annual harmonic) or none. fallback (us, none, error) covers a location the climatology lacks.
Unscented Kalman filter. obs_jitter scales the accumulator process-noise whisker that keeps the smoother covariance full-rank.
ConfigurableEpi.build_priors — Method.
name => PriorSpec pairs to a name => ParameterDistribution NamedTuple.
ConfigurableEpi.load_prior_specs — Method.
Read a flat priors TOML (one [name] table per parameter).
ConfigurableEpi.option_alias — Method.
The TOML alias of an @option value, e.g. option_alias(UKF()) == "ukf".
ConfigurableEpi.prior_R_eff_bound — Method.
Conservative bound on R_eff = R0_baseline * Rt * chi * S/N from marginal prior quantiles (S/N <= 1; a missing prior contributes 1). Pass chi_max = seasonal_forcing_upper_bound(...).
ConfigurableEpi.prior_upper — Method.
Upper quantile of a prior on its constrained scale (moment-matched lognormal for positive).
ConfigurableEpi.resolve_prior_specs — Method.
resolve_prior_specs(cfg::RunConfig, default_priors) -> Dict{String, PriorSpec}
resolve_priors(cfg::RunConfig, default_priors) -> NamedTuple
The submodel's default_priors() with the run config's [priors] merged over them per key, as specs or as built distributions.
ConfigurableEpi.submodel_name — Method.
The single [epi.<name>] key.
ConfigurableEpi.validate_run_config — Method.
Check what the schema cannot: a positive whole number of step_days, the cadence counts, origin_mode, the input scale and both inference axes.
Model¶
ConfigurableEpi.ParameterPriorBundle — Type.
Ordered scalar priors combined into one EKP distribution. constrained_values, unconstrained_values and prior_logpdf map between the optimiser's unconstrained vector and constrained NamedTuples. NamedTuple keys must equal the prior names.
ConfigurableEpi.prior_name — Method.
Name of a scalar EKP prior. Errors on a combined (multi-name) distribution.
ConfigurableEpi.prior_unconstrained_mean — Method.
Mean and variance of a scalar prior in its unconstrained coordinate, the chart that learned hyperparameters and latent coefficients are stored in.
ConfigurableEpi.unconstrained_gaussian — Method.
unconstrained_gaussian(name, mean, sd)
positive_gaussian(name, mean, sd)
unit_interval_gaussian(name, mean, sd)
Scalar EKP constrained_gaussian priors on (-Inf, Inf), (0, Inf) and (0, 1).
ConfigurableEpi.StateLayout — Type.
Layout of the state vector [core compartments (N); observation states (M); latent coefficients (L)] observed through S signals. accumulator_indices are the absolute slots of the reset accumulators, one per signal.
StateLayout(core_names, obs_names, latent_names; signal_names = (:y,), accumulator_indices = nothing)
StateLayout(petri_net, driver_specs; signal_names = nothing)
Without accumulator_indices the observation states are split evenly over the signals and each signal's last state is its accumulator. The second form reads the observation chains of a net built with AlgebraicEpiMech.attach_observation; only drivers with carries_state claim latent slots.
ConfigurableEpi.extract_latent — Method.
The latent slots of state as a NamedTuple of unconstrained values.
ConfigurableEpi.AR1ParamSpec — Type.
Mean-reverting Ornstein–Uhlenbeck latent in the unconstrained chart of init (its initial prior, which also fixes the constraint): u' | u ~ Normal(m + rho (u - m), sigma^2 (1 - rho^2)) with rho = exp(-dt / tau). mu is the constrained stationary mean, tau the correlation time in days and sigma the stationary sd; each may be a Real, a ParameterDistribution (learned under its own name) or a ParamSpec.
ConfigurableEpi.ArrivalProcess — Type.
A marked point process on the compartments (particle filter only). On each stochastic step it fires with probability 1 - exp(-rate * dt), where rate is a constant or (x_model, latent, hyper, t) -> λ; on firing it draws mark(hyper, rng) -> NamedTuple and applies transition!(x_model, mark, hyper) in place. It carries no state: the compartments record that it fired, so a single-shot arrival is a rate that reads the compartment its own jump seeds.
ConfigurableEpi.FixedParam — Type.
How a process parameter is resolved from the merged (hyperparams, constrained latents) NamedTuple: a constant, a lookup under the prior's name, or formula(params).
ConfigurableEpi.IntegratedParamSpec — Type.
Noise-free latent whose unconstrained coordinate advances by rate_value * dt / per_days, where rate_value is the constrained value of the latent or hyperparameter named rate at the start of the step (explicit Euler). With a random-walk rate the pair is an integrated Brownian motion. A negative per_days integrates with the opposite sign.
ConfigurableEpi.RWParamSpec — Type.
Driftless random walk in the unconstrained chart; a step of dt days has sd sigma_rate * sqrt(dt).
ConfigurableEpi.StochasticUpdate — Type.
The model's per-step stochastic driver over L coefficient latents, from build_stochastic_update:
advance(x, hyper, w, rng, t, dt): the pre-flow state after advancing each coefficient from unit noisew[1:L]and firing each jump driver onrng(rng === nothingskips jumps).extract(x): the coefficients' constrained values as a NamedTuple.extract_params(x, hyper):merge(hyper, extract(x)).to_unconstrained(constrained::NamedTuple): the coefficients as an unconstrainedSVector{L}.
ConfigurableEpi.advance_arrival! — Method.
Fire one jump driver in place with probability step_arrival_probability(rate, dt).
ConfigurableEpi.assert_gaussian_filter_compatible — Method.
Throw if any driver is particle-only.
ConfigurableEpi.beta_mark — Method.
Mark sampler (hyper, rng) -> (; out_key => Beta(μν, (1 - μ)ν)) with mean μ = hyper[mean_key].
ConfigurableEpi.build_stochastic_update — Method.
Split driver_specs into state-carrying coefficient drivers (which must match layout.latent_names in order) and stateless jump drivers, and build the step driver. Jumps read the pre-step coefficients; the flow then runs on the advanced ones.
ConfigurableEpi.carries_state — Method.
Whether a driver claims latent slots in the StateLayout, and whether a Gaussian (UKF) filter can propagate it. Both hold for the coefficient processes and fail for ArrivalProcess, whose fired/not-fired mixture no single Gaussian represents.
ConfigurableEpi.ou_step — Method.
Exact one-step OU transition, rho = exp(-dt / tau) and sqrt(1 - rho^2), via expm1 so a very long tau does not cancel to zero.
ConfigurableEpi.pool_redistribute! — Method.
Pool the mass in sources, empty them, then add weights[k] * pool to targets[k] (weights should sum to 1). Sources and targets may overlap; the pool is read before anything is written.
ConfigurableEpi.pro_rata_move! — Method.
Move up to amount individuals out of sources[k] into targets[k], split pro rata by each source's occupancy and capped at what is available. sources and targets must be disjoint.
ConfigurableEpi.seed_transition — Method.
Move mark[size_key] individuals from compartment from into into, capped at what from holds.
ConfigurableEpi.step_arrival_probability — Method.
1 - exp(-rate * dt) for a constant hazard rate >= 0 over a step dt > 0.
ConfigurableEpi.update_single — Function.
Advance one latent's unconstrained coordinate over dt days given unit noise w. params merges the hyperparameters with every latent's constrained value at the start of the step; constraint is spec.init's pre-resolved ScalarConstraint.
ConfigurableEpi.build_R1 — Method.
Identity process-noise covariance sized n_latent + n_accumulators; every noise magnitude is applied inside build_full_dynamics.
ConfigurableEpi.build_full_dynamics — Method.
build_full_dynamics(petri_vf!, stochastic, layout; dt = 1.0, supersample = 2, obs_jitter = 1.0)
-> dynamics(x, u, p, t, w[, rng])
One filter step of the augmented state: apply the stochastic driver (coefficient noise from w[1:L], jumps on rng), zero the reset accumulators, integrate the flow over dt with supersample RK4 substeps, then add the accumulator whisker obs_jitter * w[L+1:end]. w has size(build_R1(layout), 1) entries.
ConfigurableEpi.build_petri_vf — Method.
In-place mass-action vector field of pn whose transition rates are merge(defaults, rates(latent, hyperparams, t)): defaults holds the fixed rates and the rate function returns only the dynamic ones, keyed by flattened transition name.
ConfigurableEpi.build_unified_vf — Method.
Out-of-place form of the Petri vector field for SeeToDee.Rk4, naming the ODE slots of x.
ConfigurableEpi.make_lvector_constructor — Method.
ConfigurableEpi.LogNormalNoise — Type.
Multiplicative noise y = μ exp(σ v).
ConfigurableEpi.NegBinomialNoise — Type.
Count noise with Var(y) = μ + μ²/φ + (σμ)². The UKF uses the Gaussian approximation with one unit-normal term; the particle filter uses the exact NegativeBinomial(φ, φ/(φ+μ)), which drops the (σμ)² reporting term. Each parameter is a Real or a function (latent, hyper, t) -> Real.
ConfigurableEpi.PoissonNoise — Type.
Poisson count noise y ≈ μ + sqrt(μ) v; with sigma_mult the mean is first perturbed by exp(σ v₁) (UKF only: the particle filter rejects the mixture).
ConfigurableEpi.SignalObservationSpec — Type.
SignalObservationSpec(signal_idx, noise; mean_modifier = nothing, baseline = nothing, name)
AggregatedSignalSpec(signal_indices, noise; mean_modifier = nothing, baseline = nothing, name)
AggregatedSignalSpec(noise; ...) # the sum of every signal
One observation: a signal's reset accumulator, or the sum over several. Its mean is raw * mean_modifier + baseline, where each of the two is nothing, a Real or a function (latent, hyper, t) -> Real (an AscertainmentPath, say).
ConfigurableEpi.apply_noise — Method.
Gaussian-approximation observation given unit noise v (the UKF measurement).
ConfigurableEpi.build_measurement_logpdf — Method.
Particle weighting: the summed exact observation_logpdf of y over the observation specs. learned (a LearnedHyperparams) lets each particle's own hyperparameters override p.
ConfigurableEpi.build_measurement_model — Method.
build_measurement_model(layout, obs_specs, stochastic) -> (; measure, n_obs, n_noise)
build_measurement_model(layout, noise::ObservationNoiseSpec, stochastic)
The UKF measurement measure(x, u, p, t, v) -> SVector{n_obs} with unit noise v of length n_noise (so R2 = I). The second form observes the single signal of a one-signal layout.
ConfigurableEpi.observation_gaussian_moments — Method.
Gaussian moments of a NegBinomial observation given Gaussian moments of its accumulator (the UKF forecast mapping): mean = observation_mean(max(raw_mean, 0)) and var = scale² raw_var + mean + mean²/φ + (σ mean)², with the spec's scale and noise at t.
ConfigurableEpi.observation_logpdf — Method.
observation_logpdf(noise, y, mean, latent, hyper, t)
sample_observation(noise, mean, latent, hyper, t, rng)
Exact log-density and draw of an observation (particle weighting and simulation).
ConfigurableEpi.observation_mean — Method.
observation_mean(spec, raw, latent, hyper, t) # raw * modifier + baseline
observation_scale(spec, latent, hyper, t) # the modifier at `t`
observation_baseline(spec, latent, hyper, t) # the baseline at `t`
Reporting code must map accumulators to counts through these, never through a hyperparameter read directly, so a time-varying or latent-driven ascertainment is honoured.
ConfigurableEpi.resolve_signal_indices — Method.
Check a spec's signal indices against the layout, expanding an all-signals aggregate.
ConfigurableEpi.N_SEASON_KNOTS — Constant.
Knots per indoor_activity climatology curve: one per week of the year.
ConfigurableEpi.UnitForcing — Type.
The three forcings: flat 1.0; the annual harmonic 1 + hyper.seasonal_amp * cos(2π (t + day0 - hyper.seasonal_phase) / 365.25) with day0 the day-of-year of t = 0; and 1 + hyper.seasonal_kappa * (σ(t) - 1) with σ a unit-mean periodic spline through a location's climatology and u0 the year fraction of t = 0.
ConfigurableEpi.assert_seasonal_learnable — Function.
Reject learning a seasonality parameter the active mode never reads (an unidentified dimension), and require a unit_interval prior when seasonal_kappa is learned.
ConfigurableEpi.build_periodic_curve — Method.
Unit-mean periodic cubic spline through knots, knot k at u = (k - 0.5) / N within the year. Periodicity comes from tiling five years and evaluating in the central one (the interpolant's own periodic extrapolation repeats with period (N-1)/N); the annual mean is normalised by the analytic integral.
ConfigurableEpi.build_seasonal_forcing — Method.
build_seasonal_forcing(cfg::SeasonalityConfig, location, start_date::Date; climatology = nothing)
build_seasonal_forcings(cfg, locations, start_date; climatology = nothing) -> Vector
The forcing selected by cfg, anchored so model time t = 0 is start_date. climatology (Dict(location => 52 knots)) is required by indoor_activity. The result type depends on the mode, so specialise the vector field on it through a where {F} function barrier.
ConfigurableEpi.default_seasonal_learned — Method.
Seasonality parameters learned by default: the cosine's amplitude and phase, nothing otherwise (kappa scales an externally estimated curve, so it is opt-in via learn_params).
ConfigurableEpi.load_indoor_activity_climatology — Method.
Read a location,knot,value table of 52-knot, unit-mean curves (lowercase location keys, us included). The package ships no data; the caller owns this file.
ConfigurableEpi.seasonal_forcing_upper_bound — Function.
seasonal_forcing_upper_bound(cfg, fixed_amp, prior_specs, learn_params = ();
probability = 0.95, climatology = nothing) -> Float64
Mode-aware upper bound on the seasonal multiplier for the RK4 stability guard: 1 for none, 1 + |amplitude| for cosine (from the prior when learned), and the largest curve value in climatology scaled by the fixed or learned kappa for indoor_activity. An empty learn_params means the mode's default learned set.
ConfigurableEpi.validate_indoor_activity_climatology — Method.
Check that every (lowercase) location carries N_SEASON_KNOTS finite, positive knots with mean 1.
ConfigurableEpi.validate_seasonality — Method.
Check the mode, the fallback and kappa ∈ [0, 1] (the seasonally forced share of transmission).
ConfigurableEpi.year_fraction — Method.
Position of d within its year in [0, 1), leap-aware.
ConfigurableEpi.ASCERTAINMENT_TREND_LEVEL — Constant.
Latent name of the ascertainment level (observations per infection now); positive, stored as log alpha.
ConfigurableEpi.ASCERTAINMENT_TREND_LEVEL_LOG_SD — Constant.
Initial spread of the level in log units (pinned: the level is not identifiable alongside transmission).
ConfigurableEpi.ASCERTAINMENT_TREND_RATE — Constant.
Latent name of the decline rate per year; the same name (and prior) as the declining path's hyperparameter.
ConfigurableEpi.ASCERTAINMENT_TREND_WANDER — Constant.
Hyperparameter name of the trend's bend scale; see DEFAULT_ASCERTAINMENT_TREND_WANDER.
ConfigurableEpi.DEFAULT_ASCERTAINMENT_TREND_WANDER — Constant.
The 1-sd departure of log-ascertainment from a straight line after one year, in log units: too stiff to mimic a wave, loose enough for the rate to re-diversify over a season.
ConfigurableEpi.DEFAULT_ASCERTAINMENT_TREND_WANDER_MEMORY_DAYS — Constant.
Memory (days) of the Kulhavý forgetting applied to a learned wander: a season and a half.
ConfigurableEpi.AscertainmentPath — Type.
AscertainmentPath(floor_fraction, t_ref_days, rate_bound = Inf)
AscertainmentPath(; floor_fraction, reference_date::Date, start_date::Date, rate_bound = Inf)
Callable (hyper, t) and (latent, hyper, t) giving observations per infection at model time t,
with level = hyper.ascertainment and rate = clamp(hyper.ascertainment_decline_rate, ±rate_bound) read on every call, so a learned rate reaches each particle or optimiser candidate. A zero rate returns level bit-for-bit. Use it as an observation spec's mean_modifier and as t -> path(hyper, t) in the initial-state inversion.
ConfigurableEpi.TrendAscertainment — Type.
The trend model's observation mean_modifier: (latent, hyper, t) -> latent.ascertainment_level.
ConfigurableEpi.TrendAscertainmentSeed — Type.
t -> level0 * exp(-decline_rate * t / 365.25) for the initial-state inversion, which evaluates ascertainment at and before t = 0.
ConfigurableEpi.ascertainment_at — Method.
The path's kernel, level * (1 + (1 - floor_fraction) * expm1(-rate * days_since_ref / 365.25)).
ConfigurableEpi.ascertainment_trend_sigma_rate — Method.
The rate's random-walk diffusion per sqrt-day that makes the level's one-year departure from a straight line equal wander: wander * sqrt(3 / 365.25).
ConfigurableEpi.ascertainment_trend_specs — Method.
The trend model's two drivers: the decline rate as a random walk whose diffusion derives from the ascertainment_trend_wander hyperparameter, and the level as the noise-free integral of -rate per year. rate_prior must be named ascertainment_decline_rate.
ConfigurableEpi.assert_ascertainment_learnable — Method.
Refuse to learn the decline rate when ascertainment_floor_fraction == 1, where the path never reads it.
ConfigurableEpi.build_ascertainment_path — Method.
Anchor a submodel's ascertainment block so model time t = 0 is start_date.
ConfigurableEpi.parse_ascertainment_reference_date — Method.
Parse the ISO YYYY-MM-DD reference date carried as a string in the epi config.
ConfigurableEpi.validate_ascertainment — Method.
Check the ascertainment, ascertainment_decline_rate, ascertainment_floor_fraction, ascertainment_rate_bound and ascertainment_reference_date fields of a submodel's fixed config.
ConfigurableEpi.DayOfWeekModifier — Type.
An observation mean_modifier equal to inner(hyper, t) * w_{d(t)}, callable as (hyper, t) and (latent, hyper, t). weights::NTuple{7} is the plugin effect; weights = nothing reads the learned multipliers from hyper.dow_z1 … dow_z6.
ConfigurableEpi.HyperPhi — Type.
HyperPhi() # (latent, hyper, t) -> hyper.phi
DayOfWeekDispersion(dow0, extra_var) # (latent, hyper, t) -> 1 / (1/hyper.phi + extra_var[d(t)])
The negative-binomial dispersion without and with the plugin's per-weekday widening.
ConfigurableEpi.assert_day_of_week_learnable — Method.
The weekday coordinates in an explicit learned set must be exactly day_of_week_learned_names(cfg).
ConfigurableEpi.build_day_of_week_observation — Method.
build_day_of_week_observation(cfg, inner, start_date, history; phi, precomputed = nothing)
-> (; modifier, dispersion, effects, derived_hyperparameters)
The observation pieces for weekday effect cfg: the mean_modifier (inner itself under NoDayOfWeekConfig), the NB dispersion function, the plugin's history estimates to report, and the learned multipliers to summarise. history is (; times, counts) on the model clock; precomputed reuses a first-vintage plugin estimate.
ConfigurableEpi.day_of_week_learned_names — Method.
The θ names this effect adds to the learned set: the six Helmert coordinates under learned.
ConfigurableEpi.day_of_week_multipliers — Method.
The learned weekday multipliers Monday … Sunday, 7 * softmax(H z) (shifted by the maximum so a large coordinate cannot overflow).
ConfigurableEpi.day_of_week_report_rows — Method.
Summary rows for the plugin's estimates: dow_multiplier_<day> and dow_extra_var_<day>.
ConfigurableEpi.day_of_week_weight — Method.
The weekday factor alone at observation time t; true for a modifier without one.
ConfigurableEpi.dow_helmert_prior_sd — Method.
Prior sd of each Helmert coordinate that gives every centred weekday log-effect marginal sd sd.
<a id='ConfigurableEpi.estimate_day_of_week_effects-Tuple{AbstractVector{Dates.Date}, AbstractVector{<:Real}}'>
<a id='ConfigurableEpi.estimate_day_of_week_effects-Tuple{AbstractVector{Dates.Date}, AbstractVector{<:Real}}-1'>
ConfigurableEpi.estimate_day_of_week_effects — Method.
estimate_day_of_week_effects(dates, counts; phi, window_days = 182, exclude_recent_days = 14,
min_weeks = 4) -> (; weights, extra_var, fallback, n_used)
Multiplicative weekday decomposition of a gap-free daily series against a leave-one-out centred weekly baseline: weights w_d = 7 q_d / (6 + q_d) from the ratio of sums q_d = Σy / Σb, normalised to mean 1, and per-weekday extra variance s_d² after removing the Poisson/NB sampling variance of the counts and of the baseline. Falls back to no effect (with a warning) when any weekday has fewer than min_weeks usable days.
<a id='ConfigurableEpi.prepare_day_of_week_history-Tuple{AbstractVector{Dates.Date}, AbstractVector{<:Real}, Dates.Date}'>
<a id='ConfigurableEpi.prepare_day_of_week_history-Tuple{AbstractVector{Dates.Date}, AbstractVector{<:Real}, Dates.Date}-1'>
ConfigurableEpi.prepare_day_of_week_history — Method.
Check one daily as-of series ends on report_date - 1 and is gap-free, and drop its final observation (the model's history contract).
ConfigurableEpi.remove_day_of_week_effect — Method.
Divide each historical count by the weekday weight of its own observation date so the initial-state reconstruction inverts with ascertainment alone.
ConfigurableEpi.validate_day_of_week — Method.
The plugin window must hold at least five weeks; other modes have nothing to check.
ConfigurableEpi.RK4_STABILITY_LIMIT — Constant.
Classical RK4 is stable on a real negative eigenvalue only while |lambda * h| < 2.785.
ConfigurableEpi.RK4_WARN_LAMBDA_H — Constant.
Proximity warning threshold, about 1.4x below the stability limit.
ConfigurableEpi.anchor_is_exact — Method.
Whether R_eff = 1 holds exactly at the peak of E + I: only for a single I stage.
ConfigurableEpi.assert_integration_stable — Method.
Error beyond RK4_STABILITY_LIMIT and warn beyond RK4_WARN_LAMBDA_H. Size R_eff_max from the priors' upper tail (prior_R_eff_bound), not the endemic seed.
<a id='ConfigurableEpi.carry_susceptible-Tuple{Real, Real, Real, AbstractVector{<:Real}, AbstractVector{<:Real}, Real}'>
<a id='ConfigurableEpi.carry_susceptible-Tuple{Real, Real, Real, AbstractVector{<:Real}, AbstractVector{<:Real}, Real}-1'>
ConfigurableEpi.carry_susceptible — Method.
Integrate ds/dt = omega (1 - s) - i(t) from the anchor to the target time (midpoint RK2, steps of at most one day), holding the per-capita incidence flat outside its range.
<a id='ConfigurableEpi.find_observed_peak-Tuple{AbstractVector{<:Real}}'>
<a id='ConfigurableEpi.find_observed_peak-Tuple{AbstractVector{<:Real}}-1'>
ConfigurableEpi.find_observed_peak — Method.
Index of the observed wave peak: an interior, strict maximum of the log-smoothed series at least min_prominence above the higher flank. nothing when the history contains no identified peak.
ConfigurableEpi.initial_infection_state — Method.
initial_infection_state(y0, dur::Durations, ascertainment, accumulation_window_days)
-> (; daily_incidence, exposed, infectious, obs_stage)
Invert one partially ascertained count into quasi-steady compartment occupancies: daily_incidence = y0 / (ascertainment * accumulation_window_days) and each upstream compartment holds daily_incidence * mean_duration.
ConfigurableEpi.max_transition_rate — Method.
The fastest model rate in 1/day: the Erlang stage rates, observation progression, waning, and the faster eigenvalue of the linearised (E, I) block at R_eff_max.
ConfigurableEpi.peak_anchored_susceptible_fraction — Method.
peak_anchored_susceptible_fraction(history, dur, n_obs_stages, ascertainment, pop, dt, chi_at, R0;
n_E = 1, n_I = 1) -> Union{NamedTuple, Nothing}
Find the observed peak in history = (; times, counts) (model clock, bin-end labels), shift it back by half a bin and the reporting delay and forward by the prevalence lag, evaluate S/N = 1 / (R0 * chi_at(t_anchor)) there (R_eff = 1 at the prevalence peak, Rt = 1 by construction), and carry S/N back to t = 0 against the reconstructed incidence. ascertainment is a constant or t -> observations per infection. Returns nothing when no peak is identified or the anchor is inexact (n_I > 1).
ConfigurableEpi.prevalence_peak_lag_days — Function.
How long after the incidence peak total infected prevalence peaks: the normalised mean E[T²] / (2 E[T]) of the Erlang residence kernel.
ConfigurableEpi.reporting_delay_days — Method.
Mean infection-to-report delay, (n_obs_stages - 1) * obs_progression.
ConfigurableEpi.required_supersample — Method.
The smallest supersample whose substep keeps |lambda * h| <= target.
ConfigurableEpi.contact_matrix — Method.
(1 - a_com) I + a_com M: within-location contact at a_com = 0, the radiation matrix at 1.
ConfigurableEpi.load_radiation_matrix — Method.
Row-normalised contact matrix for locations (in order) from an origin,destination,flow table. Errors when a location is absent, has a self-flow, or retains no flow to the others.
ConfigurableEpi.EpiModel — Type.
EpiModel(; vectorfield!, layout, stochastic, observation, hyperparams, priors, initial_state,
initial_latent_variance = (;), initial_learned_variance = (;),
initial_accumulator_variance = (;), forgetting_memory_days = (;),
derived_hyperparameters = nothing)
Everything build_inference needs to fit and forecast one model:
vectorfield!: the Petri vector field frombuild_petri_vf.layout,stochastic: theStateLayoutandStochasticUpdate.observation: a tuple of observation specs.hyperparams: every hyperparameter the rates, drivers and observation read, including the starting value of each learned one.priors:name => ParameterDistributionfor the hyperparameters to learn (a subset ofhyperparams, at least one).initial_state: the model-state vector att = 0, or a functionhyperparams -> vectorwhen the seed depends on the parameters (an equilibriumS(0) = N / R0, say).initial_*_variance: by-name overrides of the initial variance of latent coefficient slots, learned slots (PF) and reset accumulators (EnKF), in unconstrained space.forgetting_memory_days: the model's default Liu-West forgetting memories (parameter => days), overridden per key byLiuWest.forgetting_memory_days.derived_hyperparameters: optionalhyper -> NamedTuplesummarised alongside the learned parameters by the particle filter.
ConfigurableEpi.initial_state — Function.
The model-state vector at t = 0 under hyperparams.
ConfigurableEpi.learned_names — Method.
The names of the learned hyperparameters.
Inference¶
ConfigurableEpi.DEFAULT_LATENT_VARIANCE — Constant.
Default initial variance of a latent coefficient slot (unconstrained space): in a log chart, sd 0.45.
ConfigurableEpi.DEFAULT_MODEL_RELATIVE_SD — Constant.
Initial sd of each compartment as a fraction of its own initial value.
ConfigurableEpi.EngineSettings — Type.
The run-level numbers every engine shares: the observation interval in days, RK4 substeps per interval, forecast horizon and forecast draw count.
ConfigurableEpi.build_inference — Method.
build_inference(filter, hyper, model::EpiModel; dt, supersample = 2, n_ahead, n_draws = 2000,
rng = Random.default_rng(), kwargs...) -> InferenceEngine
build_inference(cfg::RunConfig, model::EpiModel; rng = Random.default_rng())
Build the inference engine for a (filter, hyper) pairing: UKF + Optimise, PF + LiuWest or EnKF + EKP. Drive it with fit_forecast!. The RunConfig form reads dt, supersample, n_ahead and n_draws from the run config.
ConfigurableEpi.fit_forecast! — Function.
fit_forecast!(engine, observations, forecast_number; update_range = eachindex(observations),
emit_forecast = true) -> (; quantiles, fitted_means, summary, samples)
Assimilate observations, one entry per slot of the regular dt grid (a number or a vector, or missing where there is no observation: the filter then predicts through the slot without correcting), and forecast n_ahead steps ahead. forecast_number counts fitted origins and drives the re-optimisation cadence. The replay engines (UKF, EnKF) require the complete update_range; the online PF engine keeps its cloud between calls and update_range must start at the slot after the last one it assimilated (the default), so a replay is reset!(engine.filter) followed by the full range. fitted_means covers update_range (a nowcast at a missing slot). quantiles is [horizon, quantile] ([horizon, observation, quantile] for a multi-signal EnKF) and samples the predictive draws behind it (nothing for the analytic UKF); both are nothing when emit_forecast = false. summary is a (parameter, statistic, value) table of estimates and diagnostics.
ConfigurableEpi.marginal_loglik — Method.
Filter marginal log-likelihood of the observation vectors ys under hyperparameters p after reset!, accumulated at the promoted element type so it differentiates (forward_trajectory(...).ll sizes its buffers as Float64). A missing entry is a grid slot without an observation: the filter predicts through it without correcting.
ConfigurableEpi.positive_cholesky! — Method.
Positive-definite Cholesky via PositiveFactorizations.ldlt!, which unlike its cholesky! wrapper accepts ForwardDiff.Dual matrices.
ConfigurableEpi.build_inference — Method.
build_inference(filter::UKF, hyper::Optimise, model; dt, supersample = 2, n_ahead, n_draws = 2000,
rng = nothing, optimiser = DEFAULT_OPTIMISER_STAGES, adtype = AutoForwardDiff())
optimiser is a single optimiser, a tuple of them, or (optimiser, options) pairs; rng is unused.
ConfigurableEpi.PFLiuWestEngine — Type.
PF + Liu-West: one persistent particle cloud carrying the learned hyperparameters in its tail, assimilating only the observations it has not yet seen.
ConfigurableEpi.build_pf_dynamics — Method.
build_pf_dynamics(dynamics, layout; rng = Random.default_rng(), learned = nothing, threads = false)
-> pf_dynamics(x, u, p, t, noise = false)
Adapt the augmented dynamics from build_full_dynamics to the AdvancedParticleFilter convention: noise = true draws the process noise (and fires the jump drivers) from rng, or from a per-thread pool when threads = true, so a seeded run reproduces for a fixed thread count. With learned each particle's tail overrides p and is carried forward unchanged.
ConfigurableEpi.build_pf_measurement — Method.
build_pf_measurement(layout, obs_specs, stochastic; rng = Random.default_rng(), learned = nothing)
-> pf_measure(x, u, p, t, noise = false)
The particle filter's measurement: the observation means (floored at 1e-6), or with noise = true a draw from the exact observation distribution via sample_observation.
ConfigurableEpi.EnKFEKPEngine — Type.
EnKF + EKP: replays the complete series each origin and recalibrates every reopt_interval origins, warm-starting from the previous outer ensemble.
ConfigurableEpi.LearnedHyperparams — Type.
A block of H hyperparameters carried per particle in the tail after the model state (offset == layout.total_dim). extract(x) reads them constrained as a NamedTuple; to_unconstrained(nt) maps a constrained NamedTuple to the tail's SVector{H}.
ConfigurableEpi.build_hyperparam_updater — Method.
build_hyperparam_updater(learned; discount = 0.95, jitter_floor_fraction = DEFAULT_JITTER_FLOOR_FRACTION,
forgetting_memory_days = (;), rng = Random.default_rng(), dt = 1.0) -> update!
update!(particles, weights) refreshes every particle's learned slots in place by the Liu-West kernel θᵢ ← a θᵢ + (1 - a) θ̄ + ε, ε ~ N(0, (1 - a²) V) with a = (3δ - 1) / 2δ and θ̄, V the weighted cloud moments, which preserves the weighted mean and variance. The jitter variance is floored at jitter_floor_fraction of each prior's variance so a collapsed cloud can re-expand. Parameters named in forgetting_memory_days are additionally pulled toward their prior by Kulhavý forgetting with λ = exp(-dt / memory): the marginal N(m, v) becomes the geometric mean of itself and the prior. Call between correct! and predict! on state(pf).xprev with expweights(pf).
ConfigurableEpi.build_learned_hyperparams — Method.
priors is a NamedTuple (keys equal to the prior names), a tuple of priors, or one prior.
ConfigurableEpi.DEFAULT_OPTIMISER_STAGES — Constant.
Adam first (its step is bounded by the learning rate however badly the filter log-posterior is scaled), then LBFGS to polish; each stage is remaked from the previous solution.
ConfigurableEpi.optimiser_stages — Method.
Normalise a single optimiser, a tuple of optimisers, or a tuple of (optimiser, options) pairs.
ConfigurableEpi.optimize_hyperparams — Method.
optimize_hyperparams(neg_logposterior, initial::NamedTuple, bundle::ParameterPriorBundle;
stages = DEFAULT_OPTIMISER_STAGES, adtype = AutoForwardDiff(), options = (;))
-> (; θ, ll, retcode, unconstrained)
Minimise neg_logposterior(u, _) over the bundle's unconstrained coordinates from the constrained initial values. options (such as maxiters) are merged over each stage's own; a stage whose result is non-finite or worse than the incumbent is discarded.
ConfigurableEpi.AugmentedEnsembleKalmanFilter — Type.
AugmentedEnsembleKalmanFilter(dynamics, measurement, R1, R2, d0, N; nu, ny = size(R2, 1),
p = nothing, Ts = 1.0, inflation = 1.0, rng = Xoshiro(),
threads = false, names = nothing)
Ensemble Kalman filter with N members drawn from d0, process noise w ~ N(0, R1) applied inside dynamics and measurement noise v ~ N(0, R2) inside measurement. inflation >= 1 multiplies the ensemble spread after each propagation; threads parallelises member propagation.
Output¶
ConfigurableEpi.DEFAULT_QS — Constant.
Default forecast quantile levels.
<a id='ConfigurableEpi.append_latent_audit!-Tuple{Any, Any, AbstractVector, AbstractUnitRange{<:Integer}}'>
<a id='ConfigurableEpi.append_latent_audit!-Tuple{Any, Any, AbstractVector, AbstractUnitRange{<:Integer}}-1'>
ConfigurableEpi.append_latent_audit! — Method.
In-sample behaviour of each latent's filtered path (unconstrained chart): is_sd, the lag-1 autocorrelation is_acf1, the implied correlation time is_tau_days = -dt / log(acf1) (NaN when acf1 <= 0) and is_drift, the second-half mean minus the first-half mean. Filtered paths absorb data innovations, so read is_acf1 as a lower bound on the process's own.
ConfigurableEpi.append_latent_spread! — Method.
Per-horizon predictive spread of each latent coefficient: fc_log_sd_h<h> (the unconstrained sd, log_sd[h, l]) and fc_factor_h<h> = exp(sd), a multiplicative ±1sd spread for a log-chart latent.
ConfigurableEpi.asof_series — Method.
No-leakage as-of series at report date r_k: rows with as_of <= r_k, then the latest issue per reference date (within each group_cols series, e.g. (:location,)), sorted date-major.
ConfigurableEpi.backtest_forecast_rows — Method.
backtest_forecast_rows(quantiles, origin, target_dates, truth; qs = DEFAULT_QS, model_id,
date_col = :date, value_col = :counts[, locations, loc_col = :location]) -> DataFrame
One row per (horizon, quantile) with columns origin, horizon, target_date, quantile, value, observed, model_id, observed joined from truth at each target date. A [horizon, observation, quantile] array with locations labelling the observations prepends a location column and joins on (location, date).
ConfigurableEpi.forecast_ensemble — Method.
forecast_ensemble(filter, init_states, p; n_ahead, t0, dt = 1.0, u = Float64[], latent_range = 1:0, n_obs = 1)
-> (samples, latent_samples)
Roll each state forward n_ahead steps with sample_state and draw a predictive observation with sample_measurement (no correct!). samples[h, j] (or [h, j, o] for n_obs > 1) is the non-negative predictive observation; latent_samples[h, j, l] the requested latent slots in their unconstrained chart, the forecast-spread diagnostic.
ConfigurableEpi.forecast_quantiles — Method.
Per-horizon quantiles over draws: [horizon, quantile] from samples[h, j], or [horizon, observation, quantile] from samples[h, j, o].
ConfigurableEpi.forecast_states — Method.
Analytic Kalman forecast: seed a copy of kf at the filtered Gaussian (x0, R0) and roll n_ahead steps with predict! only, returning each horizon's state mean and covariance.
ConfigurableEpi.forecast_sample_rows — Method.
forecast_sample_rows(samples, target_dates; geo_value, disease, variable, resolution, metadata = (;))
forecast_sample_rows(samples, target_dates; geo_values, diseases, variables, resolution, metadata = (;))
Long draw-level rows from samples[horizon, draw] (or [horizon, draw, signal] with one label per signal): draw-major, with Int32 draw ids. metadata appends scalar or row-length columns after the routine ones (a backtest's origin, say).
ConfigurableEpi.write_forecast_samples — Method.
Write one sample table, or an iterable of schema-identical tables, to samples.parquet through DuckDB (COPY ... FORMAT parquet), combining the batches inside DuckDB.
ConfigurableEpi.DataLink — Type.
How a DataFrame maps onto a schema: already wide (one column per observation name), or long with a pivot_column whose values are the observation names and a value_column.
ConfigurableEpi.ObservationSchema — Type.
The observation names, in the order the measurement model emits them, and the time column.
ConfigurableEpi.build_observation_schema — Method.
The schema named by a tuple of observation specs, in their order.
ConfigurableEpi.build_observations — Method.
build_observations(df, link::DataLink; T = Float64) -> (; y, times)
build_observations(df, obs_specs; time_column = :date, value_column = :value, pivot_column = nothing, T = Float64)
Observation vectors y::Vector{SVector{N, T}} in schema order, one per time point, and the times. Missing cells throw.
ConfigurableEpi.pivot_to_wide — Method.
Wide frame with the time column followed by one column per schema name, sorted by time. A wide input is validated and sorted; a long one is unstacked on link.pivot_column.
ConfigurableEpi.require_complete_grid — Method.
Assert exactly one row for every (observation, time) cell of a long frame, reporting every missing and duplicated cell at once (the pivot alone would take the first duplicate silently).