Skip to content

Repository files navigation

nir-rs

Pure-Rust implementation of the Neuromorphic Intermediate Representation (NIR)

CI License: MIT OR Apache-2.0

Pure-Rust NIR graph model (typed nodes, edges, validation), plus opt-in HDF5 .nir read/write that interoperates with the Python reference implementation. The graph model has no system dependencies; the hdf5 feature is the one part that links native libhdf5.

NIR is to SNNs what ONNX is to conventional neural networks (or GGUF to LLMs): a framework-agnostic graph format that lets models move between simulators and hardware without being rewritten.

Why nir-rs?

  • Official NIR is primarily Python-based (neuromorphs/NIR)
  • No mature shared Rust IR crate for the Limen stack
  • Enables pure-Rust, embedded, and high-performance pipelines
  • Native integration with the rest of Limen Neural (axon-encoder, silicon-bridge, neuromod, …)

Upstream

Wire compatibility: HDF5 node type strings must match the Python IR (CubaLIF, Conv2d, SumPool2d, …), not informal aliases (CurrLIF, Convolution, …).

Scope

This crate owns:

  • The NIR graph model and standard node types
  • Reading and writing .nir (HDF5) files (v0.3+)
  • Round-trip fidelity and basic validation
  • A clean, idiomatic Rust API

This crate does not own:

  • Training or simulation of SNNs
  • Mapping to specific hardware (that lives in silicon-bridge)
  • Framework-specific converters (those live in producing/consuming crates)

Status / roadmap

Milestone Focus Status
v0.1 Dual license, module skeleton, CI, agent docs Done
v0.2 Typed graph, wire-accurate nodes, structured errors Done
v0.3 HDF5 read/write via hdf5-metno, fixtures, round-trip Done
v0.4 Serde/debug DX, examples This release
v0.5 Wire consumers (silicon-bridge, axon-encoder, engram-parser) Planned

Tracking: GitHub milestones · LIM-822

Quick start

Not published to crates.io yet. Use a git or path dependency:

[dependencies]
nir-rs = { git = "https://github.com/Limen-Neural/nir-rs", branch = "main" }

To also get HDF5 .nir I/O, enable the hdf5 feature (see File I/O for the system dependency it brings):

[dependencies]
nir-rs = { git = "https://github.com/Limen-Neural/nir-rs", branch = "main", features = ["hdf5"] }
use nir_rs::nodes::{Input, Output};
use nir_rs::{NirGraph, NirNode};

fn main() -> nir_rs::Result<()> {
    let mut g = NirGraph::new();
    g.insert_node(
        "input",
        NirNode::Input(Input {
            shape: vec![4],
            metadata: Default::default(),
        }),
    )?;
    g.insert_node(
        "output",
        NirNode::Output(Output {
            shape: vec![4],
            metadata: Default::default(),
        }),
    )?;
    g.add_edge("input", "output");
    g.validate_structure()?;
    Ok(())
}

File I/O

.nir is the official NIR interchange format: an HDF5 container whose layout is fixed by upstream. Files written here load in Python nir.read, and files written by nir.write load here.

fn main() -> nir_rs::Result<()> {
    let graph = nir_rs::io::read("model.nir")?;
    for (name, node) in &graph.nodes {
        println!("{name}: {}", node.type_name());
    }
    nir_rs::io::write("copy.nir", &graph)?;
    Ok(())
}

I/O is behind the opt-in hdf5 feature, which links the native libhdf5 library. Without this feature, the crate requires no system dependencies:

Platform System dependency
Debian / Ubuntu apt install libhdf5-dev
Fedora dnf install hdf5-devel
macOS brew install hdf5
Anywhere depend on hdf5-metno = { version = "0.14", features = ["static", "zlib"] } directly — Cargo's feature unification applies it to this crate's copy. A dependency's feature list cannot name hdf5/static, and without zlib the vendored build has no gzip filter.

Without the feature, io::read / io::write still exist and return NirError::Unimplemented, so downstream code compiles either way.

Round-trip fidelity is graph-level, not byte-level: node names and types, ordered edges, and exact parameter values are preserved, while HDF5 details such as group ordering and chunk layout may differ from h5py. In-memory dtypes (f32, f64, i64, bool) round-trip exactly; narrower on-disk integer types are widened to i64 on read. Absent optional fields (v_reset, w_in) are filled with the same defaults Python uses, so a graph read here matches what nir.read produces in memory.

Load, inspect, and save a LIF graph

The public example loads a .nir graph (default: vendored LIF fixture), prints structure including nested NIRGraph nodes, previews every LIF parameter tensor (first eight elements, with a total count when longer), writes a copy, then verifies round-trip equality for finite graphs (skips the assert if any float tensor contains NaN):

cargo run --example load_inspect_lif --features hdf5

Pass optional input and output paths to use your own model:

cargo run --example load_inspect_lif --features hdf5 -- model.nir copy.nir

When omitted, the input is tests/fixtures/lif_norse.nir and the output is a PID-qualified file in the system temporary directory.

Debug serialization

The opt-in serde feature implements Serialize and Deserialize for the graph, all wire node variants, metadata, and tensors. It is independent of the hdf5 feature:

[dependencies]
nir-rs = { git = "https://github.com/Limen-Neural/nir-rs", branch = "main", features = ["serde"] }
serde_json = "1"

Consumers can use self-describing Serde formats (JSON, RON, YAML, etc.) directly, for example serde_json::to_string_pretty(&graph). Tensor debug data is represented as { "shape": [...], "data": { "F64": [...] } }, and deserialization checks the tensor shape/data-length invariant.

JSON is debug/test output, not a NIR interchange standard or a stable schema. Use HDF5 .nir through io::read / io::write for Python NIR and hardware tool interoperability. JSON cannot represent NaN or infinities faithfully, so graphs containing non-finite floats are not guaranteed to round-trip through JSON; tests and debug round-trips should use finite values.

Develop

cargo fmt --check
cargo test                 # graph model only, no libhdf5 required
cargo test --all-features  # + HDF5 I/O, fixtures and round-trip
cargo clippy --all-targets --all-features -- -D warnings
cargo doc --no-deps --all-features

Wire compatibility is checked against real .nir files written by the Python implementation and vendored under tests/fixtures/ (BSD-3, see the README there). Nothing in the build, tests, or CI needs a Python interpreter.

See REVIEW.md and AGENTS.md.

License

This project is dual-licensed under either:

at your option.

About

Pure-Rust implementation of the Neuromorphic Intermediate Representation (NIR) — the standard interchange format for spiking neural networks.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages