Source code for topo.submodel.specifications

"""
A set of objects that allows declarative specification of a model
including training patterns, sheets and projections.

The components of a model specification can be individually inspected,
modified, resolved or instantiated.
"""

from collections import OrderedDict

import param
from holoviews.core.tree import AttrTree

import topo


[docs]class Specification(param.Parameterized): """ Specifications are templates for sheet or projection objects which may be resolved to the corresponding simulation object once instantiated. All specifications have the following attribute: :'parameters': Keyword argument dictionary specifying which parameters should be passed to the sheet or projection object. """
[docs] def update(self, **params): """ Convenience method to easy update specification parameters. """ self.parameters.update(params)
@property
[docs] def modified_parameters(self): "Dictionary of modified specification parameters" return {k:v for k, v in self.parameters.items() if self.default_parameters[k] != v}
@property def resolved_type(self): return self._object_type
[docs] def resolve(self): """ Returns the object in topo.sim corresponding to this object, typically a Sheet or a Projection. The appropriate object must be available in topo.sim. """ raise NotImplementedError
def __lt__(self, other): return self.sort_precedence < other.sort_precedence def __eq__(self, other): return self.sort_precedence == other.sort_precedence def __init__(self, object_type): self._object_type = object_type self.parameters = {} self.sort_precedence = 0 if not hasattr(object_type,'params'): self.default_parameters = {} else: for param_name, default_value in object_type.params().items(): self.parameters[param_name]=default_value.default self.default_parameters = dict(**self.parameters)
[docs] def summary(self, printed=True): """ Generate a succinct summary of the Specification object. If printed is set to True, the summary is printed, otherwise it is returned as a string. """ raise NotImplementedError
def __getitem__(self, key): "Convenient property access." return self.properties[key]
[docs] def keys(self): "The list of available property keys." return self.properties.keys()
[docs] def items(self): "The property items." return self.properties.items()
[docs]class ArraySpec(Specification): """ A simple specification used to resolve numpy arrays relative to a Topographica simulation (i.e. topo.sim). This class is primarily aimed for specifying arrays to a Collector. """ def __init__(self, pathspec, properties={}): """ ArraySpec uses a fairly unsophisticated implementation, making use of eval to resolve the desired array. :'pathspec': A string specifying how to access the array relative to topo.sim. :'properties': Optional specification of array properties """ import numpy self.pathspec = pathspec super(ArraySpec,self).__init__(numpy.ndarray) self.properties = OrderedDict(properties) def resolve(self): from topo import sim # pyflakes:ignore (import for eval) return eval("sim.%s" % self.pathspec) def __call__(self): raise NotImplementedError def __str__(self): return "topo.sim.%s" % self.pathspec def summary(self, printed=True): summary = "%s : Numpy array" % self if printed: print summary else: return summary def __repr__(self): properties_repr = ', '.join("%r:%r" % (k,v) for (k,v) in self.properties.items()) return "ArraySpec(%r, {%s})" % (self.pathspec, properties_repr)
[docs]class SheetSpec(Specification): """ SheetSpec acts as a template for sheet objects. """ name_ordering = ['eye','level', 'cone', 'polarity', 'SF','opponent','surround'] @property def level(self): return self.properties['level'] def __init__(self, sheet_type, properties): """ Initialize a SheetSpec object of a certain Sheet type with the given properties. :'sheet_type': Subclass of topo.base.sheet.Sheet. :'properties': Dictionary specifying the properties of the sheet. There must be a value given for the key 'level'. """ super(SheetSpec,self).__init__(sheet_type) if 'level' not in properties: raise Exception("SheetSpec always requires 'level' property.") properties = [(k, properties[k]) for k in self.name_ordering if k in properties] self.sheet_type = sheet_type self.properties = OrderedDict(properties) def resolve(self): from topo import sim return sim[str(self)] def __call__(self): """ Instantiate the sheet and register it in topo.sim. """ properties = dict(self.parameters['properties'], **self.properties) topo.sim[str(self)]=self.sheet_type(**dict(self.parameters, properties=properties)) def __str__(self): """ Returns a string representation of the SheetSpec from the properties values. """ name='' for prop in self.properties.itervalues(): name+=str(prop) return name def summary(self, printed=True): summary = "%s : %s" % (self, self.sheet_type.name) if printed: print summary else: return summary def __repr__(self): type_name = self.sheet_type.__name__ properties_repr = ', '.join("%r:%r" % (k,v) for (k,v) in self.properties.items()) return "SheetSpec(%s, {%s})" % (type_name, properties_repr)
[docs]class ProjectionSpec(Specification): """ ProjectionSpec acts as a template for projection objects. """ def __init__(self, projection_type, src, dest): """ Initialize a ProjectionSpec object of a certain Projection type with the given src and dest SheetSpecs. :'projection_type': Subclass of topo.base.projection.Projection :'src': SheetSpec of the source sheet :'dest': SheetSpec of the destination sheet """ super(ProjectionSpec, self).__init__(projection_type) self.projection_type = projection_type self.src = src self.dest = dest self.properties = {} # These parameters are directly passed into topo.sim.connect()! ignored_keys = ['src', 'dest'] self.parameters = dict((k,v) for (k,v) in self.parameters.items() if k not in ignored_keys) def resolve(self): from topo import sim return sim[str(self.dest)].projections(self.parameters['name']) def __call__(self): """ Instantiate the projection and register it in topo.sim. """ topo.sim.connect(str(self.src),str(self.dest), self.projection_type, **self.parameters) def __str__(self): return str(self.dest)+'.' + self.parameters['name'] def summary(self, printed=True): summary = "%s [%s -> %s] : %s" % (self, self.src, self.dest, self.projection_type.name) if printed: print summary else: return summary def __repr__(self): type_name = self.projection_type.__name__ return "ProjectionSpec(%s, %r, %r)" % (type_name, self.src, self.dest)
[docs]class ModelSpec(Specification): """ ModelSpec acts as a template for Topographica model including training patterns, sheets and projections. """ def __init__(self, model, properties): self.training_patterns = AttrTree() self.sheets = AttrTree() self.projections = AttrTree() self._instantiated = False self.properties = properties super(ModelSpec, self).__init__(model) self.model= model def resolve(self): from topo import sim # pyflakes:ignore (needed for eval) return eval('sim.model') def __call__(self, instantiate_options=True, verbose=False): """ Instantiates all sheets or projections in self.sheets or self.projections and registers them in the topo.sim instance. If instantiate_options=True, all items are initialised instantiate_options can also be a list, whereas all list items of available_instantiate_options are accepted. Available instantiation options are: 'sheets' and 'projections'. Please consult the docstring of the Model class for more information about each instantiation option. """ msglevel = self.message if verbose else self.debug if self._instantiated: msglevel('ModelSpec %r already instantiated. Returning.' % self.model.name) return available_instantiate_options = ['sheets','projections'] if instantiate_options==True: instantiate_options=available_instantiate_options if 'sheets' in instantiate_options: for sheet_spec in self.sheets.data.itervalues(): msglevel('Level ' + sheet_spec.level + ': Sheet ' + str(sheet_spec)) sheet_spec() if 'projections' in instantiate_options: for proj in sorted(self.projections): msglevel('Match: ' + proj.matchname + ': Connection ' + str(proj.src) + \ '->' + str(proj.dest) + ' ' + proj.parameters['name']) proj() self._instantiated = True def summary(self, printed=True): name = self.model.__class__.__name__ heading_line = '=' * len(name) summary = [heading_line, name, heading_line, ''] for sheet_spec in sorted(self.sheets): summary.append(sheet_spec.summary(printed=False)) projections = [proj for proj in self.projections if str(proj.dest)==str(sheet_spec)] for projection_spec in sorted(projections, key=lambda p: str(p)): summary.append(" " + projection_spec.summary(printed=False)) summary.append('') if printed: print "\n".join(summary) else: return "\n".join(summary) def __str__(self): return self.model.__class__.__name__ def _repr_pretty_(self, p, cycle): p.text(self.summary(printed=False))
[docs] def modifications(self, components=['model', 'sheets', 'projections']): """ Display the names of all modified parameters for the specified set of components. By default all modified parameters are listed - first with the model parameters, then the sheet parameters and lastly the projection parameters. """ mapping = {'model': [self], 'sheets':self.sheets, 'projections':self.projections} lines = [] for component in components: heading = "=" * len(component) lines.extend([heading, component.capitalize(), heading, '']) specs = mapping[component] padding = max(len(str(spec)) for spec in specs) for spec in sorted(specs): modified = [str(el) for el in sorted(spec.modified_parameters)] lines.append("%s : [%s]" % (str(spec).ljust(padding), ", ".join(modified))) lines.append('') print "\n".join(lines)