Skip to content

Network#

A Network object holds copies of previously defined populations, projections or monitors in order to simulate them independently.

The parallel_run() method can be used to simulate different networks in parallel.

ANNarchy.core.Network.Network #

A network gathers already defined populations, projections and monitors in order to run them independently.

This is particularly useful when varying single parameters of a network and comparing the results (see the parallel_run() method).

Only objects declared before the creation of the network can be used. Global methods such as simulate() must be used on the network object. The objects must be accessed through the get() method, as the original ones will not be part of the network (a copy is made).

Each network must be individually compiled, but it does not matter if the original objects were already compiled.

When passing everything=True to the constructor, all populations/projections/monitors already defined at the global level will be added to the network.

If not, you can select which object will be added to network with the add() method.

Example with everything=True:

pop = Population(100, Izhikevich)
proj = Projection(pop, pop, 'exc')
proj.connect_all_to_all(1.0)
m = Monitor(pop, 'spike')

compile() # Optional

net = Network(everything=True)
net.get(pop).a = 0.02
net.compile()
net.simulate(1000.)

net2 = Network(everything=True)
net2.get(pop).a = 0.05
net2.compile()
net2.simulate(1000.)

t, n = net.get(m).raster_plot()
t2, n2 = net2.get(m).raster_plot()

Example with everything=False (the default):

pop = Population(100, Izhikevich)
proj1 = Projection(pop, pop, 'exc')
proj1.connect_all_to_all(1.0)
proj2 = Projection(pop, pop, 'exc')
proj2.connect_all_to_all(2.0)
m = Monitor(pop, 'spike')

net = Network()
net.add([pop, proj1, m])
net.compile()
net.simulate(1000.)

net2 = Network()
net2.add([pop, proj2, m])
net2.compile()
net2.simulate(1000.)

