Skip to content

Commit

Permalink
Finalise text
Browse files Browse the repository at this point in the history
  • Loading branch information
thorstenhater committed Dec 9, 2024
1 parent 8f23c6a commit b382135
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 47 deletions.
2 changes: 1 addition & 1 deletion doc/cpp/remote.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Control Messages

Request termination, giving the reason as a message.

.. cpp:member:: char[512] reason
.. cpp:member:: char reason[512]

.. cpp:class:: msg_epoch

Expand Down
93 changes: 59 additions & 34 deletions doc/tutorial/connectivity.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
Declarative Connectivity in Arbor
=================================

In this tutorial, we are going to demonstrate how to leverage Arbor's
declarative connection description facilities to generate a few common network
types.

.. admonition:: Concepts and Requirements

We will assume that you have read the basic network tutorials.
We will assume that you have read the basic recipe and network tutorials.

In addition to Arbor and its requirements `matplotlib`` and ``networkx``
In addition to Arbor and its requirements ``matplotlib`` and ``networkx``
need to be installed.

In this tutorial, we are going to demonstrate how to leverage Arbor's
declarative connection description facilities to generate a few common network
types. We will gradually build up complexity and generally show the full recipe
first before discussing some of the relevant parts.


Prelude: Unconnected Cells
--------------------------
Expand All @@ -28,7 +29,7 @@ we want to emphasize building networks. We begin by defining the global settings

.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 7-15
:lines: 7-13

- ``N`` is the cell count of the simulation.
- ``T`` is the total runtime of the simulation in ``ms``.
Expand All @@ -38,37 +39,44 @@ These parameters are used here:

.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 52-62
:lines: 50-

where we run the simulation in increments of ``t_interval``.
where we run the simulation. Before we discuss the relevant details, the recipe
reads in full

Back to the recipe, we set a prototypical LIF cell:
.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 16-47

In the recipe, we set a prototypical LIF cell:

.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 23
:lines: 21

and deliver it for all ``gid``:

.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 42-43
:lines: 43-44

Also, the _first cell_ has an event generator attached, using a Poisson point process
seeded with the cell's ``gid``.
With large and complicated cells this can sometimes help with performance, here,
it's just a convenient way to structure our recipe. Also, the *first cell* has
an event generator attached, a Poisson point process seeded with the
cell's ``gid``.

.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 33-41
:lines: 31-41

All other parameters are set in the constructor:

.. literalinclude:: ../../python/example/connectivity/unconnected.py
:language: python
:lines: 19-28
:lines: 17-26

We also proceed to add spike recording and generate raster plots using a helper
function ``plot_spikes`` from ``util.py``.
function ``plot_spikes`` from ``util.py``, which results in

.. figure:: ../../python/example/connectivity/01-raster.svg
:width: 400
Expand All @@ -84,21 +92,28 @@ network. A ring structure is defined by connecting each cell to its predecessor,
i.e. the cell with ``gid = i`` is connected to the cell with ``gid = i - 1`` and
the cell ``gid = 0`` is connected to the last cell ``gid = N - 1``.

We construct such a network by defining a new class ``ring`` deriving from the
We construct such a network by defining a new recpi ``ring`` deriving from the
unconnected network

.. literalinclude:: ../../python/example/connectivity/ring.py
:language: python

The idiomatic way of extending classes with new functionality is to use
inheritance. Importantly, the burden of initializing the base class falls on the
derived class:

.. literalinclude:: ../../python/example/connectivity/ring.py
:language: python
:lines: 18-20

Next, we add a new method that is responsible for the network. Note that this
--- in contrast to most other methods on recipe --- does not have an argument of
``gid``, since it is definining the _global_ network.
``gid``, since it is definining the *global* network.

.. literalinclude:: ../../python/example/connectivity/ring.py
:language: python
:lines: 22-31
/

Similar to the construction of a ``decor`` or ``cv_policy``, a light-weight
language inspired by LISP or Scheme is used here. For this tutorial, we use
Python format strings to compose expressions. Networks comprise a structure and
Expand All @@ -115,46 +130,49 @@ algebra queries operating on abstract sets of source and target identifiers.
- ``join`` takes two sub-structures ``A`` and ``B`` and returns their union.

Upon close inspection, these combinators directly spell out the prose
description of the ring network given above! Connect adjacent cells and close
the ring by connecting the beginning and end.

Running the network and plotting the spikes we find cells deeper into the ring spiking now
description of the ring network given above: Connect adjacent cells and close
the ring by connecting the beginning and end! Running the network and plotting
the spikes we find cells deeper into the ring spiking now

.. figure:: ../../python/example/connectivity/02-raster.svg
:width: 400
:align: center

The network structure is rendered via ``networkx``

.. figure:: ../../python/example/connectivity/02-raster.svg
.. figure:: ../../python/example/connectivity/02-graph.svg
:width: 400
:align: center

Excercise: All-to-all Network
-----------------------------

Using the ``unconnected`` recipe and the `network documentation <https://docs.arbor-sim.org/en/stable/concepts/interconnectivity.html#network-selection-expressions>`_
, define fully connected network, i.e. where each cell is
connected to every other cell except itself.

Using the ``unconnected`` recipe and the
`network documentation <https://docs.arbor-sim.org/en/stable/concepts/interconnectivity.html#network-selection-expressions>`_
define a fully connected network, i.e. where each cell is connected to every other cell except itself.

.. hint::

1. ``source-cell`` and ``target-cell`` can take a range of ids
2. Use and intersection with ``inter-cell`` to remove self connections

You can find our solution in ``python/example/all-to-all.py``, it produces the following output
Our solution produces the following output

.. figure:: ../../python/example/connectivity/03-raster.svg
:width: 400
:align: center

The network structure is rendered via ``networkx``
The network should look like this

.. figure:: ../../python/example/connectivity/03-raster.svg
.. figure:: ../../python/example/connectivity/03-graph.svg
:width: 400
:align: center

For reference, we reproduce it here:

.. literalinclude:: ../../python/example/connectivity/all-to-all.py
:language: python

Brunel Network
--------------

Expand All @@ -174,11 +192,18 @@ excitatory and inhibitory populations, such that
3. If the pre-synaptic cell is in the inhitatory population, the weight is :math:`w_{inh} < 0`
- :math:`|w_{inh}| < |w_{exc}|`

We write down these rules in the recipe
The Brunel network simulation can be implemented like this

.. literalinclude:: ../../python/example/connectivity/brunel.py
:language: python
:lines: 18-32

again using the base class ``unconnected`` to define everything except the
network. We implement these by writing down the rules above in the recipe

.. literalinclude:: ../../python/example/connectivity/brunel.py
:language: python
:lines: 28-36
:lines: 34-42

The ``rand`` structure encodes the random connectivity and removes any potential
self-connections by ``intersect`` with ``inter-cell``, as before. Next, we
Expand Down
9 changes: 5 additions & 4 deletions doc/tutorial/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Hardware
network_ring_gpu

Advanced
-------
--------

.. toctree::
:maxdepth: 1
Expand All @@ -85,6 +85,7 @@ Advanced
Demonstrations
--------------

We try to collect models scientists have built in our `contributor space <https://github.com/arbor-contrib/>`_.
In addition to the tutorials, browsing these models should give you a good idea of what's possible with Arbor
and find get in contact with other Arbor users.
We try to collect models scientists have built in our `contributor space
<https://github.com/arbor-contrib/>`_. In addition to the tutorials, browsing
these models should give you a good idea of what's possible with Arbor and find
get in contact with other Arbor users.
2 changes: 1 addition & 1 deletion python/example/connectivity/all-to-all.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def network_description(self):
full = f"(intersect (inter-cell) (source-cell (gid-range 0 {self.N})) (target-cell (gid-range 0 {self.N})))"
# parameters
weight = "(scalar 125)"
delay = "(scalar 0.5)"
delay = "(scalar 0.5)"
return A.network_description(full, weight, delay, {})


Expand Down
14 changes: 10 additions & 4 deletions python/example/connectivity/brunel.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,27 @@
class brunel(unconnected):
def __init__(self, N) -> None:
super().__init__(N)
self.n_exc = int(0.8*N)
# excitatory population: first 80% of the gids
self.n_exc = int(0.8 * N)
# inhibitory population: the remainder
self.n_inh = N - self.n_exc
# seed for random number generation
self.seed = 42
# excitatory weight
self.weight = 100
# relative weight of inhibitory connections
self.g = 0.8
# probability of connecting any two neurons
self.p = 0.1

def network_description(self):
rand = f"""(intersect (inter-cell)
rand = f"""(intersect (inter-cell)
(random {self.seed} {self.p}))"""
inh = f"(gid-range {self.n_exc} {self.N})"
inh = f"(gid-range {self.n_exc} {self.N})"
weight = f"""(if-else (source-cell {inh})
(scalar {self.g*self.weight})
(scalar {self.weight}))"""
delay = "(scalar 0.5)"
delay = "(scalar 0.5)"
return A.network_description(rand, weight, delay, {})


Expand Down
4 changes: 2 additions & 2 deletions python/example/connectivity/ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ def network_description(self):
wraps = f"(intersect (source-cell {self.N - 1}) (target-cell 0))"
cells = f"(gid-range 0 {self.N})"
chain = f"(chain {cells})"
ring = f"(join {chain} {wraps})"
ring = f"(join {chain} {wraps})"
# parameters
weight = "(scalar 199.99999219)"
delay = "(scalar 0.5)"
delay = "(scalar 0.5)"
return A.network_description(ring, weight, delay, {})


Expand Down
3 changes: 2 additions & 1 deletion python/example/connectivity/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import networkx as nx
import arbor as A


def plot_network(rec, prefix=""):
fg, ax = plt.subplots()
n = rec.num_cells()
Expand Down Expand Up @@ -48,7 +49,7 @@ def plot_spikes(sim, T, N, prefix=""):
ax.set_xlabel("Time $(t/ms)$")
ax.set_ylabel("GID")
ax.set_xlim(0, T)
ax.set_ylim(0, N+1)
ax.set_ylim(0, N + 1)
fg.savefig(f"{prefix}raster.pdf")
fg.savefig(f"{prefix}raster.png")
fg.savefig(f"{prefix}raster.svg")

0 comments on commit b382135

Please sign in to comment.