NDlib - Network Diffusion Library¶


NDlib
is a Python software package that allows to describe, simulate, and study diffusion processes on complex networks.
Date | Python Versions | Main Author | GitHub | pypl |
2018-01-25 | 2.7.x/3.x | Giulio Rossetti | Source | Distribution |
If you use NDlib
as support to your research consider citing:
G. Rossetti, L. Milli, S. Rinzivillo, A. Sirbu, D. Pedreschi, F. Giannotti. “NDlib: a Python Library to Model and Analyze Diffusion Processes Over Complex Networks” Journal of Data Science and Analytics. 2017. DOI:0.1007/s41060-017-0086-6 (pre-print available on arXiv)
G. Rossetti, L. Milli, S. Rinzivillo, A. Sirbu, D. Pedreschi, F. Giannotti. “NDlib: Studying Network Diffusion Dynamics” IEEE International Conference on Data Science and Advanced Analytics, DSAA. 2017.
NDlib Dev Team¶
Name | Contribution |
Giulio Rossetti | Library Design/Documentation |
Letizia Milli | Epidemic Models |
Alina Sirbu | Opinion Dynamics Model |
Salvatore Rinzivillo | Visual Platform |
Overview¶
NDlib
is a Python language software package for the describing, simulate, and study diffusion processes on complex netowrks.
Who uses NDlib?¶
The potential audience for NDlib
includes mathematicians, physicists, biologists, computer scientists, and social scientists.
Goals¶
NDlib
is built upon the NetworkX python library and is intended to provide:
- tools for the study diffusion dynamics on social, biological, and infrastructure networks,
- a standard programming interface and diffusion models implementation that is suitable for many applications,
- a rapid development environment for collaborative, multidisciplinary, projects.
The Python NDlib library¶
NDlib
is a powerful Python package that allows simple and flexible simulations of networks diffusion processes.
Most importantly, NDlib
, as well as the Python programming language, is free, well-supported, and a joy to use.
Free software¶
NDlib
is free software; you can redistribute it and/or modify it under the terms of the BSD License.
We welcome contributions from the community.
EU H2020¶
NDlib
is a result of two European H2020 projects:
- CIMPLEX “Bringing CItizens, Models and Data together in Participatory, Interactive SociaL EXploratories”: under the funding scheme “FETPROACT-1-2014: Global Systems Science (GSS)”, grant agreement #641191.
- SoBigData “Social Mining & Big Data Ecosystem”: under the scheme “INFRAIA-1-2014-2015: Research Infrastructures”, grant agreement #654024.
Download¶
Software¶
Source and binary releases: https://pypi.python.org/pypi/ndlib
Github (latest development): https://github.com/GiulioRossetti/ndlib
Github NDlib-REST: https://github.com/GiulioRossetti/ndlib-rest
Github NDlib-Viz: https://github.com/rinziv/NDLib-Viz
Documentation¶
Installing NDlib¶
Before installing NDlib
, you need to have setuptools installed.
Quick install¶
Get NDlib
from the Python Package Index at pypl.
or install it with
pip install ndlib
and an attempt will be made to find and install an appropriate version that matches your operating system and Python version.
You can install the development version with
pip install git://github.com/GiulioRossetti/ndlib.git
Installing from source¶
You can install from source by downloading a source archive file (tar.gz or zip) or by checking out the source files from the GitHub source code repository.
NDlib
is a pure Python package; you don’t need a compiler to build or install it.
Source archive file¶
Download the source (tar.gz or zip file) from pypl or get the latest development version from GitHub
Unpack and change directory to the source directory (it should have the files README.txt and setup.py).
Run python setup.py install to build and install
GitHub¶
Clone the NDlib repostitory (see GitHub for options)
git clone https://github.com/GiulioRossetti/ndlib.git
Change directory to ndlib
Run python setup.py install to build and install
If you don’t have permission to install software on your system, you can install into another directory using the –user, –prefix, or –home flags to setup.py.
For example
python setup.py install --prefix=/home/username/python
or
python setup.py install --home=~
or
python setup.py install --user
If you didn’t install in the standard Python site-packages directory you will need to set your PYTHONPATH variable to the alternate location. See http://docs.python.org/2/install/index.html#search-path for further details.
Requirements¶
Python¶
To use NDlib you need Python 2.7, 3.2 or later.
The easiest way to get Python and most optional packages is to install the Enthought Python distribution “Canopy” or using Anaconda.
There are several other distributions that contain the key packages you need for scientific computing.
Required packages¶
The following are packages required by NDlib
.
NetworkX¶
Provides the graph representation used by the diffusion models implemented in NDlib
.
Download: http://networkx.github.io/download.html
Optional packages¶
The following are optional packages that NDlib
can use to provide additional functions.
Bokeh¶
Provides support to the visualization facilities offered by NDlib
.
Download: http://bokeh.pydata.org/en/latest/
Other packages¶
These are extra packages you may consider using with NDlib
IPython, interactive Python shell, http://ipython.scipy.org/
Tutorial¶
NDlib is built upon networkx and is designed to configure, simulate and visualize diffusion experiments.
Installation¶
In order to install the latest version of the library (with visualization facilities) use
pip install ndlib
Chose a Diffusion model¶
Let’s start importing the required libraries
import networkx as nx
import ndlib.models.epidemics.SIRModel as sir
Once imported the selected model, SIR, and the networkx library we can initialize the simulation:
# Network Definition
g = nx.erdos_renyi_graph(1000, 0.1)
# Model Selection
model = sir.SIRModel(g)
Configure the simulation¶
Each model has its own parameters: in order to completely instantiate the simulation we need to specify them using a Configuration
object:
import ndlib.models.ModelConfig as mc
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('beta', 0.001)
config.add_model_parameter('gamma', 0.01)
config.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(config)
The model configuration allows to specify model parameters (as in this scenario) as well as nodes’ and edges’ ones (e.g. individual thresholds).
Moreover it allows to specify the initial percentage of infected nodes using the percentage_infected
model parameter.
It is also possible to explicitly specify an initial set of infected nodes: see ModelConfig for the complete set of use cases.
Execute the simulation¶
In order to execute the simulation one, or more, iterations must be required using the model.iteration()
and/or model.iteration_bunch(n_iterations)
methods.
# Simulation
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
Visualize the results¶
At the end of the simulation the diffusion trend can be visualized as follows (for matplotlib
change ndlib.viz.bokeh
in ndlib.viz.mpl
)
from bokeh.io import output_notebook, show
from ndlib.viz.bokeh.DiffusionTrend import DiffusionTrend
viz = DiffusionTrend(model, trends)
p = viz.plot(width=400, height=400)
show(p)
Furthermore, a prevalence plot is also made available.
The prevalence plot captures the variation (delta) of nodes for each status in consecutive iterations.
from ndlib.viz.bokeh.DiffusionPrevalence import DiffusionPrevalence
viz2 = DiffusionPrevalence(model, trends)
p2 = viz2.plot(width=400, height=400)
show(p2)
Multiple plots can be combined in a multiplot to provide a complete description of the diffusive process
from ndlib.viz.bokeh.MultiPlot import MultiPlot
vm = MultiPlot()
vm.add_plot(p)
vm.add_plot(p2)
m = vm.plot()
show(m)
Multiplots - implemented only for the bokeh
provider - are also useful to compare different diffusion models applied to the same graph (as well as a same model instantiated with different parameters)
import ndlib.models.epidemics.SISModel as sis
import ndlib.models.epidemics.SIModel as si
import ndlib.models.epidemics.ThresholdModel as th
vm = MultiPlot()
vm.add_plot(p)
# SIS
sis_model = sis.SISModel(g)
config = mc.Configuration()
config.add_model_parameter('beta', 0.001)
config.add_model_parameter('lambda', 0.01)
config.add_model_parameter("percentage_infected", 0.05)
sis_model.set_initial_status(config)
iterations = sis_model.iteration_bunch(200)
trends = model.build_trends(iterations)
viz = DiffusionTrend(sis_model, trends)
p3 = viz.plot(width=400, height=400)
vm.add_plot(p3)
# SI
si_model = si.SIModel(g)
config = mc.Configuration()
config.add_model_parameter('beta', 0.001)
config.add_model_parameter("percentage_infected", 0.05)
si_model.set_initial_status(config)
iterations = si_model.iteration_bunch(200)
trends = model.build_trends(iterations)
viz = DiffusionTrend(si_model, trends)
p4 = viz.plot(width=400, height=400)
vm.add_plot(p4)
# Threshold
th_model = th.ThresholdModel(g)
config = mc.Configuration()
# Set individual node threshold
threshold = 0.40
for n in g.nodes():
config.add_node_configuration("threshold", n, threshold)
config.add_model_parameter("percentage_infected", 0.30)
th_model.set_initial_status(config)
iterations = th_model.iteration_bunch(60)
trends = model.build_trends(iterations)
viz = DiffusionTrend(th_model, trends)
p5 = viz.plot(width=400, height=400)
vm.add_plot(p5)
m = vm.plot()
show(m)
Network Diffusion Library Reference¶
In this section are introduced the components that constitute NDlib
, namely
- The implemented diffusion models (organized in Epidemics and Opinion Dynamics)
- The methodology adopted to configure a general simulation
- The visualization facilities embedded in the library to explore the results
Advanced topics (Custom model definition, Network Diffusion Query language (NDQL), Experiment Server and Visual Framework) are reported in separate sections.
Diffusion Models¶
The analysis of diffusive phenomena that unfold on top of complex networks is a task able to attract growing interests from multiple fields of research.
In order to provide a succinct framing of such complex and extensively studied problem it is possible to split the related literature into two broad, related, sub-classes: Epidemics and Opinion Dynamics.
Moreover, NDlib
also supports the simulation of diffusive processes on top of evolving network topologies: the Dynamic Network Models section the ones NDlib
implements.
Epidemics¶
When we talk about epidemics, we think about contagious diseases caused by biological pathogens, like influenza, measles, chickenpox and sexually transmitted viruses that spread from person to person. However, other phenomena can be linked to the concept of epidemic: think about the spread of computer virus [1] where the agent is a malware that can transmit a copy of itself from computer to computer, or the spread of mobile phone virus [2] [3], or the diffusion of knowledge, innovations, products in an online social network [4] - the so-called “social contagion”, where people are making decision to adopt a new idea or innovation.
Several elements determine the patterns by which epidemics spread through groups of people: the properties carried by the pathogen (its contagiousness, the length of its infectious period and its severity), the structure of the network as well as the mobility patterns of the people involved. Although often treated as similar processes, diffusion of information and epidemic spreading can be easily distinguished by a single feature: the degree of activeness of the subjects they affect.
Indeed, the spreading process of a virus does not require an active participation of the people that catch it (i.e., even though some behaviors acts as contagion facilitators – scarce hygiene, moist and crowded environment – we can assume that no one chooses to get the flu on purpose); conversely, we can argue that the diffusion of an idea, an innovation, or a trend strictly depend not only by the social pressure but also by individual choices.
In NDlib
are implemented the following Epidemic models:
SI¶
The SI model was introduced in 1927 by Kermack [1].
In this model, during the course of an epidemics, a node is allowed to change its status only from Susceptible (S) to Infected (I).
The model is instantiated on a graph having a non-empty set of infected nodes.
SI assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected with probability β: once a node becomes infected, it stays infected (the only transition allowed is S→I).
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.SIModel.
SIModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: beta – The infection rate (float value in [0,1])
-
SIModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
SIModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SIModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SIModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SIModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SIModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
SIModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an SI simulation on a random graph: we set the initial set of infected nodes as 5% of the overall population and a probability of infection of 1%.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIModel as si
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = si.SIModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.01)
cfg.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
SIS¶
The SIS model was introduced in 1927 by Kermack [1].
In this model, during the course of an epidemics, a node is allowed to change its status from Susceptible (S) to Infected (I).
The model is instantiated on a graph having a non-empty set of infected nodes.
SIS assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected with probability beta, than it can be switch again to susceptible with probability lambda (the only transition allowed are S→I→S).
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability | |
lambda | Model | float in [0, 1] | True | Recovery probability |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.SISModel.
SISModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: - beta – The infection rate (float value in [0,1])
- lambda – The recovery rate (float value in [0,1])
-
SISModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
SISModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SISModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SISModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SISModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SISModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
SISModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an SIS simulation on a random graph: we set the initial set of infected nodes as 5% of the overall population, a probability of infection of 1%, and a probability of recovery of 0.5%.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SISModel as sis
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sis.SISModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.01)
cfg.add_model_parameter('lambda', 0.005)
cfg.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
SIR¶
The SIR model was introduced in 1927 by Kermack [1].
In this model, during the course of an epidemics, a node is allowed to change its status from Susceptible (S) to Infected (I), then to Removed (R).
The model is instantiated on a graph having a non-empty set of infected nodes.
SIR assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected with probability beta, than it can be switch to removed with probability gamma (the only transition allowed are S→I→R).
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Removed | 2 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability | |
gamma | Model | float in [0, 1] | True | Removal probability |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.SIRModel.
SIRModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: - beta – The infection rate (float value in [0,1])
- gamma – The recovery rate (float value in [0,1])
-
SIRModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
SIRModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SIRModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SIRModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SIRModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SIRModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
SIRModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an SIR simulation on a random graph: we set the initial set of infected nodes as 5% of the overall population, a probability of infection of 1%, and a removal probability of 0.5%.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.01)
cfg.add_model_parameter('gamma', 0.005)
cfg.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
SEIR¶
In the SEIR model [1], during the course of an epidemics, a node is allowed to change its status from Susceptible (S) to Exposed (E) to Infected (I), then to Removed (R).
The model is instantiated on a graph having a non-empty set of infected nodes.
SEIR assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected after an exposition period with probability beta, than it can switch to removed with probability gamma (the only transition allowed are S→E→I→R).
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Exposed | 2 |
Removed | 3 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability | |
gamma | Model | float in [0, 1] | True | Removal probability | |
alpha | Model | float in [0, 1] | True | Incubation period |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.SEIRModel.
SEIRModel
(graph)¶
-
SEIRModel.
__init__
(graph)¶
-
SEIRModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SEIRModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SEIRModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SEIRModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SEIRModel.
iteration
(self)¶
-
SEIRModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an SEIR simulation on a random graph: we set the initial set of infected nodes as % of the overall population, a probability of infection of 1%, a removal probability of 0.5% and an incubation period of 5% (e.g. 20 iterations).
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SEIRModel as seir
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = seir.SEIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.01)
cfg.add_model_parameter('gamma', 0.005)
cfg.add_model_parameter('alpha', 0.05)
cfg.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] | J.L. Aron and I.B. Schwartz. Seasonality and period-doubling bifurcations in an epidemic model. Journal Theoretical Biology, 110:665-679, 1984 |
SEIS¶
In the SEIS model, during the course of an epidemics, a node is allowed to change its status from Susceptible (S) to Exposed (E) to Infected (I), then again to Susceptible (S).
The model is instantiated on a graph having a non-empty set of infected nodes.
SEIS assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected after an exposition period with probability beta, than it can switch back to susceptible with probability lambda (the only transition allowed are S→E→I→S).
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Exposed | 2 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability | |
lambda | Model | float in [0, 1] | True | Removal probability | |
alpha | Model | float in [0, 1] | True | Incubation period |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.SEISModel.
SEISModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: - beta – The infection rate (float value in [0,1])
- lambda – The recovery rate (float value in [0,1])
-
SEISModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
SEISModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SEISModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SEISModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SEISModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SEISModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
SEISModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an SEIS simulation on a random graph: we set the initial set of infected nodes as 5% of the overall population, a probability of infection of 1%, a removal probability of 0.5% and an incubation period of 5% (e.g. 20 iterations).
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SEISModel as seis
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = seis.SEISModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.01)
cfg.add_model_parameter('lambda', 0.005)
cfg.add_model_parameter('alpha', 0.05)
cfg.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
SWIR¶
The SWIR model was introduced in 2017 by Lee et al. [1].
In this model, during the epidemics, a node is allowed to change its status from Susceptible (S) to Weakened (W) or Infected (I), then to Removed (R).
The model is instantiated on a graph having a non-empty set of infected nodes.
At time t a node in the state I is selected randomly and the states of all neighbors are checked one by one. If the state of a neighbor is S then this state changes either i) to I with probability kappa or ii) to W with probability mu. If the state of a neighbor is W then the state W changes to I with probability nu. We repeat the above process for all nodes in state I and then changes to R for each associated node.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Weakened | 2 |
Removed | 3 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
kappa | Model | float in [0, 1] | True | ||
mu | Model | float in [0, 1] | True | ||
nu | Model | float in [0, 1] | True |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.SWIRModel.
SWIRModel
(graph)¶
-
SWIRModel.
__init__
(graph)¶
-
SWIRModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SWIRModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SWIRModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SWIRModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SWIRModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an SEIR simulation on a random graph: we set the initial set of infected nodes as % of the overall population, a probability of infection of 1%, a removal probability of 0.5% and an incubation period of 5% (e.g. 20 iterations).
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SWIRModel as swir
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = swir.SWIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('kappa', 0.01)
cfg.add_model_parameter('mu', 0.005)
cfg.add_model_parameter('nu', 0.05)
cfg.add_model_parameter("percentage_infected", 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
Threshold¶
The Threshold model was introduced in 1978 by Granovetter [1].
In this model during an epidemics, a node has two distinct and mutually exclusive behavioral alternatives, e.g., the decision to do or not do something, to participate or not participate in a riot.
Node’s individual decision depends on the percentage of its neighbors have made the same choice, thus imposing a threshold.
The model works as follows: - each node has its own threshold; - during a generic iteration every node is observed: iff the percentage of its infected neighbors is grater than its threshold it becomes infected as well.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
threshold | Node | float in [0, 1] | 0.1 | False | Individual threshold |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.ThresholdModel.
ThresholdModel
(graph)¶ - Node Parameters to be specified via ModelConfig
Parameters: threshold – The node threshold. If not specified otherwise a value of 0.1 is assumed for all nodes.
-
ThresholdModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
ThresholdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
ThresholdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
ThresholdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
ThresholdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
ThresholdModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
ThresholdModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Threshold model simulation on a random graph: we set the initial set of infected nodes as 1% of the overall population, and assign a threshold of 0.25 to all the nodes.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.ThresholdModel as th
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = th.ThresholdModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Setting node parameters
threshold = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
Generalised Threshold¶
The Generalised Threshold model was introduced in 2017 by Török and Kertesz [1].
In this model, during an epidemics, a node is allowed to change its status from Susceptible to Infected.
The model is instantiated on a graph having a non-empty set of infected nodes.
The model is defined as follows:
- At time t nodes become Infected with rate mu t/tau
- Nodes for which the ratio of the active friends dropped below the threshold are moved to the Infected queue
- Nodes in the Infected queue become infected with rate tau. If this happens check all its friends for threshold
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.GeneralisedThresholdModel.
GeneralisedThresholdModel
(graph)¶ - Node Parameters to be specified via ModelConfig
Parameters: threshold – The node threshold. If not specified otherwise a value of 0.1 is assumed for all nodes.
-
GeneralisedThresholdModel.
__init__
(graph)¶ Model Constructor :param graph: A networkx graph object
-
GeneralisedThresholdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
GeneralisedThresholdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
GeneralisedThresholdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
GeneralisedThresholdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
GeneralisedThresholdModel.
iteration
(self)¶ Execute a single model iteration :return: Iteration_id, Incremental node status (dictionary node->status)
-
GeneralisedThresholdModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Threshold model simulation on a random graph: we set the initial set of infected nodes as 1% of the overall population, and assign a threshold of 0.25 to all the nodes.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.GeneralisedThresholdModel as gth
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = gth.GeneralisedThresholdModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
config.add_model_parameter('tau', 5)
config.add_model_parameter('mu', 5)
# Setting node parameters
threshold = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] | János Török and János Kertész “Cascading collapse of online social networks” Scientific reports, vol. 7 no. 1, 2017 |
Kertesz Threshold¶
The Kertesz Threshold model was introduced in 2015 by Ruan et al. [1] and it is an extension of the Watts threshold model [2].
The authors extend the classical model introducing a density r of blocked nodes – nodes which are immune to social influence – and a probability of spontaneous adoption p to capture external influence.
Thus, the model distinguishes three kinds of node: Blocked (B), Susceptible (S) and Adoptiong (A). The latter class breaks into two categories: vulnerable and stable nodes. A node can adopt either under its neighbors’ influence, or spontaneously, due to endogenous effects.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Blocked | -1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
adopter_rate | Model | float in [0, 1] | 0 | False | Exogenous adoption rate |
percentage_blocked | Model | float in [0, 1] | 0.1 | False | Blocked nodes |
threshold | Node | float in [0, 1] | 0.1 | False | Individual threshold |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The initial blocked nodes can be defined via:
- percentage_blocked: Model Parameter, float in [0, 1]
- Blocked: Status Parameter, set of nodes
In both cases, the two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.KerteszThresholdModel.
KerteszThresholdModel
(graph)¶ - Node/Model Parameters to be specified via ModelConfig
Parameters: - threshold – The node threshold. As default a value of 0.1 is assumed for all nodes.
- adopter_rate – The probability of spontaneous adoptions. Defaults value 0.
- percentage_infected – The percentage of blocked nodes. Default value 0.1.
-
KerteszThresholdModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
KerteszThresholdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
KerteszThresholdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
KerteszThresholdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
KerteszThresholdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
KerteszThresholdModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
KerteszThresholdModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Kertesz Threshold model simulation on a random graph: we set the initial infected as well blocked node sets equals to the 10% of the overall population, assign a threshold of 0.25 to all the nodes and impose an probability of spontaneous adoptions of 40%.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.KerteszThresholdModel as ks
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = ks.KerteszThresholdModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('adopter_rate', 0.4)
config.add_model_parameter('percentage_blocked', 0.1)
config.add_model_parameter('percentage_infected', 0.1)
# Setting node parameters
threshold = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
[2] |
|
Independent Cascades¶
The Independent Cascades model was introduced by Kempe et all in 2003 [1].
This model starts with an initial set of active nodes A0: the diffusive process unfolds in discrete steps according to the following randomized rule:
- When node v becomes active in step t, it is given a single chance to activate each currently inactive neighbor w; it succeeds with a probability p(v,w).
- If w has multiple newly activated neighbors, their attempts are sequenced in an arbitrary order.
- If v succeeds, then w will become active in step t + 1; but whether or not v succeeds, it cannot make any further attempts to activate w in subsequent rounds.
- The process runs until no more activations are possible.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Removed | 2 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
Edge threshold | Edge | float in [0, 1] | 0.1 | False | Edge threshold |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.IndependentCascadesModel.
IndependentCascadesModel
(graph)¶ Edge Parameters to be specified via ModelConfig
Parameters: threshold – The edge threshold. As default a value of 0.1 is assumed for all edges.
-
IndependentCascadesModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
IndependentCascadesModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
IndependentCascadesModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
IndependentCascadesModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
IndependentCascadesModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
IndependentCascadesModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
IndependentCascadesModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of an Independent Cascades model simulation on a random graph: we set the initial set of infected nodes as 1% of the overall population, and assign a threshold of 0.1 to all the edges.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.IndependentCascadesModel as ids
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = ids.IndependentCascadesModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Setting the edge parameters
threshold = 0.1
for e in g.edges():
config.add_edge_configuration("threshold", e, threshold)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
Profile¶
The Profile model was introduced in 2017 by Milli et al. [1].
The Profile model assumes that the diffusion process is only apparent; each node decides to adopt or not a given behavior – once known its existence – only on the basis of its own interests.
In this scenario the peer pressure is completely ruled out from the overall model: it is not important how many of its neighbors have adopted a specific behaviour, if the node does not like it, it will not change its interests.
Each node has its own profile describing how many it is likely to accept a behaviour similar to the one that is currently spreading.
The diffusion process starts from a set of nodes that have already adopted a given behaviour S:
- for each of the susceptible nodes’ in the neighborhood of a node u in S an unbalanced coin is flipped, the unbalance given by the personal profile of the susceptible node;
- if a positive result is obtained the susceptible node will adopt the behaviour, thus becoming infected.
- if the blocked status is enabled, after having rejected the adoption with probability
blocked
a node becomes immune to the infection. - every iteration
adopter_rate
percentage of nodes spontaneous became infected to endogenous effects.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Blocked | -1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
profile | Node | float in [0, 1] | 0.1 | False | Node profile |
blocked | Model | float in [0, 1] | 0 | False | Blocked nodes |
adopter_rate | Model | float in [0, 1] | 0 | False | Autonomous adoption |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.ProfileModel.
ProfileModel
(graph)¶ - Node Parameters to be specified via ModelConfig
Parameters: profile – The node profile. As default a value of 0.1 is assumed for all nodes.
-
ProfileModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
ProfileModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
ProfileModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
ProfileModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
ProfileModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
ProfileModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
ProfileModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Profile model simulation on a random graph: we set the initial infected node set to the 10% of the overall population and assign a profile of 0.25 to all the nodes.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.ProfileModel as pr
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = pr.ProfileModel(g)
config = mc.Configuration()
config.add_model_parameter('blocked', 0)
config.add_model_parameter('adopter_rate', 0)
config.add_model_parameter('percentage_infected', 0.1)
# Setting nodes parameters
profile = 0.15
for i in g.nodes():
config.add_node_configuration("profile", i, profile)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] | Letizia Milli, Giulio Rossetti, Dino Pedreschi, Fosca Giannotti, “Information Diffusion in Complex Networks: The Active/Passive Conundrum,” Proceedings of International Conference on Complex Networks and their Applications, (pp. 305-313). Springer, Cham. 2017 |
Profile Threshold¶
The Profile-Threshold model was introduced in 2017 by Milli et al. [1].
The Profile-Threshold model assumes the existence of node profiles that act as preferential schemas for individual tastes but relax the constraints imposed by the Profile model by letting nodes influenceable via peer pressure mechanisms.
The peer pressure is modeled with a threshold.
The diffusion process starts from a set of nodes that have already adopted a given behaviour S:
- for each of the susceptible node an unbalanced coin is flipped if the percentage of its neighbors that are already infected excedes its threhosld. As in the Profile Model the coin unbalance is given by the personal profile of the susceptible node;
- if a positive result is obtained the susceptible node will adopt the behaviour, thus becoming infected.
- if the blocked status is enabled, after having rejected the adoption with probability
blocked
a node becomes immune to the infection. - every iteration
adopter_rate
percentage of nodes spontaneous became infected to endogenous effects.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Blocked | -1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
threshold | Node | float in [0, 1] | 0.1 | False | Individual threshold |
profile | Node | float in [0, 1] | 0.1 | False | Node profile |
blocked | Model | float in [0, 1] | 0 | False | Blocked nodes |
adopter_rate | Model | float in [0, 1] | 0 | False | Autonomous adoption |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.epidemics.ProfileThresholdModel.
ProfileThresholdModel
(graph)¶ Node Parameters to be specified via ModelConfig
Parameters: - profile – The node profile. As default a value of 0.1 is assumed for all nodes.
- threshold – The node threshold. As default a value of 0.1 is assumed for all nodes.
-
ProfileThresholdModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
ProfileThresholdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
ProfileThresholdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
ProfileThresholdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
ProfileThresholdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
ProfileThresholdModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
ProfileThresholdModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Profile Threshold model simulation on a random graph: we set the initial infected node set to the 10% of the overall population, assign a profile of 0.25 and a threshold of 0.15 to all the nodes.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.ProfileThresholdModel as pt
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = pt.ProfileThresholdModel(g)
config = mc.Configuration()
config.add_model_parameter('blocked', 0)
config.add_model_parameter('adopter_rate', 0)
config.add_model_parameter('percentage_infected', 0.1)
# Setting nodes parameters
threshold = 0.15
profile = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
config.add_node_configuration("profile", i, profile)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] | Letizia Milli, Giulio Rossetti, Dino Pedreschi, Fosca Giannotti, “Information Diffusion in Complex Networks: The Active/Passive Conundrum,” Proceedings of International Conference on Complex Networks and their Applications, (pp. 305-313). Springer, Cham. 2017 |
Opinion Dinamycs¶
A different field related with modelling social behaviour is that of opinion dynamics.
Recent years have witnessed the introduction of a wide range of models that attempt to explain how opinions form in a population [5], taking into account various social theories (e.g. bounded confidence [6] or social impact [7]).
These models have a lot in common with those seen in epidemics and spreading. In general, individuals are modelled as agents with a state and connected by a social network.
The social links can be represented by a complete graph (mean field models) or by more realistic complex networks, similar to epidemics and spreading.
The state is typically represented by variables, that can be discrete (similar to the case of spreading), but also continuous, representing for instance a probability to choose one option or another [8] . The state of individuals changes in time, based on a set of update rules, mainly through interaction with the neighbours.
While in many spreading and epidemics models this change is irreversible (susceptible to infected), in opinion dynamics the state can oscillate freely between the possible values, simulating thus how opinions change in reality.
A different important aspect in opinion dynamics is external information, which can be interpreted as the effect of mass media. In general external information is represented as a static individual with whom all others can interact, again present also in spreading models. Hence, it is clear that the two model categories have enough in common to be implemented under a common framework, which is why we introduced both in our framework.
In NDlib
are implemented the following Opinion Dynamics models:
Voter¶
The Voter model is one of the simplest models of opinion dynamics, originally introduced to analyse competition of species [1] and soon after applied to model elections [2].
The model assumes the opinion of an individual to be a discrete variable ±1.
The state of the population varies based on a very simple update rule: at each iteration, a random individual is selected, who then copies the opinion of one random neighbour.
Starting from any initial configuration, on a complete network the entire population converges to consensus on one of the two options. The probability that consensus is reached on opinion +1 is equal to the initial fraction of individuals holding that opinion [3].
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The initial blocked nodes can be defined via:
- percentage_blocked: Model Parameter, float in [0, 1]
- Blocked: Status Parameter, set of nodes
In both cases, the two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.opinions.VoterModel.
VoterModel
(graph)¶
-
VoterModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
VoterModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
VoterModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
VoterModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
VoterModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
VoterModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
VoterModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Voter model simulation on a random graph: we set the initial infected node set to the 10% of the overall population.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.opinions.VoterModel as vt
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = vt.VoterModel(g)
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
[2] |
|
[3] | P.L.Krapivsky,S.Redner,andE.Ben-Naim,Akineticviewofstatistical physics. Cambridge University Press, 2010. |
Q-Voter¶
The Q-Voter model was introduced as a generalisation of discrete opinion dynamics models [1].
Here, N individuals hold an opinion ±1. At each time step, a set of q neighbours are chosen and, if they agree, they influence one neighbour chosen at random, i.e. this agent copies the opinion of the group. If the group does not agree, the agent flips its opinion with probability ε.
It is clear that the voter and Sznajd models are special cases of this more recent model (q = 1,ε = 0 and q = 2,ε = 0).
Analytic results for q ≤ 3 validate the numerical results obtained for the special case models, with transitions from a ordered phase (small ε) to a disordered one (large ε). For q > 3, a new type of transition between the two phases appears, which consist of passing through an intermediate regime where the final state depends on the initial condition. We implemented in NDlib the model with ε = 0.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
q | Model | int in [0, V(G)] | True | Number of neighbours |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.opinions.QVoterModel.
QVoterModel
(graph)¶ Node Parameters to be specified via ModelConfig
Parameters: q – the number of neighbors that affect the opinion of a node
-
QVoterModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
QVoterModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
QVoterModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
QVoterModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
QVoterModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
QVoterModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
QVoterModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Q-Voter model simulation on a random graph: we set the initial infected node set to the 10% of the overall population and the number q of influencing neighbors equals to 5.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.opinions.QVoterModel as qvt
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = qvt.QVoterModel(g)
config = mc.Configuration()
config.add_model_parameter("q", 5)
config.add_model_parameter('percentage_infected', 0.1)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
Majority Rule¶
The Majority Rule model is a discrete model of opinion dynamics, proposed to describe public debates [1].
Agents take discrete opinions ±1, just like the Voter model. At each time step a group of r agents is selected randomly and they all take the majority opinion within the group.
The group size can be fixed or taken at each time step from a specific distribution. If r is odd, then the majority opinion is always defined, however if r is even there could be tied situations. To select a prevailing opinion in this case, a bias in favour of one opinion (+1) is introduced.
This idea is inspired by the concept of social inertia [2].
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
q | Model | int in [0, V(G)] | True | Number of neighbours |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.opinions.MajorityRuleModel.
MajorityRuleModel
(graph)¶
-
MajorityRuleModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
MajorityRuleModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
MajorityRuleModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
MajorityRuleModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
MajorityRuleModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
MajorityRuleModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
MajorityRuleModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Majority Rule model simulation on a random graph: we set the initial infected node set to the 10% of the overall population.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.opinions.MajorityRuleModel as mr
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = mr.MajorityRuleModel(g)
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] | S.Galam, “Minority opinion spreading in random geometry.” Eur.Phys. J. B, vol. 25, no. 4, pp. 403–406, 2002. |
[2] | R.Friedman and M.Friedman, “The Tyranny of the Status Quo.” Orlando, FL, USA: Harcourt Brace Company, 1984. |
Sznajd¶
The Sznajd model [1] is a variant of spin model employing the theory of social impact, which takes into account the fact that a group of individuals with the same opinion can influence their neighbours more than one single individual.
In the original model the social network is a 2-dimensional lattice, however we also implemented the variant on any complex networks.
Each agent has an opinion σi = ±1. At each time step, a pair of neighbouring agents is selected and, if their opinion coincides, all their neighbours take that opinion.
The model has been shown to converge to one of the two agreeing stationary states, depending on the initial density of up-spins (transition at 50% density).
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.opinions.SznajdModel.
SznajdModel
(graph)¶
-
SznajdModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
SznajdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
SznajdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
SznajdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
SznajdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
SznajdModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
SznajdModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Sznajd model simulation on a random graph: we set the initial infected node set to the 10% of the overall population.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.opinions.SznajdModel as sn
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sn.SznajdModel(g)
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
Cognitive Opinion Dynamics¶
The Cognitive Opinion Dynamics model was introduced in [1], which models the state of individuals taking into account several cognitively-grounded variables.
The aim of the model is to simulate response to risk in catastrophic events in the presence of external (institutional) information.
The individual opinion is modelled as a continuous variable Oi ∈ [0, 1], representing the degree of perception of the risk (how probable it is that the catastrophic event will actually happen).
This opinion evolves through interactions with neighbours and external information, based on four internal variables for each individual i:
- risk sensitivity (Ri ∈ {−1, 0, 1}),
- tendency to inform others (βi ∈ [0,1]),
- trust in institutions (Ti ∈ [0,1]), and
- trust in peers (Πi = 1 − Ti).
These values are generated when the population is initialised and stay fixed during the simulation.
The update rules define how Oi values change in time.
The model was shown to be able to reproduce well various real situations. In particular, it is visible that risk sensitivity is more important than trust in institutional information when it comes to evaluating risky situations.
Node statuses are continuous values in [0,1].
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
I | Model | float in [0, 1] | True | External information | |
T_range_min | Model | float in [0, 1] | True | Minimum of the range of initial values for T | |
T_range_max | Model | float in [0, 1] | True | Maximum of the range of initial values for T | |
B_range_min | Model | float in [0, 1] | True | Minimum of the range of initial values for B | |
B_range_max | Model | float in [0, 1] | True | Maximum of the range of initial values for B | |
R_fraction_negative | Model | float in [0, 1] | True | Fraction of nodes having R=-1 | |
R_fraction_neutral | Model | float in [0, 1] | True | Fraction of nodes having R=0 | |
R_fraction_positive | Model | float in [0, 1] | True | Fraction of nodes having R=1 |
The following relation should hold: R_fraction_negative+R_fraction_neutral+R_fraction_positive=1
.
To achieve this, the fractions selected will be normalised to sum 1.
The initial state is generated randomly uniformly from the domain defined by model parameters.
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.opinions.CognitiveOpDynModel.
CognitiveOpDynModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: - I – external information value in [0,1]
- T_range_min – the minimum of the range of initial values for T. Range [0,1].
- T_range_max – the maximum of the range of initial values for T. Range [0,1].
- B_range_min – the minimum of the range of initial values for B. Range [0,1]
- B_range_max – the maximum of the range of initial values for B. Range [0,1].
- R_fraction_negative – fraction of individuals having the node parameter R=-1.
- R_fraction_positive – fraction of individuals having the node parameter R=1
- R_fraction_neutral – fraction of individuals having the node parameter R=0
The following relation should hold: R_fraction_negative+R_fraction_neutral+R_fraction_positive=1. To achieve this, the fractions selected will be normalised to sum 1. Node states are continuous values in [0,1].
The initial state is generated randomly uniformly from the domain defined by model parameters.
-
CognitiveOpDynModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
CognitiveOpDynModel.
set_initial_status
(self, configuration)¶ Override behaviour of methods in class DiffusionModel. Overwrites initial status using random real values. Generates random node profiles.
-
CognitiveOpDynModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
CognitiveOpDynModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
CognitiveOpDynModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
-
CognitiveOpDynModel.
iteration
(self)¶ Execute a single model iteration
Returns: Iteration_id, Incremental node status (dictionary node->status)
-
CognitiveOpDynModel.
iteration_bunch
(self, bunch_size)¶ Execute a bunch of model iterations
Parameters: - bunch_size – the number of iterations to execute
- node_status – if the incremental node status has to be returned.
Returns: a list containing for each iteration a dictionary {“iteration”: iteration_id, “status”: dictionary_node_to_status}
In the code below is shown an example of instantiation and execution of a Cognitive Opinion Dynamics model simulation on a random graph: we set the initial infected node set to the 10% of the overall population, the external information value to 015, the B and T intervals equal to [0,1] and the fraction of positive/neutral/infected equal to 1/3.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.opinions.CognitiveOpDynModel as cod
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = cod.CognitiveOpDynModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter("I", 0.15)
config.add_model_parameter("B_range_min", 0)
config.add_model_parameter("B_range_max", 1)
config.add_model_parameter("T_range_min", 0)
config.add_model_parameter("T_range_max", 1)
config.add_model_parameter("R_fraction_negative", 1.0 / 3)
config.add_model_parameter("R_fraction_neutral", 1.0 / 3)
config.add_model_parameter("R_fraction_positive", 1.0 / 3)
config.add_model_parameter('percentage_infected', 0.1)
model.set_initial_status(config)
# Simulation execution
iterations = model.iteration_bunch(200)
[1] |
|
Dynamic Network Models¶
Network topology may evolve as time goes by.
In order to automatically leverage network dynamics NDlib
enables the definition of diffusion models that work on Snapshot Graphs as well as on Interaction Networks.
In particular NDlib
implements dynamic network versions of the following models:
SI¶
The SI model was introduced in 1927 by Kermack [1].
In this model, during the course of an epidemics, a node is allowed to change its status only from Susceptible (S) to Infected (I).
The model is instantiated on a graph having a non-empty set of infected nodes.
SI assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected with probability β: once a node becomes infected, it stays infected (the only transition allowed is S→I).
The dSI implementation assumes that the process occurs on a directed/undirected dynamic network; this model was introduced by Milli et al. in 2018 [2].
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.dynamic.DynSIModel.
DynSIModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: beta – The infection rate (float value in [0,1])
-
DynSIModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A dynetx graph object
-
DynSIModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
DynSIModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
DynSIModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
DynSIModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
In the code below is shown an example of instantiation and execution of an DynSI simulation on a dynamic random graph: we set the initial set of infected nodes as 5% of the overall population and a probability of infection of 1%.
import networkx as nx
import dynetx as dn
import ndlib.models.ModelConfig as mc
import ndlib.models.dynamic.DynSIModel as si
# Dynamic Network topology
dg = dn.DynGraph()
for t in past.builtins.xrange(0, 3):
g = nx.erdos_renyi_graph(200, 0.05)
dg.add_interactions_from(g.edges(), t)
# Model selection
model = si.DynSIModel(dg)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('beta', 0.01)
config.add_model_parameter("percentage_infected", 0.1)
model.set_initial_status(config)
# Simulate snapshot based execution
iterations = model.execute_snapshots()
# Simulation interaction graph based execution
iterations = model.execute_iterations()
[1] |
|
[2] | Letizia Milli, Giulio Rossetti, Fosca Giannotti, Dino Pedreschi. “Diffusive Phenomena in Dynamic Networks: a data-driven study”. Accepted to International Conference on Complex Networks (CompleNet), 2018, Boston. |
SIS¶
The SIS model was introduced in 1927 by Kermack [1].
In this model, during the course of an epidemics, a node is allowed to change its status from Susceptible (S) to Infected (I).
The model is instantiated on a graph having a non-empty set of infected nodes.
SIS assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected with probability beta, than it can be switch again to susceptible with probability lambda (the only transition allowed are S→I→S).
The dSIS implementation assumes that the process occurs on a directed/undirected dynamic network.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability | |
lambda | Model | float in [0, 1] | True | Recovery probability |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.dynamic.DynSISModel.
DynSISModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: - beta – The infection rate (float value in [0,1])
- lambda – The recovery rate (float value in [0,1])
-
DynSISModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
DynSISModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
DynSISModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
DynSISModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
DynSISModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
In the code below is shown an example of instantiation and execution of an DynSIS simulation on a dynamic random graph: we set the initial set of infected nodes as 5% of the overall population, a probability of infection of 1%, and a probability of recovery of 1%.
import networkx as nx
import dynetx as dn
import ndlib.models.ModelConfig as mc
import ndlib.models.dynamic.DynSISModel as sis
# Dynamic Network topology
dg = dn.DynGraph()
for t in past.builtins.xrange(0, 3):
g = nx.erdos_renyi_graph(200, 0.05)
dg.add_interactions_from(g.edges(), t)
# Model selection
model = sis.DynSISModel(dg)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('beta', 0.01)
config.add_model_parameter('lambda', 0.01)
config.add_model_parameter("percentage_infected", 0.1)
model.set_initial_status(config)
# Simulate snapshot based execution
iterations = model.execute_snapshots()
# Simulation interaction graph based execution
iterations = model.execute_iterations()
[1] |
|
SIR¶
The SIR model was introduced in 1927 by Kermack [1].
In this model, during the course of an epidemics, a node is allowed to change its status from Susceptible (S) to Infected (I), then to Removed (R).
The model is instantiated on a graph having a non-empty set of infected nodes.
SIR assumes that if, during a generic iteration, a susceptible node comes into contact with an infected one, it becomes infected with probability beta, than it can be switch to removed with probability gamma (the only transition allowed are S→I→R).
The dSIR implementation assumes that the process occurs on a directed/undirected dynamic network; this model was introduced by Milli et al. in 2018 [2].
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Removed | 2 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
beta | Model | float in [0, 1] | True | Infection probability | |
gamma | Model | float in [0, 1] | True | Removal probability |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.dynamic.DynSIRModel.
DynSIRModel
(graph)¶ Model Parameters to be specified via ModelConfig
Parameters: - beta – The infection rate (float value in [0,1])
- gamma – The recovery rate (float value in [0,1])
-
DynSIRModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
DynSIRModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
DynSIRModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
DynSIRModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
DynSIRModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
In the code below is shown an example of instantiation and execution of an DynSIR simulation on a dynamic random graph: we set the initial set of infected nodes as 5% of the overall population, a probability of infection of 1%, and a removal probability of 1%.
import networkx as nx
import dynetx as dn
import ndlib.models.ModelConfig as mc
import ndlib.models.dynamic.DynSIRModel as sir
# Dynamic Network topology
dg = dn.DynGraph()
for t in past.builtins.xrange(0, 3):
g = nx.erdos_renyi_graph(200, 0.05)
dg.add_interactions_from(g.edges(), t)
# Model selection
model = sir.DynSIRModel(dg)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('beta', 0.01)
config.add_model_parameter('gamma', 0.01)
config.add_model_parameter("percentage_infected", 0.1)
model.set_initial_status(config)
# Simulate snapshot based execution
iterations = model.execute_snapshots()
# Simulation interaction graph based execution
iterations = model.execute_iterations()
[1] |
|
[2] | Letizia Milli, Giulio Rossetti, Fosca Giannotti, Dino Pedreschi. “Diffusive Phenomena in Dynamic Networks: a data-driven study”. Accepted to International Conference on Complex Networks (CompleNet), 2018, Boston. |
Kertesz Threshold¶
The Kertesz Threshold model was introduced in 2015 by Ruan et al. [1] and it is an extension of the Watts threshold model [2].
The authors extend the classical model introducing a density r of blocked nodes – nodes which are immune to social influence – and a probability of spontaneous adoption p to capture external influence.
Thus, the model distinguishes three kinds of node: Blocked (B), Susceptible (S) and Adoptiong (A). The latter class breaks into two categories: vulnerable and stable nodes. A node can adopt either under its neighbors’ influence, or spontaneously, due to endogenous effects.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Blocked | -1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
adopter_rate | Model | float in [0, 1] | 0 | False | Exogenous adoption rate |
percentage_blocked | Model | float in [0, 1] | 0.1 | False | Blocked nodes |
threshold | Node | float in [0, 1] | 0.1 | False | Individual threshold |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The initial blocked nodes can be defined via:
- percentage_blocked: Model Parameter, float in [0, 1]
- Blocked: Status Parameter, set of nodes
In both cases, the two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.dynamic.DynKerteszThresholdModel.
DynKerteszThresholdModel
(graph)¶ - Node Parameters to be specified via ModelConfig
Parameters: profile – The node profile. As default a value of 0.1 is assumed for all nodes.
-
DynKerteszThresholdModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
DynKerteszThresholdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
DynKerteszThresholdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
DynKerteszThresholdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
DynKerteszThresholdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
In the code below is shown an example of instantiation and execution of a Kertesz Threshold model simulation on a random graph: we set the initial infected as well blocked node sets equals to the 10% of the overall population, assign a threshold of 0.25 to all the nodes and impose an probability of spontaneous adoptions of 40%.
import networkx as nx
import dynetx as dn
import ndlib.models.ModelConfig as mc
import ndlib.models.dynamic.DynKerteszThresholdModel as ks
# Dynamic Network topology
dg = dn.DynGraph()
for t in past.builtins.xrange(0, 3):
g = nx.erdos_renyi_graph(200, 0.05)
dg.add_interactions_from(g.edges(), t)
# Model selection
model = ks.DynKerteszThresholdModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('adopter_rate', 0.4)
config.add_model_parameter('percentage_blocked', 0.1)
config.add_model_parameter('percentage_infected', 0.1)
# Setting node parameters
threshold = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
model.set_initial_status(config)
# Simulate snapshot based execution
iterations = model.execute_snapshots()
# Simulation interaction graph based execution
iterations = model.execute_iterations()
[1] |
|
[2] |
|
Profile¶
The Profile model assumes that the diffusion process is only apparent; each node decides to adopt or not a given behavior – once known its existence – only on the basis of its own interests.
In this scenario the peer pressure is completely ruled out from the overall model: it is not important how many of its neighbors have adopted a specific behaviour, if the node does not like it, it will not change its interests.
Each node has its own profile describing how many it is likely to accept a behaviour similar to the one that is currently spreading.
The diffusion process starts from a set of nodes that have already adopted a given behaviour S:
- for each of the susceptible nodes’ in the neighborhood of a node u in S an unbalanced coin is flipped, the unbalance given by the personal profile of the susceptible node;
- if a positive result is obtained the susceptible node will adopt the behaviour, thus becoming infected.
- if the blocked status is enabled, after having rejected the adoption with probability
blocked
a node becomes immune to the infection. - every iteration
adopter_rate
percentage of nodes spontaneous became infected to endogenous effects.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Blocked | -1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
profile | Node | float in [0, 1] | 0.1 | False | Node profile |
blocked | Model | float in [0, 1] | 0 | False | Blocked nodes |
adopter_rate | Model | float in [0, 1] | 0 | False | Autonomous adoption |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.dynamic.DynProfileModel.
DynProfileModel
(graph)¶ - Node Parameters to be specified via ModelConfig
Parameters: profile – The node profile. As default a value of 0.1 is assumed for all nodes.
-
DynProfileModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
DynProfileModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
DynProfileModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
DynProfileModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
DynProfileModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
In the code below is shown an example of instantiation and execution of a Profile model simulation on a random graph: we set the initial infected node set to the 10% of the overall population and assign a profile of 0.25 to all the nodes.
import networkx as nx
import dynetx as dn
import ndlib.models.ModelConfig as mc
import ndlib.models.dynamic.DynProfileModel as ks
# Dynamic Network topology
dg = dn.DynGraph()
for t in past.builtins.xrange(0, 3):
g = nx.erdos_renyi_graph(200, 0.05)
dg.add_interactions_from(g.edges(), t)
# Model selection
model = pr.DynProfileModel(g)
config = mc.Configuration()
config.add_model_parameter('blocked', 0)
config.add_model_parameter('adopter_rate', 0)
config.add_model_parameter('percentage_infected', 0.1)
# Setting nodes parameters
profile = 0.15
for i in g.nodes():
config.add_node_configuration("profile", i, profile)
model.set_initial_status(config)
# Simulate snapshot based execution
iterations = model.execute_snapshots()
# Simulation interaction graph based execution
iterations = model.execute_iterations()
Threshold¶
The Profile-Threshold model assumes the existence of node profiles that act as preferential schemas for individual tastes but relax the constraints imposed by the Profile model by letting nodes influenceable via peer pressure mechanisms.
The peer pressure is modeled with a threshold.
The diffusion process starts from a set of nodes that have already adopted a given behaviour S:
- for each of the susceptible node an unbalanced coin is flipped if the percentage of its neighbors that are already infected excedes its threhosld. As in the Profile Model the coin unbalance is given by the personal profile of the susceptible node;
- if a positive result is obtained the susceptible node will adopt the behaviour, thus becoming infected.
- if the blocked status is enabled, after having rejected the adoption with probability
blocked
a node becomes immune to the infection. - every iteration
adopter_rate
percentage of nodes spontaneous became infected to endogenous effects.
During the simulation a node can experience the following statuses:
Name | Code |
---|---|
Susceptible | 0 |
Infected | 1 |
Blocked | -1 |
Name | Type | Value Type | Default | Mandatory | Description |
---|---|---|---|---|---|
threshold | Node | float in [0, 1] | 0.1 | False | Individual threshold |
profile | Node | float in [0, 1] | 0.1 | False | Node profile |
blocked | Model | float in [0, 1] | 0 | False | Blocked nodes |
adopter_rate | Model | float in [0, 1] | 0 | False | Autonomous adoption |
The initial infection status can be defined via:
- percentage_infected: Model Parameter, float in [0, 1]
- Infected: Status Parameter, set of nodes
The two options are mutually exclusive and the latter takes precedence over the former.
The following class methods are made available to configure, describe and execute the simulation:
-
class
ndlib.models.dynamic.DynProfileThresholdModel.
DynProfileThresholdModel
(graph)¶ Node Parameters to be specified via ModelConfig
Parameters: - profile – The node profile. As default a value of 0.1 is assumed for all nodes.
- threshold – The node threshold. As default a value of 0.1 is assumed for all nodes.
-
DynProfileThresholdModel.
__init__
(graph)¶ Model Constructor
Parameters: graph – A networkx graph object
-
DynProfileThresholdModel.
set_initial_status
(self, configuration)¶ Set the initial model configuration
Parameters: configuration – a `ndlib.models.ModelConfig.Configuration`
object
-
DynProfileThresholdModel.
reset
(self)¶ Reset the simulation setting the actual status to the initial configuration.
-
DynProfileThresholdModel.
get_info
(self)¶ Describes the current model parameters (nodes, edges, status)
Returns: a dictionary containing for each parameter class the values specified during model configuration
-
DynProfileThresholdModel.
get_status_map
(self)¶ Specify the statuses allowed by the model and their numeric code
Returns: a dictionary (status->code)
In the code below is shown an example of instantiation and execution of a Profile Threshold model simulation on a random graph: we set the initial infected node set to the 10% of the overall population, assign a profile of 0.25 and a threshold of 0.15 to all the nodes.
import networkx as nx
import dynetx as dn
import ndlib.models.ModelConfig as mc
import ndlib.models.dynamic.DynProfileThresholdModel as ks
# Dynamic Network topology
dg = dn.DynGraph()
for t in past.builtins.xrange(0, 3):
g = nx.erdos_renyi_graph(200, 0.05)
dg.add_interactions_from(g.edges(), t)
# Model selection
model = pt.DynProfileThresholdModel(g)
config = mc.Configuration()
config.add_model_parameter('blocked', 0)
config.add_model_parameter('adopter_rate', 0)
config.add_model_parameter('percentage_infected', 0.1)
# Setting nodes parameters
threshold = 0.15
profile = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
config.add_node_configuration("profile", i, profile)
model.set_initial_status(config)
# Simulate snapshot based execution
iterations = model.execute_snapshots()
# Simulation interaction graph based execution
iterations = model.execute_iterations()
Model Configuration¶
NDlib
adopts a peculiar approach to specify the configuration of expetiments.
It employs a centralyzed system that take care of:
- Describe a common syntax for model configuration;
- Provide an interface to set the initial conditions of an experiment (nodes/edges properties, initial nodes statuses)
ModelConfig¶
The ModelConfig
object is the common interface used to set up simulation experiments.
-
class
ndlib.models.ModelConfig.
Configuration
¶ Configuration Object
It allows to specify four categories of experiment configurations:
- Model configuration
- Node Configuration
- Edge Configuration
- Initial Status
Every diffusion model has its own parameters (as defined in its reference page).
Model Configuration¶
Model configuration involves the instantiation of both the mandatory and optional parameters of the chosen diffusion model.
-
Configuration.
add_model_parameter
(self, param_name, param_value)¶ Set a Model Parameter
Parameters: - param_name – parameter identifier (as specified by the chosen model)
- param_value – parameter value
Model parameters can be setted as in the following example:
import ndlib.models.ModelConfig as mc
# Model Configuration
config = mc.Configuration()
config.add_model_parameter("beta", 0.15)
The only model parameter common to all the diffusive approaches is percentage_infected
that allows to specify the ratio of infected nodes at the beginning of the simulation.
Node Configuration¶
Node configuration involves the instantiation of both the mandatory and optional parameters attached to individual nodes.
-
Configuration.
add_node_configuration
(self, param_name, node_id, param_value)¶ Set a parameter for a given node
Parameters: - param_name – parameter identifier (as specified by the chosen model)
- node_id – node identifier
- param_value – parameter value
-
Configuration.
add_node_set_configuration
(self, param_name, node_to_value)¶ Set Nodes parameter
Parameters: - param_name – parameter identifier (as specified by the chosen model)
- node_to_value – dictionary mapping each node a parameter value
Node parameters can be set as in the following example:
import ndlib.models.ModelConfig as mc
# Model Configuration
config = mc.Configuration()
threshold = 0.25
for i in g.nodes():
config.add_node_configuration("threshold", i, threshold)
Edge Configuration¶
Edge configuration involves the instantiation of both the mandatory and optional parameters attached to individual edges.
-
Configuration.
add_edge_configuration
(self, param_name, edge, param_value)¶ Set a parameter for a given edge
Parameters: - param_name – parameter identifier (as specified by the chosen model)
- edge – edge identifier
- param_value – parameter value
-
Configuration.
add_edge_set_configuration
(self, param_name, edge_to_value)¶ Set Edges parameter
Parameters: - param_name – parameter identifier (as specified by the chosen model)
- edge_to_value – dictionary mapping each edge a parameter value
Edge parameters can be set as in the following example:
import ndlib.models.ModelConfig as mc
# Model Configuration
config = mc.Configuration()
threshold = 0.25
for i in g.nodes():
config.add_edge_configuration("threshold", i, threshold)
Status Configuration¶
Status configuration allows to specify explicitly the status of a set of nodes at the beginning of the simulation.
-
Configuration.
add_model_initial_configuration
(self, status_name, nodes)¶ Set initial status for a set of nodes
Parameters: - status_name – status to be set (as specified by the chosen model)
- nodes – list of affected nodes
Node statuses can be set as in the following example:
import ndlib.models.ModelConfig as mc
# Model Configuration
config = mc.Configuration()
infected_nodes = [0, 1, 2, 3, 4, 5]
config.add_model_initial_configuration("Infected", infected_nodes)
Explicit status specification takes priority over the percentage specification expressed via model definition (e.g. percentage_infected
).
Only the statuses implemented by the chosen model can be used to specify initial configurations of nodes.
NDlib Utils¶
The ndlib.utils
module contains facilities that extend the simulation framework (i.e., automated multiple executions).
Model Multiple Executions¶
dlib.utils.multi_runs
allows the parallel execution of multiple instances of a given model starting from different initial infection conditions.
The initial infected nodes for each instance of the model can be specified either:
- by the “percentage_infected” model parameter, or
- explicitly through a list of
n
sets of nodes (wheren
is the number of executions required).
In the first scenario “percentage_infected” nodes will be sampled independently for each model execution.
Results of dlib.utils.multi_runs
can be feed directly to all the visualization facilities exposed by ndlib.viz
.
-
ndlib.utils.
multi_runs
(model, execution_number, iteration_number, infection_sets, nprocesses)¶ Multiple executions of a given model varying the initial set of infected nodes
Parameters: - model – a configured diffusion model
- execution_number – number of instantiations
- iteration_number – number of iterations per execution
- infection_sets – predefined set of infected nodes sets
- nprocesses – number of processes. Default values cpu number.
Returns: resulting trends for all the executions
Example¶
Randomly selection of initial infection sets
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.utils import multi_runs
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model1 = sir.SIRModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('beta', 0.001)
config.add_model_parameter('gamma', 0.01)
config.add_model_parameter("percentage_infected", 0.05)
model1.set_initial_status(config)
# Simulation multiple execution
trends = multi_runs(model1, execution_number=10, iteration_number=100, infection_sets=None, nprocesses=4)
Specify initial infection sets
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.utils import multi_runs
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model1 = sir.SIRModel(g)
# Model Configuration
config = mc.Configuration()
config.add_model_parameter('beta', 0.001)
config.add_model_parameter('gamma', 0.01)
model1.set_initial_status(config)
# Simulation multiple execution
infection_sets = [(1, 2, 3, 4, 5), (3, 23, 22, 54, 2), (98, 2, 12, 26, 3), (4, 6, 9) ]
trends = multi_runs(model1, execution_number=2, iteration_number=100, infection_sets=infection_sets, nprocesses=4)
Plot multiple executions
The ndlib.viz.mpl
package offers support for visualization of multiple runs.
In order to visualize the average trend/prevalence along with its inter-percentile range use the following pattern (assuming model1
and trends
be the results of the previous code snippet).
from ndlib.viz.mpl.DiffusionTrend import DiffusionTrend
viz = DiffusionTrend(model1, trends)
viz.plot("diffusion.pdf", percentile=90)
where percentile
identifies the upper and lower bound (e.g. setting it to 90 implies a range 10-90).
The same pattern can be also applied to comparison plots.
Visualization¶
In order to provide an easy proxy to study diffusion phenomena and compare different configurations as well as models NDlib
offers built-in visualizzation facilities.
In particular, the following plots are made available:
Pyplot Viz¶
Classic Visualizations
Diffusion Trend¶
The Diffusion Trend plot compares the trends of all the statuses allowed by the diffusive model tested.
Each trend line describes the variation of the number of nodes for a given status iteration after iteration.
-
class
ndlib.viz.mpl.DiffusionTrend.
DiffusionTrend
(model, trends)¶
-
DiffusionTrend.
__init__
(model, trends)¶ Parameters: - model – The model object
- trends – The computed simulation trends
-
DiffusionTrend.
plot
(filename, percentile)¶ Generates the plot
Parameters: - filename – Output filename
- percentile – The percentile for the trend variance area
Below is shown an example of Diffusion Trend description and visualization for the SIR model.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.viz.mpl.DiffusionTrend import DiffusionTrend
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.01)
cfg.add_model_parameter("percentage_infected", 0.01)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# Visualization
viz = DiffusionTrend(model, trends)
viz.plot("diffusion.pdf")
Diffusion Prevalence¶
The Diffusion Prevalence plot compares the delta-trends of all the statuses allowed by the diffusive model tested.
Each trend line describes the delta of the number of nodes for a given status iteration after iteration.
-
class
ndlib.viz.mpl.DiffusionPrevalence.
DiffusionPrevalence
(model, trends)¶
-
DiffusionPrevalence.
__init__
(model, trends)¶ Parameters: - model – The model object
- trends – The computed simulation iterations
-
DiffusionPrevalence.
plot
(filename, percentile)¶ Generates the plot
Parameters: - filename – Output filename
- percentile – The percentile for the trend variance area
Below is shown an example of Diffusion Prevalence description and visualization for the SIR model.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.viz.mpl.DiffusionPrevalence import DiffusionPrevalence
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.01)
cfg.add_model_parameter("percentage_infected", 0.01)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# Visualization
viz = DiffusionPrevalence(model, trends)
viz.plot("prevalence.pdf")
Model Comparison Visualizations
Diffusion Trend Comparison¶
The Diffusion Trend Comparison plot compares the trends of all the statuses allowed by the diffusive model tested.
Each trend line describes the variation of the number of nodes for a given status iteration after iteration.
-
class
ndlib.viz.mpl.TrendComparison.
DiffusionTrendComparison
(models, trends, statuses='Infected')¶
-
DiffusionTrendComparison.
__init__
(models, trends, statuses)¶ Parameters: - models – A list of model object
- trends – A list of computed simulation trends
- statuses – The model statuses for which make the plot. Default [“Infected”].
-
DiffusionTrendComparison.
plot
(filename, percentile)¶ Plot the comparison on file.
Parameters: - filename – the output filename
- percentile – The percentile for the trend variance area. Default 90.
Below is shown an example of Diffusion Trend description and visualization for the SIR model.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.viz.mpl.TrendComparison import DiffusionTrendComparison
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.01)
cfg.add_model_parameter("percentage_infected", 0.01)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# 2° Model selection
model1 = sir.SIRModel(g)
# 2° Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.02)
cfg.add_model_parameter("percentage_infected", 0.01)
model1.set_initial_status(cfg)
# 2° Simulation execution
iterations = model1.iteration_bunch(200)
trends1 = model1.build_trends(iterations)
# Visualization
viz = DiffusionTrend([model, model1], [trends, trends1])
viz.plot("trend_comparison.pdf")
Diffusion Prevalence Comparison¶
The Diffusion Prevalence plot compares the delta-trends of all the statuses allowed by the diffusive model tested.
Each trend line describes the delta of the number of nodes for a given status iteration after iteration.
-
class
ndlib.viz.mpl.PrevalenceComparison.
DiffusionPrevalenceComparison
(models, trends, statuses='Infected')¶
-
DiffusionPrevalenceComparison.
__init__
(model, trends)¶ Parameters: - models – A list of model object
- trends – A list of computed simulation trends
- statuses – The model statuses for which make the plot. Default [“Infected”].
-
DiffusionPrevalenceComparison.
plot
(filename, percentile)¶ Plot the comparison on file.
Parameters: - filename – the output filename
- percentile – The percentile for the trend variance area. Default 90.
Below is shown an example of Diffusion Prevalence description and visualization for two instances of the SIR model.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
import ndlib.models.epidemics.SIModel as si
from ndlib.viz.mpl.PrevalenceComparison import DiffusionPrevalenceComparison
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.02)
cfg.add_model_parameter("percentage_infected", 0.01)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# 2° Model selection
model1 = si.SIModel(g)
# 2° Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter("percentage_infected", 0.01)
model1.set_initial_status(cfg)
# 2° Simulation execution
iterations = model1.iteration_bunch(200)
trends1 = model1.build_trends(iterations)
# Visualization
viz = DiffusionPrevalenceComparison([model, model1], [trends, trends1])
viz.plot("trend_comparison.pdf")
Bokeh Viz¶
Classic Visualizations
Diffusion Trend¶
The Diffusion Trend plot compares the trends of all the statuses allowed by the diffusive model tested.
Each trend line describes the variation of the number of nodes for a given status iteration after iteration.
Below is shown an example of Diffusion Trend description and visualization for the SIR model.
import networkx as nx
from bokeh.io import show
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.viz.bokeh.DiffusionTrend import DiffusionTrend
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.01)
cfg.add_model_parameter("percentage_infected", 16 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# Visualization
viz = DiffusionTrend(model, trends)
p = viz.plot(width=400, height=400)
show(p)
Diffusion Prevalence¶
The Diffusion Prevalence plot compares the delta-trends of all the statuses allowed by the diffusive model tested.
Each trend line describes the delta of the number of nodes for a given status iteration after iteration.
Below is shown an example of Diffusion Prevalence description and visualization for the SIR model.
import networkx as nx
from bokeh.io import show
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.viz.bokeh.DiffusionPrevalence import DiffusionPrevalence
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.01)
cfg.add_model_parameter("percentage_infected", 16 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# Visualization
viz = DiffusionPrevalence(model, trends)
p = viz.plot(width=400, height=400)
show(p)
Model Comparison Visualizations
Multi Plot¶
The Multi Plot object allows the generation of composite grid figures composed by multiple Diffusion Trends and/or Diffusion Prevalence plots.
import networkx as nx
from bokeh.io import show
import ndlib.models.ModelConfig as mc
import ndlib.models.epidemics.SIRModel as sir
from ndlib.viz.bokeh.DiffusionTrend import DiffusionTrend
from ndlib.viz.bokeh.DiffusionPrevalence import DiffusionPrevalence
from ndlib.viz.bokeh.MultiPlot import Multiplot
vm = MultiPlot()
# Network topology
g = nx.erdos_renyi_graph(1000, 0.1)
# Model selection
model = sir.SIRModel(g)
# Model Configuration
cfg = mc.Configuration()
cfg.add_model_parameter('beta', 0.001)
cfg.add_model_parameter('gamma', 0.01)
cfg.add_model_parameter("percentage_infected", 16 0.05)
model.set_initial_status(cfg)
# Simulation execution
iterations = model.iteration_bunch(200)
trends = model.build_trends(iterations)
# Diffusion Trend
viz = DiffusionTrend(model, trends)
p = viz.plot(width=400, height=400)
vm.add_plot(p)
# Diffusion Prevalence
viz = DiffusionPrevalence(model, trends)
p1 = viz.plot(width=400, height=400)
vm.add_plot(p1)
m = vm.plot(ncol=2)
show(m)
[1] |
|
[2] |
|
[3] | P.Wang,M.C.Gonzalez,R.Menezes,andA.L.Baraba ́si,“Understanding the spread of malicious mobile-phone programs and their damage potential,” International Journal of Information Security, 2013. |
[4] |
|
[5] |
|
[6] |
|
[7] |
|
[8] |
|
Custom Model Definition¶
NDlib
exposes a set of built-in diffusion models (epidemic/opinion dynamics/dynamic network): how can I describe novel ones?
In order to answer such question we developed a syntax for compositional model definition.
Rationale¶
At a higher level of abstraction a diffusion process can be synthesized into two components:
- Available Statuses, and
- Transition Rules that connect them
All models of NDlib
assume an agent-based, discrete time, simulation engine.
During each simulation iteration all the nodes in the network are asked to (i) evaluate their current status and to (ii) (eventually) apply a matching transition rule.
The last step of such process can be easily decomposed into atomic operations that we will call compartments.
Note
NDlib
exposes two classes for defining custom diffusion models:
CompositeModel
describes diffusion models for static networksDynamicCompositeModel
describes diffusion models for dynamic networks
To avoid redundant documentation, here we will discuss only the former class, the latter behaving alike.
Compartments¶
We adopt the concept of compartment
to identify all those atomic conditions (i.e. operations) that describe (part of) a transition rule.
The execution of a compartment
can return either True (condition satisfied) or False (condition not satisfied).
Indeed, several compartments can be described, each one of them capturing an atomic operation.
To cover the main scenarios we defined three families of compartments as well as some operations to combine them.
Node Compartments¶
In this class fall all those compartments that evaluate conditions tied to node status/features. They model stochastic events as well as deterministic ones.
Node Stochastic¶
Node Stochastic compartments are used to evaluate stochastic events attached to network nodes.
Consider the transition rule Susceptible->Infected that requires a probability beta to be satisfied. Such rule can be described by a simple compartment that models Node Stochastic behaviors. Let’s call il NS.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the NS compartment. NS will thus require a probability (beta) of activation.
During each rule evaluation, given a node n
- if the actual status of n equals the rule initial one
- a random value b in [0,1] will be generated
- if b <= beta then NS is considered satisfied and the status of n changes from initial to final.
Moreover, NS allows to specify a triggering status in order to restrain the compartment evaluation to those nodes that:
- match the rule initial state, and
- have at least one neighbors in the triggering status.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
ratio | float in [0, 1] | True | Event probability | |
triggering_status | string | None | False | Trigger |
In the code below is shown the formulation of a SIR model using NodeStochastic compartments.
The first compartment, c1, is used to implement the transition rule Susceptible->Infected. It requires a probability threshold - here set equals to 0.02 - and restrain the rule evaluation to all those nodes that have at least an Infected neighbors.
The second compartment, c2, is used to implement the transition rule Infected->Removed. Since such transition is not tied to neighbors statuses the only parameter required by the compartment is the probability of transition.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeStochastic as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = ns.NodeStochastic(0.02, triggering_status="Infected")
c2 = ns.NodeStochastic(0.01)
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
model.add_rule("Infected", "Removed", c2)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Node Categorical Attribute¶
Node Categorical Attribute compartments are used to evaluate events attached to network nodes attributes.
Consider the transition rule Susceptible->Infected that requires a that the susceptible node express a specific value of an internal attribute, attr, to be satisfied (e.g. “Sex”=”male”). Such rule can be described by a simple compartment that models Node Categorical Attribute selection. Let’s call il NCA.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the NCA compartment. NCA will thus require a probability (beta) of activation.
During each rule evaluation, given a node n
- if the actual status of n equals the rule initial one
- a random value b in [0,1] will be generated
- if b <= beta and attr(n) == attr, then NCA is considered satisfied and the status of n changes from initial to final.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
attribute | string | None | True | Attribute name |
value | string | None | True | Attribute testing value |
probability | float in [0, 1] | 1 | False | Event probability |
In the code below is shown the formulation of a model using NodeCategoricalAttribute compartments.
The compartment, c1, is used to implement the transition rule Susceptible->Infected. It restrain the rule evaluation to all those nodes for which the attribute “Sex” equals “male”.
import networkx as nx
import random
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeCategoricalAttribute as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Setting node attribute
attr = {n: {"Sex": random.choice(['male', 'female'])} for n in g.nodes()}
nx.set_node_attributes(g, attr)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = na.NodeCategoricalAttribute("Sex", "male", probability=0.6)
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Node Numerical Attribute¶
Node Numerical Attribute compartments are used to evaluate events attached to numeric edge attributes.
Consider the transition rule Susceptible->Infected that requires a that the susceptible node express a specific value of an internal numeric attribute, attr, to be satisfied (e.g. “Age” == 18). Such rule can be described by a simple compartment that models Node Numerical Attribute selection. Let’s call il NNA.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the NNA compartment. NNA will thus require a probability (beta) of activation.
During each rule evaluation, given a node n and one of its neighbors m
- if the actual status of n equals the rule initial
- if attr(n) op attr
- a random value b in [0,1] will be generated
- if b <= beta, then NNA is considered satisfied and the status of n changes from initial to final.
op represent a logic operator and can assume one of the following values: - equality: “==” - less than: “<” - greater than: “>” - equal or less than: “<=” - equal or greater than: “>=” - not equal to: “!=” - within: “IN”
Moreover, NNA allows to specify a triggering status in order to restrain the compartment evaluation to those nodes that:
- match the rule initial state, and
- have at least one neighbors in the triggering status.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
attribute | string | None | True | Attribute name |
value | numeric(*) | None | True | Attribute testing value |
op | string | None | True | Logic operator |
probability | float in [0, 1] | 1 | False | Event probability |
triggering_status | string | None | False | Trigger |
(*) When op equals “IN” the attribute value is expected to be a tuple of two elements identifying a closed interval.
In the code below is shown the formulation of a model using NodeNumericalAttribute compartments.
The first compartment, c1, is used to implement the transition rule Susceptible->Infected. It restrain the rule evaluation to all those nodes having “Age” equals to 18.
The second compartment, c2, is used to implement the transition rule Infected->Recovered. It restrain the rule evaluation to all those nodes connected at least to a “Susceptible” neighbor and having “Age” in the range [20, 25].
import networkx as nx
import random
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeNumericalAttribute as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Setting edge attribute
attr = {n: {"Age": random.choice(range(0, 100))} for n in g.nodes()}
nx.set_edge_attributes(g, attr)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = na.NodeNumericalAttribute("Age", value=18, op="==", probability=0.6)
c2 = na.NodeNumericalAttribute("Age", value=(20, 25), op="IN", probability=0.6, triggering_status="Susceptible")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
model.add_rule("Infected", "Recovered", c2)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Node Threshold¶
Node Threshold compartments are used to evaluate deterministic events attached to network nodes.
Consider the transition rule Susceptible->Infected that requires at least a percentage beta of Infected neighbors for a node n to be satisfied.
Such rule can be described by a simple compartment that models Node Threshold behaviors. Let’s call il NT.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the NT compartment. NT will thus require a threshold (beta) of activation and a triggering status.
During each rule evaluation, given a node n
- if the actual status of n equals the rule initial one
- let b identify the ratio of n neighbors in the triggering status
- if b >= beta then NS is considered satisfied and the status of n changes from initial to final.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
threshold | float in [0, 1] | False | Node threshold | |
triggering_status | string | None | True | Trigger |
In the code below is shown the formulation of a Threshold model using NodeThreshold compartments.
The compartment, c1, is used to implement the transition rule Susceptible->Infected. It requires a threshold - here set equals to 0.2.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeThreshold as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
# Compartment definition
c1 = ns.NodeThreshold(0.1, triggering_status="Infected")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
In case of an heterogeneous node threshold distribution the same model can be expressed as follows
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeThreshold as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
# Compartment definition
c1 = ns.NodeThreshold(triggering_status="Infected")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
# Threshold specs
for i in g.nodes():
config.add_node_configuration("threshold", i, np.random.random_sample())
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Edge Compartments¶
In this class fall all those compartments that evaluate conditions tied to edge features. They model stochastic events as well as deterministic ones.
Edge Stochastic¶
Edge Stochastic compartments are used to evaluate stochastic events attached to network edges.
Consider the transition rule Susceptible->Infected that, to be triggered, requires a direct link among an infected node and a susceptible one. Moreover, it can happens subject to probability beta, a parameter tied to the specific edge connecting the two nodes. Such rule can be described by a simple compartment that models Edge Stochastic behaviors. Let’s call il ES.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the ES compartment. ES will thus require a probability (beta) of edge activation and a triggering status. In advanced scenarios, where the probability threshold vary from edge to edge, it is possible to specify it using the model configuration object.
During each rule evaluation, given a node n and one of its neighbors m
- if the actual status of n equals the rule initial one and the one of m equals the triggering one
- a random value b in [0,1] will be generated
- if b <= beta then ES is considered satisfied and the status of n changes from initial to final.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
threshold | float in [0, 1] | 1/N | True | Event probability |
triggering_status | string | None | False | Trigger |
Where N is the number of nodes in the graph.
In the code below is shown the formulation of a Cascade model using EdgeStochastic compartments.
The compartment, c1, is used to implement the transition rule Susceptible->Infected. It requires a probability threshold - here set equals to 0.02 - and restrain the rule evaluation to all those nodes that have at least an Infected neighbors.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.EdgeStochastic as es
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = ns.EdgeStochastic(0.02, triggering_status="Infected")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
In case of an heterogeneous edge threshold distribution the same model can be expressed as follows
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.EdgeStochastic as es
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = es.EdgeStochastic(triggering_status="Infected")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
# Threshold specs
for e in g.edges():
config.add_edge_configuration("threshold", e, np.random.random_sample())
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Edge Categorical Attribute¶
Edge Categorical Attribute compartments are used to evaluate events attached to edge attributes.
Consider the transition rule Susceptible->Infected that requires a that the susceptible node is connected to a neighbor through a link expressing a specific value of an internal attribute, attr, to be satisfied (e.g. “type”=”co-worker”). Such rule can be described by a simple compartment that models Edge Categorical Attribute selection. Let’s call il ECA.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the ECA compartment. ECA will thus require a probability (beta) of activation.
During each rule evaluation, given a node n and one of its neighbors m
- if the actual status of n equals the rule initial
- if attr(n,m) == attr
- a random value b in [0,1] will be generated
- if b <= beta, then ECA is considered satisfied and the status of n changes from initial to final.
Moreover, ECA allows to specify a triggering status in order to restrain the compartment evaluation to those nodes that:
- match the rule initial state, and
- have at least one neighbors in the triggering status.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
attribute | string | None | True | Attribute name |
value | string | None | True | Attribute testing value |
probability | float in [0, 1] | 1 | False | Event probability |
triggering_status | string | None | False | Trigger |
In the code below is shown the formulation of a model using EdgeCategoricalAttribute compartments.
The first compartment, c1, is used to implement the transition rule Susceptible->Infected. It restrain the rule evaluation to all those nodes connected through a link having the attribute “type” equals “co-worker”.
The second compartment, c2, is used to implement the transition rule Infected->Recovered. It restrain the rule evaluation to all those nodes connected trough a link having the attribute “type” equals “family” whose neighbors is “Susceptible”.
import networkx as nx
import random
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.EdgeCategoricalAttribute as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Setting edge attribute
attr = {e: {"type": random.choice(['co-worker', 'family'])} for e in g.edges()}
nx.set_edge_attributes(g, attr)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = na.NodeCategoricalAttribute("type", "co-worker", probability=0.6)
c2 = na.NodeCategoricalAttribute("type", "family", probability=0.6, triggering_status="Susceptible")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
model.add_rule("Infected", "Recovered", c2)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Edge Numerical Attribute¶
Edge Numerical Attribute compartments are used to evaluate events attached to numeric edge attributes.
Consider the transition rule Susceptible->Infected that requires a that the susceptible node is connected to a neighbor through a link expressing a specific value of an internal numeric attribute, attr, to be satisfied (e.g. “weight”>=3). Such rule can be described by a simple compartment that models Edge Numerical Attribute selection. Let’s call il ENA.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the ENA compartment. ENA will thus require a probability (beta) of activation.
During each rule evaluation, given a node n and one of its neighbors m
- if the actual status of n equals the rule initial
- if attr(n,m) op attr
- a random value b in [0,1] will be generated
- if b <= beta, then ECA is considered satisfied and the status of n changes from initial to final.
op represent a logic operator and can assume one of the following values: - equality: “==” - less than: “<” - greater than: “>” - equal or less than: “<=” - equal or greater than: “>=” - not equal to: “!=” - within: “IN”
Moreover, ENA allows to specify a triggering status in order to restrain the compartment evaluation to those nodes that:
- match the rule initial state, and
- have at least one neighbors in the triggering status.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
attribute | string | None | True | Attribute name |
value | numeric(*) | None | True | Attribute testing value |
op | string | None | True | Logic operator |
probability | float in [0, 1] | 1 | False | Event probability |
triggering_status | string | None | False | Trigger |
(*) When op equals “IN” the attribute value is expected to be a tuple of two elements identifying a closed interval.
In the code below is shown the formulation of a model using EdgeNumericalAttribute compartments.
The first compartment, c1, is used to implement the transition rule Susceptible->Infected. It restrain the rule evaluation to all those nodes connected at least to a neighbor through a link having “weight” equals to 4.
The second compartment, c2, is used to implement the transition rule Infected->Recovered. It restrain the rule evaluation to all those nodes connected at least to a “Susceptible” neighbor through a link having “weight” in the range [3, 6].
import networkx as nx
import random
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.EdgeNumericalAttribute as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Setting edge attribute
attr = {(u, v): {"weight": int((u+v) % 10)} for (u, v) in g.edges()}
nx.set_edge_attributes(g, attr)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = na.EdgeNumericalAttribute("weight", value=4, op="==", probability=0.6)
c2 = na.EdgeNumericalAttribute("weight", value=(3, 6), op="IN", probability=0.6, triggering_status="Susceptible")
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
model.add_rule("Infected", "Recovered", c2)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Time Compartments¶
In this class fall all those compartments that evaluate conditions tied to temporal execution. They can be used to model, for instance, lagged events as well as triggered transitions.
Count Down¶
Count Down compartments are used to evaluate time related deterministic events attached to network nodes.
Consider the transition rule Susceptible->Infected that has an incubation period of t iterations.
Such rule can be described by a simple compartment that models Count Down behaviors. Let’s call il CD.
The rule will take as input the initial node status (Susceptible), the final one (Infected) and the CD compartment. CD will thus require a countdown name (cn) and the number of iterations (t) before activation.
During each rule evaluation, given a node n
- if the actual status of n equals the rule initial one
- if the node does not have an associated countdown cn initialize it to t
- else
- if cn(t) > t decrement cn(t)
- if cn(t) <= t then CD is considered satisfied and the status of n changes from initial to final.
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
name | string | None | True | Count Down name |
iterations | int | None | True | Duration |
In the code below is shown the formulation of a model using CountDown compartments.
The compartment, c1, is used to implement the transition rule Susceptible->Infected. It requires activates after 10 iteration.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.CountDown as cd
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
# Compartment definition
c1 = cd.CountDown("incubation", iterations=10)
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Compartments Composition¶
Compartment can be chained in multiple ways so to describe complex transition rules. In particular, a transition rule can be seen as a tree whose nodes are compartments and edges connections among them.
- The initial node status is evaluated at the root of the tree (the master compartment)
- if the operation described by such compartment is satisfied the conditions of (one of) its child compartments is evaluated
- if a path from the root to one leaf of the tree is completely satisfied the transition rule applies and the node change its status.
Compartments can be combined following two criteria:
Cascading Composition¶
Since each compartment identifies an atomic condition it is natural to imagine rules described as chains of compartments.
A compartment chain identify and ordered set of conditions that needs to be satisfied to allow status transition (it allows describing an AND logic).
To implement such behaviour each compartment exposes a parameter (named composed) that allows to specify the subsequent compartment to evaluate in case it condition is satisfied.
Example¶
In the code below is shown the formulation of a model implementing cascading compartment composition.
The rule Susceptible->Infected is implemented using three NodeStochastic compartments chained as follows:
- If the node n is Susceptible
- c1: if at least a neighbor of the actual node is Infected, with probability 0.5 evaluate compartment c2
- c2: with probability 0.4 evaluate compartment c3
- c3: with probability 0.2 allow the transition to the Infected state
Indeed, heterogeneous compartment types can be mixed to build more complex scenarios.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeStochastic as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
# Compartment definition and chain construction
c3 = ns.NodeStochastic(0.2)
c2 = ns.NodeStochastic(0.4, composed=c3)
c1 = ns.NodeStochastic(0.5, "Infected", composed=c2)
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
Conditional Composition¶
Since each compartment identifies an atomic condition it is natural to imagine rules described as trees of compartments.
A compartment tree identify and ordered and disjoint set of conditions that needs to be satisfied to allow status transition (it allows describing an OR logic).
To implement such behaviour we implemented a ConditionalComposition compartment that allows to describe branching. Let’s call it CC.
CC evaluate a guard compartment and, depending from the result it gets evaluate (True or False) move to the evaluation of one of its two child compartments.
Parameters¶
Name | Value Type | Default | Mandatory | Description |
---|---|---|---|---|
condition | Compartment | None | True | Guard Compartment |
first_branch | Compartment | None | True | Positive Compartment |
second_branch | Compartment | None | True | Negative Compartment |
Example¶
In the code below is shown the formulation of a model implementing conditional compartment composition.
The rule Susceptible->Infected is implemented using three NodeStochastic compartments chained as follows:
- If the node n is Susceptible
- c1: if at least a neighbor of the actual node is Infected, with probability 0.5 evaluate compartment c2 else evaluate compartment c3
- c2: with probability 0.2 allow the transition to the Infected state
- c3: with probability 0.1 allow the transition to the Infected state
Indeed, heterogeneous compartment types can be mixed to build more complex scenarios.
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeStochastic as ns
import ndlib.models.compartments.ConditionalComposition as cif
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
# Compartment definition
c1 = ns.NodeStochastic(0.5, "Infected")
c2 = ns.NodeStochastic(0.2)
c3 = ns.NodeStochastic(0.1)
# Conditional Composition
cc = cif.ConditionalComposition(c1, c2, c3)
# Rule definition
model.add_rule("Susceptible", "Infected", cc)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(100)
A rule can be defined by employing all possible combinations of cascading and conditional compartment composition.
Examples¶
Here some example of models implemented using compartments.
SIR¶
import networkx as nx
import ndlib.models.ModelConfig as mc
import ndlib.models.CompositeModel as gc
import ndlib.models.compartments.NodeStochastic as ns
# Network generation
g = nx.erdos_renyi_graph(1000, 0.1)
# Composite Model instantiation
model = gc.CompositeModel(g)
# Model statuses
model.add_status("Susceptible")
model.add_status("Infected")
model.add_status("Removed")
# Compartment definition
c1 = ns.NodeStochastic(0.02, triggering_status="Infected")
c2 = ns.NodeStochastic(0.01)
# Rule definition
model.add_rule("Susceptible", "Infected", c1)
model.add_rule("Infected", "Removed", c2)
# Model initial status configuration
config = mc.Configuration()
config.add_model_parameter('percentage_infected', 0.1)
# Simulation execution
model.set_initial_status(config)
iterations = model.iteration_bunch(5)
NDQL: Network Diffusion Query Language¶
NDlib
aims to an heterogeneous audience composed by technicians as well as analysts.
In order to abstract from the its programming interface we designed a query language to describe diffusion simulations, NDQL
.
Rationale¶
NDQL
is built upon the custom model definition facilities offered by NDlib
.
It provides a simple, declarative, syntax for describing and executing diffusion simulations by
- creating a custom model composed of
- node statuses;
- transition rules (expressed as combinations of
compartments
)
- creating a synthetic graph / loading an existing network
- initialize initial nodes statuses
- run the simulation
NDQL
is designed to allow those users that are not familiar to the Python language to:
- abstract the technicality of the programming interface, and
- directly describe the expected model behaviour
So far, NDQL
supports only static network analysis.
NDQL Syntax¶
An NDQL
script is composed of a minimum set of directives:
- Model definition:
- MODEL, STATUS, COMPARTMENT (+), IF-THEN-ELSE (+), RULE,
- Model initialization:
- INITIALIZE
- Network specification:
- CREATE_NETWORK ($), LOAD_NETWORK ($)
- Simulation execution:
- EXECUTE
Directives marked with (+) are optional while the ones marked with ($) are mutually exclusive w.r.t. their class.
The complete language directive specification is the following:
MODEL model_name
STATUS status_name
COMPARTMENT compartment_name
TYPE compartment_type
COMPOSE compartment_name
[PARAM param_name numeric]*
[TRIGGER status_name]
IF compartment_name_1 THEN compartment_name_2 ELSE compartment_name_3 AS rule_name
RULE rule_name
FROM status_name
TO status_name
USING compartment_name
INITIALIZE
[SET status_name ratio]+
CREATE_NETWORK network_name
TYPE network_type
[PARAM param_name numeric]*
LOAD_NETWORK network_name FROM network_file
EXECUTE model_name ON network_name FOR iterations
The CREATE_NETWORK directive can take as network_type any networkx
graph generator name (param_name are inherited from generator function parameters).
Execute/Translate NDQL files¶
NDlib
installs two command line commands:
- NDQL_translate
- NDQL_execute
The former command allows to translate a generic, well-formed, NDQL
script into an equivalent Python one. It can be executed as
NDQL_translate query_file python_file
where query_file identifies the target NDQL
script and python_file specifies the desired name for the resulting Python script.
The latter command allows to directly execute a generic, well-formed, NDQL
script.It can be executed as
NDQL_execute query_file result_file
where query_file identifies the target NDQL
script and result_file specifies the desired name for the execution results.
Execution results are saved as JSON files with the following syntax:
[{"trends":
{
"node_count": {"0": [270, 179, 15, 0, 0], "1": [30, 116, 273, 256, 239], "2": [0, 5, 12, 44, 61]},
"status_delta": {"0": [0, -91, -164, -15, 0], "1": [0, 86, 157, -17, -17], "2": [0, 5, 7, 32, 17]}
},
"Statuses": {"1": "Infected", "2": "Removed", "0": "Susceptible"}
}]
where - node_count describe the trends built on the number of nodes per status - status_delta describe the trends built on the fluctuations of number of nodes per status - Statuses provides a map from numerical id to status name
Examples¶
Here some example of models implemented using NDQL
.
SIR¶
CREATE_NETWORK g1
TYPE erdos_renyi_graph
PARAM n 300
PARAM p 0.1
MODEL SIR
STATUS Susceptible
STATUS Infected
STATUS Removed
# Compartment definitions
COMPARTMENT c1
TYPE NodeStochastic
PARAM rate 0.1
TRIGGER Infected
COMPARTMENT c2
TYPE NodeStochastic
PARAM rate 0.1
# Rule definitions
RULE
FROM Susceptible
TO Infected
USING c1
RULE
FROM Infected
TO Removed
USING c2
# Model configuration
INITIALIZE
SET Infected 0.1
EXECUTE SIR ON g1 FOR 5
Experiment Server¶
The simulation facilities offered by NDlib
are specifically designed for those users that want to run experiments on their local machine.
However, in some scenarios, e.g. due to limited computational resources or to the rising of other particular needs, it may be convenient to separate the machine on which the definition of the experiment is made from the one that actually executes the simulation.
In order to satisfy such needs, we developed a RESTfull service, NDlib-REST
, that builds upon NDlib
an experiment server queryable through API calls.
Project Website: https://github.com/GiulioRossetti/ndlib-rest
Rationale¶
The simulation web service is designed around the concept of experiment.
An experiment, identified by a unique identifier, is composed of two entities:
- a network, and
- one (or more) configured diffusion models.
Experiments are used to keep track of the simulation definition, to return consecutive model iterations to the user and to store - locally on the experiment server - the current status of the diffusion process.
In particular, in order to perform an experiment, a user must:
- Request a token, which univocally identifies the experiment;
- Select or load a network resource;
- Select one, or more, diffusion model(s);
- (optional) Use the advanced configuration facilities to define node/edge parameters;
- Execute the step-by-step simulation;
- (optional) Reset the experiment status, modify the models/network;
- Destroy the experiment.
The last action, involving the destruction of the experiment, is designed to clean the serialization made by the service of the incremental experiment status.
If an experiment is not explicitly destroyed its data is removed, and the associated token invalidated, after a temporal window that can be configured by the service administrator.
NDlib-REST
is shipped as a Docker container image so to make it configuration free and easier to setup.
Moreover, the simulation server is, by default, executed within a Gunicorn instance allowing parallel executions of multiple experiments at the same time.
NDlib-REST
is built using Flask and offers a standard online documentation page that can also be directly used to test the exposed endpoints both configuring and running experiments.
API Interface¶
As a standard for REST services, all the calls made to NDlib-REST
endpoints generate JSON responses.
The APIs of the simulation service are organized in six categories so to provide a logic separation among all the exposed resources.
In particular, in NDlib-REST
are exposed endpoints handling:
- Experiment: endpoints in this category allow to create, destroy, configure, reset and describe experiments;
- Exploratories: endpoints in this category allow to load predefined scenarios (e.g. specific networks/models with explicit initial configuration);
- Resources: endpoints in this category allow to query the system to dynamically discover the endpoints (and their descriptions) defined within the system;
- Networks: endpoints in this category handle a load of network data as well as the generation of synthetic graphs (Barabasi-Albert, Erdos-Renyi, Watts-Strogatz…);
- Models: endpoints in this category expose the
NDlib
models; - Iterators: endpoints in this category expose the step-by-step and iteration bunch facilities needed to run the simulation.
The simulation service allows to attach multiple diffusion models to the same experiment, thus both the single iteration and the iteration bunch endpoints expose additional parameters that allow the user to select the models for which the call was invoked.
By default, when such parameter is not specified, all the models are executed and their incremental statuses returned.
A particular class of endpoints is the Exploratories one. Such endpoints are used to define the access to pre-set diffusion scenarios. Using such facilities the owner of the simulation server can describe, beforehand, specific scenarios, package them and make them available to the service users.
From an educational point of view such mechanism can be used, for instance, by professors to design emblematic diffusion scenarios (composed by both network and initial node/edge statuses) so to let the students explore their impact on specific models configurations (e.g. to analyze the role of weak-ties and/or community structures).
Installation¶
The project provides:
- The REST service: ndrest.py
- Web API docs: http://127.0.0.1:5000/docs
- Unittest: ndlib-rest/service_test
- Python REST client: ndlib-rest/client
REST service setup¶
Local testing
python ndrest.py
Local testig with multiple workers (using gunicorn web server):
gunicorn -w num_workers -b 127.0.0.1:5000 ndrest:app
In order to change the binding IP/port modify the apidoc.json file. To update the API page run the command:
apidoc -i ndlib-rest/ -o ndlib-rest/static/docs
Docker Container¶
The web application is shipped in a Docker container. You can use the Dockerfile to create a new image and run the web application using the gunicorn application server.
To create the Docker image, install Docker on your machine. To create the image execute the following command from the local copy of the repository
docker build -t [tagname_for_your_image] .
The command create a new image with the specified name. Pay attention to the . a the end of the command.
docker run -d -i -p 5000:5000 [tagname_for_your_image]
This command execute a container with the previous image, bind the local port 5000 to the internal port of the container. The option -d make the container to run in the background (detached)
To have a list of all active container
docker ps -al
To stop a container
docker stop container_name
Configuration¶
In ndrest.py are specified limits for graph sizes.
In particular are set the minimum and maximum numbers of nodes (for both generators and loaded networks) as well as the maximum file sizes for upload.
app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 # 50MB limit for uploads
max_number_of_nodes = 100000
min_number_of_nodes = 200 # inherited by networkx
- The “complete graph generator” endpoint represents the only exception to the specified lower bound on number of nodes: such model lowers the minimum to 100 nodes. Indeed, the suggested limits can be increased to handle bigger graphs.
- When loading external graphs nodes MUST be identified by integer ids.
Visual Framework¶
NDlib
aims to an heterogeneous audience composed by technicians as well as analysts.
In order to abstract from the its programming interface we built a simple visual framework that allows to simulate NDlib
built-in models on synthetic graphs.
Project Website: https://github.com/rinziv/NDLib-Viz
Rationale¶
NDlib-Viz
aims to make non-technicians able to design, configure and run epidemic simulations, thus removing the barriers introduced by the usual requirements of programming language knowledge.
Indeed, apart from the usual research-oriented audience, we developed NDlib-Viz
to support students and facilitate teachers to introduce epidemic models.
The platform itself is a web application: it can be executed on a local as well as on a remote NDlib-REST
installation.
Installation¶
NDlib-Viz
requires a local active instance of NDlib-REST
to be executed.
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
# build for production and view the bundle analyzer report
npm run build --report
For detailed explanation on how things work, checkout the guide and docs for vue-loader.
Architecture¶
The Visualization Framework is a single-page web application implemented using Javascript and HTML 5. The decoupling of the simulation engine and the visual interface allows us to exploit modern browsers to provide an efficient environment for visualization of models and interactions.
- The structure and layout of the page are managed with Bootstrap.
- The business logic and visualization of graphical widgets are implemented in D3.js.
- Nodes and edges of the networks are drawn using the Force Layout library provided by the D3 library.
- The network visualization is implemented using Canvas object provided by standard HTML5. This allows a very efficient update of the network view.
- The charts showing the Diffusion Trend and Prevalence are created using NVD3 library.
The Visualization Framework is implemented using a Model-Control-View (MCV) design pattern. The model is managed by a central component that implements a REST API client that handle the status of the experiment. When the user interacts with one of the views (charts, network layout, toolbar), the controller notifies the model to update the experiment. Each interaction with the visual interface is managed by the model component that centralizes all the communications with the REST server. The calls to the server are executed asynchronously, and the component updates the visual interface as soon as a response arrives from the server.
Developer Guide¶
Working with NDlib source code¶
Contents:
Introduction¶
These pages describe a git and github workflow for the NDlib project.
There are several different workflows here, for different ways of working with NDlib.
This is not a comprehensive git reference, it’s just a workflow for our own project. It’s tailored to the github hosting service. You may well find better or quicker ways of getting stuff done with git, but these should get you started.
For general resources for learning git, see git resources.
Install git¶
Overview¶
Debian / Ubuntu | sudo apt-get install git |
Fedora | sudo yum install git-core |
Windows | Download and install msysGit [1] |
OS X | Use the git-osx-installer [2] |
In detail¶
See the git page for the most recent information.
Have a look at the github install help pages available from github help [3] .
There are good instructions here: http://book.git-scm.com/2_installing_git.html
[1] | https://git-for-windows.github.io |
[2] | https://code.google.com/archive/p/git-osx-installer/downloads |
[3] | http://help.github.com/ |
Following the latest source¶
These are the instructions if you just want to follow the latest NDlib source, but you don’t need to do any development for now.
The steps are:
- Install git
- get local copy of the ndlib github git repository
- update local copy from time to time
Get the local copy of the code¶
From the command line:
git clone git://github.com/GiulioRossetti/ndlib.git
You now have a copy of the code tree in the new ndlib
directory.
Updating the code¶
From time to time you may want to pull down the latest code. It is necessary to add the NDlib repository as a remote to your configuration file. We call it upstream.
git remote set-url upstream https://github.com/GiulioRossetti/ndlib.git
Now git knows where to fetch updates from.
cd ndlib git fetch upstream
The tree in ndlib
will now have the latest changes from the initial
repository, unless you have made local changes in the meantime. In this case, you have to merge.
git merge upstream/master
It is also possible to update your local fork directly from GitHub:
- Open your fork on GitHub.
- Click on ‘Pull Requests’.
- Click on ‘New Pull Request’. By default, GitHub will compare the original with your fork. If you didn’t make any changes, there is nothing to compare.
- Click on ‘Switching the base’ or click ‘Edit’ and switch the base manually. Now GitHub will compare your fork with the original, and you should see all the latest changes.
- Click on ‘Click to create a pull request for this comparison’ and name your pull request.
- Click on Send pull request.
- Scroll down and click ‘Merge pull request’ and finally ‘Confirm merge’. You will be able to merge it automatically unless you did not change you local repo.
Making a patch¶
You’ve discovered a bug or something else you want to change in ndlib .. - excellent!
You’ve worked out a way to fix it - even better!
You want to tell us about it - best of all!
The easiest way is to make a patch or set of patches. Here we explain how.
Making patches¶
# tell git who you are
git config --global user.email you@yourdomain.example.com
git config --global user.name "Your Name Comes Here"
# get the repository if you don't have it
git clone git://github.com/GiulioRossetti/ndlib.git
# make a branch for your patching
cd networkx
git branch the-fix-im-thinking-of
git checkout the-fix-im-thinking-of
# hack, hack, hack
# Tell git about any new files you've made
git add somewhere/tests/test_my_bug.py
# commit work in progress as you go
git commit -am 'BF - added tests for Funny bug'
# hack hack, hack
git commit -am 'BF - added fix for Funny bug'
# make the patch files
git format-patch -M -C master
Then, open an issue on the projetc GitHub and attach the generated patch files.
Tell git who you are so it can label the commits you’ve made:
git config --global user.email you@yourdomain.example.com git config --global user.name "Your Name Comes Here"
If you don’t already have one, clone a copy of the ndlib repository:
git clone git://github.com/GiulioRossetti/ndlib.git cd networkx
Make a ‘feature branch’. This will be where you work on your bug fix. It’s nice and safe and leaves you with access to an unmodified copy of the code in the main branch:
git branch the-fix-im-thinking-of git checkout the-fix-im-thinking-of
Do some edits, and commit them as you go:
# hack, hack, hack # Tell git about any new files you've made git add somewhere/tests/test_my_bug.py # commit work in progress as you go git commit -am 'BF - added tests for Funny bug' # hack hack, hack git commit -am 'BF - added fix for Funny bug'
Note the
-am
options tocommit
. Them
flag just signals that you’re going to type a message on the command line.When you have finished, check you have committed all your changes:
git status
Finally, make your commits into patches. You want all the commits since you branched from the
master
branch:git format-patch -M -C master
You will now have several files named for the commits:
0001-BF-added-tests-for-Funny-bug.patch 0002-BF-added-fix-for-Funny-bug.patch
Attach these files to a novel issue on the project GitHub.
When you are done, to switch back to the main copy of the
code, just return to the master
branch:
git checkout master
Extend NDlib¶
The NDlib
library can be extended by adding both models and visualization facilities.
In this section are introduced the basilar concept behind the class model adopted in NDlib
and some best practice for the definition of novel models and visualizations.
Describe a Diffusion Model¶
All the diffusion models implemented in NDlib
extends the abstract class ndlib.models.DiffusionModel
.
-
class
ndlib.models.DiffusionModel.
DiffusionModel
(graph)¶ Partial Abstract Class that defines Diffusion Models
Such class implements the logic behind model construction, configuration and execution.
In order to describe a novel diffusion algorithm the following steps must be followed:
Model Description¶
As convention a new model should be described in a python file named after it, e.g. a MyModule
class should be implemented in a MyModule.py
file.
-
DiffusionModel.
__init__
(self, graph)¶ Model Constructor
Parameters: graph – A networkx graph object
In oder to effectively describe the model the __init__
function of ndlib.models.DiffusionModel
must be specified as follows:
from ndlib.models.DiffusionModel import DiffusionModel
class MyModel(DiffusionModel):
def __init__(self, graph):
# Call the super class constructor
super(self.__class__, self).__init__(graph)
# Method name
self.name = "MyModel"
# Available node statuses
self.available_statuses = {
"Status_0": 0,
"Status_1": 1
}
# Exposed Parameters
self.parameters = {
"model":
"parameter_name": {
"descr": "Description 1"
"range": [0,1],
"optional": False
},
},
"nodes":
"node_parameter_name": {
"descr": "Description 2"
"range": [0,1],
"optional": True
},
},
"edges":
"edge_parameter_name": {
"descr": "Description 3"
"range": [0,1],
"optional": False
},
},
}
In the __init__
methods three components are used to completely specify the model:
self.name
: its name;self.available_statuses
: the node statuses it allows along with an associated numerical code;self.parameters
: the parameters it requires, their range, description and optionality.
All those information will be used to check the user provided configurations as well as metadata for visualizations.
Iteration Rule¶
Once described the model metadata it is necessary to provide the agent-based description of its general iteration-step.
-
DiffusionModel.
iteration
(self)¶ Execute a single model iteration
Parameters: node_status – if the incremental node status has to be returned. Returns: Iteration_id, (optional) Incremental node status (dictionary node->status), Status count (dictionary status->node count), Status delta (dictionary status->node delta)
To do so, the iteration()
method of the base class has to be overridden in MyModel
as follows:
def iteration(self, node_status=True):
self.clean_initial_status(self.available_statuses.values())
# if first iteration return the initial node status
if self.actual_iteration == 0:
self.actual_iteration += 1
delta, node_count, status_delta = self.status_delta(actual_status)
if node_status:
return {"iteration": 0, "status": actual_status.copy(),
"node_count": node_count.copy(), "status_delta": status_delta.copy()}
else:
return {"iteration": 0, "status": {},
"node_count": node_count.copy(), "status_delta": status_delta.copy()}
actual_status = {node: nstatus for node, nstatus in self.status.iteritems()}
# iteration inner loop
for u in self.graph.nodes():
# evluate possible status changes using the model parameters (accessible via self.params)
# e.g. self.params['beta'], self.param['nodes']['threshold'][u], self.params['edges'][(id_node0, idnode1)]
# identify the changes w.r.t. previous iteration
delta, node_count, status_delta = self.status_delta(actual_status)
# update the actual status and iterative step
self.status = actual_status
self.actual_iteration += 1
# return the actual configuration (only nodes with status updates)
if node_status:
return {"iteration": self.actual_iteration - 1, "status": delta.copy(),
"node_count": node_count.copy(), "status_delta": status_delta.copy()}
else:
return {"iteration": self.actual_iteration - 1, "status": {},
"node_count": node_count.copy(), "status_delta": status_delta.copy()}
The provided template is composed by 4 steps:
- first iteration handling: if present the model returns as result of the first iteration is initial status;
- making a copy of the actual diffusion status;
- iteration loop: definition, and application, of the rules that regulates individual node status transitions;
- construction of the incremental result.
All the steps are mandatory in order to assure a consistent behaviour across different models
All the user specified parameters (models as well as nodes and edges ones) can be used within the iteration()
method: to access them an internal data structure is provided, self.params
.
self.params
is a dictionary that collects all the passed values using the following notation:
- Model parameters:
self.params['model']['parameter_name']
- Node parameters:
self.param['nodes']['nodes_parameter'][node_id]
- Edge parameters:
self.param['edges']['edges_parameter'][(node_id1, node_id2)]
Within the iteration loop the node status updates must be made on the actual_status
data structure, e.g. the copy made during Step 1.
Each iteration returns the incremental status of the diffusion process as well as the iteration progressive number.
Describe a Visuzlization¶
All the matplotlib
visualizations implemented so far in NDlib
extends the abstract class nndlib.viz.mpl.DiffusionViz.DiffusionPlot
.
-
class
ndlib.viz.mpl.DiffusionViz.
DiffusionPlot
(model, trends)¶
Conversely, visualizations that use the bokeh
library, should extend the abstract class nndlib.viz.bokeh.DiffusionViz.DiffusionPlot
.
Here is introduced the pattern for describing novel matplotlib
based visualization, bokeh
ones following the same rationale.
So far DiffusionPlot
implements the visualization logic only for generic trend line plot built upon simulation iterations and model metadata.
Line Plot Definition¶
As convention a new visualization should be described in a python file named after it, e.g. a MyViz
class should be implemented in a MyViz.py
file.
In oder to effectively describe the visualization the __init__
function of ndlib.viz.bokeh.DiffusionViz.DiffusionPlot
must be specified as follows:
from ndlib.viz.mpl.DiffusionViz import DiffusionPlot
class MyViz(DiffusionPlot):
def __init__(self, model, trends):
super(self.__class__, self).__init__(model, trends)
self.ylabel = "#Nodes"
self.title = "Diffusion Trend"
Data Preparation¶
Once described the plot metadata it is necessary to prepare the data to be visualized through the plot()
method.
To do so, the iteration_series(percentile)
method of the base class has to be overridden in MyViz
.
Such method can access the trend data, as returned by ndlib.models.DiffusionModel.DiffusionModel.build_trends(self, iterations)
in self.iterations
.
Bibliography¶
NDlib
was developed for research purposes.
So far it has been used as support to the following publications:
- “NDlib: a Python Library to Model and Analyze Diffusion Processes Over Complex Networks”
- G. Rossetti, L. Milli, S. Rinzivillo, A. Sirbu, D. Pedreschi, F. Giannotti. International Journal of Data Science and Analytics. 2017. DOI:0.1007/s41060-017-0086-6 (pre-print available on arXiv)
- “NDlib: Studying Network Diffusion Dynamics”
- G. Rossetti, L. Milli, S. Rinzivillo, A. Sirbu, D. Pedreschi, F. Giannotti. IEEE International Conference on Data Science and Advanced Analytics, DSAA. 2017.
- “Information Diffusion in Complex Networks: The Active/Passive Conundrum”
- L. Milli, G. Rossetti, D. Pedreschi, F. Giannotti International Conference on Complex Networks and their Applications, 2017. DOI:10.1007/978-3-319-72150-7_25
- “Diffusive Phenomena in Dynamic Networks: a data-driven study”
- L. Milli, G. Rossetti, D. Pedreschi, F. Giannotti. 9th Conference on Complex Networks, CompleNet, 2018.