AdExNeuron
July 13, 2026 · View on GitHub
Python module: sc_neurocore.neurons.models.adex
Rust engine: sc_neurocore_engine.AdExNeuron
Acceleration kernels: Rust safety, Go, Julia, and Mojo
Primary model source: Brette & Gerstner (2005), doi:10.1152/jn.00686.2005
AdExNeuron implements the adaptive exponential integrate-and-fire model. It
combines an exponential approach to spike initiation with a second state
variable for subthreshold and spike-triggered adaptation.
Maintained equations
For membrane state v, adaptation state w, and injected current I, the
maintained normalised recurrence evaluates
[ \dot v = \frac{-(v-v_{rest}) + \Delta_T \exp((v-v_{rh})/\Delta_T)}{\tau}
- \frac{-w+I}{C_m}, ]
[ \dot w = \frac{a(v-v_{rest})-w}{\tau_w}. ]
The baseline path advances both candidates with explicit Euler. The
exponential argument is clipped to [-20, 20] as a maintained numerical guard.
If the candidate voltage reaches v_threshold, the same step emits an event,
sets v = v_reset, and commits w = w_candidate + b. Invalid input, state, or
candidate values fail before either state variable is committed.
The DOI establishes the model equations and reset/adaptation structure. The repository defaults are a configurable maintained operating point; they are not presented as the fitted parameter set of a particular cell in the paper.
Python API
from sc_neurocore.neurons.models.adex import AdExNeuron
neuron = AdExNeuron()
event = neuron.step(current=250.0)
trace, events = neuron.simulate(
n_steps=1_000,
current=500.0,
backend="auto",
)
step() returns 0 or 1. simulate() returns the post-update voltage trace
and the total event count, and advances the instance to the final (v, w).
Passing zero steps returns an empty trace without changing state.
Parameters
| Parameter | Default | Meaning |
|---|---|---|
v | -65.0 | Initial membrane voltage |
w | 0.0 | Initial adaptation state |
v_rest | -65.0 | Resting voltage |
v_reset | -68.0 | Post-event reset voltage |
v_threshold | -50.0 | Candidate-voltage event threshold |
v_rh | -55.0 | Exponential rheobase voltage |
delta_t | 2.0 | Exponential slope factor |
tau | 20.0 | Membrane time constant |
tau_w | 100.0 | Adaptation time constant |
a | 0.5 | Subthreshold adaptation coupling |
b | 7.0 | Event-triggered adaptation increment |
c_m | 200.0 | Membrane capacitance scale |
dt | 0.1 | Integration step |
integrator | "baseline_euler" | baseline_euler, rk4, or rosenbrock |
All state and current values must be finite. delta_t, tau, tau_w, c_m,
and dt must also be positive.
Backend contract
| Backend | Public selection | Supported contract |
|---|---|---|
| Python | backend="python" | Full parameter surface; baseline Euler, RK4, and Rosenbrock |
| Rust engine | backend="rust" | Factory-default state and parameters; baseline Euler |
| Julia | backend="julia" | Full numeric state and parameter surface; baseline Euler |
| Go | backend="go" | Full numeric state and parameter surface through a C-shared bridge; baseline Euler |
| Mojo | backend="mojo" | Full numeric state and parameter surface through a C ABI; baseline Euler |
Compiled model-specific lanes reject RK4 or Rosenbrock rather than silently changing the configured integrator. Those integrators remain available in the Python model and in the separate generic polyglot RK4 dispatcher.
For baseline Euler, backend="auto" follows the measured order recorded by the
committed benchmark: Mojo, Julia, Go, compatible Rust, then Python. Alternative
integrators use Python. Explicit backend requests fail closed when their runtime
or shared library is unavailable.
Executed parity envelope
The acceleration tests execute every compiled lane without skip decorators. With maintained defaults over 1,000 steps, all five backends preserve these event-count goldens:
| Current | Events |
|---|---|
0.0 | 0 |
200.0 | 4 |
500.0 | 12 |
Rust and Julia reproduce the Python trace exactly in the enrolled benchmark.
Go differs by at most 7.11e-15 and Mojo by at most 7.40e-13, below the
declared 5e-12 absolute bound. A non-default full-parameter case is also
exercised for Julia, Go, and Mojo, including final (v, w) parity.
The Python-to-Verilog route is tracked separately. The existing Q16.16 Icarus
co-simulation compares Python and generated RTL event counts over 500 steps at
I=1000 with a declared maximum two-percent gap. The independent reference
trace adex_resting_adaptation_doi re-derives subthreshold explicit-Euler
features from the DOI-backed equations and matches the committed feature set to
1e-12.
Benchmark evidence
benchmarks/results/bench_adex.json is generated by
benchmarks/bench_adex.py. It records source hashes, runtimes, CPU affinity,
governor, host load, event parity, final states, and voltage-trace error.
The committed single-logical-CPU run uses 100,000 steps, seven repeats, and
I=500. Its median call times are:
| Backend | Median call time | Speed-up vs Python | Events |
|---|---|---|---|
| Mojo | 4.658 ms | 472.75x | 1065 |
| Julia | 5.040 ms | 436.91x | 1065 |
| Go | 12.807 ms | 171.95x | 1065 |
| Rust | 58.988 ms | 37.33x | 1065 |
| Python | 2202.136 ms | 1.00x | 1065 |
The run used a powersave governor on a non-isolated, loaded workstation. These numbers are local source-regression evidence for this workload, not a hardware throughput claim or a general ranking across machines.
Reproduce it from a checkout with every optional runtime built:
PYTHONPATH=src:bridge taskset -c <cpu> python \
benchmarks/bench_adex.py \
--json benchmarks/results/bench_adex.json
Evidence surfaces
tests/test_model_adex.py— model equations, integrators, validation, and Python/Rust public behaviour.tests/test_adex_backends.py— four compiled lanes, full-parameter transport, auto routing, ABI rejection, and loader failures.tests/test_bench_adex.py— benchmark schema, fail-closed behaviour, source hashes, and real five-backend execution.src/sc_neurocore/accel/go/services/adex_test.go— Go recurrence goldens, reset, fail-closed state, and native benchmark.src/sc_neurocore/accel/julia/adex_parity_test.jl— Julia goldens and mutation-free rejection.tests/test_cosim_adex.py— Q16.16 Python-to-Verilog event-count envelope.tests/test_reference_adex.py— independent DOI-backed reference features.
Current boundary
The compiled model-specific kernels implement the maintained baseline-Euler recurrence. They do not claim polyglot RK4/Rosenbrock support. The Rust engine class does not expose parameter injection, so the Python dispatcher accepts it only for the factory-default contract. The generated RTL evidence is an H1 co-simulation result with its declared event-count tolerance; it is not an ASIC or FPGA timing result.