AlgebraicEpiMech API¶
Reference for the exported API of AlgebraicEpiMech, generated from docstrings.
AlgebraicEpiMech.AtCompartment — Type.
Sample a SPECIES: prevalence. Every species whose (flattened) name begins with species gains a catalytic tap X -> X + O, carrying its own detection rate — whoever is in the compartment is currently detectable (although detection does not cause removal)
Fields
species::Symbol
AlgebraicEpiMech.AtEvent — Type.
Record a TRANSITION: incidence. Every transition whose (flattened) name begins with transition gains an output arc into an accumulator, so it fires at that transition's own rate and counts exactly one observation per occurrence.
AtEvent(:transmission) counts infections as they happen, which is what decouples a reporting delay from the latent period — the delay is then whatever the chain adds and nothing else.
Fields
transition::Symbol
AlgebraicEpiMech.CompartmentalModel — Type.
Abstract base type for compartmental epidemiological models.
Compartmental models define the specific disease dynamics and transitions between epidemiological states (e.g., S→I→R) as undirected wiring diagrams.
Fields
AlgebraicEpiMech.CompleteCrossImmunity — Type.
Complete cross-immunity multistrain model.
In the complete cross-immunity model:
- All strains share a common susceptible pool
- Infection by any strain confers immunity to all strains
- Typing: UninfectedInfectedTyping (typed S vs I/R compartments)
- Composition: Strains compete for susceptibles via shared S depletion
Fields
number_of_strains::Int: Number of competing strains in the modelstrain_names::Vector{Symbol}: Names for each strain (e.g., [:h1n1, :h3n2])
Examples
# Create a 2-strain model with custom names
multistrain = CompleteCrossImmunity([:wild_type, :variant])
# Create a 3-strain model with auto-generated names
multistrain = CompleteCrossImmunity(3) # Creates [:strain_1, :strain_2, :strain_3]
# Compose to create competing strain SIR
typing = UninfectedInfectedTyping()
strain_typed = create_model(typing, multistrain)
sir_typed = create_model(typing, SIR())
combined = typed_product(sir_typed, strain_typed)
Fields
number_of_strains::Int64strain_names::Vector{Symbol}
AlgebraicEpiMech.ContactStratification — Type.
Contact-based stratification for epidemiological models.
Represents stratifications where populations are divided into strata with contact-based interactions (full contact matrix between all pairs). This generalizes age groups, geographic regions modelled as cross-region contact (rather than explicit movement), risk groups, etc.
Multiple contact stratifications can be stacked via compose_stratifications to create product strata (e.g., age × geography).
Fields
stratum_names::Vector{Symbol}: Names of strata (e.g., [:child, :adult] or [:urban, :rural])label::Symbol: Semantic label for the stratification (e.g., :age, :geography, :risk)
Reflexive boxes (disease, reversion, and waning) are controlled via the include_reflexives keyword on create_model, not on the struct itself.
Examples
# Age stratification
age = ContactStratification([:child, :adult], :age)
# Geographic stratification
geo = ContactStratification([:urban, :rural], :geography)
# Compose to create age × geography strata
typing = OnePopulationTyping()
sir = create_model(typing, SIR())
age_sir = typed_product(sir, create_model(typing, age))
age_geo_sir = typed_product(age_sir, create_model(typing, geo))
# Result: 4 strata (childxurban, childxrural, adultxurban, adultxrural)
See also: AgeStratification, GeographicStratification
Fields
stratum_names::Vector{Symbol}label::Symbol
AlgebraicEpiMech.EpiMechModel — Type.
Abstract base type for all epidemiological-mechanical models in the AlgebraicEpiMech framework.
All concrete epidemiological-mechanical model types should be subtypes of EpiMechModel. This abstract type serves as the root of the type hierarchy for models that combine epidemiological dynamics with mechanical or algebraic structures.
Extended help
Subtypes of EpiMechModel should implement the necessary interface methods for their specific model formulation.
See also
- Related concrete model types (define as needed)
Fields
AlgebraicEpiMech.EpidemiologicalTyping — Type.
Abstract base type for epidemiological typing strategies.
An EpidemiologicalTyping describes how populations and transitions are typed when constructing epidemiological models. type_system materializes the strategy as the LabelledPetriNet used as the codomain of a typed Petri net.
Reference
Libkind et al. (2023) An algebraic framework for structured epidemic modelling
Fields
AlgebraicEpiMech.FullHistory — Type.
Full (unordered) immune history: uninfected individuals are indexed by the set of strains they are immune to (2^n classes). Immunity accumulates — reversion routes to h ∪ {i}.
Fields
AlgebraicEpiMech.ImmuneHistory — Type.
Immune-history combination of the available strain/subtype names and ImmuneHistoryMode.
Fields
strain_names::Vector{Symbol}: strain names (e.g.[:current, :invader])mode::M:FullHistory()orLatestInfection()
Examples
typing = UninfectedInfectedTyping()
seirs = create_model(typing, SEIRS())
history = create_model(typing, ImmuneHistory([:current, :invader]))
model = typed_product(seirs, history) # immune-history-resolved SEIRS
# States: S_naive, S_current, …, E_invader_from_current, I_…, R_…
Fields
strain_names::Vector{Symbol}mode::ImmuneHistoryMode
AlgebraicEpiMech.ImmuneHistory — Method.
Auto-name n strains as strain_1 … strain_n.
AlgebraicEpiMech.ImmuneHistoryMode — Type.
Abstract base type for selections of how much immune history is retained.
Fields
AlgebraicEpiMech.LatestInfection — Type.
Latest-infection status: uninfected individuals are indexed by their most recent infection (n + 1 classes). Reversion overwrites immune status — routes to {i}.
Fields
AlgebraicEpiMech.MultiStrainModel — Type.
Abstract base type for multistrain epidemiological models.
Multistrain models define how multiple pathogen strains interact through different assumptions about cross-immunity. These compose with compartmental models via typed_product to create strain-structured disease dynamics.
Fields
AlgebraicEpiMech.NoCrossImmunity — Type.
No cross-immunity multistrain model.
In the no cross-immunity model:
- Each strain operates independently with no interaction
- Strains act as independent strata (similar to age groups)
- Typing: OnePopulationTyping (all compartments have the same type)
- Composition: Creates parallel disease dynamics per strain via typed_product
Fields
number_of_strains::Int: Number of independent strains in the modelstrain_names::Vector{Symbol}: Names for each strain (e.g., [:h1n1, :h3n2, :b])
Examples
# Create a 3-strain model with custom names
multistrain = NoCrossImmunity([:h1n1, :h3n2, :b])
# Create a 2-strain model with auto-generated names
multistrain = NoCrossImmunity(2) # Creates [:strain_1, :strain_2]
# Compose to create strain-structured SIR
typing = OnePopulationTyping()
strain_typed = create_model(typing, multistrain)
sir_typed = create_model(typing, SIR())
combined = typed_product(sir_typed, strain_typed)
Fields
number_of_strains::Int64strain_names::Vector{Symbol}
AlgebraicEpiMech.ObservationChainLayout — Type.
Metadata for one observation chain.
Fields
source_name: Flattened name of the event or compartment being observedobs_names: Observation-state names in stage ordercumulative_name: Terminal observation-state name, derived fromobs_names
Fields
source_name::Symbolobs_names::NTuple{N, Symbol} where Ncumulative_name::Symbol
AlgebraicEpiMech.ObservationLayout — Type.
Metadata for all observation chains in an augmented Petri net.
Fields
obs_names: All flattened observation-state names in Petri-net orderchains: Observation chains in first-encounter ordercumulative_names: Terminal state of each chain, derived fromchains
Fields
obs_names::NTuple{N, Symbol} where Nchains::Tuplecumulative_names::NTuple{M, Symbol} where M
AlgebraicEpiMech.ObservationTarget — Type.
What an observation attaches to. AtEvent records a transition (incidence); AtCompartment samples a species (prevalence).
Fields
AlgebraicEpiMech.OnePopulationTyping — Type.
Typing strategy in which every compartment belongs to one population type and therefore has the same available stratifications.
Examples
Fields
population_type::Symbol: The symbolic name for the population type.
Susceptible-Exposed-Infected (SEI) compartmental model.
The SEI model extends SI with an exposed compartment:
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious
Transitions:
- S + I → E + I (exposure/transmission)
- E → I (progression to infectious)
The SEI model represents diseases with an incubation period but no recovery.
Fields
number_E_stages::Int64number_I_stages::Int64number_of_states::Int64
Susceptible-Exposed-Infected-Recovered (SEIR) compartmental model.
The SEIR model extends SEI with recovery:
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious
- Recovered (R): Individuals who have recovered and gained immunity
Transitions:
- S + I → E + I (exposure/transmission) [from SEI]
- E → I (progression to infectious) [from SEI]
- I → R (recovery) [extension]
Built by extending SEI model with recovery transition.
Fields
number_E_stages::Int64number_I_stages::Int64number_of_states::Int64
AlgebraicEpiMech.SEIRS — Type.
Susceptible-Exposed-Infected-Recovered-Susceptible (SEIRS) compartmental model.
The SEIRS model extends SEIR with waning immunity:
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious
- Recovered (R): Individuals who have recovered but may lose immunity
Transitions:
- S + I → E + I (exposure/transmission) [from SEIR]
- E → I (progression to infectious) [from SEIR]
- I → R (recovery) [from SEIR]
- R → S (waning immunity) [extension]
Built by extending SEIR model with waning transition.
Fields
number_E_stages::Int64number_I_stages::Int64number_of_states::Int64
Susceptible-Exposed-Infected-Susceptible (SEIS) compartmental model.
The SEIS model extends SEI with waning immunity (reversion):
- Susceptible (S): Individuals who can become infected
- Exposed (E): Individuals who are infected but not yet infectious
- Infected (I): Individuals who are infectious
Transitions:
- S + I → E + I (exposure/transmission) [from SEI]
- E → I (progression to infectious) [from SEI]
- I → S (waning immunity/reversion) [extension]
The SEIS model represents diseases with incubation period but no lasting immunity.
Fields
number_E_stages::Int64number_I_stages::Int64number_of_states::Int64
Susceptible-Infected (SI) compartmental model.
The SI model includes:
- Susceptible (S): Individuals who can become infected
- Infected (I): Individuals who are infectious
Transitions:
- S + I → I + I (infection/transmission)
The SI model represents endemic diseases with no recovery.
Fields
number_I_stages::Int64number_of_states::Int64
Susceptible-Infected-Recovered (SIR) compartmental model.
The SIR model extends SI with recovery:
- Susceptible (S): Individuals who can become infected
- Infected (I): Individuals who are infectious
- Recovered (R): Individuals who have recovered and gained immunity
Transitions:
- S + I → I + I (infection/transmission) [from SI]
- I → R (recovery) [extension]
Built by extending SI model with recovery transition.
Fields
number_I_stages::Int64number_of_states::Int64
Susceptible-Infected-Susceptible (SIS) compartmental model.
The SIS model extends SI with waning immunity (reversion):
- Susceptible (S): Individuals who can become infected
- Infected (I): Individuals who are infectious
Transitions:
- S + I → I + I (infection/transmission) [from SI]
- I → S (waning immunity/reversion) [extension]
The SIS model represents diseases with no lasting immunity.
Fields
number_I_stages::Int64number_of_states::Int64
AlgebraicEpiMech.Stratification — Type.
Represents a stratification structure for epidemiological models.
Fields
AlgebraicEpiMech.UninfectedInfectedTyping — Type.
Typing strategy that distinguishes uninfected and infected populations. The two populations may have different stratifications.
Examples
typing = UninfectedInfectedTyping()
typing = UninfectedInfectedTyping(
uninfected_type = :Susceptible,
infected_type = :Infectious,
)
See also: type_system, OnePopulationTyping
Fields
uninfected_type::Symbol: The symbolic name for the uninfected population.infected_type::Symbol: The symbolic name for the infected population.
AlgebraicEpiMech.AgeStratification — Method.
Convenience constructor for age-based contact stratification.
Creates a ContactStratification with label :age. Provided for backward compatibility and semantic clarity.
Examples
age = AgeStratification([:child, :adult, :elderly])
age = AgeStratification(:child, :adult, :elderly) # splatting syntax
AlgebraicEpiMech.GeographicStratification — Method.
Convenience constructor for geography-based contact stratification.
Creates a ContactStratification with label :geography. Represents geographic regions with cross-region contact (not movement-based models).
Examples
geo = GeographicStratification([:urban, :suburban, :rural])
geo = GeographicStratification(:urban, :suburban, :rural) # splatting syntax
AlgebraicEpiMech.add_disease_progression! — Method.
Add disease progression mechanism: fromcompartment → tocompartment
Used for transitions like E→I, I→R, etc. (infected → infected transitions)
AlgebraicEpiMech.add_infection! — Method.
add_infection!(
uwd,
infectee_junction,
infector_junction,
first_infected_junction,
typing::OnePopulationTyping
) -> Any
Add infection mechanism: Infectee + Infector → first_infected + Infector
General infection mechanism where an infectee (typically S) interacts with an infector (typically I) to produce a newly infected individual that enters the first*infected compartment, while the infector remains unchanged. The first*infected_junction can be:
- An I stage for SIR-like models (direct infection)
- An E stage for SEIR-like models (exposure before infectiousness)
The typing argument determines the population types used.
AlgebraicEpiMech.add_reversion_progression! — Method.
Add reversion progression mechanism: e.g. R → S (infected → uninfected transitions)
Used for transitions from infected compartments back to uninfected compartments.
AlgebraicEpiMech.add_uninfected_density_progression! — Method.
add_uninfected_density_progression!(
uwd,
from_junction,
to_junction,
typing::OnePopulationTyping
) -> Any
Add uninfected density progression mechanisms. This is useful for transitions like waning partial immunity (uninfected → uninfected transitions, e.g., V → S).
AlgebraicEpiMech.attach_observation — Method.
Attach an observation chain to pn, returning a new net. The result is the colimit described at the top of this file, materialized in one direct pass (see the note there for why it is not built by pushout).
n_stages Erlang delay stages are added per chain: the first receives the observation, each subsequent one takes flow from the last, and the final stage is cumulative (no outflow), i.e. the accumulator the observation model reads.
Reapplying the same target, prefix, and stage count is idempotent. Reusing a target and prefix for an incompatible chain shape throws an ArgumentError; choose a different prefix when both observation layouts are required.
Chains are grouped by stratum. For AtEvent the group is the transition's net product — for infection routes S_x + I_y -> E_x + I_y that is E_x, so all routes infecting x count into x's chain. For AtCompartment each matched species gets its own chain.
Apply this after all typed_product composition so chains are grouped over the final strata.
AlgebraicEpiMech.compose_stratifications — Method.
compose_stratifications(
a::ContactStratification,
b::ContactStratification
) -> ContactStratification
Compose two ContactStratifications via Cartesian product.
Arguments
a::ContactStratification: First contact stratificationb::ContactStratification: Second contact stratification
Returns
ContactStratification: New contact stratification representing the product ofaandb, with combined stratum names and a composite label.
Examples
age = ContactStratification([:child, :adult], :age)
geo = ContactStratification([:urban, :rural], :geography)
age_geo = compose_stratifications(age, geo)
# Resulting stratum names: [:childxurban, :childxrural, :adultxurban, :adultxrural]
# Resulting label: :age_x_geography
AlgebraicEpiMech.create_model — Method.
create_model(
typing::EpidemiologicalTyping,
model::EpiMechModel;
population_transitions,
include_reflexives
) -> Catlab.CategoricalAlgebra.Pointwise.ACSetTransformations.StructACSetTransformation{ACSets.Schemas.TypeLevelBasicSchema{Symbol, Tuple{:T, :S, :I, :O}, Tuple{(:it, :I, :T), (:is, :I, :S), (:ot, :O, :T), (:os, :O, :S)}, Tuple{:Name}, Tuple{(:tname, :T, :Name), (:sname, :S, :Name)}, Tuple{}}, Comp, AlgebraicPetri.LabelledPetriNet, AlgebraicPetri.LabelledPetriNet} where Comp<:NamedTuple
Create a typed Petri net model from an epidemiological typing strategy and model specification.
This is the unified entry point for creating all model types in AlgebraicEpiMech. Through multiple dispatch on the model parameter, it supports any subtype of EpiMechModel. The undirected wiring diagram (UWD) provides an intermediate structural representation, recording how compartments and mechanisms connect independently of the final typed Petri net constructed by oapply_typed.
Functionality Overview
The create_model function builds the typed Petri net representation of the epidemiological-mechanical model in four steps:
- Build Type System: Materializes the typing strategy as a
LabelledPetriNet - Create UWD: Builds an undirected wiring diagram with model structure and box names
- Generate Transition Names: Creates unique names for ODE parameters via dispatch
- Apply Typing: Uses
oapply_typedto create a typed Petri net
The resulting typed Petri net can be used directly for ODE simulation or composed with other typed Petri nets via typed_product to build complex hierarchical models.
Arguments
typing::EpidemiologicalTyping: The strategy defining possible compartment and transition types.model::EpiMechModel: The model specification (uses dispatch for different types)
Keyword Arguments
population_transitions=nothing: Extra transition types fortype_system, as a single pair such as:strata => (:Population => :Population)or a collection of pairs.nothinggives the standard type system. Models that will be composed withtyped_productmust be created with the same extra transitions so that they share a codomain.include_reflexives::Bool=true(forContactStratification, forwarded tocreate_model_uwd): Controls whether per-stratum reflexive boxes (disease, reversion, and waning) are added. Required fortyped_productcomposition; disable for standalone use to avoid zero-effect transitions.
Returns
-
ACSetTransformation: A typed Petri net with two components accessible via:dom(typed_model): Extract the underlyingLabelledPetriNetfor ODE solvingcodom(typed_model): Access the Petri-net type system
Model-Specific Transition Naming
Transition names are generated automatically based on model type:
- Compartmental:
transmission_S_I,E_to_I,I_to_R(describes flow between compartments) - Age Stratification:
child_child,child_adult,adult_child(infectee_infector pattern) - Multistrain: Strain identifiers like
h1n1,h3n2(enables clean composition)
These names become ODE parameters and differ from box names (:transmission, :density) used for composition.
Examples
# Basic compartmental model
typing = OnePopulationTyping()
seir = create_model(typing, SEIR())
seir_pn = dom(seir) # Extract for ODE solving
# Transitions: :transmission_S_I, :E_to_I, :I_to_R
# Multi-stage compartments (gamma-distributed delays)
si_multi = create_model(typing, SI(number_I_stages=3))
# Transitions: :transmission_S_I1, :transmission_S_I2, :transmission_S_I3, :I1_to_I2, :I2_to_I3
# Age-structured model
age_strat = AgeStratification([:child, :adult, :elderly])
age_model = create_model(typing, age_strat)
# Transitions: :child_child, :child_adult, :child_elderly, :adult_child, ...
# Multistrain model (no cross-immunity)
strains = NoCrossImmunity([:h1n1, :h3n2, :seasonal_b])
strain_model = create_model(typing, strains)
# Compose models via typed_product
sir = create_model(typing, SIR())
age = create_model(typing, AgeStratification([:child, :adult]))
age_sir = typed_product(sir, age)
age_sir_pn = dom(age_sir)
# Result: S_child, I_child, R_child, S_adult, I_adult, R_adult compartments
# Transition names become tuples: (:transmission_S_I, :child_adult)
Compositional Design
Models expressed as typed Petri nets compose via typed_product using their common type-system codomain when box names match. The vectorfield_flat function automatically handles tuple transition names in composed models for ODE parameter assignment.
See also: create_model_uwd, generate_transition_names, type_system, typed_product (from AlgebraicPetri.TypedPetri), vectorfield_flat
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::CompartmentalModel
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Create an undirected wiring diagram (UWD) for a compartmental model within a specific typing.
This function returns the undirected wiring diagram that defines the compartmental structure and transitions, using the type names from the typing. The compartments are typed according to the typing's population structure. The returned UWD does not declare an outer boundary/ports; oapply_typed derives the boundary from its junctions when materializing the typed Petri net.
Arguments
typing::EpidemiologicalTyping: The population typing defining type namesmodel::CompartmentalModel: The compartmental model instance (SI(), SEI(), SIR(), SEIR(), etc.)
Returns
- Undirected wiring diagram defining the compartmental model structure with typing-specific types
Examples
# Create SIR model UWD with single population typing
typing = OnePopulationTyping(population_type = :Individual)
sir_uwd = create_model_uwd(typing, SIR()) # Uses Individual type
# Create SEIR model UWD with uninfected/infected typing
typing = UninfectedInfectedTyping(uninfected_type = :Susceptible, infected_type = :Infectious)
seir_uwd = create_model_uwd(typing, SEIR()) # S::Susceptible, E,I,R::Infectious
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::ContactStratification;
include_reflexives
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct an undirected wiring diagram (UWD) for contact strata.
Creates an UWD where transmission boxes represent contact patterns between different strata. Example strata include age groups, risk levels, or demographic divisions, but only covers instantaneous transmission dynamics, e.g. movement between geographic regions would require additional demographic modeling.
The UWD structure depends on the typing:
OnePopulationTyping: Single junction per age group (combined susceptible/infected)UninfectedInfectedTyping: Two junctions per age group (uninfected and infected)
All transmission boxes are created with the :transmission name, enabling composition with compartmental models that have :transmission boxes (SI, SIR, SEIR, etc.).
Arguments
typing::EpidemiologicalTyping: The population typing defining type systemmodel::ContactStratification: The contact stratification configuration with stratum names
Returns
- Undirected wiring diagram with stratum junctions and transmission boxes for composition
Mathematical Structure
For n strata, creates n² transmission boxes representing the contact matrix:
- Diagonal boxes (i→i): within-stratum transmission
- Off-diagonal boxes (i→j, i≠j): between-stratum transmission
Composition Behavior
When composed with a compartmental model UWD via typed_product, the transmission boxes will align based on the :transmission name, allowing the contact structure to modulate the disease dynamics defined in the compartmental model.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::SEIRS
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct a complete SEIRS model UWD by extending SEI with recovery and waning immunity.
Builds on the SEI base model (S→E→I dynamics with multi-stage E and I support) and adds:
- R (recovered) compartment
- Recovery transition: I_last → R
- Waning immunity transition: R → S
Represents diseases with latent periods and temporary immunity. The dual multi-stage capability enables independent control of latent and infectious period distributions. Recovery occurs from the last I stage, and waning immunity returns individuals from R to S.
Usage with oapply_typed
Apply to typing with oapply_typed to create a typed Petri net for composition.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::SEIR
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct a complete SEIR model UWD by extending SEI with recovery.
Builds on the SEI base model (S→E→I dynamics with multi-stage E and I support) and adds:
- R (recovered) compartment
- Recovery transition: I_last → R
The dual multi-stage capability (independent E and I stages) enables independent control of latent and infectious period distributions. Recovery always occurs from the last I stage.
Usage with oapply_typed
Apply to typing with oapply_typed to create a typed Petri net for composition.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::SEIS
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct a complete SEIS model UWD by extending SEI with waning immunity.
Builds on the SEI base model (S→E→I dynamics with multi-stage E and I support) and adds:
- Reversion transition: I_last → S (waning immunity)
Represents diseases with latent periods but no lasting immunity. The dual multi-stage capability enables independent control of latent and infectious period distributions. Reversion occurs from the last I stage back to S.
Usage with oapply_typed
Apply to typing with oapply_typed to create a typed Petri net for composition.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::SIR
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct a complete SIR model UWD by extending SI with recovery.
Builds on the SI base model (S→I dynamics with multi-stage I support) and adds:
- R (recovered) compartment
- Recovery transition: I_last → R
The multi-stage I capability from SI is preserved, enabling gamma-distributed infectious periods. Recovery always occurs from the last I stage, ensuring proper sequencing.
Usage with oapply_typed
Apply to typing with oapply_typed to create a typed Petri net for composition.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::SIS
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct a complete SIS model UWD by extending SI with waning immunity.
Builds on the SI base model (S→I dynamics with multi-stage I support) and adds:
- Reversion transition: I_last → S (waning immunity)
Represents diseases where recovery returns individuals to susceptible state. The multi-stage I capability enables realistic infectious period distributions. Reversion occurs from the last I stage back to S.
Usage with oapply_typed
Apply to typing with oapply_typed to create a typed Petri net for composition.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::EpidemiologicalTyping,
model::Union{SEI, SI}
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct a complete undirected wiring diagram (UWD) for SI or SEI models.
Populates an initially empty UWD with compartments and mechanisms via setup_basic!. These are the base models that other compartmental models extend from.
Usage with oapply_typed
The returned UWD can be applied to the typing using oapply_typed to create a typed Petri net, enabling composition with other typed Petri nets (e.g., demographic processes, interventions).
AlgebraicEpiMech.create_model_uwd — Method.
Immune-history stratification requires the uninfected/infected type split.
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::OnePopulationTyping,
multistrain::NoCrossImmunity
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct an undirected wiring diagram (UWD) for a no cross-immunity multistrain model.
Creates a strain-stratified UWD where each strain operates independently. The strains are represented as separate junctions, and each strain has its own set of disease transition boxes (:transmission, :disease, :reversion) that will compose with corresponding boxes from a compartmental model via typed_product.
All box types are always included; typed_product will only compose boxes that exist in both UWDs, naturally filtering out non-matching transitions. That filtering is silent — a transition present in one factor and absent from the other is dropped without error — which is why each factor carries a reflexive box per transition type it wants preserved.
There is deliberately no reflexive observation box. Observation is attached to the COMPOSED net by attach_observation, so a stratification factor never has to know it exists.
Arguments
typing::OnePopulationTyping: The required single-population typingmultistrain::NoCrossImmunity: The multistrain model configuration with strain names
Returns
- Undirected wiring diagram with strain junctions and transition boxes for composition
Examples
# Create a 3-strain model with custom names
typing = OnePopulationTyping()
multistrain = NoCrossImmunity([:h1n1, :h3n2, :b])
strain_uwd = create_model_uwd(typing, multistrain)
# Compose with compartmental model
sir_typed = create_model(typing, SIR())
strain_typed = create_model(typing, multistrain)
combined = typed_product(sir_typed, strain_typed)
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::UninfectedInfectedTyping,
multistrain::CompleteCrossImmunity
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct an undirected wiring diagram (UWD) for a complete cross-immunity multistrain model.
Creates a strain-structured UWD where all strains share a common susceptible pool but have separate infected compartments. Infection by any strain depletes the shared susceptible pool and confers immunity to all strains.
The UWD has:
- One shared uninfected/susceptible junction
- N infected strain junctions
- Transmission boxes connecting shared susceptible to each strain's infected
- Disease progression boxes for each strain's infected compartments
- Reversion boxes to return to shared susceptible pool
Arguments
typing::UninfectedInfectedTyping: The required uninfected/infected typingmultistrain::CompleteCrossImmunity: The multistrain model configuration with strain names
Returns
- Undirected wiring diagram with shared susceptible and strain-specific infected junctions
Examples
# Create a 2-strain competing model
typing = UninfectedInfectedTyping()
multistrain = CompleteCrossImmunity([:wild_type, :variant])
strain_uwd = create_model_uwd(typing, multistrain)
# Compose with compartmental model
sir_typed = create_model(typing, SIR())
strain_typed = create_model(typing, multistrain)
combined = typed_product(sir_typed, strain_typed)
AlgebraicEpiMech.create_model_uwd — Method.
create_model_uwd(
typing::UninfectedInfectedTyping,
model::ImmuneHistory
) -> Catlab.WiringDiagrams.RelationDiagrams.TypedUnnamedRelationDiagram{Symbol, Symbol, Symbol}
Construct the UWD for the ImmuneHistory stratification factor over a UninfectedInfectedTyping.
This is a stratification factor (like ContactStratification), meant to be typed_product-composed with a disease model — the disease model supplies S→E→I→R, while this factor supplies the immune-status structure.
- Uninfected junctions
U_h, one per immune-history class. - Infected junctions
(h,i)= "historyh, currently fighting straini", one per (class, susceptible-strain) pair. :transmission(escape-selective):U_h + (h',i) → (h,i)for every susceptible classh(i ∉ h) and every infector(h',i). A class immune toisimply has no such box, so the pullback drops that infection — the escape.:diseaseis reflexive on each(h,i), so the base model's progression runs inside a fixed(h,i).:reversionis off-diagonal:(h,i) → U_{recover}withrecover = h∪{i}(FullHistory) or{i}(LatestInfection). This is the one stratum-changing move — recovering fromifolds it into the immune history.:waningreflexive on eachU_h(inert with SEIRS; lets a waning-bearing base compose).
Examples
typing = UninfectedInfectedTyping()
history = create_model(typing, ImmuneHistory([:current, :invader]))
model = typed_product(create_model(typing, SEIRS()), history)
AlgebraicEpiMech.flatten_symbols — Method.
Recursively flatten a tuple of symbols and join them with underscores.
Examples
flatten_symbols((:x, :y, :z)) # returns :x_y_z
flatten_symbols(((:x, :y), :z)) # returns :x_y_z
flatten_symbols((((:a, :b), :c), :d)) # returns :a_b_c_d
AlgebraicEpiMech.generate_transition_names — Method.
Generate transition names from UWD structure for compartmental models.
For boxes with 2 ports (one input, one output), generates names in the format input_to_output. For boxes with 4 ports (two inputs, two outputs), generates names in the format box_name_input1_input2 where inputs are sorted in reverse alphabetical order for consistency (e.g., transmission_S_I).
Arguments
uwd: The undirected wiring diagram with species names in junction :variable attributesmodel::CompartmentalModel: The compartmental model (used for dispatch)
Returns
Vector{Symbol}: Vector of unique transition names, one per box in the UWD
Examples
# Used internally by create_model
typing = OnePopulationTyping()
uwd = create_model_uwd(typing, SEIR())
names = generate_transition_names(uwd, SEIR())
# Returns: [:transmission_S_I, :E_to_I, :I_to_R]
See also: create_model
AlgebraicEpiMech.generate_transition_names — Method.
Generate transition names from UWD structure for age stratification models.
For transmission boxes with 4 ports (two inputs, two outputs), generates names capturing the age-to-age contact pattern in the format infectee_infector. This naming convention clearly identifies which age group is being infected (infectee) by which age group (infector), enabling interpretation of age-structured contact matrices.
For boxes with 2 ports (one input, one output), generates names in the format input_to_output. This fallback handles any non-standard box types that might appear in extended models.
Arguments
uwd: The undirected wiring diagram with age group names in junction :variable attributesmodel::AgeStratification: The age stratification model (used for dispatch)
Returns
Vector{Symbol}: Vector of transition names, one per box in the UWD
Examples
# Used internally by create_model
typing = OnePopulationTyping()
age_strat = AgeStratification([:child, :adult])
uwd = create_model_uwd(typing, age_strat)
names = generate_transition_names(uwd, age_strat)
# Returns: [:child_child, :child_adult, :adult_child, :adult_adult]
# Representing: child←child, child←adult, adult←child, adult←adult transmission
See also: create_model, ContactStratification, AgeStratification
AlgebraicEpiMech.generate_transition_names — Method.
Generate transition names for the ImmuneHistory stratification factor. These become the second component of the composed typed_product transition names.
:transmission(4-port) →infect_<strain>_<susceptible-class>_by_<infector-class>, exposing the infecting strain (recovered from the infector junction) so the composed name stays keyable per strain.- reflexive / reversion boxes (2–3 port) → the first junction's variable, mirroring
ContactStratification— e.g. the:diseasereflexives and the off-diagonal:reversionon(h,i)are named by that(h,i), and:waningby itsU_h. Composition with the base disambiguates them (base name differs).
Examples
factor = create_model_uwd(UninfectedInfectedTyping(), ImmuneHistory([:current, :invader]))
names = generate_transition_names(factor, ImmuneHistory([:current, :invader]))
# transmission names begin `infect_current…` / `infect_invader…`
AlgebraicEpiMech.observation_layout — Method.
Return deterministic observation-chain metadata for an augmented Petri net.
The result is an ObservationLayout with fields:
obs_names: all flattened observation state names in Petri-net orderchains: orderedObservationChainLayoutvaluescumulative_names: flattened terminal observation state for each chain
This centralizes the observation naming/ordering contract, so downstream packages do not each re-implement observation-state parsing. prefix must match the prefix passed to attach_observation. The function recognises the <prefix>_<source>_<stage> leaf that attach_observation produces; a chain named otherwise is not recognised as one.
AlgebraicEpiMech.type_system — Method.
type_system(
typing::EpidemiologicalTyping,
population_transitions...
) -> AlgebraicPetri.LabelledPetriNet
Materialize an epidemiological typing strategy as the LabelledPetriNet used as the codomain of a typed Petri net. Concrete EpidemiologicalTyping subtypes must implement this interface.
AlgebraicEpiMech.type_system — Method.
type_system(
typing::OnePopulationTyping,
population_transitions...
) -> AlgebraicPetri.LabelledPetriNet
Create the single-population Petri-net type system described by typing. Additional transition specifications are appended to the standard :transmission, :disease, :reversion, and :waning transitions.
Examples
typing = OnePopulationTyping(population_type = :Individual)
codomain = type_system(
typing,
:birth => (:Individual => (:Individual, :Individual)),
)
AlgebraicEpiMech.type_system — Method.
type_system(
typing::UninfectedInfectedTyping,
population_transitions...
) -> AlgebraicPetri.LabelledPetriNet
Create the uninfected/infected Petri-net type system described by typing. Additional transition specifications are appended to the standard :transmission, :disease, :reversion, and :waning transitions.
Examples
typing = UninfectedInfectedTyping(
uninfected_type = :Susceptible,
infected_type = :Infectious,
)
codomain = type_system(
typing,
:vaccination => (:Susceptible => :Susceptible),
)
AlgebraicEpiMech.vectorfield_flat — Method.
vectorfield_flat(
pn::AlgebraicPetri.AbstractPetriNet
) -> AlgebraicEpiMech.var"#vectorfield!#vectorfield_flat##8"{AlgebraicEpiMech._NamePositions, AlgebraicEpiMech._NamePositions, AlgebraicEpiMech._NamePositions, Vector{Vector{Tuple{Int64, Int64}}}, Vector{Vector{Tuple{Int64, Int64}}}, Vector{T}, Vector{T1}, Int64, Int64} where {T, T1}
Generate an ODE vectorfield function from a Petri net using mass action kinetics as per AlgebraicPetri.vectorfield. The only difference is that species and transition names are flattened using flatten_symbols, converting nested tuples into single symbols joined by underscores.
Arguments
pn::AbstractPetriNet: A Petri net representing the reaction network
Returns
A function (du, u, p, t) -> du where:
du: Array/Dict to store computed derivativesu: Current state (species concentrations), indexed by flattened species namesp: Parameters (rate constants), indexed by flattened transition namest: Current time
This function complies with SciML conventions for in-place ODE vectorfields.
Performance
Everything that can be resolved from the net alone — flattened names, the mass-action input lists, the nonzero stoichiometry — is resolved once at build time, and the right-hand side is a sparse loop over arcs rather than a dense loop over transitions × species. Name lookup into the arguments is also done once per concrete argument type: u, du and p may be anything whose propertynames lists the flattened names in the same order as its integer indexing (LVector, NamedTuple, ...), and that position map is cached on first sight of the type; an AbstractDict is looked up by name on every call.