Skip to main content

exact-event-adjoint

Grid-free exact continuous-time adjoint gradients for Time-To-First-Spike (TTFS) spiking neural networks. No surrogate gradients. No dense time grid. Every gradient is the analytic derivative of the threshold-crossing event times, and every claim in this file is backed by a numerical test in tests/.

phi_k(t) = sum_m W[o,m] * K(t, t_in[m])  -  (theta - u_reset) * sum_{j<k} R(t, t_j)  -  theta  = 0
  • K(t, s) = (tau_s*tau_m)/(tau_m-tau_s) * (exp(-(t-s)/tau_m) - exp(-(t-s)/tau_s)) double-exponential postsynaptic kernel.
  • R(t, s) = exp(-(t-s)/tau_m) decaying post-spike reset kernel (subtractive reset).

Installed features (each one was verified empirically in tests/)

Feature Claim Verified
Continuous-time IFT dt*/dx = - (d phi/dx) / u_dot(t*) for the first firing time, closed form, no surrogate ✓ weight & input Jacobians match central finite differences to 1e-9 relative (test_core_engine.py)
Reset saltation coupling multi-spike backward solves the coupled system dt_k/dx = -(dphi_k/dx + sum_{j<k} b_{k,j} dt_j/dx) / u_dot(t_k), with b_{k,j} = -(theta-u_reset)/tau_m * R(t_k, t_j) ✓ backward matches finite differences to 1e-9 relative, every spike satisfies phi(t_k)=0 to 8e-10 (test_multispike.py)
Event-ordered, grid-free crossings are found from input arrivals, kernel-peak lags and previous spikes — no uniform grid; probe count scales with # events, not horizon ✓ static guard: no linspace anywhere in the gradient path; first-crossing equals a brute-force time-domain sim to 2e-6; multi-spike equals brute-force re-crossing (test_gridfree.py, test_solver.py)
O(pending-events) engine EventDrivenO1Engine is a priority-queue event simulator of the same kernel+reset dynamics; membrane is advanced analytically between events ✓ reproduces the full solver spike chain, identical spike counts, max delta 2e-5 (test_engine.py)
Existence regularization squared peak-margin penalty for silent neurons so their gradient does not collapse ✓ silent-neuron weight gradients are nonzero and negative (descent raises weights) (test_attention_existence.py)
Full layer suite Linear, Conv2D (patchwise), Multi-Spike (reset-aware trains), Recurrent (w_in + w_rec), Spiking Attention (single + multi-head), Feed-Forward ✓ every layer constructs, runs forward and backwards finite-differenced where meaningful (test_layers.py)
Event engine == core ExactEventFunction and ExactAdjointFunction return bit-identical outputs and gradients ✓ test_core_engine.py::test_engine_identical_to_core

Precise wording (we do not overclaim)

These are the exact, defensible statements you may make in a paper:

  1. Continuous-Time IFT & Saltation resetting — TRUE. The first firing time is an implicit function of the latent variables and its gradient is the exact IFT derivative — no surrogate approximation is used. For multi-spike trains the implicit equations for all spike times are coupled through the reset kernels; the backward pass solves that coupled system exactly. The coupling terms b_{k,j} are precisely the saltation-type reset multipliers -(theta-u_reset)/tau_m * R(t_k, t_j) of the threshold-reset discontinuity: the classic instantaneous linearization 1 + (theta-u_reset)/(tau_m u_dot) is the degenerate short-gap limit, ours is the exact finite-gap generalization.

  2. Priority-queue, grid-free — TRUE, with one precision note. The package evaluates all membrane quantities on event-ordered sets (presynaptic times, kernel-peak lags, previous spikes, t_max) and never builds a uniform time grid. Probe counts scale with the number of events, not with the horizon length or any step size. The label "O(1) memory" that circulated in earlier demos is not retained: the heap-based engine is O(number of pending events) memory with O(log) work per push. That is what is actually true, so that is what we ship.

  3. Escape-Noise Regularization — TRUE with a name correction. The implemented regularizer is a deterministic peak-margin penalty (max of the differentiable soft-weighted probe peak below threshold) that provably removes dead/silent-neuron gradient collapse: gradient descent raises silent weights. This is not the stochastic escape-rate functional; we therefore call it the existence regularization (ExactAdjointFunction(use_existence=True) or existence_loss_and_grads).

  4. Full Layer Suite — TRUE. ExactAdjointLinear, ExactAdjointConv2d, ExactAdjointMultiSpike, ExactAdjointRecurrent / ExactAdjointTTFSRnn, ExactAdjointAttention, ExactAdjointMultiHeadAttention (genuine per-head split, sqrt(head_dim) scaling), ExactAdjointFFN, with AdjointSpikeNorm, latency / spike-count losses. All constructed layers run forward and backward.


