libsparsr_hdc is a C library that runs hyperdimensional computing on Sparsr.
You include one header and link one library. Every vector operation you call
then runs as wide instructions on the device. Which device is on the other
side is decided the way it is for every Sparsr program: the host library and
SPARSR_BACKEND.
The Sparsr VM. The library's kernels are RV32I, and
the VM runs RV32I. Set SPARSR_BACKEND=vm to choose it.
It is its own download, sparsr-hdc-<version>.tar.gz, beside the Kernel SDK on
the Sparsr Developer Zone. Inside:
| Path | What it is |
|---|---|
include/sparsr_hdc.h |
The public API. The only header a caller includes. |
include/sparsr.h |
The host library's header, which sparsr_hdc.h uses. |
lib/libsparsr_hdc.so |
The library, with its kernels compiled in. |
lib/libsparsr_host.so and the backends |
The runtime. |
LICENSE, LICENSE-RUNTIME |
MIT for the library, and the terms of the runtime it bundles. |
A program builds against the extracted directory and nothing else:
cc my_program.c -I include -L lib -lsparsr_hdc -lsparsr_host -o my_program
SPARSR_BACKEND=vm LD_LIBRARY_PATH=lib ./my_program
You do not need a RISC-V toolchain. One is only needed to build the library itself, and the download is already built.
| Call | What the device does |
|---|---|
hdc_bind(a, b, out) |
One wide XOR. |
hdc_bundle(members, n, out) |
The union, one wide OR per member. It is exact and it does not need a tiebreak. |
hdc_bundle_majority(members, n, out) |
A majority vote, for up to 8,191 members. The counter is a set of bit-planes added with a carry-save adder, so plane j holds bit j of all 4,096 counts, and every step is an instruction the device already has. |
hdc_similarity(a, b) |
One wide AND, then the bits are counted. |
hdc_train(...) |
Builds a class prototype from examples, with the majority bundle. |
Around them: hdc_init() loads the kernels into the device once, hdc_random()
draws a sparse hypervector, hdc_random_dense() draws a dense one confined to
the lanes that fit, and hdc_fits_device() tells you whether a hypervector
can be moved to the device at all. The header documents each one.
This is sparse binary VSA. Binding is XOR and bundling is the union. That
is a deliberate choice, and it is not the better-known Binary Spatter Code,
whose bundle is a majority vote. The majority is available too, through
hdc_bundle_majority(), and it costs more: measured over every instruction the
device retires, a union is 4.0 instructions per member and a majority is 7.8 at
80 members and 13.0 at 1,000.
The limitation to know before you design around this library: XOR binding does not decorrelate sparse hypervectors. Two sparse vectors rarely set the same bit, so their XOR is nearly their union, and it stays similar to both of its operands. A wide rotate would fix that, and Sparsr does not have one yet. The library says so in its own tests rather than hiding it.
The device stores a hypervector through a compression codec that counts non-zero 32-bit lanes, not set bits. A 4,096-bit register has 128 lanes and a stored row holds 48 of them. So two very different shapes fit:
hdc_fits_device() answers for a vector, and a move that would not fit
is refused with a clear status instead of corrupting data.
The library's worked example is handwritten digit recognition on MNIST, with every vector operation on the device. It reaches 79.6% on the full set of 60,000 training and 10,000 test images, and 75.6% at 1,536 bits on 6,000 training and 1,000 test images. The same 1,536-bit dense code with a plainer encoding manages 65.3%, so most of the gap is the encoding rather than the data. These numbers can be checked by running the example. They say that an HDC classifier works end to end on the device. They compare it against nothing else, and they are not meant to.