Dynamics

Different dynamical rules can be imposed on the network. Each dynamic is organized into a separate module, implemented as a class (inherited from the base Dynamic) alongside all necessary integration methods and utilities.

Every rule answers the same four questions, which is what makes them interchangeable behind --dyn:

  1. how the run and its state files are named, from the dynamic’s own parameters;

  2. how the input arrays are laid out in memory before integration;

  3. how a batch of networks is integrated – a numerical solver for the rate networks, brian2 for the spiking ones;

  4. where the states are written, and in what layout the rest of the package reads them back from (hetero.dataloader).

A dynamic also fixes what the readout may be: VALID_ACTIVATIONS in hetero.config pairs each dynamic with the readout activations that make sense for it, and the command line falls back to a safe default when the two are incompatible.

Warning

These utilities and methods are aimed to be used only locally within the methods of the corresponding class. They are exposed to the user only for inspiration and guidance on how to extend for other rules.

Abstract dynamics

class hetero.dynamics.base.Dynamic(sim_path, namespace, name, ext)[source]

Bases: object

Base class for for the dynamic object, that serves as containter for orchestrating the integration of the dynamical systems and storing them on the disk.

Parameters:
  • sim_path (str) – Path of the simulation directory

  • namespace (dict) – The dynaimc rule’s argument (passed to the integrators)

  • name (str) – Name of the specific dynamic rule

  • ext (str) – The extension of the state file (pkl or npy)

prepare_nets()[source]
scan_for_undone(state_name)[source]

Checks which networks are not yet integrated, and returns lists for the network ids and their corresponding time constants. These lists will be empty if all networks are integrated.

Rate dynamics

Integrates the leaky integrator with scipy, either through solve_ivp or through the in-house Euler and Runge–Kutta integrators, and can drive the batch serially or across processes with joblib. Also holds the activation_func family, which the readouts of a rate network reuse verbatim.

Leaky-Integrator dynamic

The evolution of the membrane voltage \(v_i(t)\) of neuron \(i\) is described by the following rule:

\[\tau_i \frac{\mathrm{d}v_i}{\mathrm{d}t} = -v_i(t) + J \sum_j w_{ij} f(v_j(t)) + J_u \sum_k w_{ik} u_k(t) + J_n \xi(t)\]

