DySEIR

The DySEIR (Dynamic SEIR) Model extends the classical SEIR model to time-varying networks. Instead of a fixed graph \(G=(V,E)\), diffusion evolves on a sequence of graph snapshots \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\), where the edge set \(E^{(k)}\) may change at each discrete time step \(k\). Each node can be in one of four states: \(S\) (susceptible), \(E\) (exposed/incubating), \(I\) (infected), or \(R\) (recovered).

A susceptible node \(i\) can be exposed by infected neighbors \(j \in N^{(k)}(i)\) with infection rate \(\beta\); exposed nodes become infectious with latent-progress rate \(\alpha\); infected nodes recover with rate \(\gamma\):

\[\begin{split}\begin{aligned} \frac{dS_i}{dt}\bigg|_{t=k} &= -\beta \sum_{j\in N^{(k)}(i)} S_i I_j, \\ \frac{dE_i}{dt}\bigg|_{t=k} &= \beta \sum_{j\in N^{(k)}(i)} S_i I_j - \alpha E_i, \\ \frac{dI_i}{dt}\bigg|_{t=k} &= \alpha E_i - \gamma I_i, \\ \frac{dR_i}{dt}\bigg|_{t=k} &= \gamma I_i . \end{aligned}\end{split}\]

Compared with the static SEIR model on a single graph, the DySEIR model captures the impact of evolving topology on exposure, infection, and recovery dynamics. The number of simulation steps is bounded by the length of the snapshot sequence \(T\).

Implementation

Node transitions follow three rules:

  1. if a \(S\) state node has \(I\) state neighbors in the current snapshot, each \(I\) state neighbor exposes it with probability \(\beta\) (S→E);

  2. an \(E\) state node becomes \(I\) with probability \(\alpha\) (E→I);

  3. an \(I\) state node is recovered to \(R\) with probability \(\gamma\) (I→R).

Node states are represented by three Boolean indicator vectors \(h, e, r \in \{0,1\}^N\), where \(h_i=1\) denotes infected or exposed, \(h_i=0\) denotes susceptible or recovered, \(e_i=1\) denotes exposed, and \(r_i=1\) denotes recovered. Therefore \((h_i,e_i,r_i)=(0,0,0)\) is susceptible, \((1,1,0)\) is exposed, \((1,0,0)\) is infected, and \((0,0,1)\) is recovered. The update at step \(k\) is decomposed into three stages:

1) Each infected (not exposed) neighbor \(j\) of node \(i\) in snapshot \(G^{(k)}\) transmits a log-probability contribution

\[m_{ji}^{(k)} = \mathbf{1}\!\left(h_j^{(k-1)}=1 \land e_j^{(k-1)}=0\right)\,\log\!\bigl(1-\beta\,w_{ji}^{(k)}\bigr)\]

where \(w_{ji}^{(k)}=1\) if edge weights are not provided.

  1. Node \(i\) aggregates contributions from neighbors \(N^{(k)}(i)\) to obtain exposure probability

\[m_i^{(k)} = \left(1-r_i^{(k-1)}\right)\!\left[1 - \exp\!\left( \sum_{j \in N^{(k)}(i)} m_{ji}^{(k)} \right)\right]\]

3) Indicator variables are updated with independent uniform random variables \(U_i^{\mathrm{exp}}, U_i^{\mathrm{inf}}, U_i^{\mathrm{rec}} \sim \mathrm{Uniform}(0,1)\):

\[\begin{split}\begin{aligned} h_i^{(k)} &= \begin{cases} 1, & \text{if } (h_i^{(k-1)}=0 \land r_i^{(k-1)}=0) \land (U_i^{\mathrm{exp}} < m_i^{(k)}), \\[4pt] 0, & \text{if } (h_i^{(k-1)}=1 \land e_i^{(k-1)}=0) \land (U_i^{\mathrm{rec}} < \gamma), \\[4pt] h_i^{(k-1)}, & \text{otherwise}, \end{cases} \\[6pt] e_i^{(k)} &= \begin{cases} 1, & \text{if } (h_i^{(k-1)}=0 \land r_i^{(k-1)}=0) \land (U_i^{\mathrm{exp}} < m_i^{(k)}), \\[4pt] 0, & \text{if } e_i^{(k-1)}=1 \land (U_i^{\mathrm{inf}} < \alpha), \\[4pt] e_i^{(k-1)}, & \text{otherwise}, \end{cases} \\[6pt] r_i^{(k)} &= \begin{cases} 1, & \text{if } (h_i^{(k-1)}=1 \land e_i^{(k-1)}=0) \land (U_i^{\mathrm{rec}} < \gamma), \\[4pt] r_i^{(k-1)}, & \text{otherwise}. \end{cases} \end{aligned}\end{split}\]

As in other dynamic models, \(N^{(k)}(i)\) and optional edge weights \(w_{ji}^{(k)}\) are time-dependent and taken from the \(k\)-th snapshot. The total number of iterations is bounded by \(T =\) len(edge_index_list).

Status

During the simulation, a node can be in one of the following states:

Status

Code

Susceptible

0

Infected

1

Exposed

2

Recovered

3

DySEIRModel

class fs_gplib.Dynamic.DySEIRModel(x, edge_index_list, seeds, infection_beta: float, removal_gamma: float, latent_alpha: float, device='cpu', rand_seed=None, edge_attr_list=None)[source]

Bases: DiffusionModel

Dynamic SEIR (DySEIR) epidemic model on time-varying networks (dynamic network models).

This model extends the classical static SEIR dynamics (see the epidemic SEIRModel) to a sequence of graph snapshots \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\). Nodes progress through susceptible \(S\), exposed \(E\), infectious \(I\), and recovered \(R\). Infection pressure from infectious (non-exposed) neighbors uses probability \(\beta\) per contact (optionally scaled by edge_attr_list); exposed nodes advance to \(I\) with probability \(\alpha\) (latent_alpha); infectious nodes recover with probability \(\gamma\) (removal_gamma).

Returned tensors encode states as float values: susceptible 0, infected 1, exposed 2, recovered 3.

The number of simulation steps cannot exceed len(edge_index_list). Pass an explicit node tensor x (shape (N, 1)) and edge_index_list (and optional edge_attr_list) instead of a single PyG Data object.

Parameters:
  • x (torch.Tensor) -- Node feature tensor of shape (N, 1) (node count \(N\) from the leading dimension).

  • edge_index_list (list[torch.Tensor]) -- One edge_index tensor per snapshot, length \(T\), defining \(E^{(k)}\) at each step.

  • seeds (list[int] | float) -- Initially infectious seed nodes: a list of integer node IDs, or a float in (0, 1) to infect that fraction of nodes uniformly at random (same convention as static SEIR seeds).

  • infection_beta (float) -- Exposure probability \(\beta \in [0, 1]\) for each infectious neighbor (S→E).

  • latent_alpha (float) -- Latent progression probability \(\alpha \in [0, 1]\) (E→I).

  • removal_gamma (float) -- Recovery probability \(\gamma \in [0, 1]\) (I→R).

  • device (str | int) -- (optional) 'cpu' or a CUDA device index. Defaults to 'cpu'.

  • rand_seed (int | None) -- (optional) Random seed used when seeds is a float. Defaults to None.

  • edge_attr_list (list[torch.Tensor] | None) -- (optional) One edge-weight tensor per snapshot, aligned with edge_index_list. If None, weights are 1.

run_iteration()[source]

Advance the epidemic by one snapshot step.

The internal node_status is updated so that subsequent calls continue from the latest state. Requires at least one remaining snapshot.

Returns:

Node states after that step, shape (1, 1, N) (values 03).

Return type:

torch.Tensor

run_iterations(times)[source]

Run times consecutive snapshot steps on the evolving graph sequence.

The internal node_status is updated to the state after the last step. Requires len(edge_index_list) - t >= times where \(t\) is the number of steps already consumed on this process.

Parameters:

times (int) -- Number of snapshots to advance (must not exceed remaining snapshots).

Returns:

Node states after each step, stacked with shape (times, 1, N) (values 03).

Return type:

torch.Tensor

run_epoch()[source]

Run one Monte-Carlo realisation over the full snapshot sequence.

The process internal step counter is reset; node states are re-initialised before the epoch starts.

Returns:

Node states trajectory over all snapshots, shape (T, 1, N) with \(T =\) len(edge_index_list) (values 03).

Return type:

torch.Tensor

run_epochs(epochs, batch_size=200)[source]

Run multiple independent Monte-Carlo realisations in batches.

For each realisation the snapshot index is reset to the beginning and the epidemic is evolved through all snapshots. Node states are re-initialised before the run.

Parameters:
  • epochs (int) -- Total number of independent realisations.

  • batch_size (int) -- (optional) Parallel epochs per batch. Defaults to 200.

Returns:

Node states trajectories for all realisations, shape (T, E, N) where \(T =\) len(edge_index_list) and \(E\) is epochs (values 03).

Return type:

torch.Tensor

Note

Unlike the static SEIR model which accepts a single data object containing edge_index and edge_attr, the DySEIR model requires an explicit node tensor x and a list of edge index tensors edge_index_list representing dynamic network snapshots. Edge weights are similarly provided as a list edge_attr_list.