Voter
The Voter model [1] is a classical binary opinion dynamics model. Each node holds a discrete opinion \(s \in \{0, 1\}\). At each time step: 1) a node \(i\) is selected uniformly at random from the network; 2) node \(i\) adopts the opinion of a randomly chosen neighbor \(j \in N(i)\).
This process is equivalent to computing the fraction of neighbors holding opinion 1, then updating the selected node's opinion by sampling a Bernoulli random variable with that fraction as the success probability:
where \(\#N(i)\) denotes the number of neighbors of node \(i\).
Implementation
The Voter model uses binary opinions, so each node's state is simply 0 or 1. At each iteration a single randomly chosen node updates its opinion via neighbor aggregation. Self-loops are removed to prevent a node from influencing itself.
For each neighbor \(j \in N(i)\), generate a message equal to its current opinion:
Node \(i\) aggregates received messages by computing the mean opinion of its neighbors:
A node index \(i\) is selected uniformly at random. Its opinion is updated by sampling:
where \(U_i \sim \mathrm{Uniform}(0,1)\) is a random number. All other nodes retain their current opinions.
Status
During the simulation, a node holds a binary opinion value:
Status |
Value |
|---|---|
Opinion |
0 or 1 |
VoterModel
- class fs_gplib.Opinions.VoterModel(data, seeds, device='cpu', rand_seed=None)[source]
Bases:
DiffusionModelBinary Voter opinion dynamics model on static graphs.
Each node holds a binary opinion in
{0, 1}. At every step, one node is selected uniformly at random and updates its opinion by copying a randomly chosen neighbor's opinion. In this implementation, that update is realised by computing the fraction of neighbors with opinion1and then sampling a Bernoulli random variable with that probability.Returned node states are encoded as: 0 = opinion 0, 1 = opinion 1.
Self-loops are removed internally so that a node does not influence its own opinion during the update.
- Parameters:
data (torch_geometric.data.Data) -- PyTorch Geometric
Dataobject representing graph \(G=(V,E)\). Must containedge_index(the edge set \(E\)) andnum_nodes(\(|V|\)).seeds (list[int] | float | None) -- Initial nodes with opinion
1. Pass a list of node IDs, a float in(0,1)to initialise that fraction of nodes chosen uniformly at random with opinion1, orNone.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.
- run_iteration()[source]
Execute a single opinion-update step.
The internal
node_statusis updated so that subsequent calls continue from the latest opinion configuration.- Returns:
Node opinions after one step, shape
(1, N).- Return type:
torch.Tensor
- run_iterations(times)[source]
Execute times opinion-update steps sequentially.
The internal
node_statusis updated in-place so that subsequent calls continue from the latest opinion configuration.- Parameters:
times (int) -- Number of steps to run.
- Returns:
Node opinions at final step, shape
(1, N).- Return type:
torch.Tensor
- run_epoch(iterations_times)[source]
Run a single Monte-Carlo epoch (one independent realisation).
Node opinions are re-initialised before the epoch starts.
- Parameters:
iterations_times (int) -- Number of opinion-update steps per epoch.
- Returns:
Node opinions at final step of the epoch, shape
(1, N).- Return type:
torch.Tensor
- run_epochs(epochs, iterations_times, batch_size=200)[source]
Run multiple independent Monte-Carlo epochs in batches.
Node opinions are re-initialised before the run.
- Parameters:
epochs (int) -- Total number of independent realisations.
iterations_times (int) -- Number of opinion-update steps per epoch.
batch_size (int) -- (optional) Number of epochs processed in parallel per batch. Defaults to
200.
- Returns:
Node opinions at final step of all epochs, shape
(epochs, N).- Return type:
torch.Tensor