t, n = net.get(m).raster_plot()
t2, n2 = net2.get(m).raster_plot()
Source code in ANNarchy/core/Network.py
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
class Network :
    """
    A network gathers already defined populations, projections and monitors in order to run them independently.

    This is particularly useful when varying single parameters of a network and comparing the results (see the ``parallel_run()`` method).

    Only objects declared before the creation of the network can be used. Global methods such as ``simulate()`` must be used on the network object.
    The objects must be accessed through the ``get()`` method, as the original ones will not be part of the network (a copy is made).

    Each network must be individually compiled, but it does not matter if the original objects were already compiled.

    When passing ``everything=True`` to the constructor, all populations/projections/monitors already defined at the global level will be added to the network.

    If not, you can select which object will be added to network with the ``add()`` method.

    Example with ``everything=True``:

    ```python
    pop = Population(100, Izhikevich)
    proj = Projection(pop, pop, 'exc')
    proj.connect_all_to_all(1.0)
    m = Monitor(pop, 'spike')

    compile() # Optional

    net = Network(everything=True)
    net.get(pop).a = 0.02
    net.compile()
    net.simulate(1000.)

    net2 = Network(everything=True)
    net2.get(pop).a = 0.05
    net2.compile()
    net2.simulate(1000.)

    t, n = net.get(m).raster_plot()
    t2, n2 = net2.get(m).raster_plot()
    ```

    Example with ``everything=False`` (the default):

    ```python
    pop = Population(100, Izhikevich)
    proj1 = Projection(pop, pop, 'exc')
    proj1.connect_all_to_all(1.0)
    proj2 = Projection(pop, pop, 'exc')
    proj2.connect_all_to_all(2.0)
    m = Monitor(pop, 'spike')

    net = Network()
    net.add([pop, proj1, m])
    net.compile()
    net.simulate(1000.)

    net2 = Network()
    net2.add([pop, proj2, m])
    net2.compile()
    net2.simulate(1000.)

    t, n = net.get(m).raster_plot()
    t2, n2 = net2.get(m).raster_plot()
    ```

    """

    def __init__(self, everything=False):
        """
        :param everything: defines if all existing populations and projections should be automatically added (default: False).
        """
        self.id = Global._network.add_network(self)
        self.everything = everything

        Simulate._callbacks.append([])
        Simulate._callbacks_enabled.append(True)
        self.populations = []
        self.projections = []
        self.monitors = []
        self.extensions = []

        if everything:
            self.add(Global._network[0]['populations'])
            self.add(Global._network[0]['projections'])
            self.add(Global._network[0]['monitors'])
            self.add(Global._network[0]['extensions'])

    def __del__(self):

        # Overridden destructor for two reasons:
        # 
        # a) track destruction of objects
        # b) manually deallocate C++ container data
        # 
        # Hint: this function can be called explicitly (which is not recommended in many cases) or as
        #       finalizer from the garbage collection. If called explicitely, one should take in mind,
        #       that the function will be called twice. The better approach is to trigger this function
        #       by del on the network object.
        for pop in self.get_populations():
            pop._clear()
            del pop

        for proj in self.get_projections(suppress_error=True):
            proj._clear()
            del proj

        for mon in self.monitors:
            mon._clear()
            del mon

        for ext in self.extensions:
            ext._clear()
            del ext

        Global._network._remove_network(self)

    def _cpp_memory_footprint(self):
        """
        Print the C++ memory consumption for populations, projections on the console.
        """
        for pop in self.get_populations():
            print(pop.name, pop.size_in_bytes())

        for proj in self.get_projections():
            print(proj.name, proj.size_in_bytes())

        for mon in self.monitors:
            print(type(mon), mon.size_in_bytes())

    def add(self, objects):
        """
        Adds a Population, Projection or Monitor to the network.

        :param objects: A single object or a list to add to the network.
        """
        if isinstance(objects, list):
            for item in objects:
                self._add_object(item)
        else:
            self._add_object(objects)

    def _add_object(self, obj):
        """
        Add the object *obj* to the network.

        TODO: instead of creating copies by object construction, one should check if deepcopy works ...
        """
        if isinstance(obj, Population):
            # Create a copy
            pop = obj._copy()

            # Remove the copy from the global network
            Global._network[0]['populations'].pop(-1) # FIXME: the list is iterated from left to right and we delete from right to left???

            # Copy import properties
            pop.id = obj.id
            pop.name = obj.name
            pop.class_name = obj.class_name
            pop.init = obj.init
            pop.enabled = obj.enabled
            if not obj.enabled: # Also copy the enabled state:
                pop.disable()

            # Add the copy to the local network
            Global._network[self.id]['populations'].append(pop)
            self.populations.append(pop)

            # Check whether the computation of mean-firing rate is requested
            if obj._compute_mean_fr > 0:
                pop.compute_firing_rate(obj._compute_mean_fr)

        elif isinstance(obj, Projection):
            # Check the pre- or post- populations
            try:
                pre_pop = self.get(obj.pre)
                if isinstance(obj.pre, PopulationView):
                    pre = PopulationView(population=pre_pop.population, ranks=obj.pre.ranks)
                else:
                    pre = pre_pop
                post_pop = self.get(obj.post)
                if isinstance(obj.post, PopulationView):
                    post = PopulationView(population=post_pop.population, ranks=obj.post.ranks)
                else:
                    post = post_pop
            except:
                Global._error('Network.add(): The pre- or post-synaptic population of this projection are not in the network.')

            # Create the projection
            proj = obj._copy(pre=pre, post=post)
            # Remove the copy from the global network
            Global._network[0]['projections'].pop(-1)

            # Copy import properties
            proj.id = obj.id
            proj.name = obj.name
            proj.init = obj.init

            # Copy the connectivity properties if the projection is not already set
            if proj._connection_method is None:
                proj._store_connectivity(method=obj._connection_method, args=obj._connection_args, delay=obj._connection_delay, storage_format=obj._storage_format, storage_order=obj._storage_order)

            # Add the copy to the local network
            Global._network[self.id]['projections'].append(proj)
            self.projections.append(proj)

        elif isinstance(obj, BoldMonitor):
            # Create a copy of the monitor
            m = BoldMonitor(
                populations=obj._populations,
                bold_model=obj._bold_model,
                mapping=obj._mapping,
                scale_factor=obj._scale_factor,
                normalize_input=obj._normalize_input,
                recorded_variables=obj._recorded_variables,
                start=obj._start,
                net_id=self.id,
                copied=True
            )

            # there is a bad mismatch between object ids:
            #
            # m.id     is dependent on len(_network[net_id].monitors)
            # obj.id   is dependent on len(_network[0].monitors)
            m.id = obj.id # TODO: check this !!!!

            # Stop the master monitor, otherwise it gets data.
            for var in obj._monitor.variables:
                try:
                    setattr(obj._monitor.cyInstance, 'record_'+var, False)
                except:
                    pass

            # assign contained objects
            m._monitor = self._get_object(obj._monitor)
            m._bold_pop = self._get_object(obj._bold_pop)
            m._acc_proj = []
            for tmp in obj._acc_proj:
                m._acc_proj.append(self._get_object(tmp))

            # need to be done manually for copied instances
            m._initialized = True

            # Add the copy to the local network (the monitor writes itself already in the right network)
            self.extensions.append(m)

        elif isinstance(obj, Monitor):
            # Get the copied reference of the object monitored
            # try:
            #     obj_copy = self.get(obj.object)
            # except:
            #     Global._error('Network.add(): The monitor does not exist.')

            # Stop the master monitor, otherwise it gets data.
            for var in obj.variables:
                try:
                    setattr(obj.cyInstance, 'record_'+var, False)
                except:
                    pass
            # Create a copy of the monitor
            m = Monitor(obj=self._get_object(obj.object), variables=obj.variables, period=obj._period, period_offset=obj._period_offset, start=obj._start, net_id=self.id)

            # there is a bad mismatch between object ids:
            #
            # m.id     is dependent on len(_network[net_id].monitors)
            # obj.id   is dependent on len(_network[0].monitors)
            m.id = obj.id # TODO: check this !!!!

            # Add the copy to the local network (the monitor writes itself already in the right network)
            self.monitors.append(m)

    def get(self, obj):
        """
        Returns the local Population, Projection or Monitor identical to the provided argument.

        Example:

        ```python
        pop = Population(100, Izhikevich)
        net = Network()
        net.add(pop)
        net.compile()
        net.simulate(100.)
        print net.get(pop).v
        ```

        :param obj: A single object or a list of objects.
        :return: The corresponding object or list of objects.
        """
        if isinstance(obj, list):
            return [self._get_object(o) for o in obj]
        else:
            return self._get_object(obj)

    def _get_object(self, obj):
        "Retrieves the corresponding object."
        if isinstance(obj, Population):
            for pop in self.populations:
                if pop.id == obj.id:
                    return pop
        elif isinstance(obj, PopulationView):
            for pop in self.populations:
                if pop.id == obj.id:
                    return PopulationView(pop, obj.ranks) # Create on the fly?
        elif isinstance(obj, Projection):
            for proj in self.projections:
                if proj.id == obj.id:
                    return proj
        elif isinstance(obj, Monitor):
            for m in self.monitors:
                if m.id == obj.id:
                    return m
        elif isinstance(obj, BoldMonitor):
            for m in self.extensions:
                if m.id == obj.id:
                    return m
        else:
            Global._error('The network has no such object:', obj.name, obj)

    def compile(self,
                directory='annarchy',
                clean=False,
                compiler="default",
                compiler_flags="default",
                add_sources="",
                extra_libs="",
                cuda_config={'device': 0},
                annarchy_json="",
                silent=False,
                debug_build=False,
                profile_enabled=False):
        """
        Compiles the network.

        :param directory: name of the subdirectory where the code will be generated and compiled. Must be a relative path. Default: "annarchy/".
        :param clean: boolean to specifying if the library should be recompiled entirely or only the changes since last compilation (default: False).
        :param compiler: C++ compiler to use. Default: g++ on GNU/Linux, clang++ on OS X. Valid compilers are [g++, clang++].
        :param compiler_flags: platform-specific flags to pass to the compiler. Default: "-march=native -O2". Warning: -O3 often generates slower code and can cause linking problems, so it is not recommended.
        :param cuda_config: dictionary defining the CUDA configuration for each population and projection.
        :param annarchy_json: compiler flags etc are stored in a .json file normally placed in the home directory. With this flag one can directly assign a file location.
        :param silent: defines if the "Compiling... OK" should be printed.

        """
        Compiler.compile(directory=directory, clean=clean, silent=silent, debug_build=debug_build, add_sources=add_sources, extra_libs=extra_libs, compiler=compiler, compiler_flags=compiler_flags, cuda_config=cuda_config, annarchy_json=annarchy_json, profile_enabled=profile_enabled, net_id=self.id)

    def simulate(self, duration, measure_time = False):
        """
        Runs the network for the given duration in milliseconds. 

        The number of simulation steps is  computed relative to the discretization step ``dt`` declared in ``setup()`` (default: 1ms):

        ```python
        simulate(1000.0)
        ```

        :param duration: the duration in milliseconds.
        :param measure_time: defines whether the simulation time should be printed (default=False).

        """
        Simulate.simulate(duration, measure_time, net_id=self.id)

    def simulate_until(self, max_duration, population, operator='and', measure_time = False):
        """
        Runs the network for the maximal duration in milliseconds. If the ``stop_condition`` defined in the population becomes true during the simulation, it is stopped.

        One can specify several populations. If the stop condition is true for any of the populations, the simulation will stop ('or' function).

        Example:

        ```python
        pop1 = Population( ..., stop_condition = "r > 1.0 : any")
        compile()
        simulate_until(max_duration=1000.0. population=pop1)
        ```

        :param max_duration: the maximum duration of the simulation in milliseconds.
        :param population: the (list of) population whose ``stop_condition`` should be checked to stop the simulation.
        :param operator: operator to be used ('and' or 'or') when multiple populations are provided (default: 'and').
        :param measure_time: defines whether the simulation time should be printed (default=False).
        :return: the actual duration of the simulation in milliseconds.
        """
        return Simulate.simulate_until(max_duration, population, operator, measure_time, net_id=self.id)

    def step(self):
        """
        Performs a single simulation step (duration = ``dt``).
        """
        Simulate.step(self.id)

    def reset(self, populations=True, projections=False, monitors=True, synapses=False):
        """
        Reinitialises the network to its state before the call to compile.

        :param populations: if True (default), the neural parameters and variables will be reset to their initial value.
        :param projections: if True, the synaptic parameters and variables (except the connections) will be reset (default=False).
        :param synapses: if True, the synaptic weights will be erased and recreated (default=False).
        """
        Global.reset(populations=populations, projections=projections, synapses=synapses, monitors=monitors, net_id=self.id)

    def get_time(self):
        "Returns the current time in ms."
        return Global.get_time(self.id)

    def set_time(self, t, net_id=0):
        """
        Sets the current time in ms.

        **Warning:** can be dangerous for some spiking models.
        """
        Global.set_time(t, self.id)

    def get_current_step(self):
        "Returns the current simulation step."
        return Global.get_current_step(self.id)

    def set_current_step(self, t):
        """
        Sets the current simulation step.

        **Warning:** can be dangerous for some spiking models.
        """
        Global.set_current_step(t, self.id)

    def set_seed(self, seed, use_seed_seq=True):
        """
        Sets the seed of the random number generators for this network.
        """
        Global.set_seed(seed=seed, use_seed_seq=use_seed_seq, net_id=self.id)

    def enable_learning(self, projections=None, period=None, offset=None):
        """
        Enables learning for all projections.

        :param projections: the projections whose learning should be enabled. By default, all the existing projections are disabled.
        """
        if not projections:
            projections = self.projections
        for proj in projections:
            proj.enable_learning(period=period, offset=offset)

    def disable_learning(self, projections=None):
        """
        Disables learning for all projections.

        :param projections: the projections whose learning should be disabled. By default, all the existing projections are disabled.
        """
        if not projections:
            projections = self.projections
        for proj in projections:
            proj.disable_learning()

    def get_population(self, name):
        """
        Returns the population with the given *name*.

        :param name: name of the population
        :return: The requested ``Population`` object if existing, ``None`` otherwise.
        """
        for pop in self.populations:
            if pop.name == name:
                return pop
        Global._print('get_population(): the population', name, 'does not exist in this network.')
        return None

    def get_projection(self, name):
        """
        Returns the projection with the given *name*.

        :param name: name of the projection
        :return: The requested ``Projection`` object if existing, ``None`` otherwise.
        """
        for proj in self.projections:
            if proj.name == name:
                return proj
        Global._print('get_projection(): the projection', name, 'does not exist in this network.')
        return None

    def get_populations(self):
        """
        Returns a list of all declared populations in this network.
        """
        if self.populations == []:
            Global._warning("Network.get_populations(): no populations attached to this network.")
        return self.populations

    def get_projections(self, post=None, pre=None, target=None, suppress_error=False):
        """
        Get a list of declared projections for the current network. By default,
        the method returns all connections within the network.

        By setting the arguments, post, pre and target one can select a subset.

        :param post: all returned projections should have this population as post.
        :param pre: all returned projections should have this population as pre.
        :param target: all returned projections should have this target.
        :param suppress_error: by default, ANNarchy throws an error if the list of assigned projections is empty. If this flag is set to True, the error message is suppressed.
        :return: A list of all assigned projections in this network or a subset according to the arguments.

        """
        if self.projections == []:
            if not suppress_error:
                Global._error("Network.get_projections(): no projections attached to this network.")

        if post is None and pre is None and target is None:
            return self.projections
        else:
            res = []
            if isinstance(post, str):
                post = self.get_population(post)
            if isinstance(pre, str):
                pre = self.get_population(pre)

            for proj in self.projections:
                if post is not None:
                    # post is exclusionary
                    if proj.post == post:
                        res.append(proj)

                if pre is not None:
                    raise NotImplementedError

                if target is not None:
                    raise NotImplementedError

            return res

    def load(self, filename, populations=True, projections=True, pickle_encoding=None):
        """
        Loads a saved state of the current network by calling ANNarchy.core.IO.load().

        :param filename: filename, may contain relative or absolute path.
        :param populations: if True, population data will be saved (by default True)
        :param projections: if True, projection data will be saved (by default True)
        :param pickle_encoding: optional parameter provided to the pickle.load() method. If set to None the default is used.
        """
        IO.load(filename=filename, populations=populations, projections=projections, pickle_encoding=pickle_encoding, net_id=self.id)

    def save(self, filename, populations=True, projections=True):
        """
        Saves the current network by calling ANNarchy.core.IO.save().

        :param filename: filename, may contain relative or absolute path.
        :param populations: if True, population data will be saved (by default True)
        :param projections: if True, projection data will be saved (by default True)
        """
        IO.save(filename, populations, projections, self.id)

