-
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
7 changed files
with
236 additions
and
7 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
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,95 @@ | ||
************************************************ | ||
Attraction-Repulsion Weighted Hegselmann-Krause | ||
************************************************ | ||
|
||
The Hegselmann-Krause model was introduced in 2002 by Hegselmann, Krause et al [#]_. | ||
|
||
During each interaction a random agenti is selected and the set :math:`\Gamma_{\epsilon}` of its neighbors whose | ||
opinions differ at most :math:`\epsilon` (:math:`d_{i,j}=|x_i(t)-x_j(t)|\leq \epsilon`) is identified. | ||
The selected agent i changes its opinion based on the following update rule: | ||
|
||
.. math:: | ||
x_i(t+1)= \frac{\sum_{j \in \Gamma_{\epsilon}} x_j(t)}{\#\Gamma_{\epsilon}} | ||
The idea behind the WHK formulation is that the opinion of agent :math:`i` at time :math:`t+1`, will be given by the average | ||
opinion by its, selected, :math:`\epsilon`-neighbor. | ||
|
||
-------- | ||
Statuses | ||
-------- | ||
|
||
Node statuses are continuous values in [-1,1]. | ||
|
||
---------- | ||
Parameters | ||
---------- | ||
|
||
=========================== ===== ========================= ======= ========= ============================================== | ||
Name Type Value Type Default Mandatory Description | ||
=========================== ===== ========================= ======= ========= ============================================== | ||
epsilon Model float in [0, 1] --- True Bounded confidence threshold | ||
=========================== ===== ========================= ======= ========= ============================================== | ||
|
||
------- | ||
Methods | ||
------- | ||
|
||
The following class methods are made available to configure, describe and execute the simulation: | ||
|
||
^^^^^^^^^ | ||
Configure | ||
^^^^^^^^^ | ||
|
||
.. autoclass:: ndlib.models.opinions.HKModel.HKModel | ||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.__init__(graph) | ||
|
||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.set_initial_status(self, configuration) | ||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.reset(self) | ||
|
||
^^^^^^^^ | ||
Describe | ||
^^^^^^^^ | ||
|
||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.get_info(self) | ||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.get_status_map(self) | ||
|
||
^^^^^^^^^^^^^^^^^^ | ||
Execute Simulation | ||
^^^^^^^^^^^^^^^^^^ | ||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.iteration(self) | ||
.. automethod:: ndlib.models.opinions.HKModel.HKModel.iteration_bunch(self, bunch_size) | ||
|
||
|
||
------- | ||
Example | ||
------- | ||
|
||
In the code below is shown an example of instantiation and execution of an HK model simulation on a random graph: | ||
we an epsilon value of 0.32 . | ||
|
||
|
||
.. code-block:: python | ||
import networkx as nx | ||
import ndlib.models.ModelConfig as mc | ||
import ndlib.models.opinions as opn | ||
# Network topology | ||
g = nx.erdos_renyi_graph(1000, 0.1) | ||
# Model selection | ||
model = opn.HKModel(g) | ||
# Model Configuration | ||
config = mc.Configuration() | ||
config.add_model_parameter("epsilon", 0.32) | ||
model.set_initial_status(config) | ||
# Simulation execution | ||
iterations = model.iteration_bunch(20) | ||
.. [#] R. Hegselmann, U. Krause, et al.: “Opinion dynamics and bounded confidence models, analysis, and simulation." in Journal of artificial societies and social simulation, 2002 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
from ndlib.models.DiffusionModel import DiffusionModel | ||
import future.utils | ||
import numpy as np | ||
import random | ||
from sklearn.metrics import jaccard_score | ||
|
||
__author__ = ['Letizia Milli'] | ||
__license__ = "BSD-2-Clause" | ||
|
||
class HKModel(DiffusionModel): | ||
""" | ||
Model Parameters to be specified via ModelConfig | ||
:param epsilon: bounded confidence threshold from the HK model (float in [0,1]) | ||
""" | ||
|
||
def __init__(self, graph): | ||
""" | ||
Model Constructor | ||
:param graph: A networkx graph object | ||
""" | ||
super(self.__class__, self).__init__(graph) | ||
self.discrete_state = False | ||
|
||
self.available_statuses = { | ||
"Infected": 0 | ||
} | ||
|
||
self.parameters = { | ||
"model": { | ||
"epsilon": { | ||
"descr": "Bounded confidence threshold", | ||
"range": [0, 1], | ||
"optional": False, | ||
} | ||
}, | ||
"edges": {}, | ||
"nodes": {}, | ||
} | ||
self.name = "Hegselmann-Krause" | ||
|
||
def set_initial_status(self, configuration=None): | ||
""" | ||
Override behaviour of methods in class DiffusionModel. | ||
Overwrites initial status using random real values. | ||
""" | ||
super(HKModel, self).set_initial_status(configuration) | ||
|
||
# set node status | ||
for node in self.status: | ||
self.status[node] = random.uniform(-1, 1) | ||
self.initial_status = self.status.copy() | ||
|
||
|
||
def clean_initial_status(self, valid_status=None): | ||
for n, s in future.utils.iteritems(self.status): | ||
if s > 1 or s < -1: | ||
self.status[n] = 0.0 | ||
|
||
def iteration(self, node_status=True): | ||
|
||
''' | ||
Execute a single model iteration | ||
:return: Iteration_id, Incremental node status (dictionary code -> status) | ||
''' | ||
# An iteration changes the opinion of the selected agent 'i' . | ||
|
||
self.clean_initial_status(None) | ||
|
||
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(self.status) | ||
if node_status: | ||
return {"iteration": 0, "status": self.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 i in range(0, self.graph.number_of_nodes()): | ||
# select a random node | ||
n1 = list(self.graph.nodes)[np.random.randint(0, self.graph.number_of_nodes())] | ||
|
||
# select neighbors of n1 | ||
neighbours = list(self.graph.neighbors(n1)) | ||
sum_op = 0 | ||
count_in_eps = 0 | ||
|
||
if len(neighbours) == 0: | ||
continue | ||
|
||
for neigh in neighbours: | ||
# compute the difference between opinions | ||
diff_opinion = np.abs((actual_status[n1]) - (actual_status[neigh])) | ||
if diff_opinion < self.params['model']['epsilon']: | ||
sum_op += actual_status[neigh] | ||
# count_in_eps is the number of neighbors in epsilon | ||
count_in_eps += 1 | ||
|
||
if (count_in_eps > 0): | ||
new_op = sum_op / float(count_in_eps) | ||
else: | ||
# if there aren't neighbors in epsilon, the status of n1 doesn't change | ||
new_op = actual_status[n1] | ||
|
||
actual_status[n1] = new_op | ||
|
||
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