correlation_detector#

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

NEST-compatible correlation_detector device.

1. Overview

correlation_detector receives spikes from two receptor ports (0 and 1) and accumulates lag histograms in both weighted (float64) and unweighted (int64) forms, following NEST event ordering. It mirrors the semantics of the NEST correlation_detector recording device, including dual-window filtering (activity window and counting window), Kahan-compensated weighted histogram accumulation, and NEST-compatible bin-edge conventions.

2. Event Model and Histogram Equations

Let an accepted event be represented as \(e=(s, t, m, w)\) where \(s\in\{0,1\}\) is receptor port, \(t\) is integer simulation step, \(m\) is multiplicity, and \(w\) is scalar connection weight. Each stored queue entry keeps \(\hat{w}=m\cdot w\).

For each new event, the detector correlates it against all queued events of the opposite port that survive lag-window pruning. The bin index is

\[b = \left\lfloor \frac{\tau_{\mathrm{edge}} + \sigma_s (t - t_j)} {\Delta_\tau} \right\rfloor, \qquad \sigma_s = 2s - 1, \qquad \tau_{\mathrm{edge}} = \tau_{\max} + \frac{\Delta_\tau}{2},\]

with all times represented in integer steps for the index computation. \(\sigma_s\) encodes causality direction: +1 for port-1 events (event is the “post” spike) and -1 for port-0 events (event is the “pre” spike), so positive lags correspond to port-1 spikes occurring after port-0 spikes.

For each matched opposite event \(j\), the histograms are updated as

\[H_b \leftarrow H_b + (m w)\,\hat{w}_j, \qquad C_b \leftarrow C_b + m,\]

where \(H_b\) is histogram and \(C_b\) is count_histogram. histogram uses Kahan summation per bin to reduce floating-point accumulation error; the compensation terms are exposed as histogram_correction.

The number of bins is

\[N_{\mathrm{bins}} = 1 + 2 \cdot \left(\frac{\tau_{\max,\mathrm{steps}}}{\Delta_{\tau,\mathrm{steps}}}\right).\]

