-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
257 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
********************* | ||
General Threshold | ||
********************* | ||
|
||
The General Threshold model was introduced in 20003 by Kempe [#]_. | ||
|
||
In this model, during an epidemics, a 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 if the sum of the weight of the infected neighbors is greater than the threshold | ||
|
||
-------- | ||
Statuses | ||
-------- | ||
During the simulation a node can experience the following statuses: | ||
|
||
=========== ==== | ||
Name Code | ||
=========== ==== | ||
Susceptible 0 | ||
Infected 1 | ||
=========== ==== | ||
|
||
---------- | ||
Parameters | ||
---------- | ||
|
||
========= ===== =============== ======= ========= ======================= | ||
Name Type Value Type Default Mandatory Description | ||
========= ===== =============== ======= ========= ======================= | ||
threshold Node float in [0, 1] 0.1 False Individual threshold | ||
weight Edge float in [0, 1] 0.1 False Edge weight | ||
========= ===== =============== ======= ========= ======================= | ||
|
||
The initial infection status can be defined via: | ||
|
||
- **fraction_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. | ||
|
||
------- | ||
Methods | ||
------- | ||
|
||
The following class methods are made available to configure, describe and execute the simulation: | ||
|
||
^^^^^^^^^ | ||
Configure | ||
^^^^^^^^^ | ||
.. autoclass:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel | ||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.__init__(graph) | ||
|
||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.set_initial_status(self, configuration) | ||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.reset(self) | ||
|
||
^^^^^^^^ | ||
Describe | ||
^^^^^^^^ | ||
|
||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.get_info(self) | ||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.get_status_map(self) | ||
|
||
^^^^^^^^^^^^^^^^^^ | ||
Execute Simulation | ||
^^^^^^^^^^^^^^^^^^ | ||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.iteration(self) | ||
.. automethod:: ndlib.models.epidemics.GeneralThresholdModel.GeneralThresholdModel.iteration_bunch(self, bunch_size) | ||
|
||
|
||
------- | ||
Example | ||
------- | ||
|
||
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. | ||
|
||
|
||
.. code-block:: python | ||
import networkx as nx | ||
import ndlib.models.ModelConfig as mc | ||
import ndlib.models.epidemics as ep | ||
# Network topology | ||
g = nx.erdos_renyi_graph(1000, 0.1) | ||
# Model selection | ||
model = epd.GeneralThresholdModel(g) | ||
# Model Configuration | ||
config = mc.Configuration() | ||
config.add_model_parameter('fraction_infected', 0.1) | ||
# Setting node and edges parameters | ||
threshold = 0.25 | ||
weight = 0.2 | ||
if isinstance(g, nx.Graph): | ||
nodes = g.nodes | ||
edges = g.edges | ||
else: | ||
nodes = g.vs['name'] | ||
edges = [(g.vs[e.tuple[0]]['name'], g.vs[e.tuple[1]]['name']) for e in g.es] | ||
for i in nodes: | ||
config.add_node_configuration("threshold", i, threshold) | ||
for e in edges: | ||
config.add_edge_configuration("weight", e, weight) | ||
model.set_initial_status(config) | ||
# Simulation execution | ||
iterations = model.iteration_bunch(200) | ||
.. [#] János Török and János Kertész “Cascading collapse of online social networks” Scientific reports, vol. 7 no. 1, 2017 | ||
David Kempe , Jon Kleinberg, and Éva Tardos. "Maximizing the spread of influence through a social network." Proceedings of the ninth ACM SIGKDD international conference on Knowledge discovery and data mining. ACM, 2003. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
from ..DiffusionModel import DiffusionModel | ||
import future.utils | ||
|
||
|
||
__author__ = "Letizia Milli" | ||
__license__ = "BSD-2-Clause" | ||
__email__ = "letizia.milli@di.unipi.it" | ||
|
||
|
||
class GeneralThresholdModel(DiffusionModel): | ||
""" | ||
Node Parameters to be specified via ModelConfig | ||
:param threshold: The node threshold. If not specified otherwise a value of 0.1 is assumed for all nodes. | ||
:param weight: The edge weight. If not specified otherwise a value of 0.1 is assumed for all edges. | ||
""" | ||
|
||
def __init__(self, graph): | ||
""" | ||
Model Constructor | ||
:param graph: A networkx graph object | ||
""" | ||
super(self.__class__, self).__init__(graph) | ||
self.available_statuses = { | ||
"Susceptible": 0, | ||
"Infected": 1 | ||
} | ||
|
||
self.parameters = { | ||
"model": {}, | ||
"nodes": { | ||
"threshold": { | ||
"descr": "Node threshold", | ||
"range": [0, 1], | ||
"optional": True, | ||
"default": 0.1 | ||
} | ||
}, | ||
"edges": { | ||
"weight": { | ||
"descr": "Edge threshold", | ||
"range": [0, 1], | ||
"optional": True, | ||
"default": 0.1 | ||
} | ||
}, | ||
} | ||
|
||
self.name = "GeneralThresholdModel" | ||
|
||
def iteration(self, node_status=True): | ||
""" | ||
Execute a single model iteration | ||
:return: Iteration_id, Incremental node status (dictionary node->status) | ||
""" | ||
self.clean_initial_status(self.available_statuses.values()) | ||
|
||
actual_status = {node: nstatus for node, nstatus in future.utils.iteritems(self.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()} | ||
|
||
for u in self.graph.nodes: | ||
if actual_status[u] == 1: | ||
continue | ||
|
||
neighbors = list(self.graph.neighbors(u)) | ||
if self.graph.directed: | ||
neighbors = list(self.graph.predecessors(u)) | ||
|
||
weight = 0 | ||
for v in neighbors: | ||
if self.status[v] == 1: | ||
key = (u, v) | ||
if key in self.params['edges']['weight']: | ||
weight += self.params['edges']['weight'][key] | ||
elif (v, u) in self.params['edges']['weight'] and not self.graph.directed: | ||
weight += self.params['edges']['weight'][(v, u)] | ||
|
||
if len(neighbors) > 0: | ||
if weight >= self.params['nodes']['threshold'][u]: | ||
actual_status[u] = 1 | ||
|
||
delta, node_count, status_delta = self.status_delta(actual_status) | ||
self.status = actual_status | ||
self.actual_iteration += 1 | ||
|
||
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()} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters