correlomatrix_detector#

class brainpy.state.correlomatrix_detector(in_size=1, delta_tau=None, tau_max=None, Tstart=Quantity(0., 'ms'), Tstop=None, N_channels=1, start=Quantity(0., 'ms'), stop=None, origin=Quantity(0., 'ms'), name=None)#

NEST-compatible correlomatrix_detector device.

1. Overview

correlomatrix_detector receives spikes from N_channels receptor pools and accumulates binned auto/cross-covariance matrices for non-negative lags. It mirrors the semantics of the NEST correlomatrix_detector recording device, including dual-window filtering (activity window and counting window) and NEST-compatible bin-edge and matrix-ordering conventions.

2. Event Model and Covariance Tensor Equations

Let an accepted event be \(e=(c, t, m, w)\) with receptor channel \(c\), integer simulation step \(t\), multiplicity \(m\), and connection weight \(w\). The queued event weight is \(\hat{w}=m\cdot w\).

The detector stores all accepted events in one queue sorted by time. For each new accepted event \(i\):

  1. Insert \(i\) into the queue (sorted by stamp_step).

  2. Prune events older than the lag horizon \(\tau_{\mathrm{edge}}=\tau_{\max}+\Delta_\tau/2\), including minimum delay offset.

  3. If \(t_i \in [T_{\mathrm{start}}, T_{\mathrm{stop}}]\), update covariance bins against every remaining queued event \(j\).

For pair \((i,j)\), define \(d=|t_i-t_j|\) (in steps). Channel ordering follows NEST matrix layout:

  • if \(t_i \ge t_j\), write into (c_i, c_j, b),

  • otherwise write into (c_j, c_i, b).

The bin index \(b\) (step domain) is computed as

\[\begin{split}b = \begin{cases} -\left\lfloor \dfrac{\Delta_{\tau,\mathrm{steps}}/2 - d} {\Delta_{\tau,\mathrm{steps}}} \right\rfloor, & c_{\mathrm{row}} \le c_{\mathrm{col}} \\ \left\lfloor \dfrac{\Delta_{\tau,\mathrm{steps}}/2 + d} {\Delta_{\tau,\mathrm{steps}}} \right\rfloor, & c_{\mathrm{row}} > c_{\mathrm{col}} \end{cases}\end{split}\]

and contributes

\[ \begin{align}\begin{aligned}\mathrm{cov}[c_{\mathrm{row}}, c_{\mathrm{col}}, b] \leftarrow \mathrm{cov}[c_{\mathrm{row}}, c_{\mathrm{col}}, b] + (m_i w_i)\hat{w}_j,\\\mathrm{count}[c_{\mathrm{row}}, c_{\mathrm{col}}, b] \leftarrow \mathrm{count}[c_{\mathrm{row}}, c_{\mathrm{col}}, b] + m_i.\end{aligned}\end{align} \]

At zero lag, off-diagonal or non-identical-event pairs mirror-update the transposed entry, reproducing NEST’s symmetric zero-lag handling.

The number of bins is

\[N_{\mathrm{bins}} = 1 + \frac{\tau_{\max,\mathrm{steps}}} {\Delta_{\tau,\mathrm{steps}}}.\]

Output tensor shapes are (N_channels, N_channels, N_bins) where bin 0 corresponds to zero lag and bin k to lag \(k \cdot \Delta_\tau\).

3. Windowing, Assumptions, and Constraints

Two windows are applied:

  • Activity window: \((\mathrm{origin}+\mathrm{start},\ \mathrm{origin}+\mathrm{stop}]\). Events outside this interval are discarded and never queued.

  • Counting window: \([T_{\mathrm{start}},\ T_{\mathrm{stop}}]\). Only accepted events in this interval update n_events, covariance, and count_covariance.

Calibration constraints mirror NEST semantics in this implementation:

  • dt > 0 and all finite time parameters are scalar-convertible.

  • start, stop (when finite), origin, delta_tau, and tau_max must align to integer simulation steps.

  • delta_tau must be an odd multiple of dt.

  • tau_max must be a non-negative multiple of delta_tau.

  • N_channels >= 1.

4. Computational Implications

Per accepted event, insertion is \(O(Q)\) in queue length and correlation updates are \(O(Q)\) over retained events, so total update work scales linearly with the active queue size. Memory usage is \(O(Q + N_{\mathrm{channels}}^2 \cdot N_{\mathrm{bins}})\).

Parameters:
  • in_size (Size, optional) – Output size/shape metadata consumed by brainstate.nn.Dynamics. This detector stores internal tensors and does not emit batch-shaped arrays through update. Default is 1.

  • delta_tau (ArrayLike or None, optional) – Lag bin width \(\Delta_\tau\) in milliseconds. Accepts a scalar float-like value or a saiunit quantity convertible to ms. Must be finite, strictly positive, aligned to dt, and an odd multiple of dt. None resolves to 5 * dt. Default is None.

  • tau_max (ArrayLike or None, optional) – One-sided lag horizon \(\tau_{\max}\) in milliseconds. Accepts a scalar float-like value or a quantity convertible to ms. Must be finite, non-negative, aligned to dt, and an exact multiple of delta_tau. None resolves to 10 * delta_tau. Default is None.

  • Tstart (ArrayLike, optional) – Inclusive lower bound of the counting window in milliseconds. Must be scalar-convertible; saiunit quantities are converted to ms. Default is 0.0 * u.ms.

  • Tstop (ArrayLike or None, optional) – Inclusive upper bound of the counting window in milliseconds. Must be scalar-convertible when provided. None means \(+\infty\). Default is None.

  • N_channels (int or ArrayLike, optional) – Number of receptor channels. Must resolve to a scalar integer >= 1. Channel IDs accepted at runtime are 0, 1, ..., N_channels - 1. Default is 1.

  • start (ArrayLike, optional) – Exclusive lower bound of the activity window relative to origin in milliseconds. Must be scalar-convertible and aligned to dt. Default is 0.0 * u.ms.

  • stop (ArrayLike or None, optional) – Inclusive upper bound of the activity window relative to origin in milliseconds. Must be scalar-convertible and aligned to dt when finite. None means \(+\infty\). Default is None.

  • origin (ArrayLike, optional) – Activity-window origin shift in milliseconds. Must be scalar-convertible and aligned to dt. Default is 0.0 * u.ms.

  • name (str or None, optional) – Optional node name forwarded to brainstate.nn.Dynamics. Default is None.

Parameter Mapping

Table 43 Parameter mapping to model symbols#

Parameter

Default

Math symbol

Semantics

delta_tau

None

\(\Delta_\tau\)

Lag-bin width; resolved as 5 * dt when omitted.

tau_max

None

\(\tau_{\max}\)

One-sided lag horizon; resolved as 10 * delta_tau when omitted.

Tstart

0.0 * u.ms

\(T_{\mathrm{start}}\)

Inclusive start of covariance/count update window.

Tstop

None

\(T_{\mathrm{stop}}\)

Inclusive end of covariance/count update window.

N_channels

1

\(N_{\mathrm{channels}}\)

Number of receptor channels and matrix axes.

start

0.0 * u.ms

\(t_{\mathrm{start,rel}}\)

Relative exclusive lower bound of the activity window.

stop

None

\(t_{\mathrm{stop,rel}}\)

Relative inclusive upper bound of the activity window.

origin

0.0 * u.ms

\(t_0\)

Global shift added to start and stop boundaries.

Raises:
  • ValueError – If scalar parameters are invalid (non-scalar, non-finite where finite values are required, or misaligned to dt), if consistency constraints are violated (e.g., delta_tau even in steps, tau_max not divisible by delta_tau, stop < start, or N_channels < 1), or if runtime event arrays contain invalid values/sizes (negative multiplicities, non-finite weights, unknown receptor channel, or mismatched vector lengths).

  • KeyError – If runtime environment keys such as simulation time 't' or resolution dt are unavailable when calibration or update is called.

Notes

  • Unlike some NEST recording devices, n_events is read-only here, matching correlomatrix_detector semantics.

  • This implementation uses default NEST kernel minimum delay semantics in pruning (min_delay = 1 simulation step).

  • Optional multiplicities emulate NEST SpikeEvent multiplicity.

  • Runtime event arguments accepted by update() are one-dimensional scalar-broadcastable arrays over the same event axis: spikes, receptor_ports/receptor_types, weights, multiplicities, and stamp_steps.

Examples

>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> import numpy as np
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     det = brainpy.state.correlomatrix_detector(
...         N_channels=2,
...         delta_tau=0.5 * u.ms,
...         tau_max=2.0 * u.ms,
...     )
...     det.init_state()
...     _ = det.update(
...         spikes=np.array([1.0, 1.0]),
...         receptor_ports=np.array([0, 1]),
...         weights=np.array([1.0, 2.0]),
...         stamp_steps=np.array([11, 12]),
...     )
...     out = det.flush()
>>> out["covariance"].shape
(2, 2, 5)
>>> out["count_covariance"].dtype
dtype('int64')

References

flush()[source]#

Return the current accumulated state as a dictionary.

Snapshots all three accumulated arrays without modifying internal state. This is equivalent to calling get for each of the three primary output keys.

Returns:

