You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
soil/soil_tutorial.ipynb

556 lines
19 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# SOIL Tutorial"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebook contains a tutorial to learn how to use the SOcial network sImuLator (SOIL) written in Python. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"SOIL is based in 3 main files:\n",
"* __soil.py__: It's the main file of SOIL. The network creation, simulation and visualization are done in this file.\n",
"- __models.py__: All the spread models already implemented are stored in this file.\n",
"+ __settings.py__: This file contains every variable needed in the simulation in order to be modified easily."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Soil.py"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Imports and data initialization"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First of all, you need to make all the imports. This simulator is based on [nxsim](https://pypi.python.org/pypi/nxsim), using [networkx](https://networkx.github.io/) for network management. We will also include the models and settings files where the spread models and initialization variables are stored."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"from nxsim import NetworkSimulation\n",
"import numpy\n",
"import networkx as nx\n",
"import settings\n",
"import models\n",
"from models import *\n",
"import math\n",
"import json\n",
"\n",
"settings.init() # Loads all the data from settings\n",
"models.init() # Loads the models and network variables"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Network creation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using a parameter provided in the settings file, we can choose what type of network we want to create, as well as the number of nodes and some other parameters. More types of networks can be implemented using [networkx](https://networkx.github.io/)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"if settings.network_type == 0:\n",
" G = nx.complete_graph(settings.number_of_nodes)\n",
"if settings.network_type == 1:\n",
" G = nx.barabasi_albert_graph(settings.number_of_nodes,10)\n",
"if settings.network_type == 2:\n",
" G = nx.margulis_gabber_galil_graph(settings.number_of_nodes, None)\n",
"# More types of networks can be added here"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Simulation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The simulation starts with the following code. The user can provide the network topology, the maximum time of simulation, the spread model to be used as well as other parameters."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Starting simulations...\n",
"---Trial 0---\n",
"Setting up agents...\n",
"Written 50 items to pickled binary file: sim_01/log.0.state.pickled\n",
"Simulation completed.\n"
]
}
],
"source": [
"sim = NetworkSimulation(topology=G, states=init_states, agent_type=ControlModelM2,\n",
" max_time=settings.max_time, num_trials=settings.num_trials, logging_interval=1.0)\n",
"\n",
"\n",
"sim.run_simulation()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Visualization"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to analyse the results of the simulation. We include them in the topology and a .gexf file is generated. This allows the user to picture the network in [Gephi](https://gephi.org/). A JSON file is also generated to permit further analysis.\n",
"\n",
"This is done with the following code:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Done!\n"
]
}
],
"source": [
"for x in range(0, settings.number_of_nodes):\n",
" for enterprise in models.networkStatus[\"agent_%s\"%x]:\n",
" emotionStatusAux=[]\n",
" for time in models.networkStatus[\"agent_%s\"%x][enterprise]:\n",
" prec = 2\n",
" output = math.floor(models.networkStatus[\"agent_%s\"%x][enterprise][time] * (10 ** prec)) / (10 ** prec) #Para tener 2 decimales solo\n",
" emotionStatusAux.append((output,time,None))\n",
" attributes = {}\n",
" attributes[enterprise] = emotionStatusAux\n",
" G.add_node(x, attributes)\n",
"\n",
"\n",
"print(\"Done!\")\n",
"\n",
"with open('data.txt', 'w') as outfile:\n",
" json.dump(models.networkStatus, outfile, sort_keys=True, indent=4, separators=(',', ': '))\n",
"\n",
"nx.write_gexf(G,\"test.gexf\", version=\"1.2draft\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That's only the basic visualization. Everything you need can be implemented as well. For example:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"x_values = []\n",
"infected_values = []\n",
"neutral_values = []\n",
"cured_values = []\n",
"vaccinated_values = []\n",
"\n",
"attribute_plot = 'status'\n",
"for time in range(0, settings.max_time):\n",
" value_infected = 0\n",
" value_neutral = 0\n",
" value_cured = 0\n",
" value_vaccinated = 0\n",
" real_time = time * settings.timeout\n",
" activity= False\n",
" for x in range(0, settings.number_of_nodes):\n",
" if attribute_plot in models.networkStatus[\"agent_%s\" % x]:\n",
" if real_time in models.networkStatus[\"agent_%s\" % x][attribute_plot]:\n",
" if models.networkStatus[\"agent_%s\" % x][attribute_plot][real_time] == 1: ##Represent infected\n",
" value_infected += 1\n",
" activity = True\n",
" if models.networkStatus[\"agent_%s\" % x][attribute_plot][real_time] == 0: ##Represent neutrals\n",
" value_neutral += 1\n",
" activity = True\n",
" if models.networkStatus[\"agent_%s\" % x][attribute_plot][real_time] == 2: ##Represent cured\n",
" value_cured += 1\n",
" activity = True\n",
" if models.networkStatus[\"agent_%s\" % x][attribute_plot][real_time] == 3: ##Represent vaccinated\n",
" value_vaccinated += 1\n",
" activity = True\n",
"\n",
" if activity:\n",
" x_values.append(real_time)\n",
" infected_values.append(value_infected)\n",
" neutral_values.append(value_neutral)\n",
" cured_values.append(value_cured)\n",
" vaccinated_values.append(value_vaccinated)\n",
" activity=False\n",
"\n",
"infected_line = plt.plot(x_values,infected_values,label='Infected')\n",
"neutral_line = plt.plot(x_values,neutral_values, label='Neutral')\n",
"cured_line = plt.plot(x_values,cured_values, label='Cured')\n",
"vaccinated_line = plt.plot(x_values,vaccinated_values, label='Vaccinated')\n",
"plt.legend()\n",
"plt.savefig('control_model.png')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![alt text](https://raw.githubusercontent.com/gsi-upm/soil/master/control_model.png \"Control model\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Models.py"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Imports and initialization"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from nxsim import BaseNetworkAgent\n",
"import numpy as np\n",
"import random\n",
"import settings\n",
"\n",
"settings.init()\n",
"\n",
"##############################\n",
"# Variables initializitation #\n",
"##############################\n",
"def init():\n",
" global networkStatus\n",
" networkStatus = {} # Dict that will contain the status of every agent in the network\n",
"\n",
"sentimentCorrelationNodeArray=[]\n",
"for x in range(0, settings.number_of_nodes):\n",
" sentimentCorrelationNodeArray.append({'id':x})\n",
"# Initialize agent states. Let's assume everyone is normal.\n",
"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"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Base behaviour"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Every spread model used in SOIL should extend the base behaviour class. By doing this the exportation of the attributes values will be automatic. This feature will be explained in the Spread Models section. The class looks like this:"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class BaseBehaviour(BaseNetworkAgent):\n",
" def __init__(self, environment=None, agent_id=0, state=()):\n",
" super().__init__(environment=environment, agent_id=agent_id, state=state)\n",
" self._attrs = {}\n",
"\n",
" @property\n",
" def attrs(self):\n",
" now = self.env.now\n",
" if now not in self._attrs:\n",
" self._attrs[now] = {}\n",
" return self._attrs[now]\n",
"\n",
" @attrs.setter\n",
" def attrs(self, value):\n",
" self._attrs[self.env.now] = value\n",
"\n",
" def run(self):\n",
" while True:\n",
" self.step(self.env.now)\n",
" yield self.env.timeout(settings.timeout)\n",
"\n",
" def step(self, now):\n",
" networkStatus['agent_%s'% self.id] = self.a_json()\n",
"\n",
" def a_json(self):\n",
" final = {}\n",
" for stamp, attrs in self._attrs.items():\n",
" for a in attrs:\n",
" if a not in final:\n",
" final[a] = {}\n",
" final[a][stamp] = attrs[a]\n",
" return final\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Spread models"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Every model to be implemented must include an init and a step function. Depending on your model, you would need different attributes. If you want them to be automatic exported for a further analysis, you must name them like this *self.attrs['name_of_attribute']*. Moreover, the last thing you should do inside the step function is call the following method *super().step(now)*. This call will store the values.\n",
"\n",
"Some other tips:\n",
"* __self.state['id']__: To check the id of the current agent/node.\n",
"* __self.get_neighboring_agents(state_id=x)__: Returns the neighbours agents/nodes with the id provided\n",
"\n",
"An example of a spread model already implemented and working:\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"class ControlModelM2(BaseBehaviour):\n",
" #Init infected\n",
" init_states[random.randint(0,settings.number_of_nodes-1)] = {'id':1}\n",
" init_states[random.randint(0,settings.number_of_nodes-1)] = {'id':1}\n",
"\n",
" # Init beacons\n",
" init_states[random.randint(0, settings.number_of_nodes-1)] = {'id': 4}\n",
" init_states[random.randint(0, settings.number_of_nodes-1)] = {'id': 4}\n",
" def __init__(self, environment=None, agent_id=0, state=()):\n",
" super().__init__(environment=environment, agent_id=agent_id, state=state)\n",
"\n",
" self.prob_neutral_making_denier = np.random.normal(settings.prob_neutral_making_denier, settings.standard_variance)\n",
"\n",
" self.prob_infect = np.random.normal(settings.prob_infect, settings.standard_variance)\n",
"\n",
" self.prob_cured_healing_infected = np.random.normal(settings.prob_cured_healing_infected, settings.standard_variance)\n",
" self.prob_cured_vaccinate_neutral = np.random.normal(settings.prob_cured_vaccinate_neutral, settings.standard_variance)\n",
"\n",
" self.prob_vaccinated_healing_infected = np.random.normal(settings.prob_vaccinated_healing_infected, settings.standard_variance)\n",
" self.prob_vaccinated_vaccinate_neutral = np.random.normal(settings.prob_vaccinated_vaccinate_neutral, settings.standard_variance)\n",
" self.prob_generate_anti_rumor = np.random.normal(settings.prob_generate_anti_rumor, settings.standard_variance)\n",
"\n",
" def step(self, now):\n",
"\n",
" if self.state['id'] == 0: #Neutral\n",
" self.neutral_behaviour()\n",
" elif self.state['id'] == 1: #Infected\n",
" self.infected_behaviour()\n",
" elif self.state['id'] == 2: #Cured\n",
" self.cured_behaviour()\n",
" elif self.state['id'] == 3: #Vaccinated\n",
" self.vaccinated_behaviour()\n",
" elif self.state['id'] == 4: #Beacon-off\n",
" self.beacon_off_behaviour()\n",
" elif self.state['id'] == 5: #Beacon-on\n",
" self.beacon_on_behaviour()\n",
"\n",
" self.attrs['status'] = self.state['id']\n",
" super().step(now)\n",
"\n",
"\n",
" def neutral_behaviour(self):\n",
"\n",
" # Infected\n",
" infected_neighbors = self.get_neighboring_agents(state_id=1)\n",
" if len(infected_neighbors)>0:\n",
" if random.random() < self.prob_neutral_making_denier:\n",
" self.state['id'] = 3 # Vaccinated making denier\n",
"\n",
" def infected_behaviour(self):\n",
"\n",
" # Neutral\n",
" neutral_neighbors = self.get_neighboring_agents(state_id=0)\n",
" for neighbor in neutral_neighbors:\n",
" if random.random() < self.prob_infect:\n",
" neighbor.state['id'] = 1 # Infected\n",
"\n",
" def cured_behaviour(self):\n",
"\n",
" # Vaccinate\n",
" neutral_neighbors = self.get_neighboring_agents(state_id=0)\n",
" for neighbor in neutral_neighbors:\n",
" if random.random() < self.prob_cured_vaccinate_neutral:\n",
" neighbor.state['id'] = 3 # Vaccinated\n",
"\n",
" # Cure\n",
" infected_neighbors = self.get_neighboring_agents(state_id=1)\n",
" for neighbor in infected_neighbors:\n",
" if random.random() < self.prob_cured_healing_infected:\n",
" neighbor.state['id'] = 2 # Cured\n",
"\n",
"\n",
" def vaccinated_behaviour(self):\n",
"\n",
" # Cure\n",
" infected_neighbors = self.get_neighboring_agents(state_id=1)\n",
" for neighbor in infected_neighbors:\n",
" if random.random() < self.prob_cured_healing_infected:\n",
" neighbor.state['id'] = 2 # Cured\n",
"\n",
"\n",
" # Vaccinate\n",
" neutral_neighbors = self.get_neighboring_agents(state_id=0)\n",
" for neighbor in neutral_neighbors:\n",
" if random.random() < self.prob_cured_vaccinate_neutral:\n",
" neighbor.state['id'] = 3 # Vaccinated\n",
"\n",
" # Generate anti-rumor\n",
" infected_neighbors_2 = self.get_neighboring_agents(state_id=1)\n",
" for neighbor in infected_neighbors_2:\n",
" if random.random() < self.prob_generate_anti_rumor:\n",
" neighbor.state['id'] = 2 # Cured\n",
"\n",
" def beacon_off_behaviour(self):\n",
" infected_neighbors = self.get_neighboring_agents(state_id=1)\n",
" if len(infected_neighbors) > 0:\n",
" self.state['id'] == 5 #Beacon on\n",
"\n",
" def beacon_on_behaviour(self):\n",
"\n",
" # Cure (M2 feature added)\n",
" infected_neighbors = self.get_neighboring_agents(state_id=1)\n",
" for neighbor in infected_neighbors:\n",
" if random.random() < self.prob_generate_anti_rumor:\n",
" neighbor.state['id'] = 2 # Cured\n",
" neutral_neighbors_infected = neighbor.get_neighboring_agents(state_id=0)\n",
" for neighbor in neutral_neighbors_infected:\n",
" if random.random() < self.prob_generate_anti_rumor:\n",
" neighbor.state['id'] = 3 # Vaccinated\n",
" infected_neighbors_infected = neighbor.get_neighboring_agents(state_id=1)\n",
" for neighbor in infected_neighbors_infected:\n",
" if random.random() < self.prob_generate_anti_rumor:\n",
" neighbor.state['id'] = 2 # Cured\n",
"\n",
"\n",
" # Vaccinate\n",
" neutral_neighbors = self.get_neighboring_agents(state_id=0)\n",
" for neighbor in neutral_neighbors:\n",
" if random.random() < self.prob_cured_vaccinate_neutral:\n",
" neighbor.state['id'] = 3 # Vaccinated"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Settings.py"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This file contains all the variables that can be modified from the simulation. In case of implementing a new spread model, the new variables should be also included in this file."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.4.0"
}
},
"nbformat": 4,
"nbformat_minor": 0
}