Skip to content

Commit

Permalink
Merge 4eb02ff into 09d6478
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcel Stimberg committed Jun 12, 2013
2 parents 09d6478 + 4eb02ff commit 68fdfc2
Show file tree
Hide file tree
Showing 14 changed files with 68 additions and 78 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ before_install:
install:
# Use the newest versions available
- "pip install -q numpy --upgrade --use-mirrors"
- "pip install -q scipy --upgrade --use-mirrors"
- "pip install -q sphinx --upgrade --use-mirrors"
- "pip install -q ipython --upgrade --use-mirrors"
# Use whatever version is available and be verbose to prevent timeout
- "pip install scipy --use-mirrors"
# Make sure to use the python 3 version for sympy
- "if [ ${TRAVIS_PYTHON_VERSION:0:1} == '2' ]; then pip install -q sympy --use-mirrors; else pip install -q http://sympy.googlecode.com/files/sympy-0.7.2-py3.2.tar.gz; fi"
# install different pyparsing versions for python 2 and 3
Expand Down
8 changes: 2 additions & 6 deletions brian2/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ class BrianObject(Nameable):
loop.
name : str, optional
A unique name for the object - one will be assigned automatically if
not provided (of the form ``brianobject_1``, etc.) based on the
stem `basename`.
not provided (of the form ``brianobject_1``, etc.).
Notes
-----
Expand All @@ -40,7 +39,7 @@ class BrianObject(Nameable):
Brian objects deriving from this class should always define an
``update()`` method, that gets called by `Network.run`.
'''
def __init__(self, when=None, name=None):
def __init__(self, when=None, name='brianobject*'):
scheduler = Scheduler(when)
when = scheduler.when
order = scheduler.order
Expand All @@ -66,9 +65,6 @@ def __init__(self, when=None, name=None):
"clock name {self.clock.name}, "
"when={self.when}, order={self.order}".format(self=self))

#: The stem for the automatically generated `name` attribute
basename = 'brianobject'

#: Whether or not `MagicNetwork` is invalidated when a new `BrianObject` of this type is created or removed
invalidates_magic_network = True

Expand Down
10 changes: 3 additions & 7 deletions brian2/core/clocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Clock(Nameable):
dt : `Quantity`, optional
The time step of the simulation, will be set to ``0.1*ms`` if
unspecified.
name : (str, None), optional
name : str, optional
An explicit name, if not specified gives an automatically generated name
Notes
Expand All @@ -38,17 +38,13 @@ class Clock(Nameable):
``abs(t1-t2)<epsilon*abs(t1)``, a standard test for equality of floating
point values. The value of ``epsilon`` is ``1e-14``.
'''

#: The stem for the automatically generated `name` attribute
basename = 'clock'
name = Nameable.name

@check_units(dt=second)
def __init__(self, dt=None, name=None):
def __init__(self, dt=None, name='clock*'):
self._dt_spec = dt
self.i = 0 #: The time step of the simulation as an integer.
self.i_end = 0 #: The time step the simulation will end as an integer
Nameable.__init__(self, name)
Nameable.__init__(self, name=name)
logger.debug("Created clock {self.name} with dt={self._dt_spec}".format(self=self))

def reinit(self):
Expand Down
2 changes: 1 addition & 1 deletion brian2/core/magic.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def __init__(self):
raise ValueError("There can be only one MagicNetwork.")
MagicNetwork._already_created = True

super(MagicNetwork, self).__init__(name='magicnetwork')
super(MagicNetwork, self).__init__(name='magicnetwork*')

self._previous_refs = set()