__init__(everything=False) #

Parameters:

  • everything

    defines if all existing populations and projections should be automatically added (default: False).

Source code in ANNarchy/core/Network.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
def __init__(self, everything=False):
    """
    :param everything: defines if all existing populations and projections should be automatically added (default: False).
    """
    self.id = Global._network.add_network(self)
    self.everything = everything

    Simulate._callbacks.append([])
    Simulate._callbacks_enabled.append(True)
    self.populations = []
    self.projections = []
    self.monitors = []
    self.extensions = []

    if everything:
        self.add(Global._network[0]['populations'])
        self.add(Global._network[0]['projections'])
        self.add(Global._network[0]['monitors'])
        self.add(Global._network[0]['extensions'])

add(objects) #

Adds a Population, Projection or Monitor to the network.

Parameters:

  • objects

    A single object or a list to add to the network.

Source code in ANNarchy/core/Network.py
147
148
149
150
151
152
153
154
155
156
157
def add(self, objects):
    """
    Adds a Population, Projection or Monitor to the network.

    :param objects: A single object or a list to add to the network.
    """
    if isinstance(objects, list):
        for item in objects:
            self._add_object(item)
    else:
        self._add_object(objects)

compile(directory='annarchy', clean=False, compiler='default', compiler_flags='default', add_sources='', extra_libs='', cuda_config={'device': 0}, annarchy_json='', silent=False, debug_build=False, profile_enabled=False) #

Compiles the network.

Parameters:

  • directory

    name of the subdirectory where the code will be generated and compiled. Must be a relative path. Default: "annarchy/".

  • clean

    boolean to specifying if the library should be recompiled entirely or only the changes since last compilation (default: False).

  • compiler

    C++ compiler to use. Default: g++ on GNU/Linux, clang++ on OS X. Valid compilers are [g++, clang++].

  • compiler_flags

    platform-specific flags to pass to the compiler. Default: "-march=native -O2". Warning: -O3 often generates slower code and can cause linking problems, so it is not recommended.

  • cuda_config

    dictionary defining the CUDA configuration for each population and projection.

  • annarchy_json

    compiler flags etc are stored in a .json file normally placed in the home directory. With this flag one can directly assign a file location.

  • silent

    defines if the "Compiling... OK" should be printed.

Source code in ANNarchy/core/Network.py
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
def compile(self,
            directory='annarchy',
            clean=False,
            compiler="default",
            compiler_flags="default",
            add_sources="",
            extra_libs="",
            cuda_config={'device': 0},
            annarchy_json="",
            silent=False,
            debug_build=False,
            profile_enabled=False):
    """
    Compiles the network.

    :param directory: name of the subdirectory where the code will be generated and compiled. Must be a relative path. Default: "annarchy/".
    :param clean: boolean to specifying if the library should be recompiled entirely or only the changes since last compilation (default: False).
    :param compiler: C++ compiler to use. Default: g++ on GNU/Linux, clang++ on OS X. Valid compilers are [g++, clang++].
    :param compiler_flags: platform-specific flags to pass to the compiler. Default: "-march=native -O2". Warning: -O3 often generates slower code and can cause linking problems, so it is not recommended.
    :param cuda_config: dictionary defining the CUDA configuration for each population and projection.
    :param annarchy_json: compiler flags etc are stored in a .json file normally placed in the home directory. With this flag one can directly assign a file location.
    :param silent: defines if the "Compiling... OK" should be printed.

    """
    Compiler.compile(directory=directory, clean=clean, silent=silent, debug_build=debug_build, add_sources=add_sources, extra_libs=extra_libs, compiler=compiler, compiler_flags=compiler_flags, cuda_config=cuda_config, annarchy_json=annarchy_json, profile_enabled=profile_enabled, net_id=self.id)

disable_learning(projections=None) #

Disables learning for all projections.

Parameters:

  • projections

    the projections whose learning should be disabled. By default, all the existing projections are disabled.

Source code in ANNarchy/core/Network.py
457
458
459
460
461
462
463
464
465
466
def disable_learning(self, projections=None):
    """
    Disables learning for all projections.

    :param projections: the projections whose learning should be disabled. By default, all the existing projections are disabled.
    """
    if not projections:
        projections = self.projections
    for proj in projections:
        proj.disable_learning()

enable_learning(projections=None, period=None, offset=None) #

Enables learning for all projections.

Parameters:

  • projections

    the projections whose learning should be enabled. By default, all the existing projections are disabled.

Source code in ANNarchy/core/Network.py
446
447
448
449
450
451
452
453
454
455
def enable_learning(self, projections=None, period=None, offset=None):
    """
    Enables learning for all projections.

    :param projections: the projections whose learning should be enabled. By default, all the existing projections are disabled.
    """
    if not projections:
        projections = self.projections
    for proj in projections:
        proj.enable_learning(period=period, offset=offset)

get(obj) #

Returns the local Population, Projection or Monitor identical to the provided argument.

Example:

pop = Population(100, Izhikevich)
net = Network()
net.add(pop)
net.compile()
net.simulate(100.)
print net.get(pop).v

Parameters:

  • obj

    A single object or a list of objects.

Returns:

  • The corresponding object or list of objects.

Source code in ANNarchy/core/Network.py
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
def get(self, obj):
    """
    Returns the local Population, Projection or Monitor identical to the provided argument.

    Example:

    ```python
    pop = Population(100, Izhikevich)
    net = Network()
    net.add(pop)
    net.compile()
    net.simulate(100.)
    print net.get(pop).v
    ```

    :param obj: A single object or a list of objects.
    :return: The corresponding object or list of objects.
    """
    if isinstance(obj, list):
        return [self._get_object(o) for o in obj]
    else:
        return self._get_object(obj)

get_current_step() #

Returns the current simulation step.

Source code in ANNarchy/core/Network.py
428
429
430
def get_current_step(self):
    "Returns the current simulation step."
    return Global.get_current_step(self.id)

get_population(name) #

Returns the population with the given name.

Parameters:

  • name

    name of the population

Returns:

  • The requested Population object if existing, None otherwise.

Source code in ANNarchy/core/Network.py
468
469
470
471
472
473
474
475
476
477
478
479
def get_population(self, name):
    """
    Returns the population with the given *name*.

    :param name: name of the population
    :return: The requested ``Population`` object if existing, ``None`` otherwise.
    """
    for pop in self.populations:
        if pop.name == name:
            return pop
    Global._print('get_population(): the population', name, 'does not exist in this network.')
    return None

get_populations() #

Returns a list of all declared populations in this network.

Source code in ANNarchy/core/Network.py
494
495
496
497
498
499
500
def get_populations(self):
    """
    Returns a list of all declared populations in this network.
    """
    if self.populations == []:
        Global._warning("Network.get_populations(): no populations attached to this network.")
    return self.populations

get_projection(name) #

Returns the projection with the given name.

Parameters:

  • name

    name of the projection

Returns:

  • The requested Projection object if existing, None otherwise.

Source code in ANNarchy/core/Network.py
481
482
483
484
485
486
487
488
489
490
491
492
def get_projection(self, name):
    """
    Returns the projection with the given *name*.

    :param name: name of the projection
    :return: The requested ``Projection`` object if existing, ``None`` otherwise.
    """
    for proj in self.projections:
        if proj.name == name:
            return proj
    Global._print('get_projection(): the projection', name, 'does not exist in this network.')
    return None

get_projections(post=None, pre=None, target=None, suppress_error=False) #

Get a list of declared projections for the current network. By default, the method returns all connections within the network.

By setting the arguments, post, pre and target one can select a subset.

Parameters:

  • post

    all returned projections should have this population as post.

  • pre

    all returned projections should have this population as pre.

  • target

    all returned projections should have this target.

  • suppress_error

    by default, ANNarchy throws an error if the list of assigned projections is empty. If this flag is set to True, the error message is suppressed.

Returns:

  • A list of all assigned projections in this network or a subset according to the arguments.

Source code in ANNarchy/core/Network.py
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
def get_projections(self, post=None, pre=None, target=None, suppress_error=False):
    """
    Get a list of declared projections for the current network. By default,
    the method returns all connections within the network.

    By setting the arguments, post, pre and target one can select a subset.

    :param post: all returned projections should have this population as post.
    :param pre: all returned projections should have this population as pre.
    :param target: all returned projections should have this target.
    :param suppress_error: by default, ANNarchy throws an error if the list of assigned projections is empty. If this flag is set to True, the error message is suppressed.
    :return: A list of all assigned projections in this network or a subset according to the arguments.

    """
    if self.projections == []:
        if not suppress_error:
            Global._error("Network.get_projections(): no projections attached to this network.")

    if post is None and pre is None and target is None:
        return self.projections
    else:
        res = []
        if isinstance(post, str):
            post = self.get_population(post)
        if isinstance(pre, str):
            pre = self.get_population(pre)

        for proj in self.projections:
            if post is not None:
                # post is exclusionary
                if proj.post == post:
                    res.append(proj)

            if pre is not None:
                raise NotImplementedError

            if target is not None:
                raise NotImplementedError

        return res

get_time() #

Returns the current time in ms.

Source code in ANNarchy/core/Network.py
416
417
418
def get_time(self):
    "Returns the current time in ms."
    return Global.get_time(self.id)

load(filename, populations=True, projections=True, pickle_encoding=None) #

Loads a saved state of the current network by calling ANNarchy.core.IO.load().

Parameters:

  • filename

    filename, may contain relative or absolute path.

  • populations

    if True, population data will be saved (by default True)

  • projections

    if True, projection data will be saved (by default True)

  • pickle_encoding

    optional parameter provided to the pickle.load() method. If set to None the default is used.

Source code in ANNarchy/core/Network.py
543
544
545
546
547
548
549
550
551
552
def load(self, filename, populations=True, projections=True, pickle_encoding=None):
    """
    Loads a saved state of the current network by calling ANNarchy.core.IO.load().

    :param filename: filename, may contain relative or absolute path.
    :param populations: if True, population data will be saved (by default True)
    :param projections: if True, projection data will be saved (by default True)
    :param pickle_encoding: optional parameter provided to the pickle.load() method. If set to None the default is used.
    """
    IO.load(filename=filename, populations=populations, projections=projections, pickle_encoding=pickle_encoding, net_id=self.id)

reset(populations=True, projections=False, monitors=True, synapses=False) #

Reinitialises the network to its state before the call to compile.

Parameters:

  • populations

    if True (default), the neural parameters and variables will be reset to their initial value.

  • projections

    if True, the synaptic parameters and variables (except the connections) will be reset (default=False).

  • synapses

    if True, the synaptic weights will be erased and recreated (default=False).

Source code in ANNarchy/core/Network.py
406
407
408
409
410
411
412
413
414
def reset(self, populations=True, projections=False, monitors=True, synapses=False):
    """
    Reinitialises the network to its state before the call to compile.

    :param populations: if True (default), the neural parameters and variables will be reset to their initial value.
    :param projections: if True, the synaptic parameters and variables (except the connections) will be reset (default=False).
    :param synapses: if True, the synaptic weights will be erased and recreated (default=False).
    """
    Global.reset(populations=populations, projections=projections, synapses=synapses, monitors=monitors, net_id=self.id)

save(filename, populations=True, projections=True) #

Saves the current network by calling ANNarchy.core.IO.save().

Parameters:

  • filename

    filename, may contain relative or absolute path.

  • populations

    if True, population data will be saved (by default True)

  • projections

    if True, projection data will be saved (by default True)

Source code in ANNarchy/core/Network.py
554
555
556
557
558
559
560
561
562
def save(self, filename, populations=True, projections=True):
    """
    Saves the current network by calling ANNarchy.core.IO.save().

    :param filename: filename, may contain relative or absolute path.
    :param populations: if True, population data will be saved (by default True)
    :param projections: if True, projection data will be saved (by default True)
    """
    IO.save(filename, populations, projections, self.id)

set_current_step(t) #

Sets the current simulation step.

Warning: can be dangerous for some spiking models.

Source code in ANNarchy/core/Network.py
432
433
434
435
436
437
438
def set_current_step(self, t):
    """
    Sets the current simulation step.

    **Warning:** can be dangerous for some spiking models.
    """
    Global.set_current_step(t, self.id)

set_seed(seed, use_seed_seq=True) #

Sets the seed of the random number generators for this network.

Source code in ANNarchy/core/Network.py
440
441
442
443
444
def set_seed(self, seed, use_seed_seq=True):
    """
    Sets the seed of the random number generators for this network.
    """
    Global.set_seed(seed=seed, use_seed_seq=use_seed_seq, net_id=self.id)

set_time(t, net_id=0) #

Sets the current time in ms.

Warning: can be dangerous for some spiking models.

Source code in ANNarchy/core/Network.py
420
421
422
423
424
425
426
def set_time(self, t, net_id=0):
    """
    Sets the current time in ms.

    **Warning:** can be dangerous for some spiking models.
    """
    Global.set_time(t, self.id)

simulate(duration, measure_time=False) #

Runs the network for the given duration in milliseconds.

The number of simulation steps is computed relative to the discretization step dt declared in setup() (default: 1ms):

simulate(1000.0)

Parameters:

  • duration

    the duration in milliseconds.

  • measure_time

    defines whether the simulation time should be printed (default=False).

Source code in ANNarchy/core/Network.py
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
def simulate(self, duration, measure_time = False):
    """
    Runs the network for the given duration in milliseconds. 

    The number of simulation steps is  computed relative to the discretization step ``dt`` declared in ``setup()`` (default: 1ms):

    ```python
    simulate(1000.0)
    ```

    :param duration: the duration in milliseconds.
    :param measure_time: defines whether the simulation time should be printed (default=False).

    """
    Simulate.simulate(duration, measure_time, net_id=self.id)

simulate_until(max_duration, population, operator='and', measure_time=False) #

Runs the network for the maximal duration in milliseconds. If the stop_condition defined in the population becomes true during the simulation, it is stopped.

One can specify several populations. If the stop condition is true for any of the populations, the simulation will stop ('or' function).

Example:

pop1 = Population( ..., stop_condition = "r > 1.0 : any")
compile()
simulate_until(max_duration=1000.0. population=pop1)

Parameters:

  • max_duration

    the maximum duration of the simulation in milliseconds.

  • population

    the (list of) population whose stop_condition should be checked to stop the simulation.

  • operator

    operator to be used ('and' or 'or') when multiple populations are provided (default: 'and').

  • measure_time

    defines whether the simulation time should be printed (default=False).

Returns:

  • the actual duration of the simulation in milliseconds.

Source code in ANNarchy/core/Network.py
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
def simulate_until(self, max_duration, population, operator='and', measure_time = False):
    """
    Runs the network for the maximal duration in milliseconds. If the ``stop_condition`` defined in the population becomes true during the simulation, it is stopped.

    One can specify several populations. If the stop condition is true for any of the populations, the simulation will stop ('or' function).

    Example:

    ```python
    pop1 = Population( ..., stop_condition = "r > 1.0 : any")
    compile()
    simulate_until(max_duration=1000.0. population=pop1)
    ```

    :param max_duration: the maximum duration of the simulation in milliseconds.
    :param population: the (list of) population whose ``stop_condition`` should be checked to stop the simulation.
    :param operator: operator to be used ('and' or 'or') when multiple populations are provided (default: 'and').
    :param measure_time: defines whether the simulation time should be printed (default=False).
    :return: the actual duration of the simulation in milliseconds.
    """
    return Simulate.simulate_until(max_duration, population, operator, measure_time, net_id=self.id)

step() #

Performs a single simulation step (duration = dt).

Source code in ANNarchy/core/Network.py
400
401
402
403
404
def step(self):
    """
    Performs a single simulation step (duration = ``dt``).
    """
    Simulate.step(self.id)

ANNarchy.core.Network.parallel_run(method, networks=None, number=0, max_processes=-1, measure_time=False, sequential=False, same_seed=False, annarchy_json='', visible_cores=[], **args) #

Allows to run multiple networks in parallel using multiprocessing.

If the networks argument is provided as a list of Network objects, the given method will be executed for each of these networks.

If number is given instead, the same number of networks will be created and the method is applied.

If number is used, the created networks are not returned, you should return what you need to analyse.

Example:

pop1 = PoissonPopulation(100, rates=10.0)
pop2 = Population(100, Izhikevich)
proj = Projection(pop1, pop2, 'exc')
proj.connect_fixed_probability(weights=5.0, probability=0.2)
m = Monitor(pop2, 'spike')

compile()

def simulation(idx, net):
    net.get(pop1).rates = 10. * idx
    net.simulate(1000.)
    return net.get(m).raster_plot()

results = parallel_run(method=simulation, number = 3)

t1, n1 = results[0]
t2, n2 = results[1]
t3, n3 = results[2]

Parameters:

  • method

    a Python method which will be executed for each network. This function must accept an integer as first argument (id of the simulation) and a Network object as second argument.

  • networks

    a list of networks to simulate in parallel.

  • number

    the number of identical networks to run in parallel.

  • max_processes

    maximal number of processes to start concurrently (default: the available number of cores on the machine).

  • measure_time

    if the total simulation time should be printed out.

  • sequential

    if True, runs the simulations sequentially instead of in parallel (default: False).

  • same_seed

    if True, all networks will use the same seed. If not, the seed will be randomly initialized with time(0) for each network (default). It has no influence when the networks argument is set (the seed has to be set individually for each network using net.set_seed()), only when number is used.

  • annarchy_json

    path to a different configuration file if needed (default "").

  • visible_cores

    a list of CPU core ids to simulate on (must have max_processes entries and max_processes must be != -1)

  • args

    other named arguments you want to pass to the simulation method.

Returns:

  • a list of the values returned by method.

Source code in ANNarchy/core/Network.py
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
def parallel_run(
        method, 
        networks=None, 
        number=0, 
        max_processes=-1, 
        measure_time=False, 
        sequential=False, 
        same_seed=False, 
        annarchy_json="", 
        visible_cores=[], 
        **args):
    """
    Allows to run multiple networks in parallel using multiprocessing.

    If the ``networks`` argument is provided as a list of Network objects, the given method will be executed for each of these networks.

    If ``number`` is given instead, the same number of networks will be created and the method is applied.

    If ``number`` is used, the created networks are not returned, you should return what you need to analyse.

    Example:

    ```python
    pop1 = PoissonPopulation(100, rates=10.0)
    pop2 = Population(100, Izhikevich)
    proj = Projection(pop1, pop2, 'exc')
    proj.connect_fixed_probability(weights=5.0, probability=0.2)
    m = Monitor(pop2, 'spike')

    compile()

    def simulation(idx, net):
        net.get(pop1).rates = 10. * idx
        net.simulate(1000.)
        return net.get(m).raster_plot()

    results = parallel_run(method=simulation, number = 3)

    t1, n1 = results[0]
    t2, n2 = results[1]
    t3, n3 = results[2]
    ```


    :param method: a Python method which will be executed for each network. This function must accept an integer as first argument (id of the simulation) and a Network object as second argument.
    :param networks: a list of networks to simulate in parallel.
    :param number: the number of identical networks to run in parallel.
    :param max_processes: maximal number of processes to start concurrently (default: the available number of cores on the machine).
    :param measure_time: if the total simulation time should be printed out.
    :param sequential: if True, runs the simulations sequentially instead of in parallel (default: False).
    :param same_seed: if True, all networks will use the same seed. If not, the seed will be randomly initialized with time(0) for each network (default). It has no influence when the ``networks`` argument is set (the seed has to be set individually for each network using ``net.set_seed()``), only when ``number`` is used.
    :param annarchy_json: path to a different configuration file if needed (default "").
    :param visible_cores: a list of CPU core ids to simulate on (must have max_processes entries and max_processes must be != -1)
    :param args: other named arguments you want to pass to the simulation method.
    :returns: a list of the values returned by ``method``.

    """
    # Check inputs
    if not networks and number < 1:
        Global._error('parallel_run(): the networks or number arguments must be set.', exit=True)

    if len(visible_cores) > 0 and max_processes == -1:
        Global._error('parallel_run(): when using visible cores the number of max_processes must be set.', exit=True)

    if (len(visible_cores) > 0) and (len(visible_cores) != max_processes):
        Global._error('parallel_run(): the number of entries in visible_cores must be equal to max_processes.', exit=True)

    import types
    if not isinstance(method, types.FunctionType):
        Global._error('parallel_run(): the method argument must be a method.', exit=True)

    if not networks: # The magic network will run N times
        return _parallel_multi(method, number, max_processes, measure_time, sequential, same_seed, annarchy_json, visible_cores, args)

    if not isinstance(networks, list):
        Global._error('parallel_run(): the networks argument must be a list.', exit=True)

    # Simulate the different networks
    return _parallel_networks(method, networks, max_processes, measure_time, sequential, args)