Dynamic Network Models

In many real-world systems — such as face-to-face contact networks, mobile communication networks, and transportation systems — the connections between individuals are not fixed but evolve over time. Dynamic network models capture this by operating on a sequence of graph snapshots \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\), where the node set \(V\) remains constant while the edge set \(E^{(k)}\) may change at each discrete time step \(k\).

Each dynamic model in FS_GPlib extends a corresponding static model from the Epidemic Models category to time-varying topologies. The propagation rules at each step are identical to their static counterparts, but the neighbor set and (optionally) edge weights are drawn from the current snapshot rather than a fixed graph. This enables the study of how temporal connectivity patterns affect spreading outcomes.

All dynamic network models support directed and undirected graphs with optional time-varying edge weights. They can be executed on both CPU and GPU, and are compatible with the batch-parallel acceleration described in the Tutorial.

Base Class & Common API

Every dynamic network model inherits from DiffusionModel, which provides the shared initialisation pipeline and a uniform simulation interface. Understanding the base class helps you leverage the full API of any concrete model.

Unlike the static-graph base classes, dynamic models take a node tensor x and a list of per-snapshot edge indices edge_index_list (instead of a single PyG Data object). The maximum number of simulation steps is bounded by the number of snapshots \(T =\) len(edge_index_list).

class fs_gplib.Dynamic.base.DiffusionModel(x, edge_index_list, seeds: float | List[int] | None, rand_seed=None, device='cpu', edge_attr_list=None, **kwargs)[source]

Base class for all dynamic-network diffusion models.

DiffusionModel (in the Dynamic package) provides the shared initialisation logic and a uniform simulation interface that every concrete dynamic model (DySI, DySIR, DySEIR, DyThreshold, …) inherits. Users typically do not instantiate this class directly; instead they create a subclass such as DySIRModel.

Unlike the static-graph base classes in the Epidemics and Opinions packages, dynamic models operate on a snapshot sequence \(\{G^{(k)}=(V,E^{(k)})\}_{k=1}^{T}\) where the edge set changes at every step while the node set \(V\) remains fixed. The input is therefore a node tensor x and a list of per-snapshot edge indices edge_index_list (with optional edge_attr_list for time-varying weights).

Initialisation pipeline (executed in __init__):

  1. Validate the input graph data via _validate_graph().

  2. Initialise seed nodes via _initialize_seeds().

  3. Validate and store model-specific parameters via _validate_parameters().

  4. Transfer the model to the target device via _set_device().

Simulation interface – four progressively higher-level entry points:

Method

Description

run_iteration()

Advance one snapshot step from the current state.

run_iterations(times)

Advance times snapshot steps from the current state.

run_epoch()

Reset state, then run through all snapshots (one independent realisation).

run_epochs(epochs, batch_size)

Run epochs independent realisations in batches (Monte-Carlo simulation over all snapshots).

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

  • edge_index_list (list[torch.Tensor]) -- A list of edge_index tensors, one per snapshot. The list length \(T\) determines the maximum number of simulation steps.

  • seeds (float | list[int] | None) -- Initial infected (or activated) node set. A list of node IDs or a float in [0, 1) representing the fraction of nodes to infect uniformly at random. None is accepted for models that do not require seeds.

  • rand_seed (int | None) -- Random seed for NumPy, used when seeds is a float to make the random selection reproducible. Defaults to None.

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

  • edge_attr_list (list[torch.Tensor] | None) -- (optional) A list of per-snapshot edge-weight tensors aligned with edge_index_list. If None, all edge weights default to 1.

  • kwargs -- Model-specific parameters (e.g. infection_beta, recovery_lambda). Each key-value pair is validated to lie in [0, 1] and stored as an instance attribute.

Utility Methods

The following utility methods can be called on any dynamic model instance to re-configure the model after construction:

DiffusionModel._set_seed(seeds)[source]

Replace the current seed set and refresh node states.

This is the recommended way to change seed nodes after construction. It calls _initialize_seeds() to parse and store the new seeds, then (if the model is fully initialised) _init_node_status() to rebuild the node-state tensors on the current device.

Parameters:

seeds (float | list[int] | None) -- New seed specification – same format as the constructor parameter seeds (a float fraction, a list of node IDs, or None).

Example

model = DySIRModel(x, edge_index_list, seeds=[0, 1], ...)
# switch to a random 10 % seed set
model._set_seed(0.1)
DiffusionModel._init_node_status()[source]

Reset all node states to the initial configuration.

This method rebuilds the internal node_status tensor(s) so that only the seed nodes are in the Infected (or Activated) state and all other nodes are Susceptible.

Subclasses must override this method to create the status tensors appropriate for their compartmental structure.

Calling this method is useful when you want to rerun a simulation from scratch without reconstructing the model object.

Example

result1 = model.run_iterations(5)
model._init_node_status()   # reset
result2 = model.run_iterations(5)
DiffusionModel._set_device(device)[source]

Set (or switch) the computation device for the model.

When called during initialisation the internal tensors are moved to the target device. Subclasses override this method to also move the message-passing process module to the device.

Parameters:

device (str | int) -- 'cpu' or a CUDA device index (e.g. 0).

Raises:

Exception -- If a GPU is requested but CUDA is not available.

Example

model = DySIRModel(x, edge_index_list, seeds, ...)
model._set_device(0)  # switch to GPU 0

Simulation Interface

All dynamic models expose four progressively higher-level simulation methods. Note that run_epoch / run_epochs always iterate through the entire snapshot sequence and therefore do not accept an iterations_times parameter (unlike the static-graph models).

Method

Description

Resets state?

Model.run_iteration()

Advance one snapshot step from the current state.

No

Model.run_iterations(times)

Advance times snapshot steps from the current state.

No

Model.run_epoch()

Reset to initial state, then run through all snapshots (one independent realisation).

Yes

Model.run_epochs(epochs, batch_size)

Run epochs independent realisations in batches, each covering all snapshots (Monte-Carlo simulation).

Yes

Tip

run_iteration / run_iterations do not reset node states or the snapshot counter, so they can be used to inspect intermediate states or implement early-stopping logic. run_epoch / run_epochs always start from snapshot 0 with the initial seed configuration and are the recommended entry points for Monte-Carlo studies.

Available Models

The following models are available: