Changeset 998 for trunk

Show
Ignore:
Timestamp:
10/12/11 10:20:32 (7 months ago)
Author:
apdavison
Message:

Removed ConnectionManager. Now that connect() returns a Projection, ConnectionManager is no longer needed so its functionality has been returned to Projection for the sake of simplicity.

Location:
trunk
Files:
24 modified

Legend:

Unmodified
Added
Removed
  • trunk/examples/VAbenchmarks2-csa.py

    r915 r998  
    131131 
    132132print "%s Initialising membrane potential to random values..." % node_id 
    133 rng = NumpyRNG(seed=rngseed, parallel_safe=parallel_safe, rank=node_id, num_processes=np) 
     133rng = NumpyRNG(seed=rngseed, parallel_safe=parallel_safes) 
    134134uniformDistr = RandomDistribution('uniform', [v_reset,v_thresh], rng=rng) 
    135135all_cells.initialize('v', uniformDistr) 
  • trunk/examples/iaf_sfa_relref/iaf_sfa_network_INH_GAMMA.py

    r910 r998  
    140140            # Connect everything up 
    141141            yTimer = time.time() 
    142             projection.connection_manager.convergent_connect(chosenPresIDs, currentPostID, weights, delaysClipped) 
     142            projection._convergent_connect(chosenPresIDs, currentPostID, weights, delaysClipped) 
    143143            timer4 += time.time() - myTimer 
    144144             
  • trunk/examples/iaf_sfa_relref/iaf_sfa_network_STATIC.py

    r920 r998  
    142142            # Connect everything up 
    143143            yTimer = time.time() 
    144             projection.connection_manager.convergent_connect(chosenPresIDs, currentPostID, weights, delaysClipped) 
     144            projection._convergent_connect(chosenPresIDs, currentPostID, weights, delaysClipped) 
    145145            timer4 += time.time() - myTimer 
    146146             
  • trunk/src/brian/__init__.py

    r962 r998  
    131131#                                            threshold=v_thresh, 
    132132#                                            reset=v_reset, 
    133 #                                            clock=state.simclock, 
     133#                                            clock=simulator.state.simclock, 
    134134#                                            compile=True, 
    135 #                                            max_delay=state.max_delay) 
     135#                                            max_delay=simulator.state.max_delay) 
    136136#            cell_parameters = cellparams or {} 
    137137#        elif isinstance(cellclass, type) and issubclass(cellclass, standardmodels.StandardCellType): 
     
    238238        else:         
    239239            self._plasticity_model = "static_synapse" 
    240                                          
    241         self.connection_manager = simulator.ConnectionManager(self.synapse_type, self._plasticity_model, parent=self) 
    242         self.connections = self.connection_manager         
     240         
     241        self._n                 = {} 
     242        self._brian_connections = {} 
     243        self._indices           = {} 
     244        self._populations      = [{}, {}] 
     245               
    243246        method.connect(self) 
    244         self.connection_manager._finalize() 
     247        self._finalize() 
     248         
    245249        if self._plasticity_model != "static_synapse": 
    246             for key in self.connections.keys: 
    247                 synapses = self.connections.brian_connections[key] 
     250            for key in self._brian_connections.keys: 
     251                synapses = self._brian_connections[key] 
    248252                if self._plasticity_model is "stdp_synapse":  
    249253                    parameters   = self.synapse_dynamics.slow.all_parameters 
     
    268272                                            parameters['U']) 
    269273                    simulator.state.add(stp) 
    270                      
     274     
     275    def __len__(self): 
     276        """Return the total number of connections in this Projection.""" 
     277        result = 0 
     278        for key in self._brian_connections.keys(): 
     279            result += self._n[key] 
     280        return result 
     281     
     282    def _get_indices(self): 
     283        sources = numpy.array([], int) 
     284        targets = numpy.array([], int) 
     285        for key in self._brian_connections.keys(): 
     286            paddings = self._populations[0][key[0]], self._populations[1][key[1]]  
     287            sources  = numpy.concatenate((sources, self._indices[key][0] + paddings[0])) 
     288            targets  = numpy.concatenate((targets, self._indices[key][1] + paddings[1])) 
     289        return sources.astype(int), targets.astype(int)     
     290     
     291    def __getitem__(self, i): 
     292        """Return the `i`th connection as a Connection object.""" 
     293        cumsum_idx     = numpy.cumsum(self._n.values()) 
     294        if isinstance(i, slice): 
     295            idx  = numpy.searchsorted(cumsum_idx, numpy.arange(*i.indices(i.stop)), 'left') 
     296            keys = [self._brian_connections.keys()[j] for j in idx] 
     297        else: 
     298            idx  = numpy.searchsorted(cumsum_idx, i, 'left') 
     299            keys = self._brian_connections.keys()[idx] 
     300        global_indices = self._get_indices() 
     301        if isinstance(i, int): 
     302            if i < len(self): 
     303                pad        = i - cumsum_idx[idx] 
     304                local_idx  = self._indices[keys][0][pad], self._indices[keys][1][pad] 
     305                local_addr = global_indices[0][i], global_indices[1][i] 
     306                return Connection(self._brian_connections[keys], local_idx, local_addr) 
     307            else: 
     308                raise IndexError("%d > %d" % (i, len(self)-1)) 
     309        elif isinstance(i, slice): 
     310            if i.stop < len(self): 
     311                res = [] 
     312                for count, j in enumerate(xrange(*i.indices(i.stop))): 
     313                    key = keys[count] 
     314                    pad = j - cumsum_idx[idx[count]] 
     315                    local_idx  = self._indices[key][0][pad], self._indices[key][1][pad] 
     316                    local_addr = global_indices[0][j], global_indices[1][j] 
     317                    res.append(simulator.Connection(self._brian_connections[key], local_idx, local_addr)) 
     318                return res 
     319            else: 
     320                raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
     321     
     322    def __connection_generator(self): 
     323        """Yield each connection in turn.""" 
     324        global_indices = self._get_indices() 
     325        count = 0 
     326        for key in self._brian_connections.keys(): 
     327            bc = self._brian_connections[key] 
     328            for i in xrange(bc.W.getnnz()): 
     329                local_idx  = self._indices[key][0][i], self._indices[key][0][i]  
     330                local_addr = global_indices[0][count], global_indices[1][count] 
     331                yield simulator.Connection(bc, self._indices[key]) 
     332                count += 1                 
     333                 
     334    def __iter__(self): 
     335        """Return an iterator over all connections in this Projection.""" 
     336        return self.__connection_generator() 
     337     
     338    def _finalize(self): 
     339        for key in self._brian_connections.keys(): 
     340            self._indices[key]  = self._brian_connections[key].W.nonzero() 
     341            self._brian_connections[key].compress()      
     342     
     343    def _get_brian_connection(self, source_group, target_group, synapse_obj, weight_units, homogeneous=False): 
     344        """ 
     345        Return the Brian Connection object that connects two NeuronGroups with a 
     346        given synapse model. 
     347         
     348        source_group -- presynaptic Brian NeuronGroup. 
     349        target_group -- postsynaptic Brian NeuronGroup 
     350        synapse_obj  -- name of the variable that will be modified by synaptic 
     351                        input. 
     352        weight_units -- Brian Units object: nA for current-based synapses, 
     353                        uS for conductance-based synapses. 
     354        """ 
     355        key = (source_group, target_group, synapse_obj) 
     356        if not self._brian_connections.has_key(key): 
     357            assert isinstance(source_group, brian.NeuronGroup) 
     358            assert isinstance(target_group, brian.NeuronGroup), type(target_group) 
     359            assert isinstance(synapse_obj, basestring), "%s (%s)" % (synapse_obj, type(synapse_obj)) 
     360            try: 
     361                max_delay = simulator.state.max_delay*ms 
     362            except Exception: 
     363                raise Exception("Simulation timestep not yet set. Need to call setup()") 
     364            if not homogeneous: 
     365                self._brian_connections[key] = brian.DelayConnection(source_group, 
     366                                                               target_group, 
     367                                                               synapse_obj, 
     368                                                               max_delay=max_delay) 
     369            else: 
     370                self._brian_connections[key] = brian.Connection(source_group, 
     371                                                          target_group, 
     372                                                          synapse_obj, 
     373                                                          max_delay=simulator.state.max_delay*ms) 
     374            self._brian_connections[key].weight_units = weight_units 
     375            simulator.state.add(self._brian_connections[key]) 
     376            self._n[key] = 0 
     377        return self._brian_connections[key] 
     378     
     379    def _detect_parent_groups(self, cells): 
     380        groups = {} 
     381        for index, cell in enumerate(cells): 
     382            group = cell.parent_group 
     383            if not groups.has_key(group): 
     384                groups[group] = [index] 
     385            else: 
     386                groups[group] += [index] 
     387        return groups 
     388     
     389    def _divergent_connect(self, source, targets, weights, delays, homogeneous=False): 
     390        """ 
     391        Connect a neuron to one or more other neurons with a static connection. 
     392         
     393        `source`  -- the ID of the pre-synaptic cell. 
     394        `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
     395        `weight`  -- a list/1D array of connection weights, or a single weight. 
     396                     Must have the same length as `targets`. 
     397        `delays`  -- a list/1D array of connection delays, or a single delay. 
     398                     Must have the same length as `targets`. 
     399        """ 
     400        #print "connecting", source, "to", targets, "with weights", weights, "and delays", delays 
     401        if not core.is_listlike(targets): 
     402            targets = [targets] 
     403        if isinstance(weights, float): 
     404            weights = [weights] 
     405        if isinstance(delays, float): 
     406            delays = [delays] 
     407        assert len(targets) > 0 
     408        if not isinstance(source, common.IDMixin): 
     409            raise errors.ConnectionError("source should be an ID object, actually %s" % type(source)) 
     410        for target in targets: 
     411            if not isinstance(target, common.IDMixin): 
     412                raise errors.ConnectionError("Invalid target ID: %s" % target) 
     413        assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets),len(weights),len(delays)) 
     414        if common.is_conductance(targets[0]): 
     415            units = uS 
     416        else: 
     417            units = nA 
     418        synapse_type = self.synapse_type or "excitatory" 
     419        try: 
     420            source_group = source.parent_group 
     421        except AttributeError, errmsg: 
     422            raise errors.ConnectionError("%s. Maybe trying to connect from non-existing cell (ID=%s)." % (errmsg, source)) 
     423        groups = self._detect_parent_groups(targets) # we assume here all the targets belong to the same NeuronGroup 
     424         
     425        weights = numpy.array(weights) * units 
     426        delays  = numpy.array(delays) * ms 
     427        weights[weights == 0] = simulator.ZERO_WEIGHT             
     428         
     429        for target_group, indices in groups.items(): 
     430            synapse_obj = targets[indices[0]].parent.celltype.synapses[synapse_type]         
     431            bc          = self._get_brian_connection(source_group, target_group, synapse_obj, units, homogeneous)        
     432            padding     = (int(source.parent.first_id), int(targets[indices[0]].parent.first_id)) 
     433            src         = int(source) - padding[0] 
     434            mytargets   = numpy.array(targets, int)[indices] - padding[1]             
     435            bc.W.rows[src] = mytargets 
     436            bc.W.data[src] = weights[indices]         
     437            if not homogeneous: 
     438                bc.delayvec.rows[src] = mytargets 
     439                bc.delayvec.data[src] = delays[indices] 
     440            else: 
     441                bc.delay = int(delays[0] / bc.source.clock.dt) 
     442            key = (source_group, target_group, synapse_obj) 
     443            self._n[key] += len(mytargets) 
     444             
     445            pop_sources = self._populations[0] 
     446            if len(pop_sources) is 0: 
     447                pop_sources[source_group] = 0 
     448            elif not pop_sources.has_key(source_group): 
     449                pop_sources[source_group] = numpy.sum([len(item) for item in pop_sources.keys()]) 
     450            pop_targets = self._populations[1] 
     451            if len(pop_targets) is 0: 
     452                pop_targets[target_group] = 0 
     453            elif not pop_targets.has_key(target_group): 
     454                pop_targets[target_group] = numpy.sum([len(item) for item in pop_targets.keys()])   
     455 
    271456    def saveConnections(self, file, gather=True, compatible_output=True): 
    272457        """ 
     
    275460        """ 
    276461        import operator 
    277         lines   = numpy.empty((len(self.connection_manager), 4)) 
     462        lines   = numpy.empty((len(self), 4)) 
    278463        padding = 0 
    279         for key in self.connection_manager.keys: 
    280             bc   = self.connection_manager.brian_connections[key] 
     464        for key in self._brian_connections.keys(): 
     465            bc   = self._brian_connections[key] 
    281466            size = bc.W.getnnz() 
    282             lines[padding:padding+size,0], lines[padding:padding+size,1] = self.connection_manager.indices[key] 
     467            lines[padding:padding+size,0], lines[padding:padding+size,1] = self._indices[key] 
    283468            lines[padding:padding+size,2] = bc.W.alldata / bc.weight_units 
    284469            if isinstance(bc, brian.DelayConnection): 
     
    296481        file.close() 
    297482 
     483    def set(self, name, value): 
     484        """ 
     485        Set connection attributes for all connections in this Projection. 
     486         
     487        `name`  -- attribute name 
     488        `value` -- the attribute numeric value, or a list/1D array of such 
     489                   values of the same length as the number of local connections, 
     490                   or a 2D array with the same dimensions as the connectivity 
     491                   matrix (as returned by `get(format='array')`). 
     492        """ 
     493        for key in self._brian_connections.keys(): 
     494            bc = self._brian_connections[key] 
     495            padding = 0 
     496            if name == 'weight': 
     497                M = bc.W 
     498                units = bc.weight_units 
     499            elif name == 'delay': 
     500                M = bc.delay 
     501                units = ms 
     502            else: 
     503                raise Exception("Setting parameters other than weight and delay not yet supported.") 
     504            value = value*units 
     505            if numpy.isscalar(value): 
     506                if (name == 'weight') or (name == 'delay' and isinstance(bc, brian.DelayConnection)): 
     507                    for row in xrange(M.shape[0]): 
     508                        M.set_row(row, value) 
     509                elif (name == 'delay' and isinstance(bc, brian.Connection)): 
     510                    bc.delay = int(value / bc.source.clock.dt) 
     511                else: 
     512                    raise Exception("Setting a non appropriate parameter") 
     513            elif isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
     514                if (name == 'delay') and not isinstance(bc, brian.DelayConnection): 
     515                    raise Exception("FastConnector have been used, and only fixed homogeneous delays are allowed") 
     516                address_gen = ((i, j) for i,row in enumerate(bc.W.rows) for j in row) 
     517                for (i,j) in address_gen: 
     518                    M[i,j] = value[i,j] 
     519            elif core.is_listlike(value): 
     520                N = M.getnnz() 
     521                assert len(value[padding:padding+N]) == N 
     522                if (name == 'delay') and not isinstance(bc, brian.DelayConnection): 
     523                    raise Exception("FastConnector have been used: only fixed homogeneous delays are allowed") 
     524                M.alldata = value 
     525            else: 
     526                raise Exception("Values must be scalars or lists/arrays") 
     527            padding += M.getnnz() 
     528 
     529    def get(self, parameter_name, format, gather=True): 
     530        """ 
     531        Get the values of a given attribute (weight or delay) for all 
     532        connections in this Projection. 
     533         
     534        `parameter_name` -- name of the attribute whose values are wanted. 
     535        `format` -- "list" or "array". Array format implicitly assumes that all 
     536                    connections belong to a single Projection. 
     537         
     538        Return a list or a 2D Numpy array. The array element X_ij contains the 
     539        attribute value for the connection from the ith neuron in the pre- 
     540        synaptic Population to the jth neuron in the post-synaptic Population, 
     541        if such a connection exists. If there are no such connections, X_ij will 
     542        be NaN. 
     543        """ 
     544        values = numpy.array([]) 
     545        for key in self._brian_connections.keys(): 
     546            bc = self._brian_connections[key] 
     547            if parameter_name == "weight": 
     548                values = numpy.concatenate((values, bc.W.alldata / bc.weight_units))             
     549            elif parameter_name == 'delay': 
     550                if isinstance(bc, brian.DelayConnection): 
     551                    values = numpy.concatenate((values, bc.delay.alldata / ms)) 
     552                else: 
     553                    data   = bc.delay * bc.source.clock.dt * numpy.ones(bc.W.getnnz()) /ms 
     554                    values = numpy.concatenate((values, data)) 
     555            else: 
     556                raise Exception("Getting parameters other than weight and delay not yet supported.") 
     557         
     558        if format == 'list': 
     559            values = values.tolist() 
     560        elif format == 'array': 
     561            values_arr = numpy.nan * numpy.ones((self.parent.pre.size, self.parent.post.size)) 
     562            sources, targets = self._indices 
     563            values_arr[sources, targets] = values 
     564            values = values_arr 
     565        else: 
     566            raise Exception("format must be 'list' or 'array', actually '%s'" % format) 
     567        return values 
     568 
    298569Space = space.Space 
    299570 
  • trunk/src/brian/connectors.py

    r962 r998  
    6969        homogeneous = numpy.isscalar(self.delays_generator.source) 
    7070        if len(targets) > 0: 
    71             self.projection.connection_manager.connect(src, targets.tolist(), weights, delays, homogeneous) 
     71            self.projection._divergent_connect(src, targets.tolist(), weights, delays, homogeneous) 
    7272 
    7373 
     
    136136            for tgt, src, w, d in zip(projection.post.local_cells, sources, weights, delays): 
    137137                # the float is in case the values are of type numpy.float64, which NEST chokes on 
    138                 projection.connection_manager.connect(src, [tgt], float(w), float(d), homogeneous) 
     138                projection._divergent_connect(src, [tgt], float(w), float(d), homogeneous) 
    139139                self.progression(count) 
    140140                count += 1 
  • trunk/src/brian/simulator.py

    r957 r998  
    44implementation of the API. 
    55 
    6 Functions and classes useable by the common implementation: 
     6Functions and classes usable by the common implementation: 
    77 
    88Functions: 
    9     create_cells() 
    109    reset() 
    1110    run() 
     
    1413    ID 
    1514    Recorder 
    16     ConnectionManager 
    1715    Connection 
    1816     
     
    397395                   in the weight array. 
    398396        `indices` -- the mapping of the x, y coordinates of the established 
    399                      connections, stored by the connection_manager handling those 
     397                     connections, stored by the Projection handling those 
    400398                     connections. 
    401399        """ 
     
    425423    weight = property(_get_weight, _set_weight) 
    426424    delay = property(_get_delay, _set_delay) 
    427      
    428  
    429 class ConnectionManager(object): 
    430     """ 
    431     Manage synaptic connections, providing methods for creating, listing, 
    432     accessing individual connections. 
    433     """ 
    434  
    435     def __init__(self, synapse_type, synapse_model=None, parent=None): 
    436         """ 
    437         Create a new ConnectionManager. 
    438          
    439         `synapse_type` -- the 'physiological type' of the synapse, e.g. 
    440                           'excitatory' or 'inhibitory',or any other key in the 
    441                           `synapses` attibute of the celltype class. 
    442         `synapse_model` -- not used. Present for consistency with other simulators. 
    443         `parent` -- the parent `Projection`, if any. 
    444         """ 
    445         self.synapse_type      = synapse_type 
    446         self.synapse_model     = synapse_model 
    447         self.parent            = parent 
    448         self.n                 = {} 
    449         self.brian_connections = {} 
    450         self.indices           = {} 
    451         self._populations      = [{}, {}] 
    452          
    453     def __getitem__(self, i): 
    454         """Return the `i`th connection as a Connection object.""" 
    455         cumsum_idx     = numpy.cumsum(self.n.values()) 
    456         if isinstance(i, slice): 
    457             idx  = numpy.searchsorted(cumsum_idx, numpy.arange(*i.indices(i.stop)), 'left') 
    458             keys = [self.keys[j] for j in idx] 
    459         else: 
    460             idx  = numpy.searchsorted(cumsum_idx, i, 'left') 
    461             keys = self.keys[idx] 
    462         global_indices = self._indices 
    463         if isinstance(i, int): 
    464             if i < len(self): 
    465                 pad        = i - cumsum_idx[idx] 
    466                 local_idx  = self.indices[keys][0][pad], self.indices[keys][1][pad] 
    467                 local_addr = global_indices[0][i], global_indices[1][i] 
    468                 return Connection(self.brian_connections[keys], local_idx, local_addr) 
    469             else: 
    470                 raise IndexError("%d > %d" % (i, len(self)-1)) 
    471         elif isinstance(i, slice): 
    472             if i.stop < len(self): 
    473                 res = [] 
    474                 for count, j in enumerate(xrange(*i.indices(i.stop))): 
    475                     key = keys[count] 
    476                     pad = j - cumsum_idx[idx[count]] 
    477                     local_idx  = self.indices[key][0][pad], self.indices[key][1][pad] 
    478                     local_addr = global_indices[0][j], global_indices[1][j] 
    479                     res.append(Connection(self.brian_connections[key], local_idx, local_addr)) 
    480                 return res 
    481             else: 
    482                 raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
    483      
    484     def __len__(self): 
    485         """Return the total number of connections in this manager.""" 
    486         result = 0 
    487         for key in self.keys: 
    488           result += self.n[key] 
    489         return result  
    490      
    491     def __connection_generator(self): 
    492         """Yield each connection in turn.""" 
    493         global_indices = self._indices 
    494         count          = 0 
    495         for key in self.keys: 
    496             bc = self.brian_connections[key] 
    497             for i in xrange(bc.W.getnnz()): 
    498                 local_idx  = self.indices[key][0][i], self.indices[key][0][i]  
    499                 local_addr = global_indices[0][count], global_indices[1][count] 
    500                 yield Connection(bc, self.indices[key]) 
    501                 count     += 1                 
    502                  
    503     @property 
    504     def keys(self): 
    505         return self.brian_connections.keys() 
    506                  
    507     def __iter__(self): 
    508         """Return an iterator over all connections in this manager.""" 
    509         return self.__connection_generator() 
    510      
    511     def _finalize(self): 
    512         for key in self.keys: 
    513             self.indices[key]  = self.brian_connections[key].W.nonzero() 
    514             self.brian_connections[key].compress()             
    515      
    516     @property 
    517     def _indices(self): 
    518         sources = numpy.array([], int) 
    519         targets = numpy.array([], int) 
    520         for key in self.keys: 
    521             paddings = self._populations[0][key[0]], self._populations[1][key[1]]  
    522             sources  = numpy.concatenate((sources, self.indices[key][0] + paddings[0])) 
    523             targets  = numpy.concatenate((targets, self.indices[key][1] + paddings[1])) 
    524         return sources.astype(int), targets.astype(int)     
    525      
    526     def _get_brian_connection(self, source_group, target_group, synapse_obj, weight_units, homogeneous=False): 
    527         """ 
    528         Return the Brian Connection object that connects two NeuronGroups with a 
    529         given synapse model. 
    530          
    531         source_group -- presynaptic Brian NeuronGroup. 
    532         target_group -- postsynaptic Brian NeuronGroup 
    533         synapse_obj  -- name of the variable that will be modified by synaptic 
    534                         input. 
    535         weight_units -- Brian Units object: nA for current-based synapses, 
    536                         uS for conductance-based synapses. 
    537         """ 
    538         key = (source_group, target_group, synapse_obj) 
    539         if not self.brian_connections.has_key(key): 
    540             assert isinstance(source_group, brian.NeuronGroup) 
    541             assert isinstance(target_group, brian.NeuronGroup), type(target_group) 
    542             assert isinstance(synapse_obj, basestring), "%s (%s)" % (synapse_obj, type(synapse_obj)) 
    543             try: 
    544                 max_delay = state.max_delay*ms 
    545             except Exception: 
    546                 raise Exception("Simulation timestep not yet set. Need to call setup()") 
    547             if not homogeneous: 
    548                 self.brian_connections[key] = brian.DelayConnection(source_group, 
    549                                                                target_group, 
    550                                                                synapse_obj, 
    551                                                                max_delay=max_delay) 
    552             else: 
    553                 self.brian_connections[key] = brian.Connection(source_group, 
    554                                                           target_group, 
    555                                                           synapse_obj, 
    556                                                           max_delay=state.max_delay*ms) 
    557             self.brian_connections[key].weight_units = weight_units 
    558             state.add(self.brian_connections[key]) 
    559             self.n[key] = 0 
    560         return self.brian_connections[key] 
    561      
    562     def _detect_parent_groups(self, cells): 
    563         groups = {} 
    564         for index, cell in enumerate(cells): 
    565             group = cell.parent_group 
    566             if not groups.has_key(group): 
    567                 groups[group] = [index] 
    568             else: 
    569                 groups[group] += [index] 
    570         return groups 
    571      
    572     def connect(self, source, targets, weights, delays, homogeneous=False): 
    573         """ 
    574         Connect a neuron to one or more other neurons with a static connection. 
    575          
    576         `source`  -- the ID of the pre-synaptic cell. 
    577         `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
    578         `weight`  -- a list/1D array of connection weights, or a single weight. 
    579                      Must have the same length as `targets`. 
    580         `delays`  -- a list/1D array of connection delays, or a single delay. 
    581                      Must have the same length as `targets`. 
    582         """ 
    583         #print "connecting", source, "to", targets, "with weights", weights, "and delays", delays 
    584         if not core.is_listlike(targets): 
    585             targets = [targets] 
    586         if isinstance(weights, float): 
    587             weights = [weights] 
    588         if isinstance(delays, float): 
    589             delays = [delays] 
    590         assert len(targets) > 0 
    591         if not isinstance(source, common.IDMixin): 
    592             raise errors.ConnectionError("source should be an ID object, actually %s" % type(source)) 
    593         for target in targets: 
    594             if not isinstance(target, common.IDMixin): 
    595                 raise errors.ConnectionError("Invalid target ID: %s" % target) 
    596         assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets),len(weights),len(delays)) 
    597         if common.is_conductance(targets[0]): 
    598             units = uS 
    599         else: 
    600             units = nA 
    601         synapse_type = self.synapse_type or "excitatory" 
    602         try: 
    603             source_group = source.parent_group 
    604         except AttributeError, errmsg: 
    605             raise errors.ConnectionError("%s. Maybe trying to connect from non-existing cell (ID=%s)." % (errmsg, source)) 
    606         groups = self._detect_parent_groups(targets) # we assume here all the targets belong to the same NeuronGroup 
    607          
    608         weights = numpy.array(weights) * units 
    609         delays  = numpy.array(delays) * ms 
    610         weights[weights == 0] = ZERO_WEIGHT             
    611          
    612         for target_group, indices in groups.items(): 
    613             synapse_obj = targets[indices[0]].parent.celltype.synapses[synapse_type]         
    614             bc          = self._get_brian_connection(source_group, target_group, synapse_obj, units, homogeneous)        
    615             padding     = (int(source.parent.first_id), int(targets[indices[0]].parent.first_id)) 
    616             src         = int(source) - padding[0] 
    617             mytargets   = numpy.array(targets, int)[indices] - padding[1]             
    618             bc.W.rows[src] = mytargets 
    619             bc.W.data[src] = weights[indices]         
    620             if not homogeneous: 
    621                 bc.delayvec.rows[src] = mytargets 
    622                 bc.delayvec.data[src] = delays[indices] 
    623             else: 
    624                 bc.delay = int(delays[0] / bc.source.clock.dt) 
    625             key = (source_group, target_group, synapse_obj) 
    626             self.n[key] += len(mytargets) 
    627              
    628             pop_sources = self._populations[0] 
    629             if len(pop_sources) is 0: 
    630                 pop_sources[source_group] = 0 
    631             elif not pop_sources.has_key(source_group): 
    632                 pop_sources[source_group] = numpy.sum([len(item) for item in pop_sources.keys()]) 
    633             pop_targets = self._populations[1] 
    634             if len(pop_targets) is 0: 
    635                 pop_targets[target_group] = 0 
    636             elif not pop_targets.has_key(target_group): 
    637                 pop_targets[target_group] = numpy.sum([len(item) for item in pop_targets.keys()])   
    638                  
    639          
    640     def get(self, parameter_name, format): 
    641         """ 
    642         Get the values of a given attribute (weight or delay) for all 
    643         connections in this manager. 
    644          
    645         `parameter_name` -- name of the attribute whose values are wanted. 
    646         `format` -- "list" or "array". Array format implicitly assumes that all 
    647                     connections belong to a single Projection. 
    648          
    649         Return a list or a 2D Numpy array. The array element X_ij contains the 
    650         attribute value for the connection from the ith neuron in the pre- 
    651         synaptic Population to the jth neuron in the post-synaptic Population, 
    652         if such a connection exists. If there are no such connections, X_ij will 
    653         be NaN. 
    654         """ 
    655         if self.parent is None: 
    656             raise Exception("Only implemented for connections created via a Projection object, not using connect()") 
    657         values = numpy.array([]) 
    658         for key in self.keys: 
    659             bc = self.brian_connections[key] 
    660             if parameter_name == "weight": 
    661                 values = numpy.concatenate((values, bc.W.alldata / bc.weight_units))             
    662             elif parameter_name == 'delay': 
    663                 if isinstance(bc, brian.DelayConnection): 
    664                     values = numpy.concatenate((values, bc.delay.alldata / ms)) 
    665                 else: 
    666                     data   = bc.delay * bc.source.clock.dt * numpy.ones(bc.W.getnnz()) /ms 
    667                     values = numpy.concatenate((values, data)) 
    668             else: 
    669                 raise Exception("Getting parameters other than weight and delay not yet supported.") 
    670          
    671         if format == 'list': 
    672             values = values.tolist() 
    673         elif format == 'array': 
    674             values_arr = numpy.nan * numpy.ones((self.parent.pre.size, self.parent.post.size)) 
    675             sources, targets = self._indices 
    676             values_arr[sources, targets] = values 
    677             values = values_arr 
    678         else: 
    679             raise Exception("format must be 'list' or 'array', actually '%s'" % format) 
    680         return values 
    681          
    682     def set(self, name, value): 
    683         """ 
    684         Set connection attributes for all connections in this manager. 
    685          
    686         `name`  -- attribute name 
    687         `value` -- the attribute numeric value, or a list/1D array of such 
    688                    values of the same length as the number of local connections, 
    689                    or a 2D array with the same dimensions as the connectivity 
    690                    matrix (as returned by `get(format='array')`). 
    691         """ 
    692         if self.parent is None: 
    693             raise Exception("Only implemented for connections created via a Projection object, not using connect()") 
    694         for key in self.keys: 
    695             bc = self.brian_connections[key] 
    696             padding = 0 
    697             if name == 'weight': 
    698                 M = bc.W 
    699                 units = bc.weight_units 
    700             elif name == 'delay': 
    701                 M = bc.delay 
    702                 units = ms 
    703             else: 
    704                 raise Exception("Setting parameters other than weight and delay not yet supported.") 
    705             value = value*units 
    706             if numpy.isscalar(value): 
    707                 if (name == 'weight') or (name == 'delay' and isinstance(bc, brian.DelayConnection)): 
    708                     for row in xrange(M.shape[0]): 
    709                         M.set_row(row, value) 
    710                 elif (name == 'delay' and isinstance(bc, brian.Connection)): 
    711                     bc.delay = int(value / bc.source.clock.dt) 
    712                 else: 
    713                     raise Exception("Setting a non appropriate parameter") 
    714             elif isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
    715                 if (name == 'delay') and not isinstance(bc, brian.DelayConnection): 
    716                     raise Exception("FastConnector have been used, and only fixed homogeneous delays are allowed") 
    717                 address_gen = ((i, j) for i,row in enumerate(bc.W.rows) for j in row) 
    718                 for (i,j) in address_gen: 
    719                     M[i,j] = value[i,j] 
    720             elif core.is_listlike(value): 
    721                 N = M.getnnz() 
    722                 assert len(value[padding:padding+N]) == N 
    723                 if (name == 'delay') and not isinstance(bc, brian.DelayConnection): 
    724                     raise Exception("FastConnector have been used: only fixed homogeneous delays are allowed") 
    725                 M.alldata = value 
    726             else: 
    727                 raise Exception("Values must be scalars or lists/arrays") 
    728             padding += M.getnnz() 
    729                      
     425   
    730426 
    731427# --- Initialization, and module attributes ------------------------------------ 
  • trunk/src/common.py

    r997 r998  
    6464DEFAULT_TIMESTEP = 0.1 
    6565DEFAULT_MIN_DELAY = DEFAULT_TIMESTEP 
     66 
     67deprecated = core.deprecated 
    6668 
    6769logger = logging.getLogger("PyNN") 
     
    17191721    def __len__(self): 
    17201722        """Return the total number of local connections.""" 
    1721         return len(self.connection_manager) 
     1723        raise NotImplementedError 
    17221724 
    17231725    def size(self, gather=True): 
     
    17381740    def __getitem__(self, i): 
    17391741        """Return the `i`th connection within the Projection.""" 
    1740         return self.connection_manager[i] 
     1742        raise NotImplementedError 
     1743 
     1744    def __iter__(self): 
     1745        """Return an iterator over all connections on the local MPI node.""" 
     1746        for i in range(len(self)): 
     1747            yield self[i] 
    17411748 
    17421749    # --- Methods for setting connection parameters --------------------------- 
    17431750 
     1751    def set(self, name, value): 
     1752        """ 
     1753        Set connection attributes for all connections on the local MPI node. 
     1754         
     1755        `name`  -- attribute name 
     1756         
     1757        `value` -- the attribute numeric value, or a list/1D array of such 
     1758                   values of the same length as the number of local connections, 
     1759                   or a 2D array with the same dimensions as the connectivity 
     1760                   matrix (as returned by `get(format='array')`). 
     1761        """ 
     1762        raise NotImplementedError 
     1763 
     1764    @deprecated("set('weight', w)") 
    17441765    def setWeights(self, w): 
    17451766        """ 
     
    17541775        # if post is an Assembly, some components might have cond-synapses, others curr, so need a more sophisticated check here 
    17551776        w = check_weight(w, self.synapse_type, is_conductance(self.post.local_cells[0])) 
    1756         self.connection_manager.set('weight', w) 
    1757  
     1777        self.set('weight', w) 
     1778 
     1779    @deprecated("set('weight', rand_distr)") 
    17581780    def randomizeWeights(self, rand_distr): 
    17591781        """ 
     
    17631785        # argument type. It could make for easier-to-read simulation code to 
    17641786        # give it a separate name, though. Comments? 
    1765         self.setWeights(rand_distr.next(len(self))) 
    1766  
     1787        self.set('weight', rand_distr.next(len(self))) 
     1788 
     1789    @deprecated("set('delay', d)") 
    17671790    def setDelays(self, d): 
    17681791        """ 
     
    17721795        connectivity matrix (as returned by `getDelays(format='array')`). 
    17731796        """ 
    1774         self.connection_manager.set('delay', d) 
    1775  
     1797        self.set('delay', d) 
     1798 
     1799    @deprecated("set('delay', rand_distr)") 
    17761800    def randomizeDelays(self, rand_distr): 
    17771801        """ 
    17781802        Set delays to random values taken from rand_distr. 
    17791803        """ 
    1780         self.setDelays(rand_distr.next(len(self))) 
    1781  
     1804        self.set('delay', rand_distr.next(len(self))) 
     1805 
     1806    @deprecated("set(param, value)") 
    17821807    def setSynapseDynamics(self, param, value): 
    17831808        """ 
     
    17851810        projection. 
    17861811        """ 
    1787         self.connection_manager.set(param, value) 
    1788  
     1812        self.set(param, value) 
     1813 
     1814    @deprecated("set(param, value)") 
    17891815    def randomizeSynapseDynamics(self, param, rand_distr): 
    17901816        """ 
    17911817        Set parameters of the synapse dynamics to values taken from rand_distr 
    17921818        """ 
    1793         self.setSynapseDynamics(param, rand_distr.next(len(self))) 
     1819        self.set(param, rand_distr.next(len(self))) 
    17941820 
    17951821    # --- Methods for writing/reading information to/from file. --------------- 
    17961822 
     1823    def get(self, parameter_name, format, gather=True): 
     1824        """ 
     1825        Get the values of a given attribute (weight or delay) for all 
     1826        connections in this Projection. 
     1827         
     1828        `parameter_name` -- name of the attribute whose values are wanted. 
     1829         
     1830        `format` -- "list" or "array". Array format implicitly assumes that all 
     1831                    connections belong to a single Projection. 
     1832         
     1833        Return a list or a 2D Numpy array. The array element X_ij contains the 
     1834        attribute value for the connection from the ith neuron in the pre- 
     1835        synaptic Population to the jth neuron in the post-synaptic Population, 
     1836        if a single such connection exists. If there are no such connections, 
     1837        X_ij will be NaN. If there are multiple such connections, the summed 
     1838        value will be given, which makes some sense for weights, but is 
     1839        pretty meaningless for delays.  
     1840        """ 
     1841        raise NotImplementedError 
     1842 
     1843    @deprecated("get('weight', format, gather)") 
    17971844    def getWeights(self, format='list', gather=True): 
    17981845        """ 
     
    18061853        if gather: 
    18071854            logger.error("getWeights() with gather=True not yet implemented") 
    1808         return self.connection_manager.get('weight', format) 
    1809  
     1855        return self.get('weight', format) 
     1856 
     1857    @deprecated("get('weight', format, gather)") 
    18101858    def getDelays(self, format='list', gather=True): 
    18111859        """ 
     
    18181866        if gather: 
    18191867            logger.error("getDelays() with gather=True not yet implemented") 
    1820         return self.connection_manager.get('delay', format) 
    1821  
     1868        return self.get('delay', format) 
     1869 
     1870    @deprecated("get(parameter_name, format, gather)") 
    18221871    def getSynapseDynamics(self, parameter_name, format='list', gather=True): 
    18231872        """ 
     
    18271876        if gather: 
    18281877            logger.error("getstandardmodels.SynapseDynamics() with gather=True not yet implemented") 
    1829         return self.connection_manager.get(parameter_name, format) 
    1830  
     1878        return self.get(parameter_name, format) 
     1879 
     1880    @deprecated("save('all', file, format, gather)") 
    18311881    def saveConnections(self, file, gather=True, compatible_output=True): 
    18321882        """ 
     
    18601910            file.close() 
    18611911 
     1912    @deprecated("save('weight', file, format, gather)") 
    18621913    def printWeights(self, file, format='list', gather=True): 
    18631914        """ 
     
    18651916        for non-existent connections. 
    18661917        """ 
    1867         weights = self.getWeights(format=format, gather=gather) 
     1918        weights = self.get('weight', format=format, gather=gather) 
    18681919         
    18691920        if isinstance(file, basestring): 
     
    18751926        file.close()     
    18761927 
     1928    @deprecated("save('delay', file, format, gather)") 
    18771929    def printDelays(self, file, format='list', gather=True): 
    18781930        """ 
     
    18901942        file.close()   
    18911943 
     1944    @deprecated("numpy.histogram()") 
    18921945    def weightHistogram(self, min=None, max=None, nbins=10): 
    18931946        """ 
  • trunk/src/connectors.py

    r957 r998  
    346346         
    347347        if len(targets) > 0: 
    348             self.projection.connection_manager.connect(src, targets.tolist(), weights, delays) 
     348            self.projection._divergent_connect(src, targets.tolist(), weights, delays) 
    349349 
    350350     
     
    526526            ## to use a convergent_connect method, instead of a divergent_connect one 
    527527            #idx     = eval(tests) 
    528             #projection.connection_manager.connect(src, tgts[idx].tolist(), weights[idx], delays[idx]) 
    529             projection.connection_manager.connect(src, tgts.tolist(), weights, delays) 
     528            #projection._divergent_connect(src, tgts[idx].tolist(), weights[idx], delays[idx]) 
     529            projection._divergent_connect(src, tgts.tolist(), weights, delays) 
    530530            self.progression(count) 
    531531            count += 1 
     
    646646                
    647647            if len(targets) > 0: 
    648                 projection.connection_manager.connect(src, targets.tolist(), weights, delays) 
     648                projection._divergent_connect(src, targets.tolist(), weights, delays) 
    649649             
    650650            self.progression(count) 
     
    731731                                             
    732732            for src, w, d in zip(sources, weights, delays): 
    733                 projection.connection_manager.connect(src, tgt, w, d) 
     733                projection._divergent_connect(src, tgt, w, d) 
    734734             
    735735            self.progression(count) 
     
    776776            for tgt, src, w, d in zip(projection.post.local_cells, sources, weights, delays): 
    777777                # the float is in case the values are of type numpy.float64, which NEST chokes on 
    778                 projection.connection_manager.connect(src, [tgt], [float(w)], [float(d)]) 
     778                projection._divergent_connect(src, [tgt], [float(w)], [float(d)]) 
    779779                self.progression(count) 
    780780                count += 1 
     
    859859                     
    860860        if len(targets) > 0: 
    861             self.projection.connection_manager.connect(src, targets.tolist(), weights, delays) 
     861            self.projection._divergent_connect(src, targets.tolist(), weights, delays) 
    862862     
    863863    def connect(self, projection): 
     
    934934            # Connection-set with arity 2 
    935935            for (i, j, weight, delay) in c: 
    936                 projection.connection_manager.connect (i, [j], weight, delay) 
     936                projection._divergent_connect (i, [j], weight, delay) 
    937937        elif CSAConnector.isConstant (self.weights) \ 
    938938             and CSAConnector.isConstant (self.delays): 
    939939            # Mask with constant weights and delays 
    940940            for (i, j) in c: 
    941                 projection.connection_manager.connect (i, [j], self.weights, self.delays) 
     941                projection._divergent_connect (i, [j], self.weights, self.delays) 
    942942        else: 
    943943            # Mask with weights and/or delays iterable 
     
    949949                delays = CSAConnector.constantIterator (delays) 
    950950            for (i, j), weight, delay in zip (c, weights, delays): 
    951                 projection.connection_manager.connect (i, [j], weight, delay) 
     951                projection._divergent_connect (i, [j], weight, delay) 
  • trunk/src/connectors2.py

    r741 r998  
    217217         
    218218        if len(sources) > 0: 
    219             self.projection.connection_manager.convergent_connect(sources.tolist(), tgt, weights, delays) 
     219            self.projection._convergent_connect(sources.tolist(), tgt, weights, delays) 
    220220     
    221221     
     
    364364            src = projection.pre[tuple(src)]            
    365365            tgt = projection.post[tuple(tgt)] 
    366             projection.connection_manager.connect(src, [tgt], weight, delay) 
     366            projection._divergent_connect(src, [tgt], weight, delay) 
    367367            self.progression(count) 
    368368             
     
    487487                
    488488            if len(targets) > 0: 
    489                 projection.connection_manager.connect(src, targets.tolist(), weights, delays) 
     489                projection._divergent_connect(src, targets.tolist(), weights, delays) 
    490490             
    491491            self.progression(count) 
     
    568568            delays  = delays_generator.get(n, distance_matrix, create)                                             
    569569            if len(sources) > 0: 
    570                 projection.connection_manager.convergent_connect(sources, tgt, weights, delays) 
     570                projection._convergent_connect(sources, tgt, weights, delays) 
    571571            self.progression(count) 
    572572             
     
    616616                 
    617617                # the float is in case the values are of type numpy.float64, which NEST chokes on 
    618                 projection.connection_manager.connect(src, [tgt], float(w), float(d)) 
     618                projection._divergent_connect(src, [tgt], float(w), float(d)) 
    619619                self.progression(count) 
    620620                count += 1 
     
    682682                     
    683683        if len(targets) > 0: 
    684             self.projection.connection_manager.connect(src, targets.tolist(), weights, delays) 
     684            self.projection._divergent_connect(src, targets.tolist(), weights, delays) 
    685685     
    686686    def connect(self, projection): 
  • trunk/src/core.py

    r957 r998  
    1111from copy import copy, deepcopy 
    1212import functools 
     13import warnings 
    1314 
    1415def is_listlike(obj): 
     
    275276        """Support instance methods.""" 
    276277        return functools.partial(self.__call__, obj) 
     278 
     279class deprecated(object): 
     280    """ 
     281    Decorator to mark functions/methods as deprecated. Emits a warning when 
     282    function is called and suggests a replacement. 
     283    """ 
     284     
     285    def __init__(self, replacement=''): 
     286        self.replacement = replacement 
     287         
     288    def __call__(self, func): 
     289        def new_func(*args, **kwargs): 
     290            msg = "%s() is deprecated, and will be removed in a future release." % func.__name__ 
     291            if self.replacement: 
     292                msg += " Use %s instead." % self.replacement 
     293            warnings.warn(msg, category=DeprecationWarning) 
     294            return func(*args, **kwargs) 
     295        new_func.__name__ = func.__name__ 
     296        new_func.__doc__ = func.__doc__ 
     297        new_func.__dict__.update(func.__dict__) 
     298        return new_func 
  • trunk/src/moose/__init__.py

    r957 r998  
    1616import os.path 
    1717from pyNN.moose import simulator 
    18 from pyNN import common, recording 
     18from pyNN import common, recording, core 
    1919common.simulator = simulator 
    2020recording.simulator = simulator 
     
    149149        assert synapse_dynamics is None, "don't yet handle synapse dynamics" 
    150150        self.synapse_model = None 
    151         self.connection_manager = simulator.ConnectionManager(self.synapse_type, 
    152                                                               self.synapse_model, 
    153                                                               parent=self) 
     151        self.connections = []         
     152         
    154153        # Create connections 
    155154        method.connect(self) 
    156         self.connections = self.connection_manager 
    157155        Projection.nProj += 1 
    158156         
    159          
     157    def _divergent_connect(self, source, targets, weights, delays): 
     158        """ 
     159        Connect a neuron to one or more other neurons with a static connection. 
     160         
     161        `source`  -- the ID of the pre-synaptic cell. 
     162        `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
     163        `weight`  -- a list/1D array of connection weights, or a single weight. 
     164                     Must have the same length as `targets`. 
     165        `delays`  -- a list/1D array of connection delays, or a single delay. 
     166                     Must have the same length as `targets`. 
     167        """ 
     168        if not isinstance(source, int) or source > simulator.state.gid_counter or source < 0: 
     169            errmsg = "Invalid source ID: %s (gid_counter=%d)" % (source, simulator.state.gid_counter) 
     170            raise errors.ConnectionError(errmsg) 
     171        if not core.is_listlike(targets): 
     172            targets = [targets] 
     173             
     174        weights = weights*1000.0 # scale units 
     175        if isinstance(weights, float): 
     176            weights = [weights] 
     177        if isinstance(delays, float): 
     178            delays = [delays] 
     179        assert len(targets) > 0 
     180        # need to scale weights for appropriate units 
     181        for target, weight, delay in zip(targets, weights, delays): 
     182            if target.local: 
     183                if not isinstance(target, common.IDMixin): 
     184                    raise errors.ConnectionError("Invalid target ID: %s" % target) 
     185                if self.synapse_type == "excitatory": 
     186                    synapse_object = target._cell.esyn 
     187                elif self.synapse_type == "inhibitory": 
     188                    synapse_object = target._cell.isyn 
     189                else: 
     190                    synapse_object = getattr(target._cell, self.synapse_type) 
     191                source._cell.source.connect('event', synapse_object, 'synapse') 
     192                synapse_object.n_incoming_connections += 1 
     193                index = synapse_object.n_incoming_connections - 1 
     194                synapse_object.setWeight(index, weight) 
     195                synapse_object.setDelay(index, delay) 
     196                self.connections.append((source, target, index)) 
     197                 
    160198# ============================================================================== 
    161199#   Low-level API for creating, connecting and recording from individual neurons 
  • trunk/src/moose/simulator.py

    r957 r998  
    9696            setattr(self._cell, name, val) 
    9797 
    98  
    99 class ConnectionManager(object): 
    100     """ 
    101     Manage synaptic connections, providing methods for creating, listing, 
    102     accessing individual connections. 
    103     """ 
    104  
    105     def __init__(self, synapse_type, synapse_model=None, parent=None): 
    106         """ 
    107         Create a new ConnectionManager. 
    108          
    109         `synapse_model` -- either None or 'Tsodyks-Markram'. 
    110         `parent` -- the parent `Projection` 
    111         """ 
    112         assert parent is not None 
    113         self.connections = [] 
    114         self.parent = parent 
    115         self.synapse_type = synapse_type 
    116         self.synapse_model = synapse_model 
    117      
    118     def connect(self, source, targets, weights, delays): 
    119         """ 
    120         Connect a neuron to one or more other neurons with a static connection. 
    121          
    122         `source`  -- the ID of the pre-synaptic cell. 
    123         `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
    124         `weight`  -- a list/1D array of connection weights, or a single weight. 
    125                      Must have the same length as `targets`. 
    126         `delays`  -- a list/1D array of connection delays, or a single delay. 
    127                      Must have the same length as `targets`. 
    128         """ 
    129         if not isinstance(source, int) or source > state.gid_counter or source < 0: 
    130             errmsg = "Invalid source ID: %s (gid_counter=%d)" % (source, state.gid_counter) 
    131             raise errors.ConnectionError(errmsg) 
    132         if not core.is_listlike(targets): 
    133             targets = [targets] 
    134              
    135         weights = weights*1000.0 # scale units 
    136         if isinstance(weights, float): 
    137             weights = [weights] 
    138         if isinstance(delays, float): 
    139             delays = [delays] 
    140         assert len(targets) > 0 
    141         # need to scale weights for appropriate units 
    142         for target, weight, delay in zip(targets, weights, delays): 
    143             if target.local: 
    144                 if not isinstance(target, common.IDMixin): 
    145                     raise errors.ConnectionError("Invalid target ID: %s" % target) 
    146                 if self.synapse_type == "excitatory": 
    147                     synapse_object = target._cell.esyn 
    148                 elif self.synapse_type == "inhibitory": 
    149                     synapse_object = target._cell.isyn 
    150                 else: 
    151                     synapse_object = getattr(target._cell, self.synapse_type) 
    152                 source._cell.source.connect('event', synapse_object, 'synapse') 
    153                 synapse_object.n_incoming_connections += 1 
    154                 index = synapse_object.n_incoming_connections - 1 
    155                 synapse_object.setWeight(index, weight) 
    156                 synapse_object.setDelay(index, delay) 
    157                 self.connections.append((source, target, index)) 
    158  
    15998state = _State()  # a Singleton, so only a single instance ever exists 
    16099del _State 
  • trunk/src/nemo/__init__.py

    r957 r998  
    191191        else:         
    192192            self._plasticity_model = "static_synapse" 
    193                                          
    194         self.connection_manager = simulator.ConnectionManager(self.synapse_type, self._plasticity_model, parent=self) 
    195         self.connections = self.connection_manager         
     193      
     194        self.synapse_model = self._plasticity_model 
     195        self._sources      = [] 
     196        self._is_plastic   = False 
     197        if self.synapse_model is "stdp_synapse": 
     198            self._is_plastic = True 
     199        self._connections = None 
     200         
    196201        method.connect(self) 
     202         
     203    def __getitem__(self, i): 
     204        if isinstance(i, int): 
     205            if i < len(self): 
     206                return simulator.Connection(self.connections[i]) 
     207            else: 
     208                raise IndexError("%d > %d" % (i, len(self)-1)) 
     209        elif isinstance(i, slice): 
     210            if i.stop < len(self): 
     211                return [simulator.Connection(self.connections[j]) for j in range(i.start, i.stop, i.step or 1)] 
     212            else: 
     213                raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
     214     
     215    def __len__(self): 
     216        """Return the number of connections on the local MPI node.""" 
     217        return len(self.connections) 
     218 
     219    @property 
     220    def connections(self): 
     221        if self._connections is None: 
     222            self._connections = [] 
     223            for source in numpy.unique(self.sources): 
     224                self._connections += list(simulator.state.net.get_synapses_from(source)) 
     225        return self._connections 
     226 
     227    def _divergent_connect(self, source, targets, weights, delays): 
     228        """ 
     229        Connect a neuron to one or more other neurons with a static connection. 
     230         
     231        `source`  -- the ID of the pre-synaptic cell. 
     232        `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
     233        `weight`  -- a list/1D array of connection weights, or a single weight. 
     234                     Must have the same length as `targets`. 
     235        `delays`  -- a list/1D array of connection delays, or a single delay. 
     236                     Must have the same length as `targets`. 
     237        """ 
     238        #print "connecting", source, "to", targets, "with weights", weights, "and delays", delays 
     239        if not core.is_listlike(targets): 
     240            targets = [targets] 
     241        if isinstance(weights, float): 
     242            weights = [weights] 
     243        if isinstance(delays, float): 
     244            delays = [delays] 
     245        assert len(targets) > 0 
     246        if not isinstance(source, common.IDMixin): 
     247            raise errors.ConnectionError("source should be an ID object, actually %s" % type(source)) 
     248        for target in targets: 
     249            if not isinstance(target, common.IDMixin): 
     250                raise errors.ConnectionError("Invalid target ID: %s" % target) 
     251        assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets),len(weights),len(delays)) 
     252        synapse_type = self.synapse_type or "excitatory" 
     253        delays = numpy.array(delays).astype(int).tolist() 
     254        if isinstance(weights, numpy.ndarray): 
     255            weights = weights.tolist()     
     256        source   = int(source)         
     257        synapses = simulator.state.net.add_synapse(source, targets, delays, weights, self.is_plastic) 
     258        self._sources.append(source) 
     259 
     260    def get(self, parameter_name, format, gather=True): 
     261        """ 
     262        Get the values of a given attribute (weight or delay) for all 
     263        connections in this Projection. 
     264         
     265        `parameter_name` -- name of the attribute whose values are wanted. 
     266        `format` -- "list" or "array". Array format implicitly assumes that all 
     267                    connections belong to a single Projection. 
     268         
     269        Return a list or a 2D Numpy array. The array element X_ij contains the 
     270        attribute value for the connection from the ith neuron in the pre- 
     271        synaptic Population to the jth neuron in the post-synaptic Population, 
     272        if such a connection exists. If there are no such connections, X_ij will 
     273        be NaN. 
     274        """ 
     275        if parameter_name not in ('weight', 'delay'): 
     276            raise Exception("Only weights and delays can be accessed by Nemo") 
     277 
     278        if format == 'list': 
     279            if parameter_name is "weight": 
     280                values = list(simulator.state.sim.get_synapse_weight(self.connections)) 
     281            if parameter_name is "delay": 
     282                values = list(simulator.state.sim.get_synapse_delay(self.connections)) 
     283        elif format == 'array': 
     284            value_arr = numpy.nan * numpy.ones((self.pre.size, self.post.size)) 
     285            sources  = [i.source for i in self] 
     286            synapses = [i.synapse for i in self] 
     287            targets  = list(simulator.state.sim.get_targets(synapses)) 
     288            addr     = self.pre.id_to_index(sources), self.post.id_to_index(targets)       
     289            if parameter_name is "weight": 
     290                data = list(simulator.state.sim.get_weights(synapses)) 
     291            if parameter_name is "delay": 
     292                data = list(simulator.state.sim.get_delays(synapses))           
     293            for idx in xrange(len(data)): 
     294                address = addr[0][idx], addr[1][idx] 
     295                if numpy.isnan(value_arr[address]): 
     296                    value_arr[address] = data[idx] 
     297                else: 
     298                    value_arr[address] += data[idx] 
     299            values = value_arr 
     300        else: 
     301            raise Exception("format must be 'list' or 'array', actually '%s'" % format) 
     302        return values 
    197303 
    198304    def saveConnections(self, file, gather=True, compatible_output=True): 
     
    205311            file = files.StandardTextFile(file, mode='w') 
    206312         
    207         lines = numpy.empty((len(self.connection_manager), 4))         
    208         lines[:,0] = [i.source for i in self.connection_manager] 
    209         lines[:,1] = [i.target for i in self.connection_manager]             
     313        lines = numpy.empty((len(self), 4))         
     314        lines[:,0] = [i.source for i in self] 
     315        lines[:,1] = [i.target for i in self]             
    210316        if compatible_output: 
    211317            lines[:,0] = self.pre.id_to_index(lines[:, 0])  
    212318            lines[:,1] = self.post.id_to_index(lines[:, 1])     
    213         synapses   = [i.synapse for i in self.connection_manager 
     319        synapses   = [i.synapse for i in self 
    214320        lines[:,2] = list(simulator.state.sim.get_weights(synapses)) 
    215321        lines[:,3] = list(simulator.state.sim.get_delays(synapses))          
  • trunk/src/nemo/simulator.py

    r977 r998  
    225225    weight = property(_get_weight, _set_weight) 
    226226    delay = property(_get_delay, _set_delay) 
    227      
    228  
    229 class ConnectionManager(object): 
    230     """ 
    231     Manage synaptic connections, providing methods for creating, listing, 
    232     accessing individual connections. 
    233     """ 
    234  
    235     def __init__(self, synapse_type, synapse_model=None, parent=None): 
    236         """ 
    237         Create a new ConnectionManager. 
    238          
    239         `synapse_type` -- the 'physiological type' of the synapse, e.g. 
    240                           'excitatory' or 'inhibitory',or any other key in the 
    241                           `synapses` attibute of the celltype class. 
    242         `synapse_model` -- not used. Present for consistency with other simulators. 
    243         `parent` -- the parent `Projection`, if any. 
    244         """ 
    245         self.synapse_type      = synapse_type 
    246         self.synapse_model     = synapse_model 
    247         self.parent            = parent 
    248         self.sources           = [] 
    249         self.is_plastic        = False 
    250         if self.synapse_model is "stdp_synapse": 
    251             self.is_plastic = True 
    252         self._connections = None 
    253          
    254     def __getitem__(self, i): 
    255         if isinstance(i, int): 
    256             if i < len(self): 
    257                 return Connection(self.connections[i]) 
    258             else: 
    259                 raise IndexError("%d > %d" % (i, len(self)-1)) 
    260         elif isinstance(i, slice): 
    261             if i.stop < len(self): 
    262                 return [Connection(self.connections[j]) for j in range(i.start, i.stop, i.step or 1)] 
    263             else: 
    264                 raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
    265      
    266     def __len__(self): 
    267         """Return the number of connections on the local MPI node.""" 
    268         return len(self.connections) 
    269      
    270     def __iter__(self): 
    271         """Return an iterator over all connections on the local MPI node.""" 
    272         for i in range(len(self)): 
    273             yield self[i] 
    274      
    275     @property 
    276     def connections(self): 
    277         if self._connections is None: 
    278             self._connections = [] 
    279             for source in numpy.unique(self.sources): 
    280                 self._connections += list(state.net.get_synapses_from(source)) 
    281         return self._connections 
    282      
    283     def connect(self, source, targets, weights, delays): 
    284         """ 
    285         Connect a neuron to one or more other neurons with a static connection. 
    286          
    287         `source`  -- the ID of the pre-synaptic cell. 
    288         `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
    289         `weight`  -- a list/1D array of connection weights, or a single weight. 
    290                      Must have the same length as `targets`. 
    291         `delays`  -- a list/1D array of connection delays, or a single delay. 
    292                      Must have the same length as `targets`. 
    293         """ 
    294         #print "connecting", source, "to", targets, "with weights", weights, "and delays", delays 
    295         if not core.is_listlike(targets): 
    296             targets = [targets] 
    297         if isinstance(weights, float): 
    298             weights = [weights] 
    299         if isinstance(delays, float): 
    300             delays = [delays] 
    301         assert len(targets) > 0 
    302         if not isinstance(source, common.IDMixin): 
    303             raise errors.ConnectionError("source should be an ID object, actually %s" % type(source)) 
    304         for target in targets: 
    305             if not isinstance(target, common.IDMixin): 
    306                 raise errors.ConnectionError("Invalid target ID: %s" % target) 
    307         assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets),len(weights),len(delays)) 
    308         synapse_type = self.synapse_type or "excitatory" 
    309         delays = numpy.array(delays).astype(int).tolist() 
    310         if isinstance(weights, numpy.ndarray): 
    311             weights = weights.tolist()     
    312         source   = int(source)         
    313         synapses = state.net.add_synapse(source, targets, delays, weights, self.is_plastic) 
    314         self.sources.append(source) 
    315          
    316     def get(self, parameter_name, format): 
    317         """ 
    318         Get the values of a given attribute (weight or delay) for all 
    319         connections in this manager. 
    320          
    321         `parameter_name` -- name of the attribute whose values are wanted. 
    322         `format` -- "list" or "array". Array format implicitly assumes that all 
    323                     connections belong to a single Projection. 
    324          
    325         Return a list or a 2D Numpy array. The array element X_ij contains the 
    326         attribute value for the connection from the ith neuron in the pre- 
    327         synaptic Population to the jth neuron in the post-synaptic Population, 
    328         if such a connection exists. If there are no such connections, X_ij will 
    329         be NaN. 
    330         """ 
    331         if parameter_name not in ('weight', 'delay'): 
    332             raise Exception("Only weights and delays can be accessed by Nemo") 
    333  
    334         if format == 'list': 
    335             if parameter_name is "weight": 
    336                 values = list(state.sim.get_synapse_weight(self.connections)) 
    337             if parameter_name is "delay": 
    338                 values = list(state.sim.get_synapse_delay(self.connections)) 
    339         elif format == 'array': 
    340             value_arr = numpy.nan * numpy.ones((self.parent.pre.size, self.parent.post.size)) 
    341             sources  = [i.source for i in self] 
    342             synapses = [i.synapse for i in self] 
    343             targets  = list(state.sim.get_targets(synapses)) 
    344             addr     = self.parent.pre.id_to_index(sources), self.parent.post.id_to_index(targets)       
    345             if parameter_name is "weight": 
    346                 data = list(state.sim.get_weights(synapses)) 
    347             if parameter_name is "delay": 
    348                 data = list(state.sim.get_delays(synapses))           
    349             for idx in xrange(len(data)): 
    350                 address = addr[0][idx], addr[1][idx] 
    351                 if numpy.isnan(value_arr[address]): 
    352                     value_arr[address] = data[idx] 
    353                 else: 
    354                     value_arr[address] += data[idx] 
    355             values = value_arr 
    356         else: 
    357             raise Exception("format must be 'list' or 'array', actually '%s'" % format) 
    358         return values 
    359  
    360     def set(self, name, value): 
    361         """ 
    362         Set connection attributes for all connections in this manager. 
    363          
    364         `name`  -- attribute name 
    365         `value` -- the attribute numeric value, or a list/1D array of such 
    366                    values of the same length as the number of local connections, 
    367                    or a 2D array with the same dimensions as the connectivity 
    368                    matrix (as returned by `get(format='array')`). 
    369         """ 
    370         if self.parent is None: 
    371             raise Exception("Only implemented for connections created via a Projection object, not using connect()") 
    372         pass          
     227        
    373228 
    374229# --- Initialization, and module attributes ------------------------------------ 
  • trunk/src/nest/__init__.py

    r991 r998  
    133133                                         'min_delay': min_delay, 
    134134                                         'max_delay': max_delay}) 
    135     simulator.connection_managers = [] 
    136135    simulator.reset() 
    137136     
     
    325324        else:         
    326325            synapse_dynamics = NativeSynapseDynamics("static_synapse") 
    327         self.synapse_model = synapse_dynamics._get_nest_synapse_model("projection_%d" % Projection.nProj) 
     326        synapse_model = synapse_dynamics._get_nest_synapse_model("projection_%d" % Projection.nProj) 
     327        if synapse_model is None: 
     328            self.synapse_model = 'static_synapse_%s' % id(self) 
     329            nest.CopyModel('static_synapse', self.synapse_model) 
     330        else: 
     331            self.synapse_model = synapse_model 
     332        self._sources = [] 
     333        self._connections = None 
    328334        Projection.nProj += 1 
    329          
    330         self.connection_manager = simulator.ConnectionManager(self.synapse_type, 
    331                                                               self.synapse_model, 
    332                                                               parent=self) 
    333          
     335                
    334336        # Create connections 
    335337        method.connect(self) 
    336         self.connection_manager._set_tsodyks_params() 
    337         self.connections = self.connection_manager 
    338          
     338     
     339    def __getitem__(self, i): 
     340        """Return the `i`th connection on the local MPI node.""" 
     341        if isinstance(i, int): 
     342            if i < len(self): 
     343                return simulator.Connection(self, i) 
     344            else: 
     345                raise IndexError("%d > %d" % (i, len(self)-1)) 
     346        elif isinstance(i, slice): 
     347            if i.stop < len(self): 
     348                return [simulator.Connection(self, j) for j in range(i.start, i.stop, i.step or 1)] 
     349            else: 
     350                raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
     351 
     352    def __len__(self): 
     353        """Return the number of connections on the local MPI node.""" 
     354        return nest.GetDefaults(self.synapse_model)['num_connections'] 
     355 
     356    @property 
     357    def connections(self): 
     358        if self._connections is None: 
     359            self._sources = numpy.unique(self._sources) 
     360            self._connections = nest.FindConnections(self._sources, synapse_type=self.synapse_model) 
     361        return self._connections 
     362 
     363    def _set_tsodyks_params(self): 
     364        if 'tsodyks' in self.synapse_model: # there should be a better way to do this. In particular, if the synaptic time constant is changed 
     365                                            # after creating the Projection, tau_psc ought to be changed as well. 
     366            assert self.synapse_type in ('excitatory', 'inhibitory'), "only basic synapse types support Tsodyks-Markram connections" 
     367            logger.debug("setting tau_psc") 
     368            targets = nest.GetStatus(self.connections, 'target')             
     369            if self.synapse_type == 'inhibitory': 
     370                param_name = self.post.local_cells[0].celltype.translations['tau_syn_I']['translated_name'] 
     371            if self.synapse_type == 'excitatory': 
     372                param_name = self.post.local_cells[0].celltype.translations['tau_syn_E']['translated_name'] 
     373            tau_syn = nest.GetStatus(targets, (param_name)) 
     374            nest.SetStatus(self.connections, 'tau_psc', tau_syn)  
     375 
     376    def _divergent_connect(self, source, targets, weights, delays): 
     377        """ 
     378        Connect a neuron to one or more other neurons. 
     379         
     380        `source`  -- the ID of the pre-synaptic cell. 
     381        `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
     382        `weight`  -- a list/1D array of connection weights, or a single weight. 
     383                     Must have the same length as `targets`. 
     384        `delays`  -- a list/1D array of connection delays, or a single delay. 
     385                     Must have the same length as `targets`. 
     386        """ 
     387        # are we sure the targets are all on the current node? 
     388        if core.is_listlike(source): 
     389            assert len(source) == 1 
     390            source = source[0] 
     391        if not core.is_listlike(targets): 
     392            targets = [targets] 
     393        assert len(targets) > 0 
     394         
     395        if self.synapse_type not in targets[0].celltype.synapse_types: 
     396            raise errors.ConnectionError("User gave synapse_type=%s, synapse_type must be one of: %s" % ( self.synapse_type, "'"+"', '".join(st for st in targets[0].celltype.synapse_types or ['*No connections supported*']))+"'" ) 
     397        weights = numpy.array(weights)*1000.0 # weights should be in nA or uS, but iaf_neuron uses pA and iaf_cond_neuron uses nS. 
     398                                 # Using convention in this way is not ideal. We should 
     399                                 # be able to look up the units used by each model somewhere. 
     400        if self.synapse_type == 'inhibitory' and common.is_conductance(targets[0]): 
     401            weights = -1*weights # NEST wants negative values for inhibitory weights, even if these are conductances 
     402        if isinstance(weights, numpy.ndarray): 
     403            weights = weights.tolist() 
     404        elif isinstance(weights, float): 
     405            weights = [weights] 
     406        if isinstance(delays, numpy.ndarray): 
     407            delays = delays.tolist() 
     408        elif isinstance(delays, float): 
     409            delays = [delays] 
     410         
     411        if targets[0].celltype.standard_receptor_type: 
     412            try: 
     413                nest.DivergentConnect([source], targets, weights, delays, self.synapse_model)             
     414            except nest.NESTError, e: 
     415                raise errors.ConnectionError("%s. source=%s, targets=%s, weights=%s, delays=%s, synapse model='%s'" % ( 
     416                                             e, source, targets, weights, delays, self.synapse_model)) 
     417        else: 
     418            for target, w, d in zip(targets, weights, delays): 
     419                nest.Connect([source], [target], {'weight': w, 'delay': d, 'receptor_type': target.celltype.get_receptor_type(self.synapse_type)}) 
     420        self._connections = None # reset the caching of the connection list, since this will have to be recalculated 
     421        self._sources.append(source)   
     422 
     423    def _convergent_connect(self, sources, target, weights, delays): 
     424        """ 
     425        Connect one or more neurons to a single post-synaptic neuron. 
     426        `sources` -- a list/1D array of pre-synaptic cell IDs, or a single ID. 
     427        `target`  -- the ID of the post-synaptic cell. 
     428        `weight`  -- a list/1D array of connection weights, or a single weight. 
     429                     Must have the same length as `targets`. 
     430        `delays`  -- a list/1D array of connection delays, or a single delay. 
     431                     Must have the same length as `targets`. 
     432        """ 
     433        # are we sure the targets are all on the current node? 
     434        if core.is_listlike(target): 
     435            assert len(target) == 1 
     436            target = target[0] 
     437        if not core.is_listlike(sources): 
     438            sources = [sources] 
     439        assert len(sources) > 0, sources 
     440        if self.synapse_type not in ('excitatory', 'inhibitory', None): 
     441            raise errors.ConnectionError("synapse_type must be 'excitatory', 'inhibitory', or None (equivalent to 'excitatory')") 
     442        weights = numpy.array(weights)*1000.0# weights should be in nA or uS, but iaf_neuron uses pA and iaf_cond_neuron uses nS. 
     443                                 # Using convention in this way is not ideal. We should 
     444                                 # be able to look up the units used by each model somewhere. 
     445        if self.synapse_type == 'inhibitory' and common.is_conductance(target): 
     446            weights = -1*weights # NEST wants negative values for inhibitory weights, even if these are conductances 
     447        if isinstance(weights, numpy.ndarray): 
     448            weights = weights.tolist() 
     449        elif isinstance(weights, float): 
     450            weights = [weights] 
     451        if isinstance(delays, numpy.ndarray): 
     452            delays = delays.tolist() 
     453        elif isinstance(delays, float): 
     454            delays = [delays] 
     455                
     456        try: 
     457            nest.ConvergentConnect(sources, [target], weights, delays, self.synapse_model)             
     458        except nest.NESTError, e: 
     459            raise errors.ConnectionError("%s. sources=%s, target=%s, weights=%s, delays=%s, synapse model='%s'" % ( 
     460                                         e, sources, target, weights, delays, self.synapse_model)) 
     461        self._connections = None # reset the caching of the connection list, since this will have to be recalculated 
     462        self._sources.extend(sources) 
     463 
     464    def set(self, name, value): 
     465        """ 
     466        Set connection attributes for all connections on the local MPI node. 
     467         
     468        `name`  -- attribute name 
     469         
     470        `value` -- the attribute numeric value, or a list/1D array of such 
     471                   values of the same length as the number of local connections, 
     472                   or a 2D array with the same dimensions as the connectivity 
     473                   matrix (as returned by `get(format='array')`). 
     474        """ 
     475        if not (numpy.isscalar(value) or core.is_listlike(value)): 
     476            raise TypeError("Argument should be a numeric type (int, float...), a list, or a numpy array.")    
     477         
     478        if isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
     479            value_list = [] 
     480            connection_parameters = nest.GetStatus(self.connections, ('source', 'target')) 
     481            for conn in connection_parameters:  
     482                addr = self.pre.id_to_index(conn['source']), self.post.id_to_index(conn['target']) 
     483                try: 
     484                    val = value[addr] 
     485                except IndexError, e: 
     486                    raise IndexError("%s. addr=%s" % (e, addr)) 
     487                if numpy.isnan(val): 
     488                    raise Exception("Array contains no value for synapse from %d to %d" % (c.source, c.target)) 
     489                else: 
     490                    value_list.append(val) 
     491            value = value_list 
     492        if core.is_listlike(value): 
     493            value = numpy.array(value) 
     494        else: 
     495            value = float(value) 
     496 
     497        if name == 'weight': 
     498            value *= 1000.0 
     499            if self.synapse_type == 'inhibitory' and common.is_conductance(self[0].target): 
     500                value *= -1 # NEST wants negative values for inhibitory weights, even if these are conductances 
     501        elif name == 'delay': 
     502            pass 
     503        else: 
     504            #translation = self.synapse_dynamics.reverse_translate({name: value}) 
     505            #name, value = translation.items()[0] 
     506            translated_name = None 
     507            if self.synapse_dynamics.fast: 
     508                if name in self.synapse_dynamics.fast.translations: 
     509                    translated_name = self.synapse_dynamics.fast.translations[name]["translated_name"] # a hack 
     510            if translated_name is None: 
     511                if self.synapse_dynamics.slow: 
     512                    for component_name in "timing_dependence", "weight_dependence", "voltage_dependence": 
     513                        component = getattr(self.synapse_dynamics.slow, component_name) 
     514                        if component and name in component.translations: 
     515                            translated_name = component.translations[name]["translated_name"] 
     516                            break 
     517            if translated_name: 
     518                name = translated_name 
     519         
     520        i = 0 
     521        try: 
     522            nest.SetStatus(self.connections, name, value) 
     523        except nest.NESTError, e: 
     524            n = 1 
     525            if hasattr(value, '__len__'): 
     526                n = len(value) 
     527            raise Exception("%s. Trying to set %d values." % (e, n)) 
    339528 
    340529    def saveConnections(self, file, gather=True, compatible_output=True): 
     
    348537            file = files.StandardTextFile(file, mode='w') 
    349538         
    350         lines   = nest.GetStatus(self.connection_manager.connections, ('source', 'target', 'weight', 'delay'))   
     539        lines   = nest.GetStatus(self.connections, ('source', 'target', 'weight', 'delay'))   
    351540         
    352541        if gather == True and num_processes() > 1: 
     
    386575        self.setDelays(rand_distr.next(len(self), mask_local=False)) 
    387576 
     577    def get(self, parameter_name, format, gather=True): 
     578        """ 
     579        Get the values of a given attribute (weight or delay) for all 
     580        connections in this Projection. 
     581         
     582        `parameter_name` -- name of the attribute whose values are wanted. 
     583         
     584        `format` -- "list" or "array". Array format implicitly assumes that all 
     585                    connections belong to a single Projection. 
     586         
     587        Return a list or a 2D Numpy array. The array element X_ij contains the 
     588        attribute value for the connection from the ith neuron in the pre- 
     589        synaptic Population to the jth neuron in the post-synaptic Population, 
     590        if a single such connection exists. If there are no such connections, 
     591        X_ij will be NaN. If there are multiple such connections, the summed 
     592        value will be given, which makes some sense for weights, but is 
     593        pretty meaningless for delays.  
     594        """ 
     595         
     596        if parameter_name not in ('weight', 'delay'): 
     597            translated_name = None 
     598            if self.synapse_dynamics.fast and parameter_name in self.synapse_dynamics.fast.translations: 
     599                translated_name = self.synapse_dynamics.fast.translations[parameter_name]["translated_name"] # this is a hack that works because there are no units conversions 
     600            elif self.synapse_dynamics.slow: 
     601                for component_name in "timing_dependence", "weight_dependence", "voltage_dependence": 
     602                    component = getattr(self.synapse_dynamics.slow, component_name) 
     603                    if component and parameter_name in component.translations: 
     604                        translated_name = component.translations[parameter_name]["translated_name"] 
     605                        break 
     606            if translated_name: 
     607                parameter_name = translated_name 
     608            else: 
     609                raise Exception("synapse type does not have an attribute '%s', or else this attribute is not accessible." % parameter_name) 
     610        if format == 'list': 
     611            values = nest.GetStatus(self.connections, parameter_name) 
     612            if parameter_name == "weight": 
     613                values = [0.001*val for val in values] 
     614        elif format == 'array': 
     615            value_arr = numpy.nan * numpy.ones((self.pre.size, self.post.size)) 
     616            connection_parameters = nest.GetStatus(self.connections, ('source', 'target', parameter_name)) 
     617            for conn in connection_parameters:  
     618                # (offset is always 0,0 for connections created with connect()) 
     619                src, tgt, value = conn 
     620                addr = self.pre.id_to_index(src), self.post.id_to_index(tgt) 
     621                if numpy.isnan(value_arr[addr]): 
     622                    value_arr[addr] = value 
     623                else: 
     624                    value_arr[addr] += value 
     625            if parameter_name == 'weight': 
     626                value_arr *= 0.001 
     627                if self.synapse_type == 'inhibitory' and common.is_conductance(self[0].target): 
     628                    value_arr *= -1 # NEST uses negative values for inhibitory weights, even if these are conductances 
     629            values = value_arr 
     630        else: 
     631            raise Exception("format must be 'list' or 'array', actually '%s'" % format) 
     632        return values 
     633 
    388634Space = space.Space 
    389635 
  • trunk/src/nest/connectors.py

    r970 r998  
    9292         
    9393        if len(sources) > 0: 
    94             self.projection.connection_manager.convergent_connect(sources.tolist(), tgt, weights, delays) 
     94            self.projection._convergent_connect(sources.tolist(), tgt, weights, delays) 
    9595     
    9696     
  • trunk/src/nest/simulator.py

    r991 r998  
    44implementation of the API. 
    55 
    6 Functions and classes useable by the common implementation: 
     6Functions and classes usable by the common implementation: 
    77 
    88Functions: 
    9     create_cells() 
    109    run() 
    1110 
     
    1312    ID 
    1413    Recorder 
    15     ConnectionManager 
    1614    Connection 
    1715     
     
    3937recorder_list = [] 
    4038recording_devices = [] 
    41 connection_managers = [] 
    4239 
    4340global net 
     
    211208     
    212209 
    213 class ConnectionManager: 
    214     """ 
    215     Manage synaptic connections, providing methods for creating, listing, 
    216     accessing individual connections. 
    217     """ 
    218  
    219     def __init__(self, synapse_type, synapse_model=None, parent=None): 
    220         """ 
    221         Create a new ConnectionManager. 
    222          
    223         `synapse_type` -- the 'physiological type' of the synapse, e.g. 
    224                           'excitatory' or 'inhibitory' 
    225         `synapse_model` -- the NEST synapse model to be used for all connections 
    226                            created with this manager. 
    227         `parent` -- the parent `Projection`, if any. 
    228         """ 
    229         global connection_managers 
    230         self.sources = [] 
    231         if synapse_model is None: 
    232             self.synapse_model = 'static_synapse_%s' % id(self) 
    233             nest.CopyModel('static_synapse', self.synapse_model) 
    234         else: 
    235             self.synapse_model = synapse_model 
    236         self.synapse_type = synapse_type 
    237         self.parent = parent 
    238         if parent is not None: 
    239             assert parent.synapse_model == self.synapse_model 
    240         self._connections = None 
    241         connection_managers.append(self) 
    242  
    243     def __getitem__(self, i): 
    244         """Return the `i`th connection on the local MPI node.""" 
    245         if isinstance(i, int): 
    246             if i < len(self): 
    247                 return Connection(self, i) 
    248             else: 
    249                 raise IndexError("%d > %d" % (i, len(self)-1)) 
    250         elif isinstance(i, slice): 
    251             if i.stop < len(self): 
    252                 return [Connection(self, j) for j in range(i.start, i.stop, i.step or 1)] 
    253             else: 
    254                 raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
    255      
    256     def __len__(self): 
    257         """Return the number of connections on the local MPI node.""" 
    258         return nest.GetDefaults(self.synapse_model)['num_connections'] 
    259      
    260     def __iter__(self): 
    261         """Return an iterator over all connections on the local MPI node.""" 
    262         for i in range(len(self)): 
    263             yield self[i] 
    264  
    265     @property 
    266     def connections(self): 
    267         if self._connections is None: 
    268             self.sources = numpy.unique(self.sources) 
    269             self._connections = nest.FindConnections(self.sources, synapse_type=self.synapse_model) 
    270         return self._connections 
    271      
    272     def _set_tsodyks_params(self): 
    273         if 'tsodyks' in self.synapse_model: # there should be a better way to do this. In particular, if the synaptic time constant is changed 
    274                                             # after creating the Projection, tau_psc ought to be changed as well. 
    275             assert self.synapse_type in ('excitatory', 'inhibitory'), "only basic synapse types support Tsodyks-Markram connections" 
    276             logger.debug("setting tau_psc") 
    277             targets = nest.GetStatus(self.connections, 'target')             
    278             if self.synapse_type == 'inhibitory': 
    279                 param_name = self.parent.post.local_cells[0].celltype.translations['tau_syn_I']['translated_name'] 
    280             if self.synapse_type == 'excitatory': 
    281                 param_name = self.parent.post.local_cells[0].celltype.translations['tau_syn_E']['translated_name'] 
    282             tau_syn = nest.GetStatus(targets, (param_name)) 
    283             nest.SetStatus(self.connections, 'tau_psc', tau_syn)     
    284  
    285     def connect(self, source, targets, weights, delays): 
    286         """ 
    287         Connect a neuron to one or more other neurons. 
    288          
    289         `source`  -- the ID of the pre-synaptic cell. 
    290         `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
    291         `weight`  -- a list/1D array of connection weights, or a single weight. 
    292                      Must have the same length as `targets`. 
    293         `delays`  -- a list/1D array of connection delays, or a single delay. 
    294                      Must have the same length as `targets`. 
    295         """ 
    296         # are we sure the targets are all on the current node? 
    297         if core.is_listlike(source): 
    298             assert len(source) == 1 
    299             source = source[0] 
    300         if not core.is_listlike(targets): 
    301             targets = [targets] 
    302         assert len(targets) > 0 
    303          
    304         if self.synapse_type not in targets[0].celltype.synapse_types: 
    305             raise errors.ConnectionError("User gave synapse_type=%s, synapse_type must be one of: %s" % ( self.synapse_type, "'"+"', '".join(st for st in targets[0].celltype.synapse_types or ['*No connections supported*']))+"'" ) 
    306         weights = numpy.array(weights)*1000.0 # weights should be in nA or uS, but iaf_neuron uses pA and iaf_cond_neuron uses nS. 
    307                                  # Using convention in this way is not ideal. We should 
    308                                  # be able to look up the units used by each model somewhere. 
    309         if self.synapse_type == 'inhibitory' and common.is_conductance(targets[0]): 
    310             weights = -1*weights # NEST wants negative values for inhibitory weights, even if these are conductances 
    311         if isinstance(weights, numpy.ndarray): 
    312             weights = weights.tolist() 
    313         elif isinstance(weights, float): 
    314             weights = [weights] 
    315         if isinstance(delays, numpy.ndarray): 
    316             delays = delays.tolist() 
    317         elif isinstance(delays, float): 
    318             delays = [delays] 
    319          
    320         if targets[0].celltype.standard_receptor_type: 
    321             try: 
    322                 nest.DivergentConnect([source], targets, weights, delays, self.synapse_model)             
    323             except nest.NESTError, e: 
    324                 raise errors.ConnectionError("%s. source=%s, targets=%s, weights=%s, delays=%s, synapse model='%s'" % ( 
    325                                              e, source, targets, weights, delays, self.synapse_model)) 
    326         else: 
    327             for target, w, d in zip(targets, weights, delays): 
    328                 nest.Connect([source], [target], {'weight': w, 'delay': d, 'receptor_type': target.celltype.get_receptor_type(self.synapse_type)}) 
    329         self._connections = None # reset the caching of the connection list, since this will have to be recalculated 
    330         self.sources.append(source) 
    331  
    332     def convergent_connect(self, sources, target, weights, delays): 
    333         """ 
    334         Connect one or more neurons to a single post-synaptic neuron. 
    335         `sources` -- a list/1D array of pre-synaptic cell IDs, or a single ID. 
    336         `target`  -- the ID of the post-synaptic cell. 
    337         `weight`  -- a list/1D array of connection weights, or a single weight. 
    338                      Must have the same length as `targets`. 
    339         `delays`  -- a list/1D array of connection delays, or a single delay. 
    340                      Must have the same length as `targets`. 
    341         """ 
    342         # are we sure the targets are all on the current node? 
    343         if core.is_listlike(target): 
    344             assert len(target) == 1 
    345             target = target[0] 
    346         if not core.is_listlike(sources): 
    347             sources = [sources] 
    348         assert len(sources) > 0, sources 
    349         if self.synapse_type not in ('excitatory', 'inhibitory', None): 
    350             raise errors.ConnectionError("synapse_type must be 'excitatory', 'inhibitory', or None (equivalent to 'excitatory')") 
    351         weights = numpy.array(weights)*1000.0# weights should be in nA or uS, but iaf_neuron uses pA and iaf_cond_neuron uses nS. 
    352                                  # Using convention in this way is not ideal. We should 
    353                                  # be able to look up the units used by each model somewhere. 
    354         if self.synapse_type == 'inhibitory' and common.is_conductance(target): 
    355             weights = -1*weights # NEST wants negative values for inhibitory weights, even if these are conductances 
    356         if isinstance(weights, numpy.ndarray): 
    357             weights = weights.tolist() 
    358         elif isinstance(weights, float): 
    359             weights = [weights] 
    360         if isinstance(delays, numpy.ndarray): 
    361             delays = delays.tolist() 
    362         elif isinstance(delays, float): 
    363             delays = [delays] 
    364                 
    365         try: 
    366             nest.ConvergentConnect(sources, [target], weights, delays, self.synapse_model)             
    367         except nest.NESTError, e: 
    368             raise errors.ConnectionError("%s. sources=%s, target=%s, weights=%s, delays=%s, synapse model='%s'" % ( 
    369                                          e, sources, target, weights, delays, self.synapse_model)) 
    370         self._connections = None # reset the caching of the connection list, since this will have to be recalculated 
    371         self.sources.extend(sources) 
    372      
    373     def get(self, parameter_name, format): 
    374         """ 
    375         Get the values of a given attribute (weight or delay) for all 
    376         connections in this manager. 
    377          
    378         `parameter_name` -- name of the attribute whose values are wanted. 
    379          
    380         `format` -- "list" or "array". Array format implicitly assumes that all 
    381                     connections belong to a single Projection. 
    382          
    383         Return a list or a 2D Numpy array. The array element X_ij contains the 
    384         attribute value for the connection from the ith neuron in the pre- 
    385         synaptic Population to the jth neuron in the post-synaptic Population, 
    386         if a single such connection exists. If there are no such connections, 
    387         X_ij will be NaN. If there are multiple such connections, the summed 
    388         value will be given, which makes some sense for weights, but is 
    389         pretty meaningless for delays.  
    390         """ 
    391          
    392         if parameter_name not in ('weight', 'delay'): 
    393             translated_name = None 
    394             if self.parent.synapse_dynamics.fast and parameter_name in self.parent.synapse_dynamics.fast.translations: 
    395                 translated_name = self.parent.synapse_dynamics.fast.translations[parameter_name]["translated_name"] # this is a hack that works because there are no units conversions 
    396             elif self.parent.synapse_dynamics.slow: 
    397                 for component_name in "timing_dependence", "weight_dependence", "voltage_dependence": 
    398                     component = getattr(self.parent.synapse_dynamics.slow, component_name) 
    399                     if component and parameter_name in component.translations: 
    400                         translated_name = component.translations[parameter_name]["translated_name"] 
    401                         break 
    402             if translated_name: 
    403                 parameter_name = translated_name 
    404             else: 
    405                 raise Exception("synapse type does not have an attribute '%s', or else this attribute is not accessible." % parameter_name) 
    406         if format == 'list': 
    407             values = nest.GetStatus(self.connections, parameter_name) 
    408             if parameter_name == "weight": 
    409                 values = [0.001*val for val in values] 
    410         elif format == 'array': 
    411             value_arr = numpy.nan * numpy.ones((self.parent.pre.size, self.parent.post.size)) 
    412             connection_parameters = nest.GetStatus(self.connections, ('source', 'target', parameter_name)) 
    413             for conn in connection_parameters:  
    414                 # don't need to pass offset as arg, now we store the parent projection 
    415                 # (offset is always 0,0 for connections created with connect()) 
    416                 src, tgt, value = conn 
    417                 addr = self.parent.pre.id_to_index(src), self.parent.post.id_to_index(tgt) 
    418                 if numpy.isnan(value_arr[addr]): 
    419                     value_arr[addr] = value 
    420                 else: 
    421                     value_arr[addr] += value 
    422             if parameter_name == 'weight': 
    423                 value_arr *= 0.001 
    424                 if self.synapse_type == 'inhibitory' and common.is_conductance(self[0].target): 
    425                     value_arr *= -1 # NEST uses negative values for inhibitory weights, even if these are conductances 
    426             values = value_arr 
    427         else: 
    428             raise Exception("format must be 'list' or 'array', actually '%s'" % format) 
    429         return values 
    430      
    431     def set(self, name, value): 
    432         """ 
    433         Set connection attributes for all connections on the local MPI node. 
    434          
    435         `name`  -- attribute name 
    436          
    437         `value` -- the attribute numeric value, or a list/1D array of such 
    438                    values of the same length as the number of local connections, 
    439                    or a 2D array with the same dimensions as the connectivity 
    440                    matrix (as returned by `get(format='array')`). 
    441         """ 
    442         if not (numpy.isscalar(value) or core.is_listlike(value)): 
    443             raise TypeError("Argument should be a numeric type (int, float...), a list, or a numpy array.")    
    444          
    445         if isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
    446             value_list = [] 
    447             connection_parameters = nest.GetStatus(self.connections, ('source', 'target')) 
    448             for conn in connection_parameters:  
    449                 addr = self.parent.pre.id_to_index(conn['source']), self.parent.post.id_to_index(conn['target']) 
    450                 try: 
    451                     val = value[addr] 
    452                 except IndexError, e: 
    453                     raise IndexError("%s. addr=%s" % (e, addr)) 
    454                 if numpy.isnan(val): 
    455                     raise Exception("Array contains no value for synapse from %d to %d" % (c.source, c.target)) 
    456                 else: 
    457                     value_list.append(val) 
    458             value = value_list 
    459         if core.is_listlike(value): 
    460             value = numpy.array(value) 
    461         else: 
    462             value = float(value) 
    463  
    464         if name == 'weight': 
    465             value *= 1000.0 
    466             if self.synapse_type == 'inhibitory' and common.is_conductance(self[0].target): 
    467                 value *= -1 # NEST wants negative values for inhibitory weights, even if these are conductances 
    468         elif name == 'delay': 
    469             pass 
    470         else: 
    471             #translation = self.parent.synapse_dynamics.reverse_translate({name: value}) 
    472             #name, value = translation.items()[0] 
    473             translated_name = None 
    474             if self.parent.synapse_dynamics.fast: 
    475                 if name in self.parent.synapse_dynamics.fast.translations: 
    476                     translated_name = self.parent.synapse_dynamics.fast.translations[name]["translated_name"] # a hack 
    477             if translated_name is None: 
    478                 if self.parent.synapse_dynamics.slow: 
    479                     for component_name in "timing_dependence", "weight_dependence", "voltage_dependence": 
    480                         component = getattr(self.parent.synapse_dynamics.slow, component_name) 
    481                         if component and name in component.translations: 
    482                             translated_name = component.translations[name]["translated_name"] 
    483                             break 
    484             if translated_name: 
    485                 name = translated_name 
    486          
    487         i = 0 
    488         try: 
    489             nest.SetStatus(self.connections, name, value) 
    490         except nest.NESTError, e: 
    491             n = 1 
    492             if hasattr(value, '__len__'): 
    493                 n = len(value) 
    494             raise Exception("%s. Trying to set %d values." % (e, n))         
    495  
    496210# --- Initialization, and module attributes ------------------------------------ 
    497211 
  • trunk/src/neuron/__init__.py

    r957 r998  
    1212from pyNN.random import * 
    1313from pyNN.neuron import simulator 
    14 from pyNN import common, recording as base_recording, space, __doc__ 
     14from pyNN import common, core, recording as base_recording, space, __doc__ 
    1515common.simulator = simulator 
    1616base_recording.simulator = simulator 
     
    205205            for cell in self.post: 
    206206                cell._cell.set_Tsodyks_Markram_synapses(self.synapse_type, U, tau_rec, tau_facil, u0) 
    207             synapse_model = 'Tsodyks-Markram' 
     207            self.synapse_model = 'Tsodyks-Markram' 
    208208        else: 
    209             synapse_model = None 
    210                  
    211         self.connection_manager = simulator.ConnectionManager(self.synapse_type, 
    212                                                               synapse_model=synapse_model, 
    213                                                               parent=self) 
    214         self.connections = self.connection_manager         
     209            self.synapse_model = None 
     210        self.connections = [] 
     211         
    215212        ## Create connections 
    216213        method.connect(self) 
     
    243240        Projection.nProj += 1            
    244241     
     242    def __getitem__(self, i): 
     243        """Return the `i`th connection on the local MPI node.""" 
     244        if isinstance(i, int): 
     245            if i < len(self): 
     246                return self.connections[i] 
     247            else: 
     248                raise IndexError("%d > %d" % (i, len(self)-1)) 
     249        elif isinstance(i, slice): 
     250            if i.stop < len(self): 
     251                return [self.connections[j] for j in range(*i.indices(i.stop))] 
     252            else: 
     253                raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
     254     
     255    def __len__(self): 
     256        """Return the number of connections on the local MPI node.""" 
     257        return len(self.connections) 
     258     
     259    def _resolve_synapse_type(self): 
     260        if self.synapse_type is None: 
     261            self.synapse_type = weight>=0 and 'excitatory' or 'inhibitory' 
     262        if self.synapse_model == 'Tsodyks-Markram' and 'TM' not in self.synapse_type: 
     263            self.synapse_type += '_TM'  
     264     
     265    def _divergent_connect(self, source, targets, weights, delays): 
     266        """ 
     267        Connect a neuron to one or more other neurons with a static connection. 
     268         
     269        `source`  -- the ID of the pre-synaptic cell. 
     270        `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
     271        `weight`  -- a list/1D array of connection weights, or a single weight. 
     272                     Must have the same length as `targets`. 
     273        `delays`  -- a list/1D array of connection delays, or a single delay. 
     274                     Must have the same length as `targets`. 
     275        """ 
     276        if not isinstance(source, int) or source > simulator.state.gid_counter or source < 0: 
     277            errmsg = "Invalid source ID: %s (gid_counter=%d)" % (source, simulator.state.gid_counter) 
     278            raise errors.ConnectionError(errmsg) 
     279        if not core.is_listlike(targets): 
     280            targets = [targets] 
     281        if isinstance(weights, float): 
     282            weights = [weights] 
     283        if isinstance(delays, float): 
     284            delays = [delays] 
     285        assert len(targets) > 0 
     286        for target in targets: 
     287            if not isinstance(target, common.IDMixin): 
     288                raise errors.ConnectionError("Invalid target ID: %s" % target) 
     289               
     290        assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets), len(weights), len(delays)) 
     291        self._resolve_synapse_type() 
     292        for target, weight, delay in zip(targets, weights, delays): 
     293            if target.local: 
     294                if "." in self.synapse_type:  
     295                    section, synapse_type = self.synapse_type.split(".")  
     296                    synapse_object = getattr(getattr(target._cell, section), synapse_type)  
     297                else:  
     298                    synapse_object = getattr(target._cell, self.synapse_type)  
     299                nc = simulator.state.parallel_context.gid_connect(int(source), synapse_object) 
     300                nc.weight[0] = weight 
     301                 
     302                # if we have a mechanism (e.g. from 9ML) that includes multiple 
     303                # synaptic channels, need to set nc.weight[1] here 
     304                if nc.wcnt() > 1 and hasattr(target._cell, "type"): 
     305                    nc.weight[1] = target._cell.type.synapse_types.index(self.synapse_type) 
     306                nc.delay  = delay 
     307                # nc.threshold is supposed to be set by ParallelContext.threshold, called in _build_cell(), above, but this hasn't been tested 
     308                self.connections.append(simulator.Connection(source, target, nc)) 
     309 
     310    def _convergent_connect(self, sources, target, weights, delays): 
     311        """ 
     312        Connect a neuron to one or more other neurons with a static connection. 
     313         
     314        `sources`  -- a list/1D array of pre-synaptic cell IDs, or a single ID. 
     315        `target` -- the ID of the post-synaptic cell. 
     316        `weight`  -- a list/1D array of connection weights, or a single weight. 
     317                     Must have the same length as `targets`. 
     318        `delays`  -- a list/1D array of connection delays, or a single delay. 
     319                     Must have the same length as `targets`. 
     320        """ 
     321        if not isinstance(target, int) or target > simulator.state.gid_counter or target < 0: 
     322            errmsg = "Invalid target ID: %s (gid_counter=%d)" % (target, simulator.state.gid_counter) 
     323            raise errors.ConnectionError(errmsg) 
     324        if not core.is_listlike(sources): 
     325            sources = [sources] 
     326        if isinstance(weights, float): 
     327            weights = [weights] 
     328        if isinstance(delays, float): 
     329            delays = [delays] 
     330        assert len(sources) > 0 
     331        for source in sources: 
     332            if not isinstance(source, common.IDMixin): 
     333                raise errors.ConnectionError("Invalid source ID: %s" % source) 
     334               
     335        assert len(sources) == len(weights) == len(delays), "%s %s %s" % (len(sources),len(weights),len(delays)) 
     336                 
     337        if target.local: 
     338            for source, weight, delay in zip(sources, weights, delays): 
     339                if self.synapse_type is None: 
     340                    self.synapse_type = weight >= 0 and 'excitatory' or 'inhibitory' 
     341                if self.synapse_model == 'Tsodyks-Markram' and 'TM' not in self.synapse_type: 
     342                    self.synapse_type += '_TM' 
     343                synapse_object = getattr(target._cell, self.synapse_type)   
     344                nc = simulator.state.parallel_context.gid_connect(int(source), synapse_object) 
     345                nc.weight[0] = weight 
     346                nc.delay  = delay 
     347                # nc.threshold is supposed to be set by ParallelContext.threshold, called in _build_cell(), above, but this hasn't been tested 
     348                self.connections.append(Connection(source, target, nc)) 
     349 
     350     
    245351    # --- Methods for setting connection parameters ---------------------------- 
    246352     
     353    def set(self, name, value): 
     354        """ 
     355        Set connection attributes for all connections on the local MPI node. 
     356         
     357        `name`  -- attribute name 
     358        `value` -- the attribute numeric value, or a list/1D array of such 
     359                   values of the same length as the number of local connections, 
     360                   or a 2D array with the same dimensions as the connectivity 
     361                   matrix (as returned by `get(format='array')`). 
     362        """ 
     363        if numpy.isscalar(value): 
     364            for c in self: 
     365                setattr(c, name, value) 
     366        elif isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
     367            for c in self.connections: 
     368                addr = (self.pre.id_to_index(c.source), self.post.id_to_index(c.target)) 
     369                try: 
     370                    val = value[addr] 
     371                except IndexError, e: 
     372                    raise IndexError("%s. addr=%s" % (e, addr)) 
     373                if numpy.isnan(val): 
     374                    raise Exception("Array contains no value for synapse from %d to %d" % (c.source, c.target)) 
     375                else: 
     376                    setattr(c, name, val) 
     377        elif core.is_listlike(value): 
     378            for c,val in zip(self.connections, value): 
     379                setattr(c, name, val) 
     380        else: 
     381            raise TypeError("Argument should be a numeric type (int, float...), a list, or a numpy array.") 
     382 
    247383    def randomizeWeights(self, rand_distr): 
    248384        """ 
     
    277413        self.setDelays(rarr) 
    278414 
     415    def get(self, parameter_name, format, gather=True): 
     416        """ 
     417        Get the values of a given attribute (weight, delay, etc) for all 
     418        connections on the local MPI node. 
     419         
     420        `parameter_name` -- name of the attribute whose values are wanted. 
     421        `format` -- "list" or "array". Array format implicitly assumes that all 
     422                    connections belong to a single Projection. 
     423         
     424        Return a list or a 2D Numpy array. The array element X_ij contains the 
     425        attribute value for the connection from the ith neuron in the pre- 
     426        synaptic Population to the jth neuron in the post-synaptic Population, 
     427        if a single such connection exists. If there are no such connections, 
     428        X_ij will be NaN. If there are multiple such connections, the summed 
     429        value will be given, which makes some sense for weights, but is 
     430        pretty meaningless for delays.  
     431        """ 
     432        if format == 'list': 
     433            values = [getattr(c, parameter_name) for c in self.connections] 
     434        elif format == 'array': 
     435            values = numpy.nan * numpy.ones((self.pre.size, self.post.size)) 
     436            for c in self.connections: 
     437                value = getattr(c, parameter_name) 
     438                addr = (self.pre.id_to_index(c.source), self.post.id_to_index(c.target)) 
     439                if numpy.isnan(values[addr]): 
     440                    values[addr] = value 
     441                else: 
     442                    values[addr] += value 
     443        else: 
     444            raise Exception("format must be 'list' or 'array'") 
     445        return values 
     446     
    279447 
    280448Space = space.Space 
  • trunk/src/neuron/simulator.py

    r967 r998  
    77 
    88Functions: 
    9     create_cells() 
    109    reset() 
    1110    run() 
     
    1514    ID 
    1615    Recorder 
    17     ConnectionManager 
    1816    Connection 
    1917     
     
    4240nrn_dll_loaded = [] 
    4341recorder_list = [] 
    44 connection_managers = [] 
    4542gid_sources = [] 
    4643logger = logging.getLogger("PyNN") 
     
    167164 
    168165    def clear(self): 
    169         global connection_managers, gid_sources 
     166        global gid_sources 
    170167        self.parallel_context.gid_clear() 
    171168        gid_sources = [] 
     
    173170        self.running = False 
    174171        h.plastic_connections = [] 
    175         connection_managers = [] 
    176172 
    177173def reset(): 
     
    366362 
    367363 
    368  
    369 class ConnectionManager(object): 
    370     """ 
    371     Manage synaptic connections, providing methods for creating, listing, 
    372     accessing individual connections. 
    373     """ 
    374  
    375     def __init__(self, synapse_type, synapse_model=None, parent=None): 
    376         """ 
    377         Create a new ConnectionManager. 
    378          
    379         `synapse_model` -- either None or 'Tsodyks-Markram'. 
    380         `parent` -- the parent `Projection` 
    381         """ 
    382         global connection_managers 
    383         assert parent is not None 
    384         self.connections = [] 
    385         self.parent = parent 
    386         self.synapse_type = synapse_type 
    387         self.synapse_model = synapse_model 
    388         connection_managers.append(self) 
    389          
    390     def __getitem__(self, i): 
    391         """Return the `i`th connection on the local MPI node.""" 
    392         if isinstance(i, int): 
    393             if i < len(self): 
    394                 return self.connections[i] 
    395             else: 
    396                 raise IndexError("%d > %d" % (i, len(self)-1)) 
    397         elif isinstance(i, slice): 
    398             if i.stop < len(self): 
    399                 return [self.connections[j] for j in range(*i.indices(i.stop))] 
    400             else: 
    401                 raise IndexError("%d > %d" % (i.stop, len(self)-1)) 
    402      
    403     def __len__(self): 
    404         """Return the number of connections on the local MPI node.""" 
    405         return len(self.connections) 
    406      
    407     def __iter__(self): 
    408         """Return an iterator over all connections on the local MPI node.""" 
    409         return iter(self.connections) 
    410      
    411     def _resolve_synapse_type(self): 
    412         if self.synapse_type is None: 
    413             self.synapse_type = weight>=0 and 'excitatory' or 'inhibitory' 
    414         if self.synapse_model == 'Tsodyks-Markram' and 'TM' not in self.synapse_type: 
    415             self.synapse_type += '_TM'   
    416      
    417     def connect(self, source, targets, weights, delays): 
    418         """ 
    419         Connect a neuron to one or more other neurons with a static connection. 
    420          
    421         `source`  -- the ID of the pre-synaptic cell. 
    422         `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
    423         `weight`  -- a list/1D array of connection weights, or a single weight. 
    424                      Must have the same length as `targets`. 
    425         `delays`  -- a list/1D array of connection delays, or a single delay. 
    426                      Must have the same length as `targets`. 
    427         """ 
    428         if not isinstance(source, int) or source > state.gid_counter or source < 0: 
    429             errmsg = "Invalid source ID: %s (gid_counter=%d)" % (source, state.gid_counter) 
    430             raise errors.ConnectionError(errmsg) 
    431         if not core.is_listlike(targets): 
    432             targets = [targets] 
    433         if isinstance(weights, float): 
    434             weights = [weights] 
    435         if isinstance(delays, float): 
    436             delays = [delays] 
    437         assert len(targets) > 0 
    438         for target in targets: 
    439             if not isinstance(target, common.IDMixin): 
    440                 raise errors.ConnectionError("Invalid target ID: %s" % target) 
    441                
    442         assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets), len(weights), len(delays)) 
    443         self._resolve_synapse_type() 
    444         for target, weight, delay in zip(targets, weights, delays): 
    445             if target.local: 
    446                 if "." in self.synapse_type:  
    447                     section, synapse_type = self.synapse_type.split(".")  
    448                     synapse_object = getattr(getattr(target._cell, section), synapse_type)  
    449                 else:  
    450                     synapse_object = getattr(target._cell, self.synapse_type)  
    451                 nc = state.parallel_context.gid_connect(int(source), synapse_object) 
    452                 nc.weight[0] = weight 
    453                  
    454                 # if we have a mechanism (e.g. from 9ML) that includes multiple 
    455                 # synaptic channels, need to set nc.weight[1] here 
    456                 if nc.wcnt() > 1 and hasattr(target._cell, "type"): 
    457                     nc.weight[1] = target._cell.type.synapse_types.index(self.synapse_type) 
    458                 nc.delay  = delay 
    459                 # nc.threshold is supposed to be set by ParallelContext.threshold, called in _build_cell(), above, but this hasn't been tested 
    460                 self.connections.append(Connection(source, target, nc)) 
    461  
    462     def convergent_connect(self, sources, target, weights, delays): 
    463         """ 
    464         Connect a neuron to one or more other neurons with a static connection. 
    465          
    466         `sources`  -- a list/1D array of pre-synaptic cell IDs, or a single ID. 
    467         `target` -- the ID of the post-synaptic cell. 
    468         `weight`  -- a list/1D array of connection weights, or a single weight. 
    469                      Must have the same length as `targets`. 
    470         `delays`  -- a list/1D array of connection delays, or a single delay. 
    471                      Must have the same length as `targets`. 
    472         """ 
    473         if not isinstance(target, int) or target > state.gid_counter or target < 0: 
    474             errmsg = "Invalid target ID: %s (gid_counter=%d)" % (target, state.gid_counter) 
    475             raise errors.ConnectionError(errmsg) 
    476         if not core.is_listlike(sources): 
    477             sources = [sources] 
    478         if isinstance(weights, float): 
    479             weights = [weights] 
    480         if isinstance(delays, float): 
    481             delays = [delays] 
    482         assert len(sources) > 0 
    483         for source in sources: 
    484             if not isinstance(source, common.IDMixin): 
    485                 raise errors.ConnectionError("Invalid source ID: %s" % source) 
    486                
    487         assert len(sources) == len(weights) == len(delays), "%s %s %s" % (len(sources),len(weights),len(delays)) 
    488                  
    489         if target.local: 
    490             for source, weight, delay in zip(sources, weights, delays): 
    491                 if self.synapse_type is None: 
    492                     self.synapse_type = weight >= 0 and 'excitatory' or 'inhibitory' 
    493                 if self.synapse_model == 'Tsodyks-Markram' and 'TM' not in self.synapse_type: 
    494                     self.synapse_type += '_TM' 
    495                 synapse_object = getattr(target._cell, self.synapse_type)   
    496                 nc = state.parallel_context.gid_connect(int(source), synapse_object) 
    497                 nc.weight[0] = weight 
    498                 nc.delay  = delay 
    499                 # nc.threshold is supposed to be set by ParallelContext.threshold, called in _build_cell(), above, but this hasn't been tested 
    500                 self.connections.append(Connection(source, target, nc)) 
    501  
    502     def get(self, parameter_name, format): 
    503         """ 
    504         Get the values of a given attribute (weight, delay, etc) for all 
    505         connections on the local MPI node. 
    506          
    507         `parameter_name` -- name of the attribute whose values are wanted. 
    508         `format` -- "list" or "array". Array format implicitly assumes that all 
    509                     connections belong to a single Projection. 
    510          
    511         Return a list or a 2D Numpy array. The array element X_ij contains the 
    512         attribute value for the connection from the ith neuron in the pre- 
    513         synaptic Population to the jth neuron in the post-synaptic Population, 
    514         if a single such connection exists. If there are no such connections, 
    515         X_ij will be NaN. If there are multiple such connections, the summed 
    516         value will be given, which makes some sense for weights, but is 
    517         pretty meaningless for delays.  
    518         """ 
    519         if format == 'list': 
    520             values = [getattr(c, parameter_name) for c in self.connections] 
    521         elif format == 'array': 
    522             values = numpy.nan * numpy.ones((self.parent.pre.size, self.parent.post.size)) 
    523             for c in self.connections: 
    524                 value = getattr(c, parameter_name) 
    525                 addr = (self.parent.pre.id_to_index(c.source), self.parent.post.id_to_index(c.target)) 
    526                 if numpy.isnan(values[addr]): 
    527                     values[addr] = value 
    528                 else: 
    529                     values[addr] += value 
    530         else: 
    531             raise Exception("format must be 'list' or 'array'") 
    532         return values 
    533  
    534     def set(self, name, value): 
    535         """ 
    536         Set connection attributes for all connections on the local MPI node. 
    537          
    538         `name`  -- attribute name 
    539         `value` -- the attribute numeric value, or a list/1D array of such 
    540                    values of the same length as the number of local connections, 
    541                    or a 2D array with the same dimensions as the connectivity 
    542                    matrix (as returned by `get(format='array')`). 
    543         """ 
    544         if numpy.isscalar(value): 
    545             for c in self: 
    546                 setattr(c, name, value) 
    547         elif isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
    548             for c in self.connections: 
    549                 addr = (self.parent.pre.id_to_index(c.source), self.parent.post.id_to_index(c.target)) 
    550                 try: 
    551                     val = value[addr] 
    552                 except IndexError, e: 
    553                     raise IndexError("%s. addr=%s" % (e, addr)) 
    554                 if numpy.isnan(val): 
    555                     raise Exception("Array contains no value for synapse from %d to %d" % (c.source, c.target)) 
    556                 else: 
    557                     setattr(c, name, val) 
    558         elif core.is_listlike(value): 
    559             for c,val in zip(self.connections, value): 
    560                 setattr(c, name, val) 
    561         else: 
    562             raise TypeError("Argument should be a numeric type (int, float...), a list, or a numpy array.") 
    563  
    564  
    565364# --- Initialization, and module attributes ------------------------------------ 
    566365 
  • trunk/src/pcsim/__init__.py

    r957 r998  
    254254            - the ID of the last cell created 
    255255        """ 
    256         global net 
    257256        assert n > 0, 'n must be a positive integer' 
    258257         
     
    419418     
    420419    nProj = 0 
     420    synapse_target_ids = { 'excitatory': 1, 'inhibitory': 2 } 
    421421     
    422422    def __init__(self, presynaptic_population, postsynaptic_population, 
     
    614614        ##self.synapse_type = self.syn_factory #target or 'excitatory' 
    615615        self.synapse_type = target or 'excitatory' 
    616         self.connection_manager = simulator.ConnectionManager(self.syn_factory, parent=self) 
    617         self.connections = self.connection_manager 
     616        self.connections = [] 
    618617        method.connect(self) 
    619618        Projection.nProj += 1         
     
    622621    # useful when we start (re-)optimizing the implementation 
    623622 
    624     ##def __len__(self): 
    625     ##    """Return the total number of connections.""" 
    626     ##    return self.pcsim_projection.size() 
     623    def __len__(self): 
     624        """Return the total number of connections.""" 
     625        ###return self.pcsim_projection.size() 
     626        return len(self.connections) 
    627627     
    628628    #def __getitem__(self, n): 
    629629    #    return self.pcsim_projection[n] 
    630  
    631       
     630    def __getitem__(self, i): 
     631        """Return the `i`th connection on the local MPI node.""" 
     632        #if self.parent: 
     633        #    if self.parent.is_conductance: 
     634        #        A = 1e6 # S --> uS 
     635        #    else: 
     636        #        A = 1e9 # A --> nA 
     637        #    return Connection(self.parent.pcsim_projection.object(i), A) 
     638        #else: 
     639        return self.connections[i] 
     640     
     641    def _divergent_connect(self, source, targets, weights, delays): 
     642        """ 
     643        Connect a neuron to one or more other neurons with a static connection. 
     644         
     645        `source`  -- the ID of the pre-synaptic cell. 
     646        `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
     647        `weight`  -- a list/1D array of connection weights, or a single weight. 
     648                     Must have the same length as `targets`. 
     649        `delays`  -- a list/1D array of connection delays, or a single delay. 
     650                     Must have the same length as `targets`. 
     651        """ 
     652        if not isinstance(source, (int, long)) or source < 0: 
     653            errmsg = "Invalid source ID: %s" % source 
     654            raise errors.ConnectionError(errmsg) 
     655        if not core.is_listlike(targets): 
     656            targets = [targets] 
     657        if isinstance(weights, float): 
     658            weights = [weights] 
     659        if isinstance(delays, float): 
     660            delays = [delays] 
     661        assert len(targets) > 0 
     662        for target in targets: 
     663            if not isinstance(target, common.IDMixin): 
     664                raise errors.ConnectionError("Invalid target ID: %s" % target) 
     665        assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets),len(weights),len(delays)) 
     666        if common.is_conductance(targets[0]): 
     667            weight_scale_factor = 1e-6 # Convert from µS to S   
     668        else: 
     669            weight_scale_factor = 1e-9 # Convert from nA to A 
     670         
     671        synapse_type = self.syn_factory or "excitatory" 
     672        if isinstance(synapse_type, basestring): 
     673            syn_target_id = Projection.synapse_target_ids[synapse_type] 
     674            syn_factory = pypcsim.SimpleScalingSpikingSynapse( 
     675                              syn_target_id, weights[0], delays[0]) 
     676        elif isinstance(synapse_type, pypcsim.SimObject): 
     677            syn_factory = synapse_type 
     678        else: 
     679            raise errors.ConnectionError("synapse_type must be a string or a PCSIM synapse factory. Actual type is %s" % type(synapse_type)) 
     680        for target, weight, delay in zip(targets, weights, delays): 
     681            syn_factory.W = weight*weight_scale_factor 
     682            syn_factory.delay = delay*0.001 # ms --> s 
     683            try: 
     684                c = simulator.net.connect(source, target, syn_factory) 
     685            except RuntimeError, e: 
     686                raise errors.ConnectionError(e) 
     687            if target.local: 
     688                self.connections.append(simulator.Connection(source, target, simulator.net.object(c), 1.0/weight_scale_factor)) 
     689     
     690    def _convergent_connect(self, sources, target, weights, delays): 
     691        """ 
     692        Connect a neuron to one or more other neurons with a static connection. 
     693         
     694        `sources`  -- a list/1D array of pre-synaptic cell IDs, or a single ID. 
     695        `target` -- the ID of the post-synaptic cell. 
     696        `weight`  -- a list/1D array of connection weights, or a single weight. 
     697                     Must have the same length as `targets`. 
     698        `delays`  -- a list/1D array of connection delays, or a single delay. 
     699                     Must have the same length as `targets`. 
     700        """ 
     701        if not isinstance(target, (int, long)) or target < 0: 
     702            errmsg = "Invalid target ID: %s" % target 
     703            raise errors.ConnectionError(errmsg) 
     704        if not core.is_listlike(sources): 
     705            sources = [sources] 
     706        if isinstance(weights, float): 
     707            weights = [weights] 
     708        if isinstance(delays, float): 
     709            delays = [delays] 
     710        assert len(sources) > 0 
     711        for source in sources: 
     712            if not isinstance(source, common.IDMixin): 
     713                raise errors.ConnectionError("Invalid source ID: %s" % source) 
     714        assert len(sources) == len(weights) == len(delays), "%s %s %s" % (len(sources),len(weights),len(delays)) 
     715        if common.is_conductance(target): 
     716            weight_scale_factor = 1e-6 # Convert from µS to S   
     717        else: 
     718            weight_scale_factor = 1e-9 # Convert from nA to A 
     719         
     720        synapse_type = self.syn_factory or "excitatory" 
     721        if isinstance(synapse_type, basestring): 
     722            syn_target_id = Projection.synapse_target_ids[synapse_type] 
     723            syn_factory = pypcsim.SimpleScalingSpikingSynapse( 
     724                              syn_target_id, weights[0], delays[0]) 
     725        elif isinstance(synapse_type, pypcsim.SimObject): 
     726            syn_factory = synapse_type 
     727        else: 
     728            raise errors.ConnectionError("synapse_type must be a string or a PCSIM synapse factory. Actual type is %s" % type(synapse_type)) 
     729        for source, weight, delay in zip(sources, weights, delays): 
     730            syn_factory.W = weight*weight_scale_factor 
     731            syn_factory.delay = delay*0.001 # ms --> s 
     732            try: 
     733                c = simulator.net.connect(source, target, syn_factory) 
     734            except RuntimeError, e: 
     735                raise errors.ConnectionError(e) 
     736            if target.local: 
     737                self.connections.append(simulator.Connection(source, target, simulator.net.object(c), 1.0/weight_scale_factor))   
     738     
    632739    # --- Methods for setting connection parameters ---------------------------- 
    633      
     740 
     741    def set(self, name, value): 
     742        """ 
     743        Set connection attributes for all connections on the local MPI node. 
     744         
     745        `name`  -- attribute name 
     746        `value` -- the attribute numeric value, or a list/1D array of such 
     747                   values of the same length as the number of local connections, 
     748                   or a 2D array with the same dimensions as the connectivity 
     749                   matrix (as returned by `get(format='array')`) 
     750        """ 
     751        if numpy.isscalar(value): 
     752            for c in self: 
     753                setattr(c, name, value) 
     754        elif isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
     755            for c in self.connections: 
     756                addr = (self.pre.id_to_index(c.source), self.post.id_to_index(c.target)) 
     757                try: 
     758                    val = value[addr] 
     759                except IndexError, e: 
     760                    raise IndexError("%s. addr=%s" % (e, addr)) 
     761                if numpy.isnan(val): 
     762                    raise Exception("Array contains no value for synapse from %d to %d" % (c.source, c.target)) 
     763                else: 
     764                    setattr(c, name, val) 
     765        elif core.is_listlike(value): 
     766            for c,val in zip(self.connections, value): 
     767                setattr(c, name, val) 
     768        else: 
     769            raise TypeError("Argument should be a numeric type (int, float...), a list, or a numpy array.") 
     770 
    634771    ##def setWeights(self, w): 
    635772    ##    """ 
     
    684821    ##    for i in range(len(self)): 
    685822    ##        simulator.net.object(self.pcsim_projection[i]).delay = delays[i] 
    686     ## 
     823     
     824    def get(self, parameter_name, format, gather=True): 
     825        """ 
     826        Get the values of a given attribute (weight, delay, etc) for all 
     827        connections on the local MPI node. 
     828         
     829        `parameter_name` -- name of the attribute whose values are wanted. 
     830        `format` -- "list" or "array". Array format implicitly assumes that all 
     831                    connections belong to a single Projection. 
     832         
     833        Return a list or a 2D Numpy array. The array element X_ij contains the 
     834        attribute value for the connection from the ith neuron in the pre- 
     835        synaptic Population to the jth neuron in the post-synaptic Population, 
     836        if such a connection exists. If there are no such connections, X_ij will 
     837        be NaN. 
     838        """ 
     839        if format == 'list': 
     840            values = [getattr(c, parameter_name) for c in self] 
     841        elif format == 'array': 
     842            values = numpy.nan * numpy.ones((self.pre.size, self.post.size)) 
     843            for c in self: 
     844                addr = (self.pre.id_to_index(c.source), self.post.id_to_index(c.target)) 
     845                values[addr] = getattr(c, parameter_name) 
     846        else: 
     847            raise Exception("format must be 'list' or 'array'") 
     848        return values         
     849     
     850     
    687851    ##def getWeights(self, format='list', gather=True): 
    688852    ##    """ 
  • trunk/src/pcsim/simulator.py

    r957 r998  
    77 
    88Functions: 
    9     create_cells() 
    109    reset() 
    1110 
     
    1312    ID 
    1413    Recorder 
    15     ConnectionManager 
    1614    Connection 
    1715     
     
    3634 
    3735recorder_list = [] 
    38 connection_managers = [] 
    3936STATE_VARIABLE_MAP = {"v": ("Vinit", 1e-3)} 
    4037 
     
    197194     
    198195 
    199 class ConnectionManager(object): 
    200     """ 
    201     Manage synaptic connections, providing methods for creating, listing, 
    202     accessing individual connections. 
    203     """ 
    204  
    205     synapse_target_ids = { 'excitatory': 1, 'inhibitory': 2 } 
    206  
    207     def __init__(self, synapse_type, synapse_model=None, parent=None): 
    208         """ 
    209         Create a new ConnectionManager. 
    210          
    211         `synapse_type` -- the 'physiological type' of the synapse, e.g. 
    212                           'excitatory' or 'inhibitory', or a PCSIM synapse 
    213                           factory. 
    214         `synapse_model` -- not used. Present for consistency with other simulators. 
    215         `parent` -- the parent `Projection`, if any. 
    216         """ 
    217         global connection_managers 
    218         self.synapse_type = synapse_type 
    219         self.connections = [] 
    220         self.parent = parent 
    221         connection_managers.append(self) 
    222         self.parent = parent 
    223         #if parent is None: 
    224         self.connections = [] 
    225  
    226     def __getitem__(self, i): 
    227         """Return the `i`th connection on the local MPI node.""" 
    228         #if self.parent: 
    229         #    if self.parent.is_conductance: 
    230         #        A = 1e6 # S --> uS 
    231         #    else: 
    232         #        A = 1e9 # A --> nA 
    233         #    return Connection(self.parent.pcsim_projection.object(i), A) 
    234         #else: 
    235         return self.connections[i] 
    236      
    237     def __len__(self): 
    238         """Return the number of connections on the local MPI node.""" 
    239         #if self.parent: 
    240         #    return self.parent.pcsim_projection.size() 
    241         #else: 
    242         return len(self.connections) 
    243      
    244     def __iter__(self): 
    245         """Return an iterator over all connections on the local MPI node.""" 
    246         for i in range(len(self)): 
    247             yield self[i] 
    248      
    249     def connect(self, source, targets, weights, delays): 
    250         """ 
    251         Connect a neuron to one or more other neurons with a static connection. 
    252          
    253         `source`  -- the ID of the pre-synaptic cell. 
    254         `targets` -- a list/1D array of post-synaptic cell IDs, or a single ID. 
    255         `weight`  -- a list/1D array of connection weights, or a single weight. 
    256                      Must have the same length as `targets`. 
    257         `delays`  -- a list/1D array of connection delays, or a single delay. 
    258                      Must have the same length as `targets`. 
    259         """ 
    260         if not isinstance(source, (int, long)) or source < 0: 
    261             errmsg = "Invalid source ID: %s" % source 
    262             raise errors.ConnectionError(errmsg) 
    263         if not core.is_listlike(targets): 
    264             targets = [targets] 
    265         if isinstance(weights, float): 
    266             weights = [weights] 
    267         if isinstance(delays, float): 
    268             delays = [delays] 
    269         assert len(targets) > 0 
    270         for target in targets: 
    271             if not isinstance(target, common.IDMixin): 
    272                 raise errors.ConnectionError("Invalid target ID: %s" % target) 
    273         assert len(targets) == len(weights) == len(delays), "%s %s %s" % (len(targets),len(weights),len(delays)) 
    274         if common.is_conductance(targets[0]): 
    275             weight_scale_factor = 1e-6 # Convert from µS to S   
    276         else: 
    277             weight_scale_factor = 1e-9 # Convert from nA to A 
    278          
    279         synapse_type = self.synapse_type or "excitatory" 
    280         if isinstance(synapse_type, basestring): 
    281             syn_target_id = ConnectionManager.synapse_target_ids[synapse_type] 
    282             syn_factory = pypcsim.SimpleScalingSpikingSynapse( 
    283                               syn_target_id, weights[0], delays[0]) 
    284         elif isinstance(synapse_type, pypcsim.SimObject): 
    285             syn_factory = synapse_type 
    286         else: 
    287             raise errors.ConnectionError("synapse_type must be a string or a PCSIM synapse factory. Actual type is %s" % type(synapse_type)) 
    288         for target, weight, delay in zip(targets, weights, delays): 
    289             syn_factory.W = weight*weight_scale_factor 
    290             syn_factory.delay = delay*0.001 # ms --> s 
    291             try: 
    292                 c = net.connect(source, target, syn_factory) 
    293             except RuntimeError, e: 
    294                 raise errors.ConnectionError(e) 
    295             if target.local: 
    296                 self.connections.append(Connection(source, target, net.object(c), 1.0/weight_scale_factor)) 
    297      
    298     def convergent_connect(self, sources, target, weights, delays): 
    299         """ 
    300         Connect a neuron to one or more other neurons with a static connection. 
    301          
    302         `sources`  -- a list/1D array of pre-synaptic cell IDs, or a single ID. 
    303         `target` -- the ID of the post-synaptic cell. 
    304         `weight`  -- a list/1D array of connection weights, or a single weight. 
    305                      Must have the same length as `targets`. 
    306         `delays`  -- a list/1D array of connection delays, or a single delay. 
    307                      Must have the same length as `targets`. 
    308         """ 
    309         if not isinstance(target, (int, long)) or target < 0: 
    310             errmsg = "Invalid target ID: %s" % target 
    311             raise errors.ConnectionError(errmsg) 
    312         if not core.is_listlike(sources): 
    313             sources = [sources] 
    314         if isinstance(weights, float): 
    315             weights = [weights] 
    316         if isinstance(delays, float): 
    317             delays = [delays] 
    318         assert len(sources) > 0 
    319         for source in sources: 
    320             if not isinstance(source, common.IDMixin): 
    321                 raise errors.ConnectionError("Invalid source ID: %s" % source) 
    322         assert len(sources) == len(weights) == len(delays), "%s %s %s" % (len(sources),len(weights),len(delays)) 
    323         if common.is_conductance(target): 
    324             weight_scale_factor = 1e-6 # Convert from µS to S   
    325         else: 
    326             weight_scale_factor = 1e-9 # Convert from nA to A 
    327          
    328         synapse_type = self.synapse_type or "excitatory" 
    329         if isinstance(synapse_type, basestring): 
    330             syn_target_id = ConnectionManager.synapse_target_ids[synapse_type] 
    331             syn_factory = pypcsim.SimpleScalingSpikingSynapse( 
    332                               syn_target_id, weights[0], delays[0]) 
    333         elif isinstance(synapse_type, pypcsim.SimObject): 
    334             syn_factory = synapse_type 
    335         else: 
    336             raise errors.ConnectionError("synapse_type must be a string or a PCSIM synapse factory. Actual type is %s" % type(synapse_type)) 
    337         for source, weight, delay in zip(sources, weights, delays): 
    338             syn_factory.W = weight*weight_scale_factor 
    339             syn_factory.delay = delay*0.001 # ms --> s 
    340             try: 
    341                 c = net.connect(source, target, syn_factory) 
    342             except RuntimeError, e: 
    343                 raise errors.ConnectionError(e) 
    344             if target.local: 
    345                 self.connections.append(Connection(source, target, net.object(c), 1.0/weight_scale_factor)) 
    346          
    347     def get(self, parameter_name, format): 
    348         """ 
    349         Get the values of a given attribute (weight, delay, etc) for all 
    350         connections on the local MPI node. 
    351          
    352         `parameter_name` -- name of the attribute whose values are wanted. 
    353         `format` -- "list" or "array". Array format implicitly assumes that all 
    354                     connections belong to a single Projection. 
    355          
    356         Return a list or a 2D Numpy array. The array element X_ij contains the 
    357         attribute value for the connection from the ith neuron in the pre- 
    358         synaptic Population to the jth neuron in the post-synaptic Population, 
    359         if such a connection exists. If there are no such connections, X_ij will 
    360         be NaN. 
    361         """ 
    362         if format == 'list': 
    363             values = [getattr(c, parameter_name) for c in self] 
    364         elif format == 'array': 
    365             values = numpy.nan * numpy.ones((self.parent.pre.size, self.parent.post.size)) 
    366             for c in self: 
    367                 addr = (self.parent.pre.id_to_index(c.source), self.parent.post.id_to_index(c.target)) 
    368                 values[addr] = getattr(c, parameter_name) 
    369         else: 
    370             raise Exception("format must be 'list' or 'array'") 
    371         return values         
    372      
    373     def set(self, name, value): 
    374         """ 
    375         Set connection attributes for all connections on the local MPI node. 
    376          
    377         `name`  -- attribute name 
    378         `value` -- the attribute numeric value, or a list/1D array of such 
    379                    values of the same length as the number of local connections, 
    380                    or a 2D array with the same dimensions as the connectivity 
    381                    matrix (as returned by `get(format='array')`) 
    382         """ 
    383         if numpy.isscalar(value): 
    384             for c in self: 
    385                 setattr(c, name, value) 
    386         elif isinstance(value, numpy.ndarray) and len(value.shape) == 2: 
    387             for c in self.connections: 
    388                 addr = (self.parent.pre.id_to_index(c.source), self.parent.post.id_to_index(c.target)) 
    389                 try: 
    390                     val = value[addr] 
    391                 except IndexError, e: 
    392                     raise IndexError("%s. addr=%s" % (e, addr)) 
    393                 if numpy.isnan(val): 
    394                     raise Exception("Array contains no value for synapse from %d to %d" % (c.source, c.target)) 
    395                 else: 
    396                     setattr(c, name, val) 
    397         elif core.is_listlike(value): 
    398             for c,val in zip(self.connections, value): 
    399                 setattr(c, name, val) 
    400         else: 
    401             raise TypeError("Argument should be a numeric type (int, float...), a list, or a numpy array.") 
    402  
    403  
    404196# --- Initialization, and module attributes ------------------------------------ 
    405197           
  • trunk/test/system/scenarios.py

    r993 r998  
    408408        assert_arrays_equal(rec, data[0]) 
    409409 
    410 @register(exclude=['pcsim']) 
     410@register(exclude=['pcsim', 'moose']) 
    411411def test_EIF_cond_alpha_isfa_ista(sim): 
    412412    set_simulator(sim) 
     
    448448     
    449449 
    450 @register(exclude=['pcsim']) 
     450@register(exclude=['pcsim', 'moose']) 
    451451def test_record_vm_and_gsyn_from_assembly(sim): 
    452452    from pyNN.utility import init_logging 
  • trunk/test/unittests/test_connectors.py

    r850 r998  
    5353 
    5454 
    55 class MockConnectionManager(object): 
    56      
    57     def __init__(self): 
     55class MockRNG(random.WrappedRNG): 
     56    rng = None 
     57     
     58    def __init__(self, num_processes, delta=1): 
     59        random.num_processes = num_processes 
     60        random.WrappedRNG.__init__(self) 
     61        self.start = 0.0 
     62        self.delta = delta 
     63     
     64    def _next(self, distribution, n, parameters): 
     65        s = self.start 
     66        self.start += n*self.delta 
     67        return numpy.arange(s, s+n*self.delta, self.delta) 
     68 
     69 
     70class MockProjection(object): 
     71     
     72    def __init__(self, pre, post): 
     73        self.pre = pre 
     74        self.post = post 
    5875        self.connections = [] 
    59      
    60     def connect(self, src, targets, weights, delays): 
     76        self.rng = MockRNG(num_processes=2, delta=0.1) 
     77        self.synapse_type = 'inhibitory' 
     78 
     79    def _divergent_connect(self, src, targets, weights, delays): 
    6180        #if src in self.connections: 
    6281        #    raise Exception("connect already called with source %s" % src) # no reason why this shouldn't happen, but it doesn't in the current implementation, so I'm being lazy 
     
    7493            self.connections.append((src, tgt, w, d)) 
    7594 
    76     def convergent_connect(self, sources, tgt, weights, delays): 
     95    def _convergent_connect(self, sources, tgt, weights, delays): 
    7796        if isinstance(weights, float): 
    7897            weights = repeat(weights) 
     
    81100        for src, w, d in zip(sources, weights, delays): 
    82101            self.connections.append((src, tgt, w, d)) 
    83          
    84  
    85 class MockRNG(random.WrappedRNG): 
    86     rng = None 
    87      
    88     def __init__(self, num_processes, delta=1): 
    89         random.num_processes = num_processes 
    90         random.WrappedRNG.__init__(self) 
    91         self.start = 0.0 
    92         self.delta = delta 
    93      
    94     def _next(self, distribution, n, parameters): 
    95         s = self.start 
    96         self.start += n*self.delta 
    97         return numpy.arange(s, s+n*self.delta, self.delta) 
    98  
    99  
    100 class MockProjection(object): 
    101      
    102     def __init__(self, pre, post): 
    103         self.pre = pre 
    104         self.post = post 
    105         self.connection_manager = MockConnectionManager() 
    106         self.rng = MockRNG(num_processes=2, delta=0.1) 
    107         self.synapse_type = 'inhibitory' 
    108102 
    109103 
     
    119113        C.progression = Mock() 
    120114        C.connect(self.prj) 
    121         assert_equal(self.prj.connection_manager.connections, 
     115        assert_equal(self.prj.connections, 
    122116                     [(18, 80, 5.0, 0.5), (20, 82, 5, 0.5)]) 
    123117 
     
    128122        C.progression = Mock() 
    129123        C.connect(self.prj) 
    130         assert_equal(self.prj.connection_manager.connections, 
     124        assert_equal(self.prj.connections, 
    131125                     [(18, 80, 1.0, 0.5), (20, 82, 3.0, 0.5)]) 
    132126 
     
    143137        C.progression = Mock() 
    144138        C.connect(self.prj) 
    145         assert_equal(set(self.prj.connection_manager.connections), 
     139        assert_equal(set(self.prj.connections), 
    146140                     set([(17, 80, 5.0, 0.5), 
    147141                          (17, 82, 5.0, 0.5), 
     
    159153        C.progression = Mock() 
    160154        C.connect(self.prj) 
    161         assert_equal(self.prj.connection_manager.connections, 
     155        assert_equal(self.prj.connections, 
    162156                     [(17, 80, 1.0, 0.5), 
    163157                      (17, 82, 3.0, 0.5), 
     
    175169        C.progression = Mock() 
    176170        C.connect(self.prj) 
    177         assert_equal(self.prj.connection_manager.connections, 
     171        assert_equal(self.prj.connections, 
    178172                     [(17, 80, 163.0, 0.5),   # 100+|17-80| 
    179173                      (17, 82, 165.0, 0.5),   # 100+|17-82| 
     
    220214        # first 8 are created (17, 79), (17, 80), (17,81), (17,82), (17,83), (18,79), (18,80), (18,81) 
    221215        # of these, (17,80), (17,82), (18,80) are created on this node 
    222         assert_equal(self.prj.connection_manager.connections, 
     216        assert_equal(self.prj.connections, 
    223217                     [(17, 80, 0.0, MIN_DELAY), 
    224218                      (17, 82, 0.0, MIN_DELAY), 
     
    240234        # 20 possible connections. Only those with a sufficiently small distance 
    241235        # are created 
    242         assert_equal(self.prj.connection_manager.connections, 
     236        assert_equal(self.prj.connections, 
    243237                     [(18, 80, 0.0, MIN_DELAY), 
    244238                      (19, 80, 0.0, MIN_DELAY), 
     
    266260        C.connect(self.prj) 
    267261        # note that ListConnector does not filter out non-local connections 
    268         assert_equal(self.prj.connection_manager.connections, 
     262        assert_equal(self.prj.connections, 
    269263                     [(17, 79, 0.1, 0.1), 
    270264                      (17, 80, 0.5, 0.14), 
     
    307301        C = connectors.FromFileConnector("test.connections", distributed=False) 
    308302        C.connect(self.prj) 
    309         assert_equal(self.prj.connection_manager.connections, 
     303        assert_equal(self.prj.connections, 
    310304                     [(17, 79, 0.1, 0.1), 
    311305                      (17, 80, 0.5, 0.14), 
     
    319313        C = connectors.FromFileConnector("test.connections", distributed=True) 
    320314        C.connect(self.prj) 
    321         assert_equal(self.prj.connection_manager.connections, 
     315        assert_equal(self.prj.connections, 
    322316                     [(17, 80, 0.5, 0.14), 
    323317                      (19, 82, 0.3, 0.12)]) 
     
    340334        C.connect(self.prj) 
    341335        # FixedNumberPost does not currently filter out only local connections 
    342         assert_equal(self.prj.connection_manager.connections, 
     336        assert_equal(self.prj.connections, 
    343337                     [(17, 79, 0.0, MIN_DELAY), 
    344338                      (17, 80, 0.0, MIN_DELAY), 
     
    371365        self.prj.post.local_cells = [MockCell(n) for n in self.prj.post.local_cells] 
    372366        C.connect(self.prj) 
    373         assert_equal(self.prj.connection_manager.connections, 
     367        assert_equal(self.prj.connections, 
    374368                     [(17, 80, 0.0, MIN_DELAY), 
    375369                      (18, 80, 0.0, MIN_DELAY), 
  • trunk/test/unittests/test_projection.py

    r880 r998  
    2424    first_id = 555 
    2525 
    26 class MockConnectionManager(object): 
    2726    def __len__(self): 
    2827        return 999 
     
    4948                            synapse_dynamics=standardmodels.SynapseDynamics()) 
    5049     
    51 def test_len(): 
    52     p1 = MockPopulation() 
    53     p2 = MockPopulation() 
    54     prj = common.Projection(p1, p2, method=Mock()) 
    55     prj.connection_manager = MockConnectionManager() 
    56     assert_equal(len(prj), len(prj.connection_manager)) 
    57      
    5850def test_size_no_gather(): 
    5951    p1 = MockPopulation() 
    6052    p2 = MockPopulation() 
    6153    prj = common.Projection(p1, p2, method=Mock()) 
    62     prj.connection_manager = MockConnectionManager() 
    63     assert_equal(prj.size(gather=False), len(prj)) 
     54    orig_len = common.Projection.__len__ 
     55    common.Projection.__len__ = Mock(return_value=42) 
     56    n = prj.size(gather=False) 
     57    prj.__len__.assert_called() 
     58    common.Projection.__len__ = orig_len 
    6459     
    6560def test_size_with_gather(): 
    6661    orig_mpi_sum = common.recording.mpi_sum 
     62    orig_len = common.Projection.__len__ 
    6763    common.recording.mpi_sum = Mock() 
    68     p1 = MockPopulation() 
    69     p2 = MockPopulation() 
    70     prj = common.Projection(p1, p2, method=Mock()) 
    71     prj.connection_manager = MockConnectionManager() 
     64    common.Projection.__len__ = Mock(return_value=42) 
     65    p1 = MockPopulation() 
     66    p2 = MockPopulation() 
     67    prj = common.Projection(p1, p2, method=Mock()) 
    7268    prj.size(gather=True) 
    7369    common.recording.mpi_sum.assert_called_with(len(prj)) 
    7470    common.recording.mpi_sum = orig_mpi_sum 
    75      
    76 def test__getitem(): 
    77     p1 = MockPopulation() 
    78     p2 = MockPopulation() 
    79     prj = common.Projection(p1, p2, method=Mock()) 
    80     prj.connection_manager = MockConnectionManager() 
    81     assert_equal(prj[0], 888) 
     71    common.Projection.__len__ = orig_len 
    8272     
    8373def test_set_weights(): 
     
    8777    prj.synapse_type = "foo" 
    8878    prj.post.local_cells = [0] 
    89     prj.connection_manager = MockConnectionManager() 
    90     prj.connection_manager.set = Mock() 
     79    prj.set = Mock() 
    9180    prj.setWeights(0.5) 
    92     prj.connection_manager.set.assert_called_with('weight', 0.5) 
     81    prj.set.assert_called_with('weight', 0.5) 
    9382     
    9483def test_randomize_weights(): 
    95     p1 = MockPopulation() 
    96     p2 = MockPopulation() 
    97     prj = common.Projection(p1, p2, method=Mock()) 
    98     prj.connection_manager = MockConnectionManager() 
    99     prj.setWeights = Mock() 
     84    orig_len = common.Projection.__len__ 
     85    common.Projection.__len__ = Mock(return_value=42) 
     86    p1 = MockPopulation() 
     87    p2 = MockPopulation() 
     88    prj = common.Projection(p1, p2, method=Mock()) 
     89    prj.set = Mock() 
    10090    rd = Mock() 
    10191    rd.next = Mock(return_value=777) 
    10292    prj.randomizeWeights(rd) 
    10393    rd.next.assert_called_with(len(prj)) 
    104     prj.setWeights.assert_called_with(777) 
     94    prj.set.assert_called_with('weight', 777) 
     95    common.Projection.__len__ = orig_len 
    10596     
    10697def test_set_delays(): 
     
    10899    p2 = MockPopulation() 
    109100    prj = common.Projection(p1, p2, method=Mock()) 
    110     prj.connection_manager = MockConnectionManager() 
    111     prj.connection_manager.set = Mock() 
     101    prj.set = Mock() 
    112102    prj.setDelays(0.5) 
    113     prj.connection_manager.set.assert_called_with('delay', 0.5) 
     103    prj.set.assert_called_with('delay', 0.5) 
    114104     
    115105def test_randomize_delays(): 
    116     p1 = MockPopulation() 
    117     p2 = MockPopulation() 
    118     prj = common.Projection(p1, p2, method=Mock()) 
    119     prj.connection_manager = MockConnectionManager() 
    120     prj.setDelays = Mock() 
     106    orig_len = common.Projection.__len__ 
     107    common.Projection.__len__ = Mock(return_value=42) 
     108    p1 = MockPopulation() 
     109    p2 = MockPopulation() 
     110    prj = common.Projection(p1, p2, method=Mock()) 
     111    prj.set = Mock() 
    121112    rd = Mock() 
    122113    rd.next = Mock(return_value=777) 
    123114    prj.randomizeDelays(rd) 
    124115    rd.next.assert_called_with(len(prj)) 
    125     prj.setDelays.assert_called_with(777) 
     116    prj.set.assert_called_with('delay', 777) 
     117    common.Projection.__len__ = orig_len 
    126118     
    127119def test_set_synapse_dynamics_param(): 
     
    129121    p2 = MockPopulation() 
    130122    prj = common.Projection(p1, p2, method=Mock()) 
    131     prj.connection_manager = MockConnectionManager() 
    132     prj.connection_manager.set = Mock() 
     123    prj.set = Mock() 
    133124    prj.setSynapseDynamics('U', 0.5) 
    134     prj.connection_manager.set.assert_called_with('U', 0.5) 
     125    prj.set.assert_called_with('U', 0.5) 
    135126     
    136127def test_get_weights(): 
     
    138129    p2 = MockPopulation() 
    139130    prj = common.Projection(p1, p2, method=Mock()) 
    140     prj.connection_manager = MockConnectionManager() 
    141     prj.connection_manager.get = Mock() 
     131    prj.get = Mock() 
    142132    prj.getWeights(format='list', gather=False) 
    143     prj.connection_manager.get.assert_called_with('weight', 'list') 
     133    prj.get.assert_called_with('weight', 'list') 
    144134     
    145135def test_get_delays(): 
     
    147137    p2 = MockPopulation() 
    148138    prj = common.Projection(p1, p2, method=Mock()) 
    149     prj.connection_manager = MockConnectionManager() 
    150     prj.connection_manager.get = Mock() 
     139    prj.get = Mock() 
    151140    prj.getDelays(format='list', gather=False) 
    152     prj.connection_manager.get.assert_called_with('delay', 'list') 
     141    prj.get.assert_called_with('delay', 'list') 
    153142 
    154143def test_save_connections(): 
     
    159148    p2 = MockPopulation() 
    160149    prj = common.Projection(p1, p2, method=Mock()) 
    161     prj.connection_manager = MockConnectionManager() 
    162150    prj.connections = [MockConnection(), MockConnection(), MockConnection()] 
    163151    prj.saveConnections(filename, gather=False, compatible_output=False) 
     
    172160    p2 = MockPopulation() 
    173161    prj = common.Projection(p1, p2, method=Mock()) 
    174     prj.connection_manager = MockConnectionManager() 
     162    prj.get = Mock(return_value=range(5)) 
    175163    prj.printWeights(filename, format='list', gather=False) 
     164    prj.get.assert_called_with('weight', format='list', gather=False) 
    176165    assert os.path.exists(filename) 
    177166    os.remove(filename) 
     
    184173    p2 = MockPopulation() 
    185174    prj = common.Projection(p1, p2, method=Mock()) 
    186     prj.connection_manager = MockConnectionManager() 
     175    prj.get = Mock(return_value=numpy.arange(5.0)) 
    187176    prj.printWeights(filename, format='array', gather=False) 
     177    prj.get.assert_called_with('weight', format='array', gather=False) 
    188178    assert os.path.exists(filename) 
    189179    os.remove(filename) 
     
    214204 
    215205def test_describe(): 
     206    orig_len = common.Projection.__len__ 
     207    common.Projection.__len__ = Mock(return_value=42) 
    216208    p1 = MockPopulation() 
    217209    p2 = MockPopulation() 
    218210    prj = common.Projection(p1, p2, method=Mock(), synapse_dynamics=standardmodels.SynapseDynamics()) 
    219     prj.connection_manager = MockConnectionManager() 
    220211    prj.pre.describe = Mock() 
    221212    prj.post.describe = Mock() 
    222213    assert isinstance(prj.describe(engine='string'), basestring) 
    223214    assert isinstance(prj.describe(template=None), dict) 
     215    common.Projection.__len__ = orig_len