Source code for netrd.dynamics.voter

"""
voter.py
--------

Implementation of voter model dynamics on a network.

author: Stefan McCabe

Submitted as part of the 2019 NetSI Collabathon.

"""

from netrd.dynamics import BaseDynamics
import numpy as np
import networkx as nx
from ..utilities import unweighted


[docs]class VoterModel(BaseDynamics): """Voter dynamics."""
[docs] @unweighted def simulate(self, G, L, noise=None): r"""Simulate voter-model-style dynamics on a network. Nodes are randomly assigned a state in :math:`\{-1, 1\}`; at each time step all nodes asynchronously update by choosing their new state uniformly from their neighbors. Generates an :math:`N \times L` time series. The results dictionary also stores the ground truth network as `'ground_truth'`. Parameters ---------- G (nx.Graph) the input (ground-truth) graph with `N` nodes. L (int) the length of the desired time series. noise (float, str or None) if noise is present, with this probability a node's state will be randomly redrawn from :math:`\{-1, 1\}` independent of its neighbors' states. If 'automatic', set noise to :math:`1/N`. Returns ------- TS (np.ndarray) an :math:`N \times L` array of synthetic time series data. """ N = G.number_of_nodes() if noise is None: noise = 0 elif noise == 'automatic' or noise == 'auto': noise = 1 / N elif not isinstance(noise, (int, float)): raise ValueError("noise must be a number, 'automatic', or None") transitions = nx.to_numpy_array(G) transitions = transitions / np.sum(transitions, axis=0) TS = np.zeros((N, L)) TS[:, 0] = [1 if x < 0.5 else -1 for x in np.random.rand(N)] indices = np.arange(N) for t in range(1, L): np.random.shuffle(indices) TS[:, t] = TS[:, t - 1] for i in indices: TS[i, t] = np.random.choice(TS[:, t], p=transitions[:, i]) if np.random.rand() < noise: TS[i, t] = 1 if np.random.rand() < 0.5 else -1 self.results['ground_truth'] = G self.results['TS'] = TS return TS