Initial commit
@ -1,4 +0,0 @@
|
||||
include requirements.txt
|
||||
include test-requirements.txt
|
||||
include README.rst
|
||||
graft soil
|
@ -1,34 +1,12 @@
|
||||
# [SOIL](https://github.com/gsi-upm/soil)
|
||||
|
||||
Soil is an extensible and user-friendly Agent-based Social Simulator for Social Networks.
|
||||
Learn how to run your own simulations with our [documentation](http://soilsim.readthedocs.io).
|
||||
|
||||
Follow our [tutorial](notebooks/soil_tutorial.ipynb) to develop your own agent models.
|
||||
|
||||
If you use Soil in your research, don't forget to cite this paper:
|
||||
|
||||
```bibtex
|
||||
@inbook{soil-gsi-conference-2017,
|
||||
author = "S{\'a}nchez, Jes{\'u}s M. and Iglesias, Carlos A. and S{\'a}nchez-Rada, J. Fernando",
|
||||
booktitle = "Advances in Practical Applications of Cyber-Physical Multi-Agent Systems: The PAAMS Collection",
|
||||
doi = "10.1007/978-3-319-59930-4_19",
|
||||
editor = "Demazeau Y., Davidsson P., Bajo J., Vale Z.",
|
||||
isbn = "978-3-319-59929-8",
|
||||
keywords = "soil;social networks;agent based social simulation;python",
|
||||
month = "June",
|
||||
organization = "PAAMS 2017",
|
||||
pages = "234-245",
|
||||
publisher = "Springer Verlag",
|
||||
series = "LNAI",
|
||||
title = "{S}oil: {A}n {A}gent-{B}ased {S}ocial {S}imulator in {P}ython for {M}odelling and {S}imulation of {S}ocial {N}etworks",
|
||||
url = "https://link.springer.com/chapter/10.1007/978-3-319-59930-4_19",
|
||||
volume = "10349",
|
||||
year = "2017",
|
||||
}
|
||||
|
||||
```
|
||||
#[Soil](https://github.com/gsi-upm/soil)
|
||||
|
||||
The purpose of Soil (SOcial network sImuLator) is provding an Agent-based Social Simulator written in Python for Social Networks.
|
||||
|
||||
|
||||
In order to see quickly how to use Soil, you can follow the following [tutorial](https://github.com/gsi-upm/soil/blob/master/soil_tutorial.ipynb).
|
||||
|
||||
@Copyright GSI - Universidad Politécnica de Madrid 2017
|
||||
|
||||
[![SOIL](logo_gsi.png)](https://www.gsi.dit.upm.es)
|
||||
|
||||
|
||||
|
||||
@Copyright GSI - Universidad Politécnica de Madrid 2017
|
||||
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 16 KiB |
@ -1,24 +1,7 @@
|
||||
Installation
|
||||
------------
|
||||
|
||||
The easiest way to install Soil is through pip:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
pip install soil
|
||||
|
||||
|
||||
Now test that it worked by running the command line tool
|
||||
The latest version can be installed through GitLab.
|
||||
|
||||
.. code:: bash
|
||||
|
||||
soil --help
|
||||
|
||||
Or using soil programmatically:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import soil
|
||||
print(soil.__version__)
|
||||
|
||||
The latest version can be installed through `GitLab <https://lab.cluster.gsi.dit.upm.es/soil/soil.git>`_.
|
||||
git clone https://lab.cluster.gsi.dit.upm.es/soil/soil.git
|
@ -0,0 +1,112 @@
|
||||
Developing new models
|
||||
---------------------
|
||||
This document describes how to develop a new analysis model.
|
||||
|
||||
What is a model?
|
||||
================
|
||||
|
||||
A model defines the behaviour of the agents with a view to assessing their effects on the system as a whole.
|
||||
In practice, a model consists of at least two parts:
|
||||
|
||||
* Python module: the actual code that describes the behaviour.
|
||||
* Setting up the variables in the Settings JSON file.
|
||||
|
||||
This separation allows us to run the simulation with different agents.
|
||||
|
||||
Models Code
|
||||
===========
|
||||
|
||||
All the models are imported to the main file. The initialization look like this:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import settings
|
||||
|
||||
networkStatus = {} # Dict that will contain the status of every agent in the network
|
||||
|
||||
sentimentCorrelationNodeArray = []
|
||||
for x in range(0, settings.network_params["number_of_nodes"]):
|
||||
sentimentCorrelationNodeArray.append({'id': x})
|
||||
# Initialize agent states. Let's assume everyone is normal.
|
||||
init_states = [{'id': 0, } for _ in range(settings.network_params["number_of_nodes"])]
|
||||
# add keys as as necessary, but "id" must always refer to that state category
|
||||
|
||||
A new model have to inherit the BaseBehaviour class which is in the same module.
|
||||
There are two basics methods:
|
||||
|
||||
* __init__
|
||||
* step: used to define the behaviour over time.
|
||||
|
||||
Variable Initialization
|
||||
=======================
|
||||
|
||||
The different parameters of the model have to be initialize in the Simulation Settings JSON file which will be
|
||||
passed as a parameter to the simulation.
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"agent": ["SISaModel","ControlModelM2"],
|
||||
|
||||
"neutral_discontent_spon_prob": 0.04,
|
||||
"neutral_discontent_infected_prob": 0.04,
|
||||
"neutral_content_spon_prob": 0.18,
|
||||
"neutral_content_infected_prob": 0.02,
|
||||
|
||||
"discontent_neutral": 0.13,
|
||||
"discontent_content": 0.07,
|
||||
"variance_d_c": 0.02,
|
||||
|
||||
"content_discontent": 0.009,
|
||||
"variance_c_d": 0.003,
|
||||
"content_neutral": 0.088,
|
||||
|
||||
"standard_variance": 0.055,
|
||||
|
||||
|
||||
"prob_neutral_making_denier": 0.035,
|
||||
|
||||
"prob_infect": 0.075,
|
||||
|
||||
"prob_cured_healing_infected": 0.035,
|
||||
"prob_cured_vaccinate_neutral": 0.035,
|
||||
|
||||
"prob_vaccinated_healing_infected": 0.035,
|
||||
"prob_vaccinated_vaccinate_neutral": 0.035,
|
||||
"prob_generate_anti_rumor": 0.035
|
||||
}
|
||||
|
||||
In this file you will also define the models you are going to simulate. You can simulate as many models as you want.
|
||||
The simulation returns one result for each model, executing each model separately. For the usage, see :doc:`usage`.
|
||||
|
||||
Example Model
|
||||
=============
|
||||
|
||||
In this section, we will implement a Sentiment Correlation Model.
|
||||
|
||||
The class would look like this:
|
||||
|
||||
.. code:: python
|
||||
|
||||
from ..BaseBehaviour import *
|
||||
from .. import sentimentCorrelationNodeArray
|
||||
|
||||
class SentimentCorrelationModel(BaseBehaviour):
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.outside_effects_prob = environment.environment_params['outside_effects_prob']
|
||||
self.anger_prob = environment.environment_params['anger_prob']
|
||||
self.joy_prob = environment.environment_params['joy_prob']
|
||||
self.sadness_prob = environment.environment_params['sadness_prob']
|
||||
self.disgust_prob = environment.environment_params['disgust_prob']
|
||||
self.time_awareness = []
|
||||
for i in range(4): # In this model we have 4 sentiments
|
||||
self.time_awareness.append(0) # 0-> Anger, 1-> joy, 2->sadness, 3 -> disgust
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now] = 0
|
||||
|
||||
def step(self, now):
|
||||
self.behaviour() # Method which define the behaviour
|
||||
super().step(now)
|
||||
|
||||
The variables will be modified by the user, so you have to include them in the Simulation Settings JSON file.
|
Before Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB |
@ -1,194 +0,0 @@
|
||||
Quickstart
|
||||
----------
|
||||
|
||||
This section shows how to run simulations from simulation configuration files.
|
||||
First of all, you need to install the package (See :doc:`installation`)
|
||||
|
||||
Simulation configuration files are ``json`` or ``yaml`` files that define all the parameters of a simulation.
|
||||
Here's an example (``example.yml``).
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
---
|
||||
name: MyExampleSimulation
|
||||
max_time: 50
|
||||
num_trials: 3
|
||||
timeout: 2
|
||||
network_params:
|
||||
network_type: barabasi_albert_graph
|
||||
n: 100
|
||||
m: 2
|
||||
agent_distribution:
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: content
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: discontent
|
||||
- agent_type: SISaModel
|
||||
weight: 8
|
||||
state:
|
||||
id: neutral
|
||||
environment_params:
|
||||
prob_infect: 0.075
|
||||
|
||||
Now run the simulation with the command line tool:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
soil example.yml
|
||||
|
||||
Once the simulation finishes, its results will be stored in a folder named ``MyExampleSimulation``.
|
||||
Four types of objects are saved by default: a pickle of the simulation, a ``YAML`` representation of the simulation (to re-launch it), for every trial, a csv file with the content of the state of every network node and the environment parameters at every step of the simulation as well as the network in gephi format (``gexf``).
|
||||
|
||||
|
||||
.. code::
|
||||
|
||||
soil_output
|
||||
├── Sim_prob_0
|
||||
│ ├── Sim_prob_0.dumped.yml
|
||||
│ ├── Sim_prob_0.simulation.pickle
|
||||
│ ├── Sim_prob_0_trial_0.environment.csv
|
||||
│ └── Sim_prob_0_trial_0.gexf
|
||||
|
||||
|
||||
This example configuration will run three trials of a simulation containing a randomly generated network.
|
||||
The 100 nodes in the network will be SISaModel agents, 10% of them will start in the content state, 10% in the discontent state, and the remaining 80% in the neutral state.
|
||||
All agents will have access to the environment, which only contains one variable, ``prob_infected``.
|
||||
The state of the agents will be updated every 2 seconds (``timeout``).
|
||||
|
||||
|
||||
Network
|
||||
=======
|
||||
|
||||
The network topology for the simulation can be loaded from an existing network file or generated with one of the random network generation methods from networkx.
|
||||
|
||||
Loading a network
|
||||
#################
|
||||
|
||||
To load an existing network, specify its path in the configuration:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
---
|
||||
network_params:
|
||||
path: /tmp/mynetwork.gexf
|
||||
|
||||
Soil will try to guess what networkx method to use to read the file based on its extension.
|
||||
However, we only test using ``gexf`` files.
|
||||
|
||||
Generating a random network
|
||||
###########################
|
||||
|
||||
To generate a random network using one of networkx's built-in methods, specify the `graph generation algorithm <https://networkx.github.io/documentation/development/reference/generators.html>`_ and other parameters.
|
||||
For example, the following configuration is equivalent to :code:`nx.complete_graph(100)`:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
network_params:
|
||||
network_type: complete_graph
|
||||
n: 100
|
||||
|
||||
Environment
|
||||
============
|
||||
The environment is the place where the shared state of the simulation is stored.
|
||||
For instance, the probability of certain events.
|
||||
The configuration file may specify the initial value of the environment parameters:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
environment_params:
|
||||
daily_probability_of_earthquake: 0.001
|
||||
number_of_earthquakes: 0
|
||||
|
||||
Agents
|
||||
======
|
||||
Agents are a way of modelling behavior.
|
||||
Agents can be characterized with two variables: an agent type (``agent_type``) and its state.
|
||||
Only one agent is executed at a time (generally, every ``timeout`` seconds), and it has access to its state and the environment parameters.
|
||||
Through the environment, it can access the network topology and the state of other agents.
|
||||
|
||||
There are three three types of agents according to how they are added to the simulation: network agents, environment agent, and other agents.
|
||||
|
||||
Network Agents
|
||||
##############
|
||||
Network agents are attached to a node in the topology.
|
||||
The configuration file allows you to specify how agents will be mapped to topology nodes.
|
||||
|
||||
The simplest way is to specify a single type of agent.
|
||||
Hence, every node in the network will have an associated agent of that type.
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
agent_type: SISaModel
|
||||
|
||||
It is also possible to add more than one type of agent to the simulation, and to control the ratio of each type (``weight``).
|
||||
For instance, with following configuration, it is five times more likely for a node to be assigned a CounterModel type than a SISaModel type.
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
agent_distribution:
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
- agent_type: CounterModel
|
||||
weight: 5
|
||||
|
||||
In addition to agent type, you may also add a custom initial state to the distribution.
|
||||
This is very useful to add the same agent type with different states.
|
||||
e.g., to populate the network with SISaModel, roughly 10% of them with a discontent state:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
agent_distribution:
|
||||
- agent_type: SISaModel
|
||||
weight: 9
|
||||
state:
|
||||
id: neutral
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: discontent
|
||||
|
||||
Lastly, the configuration may include initial state for one or more nodes.
|
||||
For instance, to add a state for the two nodes in this configuration:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
agent_type: SISaModel
|
||||
network:
|
||||
network_type: complete_graph
|
||||
n: 2
|
||||
states:
|
||||
- id: content
|
||||
- id: discontent
|
||||
|
||||
|
||||
Or to add state only to specific nodes (by ``id``).
|
||||
For example, to apply special skills to Linux Torvalds in a simulation:
|
||||
|
||||
.. literalinclude:: ../examples/torvalds.yml
|
||||
:language: yaml
|
||||
|
||||
|
||||
Environment Agents
|
||||
##################
|
||||
In addition to network agents, more agents can be added to the simulation.
|
||||
These agens are programmed in much the same way as network agents, the only difference is that they will not be assigned to network nodes.
|
||||
|
||||
|
||||
.. code::
|
||||
|
||||
environment_agents:
|
||||
- agent_type: MyAgent
|
||||
state:
|
||||
mood: happy
|
||||
- agent_type: DummyAgent
|
||||
|
||||
|
||||
Visualizing the results
|
||||
=======================
|
||||
|
||||
The simulation will return a dynamic graph .gexf file which could be visualized with
|
||||
`Gephi <https://gephi.org/users/download/>`__.
|
@ -0,0 +1,99 @@
|
||||
Usage
|
||||
-----
|
||||
|
||||
First of all, you need to install the package. See :doc:`installation` for installation instructions.
|
||||
|
||||
Simulation Settings
|
||||
===================
|
||||
|
||||
Once installed, before running a simulation, you need to configure it.
|
||||
|
||||
* In the Settings JSON file you will find the configuration of the network.
|
||||
|
||||
.. code:: python
|
||||
|
||||
{
|
||||
"network_type": 1,
|
||||
"number_of_nodes": 1000,
|
||||
"max_time": 50,
|
||||
"num_trials": 1,
|
||||
"timeout": 2
|
||||
}
|
||||
|
||||
* In the Settings JSON file, you will also find the configuration of the models.
|
||||
|
||||
Network Types
|
||||
=============
|
||||
|
||||
There are three types of network implemented, but you could add more.
|
||||
|
||||
.. code:: python
|
||||
|
||||
if settings.network_type == 0:
|
||||
G = nx.complete_graph(settings.number_of_nodes)
|
||||
if settings.network_type == 1:
|
||||
G = nx.barabasi_albert_graph(settings.number_of_nodes, 10)
|
||||
if settings.network_type == 2:
|
||||
G = nx.margulis_gabber_galil_graph(settings.number_of_nodes, None)
|
||||
# More types of networks can be added here
|
||||
|
||||
Models Settings
|
||||
===============
|
||||
|
||||
After having configured the simulation, the next step is setting up the variables of the models.
|
||||
For this, you will need to modify the Settings JSON file again.
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"agent": ["SISaModel","ControlModelM2"],
|
||||
|
||||
"neutral_discontent_spon_prob": 0.04,
|
||||
"neutral_discontent_infected_prob": 0.04,
|
||||
"neutral_content_spon_prob": 0.18,
|
||||
"neutral_content_infected_prob": 0.02,
|
||||
|
||||
"discontent_neutral": 0.13,
|
||||
"discontent_content": 0.07,
|
||||
"variance_d_c": 0.02,
|
||||
|
||||
"content_discontent": 0.009,
|
||||
"variance_c_d": 0.003,
|
||||
"content_neutral": 0.088,
|
||||
|
||||
"standard_variance": 0.055,
|
||||
|
||||
|
||||
"prob_neutral_making_denier": 0.035,
|
||||
|
||||
"prob_infect": 0.075,
|
||||
|
||||
"prob_cured_healing_infected": 0.035,
|
||||
"prob_cured_vaccinate_neutral": 0.035,
|
||||
|
||||
"prob_vaccinated_healing_infected": 0.035,
|
||||
"prob_vaccinated_vaccinate_neutral": 0.035,
|
||||
"prob_generate_anti_rumor": 0.035
|
||||
}
|
||||
|
||||
In this file you will define the different models you are going to simulate. You can simulate as many models
|
||||
as you want. Each model will be simulated separately.
|
||||
|
||||
After setting up the models, you have to initialize the parameters of each one. You will find the parameters needed
|
||||
in the documentation of each model.
|
||||
|
||||
Parameter validation will fail if a required parameter without a default has not been provided.
|
||||
|
||||
Running the Simulation
|
||||
======================
|
||||
|
||||
After setting all the configuration, you will be able to run the simulation. All you need to do is execute:
|
||||
|
||||
.. code:: bash
|
||||
|
||||
python3 soil.py
|
||||
|
||||
The simulation will return a dynamic graph .gexf file which could be visualized with
|
||||
`Gephi <https://gephi.org/users/download/>`__.
|
||||
|
||||
It will also return one .png picture for each model simulated.
|
@ -1,24 +0,0 @@
|
||||
---
|
||||
name: simple
|
||||
dir_path: "/tmp/"
|
||||
num_trials: 3
|
||||
max_time: 100
|
||||
interval: 1
|
||||
network_params:
|
||||
generator: complete_graph
|
||||
n: 10
|
||||
network_agents:
|
||||
- agent_type: CounterModel
|
||||
weight: 1
|
||||
state:
|
||||
id: 0
|
||||
- agent_type: AggregatedCounter
|
||||
weight: 0.2
|
||||
environment_agents: []
|
||||
environment_params:
|
||||
am_i_complete: true
|
||||
default_state:
|
||||
incidents: 0
|
||||
states:
|
||||
- name: 'The first node'
|
||||
- name: 'The second node'
|
@ -1,17 +0,0 @@
|
||||
default_state: {}
|
||||
environment_agents: []
|
||||
environment_params: {prob_neighbor_spread: 0.0, prob_tv_spread: 0.01}
|
||||
interval: 1
|
||||
max_time: 20
|
||||
name: Sim_prob_0
|
||||
network_agents:
|
||||
- agent_type: NewsSpread
|
||||
state: {has_tv: false}
|
||||
weight: 1
|
||||
- agent_type: NewsSpread
|
||||
state: {has_tv: true}
|
||||
weight: 2
|
||||
network_params: {generator: erdos_renyi_graph, n: 500, p: 0.1}
|
||||
num_trials: 1
|
||||
states:
|
||||
- {has_tv: true}
|
@ -1,20 +0,0 @@
|
||||
import soil
|
||||
import random
|
||||
|
||||
class NewsSpread(soil.agents.FSM):
|
||||
@soil.agents.default_state
|
||||
@soil.agents.state
|
||||
def neutral(self):
|
||||
r = random.random()
|
||||
if self['has_tv'] and r < self.env['prob_tv_spread']:
|
||||
return self.infected
|
||||
return
|
||||
|
||||
@soil.agents.state
|
||||
def infected(self):
|
||||
prob_infect = self.env['prob_neighbor_spread']
|
||||
for neighbor in self.get_neighboring_agents(state_id=self.neutral.id):
|
||||
r = random.random()
|
||||
if r < prob_infect:
|
||||
neighbor.state['id'] = self.infected.id
|
||||
return
|
@ -1,2 +0,0 @@
|
||||
balkian Torvalds {}
|
||||
anonymous Torvalds {}
|
@ -1,14 +0,0 @@
|
||||
---
|
||||
name: torvalds_example
|
||||
max_time: 1
|
||||
interval: 2
|
||||
agent_type: CounterModel
|
||||
default_state:
|
||||
skill_level: 'beginner'
|
||||
network_params:
|
||||
path: 'torvalds.edgelist'
|
||||
states:
|
||||
Torvalds:
|
||||
skill_level: 'God'
|
||||
balkian:
|
||||
skill_level: 'developer'
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,38 @@
|
||||
import settings
|
||||
from nxsim import BaseNetworkAgent
|
||||
from .. import networkStatus
|
||||
|
||||
|
||||
class BaseBehaviour(BaseNetworkAgent):
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self._attrs = {}
|
||||
|
||||
@property
|
||||
def attrs(self):
|
||||
now = self.env.now
|
||||
if now not in self._attrs:
|
||||
self._attrs[now] = {}
|
||||
return self._attrs[now]
|
||||
|
||||
@attrs.setter
|
||||
def attrs(self, value):
|
||||
self._attrs[self.env.now] = value
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self.step(self.env.now)
|
||||
yield self.env.timeout(settings.network_params["timeout"])
|
||||
|
||||
def step(self, now):
|
||||
networkStatus['agent_%s'% self.id] = self.to_json()
|
||||
|
||||
def to_json(self):
|
||||
final = {}
|
||||
for stamp, attrs in self._attrs.items():
|
||||
for a in attrs:
|
||||
if a not in final:
|
||||
final[a] = {}
|
||||
final[a][stamp] = attrs[a]
|
||||
return final
|
@ -0,0 +1 @@
|
||||
from .BaseBehaviour import BaseBehaviour
|
@ -0,0 +1,367 @@
|
||||
import random
|
||||
import numpy as np
|
||||
from ..BaseBehaviour import *
|
||||
import settings
|
||||
import networkx as nx
|
||||
|
||||
|
||||
|
||||
POPULATION = 0
|
||||
LEADERS = 1
|
||||
HAVEN = 2
|
||||
TRAININGENV = 3
|
||||
|
||||
NON_RADICAL = 0
|
||||
NEUTRAL = 1
|
||||
RADICAL = 2
|
||||
|
||||
POPNON =0
|
||||
POPNE=1
|
||||
POPRAD=2
|
||||
|
||||
HAVNON=3
|
||||
HAVNE=4
|
||||
HAVRAD=5
|
||||
|
||||
LEADER=6
|
||||
|
||||
TRAINING = 7
|
||||
|
||||
|
||||
class TerroristModel(BaseBehaviour):
|
||||
num_agents = 0
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.population = settings.network_params["number_of_nodes"] * settings.environment_params['initial_population']
|
||||
self.havens = settings.network_params["number_of_nodes"] * settings.environment_params['initial_havens']
|
||||
self.training_enviroments = settings.network_params["number_of_nodes"] * settings.environment_params['initial_training_enviroments']
|
||||
|
||||
self.initial_radicalism = settings.environment_params['initial_radicalism']
|
||||
self.information_spread_intensity = settings.environment_params['information_spread_intensity']
|
||||
self.influence = settings.environment_params['influence']
|
||||
self.relative_inequality = settings.environment_params['relative_inequality']
|
||||
self.additional_influence = settings.environment_params['additional_influence']
|
||||
|
||||
if TerroristModel.num_agents < self.population:
|
||||
self.state['type'] = POPULATION
|
||||
TerroristModel.num_agents = TerroristModel.num_agents + 1
|
||||
random1 = random.random()
|
||||
if random1 < 0.7:
|
||||
self.state['id'] = NON_RADICAL
|
||||
self.state['fstatus'] = POPNON
|
||||
elif random1 >= 0.7 and random1 < 0.9:
|
||||
self.state['id'] = NEUTRAL
|
||||
self.state['fstatus'] = POPNE
|
||||
elif random1 >= 0.9:
|
||||
self.state['id'] = RADICAL
|
||||
self.state['fstatus'] = POPRAD
|
||||
|
||||
elif TerroristModel.num_agents < self.havens + self.population:
|
||||
self.state['type'] = HAVEN
|
||||
TerroristModel.num_agents = TerroristModel.num_agents + 1
|
||||
random2 = random.random()
|
||||
random1 = random2 + self.initial_radicalism
|
||||
if random1 < 1.2:
|
||||
self.state['id'] = NON_RADICAL
|
||||
self.state['fstatus'] = HAVNON
|
||||
elif random1 >= 1.2 and random1 < 1.6:
|
||||
self.state['id'] = NEUTRAL
|
||||
self.state['fstatus'] = HAVNE
|
||||
elif random1 >= 1.6:
|
||||
self.state['id'] = RADICAL
|
||||
self.state['fstatus'] = HAVRAD
|
||||
|
||||
elif TerroristModel.num_agents < self.training_enviroments + self.havens + self.population:
|
||||
self.state['type'] = TRAININGENV
|
||||
self.state['fstatus'] = TRAINING
|
||||
TerroristModel.num_agents = TerroristModel.num_agents + 1
|
||||
|
||||
def step(self, now):
|
||||
if self.state['type'] == POPULATION:
|
||||
self.population_and_leader_conduct()
|
||||
if self.state['type'] == LEADERS:
|
||||
self.population_and_leader_conduct()
|
||||
if self.state['type'] == HAVEN:
|
||||
self.haven_conduct()
|
||||
if self.state['type'] == TRAININGENV:
|
||||
self.training_enviroment_conduct()
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
self.attrs['type'] = self.state['type']
|
||||
self.attrs['radicalism'] = self.state['rad']
|
||||
self.attrs['fstatus'] = self.state['fstatus']
|
||||
super().step(now)
|
||||
|
||||
def population_and_leader_conduct(self):
|
||||
if self.state['id'] == NON_RADICAL:
|
||||
if self.state['rad'] == 0.000:
|
||||
self.state['rad'] = self.set_radicalism()
|
||||
self.non_radical_behaviour()
|
||||
if self.state['id'] == NEUTRAL:
|
||||
if self.state['rad'] == 0.000:
|
||||
self.state['rad'] = self.set_radicalism()
|
||||
while self.state['id'] == RADICAL:
|
||||
self.radical_behaviour()
|
||||
break
|
||||
self.neutral_behaviour()
|
||||
if self.state['id'] == RADICAL:
|
||||
if self.state['rad'] == 0.000:
|
||||
self.state['rad'] = self.set_radicalism()
|
||||
self.radical_behaviour()
|
||||
|
||||
def haven_conduct(self):
|
||||
non_radical_neighbors = self.get_neighboring_agents(state_id=NON_RADICAL)
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=NEUTRAL)
|
||||
radical_neighbors = self.get_neighboring_agents(state_id=RADICAL)
|
||||
|
||||
neighbors_of_non_radical = len(neutral_neighbors) + len(radical_neighbors)
|
||||
neighbors_of_neutral = len(non_radical_neighbors) + len(radical_neighbors)
|
||||
neighbors_of_radical = len(non_radical_neighbors) + len(neutral_neighbors)
|
||||
threshold = 8
|
||||
if (len(non_radical_neighbors) > neighbors_of_non_radical) and len(non_radical_neighbors) >= threshold:
|
||||
self.state['id'] = NON_RADICAL
|
||||
elif (len(neutral_neighbors) > neighbors_of_neutral) and len(neutral_neighbors) >= threshold:
|
||||
self.state['id'] = NEUTRAL
|
||||
elif (len(radical_neighbors) > neighbors_of_radical) and len(radical_neighbors) >= threshold:
|
||||
self.state['id'] = RADICAL
|
||||
|
||||
if self.state['id'] == NEUTRAL:
|
||||
for neighbor in non_radical_neighbors:
|
||||
neighbor.state['rad'] = neighbor.state['rad'] + (self.influence + self.additional_influence) * self.information_spread_intensity
|
||||
if neighbor.state['rad'] >= 0.3 and neighbor.state['rad'] <= 0.59:
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
elif neighbor.state['rad'] > 0.59:
|
||||
neighbor.state['rad'] = 0.59
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
|
||||
if self.state['id'] == RADICAL:
|
||||
|
||||
for neighbor in non_radical_neighbors:
|
||||
neighbor.state['rad'] = neighbor.state['rad'] + (self.influence + self.additional_influence) * self.information_spread_intensity
|
||||
if neighbor.state['rad'] >= 0.3 and neighbor.state['rad'] <= 0.59:
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
elif neighbor.state['rad'] > 0.59:
|
||||
neighbor.state['rad'] = 0.59
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
|
||||
for neighbor in neutral_neighbors:
|
||||
neighbor.state['rad'] = neighbor.state['rad'] + (self.influence + self.additional_influence) * self.information_spread_intensity
|
||||
if neighbor.state['rad'] >= 0.6:
|
||||
neighbor.state['id'] = RADICAL
|
||||
if neighbor.state['type'] != HAVEN and neighbor.state['type']!=TRAININGENV:
|
||||
if neighbor.state['rad'] >= 0.62:
|
||||
if create_leader(neighbor):
|
||||
neighbor.state['type'] = LEADERS
|
||||
neighbor.state['fstatus'] = LEADER
|
||||
# elif neighbor.state['type'] == LEADERS:
|
||||
# neighbor.state['type'] = POPULATION
|
||||
# neighbor.state['fstatus'] = POPRAD
|
||||
elif neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPRAD
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVRAD
|
||||
|
||||
def training_enviroment_conduct(self):
|
||||
self.state['id'] = RADICAL
|
||||
self.state['rad'] = 1
|
||||
neighbors = self.get_neighboring_agents()
|
||||
for neighbor in neighbors:
|
||||
if neighbor.state['id'] == NON_RADICAL:
|
||||
neighbor.state['rad'] = neighbor.state['rad'] + (self.influence + self.additional_influence) * self.information_spread_intensity
|
||||
if neighbor.state['rad'] >= 0.3 and self.state['rad'] <= 0.59:
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
elif neighbor.state['rad'] > 0.59:
|
||||
neighbor.state['rad'] = 0.59
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
|
||||
|
||||
neighbor.state['rad'] = neighbor.state['rad'] + (neighbor.influence + neighbor.additional_influence) * neighbor.information_spread_intensity
|
||||
if neighbor.state['rad'] >= 0.3 and neighbor.state['rad'] <= 0.59:
|
||||
neighbor.state['id'] = NEUTRAL
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPNE
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVNE
|
||||
elif neighbor.state['rad'] >= 0.6:
|
||||
neighbor.state['id'] = RADICAL
|
||||
if neighbor.state['type'] != HAVEN and neighbor.state['type'] != TRAININGENV:
|
||||
if neighbor.state['rad'] >= 0.62:
|
||||
if create_leader(neighbor):
|
||||
neighbor.state['type'] = LEADERS
|
||||
neighbor.state['fstatus'] = LEADER
|
||||
# elif neighbor.state['type'] == LEADERS:
|
||||
# neighbor.state['type'] = POPULATION
|
||||
# neighbor.state['fstatus'] = POPRAD
|
||||
elif neighbor.state['type'] == POPULATION:
|
||||
neighbor.state['fstatus'] = POPRAD
|
||||
elif neighbor.state['type'] == HAVEN:
|
||||
neighbor.state['fstatus'] = HAVRAD
|
||||
|
||||
def non_radical_behaviour(self):
|
||||
neighbors = self.get_neighboring_agents()
|
||||
|
||||
for neighbor in neighbors:
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
if neighbor.state['id'] == NEUTRAL or neighbor.state['id'] == RADICAL:
|
||||
self.state['rad'] = self.state['rad'] + self.influence * self.information_spread_intensity
|
||||
if self.state['rad'] >= 0.3 and self.state['rad'] <= 0.59:
|
||||
self.state['id'] = NEUTRAL
|
||||
|
||||
if self.state['type']==POPULATION:
|
||||
self.state['fstatus'] = POPNE
|
||||
elif self.state['type'] == HAVEN:
|
||||
self.state['fstatus'] = HAVNE
|
||||
elif self.state['rad'] > 0.59:
|
||||
self.state['rad'] = 0.59
|
||||
self.state['id'] = NEUTRAL
|
||||
if self.state['type']==POPULATION:
|
||||
self.state['fstatus'] = POPNE
|
||||
elif self.state['type'] == HAVEN:
|
||||
self.state['fstatus'] = HAVNE
|
||||
|
||||
elif neighbor.state['type'] == LEADERS:
|
||||
|
||||
if neighbor.state['id'] == NEUTRAL or neighbor.state['id'] == RADICAL:
|
||||
self.state['rad'] = self.state['rad'] + (self.influence + self.additional_influence) * self.information_spread_intensity
|
||||
if self.state['rad'] >= 0.3 and self.state['rad'] <= 0.59:
|
||||
self.state['id'] = NEUTRAL
|
||||
if self.state['type']==POPULATION:
|
||||
self.state['fstatus'] = POPNE
|
||||
elif self.state['type'] == HAVEN:
|
||||
self.state['fstatus'] = HAVNE
|
||||
elif self.state['rad'] > 0.59:
|
||||
self.state['rad'] = 0.59
|
||||
self.state['id'] = NEUTRAL
|
||||
if self.state['type']==POPULATION:
|
||||
self.state['fstatus'] = POPNE
|
||||
elif self.state['type'] == HAVEN:
|
||||
self.state['fstatus'] = HAVNE
|
||||
|
||||
|
||||
def neutral_behaviour(self):
|
||||
neighbors = self.get_neighboring_agents()
|
||||
for neighbor in neighbors:
|
||||
if neighbor.state['type'] == POPULATION:
|
||||
if neighbor.state['id'] == RADICAL:
|
||||
self.state['rad'] = self.state['rad'] + self.influence * self.information_spread_intensity
|
||||
if self.state['rad'] >= 0.6:
|
||||
self.state['id'] = RADICAL
|
||||
if self.state['type'] != HAVEN:
|
||||
if self.state['rad'] >= 0.62:
|
||||
if create_leader(self):
|
||||
self.state['type'] = LEADERS
|
||||
|
||||
self.state['fstatus'] = LEADER
|
||||
# elif self.state['type'] == LEADERS:
|
||||
# self.state['type'] = POPULATION
|
||||
# self.state['fstatus'] = POPRAD
|
||||
elif neighbor.state['type'] == POPULATION:
|
||||
self.state['fstatus'] = POPRAD
|
||||
elif self.state['type'] == HAVEN:
|
||||
self.state['fstatus'] = HAVRAD
|
||||
|
||||
|
||||
elif neighbor.state['type'] == LEADERS:
|
||||
if neighbor.state['id'] == RADICAL:
|
||||
self.state['rad'] = self.state['rad'] + (self.influence + self.additional_influence) * self.information_spread_intensity
|
||||
if self.state['rad'] >= 0.6:
|
||||
self.state['id'] = RADICAL
|
||||
if self.state['type'] != HAVEN:
|
||||
if self.state['rad'] >= 0.62:
|
||||
if create_leader(self):
|
||||
self.state['type'] = LEADERS
|
||||
self.state['fstatus'] = LEADER
|
||||
# elif self.state['type'] == LEADERS:
|
||||
# self.state['type'] = POPULATION
|
||||
# self.state['fstatus'] = POPRAD
|
||||
elif neighbor.state['type'] == POPULATION:
|
||||
self.state['fstatus'] = POPRAD
|
||||
elif self.state['type'] == HAVEN:
|
||||
self.state['fstatus'] = HAVRAD
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def radical_behaviour(self):
|
||||
neighbors = self.get_neighboring_agents(state_id=RADICAL)
|
||||
|
||||
for neighbor in neighbors:
|
||||
if self.state['rad']< neighbor.state['rad'] and self.state['type']== LEADERS and neighbor.state['type']==LEADERS:
|
||||
self.state['type'] = POPULATION
|
||||
self.state['fstatus'] = POPRAD
|
||||
|
||||
|
||||
def set_radicalism(self):
|
||||
if self.state['id'] == NON_RADICAL:
|
||||
radicalism = random.uniform(0.0, 0.29) * self.relative_inequality
|
||||
return radicalism
|
||||
elif self.state['id'] == NEUTRAL:
|
||||
radicalism = 0.3 + random.uniform(0.3, 0.59) * self.relative_inequality
|
||||
if radicalism >= 0.6:
|
||||
self.state['id'] = RADICAL
|
||||
return radicalism
|
||||
elif self.state['id'] == RADICAL:
|
||||
radicalism = 0.6 + random.uniform(0.6, 1.0) * self.relative_inequality
|
||||
return radicalism
|
||||
|
||||
def get_partition(agent):
|
||||
return settings.partition_param[agent.id]
|
||||
|
||||
def get_centrality(agent):
|
||||
return settings.centrality_param[agent.id]
|
||||
def get_centrality_given_id(id):
|
||||
return settings.centrality_param[id]
|
||||
|
||||
def get_leader(partition):
|
||||
if not bool(settings.leaders) or partition not in settings.leaders.keys():
|
||||
return None
|
||||
return settings.leaders[partition]
|
||||
|
||||
def set_leader(partition, agent):
|
||||
settings.leaders[partition] = agent.id
|
||||
|
||||
def create_leader(agent):
|
||||
my_partition = get_partition(agent)
|
||||
old_leader = get_leader(my_partition)
|
||||
|
||||
if old_leader == None:
|
||||
set_leader(my_partition, agent)
|
||||
return True
|
||||
else:
|
||||
my_centrality = get_centrality(agent)
|
||||
old_leader_centrality = get_centrality_given_id(old_leader)
|
||||
if my_centrality > old_leader_centrality:
|
||||
set_leader(my_partition, agent)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
@ -0,0 +1 @@
|
||||
from .TerroristModel import TerroristModel
|
@ -0,0 +1,3 @@
|
||||
from .models import *
|
||||
from .BaseBehaviour import *
|
||||
from .TerroristModel import *
|
@ -0,0 +1,7 @@
|
||||
import settings
|
||||
|
||||
networkStatus = {} # Dict that will contain the status of every agent in the network
|
||||
|
||||
# Initialize agent states. Let's assume everyone is normal and all types are population.
|
||||
init_states = [{'id': 0, 'type': 0, 'rad': 0, 'fstatus':0, } for _ in range(settings.network_params["number_of_nodes"])]
|
||||
|
@ -1,596 +0,0 @@
|
||||
from nxsim import BaseNetworkAgent
|
||||
import numpy as np
|
||||
import random
|
||||
import settings
|
||||
|
||||
settings.init()
|
||||
|
||||
##############################
|
||||
# Variables initialization #
|
||||
##############################
|
||||
def init():
|
||||
global networkStatus
|
||||
networkStatus = {} # Dict that will contain the status of every agent in the network
|
||||
|
||||
sentimentCorrelationNodeArray=[]
|
||||
for x in range(0, settings.number_of_nodes):
|
||||
sentimentCorrelationNodeArray.append({'id':x})
|
||||
# Initialize agent states. Let's assume everyone is normal.
|
||||
init_states = [{'id': 0, } for _ in range(settings.number_of_nodes)] # add keys as as necessary, but "id" must always refer to that state category
|
||||
|
||||
|
||||
####################
|
||||
# Available models #
|
||||
####################
|
||||
|
||||
class BaseBehaviour(BaseNetworkAgent):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self._attrs = {}
|
||||
|
||||
@property
|
||||
def attrs(self):
|
||||
now = self.env.now
|
||||
if now not in self._attrs:
|
||||
self._attrs[now] = {}
|
||||
return self._attrs[now]
|
||||
|
||||
@attrs.setter
|
||||
def attrs(self, value):
|
||||
self._attrs[self.env.now] = value
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self.step(self.env.now)
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
def step(self, now):
|
||||
networkStatus['agent_%s'% self.id] = self.to_json()
|
||||
|
||||
def to_json(self):
|
||||
final = {}
|
||||
for stamp, attrs in self._attrs.items():
|
||||
for a in attrs:
|
||||
if a not in final:
|
||||
final[a] = {}
|
||||
final[a][stamp] = attrs[a]
|
||||
return final
|
||||
|
||||
class ControlModelM2(BaseBehaviour):
|
||||
#Init infected
|
||||
init_states[random.randint(0,settings.number_of_nodes-1)] = {'id':1}
|
||||
init_states[random.randint(0,settings.number_of_nodes-1)] = {'id':1}
|
||||
|
||||
# Init beacons
|
||||
init_states[random.randint(0, settings.number_of_nodes-1)] = {'id': 4}
|
||||
init_states[random.randint(0, settings.number_of_nodes-1)] = {'id': 4}
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.prob_neutral_making_denier = np.random.normal(settings.prob_neutral_making_denier, settings.standard_variance)
|
||||
|
||||
self.prob_infect = np.random.normal(settings.prob_infect, settings.standard_variance)
|
||||
|
||||
self.prob_cured_healing_infected = np.random.normal(settings.prob_cured_healing_infected, settings.standard_variance)
|
||||
self.prob_cured_vaccinate_neutral = np.random.normal(settings.prob_cured_vaccinate_neutral, settings.standard_variance)
|
||||
|
||||
self.prob_vaccinated_healing_infected = np.random.normal(settings.prob_vaccinated_healing_infected, settings.standard_variance)
|
||||
self.prob_vaccinated_vaccinate_neutral = np.random.normal(settings.prob_vaccinated_vaccinate_neutral, settings.standard_variance)
|
||||
self.prob_generate_anti_rumor = np.random.normal(settings.prob_generate_anti_rumor, settings.standard_variance)
|
||||
|
||||
def step(self, now):
|
||||
|
||||
if self.state['id'] == 0: #Neutral
|
||||
self.neutral_behaviour()
|
||||
elif self.state['id'] == 1: #Infected
|
||||
self.infected_behaviour()
|
||||
elif self.state['id'] == 2: #Cured
|
||||
self.cured_behaviour()
|
||||
elif self.state['id'] == 3: #Vaccinated
|
||||
self.vaccinated_behaviour()
|
||||
elif self.state['id'] == 4: #Beacon-off
|
||||
self.beacon_off_behaviour()
|
||||
elif self.state['id'] == 5: #Beacon-on
|
||||
self.beacon_on_behaviour()
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
super().step(now)
|
||||
|
||||
|
||||
def neutral_behaviour(self):
|
||||
|
||||
# Infected
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors)>0:
|
||||
if random.random() < self.prob_neutral_making_denier:
|
||||
self.state['id'] = 3 # Vaccinated making denier
|
||||
|
||||
def infected_behaviour(self):
|
||||
|
||||
# Neutral
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_infect:
|
||||
neighbor.state['id'] = 1 # Infected
|
||||
|
||||
def cured_behaviour(self):
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
def vaccinated_behaviour(self):
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Generate anti-rumor
|
||||
infected_neighbors_2 = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_2:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def beacon_off_behaviour(self):
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors) > 0:
|
||||
self.state['id'] == 5 #Beacon on
|
||||
|
||||
def beacon_on_behaviour(self):
|
||||
|
||||
# Cure (M2 feature added)
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
neutral_neighbors_infected = neighbor.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors_infected:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
infected_neighbors_infected = neighbor.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_infected:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
|
||||
class SpreadModelM2(BaseBehaviour):
|
||||
init_states[random.randint(0,settings.number_of_nodes)] = {'id':1}
|
||||
init_states[random.randint(0,settings.number_of_nodes)] = {'id':1}
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.prob_neutral_making_denier = np.random.normal(settings.prob_neutral_making_denier, settings.standard_variance)
|
||||
|
||||
self.prob_infect = np.random.normal(settings.prob_infect, settings.standard_variance)
|
||||
|
||||
self.prob_cured_healing_infected = np.random.normal(settings.prob_cured_healing_infected, settings.standard_variance)
|
||||
self.prob_cured_vaccinate_neutral = np.random.normal(settings.prob_cured_vaccinate_neutral, settings.standard_variance)
|
||||
|
||||
self.prob_vaccinated_healing_infected = np.random.normal(settings.prob_vaccinated_healing_infected, settings.standard_variance)
|
||||
self.prob_vaccinated_vaccinate_neutral = np.random.normal(settings.prob_vaccinated_vaccinate_neutral, settings.standard_variance)
|
||||
self.prob_generate_anti_rumor = np.random.normal(settings.prob_generate_anti_rumor, settings.standard_variance)
|
||||
|
||||
def step(self, now):
|
||||
|
||||
if self.state['id'] == 0: #Neutral
|
||||
self.neutral_behaviour()
|
||||
elif self.state['id'] == 1: #Infected
|
||||
self.infected_behaviour()
|
||||
elif self.state['id'] == 2: #Cured
|
||||
self.cured_behaviour()
|
||||
elif self.state['id'] == 3: #Vaccinated
|
||||
self.vaccinated_behaviour()
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
super().step(now)
|
||||
|
||||
|
||||
def neutral_behaviour(self):
|
||||
|
||||
# Infected
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors)>0:
|
||||
if random.random() < self.prob_neutral_making_denier:
|
||||
self.state['id'] = 3 # Vaccinated making denier
|
||||
|
||||
def infected_behaviour(self):
|
||||
|
||||
# Neutral
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_infect:
|
||||
neighbor.state['id'] = 1 # Infected
|
||||
|
||||
def cured_behaviour(self):
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
def vaccinated_behaviour(self):
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Generate anti-rumor
|
||||
infected_neighbors_2 = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_2:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
class SISaModel(BaseBehaviour):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.neutral_discontent_spon_prob = np.random.normal(settings.neutral_discontent_spon_prob, settings.standard_variance)
|
||||
self.neutral_discontent_infected_prob = np.random.normal(settings.neutral_discontent_infected_prob,settings.standard_variance)
|
||||
self.neutral_content_spon_prob = np.random.normal(settings.neutral_content_spon_prob,settings.standard_variance)
|
||||
self.neutral_content_infected_prob = np.random.normal(settings.neutral_content_infected_prob,settings.standard_variance)
|
||||
|
||||
self.discontent_neutral = np.random.normal(settings.discontent_neutral,settings.standard_variance)
|
||||
self.discontent_content = np.random.normal(settings.discontent_content,settings.variance_d_c)
|
||||
|
||||
self.content_discontent = np.random.normal(settings.content_discontent,settings.variance_c_d)
|
||||
self.content_neutral = np.random.normal(settings.content_neutral,settings.standard_variance)
|
||||
|
||||
def step(self, now):
|
||||
|
||||
if self.state['id'] == 0:
|
||||
self.neutral_behaviour()
|
||||
if self.state['id'] == 1:
|
||||
self.discontent_behaviour()
|
||||
if self.state['id'] == 2:
|
||||
self.content_behaviour()
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
super().step(now)
|
||||
|
||||
|
||||
def neutral_behaviour(self):
|
||||
|
||||
#Spontaneus effects
|
||||
if random.random() < self.neutral_discontent_spon_prob:
|
||||
self.state['id'] = 1
|
||||
if random.random() < self.neutral_content_spon_prob:
|
||||
self.state['id'] = 2
|
||||
|
||||
#Infected
|
||||
discontent_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if random.random() < len(discontent_neighbors)*self.neutral_discontent_infected_prob:
|
||||
self.state['id'] = 1
|
||||
content_neighbors = self.get_neighboring_agents(state_id=2)
|
||||
if random.random() < len(content_neighbors)*self.neutral_content_infected_prob:
|
||||
self.state['id'] = 2
|
||||
|
||||
def discontent_behaviour(self):
|
||||
|
||||
#Healing
|
||||
if random.random() < self.discontent_neutral:
|
||||
self.state['id'] = 0
|
||||
|
||||
#Superinfected
|
||||
content_neighbors = self.get_neighboring_agents(state_id=2)
|
||||
if random.random() < len(content_neighbors)*self.discontent_content:
|
||||
self.state['id'] = 2
|
||||
|
||||
def content_behaviour(self):
|
||||
|
||||
#Healing
|
||||
if random.random() < self.content_neutral:
|
||||
self.state['id'] = 0
|
||||
|
||||
#Superinfected
|
||||
discontent_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if random.random() < len(discontent_neighbors)*self.content_discontent:
|
||||
self.state['id'] = 1
|
||||
|
||||
|
||||
class BigMarketModel(BaseBehaviour):
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.enterprises = settings.enterprises
|
||||
self.type = ""
|
||||
self.number_of_enterprises = len(settings.enterprises)
|
||||
|
||||
if self.id < self.number_of_enterprises: #Enterprises
|
||||
self.state['id']=self.id
|
||||
self.type="Enterprise"
|
||||
self.tweet_probability = settings.tweet_probability_enterprises[self.id]
|
||||
else: #normal users
|
||||
self.state['id']=self.number_of_enterprises
|
||||
self.type="User"
|
||||
self.tweet_probability = settings.tweet_probability_users
|
||||
self.tweet_relevant_probability = settings.tweet_relevant_probability
|
||||
self.tweet_probability_about = settings.tweet_probability_about #List
|
||||
self.sentiment_about = settings.sentiment_about #List
|
||||
|
||||
def step(self, now):
|
||||
|
||||
if(self.id < self.number_of_enterprises): # Ennterprise
|
||||
self.enterpriseBehaviour()
|
||||
else: # Usuario
|
||||
self.userBehaviour()
|
||||
for i in range(self.number_of_enterprises): # So that it never is set to 0 if there are not changes (logs)
|
||||
self.attrs['sentiment_enterprise_%s'% self.enterprises[i]] = self.sentiment_about[i]
|
||||
|
||||
super().step(now)
|
||||
|
||||
def enterpriseBehaviour(self):
|
||||
|
||||
if random.random()< self.tweet_probability: #Tweets
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=self.number_of_enterprises) #Nodes neighbour users
|
||||
for x in aware_neighbors:
|
||||
if random.uniform(0,10) < 5:
|
||||
x.sentiment_about[self.id] += 0.1 #Increments for enterprise
|
||||
else:
|
||||
x.sentiment_about[self.id] -= 0.1 #Decrements for enterprise
|
||||
|
||||
# Establecemos limites
|
||||
if x.sentiment_about[self.id] > 1:
|
||||
x.sentiment_about[self.id] = 1
|
||||
if x.sentiment_about[self.id]< -1:
|
||||
x.sentiment_about[self.id] = -1
|
||||
|
||||
x.attrs['sentiment_enterprise_%s'% self.enterprises[self.id]] = x.sentiment_about[self.id]
|
||||
|
||||
|
||||
def userBehaviour(self):
|
||||
|
||||
if random.random() < self.tweet_probability: #Tweets
|
||||
if random.random() < self.tweet_relevant_probability: #Tweets something relevant
|
||||
#Tweet probability per enterprise
|
||||
for i in range(self.number_of_enterprises):
|
||||
random_num = random.random()
|
||||
if random_num < self.tweet_probability_about[i]:
|
||||
#The condition is fulfilled, sentiments are evaluated towards that enterprise
|
||||
if self.sentiment_about[i] < 0:
|
||||
#NEGATIVO
|
||||
self.userTweets("negative",i)
|
||||
elif self.sentiment_about[i] == 0:
|
||||
#NEUTRO
|
||||
pass
|
||||
else:
|
||||
#POSITIVO
|
||||
self.userTweets("positive",i)
|
||||
|
||||
def userTweets(self,sentiment,enterprise):
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=self.number_of_enterprises) #Nodes neighbours users
|
||||
for x in aware_neighbors:
|
||||
if sentiment == "positive":
|
||||
x.sentiment_about[enterprise] +=0.003
|
||||
elif sentiment == "negative":
|
||||
x.sentiment_about[enterprise] -=0.003
|
||||
else:
|
||||
pass
|
||||
|
||||
# Establecemos limites
|
||||
if x.sentiment_about[enterprise] > 1:
|
||||
x.sentiment_about[enterprise] = 1
|
||||
if x.sentiment_about[enterprise] < -1:
|
||||
x.sentiment_about[enterprise] = -1
|
||||
|
||||
x.attrs['sentiment_enterprise_%s'% self.enterprises[enterprise]] = x.sentiment_about[enterprise]
|
||||
|
||||
class SentimentCorrelationModel(BaseBehaviour):
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.outside_effects_prob = settings.outside_effects_prob
|
||||
self.anger_prob = settings.anger_prob
|
||||
self.joy_prob = settings.joy_prob
|
||||
self.sadness_prob = settings.sadness_prob
|
||||
self.disgust_prob = settings.disgust_prob
|
||||
self.time_awareness=[]
|
||||
for i in range(4): #In this model we have 4 sentiments
|
||||
self.time_awareness.append(0) #0-> Anger, 1-> joy, 2->sadness, 3 -> disgust
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=0
|
||||
|
||||
|
||||
def step(self, now):
|
||||
self.behaviour()
|
||||
super().step(now)
|
||||
|
||||
def behaviour(self):
|
||||
|
||||
angry_neighbors_1_time_step=[]
|
||||
joyful_neighbors_1_time_step=[]
|
||||
sad_neighbors_1_time_step=[]
|
||||
disgusted_neighbors_1_time_step=[]
|
||||
|
||||
|
||||
angry_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for x in angry_neighbors:
|
||||
if x.time_awareness[0] > (self.env.now-500):
|
||||
angry_neighbors_1_time_step.append(x)
|
||||
num_neighbors_angry = len(angry_neighbors_1_time_step)
|
||||
|
||||
|
||||
joyful_neighbors = self.get_neighboring_agents(state_id=2)
|
||||
for x in joyful_neighbors:
|
||||
if x.time_awareness[1] > (self.env.now-500):
|
||||
joyful_neighbors_1_time_step.append(x)
|
||||
num_neighbors_joyful = len(joyful_neighbors_1_time_step)
|
||||
|
||||
|
||||
sad_neighbors = self.get_neighboring_agents(state_id=3)
|
||||
for x in sad_neighbors:
|
||||
if x.time_awareness[2] > (self.env.now-500):
|
||||
sad_neighbors_1_time_step.append(x)
|
||||
num_neighbors_sad = len(sad_neighbors_1_time_step)
|
||||
|
||||
|
||||
disgusted_neighbors = self.get_neighboring_agents(state_id=4)
|
||||
for x in disgusted_neighbors:
|
||||
if x.time_awareness[3] > (self.env.now-500):
|
||||
disgusted_neighbors_1_time_step.append(x)
|
||||
num_neighbors_disgusted = len(disgusted_neighbors_1_time_step)
|
||||
|
||||
|
||||
anger_prob= settings.anger_prob+(len(angry_neighbors_1_time_step)*settings.anger_prob)
|
||||
joy_prob= settings.joy_prob+(len(joyful_neighbors_1_time_step)*settings.joy_prob)
|
||||
sadness_prob = settings.sadness_prob+(len(sad_neighbors_1_time_step)*settings.sadness_prob)
|
||||
disgust_prob = settings.disgust_prob+(len(disgusted_neighbors_1_time_step)*settings.disgust_prob)
|
||||
outside_effects_prob= settings.outside_effects_prob
|
||||
|
||||
|
||||
num = random.random()
|
||||
|
||||
|
||||
if(num<outside_effects_prob):
|
||||
self.state['id'] = random.randint(1,4)
|
||||
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=self.state['id'] #It is stored when it has been infected for the dynamic network
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
self.attrs['sentiment'] = self.state['id']
|
||||
|
||||
|
||||
|
||||
if(num<anger_prob):
|
||||
|
||||
self.state['id'] = 1
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=1
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
elif (num<joy_prob+anger_prob and num>anger_prob):
|
||||
|
||||
self.state['id'] = 2
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=2
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
elif (num<sadness_prob+anger_prob+joy_prob and num>joy_prob+anger_prob):
|
||||
|
||||
|
||||
self.state['id'] = 3
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=3
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
elif (num<disgust_prob+sadness_prob+anger_prob+joy_prob and num>sadness_prob+anger_prob+joy_prob):
|
||||
|
||||
|
||||
self.state['id'] = 4
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=4
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
|
||||
self.attrs['sentiment'] = self.state['id']
|
||||
|
||||
|
||||
class BassModel(BaseBehaviour):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.innovation_prob = settings.innovation_prob
|
||||
self.imitation_prob = settings.imitation_prob
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=0
|
||||
|
||||
def step(self, now):
|
||||
self.behaviour()
|
||||
super().step(now)
|
||||
|
||||
def behaviour(self):
|
||||
#Outside effects
|
||||
if random.random() < settings.innovation_prob:
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=1
|
||||
else:
|
||||
pass
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
return
|
||||
|
||||
#Imitation effects
|
||||
if self.state['id'] == 0:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
num_neighbors_aware = len(aware_neighbors)
|
||||
if random.random() < (settings.imitation_prob*num_neighbors_aware):
|
||||
self.state['id'] = 1
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=1
|
||||
|
||||
else:
|
||||
pass
|
||||
self.attrs['status'] = self.state['id']
|
||||
|
||||
|
||||
class IndependentCascadeModel(BaseBehaviour):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.innovation_prob = settings.innovation_prob
|
||||
self.imitation_prob = settings.imitation_prob
|
||||
self.time_awareness = 0
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=0
|
||||
|
||||
def step(self,now):
|
||||
self.behaviour()
|
||||
super().step(now)
|
||||
|
||||
def behaviour(self):
|
||||
aware_neighbors_1_time_step=[]
|
||||
#Outside effects
|
||||
if random.random() < settings.innovation_prob:
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=1
|
||||
self.time_awareness = self.env.now #To know when they have been infected
|
||||
else:
|
||||
pass
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
return
|
||||
|
||||
#Imitation effects
|
||||
if self.state['id'] == 0:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for x in aware_neighbors:
|
||||
if x.time_awareness == (self.env.now-1):
|
||||
aware_neighbors_1_time_step.append(x)
|
||||
num_neighbors_aware = len(aware_neighbors_1_time_step)
|
||||
if random.random() < (settings.imitation_prob*num_neighbors_aware):
|
||||
self.state['id'] = 1
|
||||
sentimentCorrelationNodeArray[self.id][self.env.now]=1
|
||||
else:
|
||||
pass
|
||||
|
||||
self.attrs['status'] = self.state['id']
|
||||
return
|
@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"network_type": 0,
|
||||
"number_of_nodes": 80,
|
||||
"max_time": 50,
|
||||
"num_trials": 1,
|
||||
"timeout": 2
|
||||
},
|
||||
|
||||
{
|
||||
"agent": ["TerroristModel"],
|
||||
|
||||
"initial_population": 0.85,
|
||||
"initial_havens": 0.1,
|
||||
"initial_training_enviroments": 0.05,
|
||||
|
||||
"initial_radicalism": 0.12,
|
||||
"relative_inequality": 0.33,
|
||||
"information_spread_intensity": 0.1,
|
||||
"influence": 0.4,
|
||||
"additional_influence": 0.1
|
||||
}
|
||||
]
|
@ -0,0 +1,13 @@
|
||||
# General configuration
|
||||
import json
|
||||
|
||||
with open('settings.json', 'r') as f:
|
||||
settings = json.load(f)
|
||||
|
||||
network_params = settings[0]
|
||||
environment_params = settings[1]
|
||||
|
||||
centrality_param = {}
|
||||
partition_param={}
|
||||
leaders={}
|
||||
|
@ -1,39 +0,0 @@
|
||||
import pip
|
||||
from setuptools import setup
|
||||
# parse_requirements() returns generator of pip.req.InstallRequirement objects
|
||||
from pip.req import parse_requirements
|
||||
from soil import __version__
|
||||
|
||||
try:
|
||||
install_reqs = parse_requirements(
|
||||
"requirements.txt", session=pip.download.PipSession())
|
||||
test_reqs = parse_requirements(
|
||||
"test-requirements.txt", session=pip.download.PipSession())
|
||||
except AttributeError:
|
||||
install_reqs = parse_requirements("requirements.txt")
|
||||
test_reqs = parse_requirements("test-requirements.txt")
|
||||
|
||||
install_reqs = [str(ir.req) for ir in install_reqs]
|
||||
test_reqs = [str(ir.req) for ir in test_reqs]
|
||||
|
||||
|
||||
setup(
|
||||
name='soil',
|
||||
packages=['soil'], # this must be the same as the name above
|
||||
version=__version__,
|
||||
description=('An Agent-Based Social Simulator for Social Networks'),
|
||||
author='J. Fernando Sanchez',
|
||||
author_email='jf.sanchez@upm.es',
|
||||
url='https://github.com/gsi-upm/soil', # use the URL to the github repo
|
||||
download_url='https://github.com/gsi-upm/soil/archive/{}.tar.gz'.format(
|
||||
__version__),
|
||||
keywords=['agent', 'social', 'simulator'],
|
||||
classifiers=[],
|
||||
install_requires=install_reqs,
|
||||
tests_require=test_reqs,
|
||||
setup_requires=['pytest-runner', ],
|
||||
include_package_data=True,
|
||||
entry_points={
|
||||
'console_scripts':
|
||||
['soil = soil.__init__:main']
|
||||
})
|
@ -1,63 +0,0 @@
|
||||
---
|
||||
name: ControlModelM2_sim
|
||||
max_time: 50
|
||||
num_trials: 1
|
||||
timeout: 2
|
||||
network_params:
|
||||
generator: barabasi_albert_graph
|
||||
n: 100
|
||||
m: 2
|
||||
agent_distribution:
|
||||
- agent_type: ControlModelM2
|
||||
weight: 0.1
|
||||
state:
|
||||
id: 1
|
||||
- agent_type: ControlModelM2
|
||||
weight: 0.9
|
||||
state:
|
||||
id: 0
|
||||
environment_params:
|
||||
prob_neutral_making_denier: 0.035
|
||||
prob_infect: 0.075
|
||||
prob_cured_healing_infected: 0.035
|
||||
prob_cured_vaccinate_neutral: 0.035
|
||||
prob_vaccinated_healing_infected: 0.035
|
||||
prob_vaccinated_vaccinate_neutral: 0.035
|
||||
prob_generate_anti_rumor: 0.035
|
||||
standard_variance: 0.055
|
||||
---
|
||||
name: SISA_sm
|
||||
max_time: 50
|
||||
num_trials: 2
|
||||
timeout: 2
|
||||
network_params:
|
||||
generator: erdos_renyi_graph
|
||||
n: 10000
|
||||
p: 0.05
|
||||
#other_agents:
|
||||
# - agent_type: DrawingAgent
|
||||
agent_distribution:
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: content
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: neutral
|
||||
- agent_type: SISaModel
|
||||
weight: 1
|
||||
state:
|
||||
id: discontent
|
||||
environment_params:
|
||||
neutral_discontent_spon_prob: 0.04
|
||||
neutral_discontent_infected_prob: 0.04
|
||||
neutral_content_spon_prob: 0.18
|
||||
neutral_content_infected_prob: 0.02
|
||||
discontent_neutral: 0.13
|
||||
discontent_content: 0.07
|
||||
variance_d_c: 0.02
|
||||
content_discontent: 0.009
|
||||
variance_c_d: 0.003
|
||||
content_neutral: 0.088
|
||||
standard_variance: 0.055
|
@ -0,0 +1,215 @@
|
||||
from models import *
|
||||
from nxsim import NetworkSimulation
|
||||
# import numpy
|
||||
from matplotlib import pyplot as plt
|
||||
import networkx as nx
|
||||
import settings
|
||||
import models
|
||||
import math
|
||||
import json
|
||||
import operator
|
||||
import community
|
||||
|
||||
|
||||
|
||||
POPULATION = 0
|
||||
LEADERS = 1
|
||||
HAVEN = 2
|
||||
TRAINING = 3
|
||||
|
||||
NON_RADICAL = 0
|
||||
NEUTRAL = 1
|
||||
RADICAL = 2
|
||||
#################
|
||||
# Visualization #
|
||||
#################
|
||||
|
||||
def visualization(graph_name):
|
||||
|
||||
for x in range(0, settings.network_params["number_of_nodes"]):
|
||||
attributes = {}
|
||||
spells = []
|
||||
for attribute in models.networkStatus["agent_%s" % x]:
|
||||
if attribute == 'visible':
|
||||
lastvisible = False
|
||||
laststep = 0
|
||||
for t_step in models.networkStatus["agent_%s" % x][attribute]:
|
||||
nowvisible = models.networkStatus["agent_%s" % x][attribute][t_step]
|
||||
if nowvisible and not lastvisible:
|
||||
laststep = t_step
|
||||
if not nowvisible and lastvisible:
|
||||
spells.append((laststep, t_step))
|
||||
|
||||
lastvisible = nowvisible
|
||||
if lastvisible:
|
||||
spells.append((laststep, None))
|
||||
else:
|
||||
emotionStatusAux = []
|
||||
for t_step in models.networkStatus["agent_%s" % x][attribute]:
|
||||
prec = 2
|
||||
output = math.floor(models.networkStatus["agent_%s" % x][attribute][t_step] * (10 ** prec)) / (10 ** prec) # 2 decimals
|
||||
emotionStatusAux.append((output, t_step, t_step + settings.network_params["timeout"]))
|
||||
attributes[attribute] = emotionStatusAux
|
||||
if spells:
|
||||
G.add_node(x, attributes, spells=spells)
|
||||
else:
|
||||
G.add_node(x, attributes)
|
||||
|
||||
print("Done!")
|
||||
|
||||
|
||||
with open('data.txt', 'w') as outfile:
|
||||
json.dump(models.networkStatus, outfile, sort_keys=True, indent=4, separators=(',', ': '))
|
||||
|
||||
for node in range(settings.network_params["number_of_nodes"]):
|
||||
G.node[node]['x'] = G.node[node]['pos'][0]
|
||||
G.node[node]['y'] = G.node[node]['pos'][1]
|
||||
G.node[node]['viz'] = {"position": {"x": G.node[node]['pos'][0], "y": G.node[node]['pos'][1], "z": 0.0}}
|
||||
del (G.node[node]['pos'])
|
||||
|
||||
nx.write_gexf(G, graph_name+".gexf", version="1.2draft")
|
||||
|
||||
###########
|
||||
# Results #
|
||||
###########
|
||||
|
||||
def results(model_name):
|
||||
x_values = []
|
||||
neutral_values = []
|
||||
non_radical_values = []
|
||||
radical_values = []
|
||||
|
||||
attribute_plot = 'status'
|
||||
for time in range(0, settings.network_params["max_time"]):
|
||||
value_neutral = 0
|
||||
value_non_radical = 0
|
||||
value_radical = 0
|
||||
real_time = time * settings.network_params["timeout"]
|
||||
activity = False
|
||||
for x in range(0, settings.network_params["number_of_nodes"]):
|
||||
if attribute_plot in models.networkStatus["agent_%s" % x]:
|
||||
if real_time in models.networkStatus["agent_%s" % x][attribute_plot]:
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == NON_RADICAL:
|
||||
value_non_radical += 1
|
||||
activity = True
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == NEUTRAL:
|
||||
value_neutral += 1
|
||||
activity = True
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == RADICAL:
|
||||
value_radical += 1
|
||||
activity = True
|
||||
|
||||
|
||||
if activity:
|
||||
x_values.append(real_time)
|
||||
neutral_values.append(value_neutral)
|
||||
non_radical_values.append(value_non_radical)
|
||||
radical_values.append(value_radical)
|
||||
activity = False
|
||||
|
||||
fig1 = plt.figure()
|
||||
ax1 = fig1.add_subplot(111)
|
||||
|
||||
non_radical_line = ax1.plot(x_values, non_radical_values, label='Non radical')
|
||||
neutral_line = ax1.plot(x_values, neutral_values, label='Neutral')
|
||||
radical_line = ax1.plot(x_values, radical_values, label='Radical')
|
||||
ax1.legend()
|
||||
fig1.savefig(model_name+'.png')
|
||||
plt.show()
|
||||
|
||||
###########
|
||||
# Results #
|
||||
###########
|
||||
|
||||
def resultadosTipo(model_name):
|
||||
x_values = []
|
||||
population_values = []
|
||||
leaders_values = []
|
||||
havens_values = []
|
||||
training_enviroments_values = []
|
||||
|
||||
attribute_plot = 'type'
|
||||
for time in range(0, settings.network_params["max_time"]):
|
||||
value_population = 0
|
||||
value_leaders = 0
|
||||
value_havens = 0
|
||||
value_training_enviroments = 0
|
||||
real_time = time * settings.network_params["timeout"]
|
||||
activity = False
|
||||
for x in range(0, settings.network_params["number_of_nodes"]):
|
||||
if attribute_plot in models.networkStatus["agent_%s" % x]:
|
||||
if real_time in models.networkStatus["agent_%s" % x][attribute_plot]:
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == POPULATION:
|
||||
value_population += 1
|
||||
activity = True
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == LEADERS:
|
||||
value_leaders += 1
|
||||
activity = True
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == HAVEN:
|
||||
value_havens += 1
|
||||
activity = True
|
||||
if models.networkStatus["agent_%s" % x][attribute_plot][real_time] == TRAINING:
|
||||
value_training_enviroments += 1
|
||||
activity = True
|
||||
if activity:
|
||||
x_values.append(real_time)
|
||||
population_values.append(value_population)
|
||||
leaders_values.append(value_leaders)
|
||||
havens_values.append(value_havens)
|
||||
training_enviroments_values.append(value_training_enviroments)
|
||||
activity = False
|
||||
|
||||
fig2 = plt.figure()
|
||||
ax2 = fig2.add_subplot(111)
|
||||
|
||||
population_line = ax2.plot(x_values, population_values, label='Population')
|
||||
leaders_line = ax2.plot(x_values, leaders_values, label='Leader')
|
||||
havens_line = ax2.plot(x_values, havens_values, label='Havens')
|
||||
training_enviroments_line = ax2.plot(x_values, training_enviroments_values, label='Training Enviroments')
|
||||
ax2.legend()
|
||||
fig2.savefig(model_name+'_type'+'.png')
|
||||
plt.show()
|
||||
|
||||
####################
|
||||
# Network creation #
|
||||
####################
|
||||
|
||||
# nx.degree_centrality(G);
|
||||
|
||||
if settings.network_params["network_type"] == 0:
|
||||
G = nx.random_geometric_graph(settings.network_params["number_of_nodes"], 0.2)
|
||||
|
||||
settings.partition_param = community.best_partition(G)
|
||||
settings.centrality_param = nx.betweenness_centrality(G).copy()
|
||||
|
||||
|
||||
# print(settings.centrality_param)
|
||||
# print(settings.partition_param)
|
||||
# More types of networks can be added here
|
||||
|
||||
##############
|
||||
# Simulation #
|
||||
##############
|
||||
|
||||
agents = settings.environment_params['agent']
|
||||
|
||||
print("Using Agent(s): {agents}".format(agents=agents))
|
||||
|
||||
if len(agents) > 1:
|
||||
for agent in agents:
|
||||
sim = NetworkSimulation(topology=G, states=init_states, agent_type=locals()[agent], max_time=settings.network_params["max_time"],
|
||||
num_trials=settings.network_params["num_trials"], logging_interval=1.0, **settings.environment_params)
|
||||
sim.run_simulation()
|
||||
print(str(agent))
|
||||
results(str(agent))
|
||||
resultadosTipo(str(agent))
|
||||
visualization(str(agent))
|
||||
else:
|
||||
agent = agents[0]
|
||||
sim = NetworkSimulation(topology=G, states=init_states, agent_type=locals()[agent], max_time=settings.network_params["max_time"],
|
||||
num_trials=settings.network_params["num_trials"], logging_interval=1.0, **settings.environment_params)
|
||||
sim.run_simulation()
|
||||
results(str(agent))
|
||||
resultadosTipo(str(agent))
|
||||
|
||||
visualization(str(agent))
|
@ -0,0 +1,394 @@
|
||||
from nxsim import NetworkSimulation
|
||||
from nxsim import BaseNetworkAgent
|
||||
from nxsim import BaseLoggingAgent
|
||||
from random import randint
|
||||
from matplotlib import pyplot as plt
|
||||
import random
|
||||
import numpy as np
|
||||
import networkx as nx
|
||||
import settings
|
||||
|
||||
|
||||
settings.init()
|
||||
|
||||
if settings.network_type == 0:
|
||||
G = nx.complete_graph(settings.number_of_nodes)
|
||||
if settings.network_type == 1:
|
||||
G = nx.barabasi_albert_graph(settings.number_of_nodes,3)
|
||||
if settings.network_type == 2:
|
||||
G = nx.margulis_gabber_galil_graph(settings.number_of_nodes, None)
|
||||
|
||||
|
||||
myList=[]
|
||||
networkStatus=[]
|
||||
for x in range(0, settings.number_of_nodes):
|
||||
networkStatus.append({'id':x})
|
||||
|
||||
|
||||
|
||||
# # Just like subclassing a process in SimPy
|
||||
# class MyAgent(BaseNetworkAgent):
|
||||
# def __init__(self, environment=None, agent_id=0, state=()): # Make sure to have these three keyword arguments
|
||||
# super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
# # Add your own attributes here
|
||||
|
||||
# def run(self):
|
||||
# # Add your behaviors here
|
||||
|
||||
|
||||
|
||||
|
||||
class SentimentCorrelationModel(BaseNetworkAgent):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.outside_effects_prob = settings.outside_effects_prob
|
||||
self.anger_prob = settings.anger_prob
|
||||
self.joy_prob = settings.joy_prob
|
||||
self.sadness_prob = settings.sadness_prob
|
||||
self.disgust_prob = settings.disgust_prob
|
||||
self.time_awareness=[]
|
||||
for i in range(4):
|
||||
self.time_awareness.append(0) #0-> Anger, 1-> joy, 2->sadness, 3 -> disgust
|
||||
networkStatus[self.id][self.env.now]=0
|
||||
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if self.env.now > 10:
|
||||
G.add_node(205)
|
||||
G.add_edge(205,0)
|
||||
angry_neighbors_1_time_step=[]
|
||||
joyful_neighbors_1_time_step=[]
|
||||
sad_neighbors_1_time_step=[]
|
||||
disgusted_neighbors_1_time_step=[]
|
||||
|
||||
|
||||
angry_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for x in angry_neighbors:
|
||||
if x.time_awareness[0] > (self.env.now-500):
|
||||
angry_neighbors_1_time_step.append(x)
|
||||
num_neighbors_angry = len(angry_neighbors_1_time_step)
|
||||
|
||||
|
||||
joyful_neighbors = self.get_neighboring_agents(state_id=2)
|
||||
for x in joyful_neighbors:
|
||||
if x.time_awareness[1] > (self.env.now-500):
|
||||
joyful_neighbors_1_time_step.append(x)
|
||||
num_neighbors_joyful = len(joyful_neighbors_1_time_step)
|
||||
|
||||
|
||||
sad_neighbors = self.get_neighboring_agents(state_id=3)
|
||||
for x in sad_neighbors:
|
||||
if x.time_awareness[2] > (self.env.now-500):
|
||||
sad_neighbors_1_time_step.append(x)
|
||||
num_neighbors_sad = len(sad_neighbors_1_time_step)
|
||||
|
||||
|
||||
disgusted_neighbors = self.get_neighboring_agents(state_id=4)
|
||||
for x in disgusted_neighbors:
|
||||
if x.time_awareness[3] > (self.env.now-500):
|
||||
disgusted_neighbors_1_time_step.append(x)
|
||||
num_neighbors_disgusted = len(disgusted_neighbors_1_time_step)
|
||||
|
||||
# #Outside effects. Asignamos un estado aleatorio
|
||||
# if random.random() < settings.outside_effects_prob:
|
||||
# if self.state['id'] == 0:
|
||||
# self.state['id'] = random.randint(1,4)
|
||||
# myList.append(self.id)
|
||||
# networkStatus[self.id][self.env.now]=self.state['id'] #Almaceno cuando se ha infectado para la red dinamica
|
||||
# self.time_awareness = self.env.now #Para saber cuando se han contagiado
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
# else:
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
# #Imitation effects-Joy
|
||||
|
||||
# if random.random() < (settings.joy_prob*(num_neighbors_joyful)/10):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 2
|
||||
# networkStatus[self.id][self.env.now]=2
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
# #Imitation effects-Sadness
|
||||
|
||||
# if random.random() < (settings.sadness_prob*(num_neighbors_sad)/10):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 3
|
||||
# networkStatus[self.id][self.env.now]=3
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
# #Imitation effects-Disgust
|
||||
|
||||
# if random.random() < (settings.disgust_prob*(num_neighbors_disgusted)/10):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 4
|
||||
# networkStatus[self.id][self.env.now]=4
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
# #Imitation effects-Anger
|
||||
|
||||
# if random.random() < (settings.anger_prob*(num_neighbors_angry)/10):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 1
|
||||
# networkStatus[self.id][self.env.now]=1
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
###########################################
|
||||
|
||||
|
||||
anger_prob= settings.anger_prob+(len(angry_neighbors_1_time_step)*settings.anger_prob)
|
||||
print("anger_prob " + str(anger_prob))
|
||||
joy_prob= settings.joy_prob+(len(joyful_neighbors_1_time_step)*settings.joy_prob)
|
||||
print("joy_prob " + str(joy_prob))
|
||||
sadness_prob = settings.sadness_prob+(len(sad_neighbors_1_time_step)*settings.sadness_prob)
|
||||
print("sadness_prob "+ str(sadness_prob))
|
||||
disgust_prob = settings.disgust_prob+(len(disgusted_neighbors_1_time_step)*settings.disgust_prob)
|
||||
print("disgust_prob " + str(disgust_prob))
|
||||
outside_effects_prob= settings.outside_effects_prob
|
||||
print("outside_effects_prob " + str(outside_effects_prob))
|
||||
|
||||
|
||||
num = random.random()
|
||||
|
||||
|
||||
if(num<outside_effects_prob):
|
||||
self.state['id'] = random.randint(1,4)
|
||||
myList.append(self.id)
|
||||
networkStatus[self.id][self.env.now]=self.state['id'] #Almaceno cuando se ha infectado para la red dinamica
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
if(num<anger_prob):
|
||||
|
||||
myList.append(self.id)
|
||||
self.state['id'] = 1
|
||||
networkStatus[self.id][self.env.now]=1
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
elif (num<joy_prob+anger_prob and num>anger_prob):
|
||||
|
||||
myList.append(self.id)
|
||||
self.state['id'] = 2
|
||||
networkStatus[self.id][self.env.now]=2
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
elif (num<sadness_prob+anger_prob+joy_prob and num>joy_prob+anger_prob):
|
||||
|
||||
myList.append(self.id)
|
||||
self.state['id'] = 3
|
||||
networkStatus[self.id][self.env.now]=3
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
elif (num<disgust_prob+sadness_prob+anger_prob+joy_prob and num>sadness_prob+anger_prob+joy_prob):
|
||||
|
||||
myList.append(self.id)
|
||||
self.state['id'] = 4
|
||||
networkStatus[self.id][self.env.now]=4
|
||||
self.time_awareness[self.state['id']-1] = self.env.now
|
||||
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
# anger_propagation = settings.anger_prob*num_neighbors_angry/10
|
||||
# joy_propagation = anger_propagation + (settings.joy_prob*num_neighbors_joyful/10)
|
||||
# sadness_propagation = joy_propagation + (settings.sadness_prob*num_neighbors_sad/10)
|
||||
# disgust_propagation = sadness_propagation + (settings.disgust_prob*num_neighbors_disgusted/10)
|
||||
# outside_effects_propagation = disgust_propagation + settings.outside_effects_prob
|
||||
|
||||
# if (num<anger_propagation):
|
||||
# if(self.state['id'] !=0):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 1
|
||||
# networkStatus[self.id][self.env.now]=1
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
# if (num<joy_propagation):
|
||||
# if(self.state['id'] !=0):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 2
|
||||
# networkStatus[self.id][self.env.now]=2
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
# if(num<sadness_propagation):
|
||||
# if(self.state['id'] !=0):
|
||||
# myList.append(self.id)
|
||||
# self.state['id'] = 3
|
||||
# networkStatus[self.id][self.env.now]=3
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
# # if(num<disgust_propagation):
|
||||
# # if(self.state['id'] !=0):
|
||||
# # myList.append(self.id)
|
||||
# # self.state['id'] = 4
|
||||
# # networkStatus[self.id][self.env.now]=4
|
||||
# # yield self.env.timeout(settings.timeout)
|
||||
# if(num <outside_effects_propagation):
|
||||
# if self.state['id'] == 0:
|
||||
# self.state['id'] = random.randint(1,4)
|
||||
# myList.append(self.id)
|
||||
# networkStatus[self.id][self.env.now]=self.state['id'] #Almaceno cuando se ha infectado para la red dinamica
|
||||
# self.time_awareness = self.env.now #Para saber cuando se han contagiado
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
# else:
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
# else:
|
||||
# yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class BassModel(BaseNetworkAgent):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.innovation_prob = settings.innovation_prob
|
||||
self.imitation_prob = settings.imitation_prob
|
||||
networkStatus[self.id][self.env.now]=0
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
|
||||
|
||||
#Outside effects
|
||||
if random.random() < settings.innovation_prob:
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
myList.append(self.id)
|
||||
networkStatus[self.id][self.env.now]=1
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
#Imitation effects
|
||||
if self.state['id'] == 0:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
num_neighbors_aware = len(aware_neighbors)
|
||||
if random.random() < (settings.imitation_prob*num_neighbors_aware):
|
||||
myList.append(self.id)
|
||||
self.state['id'] = 1
|
||||
networkStatus[self.id][self.env.now]=1
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
class IndependentCascadeModel(BaseNetworkAgent):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.innovation_prob = settings.innovation_prob
|
||||
self.imitation_prob = settings.imitation_prob
|
||||
self.time_awareness = 0
|
||||
networkStatus[self.id][self.env.now]=0
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
aware_neighbors_1_time_step=[]
|
||||
#Outside effects
|
||||
if random.random() < settings.innovation_prob:
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
myList.append(self.id)
|
||||
networkStatus[self.id][self.env.now]=1
|
||||
self.time_awareness = self.env.now #Para saber cuando se han contagiado
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
#Imitation effects
|
||||
if self.state['id'] == 0:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for x in aware_neighbors:
|
||||
if x.time_awareness == (self.env.now-1):
|
||||
aware_neighbors_1_time_step.append(x)
|
||||
num_neighbors_aware = len(aware_neighbors_1_time_step)
|
||||
if random.random() < (settings.imitation_prob*num_neighbors_aware):
|
||||
myList.append(self.id)
|
||||
self.state['id'] = 1
|
||||
networkStatus[self.id][self.env.now]=1
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
class ZombieOutbreak(BaseNetworkAgent):
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.bite_prob = settings.bite_prob
|
||||
networkStatus[self.id][self.env.now]=0
|
||||
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if random.random() < settings.heal_prob:
|
||||
if self.state['id'] == 1:
|
||||
self.zombify()
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
if self.state['id'] == 1:
|
||||
print("Soy el zombie " + str(self.id) + " y me voy a curar porque el num aleatorio ha sido " + str(num))
|
||||
networkStatus[self.id][self.env.now]=0
|
||||
if self.id in myList:
|
||||
myList.remove(self.id)
|
||||
self.state['id'] = 0
|
||||
yield self.env.timeout(settings.timeout)
|
||||
else:
|
||||
yield self.env.timeout(settings.timeout)
|
||||
|
||||
|
||||
def zombify(self):
|
||||
normal_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in normal_neighbors:
|
||||
if random.random() < self.bite_prob:
|
||||
print("Soy el zombie " + str(self.id) + " y voy a contagiar a " + str(neighbor.id))
|
||||
neighbor.state['id'] = 1 # zombie
|
||||
myList.append(neighbor.id)
|
||||
networkStatus[self.id][self.env.now]=1
|
||||
networkStatus[neighbor.id][self.env.now]=1
|
||||
print(self.env.now, "Soy el zombie: "+ str(self.id), "Mi vecino es: "+ str(neighbor.id), sep='\t')
|
||||
break
|
||||
|
||||
|
||||
# Initialize agent states. Let's assume everyone is normal.
|
||||
init_states = [{'id': 0, } for _ in range(settings.number_of_nodes)] # add keys as as necessary, but "id" must always refer to that state category
|
||||
|
||||
# Seed a zombie
|
||||
#init_states[5] = {'id': 1}
|
||||
#init_states[3] = {'id': 1}
|
||||
|
||||
sim = NetworkSimulation(topology=G, states=init_states, agent_type=SentimentCorrelationModel,
|
||||
max_time=settings.max_time, num_trials=settings.num_trials, logging_interval=1.0)
|
||||
|
||||
|
||||
sim.run_simulation()
|
||||
|
||||
myList = sorted(myList, key=int)
|
||||
#print("Los zombies son: " + str(myList))
|
||||
|
||||
trial = BaseLoggingAgent.open_trial_state_history(dir_path='sim_01', trial_id=0)
|
||||
zombie_census = [sum([1 for node_id, state in g.items() if state['id'] == 1]) for t,g in trial.items()]
|
||||
|
||||
#for x in range(len(myList)):
|
||||
# G.node[myList[x]]['viz'] = {'color': {'r': 255, 'g': 0, 'b': 0, 'a': 0}}
|
||||
|
||||
#G.node[1]['viz'] = {'color': {'r': 255, 'g': 0, 'b': 0, 'a': 0}}
|
||||
|
||||
#lista = nx.nodes(G)
|
||||
#print('Nodos: ' + str(lista))
|
||||
for x in range(0, settings.number_of_nodes):
|
||||
networkStatusAux=[]
|
||||
for tiempo in networkStatus[x]:
|
||||
if tiempo != 'id':
|
||||
networkStatusAux.append((networkStatus[x][tiempo],tiempo,None))
|
||||
G.add_node(x, zombie= networkStatusAux)
|
||||
#print(networkStatus)
|
||||
|
||||
|
||||
nx.write_gexf(G,"test.gexf", version="1.2draft")
|
||||
plt.plot(zombie_census)
|
||||
plt.draw() # pyplot draw()
|
||||
plt.savefig("zombie.png")
|
||||
#print(networkStatus)
|
||||
#nx.draw(G)
|
||||
#plt.show()
|
||||
#plt.savefig("path.png")
|
@ -1,42 +0,0 @@
|
||||
import importlib
|
||||
import sys
|
||||
import os
|
||||
|
||||
__version__ = "0.9.2"
|
||||
|
||||
try:
|
||||
basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
from . import agents
|
||||
from . import simulation
|
||||
from . import environment
|
||||
from . import utils
|
||||
from . import settings
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
from . import simulation
|
||||
|
||||
parser = argparse.ArgumentParser(description='Run a SOIL simulation')
|
||||
parser.add_argument('file', type=str,
|
||||
nargs="?",
|
||||
default='simulation.yml',
|
||||
help='python module containing the simulation configuration.')
|
||||
parser.add_argument('--module', '-m', type=str,
|
||||
help='file containing the code of any custom agents.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.module:
|
||||
sys.path.append(os.getcwd())
|
||||
importlib.import_module(args.module)
|
||||
|
||||
print('Loading config file: {}'.format(args.file))
|
||||
simulation.run_from_config(args.file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -1,123 +0,0 @@
|
||||
import nxsim
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
from functools import wraps
|
||||
|
||||
|
||||
class BaseAgent(nxsim.BaseAgent):
|
||||
"""
|
||||
A special simpy BaseAgent that keeps track of its state history.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._history = OrderedDict()
|
||||
self._neighbors = None
|
||||
super().__init__(*args, **kwargs)
|
||||
self._history[None] = deepcopy(self.state)
|
||||
|
||||
@property
|
||||
def now(self):
|
||||
try:
|
||||
return self.env.now
|
||||
except AttributeError:
|
||||
# No environment
|
||||
return None
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
res = self.step()
|
||||
self._history[self.env.now] = deepcopy(self.state)
|
||||
yield res or self.env.timeout(self.env.interval)
|
||||
|
||||
def step(self):
|
||||
pass
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(self._history)
|
||||
|
||||
class NetworkAgent(BaseAgent, nxsim.BaseNetworkAgent):
|
||||
|
||||
def count_agents(self, state_id=None, limit_neighbors=False):
|
||||
if limit_neighbors:
|
||||
agents = self.global_topology.neighbors(self.id)
|
||||
else:
|
||||
agents = self.global_topology.nodes()
|
||||
count = 0
|
||||
for agent in agents:
|
||||
if state_id and state_id != self.global_topology.node[agent]['agent'].state['id']:
|
||||
continue
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def count_neighboring_agents(self, state_id=None):
|
||||
return self.count_agents(state_id, limit_neighbors=True)
|
||||
|
||||
|
||||
def state(func):
|
||||
|
||||
@wraps(func)
|
||||
def func_wrapper(self):
|
||||
when = None
|
||||
next_state = func(self)
|
||||
try:
|
||||
next_state, when = next_state
|
||||
except TypeError:
|
||||
pass
|
||||
if next_state:
|
||||
try:
|
||||
self.state['id'] = next_state.id
|
||||
except AttributeError:
|
||||
raise NotImplemented('State id %s is not valid.' % next_state)
|
||||
return when
|
||||
|
||||
func_wrapper.id = func.__name__
|
||||
func_wrapper.is_default = False
|
||||
return func_wrapper
|
||||
|
||||
|
||||
def default_state(func):
|
||||
func.is_default = True
|
||||
return func
|
||||
|
||||
|
||||
class MetaFSM(type):
|
||||
def __init__(cls, name, bases, nmspc):
|
||||
super(MetaFSM, cls).__init__(name, bases, nmspc)
|
||||
states = {}
|
||||
# Re-use states from inherited classes
|
||||
default_state = None
|
||||
for i in bases:
|
||||
if isinstance(i, MetaFSM):
|
||||
for state_id, state in i.states.items():
|
||||
if state.is_default:
|
||||
default_state = state
|
||||
states[state_id] = state
|
||||
|
||||
# Add new states
|
||||
for name, func in nmspc.items():
|
||||
if hasattr(func, 'id'):
|
||||
if func.is_default:
|
||||
default_state = func
|
||||
states[func.id] = func
|
||||
cls.default_state = default_state
|
||||
cls.states = states
|
||||
|
||||
|
||||
class FSM(BaseAgent, metaclass=MetaFSM):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FSM, self).__init__(*args, **kwargs)
|
||||
if 'id' not in self.state:
|
||||
self.state['id'] = self.default_state.id
|
||||
|
||||
def step(self):
|
||||
if 'id' in self.state:
|
||||
next_state = self.state['id']
|
||||
elif self.default_state:
|
||||
next_state = self.default_state.id
|
||||
else:
|
||||
raise Exception('{} has no valid state id or default state'.format(self))
|
||||
if next_state not in self.states:
|
||||
raise Exception('{} is not a valid id for {}'.format(next_state, self))
|
||||
self.states[next_state](self)
|
@ -1,40 +0,0 @@
|
||||
import random
|
||||
from . import NetworkAgent
|
||||
|
||||
|
||||
class BassModel(NetworkAgent):
|
||||
"""
|
||||
Settings:
|
||||
innovation_prob
|
||||
imitation_prob
|
||||
"""
|
||||
|
||||
def __init__(self, environment, agent_id, state):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
env_params = environment.environment_params
|
||||
self.state['sentimentCorrelation'] = 0
|
||||
|
||||
def step(self):
|
||||
self.behaviour()
|
||||
|
||||
def behaviour(self):
|
||||
# Outside effects
|
||||
if random.random() < self.state_params['innovation_prob']:
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
else:
|
||||
pass
|
||||
|
||||
return
|
||||
|
||||
# Imitation effects
|
||||
if self.state['id'] == 0:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
num_neighbors_aware = len(aware_neighbors)
|
||||
if random.random() < (self.state_params['imitation_prob']*num_neighbors_aware):
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
|
||||
else:
|
||||
pass
|
@ -1,102 +0,0 @@
|
||||
import random
|
||||
from . import NetworkAgent
|
||||
|
||||
|
||||
class BigMarketModel(NetworkAgent):
|
||||
"""
|
||||
Settings:
|
||||
Names:
|
||||
enterprises [Array]
|
||||
|
||||
tweet_probability_enterprises [Array]
|
||||
Users:
|
||||
tweet_probability_users
|
||||
|
||||
tweet_relevant_probability
|
||||
|
||||
tweet_probability_about [Array]
|
||||
|
||||
sentiment_about [Array]
|
||||
"""
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.enterprises = environment.environment_params['enterprises']
|
||||
self.type = ""
|
||||
self.number_of_enterprises = len(environment.environment_params['enterprises'])
|
||||
|
||||
if self.id < self.number_of_enterprises: # Enterprises
|
||||
self.state['id'] = self.id
|
||||
self.type = "Enterprise"
|
||||
self.tweet_probability = environment.environment_params['tweet_probability_enterprises'][self.id]
|
||||
else: # normal users
|
||||
self.state['id'] = self.number_of_enterprises
|
||||
self.type = "User"
|
||||
self.tweet_probability = environment.environment_params['tweet_probability_users']
|
||||
self.tweet_relevant_probability = environment.environment_params['tweet_relevant_probability']
|
||||
self.tweet_probability_about = environment.environment_params['tweet_probability_about'] # List
|
||||
self.sentiment_about = environment.environment_params['sentiment_about'] # List
|
||||
|
||||
def step(self):
|
||||
|
||||
if self.id < self.number_of_enterprises: # Enterprise
|
||||
self.enterpriseBehaviour()
|
||||
else: # Usuario
|
||||
self.userBehaviour()
|
||||
for i in range(self.number_of_enterprises): # So that it never is set to 0 if there are not changes (logs)
|
||||
self.attrs['sentiment_enterprise_%s'% self.enterprises[i]] = self.sentiment_about[i]
|
||||
|
||||
def enterpriseBehaviour(self):
|
||||
|
||||
if random.random() < self.tweet_probability: # Tweets
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=self.number_of_enterprises) # Nodes neighbour users
|
||||
for x in aware_neighbors:
|
||||
if random.uniform(0,10) < 5:
|
||||
x.sentiment_about[self.id] += 0.1 # Increments for enterprise
|
||||
else:
|
||||
x.sentiment_about[self.id] -= 0.1 # Decrements for enterprise
|
||||
|
||||
# Establecemos limites
|
||||
if x.sentiment_about[self.id] > 1:
|
||||
x.sentiment_about[self.id] = 1
|
||||
if x.sentiment_about[self.id]< -1:
|
||||
x.sentiment_about[self.id] = -1
|
||||
|
||||
x.attrs['sentiment_enterprise_%s'% self.enterprises[self.id]] = x.sentiment_about[self.id]
|
||||
|
||||
def userBehaviour(self):
|
||||
|
||||
if random.random() < self.tweet_probability: # Tweets
|
||||
if random.random() < self.tweet_relevant_probability: # Tweets something relevant
|
||||
# Tweet probability per enterprise
|
||||
for i in range(self.number_of_enterprises):
|
||||
random_num = random.random()
|
||||
if random_num < self.tweet_probability_about[i]:
|
||||
# The condition is fulfilled, sentiments are evaluated towards that enterprise
|
||||
if self.sentiment_about[i] < 0:
|
||||
# NEGATIVO
|
||||
self.userTweets("negative",i)
|
||||
elif self.sentiment_about[i] == 0:
|
||||
# NEUTRO
|
||||
pass
|
||||
else:
|
||||
# POSITIVO
|
||||
self.userTweets("positive",i)
|
||||
|
||||
def userTweets(self,sentiment,enterprise):
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=self.number_of_enterprises) # Nodes neighbours users
|
||||
for x in aware_neighbors:
|
||||
if sentiment == "positive":
|
||||
x.sentiment_about[enterprise] +=0.003
|
||||
elif sentiment == "negative":
|
||||
x.sentiment_about[enterprise] -=0.003
|
||||
else:
|
||||
pass
|
||||
|
||||
# Establecemos limites
|
||||
if x.sentiment_about[enterprise] > 1:
|
||||
x.sentiment_about[enterprise] = 1
|
||||
if x.sentiment_about[enterprise] < -1:
|
||||
x.sentiment_about[enterprise] = -1
|
||||
|
||||
x.attrs['sentiment_enterprise_%s'% self.enterprises[enterprise]] = x.sentiment_about[enterprise]
|
@ -1,31 +0,0 @@
|
||||
from . import NetworkAgent
|
||||
|
||||
|
||||
class CounterModel(NetworkAgent):
|
||||
"""
|
||||
Dummy behaviour. It counts the number of nodes in the network and neighbors
|
||||
in each step and adds it to its state.
|
||||
"""
|
||||
|
||||
def step(self):
|
||||
# Outside effects
|
||||
total = len(self.get_all_agents())
|
||||
neighbors = len(self.get_neighboring_agents())
|
||||
self.state['times'] = self.state.get('times', 0) + 1
|
||||
self.state['neighbors'] = neighbors
|
||||
self.state['total'] = total
|
||||
|
||||
|
||||
class AggregatedCounter(NetworkAgent):
|
||||
"""
|
||||
Dummy behaviour. It counts the number of nodes in the network and neighbors
|
||||
in each step and adds it to its state.
|
||||
"""
|
||||
|
||||
def step(self):
|
||||
# Outside effects
|
||||
total = len(self.get_all_agents())
|
||||
neighbors = len(self.get_neighboring_agents())
|
||||
self.state['times'] = self.state.get('times', 0) + 1
|
||||
self.state['neighbors'] = self.state.get('neighbors', 0) + neighbors
|
||||
self.state['total'] = self.state.get('total', 0) + total
|
@ -1,18 +0,0 @@
|
||||
from . import BaseAgent
|
||||
|
||||
import os.path
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
import networkx as nx
|
||||
|
||||
|
||||
class DrawingAgent(BaseAgent):
|
||||
"""
|
||||
Agent that draws the state of the network.
|
||||
"""
|
||||
|
||||
def step(self):
|
||||
# Outside effects
|
||||
f = plt.figure()
|
||||
nx.draw(self.env.G, node_size=10, width=0.2, pos=nx.spring_layout(self.env.G, scale=100), ax=f.add_subplot(111))
|
||||
f.savefig(os.path.join(self.env.sim().dir_path, "graph-"+str(self.env.now)+".png"))
|
@ -1,49 +0,0 @@
|
||||
import random
|
||||
from . import BaseAgent
|
||||
|
||||
|
||||
class IndependentCascadeModel(BaseAgent):
|
||||
"""
|
||||
Settings:
|
||||
innovation_prob
|
||||
|
||||
imitation_prob
|
||||
"""
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.innovation_prob = environment.environment_params['innovation_prob']
|
||||
self.imitation_prob = environment.environment_params['imitation_prob']
|
||||
self.state['time_awareness'] = 0
|
||||
self.state['sentimentCorrelation'] = 0
|
||||
|
||||
def step(self):
|
||||
self.behaviour()
|
||||
|
||||
def behaviour(self):
|
||||
aware_neighbors_1_time_step = []
|
||||
# Outside effects
|
||||
if random.random() < self.innovation_prob:
|
||||
if self.state['id'] == 0:
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
self.state['time_awareness'] = self.env.now # To know when they have been infected
|
||||
else:
|
||||
pass
|
||||
|
||||
return
|
||||
|
||||
# Imitation effects
|
||||
if self.state['id'] == 0:
|
||||
aware_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for x in aware_neighbors:
|
||||
if x.state['time_awareness'] == (self.env.now-1):
|
||||
aware_neighbors_1_time_step.append(x)
|
||||
num_neighbors_aware = len(aware_neighbors_1_time_step)
|
||||
if random.random() < (self.imitation_prob*num_neighbors_aware):
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
else:
|
||||
pass
|
||||
|
||||
return
|
@ -1,242 +0,0 @@
|
||||
import random
|
||||
import numpy as np
|
||||
from . import NetworkAgent
|
||||
|
||||
|
||||
class SpreadModelM2(NetworkAgent):
|
||||
"""
|
||||
Settings:
|
||||
prob_neutral_making_denier
|
||||
|
||||
prob_infect
|
||||
|
||||
prob_cured_healing_infected
|
||||
|
||||
prob_cured_vaccinate_neutral
|
||||
|
||||
prob_vaccinated_healing_infected
|
||||
|
||||
prob_vaccinated_vaccinate_neutral
|
||||
|
||||
prob_generate_anti_rumor
|
||||
"""
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.prob_neutral_making_denier = np.random.normal(environment.environment_params['prob_neutral_making_denier'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_infect = np.random.normal(environment.environment_params['prob_infect'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_cured_healing_infected = np.random.normal(environment.environment_params['prob_cured_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_cured_vaccinate_neutral = np.random.normal(environment.environment_params['prob_cured_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_vaccinated_healing_infected = np.random.normal(environment.environment_params['prob_vaccinated_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_vaccinated_vaccinate_neutral = np.random.normal(environment.environment_params['prob_vaccinated_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_generate_anti_rumor = np.random.normal(environment.environment_params['prob_generate_anti_rumor'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
def step(self):
|
||||
|
||||
if self.state['id'] == 0: # Neutral
|
||||
self.neutral_behaviour()
|
||||
elif self.state['id'] == 1: # Infected
|
||||
self.infected_behaviour()
|
||||
elif self.state['id'] == 2: # Cured
|
||||
self.cured_behaviour()
|
||||
elif self.state['id'] == 3: # Vaccinated
|
||||
self.vaccinated_behaviour()
|
||||
|
||||
def neutral_behaviour(self):
|
||||
|
||||
# Infected
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors) > 0:
|
||||
if random.random() < self.prob_neutral_making_denier:
|
||||
self.state['id'] = 3 # Vaccinated making denier
|
||||
|
||||
def infected_behaviour(self):
|
||||
|
||||
# Neutral
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_infect:
|
||||
neighbor.state['id'] = 1 # Infected
|
||||
|
||||
def cured_behaviour(self):
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def vaccinated_behaviour(self):
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Generate anti-rumor
|
||||
infected_neighbors_2 = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_2:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
|
||||
class ControlModelM2(NetworkAgent):
|
||||
"""
|
||||
Settings:
|
||||
prob_neutral_making_denier
|
||||
|
||||
prob_infect
|
||||
|
||||
prob_cured_healing_infected
|
||||
|
||||
prob_cured_vaccinate_neutral
|
||||
|
||||
prob_vaccinated_healing_infected
|
||||
|
||||
prob_vaccinated_vaccinate_neutral
|
||||
|
||||
prob_generate_anti_rumor
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.prob_neutral_making_denier = np.random.normal(environment.environment_params['prob_neutral_making_denier'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_infect = np.random.normal(environment.environment_params['prob_infect'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_cured_healing_infected = np.random.normal(environment.environment_params['prob_cured_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_cured_vaccinate_neutral = np.random.normal(environment.environment_params['prob_cured_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.prob_vaccinated_healing_infected = np.random.normal(environment.environment_params['prob_vaccinated_healing_infected'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_vaccinated_vaccinate_neutral = np.random.normal(environment.environment_params['prob_vaccinated_vaccinate_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.prob_generate_anti_rumor = np.random.normal(environment.environment_params['prob_generate_anti_rumor'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
def step(self):
|
||||
|
||||
if self.state['id'] == 0: # Neutral
|
||||
self.neutral_behaviour()
|
||||
elif self.state['id'] == 1: # Infected
|
||||
self.infected_behaviour()
|
||||
elif self.state['id'] == 2: # Cured
|
||||
self.cured_behaviour()
|
||||
elif self.state['id'] == 3: # Vaccinated
|
||||
self.vaccinated_behaviour()
|
||||
elif self.state['id'] == 4: # Beacon-off
|
||||
self.beacon_off_behaviour()
|
||||
elif self.state['id'] == 5: # Beacon-on
|
||||
self.beacon_on_behaviour()
|
||||
|
||||
def neutral_behaviour(self):
|
||||
self.state['visible'] = False
|
||||
|
||||
# Infected
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors) > 0:
|
||||
if random.random() < self.prob_neutral_making_denier:
|
||||
self.state['id'] = 3 # Vaccinated making denier
|
||||
|
||||
def infected_behaviour(self):
|
||||
|
||||
# Neutral
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_infect:
|
||||
neighbor.state['id'] = 1 # Infected
|
||||
self.state['visible'] = False
|
||||
|
||||
def cured_behaviour(self):
|
||||
|
||||
self.state['visible'] = True
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def vaccinated_behaviour(self):
|
||||
self.state['visible'] = True
|
||||
|
||||
# Cure
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_cured_healing_infected:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
|
||||
# Generate anti-rumor
|
||||
infected_neighbors_2 = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_2:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
def beacon_off_behaviour(self):
|
||||
self.state['visible'] = False
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
if len(infected_neighbors) > 0:
|
||||
self.state['id'] == 5 # Beacon on
|
||||
|
||||
def beacon_on_behaviour(self):
|
||||
self.state['visible'] = False
|
||||
# Cure (M2 feature added)
|
||||
infected_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
neutral_neighbors_infected = neighbor.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors_infected:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
||||
infected_neighbors_infected = neighbor.get_neighboring_agents(state_id=1)
|
||||
for neighbor in infected_neighbors_infected:
|
||||
if random.random() < self.prob_generate_anti_rumor:
|
||||
neighbor.state['id'] = 2 # Cured
|
||||
|
||||
# Vaccinate
|
||||
neutral_neighbors = self.get_neighboring_agents(state_id=0)
|
||||
for neighbor in neutral_neighbors:
|
||||
if random.random() < self.prob_cured_vaccinate_neutral:
|
||||
neighbor.state['id'] = 3 # Vaccinated
|
@ -1,93 +0,0 @@
|
||||
import random
|
||||
import numpy as np
|
||||
from . import FSM, state
|
||||
|
||||
|
||||
class SISaModel(FSM):
|
||||
"""
|
||||
Settings:
|
||||
neutral_discontent_spon_prob
|
||||
|
||||
neutral_discontent_infected_prob
|
||||
|
||||
neutral_content_spong_prob
|
||||
|
||||
neutral_content_infected_prob
|
||||
|
||||
discontent_neutral
|
||||
|
||||
discontent_content
|
||||
|
||||
variance_d_c
|
||||
|
||||
content_discontent
|
||||
|
||||
variance_c_d
|
||||
|
||||
content_neutral
|
||||
|
||||
standard_variance
|
||||
"""
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
|
||||
self.neutral_discontent_spon_prob = np.random.normal(environment.environment_params['neutral_discontent_spon_prob'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.neutral_discontent_infected_prob = np.random.normal(environment.environment_params['neutral_discontent_infected_prob'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.neutral_content_spon_prob = np.random.normal(environment.environment_params['neutral_content_spon_prob'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.neutral_content_infected_prob = np.random.normal(environment.environment_params['neutral_content_infected_prob'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
self.discontent_neutral = np.random.normal(environment.environment_params['discontent_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
self.discontent_content = np.random.normal(environment.environment_params['discontent_content'],
|
||||
environment.environment_params['variance_d_c'])
|
||||
|
||||
self.content_discontent = np.random.normal(environment.environment_params['content_discontent'],
|
||||
environment.environment_params['variance_c_d'])
|
||||
self.content_neutral = np.random.normal(environment.environment_params['content_neutral'],
|
||||
environment.environment_params['standard_variance'])
|
||||
|
||||
@state
|
||||
def neutral(self):
|
||||
# Spontaneous effects
|
||||
if random.random() < self.neutral_discontent_spon_prob:
|
||||
return self.discontent
|
||||
if random.random() < self.neutral_content_spon_prob:
|
||||
return self.content
|
||||
|
||||
# Infected
|
||||
discontent_neighbors = self.count_neighboring_agents(state_id=self.discontent)
|
||||
if random.random() < discontent_neighbors * self.neutral_discontent_infected_prob:
|
||||
return self.discontent
|
||||
content_neighbors = self.count_neighboring_agents(state_id=self.content.id)
|
||||
if random.random() < content_neighbors * self.neutral_content_infected_prob:
|
||||
return self.content
|
||||
return self.neutral
|
||||
|
||||
@state
|
||||
def discontent(self):
|
||||
# Healing
|
||||
if random.random() < self.discontent_neutral:
|
||||
return self.neutral
|
||||
|
||||
# Superinfected
|
||||
content_neighbors = self.count_neighboring_agents(state_id=self.content.id)
|
||||
if random.random() < content_neighbors * self.discontent_content:
|
||||
return self.content
|
||||
return self.discontent
|
||||
|
||||
@state
|
||||
def content(self):
|
||||
# Healing
|
||||
if random.random() < self.content_neutral:
|
||||
return self.neutral
|
||||
|
||||
# Superinfected
|
||||
discontent_neighbors = self.count_neighboring_agents(state_id=self.discontent.id)
|
||||
if random.random() < discontent_neighbors * self.content_discontent:
|
||||
self.discontent
|
||||
return self.content
|
@ -1,102 +0,0 @@
|
||||
import random
|
||||
from . import NetworkAgent
|
||||
|
||||
|
||||
class SentimentCorrelationModel(NetworkAgent):
|
||||
"""
|
||||
Settings:
|
||||
outside_effects_prob
|
||||
|
||||
anger_prob
|
||||
|
||||
joy_prob
|
||||
|
||||
sadness_prob
|
||||
|
||||
disgust_prob
|
||||
"""
|
||||
|
||||
def __init__(self, environment=None, agent_id=0, state=()):
|
||||
super().__init__(environment=environment, agent_id=agent_id, state=state)
|
||||
self.outside_effects_prob = environment.environment_params['outside_effects_prob']
|
||||
self.anger_prob = environment.environment_params['anger_prob']
|
||||
self.joy_prob = environment.environment_params['joy_prob']
|
||||
self.sadness_prob = environment.environment_params['sadness_prob']
|
||||
self.disgust_prob = environment.environment_params['disgust_prob']
|
||||
self.state['time_awareness'] = []
|
||||
for i in range(4): # In this model we have 4 sentiments
|
||||
self.state['time_awareness'].append(0) # 0-> Anger, 1-> joy, 2->sadness, 3 -> disgust
|
||||
self.state['sentimentCorrelation'] = 0
|
||||
|
||||
def step(self):
|
||||
self.behaviour()
|
||||
|
||||
def behaviour(self):
|
||||
|
||||
angry_neighbors_1_time_step = []
|
||||
joyful_neighbors_1_time_step = []
|
||||
sad_neighbors_1_time_step = []
|
||||
disgusted_neighbors_1_time_step = []
|
||||
|
||||
angry_neighbors = self.get_neighboring_agents(state_id=1)
|
||||
for x in angry_neighbors:
|
||||
if x.state['time_awareness'][0] > (self.env.now-500):
|
||||
angry_neighbors_1_time_step.append(x)
|
||||
num_neighbors_angry = len(angry_neighbors_1_time_step)
|
||||
|
||||
joyful_neighbors = self.get_neighboring_agents(state_id=2)
|
||||
for x in joyful_neighbors:
|
||||
if x.state['time_awareness'][1] > (self.env.now-500):
|
||||
joyful_neighbors_1_time_step.append(x)
|
||||
num_neighbors_joyful = len(joyful_neighbors_1_time_step)
|
||||
|
||||
sad_neighbors = self.get_neighboring_agents(state_id=3)
|
||||
for x in sad_neighbors:
|
||||
if x.state['time_awareness'][2] > (self.env.now-500):
|
||||
sad_neighbors_1_time_step.append(x)
|
||||
num_neighbors_sad = len(sad_neighbors_1_time_step)
|
||||
|
||||
disgusted_neighbors = self.get_neighboring_agents(state_id=4)
|
||||
for x in disgusted_neighbors:
|
||||
if x.state['time_awareness'][3] > (self.env.now-500):
|
||||
disgusted_neighbors_1_time_step.append(x)
|
||||
num_neighbors_disgusted = len(disgusted_neighbors_1_time_step)
|
||||
|
||||
anger_prob = self.anger_prob+(len(angry_neighbors_1_time_step)*self.anger_prob)
|
||||
joy_prob = self.joy_prob+(len(joyful_neighbors_1_time_step)*self.joy_prob)
|
||||
sadness_prob = self.sadness_prob+(len(sad_neighbors_1_time_step)*self.sadness_prob)
|
||||
disgust_prob = self.disgust_prob+(len(disgusted_neighbors_1_time_step)*self.disgust_prob)
|
||||
outside_effects_prob = self.outside_effects_prob
|
||||
|
||||
num = random.random()
|
||||
|
||||
if num<outside_effects_prob:
|
||||
self.state['id'] = random.randint(1, 4)
|
||||
|
||||
self.state['sentimentCorrelation'] = self.state['id'] # It is stored when it has been infected for the dynamic network
|
||||
self.state['time_awareness'][self.state['id']-1] = self.env.now
|
||||
self.state['sentiment'] = self.state['id']
|
||||
|
||||
|
||||
if(num<anger_prob):
|
||||
|
||||
self.state['id'] = 1
|
||||
self.state['sentimentCorrelation'] = 1
|
||||
self.state['time_awareness'][self.state['id']-1] = self.env.now
|
||||
elif (num<joy_prob+anger_prob and num>anger_prob):
|
||||
|
||||
self.state['id'] = 2
|
||||
self.state['sentimentCorrelation'] = 2
|
||||
self.state['time_awareness'][self.state['id']-1] = self.env.now
|
||||
elif (num<sadness_prob+anger_prob+joy_prob and num>joy_prob+anger_prob):
|
||||
|
||||
self.state['id'] = 3
|
||||
self.state['sentimentCorrelation'] = 3
|
||||
self.state['time_awareness'][self.state['id']-1] = self.env.now
|
||||
elif (num<disgust_prob+sadness_prob+anger_prob+joy_prob and num>sadness_prob+anger_prob+joy_prob):
|
||||
|
||||
self.state['id'] = 4
|
||||
self.state['sentimentCorrelation'] = 4
|
||||
self.state['time_awareness'][self.state['id']-1] = self.env.now
|
||||
|
||||
self.state['sentiment'] = self.state['id']
|
@ -1,166 +0,0 @@
|
||||
# networkStatus = {} # Dict that will contain the status of every agent in the network
|
||||
# sentimentCorrelationNodeArray = []
|
||||
# for x in range(0, settings.network_params["number_of_nodes"]):
|
||||
# sentimentCorrelationNodeArray.append({'id': x})
|
||||
# Initialize agent states. Let's assume everyone is normal.
|
||||
|
||||
|
||||
import nxsim
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
from functools import wraps
|
||||
|
||||
|
||||
agent_types = {}
|
||||
|
||||
|
||||
class MetaAgent(type):
|
||||
def __init__(cls, name, bases, nmspc):
|
||||
super(MetaAgent, cls).__init__(name, bases, nmspc)
|
||||
agent_types[name] = cls
|
||||
|
||||
|
||||
class BaseAgent(nxsim.BaseAgent, metaclass=MetaAgent):
|
||||
"""
|
||||
A special simpy BaseAgent that keeps track of its state history.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._history = OrderedDict()
|
||||
self._neighbors = None
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, tuple):
|
||||
k, t_step = key
|
||||
if k is not None:
|
||||
if t_step is not None:
|
||||
return self._history[t_step][k]
|
||||
else:
|
||||
return {tt: tv.get(k, None) for tt, tv in self._history.items()}
|
||||
else:
|
||||
return self._history[t_step]
|
||||
return self.state[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.state[key] = value
|
||||
|
||||
def save_state(self):
|
||||
self._history[self.now] = deepcopy(self.state)
|
||||
|
||||
@property
|
||||
def now(self):
|
||||
try:
|
||||
return self.env.now
|
||||
except AttributeError:
|
||||
# No environment
|
||||
return None
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
res = self.step()
|
||||
yield res or self.env.timeout(self.env.interval)
|
||||
|
||||
def step(self):
|
||||
pass
|
||||
|
||||
def to_json(self):
|
||||
return json.dumps(self._history)
|
||||
|
||||
|
||||
class NetworkAgent(BaseAgent, nxsim.BaseNetworkAgent):
|
||||
|
||||
def count_agents(self, state_id=None, limit_neighbors=False):
|
||||
if limit_neighbors:
|
||||
agents = self.global_topology.neighbors(self.id)
|
||||
else:
|
||||
agents = self.global_topology.nodes()
|
||||
count = 0
|
||||
for agent in agents:
|
||||
if state_id and state_id != self.global_topology.node[agent]['agent'].state['id']:
|
||||
continue
|
||||
count += 1
|
||||
return count
|
||||
|
||||
def count_neighboring_agents(self, state_id=None):
|
||||
return self.count_agents(state_id, limit_neighbors=True)
|
||||
|
||||
|
||||
def state(func):
|
||||
|
||||
@wraps(func)
|
||||
def func_wrapper(self):
|
||||
when = None
|
||||
next_state = func(self)
|
||||
try:
|
||||
next_state, when = next_state
|
||||
except TypeError:
|
||||
pass
|
||||
if next_state:
|
||||
try:
|
||||
self.state['id'] = next_state.id
|
||||
except AttributeError:
|
||||
raise NotImplemented('State id %s is not valid.' % next_state)
|
||||
return when
|
||||
|
||||
func_wrapper.id = func.__name__
|
||||
func_wrapper.is_default = False
|
||||
return func_wrapper
|
||||
|
||||
|
||||
def default_state(func):
|
||||
func.is_default = True
|
||||
return func
|
||||
|
||||
|
||||
class MetaFSM(MetaAgent):
|
||||
def __init__(cls, name, bases, nmspc):
|
||||
super(MetaFSM, cls).__init__(name, bases, nmspc)
|
||||
states = {}
|
||||
# Re-use states from inherited classes
|
||||
default_state = None
|
||||
for i in bases:
|
||||
if isinstance(i, MetaFSM):
|
||||
for state_id, state in i.states.items():
|
||||
if state.is_default:
|
||||
default_state = state
|
||||
states[state_id] = state
|
||||
|
||||
# Add new states
|
||||
for name, func in nmspc.items():
|
||||
if hasattr(func, 'id'):
|
||||
if func.is_default:
|
||||
default_state = func
|
||||
states[func.id] = func
|
||||
cls.default_state = default_state
|
||||
cls.states = states
|
||||
|
||||
|
||||
class FSM(BaseAgent, metaclass=MetaFSM):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FSM, self).__init__(*args, **kwargs)
|
||||
if 'id' not in self.state:
|
||||
self.state['id'] = self.default_state.id
|
||||
|
||||
def step(self):
|
||||
if 'id' in self.state:
|
||||
next_state = self.state['id']
|
||||
elif self.default_state:
|
||||
next_state = self.default_state.id
|
||||
else:
|
||||
raise Exception('{} has no valid state id or default state'.format(self))
|
||||
if next_state not in self.states:
|
||||
raise Exception('{} is not a valid id for {}'.format(next_state, self))
|
||||
self.states[next_state](self)
|
||||
|
||||
|
||||
from .BassModel import *
|
||||
from .BigMarketModel import *
|
||||
from .IndependentCascadeModel import *
|
||||
from .ModelM2 import *
|
||||
from .SentimentCorrelationModel import *
|
||||
from .SISaModel import *
|
||||
from .CounterModel import *
|
||||
from .DrawingAgent import *
|
@ -1,23 +0,0 @@
|
||||
import pandas as pd
|
||||
|
||||
import glob
|
||||
import yaml
|
||||
from os.path import join
|
||||
|
||||
|
||||
def get_data(pattern, process=True, attributes=None):
|
||||
for folder in glob.glob(pattern):
|
||||
config_file = glob.glob(join(folder, '*.yml'))[0]
|
||||
config = yaml.load(open(config_file))
|
||||
for trial_data in sorted(glob.glob(join(folder, '*.environment.csv'))):
|
||||
df = pd.read_csv(trial_data)
|
||||
if process:
|
||||
if attributes is not None:
|
||||
df = df[df['attribute'].isin(attributes)]
|
||||
df = df.pivot_table(values='attribute', index='tstep', columns=['value'], aggfunc='count').fillna(0)
|
||||
yield config_file, df, config
|
||||
|
||||
|
||||
def plot_all(*args, **kwargs):
|
||||
for config_file, df, config in sorted(get_data(*args, **kwargs)):
|
||||
df.plot(title=config['name'])
|
@ -1,190 +0,0 @@
|
||||
import os
|
||||
import csv
|
||||
import weakref
|
||||
from random import random
|
||||
from copy import deepcopy
|
||||
|
||||
import networkx as nx
|
||||
import nxsim
|
||||
|
||||
|
||||
class SoilEnvironment(nxsim.NetworkEnvironment):
|
||||
|
||||
def __init__(self, name=None,
|
||||
network_agents=None,
|
||||
environment_agents=None,
|
||||
states=None,
|
||||
default_state=None,
|
||||
interval=1,
|
||||
*args, **kwargs):
|
||||
self.name = name or 'UnnamedEnvironment'
|
||||
self.states = deepcopy(states) or {}
|
||||
self.default_state = deepcopy(default_state) or {}
|
||||
super().__init__(*args, **kwargs)
|
||||
self._env_agents = {}
|
||||
self._history = {}
|
||||
self.interval = interval
|
||||
self.logger = None
|
||||
# Add environment agents first, so their events get
|
||||
# executed before network agents
|
||||
self.environment_agents = environment_agents or []
|
||||
self.network_agents = network_agents or []
|
||||
self.process(self.save_state())
|
||||
|
||||
@property
|
||||
def agents(self):
|
||||
yield from self.environment_agents
|
||||
yield from self.network_agents
|
||||
|
||||
@property
|
||||
def environment_agents(self):
|
||||
for ref in self._env_agents.values():
|
||||
yield ref()
|
||||
|
||||
@environment_agents.setter
|
||||
def environment_agents(self, environment_agents):
|
||||
# Set up environmental agent
|
||||
self._env_agents = {}
|
||||
for item in environment_agents:
|
||||
kwargs = deepcopy(item)
|
||||
atype = kwargs.pop('agent_type')
|
||||
kwargs['agent_id'] = kwargs.get('agent_id', atype.__name__)
|
||||
kwargs['state'] = kwargs.get('state', {})
|
||||
a = atype(**kwargs,
|
||||
environment=self)
|
||||
self._env_agents[a.id] = weakref.ref(a)
|
||||
|
||||
@property
|
||||
def network_agents(self):
|
||||
for i in self.G.nodes():
|
||||
node = self.G.node[i]
|
||||
if 'agent' in node:
|
||||
yield node['agent']
|
||||
|
||||
@network_agents.setter
|
||||
def network_agents(self, network_agents):
|
||||
for ix in self.G.nodes():
|
||||
i = ix
|
||||
node = self.G.node[i]
|
||||
v = random()
|
||||
found = False
|
||||
for d in network_agents:
|
||||
threshold = d['threshold']
|
||||
if v >= threshold[0] and v < threshold[1]:
|
||||
agent = d['agent_type']
|
||||
state = None
|
||||
if 'state' in d:
|
||||
state = deepcopy(d['state'])
|
||||
else:
|
||||
try:
|
||||
state = self.states[i]
|
||||
except (IndexError, KeyError):
|
||||
state = deepcopy(self.default_state)
|
||||
node['agent'] = agent(environment=self,
|
||||
agent_id=i,
|
||||
state=state)
|
||||
found = True
|
||||
break
|
||||
assert found
|
||||
|
||||
def run(self, *args, **kwargs):
|
||||
self._save_state()
|
||||
super().run(*args, **kwargs)
|
||||
self._save_state()
|
||||
|
||||
def _save_state(self):
|
||||
for agent in self.agents:
|
||||
agent.save_state()
|
||||
self._history[self.now] = deepcopy(self.environment_params)
|
||||
|
||||
def save_state(self):
|
||||
while True:
|
||||
ev = self.event()
|
||||
ev._ok = True
|
||||
# Schedule the event with minimum priority so
|
||||
# that it executes after all agents are done
|
||||
self.schedule(ev, -1, self.interval)
|
||||
yield ev
|
||||
self._save_state()
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.environment_params[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.environment_params[key] = value
|
||||
|
||||
def get_path(self, dir_path=None):
|
||||
dir_path = dir_path or self.sim().dir_path
|
||||
if not os.path.exists(dir_path):
|
||||
os.makedirs(dir_path)
|
||||
return dir_path
|
||||
|
||||
def get_agent(self, agent_id):
|
||||
return self.G.node[agent_id]['agent']
|
||||
|
||||
def get_agents(self):
|
||||
return list(self.agents)
|
||||
|
||||
def dump_csv(self, dir_path=None):
|
||||
csv_name = os.path.join(self.get_path(dir_path),
|
||||
'{}.environment.csv'.format(self.name))
|
||||
|
||||
with open(csv_name, 'w') as f:
|
||||
cr = csv.writer(f)
|
||||
cr.writerow(('agent_id', 'tstep', 'attribute', 'value'))
|
||||
for i in self.history_to_tuples():
|
||||
cr.writerow(i)
|
||||
|
||||
def dump_gexf(self, dir_path=None):
|
||||
G = self.history_to_graph()
|
||||
graph_path = os.path.join(self.get_path(dir_path),
|
||||
self.name+".gexf")
|
||||
nx.write_gexf(G, graph_path, version="1.2draft")
|
||||
|
||||
def history_to_tuples(self):
|
||||
for tstep, state in self._history.items():
|
||||
for attribute, value in state.items():
|
||||
yield ('env', tstep, attribute, value)
|
||||
for agent in self.agents:
|
||||
for tstep, state in agent._history.items():
|
||||
for attribute, value in state.items():
|
||||
yield (agent.id, tstep, attribute, value)
|
||||
|
||||
def history_to_graph(self):
|
||||
G = nx.Graph(self.G)
|
||||
|
||||
for agent in self.agents:
|
||||
|
||||
attributes = {'agent': str(agent.__class__)}
|
||||
lastattributes = {}
|
||||
spells = []
|
||||
lastvisible = False
|
||||
laststep = None
|
||||
for t_step, state in reversed(agent._history.items()):
|
||||
for attribute, value in state.items():
|
||||
if attribute == 'visible':
|
||||
nowvisible = state[attribute]
|
||||
if nowvisible and not lastvisible:
|
||||
laststep = t_step
|
||||
if not nowvisible and lastvisible:
|
||||
spells.append((laststep, t_step))
|
||||
|
||||
lastvisible = nowvisible
|
||||
else:
|
||||
if attribute not in lastattributes or lastattributes[attribute][0] != value:
|
||||
laststep = lastattributes.get(attribute,
|
||||
(None, None))[1]
|
||||
value = (state[attribute], t_step, laststep)
|
||||
key = 'attr_' + attribute
|
||||
if key not in attributes:
|
||||
attributes[key] = list()
|
||||
attributes[key].append(value)
|
||||
lastattributes[attribute] = (state[attribute], t_step)
|
||||
if lastvisible:
|
||||
spells.append((laststep, None))
|
||||
if spells:
|
||||
G.add_node(agent.id, attributes, spells=spells)
|
||||
else:
|
||||
G.add_node(agent.id, attributes)
|
||||
|
||||
return G
|
@ -1 +0,0 @@
|
||||
# General configuration
|
@ -1,241 +0,0 @@
|
||||
import weakref
|
||||
import os
|
||||
import csv
|
||||
import time
|
||||
import yaml
|
||||
import networkx as nx
|
||||
from networkx.readwrite import json_graph
|
||||
|
||||
from copy import deepcopy
|
||||
from random import random
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
import pickle
|
||||
|
||||
from nxsim import NetworkSimulation
|
||||
|
||||
from . import agents, utils, environment, basestring
|
||||
|
||||
|
||||
class SoilSimulation(NetworkSimulation):
|
||||
"""
|
||||
Subclass of nsim.NetworkSimulation with three main differences:
|
||||
1) agent type can be specified by name or by class.
|
||||
2) instead of just one type, an network_agents can be used.
|
||||
The distribution specifies the weight (or probability) of each
|
||||
agent type in the topology. This is an example distribution: ::
|
||||
|
||||
[
|
||||
{'agent_type': 'agent_type_1',
|
||||
'weight': 0.2,
|
||||
'state': {
|
||||
'id': 0
|
||||
}
|
||||
},
|
||||
{'agent_type': 'agent_type_2',
|
||||
'weight': 0.8,
|
||||
'state': {
|
||||
'id': 1
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
In this example, 20% of the nodes will be marked as type
|
||||
'agent_type_1'.
|
||||
3) if no initial state is given, each node's state will be set
|
||||
to `{'id': 0}`.
|
||||
"""
|
||||
def __init__(self, name=None, topology=None, network_params=None,
|
||||
network_agents=None, agent_type=None, states=None,
|
||||
default_state=None, interval=1,
|
||||
dir_path=None, num_trials=3, max_time=100,
|
||||
agent_module=None,
|
||||
environment_agents=None, environment_params=None):
|
||||
|
||||
if topology is None:
|
||||
topology = utils.load_network(network_params,
|
||||
dir_path=dir_path)
|
||||
elif isinstance(topology, basestring) or isinstance(topology, dict):
|
||||
topology = json_graph.node_link_graph(topology)
|
||||
|
||||
self.topology = nx.Graph(topology)
|
||||
self.network_params = network_params
|
||||
self.name = name or 'UnnamedSimulation'
|
||||
self.num_trials = num_trials
|
||||
self.max_time = max_time
|
||||
self.default_state = default_state or {}
|
||||
self.dir_path = dir_path or os.getcwd()
|
||||
self.interval = interval
|
||||
self.environment_params = environment_params or {}
|
||||
|
||||
environment_agents = environment_agents or []
|
||||
self.environment_agents = self._convert_agent_types(environment_agents)
|
||||
|
||||
distro = self.calculate_distribution(network_agents,
|
||||
agent_type)
|
||||
self.network_agents = self._convert_agent_types(distro)
|
||||
|
||||
self.states = self.validate_states(states,
|
||||
topology)
|
||||
|
||||
def calculate_distribution(self,
|
||||
network_agents=None,
|
||||
agent_type=None):
|
||||
if network_agents:
|
||||
network_agents = deepcopy(network_agents)
|
||||
elif agent_type:
|
||||
network_agents = [{'agent_type': agent_type}]
|
||||
else:
|
||||
return []
|
||||
|
||||
# Calculate the thresholds
|
||||
total = sum(x.get('weight', 1) for x in network_agents)
|
||||
acc = 0
|
||||
for v in network_agents:
|
||||
upper = acc + (v.get('weight', 1)/total)
|
||||
v['threshold'] = [acc, upper]
|
||||
acc = upper
|
||||
return network_agents
|
||||
|
||||
def serialize_distribution(self):
|
||||
d = self._convert_agent_types(self.network_agents,
|
||||
to_string=True)
|
||||
for v in d:
|
||||
if 'threshold' in v:
|
||||
del v['threshold']
|
||||
return d
|
||||
|
||||
def _convert_agent_types(self, ind, to_string=False):
|
||||
d = deepcopy(ind)
|
||||
for v in d:
|
||||
agent_type = v['agent_type']
|
||||
if to_string and not isinstance(agent_type, str):
|
||||
v['agent_type'] = str(agent_type.__name__)
|
||||
elif not to_string and isinstance(agent_type, str):
|
||||
v['agent_type'] = agents.agent_types[agent_type]
|
||||
return d
|
||||
|
||||
def validate_states(self, states, topology):
|
||||
states = states or []
|
||||
# Validate states to avoid ignoring states during
|
||||
# initialization
|
||||
if isinstance(states, dict):
|
||||
for x in states:
|
||||
assert x in self.topology.node
|
||||
else:
|
||||
assert len(states) <= len(self.topology)
|
||||
return states
|
||||
|
||||
def run_simulation(self):
|
||||
return self.run()
|
||||
|
||||
def run(self):
|
||||
return list(self.run_simulation_gen())
|
||||
|
||||
def run_simulation_gen(self):
|
||||
with utils.timer('simulation'):
|
||||
for i in range(self.num_trials):
|
||||
yield self.run_trial(i)
|
||||
|
||||
def run_trial(self, trial_id=0):
|
||||
"""Run a single trial of the simulation
|
||||
|
||||
Parameters
|
||||
----------
|
||||
trial_id : int
|
||||
"""
|
||||
# Set-up trial environment and graph
|
||||
print('Trial: {}'.format(trial_id))
|
||||
env_name = '{}_trial_{}'.format(self.name, trial_id)
|
||||
env = environment.SoilEnvironment(name=env_name,
|
||||
topology=self.topology.copy(),
|
||||
initial_time=0,
|
||||
interval=self.interval,
|
||||
network_agents=self.network_agents,
|
||||
states=self.states,
|
||||
default_state=self.default_state,
|
||||
environment_agents=self.environment_agents,
|
||||
**self.environment_params)
|
||||
|
||||
env.sim = weakref.ref(self)
|
||||
# Set up agents on nodes
|
||||
print('\tRunning')
|
||||
with utils.timer('trial'):
|
||||
env.run(until=self.max_time)
|
||||
return env
|
||||
|
||||
def to_dict(self):
|
||||
return self.__getstate__()
|
||||
|
||||
def to_yaml(self):
|
||||
return yaml.dump(self.to_dict())
|
||||
|
||||
def dump_yaml(self, dir_path=None, file_name=None):
|
||||
dir_path = dir_path or self.dir_path
|
||||
if not os.path.exists(dir_path):
|
||||
os.makedirs(dir_path)
|
||||
if not file_name:
|
||||
file_name = os.path.join(dir_path,
|
||||
'{}.dumped.yml'.format(self.name))
|
||||
with open(file_name, 'w') as f:
|
||||
f.write(self.to_yaml())
|
||||
|
||||
def dump_pickle(self, dir_path=None, pickle_name=None):
|
||||
dir_path = dir_path or self.dir_path
|
||||
if not os.path.exists(dir_path):
|
||||
os.makedirs(dir_path)
|
||||
if not pickle_name:
|
||||
pickle_name = os.path.join(dir_path,
|
||||
'{}.simulation.pickle'.format(self.name))
|
||||
with open(pickle_name, 'wb') as f:
|
||||
pickle.dump(self, f)
|
||||
|
||||
def __getstate__(self):
|
||||
state = self.__dict__.copy()
|
||||
state['topology'] = json_graph.node_link_data(self.topology)
|
||||
state['network_agents'] = self.serialize_distribution()
|
||||
state['environment_agents'] = self._convert_agent_types(self.environment_agents,
|
||||
to_string=True)
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.__dict__ = state
|
||||
self.topology = json_graph.node_link_graph(state['topology'])
|
||||
self.network_agents = self._convert_agent_types(self.network_agents)
|
||||
self.environment_agents = self._convert_agent_types(self.environment_agents)
|
||||
return state
|
||||
|
||||
|
||||
def from_config(config, G=None):
|
||||
config = list(utils.load_config(config))
|
||||
if len(config) > 1:
|
||||
raise AttributeError('Provide only one configuration')
|
||||
config = config[0][0]
|
||||
sim = SoilSimulation(**config)
|
||||
return sim
|
||||
|
||||
|
||||
def run_from_config(*configs, dump=True, results_dir=None, timestamp=False):
|
||||
if not results_dir:
|
||||
results_dir = 'soil_output'
|
||||
for config_def in configs:
|
||||
for config, cpath in utils.load_config(config_def):
|
||||
name = config.get('name', 'unnamed')
|
||||
print("Using config(s): {name}".format(name=name))
|
||||
|
||||
sim = SoilSimulation(**config)
|
||||
if timestamp:
|
||||
sim_folder = '{}_{}'.format(sim.name,
|
||||
time.strftime("%Y-%m-%d_%H:%M:%S"))
|
||||
else:
|
||||
sim_folder = sim.name
|
||||
dir_path = os.path.join(results_dir,
|
||||
sim_folder)
|
||||
results = sim.run_simulation()
|
||||
|
||||
if dump:
|
||||
sim.dump_pickle(dir_path)
|
||||
sim.dump_yaml(dir_path)
|
||||
for env in results:
|
||||
env.dump_gexf(dir_path)
|
||||
env.dump_csv(dir_path)
|
@ -1,61 +0,0 @@
|
||||
import os
|
||||
import yaml
|
||||
from time import time
|
||||
from glob import glob
|
||||
|
||||
import networkx as nx
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
|
||||
def load_network(network_params, dir_path=None):
|
||||
path = network_params.get('path', None)
|
||||
if path:
|
||||
if dir_path and not os.path.isabs(path):
|
||||
path = os.path.join(dir_path, path)
|
||||
extension = os.path.splitext(path)[1][1:]
|
||||
kwargs = {}
|
||||
if extension == 'gexf':
|
||||
kwargs['version'] = '1.2draft'
|
||||
kwargs['node_type'] = int
|
||||
try:
|
||||
method = getattr(nx.readwrite, 'read_' + extension)
|
||||
except AttributeError:
|
||||
raise AttributeError('Unknown format')
|
||||
return method(path, **kwargs)
|
||||
|
||||
net_args = network_params.copy()
|
||||
net_type = net_args.pop('generator')
|
||||
|
||||
method = getattr(nx.generators, net_type)
|
||||
return method(**net_args)
|
||||
|
||||
|
||||
def load_file(infile):
|
||||
with open(infile, 'r') as f:
|
||||
return list(yaml.load_all(f))
|
||||
|
||||
|
||||
def load_files(*patterns):
|
||||
for pattern in patterns:
|
||||
for i in glob(pattern):
|
||||
for config in load_file(i):
|
||||
yield config, os.path.abspath(i)
|
||||
|
||||
|
||||
def load_config(config):
|
||||
if isinstance(config, dict):
|
||||
yield config, None
|
||||
else:
|
||||
yield from load_files(config)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def timer(name='task', pre="", function=print, to_object=None):
|
||||
start = time()
|
||||
yield start
|
||||
end = time()
|
||||
function('{}Finished {} in {} seconds'.format(pre, name, str(end-start)))
|
||||
if to_object:
|
||||
to_object.start = start
|
||||
to_object.end = end
|
@ -1,225 +0,0 @@
|
||||
from unittest import TestCase
|
||||
|
||||
import os
|
||||
import yaml
|
||||
from functools import partial
|
||||
|
||||
from os.path import join
|
||||
from soil import simulation, agents, utils
|
||||
|
||||
|
||||
ROOT = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
EXAMPLES = join(ROOT, '..', 'examples')
|
||||
|
||||
|
||||
class TestMain(TestCase):
|
||||
|
||||
def test_load_graph(self):
|
||||
"""
|
||||
Load a graph from file if the extension is known.
|
||||
Raise an exception otherwise.
|
||||
"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
}
|
||||
}
|
||||
G = utils.load_network(config['network_params'])
|
||||
assert G
|
||||
assert len(G) == 2
|
||||
with self.assertRaises(AttributeError):
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'unknown.extension')
|
||||
}
|
||||
}
|
||||
G = utils.load_network(config['network_params'])
|
||||
print(G)
|
||||
|
||||
def test_generate_barabasi(self):
|
||||
"""
|
||||
If no path is given, a generator and network parameters
|
||||
should be used to generate a network
|
||||
"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'generator': 'barabasi_albert_graph'
|
||||
}
|
||||
}
|
||||
with self.assertRaises(TypeError):
|
||||
G = utils.load_network(config['network_params'])
|
||||
config['network_params']['n'] = 100
|
||||
config['network_params']['m'] = 10
|
||||
G = utils.load_network(config['network_params'])
|
||||
assert len(G) == 100
|
||||
|
||||
def test_empty_simulation(self):
|
||||
"""A simulation with a base behaviour should do nothing"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'agent_type': 'NetworkAgent',
|
||||
'environment_params': {
|
||||
}
|
||||
}
|
||||
s = simulation.from_config(config)
|
||||
s.run_simulation()
|
||||
|
||||
def test_counter_agent(self):
|
||||
"""
|
||||
The initial states should be applied to the agent and the
|
||||
agent should be able to update its state."""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'agent_type': 'CounterModel',
|
||||
'states': [{'neighbors': 10}, {'total': 12}],
|
||||
'max_time': 2,
|
||||
'num_trials': 1,
|
||||
'environment_params': {
|
||||
}
|
||||
}
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation()[0]
|
||||
assert env.get_agent(0)['neighbors', 0] == 10
|
||||
assert env.get_agent(0)['neighbors', 1] == 1
|
||||
assert env.get_agent(1)['total', 0] == 12
|
||||
assert env.get_agent(1)['neighbors', 1] == 1
|
||||
|
||||
def test_counter_agent_history(self):
|
||||
"""
|
||||
The evolution of the state should be recorded in the logging agent
|
||||
"""
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'network_agents': [{
|
||||
'agent_type': 'AggregatedCounter',
|
||||
'weight': 1,
|
||||
'state': {'id': 0}
|
||||
|
||||
}],
|
||||
'max_time': 10,
|
||||
'environment_params': {
|
||||
}
|
||||
}
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation()[0]
|
||||
for agent in env.network_agents:
|
||||
last = 0
|
||||
assert len(agent._history) == 11
|
||||
for step, total in agent['total', None].items():
|
||||
if step > 0:
|
||||
assert total == last + 2
|
||||
last = total
|
||||
|
||||
def test_custom_agent(self):
|
||||
"""Allow for search of neighbors with a certain state_id"""
|
||||
class CustomAgent(agents.NetworkAgent):
|
||||
def step(self):
|
||||
self.state['neighbors'] = self.count_agents(state_id=0,
|
||||
limit_neighbors=True)
|
||||
config = {
|
||||
'network_params': {
|
||||
'path': join(ROOT, 'test.gexf')
|
||||
},
|
||||
'network_agents': [{
|
||||
'agent_type': CustomAgent,
|
||||
'weight': 1,
|
||||
'state': {'id': 0}
|
||||
|
||||
}],
|
||||
'max_time': 10,
|
||||
'environment_params': {
|
||||
}
|
||||
}
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation()[0]
|
||||
assert env.get_agent(0).state['neighbors'] == 1
|
||||
|
||||
def test_torvalds_example(self):
|
||||
"""A complete example from a documentation should work."""
|
||||
config = utils.load_file(join(EXAMPLES, 'torvalds.yml'))[0]
|
||||
config['network_params']['path'] = join(EXAMPLES,
|
||||
config['network_params']['path'])
|
||||
s = simulation.from_config(config)
|
||||
env = s.run_simulation()[0]
|
||||
for a in env.network_agents:
|
||||
skill_level = a.state['skill_level']
|
||||
if a.id == 'Torvalds':
|
||||
assert skill_level == 'God'
|
||||
assert a.state['total'] == 3
|
||||
assert a.state['neighbors'] == 2
|
||||
elif a.id == 'balkian':
|
||||
assert skill_level == 'developer'
|
||||
assert a.state['total'] == 3
|
||||
assert a.state['neighbors'] == 1
|
||||
else:
|
||||
assert skill_level == 'beginner'
|
||||
assert a.state['total'] == 3
|
||||
assert a.state['neighbors'] == 1
|
||||
|
||||
def test_yaml(self):
|
||||
"""
|
||||
The YAML version of a newly created simulation
|
||||
should be equivalent to the configuration file used
|
||||
"""
|
||||
with utils.timer('loading'):
|
||||
config = utils.load_file(join(EXAMPLES, 'complete.yml'))[0]
|
||||
s = simulation.from_config(config)
|
||||
with utils.timer('serializing'):
|
||||
serial = s.to_yaml()
|
||||
with utils.timer('recovering'):
|
||||
recovered = yaml.load(serial)
|
||||
with utils.timer('deleting'):
|
||||
del recovered['topology']
|
||||
assert config == recovered
|
||||
|
||||
def test_configuration_changes(self):
|
||||
"""
|
||||
The configuration should not change after running
|
||||
the simulation.
|
||||
"""
|
||||
config = utils.load_file('examples/complete.yml')[0]
|
||||
s = simulation.from_config(config)
|
||||
for i in range(5):
|
||||
s.run_simulation()
|
||||
nconfig = s.to_dict()
|
||||
del nconfig['topology']
|
||||
assert config == nconfig
|
||||
|
||||
def test_examples(self):
|
||||
"""
|
||||
Make sure all examples in the examples folder are correct
|
||||
"""
|
||||
|
||||
|
||||
def make_example_test(path, config):
|
||||
def wrapped(self):
|
||||
root = os.getcwd()
|
||||
os.chdir(os.path.dirname(path))
|
||||
s = simulation.from_config(config)
|
||||
envs = s.run_simulation()
|
||||
for env in envs:
|
||||
n = config['network_params'].get('n', None)
|
||||
if n is not None:
|
||||
assert len(env.get_agents()) == n
|
||||
os.chdir(root)
|
||||
return wrapped
|
||||
|
||||
|
||||
def add_example_tests():
|
||||
for config, path in utils.load_config(join(EXAMPLES, '*.yml')):
|
||||
p = make_example_test(path=path, config=config)
|
||||
fname = os.path.basename(path)
|
||||
p.__name__ = 'test_example_file_%s' % fname
|
||||
p.__doc__ = '%s should be a valid configuration' % fname
|
||||
setattr(TestMain, p.__name__, p)
|
||||
del p
|
||||
|
||||
|
||||
add_example_tests()
|
@ -1 +0,0 @@
|
||||
This is an unknown file
|