Repository navigation
c package contract
How a spikeforge bundle reaches a torch-free target. A .spkf bundle needs
Python and torch (a pickled weights.pt and a Python-envelope graph), so
deployment to C goes through a derived plain-JSON artifact instead. This
document owns the exact JSON the C loader consumes, so the two sides cannot
drift silently. The consumer is nir_graph_load in nir-c-runtime's
src/graph.c.
-
DeploymentBundle.export_c_package(dir)(spikeforge/serving/c_package.py) writes a float package: the NIR graph ingraph_summaryshape with the bundle's real weights as plain nested float arrays. Compressed bundles export their dequantized floats. The.spkfformat itself is unchanged. -
export_quantized_summary(graph_or_spec, scheme)(spikeforge_targets/quantized_summary.py) returns the same shape with every floatingweightreplaced by a quantized envelope. Thenonescheme returns the float summary itself, so it is byte-comparable to the existing float path. - Grids come from
spikeforge/compression/grid.py, shared by the bundle codec and the drift simulation, so all three agree on every(scale, zero_point)pair by construction.
Top level {"nodes": [...], "edges": [...]}. A node is
{name, kind, params}; an edge is {source, target, delayed} (the C loader
reads source/target and ignores delayed). Eleven node kinds load;
anything else fails in C with a named error, and export_c_package refuses
it first with CExportError naming the offending nodes and kinds (shape
violations refuse the same way, through the single-sourced
nir-c-runtime profile):
Input, Output, Conv2d, Affine, Flatten, AvgPool2d, SumPool2d,
LI, Threshold, Scale, Delay.
Per-kind parameters the C loader reads (extra parameters are ignored):
-
Conv2d:weight(4-D), optionalbias(1-D),stride/padding/dilationpairs. -
Affine:weight(2-D) andbias(1-D); the bias is required. -
AvgPool2d/SumPool2d:kernel_size/stride/paddingpairs. -
LI:tau,r,v_leak.Threshold:threshold.Scale:scale. -
Input,Output,Flatten,Delay: no parameters read.
A quantized weight is {data, dtype, scale, zero_point}, decoded as
(code - zero_point) * scale:
-
data: nested integer lists with the same nesting as the plain weight. -
dtype:"int8"(symmetric, zero point 0, codes in [-127, 127]) or"uint8"(asymmetric, codes in [0, 255]). -
scale: a number greater than 0 and finite;zero_point: a number. The C loader rejects a missing, non-positive, or non-finite scale.
Only weight tensors are enveloped, exactly the tensors the drift
simulation quantizes; biases and every other parameter stay the plain
graph_summary values. Envelopes decode to the simulation's quantized
weights, so the C readout matches the simulated-quantization drift run.
Degenerate tensors keep a loadable, exact grid:
| Tensor | Grid (scale, zero_point)
|
Codes | Decodes to |
|---|---|---|---|
| int8 all-zero or empty (peak <= 1e-12) | (1.0, 0) |
all 0 | zeros |
uint8 constant c > 0
|
(c, 0) |
all 1 | c |
uint8 constant c < 0
|
(-c, 1) |
all 0 | c |
uint8 constant 0 or empty |
(1.0, 0) |
all 0 | 0 |
| uint8 near-constant (span <= 1e-12) | single level at the midpoint | per sign above | within 1e-12 of every value |
Non-finite weights are refused with QuantizationError: no finite grid
can represent them. Empty dimensions do not survive nested-list JSON
([] carries no shape); the float summary has the same property.
export_c_package writes two files into the target directory:
-
graph.json: the graph summary the C loader parses. -
manifest.json:format("spikeforge-c-package"),version(1),created_at,graph("graph.json"), node/edge counts, andsource: the source bundle's path, its file SHA-256 (null for an in-memory bundle), and the SHA-256 of its canonical manifest JSON.
Float weights round-trip through JSON bit-exactly (float32 values are
exact in doubles), and the quantized envelopes decode to the same floats
the drift simulation runs. Measured on a conv_net bundle over 6 steps
of 28x28 input, silent and firing, float/int8/uint8/compressed: C readout
matches the reference readout with max abs diff 0.0 in every case. The
acceptance bar stays 1e-3 readout max-abs, the same bar nir-c-runtime
uses in its own end-to-end test, leaving margin for larger graphs.
- Home
- Architecture
- Backend Execution
- Benchmarks
- Dashboard
- Development
- Encoding Goldens
- Event Datasets
- Event Runtime And Energy
- Features
- Implications And Boundaries
- Interop Foldins
- Interpreter Spine
- Introspection
- Model Deployment
- Model Hub
- Notes
- Operational Maturity
- Production Workflows
- Project Layout
- Quickstart
- Requirements
- Sequence Primitives
- Streaming Timeseries
- Targets And Interop
- Usage
- Arch 0001 Adr Repo Topology
- Arch 0001 Core Boundary
- Arch 0001 Decision Metrics
- Arch 0001 Migration Plan
- Arch 0001 Packaging Versioning
- Arch 0001 Protocol Contract
- Arch 0001 Risk Register
- Arch 0001 Target Topology
- Backend Execution Plan
- C Package Contract
- Client Diff Classification
- Ecosystem Listings
- Ecosystem Roadmap
- Event Runtime Plan
- Hub Accounts Plan
- Hub Expansion Plan
- Plans
- Integration Plan Historical
- Interop Foldins Plan
- Interpreter Spine Plan
- Memory System Research
- Model Hub Plan
- Nir C Runtime Profile
- Nir Unmappable Decisions
- Operations Plan
- Production Toolkit Plan
- Production Use Cases
- Professional Roadmap
- Repo Topology Plan
- Sequence Primitives Plan
- Snn Interpreter Provenance
- Use Case Audio Keyword Spotting
- Use Case Biosignal Medical Monitoring
- Use Case Computational Neuroscience
- Use Case Edge Power Budgets
- Use Case Event Camera Vision
- Use Case Intrusion Anomaly Detection
- Use Case Low Latency Sensor Stream
- Use Case Rl Control Robotics
- Use Case Spiking Transformers
- Use Case Streaming Timeseries