# -*- coding: utf-8 -*-
"""
Created on Wed Oct 9 11:29:39 2019
By Olivia L. Calvin at the University of Minnesota
9 Oct 2019 - The purpose of this code is to implement an agent base class that
can be used with tasks. This code will adapt as I wrote more
tasks, and the first task that are designed to interact with is
the DPX.
There are two guiding principles for how the agent interacts with
tasks. The first is that the agent is responsible for recording
data about itself, because if this responsibility were the
labratory's then it would hinder reusability. Otherwise, the
laboratory would have to know the internal mechanisms of whatever
agent it is testing. The second is that neither the agent nor
task will know how the other represents behaviors and stimuli.
Instead a 'dictionary' will be passed between the two that will
contain this information and translate between them.
11 Oct 2019 - NOTE: General guideline for the map is that the map is
FROM -> TO. For example, cues come from the world so it would be
the world's representation in column 1, and the agent
representation in column 2. Acts come from the agent, so the
agent's representation would be in column 1 and the world in
column 2.
The act_map will always be one longer than the number of
responses. The first element will be 'no response' and the rest
will actions. Dimensions of act_map are [#responses+1, 0]. For
this first agent, the mapping to action is ['O', 'L', 'R'].
21 Oct 2019 - This code was not directly changed, but the back code that goes
into ringAgent was adjusted to account for multiple sources of
pyramidal spikes.
22 Nov 2019 - Updated the agent with the new, faster LIF code. The old version
is backed up in the scrap file.
06 Apr 2020 - Made some updates to the agents so that they are easier to work
with. Mostly modified the agents to better use kwargs.
18 Sep 2020 - Improved documentation and made the code more in line with
Python coding standards.
22 Apr 2021 - Separated AgentBase from more specific agents.
"""
__version__ = "1.0"
class agentBase(object):
"""
Base class for agents. Provides some basic utilities and defines
common methods (while not implementing them).
Attributes
----------
act_map : dict
The mapping between the agent's action and the task. Provides
a response that matches the task
Methods
-------
__init__(act_map)
Initialize the agent_base class.
Class Methods
-------------
fill_parser(parser, required=False)
Adds the arguments that go with this class to the argument parser.
pop_kwargs(kwargs)
Pops the kwargs that go with this class from those passed to the
program.
Place Holder Methods
--------------------
description() - Prints a description of the agent.
pull_data() - Extracts data from the agent.
act() - Checks to see whether the agent is prepared to act.
present_cue() - Receive information from the world.
hide_cue() - Remove information about the world.
reward() - Reinforce the agent.
state_reset() - Resets the agent for the next trial.
full_reset() - Resets the agent for the next experiment.
"""
_init_kwargs = []
def __init__(self, act_map={}):
'''
Initialize the agent_base class.
Parameters
----------
act_map : dict
The mapping between the agent's action and the task. Provides
a response that matches the task
'''
self.act_map = act_map
def act(self):
'''
Checks to see whether the agent is prepared to act.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call act with the base class.')
def present_cue(self):
'''
Receive information from the world.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call present_cue with the base class.')
def hide_cue(self):
'''
Remove information about the world.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call hide_cue with the base class.')
def reward(self):
'''
Receive a reward from the world.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call reward with the base class.')
def pull_data(self):
'''
Extracts data from the agent.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call pull_data with the base class.')
def state_reset(self):
'''
Resets the agent for the next trial.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call state_reset with the base class.')
def full_reset(self):
'''
Resets the agent for the next experiment
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call full_reset with the base class.')
def description(self):
'''
Prints a description of the agent to the console.
Raises
------
NotImplementedError
This is the base class and this method is not implemented.
'''
raise NotImplementedError('Trying to call description with the base class.')
@classmethod
def fill_parser(cls, parser, required=False):
'''
Adds the arguments that go with this class to the argument parser.
Parameters
----------
parser : argparse.ArgumentParser
Argument parser
required : bool, optional
Whether the argument is required. The default is False.
'''
_pref = '--'
if required: _pref = ''
for keys, items in cls._init_kwargs.items():
parser.add_argument(_pref + keys,
type=items['type'],
help=items['help']
)
@classmethod
def pop_kwargs(cls, kwargs):
'''
Pops the kwargs that go with this class from those passed to the
program.
Parameters
----------
kwargs : dict
Key word arguments that are to be parsed
Returns
-------
pop_kwargs : dict
Removed kwargs that belong to this class.
'''
pop_kwargs = {}
delete = []
# check to see if any of the kwargs belong to this class
for keys, items in cls._init_kwargs.items():
if keys in kwargs:
pop_kwargs.update({keys:kwargs.pop(keys)})
if pop_kwargs[keys] is None:
delete.append(keys)
# strip out all of the empty kwargs
for k in delete:
del pop_kwargs[k]
return pop_kwargs