Sparse Distributed Memory (SDM) implementation based on Kanerva (1992)
Project description
KanervaSDM
A high-performance C++ implementation of Sparse Distributed Memory (SDM) with Python bindings, based on Pentti Kanerva's 1992 technical report.
Overview
Sparse Distributed Memory is a cognitive model that stores information in a distributed manner across many locations. This implementation provides:
- Fast C++ core with Python bindings via pybind11.
- Hamming distance-based activation for memory retrieval.
- Support for arbitrary address and memory dimensions.
- Reproducible results with seeded random initialization.
Installation
From Source
git clone https://github.com/made-by-simon/KanervaSDM.git
cd KanervaSDM
pip install .
Development Installation
pip install -e ".[dev]"
Requirements
- Python >= 3.7.
- C++11 compatible compiler.
- pybind11 >= 2.6.0.
Quick Start
import kanerva_sdm
# Initialize SDM with 100-dimensional addresses and memories
sdm = kanerva_sdm.KanervaSDM(
address_dimension=100,
memory_dimension=100,
num_locations=1000,
hamming_threshold=37,
random_seed=42
)
# Write a memory to an address
address = [0, 1] * 50 # Binary address vector
memory = [1, 0] * 50 # Binary memory vector
sdm.write(address, memory)
# Read memory back
recalled = sdm.read(address)
print(f"Recalled memory: {recalled}")
# Check memory count
print(f"Stored memories: {sdm.memory_count}")
API Reference
KanervaSDM
Main class for Sparse Distributed Memory operations.
Initialization
KanervaSDM(
address_dimension: int,
memory_dimension: int,
num_locations: int,
hamming_threshold: int,
random_seed: int = 42
)
Parameters:
address_dimension: Length of address vectors (N).memory_dimension: Length of memory vectors (U).num_locations: Number of hard locations (M).hamming_threshold: Hamming distance threshold for activation (H).random_seed: Seed for reproducible random generation.
Raises:
ValueError: If any dimension or threshold is non-positive.
Methods
write(address, memory)
Store a memory at the given address.
sdm.write([0, 1, 0, 1], [1, 1, 0, 0])
Parameters:
address: Binary list of lengthaddress_dimension.memory: Binary list of lengthmemory_dimension.
Raises:
ValueError: If vectors have incorrect size or contain non-binary values.
read(address)
Retrieve memory from the given address.
recalled = sdm.read([0, 1, 0, 1])
Parameters:
address: Binary list of lengthaddress_dimension.
Returns:
- Binary list of length
memory_dimension. - Returns all zeros if no locations are activated.
Raises:
ValueError: If address has incorrect size or contains non-binary values.
erase_memory()
Reset all memory counters to zero while preserving hard locations.
sdm.erase_memory()
Properties
address_dimension: Length of address vectors.memory_dimension: Length of memory vectors.num_locations: Number of hard locations.hamming_threshold: Activation threshold.memory_count: Number of stored memories.
How It Works
Core Concepts
- Hard Locations (A): Random binary vectors that serve as reference points in the address space.
- Memory Matrix (C): Counters that accumulate memory values at each location.
- Activation: Locations within Hamming distance H of the query address are activated.
- Polar Encoding: Binary values {0,1} are converted to {-1,+1} for storage.
Write Operation
- Find all hard locations within Hamming distance H of the target address.
- Convert memory vector from binary to polar form.
- Add polar values to the memory counters at activated locations.
Read Operation
- Find all hard locations within Hamming distance H of the target address.
- Sum memory counters across activated locations.
- Threshold summation to produce binary output (>= 0 → 1, < 0 → 0).
Examples
Basic Usage
import kanerva_sdm
# Create SDM instance
sdm = kanerva_sdm.KanervaSDM(
address_dimension=100,
memory_dimension=100,
num_locations=1000,
hamming_threshold=37
)
# Store multiple memories
patterns = [
([0]*100, [1]*100),
([1]*100, [0]*100),
([0,1]*50, [1,0]*50)
]
for addr, mem in patterns:
sdm.write(addr, mem)
print(f"Total memories stored: {sdm.memory_count}")
# Retrieve a memory
recalled = sdm.read([0]*100)
print(f"Recalled: {recalled[:10]}...") # First 10 elements
Testing Recall Accuracy
import kanerva_sdm
sdm = kanerva_sdm.KanervaSDM(100, 100, 1000, 37, random_seed=42)
# Store a pattern
original_address = [0, 1] * 50
original_memory = [1, 0] * 50
sdm.write(original_address, original_memory)
# Test recall
recalled = sdm.read(original_address)
accuracy = sum(r == m for r, m in zip(recalled, original_memory)) / len(original_memory)
print(f"Recall accuracy: {accuracy * 100:.1f}%")
Experimenting with Parameters
import kanerva_sdm
# Test different thresholds
for threshold in [30, 35, 40, 45]:
sdm = kanerva_sdm.KanervaSDM(100, 100, 1000, threshold)
sdm.write([0]*100, [1]*100)
recalled = sdm.read([0]*100)
accuracy = sum(recalled) / len(recalled)
print(f"Threshold {threshold}: {accuracy * 100:.1f}% ones recalled")
Testing
Run the test suite using pytest:
# Run all tests
pytest tests/
# Run with verbose output
pytest tests/ -v
# Run specific test
pytest tests/test_kanerva_sdm.py::TestKanervaSDM::test_write_and_read
Performance Considerations
- C++ implementation provides significant speedup over pure Python.
- Memory operations are O(M × N) where M is
num_locationsand N isaddress_dimension. - Larger Hamming thresholds activate more locations, increasing computation.
- Optimal threshold is typically around 40-45% of
address_dimension.
Project Structure
kanerva-sdm/
│
├── include/
│ └── kanerva_sdm/
│ └── kanerva_sdm.h # C++ header
│
├── src/
│ └── kanerva_sdm/
│ ├── __init__.py # Python package init
│ └── bindings.cpp # pybind11 bindings
│
├── tests/
│ └── kanerva_sdm/
│ ├── __init__.py
│ └── test_kanerva_sdm.py # Unit tests
│
├── .gitignore
├── LICENSE
├── MANIFEST.in
├── pyproject.toml
├── README.md
└── setup.py
Reference
This implementation is based on:
Pentti Kanerva (1992). "Sparse Distributed Memory and Related Models."
License
MIT License. See LICENSE for details.
Author
Simon Wong (smw2@ualberta.ca)
Contributing
Contributions are welcome. Please:
- Fork the repository.
- Create a feature branch.
- Add tests for new functionality.
- Ensure all tests pass.
- Submit a pull request.
Issues
Report bugs and request features at GitHub Issues.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kanervasdm-1.0.1.tar.gz.
File metadata
- Download URL: kanervasdm-1.0.1.tar.gz
- Upload date:
- Size: 11.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7423ecf28fc8f34ad5fadb6d306a092bbdd685505faa66ad3f6b5e65d12a00cb
|
|
| MD5 |
6568ae4324a1019a02ed8099e1a7e3aa
|
|
| BLAKE2b-256 |
ee11be5b96a8b101a06acdbe5566aa5be319ac395fd00f466da21a22aed24d34
|
File details
Details for the file kanervasdm-1.0.1-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: kanervasdm-1.0.1-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 93.4 kB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6fb96298e48cdc865950762c56e477a0264132d4f1d7e02cd499483e39c0e00
|
|
| MD5 |
16cdbd8cccde913b4f197363e637001c
|
|
| BLAKE2b-256 |
315f78e223f30700d3581ad50903b7c672bdcb14cbb83ecdf365d1845acca2ac
|