1
0
mirror of https://github.com/gsi-upm/soil synced 2024-11-13 06:52:28 +00:00
soil/soil.py

493 lines
19 KiB
Python

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
import math
import json
settings.init() # Loads all the data from settings
####################
# Network creation #
####################
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)
# More types of networks can be added here
##############################
# Variables initializitation #
##############################
myList=[] # List just for debugging
networkStatus=[] # This list will contain the status of every node of the network
emotionStatus=[]
enterprise1Status=[]
enterprise2Status=[]
allEnterprisesEmotionList = {}
for x in range(0, settings.number_of_nodes):
networkStatus.append({'id':x})
emotionStatus.append({'id':x})
enterprise1Status.append({'id':x})
enterprise2Status.append({'id':x})
for enterpriseIndex in range(0,len(settings.tweet_probability_about)):
allEnterprisesEmotionList['enterprise'+str(enterpriseIndex)] = enterprise1Status
# for node in range(0, settings.number_of_nodes):
# allEnterprisesEmotionList['enterprise'+str(enterpriseIndex)].update({'id':node})
#print(allEnterprisesEmotionList)
# 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, just for zombie model
#init_states[5] = {'id': 1}
#init_states[3] = {'id': 1}
####################
# Available models #
####################
class BigMarketModel(BaseNetworkAgent):
number_of_enterprises = 0
def __init__(self, environment=None, agent_id=0, state=()):
super().__init__(environment=environment, agent_id=agent_id, state=state)
self.time_awareness = 0
self.type = ""
self.number_of_enterprises = len(settings.tweet_probability_about)
if self.id < self.number_of_enterprises: #Empresas
self.state['id']=self.id
self.type="Enterprise"
self.tweet_probability = settings.tweet_probability_enterprises[self.id]
else: #Usuarios normales
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 #Lista
self.sentiment_about = settings.sentiment_about #Lista
#Inicializacion de visualizacion
for enterpriseIndex in range(0,len(settings.tweet_probability_about)):
allEnterprisesEmotionList['enterprise'+str(enterpriseIndex)][self.id].update({0:self.sentiment_about[enterpriseIndex]})
#print(allEnterprisesEmotionList)
#networkStatus[self.id][self.env.now]=self.state['id']
#emotionStatus[self.id][self.env.now]=0
def run(self):
while True:
if(self.id < self.number_of_enterprises): # Empresa
self.enterpriseBehaviour()
else: # Usuario
self.userBehaviour()
yield self.env.timeout(settings.timeout)
def enterpriseBehaviour(self):
if random.random()< self.tweet_probability: #Twittea
aware_neighbors = self.get_neighboring_agents(state_id=self.number_of_enterprises) #Nodos vecinos usuarios
for x in aware_neighbors:
if random.uniform(0,10) < 5:
x.sentiment_about[self.id] += 0.1 #Aumenta para empresa
else:
x.sentiment_about[self.id] -= 0.1 #Reduce para empresa
# 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
#Visualización
enterpriseEmotion=[]
if self.id < self.number_of_enterprises:
#try:
#enterpriseEmotion = allEnterprisesEmotionList[self.id] #Cogemos la lista si ya ha sido creada
#print (enterpriseEmotion)
#except IndexError: # Si no existe la inicializamos
# for y in range(0, settings.number_of_nodes):
# enterpriseEmotion.append({'id':y})
#enterpriseEmotion[x.id][self.env.now]=x.sentiment_about[self.id]
#allEnterprisesEmotionList.insert(self.id,enterpriseEmotion) #Guardamos el valor
#enterpriseEmotion[:] = [] #Vaciamos la lista
allEnterprisesEmotionList['enterprise'+str(self.id)][x.id].update({self.env.now:x.sentiment_about[self.id]})
#if self.id == 0:
# enterprise1Status[x.id][self.env.now]=x.sentiment_about[self.id]
#if self.id == 1:
# enterprise2Status[x.id][self.env.now]=x.sentiment_about[self.id]
def userBehaviour(self):
if random.random() < self.tweet_probability: #Twittea
if random.random() < self.tweet_relevant_probability: #Twittea algo relevante
#Probabilidad de tweet para cada empresa
for i in range(len(self.tweet_probability_about)):
random_num = random.random()
if random_num < self.tweet_probability_about[i]:
#Se ha cumplido la condicion, evaluo los sentimientos hacia esa empresa
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=2) #Nodos vecinos usuarios
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
#Visualización
# enterpriseEmotion=[]
# try:
# enterpriseEmotion = allEnterprisesEmotionList[self.id] #Cogemos la lista si ya ha sido creada
# except IndexError: # Si no existe la inicializamos
# for y in range(0, settings.number_of_nodes):
# enterpriseEmotion.append({'id':y})
# enterpriseEmotion[x.id][self.env.now]=x.sentiment_about[enterprise]
# allEnterprisesEmotionList.insert(enterprise,enterpriseEmotion) #Guardamos el valor
# enterpriseEmotion[:] = [] #Vaciamos la lista
#if enterprise == 0:
# enterprise1Status[x.id][self.env.now]=x.sentiment_about[enterprise]
#if enterprise == 1:
# enterprise2Status[x.id][self.env.now]=x.sentiment_about[enterprise]
allEnterprisesEmotionList['enterprise'+str(enterprise)][x.id].update({self.env.now:x.sentiment_about[enterprise]})
def checkLimits(sentimentValue):
if sentimentValue > 1:
return 1
if sentimentValue < -1:
return -1
################################################
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): #En este modelo tenemos 4 sentimientos
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:
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)
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)
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
##############
# Simulation #
##############
sim = NetworkSimulation(topology=G, states=init_states, agent_type=BigMarketModel,
max_time=settings.max_time, num_trials=settings.num_trials, logging_interval=1.0)
sim.run_simulation()
###########
# Results #
###########
myList = sorted(myList, key=int)
#print("Los zombies son: " + str(myList))
trial = BaseLoggingAgent.open_trial_state_history(dir_path='sim_01', trial_id=0)
status_census = [sum([1 for node_id, state in g.items() if state['id'] == 1]) for t,g in trial.items()]
#################
# Visualization #
#################
# print("Empresa1")
# print (enterprise1Status)
# print("Empresa2")
# print (enterprise2Status)
for y in allEnterprisesEmotionList:
for x in range(0, settings.number_of_nodes):
emotionStatusAux=[]
enterpriseStatus = allEnterprisesEmotionList[y]
for tiempo in enterpriseStatus[x]:
if tiempo != 'id':
prec = 2
output = math.floor(enterpriseStatus[x][tiempo] * (10 ** prec)) / (10 ** prec) #Para tener 2 decimales solo
emotionStatusAux.append((output,tiempo,None))
keyword = 'enterprise'+str(y)+'Emotion'
G.add_node(x, keyword = emotionStatusAux)
# for x in range(0, settings.number_of_nodes):
# emotionStatusAux2=[]
# for tiempo in enterprise2Status[x]:
# if tiempo != 'id':
# prec = 2
# output = math.floor(enterprise2Status[x][tiempo] * (10 ** prec)) / (10 ** prec) #Para tener 2 decimales solo
# emotionStatusAux2.append((output,tiempo,None))
# G.add_node(x, enterprise2emotion= emotionStatusAux2)
print("Done!")
#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, status= networkStatusAux)
#print(networkStatus)
print(allEnterprisesEmotionList)
with open('data.txt', 'w') as outfile:
json.dump(allEnterprisesEmotionList, outfile)
nx.write_gexf(G,"test.gexf", version="1.2draft")
plt.plot(status_census)
plt.draw() # pyplot draw()
plt.savefig("status.png")
#print(networkStatus)
#nx.draw(G)
#plt.show()
#plt.savefig("path.png")