-
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.
Merge pull request #135 from GiulioRossetti/community-aware
🆕 community-aware IC
- Loading branch information
Showing
6 changed files
with
266 additions
and
6 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,89 @@ | ||
from ndlib.models.DiffusionModel import DiffusionModel | ||
import numpy as np | ||
import future.utils | ||
|
||
__author__ = 'Giulio Rossetti' | ||
__license__ = "BSD-2-Clause" | ||
__email__ = "giulio.rossetti@gmail.com" | ||
|
||
|
||
class ICEModel(DiffusionModel): | ||
""" | ||
Parameter free model: probability of diffusion tied to community embeddedness of individual nodes | ||
""" | ||
|
||
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, | ||
"Removed": 2 | ||
} | ||
|
||
self.parameters = { | ||
"model": {}, | ||
"nodes": {}, | ||
"edges": {} | ||
} | ||
|
||
self.name = "Community Embeddedness" | ||
|
||
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 self.status[u] != 1: | ||
continue | ||
|
||
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: | ||
|
||
for v in neighbors: | ||
if actual_status[v] == 0: | ||
|
||
if self.params['nodes']['com'][u] == self.params['nodes']['com'][v]: | ||
threshold = float(len(same_community_neighbors))/len(neighbors) | ||
|
||
else: # across communities | ||
threshold = 1 - float(len(same_community_neighbors))/len(neighbors) | ||
|
||
flip = np.random.random_sample() | ||
if flip <= threshold: | ||
actual_status[v] = 1 | ||
|
||
actual_status[u] = 2 | ||
|
||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
from ndlib.models.DiffusionModel import DiffusionModel | ||
import numpy as np | ||
import future.utils | ||
|
||
__author__ = 'Giulio Rossetti' | ||
__license__ = "BSD-2-Clause" | ||
__email__ = "giulio.rossetti@gmail.com" | ||
|
||
|
||
class ICPModel(DiffusionModel): | ||
""" | ||
Edge Parameters to be specified via ModelConfig | ||
:param threshold: The edge threshold. As default a value of 0.1 is assumed for all edges. | ||
:param permeability: The degree of permeability of a community toward outgoing diffusion processes | ||
""" | ||
|
||
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, | ||
"Removed": 2 | ||
} | ||
|
||
self.parameters = { | ||
"model": { | ||
"permeability":{ | ||
"descr": "Community permeability", | ||
"range": [0,1], | ||
"optional": False, | ||
"default": 0.5 | ||
} | ||
}, | ||
"nodes": {}, | ||
"edges": { | ||
"threshold": { | ||
"descr": "Edge threshold", | ||
"range": [0, 1], | ||
"optional": True, | ||
"default": 0.1 | ||
} | ||
}, | ||
} | ||
|
||
self.name = "Community Permeability" | ||
|
||
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 self.status[u] != 1: | ||
continue | ||
|
||
neighbors = list(self.graph.neighbors(u)) # neighbors and successors (in DiGraph) produce the same result | ||
|
||
# Standard threshold | ||
if len(neighbors) > 0: | ||
threshold = 1.0/len(neighbors) | ||
|
||
for v in neighbors: | ||
if actual_status[v] == 0: | ||
key = (u, v) | ||
|
||
if self.params['nodes']['com'][u] == self.params['nodes']['com'][v]: # within same community | ||
# Individual specified thresholds | ||
if 'threshold' in self.params['edges']: | ||
if key in self.params['edges']['threshold']: | ||
threshold = self.params['edges']['threshold'][key] | ||
elif (v, u) in self.params['edges']['threshold'] and not self.graph.directed: | ||
threshold = self.params['edges']['threshold'][(v, u)] | ||
|
||
else: # across communities | ||
p = self.params['model']['permeability'] | ||
if 'threshold' in self.params['edges']: | ||
if key in self.params['edges']['threshold']: | ||
threshold = self.params['edges']['threshold'][key] * p | ||
elif (v, u) in self.params['edges']['threshold'] and not self.graph.directed: | ||
threshold = self.params['edges']['threshold'][(v, u)] * p | ||
|
||
flip = np.random.random_sample() | ||
if flip <= threshold: | ||
actual_status[v] = 1 | ||
|
||
actual_status[u] = 2 | ||
|
||
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
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