Source code for hypergraphx.dynamics.contagion

import numpy as np


[docs] def simplicial_contagion(hypergraph, I_0, T, beta, beta_D, mu, *, seed=None, rng=None): """ Simulates the contagion process on a simplicial hypergraph. The process is run for T time steps. The initial condition is given by I_0, which is a dictionary where the keys are the nodes and the values are 1 if the node is infected and 0 otherwise. The infection rate is beta, the three-body infection rate is beta_D, and the recovery rate is mu. The output is a vector of length T, where the i-th entry is the fraction of infected nodes at time i. Parameters ---------- hypergraph : hypergraphx.Hypergraph The hypergraph on which the contagion process is run. I_0 : dictionary The initial condition of the contagion process. T : int The number of time steps. beta : float The infection rate. beta_D : float The three-body infection rate. mu : float The recovery rate. seed : int, optional (keyword-only) Seed for reproducibility. Ignored if `rng` is provided. rng : numpy.random.Generator, optional (keyword-only) Random number generator to use. If provided, makes the simulation reproducible without touching global RNG state. Returns ------- numpy.ndarray The fraction of infected nodes at each time step. """ if rng is not None and seed is not None: raise ValueError("Provide only one of seed= or rng=.") rng = rng if rng is not None else np.random.default_rng(seed) numberInf = np.linspace(0, 0, T) Infected = sum(I_0.values()) numberInf[0] = Infected N = len(I_0) nodes = hypergraph.get_nodes() mapping = hypergraph.get_mapping() I_old = I_0.copy() t = 1 while Infected > 0 and t < T: # I_new = np.copy(I_old) I_new = I_old.copy() # We run over the nodes for node in nodes: # if the node is susceptible, we run the infection process if I_old[node] == 0: # we first run the two-body infections neighbors = hypergraph.get_neighbors(node, order=1) for neigh in neighbors: if I_old[neigh] == 1 and rng.random() < beta: I_new[node] = 1 break # if the susceptile node gets infected, we stop iterating over its neighbors if I_new[node] == 1: continue # if the susceptile node is already infected, we don't run the three-body processes # we run the three-body infections triplets = hypergraph.get_incident_edges(node, order=2) for triplet in triplets: neighbors = list(triplet) neighbors.remove(node) neigh1, neigh2 = tuple(neighbors) if ( I_old[neigh1] == 1 and I_old[neigh2] == 1 and rng.random() < beta_D ): I_new[node] = 1 break # if the susceptile node gets infected, we stop iterating over the triplets # if the node is infected, we run the recovery process elif rng.random() < mu: I_new[node] = 0 I_old = I_new.copy() Infected = sum(I_new.values()) numberInf[t] = Infected t = t + 1 return numberInf / N