# 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 import logging from collections import OrderedDict from copy import deepcopy from functools import partial 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. """ defaults = {} def __init__(self, **kwargs): self._neighbors = None self.alive = True state = deepcopy(self.defaults) state.update(kwargs.pop('state', {})) kwargs['state'] = state super().__init__(**kwargs) if not hasattr(self, 'level'): self.level = logging.DEBUG self.logger = logging.getLogger('Agent-{}'.format(self.id)) self.logger.setLevel(self.level) def __getitem__(self, key): if isinstance(key, tuple): k, t_step = key return self.env[self.id, t_step, k] return self.state.get(key, None) def __delitem__(self, key): del self.state[key] def __contains__(self, key): return key in self.state def __setitem__(self, key, value): self.state[key] = value def get(self, key, default=None): return self[key] if key in self else default @property def now(self): try: return self.env.now except AttributeError: # No environment return None def run(self): interval = self.env.interval while self.alive: res = self.step() yield res or self.env.timeout(interval) def die(self, remove=False): self.alive = False if remove: super().die() def step(self): pass def to_json(self): return json.dumps(self.state) 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 len(super().get_agents(state_id, limit_neighbors=True)) def get_agents(self, state_id=None, limit_neighbors=False, iterator=False, **kwargs): if limit_neighbors: agents = super().get_agents(state_id, limit_neighbors) else: agents = filter(lambda x: state_id is None or x.state.get('id', None) == state_id, self.env.agents) def matches_all(agent): state = agent.state for k, v in kwargs.items(): if state.get(k, None) != v: return False return True f = filter(matches_all, agents) if iterator: return f return list(f) def log(self, message, *args, level=logging.INFO, **kwargs): message = message + " ".join(str(i) for i in args) message = "\t@{:>5}:\t{}".format(self.now, message) for k, v in kwargs: message += " {k}={v} ".format(k, v) extra = {} extra['now'] = self.now extra['id'] = self.id return self.logger.log(level, message, extra=extra) def debug(self, *args, **kwargs): return self.log(*args, level=logging.DEBUG, **kwargs) def info(self, *args, **kwargs): return self.log(*args, level=logging.INFO, **kwargs) 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 ValueError('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) def set_state(self, state): if hasattr(state, 'id'): state = state.id if state not in self.states: raise ValueError('{} is not a valid state'.format(state)) self.state['id'] = state from .BassModel import * from .BigMarketModel import * from .IndependentCascadeModel import * from .ModelM2 import * from .SentimentCorrelationModel import * from .SISaModel import * from .CounterModel import * from .DrawingAgent import *