DySEIR_ct

The DySEIR_ct (Dynamic SEIR with continuous-time transition hazards) model extends the classical SEIR process 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 step \(k\). Each node can be in one of four states: \(S\) (susceptible), \(E\) (exposed), \(I\) (infected), or \(R\) (recovered).

Compared with the discrete DySEIR model, DySEIR_ct keeps the same \(S\to E\) infection mechanism but uses elapsed-time dependent transition probabilities for \(E\to I\) and \(I\to R\). For node \(i\), if \(\Delta t_i^E\) is time since entering \(E\), and \(\Delta t_i^I\) is time since entering \(I\), then

\[P(E\to I) = 1-\exp(-\alpha\Delta t_i^E), \qquad P(I\to R) = 1-\exp(-\gamma\Delta t_i^I).\]

This design captures non-memoryless progression and recovery effects while still running on snapshot-based dynamic contact networks.

Implementation

Node states are represented by three Boolean vectors \(h,e,r \in \{0,1\}^N\) plus two integer entry-time tensors \(t^E,t^I\):

  • \(h_i=1\) indicates node \(i\) is infected or exposed; \(h_i=0\) indicates susceptible or recovered.

  • \((h_i,e_i,r_i)=(1,0,0)\) denotes infected, \((h_i,e_i,r_i)=(1,1,0)\) denotes exposed.

  • \((h_i,e_i,r_i)=(0,0,1)\) denotes recovered, \((h_i,e_i,r_i)=(0,0,0)\) denotes susceptible.

  • \(t_i^{E}\) records the iteration \(k\) when node \(i\) entered E.

  • \(t_i^{I}\) records the iteration \(k\) when node \(i\) entered I.

At step \(k\), define \(\Delta t_i^E = k - t_i^E\) and \(\Delta t_i^I = k - t_i^I\). The update has three stages:

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

\[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)\]

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

\[m_i^{(k)} = 1-\exp\!\left(\sum_{j\in N^{(k)}(i)}m_{ji}^{(k)}\right)\]
  1. The integer tensors and 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} t_i^E &= k, \text{if } (U_i^{\mathrm{exp}}<m_i^{(k)}) \land (h_i^{(k-1)}=0 \land r_i^{(k-1)}=0) \\ t_i^I &= k, \text{if } (U_i^{\mathrm{inf}}<1-exp(-\alpha \cdot \Delta t_i^E)) \land e_i^{(k-1)}=1 \end{aligned}\end{split}\]
\[\begin{split}\begin{aligned} h_i^{(k)} &= \begin{cases} 1, & \text{if } (U_i^{\mathrm{exp}} < m_i^{(k)}) \land (h_i^{(k-1)}=0 \land r_i^{(k-1)}=0), \\[4pt] 0, & \text{if } (U_i^{\mathrm{rec}} < 1-exp(-\gamma\cdot \Delta t_i^I)) \land (h_i^{(k-1)}=1 \land e_i^{(k-1)}=0), \\[4pt] h_i^{(k-1)}, & \text{otherwise}, \end{cases} \\[6pt] e_i^{(k)} &= \begin{cases} 1, & \text{if } (U_i^{\mathrm{exp}} < m_i^{(k)}) \land (h_i^{(k-1)}=0 \land r_i^{(k-1)}=0), \\[4pt] 0, & \text{if } (U_i^{\mathrm{inf}} < 1-exp(-\alpha \cdot \Delta t_i^E)) \land e_i^{(k-1)}=1 , \\[4pt] e_i^{(k-1)}, & \text{otherwise}, \end{cases} \\[6pt] r_i^{(k)} &= \begin{cases} 1, & \text{if } (U_i^{\mathrm{rec}} < 1-exp(-\gamma\cdot \Delta t_i^I)) \land (h_i^{(k-1)}=1 \land e_i^{(k-1)}=0), \\[4pt] r_i^{(k-1)}, & \text{otherwise}. \end{cases} \end{aligned}\end{split}\]

As in other dynamic models, neighbors \(N^{(k)}(i)\) and optional edge weights \(w_{ji}^{(k)}\) are read 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

DySEIRctModel

class fs_gplib.Dynamic.DySEIRctModel(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 with continuous-time hazards (DySEIR_ct) on time-varying networks.

This dynamic network model runs SEIR diffusion on a snapshot sequence \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\). The infection mechanism for \(S\to E\) follows the (discrete) DySEIR model: infectious neighbors in the current snapshot expose a susceptible node with probability \(\beta\) per contact (optionally scaled by snapshot edge weights).

Unlike DySEIR, transitions \(E\to I\) and \(I\to R\) are governed by elapsed-time dependent probabilities. If a node entered state \(E\) at iteration \(t_i^E\) and state \(I\) at iteration \(t_i^I\), then at snapshot index \(k\):

  • \(P(E\to I)=1-\exp(-\alpha\,(k-t_i^E))\)

  • \(P(I\to R)=1-\exp(-\gamma\,(k-t_i^I))\)

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).

Parameters:
  • x (torch.Tensor) -- Node tensor of shape (N, 1).

  • edge_index_list (list[torch.Tensor]) -- List of snapshot edge_index tensors, length \(T\).

  • seeds (list[int] | float) -- Initially infectious nodes: list of node IDs or a float in (0,1).

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

  • latent_alpha (float) -- Hazard parameter \(\alpha > 0\) for E→I.

  • removal_gamma (float) -- Hazard parameter \(\gamma > 0\) for 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) Snapshot edge weights aligned with edge_index_list.

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_ct model which accepts a single graph object, DySEIR_ct requires a node tensor x and a snapshot list edge_index_list. Optional edge weights are provided by edge_attr_list with one tensor per snapshot.