synaptic_wiring/lib.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! # synaptic-wiring
4//!
5//! The **connectivity layer** of a spiking neural network: which neuron
6//! connects to which, how strongly, and how long the spike takes to arrive.
7//! You bring the neuron model and the simulation loop; this crate wires the
8//! network and delivers each spike to the right target on the right tick.
9//!
10//! Reach for it to generate biologically plausible topologies, give synapses
11//! axonal delays, respect Dale's law, or store a large sparse weight matrix
12//! compactly — all deterministically, with `serde` and `sha2` as the only
13//! runtime dependencies.
14//!
15//! ## Where to start
16//!
17//! 1. [`topology::generate_small_world`] (or [`generate_random`],
18//! [`generate_scale_free`], [`generate_layered`]) to build a
19//! [`SynapticGraph`], or [`SynapticGraph::from_descriptors`] to specify
20//! every synapse yourself.
21//! 2. [`SynapticMesh::new`] to wrap it, then [`SynapticMesh::propagate`] once
22//! per tick — its docs state the full delivery contract (destination,
23//! sign, magnitude, tick). Reuse a caller-owned buffer with
24//! [`SynapticMesh::propagate_into`] and
25//! [`SynapticMesh::propagate_graded_into`] when a
26//! fixed-rate loop must avoid allocating every tick.
27//! 3. [`topology::assign_delays`] to rewrite a descriptor list's delays from
28//! neuron positions, and [`topology::apply_dale_polarity`] to compute a
29//! per-neuron excitatory/inhibitory split — both work on the inputs to
30//! [`SynapticGraph::from_descriptors`], not on an already-built graph.
31//! 4. [`SynapticGraph::topology_digest`] (or [`SynapticMesh::topology_digest`])
32//! for a printable, versioned identifier of the logical graph, usable in
33//! manifests and cross-runtime comparisons.
34//! 5. [`sparse::SparseSynapticMap`] or [`SynapticMesh::to_gpu_arrays`] when
35//! you need the weights as flat CSR arrays.
36//! 6. [`router::ChannelRouter`] only if you also want a sparse channel
37//! classifier; it is independent of the mesh and safe to ignore.
38//!
39//! [`generate_random`]: topology::generate_random
40//! [`generate_scale_free`]: topology::generate_scale_free
41//! [`generate_layered`]: topology::generate_layered
42//!
43//! ## Modules
44//!
45//! | Module | Purpose |
46//! |--------|---------|
47//! | [`topology`] | Network graph construction — CSR adjacency with delay & polarity metadata, deterministic generators (Erdős–Rényi, Watts–Strogatz, Barabási–Albert, layered), and a versioned [`TopologyDigest`] |
48//! | [`delay`] | Temporal delay infrastructure — ring-buffer spike queues for tick-aligned delivery with configurable axonal propagation delays |
49//! | [`mesh`] | [`SynapticMesh`] orchestrator — the top-level struct owning topology + delays, provides `propagate()` / `propagate_into()` for spike → current conversion |
50//! | [`sparse`] | Compressed Sparse Row (CSR) synaptic maps for GPU-optimized weight matrices |
51//! | [`router`] | Optional multi-channel classifier built on [`NeuromodNeuron`], a router-internal integration primitive |
52//!
53//! ## Crate boundary
54//!
55//! This crate owns connectivity and timing. Neuron models (LIF, Izhikevich,
56//! Hodgkin-Huxley, …), learning rules, and training loops are deliberately
57//! out of scope — pair it with whatever integrator you already use, or with a
58//! dedicated crate such as `neuromod`, on which `synaptic-wiring` takes **no**
59//! dependency so the two can evolve independently.
60//!
61//! [`NeuromodNeuron`] is the one neuron-like type here: an integration
62//! primitive internal to [`router::ChannelRouter`], not a general-purpose
63//! neuron model.
64//!
65//! ## Quick start
66//!
67//! ```rust
68//! use synaptic_wiring::topology::generate_small_world;
69//! use synaptic_wiring::mesh::SynapticMesh;
70//!
71//! // Build a 256-neuron small-world network with delays up to 5 ticks
72//! let graph = generate_small_world(256, 6, 0.2, 5, 0.2).unwrap();
73//! let mut mesh = SynapticMesh::new(graph);
74//!
75//! // Each tick: provide spike vector → receive delayed synaptic currents
76//! let mut spikes = vec![false; 256];
77//! spikes[0] = true; // neuron 0 fires
78//!
79//! let currents = mesh.propagate(&spikes).unwrap();
80//! // currents[i] = total incoming synaptic current at neuron i this tick
81//! ```
82//!
83//! ## Architecture
84//!
85//! ```text
86//! ┌──────────────────────────────────────────────────┐
87//! │ Source spike vector [bool; N] │
88//! └────────────────┬─────────────────────────────────┘
89//! │
90//! ┌─────────▼─────────┐
91//! │ SynapticGraph │ CSR adjacency + delays + polarities
92//! │ (topology) │ Generators: random, small-world,
93//! │ │ scale-free, layered
94//! └─────────┬─────────┘
95//! │ per-synapse: (target, weight, delay)
96//! ┌─────────▼─────────┐
97//! │ SpikeDelayBuffer │ Ring-buffer delay queue
98//! │ (delay) │ inject() → advance() → drain()
99//! └─────────┬─────────┘
100//! │ tick-aligned delivery
101//! ┌─────────▼─────────┐
102//! │ Synaptic current │ Vec<f32> of length N
103//! │ per target neuron│
104//! └───────────────────┘
105//! ```
106//!
107//! ## References
108//!
109//! - Lapicque, L. (1907). *Recherches quantitatives sur l'excitation électrique des
110//! nerfs traitée comme une polarisation.* Journal de Physiologie et de Pathologie
111//! Générale, 9, 620–635.
112//! - Stein, R. B. (1967). *Some models of neuronal variability.* Biophysical
113//! Journal, 7(1), 37–68.
114//!
115//! **Dale's law:**
116//! - Dale, H. H. (1935). *Pharmacology and Nerve-endings.* Proceedings of the
117//! Royal Society of Medicine, 28(3), 319–332.
118//!
119//! **Network topology:**
120//! - Watts, D. J. & Strogatz, S. H. (1998). *Collective dynamics of 'small-world'
121//! networks.* Nature, 393, 440–442.
122//! - Barabási, A.-L. & Albert, R. (1999). *Emergence of scaling in random networks.*
123//! Science, 286, 509–512.
124//!
125//! **STDP / Hebbian plasticity:**
126//! - Hebb, D. O. (1949). *The Organization of Behavior.* Wiley.
127//! - Bi, G. Q., & Poo, M. M. (1998). Synaptic modifications in cultured
128//! hippocampal neurons: dependence on spike timing, synaptic strength, and
129//! postsynaptic cell type. *Journal of Neuroscience*, 18(24), 10464–10472.
130//!
131//! **Winner-take-all lateral inhibition:**
132//! - Maass, W. (2000). On the computational power of winner-take-all.
133//! *Neural Computation*, 12(11), 2519–2535.
134
135// ── New modules: wiring, topology, delays ─────────────────────────────────────
136pub mod delay;
137pub mod error;
138pub mod mesh;
139pub mod topology;
140pub mod types;
141
142// ── Existing modules: router + sparse maps ────────────────────────────────────
143pub mod router;
144pub mod sparse;
145
146// ── Public re-exports ─────────────────────────────────────────────────────────
147
148// New mesh infrastructure
149pub use delay::SpikeDelayBuffer;
150pub use error::{MeshError, Result};
151pub use mesh::SynapticMesh;
152pub use topology::{
153 SynapticGraph, TOPOLOGY_DIGEST_ALGORITHM, TOPOLOGY_DIGEST_DOMAIN,
154 TOPOLOGY_DIGEST_SCHEMA_VERSION, TopologyDigest,
155};
156pub use types::{
157 ConnectionModel, DelayModel, DelayTicks, NeuronId, Polarity, SynapseDescriptor, TopologyConfig,
158};
159
160// Generic router exports (NeuromodNeuron is a router-internal NIF primitive; see "Crate boundary" above)
161pub use router::{
162 ChannelRouter, MAX_ROUTER_CHANNELS, MAX_ROUTING_TIMESTEPS, NeuromodNeuron, NeuromodState,
163 RouterConfig, RoutingDecision,
164};
165
166// Sparse map exports
167pub use sparse::{
168 MAX_SPARSE_NEURONS, NeuronStateSnapshot, RoutingPolicy, SparseSynapticMap,
169 SparseSynapticMapBuilder, Synapse,
170};
171
172#[cfg(test)]
173mod tests;
174
175/// Compiles the Rust examples in `README.md` as doctests, so the quickstart a
176/// new user copies is guaranteed to build against the current API using this
177/// crate alone. `cfg(doctest)` keeps the README out of the rendered docs.
178#[cfg(doctest)]
179#[doc = include_str!("../README.md")]
180struct ReadmeExamples;