Quickstart

import torch
from exact_event_adjoint import (
    ExactAdjointLinear, ExactAdjointMultiSpike,
    latency_cross_entropy, AdjointSpikeNorm,
)

torch.manual_seed(0)
encoder = ExactAdjointLinear(4, 6, tau_m=15.0, tau_s=4.0, theta=1.0, t_max=50.0)
decoder = ExactAdjointMultiSpike(6, 3, max_spikes=4)
norm    = AdjointSpikeNorm(6)

t_in = torch.rand(8, 4) * 40 + 1          # latency-encoded input spikes
t1   = encoder(t_in)                      # (B, O) exact first-spike times
h    = norm(t1)
train = decoder(h)                        # (O, B, K) reset-aware spike trains

loss = latency_cross_entropy(t1, torch.randint(0, 6, (8,)))
loss.backward()                           # exact IFT gradients, no surrogates

Mixed firing/silent training uses the existence flag:

layer = ExactAdjointLinear(4, 3, use_existence=True)   # dead neurons get gradient pressure

The exact per-layer alternative with the same maths lives in ExactEventLinear / ExactEventFunction (bit-identical to ExactAdjointFunction).

Running the verification suite

python -m pytest exact_event_adjoint/tests -q
# 20+ tests: finite-difference Jacobians, brute-force simulations, engine-vs-solver,
# existence direction, head split, layer suite, grid-free static guard

Integrity notes

  • The solver (solver.py) performs no autograd; all broadcast arithmetic is ordinary tensor ops and every gradient is provided analytically by the autograd Function backward passes.
  • Recurrent loops connect spike-latency outputs to latency-encoded inputs (w_in + w_rec); this is differentiable TTFS feedback, not a continuous dynamical-system solver for the recurrent loop (scope note).
  • EventDrivenO1Engine.simulate_events implements feedforward receptive fields (static inputs). Causal recurrent rescheduling is future work.

License

MIT — see LICENSE.

Metadata

Release files for exact-event-adjoint 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for exact-event-adjoint 0.2.0
File Size Uploaded Provenance
exact_event_adjoint-0.2.0.tar.gz 26.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for exact-event-adjoint 0.2.0
File Interpreter ABI Platform
exact_event_adjoint-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 47.7 kB

Release files / exact_event_adjoint-0.2.0.tar.gz

Download URL exact_event_adjoint-0.2.0.tar.gz
Size 26.7 kB
Tags Source
SHA-256 checksum
How to use checksums
a32e967596c116fc236381c54063ad9de52c1b16146e3e5e91924b702c8e6ace
BLAKE2b-256 checksum
How to use checksums
379c1de799bc97be73a255ef0c3974f10f624c350de142449cb2fcb0670f088b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release files / exact_event_adjoint-0.2.0-py3-none-any.whl

Download URL exact_event_adjoint-0.2.0-py3-none-any.whl
Size 21.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa952917e5eccf4ce198954b8c7e7892af25aee1c8a3c226b3e041a6e567da01
BLAKE2b-256 checksum
How to use checksums
f98f6dfa757b3d0e133876fb0d1d608ffde75e3709cd814e96fab4284974ca2b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Security for exact-event-adjoint 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page