Source code for abm.entities
# -*- coding: utf-8 -*-
"""
abm.entities
~~~~~~~~~~~~
Individual objects from agent world
"""
from uuid import uuid4
from random import choice
from abm.learners import SoftmaxLearnerMixin, DunceMixin
[docs]class Task(object):
"""Represents a message to be routed."""
def __init__(self, target, features=None):
self.target = target
self.id = uuid4()
self.value = 1.
if features is not None:
self.features = features
[docs]class Entity(object):
"""An entity in our world"""
def __init__(self, environment, index):
self.index = index
self.environment = environment
self.value = 0 # value awarded for a successful message
[docs] def log(self, msg):
self.environment.log(msg)
def _get_next_recipient(self, task):
"""
Returns the node index that this entity would like to hand message to
May enter a 'pending' state recording this decision for future feedback
"""
raise NotImplementedError
[docs] def next(self, task, sender):
"""
Called by environment to get the next step in the path
"""
next_recipient = self._get_next_recipient(task)
self.log("%s -> %s" % (self.index, next_recipient))
return next_recipient
[docs] def award(self, value):
"""
Accepts <value> as award to register the outcome of recent decision(s).
Calls self._learn() and then cleans up to prepare for the next message.
"""
self.value = value
self.log("""
Node {ix} receiving award {award}
""".format(ix=self.index, award=value))
self._learn()
self.value = 0
def _learn(self):
"""
Update node's brain, however that is implemented in subclass.
May resolve a 'pending' state by taking the current self.value as its outcome
"""
raise NotImplementedError
[docs]class XyEntity(Entity):
"""An entity in x-y world"""
def __init__(self, environment, index, x, y, cluster):
super(XyEntity, self).__init__(environment, index)
self.x = x
self.y = y
self.cluster = cluster
self.adjacencies = []
[docs] def set_adjacencies(self, adjacencies):
"""
Builds the adjacency list for this Entity.
:param adjacencies: set of integers referencing other entities in self.population
"""
self.adjacencies = list(adjacencies)
[docs]class NxEntity(Entity):
"""An entity that can be a Nx graph node
It can have more freeform attributes and doesn't need x, y positions for viz
"""
def __init__(self, environment, index, **kwargs):
super(NxEntity, self).__init__(environment, index)
self.update(kwargs)
[docs] def update(self, kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def __getitem__(self, attr):
return getattr(self, attr)
@property
def adjacencies(self):
"""
List connected nodes via the parent graph
"""
if self.environment and self.environment.graph:
return self.environment.graph.neighbors(self.index)
else:
return []
[docs]class DunceNode(DunceMixin, NxEntity):
"""
Nx compatible node that doesn't learn and just randomly draws its recipients
"""
[docs]class XyDunceNode(DunceMixin, XyEntity):
"""
Xy compatible node that doesn't learn and just randomly draws its recipients
"""
[docs]class SoftmaxNode(SoftmaxLearnerMixin, NxEntity):
"""
Nx nodes with softmax learning
"""