1
0
mirror of https://github.com/gsi-upm/soil synced 2025-08-24 12:02:20 +00:00
* Pandas integration
* Improved environment
* Logging and data dumps
* Tests
* Added Finite State Machine models
* Rewritten ipython notebook and documentation
This commit is contained in:
J. Fernando Sánchez
2017-06-20 17:45:43 +02:00
parent 764177c634
commit e1be3a730e
110 changed files with 32706 additions and 57437 deletions

View File

@@ -0,0 +1,123 @@
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)

40
soil/agents/BassModel.py Normal file
View File

@@ -0,0 +1,40 @@
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

View File

@@ -0,0 +1,102 @@
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]

View File

@@ -0,0 +1,31 @@
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

View File

@@ -0,0 +1,18 @@
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"))

View File

@@ -0,0 +1,49 @@
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

242
soil/agents/ModelM2.py Normal file
View File

@@ -0,0 +1,242 @@
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

93
soil/agents/SISaModel.py Normal file
View File

@@ -0,0 +1,93 @@
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

View File

@@ -0,0 +1,102 @@
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']

166
soil/agents/__init__.py Normal file
View File

@@ -0,0 +1,166 @@
# 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 *