Skip to content

3.1 SynapticGraph and CSR Representation

Raul Cardenas Montoya edited this page Sep 19, 2026 · 1 revision

SynapticGraph and CSR Representation

Relevant source files

The following files were used as context for generating this wiki page:

The SynapticGraph struct ([src/topology/graph.rs:33-47]()) serves as the core adjacency and wiring representation for the synaptic-wiring crate. It extends traditional Compressed Sparse Row (CSR) sparse graph storage with domain-specific metadata: signed synaptic weights, axonal propagation delays, and Dale's law polarities. This page details its internal layout, construction from descriptors, validation invariants, and serialization/export characteristics.


1. CSR Layout and Data Structures

To achieve cache-friendly traversal during spike propagation in SynapticMesh ([src/mesh.rs:49-63]()), SynapticGraph stores outgoing edges sequentially per source neuron using a CSR layout.

The structural components of SynapticGraph are:

  • neuron_count: The total number of neurons in the graph ([src/topology/graph.rs:35]).
  • row_ptr: An array of length neuron_count + 1 where row_ptr[i] indicates the starting index of outgoing edges for neuron i ([src/topology/graph.rs:36-38]()).
  • targets: Flattened array of destination neuron IDs ([src/topology/graph.rs:39-40]()).
  • weights: Flattened array of signed synaptic weights ([src/topology/graph.rs:41-42]()).
  • delays: Flattened array of axonal propagation delays in simulation ticks ([src/topology/graph.rs:43-44]()).
  • polarities: Flattened array of Dale's law polarities ([src/topology/graph.rs:45-46]()).
graph TD
    subgraph "Conceptual Wiring Space"
        A["Source Neuron i"] -->|Weight, Delay, Polarity| B["Target Neuron j"]
    end
    subgraph "Code Entity Space: SynapticGraph"
        SG["SynapticGraph"] --> RP["row_ptr: Vec<usize>"]
        SG --> T["targets: Vec<NeuronId>"]
        SG --> W["weights: Vec<f32>"]
        SG --> D["delays: Vec<DelayTicks>"]
        SG --> P["polarities: Vec<Polarity>"]
    end
Loading

Sources: src/topology/graph.rs:33-47


2. Construction and Validation Invariants

Graphs are typically constructed from a collection of SynapseDescriptor instances ([src/types.rs:52-64]()). During construction, edges are sorted and grouped by source neuron to build the monotonic row_ptr index structure.

Because external serialization formats (such as Postcard or JSON) can inject arbitrary values, RawSynapticGraph ([src/topology/graph.rs:50-57]()) implements a strict validation phase via into_graph ([src/topology/graph.rs:65-88]()) before instantiating a valid SynapticGraph. The validation suite enforces the following checks:

  1. Row Pointer Monotonicity & Length: validate_row_ptr ensures row_ptr has length neuron_count + 1, starts at 0, and is non-decreasing ([src/topology/graph.rs:93-111]()).
  2. Edge Array Alignment: validate_edge_array_lengths confirms that targets, weights, delays, and polarities all have lengths exactly equal to the total non-zero edge count (nnz) given by the final entry of row_ptr ([src/topology/graph.rs:114-126]()).
  3. Target Bounds: validate_targets_in_bounds guarantees all target neuron IDs fall within [0, neuron_count) ([src/topology/graph.rs:129-137]()).
  4. Finite Weights: validate_weights_finite rejects NaN or infinite weights ([src/topology/graph.rs:142-147]()).
  5. Polarity Agreement: validate_weights_agree_with_polarities ensures that signed weights agree with their assigned Polarity (excitatory weights must be $\ge 0$, inhibitory weights must be $\le 0$) ([src/topology/graph.rs:149-161], [src/types.rs:105-113]()).
graph TD
    Deserialization["RawSynapticGraph Deserialization"] --> VR["validate_row_ptr"]
    VR --> VE["validate_edge_array_lengths"]
    VE --> VT["validate_targets_in_bounds"]
    VT --> VW["validate_weights_finite"]
    VW --> VP["validate_weights_agree_with_polarities"]
    VP -->|All Valid| SG["SynapticGraph Ready"]
    VP -->|Failure| Err["Deserialization Error"]
Loading

Sources: src/topology/graph.rs:50-89, src/topology/graph.rs:93-161, src/types.rs:105-113


3. Neuron Count Limits and Memory Safety

The size of a SynapticGraph is bounded by available system memory and integer type capacities:

  • Neuron IDs are represented by NeuronId (u32), limiting networks to $2^{32}-1$ neurons ([src/types.rs:14]()).
  • Axonal delays are represented by DelayTicks (u16), bounding maximum delays to $65,535$ simulation ticks ([src/types.rs:18]()).
  • Row pointer allocations check for overflow during network scaling using checked arithmetic via neuron_count.checked_add(1) ([src/topology/graph.rs:94-96]()).

4. GPU Array Export and Serialization

The flat vector design of SynapticGraph (row_ptr, targets, weights, delays, polarities) maps directly to GPU memory layouts (such as CUDA or OpenCL buffers). Because all sparse connections are stored contiguously in standard Vec<T> buffers, they can be exported to device arrays or serialized via serde without pointer-chasing overhead.

Deserialization is guarded by RawSynapticGraph ([src/topology/graph.rs:50-57]()), which intercepts raw deserialized streams to run comprehensive structural validation before releasing the object to runtime code ([src/topology/graph.rs:163-172]()).

Sources: src/topology/graph.rs:33-89, src/topology/graph.rs:163-172

Clone this wiki locally