diff --git a/docs/reference/models/epidemics/ICE.rst b/docs/reference/models/epidemics/ICE.rst new file mode 100644 index 0000000..a258a59 --- /dev/null +++ b/docs/reference/models/epidemics/ICE.rst @@ -0,0 +1,107 @@ +************************************************** +Independent Cascades with Community Embeddedness +************************************************** + +The Independent Cascades with Community Embeddedness model was introduced by Milli and Rossetti in 2019 [#]_. + +This model is a variation of the well-known Independent Cascade (IC), and it is designed to embed community awareness into the IC model. +The probability p(u,v) of the IC model is replaced by the edge embeddedness. + +The embeddedness of an edge :math:`(u,v)` with :math:`u,v \in C` is defined as: +:math:`e_{u,v} = \frac{\phi_{u,v}}{|\Gamma(u) \cup \Gamma(v)|}` +where :math:`\phi_{u,v}` is the number of common neighbors of u and v within :math:`C`, and :math:`\Gamma(u)` ( :math:`\Gamma(v)`) is the set of neighbors of the node u (v) in the analyzed graph G. + +The ICE 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 u. If v and u belong to the same community, it succeeds with a probability :math:`e_{u,v}`; otherwise with probability :math:`\min\{e_{z,v}|(z, v)\in E\}`. +- If u has multiple newly activated neighbors, their attempts are sequenced in an arbitrary order. +- If v succeeds, then u will become active in step t + 1; but whether or not v succeeds, it cannot make any further attempts to activate u in subsequent rounds. +- The process runs until no more activations are possible. + +-------- +Statuses +-------- + +During the simulation a node can experience the following statuses: + +=========== ==== +Name Code +=========== ==== +Susceptible 0 +Infected 1 +Removed 2 +=========== ==== + + +---------- +Parameters +---------- + +The model is parameter free + +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.ICEModel.ICEModel +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.__init__(graph) + +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.set_initial_status(self, configuration) +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.reset(self) + +^^^^^^^^ +Describe +^^^^^^^^ + +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.get_info(self) +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.get_status_map(self) + +^^^^^^^^^^^^^^^^^^ +Execute Simulation +^^^^^^^^^^^^^^^^^^ +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.iteration(self) +.. automethod:: ndlib.models.epidemics.ICEModel.ICEModel.iteration_bunch(self, bunch_size) + +------- +Example +------- + +In the code below is shown an example of instantiation and execution of an ICE model simulation on a random graph: we set the initial set of infected nodes as 1% of the overall population. + + +.. 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 = ep.ICEModel(g) + + # Model Configuration + config = mc.Configuration() + config.add_model_parameter('fraction_infected', 0.1) + + model.set_initial_status(config) + + # Simulation execution + iterations = model.iteration_bunch(200) + + +.. [#] L. Milli and G. Rossetti. “Community-Aware Content Diffusion: Embeddednes and Permeability,” in Proceedings of International Conference on Complex Networks and Their Applications, 2019 pp. 362--371. \ No newline at end of file diff --git a/docs/reference/models/epidemics/ICEP.rst b/docs/reference/models/epidemics/ICEP.rst new file mode 100644 index 0000000..904c532 --- /dev/null +++ b/docs/reference/models/epidemics/ICEP.rst @@ -0,0 +1,114 @@ +****************************************************************** +Independent Cascades with Community Embeddedness and Permeability +****************************************************************** + +The Independent Cascades with Community Embeddedness and Permeability model was introduced by Milli and Rossetti in 2020 [#]_. + +This model is a combination of ICE and ICP methods. + +The ICEP 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 u. If v and u belong to the same community, the method acts as the ICE model, otherwise as the ICP model. +- If u has multiple newly activated neighbors, their attempts are sequenced in an arbitrary order. +- If v succeeds, then u will become active in step t + 1; but whether or not v succeeds, it cannot make any further attempts to activate u in subsequent rounds. +- The process runs until no more activations are possible. + +-------- +Statuses +-------- + +During the simulation a node can experience the following statuses: + +=========== ==== +Name Code +=========== ==== +Susceptible 0 +Infected 1 +Removed 2 +=========== ==== + + +---------- +Parameters +---------- + +====================== ===== =============== ======= ========= ====================== +Name Type Value Type Default Mandatory Description +====================== ===== =============== ======= ========= ====================== +Edge threshold Edge float in [0, 1] 0.1 False Edge threshold +Community permeability Model float in [0, 1] 0.5 True Community Permeability +====================== ===== =============== ======= ========= ====================== + +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.ICEPModel.ICEPModel +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.__init__(graph) + +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.set_initial_status(self, configuration) +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.reset(self) + +^^^^^^^^ +Describe +^^^^^^^^ + +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.get_info(self) +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.get_status_map(self) + +^^^^^^^^^^^^^^^^^^ +Execute Simulation +^^^^^^^^^^^^^^^^^^ +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.iteration(self) +.. automethod:: ndlib.models.epidemics.ICEPModel.ICEPModel.iteration_bunch(self, bunch_size) + +------- +Example +------- + +In the code below is shown an example of instantiation and execution of an ICEP model simulation on a random graph: we set the initial set of infected nodes as 1% of the overall population, assign a threshold of 0.1 to all the edges and set the community permeability equal 0.3. + + +.. 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 = ep.ICEPModel(g) + + # Model Configuration + config = mc.Configuration() + config.add_model_parameter('fraction_infected', 0.1) + config.add_model_parameter('permeability', 0.3) + + + # 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) + + +.. [#] L. Milli and G. Rossetti. “Barriers or Accelerators? Modeling the two-foldnature of meso-scale network topologies indiffusive phenomena,” 2020 \ No newline at end of file diff --git a/docs/reference/models/epidemics/ICP.rst b/docs/reference/models/epidemics/ICP.rst new file mode 100644 index 0000000..30a862d --- /dev/null +++ b/docs/reference/models/epidemics/ICP.rst @@ -0,0 +1,116 @@ +************************************************** +Independent Cascades with Community Permeability +************************************************** + +The Independent Cascades with Community Permeability model was introduced by Milli and Rossetti in 2019 [#]_. + +This model is a variation of the well-known Independent Cascade (IC), and it is designed to embed community awareness into the IC model. +This model exploits the idea of permeability. A community is “permeable” to a given content if it permits that content to spread from it fast +(or vice-versa, if it permits the content to be easily received from nodes outside the community). Conversely, a community has a low degree of permeability if it dampens the diffusion probability across its border. + +The ICP 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 u. If v and u belong to the same community, the method works as a standard IC model (it succeeds with a probability p(v,u)); instead, if the nodes are part of to different communities, the likelihood p(v,u) is dampened of a factor :math:`\eta` (the community permeability parameter). +- If u has multiple newly activated neighbors, their attempts are sequenced in an arbitrary order. +- If v succeeds, then u will become active in step t + 1; but whether or not v succeeds, it cannot make any further attempts to activate u in subsequent rounds. +- The process runs until no more activations are possible. + +-------- +Statuses +-------- + +During the simulation a node can experience the following statuses: + +=========== ==== +Name Code +=========== ==== +Susceptible 0 +Infected 1 +Removed 2 +=========== ==== + + +---------- +Parameters +---------- + +====================== ===== =============== ======= ========= ====================== +Name Type Value Type Default Mandatory Description +====================== ===== =============== ======= ========= ====================== +Edge threshold Edge float in [0, 1] 0.1 False Edge threshold +Community permeability Model float in [0, 1] 0.5 True Community Permeability +====================== ===== =============== ======= ========= ====================== + +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.ICPModel.IndependentCascadesModel +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.__init__(graph) + +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.set_initial_status(self, configuration) +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.reset(self) + +^^^^^^^^ +Describe +^^^^^^^^ + +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.get_info(self) +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.get_status_map(self) + +^^^^^^^^^^^^^^^^^^ +Execute Simulation +^^^^^^^^^^^^^^^^^^ +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.iteration(self) +.. automethod:: ndlib.models.epidemics.ICPModel.ICPModel.iteration_bunch(self, bunch_size) + +------- +Example +------- + +In the code below is shown an example of instantiation and execution of an ICP model simulation on a random graph: we set the initial set of infected nodes as 1% of the overall population, assign a threshold of 0.1 to all the edges and set the community permeability equal 0.3. + + +.. 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 = ep.ICPModel(g) + + # Model Configuration + config = mc.Configuration() + config.add_model_parameter('fraction_infected', 0.1) + config.add_model_parameter('permeability', 0.3) + + + # 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) + + +.. [#] L. Milli and G. Rossetti. “Community-Aware Content Diffusion: Embeddednes and Permeability,” in Proceedings of International Conference on Complex Networks and Their Applications, 2019 pp. 362--371. \ No newline at end of file diff --git a/docs/reference/reference.rst b/docs/reference/reference.rst index b363591..26453e1 100644 --- a/docs/reference/reference.rst +++ b/docs/reference/reference.rst @@ -50,6 +50,9 @@ In ``NDlib`` are implemented the following **Epidemic** models: models/epidemics/Profile.rst models/epidemics/ProfileThreshold.rst models/epidemics/UTLDR.rst + models/epidemics/ICEP.rst + models/epidemics/ICP.rst + models/epidemics/ICE.rst ---------------- diff --git a/ndlib/models/epidemics/ICEModel.py b/ndlib/models/epidemics/ICEModel.py index 0be34bb..98b2b5c 100644 --- a/ndlib/models/epidemics/ICEModel.py +++ b/ndlib/models/epidemics/ICEModel.py @@ -1,6 +1,7 @@ from ndlib.models.DiffusionModel import DiffusionModel import numpy as np import future.utils +import networkx as nx __author__ = 'Giulio Rossetti' __license__ = "BSD-2-Clause" @@ -12,13 +13,13 @@ class ICEModel(DiffusionModel): Parameter free model: probability of diffusion tied to community embeddedness of individual nodes """ - def __init__(self, graph, seed=None): + def __init__(self, graph): """ Model Constructor :param graph: A networkx graph object """ - super(self.__class__, self).__init__(graph, seed) + super(self.__class__, self).__init__(graph) self.available_statuses = { "Susceptible": 0, "Infected": 1, @@ -52,12 +53,32 @@ def iteration(self, node_status=True): return {"iteration": 0, "status": {}, "node_count": node_count.copy(), "status_delta": status_delta.copy()} + edge_embeddedness = {} for u in self.graph.nodes: if self.status[u] != 1: continue + edge_embeddedness[u] = {} + com_embeddedness = {} + neighbors = list(self.graph.neighbors(u)) # neighbors and successors (in DiGraph) produce the same result - same_community_neighbors = [n for n in neighbors if self.params['nodes']['com'][u] == self.params['nodes']['com'][n]] + embeddedness = 1 + for v in neighbors: + same_community_neighbors = 0 + neighbors_v = list(self.graph.neighbors(v)) + for neighbor in neighbors_v: + if neighbor in neighbors and self.params['nodes']['com'][neighbor] == self.params['nodes']['com'][u]: + same_community_neighbors += 1 + tmp_embeddedness = float(same_community_neighbors) / float( + len(neighbors) + len(neighbors_v) - same_community_neighbors) + edge_embeddedness[u][v] = tmp_embeddedness + if tmp_embeddedness < embeddedness: + embeddedness = tmp_embeddedness + com_embeddedness[self.params['nodes']['com'][u]] = embeddedness + + + # neighbors = list(self.graph.neighbors(u)) # neighbors and successors (in DiGraph) produce the same result + #same_community_neighbors = [n for n in neighbors if self.params['nodes']['com'][u] == self.params['nodes']['com'][n]] # Standard threshold if len(neighbors) > 0: @@ -66,10 +87,10 @@ def iteration(self, node_status=True): if actual_status[v] == 0: if self.params['nodes']['com'][u] == self.params['nodes']['com'][v]: - threshold = float(len(same_community_neighbors))/len(neighbors) + threshold = edge_embeddedness[u][v] else: # across communities - threshold = 1 - float(len(same_community_neighbors))/len(neighbors) + threshold = com_embeddedness[self.params['nodes']['com'][u]] flip = np.random.random_sample() if flip <= threshold: diff --git a/ndlib/models/epidemics/ICEPModel.py b/ndlib/models/epidemics/ICEPModel.py index c07de43..904cba3 100644 --- a/ndlib/models/epidemics/ICEPModel.py +++ b/ndlib/models/epidemics/ICEPModel.py @@ -37,7 +37,13 @@ def __init__(self, graph): } }, "nodes": {}, - "edges": {}, + "edges": { + "threshold": { + "descr": "Edge threshold", + "range": [0, 1], + "optional": True, + "default": 0.1} + }, } self.name = "Community Permeability" @@ -61,15 +67,17 @@ def iteration(self, node_status=True): return {"iteration": 0, "status": {}, "node_count": node_count.copy(), "status_delta": status_delta.copy()} + edge_embeddedness = {} for u in self.graph.nodes: if self.status[u] != 1: continue + edge_embeddedness[u] = {} + neighbors = list(self.graph.neighbors(u)) # neighbors and successors (in DiGraph) produce the same result - same_community_neighbors = [n for n in neighbors if - self.params['nodes']['com'][u] == self.params['nodes']['com'][n]] - # Standard threshold + + # Standard threshold if len(neighbors) > 0: threshold = 1.0/len(neighbors) @@ -77,8 +85,16 @@ def iteration(self, node_status=True): if actual_status[v] == 0: key = (u, v) + same_community_neighbors = 0 + neighbors_v = list(self.graph.neighbors(v)) + for neighbor in neighbors_v: + if neighbor in neighbors and self.params['nodes']['com'][neighbor] == self.params['nodes']['com'][u]: + same_community_neighbors += 1 + edge_embeddedness[u][v] = float(same_community_neighbors) / float( + len(neighbors) + len(neighbors_v) - same_community_neighbors) + if self.params['nodes']['com'][u] == self.params['nodes']['com'][v]: # within same community - threshold = float(len(same_community_neighbors))/len(neighbors) # Embedness + threshold = edge_embeddedness[u][v] # Embedness else: # across communities p = self.params['model']['permeability']