ANNarchy 5.0.0
  • ANNarchy
  • Installation
  • Tutorial
  • Manual
  • Notebooks
  • Reference

Random distributions

  • Core objects
    • Overview
    • Equation parser
    • Rate-coded neurons
    • Spiking neurons
    • Populations
    • Rate-coded synapses
    • Spiking synapses
    • Projections
    • Connectors
    • Monitors
    • Network
    • Setting inputs
    • Random distributions
    • Numerical methods
    • Saving and loading
    • Parallel simulations
  • Extensions
    • Hybrid networks
    • Structural plasticity
    • Convolution and pooling
    • Reporting
    • Logging with tensorboard

On this page

  • Inside equations
  • Python classes

Random distributions

ANNarchy allows to sample values from various probability distributions. The list is also available in the reference section: RandomDistribution

  • Uniform: Uniform distribution between min and max.
  • DiscreteUniform: Discrete uniform distribution between min and max.
  • Normal: Normal distribution.
  • LogNormal: Log-normal distribution.
  • Exponential: Exponential distribution, according to the density function:
  • Gamma: Gamma distribution.
  • Binomial: Binomial distribution.

Inside equations

The probability distributions can be used inside neural or synaptic equations to add noise. The arguments to the random distributions can be either fixed values or global parameters.

neuron = ann.Neuron(
    parameters = dict(
        noise_min = -0.1,
        noise_max = 0.1,
    ),
    equations = [
        ann.Variable('noise += Uniform(noise_min, noise_max)'),
    ]
)

It is not allowed to use local parameters (with different values per neuron) or variables, as the random number generators are initialized only once at network creation (doing otherwise would impair performance too much).

Caution

If a global parameter is used, changing its value will not affect the generator after compilation (net.compile()).

It is therefore better practice to use normalized random generators and scale their outputs:

neuron = ann.Neuron(
    parameters = dict(
        noise_min = -0.1,
        noise_max = 0.1,
    ),
    equations = [
        ann.Variable('noise += noise_min + (noise_max - noise_min) * Uniform(0, 1)'),
    ]
)

Python classes

ANNarchy also exposes these distributions as Python classes deriving from ann.RandomDistribution:

rd = ann.Uniform(min=-1.0, max=1.0)

values = rd.get_values(shape=(5, 5))
print(values)
[[ 0.52496801  0.8304131   0.18981183  0.90584312  0.45013294]
 [-0.8496625   0.13878709 -0.71916338  0.65327206 -0.74278506]
 [-0.41181912  0.18992222 -0.71336558 -0.31109334  0.56593865]
 [ 0.95857898 -0.92678771  0.04872276 -0.80440061  0.91366882]
 [-0.43897458  0.53091326  0.5378137   0.64775663 -0.49223366]]

Those classes are only thin wrappers around numpy’s random module. The code above is fully equivalent to:

rng = np.random.default_rng()

values = rng.uniform(-1.0, 1.0, (5,5))
print(values)
[[ 0.18875554 -0.04882092 -0.45888849 -0.75761291  0.10636076]
 [-0.84540858  0.28957174 -0.42878277  0.6277162   0.08221608]
 [-0.86781869  0.95202885 -0.56962942 -0.95892803  0.03947233]
 [ 0.92376797 -0.89519452 -0.94021693 -0.77945232 -0.7258296 ]
 [-0.80374599  0.67538198  0.22838406  0.13981939  0.81150928]]

The main interest of using these objects instead of directly numpy is that the get_values() method can only be called when the network is instantiated (at the end of net.compile()).

For example, in the following code, the random values are only created after compilation and transferred to the C++ kernel. They do not comsume RAM unnecessarily on the Python side.

net = ann.Network()
pop = net.create(100000000, ann.Neuron("r = 0.0"))
pop.r = ann.Uniform(min=0.0, max=1.0) 
# The values are not drawn yet
net.compile()
# The values are now drawn and stored in the C++ kernel.

If you want to control the seed of the random distributions, you should pass the numpy default RNG to it, initialized with the network’s seed:

net = ann.Network(seed=42) # or leave the seed to None to have it automatically set

rng = np.random.default_rng(seed=net.seed)

rd = ann.Uniform(min=0.0, max=1.0, rng=rng)

This is especially important when running simulations in parallel with parallel_run().

Setting inputs
Numerical methods
 

Copyright Julien Vitay, Helge Ülo Dinkelbach, Fred Hamker