where \(f(.)\) is some activation function and \('xi\) is the white noise imposed on the neuron. Note that time constants are in general neuron-specific, which renders the network heterogeneous.

class hetero.dynamics.li.LI(sim_path, namespace, dyn_params={})[source]

Bases: Dynamic

The object for integrating neworks of Leaking-Integrator (LI) neurons.

run(solver, state_name, stype=float, ncpu=-1, **kwargs)[source]

Runs the LI dynamic.

Parameters:
  • solver (str) – Integrator’s name (euler or runge_kutta)

  • state_name (str) – State file name

  • stype (str or type, optional) – The data type in which the state is stoerd on the disk, by default float

  • ncpu (int, optional) – Number of CPU cores to use. The default of -1 means use all.

hetero.dynamics.li.LI_grad(t, y, taus=None, A_adj=None, wu=None, w=None, Ju=1, J=1, Jn=1, af='possig', ut=None, xit=None, dt=1., delay=0, **kwargs)[source]

Implentation of the LI dynamics with noise.

hetero.dynamics.li.integrate_n_save_joblib(integrator, namespace, taus, net_ids, sim_path, state_name, stype, ncpu)[source]
hetero.dynamics.li.integrate_n_save_serial(integrator, namespace, taus, net_ids, sim_path, state_name, stype, ncpu)[source]
hetero.dynamics.li.forward_euler(**arg_dict)[source]

Implementation of the forward Euler solver.

hetero.dynamics.li.runge_kutta(**arg_dict)[source]

Implementation of the Runge-Kutta solver. This function is a wrapper around Scipy’s solve_ivp method.

hetero.dynamics.li.activation_func(x, af, x0=1., thr=0, **kwargs)[source]

Apply a specified activation function to input data with optional scaling and thresholding. The valid activation fucntions are:

  • ‘lin’: linear

  • ‘relu’: rectified linear unit

  • ‘caplin’ : same as ‘lin’ but capped between 0 and 1

  • ‘caprelu’: same as ‘relu’ but capped between 0 and 1

  • ‘capquad’: quadratic function capped between 0 and 1

  • ‘capcube’: cubic function capped between 0 and 1

  • ‘capcube’: cubic function capped between 0 and 1

  • ‘capexp’: exponential function capped between 0 and 1

  • ‘tanh’: tangent hyperbolic

  • symsig: an even sigmoidal function centered at t=0 with range between -1 and 1.

  • ‘possig’: sigmoidal function centered at y=0.5 with range between 0 and 1 .

  • ‘possig_plus’: same as ‘possig’ but only for values larger than threshold and zero otherwise.

  • ‘bell’ : non-normalized Gaussian activation function

  • ‘camel’: a gaussian multiplied by a pure quadratic function, resulting in two identical bumps

    at (±1, 1).

  • ‘switch’: a binary activation. Zero for values smaller than thr and 1 otherwise.

Parameters:
  • x (float or ndarray) – Input array or value to be transformed

  • af (str) – Name of the activation function to apply (e.g., ‘relu’, ‘tanh’, ‘possig’, etc.)

  • x0 (float) – Scaling factor for the input (default: 1.0)

  • thr (float) – Threshold (bias) value to shift the input (default: 0)

  • kwargs (dict) – Additional keyword arguments for specific activation functions

Returns:

float or ndarray – The result of applying the chosen activation function to the input

Spiking dynamics

Integrates the leaky integrate-and-fire neurons with brian2. Instead of a solver call it builds a brian2 network with a StateMonitor per quantity, so the monitors are written chunk by chunk to keep the memory footprint bounded on long runs. The conversion helpers between voltage, background current and firing rate live here too.

Leaky Integrate-and-Fire dynamic

The evolution of the membrane voltage \(v_i(t)\) of neuron \(i\) is described by the following rule:

\[\begin{split}\tau_i \frac{\mathrm{d}v_i}{\mathrm{d}t} &= -v_i(t) + (v_{bg} + E) + J \sum_j w_{ij} s_j(t) + J_u \sum_k w_{ik} u_k(t) + J_n \xi(t) \\ s_j(t) &= \tau_\text{ref} \sum_{f} \delta(t-t_j^f) \\ t_j^f &= \arg v_j(t) = v_{\text{thr}} \\ v_j(t) &= v_\text{reset} \hspace{2cm} t\in (t_j^f, t_j^f+ \tau_\text{ref}]\end{split}\]
class hetero.dynamics.lif.LIF(sim_path, namespace, dyn_params={})[source]

Bases: Dynamic

The object for integrating neworks of Leaking-Integrator (LI) neurons.

run(state_name, solver='euler', nu0=None, nchunks=10, **kwargs)[source]

Runs the LIF dynamic.

Parameters:
  • state_name (str) – State file name

  • solver (str) – Integrator’s name (euler or heun)

  • nu0 (float, optional) – The background firing rate of the neurons (in Hz). A unitless number must be provided. By default is None.

  • nchunks (int, optional) – Number of simulation chunks, by default 10

Note

When networks are large, it is better to break down the simulation into several chunks. Otherwise Brian accumulates all recoreded variables in RAM and soon the simulation stalls.

hetero.dynamics.lif.get_eqs(params)[source]

Returns the neuronal and synaptic equations in Brian-compatible format. Note that for simplcity, we treat the feedforward, recurrent, and noise inputs as unit-free quantities (unit: 1) and absorb their overall unit in the newly introduced parameter RI which matches to the dimension of the voltage (i.e., it can be volt, mV, or even dimensionless, if voltage is expressed like so).

Parameters:

params (dict) – The arguments of the dynamical rule, specifying the type of synaptic kernels to be used.

hetero.dynamics.lif.get_obj(net_id, objs, obj_name)[source]

Returns the object associated with network net_id whose name contains obj_name. The list of all objects objs must be passed as well.

hetero.dynamics.lif.make_monitors(nets)[source]

Creates StateMonitors for networks.

hetero.dynamics.lif.save_chunked_monitors(mons, chunk_id, sim_path, state_name)[source]

saves the recorded vars of the monitor on disk

hetero.dynamics.lif.save_merged_monitors(nchunks, net_ids, sim_path, state_name, cleanup=True)[source]

Merges all monitors and saves them on the disk. Moreover, cleans the old monitor chunks.

hetero.dynamics.lif.nu2ubg(nu, E, vreset, thr, tau, tau_ref)[source]

Convert target firing rate to required background voltage.

Parameters:
  • nu (float) – Target firing rate in Hz

  • E (float) – Reversal potential

  • vreset (float) – Reset potential

  • thr (float) – Threshold potential

  • tau (float) – Membrane time constant

  • tau_ref (float) – Refractory period

Returns:

float – Required background voltage to achieve target rate

hetero.dynamics.lif.ubg2nu(u, E, vreset, thr, tau, tau_ref)[source]

converts a given background voltage to the firing rate.