def __init__(self, selector, portmap=None): self.sel = SelectorMethods() N = self.sel.count_ports(selector) if portmap is None: self.portmap = pd.Series(data=np.arange(N)) else: assert len(portmap) == N self.portmap = pd.Series(data=np.array(portmap)) self.portmap.index = self.sel.make_index(selector)
def __init__(self, selector, portmap=None): self.sel = SelectorMethods() N = self.sel.count_ports(selector) if portmap is None: self.portmap = pd.Series(data=np.arange(N)) else: assert len(portmap) == N self.portmap = pd.Series(data=np.array(portmap)) self.portmap.index = self.sel.make_index(selector)
def __init__(self, sel, sel_in, sel_out, sel_gpot, sel_spike, data_gpot, data_spike, columns=['interface', 'io', 'type'], ctrl_tag=CTRL_TAG, gpot_tag=GPOT_TAG, spike_tag=SPIKE_TAG, id=None, device=None, routing_table=None, rank_to_id=None, debug=False, time_sync=False): super(Module, self).__init__(ctrl_tag) self.debug = debug self.time_sync = time_sync self.device = device self._gpot_tag = gpot_tag self._spike_tag = spike_tag # Require several necessary attribute columns: if 'interface' not in columns: raise ValueError('interface column required') if 'io' not in columns: raise ValueError('io column required') if 'type' not in columns: raise ValueError('type column required') # Manually register the file close method associated with MPIOutput # so that it is called by atexit before MPI.Finalize() (if the file is # closed after MPI.Finalize() is called, an error will occur): for k, v in twiggy.emitters.iteritems(): if isinstance(v._output, MPIOutput): atexit.register(v._output.close) # Ensure that the input and output port selectors respectively # select mutually exclusive subsets of the set of all ports exposed by # the module: if not SelectorMethods.is_in(sel_in, sel): raise ValueError('input port selector not in selector of all ports') if not SelectorMethods.is_in(sel_out, sel): raise ValueError('output port selector not in selector of all ports') if not SelectorMethods.are_disjoint(sel_in, sel_out): raise ValueError('input and output port selectors not disjoint') # Ensure that the graded potential and spiking port selectors # respectively select mutually exclusive subsets of the set of all ports # exposed by the module: if not SelectorMethods.is_in(sel_gpot, sel): raise ValueError('gpot port selector not in selector of all ports') if not SelectorMethods.is_in(sel_spike, sel): raise ValueError('spike port selector not in selector of all ports') if not SelectorMethods.are_disjoint(sel_gpot, sel_spike): raise ValueError('gpot and spike port selectors not disjoint') # Save routing table and mapping between MPI ranks and module IDs: self.routing_table = routing_table self.rank_to_id = rank_to_id # Generate a unique ID if none is specified: if id is None: self.id = uid() else: # If a unique ID was specified and the routing table is not empty # (i.e., there are connections between multiple modules), # the id must be a node in the table: if routing_table is not None and len(routing_table.ids) and \ not routing_table.has_node(id): raise ValueError('routing table must contain specified module ID') self.id = id # Reformat logger name: LoggerMixin.__init__(self, 'mod %s' % self.id) # Create module interface given the specified ports: self.interface = Interface(sel, columns) # Set the interface ID to 0; we assume that a module only has one interface: self.interface[sel, 'interface'] = 0 # Set the port attributes: self.interface[sel_in, 'io'] = 'in' self.interface[sel_out, 'io'] = 'out' self.interface[sel_gpot, 'type'] = 'gpot' self.interface[sel_spike, 'type'] = 'spike' # Find the input and output ports: self.in_ports = self.interface.in_ports().to_tuples() self.out_ports = self.interface.out_ports().to_tuples() # Find the graded potential and spiking ports: self.gpot_ports = self.interface.gpot_ports().to_tuples() self.spike_ports = self.interface.spike_ports().to_tuples() self.in_gpot_ports = self.interface.in_ports().gpot_ports().to_tuples() self.in_spike_ports = self.interface.in_ports().spike_ports().to_tuples() self.out_gpot_ports = self.interface.out_ports().gpot_ports().to_tuples() self.out_spike_ports = self.interface.out_ports().spike_ports().to_tuples() # Set up mapper between port identifiers and their associated data: if len(data_gpot) != len(self.gpot_ports): raise ValueError('incompatible gpot port data array length') if len(data_spike) != len(self.spike_ports): raise ValueError('incompatible spike port data array length') self.data = {} self.data['gpot'] = data_gpot self.data['spike'] = data_spike self.pm = {} self.pm['gpot'] = PortMapper(sel_gpot, self.data['gpot']) self.pm['spike'] = PortMapper(sel_spike, self.data['spike'])
logger = mpi.setup_logger(screen=True, file_name='neurokernel.log', mpi_comm=MPI.COMM_WORLD, multiline=True) man = Manager() m1_int_sel_in_gpot = '/a/in/gpot0,/a/in/gpot1' m1_int_sel_out_gpot = '/a/out/gpot0,/a/out/gpot1' m1_int_sel_in_spike = '/a/in/spike0,/a/in/spike1' m1_int_sel_out_spike = '/a/out/spike0,/a/out/spike1' m1_int_sel = ','.join([m1_int_sel_in_gpot, m1_int_sel_out_gpot, m1_int_sel_in_spike, m1_int_sel_out_spike]) m1_int_sel_in = ','.join((m1_int_sel_in_gpot, m1_int_sel_in_spike)) m1_int_sel_out = ','.join((m1_int_sel_out_gpot, m1_int_sel_out_spike)) m1_int_sel_gpot = ','.join((m1_int_sel_in_gpot, m1_int_sel_out_gpot)) m1_int_sel_spike = ','.join((m1_int_sel_in_spike, m1_int_sel_out_spike)) N1_gpot = SelectorMethods.count_ports(m1_int_sel_gpot) N1_spike = SelectorMethods.count_ports(m1_int_sel_spike) m2_int_sel_in_gpot = '/b/in/gpot0,/b/in/gpot1' m2_int_sel_out_gpot = '/b/out/gpot0,/b/out/gpot1' m2_int_sel_in_spike = '/b/in/spike0,/b/in/spike1' m2_int_sel_out_spike = '/b/out/spike0,/b/out/spike1' m2_int_sel = ','.join([m2_int_sel_in_gpot, m2_int_sel_out_gpot, m2_int_sel_in_spike, m2_int_sel_out_spike]) m2_int_sel_in = ','.join((m2_int_sel_in_gpot, m2_int_sel_in_spike)) m2_int_sel_out = ','.join((m2_int_sel_out_gpot, m2_int_sel_out_spike)) m2_int_sel_gpot = ','.join((m2_int_sel_in_gpot, m2_int_sel_out_gpot)) m2_int_sel_spike = ','.join((m2_int_sel_in_spike, m2_int_sel_out_spike)) N2_gpot = SelectorMethods.count_ports(m2_int_sel_gpot) N2_spike = SelectorMethods.count_ports(m2_int_sel_spike)
class BasePortMapper(object): """ Maps integer sequence to/from path-like port identifiers. Examples -------- >>> pm = BasePortMapper('/[a,b][0:2]') >>> print pm.ports_to_inds('/b[0:2]') array([2, 3]) >>> print pm.inds_to_ports([0, 1]) [('a', 0), ('a', 1)] Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]) to map to `data`. portmap : sequence of int Integer indices to map to port identifiers. If no map is specified, it is assumed to be an array of consecutive integers from 0 through one less than the number of ports. Attributes ---------- index : pandas.MultiIndex Index of port identifiers. portmap : pandas.Series Map of port identifiers to integer indices. Notes ----- The selectors may not contain any '*' or '[:]' characters. A single port identifier may be mapped to multiple integer indices, but not vice-versa. """ def __init__(self, selector, portmap=None): self.sel = SelectorMethods() N = self.sel.count_ports(selector) if portmap is None: self.portmap = pd.Series(data=np.arange(N)) else: assert len(portmap) == N self.portmap = pd.Series(data=np.array(portmap)) self.portmap.index = self.sel.make_index(selector) def copy(self): """ Return copy of this port mapper. Returns ------- result : neurokernel.plsel.BasePortMapper Copy of port mapper instance. """ c = BasePortMapper('') c.portmap = self.portmap.copy() return c @classmethod def from_index(cls, idx, portmap=None): """ Create port mapper from a Pandas index and a sequence of integer indices. Parameters ---------- index : pandas.MultiIndex Index containing selector data. portmap : sequence of int Integer indices to map to port identifiers. If no map is specified, it is assumed to be an array of consecutive integers from 0 through one less than the number of ports. Returns ------- result : neurokernel.plsel.BasePortMapper New port mapper instance. Notes ----- If specified, the portmap sequence is copied into the new mapper to avoid side effects associated with modifying the specified sequence after mapper instantiation. """ pm = cls('') N = len(idx) if portmap is None: pm.portmap = pd.Series.from_array(np.arange(N), idx) else: assert len(portmap) == N pm.portmap = pd.Series.from_array(np.array(portmap), idx) return pm @classmethod def from_pm(cls, pm): """ Create a new port mapper instance given an existing instance. Parameters ---------- result : neurokernel.plsel.BasePortMapper Existing port mapper instance. Returns ------- result : neurokernel.plsel.BasePortMapper New port mapper instance. """ assert isinstance(pm, cls) r = cls('') r.portmap = pm.portmap.copy() return r @property def index(self): """ Port mapper index. """ return self.portmap.index @index.setter def index(self, i): self.portmap.index = i def inds_to_ports(self, inds): """ Convert list of integer indices to port identifiers. Examples -------- >>> pm = BasePortMapper('/[a,b][0:2]') >>> print pm.inds_to_ports([0, 1]) [('a', 0), ('a', 1)] Parameters ---------- inds : array_like of int Integer indices of ports. Returns ------- t : list of tuple Expanded port identifiers. """ return self.portmap[self.portmap.isin(inds)].index.tolist() def ports_to_inds(self, selector): """ Convert port selector to list of integer indices. Examples -------- >>> pm = BasePortMapper('/[a,b][0:2]') >>> print pm.ports_to_inds('/b[0:2]') Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]). Returns ------- inds : numpy.ndarray of int Integer indices of ports comprised by selector. """ return self.sel.select(self.portmap, selector).dropna().astype(np.int_).values def get_map(self, selector): """ Retrieve integer indices associated with selector. Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]). Returns ------- result : numpy.ndarray Selected data. """ return np.asarray(self.sel.select(self.portmap, selector).dropna()) def set_map(self, selector, portmap): """ Set mapped integer index associated with selector. Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]). portmap : sequence of int Integer indices to map to port identifiers. """ self.portmap[self.sel.get_index(self.portmap, selector)] = portmap def equals(self, pm): """ Check whether this mapper is equivalent to another mapper. Parameters ---------- pm : neurokernel.plsel.BasePortMapper Mapper to compare to this mapper. Returns ------- result : bool True if the specified port mapper contains the same port identifiers as this instance and maps them to the same integer values. Notes ----- The port identifiers and maps in the specified port mapper need not be in the same order as this instance to be deemed equal. """ assert isinstance(pm, BasePortMapper) pm0 = self.portmap.sort_values() pm1 = pm.portmap.sort_values() if np.array_equal(pm0.values, pm1.values) and \ pm0.index.equals(pm1.index): return True else: return False def __len__(self): return self.portmap.size def __repr__(self): return 'Map:\n----\n' + self.portmap.__repr__()
def __init__(self, sel, sel_in, sel_out, sel_gpot, sel_spike, data_gpot, data_spike, columns=['interface', 'io', 'type'], ctrl_tag=CTRL_TAG, gpot_tag=GPOT_TAG, spike_tag=SPIKE_TAG, id=None, device=None, routing_table=None, rank_to_id=None, pm_all=None, debug=False, time_sync=False): # Call super for BaseModule rather than Module because most of the # functionality of the former's constructor must be overridden in any case: super(BaseModule, self).__init__(ctrl_tag) self.debug = debug self.time_sync = time_sync self.device = device self._gpot_tag = gpot_tag self._spike_tag = spike_tag # Require several necessary attribute columns: assert 'interface' in columns assert 'io' in columns assert 'type' in columns self._init_gpu() # This is needed to ensure that MPI_Finalize is called before PyCUDA # attempts to clean up; see # https://groups.google.com/forum/#!topic/mpi4py/by0Rd5q0Ayw atexit.register(MPI.Finalize) # Manually register the file close method associated with MPIOutput # so that it is called by atexit before MPI.Finalize() (if the file is # closed after MPI.Finalize() is called, an error will occur): for k, v in twiggy.emitters.iteritems(): if isinstance(v._output, MPIOutput): atexit.register(v._output.close) # Ensure that the input and output port selectors respectively # select mutually exclusive subsets of the set of all ports exposed by # the module: assert SelectorMethods.is_in(sel_in, sel) assert SelectorMethods.is_in(sel_out, sel) assert SelectorMethods.are_disjoint(sel_in, sel_out) # Ensure that the graded potential and spiking port selectors # respectively select mutually exclusive subsets of the set of all ports # exposed by the module: assert SelectorMethods.is_in(sel_gpot, sel) assert SelectorMethods.is_in(sel_spike, sel) assert SelectorMethods.are_disjoint(sel_gpot, sel_spike) # Save routing table and mapping between MPI ranks and module IDs: self.routing_table = routing_table self.rank_to_id = rank_to_id # Save module interface data (stored in a dict of BasePortMapper instances): self.pm_all = pm_all # Generate a unique ID if none is specified: if id is None: self.id = uid() else: # Save routing table; if a unique ID was specified, it must be a node in # the routing table: if routing_table is not None and not routing_table.has_node(id): raise ValueError( 'routing table must contain specified module ID') self.id = id # Reformat logger name: LoggerMixin.__init__(self, 'mod %s' % self.id) # Create module interface given the specified ports: self.interface = Interface(sel, columns) # Set the interface ID to 0; we assume that a module only has one interface: self.interface[sel, 'interface'] = 0 # Set the port attributes: self.interface[sel_in, 'io'] = 'in' self.interface[sel_out, 'io'] = 'out' self.interface[sel_gpot, 'type'] = 'gpot' self.interface[sel_spike, 'type'] = 'spike' # Find the input and output ports: self.in_ports = self.interface.in_ports().to_tuples() self.out_ports = self.interface.out_ports().to_tuples() # Find the graded potential and spiking ports: self.gpot_ports = self.interface.gpot_ports().to_tuples() self.spike_ports = self.interface.spike_ports().to_tuples() self.in_gpot_ports = self.interface.in_ports().gpot_ports().to_tuples() self.in_spike_ports = self.interface.in_ports().spike_ports( ).to_tuples() self.out_gpot_ports = self.interface.out_ports().gpot_ports( ).to_tuples() self.out_spike_ports = self.interface.out_ports().spike_ports( ).to_tuples() # Set up mapper between port identifiers and their associated data: assert len(data_gpot) == len(self.gpot_ports) assert len(data_spike) == len(self.spike_ports) self.data = {} self.data['gpot'] = gpuarray.to_gpu(data_gpot) self.data['spike'] = gpuarray.to_gpu(data_spike) self.pm = {} self.pm['gpot'] = GPUPortMapper(sel_gpot, self.data['gpot'], make_copy=False) self.pm['spike'] = GPUPortMapper(sel_spike, self.data['spike'], make_copy=False)
man = Manager() m1_int_sel_in_gpot = '/a/in/gpot0,/a/in/gpot1' m1_int_sel_out_gpot = '/a/out/gpot0,/a/out/gpot1' m1_int_sel_in_spike = '/a/in/spike0,/a/in/spike1' m1_int_sel_out_spike = '/a/out/spike0,/a/out/spike1' m1_int_sel = ','.join([ m1_int_sel_in_gpot, m1_int_sel_out_gpot, m1_int_sel_in_spike, m1_int_sel_out_spike ]) m1_int_sel_in = ','.join((m1_int_sel_in_gpot, m1_int_sel_in_spike)) m1_int_sel_out = ','.join((m1_int_sel_out_gpot, m1_int_sel_out_spike)) m1_int_sel_gpot = ','.join((m1_int_sel_in_gpot, m1_int_sel_out_gpot)) m1_int_sel_spike = ','.join((m1_int_sel_in_spike, m1_int_sel_out_spike)) N1_gpot = SelectorMethods.count_ports(m1_int_sel_gpot) N1_spike = SelectorMethods.count_ports(m1_int_sel_spike) m2_int_sel_in_gpot = '/b/in/gpot0,/b/in/gpot1' m2_int_sel_out_gpot = '/b/out/gpot0,/b/out/gpot1' m2_int_sel_in_spike = '/b/in/spike0,/b/in/spike1' m2_int_sel_out_spike = '/b/out/spike0,/b/out/spike1' m2_int_sel = ','.join([ m2_int_sel_in_gpot, m2_int_sel_out_gpot, m2_int_sel_in_spike, m2_int_sel_out_spike ]) m2_int_sel_in = ','.join((m2_int_sel_in_gpot, m2_int_sel_in_spike)) m2_int_sel_out = ','.join((m2_int_sel_out_gpot, m2_int_sel_out_spike)) m2_int_sel_gpot = ','.join((m2_int_sel_in_gpot, m2_int_sel_out_gpot)) m2_int_sel_spike = ','.join((m2_int_sel_in_spike, m2_int_sel_out_spike)) N2_gpot = SelectorMethods.count_ports(m2_int_sel_gpot)
def __init__(self, sel, sel_in, sel_out, sel_gpot, sel_spike, data_gpot, data_spike, columns=['interface', 'io', 'type'], port_data=PORT_DATA, port_ctrl=PORT_CTRL, port_time=PORT_TIME, id=None, device=None, debug=False, time_sync=False): self.debug = debug self.time_sync = time_sync self.device = device # Require several necessary attribute columns: assert 'interface' in columns assert 'io' in columns assert 'type' in columns # Generate a unique ID if none is specified: if id is None: id = uid() # Call super for BaseModule rather than Module because most of the # functionality of the former's constructor must be overridden in any case: super(BaseModule, self).__init__(port_ctrl, id) # Reformat logger name: LoggerMixin.__init__(self, 'mod %s' % self.id) # Data port: if port_data == port_ctrl: raise ValueError('data and control ports must differ') self.port_data = port_data if port_time == port_ctrl or port_time == port_data: raise ValueError('time port must differ from data and control ports') self.port_time = port_time # Initial network connectivity: self.net = 'none' # Create module interface given the specified ports: self.interface = Interface(sel, columns) # Set the interface ID to 0 # we assume that a module only has one interface: self.interface[sel, 'interface'] = 0 # Set port types: assert SelectorMethods.is_in(sel_in, sel) assert SelectorMethods.is_in(sel_out, sel) assert SelectorMethods.are_disjoint(sel_in, sel_out) self.interface[sel_in, 'io'] = 'in' self.interface[sel_out, 'io'] = 'out' assert SelectorMethods.is_in(sel_gpot, sel) assert SelectorMethods.is_in(sel_spike, sel) assert SelectorMethods.are_disjoint(sel_gpot, sel_spike) self.interface[sel_gpot, 'type'] = 'gpot' self.interface[sel_spike, 'type'] = 'spike' # Set up mapper between port identifiers and their associated data: assert len(data_gpot) == len(self.interface.gpot_ports()) assert len(data_spike) == len(self.interface.spike_ports()) self.data = {} self.data['gpot'] = data_gpot self.data['spike'] = data_spike self.pm = {} self.pm['gpot'] = PortMapper(sel_gpot, self.data['gpot']) self.pm['spike'] = PortMapper(sel_spike, self.data['spike']) # Patterns connecting this module instance with other modules instances. # Keyed on the IDs of those modules: self.patterns = {} # Each entry in pat_ints is a tuple containing the identifiers of which # of a pattern's identifiers are connected to the current module (first # entry) and the modules to which it is connected (second entry). # Keyed on the IDs of those modules: self.pat_ints = {} # Dict for storing incoming data; each entry (corresponding to each # module that sends input to the current module) is a deque containing # incoming data, which in turn contains transmitted data arrays. Deques # are used here to accommodate situations when multiple data from a # single source arrive: self._in_data = {} # List for storing outgoing data; each entry is a tuple whose first # entry is the source or destination module ID and whose second entry is # the data to transmit: self._out_data = [] # Dictionaries containing ports of source modules that # send output to this module. Must be initialized immediately before # an emulation begins running. Keyed on source module ID: self._in_port_dict = {} self._in_port_dict_ids = {} self._in_port_dict['gpot'] = {} self._in_port_dict['spike'] = {} # Dictionaries containing ports of destination modules that # receive input from this module. Must be initialized immediately before # an emulation begins running. Keyed on destination module ID: self._out_port_dict = {} self._out_port_dict_ids = {} self._out_port_dict['gpot'] = {} self._out_port_dict['spike'] = {} self._out_ids = [] self._in_ids = []
def emulate(n, steps): assert(n>1) n = str(n) # Set up emulation: man = Manager(get_random_port(), get_random_port(), get_random_port()) man.add_brok() m1_int_sel_in_gpot = '/a/in/gpot0,/a/in/gpot1' m1_int_sel_out_gpot = '/a/out/gpot0,/a/out/gpot1' m1_int_sel_in_spike = '/a/in/spike0,/a/in/spike1' m1_int_sel_out_spike = '/a/out/spike0,/a/out/spike1' m1_int_sel = ','.join([m1_int_sel_in_gpot, m1_int_sel_out_gpot, m1_int_sel_in_spike, m1_int_sel_out_spike]) m1_int_sel_in = ','.join([m1_int_sel_in_gpot, m1_int_sel_in_spike]) m1_int_sel_out = ','.join([m1_int_sel_out_gpot, m1_int_sel_out_spike]) m1_int_sel_gpot = ','.join([m1_int_sel_in_gpot, m1_int_sel_out_gpot]) m1_int_sel_spike = ','.join([m1_int_sel_in_spike, m1_int_sel_out_spike]) N1_gpot = SelectorMethods.count_ports(m1_int_sel_gpot) N1_spike = SelectorMethods.count_ports(m1_int_sel_spike) m1 = MyModule(m1_int_sel, m1_int_sel_in, m1_int_sel_out, m1_int_sel_gpot, m1_int_sel_spike, np.zeros(N1_gpot, np.float64), np.zeros(N1_spike, int), ['interface', 'io', 'type'], man.port_data, man.port_ctrl, man.port_time, 'm1', None, False, True) man.add_mod(m1) m2_int_sel_in_gpot = '/b/in/gpot0,/b/in/gpot1' m2_int_sel_out_gpot = '/b/out/gpot0,/b/out/gpot1' m2_int_sel_in_spike = '/b/in/spike0,/b/in/spike1' m2_int_sel_out_spike = '/b/out/spike0,/b/out/spike1' m2_int_sel = ','.join([m2_int_sel_in_gpot, m2_int_sel_out_gpot, m2_int_sel_in_spike, m2_int_sel_out_spike]) m2_int_sel_in = ','.join([m2_int_sel_in_gpot, m2_int_sel_in_spike]) m2_int_sel_out = ','.join([m2_int_sel_out_gpot, m2_int_sel_out_spike]) m2_int_sel_gpot = ','.join([m2_int_sel_in_gpot, m2_int_sel_out_gpot]) m2_int_sel_spike = ','.join([m2_int_sel_in_spike, m2_int_sel_out_spike]) N2_gpot = SelectorMethods.count_ports(m2_int_sel_gpot) N2_spike = SelectorMethods.count_ports(m2_int_sel_spike), m2 = MyModule(m2_int_sel, m2_int_sel_in, m2_int_sel_out, m2_int_sel_gpot, m2_int_sel_spike, np.zeros(N2_gpot, np.float64), np.zeros(N2_spike, int), ['interface', 'io', 'type'], man.port_data, man.port_ctrl, man.port_time, 'm2', None, False, True) man.add_mod(m2) # Make sure that all ports in the patterns' interfaces are set so # that they match those of the modules: pat12 = Pattern(m1_int_sel, m2_int_sel) pat12.interface[m1_int_sel_out_gpot] = [0, 'in', 'gpot'] pat12.interface[m1_int_sel_in_gpot] = [0, 'out', 'gpot'] pat12.interface[m1_int_sel_out_spike] = [0, 'in', 'spike'] pat12.interface[m1_int_sel_in_spike] = [0, 'out', 'spike'] pat12.interface[m2_int_sel_in_gpot] = [1, 'out', 'gpot'] pat12.interface[m2_int_sel_out_gpot] = [1, 'in', 'gpot'] pat12.interface[m2_int_sel_in_spike] = [1, 'out', 'spike'] pat12.interface[m2_int_sel_out_spike] = [1, 'in', 'spike'] pat12['/a/out/gpot0', '/b/in/gpot0'] = 1 pat12['/a/out/gpot1', '/b/in/gpot1'] = 1 pat12['/b/out/gpot0', '/a/in/gpot0'] = 1 pat12['/b/out/gpot1', '/a/in/gpot1'] = 1 pat12['/a/out/spike0', '/b/in/spike0'] = 1 pat12['/a/out/spike1', '/b/in/spike1'] = 1 pat12['/b/out/spike0', '/a/in/spike0'] = 1 pat12['/b/out/spike1', '/a/in/spike1'] = 1 man.connect(m1, m2, pat12, 0, 1) # To set the emulation to exit after executing a fixed number of steps, # start it as follows and remove the sleep statement: man.start(steps=steps) # man.start() # time.sleep(2) man.stop() return m1
def __init__(self, sel, sel_in, sel_out, sel_gpot, sel_spike, data_gpot, data_spike, columns=['interface', 'io', 'type'], ctrl_tag=CTRL_TAG, gpot_tag=GPOT_TAG, spike_tag=SPIKE_TAG, id=None, device=None, routing_table=None, rank_to_id=None, debug=False, time_sync=False): super(Module, self).__init__(ctrl_tag) self.debug = debug self.time_sync = time_sync self.device = device self._gpot_tag = gpot_tag self._spike_tag = spike_tag # Require several necessary attribute columns: if 'interface' not in columns: raise ValueError('interface column required') if 'io' not in columns: raise ValueError('io column required') if 'type' not in columns: raise ValueError('type column required') # Initialize GPU here so as to be able to initialize a port mapper # containing GPU memory: self._init_gpu() # This is needed to ensure that MPI_Finalize is called before PyCUDA # attempts to clean up; see # https://groups.google.com/forum/#!topic/mpi4py/by0Rd5q0Ayw atexit.register(MPI.Finalize) # Manually register the file close method associated with MPIOutput # so that it is called by atexit before MPI.Finalize() (if the file is # closed after MPI.Finalize() is called, an error will occur): for k, v in twiggy.emitters.iteritems(): if isinstance(v._output, MPIOutput): atexit.register(v._output.close) # Ensure that the input and output port selectors respectively # select mutually exclusive subsets of the set of all ports exposed by # the module: if not SelectorMethods.is_in(sel_in, sel): raise ValueError('input port selector not in selector of all ports') if not SelectorMethods.is_in(sel_out, sel): raise ValueError('output port selector not in selector of all ports') if not SelectorMethods.are_disjoint(sel_in, sel_out): raise ValueError('input and output port selectors not disjoint') # Ensure that the graded potential and spiking port selectors # respectively select mutually exclusive subsets of the set of all ports # exposed by the module: if not SelectorMethods.is_in(sel_gpot, sel): raise ValueError('gpot port selector not in selector of all ports') if not SelectorMethods.is_in(sel_spike, sel): raise ValueError('spike port selector not in selector of all ports') if not SelectorMethods.are_disjoint(sel_gpot, sel_spike): raise ValueError('gpot and spike port selectors not disjoint') # Save routing table and mapping between MPI ranks and module IDs: self.routing_table = routing_table self.rank_to_id = rank_to_id # Generate a unique ID if none is specified: if id is None: self.id = uid() else: # If a unique ID was specified and the routing table is not empty # (i.e., there are connections between multiple modules), the id # must be a node in the routing table: if routing_table is not None and len(routing_table.ids) and \ not routing_table.has_node(id): raise ValueError('routing table must contain specified ' 'module ID: {}'.format(id)) self.id = id # Reformat logger name: LoggerMixin.__init__(self, 'mod %s' % self.id) # Create module interface given the specified ports: self.interface = Interface(sel, columns) # Set the interface ID to 0; we assume that a module only has one interface: self.interface[sel, 'interface'] = 0 # Set the port attributes: self.interface[sel_in, 'io'] = 'in' self.interface[sel_out, 'io'] = 'out' self.interface[sel_gpot, 'type'] = 'gpot' self.interface[sel_spike, 'type'] = 'spike' # Find the input and output ports: self.in_ports = self.interface.in_ports().to_tuples() self.out_ports = self.interface.out_ports().to_tuples() # Find the graded potential and spiking ports: self.gpot_ports = self.interface.gpot_ports().to_tuples() self.spike_ports = self.interface.spike_ports().to_tuples() self.in_gpot_ports = self.interface.in_ports().gpot_ports().to_tuples() self.in_spike_ports = self.interface.in_ports().spike_ports().to_tuples() self.out_gpot_ports = self.interface.out_ports().gpot_ports().to_tuples() self.out_spike_ports = self.interface.out_ports().spike_ports().to_tuples() # Set up mapper between port identifiers and their associated data: if len(data_gpot) != len(self.gpot_ports): raise ValueError('incompatible gpot port data array length') if len(data_spike) != len(self.spike_ports): raise ValueError('incompatible spike port data array length') self.data = {} self.data['gpot'] = gpuarray.to_gpu(data_gpot) self.data['spike'] = gpuarray.to_gpu(data_spike) self.pm = {} self.pm['gpot'] = GPUPortMapper(sel_gpot, self.data['gpot'], make_copy=False) self.pm['spike'] = GPUPortMapper(sel_spike, self.data['spike'], make_copy=False) # MPI Request object for resolving asynchronous transfers: self.req = MPI.Request()
class BasePortMapper(object): """ Maps integer sequence to/from path-like port identifiers. Examples -------- >>> pm = BasePortMapper('/[a,b][0:2]') >>> print pm.ports_to_inds('/b[0:2]') array([2, 3]) >>> print pm.inds_to_ports([0, 1]) [('a', 0), ('a', 1)] Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]) to map to `data`. portmap : sequence of int Integer indices to map to port identifiers. If no map is specified, it is assumed to be an array of consecutive integers from 0 through one less than the number of ports. Attributes ---------- index : pandas.MultiIndex Index of port identifiers. portmap : pandas.Series Map of port identifiers to integer indices. Notes ----- The selectors may not contain any '*' or '[:]' characters. A single port identifier may be mapped to multiple integer indices, but not vice-versa. """ def __init__(self, selector, portmap=None): self.sel = SelectorMethods() N = self.sel.count_ports(selector) if portmap is None: self.portmap = pd.Series(data=np.arange(N)) else: assert len(portmap) == N self.portmap = pd.Series(data=np.array(portmap)) self.portmap.index = self.sel.make_index(selector) def copy(self): """ Return copy of this port mapper. Returns ------- result : neurokernel.plsel.BasePortMapper Copy of port mapper instance. """ c = BasePortMapper('') c.portmap = self.portmap.copy() return c @classmethod def from_index(cls, idx, portmap=None): """ Create port mapper from a Pandas index and a sequence of integer indices. Parameters ---------- index : pandas.MultiIndex Index containing selector data. portmap : sequence of int Integer indices to map to port identifiers. If no map is specified, it is assumed to be an array of consecutive integers from 0 through one less than the number of ports. Returns ------- result : neurokernel.plsel.BasePortMapper New port mapper instance. Notes ----- If specified, the portmap sequence is copied into the new mapper to avoid side effects associated with modifying the specified sequence after mapper instantiation. """ pm = cls('') N = len(idx) if portmap is None: pm.portmap = pd.Series.from_array(np.arange(N), idx) else: assert len(portmap) == N pm.portmap = pd.Series.from_array(np.array(portmap), idx) return pm @classmethod def from_pm(cls, pm): """ Create a new port mapper instance given an existing instance. Parameters ---------- result : neurokernel.plsel.BasePortMapper Existing port mapper instance. Returns ------- result : neurokernel.plsel.BasePortMapper New port mapper instance. """ assert isinstance(pm, cls) r = cls('') r.portmap = pm.portmap.copy() return r @property def index(self): """ Port mapper index. """ return self.portmap.index @index.setter def index(self, i): self.portmap.index = i def inds_to_ports(self, inds): """ Convert list of integer indices to port identifiers. Examples -------- >>> pm = BasePortMapper('/[a,b][0:2]') >>> print pm.inds_to_ports([0, 1]) [('a', 0), ('a', 1)] Parameters ---------- inds : array_like of int Integer indices of ports. Returns ------- t : list of tuple Expanded port identifiers. """ return self.portmap[self.portmap.isin(inds)].index.tolist() def ports_to_inds(self, selector): """ Convert port selector to list of integer indices. Examples -------- >>> pm = BasePortMapper('/[a,b][0:2]') >>> print pm.ports_to_inds('/b[0:2]') Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]). Returns ------- inds : numpy.ndarray of int Integer indices of ports comprised by selector. """ return self.sel.select(self.portmap, selector).dropna().astype(np.int_).values def get_map(self, selector): """ Retrieve integer indices associated with selector. Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]). Returns ------- result : numpy.ndarray Selected data. """ return np.asarray(self.sel.select(self.portmap, selector).dropna()) def set_map(self, selector, portmap): """ Set mapped integer index associated with selector. Parameters ---------- selector : str, unicode, or sequence Selector string (e.g., '/foo[0:2]') or sequence of token sequences (e.g., [['foo', (0, 2)]]). portmap : sequence of int Integer indices to map to port identifiers. """ self.portmap[self.sel.get_index(self.portmap, selector)] = portmap def equals(self, pm): """ Check whether this mapper is equivalent to another mapper. Parameters ---------- pm : neurokernel.plsel.BasePortMapper Mapper to compare to this mapper. Returns ------- result : bool True if the specified port mapper contains the same port identifiers as this instance and maps them to the same integer values. Notes ----- The port identifiers and maps in the specified port mapper need not be in the same order as this instance to be deemed equal. """ assert isinstance(pm, BasePortMapper) pm0 = self.portmap.sort_values() pm1 = pm.portmap.sort_values() if np.array_equal(pm0.values, pm1.values) and \ pm0.index.equals(pm1.index): return True else: return False def __len__(self): return self.portmap.size def __repr__(self): return 'Map:\n----\n'+self.portmap.__repr__()
def __init__(self, sel, sel_in, sel_out, sel_gpot, sel_spike, data_gpot, data_spike, columns=['interface', 'io', 'type'], ctrl_tag=CTRL_TAG, gpot_tag=GPOT_TAG, spike_tag=SPIKE_TAG, id=None, device=None, routing_table=None, rank_to_id=None, pm_all=None, debug=False, time_sync=False): # Call super for BaseModule rather than Module because most of the # functionality of the former's constructor must be overridden in any case: super(BaseModule, self).__init__(ctrl_tag) self.debug = debug self.time_sync = time_sync self.device = device self._gpot_tag = gpot_tag self._spike_tag = spike_tag # Require several necessary attribute columns: assert 'interface' in columns assert 'io' in columns assert 'type' in columns self._init_gpu() # This is needed to ensure that MPI_Finalize is called before PyCUDA # attempts to clean up; see # https://groups.google.com/forum/#!topic/mpi4py/by0Rd5q0Ayw atexit.register(MPI.Finalize) # Manually register the file close method associated with MPIOutput # so that it is called by atexit before MPI.Finalize() (if the file is # closed after MPI.Finalize() is called, an error will occur): for k, v in twiggy.emitters.iteritems(): if isinstance(v._output, MPIOutput): atexit.register(v._output.close) # Ensure that the input and output port selectors respectively # select mutually exclusive subsets of the set of all ports exposed by # the module: assert SelectorMethods.is_in(sel_in, sel) assert SelectorMethods.is_in(sel_out, sel) assert SelectorMethods.are_disjoint(sel_in, sel_out) # Ensure that the graded potential and spiking port selectors # respectively select mutually exclusive subsets of the set of all ports # exposed by the module: assert SelectorMethods.is_in(sel_gpot, sel) assert SelectorMethods.is_in(sel_spike, sel) assert SelectorMethods.are_disjoint(sel_gpot, sel_spike) # Save routing table and mapping between MPI ranks and module IDs: self.routing_table = routing_table self.rank_to_id = rank_to_id # Save module interface data (stored in a dict of BasePortMapper instances): self.pm_all = pm_all # Generate a unique ID if none is specified: if id is None: self.id = uid() else: # Save routing table; if a unique ID was specified, it must be a node in # the routing table: if routing_table is not None and not routing_table.has_node(id): raise ValueError('routing table must contain specified module ID') self.id = id # Reformat logger name: LoggerMixin.__init__(self, 'mod %s' % self.id) # Create module interface given the specified ports: self.interface = Interface(sel, columns) # Set the interface ID to 0; we assume that a module only has one interface: self.interface[sel, 'interface'] = 0 # Set the port attributes: self.interface[sel_in, 'io'] = 'in' self.interface[sel_out, 'io'] = 'out' self.interface[sel_gpot, 'type'] = 'gpot' self.interface[sel_spike, 'type'] = 'spike' # Find the input and output ports: self.in_ports = self.interface.in_ports().to_tuples() self.out_ports = self.interface.out_ports().to_tuples() # Find the graded potential and spiking ports: self.gpot_ports = self.interface.gpot_ports().to_tuples() self.spike_ports = self.interface.spike_ports().to_tuples() self.in_gpot_ports = self.interface.in_ports().gpot_ports().to_tuples() self.in_spike_ports = self.interface.in_ports().spike_ports().to_tuples() self.out_gpot_ports = self.interface.out_ports().gpot_ports().to_tuples() self.out_spike_ports = self.interface.out_ports().spike_ports().to_tuples() # Set up mapper between port identifiers and their associated data: assert len(data_gpot) == len(self.gpot_ports) assert len(data_spike) == len(self.spike_ports) self.data = {} self.data['gpot'] = gpuarray.to_gpu(data_gpot) self.data['spike'] = gpuarray.to_gpu(data_spike) self.pm = {} self.pm['gpot'] = GPUPortMapper(sel_gpot, self.data['gpot'], make_copy=False) self.pm['spike'] = GPUPortMapper(sel_spike, self.data['spike'], make_copy=False)