The HDC library

The HDC library

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.

What it runs on

The Sparsr VM. The library's kernels are RV32I, and the VM runs RV32I. Set SPARSR_BACKEND=vm to choose it.

How you get 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.

The operations

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.

The algebra, and the one thing it cannot do

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.

What fits in a register

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:

  • Bits spread over all 4,096 positions have to be sparse: about 1.5% density, because every set bit occupies a fresh lane.
  • Bits confined to 48 lanes can be at any density, including 50%. That is a fully dense hypervector 1,536 bits wide, and it always fits.

hdc_fits_device() answers for a vector, and a move that would not fit is refused with a clear status instead of corrupting data.

What it measures

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.