DySI

The DySI (Dynamic SI) Model extends the classical SI model to time-varying networks. Instead of a fixed graph \(G=(V,E)\), the system evolves on a sequence of graph snapshots \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\), where the edge set \(E^{(k)}\) changes at each discrete time step \(k\). Each node is in one of two states: \(S\) (susceptible) or \(I\) (infected). A susceptible node \(i\) becomes infected by its infected neighbors \(j \in N^{(k)}(i)\) in the current snapshot with rate \(\beta\):

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

Compared with the static SI model which operates on a single fixed graph, the DySI model captures the influence of evolving network topology on infection dynamics. The number of simulation steps is bounded by the length of the snapshot sequence \(T\).

Implementation

Node transitions follow two rules:

  1. if a \(S\) state node has \(I\) state neighbors in the current snapshot \(G^{(k)}\), each \(I\) state neighbor transmits the infection to the \(S\) state node with probability \(\beta\);

  2. once infected, the node remains infected forever.

Node states are represented by a Boolean indicator vector \(h \in \{0,1\}^N\), where \(h_i=1\) denotes infected and \(h_i=0\) denotes susceptible. The update of the system at step \(k\) is decomposed into three stages:

  1. Each infected neighbor \(j\) of node \(i\) in the current snapshot transmits a log-probability contribution

\[m_{ji}^{(k)} = h_j^{(k-1)} \cdot \log\!\bigl(1-\beta\bigr)\]
  1. Node \(i\) collects contributions from all neighbors \(N^{(k)}(i)\) to compute its infection probability

\[m_i^{(k)} = 1 - \exp\!\left( \sum_{j \in N^{(k)}(i)} m_{ji}^{(k)} \right)\]
  1. The indicator variable is updated with independent uniform random variables \(U_i^{\mathrm{inf}} \sim \mathrm{Uniform}(0,1)\):

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

The key distinction from the static SI model is that the neighbor set \(N^{(k)}(i)\) and the edge weights \(w_{ji}^{(k)}\) (If provided) are time-dependent, drawn from the \(k\)-th graph snapshot. The total number of iterations is bounded by the number of available snapshots \(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

DySIModel

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

Bases: DiffusionModel

Dynamic SI (DySI) epidemic model on time-varying networks (dynamic network models).

This model extends the classical static SI dynamics (see the epidemic SIModel) to a sequence of graph snapshots \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\): at step \(k\) infections propagate only along edges present in \(E^{(k)}\). Each infected neighbor transmits with probability \(\beta\) (optionally scaled by per-edge weights in edge_attr_list); once infected, a node stays infected.

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

Parameters:
  • x (torch.Tensor) -- Node feature tensor of shape (N, 1) (node count \(N\) is inferred 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 infected nodes: a list of integer node IDs, or a float in (0, 1) to infect that fraction of nodes chosen uniformly at random.

  • infection_beta (float) -- Per-contact infection probability \(\beta \in [0, 1]\).

  • 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, all edge weights are treated as 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:

State tensor after that step, shape (1, 1, N).

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:

States after each of the times steps, stacked with shape (times, 1, N).

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:

State trajectory over all snapshots, shape (T, 1, N) with \(T =\) len(edge_index_list).

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:

Trajectories for all realisations, shape (T, E, N) where \(T =\) len(edge_index_list) and \(E\) is epochs.

Return type:

torch.Tensor

Note

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