Skip to content

Hyper-Dimensional Computing — Binary Vector Algebra

High-dimensional binary vector algebra for symbolic reasoning in spiking networks. HDC maps naturally to stochastic computing hardware: bind = XOR gate, bundle = popcount tree, similarity = Hamming distance.

Theory

HDC represents symbols as random binary vectors of dimension D (typically D >= 10,000). At high D, random vectors are quasi-orthogonal with high probability: E[d_H(a,b)] = D/2. Three operations form an algebra:

Operation Implementation Property
Bind (⊗) XOR Self-inverse: a ⊗ a = 0, a ⊗ b ⊗ b = a
Bundle (⊕) Majority vote Preserves similarity to all inputs
Permute (ρ) Cyclic shift Breaks commutativity for ordered structures

Components

  • HDCEncoder — Generate random D-dimensional binary vectors and perform algebraic operations.
Parameter Default Meaning
dim 10000 Hypervector dimension

Methods: generate_random_vector(), bind(v1, v2), bundle(vectors), permute(v, shifts).

  • AssociativeMemory — Clean-up memory via Hamming distance nearest-neighbor lookup. Store labeled vectors, retrieve by similarity. Tolerates up to ~35% bit noise.

Usage

from sc_neurocore.hdc import HDCEncoder, AssociativeMemory
import numpy as np

np.random.seed(42)
enc = HDCEncoder(dim=10000)

# Create symbols
country = enc.generate_random_vector()
capital = enc.generate_random_vector()
usa = enc.generate_random_vector()
washington = enc.generate_random_vector()

# Encode: USA_record = bind(country, usa) ⊕ bind(capital, washington)
record = enc.bundle([
    enc.bind(country, usa),
    enc.bind(capital, washington),
])

# Query: "What is the capital of USA?" → bind(record, capital)
query = enc.bind(record, capital)

# Store in associative memory and retrieve
mem = AssociativeMemory()
mem.store("washington", washington)
mem.store("usa", usa)
print(mem.query(query))  # → "washington"

See Tutorial 4: Hyper-Dimensional Computing.

sc_neurocore.hdc.base

HDCEncoder dataclass

Hyperdimensional Computing Encoder. Dimension D usually >= 10,000.

Source code in src/sc_neurocore/hdc/base.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@dataclass
class HDCEncoder:
    """
    Hyperdimensional Computing Encoder.
    Dimension D usually >= 10,000.
    """

    dim: int = 10000

    def generate_random_vector(self) -> np.ndarray[Any, Any]:
        """Generates a random D-dimensional bipolar vector {-1, 1} or {0, 1}."""
        # We use {0, 1} for compatibility with our SC
        return np.random.randint(0, 2, self.dim).astype(np.uint8)

    def bind(self, v1: np.ndarray[Any, Any], v2: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]:
        """XOR Binding operation."""
        return np.bitwise_xor(v1, v2)

    def bundle(self, vectors: list[np.ndarray[Any, Any]]) -> np.ndarray[Any, Any]:
        """
        Majority Bundling (Superposition).
        """
        if not vectors:
            return np.zeros(self.dim, dtype=np.uint8)

        # Sum columns
        sum_vec = np.sum(vectors, axis=0)
        threshold = len(vectors) / 2.0

        return (sum_vec > threshold).astype(np.uint8)

    def permute(self, v: np.ndarray[Any, Any], shifts: int = 1) -> np.ndarray[Any, Any]:
        """Cyclic shift (Permutation)."""
        return np.roll(v, shifts)

generate_random_vector()

Generates a random D-dimensional bipolar vector {-1, 1} or {0, 1}.

Source code in src/sc_neurocore/hdc/base.py
24
25
26
27
def generate_random_vector(self) -> np.ndarray[Any, Any]:
    """Generates a random D-dimensional bipolar vector {-1, 1} or {0, 1}."""
    # We use {0, 1} for compatibility with our SC
    return np.random.randint(0, 2, self.dim).astype(np.uint8)

bind(v1, v2)

XOR Binding operation.

Source code in src/sc_neurocore/hdc/base.py
29
30
31
def bind(self, v1: np.ndarray[Any, Any], v2: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]:
    """XOR Binding operation."""
    return np.bitwise_xor(v1, v2)

bundle(vectors)

Majority Bundling (Superposition).

Source code in src/sc_neurocore/hdc/base.py
33
34
35
36
37
38
39
40
41
42
43
44
def bundle(self, vectors: list[np.ndarray[Any, Any]]) -> np.ndarray[Any, Any]:
    """
    Majority Bundling (Superposition).
    """
    if not vectors:
        return np.zeros(self.dim, dtype=np.uint8)

    # Sum columns
    sum_vec = np.sum(vectors, axis=0)
    threshold = len(vectors) / 2.0

    return (sum_vec > threshold).astype(np.uint8)

permute(v, shifts=1)

Cyclic shift (Permutation).

Source code in src/sc_neurocore/hdc/base.py
46
47
48
def permute(self, v: np.ndarray[Any, Any], shifts: int = 1) -> np.ndarray[Any, Any]:
    """Cyclic shift (Permutation)."""
    return np.roll(v, shifts)

AssociativeMemory dataclass

Simple HDC Associative Memory (Clean-Up Memory). Stores (Key, Value) pairs or just prototypes.

Source code in src/sc_neurocore/hdc/base.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
@dataclass
class AssociativeMemory:
    """
    Simple HDC Associative Memory (Clean-Up Memory).
    Stores (Key, Value) pairs or just prototypes.
    """

    memory: dict[str, Any] = None

    def __post_init__(self):
        self.memory = {}

    def store(self, label: str, vector: np.ndarray[Any, Any]):
        self.memory[label] = vector

    def query(self, query_vec: np.ndarray[Any, Any]) -> str:
        """Returns label of closest vector (Hamming Distance)."""
        best_label = None
        min_dist = float("inf")

        for label, mem_vec in self.memory.items():
            # Hamming distance = count(XOR)
            dist = np.count_nonzero(np.bitwise_xor(query_vec, mem_vec))
            if dist < min_dist:
                min_dist = dist
                best_label = label

        return best_label

query(query_vec)

Returns label of closest vector (Hamming Distance).

Source code in src/sc_neurocore/hdc/base.py
66
67
68
69
70
71
72
73
74
75
76
77
78
def query(self, query_vec: np.ndarray[Any, Any]) -> str:
    """Returns label of closest vector (Hamming Distance)."""
    best_label = None
    min_dist = float("inf")

    for label, mem_vec in self.memory.items():
        # Hamming distance = count(XOR)
        dist = np.count_nonzero(np.bitwise_xor(query_vec, mem_vec))
        if dist < min_dist:
            min_dist = dist
            best_label = label

    return best_label