Bin intervals are left-closed/right-open in the internal index rule, which matches NEST edge handling in correlation_detector. The centre bin (index \(N_{\mathrm{bins}}//2\)) corresponds to zero lag.

3. Windowing, Assumptions, and Constraints

Two windows are applied exactly as in NEST:

  • Activity window: \((\mathrm{origin}+\mathrm{start},\ \mathrm{origin}+\mathrm{stop}]\) in simulation time. Events outside are discarded and never buffered.

  • Counting window: \([\mathrm{Tstart},\ \mathrm{Tstop}]\). Only events in this window increment n_events and update histograms. Events outside this window can still be buffered and can affect later counted events via cross-correlation with subsequently counted events.

Grid-alignment constraints are strict: start, stop (if finite), origin, delta_tau, and tau_max must map to integer multiples of simulation dt. Additionally, tau_max must be an exact multiple of delta_tau. Violations raise ValueError at calibration time.

4. Computational Implications

Per accepted event, work is linear in queue lengths:

  • \(O(Q_{\mathrm{other}})\) for pruning and correlation against the opposite-port queue,

  • \(O(Q_{\mathrm{self}})\) for sorted insertion into the sender queue.

Memory usage is \(O(Q_0 + Q_1 + N_{\mathrm{bins}})\), where queue length depends on event rate and tau_max. Calibration is triggered lazily on first access; subsequent calls reuse cached state unless dt or window parameters change.

Parameters:
  • in_size (Size, optional) – Output size/shape metadata consumed by brainstate.nn.Dynamics. This detector is event-driven and stores scalar histograms; in_size is retained for API consistency and does not affect histogram shape. Default is 1.

  • delta_tau (quantity (ms) or float or None, optional) – Bin width \(\Delta_\tau\). Unitful saiunit quantities are accepted and converted to ms; bare floats are interpreted as ms. Must be finite, strictly positive, and an integer multiple of simulation dt. None auto-selects 5 * dt. Default is None.

  • tau_max (quantity (ms) or float or None, optional) – One-sided lag limit \(\tau_{\max}\). Unitful quantities accepted. Must be finite, non-negative, an integer multiple of dt, and an exact integer multiple of delta_tau. None auto-selects 10 * delta_tau. Default is None.

  • Tstart (quantity (ms) or float, optional) – Inclusive lower bound of the counting window in ms. Scalar-convertible; unitful values are converted to ms. Default is 0.0 * u.ms.

  • Tstop (quantity (ms) or float or None, optional) – Inclusive upper bound of the counting window in ms. None means \(+\infty\) (no upper bound). Scalar-convertible when provided. Default is None.

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

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

  • origin (quantity (ms) or float, optional) – Global time origin shift in ms for activity-window evaluation. The effective activity window becomes (origin + start, origin + stop]. 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. If None, a name is auto-generated. Default is None.

Parameter Mapping

Parameter

Default

Math symbol

Semantics

delta_tau

None5 * dt

\(\Delta_\tau\)

Lag-histogram bin width; auto-resolved when omitted.

tau_max

None10 * delta_tau

\(\tau_{\max}\)

One-sided correlation horizon; auto-resolved when omitted.

Tstart

0.0 ms

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

Inclusive start of histogram and event-count update window.

Tstop

None (\(+\infty\))

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

Inclusive end of histogram and event-count update window.

start

0.0 ms

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

Relative exclusive lower bound of the activity window.

stop

None (\(+\infty\))

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

Relative inclusive upper bound of the activity window.

origin

0.0 ms

\(t_0\)

Global offset applied to start and stop boundaries.

Raises:
  • ValueError – If time parameters are non-scalar, non-finite where finite values are required, misaligned to simulation resolution, or violate consistency constraints (e.g. tau_max % delta_tau != 0 or stop < start). Also raised for invalid runtime event arguments (unknown receptor port, negative multiplicity, non-finite weights, or size mismatches).

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

  • RuntimeError – If an internal lag-bin index falls outside histogram range; this indicates inconsistency between calibration and event processing.

Notes

  • n_events can only be assigned [0, 0], which resets all detector state and clears histograms, matching NEST’s reset semantics.

  • Runtime input events are provided through update(): spikes, receptor_ports, weights, multiplicities, and stamp_steps are each scalar-broadcastable to a common 1-D event axis.

  • Receptor ports are restricted to integer values 0 and 1.

  • Connection delays are ignored by design; only event time stamps are used for lag computation.

  • Calibration is cached and reused across steps; it is automatically invalidated if dt or any window parameter changes between calls.

Examples

Basic correlation of simultaneous spikes on opposite ports:

>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> import numpy as np
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     det = brainpy.state.correlation_detector(
...         delta_tau=0.5 * u.ms,
...         tau_max=5.0 * u.ms,
...     )
...     with brainstate.environ.context(t=1.0 * u.ms):
...         out = det.update(
...             spikes=np.array([1.0, 1.0]),
...             receptor_ports=np.array([0, 1]),
...             weights=np.array([1.0, 2.0]),
...             multiplicities=np.array([1, 1]),
...             stamp_steps=np.array([11, 11]),
...         )
...     _ = out['histogram'].shape  # (21,) for tau_max=5ms, delta_tau=0.5ms

Default parameters with no input events and explicit state reset:

>>> import brainpy
>>> import brainstate
>>> import saiunit as u
>>> with brainstate.environ.context(dt=0.1 * u.ms):
...     det = brainpy.state.correlation_detector()
...     with brainstate.environ.context(t=0.0 * u.ms):
...         _ = det.update()  # no input events; returns current state
...     det.n_events = [0, 0]  # explicit reset, NEST-compatible

References

connect()[source]#

Compatibility no-op for NEST-like device interface.

flush()[source]#

Return current detector outputs without consuming internal state.

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

Return one detector state variable or calibrated scalar parameter.

Parameters:

key (str, optional) – Query key. Supported values are 'histogram', 'histogram_correction', 'count_histogram', 'n_events', 'delta_tau', 'tau_max', 'Tstart', 'Tstop', 'start', 'stop', and 'origin'. Default is 'histogram'.

Returns:

out – Requested value. Histogram outputs are NumPy arrays with shapes (N_bins,) (float64/int64). n_events has shape (2,). Time scalar outputs are returned in milliseconds as Python float; infinite bounds are returned as math.inf.

Return type:

dict

Raises:
  • KeyError – If key is unsupported.

  • ValueError – If scalar conversion of configured time parameters fails.

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

Reset detector buffers and histogram state for current calibration.

Parameters:
  • batch_size (int or None, optional) – Unused placeholder for brainstate.nn.Dynamics compatibility.

  • **kwargs – Unused compatibility arguments.

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

Process one simulation step of incoming events and return outputs.

Parameters:
  • spikes (ArrayLike or None, optional) – Event-presence/multiplicity proxy with shape (N,) after flattening (scalars are broadcast). If None, no events are processed and current state is returned. When multiplicities is None, integer-like spikes values are rounded and clipped to non-negative multiplicities; otherwise non-integer values are interpreted as binary spike > 0 flags.

  • receptor_ports (ArrayLike or None, optional) – Receptor port indices with shape (N,) (or scalar broadcast). Valid values are 0 and 1 only. If None, defaults to 0 for all events unless receptor_types is provided.

  • receptor_types (ArrayLike or None, optional) – Alias for receptor_ports kept for NEST API compatibility. Used only when receptor_ports is None.

  • weights (ArrayLike or None, optional) – Per-event connection weights with shape (N,) (or scalar broadcast). Must be finite. Default is 1.0 when omitted.

  • multiplicities (ArrayLike or None, optional) – Explicit non-negative integer multiplicities with shape (N,) (or scalar broadcast). Effective multiplicity is forced to zero where corresponding spikes <= 0.

  • stamp_steps (ArrayLike or None, optional) – Integer event time stamps in simulation steps with shape (N,) (or scalar broadcast). If None, all events are stamped at current_step + 1.

Returns:

out – Same dictionary as flush(), containing current histogram, histogram_correction, count_histogram, and n_events after processing this call.

Return type:

jax.Array

Raises:
  • KeyError – If required environment values ('t' or dt) are missing.

  • ValueError – If argument sizes are inconsistent, receptor ports are outside {0, 1}, multiplicities are negative, times are not grid-aligned, or calibration constraints are violated.

  • RuntimeError – If a computed bin index is outside histogram bounds.