Expand Down
63 changes: 34 additions & 29 deletions brian2/core/names.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,51 @@ class Nameable(Trackable):
Base class to find a unique name for an object
If you specify a name explicitly, and it has already been taken, a
`ValueError` is raised. If a name is not specified, it will try names of
the form ``basename_0``, ``basename_1`` until it finds one which hasn't
been taken. If the object has a ``source`` attribute with a ``name``
attribute, the base name will be given by ``source.name+'_'+basename``. If
the object also has a ``target`` attribute the format will be
``sourcename_targetname_basename``. Note that to get this behaviour, the
``source`` and ``target`` attributes have to have been set at the time that
``Nameable.__init__`` is called.
`ValueError` is raised. You can also specify a name with a wildcard asterisk
in the end, i.e. in the form ``'name*'``. It will then try ``name`` first
but if this is already specified, it will try ``name_1``, `name__2``, etc.
This is the default mechanism used by most core objects in Brian, e.g.
`NeuronGroup` uses a default name of ``'neurongroup*'``.
Parameters
----------
name : (str, None), optional
An explicit name, if not specified gives an automatically generated name
name : str
An name for the object, possibly ending in ``*`` to specify that
variants of this name should be tried if the name (without the asterisk)
is already taken.
Raises
------
ValueError
If the name is already taken.
'''
#: Stem of automatically generated names
basename = 'nameable_object'

def _find_name(self, name):
if name.endswith('*'):
name = name[:-1]
wildcard = True
else:
wildcard = False
instances = set(Nameable.__instances__())
allnames = set(obj().name for obj in instances if hasattr(obj(), 'name'))
if name is not None:
if name in allnames:
raise ValueError("An object with name "+name+" is already defined.")
allnames = set(obj().name for obj in instances
if hasattr(obj(), 'name'))

# Try the name without any additions first:
if name not in allnames:
return name
basename = self.basename
if hasattr(self, 'target') and hasattr(self.target, 'name'):
basename = self.target.name+'_'+basename
if hasattr(self, 'source') and hasattr(self.source, 'name'):
basename = self.source.name+'_'+basename
i = 0
while basename+'_'+str(i) in allnames:
elif not wildcard:
raise ValueError("An object with name "+name+" is already defined.")

# Name is already taken, try _1, _2, etc.
i = 1
while name+'_'+str(i) in allnames:
i += 1
return basename+'_'+str(i)
return name+'_'+str(i)

def __init__(self, name=None):
def __init__(self, name):
if not isinstance(name, basestring):
raise TypeError(('"name" argument has to be a string, is type '
'{type} instead').format(type=repr(type(name))))

self._name = self._find_name(name)
logger.debug("Created object of class "+self.__class__.__name__+" with name "+self._name)

Expand All @@ -68,7 +73,7 @@ def __init__(self, name=None):
if __name__=='__main__':
from brian2 import *
from brian2.core.names import Nameable
nam = Nameable()
obj = BrianObject()
obj2 = BrianObject()
nam = Nameable('nameable')
obj = BrianObject(name='object*')
obj2 = BrianObject(name='object*')
print nam.name, obj.name, obj2.name
11 changes: 4 additions & 7 deletions brian2/core/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

class Network(Nameable):
'''
Network(*objs, name=None)
Network(*objs, name='network*')
The main simulation controller in Brian
Expand All @@ -31,7 +31,7 @@ class Network(Nameable):
objs : (`BrianObject`, container), optional
A list of objects to be added to the `Network` immediately, see
`~Network.add`.
name : (str, None), optional
name : str, optional
An explicit name, if not specified gives an automatically generated name
Notes
Expand Down Expand Up @@ -73,17 +73,14 @@ class Network(Nameable):
MagicNetwork, run, stop
'''

basename = 'network'
name = Nameable.name


def __init__(self, *objs, **kwds):
#: The list of objects in the Network, should not normally be modified directly
#:
#: Stores `weakref.proxy` references to the objects.
self.objects = []

name = kwds.pop('name', None)
name = kwds.pop('name', 'network*')
if kwds:
raise TypeError("Only keyword argument to Network is name")
Nameable.__init__(self, name=name)
Expand Down
2 changes: 1 addition & 1 deletion brian2/core/operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class NetworkOperation(BrianObject):
network_operation, Network, BrianObject
"""
def __init__(self, function, when=None):
super(NetworkOperation, self).__init__(when=when)
BrianObject.__init__(self, when=when, name='networkoperation*')

#: The function to be called each time step
self.function = function
Expand Down
4 changes: 2 additions & 2 deletions brian2/groups/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,11 @@ class GroupCodeRunner(BrianObject):
`update_abstract_code` is called before a run to allow taking into account
changes in the namespace or in the reset/threshold definition itself.
`pre_update` and `post_update` are used to connect the `CodeObject` to the
state of the `Group`. For example, the `Tresholder` sets the
state of the `Group`. For example, the `Thresholder` sets the
`NeuronGroup.spikes` property in `post_update`.
'''
def __init__(self, group, template, code=None, iterate_all=True,
when=None, name=None, check_units=True,
when=None, name='coderunner*', check_units=True,
additional_specifiers=None):
BrianObject.__init__(self, when=when, name=name)
self.group = weakref.proxy(group)
Expand Down
21 changes: 10 additions & 11 deletions brian2/groups/neurongroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def __init__(self, group, method):
GroupCodeRunner.__init__(self, group,
group.language.template_state_update,
when=(group.clock, 'groups'),
name=group.name + '_stateupdater',
name=group.name+'_stateupdater*',
check_units=False)

self.method = StateUpdateMethod.determine_stateupdater(self.group.equations,
Expand Down Expand Up @@ -73,7 +73,7 @@ def __init__(self, group):
GroupCodeRunner.__init__(self, group,
group.language.template_threshold,
when=(group.clock, 'thresholds'),
name=group.name + '_thresholder',
name=group.name+'_thresholder*',
# TODO: This information should be included in
# the template instead
additional_specifiers=['t',
Expand All @@ -97,7 +97,7 @@ def __init__(self, group):
GroupCodeRunner.__init__(self, group,
group.language.template_reset,
when=(group.clock, 'resets'),
name=group.name + '_resetter',
name=group.name+'_resetter*',
iterate_all=False,
additional_specifiers=['_spikes'])

Expand Down Expand Up @@ -152,13 +152,12 @@ class NeuronGroup(BrianObject, Group, SpikeSource):
attribute is set to 0 initially, but this can be modified using the
attributes `state_updater`, `thresholder` and `resetter`.
'''
basename = 'neurongroup'
def __init__(self, N, equations, method=None,
threshold=None,
reset=None,
namespace=None,
dtype=None, language=None,
clock=None, name=None):
clock=None, name='neurongroup*'):
BrianObject.__init__(self, when=clock, name=name)

try:
Expand Down Expand Up @@ -285,18 +284,18 @@ def runner(self, code, when=None, name=None):
When to run, by default in the 'start' slot with the same clock as
the group.
name : str, optional
A unique name, by default the name of the group appended with
'runner_0', 'runner_1', etc.
A unique name, if non is given the name of the group appended with
'runner', 'runner_1', etc. will be used. If a name is given
explicitly, it will be used as given (i.e. the group name will not
be prepended automatically).
'''
if when is None: # TODO: make this better with default values
when = Scheduler(clock=self.clock)
else:
raise NotImplementedError

if name is None:
if not hasattr(self, 'num_runners'):
self.num_runners = 0
name = self.name + '_runner_' + str(self.num_runners)
self.num_runners += 1
name = self.name + '_runner*'

runner = GroupCodeRunner(self, self.language.template_state_update,
code=code, name=name, when=when)
Expand Down
5 changes: 2 additions & 3 deletions brian2/groups/poissongroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ class PoissonGroup(BrianObject, SpikeSource):
When the `spikes` should be updated, will always be in the
'thresholds' slot.
name : str, optional
Unique name, or use poisson_group_0, etc.
Unique name, or use poissongroup, poissongroup_1, etc.
Notes
-----
TODO: make rates not have to be a value/array, use code generation for str
'''
basename = 'poisson_group'
@check_units(rates=Hz)
def __init__(self, N, rates, when=None, name=None):
def __init__(self, N, rates, when=None, name='poissongroup*'):
# TODO: sort out the default values in Scheduler
scheduler = Scheduler(when)
scheduler.when = 'thresholds'
Expand Down
1 change: 0 additions & 1 deletion brian2/groups/subgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ class Subgroup(BrianObject, SpikeSource):
TODO: Group state variable access
'''
basename = 'subgroup'
def __init__(self, source, start, end, name=None):
self.source = weakref.proxy(source)
# We want to update the spikes attribute after it has been updated
Expand Down
3 changes: 1 addition & 2 deletions brian2/monitors/spikemonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ class SpikeMonitor(BrianObject):
A unique name for the object, otherwise will use
``source.name+'_spikemonitor_0'``, etc.
'''
basename = 'spikemonitor'
def __init__(self, source, record=True, when=None, name=None):
def __init__(self, source, record=True, when=None, name='spikemonitor*'):
self.source = weakref.proxy(source)
self.record = bool(record)

Expand Down
4 changes: 2 additions & 2 deletions brian2/monitors/statemonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ class StateMonitor(BrianObject, Group):
* Cacheing extracted values (t, V, etc.)
* Improve efficiency by using dynamic arrays instead of lists?
'''
basename = 'statemonitor'
def __init__(self, source, variables, record=None, when=None, name=None):
def __init__(self, source, variables, record=None, when=None,
name='statemonitor*'):
self.source = weakref.proxy(source)

# run by default on source clock at the end
Expand Down
9 changes: 4 additions & 5 deletions brian2/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
from nose import with_setup

class DerivedBrianObject(BrianObject):
basename = 'derivedbrianobject'
def __init__(self, name=None):
def __init__(self, name='derivedbrianobject*'):
super(DerivedBrianObject, self).__init__(name=name)
def __str__(self):
return self.name
Expand Down Expand Up @@ -61,10 +60,10 @@ def test_names():
obj = BrianObject()
obj2 = BrianObject()
obj3 = DerivedBrianObject()
assert_equal(obj.name, 'brianobject_0')
assert_equal(obj.name, 'brianobject')
assert_equal(obj2.name, 'brianobject_1')
assert_equal(obj3.name, 'derivedbrianobject_0')
assert_raises(ValueError, lambda: BrianObject(name='brianobject_0'))
assert_equal(obj3.name, 'derivedbrianobject')
assert_raises(ValueError, lambda: BrianObject(name='brianobject'))

if __name__=='__main__':
test_base()
Expand Down

0 comments on commit 68fdfc2

Please sign in to comment.