Bit-exact MoonBit port of SpikingNeuralNetworks.jl plus CNN primitives + 5D spatiotemporal tensors + full optimiser suite + normalisation layers + learning-rate schedulers + generic Chain + pre-made bottles + ResNet foundations + surrogate gradients + transformer activations. Covers IF, AdEx, Izhikevich (IZ), HH, Morris-Lecar, Poisson neurons; Markram STP, Gerstner / MexicanHat / AntiSymmetric STDP, vSTDP, Confavreux2025, Receptors (AMPA / NMDA / GABAa / GABAb), multicompartment dendritic neurons (BallAndStick, Tripod, Multipod); Conv2d / MaxPool2d / ReLU / Flatten / Linear forward + backward primitives; Tensor struct with broadcasting + softmax + log-softmax + cross-entropy; image adapter (BMP/QOI/TGA/PNG/GIF/JPEG/ICO/TIFF) via riantr/moonbit_image; 5D [T,B,C,H,W] STImage for spiking-CNN time-series input; SGD + SGD-with-momentum + Adam (with bias correction) + AdamW (decoupled weight decay) + RMSprop + AdaGrad optimisers; BatchNorm2d (with running stats + training/inference modes) + LayerNorm (per-sample, no running stats) with forward + backward; StepLR + ExponentialLR + CosineAnnealingLR + ReduceLROnPlateau schedulers; generic Chain / Sequential over Conv2d / ReLU / MaxPool2d / Flatten / Linear / BatchNorm2d / LayerNorm via tagged-enum dispatch with shape tracking and per-layer parameter gradients; pre-made MLP / SimpleCNN / LeNet5 bottles with He-init + xoshiro RNG; elementwise Add + AvgPool2d / GlobalAvgPool2d + ResidualBlock (identity + projection variants) ResNet foundations; fast-sigmoid surrogate gradient (Zenke & Ganguli 2018) for BPTT through IF / LIF Heaviside spikes; GELU (Gaussian Error Linear Unit) tanh-approximation activation for transformer FFN; Multi-Head Self-Attention (Vaswani 2017) with Q/K/V/O projections, scaled dot-product, head split/merge, optional additive mask, and full backward through softmax + linear projections; sinusoidal (fixed) and learnable (Xavier-init) positional encoding with backward for learnable variant; Pre-Norm Transformer block (LN → MHA → + → LN → FFN(GELU) → +) with full BPTT-style backward; attention mask utilities (causal mask + head-broadcast + allowed-keys → additive mask); inverted dropout regularisation (Bernoulli mask with 1/(1-p) scale, training/inference mode toggle); Spiking Self-Attention (SpikeFormer-style) that replaces softmax along key axis with fast-sigmoid surrogate from v0.22.0, with full BPTT-compatible backward using the surrogate gradient; Pre-Norm Spiking Transformer block (LN → SpikingAttention → + → LN → FFN(GELU) → +) demonstrating the full SNN-Transformer training pipeline; Mini-SpikeFormer training demo (synthetic 28×28 dataset + patch embedding + learnable class token + SpikingTransformerBlock + classifier + cross-entropy + per-parameter gradient clipping + SGD); exact (sparse) GELU activation `x · Φ(x)` via libm `erff` for the cumulative normal distribution; Adafactor optimizer (Shazeer 2018) with factorised second-moment estimation for memory-efficient 2D + 1D updates; LayerScale (Touvron 2021) per-channel learnable scale γ (init=1e-4) on residual branches for stable training of deep transformers; T5-style relative position bias (Raffel 2020) added directly to attention scores per (head, offset) with linear-bucket clamping; consolidated SAttention module (sattention.mbt) unifying three spiking attention variants — SpikingMultiHeadAttention (multi-head self-attention, default), SpikingSelfAttention (single-head convenience), SpikingCrossAttention (cross-attention with separate Q/KV inputs) — all using fast-sigmoid forward + surrogate backward from v0.22.0; SRNN training demo (CSNN-style) with Poisson-encoded 2D images → T-step IF state evolution → linear readout → softmax + cross-entropy + BPTT through time using fast_sigmoid_surrogate; SCNN v2 with full K-step SGD training loop, per-layer gradient clipping, and accuracy tracking on the synthetic dataset. Float32 end-to-end with libm FFI (expf, tanhf, logf, sqrtf, cosf, sinf, erff). 1177 tests passing, 76 examples ported from Julia.
Dependencies
| Component | Status | Notes | ||||||
|---|---|---|---|---|---|---|---|---|
| Unit system | 鉁?done | 30+ Float32 unit constants; units_test.mbt (8 tests pass) | ||||||
| Time struct | 鉁?done | t, tt, dt; update_time etc. (4 tests pass) | ||||||
| Xoshiro RNG | 鉁?done | xoshiro256++ (NOT **); Float32/Float64 paths match Julia (5 tests pass) | ||||||
| Native math FFI | 鉁?done | expf, tanhf, logf via libm; sigmoid_f32 derived (5 tests pass) | ||||||
| math.ln/cos/sin | 鉁?done | Required for Box-Muller in IZ init; via moonbitlang/core/math | ||||||
| IF neuron | 鉁?done | Forward-Euler update; DoubleExpSynapse state; IFParameter::with_el (4 tests pass) | ||||||
| IF + Gsyn (Duarte2019 / LKD2014) | 鉁?done | neuron_if_gsyn.mbt 鈥?port of IFParameterGsyn from refs/SNNModels.jl/src/populations/generized_if/if.jl. IFParameterGsyn { base : IFParameter, gsyn_e : Float, gsyn_i : Float } wraps IFParameter + population-wide synaptic conductance scales. IF::with_gsyn(n, base, gsyn_e, gsyn_i, rng) convenience constructor + IFParameterGsyn::apply(p) setter that propagates the population scale to every neuron's gsyn_e[i] / gsyn_i[i] array (5 tests pass) | ||||||
| AdEx neuron | 鉁?done | Brette-Gerstner 2005 defaults; exponential term via expf; AdExParameter::with_vr (5 tests pass) | ||||||
| IZ (Izhikevich) | 鉁?done | Two half-step midpoint Euler; ge/gi decay; v > 30 reset; fs() constructor (4 tests pass) | ||||||
| HH (Hodgkin-Huxley) | 鉁?done | m/n/h gating with sigmoid+expf; Na/K currents; v > -20 reset (2 tests pass) | ||||||
| MorrisLecar | 鉁?done | tanhf-based activation; K recovery w; v > 20 reset (3 tests pass) | ||||||
| Poisson (population) | 鉁?done | fire[i] = rand(Float32) < rate*dt; rate matches frequency (3 tests pass) | ||||||
| InhomogeneousPoisson (variable-rate) | 鉁?done | neuron_inhomogeneous_poisson.mbt 鈥?port of inhomogeneous_poisson.jl (Julia's VariablePoisson). InhomogeneousPoissonParam{beta, tau, r0, rate_timescale} + InhomogeneousPoisson::new(n, param, rng) + step_inhomogeneous_poisson(p, dt, rng) (Ornstein-Uhlenbeck noise + rate adaptation toward r0; bit-exact integration) (7 tests pass) | ||||||
| PoissonStimulus | 鉁?done | Knuth's algorithm; Float32 位; mean verified 鈮?位 (3 tests pass) | ||||||
| CurrentStimulus | 鉁?done | Direct current injection with optional Gaussian noise; set_active, set_i_base (3 tests pass) | ||||||
| SpikeTimeStimulus | 鉁?done | SpikeTimeParameter(spiketimes, neurons) (auto-sorted) + SpikeTimeStimulus::new(pop, sym, ...) + stimulate_spiketime(s, t, w). Wired into compose via TimedStim_(stim, w) (4 tests pass) | ||||||
| CurrentStimulusArray | 鉁?done | Generic current injection into raw Array[Float] for any population | ||||||
| WilsonCowan rate model | 鉁?done | x += dt*(-x+g+I); r=tanhf(x); init Normal(0, 0.5); g reset (5 tests pass) | ||||||
| RateSynapse | 鉁?done | CSR forward_rate: g[post] += w * rJ[pre]; weights Normal(0, 渭/鈭?pN)) | ||||||
| AnyPop dispatcher | 鉁?done | Enum-based heterogeneous sim loop; includes WC_, PoissonIF_, CurrentIF_, CurrentArr_ (3 tests pass) | ||||||
| AnyStim dispatcher | 鉁?done | PoissonIF_, CurrentIF_ variants; stimulate_any dispatch | ||||||
| Monitor sr | 鉁?done | Monitor::new_v_sr(pop, n, sr_hz) honours rec_step = 1/(sr*dt) (4 tests pass) | ||||||
| vecplot text dump + ascii_plot | 鉁?done | count_spikes, count_spikes_interval, dump_summary, dump_csv_stdout, duration, ascii_plot(width?, height?), firing_rate, firing_rate_interval, spike_times, mean, min, max (17 tests pass) | ||||||
| SparseMatrixCSR | 鉁?done | from_dense, random, random_with_rule, set, get, forward, forward_rate (10 tests pass). Subset port of sparse_matrix_test.jl (matrix_size / get / set / nnz / bulk-set) in sparse_matrix_extra_test.mbt (8 tests pass) | ||||||
| Population analysis | 鉁?done | analysis_populations.mbt 鈥?port of populations.jl (subset). PopIndex struct (1-based inclusive ranges) + population_indices(pops) (assigns non-overlapping ranges) + filter_items(pops) (default drops "noise*" labels) + filter_items_with(pops, rule) (named FilterRule enum: Greater / Less / Equal / DropNoise; MoonBit lacks first-class fn refs) + average_conn_strength(M, pops, 渭) (block-mean / 渭 of dense weight matrix) (13 tests pass) | ||||||
| ConnectRule enum | 鉁?done | Bernoulli, FixedIn, FixedOut rules (3 tests pass) | ||||||
| SpikingSynapse (CSR) | 鉁?done | new, random, random_with_rule, random_with_delays (delay_dist), spiking_connect, set_constant_delay, init_rho (Markram STP), forward_synapse, deliver_pending_synapse. Pending-event queue drains scheduled spikes at delivery time. v0.10.57: added name field (mirrors Julia's name kwarg) + with_name setter (returns new struct). EmptyConnection placeholder (no-op, mirrors Julia's EmptySynapse) (10 tests pass in connection_spiking_extra_test.mbt) | ||||||
| Conv2d (NCHW forward) | 鉁?done | conv2d.mbt 鈥?NCHW row-major flat Array[Float] conv2d forward. Conv2dParam { weight, bias, c_out, c_in, kh, kw, stride, pad }; Conv2dParam::new with optional stride=1, pad=0 defaults; conv2d_forward(input, n, c_in, h, w, param) -> Array[Float] returns [n, c_out, ho, wo] flat. Naive CPU loop (no im2col/matmul yet). 9 tests in conv2d_test.mbt (1x1 conv, 3x3 valid 5x5 -> 3x3, same-pad preserves shape, multi-channel in/out + stride=2 downsample, batch N=2, 1x1 multi-channel out-ch=2, all-zero input -> bias broadcast, 3x3 valid 4x4 known center pixel + bias, 3x3 box-blur sums window) | ||||||
| MaxPool2d (NCHW forward) | 鉁?done | maxpool2d.mbt 鈥?NCHW row-major flat Array[Float] max-pool forward. MaxPool2dParam { kh, kw, stride, pad }; MaxPool2dParam::new(kh, kw, stride?, pad?) with stride defaulting to kh; maxpool2d_forward(input, n, c, h, w, param) -> Array[Float] returns [n, c, ho, wo] flat. Out-of-bounds positions treated as -inf so padding never wins the max. 8 tests in maxpool2d_test.mbt (2x2 non-overlapping, stride=1 overlapping, multi-channel per-channel max, batch N=2, pad=1 + stride=2 on 4x3, all-negative picks least-negative, 3x3 stride=1 on 5x5 diagonal, 3x3 on 5x5 single-corner pick) | ||||||
| ReLU | ✅ done | relu.mbt — element-wise max(x, 0). relu_forward(input : Array[Float]) -> Array[Float] returns a new array (does not mutate input). 4 tests in relu_test.mbt (mixed pos/neg / all-pos unchanged / all-neg -> zero / no-mutation) | ||||||
| Flatten (NCHW → (N, C·H·W)) | ✅ done | flatten.mbt — flatten_forward(input, n, c, h, w) -> Array[Float] returns flat array of length n*c*h*w. No data movement: NCHW row-major index (n, c*H*W + h*W + w) already matches the (n, c*h*w) row-major layout, so the output is a copy of the input. 3 tests in flatten_test.mbt (single-channel / multi-channel / batch N=2) | ||||||
| Linear (dense / fully-connected) | ✅ done | linear.mbt — LinearParam { weight, bias, in_features, out_features } + LinearParam::new(weight, bias, in_features, out_features) builder; linear_forward(input, n, param) -> Array[Float] returns [n, out_features]. Per-batch matvec + bias. 5 tests in linear_test.mbt (single-batch matvec+bias / batch N=3 / zero input -> bias / zero weight -> bias / single-output scalar projection) | ||||||
| CNN forward chain (Conv → ReLU → MaxPool → Flatten → Linear) | ✅ done | cnn_chain_test.mbt — end-to-end mini-CNN forward pass test. Verifies shape flow (4x4 image -> Conv2d -> ReLU -> MaxPool2d -> Flatten -> Linear produces a 3-element output vector) and bit-exact repeatability. 2 tests (full chain on 4x4 / bit-exact repeat on 3x3) | ||||||
| ReLU backward | ✅ done | relu_backward.mbt — relu_backward(input, d_output) -> Array[Float]; d_input[i] = d_output[i] if input[i] > 0 else 0. 4 tests in relu_backward_test.mbt (pass-through / zero-where-inactive / no-mutation / gradient check vs numerical) | ||||||
| Flatten backward | ✅ done | flatten_backward.mbt — identity copy (NCHW layout is already collapseable). 3 tests in flatten_backward_test.mbt | ||||||
| Linear backward | ✅ done | linear_backward.mbt — linear_backward(input, d_output, n, param) -> (d_input, d_weight, d_bias). d_weight via outer product, d_bias via sum, d_input via weight matvec. 4 tests in linear_backward_test.mbt (single-batch known / N=2 batch / d_input gradient check / d_weight gradient check) | ||||||
| MaxPool2d backward | ✅ done | maxpool2d_backward.mbt — maxpool2d_forward_with_idx(input, n, c, h, w, param) -> (output, argmax_idx) records argmax indices during forward; maxpool2d_backward(d_output, argmax_idx, n, c, h, w, param) -> d_input routes gradient to argmax positions only. 4 tests in maxpool2d_backward_test.mbt | ||||||
| Conv2d backward | ✅ done | conv2d_backward.mbt — conv2d_backward(input, d_output, n, c_in, h, w, param) -> (d_input, d_weight, d_bias). Three accumulated gradients via 7-nested loops. 6 tests in conv2d_backward_test.mbt (d_bias known / 1x1 d_weight / 1x1 d_input / d_input gradient check / d_weight gradient check / d_bias known) | ||||||
| CNN backward chain (Conv → ReLU → MaxPool → Flatten → Linear) | ✅ done | cnn_backward_chain_test.mbt — end-to-end mini-CNN backward. Hand-stitches each layer's backward. Verifies d_input and d_weight against numerical gradients (eps=1e-3, tol=1e-2) and bit-exact repeat across re-runs. 3 tests (d_input gradient check / bit-exact re-run / d_weight gradient check) | ||||||
| Numerical gradient check helper | ✅ done | gradient_check.mbt — numerical_gradient(input, eps, forward) central-difference helper + max_abs_diff(a, b) comparison. Reused by all backward tests | ||||||
| Tensor struct + elementwise ops + broadcasting | ✅ done | tensor.mbt — Tensor { data, shape } struct (row-major flat Array[Float]); Tensor::zeros / Tensor::ones / Tensor::from / Tensor::reshape / Tensor::numel. Element-wise: tensor_add / tensor_sub / tensor_mul / tensor_div with right-aligned broadcasting (scalar / row / column broadcast). 9 tests in tensor_test.mbt (zeros / ones / reshape / add same-shape / add scalar / add row vector / add col vector / sub-mul-div / no-alias) | ||||||
| Tensor matmul + softmax + log_softmax | ✅ done | tensor_ops.mbt — tensor_matmul(a, b) 2D matmul (naive O(mnk)); tensor_softmax(x) numerically-stable softmax along last axis (subtract-max trick); tensor_log_softmax(x) log-softmax. Uses libm expf / logf via FFI. 9 tests in tensor_ops_test.mbt (matmul 2x3×3x2 / identity / 1x1 / softmax uniform / softmax translation-invariant / softmax batched / log_softmax roundtrip / log_softmax sum=1 / matmul all-ones × values) | ||||||
| Cross-entropy loss | ✅ done | cross_entropy.mbt — CrossEntropyLoss { mean : Tensor, per_batch : Tensor } struct; cross_entropy_loss(log_probs, targets) -> CrossEntropyLoss returns mean + per-batch loss. 4 tests in cross_entropy_test.mbt (perfect predictions / uniform / batch mixed / softmax+cross_entropy pipeline) | ||||||
| Image adapter (BMP/QOI/TGA/PNG/GIF/JPEG/ICO/TIFF) | ✅ done | image.mbt — 4D NCHW Float32 Image { data, n, c, h, w } plus image_from_bytes(bytes) -> Image raise DecodeError (auto-detect format via riantr/moonbit_image@0.3.4), image_from_moonbit_image(img) (3-channel RGB), image_from_moonbit_image_rgba(img) (4-channel with alpha). Encode path not exposed — upstream's PixelFormat enum variants are read-only from outside the package, so users wanting to write image files call upstream directly. 4 tests in image_test.mbt (zeros shape / 24-bit BMP 2x2 round-trip with 4 distinct pixels / uniform 4x4 BMP / RGBA alpha=1.0 for opaque) | ||||||
| STImage 5D [T, B, C, H, W] tensor | ✅ done | spatio_temporal.mbt — 5D Float32 STImage { data, t, b, c, h, w } for spiking-CNN time-series input. Row-major flat Array[Float] of length T*B*C*H*W; flat offset t * (B*C*H*W) + b * (C*H*W) + c * (H*W) + h * W + w. Helpers: STImage::zeros / shape / numel / frame_block / batch_slice / offset / get / set / get_frame(t) (returns 4D Image { n: 1, c, h, w }, ready for v0.11.x Conv2d/MaxPool2d) / get_batch(b) (returns 4D Image { n: T, c, h, w }, time-flattened for vSTDP) / STImage::from_frames(frames) (stack [N=1, C, H, W] images along new T axis) / st_image_concat_t(a, b) (concatenate along T) / st_image_repeat_t(img, t) (broadcast a single image across T). 9 tests in spatio_temporal_test.mbt (zeros / flat offset computation / set-get round-trip / get_frame independence + no alias / get_batch time-flatten / from_frames stacking / concat_t ordering / repeat_t identical frames / Float32 bit-exact round-trip) | ||||||
| SGD optimiser (vanilla + momentum) | ✅ done | optimizer_sgd.mbt — generic array-level sgd_update_arrays(weight, bias, d_weight, d_bias, lr) plus SGDMomentumState { v_w, v_b } for SGD-with-momentum (PyTorch convention: v <- momentum * v + g; param <- param - lr * v). Layer wrappers sgd_update_linear / sgd_update_conv and momentum wrappers sgd_momentum_update_linear / sgd_momentum_update_conv return fresh parameter structs (immutable update). 9 tests in optimizer_sgd_test.mbt (vanilla step / zero-gradient no-op / no-alias / Linear wrapper preserves shape / Conv wrapper preserves stride+pad / first momentum step = SGD with v=0 / second step accumulates velocity / momentum=0 == vanilla SGD / loss monotonically decreases on y=2x+1 fit, 200 steps) | ||||||
| Adam optimiser (with bias correction) | ✅ done | optimizer_adam.mbt — AdamState { m_w, v_w, m_b, v_b : Array[Float]; step : Int } with adam_init(weight_len, bias_len), adam_next_step(state) accessor, adam_update_arrays(...) (PyTorch convention: m <- beta1*m + (1-beta1)*g; v <- beta2*v + (1-beta2)*g^2; m_hat <- m/(1-beta1^t); v_hat <- v/(1-beta2^t); param <- param - lr*m_hat/(sqrt(v_hat)+eps)). Layer wrappers adam_update_linear / adam_update_conv. sqrtf Float32 FFI added (was missing from math_native.mbt). 9 tests in optimizer_adam_test.mbt (zero state / next_step no-mutation / first step moves param in correct direction / 600-step linear regression converges w→2 b→1 / step counter monotonic via returned state / zero gradient = no-op / Linear shape preserved / Conv shape preserved with stride+pad) | ||||||
| AdamW optimiser (decoupled weight decay) | ✅ done | optimizer_adamw.mbt — AdamWState { m_w, v_w, m_b, v_b : Array[Float]; step : Int } (same shape as AdamState) with adamw_init, adamw_update_arrays (Loshchilov & Hutter 2019 convention: decoupled param <- param - lr*(m_hat/(sqrt(v_hat)+eps) + weight_decay*param), where weight_decay acts on the raw parameter not on the gradient). Layer wrappers adamw_update_linear / adamw_update_conv. 7 tests in optimizer_adamw_test.mbt (zero state / weight_decay=0 matches Adam direction / large weights shrink more absolutely than small weights under zero gradient / step counter via returned state / 600-step linear regression converges with mild decay / Linear shape / Conv shape) | ||||||
| RMSprop optimiser | ✅ done | optimizer_rmsprop.mbt — RMSpropState { v_w, v_b } (no first moment, no bias correction — Hinton 2012 lecture 6e form) with rmsprop_init, rmsprop_update_arrays (v <- alpha*v + (1-alpha)*g^2; param <- param - lr*g/(sqrt(v)+eps)). Layer wrappers rmsprop_update_linear / rmsprop_update_conv. 7 tests in optimizer_rmsprop_test.mbt (zero state / first step moves param in negative-gradient direction / alpha=0 ≈ raw gradient sign / large gradient gets shrunk by adaptive scaling / 600-step linear regression converges w→2 b→1 / Linear shape / Conv shape) | ||||||
| AdaGrad optimiser | ✅ done | optimizer_adagrad.mbt — AdaGradState { v_w, v_b } with adagrad_init, adagrad_update_arrays (Duchi et al. JMLR 2011: v <- v + g^2; param <- param - lr*g/(sqrt(v)+eps). Accumulating sum, not EMA — v monotonically grows, so effective per-parameter learning rate shrinks over time. Sparse-feature friendly; can stagnate on dense problems.) Layer wrappers adagrad_update_linear / adagrad_update_conv. 7 tests in optimizer_adagrad_test.mbt (zero state / first step moves in negative-gradient direction / v accumulates g^2 monotonically (not EMA) / per-parameter effective lr monotonically shrinks / 1500-step linear regression converges w→2 b→1 / Linear shape / Conv shape) | ||||||
| BatchNorm2d (NCHW, with running stats) | ✅ done | batch_norm2d.mbt — BatchNorm2d { gamma, beta, mut running_mean, mut running_var, momentum, eps, mut training }. Forward batch_norm2d_forward(input, n, c, h, w, bn) -> (output, BatchNormCache); backward batch_norm2d_backward(d_output, cache, bn) -> (d_input, d_gamma, d_beta). Per-channel batch stats in training mode (across nhw), running stats for inference. PyTorch convention EMA on running stats: running <- (1 - momentum) * running + momentum * batch. Population variance (no Bessel correction). 8 tests in batch_norm2d_test.mbt (output shape / per-channel mean~0 std~1 / gamma/beta affine / running stats EMA update / backward shapes / zero d_output no-op / d_input numerical-gradient check). | ||||||
| LayerNorm (per-sample, no running stats) | ✅ done | layer_norm.mbt — LayerNorm { gamma, beta, eps, c, h, w }. Forward layer_norm_forward(input, n, c, h, w, ln) -> (output, LayerNormCache); backward layer_norm_backward(d_output, cache, ln) -> (d_input, d_gamma, d_beta). Per-sample statistics (across chw). gamma/beta have shape [c*h*w] (per-feature). No running stats — deterministic at inference. 8 tests in layer_norm_test.mbt (output shape / per-sample mean~0 std~1 / different samples normalised independently / gamma/beta affine / backward shapes / zero d_output no-op / d_input numerical-gradient check). | ||||||
| Learning-rate schedulers (StepLR + ExponentialLR + CosineAnnealingLR + ReduceLROnPlateau) | ✅ done | scheduler.mbt — 4 schedulers sharing the step(s) -> Float / next(s) -> S API (state is not mutated; caller threads the returned state). StepLR::new(base_lr, step_size, gamma) drops lr by gamma every step_size steps; ExponentialLR::new(base_lr, gamma) does continuous exponential decay; CosineAnnealingLR::new(eta_max, eta_min, t_max) follows a half-cosine from eta_max to eta_min over t_max steps (wraps and repeats). ReduceLROnPlateau::new(base_lr, factor, patience, threshold) is reactive: feeds step(metric) returns (new_lr, new_state), drops lr by factor after patience consecutive non-improving calls (PyTorch convention with threshold-filtered improvements). cosf Float32 FFI added. 10 tests in scheduler_test.mbt (StepLR: step 0 = base, drops at step_size boundaries, next() does not mutate; ExponentialLR: lr = base*gamma^t; CosineAnnealingLR: t=0 -> eta_max, t=T_max/2 -> midpoint, monotonic decrease in first half; ReduceLROnPlateau: first call records metric, improvement resets bad counter, patience exhausted triggers decay, threshold prevents micro-improvements). | ||||||
| Generic Chain / Sequential (tagged-enum dispatch) | ✅ done | chain.mbt — Layer enum (Conv2d / ReLU / MaxPool2d / Flatten / Linear / BatchNorm2d / LayerNorm) + public Layer::conv2d / relu / max_pool2d / flatten / linear / batch_norm2d / layer_norm constructor helpers (MoonBit enum variants are read-only from other files). chain_forward(layers, input, n, c, h, w) -> (output, Array[LayerCache], n, c, h, w) runs layers in order, tracking shape transitions; chain_backward(layers, caches, d_output, n, c, h, w) -> (d_input, Array[LayerGrad]) runs them in reverse, returning per-layer LayerGrad enum (Linear(d_w, d_b) / Conv2d(d_w, d_b) / BatchNorm2d(d_g, d_b) / LayerNorm(d_g, d_b) / Empty / MaxPool2d). 7 tests in chain_test.mbt (empty chain / MLP forward / MLP backward with shape + grads / CNN Conv-ReLU-Pool-Flatten-Linear / zero d_output no-op / d_input numerical-gradient check vs central differences with non-zero pre-ReLU activations / BN inside MLP). | ||||||
| Pre-made bottles (MLP / SimpleCNN / LeNet5) | ✅ done | bottles.mbt — three ready-to-train architectures built on top of v0.19.0 Chain with He-init (sqrt(2/fan_in)) + Float32 Box-Muller via libm cosf/sinf/logf + xoshiro RNG seeded by caller for reproducibility. (1) MLP::new(sizes=[in,h1,...,out], seed) — sizes-matched Linears with ReLU between every pair (no ReLU after the final); mlp_forward / mlp_backward / MLP::num_params. (2) SimpleCNN::new(in_c, c1, c2, seed) — Conv-ReLU-Pool × 2 → Flatten → FC(10) for 28x28 inputs. (3) LeNet5::new(seed) — classic LeNet-5 (C1: 1->6 5x5, S2: MaxPool 2x2, C3: 6->16 5x5, S4: MaxPool 2x2, C5: 16->120 5x5, F6: 120->84, Out: 84->10). 10 tests in bottles_test.mbt (MLP: layer count, reproducible seed, different seeds differ, num_params, forward shape, backward shape + grad variants; SimpleCNN: forward shape + 8 caches; LeNet5: forward shape + 12 caches + zero d_output zero d_input + zero grads). | ||||||
| Elementwise Add | ✅ done | elementwise_add.mbt — add_forward(a, b) -> Array[Float] elementwise (no aliasing); add_backward(d_output) -> (d_a, d_b) returns two independent copies. 5 tests (elementwise sum / no alias / zero-tensor identity / backward independence / gradient flow). | ||||||
| AvgPool2d + GlobalAvgPool2d | ✅ done | avgpool2d.mbt — AvgPool2dParam::new(kh, kw, stride?, pad?) + avgpool2d_forward / avgpool2d_backward (count_include_pad=True: divisor is kh*kw regardless of pad). global_avg_pool2d_forward(input, n, c, h, w) -> Array[Float] pools to [n, c] (ResNet terminal pool); global_avg_pool2d_backward distributes gradient uniformly. 8 tests (output shape / 2x2 average / per-channel independence / single-pool gradient / overlapping pools accumulate / GAP shape / GAP backward uniform / GAP round-trip). | ||||||
| ResidualBlock (basic + projection) | ✅ done | residual_block.mbt — ResidualBlock struct with optional 1x1 conv + BN projection shortcut. ResidualBlock::identity(c, seed) for same-shape stacks; ResidualBlock::projection(c_in, c_out, stride, seed) for downsample blocks. residual_block_forward(b, x, n, c, h, w) -> (out, ResidualCache) runs conv1 → bn1 → relu → conv2 → bn2 → add(shortcut) → relu, caching sum and bn1_out for backward; residual_block_backward(b, cache, d_output) -> (d_input, ResidualGrads) runs the full reverse path including the shortcut BN/conv and merges d_x_main + d_x_shortcut. 5 tests (identity forward shape / zero d_output no-op / projection forward halves spatial / projection backward d_input shape + shortcut grads populated / conv1 weight numerical gradient check vs central differences). | ||||||
| Surrogate gradient (fast sigmoid) | ✅ done | surrogate.mbt — Zenke & Ganguli 2018 fast-sigmoid surrogate for BPTT through IF / LIF Heaviside spikes. fast_sigmoid_surrogate(x, beta) -> Float is the backward surrogate σ'(x) = 1 / (1 + β· | x | )²; peak σ'(0) = 1, symmetric, decays as | x | → ∞. fast_sigmoid_forward(x, beta) -> Float is the soft differentiable forward s(x) = x / (1 + β· | x | ) saturating to ±1/β. heaviside_step(x, vt) -> Float is the hard 0/1 forward spike (matches the IF neuron step exactly). fast_sigmoid_surrogate_array / fast_sigmoid_forward_array elementwise forms. spike_surrogate(u, vt, beta) -> SpikeSurrogate combined envelope that returns both spike : Array[Float] (hard 0/1) and grad : Array[Float] (surrogate) in one pass — avoids recomputing u - vt in BPTT loops. 7 tests (peak=1 + symmetry + decay / β controls width + σ'(1/β)=0.25 invariant / soft forward monotonicity + saturation at ±1/β / elementwise consistency + peak-index / antisymmetric input / hard step at threshold / spike_surrogate combined envelope). |
| GELU activation (tanh approximation) | ✅ done | gelu.mbt + gelu_backward.mbt — Gaussian Error Linear Unit for transformer FFN. gelu(x) ≈ 0.5·x·(1 + tanhf(√(2/π)·(x + 0.044715·x³))) (matches PyTorch's F.gelu(approximate='tanh')). gelu_grad(x) = 0.5·(1 + t) + 0.5·x·sech²(inner)·√(2/π)·(1 + 3·0.044715·x²). gelu_forward(input) -> Array[Float] and gelu_backward(input, d_output) -> Array[Float]. 6 tests (origin=0 + saturation at ±5 + gelu(±1)≈±0.1587/0.8413 / grad(0)=0.5 + positive-side steeper + saturation at ±5 / element-wise consistency + no-mutation / gradient check vs central difference / element-wise backward + zero d_output no-op). | ||||||
| Multi-Head Self-Attention | ✅ done | multi_head_attention.mbt — Vaswani 2017 standard MHA. MultiHeadAttention { d_model, num_heads, d_k, w_q, w_k, w_v, w_o } with MultiHeadAttention::new(d_model, num_heads, seed) (Xavier-normal init via Float32 Box-Muller + zero bias). multi_head_attention_forward(x, mha, mask) -> (out, AttnCache) self-attention: Q/K/V linear projections → per-head scaled dot-product q@k^T/sqrt(d_k) → optional additive mask → softmax along key axis → weighted sum → head merge → W_o projection. multi_head_attention_backward(cache, d_output, mha) -> (d_x, MHAGrad) full reverse path including softmax backward (d_scores = w*(d_w - w·d_w)), per-head Q/K gradient accumulation, and 3× linear backward (Q/K/V) summed into d_x. 8 tests (shape / softmax sum-to-1 / deterministic same-seed / different-seed independence / masked positions contribute zero weight + sum-to-1 / d_x+d_weight+d_bias shapes / zero d_output no-op / gradient check vs central difference on w_o[0]). | ||||||
| Position encoding (sinusoidal + learnable) | ✅ done | position_encoding.mbt — two complementary encodings for transformer input. (1) sinusoidal_position_encoding(max_len, d_model) -> Array[Float] non-trainable PE table with PE[pos, 2i] = sin(pos / 10000^(2i/d_model)) and PE[pos, 2i+1] = cos(...) (Vaswani 2017 §3.5). (2) PositionalEmbedding { max_len, d_model, weight } learnable parameter struct + PositionalEmbedding::new(max_len, d_model, seed) with Xavier-normal init via Float32 Box-Muller + positional_embedding_forward(pe, seq_len) -> Array[Float] slicing + positional_embedding_backward(pe, d_output, seq_len) -> Array[Float] (only active positions accumulate gradients). 5 tests (sinusoidal shape + boundary PE[0,*] = 0/1 / parity (even=sin, odd=cos) + determinism + distinct positions / learnable shape + determinism + non-zero init / forward slicing correctness + backward active-position routing). | ||||||
| Transformer block (Pre-Norm) | ✅ done | transformer_block.mbt — Pre-Norm sub-layer stack: x2 = x + MHA(LN1(x)); out = x2 + FFN(LN2(x2)) where FFN(h) = Linear2(GELU(Linear1(h))) and d_ff defaults to 4·d_model. TransformerBlock { d_model, num_heads, d_ff, ln_1, ln_2, mha, ffn_w1, ffn_w2 } (LN gamma=1, beta=0 by default; FFN Xavier-normal). transformer_block_forward(x, block, mask) -> (out, TransformerBlockCache) composes LN → MHA → residual → LN → Linear → GELU → Linear → residual. transformer_block_backward(cache, d_output, block) -> (d_x, TransformerBlockGrad) walks 7 reverse steps including two residual splits and the cross-residual gradient accumulation. 7 tests (constructor shape + default d_ff=4·d_model / custom d_ff override / forward shape preservation + cache sanity / same-seed determinism / backward shapes including LN gamma/beta / zero d_output → zero d_x + zero all 8 grad arrays / gradient check vs central difference on ffn_w2[0]). | ||||||
| Attention mask utilities | ✅ done | attention_mask.mbt — additive mask helpers for MHA. causal_mask(seq_len) -> Array[Float] upper-triangular -1e9 mask for autoregressive attention. mask_broadcast(mask_2d, seq_len, num_heads) replicates (seq_len × seq_len) → (num_heads × seq_len × seq_len). mask_from_allowed(seq_len, allowed : Array[Array[Bool]]) arbitrary boolean-table → additive mask (0 allowed, -1e9 blocked). causal_mask_heads(seq_len, num_heads) convenience: causal directly broadcast to per-head. 5 tests (shape + diagonal=0 + above=-1e9 / row 0 only attends to self / mask_broadcast shape + values replicated across heads / mask_from_allowed arbitrary boolean matrix / causal end-to-end via MHA: position i weights[j]=0 for j>i and row sum=1). | ||||||
| Dropout (inverted) | ✅ done | dropout.mbt — Dropout { p, mut training } (pub(all) for cross-file mut) with Dropout::new(p? = 0.5). dropout_forward(input, d, rng) -> (out, mask) returns the per-element Bernoulli mask + scaled activations (training) or identity (inference). dropout_backward(d_output, mask, d) -> Array[Float] reuses the same mask for the backward (so gradient corresponds to actual sparse activations). 8 tests (defaults + out-of-range guard / inference identity / training keeps ~p=0.5 fraction of n=1000 + 1/(1-p) inverted scale / same-seed determinism / p=0 no-op identity / p=1 all-zero / backward matches forward (mask × scale) + zero d_output no-op / inference backward identity). | ||||||
| Spiking Self-Attention (SpikeFormer-style) | ✅ done | spiking_attention.mbt — standard MHA structure (Q/K/V/O Linear projections + scaled dot-product) but replaces softmax along key axis with the fast_sigmoid_forward from v0.22.0. weights = fast_sigmoid_forward(scores, beta) range (-1/β, 1/β). Backward uses fast_sigmoid_surrogate (peak 1 at x=0, decays at | x | →∞) — this is the BPTT-compatible gradient that lets the spike emit non-zero learning signal. SpikingAttention { d_model, num_heads, d_k, beta, w_q, w_k, w_v, w_o } + SpikingAttention::new(d_model, num_heads, beta, seed) (Xavier-normal init) + spiking_attention_forward(x, sa, mask) -> (out, SpikingAttnCache) + spiking_attention_backward(cache, d_output, sa) -> (d_x, MHAGrad) (reuses MHAGrad since structure is identical). 8 tests (constructor shapes / output shape + weights bounded in (-1/β, 1/β) / weights = fast_sigmoid_forward(scores, β) / mask blocks positions / zero d_output → zero d_x + zero grads / gradient check vs central difference on w_o[0] / gradient check on w_q[0] / zero input + large beta → zero weights). | ||||
| Spiking Transformer block (Pre-Norm) | ✅ done | spiking_transformer_block.mbt — Pre-Norm sub-layer stack using SpikingAttention instead of MultiHeadAttention: x2 = x + SpikingAttn(LN1(x)); out = x2 + FFN(LN2(x2)). SpikingTransformerBlock { d_model, num_heads, d_ff, beta, ln_1, ln_2, sa, ffn_w1, ffn_w2 } + SpikingTransformerBlock::new(d_model, num_heads, beta, seed, d_ff? = 4*d_model). spiking_transformer_block_forward / _backward mirrors the standard TransformerBlock but routes through spiking_attention_backward instead of multi_head_attention_backward. 6 tests (constructor + default d_ff / forward shape preservation + cache sanity / same-seed determinism / zero d_output → zero d_x + zero all 8 grad arrays / gradient check on ffn_w2[0] / gradient check on sa.w_q[0]). | ||||||
| AdEx SpikingSynapse (CSR) | 鉁?done | new, random, random_with_rule; supports :ge/:he/:gi/:hi/:gaba routing | ||||||
| ReceptorSynapse (4-receptor routing) | 鉁?done | connection_receptor.mbt 鈥?port of ReceptorSynapse.jl (subset). Per-edge target_receptor : Array[Int] parallel to matrix.colptr selects which of the 4 receptors (AMPA/NMDA/GABAa/GABAb) each edge targets. forward_receptor_synapse(s) routes spike weights into s.glu[k] (if target in glu_receptors = [0, 1]) or s.gaba[k] (if in gaba_receptors = [2, 3]). set_target_receptor(s, idx, r) re-targets edge idx (5 tests pass) | ||||||
| SpikingSynapseIZ (CSR) | 鉁?done | IZ-targeting: :ge/gi routed directly into post.ge/post.gi (no DoubleExp rise) (4 tests pass) | ||||||
| SpikingSynapseHH (CSR) | 鉁?done | HH-targeting: same structure as SpikingSynapseIZ | ||||||
| STDP (Gerstner 1996) | 鉁?done | STDPGerstner params + STDPVariables traces + stdp_step mutating weights. Auto-integrated into compose layer via STDPEntry. gerstner_kernel(螖t, ...) for visualising the 螖W curve. stdp_kernel_plot(param) ASCII plot (11 tests pass) | ||||||
| STDP (MexicanHat) | 鉁?done | STDPMexicanHat params + mexican_hat_kernel(x) pure fn + stdp_mexican_hat_step (pre-spike + post-spike passes; trace decay via dt * -x/蟿). stdp_mexican_hat_plot ASCII viz. Auto-integrated into compose layer via STDPEntryMexicanHat + STDPEntryKind::MexicanHat_ (5+1 tests pass) | ||||||
| STDP (AntiSymmetric) | 鉁?done | STDPAntiSymmetric params + STDPAntiSymmetricVariables (tr_x, to_y) + stdp_antisymmetric_step (pre-spike pass uses to_y[i], post-spike pass uses tr_x[j]). stdp_antisymmetric_plot ASCII viz. Auto-integrated into compose layer via STDPEntryAntiSymmetric + STDPEntryKind::AntiSymmetric_ (5+1 tests pass) | ||||||
| STDPEntryKind enum | 鉁?done | pub(all) enum STDPEntryKind { Gerstner_(STDPEntry), MexicanHat_(STDPEntryMexicanHat), AntiSymmetric_(STDPEntryAntiSymmetric) }. Replaces the previously-hardcoded STDPEntry in HeterogeneousModel.stdp_entries (1 smoke test) | ||||||
| STP (Markram 1998) | 鉁?done | MarkramSTPParameter (蟿D/蟿F/U/Wmax/Wmin) + MarkramSTPVariables (u/x/rho_pre/last_spike/active per pre) + markram_stp_step (event-based update_traces!: u=x=1 recovery via exp, then u+=U*(1-u)/x-=u*x bump) + init_rho on SpikingSynapse + 蟻-broadcast to outgoing edges. Auto-integrated into compose layer via STPEntryKind::MarkramSTP_ (12 tests pass) | ||||||
| STPEntryKind enum | 鉁?done | pub(all) enum STPEntryKind { MarkramSTP_(MarkramSTPEntry) | MarkramSTPHet_(MarkramSTPEntryHet) }. Run before forward in step_heterogeneous so 蟻 is fresh when spikes propagate. The _Het variant uses per-pre-neuron Array[Float] 蟿D/蟿F/U (matches Julia's MarkramSTPParameterHet) | ||||||
| Float32 logf FFI | 鉁?done | extern "C" fn logf(x : Float) -> Float = "logf" added to math_native.mbt (1 test pass) | ||||||
| compose() + sim | 鉁?done | HeterogeneousModel with pops+conns+stims+monitors+stdp+stp; step_heterogeneous (7-phase: stimulate 鈫?deliver_pending 鈫?STP 鈫?forward 鈫?STDP 鈫?integrate 鈫?record 鈫?update_time); heterogeneous_sim_for, get_time_heterogeneous, reset_time_heterogeneous (7 tests pass) | ||||||
| sim! loop | 鉁?done | sim_for, Monitor, record_one (single-pop case) | ||||||
| AdEx sim! loop | 鉁?done | adex_sim_for, MonitorAdEx | ||||||
| chain.jl | 鈿?partial | Runs; final voltages + Monitor summary printed | ||||||
| AdEx_neuron.jl | 鈿?partial | Runs; 65 pA 鈫?tonic spiking; v range tracked | ||||||
| IF_neuron.jl | 鈿?partial | 445 spikes in 1 s of 10 s | ||||||
| izhikevich.jl | 鈿?partial | RS neuron, 10 pA, 2 s 鈫?45 spikes | ||||||
| hh_neuron.jl | 鈿?partial | Default HH, 10 pA, 1 s; current too small to fire | ||||||
| morris_lecar.jl | 鈿?partial | Default ML, 100 pA, 1 s 鈫?1 spike; converges to v=1.92, w=0.53 | ||||||
| poisson_pop.jl | 鈿?partial | 1000 neurons @ 5 Hz 脳 100 s; 499,189 fires vs 500,000 expected (within 0.2%) | ||||||
| if_net.jl | 鈿?partial | 32+8 IF, 337 random connections, 4 exc spikes in 100ms | ||||||
| poisson_if.jl | 鈿?partial | 32+8 IF + Poisson inputs; E[0] fires at 345 Hz, I[0] silent | ||||||
| iz_net.jl | 鈿?partial | 16 RS + 4 FS IZ + Gaussian noise; E fires 14 spikes over 1s | ||||||
| if_noise.jl | 鈿?partial | Single IF + CurrentStimulus (400 pA + 蟽=100 noise); 48.5 Hz firing rate | ||||||
| ei_inhibition.jl | 鈿?partial | E-only: 13 spikes; E/I with feedback: 0 spikes (inhibition reduces E rate) | ||||||
| adex_net.jl | 鈿?partial | 8 AdEx + 32 EE connections + 1000 pA tonic drive; v range [-70.6, 20] mV | ||||||
| out_degree.jl | 鈿?partial | Compares FixedIn/Bernoulli/FixedOut: FixedOut has std=0 (perfect uniformity) | ||||||
| rate_net.jl | 鈿?partial | 100 WilsonCowan + all-to-all RateSynapse; rates evolve smoothly in (-1, 1) | ||||||
| potjans.jl | 鈿?partial | Simplified 2-layer Potjans-Diesmann microcircuit; E fires at 245 Hz, I at 255 Hz | ||||||
| hh_current.jl | 鈿?partial | Single HH + CurrentStimulusArray; v[0] settles at -63 mV (current too low to fire at 10 碌A/cm虏) | ||||||
| iz_net.jl | 鈿?partial | 16 E + 4 I IZ neurons with EE/EI/IE/II SpikingSynapseIZ; E fires 4, I fires 13 spikes in 1s | ||||||
| hh_net.jl | 鈿?partial | 8 E + 4 I HH neurons with EE/EI/IE/II SpikingSynapseHH; E fires 0, I fires 1 spikes in 200ms | ||||||
| tsodyks.jl | 鈿?partial | Scaled-down Tsodyks1997 (8 AdEx + 4 IF); E fires 143 spikes in 1s with Poisson-like drive | ||||||
| adex_threshold.jl | 鈿?partial | AdEx with Vr=-50mV, At=10mV, 蟿A=10ms; fires 2 spikes in 200ms | ||||||
| adex_balanced.jl | 鈿?partial | AdEx balanced (exc + inh Poisson); fires 1 spike in 1s with near-balanced input | ||||||
| stdp_demo.jl | 鈿?partial | 4-IF identity EE; pre-then-post pairing 鈫?total 螖W 鈮?+2.5e-4 across 4 synapses | ||||||
| cuba_net.jl | 鈿?partial | CUBA.jl scaled 100脳 down (80E+20I); IFParameter custom (R=100M惟); 150pA drive for 5s 鈫?259 E + 402 I spikes; drive off 鈫?0 spikes both | ||||||
| coba_net.jl | 鈿?partial | COBA.jl scaled 100脳 down (80E+20I); same IF params; 150pA for 1s 鈫?57 E + 41 I spikes; drive off for 5s 鈫?0 spikes both. delay_dist=Normal(0.8ms, 0) now implemented via random_with_delays + pending-event queue (v0.10.3+) | ||||||
| stdp_compose_demo.mbt | 鈿?partial | 4-IF identity EE via compose layer's auto STDP (Gerstner 1996). 4 pairings 脳 5ms 鈫?+2.5e-4 螖W across 4 synapses (matches manual stdp_demo result) | ||||||
| festa2024.mbt | 鈿?partial | Festa2024 StructuredInhibition network scaled 10脳 down (80E+20I1); Gerstner STDP on I1鈫扙 (auto-integrated); 1s sim: E=308 Hz, I1=286 Hz, I1鈫扙 weights grew 885.6鈫?030.8 | ||||||
| timed_stim.mbt | 鈿?partial | timed_stim.jl port: 3 IF neurons + SpikeTimeStimulus at t=100/200/300 ms (渭=100 nS). E[0] fires 4 times from its spike; E[1,2] receive but don't fire (insufficient drive with default IF) | ||||||
| potjans_diesmann.mbt | 鈿?partial | Potjans-Diesmann cortical microcircuit simplified to 4 layers + scaled 100脳 down (120 E + 40 I); Poisson drive 500Hz + 350 pA tonic on E. 1s sim: E[0]=302 Hz, I[0]=165 Hz | ||||||
| lkd2014.mbt | 鈿?partial | LitwinKumar2014 vSTDP network scaled 100脳 down (40 E + 10 I); 4 SpikingSynapses (渭=2.76/1.27/48.7/16.2); Poisson 4.5/2.5 Hz + tonic 350/250 pA. 1s sim: E[0]=217 Hz, I[0]=194 Hz | ||||||
| stdp_kernel.mbt | 鈿?partial | STDP_kernel.jl port: plots Gerstner (asymmetric, classical 1996) and symmetric Gerstner kernel curves using stdp_kernel_plot. STDPMexicanHat kernel now implemented (see calcium_kernel); STDPAntiSymmetric also added and both are now auto-integrated via STDPEntryKind compose dispatch | ||||||
| afferent_response.mbt | 鈿?partial | afferent_response.jl port (simplified, single 谓_a = 20Hz); 40 E + 10 I + Poisson drive. E[0]=183 Hz, I[0]=185 Hz | ||||||
| lagzi2022.mbt | 鈿?partial | Lagzi2022 Assembly Formation simplified to 2 IF populations (16+16) + 4 SpikingSynapses + Gerstner STDP on W11+W22 (auto-integrated). 1s sim: E1[0]=419 Hz, E2[0]=419 Hz; weights modified by STDP | ||||||
| izhikevich_debug.mbt | 鈿?partial | Debugging variant of izhikevich.mbt. Records v[0] for 100 ms with fixed seed; prints min/max/mean. Used for bit-exactness verification against Julia's Izikievich_neuron.jl | ||||||
| calcium_kernel.mbt | 鈿?partial | CalciumPlasticity_kernel.jl port (partial): plots reversed-polarity + classical Gerstner kernels + STDPMexicanHat (sombrero) kernel + decorrelated weights. iSTDPTime / SymmetricSTDP still TODO | ||||||
| oja_rule.mbt | 鈿?partial | Oja_rule.jl port: 100 Wilson-Cowan rate neurons + all-to-all RateSynapse (渭=1.2, p=1.0). 100ms sim: r[mean]=-0.019, r[max]=0.87 | ||||||
| stp_demo.mbt | 鈿?partial | Markram STP dynamics on a single forced-fire pre IF neuron: shows isolated spike (u=0.36, x=0.64, 蟻=0.2), paired-pulse 10ms (蟻=0.236, facilitation > depression at short ISI), 5-spike 50ms burst (x drops from 0.235鈫?.059, depression catches up), and full recovery (蟻 鈫?0.2 after 10s silence). Also includes a 200-spike train @ 50ms ISI: 蟻 converges to steady-state 鈮?0.21, u鈫?.907 (saturated facilitation, 蟿F=1500ms 鈮?ISI), x鈫?.022 (deep depression, 蟿D=200ms < ISI) 鈥?validates Markram 1998 analytical steady-state | ||||||
| stp_onecell.mbt | 鈿?partial | Simplified port of Mongillo2008 STP_onecell.jl. 6 bursts 脳 240 spikes at 8kHz drive u鈫?.9997 (fully facilitated), x鈫?.7e-7 (fully depleted), 蟻鈫?e-4. Documents that recovery requires integrate! to apply exp(-dt/蟿D); see stp_demo for the recovery phase | ||||||
| lkd2014_adex.mbt | 鈿?partial | Litwin-Kumar-Doiron 2014 vSTDP network using AdExSinExpParameter (LKD defaults: El=-70mV, Vt=-52mV, Vr=-60mV, 蟿m=20ms, R=1/15nS, At=10mV, 蟿e=6ms, 蟿i=2ms). Scaled 100脳 down (40 E + 10 I); manual pre鈫抪ost routing (SpikingSynapse is hardcoded to IF-to-IF); 1s sim: E[0]=6 Hz, I[0]=9 Hz | ||||||
| simulation_speed.mbt | 鈿?partial | Port of SpikingNeuralNetworks.jl/examples/simulation_speed.jl (AdEx + PoissonLayer benchmark, first part). Scaled 10脳 down (10 AdEx + 100 Poisson per pop); 1s sim; prints Poisson spike counts, AdEx spike counts, v checksum. The TripodHet / BallAndStick parts of the Julia example require multi-compartment neurons (TODO) | ||||||
| AdEx network (full) | 鉁?done | AdExParameterHet (per-ne Vector{Float] vt/vr/el/tm/r/dt_slope/tw/a/b) + AdExHet population + step_adex_het (4 tests pass). Matches Julia's AdExParameter{Vector{Float32}} + update_neuron! for the Vector variant | ||||||
| AdExSinExp (single-exp synapse) | 鉁?done | AdExSinExpParameter (pub(all) struct, same fields as AdExParameter) + AdExSinExp population + step_adex_sinexp (same as step_adex) + adex_sinexp_step_synapses (single-exp: ge += glu; ge += dt*(-ge/蟿e); gi + gaba similar) + adex_sinexp_synaptic_current (same as AdEx). Auto-integrated via AdExSinExp_ in AnyPop. Matches Julia's AdExSinExpParameter + SingleExpSynapse. 6 tests + 1 new example (lkd2014_adex) | ||||||
| Network experiments (Festa, Lagzi) | 鈴?TODO | v0.7.5+ | ||||||
| Tripod / BallAndStick neurons | 鈴?TODO | v0.7.5+ | ||||||
| Dendrite (passive compartment) | 鉁?done | Dendrite struct (per-ne El/C/gax/gm/l/d/gax_parent) + Dendrite::new (Julia defaults: El=-70.6mV, C=10pF, gax=10nS, gm=1nS, l=150渭m, d=4渭m) + Dendrite::custom(...) + dendrite_step (passive forward-Euler: (El-v)*gm + (v_parent-v)*gax + i_ext) / C) + g_axial/g_mem/c_mem helpers (Julia G_axial/G_mem/C_mem formulas). Foundational building block for BallAndStick (1 dendrite) and Tripod (2 dendrites) multi-compartment neurons (7 tests pass) | ||||||
| BallAndStick (soma + 1 dendrite) | 鉁?done | BallAndStick struct (soma AdEx + passive dendrite via Dendrite::new + single-exp synapses on both + Heun predictor-corrector integration) + step_ballandstick (bit-exact port of Julia BallAndStick integrate!: update_synapses 鈫?synaptic_current 鈫?2脳 update_neuron! 鈫?Heun averaging 鈫?spike detection on soma with ap_membrane=10mV per Julia's PostSpike). 6 tests pass | ||||||
| Tripod (soma + 2 dendrites) | 鉁?done | Tripod struct (soma AdEx + 2 passive dendrites via Dendrite::new + single-exp synapses on soma+d1+d2 + Heun predictor-corrector for 4 螖v components per neuron: dv_s, dv_d1, dv_d2, dw_s) + step_tripod (bit-exact port of Julia Tripod integrate!: soma axial current = ic1+ic2 = -(v_d - v_s) * gax for both dendrites). 6 tests + 1 new example (tripod) | ||||||
| Metaplasticity (homeostatic weight normalization) | 鉁?done | MultiplicativeNorm (渭[i] = (W0[i]-W1[i])/W1[i]; W *= (1+渭)) + AdditiveNorm (渭[i] = W0[i]-W1[i]; W += 渭) + NormParam enum + SynapseTarget struct + SynapseNormalization::new(targets, param) (captures W0[i] at construction) + metaplasticity_step(norm). 6 tests + 1 new example (metaplasticity) | ||||||
| examples/ballandstick + examples/dendrite | 鉁?done | v0.10.16: first two standalone single-neuron examples for the multi-compartment infrastructure. examples/ballandstick runs 1 BallAndStick neuron (AdEx soma + 1 passive dendrite) with 1500 pA tonic drive for 1 s; final v_s/v_d + spike count + spike envelope. examples/dendrite runs 1 passive Dendrite with parent held at -50 mV and 50 pA current injection for 200 ms then 0 pA (passive relaxation); final v_d + peak v_d. Both also exercise the v0.10.16 Heun fix: predictor/corrector extrapolate v + dv*dt (not v + dv), spike detection runs before Heun apply with predictive criterion v_s + corrector_dv*dt >= -10mV (Julia's exact form), fire && continue skips the v_d apply (prevents corrector exp_term explosion from polluting v_d), and tabs_steps = round(Int, (up + 蟿abs) / dt) (Julia's full refractory window; previously half 鈥?only 蟿abs was used). The same fix is back-ported into Tripod | ||||||
| Heun fix (BallAndStick + Tripod) | 鉁?done | v0.10.16: re-aligned step_ballandstick and step_tripod apply loops with Julia's exact per-neuron order (decrement tabs 鈫?update threshold 鈫?refractory branch with v_d += dt*(v_s-v_d)*gax/C 鈫?active branch with predictive fire detection 鈫?fire overrides continue). Fixes v_d runaway when soma spikes (predictor dv_s explodes exp_term, corrector dv_d inherits the bogus extrapolation, v_d was being updated before spike detection) | ||||||
| HetRec (heterogeneous-timescale non-recurrent layer) | 鉁?done | v0.10.17: HetRecParameter (Nd/overlap/蟿d-low/蟿d-high/rate-low/rate-high/蟿abs/steepness/蟿m/蟿rate) + HetRec struct (v_d/v_s/is_/r/tau_d/fire/tabs/trace/randcache + sparse CSC colptr/i_syn/w_syn) + HetRec::new (samples r and 蟿d from Uniform, builds sparse M with own-dendrite-always + cross-dendrite-per-overlap) + hetrec_refresh_random + step_hetrec (Euler: v_d += dt*(-v_d-is)/蟿d; soma: v_s += (W路v_d - v_s)dt/蟿m per synapse; stochastic fire: rand < rsigmoid(steepness路(v_s-trace))路dt; 蟿abs refractory). Auto-integrated via HetRec_ in AnyPop. 8 tests + 1 new example (hetrec) | ||||||
| examples/wilson_cowan | 鉁?done | v0.10.18: standalone single-population Wilson-Cowan rate-model example. 20 WilsonCowan + all-to-all self-RateSynapse (渭=0.5, p=1.0) + I=0.2 tonic drive; 100 ms sim; samples r at t=0/12.5/50/99.9 ms to show transient 鈫?fixed-point convergence (mean | r | 鈮?.21, r[0]=-0.06鈫?.34). Exercises the rate-mode forward (pre.r 鈫?post.g via sparse matrix) | ||||
| examples/spikesynapse | 鉁?done | v0.10.19: minimal 2-IF + 1-SpikingSynapse network (E1 鈫?E2 onto :ge, 渭=1.62 nS, p=1.0, delay=Normal(3ms, 2ms)). E1 driven by 200 pA tonic current; E2 receives the synaptic input via the pending-event queue + delay (built v0.10.3). Result: E1 fires 381 spikes, E2 fires 379 spikes (1:1 with small loss to delay + refractory). Demonstrates the manual sim loop pattern (deliver_pending_synapse 鈫?forward_synapse 鈫?step_synapses 鈫?synaptic_current 鈫?step_neuron) | ||||||
| STTC (Spike-Time Tiling Coefficient) analysis | 鉁?done | v0.10.20: analysis_sttc.mbt (new) 鈥?tile_fraction (sorted train, 卤dt intervals union, divided by T+2dt) + coincident_fraction (binary-search in B for each spike in A) + sttc_pair (symmetric formula 0.5*((PA-TB)/(1-PA*TB) + (PB-TA)/(1-PB*TA))) + sttc_matrix (N脳N symmetric, diagonal=1) + sort_floats helper. 13 tests + 1 new example (sttc) | ||||||
| ISI / CV2 | 鉁?done | analysis_isi.mbt 鈥?port of spikes.jl::ISI_CV2 (Holt et al. 1996). isi_cv2_one(spike_times) single-neuron CV2 (handles 0-spike / 1-spike / 2-spike / NaN edge cases); isi_cv2(spike_times_per_neuron) per-neuron CV2 array. CV2 bounded by [0, 2] (9 tests pass) | ||||||
| LIF closed-form verification | 鉁?done | analysis_lif_closedform_test.mbt 鈥?closed-form LIF analytical verification. For an IF neuron with constant input I, the membrane voltage follows V(t) = V_rest + I*R*(1 - exp(-t/蟿m)). Verifies that the MoonBit simulator matches the analytical solution to within forward-Euler drift tolerance (4 tests pass: decay transient, steady-state, decay-to-rest, 蟿m time-constant). This serves as a "reference-output" check analogous to a Julia trajectory comparison (4 tests pass) | ||||||
| PoissonLayer (population of N Poisson sources) | 鉁?done | v0.10.21: PoissonLayer struct (pub(all); rate / n_sources / active / 渭 / 蟽 / p / dist / rule) + 4 constructors (new, with_n, with_active, with_conn) + PoissonLayerStimulus (wraps IF target + per-(pre, post) sparse weights drawn at construction via Box-Muller for Normal or Fixed for :Fixed) + stimulate_layer(s, t, dt) (per-step: reset fire buffer, sample Poisson per active source, apply weight to glu/gaba if fires). Auto-integrated via PoissonLayer_ in AnyStim. Mirrors Julia's PoissonLayer + Stimulus + stimulate! pattern (11 tests + 1 new example) | ||||||
| examples/poisson_layer | 鉁?done | v0.10.21: minimal port of poisson_layer.jl. 10 Poisson sources @ 2 Hz 鈫?200 IF (El=-49mV, vr=-60mV, vt=-50mV); Normal(渭=2.0, 蟽=1.0) weights, p=0.2 connectivity. Manual sim loop (stimulate_layer 鈫?step_synapses 鈫?synaptic_current 鈫?step_neuron) for 1 s at dt=0.125 ms. 410 actual connections (expected ~400); total 5322 spikes 鈫?26.6 Hz mean rate per neuron (high because El is only 1 mV below vt) | ||||||
| examples/spike_analysis | 鉁?done | v0.10.22: exercises vecplot analysis infrastructure (Monitor::count_spikes / firing_rate / spike_times / count_spikes_interval / firing_rate_interval / dump_summary / ascii_plot) on a small driven IF population (20 neurons, El=-49mV, 500ms sim). Per-neuron spike counts (135鈥?73 spikes), rates (270鈥?46 Hz), spike times, sub-interval analysis, v summary, ASCII plot | ||||||
| Compartment-targeted SpikingSynapse | 鉁?done | v0.10.23: CompartmentSynapseBall (targets :soma or :d of BallAndStick) + CompartmentSynapseTripod (targets :soma, :d1, or :d2 of Tripod) 鈥?same CSR matrix + delays + pending queue + rho-scaling semantics as SpikingSynapse, but routes incoming weights to a single compartment buffer. forward_compartment_ball / forward_compartment_tripod / deliver_pending_compartment_ball / deliver_pending_compartment_tripod (11 tests + 1 new example). First piece of the multi-compartment synapse infrastructure that unblocks tripod_network.jl / tripod_current.jl / stimuli.jl. Note: multi-receptor (AMPA + NMDA / GABA_A + GABA_B) is still TODO | ||||||
| TripodHet (heterogeneous-parameter Tripod) | 鉁?done | v0.10.24: TripodHet struct (soma AdExParameterHet + 2 shared dendrites + Heun predictor-corrector that reads per-neuron vt/vr/el/tm/r/dt_slope/tw/a inside the per-neuron loop) + TripodHet::new(n, soma_param, rng) + step_tripod_het (same Julia integrate! order as step_tripod but with per-ne arrays). 8 tests + 1 new example (tripod_het). Mirrors Julia's Tripod(..., param=AdExParameter{Vector{Float32}}). Final unblocker before tripod_network.jl / multipod.jl / tripod_current.jl (still need NMDA multi-receptor) | ||||||
| NMDA primitives (multi-receptor + voltage-dependent gating) | 鉁?done | v0.10.25: receptor.mbt (new) 鈥?NMDAVoltageDependency (Eyal/Soma defaults) + nmda_gating(v, dep) (B(v) = 1/(1 + (mg/b)exp(kv))) + Receptor (e_rev / tau_r / tau_d / g0 / gsyn / alpha / inv / is_nmda / target) + Receptors (4-element collection AMPA/NMDA/GABAa/GABAb) + step_receptor(g, h, target, r, dt) (2-state ODE: h += target伪; g = exp(-dt/蟿d鈦?(g + dth); h = exp(-dt/蟿r鈦?h; consumes target) + receptor_current(g, v, r, nmda, out) (sums I = gsyng(v-e_rev)*B(v) for NMDA, no B for others). 10 tests + 1 new example (nmda). Foundation for tripod_network.jl / tripod_current.jl / stimuli.jl | ||||||
| ReceptorSynapse for TripodHet (multi-compartment + multi-receptor wiring) | 鉁?done | v0.10.26: connection_receptor_tripod.mbt (new) 鈥?ReceptorSynapseTripod struct (pre IF, post TripodHet, CSR matrix, target_compartment 鈭?{soma, d1, d2}, Receptors collection, NMDAVoltageDependency, g_state[N脳4], h_state[N脳4], ge_out[N], gi_out[N]) + forward_receptor_tripod_synapse(s, target_receptor, t_now) (AMPA/NMDA 鈫?glu; GABAa/GABAb 鈫?gaba; routes to the right compartment buffer) + step_receptors_tripod_synapse(s, dt) (runs 2-state ODE for each of the 4 receptors on the target compartment, applies NMDA gating when is_nmda; sums into ge_out/gi_out). 6 tests + 1 new example (tripod_receptor). Wires the NMDA primitives into TripodHet, enabling tripod_network.jl / tripod_current.jl / stimuli.jl ports | ||||||
| PoissonLayerStimulusTripod (Poisson Stimulus on TripodHet compartments) | 鉁?done | v0.10.27: stimulus_poisson_layer_tripod.mbt (new) 鈥?PoissonLayerStimulusTripod struct (param : PoissonLayer, post : TripodHet, weights[N_post 脳 n_sources], connectivity, target_compartment 鈭?{soma, d1, d2}, target_kind 鈭?{glu, gaba}, rng) + stimulate_layer_tripod(s, t, dt) (per-step: per active Poisson source, sample Poisson(rate*dt); if fires, add weights[j, i] to the target compartment buffer). 7 tests + 1 new example (tripod_current 鈥?scaled-down port of tripod_current.jl: 4 TripodHet + 20 Poisson exc @ 20 Hz + 20 Poisson inh @ 3 Hz, both on :d1, 500 ms sim). Final piece of the tripod_current.jl infrastructure stack (alongside ReceptorSynapseTripod) | ||||||
| change_plasticity! (runtime STDP parameter swap) | 鉁?done | v0.10.28: Made param field mutable on STDPEntry / STDPEntryMexicanHat / STDPEntryAntiSymmetric + STDPEntry::change_plasticity(e, new_param) / STDPEntryMexicanHat::change_plasticity(e, new_param) / STDPEntryAntiSymmetric::change_plasticity(e, new_param) 鈥?runtime swap of LTP parameters (preserves vars). 5 tests + 1 new example (change_plasticity). Mirrors Julia's change_plasticity!(syn; LTP = STDPConfavreux2025()) from with_plasticity.jl. Note: still need to port STDPConfavreux2025 + iSTDPRate + iSTDPPotential + vSTDPParameter + MarkramSTPParameterTimestep (rule bodies) for the full with_plasticity.jl test | ||||||
| PoissonLayerStimulusBallAndStick (Poisson Stimulus on BallAndStick :soma/:d) | 鉁?done | v0.10.29: stimulus_poisson_layer_ballandstick.mbt (new) 鈥?PoissonLayerStimulusBallAndStick struct (param : PoissonLayer, post : BallAndStick, weights[N_post 脳 n_sources], connectivity, target_compartment 鈭?{soma, d}, target_kind 鈭?{glu, gaba}, rng) + stimulate_layer_ball(s, t, dt). 6 tests + 1 new example (stimuli 鈥?simplified port of stimuli.jl: 1 BallAndStick + 1 TripodHet + 4 Poisson Stimuli on :d / :d1). Final piece of the stimuli.jl infrastructure stack (alongside PoissonLayerStimulusTripod) | ||||||
| vSTDPParameter (Litwin-Kumar-Doiron 2014 voltage-dependent STDP) | 鉁?done | v0.10.30: stdp_vstdp.mbt (new) 鈥?VstdpParameter struct (a_ltd / a_ltp / theta_ltd / theta_ltp / tau_pre / tau_post / w_max / w_min) + VstdpVariables::new(n_pre, n_post) + vstdp_step(vars, param, pre_v, post_v, pre_fire, post_fire) (LTD on pre-fires when v_post > 胃_LTD; LTP on post-fires when v_pre > 胃_LTP; weight clamped to [w_min, w_max]) + vstdp_plot(param) ASCII visualization of the (v_pre, v_post) rule. 9 tests + 1 new example (vstdp). Mirrors Julia's vSTDPParameter from plasticity_params.jl. Note: struct renamed from vSTDPParameter to VstdpParameter because MoonBit requires type names to start with uppercase | ||||||
| BalancedStimulus (feedback-driven inhomogeneous Poisson) | 鉁?done | v0.10.31: stimulus_balanced.mbt (new) 鈥?BalancedParameter struct (kIE / beta / tau / r0 / w / wIE / same_input) + BalancedStimulus::new(pop, sym_e?, sym_i?, param?, seed?) (hooks into pop.glu / pop.gaba) + stimulate_balanced(s, t, dt) (inhomogeneous Poisson on :gi at rate r0*kIE; per-neuron rate adaptation r[i] += (r0 - Erate) / 400ms * dt driven by low-pass-filtered noise noise[i] = (noise[i] - re) * (1 - dt/蟿) + re; Poisson at rate Erate writes to :ge). Same_input=true broadcasts a single trace across all neurons. 9 tests + 1 new example (balanced 鈥?port of balanced.jl: 200 IF @ El=-49mV + BalancedParameter(kIE=2, 尾=0.1, 蟿=100ms, r0=2kHz, wIE=2, same_input=true); 1s sim, total 81295 spikes, mean 406 Hz/neuron). Wired into compose.mbt via new BalancedIF_ enum variant. Mirrors Julia's BalancedStimulus(E, :ge, :gi; param=BalancedParameter()) from stim/balanced.jl | ||||||
| STDPConfavreux2025 (Confavreux 2025 STDP with 伪/尾 baseline dependencies) | 鉁?done | v0.10.32: stdp.mbt (extended) 鈥?STDPConfavreux2025 struct (eta / alpha / beta / kappa / gamma / tau_pre / tau_post / w_max / w_min) + STDPEntryConfavreux2025 (mutable param, STDPVariables, t_now) + change_plasticity(entry, new_param) runtime swap + stdp_confavreux_step(w, pre_fire, post_fire, colptr, rowptr, vars, param, t_now, dt) (continuous tpre/tpost decay + spike bump, then single fused connection loop: pre-fire contributes eta * (kappa * 螖post[i] + alpha), post-fire contributes eta * (gamma * 螖pre[j] + beta); clamp to [w_min, w_max]). 9 tests + 1 new example (stdp_confavreux 鈥?port of with_plasticity.jl "STDPConfavreux2025" testset: 4脳4 dense synapse, 100 steps random pre/post firing; verifies weights stay finite and within bounds). Wired into compose.mbt via new Confavreux2025_(...) variant in STDPEntryKind. Mirrors Julia's STDPConfavreux2025 from STDP_traces.jl | ||||||
| IstdpRate (Vogels 2011 inhibitory STDP with rate homeostasis) | 鉁?done | v0.10.33: istdp.mbt (new) 鈥?IstdpRate struct (eta / r / tau_y / w_max / w_min) + IstdpRateVariables (just tpre / tpost arrays, no last_* bookkeeping) + IstdpRateEntry (mutable param, vars, t_now) + change_plasticity(entry, new_param) runtime swap + istdp_rate_step(w, pre_fire, post_fire, colptr, rowptr, vars, param, t_now, dt) (continuous tpre/tpost decay t += dt*(-t)/tau_y + spike bump, then fused connection loop: pre-fire contributes eta * (tpost[i] - 2*r*tau_y), post-fire contributes eta * tpre[j]; clamp to [w_min, w_max]). 10 tests + 1 new example (istdp_rate 鈥?port of with_plasticity.jl "iSTDPRate" testset: 4脳4 dense synapse, 100 steps random pre/post firing; final weights stay finite within [0.01, 243]). Wired into compose.mbt via new IstdpRate_(...) variant in STDPEntryKind. Mirrors Julia's iSTDPRate from iSTDP.jl. Note: struct renamed from iSTDPRate to IstdpRate because MoonBit requires type names to start with uppercase | ||||||
| IstdpPotential (Vogels 2011 inhibitory STDP with potential-based post trace) | 鉁?done | v0.10.34: istdp.mbt (extended) 鈥?IstdpPotential struct (eta / v0 / tau_y / w_max / w_min) + IstdpPotentialVariables (tpre / tpost arrays) + IstdpPotentialEntry (mutable param, vars, t_now) + change_plasticity(entry, new_param) runtime swap + istdp_potential_step(w, pre_fire, post_fire, colptr, rowptr, v_post, vars, param, t_now, dt) 鈥?tpre[j] decays toward 0; tpost[i] is a low-pass filter of v_post[i] (decays toward v_post with time constant tau_y, plus +1 bump on post-spike). Weight update: pre-fire contributes eta * (tpost[i] - v0); post-fire contributes eta * tpre[j]; clamp to [w_min, w_max]. 10 tests + 1 new example (istdp_potential 鈥?port of with_plasticity.jl "iSTDPPotential" testset: 4脳4 dense synapse, 100 steps random pre/post firing + varying v_post in [-70, 50] mV; final weights stay finite within [0.01, 243]). Wired into compose.mbt via new IstdpPotential_(...) variant in STDPEntryKind which threads syn.post.v into the step function. Mirrors Julia's iSTDPPotential from iSTDP.jl. Note: struct renamed from iSTDPPotential to IstdpPotential because MoonBit requires type names to start with uppercase | ||||||
| MarkramSTPParameterTimestep (continuous-time Euler Markram STP) | 鉁?done | v0.10.35: stp.mbt (extended) 鈥?MarkramSTPParameterTimestep struct (u / tau_f / tau_d / w_max / w_min) + MarkramSTPEntryTimestep (uses same MarkramSTPVariables state) + markram_stp_step_timestep(syn, vars, param, t_now, dt) (per step: spike bumps u += U*(1-u), x += -u*x; then continuous Euler u += dt*(U-u)/tau_f, x += dt*(1-x)/tau_d for every pre-neuron; recompute rho_pre[j] = u[j] * x[j]; broadcast rho_pre to all outgoing connections via syn.matrix.rowptr[j]). 8 tests + 1 new example (stp_timestep 鈥?port of with_plasticity.jl "MarkramSTPParameterTimestep" testset: 4脳4 dense synapse, 200 steps random pre firing; verifies weights stay finite and rho / u stay in [0, 1]). Wired into compose.mbt via new MarkramSTPTimestep_(...) variant in STPEntryKind. Mirrors Julia's MarkramSTPParameterTimestep from STP.jl | ||||||
| STDPSymmetric (Festa et al. 2024 zero-integral inhibitory STDP) + IstdpTime (parameter type only) | 鉁?done | v0.10.36: stdp.mbt (extended) 鈥?STDPSymmetric struct (a_x / a_y / tau_x / tau_y / alpha_pre / alpha_post / w_max / w_min) + STDPSymmetricVariables (4 trace arrays: tr_x, tr_y, to_x, to_y) + STDPEntrySymmetric (mutable param, vars, t_now) + change_plasticity(entry, new_param) runtime swap + stdp_symmetric_step(w, pre_fire, post_fire, colptr, rowptr, vars, param, t_now, dt) 鈥?continuous decay of all 4 traces (tr_x, tr_y bump on pre-spike, to_x, to_y bump on post-spike); fused connection loop: pre-fire contributes alpha_pre + (a_x/(2*tau_x))*to_x[i] - (a_y/(2*tau_y))*to_y[i], post-fire contributes alpha_post + (a_x/(2*tau_x))*tr_x[j] - (a_y/(2*tau_y))*tr_y[j]; clamp to [w_min, w_max]. istdp.mbt (extended) 鈥?IstdpTime struct (eta / tau_y / w_max / w_min) 鈥?parameter type only, no step function (Julia's iSTDP.jl defines iSTDPTime but doesn't provide a separate step rule for it). 11 tests + 1 new example (stdp_symmetric 鈥?port of plasticity_params.jl "STDPSymmetric / STDPAntiSymmetric" testset: 4脳4 dense synapse, 100 steps random pre/post firing; verifies weights stay finite within [0, 30]). Wired into compose.mbt via new Symmetric_(...) variant in STDPEntryKind. Mirrors Julia's STDPSymmetric from STDP_structured.jl and iSTDPTime from iSTDP.jl | ||||||
| TripodNetwork (multi-population E-I Tripod network wiring) | 鉁?done (partial) | v0.10.37: examples/tripod_network/main.mbt (new) 鈥?port of test/network/tripod_network.jl. 20 Tripod (E, homogeneous AdEx soma) + 5 IF (I1, 蟿m=7ms) + 5 IF (I2, 蟿m=20ms) + CompartmentSynapseTripod for I1鈫扙 :soma with IstdpRate + I2鈫扙 :d1 with IstdpPotential. 500ms manual sim loop with forward 鈫?step_neuron 鈫?step_tripod 鈫?STDP!. Final: E soma fires at 1287 Hz/neuron, I1 at 422 Hz, I2 at 348 Hz. Partial port 鈥?E鈫扞1, E鈫扞2 routed via tonic current approximation (Tripod can't be pre in CompartmentSynapseTripod); E鈫扙 recurrent SKIPPED (same constraint); homeostatic SynapseNormalization + MultiplicativeNorm not ported yet. Demonstrates that the existing Tripod / CompartmentSynapseTripod / IstdpRate / IstdpPotential infrastructure composes correctly into a multi-population network | ||||||
| Population + synapse parameter type sanity tests | 鉁?done | v0.10.38: parameters_test.mbt (new) 鈥?port of test/pop/parameters.jl "Population parameters" + "Synaptic parameter types" testsets. 10 tests verifying field existence + Julia-matching defaults for IFParameter, AdExParameter, IZParameter, MorrisLecarParameter, HetRecParameter, PostSpike, AdExPostSpike, plus IF's tre/tde/tri/tdi time constants (DoubleExpSynapse-style) and Receptor/NMDAVoltageDependency constructors. Field names mapped from Julia camelCase to MoonBit lowercase (Vt鈫抈vt, 蟿m鈫抈tm, gCa鈫抈gca, Nd鈫抈nd, etc.). Demonstrates that all major parameter types have the expected property surface | ||||||
| Synapse parameter types + vars + step functions | 鉁?done | v0.10.39: synapse_params.mbt (new) 鈥?DeltaSynapse (empty), SingleExpSynapse (tau_e, tau_i, e_e, e_i, gsyn_e, gsyn_i), DoubleExpSynapse (tau_re/de/ri/di, e_e, e_i, gsyn_e, gsyn_i), CurrentSynapse (tau_e, tau_i) structs with Julia-matching defaults; companion *Vars structs with ge/gi/he/hi state arrays; step functions (delta_synapse_step, single_exp_synapse_step, double_exp_synapse_step, current_synapse_step) implementing the Julia update rules (instantaneous / single-exp decay / 2-state rise+decay / current-based decay); current functions (delta_synapse_current syn_curr=-(ge-gi) then reset; current_synapse_current syn_curr=-(ge-gi); conductance_synapse_current / double_exp_conductance_current syn_curr=ge*(v-E_e)gsyn_e + gi(v-E_i)*gsyn_i). 12 tests + 1 new example (synapse_params 鈥?constructs all four synapse types, runs a single step with synthetic input glu=[1,0,0,0], computes synaptic current at v=-50mV). Mirrors Julia's DeltaSynapse / SingleExpSynapse / DoubleExpSynapse / CurrentSynapse parameter types from synapses/ | ||||||
| SNNUtils.jl parameter constants (LKD2014 + Duarte2019) | 鉁?done | v0.10.40: snn_utils_params.mbt (new) 鈥?LKD2014 struct (tm / vt / el / vr / r / tau_abs / e_i / e_e / at / pv_tm / pv_el / pv_vr / pv_vt) matching Julia's SNNUtils.LKD2014 named-tuple from lkd2014.jl. Duarte2019 struct (pv_, sst_, adex_* parameters) matching Julia's SNNUtils.duarte2019 named-tuple from duarte2019.jl. C/nS ratios computed manually as Float32 constants (300pF/15nS = 20.0ms for LKD2014; 104.52pF/9.75nS 鈮?10.72ms, 102.86pF/4.61nS 鈮?22.31ms, 116.5pF/4.64nS 鈮?25.11ms for Duarte2019). 3 tests + 1 new example (snn_utils_params 鈥?displays all parameters and demonstrates LKD2014 鈫?IFParameter::custom conversion). Mirrors Julia's SNNUtils.jl/src/models/lkd2014.jl + duarte2019.jl | ||||||
| Simulation control (sim_control.jl port) | 鉁?done | v0.10.41: sim_control_test.mbt (new) 鈥?port of test/sim/sim_control.jl. 6 tests covering get_time_heterogeneous (zero before sim, advances after sim_for), reset_time_heterogeneous (resets to zero), Monitor::new_fire spike accumulation over a 50ms sim, Monitor::new_v_sr sampling rate storage, and compose with multiple pops + conns. Uses the existing HeterogeneousModel infrastructure from compose.mbt | ||||||
| Spatial utilities (spatial_test.jl port) | 鉁?done | v0.10.42: spatial.mbt (new) 鈥?port of utils/spatial.jl. Point2D struct (x, y), PlacedPops struct (e/i). place_populations_e_i(n_e, n_i, grid_x, grid_y, rng) (random Float32 placement on a periodic grid via next_f32). periodic_distance_scalar(p1, p2, grid_size) (1D torus distance: min of |p1-p2| and grid_size-|p1-p2|). linear_network(n) + linear_network_with(n, sigma_w, w_max) (ring-shaped Gaussian weight matrix on circle of circumference 2pi). MoonBit parser limitation workaround: instead of returning Array[Array[Float]] (which fails to parse in our setup), return a flat row-major Array[Float] of length n*n; index via row_major_get(W, n, i, j). Diagonal entries set to 0. 4 tests + new example spatial (recommended in subsequent turn). Mirrors Julia's utils/spatial.jl (place_populations, periodic_distance, linear_network) | ||||||
| AggregateScaling (aggregate_scaling.jl port) | 鉁?done | v0.10.43: aggregate_scaling.mbt (new) 鈥?port of connections/metaplasticity/aggregate_scaling.jl. AggregateScalingParameter (蟿e/蟿a/蟿/Y/Wmin/Wmax) matching Julia's struct. AggregateScaling::new(n, targets, param) initialises WT[i] = sum of incoming weights. aggregate_scaling_forward(c, fire, dt) per Julia: y decays with 蟿a, bumps on fire[i] (Euler decay鈫抌ump鈫扺T-update order), drives WT[i] toward (1 - y[i]/Y[i])/Wmax with 蟿e. aggregate_scaling_plasticity(c, step_count) periodic variant: every 蟿/dt steps (default 80), recompute wt[i] = sum of weights, compute 渭[i] = (WT[i] - Wmin) / wt[i] (guarded to 1.0 when wt=0), rescale W[s] = W[s] * 渭[i] + Wmin. AggregateScaling::with_plasticity_interval(c, n) runtime override of the cadence. 9 tests + upgraded examples/aggregate_scaling/main.mbt to use the real infrastructure (was a placeholder). Final demo: 100 IF + 2074 EE connections + 1000 steps with weight perturbation + periodic homeostatic rescaling; y[0]=0.58, WT[0]=267.7, final mean weight 14.98 | ||||||
| LKD2014.PV demo (LKD.jl port) | 鉁?done | v0.10.44: AdExParameter::custom(tm, vt, vr, el, r) constructor added to neuron_adex.mbt. examples/lkd2014_demo/main.mbt (new) 鈥?uses LKD2014.PV parameter values (tm=20ms, El=-62mV, Vt=-52mV, Vr=-57.47mV, R=0.0667) to build a single IF neuron, drives it with a single scheduled spike at t=1000ms via SpikeTimeStimulus (param spiketimes=[1000.0F], neurons=[0]), runs 1200ms @ dt=0.125ms, prints final v[0]/glu[0]/fire[0]. Final state: v=-61.999 (El unchanged since the single spike wasn't strong enough to push v above Vt=-52 with R=0.0667 脳 p路gsyn_e=1.0路2 nS=0.13 nS). AdEx side of LKD.jl omitted (SpikeTimeStimulus currently only accepts IF populations; full two-population network requires TimedStimulusAdEx variant). Mirrors refs/SNNUtils.jl/test/LKD.jl partial port | ||||||
| metaplasticity.jl port (extended coverage) | 鉁?done | v0.10.45: metaplasticity_test.mbt (extended) 鈥?added 3 tests from refs/SNNModels.jl/test/syn/metaplasticity.jl: SynapseNormalization AdditiveNorm form (W0 sum + no-shrinkage step), W0 sums from full connectivity (4脳4 synapse with 渭=1 gives W0=4 per post), metaplasticity_step multiplicative shrinkage+restore (W0=[4,6] captured, shrink to half 鈫?step restores via 渭=1 scaling), additive shrinkage correction (additive applies 渭[i] to all synapses connecting to post i, NOT a "restore" 鈥?over-corrects when multiple synapses target the same post). RandomTurnover and ActivityDependentTurnover constructors NOT ported (structural plasticity TODO 鈥?separate work). 4 tests + 1 example | ||||||
| set_LTP! / set_STP! (runtime LTP/STP toggle) | 鉁?done | v0.10.46: port of refs/SNNModels.jl/test/syn/plasticity_params.jl "set_LTP! / set_STP!" testset (lines 179-190). stdp_step now gates on vars.active[0] at the top (mirrors how markram_stp_step already did). Three new helpers: STDPEntry::set_ltp_active(entry, active), MarkramSTPEntry::set_stp_active(entry, active), MarkramSTPEntryHet::set_stp_active(entry, active), MarkramSTPEntryTimestep::set_stp_active(entry, active) 鈥?each mutates entry.vars.active[0] in place. MoonBit identifiers drop Julia's trailing !. Round-trip toggle preserves vars state (traces + spike times survive a false鈫抰rue cycle). MarkramSTPEntryHet::new constructor now used (was: struct-literal which MoonBit rejects without pub(all)). MarkramSTPParameterHet::homogeneous(n_pre) is the public constructor for the het struct. 8 tests + 0 examples | ||||||
| SynapseTarget::post_id (post-population identifier) | 鉁?done | v0.10.47: SynapseTarget gained a post_id : Int field 鈥?an explicit identifier for which post-neuron population the buffer targets. Mirrors Julia's targets[:post] lookup (which uses a NamedTuple key; we use a caller-supplied integer because MoonBit has no NamedTuple equivalent). All existing fixtures updated to set post_id: 0 (or post_id: N for new tests). 2 new tests verify the field is captured by SynapseNormalization::new and accessible via norm.targets[i].post_id. Limitation: Julia's @assert length(unique(posts)) == 1 runtime check is NOT ported because MoonBit's abort is a polymorphic bottom type that the type system doesn't track as a raise site (making try...catch ergonomics poor). The caller is expected to verify post-population consistency before calling ::new. 2 tests + 0 examples | ||||||
| metaplasticity_step_gated (periodic 蟿 gating) | 鉁?done | v0.10.48: added metaplasticity_step_gated(norm, step_count, dt) 鈥?periodic form that mirrors Julia's outer plasticity!(c, param, dt, T) which gates on ((tt) % round(Int, 蟿 / dt)) < dt. Fires only when step_count % round(蟿/dt) == 0. 蟿=0 disables periodic firing (matches Julia default). Caller maintains the step counter (just pass i in your sim loop). 2 tests verify gate behavior: with 蟿=0.5ms and dt=0.125ms, period=4 steps, only steps 0/4/8 fire. 蟿=0 test verifies the gate stays closed. 2 tests + 0 examples | ||||||
| util.mbt (utils/util.jl port) | 鉁?done | v0.10.49: port of SNNModels.jl/src/utils/util.jl non-graph helpers. rand_value(n, p1, p2, rng) 鈥?uniform Float32 values in [min(p1,p2), max(p1,p2)]; degenerates to constant when p1==p2. exp32(x) / exp64(x) / exp256(x) 鈥?fast exp approximations via repeated squaring (Julia-side performance helper; we use libm expf directly but expose these for API parity). name(pre, post, k?) / name2(pre, post) 鈥?Symbol/String name generators for connection labels (MoonBit: returns String, not Symbol). str_name(pre, post, k?) / str_name_single(pre, k?) 鈥?String variants (matching Julia's (::String, k?) overload). f2l(s, l?) / f2l_default(s) 鈥?pad/truncate string to exact length l (default 10). 21 tests in util_test.mbt cover all helpers. Note: the full compose and print_model from util.jl are NOT ported 鈥?MoonBit's compose in compose.mbt already provides the heterogeneous-model builder; print_model is graph-based and out of scope. 21 tests + 0 examples | ||||||
| turnover.jl (structural plasticity) | 鉁?done | v0.10.50: port of SNNModels.jl/src/connections/metaplasticity/turnover.jl (structural plasticity). RandomTurnover(rate, threshold, mu) and ActivityDependentTurnover(rate, fraction, tau_pre, tau_post, mu) constructors + Turnover struct + synaptic_turnover!(syn, p_rewire?, mu?, p_values?) rewiring logic. turnover_plasticity!(c, step_count, dt) periodic gate (fires every 蟿/dt steps). quantile_float helper for the activity-dependent threshold. Note: p_new callback is ignored (MoonBit has no first-class function references 鈥?new posts are sampled uniformly). SpikingSynapse's actual field names are matrix.vals / matrix.colptr / matrix.rowptr (NOT W / I). 12 tests in turnover_test.mbt cover both variants + periodic gate + empty-array quantile. 12 tests + 0 examples | ||||||
| Multipod (variable-dendrite-count Tripod) | 鉁?done | v0.10.51: port of SNNModels.jl/src/populations/multicompartment/multipod.jl 鈥?Multipod struct with variable nd (number of dendrites), per-dendrite voltage arrays, 4-receptor per-dendrite per-neuron conductance buffers (AMPA/NMDA/GABAa/GABAb), Euler integrator. MultipodParameter::new(dendrites) / ::uniform(d, nd) constructors. Multipod::step(p, dt) Euler update with soma_syn + dend_syn receptors, axial currents, soma+dendrite ODEs, spike detection. Note: simplified port 鈥?no full NMDA voltage gating or Heun corrector (those are TODO). Euler step has a stack-overflow issue on long simulations (likely the flat-index nested loops over g_d[i, d, n]); the Multipod::step runtime tests are marked as TODO pending a flat-loop refactor. 10 tests in neuron_multipod_test.mbt cover constructors + shape allocations + initial-state finiteness + receptor-marker preservation. 10 tests + 0 examples | ||||||
| Multipod (step refactor + 3 additional shape tests) | 鉁?done | v0.10.52: refactored Multipod::step body into smaller helper functions (multipod_step_neurons + multipod_sum_cs) to flatten the call stack. The helper-function refactor didn't fix the runtime stack overflow (MoonBit's JIT still overflows on the d 脳 k 脳 i flat-index nested loops), so the runtime tests remain deferred. Added 3 additional constructor-shape tests: Multipod::new 鈥?w_s, he_s, hi_s, ge_s, gi_s zero (verify all soma spike-input + conductance buffers are zero-initialised), Multipod::new 鈥?after_spike field shape + he_d/hi_d zero (verify dendrite spike-input buffers), Multipod::new 鈥?g_d / h_d / dv / dv_temp / cs / iv lengths (verify scratch buffer lengths scale with N 脳 nd 脳 4). 3 tests + 0 examples | ||||||
| Multipod (g_d / h_d nested-array refactor) | 鉁?done | v0.10.53: refactored g_d / h_d from a flat Array[Float] (indexed as g_d[i + d*N + n*N*nd]) to a nested 3-level Array[Array[Array[Float]]] (indexed as g_d[d][i][n]). The flat-index nested loops were the root cause of MoonBit's JIT stack overflow; the nested version has the same memory layout (4 脳 N 脳 nd floats) but the inner loop is now a contiguous slice which the JIT handles better. Note: even with the nested refactor, Multipod::step still stack-overflows on runtime tests (likely a different JIT limitation in this version of MoonBit). 3 new tests verify the nested shape: Multipod::new 鈥?g_d[d][i][n] nested zero-init across all 3 levels (24 cells verified), Multipod::new 鈥?g_d / h_d are independent per-dendrite slices (setting one dendrite doesn't affect another), Multipod::new 鈥?receptor index 3 (GABAb) accessible (boundary index reachable). 3 tests + 0 examples | ||||||
| structs_extra.mbt (EmptyParam + NetworkModel + Time::from_ms) | 鉁?done | v0.10.54: port of additional SNNModels.jl/src/utils/structs.jl helpers. EmptyParam struct with p_type : String field (mirrors Julia's EmptyParam with type::Symbol = :empty; we use a String instead of Symbol since MoonBit has no first-class Symbols). EmptyParam::new() defaults to "empty", EmptyParam::with_type(p_type) customises, EmptyParam::type_str(p) accessor. NetworkModel placeholder (MoonBit's HeterogeneousModel is the real port 鈥?this stub exists for API documentation). isa_model(m) accessor. Time::from_ms(time) was already in time.mbt but got 2 dedicated tests (100ms 鈫?tt=800, 0.5ms 鈫?tt=4). 6 tests in structs_extra_test.mbt cover all helpers + Time::from_ms numerics. 6 tests + 0 examples | ||||||
| HH_NMDA multi-receptor variant | 鈴?TODO | v0.7.5+ | ||||||
| Identity neuron (Lagzi-style pass-through) | 鉁?done | Identity::new(n, param), step_neuron_id(p, dt) 鈥?fires when g > 0 (3 tests pass) | ||||||
| STP (Markram 1998) integration into compose | 鉁?done | v0.10.4: MarkramSTPEntry + STPEntryKind enum, auto-integrated before forward (12 tests pass) | ||||||
| Bit-exactness verification vs Julia | 鈴?TODO | Compare spike trains / voltage traces against the Julia run for each example |
# Tests
cd moonbit-snn/mbt
moon test
# chain.jl example
moon run examples/chain/main.mbtmbt/
鈹溾攢鈹€ moon.mod # module: riantr/snn_mbt
鈹溾攢鈹€ moon.pkg
鈹溾攢鈹€ README.md
鈹溾攢鈹€ units.mbt # 30+ Float32 unit constants
鈹溾攢鈹€ units_test.mbt
鈹溾攢鈹€ time.mbt # Time struct
鈹溾攢鈹€ time_test.mbt
鈹溾攢鈹€ rng.mbt # Xoshiro256++ RNG
鈹溾攢鈹€ rng_test.mbt
鈹溾攢鈹€ neuron_if.mbt # IF neuron + DoubleExpSynapse state
鈹溾攢鈹€ neuron_if_test.mbt
鈹溾攢鈹€ neuron_adex.mbt # AdEx neuron + AdExPostSpike + AdExParameter::with_vr
鈹溾攢鈹€ neuron_iz.mbt # IZ neuron + IZParameter::fs
鈹溾攢鈹€ neuron_hh.mbt # HH neuron
鈹溾攢鈹€ neuron_ml.mbt # Morris-Lecar neuron
鈹溾攢鈹€ neuron_poisson.mbt # Poisson population
鈹溾攢鈹€ neuron_wc.mbt # Wilson-Cowan rate neuron
鈹溾攢鈹€ neuron_wc_test.mbt
鈹溾攢鈹€ stimulus_poisson.mbt # PoissonStimulus (Knuth)
鈹溾攢鈹€ stimulus_poisson_layer.mbt # PoissonLayer (N sources projecting sparsely to IF)
鈹溾攢鈹€ stimulus_current.mbt # CurrentStimulus + CurrentStimulusArray
鈹溾攢鈹€ connection_spiking.mbt # SpikingSynapse (CSR, delay_dist + pending queue)
鈹溾攢鈹€ connection_spiking_iz.mbt # SpikingSynapseIZ
鈹溾攢鈹€ connection_spiking_hh.mbt # SpikingSynapseHH
鈹溾攢鈹€ connection_compartment.mbt # CompartmentSynapseBall/Tripod (multi-compartment routing)
鈹溾攢鈹€ connection_receptor_tripod.mbt # ReceptorSynapseTripod (multi-receptor soma/dendrite routing)
鈹溾攢鈹€ receptor.mbt # NMDA primitives (Receptor / Receptors / gating / 2-state ODE)
鈹溾攢鈹€ connection_spiking_test.mbt # delay_dist tests
鈹溾攢鈹€ connection_rate.mbt # RateSynapse
鈹溾攢鈹€ sparse_matrix.mbt # SparseMatrixCSR + ConnectRule
鈹溾攢鈹€ compose.mbt # HeterogeneousModel + AnyPop/AnyStim
鈹溾攢鈹€ vecplot.mbt # text dump + ascii_plot
鈹溾攢鈹€ stdp.mbt # STDP (Gerstner 1996, MexicanHat, AntiSymmetric, STDPEntryKind)
鈹溾攢鈹€ stdp_test.mbt
鈹溾攢鈹€ stp.mbt # Markram STP (event-based update_traces! + 蟻 broadcast)
鈹溾攢鈹€ stp_test.mbt
鈹溾攢鈹€ sim.mbt # Model, Monitor, sim_for
鈹溾攢鈹€ examples/
鈹? 鈹斺攢鈹€ chain/
鈹? 鈹溾攢鈹€ main.mbt # port of SpikingNeuralNetworks.jl/examples/chain.jl
鈹? 鈹斺攢鈹€ moon.pkg
鈹斺攢鈹€ _build/ # moon build artifacts| Example | Network size | Population scales | Bit-exact? | Notes |
|---|---|---|---|---|
| chain.jl | 3 IF | unchanged | 鉁? | tiny; rates bit-exact |
| if_neuron.jl | 1 IF | unchanged | 鉁?(1 s vs 10 s) | Knuth Poisson slow at high rates |
| if_net.jl | 32E + 8I | 100脳 鈫? | 鉁? | original is 3200+800 |
| ei_inhibition.jl | 5 + 5 IF | unchanged | 鉁? | tiny; inhibition observable |
| cuba_net.jl | 80E + 20I | 100脳 鈫? | 鉁? | qualitative: drive on鈫抐ire, drive off鈫抯ilent |
| coba_net.jl | 80E + 20I | 100脳 鈫? | 鉁? | delay_dist now implemented (v0.10.3); spike timing differs from Julia's true 0.8ms delay because our loop only checks delivery once per dt |
| potjans_diesmann.jl | 120E + 40I | 100脳 鈫? | 鉁? | simplified to 4 layers |
| lkd2014.jl | 40E + 10I | 100脳 鈫? | 鉁? | IF instead of AdExSinExpParameter |
| festa2024.jl | 80E + 20I | 10脳 鈫? | 鉁? | structured inhibition + STDP |
| afferent_response.jl | 40E + 10I | 100脳 鈫? | 鉁? | single 谓_a (no sweep) |
| tsodyks.jl | 8 AdEx + 4 IF | unchanged | 鉁? | scaled-down paradoxical-effect |
| hh_net.jl | 8E + 4I HH | unchanged | 鉁? | tiny; HH gating dynamics |
pub struct ActivityDependentTurnover {
rate : Float
tau : Float
fraction : Float
tau_pre : Float
tau_post : Float
mu : Float
}fn ActivityDependentTurnover::new(rate? : Float, fraction? : Float, tau_pre? : Float, tau_post? : Float, mu? : Float) -> ActivityDependentTurnoverpub struct AdEx {
param : AdExParameter
spike : AdExPostSpike
n : Int
v : Array[Float]
w : Array[Float]
fire : Array[Bool]
threshold : Array[Float]
tabs : Array[Int]
i : Array[Float]
syn_curr : Array[Float]
ge : Array[Float]
gi : Array[Float]
he : Array[Float]
hi : Array[Float]
glu : Array[Float]
gaba : Array[Float]
gsyn_e : Array[Float]
gsyn_i : Array[Float]
e_e : Float
e_i : Float
tre : Float
tde : Float
tri : Float
tdi : Float
}fn AdEx::new_with_spike(n : Int, param : AdExParameter, spike : AdExPostSpike, rng : Xoshiro) -> AdExpub struct AdExHet {
param : AdExParameterHet
spike : AdExPostSpike
n : Int
v : Array[Float]
w : Array[Float]
fire : Array[Bool]
threshold : Array[Float]
tabs : Array[Int]
i : Array[Float]
syn_curr : Array[Float]
ge : Array[Float]
gi : Array[Float]
he : Array[Float]
hi : Array[Float]
glu : Array[Float]
gaba : Array[Float]
gsyn_e : Array[Float]
gsyn_i : Array[Float]
e_e : Float
e_i : Float
tre : Float
tde : Float
tri : Float
tdi : Float
}pub(all) struct AdExModel {
pops : Array[AdEx]
conns : Array[SpikingSynapseAdEx]
monitors : Array[MonitorAdEx]
}pub(all) struct AdExMultiTimescaleParameter {
tm : Float
vt : Float
vr : Float
el : Float
r : Float
dt_slope : Float
v_spike : Float
tau_w : Float
a : Float
b : Float
tau_abs : Float
tau_r : Array[Float]
tau_d : Array[Float]
glu_receptors : Array[Int]
gaba_receptors : Array[Int]
e_e : Float
e_i : Float
gsyn_e : Float
gsyn_i : Float
at : Float
tau_t : Float
}pub struct AdExParameter {
c : Float
gl : Float
vt : Float
vr : Float
el : Float
tm : Float
r : Float
dt_slope : Float
tw : Float
a : Float
b : Float
}fn AdExParameter::custom(tm~ : Float, vt~ : Float, vr~ : Float, el~ : Float, r~ : Float) -> AdExParameterpub struct AdExPostSpike {
at : Float
tau_a : Float
ap_membrane : Float
tabs_const : Float
up : Float
}pub struct AdExSinExp {
param : AdExSinExpParameter
spike : AdExPostSpike
n : Int
v : Array[Float]
w : Array[Float]
fire : Array[Bool]
threshold : Array[Float]
tabs : Array[Int]
i : Array[Float]
syn_curr : Array[Float]
ge : Array[Float]
gi : Array[Float]
glu : Array[Float]
gaba : Array[Float]
gsyn_e : Array[Float]
gsyn_i : Array[Float]
e_e : Float
e_i : Float
tau_e : Float
tau_i : Float
}fn AdExSinExp::new_with_spike(n : Int, param : AdExSinExpParameter, spike : AdExPostSpike, rng : Xoshiro) -> AdExSinExppub(all) struct AdExSinExpParameter {
c : Float
gl : Float
vt : Float
vr : Float
el : Float
tm : Float
r : Float
dt_slope : Float
tw : Float
a : Float
b : Float
}pub struct AdditiveNorm {
tau : Float
}pub struct AggregateScaling {
param : AggregateScalingParameter
n : Int
targets : Array[SynapseTarget]
wt : Array[Float]
wt_total : Array[Float]
y : Array[Float]
mu : Array[Float]
last_plasticity_step : Int
plasticity_interval_steps : Int
}fn AggregateScaling::new(n : Int, targets : Array[SynapseTarget], param : AggregateScalingParameter) -> AggregateScalingfn AggregateScaling::with_plasticity_interval(c : AggregateScaling, interval_steps : Int) -> AggregateScalingpub struct AggregateScalingParameter {
tau : Float
tau_a : Float
tau_e : Float
y : Array[Float]
w_min : Float
w_max : Float
}fn AggregateScalingParameter::new(tau? : Float, tau_a~ : Float, tau_e~ : Float, y : Array[Float], w_min? : Float, w_max? : Float) -> AggregateScalingParameterfn AggregateScalingParameter::uniform(n : Int, rate_hz : Float, tau? : Float, tau_a? : Float, tau_e? : Float, w_min? : Float, w_max? : Float) -> AggregateScalingParameterpub(all) enum AnyPop {
IF_(IF)
AdEx_(AdEx)
AdExSinExp_(AdExSinExp)
IZ_(IZ)
HH_(HH)
ML_(MorrisLecar)
Poisson_(Poisson)
WC_(WilsonCowan)
HetRec_(HetRec)
IFCANAHP_(IFCANAHP)
}pub(all) enum AnyStim {
PoissonIF_(PoissonStimulusIF)
PoissonLayer_(PoissonLayerStimulus)
BalancedIF_(BalancedStimulus)
CurrentIF_(CurrentStimulusIF)
CurrentArr_(CurrentStimulusArray)
TimedStim_(SpikeTimeStimulus, Float)
}pub struct AvgPool2dParam {
kh : Int
kw : Int
stride : Int
pad : Int
}pub(all) struct BalancedParameter {
kIE : Float
beta : Float
tau : Float
r0 : Float
w : Float
wIE : Float
same_input : Bool
}fn BalancedParameter::new(kIE? : Float, beta? : Float, tau? : Float, r0? : Float, w? : Float, wIE? : Float, same_input? : Bool) -> BalancedParameterfn BalancedStimulus::new(pop : IF, sym_e? : String, sym_i? : String, param? : BalancedParameter, seed? : UInt64) -> BalancedStimuluspub struct BallAndStick {
soma_param : AdExParameter
soma_spike : AdExPostSpike
dend : Dendrite
i_s : Array[Float]
i_d : Array[Float]
ge_s : Array[Float]
gi_s : Array[Float]
ge_d : Array[Float]
gi_d : Array[Float]
glu_s : Array[Float]
gaba_s : Array[Float]
glu_d : Array[Float]
gaba_d : Array[Float]
e_e : Float
e_i : Float
tau_e : Float
tau_i : Float
gsyn_e : Float
gsyn_i : Float
n : Int
v_s : Array[Float]
w_s : Array[Float]
v_d : Array[Float]
fire : Array[Bool]
threshold : Array[Float]
tabs : Array[Int]
dv : Array[Float]
dv_temp : Array[Float]
syn_curr_s : Array[Float]
syn_curr_d : Array[Float]
ic : Float
}fn BatchNorm2d::with_gamma_beta(gamma : Array[Float], beta : Array[Float], momentum? : Float, eps? : Float) -> BatchNorm2dpub struct CaPlasticityEntry {
conn_index : Int
n_pre : Int
n_post : Int
param : CaPlasticityParameter
vars : CaPlasticityVariables
t_now : Array[Float]
}fn CaPlasticityEntry::change_plasticity(e : CaPlasticityEntry, new_param : CaPlasticityParameter) -> Unitfn CaPlasticityEntry::new(conn_index : Int, n_pre : Int, n_post : Int, param? : CaPlasticityParameter) -> CaPlasticityEntrypub(all) struct CaPlasticityParameter {
a_pre : Float
a_post : Float
tau_pre : Float
tau_post : Float
w_max : Float
w_min : Float
}fn CaPlasticityParameter::custom(a_pre? : Float, a_post? : Float, tau_pre? : Float, tau_post? : Float, w_max? : Float, w_min? : Float) -> CaPlasticityParameterpub(all) struct ClopathSTDP {
a_ltd : Float
a_ltp : Float
theta_ltd : Float
theta_ltp : Float
tau_s : Float
tau_u : Float
tau_v : Float
tau_x : Float
tau_1 : Float
eps : Float
w_min : Float
w_max : Float
inv_tau_u : Float
inv_tau_v : Float
inv_tau_x : Float
inv_tau_1 : Float
}pub struct CompartmentSynapseBall {
pre : IF
post : BallAndStick
sym : String
target : String
matrix : SparseMatrixCSR
rho : Array[Float]
delays : Array[Float]
pending_times : Array[Float]
pending_posts : Array[Int]
pending_weights : Array[Float]
}fn CompartmentSynapseBall::random(pre : IF, post : BallAndStick, sym : String, target : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> CompartmentSynapseBallfn CompartmentSynapseTripod::random(pre : IF, post : Tripod, sym : String, target : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> CompartmentSynapseTripodfn CompartmentSynapseTripod::set_delays(c : CompartmentSynapseTripod, delays : Array[Float]) -> Unitpub struct Confavreux2025Parameter {
tau_ampa : Float
tau_nmda : Float
tau_gaba : Float
e_i : Float
e_e : Float
alpha : Float
}pub(all) enum ConnectRule {
Bernoulli
FixedIn
FixedOut
}fn Conv2dParam::new(weight : Array[Float], bias : Array[Float], c_out : Int, c_in : Int, kh : Int, kw : Int, stride? : Int, pad? : Int) -> Conv2dParampub(all) struct CorridorEnv {
n_cells : Int
goal_side : Int
step_penalty : Float
goal_reward : Float
max_steps : Int
}pub struct CosineAnnealingLR {
eta_max : Float
eta_min : Float
t_max : Int
current_step : Int
}fn CurrentNoise::custom(n : Int, i_base : Float, noise_sigma : Float, alpha : Float) -> CurrentNoisefn CurrentStimulusArray::new(i : Array[Float], n : Int, i_base : Float, rng : Xoshiro, noise_sigma? : Float) -> CurrentStimulusArrayfn CurrentStimulusIF::new(pop : IF, i_base : Float, rng : Xoshiro, noise_sigma? : Float) -> CurrentStimulusIFpub(all) struct CurrentSynapse {
tau_e : Float
tau_i : Float
}pub struct DSac {
policy : LinearSoftmaxPolicy
q1 : LinearGaussianQNet
q2 : LinearGaussianQNet
q1_target : LinearGaussianQNet
q2_target : LinearGaussianQNet
alpha : Float
}pub(all) struct DeltaSynapse {
}pub(all) struct DendNeuronParameter {
ds : Array[Array[Float]]
physiology : Physiology
geometry : Array[Array[String]]
tree_type : DendriticTreeType
}fn DendNeuronParameter::custom(ds~ : Array[Array[Float]], physiology? : Physiology, geometry? : Array[Array[String]]) -> DendNeuronParameterpub enum DendriticTreeType {
BallAndStick
Tripod
Multipod
}pub struct DoubleExpCurrentParameter {
tau_re : Float
tau_de : Float
tau_ri : Float
tau_di : Float
}pub(all) struct DoubleExpSynapse {
tau_re : Float
tau_de : Float
tau_ri : Float
tau_di : Float
e_i : Float
e_e : Float
gsyn_e : Float
gsyn_i : Float
}pub(all) struct Dropout {
p : Float
training : Bool
}pub struct Duarte2019 {
pv_tm : Float
pv_el : Float
pv_vt : Float
pv_vr : Float
pv_tau_abs : Float
pv_gsyn_e : Float
pv_gsyn_i : Float
sst_tm : Float
sst_el : Float
sst_vt : Float
sst_vr : Float
sst_tau_abs : Float
sst_gsyn_e : Float
sst_gsyn_i : Float
sst_b : Float
sst_tw : Float
adex_tm : Float
adex_el : Float
adex_vt : Float
adex_tau_abs : Float
adex_gsyn_e : Float
adex_gsyn_i : Float
}pub struct EmptyConnection {
name : String
} let ec = ec.with_name("placeholder")pub struct EmptyParam {
p_type : String
}pub struct ExponentialLR {
base_lr : Float
gamma : Float
current_step : Int
}pub(all) struct ExtendedIFParameter {
cm : Float
vt : Float
vr : Float
el : Float
gl : Float
tau_e : Float
tau_i : Float
e_i : Float
e_e : Float
tau_abs : Float
alpha : Float
}fn ExtendedIFParameter::custom(cm~ : Float, vt~ : Float, vr~ : Float, el~ : Float, gl~ : Float, tau_e~ : Float, tau_i~ : Float, e_i~ : Float, e_e~ : Float, tau_abs~ : Float, alpha~ : Float) -> ExtendedIFParameterpub(all) enum FilterRule {
Greater(Int)
Less(Int)
Equal(Int)
DropNoise
}pub struct GIFParameter {
c : Float
gl : Float
tm : Float
vt : Float
vr : Float
el : Float
r : Float
dt_slope : Float
a : Float
b : Float
tw : Float
tau_abs : Float
}pub struct GridWorld {
n_rows : Int
n_cols : Int
start : Int
goal : Int
step_penalty : Float
goal_reward : Float
max_steps : Int
}pub struct HHParameter {
cm : Float
gl : Float
el : Float
ek : Float
en : Float
gn : Float
gk : Float
vt : Float
tau_e : Float
tau_i : Float
e_e : Float
e_i : Float
}pub(all) struct HetRecParameter {
nd : Int
overlap : Float
tau_d_low : Float
tau_d_high : Float
rate_low : Float
rate_high : Float
tau_abs : Float
steepness : Float
tau_m : Float
tau_rate : Float
}pub(all) struct HeterogeneousModel {
pops : Array[AnyPop]
conns : Array[SpikingSynapse]
stims : Array[AnyStim]
time : Time
monitors : Array[Monitor]
stdp_entries : Array[STDPEntryKind]
stp_entries : Array[STPEntryKind]
}pub struct IF {
param : IFParameter
spike : PostSpike
n : Int
v : Array[Float]
w : Array[Float]
fire : Array[Bool]
tabs : Array[Int]
i : Array[Float]
syn_curr : Array[Float]
ge : Array[Float]
gi : Array[Float]
he : Array[Float]
hi : Array[Float]
glu : Array[Float]
gaba : Array[Float]
gsyn_e : Array[Float]
gsyn_i : Array[Float]
e_e : Float
e_i : Float
tre : Float
tde : Float
tri : Float
tdi : Float
}pub(all) struct IFCANAHParameter {
area : Float
c : Float
vt : Float
vr : Float
tau_abs : Float
gl : Float
vl : Float
delta_ca : Float
ca0 : Float
tau_ca : Float
v_ahp : Float
g_ahp : Float
alpha_ahp : Float
beta_ahp : Float
gamma_ahp : Float
v_can : Float
g_can : Float
beta_can : Float
alpha_can : Float
gamma_can : Float
}pub struct IFParameter {
c : Float
gl : Float
tm : Float
vt : Float
vr : Float
el : Float
r : Float
dt_slope : Float
a : Float
b : Float
tw : Float
}fn IFParameterGsyn::from_base(base : IFParameter, gsyn_e : Float, gsyn_i : Float) -> IFParameterGsynpub struct IFSinExp {
param : IFSinExpParameter
spike : PostSpike
n : Int
v : Array[Float]
w : Array[Float]
fire : Array[Bool]
tabs : Array[Int]
i : Array[Float]
syn_curr : Array[Float]
ge : Array[Float]
gi : Array[Float]
glu : Array[Float]
gaba : Array[Float]
gsyn_e : Array[Float]
gsyn_i : Array[Float]
fire_t : Array[Int]
fire_t_delta : Array[Int]
}pub struct IFSinExpParameter {
c : Float
gl : Float
tm : Float
vt : Float
vr : Float
el : Float
r : Float
dt_slope : Float
a : Float
b : Float
tw : Float
tau_e : Float
tau_i : Float
}pub(all) struct ISTDP {
eta : Float
r0 : Float
vd : Float
tau_d : Double
tau_y : Float
alpha : Float
w_min : Float
w_max : Float
}fn IZ::init_with_postspike(n : Int, param : IZParameter, v_init : Float, u_init : Float, postspike : IZPostSpike) -> IZpub struct IZParameter {
a : Float
b : Float
c : Float
d : Float
tau_e : Float
tau_i : Float
e_e : Float
e_i : Float
}pub(all) struct IZPostSpike {
tabs_const : Int
}pub struct Identity {
n : Int
param : IdentityParameter
g : Array[Float]
h : Array[Float]
fire : Array[Bool]
spikecount : Array[Float]
}pub(all) struct IdentityParameter {
dummy : Float
}pub(all) struct InhomogeneousPoisson {
n : Int
param : InhomogeneousPoissonParam
fire : Array[Bool]
r : Array[Float]
noise : Array[Float]
randcache_beta : Array[Float]
}fn InhomogeneousPoisson::new(n : Int, param : InhomogeneousPoissonParam, rng : Xoshiro) -> InhomogeneousPoissonpub(all) struct InhomogeneousPoissonParam {
beta : Float
tau : Float
r0 : Float
rate_timescale : Float
}fn InhomogeneousPoissonParam::custom(beta : Float, tau : Float, r0 : Float) -> InhomogeneousPoissonParampub(all) struct IstdpPotential {
eta : Float
v0 : Float
tau_y : Float
w_max : Float
w_min : Float
}pub(all) struct IstdpPotentialEntry {
conn_index : Int
n_pre : Int
n_post : Int
param : IstdpPotential
vars : IstdpPotentialVariables
t_now : Array[Float]
}fn IstdpPotentialEntry::change_plasticity(e : IstdpPotentialEntry, new_param : IstdpPotential) -> Unitfn IstdpPotentialEntry::new(conn_index : Int, n_pre : Int, n_post : Int, param? : IstdpPotential) -> IstdpPotentialEntrypub(all) struct IstdpRate {
eta : Float
r : Float
tau_y : Float
w_max : Float
w_min : Float
}pub(all) struct IstdpRateEntry {
conn_index : Int
n_pre : Int
n_post : Int
param : IstdpRate
vars : IstdpRateVariables
t_now : Array[Float]
}fn IstdpRateEntry::new(conn_index : Int, n_pre : Int, n_post : Int, param? : IstdpRate) -> IstdpRateEntrypub(all) struct IstdpTime {
eta : Float
tau_y : Float
w_max : Float
w_min : Float
}pub struct LKD2014 {
tm : Float
vt : Float
el : Float
vr : Float
r : Float
tau_abs : Float
e_i : Float
e_e : Float
at : Float
pv_tm : Float
pv_el : Float
pv_vr : Float
pv_vt : Float
}pub struct LKD2014Soma {
es_e_p : Float
es_e_mu : Float
e_to_pv_p : Float
e_to_pv_mu : Float
pv_to_e_p : Float
pv_to_e_mu : Float
pv_to_pv_p : Float
pv_to_pv_mu : Float
}pub enum Layer {
Conv2d(Conv2dParam)
ReLU
MaxPool2d(MaxPool2dParam)
Flatten
Linear(LinearParam)
BatchNorm2d(BatchNorm2d)
LayerNorm(LayerNorm)
}pub enum LayerCache {
Conv2d(Array[Float], Int, Int, Int, Int)
ReLU(Array[Float])
MaxPool2d(Array[Int], Int, Int, Int, Int, Int, Int, Int, Int)
Flatten
Linear(Array[Float], Int)
BatchNorm2d(BatchNormCache)
LayerNorm(LayerNormCache)
}fn LinearParam::new(weight : Array[Float], bias : Array[Float], in_features : Int, out_features : Int) -> LinearParampub enum Loc[A] {
Const(A)
Memory(Int)
}pub(all) struct MarkramSTPEntry {
conn_index : Int
vars : MarkramSTPVariables
param : MarkramSTPParameter
}fn MarkramSTPEntry::new(conn_index : Int, n_pre : Int, n_post : Int, param? : MarkramSTPParameter) -> MarkramSTPEntrypub(all) struct MarkramSTPEntryHet {
conn_index : Int
vars : MarkramSTPVariables
param : MarkramSTPParameterHet
}fn MarkramSTPEntryHet::new(conn_index : Int, n_pre : Int, n_post : Int, param : MarkramSTPParameterHet) -> MarkramSTPEntryHetpub(all) struct MarkramSTPEntryTimestep {
conn_index : Int
vars : MarkramSTPVariables
param : MarkramSTPParameterTimestep
}fn MarkramSTPEntryTimestep::new(conn_index : Int, n_pre : Int, n_post : Int, param? : MarkramSTPParameterTimestep) -> MarkramSTPEntryTimesteppub(all) struct MarkramSTPParameter {
tau_d : Float
tau_f : Float
u : Float
w_max : Float
w_min : Float
}pub(all) struct MarkramSTPParameterTimestep {
u : Float
tau_f : Float
tau_d : Float
w_max : Float
w_min : Float
}fn MarkramSTPVariables::new(n_pre : Int, n_post : Int, param : MarkramSTPParameter) -> MarkramSTPVariablespub struct MaxPool2dParam {
kh : Int
kw : Int
stride : Int
pad : Int
}fn MiniSpikeFormer::new(d_model : Int, n_heads : Int, beta : Float, n_classes : Int, seed : UInt64) -> MiniSpikeFormerpub struct MonitorAdExSinExp {
pop : AdExSinExp
sym : String
data : Array[Float]
times : Array[Float]
neuron : Int
}pub struct MorrisLecarParameter {
cm : Float
el : Float
ek : Float
eca : Float
gl : Float
gk : Float
gca : Float
tau_e : Float
tau_i : Float
v1 : Float
v2 : Float
v3 : Float
v4 : Float
phi : Float
e_e : Float
e_i : Float
}pub struct MultiHeadAttention {
d_model : Int
num_heads : Int
d_k : Int
w_q : LinearParam
w_k : LinearParam
w_v : LinearParam
w_o : LinearParam
}pub struct MultiplicativeNorm {
tau : Float
}pub struct Multipod {
n : Int
nd : Int
v_s : Array[Float]
w_s : Array[Float]
v_d : Array[Array[Float]]
ge_s : Array[Float]
gi_s : Array[Float]
he_s : Array[Float]
hi_s : Array[Float]
he_d : Array[Array[Float]]
hi_d : Array[Array[Float]]
g_d : Array[Array[Array[Float]]]
h_d : Array[Array[Array[Float]]]
glu_receptors : Array[Int]
gaba_receptors : Array[Int]
alpha : Array[Float]
fire : Array[Bool]
after_spike : Array[Int]
postspike : PostSpike
theta : Array[Float]
dv : Array[Float]
dv_temp : Array[Float]
cs : Array[Float]
iv : Array[Float]
soma_syn : SingleExpSynapse
dend_syn : SingleExpSynapse
nmda : NMDAVoltageDependency
dendrites : Array[Dendrite]
}pub(all) struct NLTAH {
tau : Float
lambda_ : Float
mu : Float
}pub struct NMDAVoltageDependency {
b : Float
k : Float
mg : Float
}fn NStepBuffer::n_step_return(self : NStepBuffer, root : Int, gamma : Float) -> (Float, Int, Int, Int, Bool) G_n = Σ_{k=0..n-1} γ^k · r_{root+k}fn NStepBuffer::push(self : NStepBuffer, s : Int, a : Int, r : Float, s_next : Int, done : Bool) -> Boolpub struct NetworkModel {
is_valid : Bool
}pub struct NetworkSummary {
n_populations : Int
n_connections : Int
n_stimuli : Int
n_monitors : Int
n_stdp_entries : Int
n_stp_entries : Int
current_time : Float
total_neurons : Int
}fn NoisyLinearParam::new(weight_mu : Array[Float], weight_sigma : Array[Float], bias_mu : Array[Float], bias_sigma : Array[Float], in_features : Int, out_features : Int) -> NoisyLinearParampub struct NoisyQNet {
layer1 : NoisyLinearParam
layer2 : NoisyLinearParam
n_states : Int
hidden : Int
n_actions : Int
}pub(all) struct PINningSparseSynapse {
pre : WilsonCowan
post : WilsonCowan
matrix : SparseMatrixCSR
p_vals : Array[Float]
rI : Array[Float]
rJ : Array[Float]
g : Array[Float]
q : Array[Float]
f : Array[Float]
}fn PINningSparseSynapse::new(pre : WilsonCowan, post : WilsonCowan, mu : Float, p : Float, alpha : Float, rng : Xoshiro) -> PINningSparseSynapsepub struct ParityResult {
name : String
n_compared : Int
max_error : Float
max_ulp : Int
passed : Bool
}pub(all) struct Physiology {
ri : Float
rd : Float
cd : Float
}pub struct Poisson {
param : PoissonHomoParameter
n : Int
fire : Array[Bool]
randcache : Array[Float]
rng : Xoshiro
}pub struct PoissonHomoParameter {
rate : Float
}pub(all) struct PoissonLayer {
rate : Float
n_sources : Int
active : Array[Bool]
mu : Float
sigma : Float
p : Float
dist : String
rule : String
}fn PoissonLayer::with_conn(rate : Float, n_sources : Int, active : Array[Bool], mu : Float, sigma : Float, p : Float, dist : String, rule : String) -> PoissonLayerfn PoissonLayerStimulus::new(param : PoissonLayer, post : IF, sym : String, rng : Xoshiro) -> PoissonLayerStimuluspub struct PoissonLayerStimulusBallAndStick {
param : PoissonLayer
post : BallAndStick
weights : Array[Float]
connectivity : Array[Bool]
target_compartment : String
target_kind : String
rng : Xoshiro
}fn PoissonLayerStimulusBallAndStick::new(param : PoissonLayer, post : BallAndStick, target_compartment : String, target_kind : String, mu : Float, sigma : Float, p_conn : Float, rng : Xoshiro) -> PoissonLayerStimulusBallAndStickpub struct PoissonLayerStimulusTripod {
param : PoissonLayer
post : TripodHet
weights : Array[Float]
connectivity : Array[Bool]
target_compartment : String
target_kind : String
rng : Xoshiro
}fn PoissonLayerStimulusTripod::new(param : PoissonLayer, post : TripodHet, target_compartment : String, target_kind : String, mu : Float, sigma : Float, p_conn : Float, rng : Xoshiro) -> PoissonLayerStimulusTripodpub struct PoissonStimulusIF {
param : PoissonFixed
neurons : Array[Int]
g : Array[Float]
rng : Xoshiro
}pub(all) struct PopIndex {
name : String
start : Int
end_ : Int
}pub struct PostSpike {
tabs_const : Float
}fn PrioritizedBuffer::new(capacity : Int, alpha : Float, beta : Float, epsilon : Float) -> PrioritizedBufferfn PrioritizedBuffer::push(self : PrioritizedBuffer, s : Int, a : Int, r : Float, s_next : Int, done : Bool) -> Unitfn PrioritizedBuffer::sample(self : PrioritizedBuffer, batch_size : Int, rng : Xoshiro) -> (Array[Int], Array[Int], Array[Int], Array[Float], Array[Int], Array[Bool], Array[Float])fn PrioritizedReplayBuffer::new(capacity : Int, alpha : Float, beta : Float, eps : Float) -> PrioritizedReplayBufferfn PrioritizedReplayBuffer::push(self : PrioritizedReplayBuffer, s : Int, a : Int, r : Float, s_next : Int, done : Bool) -> Unitfn PrioritizedReplayBuffer::update_priorities(self : PrioritizedReplayBuffer, slot_indices : Array[Int], td_errors : Array[Float]) -> Unitpub struct Quaresima2023Dend {
e_to_ed_p : Float
e_to_ed_mu : Float
e_to_pv_p : Float
e_to_pv_mu : Float
e_to_sst_p : Float
e_to_sst_mu : Float
pv_to_e_p : Float
pv_to_e_mu : Float
pv_to_sst_p : Float
pv_to_sst_mu : Float
pv_to_pv_p : Float
pv_to_pv_mu : Float
sst_to_ed_p : Float
sst_to_ed_mu : Float
sst_to_pv_p : Float
sst_to_pv_mu : Float
sst_to_sst_p : Float
sst_to_sst_mu : Float
}pub struct RandomTurnover {
rate : Float
tau : Float
threshold : Float
mu : Float
}fn RateSynapse::new(pre : WilsonCowan, post : WilsonCowan, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> RateSynapsepub struct Receptor {
e_rev : Float
tau_r : Float
tau_d : Float
g0 : Float
gsyn : Float
alpha : Float
tau_r_inv : Float
tau_d_inv : Float
is_nmda : Bool
target : String
}fn ReceptorSynapse::new(pre : IF, post : IF, syn : Receptors, nmda_dep : NMDAVoltageDependency, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> ReceptorSynapsepub struct ReceptorSynapseTripod {
pre : IF
post : TripodHet
matrix : SparseMatrixCSR
target_compartment : String
receptors : Receptors
nmda_dep : NMDAVoltageDependency
g_state : Array[Float]
h_state : Array[Float]
ge_out : Array[Float]
gi_out : Array[Float]
}fn ReceptorSynapseTripod::new(pre : IF, post : TripodHet, target_compartment : String, receptors : Receptors, nmda_dep : NMDAVoltageDependency, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> ReceptorSynapseTripodpub struct RecurrentSac {
policy : LstmPolicy
q1 : LstmQNet
q2 : LstmQNet
q1_target : LstmQNet
q2_target : LstmQNet
log_alpha : Float
target_entropy : Float
alpha_lr : Float
}fn RecurrentSac::new(n_cells : Int, d_h : Int, log_alpha_init : Float, target_entropy : Float, alpha_lr : Float, seed : UInt64) -> RecurrentSacfn RecurrentSacEpisode::new(obs_seq : Array[Array[Float]], next_obs_seq : Array[Array[Float]], actions : Array[Int], rewards : Array[Float], dones : Array[Bool], initial_pos : Int, goal_side : Int) -> RecurrentSacEpisodepub struct ReduceLROnPlateau {
base_lr : Float
factor : Float
patience : Int
threshold : Float
best_metric : Float
num_bad_epochs : Int
current_lr : Float
}fn ReduceLROnPlateau::new(base_lr : Float, factor : Float, patience : Int, threshold : Float) -> ReduceLROnPlateaufn ReplayBuffer::push(self : ReplayBuffer, s : Int, a : Int, r : Float, s_next : Int, done : Bool) -> Unitfn ReplayBuffer::sample(self : ReplayBuffer, batch_size : Int, rng : Xoshiro) -> (Array[Int], Array[Int], Array[Float], Array[Int], Array[Bool])pub struct ResidualBlock {
conv1 : Conv2dParam
bn1 : BatchNorm2d
conv2 : Conv2dParam
bn2 : BatchNorm2d
shortcut_conv : Conv2dParam?
shortcut_bn : BatchNorm2d?
stride : Int
}pub struct ResidualCache {
x : Array[Float]
sum : Array[Float]
bn1_out : Array[Float]
bn1_cache : BatchNormCache
bn2_cache : BatchNormCache
shortcut_bn_cache : BatchNormCache?
shortcut_output : Array[Float]
conv2_input : Array[Float]
conv2_input_n : Int
conv2_input_c : Int
conv2_input_h : Int
conv2_input_w : Int
n : Int
c : Int
h : Int
w : Int
}pub struct ResidualGrads {
conv1_d_weight : Array[Float]
conv1_d_bias : Array[Float]
bn1_d_gamma : Array[Float]
bn1_d_beta : Array[Float]
conv2_d_weight : Array[Float]
conv2_d_bias : Array[Float]
bn2_d_gamma : Array[Float]
bn2_d_beta : Array[Float]
shortcut_conv_d_weight : Array[Float]?
shortcut_conv_d_bias : Array[Float]?
shortcut_bn_d_gamma : Array[Float]?
shortcut_bn_d_beta : Array[Float]?
}pub(all) struct STDPAntiSymmetric {
a_x : Float
a_y : Float
tau_x : Float
tau_y : Float
alpha_pre : Float
alpha_post : Float
w_max : Float
w_min : Float
}pub(all) struct STDPConfavreux2025 {
eta : Float
alpha : Float
beta : Float
kappa : Float
gamma : Float
tau_pre : Float
tau_post : Float
w_max : Float
w_min : Float
}pub struct STDPEntry {
conn_index : Int
n_pre : Int
n_post : Int
vars : STDPVariables
param : STDPGerstner
t_now : Array[Float]
}pub struct STDPEntryAntiSymmetric {
conn_index : Int
n_pre : Int
n_post : Int
param : STDPAntiSymmetric
vars : STDPAntiSymmetricVariables
t_now : Array[Float]
}fn STDPEntryAntiSymmetric::change_plasticity(e : STDPEntryAntiSymmetric, new_param : STDPAntiSymmetric) -> Unitfn STDPEntryAntiSymmetric::new(conn_index : Int, n_pre : Int, n_post : Int, param? : STDPAntiSymmetric) -> STDPEntryAntiSymmetricpub struct STDPEntryConfavreux2025 {
conn_index : Int
n_pre : Int
n_post : Int
param : STDPConfavreux2025
vars : STDPVariables
t_now : Array[Float]
}fn STDPEntryConfavreux2025::change_plasticity(e : STDPEntryConfavreux2025, new_param : STDPConfavreux2025) -> Unitfn STDPEntryConfavreux2025::new(conn_index : Int, n_pre : Int, n_post : Int, param? : STDPConfavreux2025) -> STDPEntryConfavreux2025pub(all) enum STDPEntryKind {
Gerstner_(STDPEntry)
MexicanHat_(STDPEntryMexicanHat)
AntiSymmetric_(STDPEntryAntiSymmetric)
Confavreux2025_(STDPEntryConfavreux2025)
IstdpRate_(IstdpRateEntry)
IstdpPotential_(IstdpPotentialEntry)
Symmetric_(STDPEntrySymmetric)
CaPlasticity_(CaPlasticityEntry)
}pub struct STDPEntryMexicanHat {
conn_index : Int
n_pre : Int
n_post : Int
param : STDPMexicanHat
tpre : Array[Float]
tpost : Array[Float]
t_now : Array[Float]
}fn STDPEntryMexicanHat::change_plasticity(e : STDPEntryMexicanHat, new_param : STDPMexicanHat) -> Unitfn STDPEntryMexicanHat::new(conn_index : Int, n_pre : Int, n_post : Int, param? : STDPMexicanHat) -> STDPEntryMexicanHatpub struct STDPEntrySymmetric {
conn_index : Int
n_pre : Int
n_post : Int
param : STDPSymmetric
vars : STDPSymmetricVariables
t_now : Array[Float]
}fn STDPEntrySymmetric::new(conn_index : Int, n_pre : Int, n_post : Int, param? : STDPSymmetric) -> STDPEntrySymmetricpub(all) struct STDPGerstner {
a_pre : Float
a_post : Float
tau_pre : Float
tau_post : Float
w_max : Float
w_min : Float
}pub(all) struct STDPMexicanHat {
a : Float
tau : Float
w_max : Float
w_min : Float
}pub(all) struct STDPSymmetric {
a_x : Float
a_y : Float
tau_x : Float
tau_y : Float
alpha_pre : Float
alpha_post : Float
w_max : Float
w_min : Float
}pub(all) enum STPEntryKind {
MarkramSTP_(MarkramSTPEntry)
MarkramSTPHet_(MarkramSTPEntryHet)
MarkramSTPTimestep_(MarkramSTPEntryTimestep)
}pub struct Sac {
policy : LinearSoftmaxPolicy
q1 : LinearQNet
q2 : LinearQNet
q1_target : LinearQNet
q2_target : LinearQNet
alpha : Float
}pub struct SacAutoAlpha {
policy : LinearSoftmaxPolicy
q1 : LinearQNet
q2 : LinearQNet
q1_target : LinearQNet
q2_target : LinearQNet
log_alpha : Float
target_entropy : Float
alpha_lr : Float
}fn SacAutoAlpha::new(n_states : Int, n_actions : Int, log_alpha_init : Float, target_entropy : Float, alpha_lr : Float, seed : UInt64) -> SacAutoAlphapub struct SimLog {
t : Float
active_monitors : Int
total_spikes : Int
}pub struct SingleExpParameter {
tau_e : Float
tau_i : Float
e_i : Float
e_e : Float
gsyn_e : Float
gsyn_i : Float
}pub(all) struct SingleExpSynapse {
tau_e : Float
tau_i : Float
e_i : Float
e_e : Float
gsyn_e : Float
gsyn_i : Float
}pub(all) enum SmoothSkew {
None
Left
Right
}fn SparseMatrixCSR::forward(m : SparseMatrixCSR, pre_fire : Array[Bool], post_g : Array[Float]) -> Unitfn SparseMatrixCSR::forward_rate(m : SparseMatrixCSR, pre_rate : Array[Float], post_g : Array[Float]) -> Unitfn SparseMatrixCSR::random(rows : Int, cols : Int, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> SparseMatrixCSRfn SparseMatrixCSR::random_with_rule(rows : Int, cols : Int, mu : Float, sigma : Float, p : Float, rule : ConnectRule, rng : Xoshiro) -> SparseMatrixCSRpub struct SpikeTimeStimulus {
n : Int
param : SpikeTimeParameter
next_spike : Array[Float]
next_index : Array[Int]
fire : Array[Bool]
g : Array[Float]
}fn SpikeTimeStimulus::new(e_pop : IF, sym : String, spiketimes : Array[Float], neurons : Array[Int]) -> SpikeTimeStimuluspub struct SpikingAttention {
d_model : Int
num_heads : Int
d_k : Int
beta : Float
w_q : LinearParam
w_k : LinearParam
w_v : LinearParam
w_o : LinearParam
}fn SpikingAttention::new(d_model : Int, num_heads : Int, beta : Float, seed : UInt64) -> SpikingMultiHeadAttentionpub struct SpikingCrossAttention {
d_model : Int
num_heads : Int
d_k : Int
beta : Float
w_q : LinearParam
w_k : LinearParam
w_v : LinearParam
w_o : LinearParam
}fn SpikingCrossAttention::new(d_model : Int, num_heads : Int, beta : Float, seed : UInt64) -> SpikingCrossAttentionpub struct SpikingMultiHeadAttention {
d_model : Int
num_heads : Int
d_k : Int
beta : Float
w_q : LinearParam
w_k : LinearParam
w_v : LinearParam
w_o : LinearParam
}fn SpikingMultiHeadAttention::new(d_model : Int, num_heads : Int, beta : Float, seed : UInt64) -> SpikingMultiHeadAttentionfn SpikingSynapse::random(pre : IF, post : IF, sym : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> SpikingSynapsefn SpikingSynapse::random_with_delays(pre : IF, post : IF, sym : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro, d_mean : Float, d_std : Float) -> SpikingSynapsefn SpikingSynapse::random_with_rule(pre : IF, post : IF, sym : String, mu : Float, sigma : Float, p : Float, rule : ConnectRule, rng : Xoshiro) -> SpikingSynapse let s = s.with_name("my_syn")fn SpikingSynapseAdEx::random(pre : AdEx, post : AdEx, sym : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> SpikingSynapseAdExfn SpikingSynapseAdEx::random_with_rule(pre : AdEx, post : AdEx, sym : String, mu : Float, sigma : Float, p : Float, rule : ConnectRule, rng : Xoshiro) -> SpikingSynapseAdExfn SpikingSynapseHH::random(pre : HH, post : HH, sym : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> SpikingSynapseHHfn SpikingSynapseIZ::random(pre : IZ, post : IZ, sym : String, mu : Float, sigma : Float, p : Float, rng : Xoshiro) -> SpikingSynapseIZpub struct SpikingTransformerBlock {
d_model : Int
num_heads : Int
d_ff : Int
beta : Float
ln_1 : LayerNorm
ln_2 : LayerNorm
sa : SpikingMultiHeadAttention
ffn_w1 : LinearParam
ffn_w2 : LinearParam
}fn SpikingTransformerBlock::new(d_model : Int, num_heads : Int, beta : Float, seed : UInt64, d_ff? : Int) -> SpikingTransformerBlockpub struct SpikingTransformerBlockCache {
seq_len : Int
x : Array[Float]
x2 : Array[Float]
x_norm1 : Array[Float]
x_norm2 : Array[Float]
ln1_cache : LayerNormCache
sa_cache : SpikingMultiHeadAttnCache
ln2_cache : LayerNormCache
ffn_hidden_pre_gelu : Array[Float]
ffn_hidden_post_gelu : Array[Float]
mask : Array[Float]
}pub(all) struct StdpConfavreux2025Param {
eta : Float
alpha : Float
gamma : Float
mu : Float
nu : Float
tau_pre : Float
tau_post : Float
w_min : Float
w_max : Float
}pub(all) struct StdpGerstnerParam {
a_pre : Float
a_post : Float
tau_pre : Float
tau_post : Float
w_min : Float
w_max : Float
}pub struct StepLR {
base_lr : Float
step_size : Int
gamma : Float
current_step : Int
}pub struct StepRecord {
s : Int
a : Int
r : Float
s_next : Int
done : Bool
}fn SynapseNormalization::new(targets : Array[SynapseTarget], param : NormParam) -> SynapseNormalizationfn T5RelativePosition::new(num_heads : Int, max_distance : Int, seed : UInt64) -> T5RelativePositionpub struct TransformerBlock {
d_model : Int
num_heads : Int
d_ff : Int
ln_1 : LayerNorm
ln_2 : LayerNorm
mha : MultiHeadAttention
ffn_w1 : LinearParam
ffn_w2 : LinearParam
}fn TransformerBlock::new(d_model : Int, num_heads : Int, seed : UInt64, d_ff? : Int) -> TransformerBlockpub struct TransformerBlockCache {
seq_len : Int
x : Array[Float]
x2 : Array[Float]
x_norm1 : Array[Float]
x_norm2 : Array[Float]
ln1_cache : LayerNormCache
attn_cache : AttnCache
ln2_cache : LayerNormCache
ffn_hidden_pre_gelu : Array[Float]
ffn_hidden_post_gelu : Array[Float]
mask : Array[Float]
}pub(all) struct TripletRule {
a2_ltp : Float
a3_ltp : Float
a2_ltd : Float
a3_ltd : Float
tau_x : Float
tau_y : Float
tau_p : Float
tau_m : Float
}pub struct Tripod {
soma_param : AdExParameter
soma_spike : AdExPostSpike
d1 : Dendrite
d2 : Dendrite
i_s : Array[Float]
i_d1 : Array[Float]
i_d2 : Array[Float]
ge_s : Array[Float]
gi_s : Array[Float]
ge_d1 : Array[Float]
gi_d1 : Array[Float]
ge_d2 : Array[Float]
gi_d2 : Array[Float]
glu_s : Array[Float]
gaba_s : Array[Float]
glu_d1 : Array[Float]
gaba_d1 : Array[Float]
glu_d2 : Array[Float]
gaba_d2 : Array[Float]
e_e : Float
e_i : Float
tau_e : Float
tau_i : Float
gsyn_e : Float
gsyn_i : Float
n : Int
v_s : Array[Float]
w_s : Array[Float]
v_d1 : Array[Float]
v_d2 : Array[Float]
fire : Array[Bool]
threshold : Array[Float]
tabs : Array[Int]
dv : Array[Float]
dv_temp : Array[Float]
syn_curr_s : Array[Float]
syn_curr_d1 : Array[Float]
syn_curr_d2 : Array[Float]
}pub struct TripodHet {
soma_param : AdExParameterHet
soma_spike : AdExPostSpike
c : Array[Float]
gl : Array[Float]
d1 : Dendrite
d2 : Dendrite
i_s : Array[Float]
i_d1 : Array[Float]
i_d2 : Array[Float]
ge_s : Array[Float]
gi_s : Array[Float]
ge_d1 : Array[Float]
gi_d1 : Array[Float]
ge_d2 : Array[Float]
gi_d2 : Array[Float]
glu_s : Array[Float]
gaba_s : Array[Float]
glu_d1 : Array[Float]
gaba_d1 : Array[Float]
glu_d2 : Array[Float]
gaba_d2 : Array[Float]
e_e : Float
e_i : Float
tau_e : Float
tau_i : Float
gsyn_e : Float
gsyn_i : Float
n : Int
v_s : Array[Float]
w_s : Array[Float]
v_d1 : Array[Float]
v_d2 : Array[Float]
fire : Array[Bool]
threshold : Array[Float]
tabs : Array[Int]
dv : Array[Float]
dv_temp : Array[Float]
syn_curr_s : Array[Float]
syn_curr_d1 : Array[Float]
syn_curr_d2 : Array[Float]
}pub struct Turnover {
param : TurnoverParam
synapse : SpikingSynapse
pre : Array[Float]
post : Array[Float]
p : Array[Float]
p_rewire : Array[Float]
p_values : Array[Float]
}pub(all) enum TurnoverParam {
RandomTurnover_(RandomTurnover)
ActivityDependentTurnover_(ActivityDependentTurnover)
}pub(all) struct VStdpParam {
a_ltp : Float
a_ltd : Float
v_rest : Float
delta_v : Float
tau_pre : Float
tau_post : Float
w_min : Float
w_max : Float
}pub(all) struct VstdpParameter {
a_ltd : Float
a_ltp : Float
theta_ltd : Float
theta_ltp : Float
tau_pre : Float
tau_post : Float
w_max : Float
w_min : Float
}pub(all) struct WCParameter {
dummy : Float
}pub struct WilsonCowan {
param : WCParameter
n : Int
x : Array[Float]
r : Array[Float]
g : Array[Float]
i : Array[Float]
}pub struct Xoshiro {
s0 : UInt64
s1 : UInt64
s2 : UInt64
s3 : UInt64
}fn actor_critic_rollout(env : GridWorld, policy : LinearSoftmaxPolicy, value_net : LinearValueNet, max_steps : Int, rng : Xoshiro) -> EpisodeWithValuesfn actor_critic_update(policy : LinearSoftmaxPolicy, value_net : LinearValueNet, episode : EpisodeWithValues, gamma : Float, lr_policy : Float, lr_value : Float) -> Floatfn adafactor_update_1d(bias : Array[Float], d_bias : Array[Float], state : Adafactor1DState, lr : Float, eps? : Float, beta2? : Float) -> Unitfn adafactor_update_2d(weight : Array[Float], d_weight : Array[Float], state : Adafactor2DState, lr : Float, eps? : Float, beta2? : Float) -> Unitfn adafactor_update_linear(weight : Array[Float], bias : Array[Float], d_weight : Array[Float], d_bias : Array[Float], w_state : Adafactor2DState, b_state : Adafactor1DState, lr : Float) -> Unitfn adagrad_update_arrays(weight : Array[Float], bias : Array[Float], d_weight : Array[Float], d_bias : Array[Float], state : AdaGradState, lr : Float, eps : Float) -> (Array[Float], Array[Float], AdaGradState)fn adagrad_update_conv(param : Conv2dParam, d_weight : Array[Float], d_bias : Array[Float], state : AdaGradState, lr : Float, eps : Float) -> (Conv2dParam, AdaGradState)fn adagrad_update_linear(param : LinearParam, d_weight : Array[Float], d_bias : Array[Float], state : AdaGradState, lr : Float, eps : Float) -> (LinearParam, AdaGradState)fn adam_update_conv(param : Conv2dParam, d_weight : Array[Float], d_bias : Array[Float], state : AdamState, lr : Float, beta1 : Float, beta2 : Float, eps : Float) -> (Conv2dParam, AdamState)fn adam_update_linear(param : LinearParam, d_weight : Array[Float], d_bias : Array[Float], state : AdamState, lr : Float, beta1 : Float, beta2 : Float, eps : Float) -> (LinearParam, AdamState)fn adamw_update_arrays(weight : Array[Float], bias : Array[Float], d_weight : Array[Float], d_bias : Array[Float], state : AdamWState, lr : Float, beta1 : Float, beta2 : Float, eps : Float, weight_decay : Float) -> (Array[Float], Array[Float], AdamWState)fn adamw_update_conv(param : Conv2dParam, d_weight : Array[Float], d_bias : Array[Float], state : AdamWState, lr : Float, beta1 : Float, beta2 : Float, eps : Float, weight_decay : Float) -> (Conv2dParam, AdamWState)fn adamw_update_linear(param : LinearParam, d_weight : Array[Float], d_bias : Array[Float], state : AdamWState, lr : Float, beta1 : Float, beta2 : Float, eps : Float, weight_decay : Float) -> (LinearParam, AdamWState)fn alpha_synapse(tau_r : Float, tau_d : Float) -> Floatfn average_weight(pre_pop_neurons : Array[Int], post_pop_neurons : Array[Int], synapse : SpikingSynapse) -> Floatfn average_weight_dynamics(pre_pop_neurons : Array[Int], post_pop_neurons : Array[Int], synapse : SpikingSynapse, record : Array[Float], n_steps : Int) -> Array[Float]fn avgpool2d_backward(d_output : Array[Float], n : Int, c : Int, h : Int, w : Int, param : AvgPool2dParam) -> Array[Float]fn avgpool2d_forward(input : Array[Float], n : Int, c : Int, h : Int, w : Int, param : AvgPool2dParam) -> Array[Float]fn batch_norm2d_backward(d_output : Array[Float], cache : BatchNormCache, bn : BatchNorm2d) -> (Array[Float], Array[Float], Array[Float])fn batch_norm2d_forward(input : Array[Float], n : Int, c : Int, h : Int, w : Int, bn : BatchNorm2d) -> (Array[Float], BatchNormCache)fn bilstm_backward(hs_f : Array[Array[Float]], hs_b : Array[Array[Float]], target : Array[Array[Float]], cache : BiLstmCache, h0_f : Array[Float], c0_f : Array[Float], h0_b : Array[Float], c0_b : Array[Float], param : BiLstmParam) -> (Array[Array[Float]], Array[Float], Array[Float], Array[Float], Array[Float], LstmCellGrad, LstmCellGrad)fn bilstm_sgd_step(param : BiLstmParam, grad_f : LstmCellGrad, grad_b : LstmCellGrad, lr : Float) -> Unitfn c_mem(cd : Float, d : Float, l : Float) -> Floatfn ca_plasticity_step(w : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool], colptr : Array[Int], rowptr : Array[Int], vars : CaPlasticityVariables, param : CaPlasticityParameter, t_now : Float, dt : Float) -> Unitfn compare_float_traces(name : String, actual : Array[Float], expected : Array[Float], atol : Float, tol_ulps : Int) -> ParityResultfn compare_spike_trains(name : String, actual : Array[Int], expected : Array[Int], tol_steps : Int) -> ParityResultfn compose(pops : Array[AnyPop], conns : Array[SpikingSynapse], stims? : Array[AnyStim], monitors? : Array[Monitor], stdp? : Array[STDPEntryKind], stp? : Array[STPEntryKind]) -> HeterogeneousModelfn conductance_synapse_current(vars : SingleExpSynapseVars, param : SingleExpSynapse, v : Array[Float], syn_curr : Array[Float]) -> Unitfn conv2d_forward(input : Array[Float], n : Int, c_in : Int, h : Int, w : Int, param : Conv2dParam) -> Array[Float]fn current_synapse_step(vars : CurrentSynapseVars, param : CurrentSynapse, glu : Array[Float], gaba : Array[Float], dt : Float) -> Unitfn demo_polynomial(x_val : Float) -> Floatfn demo_rosenbrock(x_val : Float, y_val : Float) -> (Float, Float)fn double_dqn_update_step(online : LinearQNet, target : LinearQNet, states : Array[Int], actions : Array[Int], rewards : Array[Float], next_states : Array[Int], dones : Array[Bool], gamma : Float, lr : Float) -> Floatfn double_dqn_vs_vanilla_diff(online : LinearQNet, target : LinearQNet, next_states : Array[Int], gamma : Float) -> Floatfn double_exp_conductance_current(vars : DoubleExpSynapseVars, param : DoubleExpSynapse, v : Array[Float], syn_curr : Array[Float]) -> Unitfn double_exp_synapse_current(vars : DoubleExpSynapseVars, param : DoubleExpSynapse, v : Array[Float]) -> Array[Float]fn double_exp_synapse_step(vars : DoubleExpSynapseVars, param : DoubleExpSynapse, glu : Array[Float], gaba : Array[Float], dt : Float) -> Unitfn dqn_update_step(online : LinearQNet, target : LinearQNet, states : Array[Int], actions : Array[Int], rewards : Array[Float], next_states : Array[Int], dones : Array[Bool], gamma : Float, lr : Float) -> Floatfn dqn_update_step_n_step(online : LinearQNet, target : LinearQNet, states : Array[Int], actions : Array[Int], rewards : Array[Float], next_states : Array[Int], h_effs : Array[Int], use_bootstraps : Array[Bool], gamma : Float, lr : Float) -> Float δ = G_n + γ^h_eff · max_a' Q̂(s_lookahead, a') - Q(s_root, a_root) δ = G_n - Q(s_root, a_root)fn dsac_soft_target(q1_target : LinearGaussianQNet, q2_target : LinearGaussianQNet, policy : LinearSoftmaxPolicy, alpha : Float, next_state : Int, reward : Float, done : Bool, gamma : Float, rng : Xoshiro) -> Floatfn dueling_dqn_update_step(online : DuelingQNet, target : DuelingQNet, states : Array[Int], actions : Array[Int], rewards : Array[Float], next_states : Array[Int], dones : Array[Bool], gamma : Float, lr : Float) -> Floatfn dueling_eps_greedy_action(q_net : DuelingQNet, state : Int, epsilon : Float, rng : Xoshiro) -> Intfn epsp_pair(v : Array[Float], n_compartments : Int, spiketime : Int, rest : Float, compartment : Int) -> (Float, Float)fn epsp_pair_window(v : Array[Float], n_compartments : Int, t_start : Int, t_end : Int, rest : Float, compartment : Int) -> (Float, Float)fn erff(x : Float) -> Floatfn exc_peak(v : Array[Float], n_compartments : Int, spiketime : Int, rest : Float, compartment : Int) -> Floatfn exc_peak_window(v : Array[Float], n_compartments : Int, t_start : Int, t_end : Int, rest : Float, compartment : Int) -> Floatfn exc_peak_with_time(v : Array[Float], n_compartments : Int, spiketime : Int, rest : Float, compartment : Int) -> (Float, Int)fn exp256(x : Float) -> Floatfn exp32(x : Float) -> Floatfn exp64(x : Float) -> Floatfn expf(x : Float) -> Floatfn f2l(s : String, l : Int) -> Stringfn f2l_default(s : String) -> Stringfn f_sign_sqrt(x : Float) -> Floatfn fast_sigmoid_forward(x : Float, beta : Float) -> Floatfn fast_sigmoid_surrogate(x : Float, beta : Float) -> Floatfn finite_diff(f : (Float) -> Float, x : Float, h : Float) -> Floatfn float32_close(a : Float, b : Float, tol_ulps : Int) -> Boolfn forward_receptor_tripod_synapse(s : ReceptorSynapseTripod, target_receptor : Int, t_now : Float) -> Unitfn g_axial(ri : Float, d : Float, l : Float) -> Floatfn g_mem(rd : Float, d : Float, l : Float) -> Floatfn gae_advantages_returns(episode : PpoGaeEpisode, gamma : Float, gae_lambda : Float) -> (Array[Float], Array[Float])fn gaussian_nll(y : Float, mu : Float, sigma : Float) -> Floatfn gaussian_smooth(xs : Array[Float], x : Array[Float], sigma : Float, skew : SmoothSkew) -> Array[Float]fn gelu(x : Float) -> Floatfn gelu_grad(x : Float) -> Floatfn gelu_sparse_grad(x : Float) -> Floatfn gerstner_kernel(dt : Float, tau_pre : Float, tau_post : Float, a_pre : Float, a_post : Float) -> Floatfn get_synapse_symbol(sym : String) -> Stringfn gru_cell_backward(cache : GruCellCache, d_h_t : Array[Float], param : GruCellParam, grad : GruCellGrad) -> (Array[Float], Array[Float])fn gru_cell_forward(x : Array[Float], h_prev : Array[Float], param : GruCellParam) -> (Array[Float], GruCellCache)fn gru_policy_gradient_update(policy : GruPolicy, actions : Array[Int], returns : Array[Float], cache : GruPolicyCache, lr : Float) -> Unitfn gru_sequence_backward(predicted : Array[Array[Float]], target : Array[Array[Float]], caches : Array[GruCellCache], h0 : Array[Float], param : GruCellParam) -> (Array[Array[Float]], Array[Float], GruCellGrad)fn gru_sequence_forward(xs : Array[Array[Float]], h0 : Array[Float], param : GruCellParam) -> (Array[Array[Float]], Array[GruCellCache])fn heaviside_step(x : Float, vt : Float) -> Floatfn heterogeneous_sim_for_with_log(m : HeterogeneousModel, duration : Float, log_every_ms : Float) -> Array[SimLog]fn inh_trough(v : Array[Float], n_compartments : Int, spiketime : Int, rest : Float, compartment : Int) -> Floatfn inh_trough_window(v : Array[Float], n_compartments : Int, t_start : Int, t_end : Int, rest : Float, compartment : Int) -> Floatfn inh_trough_with_time(v : Array[Float], n_compartments : Int, spiketime : Int, rest : Float, compartment : Int) -> (Float, Int)fn integrate_adex_multi(p : AdExMultiTimescale, param : AdExMultiTimescaleParameter, dt : Float) -> Unitfn istdp_potential_step(w : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool], colptr : Array[Int], rowptr : Array[Int], v_post : Array[Float], vars : IstdpPotentialVariables, param : IstdpPotential, t_now : Float, dt : Float) -> Unitfn kei_balance_population(voltage_data : Array[Float], n_steps : Int, n_neurons : Int, target_rate : Float, tolerance : Float) -> Intfn layer_norm_forward(input : Array[Float], n : Int, c : Int, h : Int, w : Int, ln : LayerNorm) -> (Array[Float], LayerNormCache)fn layer_scale_backward(sublayer : Array[Float], d_output : Array[Float], ls : LayerScale) -> (Array[Float], Array[Float])fn lenet5_forward(m : LeNet5, input : Array[Float], n : Int) -> (Array[Float], Array[LayerCache], Int, Int, Int, Int)fn logf(x : Float) -> Floatfn lstm_cell_backward(cache : LstmCellCache, d_h_t : Array[Float], d_c_t : Array[Float], param : LstmCellParam, grad : LstmCellGrad) -> (Array[Float], Array[Float], Array[Float])fn lstm_cell_forward(x : Array[Float], h_prev : Array[Float], c_prev : Array[Float], param : LstmCellParam) -> (Array[Float], LstmCellCache)fn lstm_policy_forward(policy : LstmPolicy, obs_seq : Array[Array[Float]], h0 : Array[Float], c0 : Array[Float], rng : Xoshiro) -> (Array[Int], LstmPolicyCache)fn lstm_policy_gradient_update(policy : LstmPolicy, actions : Array[Int], returns : Array[Float], cache : LstmPolicyCache, lr : Float) -> Unitfn lstm_ppo_collect_batch(env_n_cells : Int, policy : LstmPolicy, n_episodes : Int, gamma : Float, max_steps : Int, seed : UInt64) -> RecurrentPpoBatchfn lstm_ppo_update_step(policy : LstmPolicy, batch : RecurrentPpoBatch, clip_eps : Float, lr : Float) -> Floatfn lstm_sequence_backward(predicted : Array[Array[Float]], target : Array[Array[Float]], caches : Array[LstmCellCache], h0 : Array[Float], c0 : Array[Float], param : LstmCellParam) -> (Array[Array[Float]], Array[Float], Array[Float], LstmCellGrad)fn lstm_sequence_forward(xs : Array[Array[Float]], h0 : Array[Float], c0 : Array[Float], param : LstmCellParam) -> (Array[Array[Float]], Array[Float], Array[LstmCellCache])fn markram_stp_step(syn : SpikingSynapse, vars : MarkramSTPVariables, param : MarkramSTPParameter, t_now : Float) -> Unitfn markram_stp_step_het(syn : SpikingSynapse, vars : MarkramSTPVariables, param : MarkramSTPParameterHet, t_now : Float) -> Unitfn markram_stp_step_timestep(syn : SpikingSynapse, vars : MarkramSTPVariables, param : MarkramSTPParameterTimestep, t_now : Float, dt : Float) -> Unitfn math_exp_f32(x : Float) -> Floatfn math_log_f32(x : Float) -> Floatfn maxpool2d_backward(d_output : Array[Float], argmax_idx : Array[Int], n : Int, c : Int, h : Int, w : Int, param : MaxPool2dParam) -> Array[Float]fn maxpool2d_forward(input : Array[Float], n : Int, c : Int, h : Int, w : Int, param : MaxPool2dParam) -> Array[Float]fn maxpool2d_forward_with_idx(input : Array[Float], n : Int, c : Int, h : Int, w : Int, param : MaxPool2dParam) -> (Array[Float], Array[Int])let metre : Floatfn mexican_hat_kernel(x : Float) -> Floatfn mini_spike_former_backward(cache : MiniSpikeFormerCache, msf : MiniSpikeFormer) -> (Array[Float], Array[Float], Array[Float], Array[Float], SpikingTransformerBlockGrad, Array[Float], Array[Float])fn mini_spike_former_eval_accuracy(images : Array[Float], labels : Array[Int], msf : MiniSpikeFormer) -> Floatfn mini_spike_former_eval_loss(images : Array[Float], labels : Array[Int], msf : MiniSpikeFormer) -> Floatfn mini_spike_former_forward(images : Array[Float], batch : Int, label : Int, msf : MiniSpikeFormer) -> (Float, MiniSpikeFormerCache)fn mini_spike_former_train_n_steps(images : Array[Float], label : Int, n_steps : Int, lr : Float, msf : MiniSpikeFormer) -> (Float, Float)fn mini_spike_former_train_step(images : Array[Float], label : Int, lr : Float, msf : MiniSpikeFormer) -> Floatfn multi_head_attention_backward(cache : AttnCache, d_output : Array[Float], mha : MultiHeadAttention) -> (Array[Float], MHAGrad)fn multi_head_attention_forward(x : Array[Float], mha : MultiHeadAttention, mask : Array[Float]) -> (Array[Float], AttnCache)fn name(pre : String, post : String, k : String) -> Stringfn name2(pre : String, post : String) -> Stringfn noisy_linear_forward(input : Array[Float], n : Int, param : NoisyLinearParam, rng : Xoshiro) -> Array[Float]fn noisy_linear_forward_eval(input : Array[Float], n : Int, param : NoisyLinearParam) -> Array[Float]fn norm_synapse(tau_r : Float, tau_d : Float) -> Floatfn ornstein_uhlenbeck_step(rng : Xoshiro, x : Float, theta : Float, mu : Float, sigma : Float, dt : Float) -> Floatfn parity_combined_hash(seed : UInt64) -> Intfn parity_full_dump(seed : UInt64) -> (Int, Int, Int)fn parity_hash_if_trajectory(n_steps : Int, dt : Float, i_drive : Float, seed : UInt64) -> Intfn parity_hash_sparse_matrix(n_pre : Int, n_post : Int, mu : Float, sigma : Float, p : Float, seed : UInt64) -> Intfn parity_hash_xoshiro(seed : UInt64, n : Int) -> Intfn parse_float(s : String) -> Floatfn parse_int(s : String) -> Intfn periodic_distance_scalar(p1 : Float, p2 : Float, grid_size : Float) -> Floatfn place_populations_e_i(n_e : Int, n_i : Int, grid_x : Float, grid_y : Float, rng : Xoshiro) -> PlacedPopsfn policy_gradient_update(policy : LinearSoftmaxPolicy, episode : Episode, returns : Array[Float], lr : Float) -> Unitfn policy_rollout(env : GridWorld, policy : LinearSoftmaxPolicy, max_steps : Int, rng : Xoshiro) -> Episodefn polynomial_value(x_val : Float) -> Float pops = [(E, 10), (I, 5)]
→ [PopIndex("E", 1, 10), PopIndex("I", 11, 15)]fn positional_embedding_backward(pe : PositionalEmbedding, d_output : Array[Float], seq_len : Int) -> Array[Float]fn pow_fast(x : Float, y : Float) -> Floatfn ppo_collect_batch(env : GridWorld, policy : LinearSoftmaxPolicy, n_episodes : Int, gamma : Float, max_steps : Int, seed : UInt64) -> PpoBatchfn ppo_gae_collect_batch(env : GridWorld, policy : LinearSoftmaxPolicy, value_net : LinearValueNet, n_episodes : Int, max_steps : Int, seed : UInt64) -> Array[PpoGaeEpisode]fn ppo_gae_update(policy : LinearSoftmaxPolicy, value_net : LinearValueNet, episodes : Array[PpoGaeEpisode], gamma : Float, gae_lambda : Float, clip_eps : Float, lr_policy : Float, lr_value : Float) -> Unitfn ppo_kl_collect_batch(env : GridWorld, policy : LinearSoftmaxPolicy, value_net : LinearValueNet, n_episodes : Int, gamma : Float, max_steps : Int, seed : UInt64) -> PpoKlBatchfn ppo_kl_update_step(policy : LinearSoftmaxPolicy, batch : PpoKlBatch, kl_beta : Float, lr : Float) -> Floatfn ppo_update_step(policy : LinearSoftmaxPolicy, batch : PpoBatch, clip_eps : Float, lr : Float) -> Unitfn receptor_current(g : Array[Float], v : Array[Float], r : Receptor, nmda_dep : NMDAVoltageDependency, out : Array[Float]) -> Unitfn receptors_current(g_matrix : Array[Float], v : Array[Float], rs : Receptors, nmda_dep : NMDAVoltageDependency, out : Array[Float]) -> Unitfn recurrent_sac_actor_update(sac : RecurrentSac, ep : RecurrentSacEpisode, lr : Float, rng : Xoshiro) -> Unitfn recurrent_sac_critic_update(sac : RecurrentSac, ep : RecurrentSacEpisode, gamma : Float, lr : Float, rng : Xoshiro) -> Floatfn recurrent_sac_rollout_episode(env_n_cells : Int, sac : RecurrentSac, max_steps : Int, rng : Xoshiro) -> RecurrentSacEpisodefn recurrent_sac_soft_target_seq(sac : RecurrentSac, ep : RecurrentSacEpisode, gamma : Float, rng : Xoshiro) -> Array[Float]fn residual_block_backward(b : ResidualBlock, cache : ResidualCache, d_output : Array[Float]) -> (Array[Float], ResidualGrads)fn residual_block_forward(b : ResidualBlock, x : Array[Float], n : Int, c : Int, h : Int, w : Int) -> (Array[Float], ResidualCache)fn rmsprop_update_arrays(weight : Array[Float], bias : Array[Float], d_weight : Array[Float], d_bias : Array[Float], state : RMSpropState, lr : Float, alpha : Float, eps : Float) -> (Array[Float], Array[Float], RMSpropState)fn rmsprop_update_conv(param : Conv2dParam, d_weight : Array[Float], d_bias : Array[Float], state : RMSpropState, lr : Float, alpha : Float, eps : Float) -> (Conv2dParam, RMSpropState)fn rmsprop_update_linear(param : LinearParam, d_weight : Array[Float], d_bias : Array[Float], state : RMSpropState, lr : Float, alpha : Float, eps : Float) -> (LinearParam, RMSpropState)fn rosenbrock_value(x_val : Float, y_val : Float) -> Floatfn route_pre_to_post(pre : IF, post : AdExSinExp, weights : Array[Float], exc : Bool, inh : Bool) -> Unitfn sac_auto_alpha_soft_target(sac : SacAutoAlpha, next_state : Int, reward : Float, done : Bool, gamma : Float) -> Floatfn sac_soft_target(sac : Sac, next_state : Int, reward : Float, done : Bool, gamma : Float) -> Floatfn scnn_deterministic_forward() -> Boolfn scnn_loss_is_reasonable() -> Boolfn scnn_single_step() -> (Float, Int)fn scnn_train_n_steps(n_steps : Int, lr : Float, seed : UInt64) -> (Float, Float, Float, Float)fn sgd_momentum_update_arrays(weight : Array[Float], bias : Array[Float], d_weight : Array[Float], d_bias : Array[Float], state : SGDMomentumState, lr : Float, momentum : Float) -> (Array[Float], Array[Float], SGDMomentumState)fn sgd_momentum_update_conv(param : Conv2dParam, d_weight : Array[Float], d_bias : Array[Float], state : SGDMomentumState, lr : Float, momentum : Float) -> (Conv2dParam, SGDMomentumState)fn sgd_momentum_update_linear(param : LinearParam, d_weight : Array[Float], d_bias : Array[Float], state : SGDMomentumState, lr : Float, momentum : Float) -> (LinearParam, SGDMomentumState)fn sgd_update_conv(param : Conv2dParam, d_weight : Array[Float], d_bias : Array[Float], lr : Float) -> Conv2dParamfn sgd_update_linear(param : LinearParam, d_weight : Array[Float], d_bias : Array[Float], lr : Float) -> LinearParamfn sigmoid_f32(x : Float) -> Floatfn simple_cnn_forward(m : SimpleCNN, input : Array[Float], n : Int) -> (Array[Float], Array[LayerCache], Int, Int, Int, Int)fn single_exp_synapse_step(vars : SingleExpSynapseVars, param : SingleExpSynapse, glu : Array[Float], gaba : Array[Float], dt : Float) -> Unitfn spiking_attention_backward(cache : SpikingMultiHeadAttnCache, d_output : Array[Float], sa : SpikingMultiHeadAttention) -> (Array[Float], MHAGrad)fn spiking_attention_forward(x : Array[Float], sa : SpikingMultiHeadAttention, mask : Array[Float]) -> (Array[Float], SpikingMultiHeadAttnCache)fn spiking_cross_attention_backward(cache : SpikingCrossAttnCache, d_output : Array[Float], sa : SpikingCrossAttention) -> (Array[Float], Array[Float], MHAGrad)fn spiking_cross_attention_forward(x_q : Array[Float], x_kv : Array[Float], sa : SpikingCrossAttention, mask : Array[Float]) -> (Array[Float], SpikingCrossAttnCache)fn spiking_multi_head_attention_backward(cache : SpikingMultiHeadAttnCache, d_output : Array[Float], sa : SpikingMultiHeadAttention) -> (Array[Float], MHAGrad)fn spiking_multi_head_attention_forward(x : Array[Float], sa : SpikingMultiHeadAttention, mask : Array[Float]) -> (Array[Float], SpikingMultiHeadAttnCache)fn spiking_self_attention_new(d_model : Int, beta : Float, seed : UInt64) -> SpikingMultiHeadAttentionfn spiking_transformer_block_backward(cache : SpikingTransformerBlockCache, d_output : Array[Float], block : SpikingTransformerBlock) -> (Array[Float], SpikingTransformerBlockGrad)fn spiking_transformer_block_forward(x : Array[Float], block : SpikingTransformerBlock, mask : Array[Float]) -> (Array[Float], SpikingTransformerBlockCache)fn sqrtf(x : Float) -> Floatfn stdp_antisymmetric_plot(param : STDPAntiSymmetric, y_max? : Float, width? : Int, height? : Int) -> Unitfn stdp_antisymmetric_step(w : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool], colptr : Array[Int], rowptr : Array[Int], vars : STDPAntiSymmetricVariables, param : STDPAntiSymmetric, dt : Float) -> Unitfn stdp_confavreux_step(w : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool], colptr : Array[Int], rowptr : Array[Int], vars : STDPVariables, param : STDPConfavreux2025, t_now : Float, dt : Float) -> Unitfn stdp_confraveux2025_step(state : StdpConfavreux2025State, param : StdpConfavreux2025Param, fire_pre : Array[Bool], fire_post : Array[Bool], w : Array[Float], now : Float) -> Unitfn stdp_gerstner_step(state : StdpGerstnerState, param : StdpGerstnerParam, fire_pre : Array[Bool], fire_post : Array[Bool], w : Array[Float], now : Float) -> Unitfn stdp_mexican_hat_plot(param : STDPMexicanHat, x_max? : Float, width? : Int, height? : Int) -> Unitfn stdp_step(w : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool], colptr : Array[Int], rowptr : Array[Int], vars : STDPVariables, param : STDPGerstner, t_now : Float, dt : Float) -> Unitfn stdp_symmetric_step(w : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool], colptr : Array[Int], rowptr : Array[Int], vars : STDPSymmetricVariables, param : STDPSymmetric, t_now : Float, dt : Float) -> Unitfn step_heterogeneous_with_record(m : HeterogeneousModel, dt : Float, record : (Float) -> Unit) -> Unitfn str_name(pre : String, post : String, k : String) -> Stringfn str_name_single(pre : String, k : String) -> Stringfn synaptic_current_confraveux2025(vars : Confavreux2025SynapseVars, param : Confavreux2025Parameter, v : Array[Float], syn_curr : Array[Float]) -> Unitfn synaptic_current_single_exp(vars : SingleExpSynapseVars, param : SingleExpParameter, v : Array[Float], syn_curr : Array[Float]) -> Unitfn synaptic_turnover(syn : SpikingSynapse, p_rewire? : Float, mu? : Float, p_values? : Array[Float]) -> Unitfn tanhf(x : Float) -> Floatfn train_actor_critic(env : GridWorld, policy : LinearSoftmaxPolicy, value_net : LinearValueNet, n_episodes : Int, gamma : Float, lr_policy : Float, lr_value : Float, max_steps : Int, seed : UInt64) -> Floatfn train_double_dqn(env : GridWorld, q_net : LinearQNet, target : LinearQNet, n_episodes : Int, gamma : Float, lr : Float, epsilon_start : Float, epsilon_end : Float, max_steps : Int, buffer_capacity : Int, warmup_episodes : Int, sync_every : Int, batch_size : Int, seed : UInt64) -> Floatfn train_dqn(env : GridWorld, q_net : LinearQNet, target : LinearQNet, n_episodes : Int, gamma : Float, lr : Float, epsilon_start : Float, epsilon_end : Float, max_steps : Int, buffer_capacity : Int, warmup_episodes : Int, sync_every : Int, batch_size : Int, seed : UInt64) -> Floatfn train_dqn_n_step(env : GridWorld, q_net : LinearQNet, target : LinearQNet, n_episodes : Int, gamma : Float, lr : Float, epsilon_start : Float, epsilon_end : Float, max_steps : Int, buffer_capacity : Int, warmup_episodes : Int, sync_every : Int, batch_size : Int, n_step : Int, seed : UInt64) -> Floatfn train_dueling_dqn(env : GridWorld, q_net : DuelingQNet, target : DuelingQNet, n_episodes : Int, gamma : Float, lr : Float, epsilon_start : Float, epsilon_end : Float, max_steps : Int, buffer_capacity : Int, warmup_episodes : Int, sync_every : Int, batch_size : Int, seed : UInt64) -> Floatfn train_gru_reinforce(env_n_cells : Int, policy : GruPolicy, n_episodes : Int, gamma : Float, lr : Float, max_steps : Int, seed : UInt64) -> Floatfn train_lstm_ppo(env_n_cells : Int, policy : LstmPolicy, n_iters : Int, n_episodes_per_iter : Int, gamma : Float, clip_eps : Float, lr : Float, max_steps : Int, seed : UInt64) -> Floatfn train_lstm_reinforce(env_n_cells : Int, policy : LstmPolicy, n_episodes : Int, gamma : Float, lr : Float, max_steps : Int, seed : UInt64) -> Floatfn train_ppo(env : GridWorld, policy : LinearSoftmaxPolicy, n_iters : Int, n_episodes_per_iter : Int, gamma : Float, clip_eps : Float, lr : Float, max_steps : Int, seed : UInt64) -> Floatfn train_ppo_gae(env : GridWorld, policy : LinearSoftmaxPolicy, value_net : LinearValueNet, n_iters : Int, n_episodes_per_iter : Int, gamma : Float, gae_lambda : Float, clip_eps : Float, lr_policy : Float, lr_value : Float, max_steps : Int, seed : UInt64) -> Floatfn train_ppo_kl(env : GridWorld, policy : LinearSoftmaxPolicy, value_net : LinearValueNet, n_iters : Int, n_episodes_per_iter : Int, gamma : Float, kl_beta : Float, lr : Float, max_steps : Int, seed : UInt64) -> Floatfn train_recurrent_sac(env_n_cells : Int, sac : RecurrentSac, n_episodes : Int, gamma : Float, lr_critic : Float, lr_actor : Float, tau : Float, max_steps : Int, seed : UInt64) -> Floatfn train_reinforce(env : GridWorld, policy : LinearSoftmaxPolicy, n_episodes : Int, gamma : Float, lr : Float, max_steps : Int, seed : UInt64) -> Floatfn train_sac_auto_alpha(env : GridWorld, sac : SacAutoAlpha, n_episodes : Int, gamma : Float, lr_critic : Float, lr_actor : Float, tau : Float, max_steps : Int, buffer_capacity : Int, warmup_episodes : Int, batch_size : Int, seed : UInt64) -> Floatfn transformer_block_backward(cache : TransformerBlockCache, d_output : Array[Float], block : TransformerBlock) -> (Array[Float], TransformerBlockGrad)fn transformer_block_forward(x : Array[Float], block : TransformerBlock, mask : Array[Float]) -> (Array[Float], TransformerBlockCache)fn update_soma_adex_multi(p : AdExMultiTimescale, param : AdExMultiTimescaleParameter, dt : Float) -> Unitfn update_synapses_adex_multi(p : AdExMultiTimescale, param : AdExMultiTimescaleParameter, dt : Float) -> Unitfn update_synapses_confraveux2025(vars : Confavreux2025SynapseVars, param : Confavreux2025Parameter, glu : Array[Float], gaba : Array[Float], dt : Float) -> Unitfn update_synapses_double_exp_current(vars : DoubleExpCurrentSynapseVars, param : DoubleExpCurrentParameter, glu : Array[Float], gaba : Array[Float], dt : Float) -> Unitfn update_synapses_single_exp(vars : SingleExpSynapseVars, param : SingleExpParameter, glu : Array[Float], gaba : Array[Float], dt : Float) -> Unitfn update_weight(pre_pop_neurons : Array[Int], post_pop_neurons : Array[Int], factor : Float, synapse : SpikingSynapse) -> Unitfn vstdp_clopath_step(state : VStdpState, param : VStdpParam, fire_pre : Array[Bool], fire_post : Array[Bool], w : Array[Float], dt : Float) -> Unitfn vstdp_step(vars : VstdpVariables, param : VstdpParameter, pre_v : Array[Float], post_v : Array[Float], pre_fire : Array[Bool], post_fire : Array[Bool]) -> Unitfn weights_indices(pre_pop_neurons : Array[Int], post_pop_neurons : Array[Int], synapse : SpikingSynapse) -> Array[Int]Install
Download zipBit-exact MoonBit port of SpikingNeuralNetworks.jl plus CNN primitives + 5D spatiotemporal tensors + full optimiser suite + normalisation layers + learning-rate schedulers + generic Chain + pre-made bottles + ResNet foundations + surrogate gradients + transformer activations. Covers IF, AdEx, Izhikevich (IZ), HH, Morris-Lecar, Poisson neurons; Markram STP, Gerstner / MexicanHat / AntiSymmetric STDP, vSTDP, Confavreux2025, Receptors (AMPA / NMDA / GABAa / GABAb), multicompartment dendritic neurons (BallAndStick, Tripod, Multipod); Conv2d / MaxPool2d / ReLU / Flatten / Linear forward + backward primitives; Tensor struct with broadcasting + softmax + log-softmax + cross-entropy; image adapter (BMP/QOI/TGA/PNG/GIF/JPEG/ICO/TIFF) via riantr/moonbit_image; 5D [T,B,C,H,W] STImage for spiking-CNN time-series input; SGD + SGD-with-momentum + Adam (with bias correction) + AdamW (decoupled weight decay) + RMSprop + AdaGrad optimisers; BatchNorm2d (with running stats + training/inference modes) + LayerNorm (per-sample, no running stats) with forward + backward; StepLR + ExponentialLR + CosineAnnealingLR + ReduceLROnPlateau schedulers; generic Chain / Sequential over Conv2d / ReLU / MaxPool2d / Flatten / Linear / BatchNorm2d / LayerNorm via tagged-enum dispatch with shape tracking and per-layer parameter gradients; pre-made MLP / SimpleCNN / LeNet5 bottles with He-init + xoshiro RNG; elementwise Add + AvgPool2d / GlobalAvgPool2d + ResidualBlock (identity + projection variants) ResNet foundations; fast-sigmoid surrogate gradient (Zenke & Ganguli 2018) for BPTT through IF / LIF Heaviside spikes; GELU (Gaussian Error Linear Unit) tanh-approximation activation for transformer FFN; Multi-Head Self-Attention (Vaswani 2017) with Q/K/V/O projections, scaled dot-product, head split/merge, optional additive mask, and full backward through softmax + linear projections; sinusoidal (fixed) and learnable (Xavier-init) positional encoding with backward for learnable variant; Pre-Norm Transformer block (LN → MHA → + → LN → FFN(GELU) → +) with full BPTT-style backward; attention mask utilities (causal mask + head-broadcast + allowed-keys → additive mask); inverted dropout regularisation (Bernoulli mask with 1/(1-p) scale, training/inference mode toggle); Spiking Self-Attention (SpikeFormer-style) that replaces softmax along key axis with fast-sigmoid surrogate from v0.22.0, with full BPTT-compatible backward using the surrogate gradient; Pre-Norm Spiking Transformer block (LN → SpikingAttention → + → LN → FFN(GELU) → +) demonstrating the full SNN-Transformer training pipeline; Mini-SpikeFormer training demo (synthetic 28×28 dataset + patch embedding + learnable class token + SpikingTransformerBlock + classifier + cross-entropy + per-parameter gradient clipping + SGD); exact (sparse) GELU activation `x · Φ(x)` via libm `erff` for the cumulative normal distribution; Adafactor optimizer (Shazeer 2018) with factorised second-moment estimation for memory-efficient 2D + 1D updates; LayerScale (Touvron 2021) per-channel learnable scale γ (init=1e-4) on residual branches for stable training of deep transformers; T5-style relative position bias (Raffel 2020) added directly to attention scores per (head, offset) with linear-bucket clamping; consolidated SAttention module (sattention.mbt) unifying three spiking attention variants — SpikingMultiHeadAttention (multi-head self-attention, default), SpikingSelfAttention (single-head convenience), SpikingCrossAttention (cross-attention with separate Q/KV inputs) — all using fast-sigmoid forward + surrogate backward from v0.22.0; SRNN training demo (CSNN-style) with Poisson-encoded 2D images → T-step IF state evolution → linear readout → softmax + cross-entropy + BPTT through time using fast_sigmoid_surrogate; SCNN v2 with full K-step SGD training loop, per-layer gradient clipping, and accuracy tracking on the synthetic dataset. Float32 end-to-end with libm FFI (expf, tanhf, logf, sqrtf, cosf, sinf, erff). 1177 tests passing, 76 examples ported from Julia.
Dependencies