out – A dictionary with the following keys:

  • 'covariance' : np.ndarray, shape (N_channels, N_channels, N_bins), dtype float64. Weighted auto/cross-covariance accumulated since the last init_state call.

  • 'count_covariance' : np.ndarray, shape (N_channels, N_channels, N_bins), dtype int64. Unweighted spike-count covariance accumulated since the last init_state call.

  • 'n_events' : np.ndarray, shape (N_channels,), dtype int64. Total number of accepted events per channel within the counting window since the last init_state call.

Return type:

dict

get(key='covariance')[source]#

Retrieve a named scalar or array from the detector.

Parameters:

key (str, optional) –

Name of the quantity to retrieve. Supported keys:

  • 'covariance' — accumulated weighted covariance tensor, shape (N_channels, N_channels, N_bins), dtype float64.

  • 'count_covariance' — unweighted spike-count covariance tensor, same shape, dtype int64.

  • 'n_events' — per-channel accepted event counts, shape (N_channels,), dtype int64.

  • 'delta_tau' — calibrated lag-bin width in ms, scalar float or None if not yet calibrated.

  • 'tau_max' — calibrated one-sided lag horizon in ms, scalar float or None if not yet calibrated.

  • 'Tstart' — counting-window lower bound in ms, scalar float (may be -inf).

  • 'Tstop' — counting-window upper bound in ms, scalar float (may be +inf).

  • 'N_channels' — number of receptor channels, scalar int.

  • 'start' — activity-window lower bound (relative) in ms, scalar float.

  • 'stop' — activity-window upper bound (relative) in ms, scalar float (may be +inf).

  • 'origin' — activity-window origin shift in ms, scalar float.

Default is 'covariance'.

Returns:

value – The requested quantity. Array types match the shapes and dtypes described above; scalar keys return Python numeric scalars.

Return type:

np.ndarray or float or int or None

Raises:
  • KeyError – If key is not one of the supported strings listed above.

  • ValueError – If the underlying parameter is non-scalar or non-convertible during retrieval.

init_state(batch_size=None, **kwargs)[source]#

Reset accumulated state and recalibrate from the environment.

Clears the event queue, zeroes all accumulated arrays (covariance, count_covariance, n_events), and recomputes calibration from the current brainstate environment if dt is available. Must be called before the first update() when running inside a brainstate.environ.context.

Parameters:
  • batch_size (int or None, optional) – Ignored. Accepted for API compatibility with brainstate.nn.Dynamics. Default is None.

  • **kwargs – Ignored. Accepted for API compatibility.

update(spikes=None, receptor_ports=None, receptor_types=None, weights=None, multiplicities=None, stamp_steps=None)[source]#

Process one batch of incoming spike events and update accumulators.

Reads the current simulation time 't' and resolution dt from the brainstate environment, calibrates if necessary, then iterates over each event in the batch. Events outside the activity window are silently discarded. Events inside the counting window update covariance, count_covariance, and n_events.

Parameters:
  • spikes (ArrayLike or None, optional) – 1-D array of spike indicators over a batch of n_items senders. A value > 0 is treated as a spike. If the array contains integer-like floats, the rounded value is used as multiplicity when multiplicities is None. None or empty array causes an immediate return of flush() output.

  • receptor_ports (ArrayLike or None, optional) – 1-D integer array of receptor channel indices, shape (n_items,) or broadcastable scalar. Values must be in [0, N_channels - 1]. Alias receptor_types is also accepted; if both are provided, receptor_ports takes precedence. Default (None) maps all events to channel 0.

  • receptor_types (ArrayLike or None, optional) – Alias for receptor_ports. Ignored when receptor_ports is also provided.

  • weights (ArrayLike or None, optional) – 1-D float array of connection weights, shape (n_items,) or broadcastable scalar. Must contain finite values. Default (None) uses weight 1.0 for all events.

  • multiplicities (ArrayLike or None, optional) – 1-D non-negative integer array of NEST SpikeEvent multiplicities, shape (n_items,) or broadcastable scalar. When None, multiplicities are inferred from spikes: integer-like spike values are used directly; non-integer spike values are binarized to 0 or 1.

  • stamp_steps (ArrayLike or None, optional) – 1-D integer array of simulation step stamps for each event, shape (n_items,) or broadcastable scalar. When None, all events are stamped at step_now + 1 (next step), matching NEST’s default delivery delay of one step.

Returns:

out – Same mapping as flush(): {'covariance': ..., 'count_covariance': ..., 'n_events': ...}.

Return type:

dict

Raises:
  • ValueError – If any of the following occur: - multiplicities contains negative values. - weights contains non-finite values. - receptor_ports contains a channel index outside [0, N_channels - 1]. - Any size-mismatched pair of (spikes, receptor_ports), (spikes, weights), (spikes, multiplicities), or (spikes, stamp_steps) where neither has size 1.

  • KeyError – If the brainstate environment does not expose 't' or dt at call time.