Пример #1
0
 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)
Пример #2
0
 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)
Пример #3
0
    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'])
Пример #4
0
    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)
Пример #5
0
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__()
Пример #6
0
    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)
Пример #7
0
    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)
Пример #8
0
    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 = []
Пример #9
0
    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
Пример #10
0
    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()
Пример #11
0
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__()
Пример #12
0
    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)