This guide provides detailed walkthroughs of the VSA example scripts, explaining key concepts and demonstrating practical applications.
The VSA module uses an array-based API for consistency with the rest of the cognitive_computing package:
- No
encode()method: Usevsa.generate_vector()to create random vectors - No vector objects in public API: All operations work with numpy arrays directly
- No
inverse(),zero(), oridentity()methods: Use appropriate numpy operations - Direct architecture instantiation: Use
BSC(),MAP(), etc. instead of factory functions - Permutation requires shift parameter: Use
vsa.permute(vector, shift=n) - Thinning rate parameter:
vsa.thin(vector, rate=0.9)zeros out 90% of elements
- basic_vsa_demo.py - Introduction to VSA concepts
- binding_comparison.py - Comparing binding operations
- vector_types_demo.py - Understanding vector types
- symbolic_reasoning.py - Advanced reasoning capabilities
- data_encoding.py - Encoding various data types
Location: examples/vsa/basic_vsa_demo.py
This example introduces fundamental VSA concepts through hands-on demonstrations.
# Import vector types and utility function
from cognitive_computing.vsa import (
BinaryVector, BipolarVector, TernaryVector,
ComplexVector, IntegerVector, generate_random_vector
)
# Binary vectors for hardware efficiency
binary_vec = generate_random_vector(1000, BinaryVector)
# Bipolar vectors for general use
bipolar_vec = generate_random_vector(1000, BipolarVector)
# Sparse ternary vectors (sparsity = fraction of non-zeros)
ternary_vec = generate_random_vector(1000, TernaryVector, sparsity=0.1)Learning Points:
- Different vector types have different properties
- Binary is memory-efficient (1 bit per element)
- Bipolar is most versatile (-1/+1 values)
- Ternary enables sparse representations
# Create VSA instance
vsa = create_vsa(
dimension=1000,
vector_type='binary',
vsa_type='bsc' # Binary Spatter Codes use XOR binding
)
# Generate vectors (no encode() method)
red = vsa.generate_vector()
apple = vsa.generate_vector()
# XOR binding (binary vectors)
red_apple = vsa.bind(red, apple)
# Self-inverse property
original = vsa.bind(red_apple, red) # Recovers appleKey Insights:
- Binding creates associations between concepts
- Different binding operations have different properties
- XOR is self-inverse:
A ⊕ B ⊕ B = A
# Generate concept vectors
apple = vsa.generate_vector()
banana = vsa.generate_vector()
orange = vsa.generate_vector()
car = vsa.generate_vector()
# Create a set representation
fruits = vsa.bundle([apple, banana, orange])
# Check membership
similarity = vsa.similarity(fruits, apple) # ~0.3-0.4
similarity = vsa.similarity(fruits, car) # ~0.0Important Concepts:
- Bundling creates set-like structures
- Items remain recoverable from bundles
- Capacity limited to ~√dimension items
python examples/vsa/basic_vsa_demo.pyExpected output shows:
- Vector type properties
- Binding operation results
- Bundling demonstrations
- Different VSA architectures
Location: examples/vsa/binding_comparison.py
This example provides an in-depth comparison of different binding operations.
The script measures binding performance:
# Time different binding operations
results = measure_binding_performance(
dimension=1000,
num_operations=1000
)Results Interpretation:
- XOR: Fastest (bitwise operations)
- Multiplication: Fast (element-wise)
- Convolution: Slower (FFT required)
- MAP: Moderate (multiple steps)
# Test commutativity: A ⊗ B = B ⊗ A
ab = vsa.bind(a, b)
ba = vsa.bind(b, a)
commutative = vsa.similarity(ab, ba) > 0.95Property Summary:
| Operation | Commutative | Associative | Self-Inverse | Distributive |
|---|---|---|---|---|
| XOR | ✓ | ✓ | ✓ | ✗ |
| Multiplication | ✓ | ✓ | ✗ | ✗ |
| Convolution | ✓ | ✓ | ✗ | ✓ |
| MAP† | ✓ | ≈ | ✗ | ≈ |
| Permutation | ✗ | ✗ | ✗ | ✗ |
† Note: MAP architecture with bipolar vectors defaults to multiplication binding.
Important: When using convolution binding with bipolar vectors and normalization, the similarity after unbinding is typically around 0.5-0.6 rather than near 1.0. This is due to the discrete nature of the vectors and the sign() normalization applied.
# Add noise and test recovery
noisy_bound = add_noise(bound, noise_level=0.2)
recovered = vsa.unbind(noisy_bound, key)Findings:
- MAP most noise-tolerant
- Convolution good for moderate noise
- XOR sensitive to bit flips
# Test multiple bindings
pairs = [(key_i, value_i) for i in range(n)]
bundle = vsa.bundle([vsa.bind(k, v) for k, v in pairs])Capacity Guidelines:
- Single binding: High fidelity
- 5-10 bindings: Good recovery
- 20+ bindings: Degraded performance
-
XOR Binding
- Binary data
- Hardware implementations
- Cryptographic applications
-
Multiplication Binding
- General-purpose VSA
- Neural network integration
- Real-valued data
-
Convolution Binding
- Sequential data
- Signal processing
- HRR compatibility
-
MAP Binding
- Noisy environments
- Multiple simultaneous bindings
- Cognitive modeling
Location: examples/vsa/vector_types_demo.py
Comprehensive exploration of different vector types and their properties.
# Generate binary vectors
binary_vec = generate_random_vector(1000, BinaryVector)
vec1 = binary_vec.data # Access numpy array
vec2 = generate_random_vector(1000, BinaryVector).data
# Properties
density = np.mean(vec1) # ~0.5
hamming_dist = np.sum(vec1 != vec2)Use Cases:
- Bloom filters
- Hardware accelerators
- Memory-constrained systems
# Generate bipolar vectors
vec1 = generate_random_vector(1000, BipolarVector).data
vec2 = generate_random_vector(1000, BipolarVector).data
# Statistical properties
mean = np.mean(vec1) # ~0
correlation = np.corrcoef(vec1, vec2)[0,1] # ~0Applications:
- Neural networks
- Continuous embeddings
- General VSA operations
# Generate sparse ternary vector
# Note: sparsity parameter = fraction of non-zeros
ternary_vec = generate_random_vector(1000, TernaryVector, sparsity=0.1)
vec_data = ternary_vec.data
# Sparse representation
sparsity = 0.1 # 10% non-zeros, 90% zeros
active_elements = np.sum(vec_data != 0)Benefits:
- Memory efficiency
- Faster operations on sparse data
- Biological plausibility
# Generate complex vector
complex_vec = generate_random_vector(1000, ComplexVector)
vec_data = complex_vec.data
# Phase-based encoding
phases = np.angle(vec_data)
magnitudes = np.abs(vec_data) # All 1.0Advantages:
- Frequency domain operations
- Holographic properties
- Rich mathematical structure
# Generate integer vectors
vec1 = generate_random_vector(1000, IntegerVector, modulus=256)
vec2 = generate_random_vector(1000, IntegerVector, modulus=256)
# Modular arithmetic
modulus = 256
result = (vec1.data + vec2.data) % modulusApplications:
- Finite field operations
- Cryptography
- Error correction
| Vector Type | Bits per Element | 10K Dimension Size |
|---|---|---|
| Binary | 1 | 1.25 KB |
| Bipolar | 8 | 10 KB |
| Ternary (10% sparse) | ~3.2 | 4 KB |
| Complex | 128 | 160 KB |
| Integer (mod 256) | 8 | 10 KB |
Location: examples/vsa/symbolic_reasoning.py
Advanced reasoning capabilities using VSA.
# A:B :: C:?
# King:Queen :: Man:Woman
# Generate concept vectors
king = vsa.generate_vector()
queen = vsa.generate_vector()
man = vsa.generate_vector()
woman = vsa.generate_vector()
# Learn transformation (no inverse() method)
# For multiplication binding, we use a different approach
transform = vsa.bind(queen, king)
# Apply transformation
result = vsa.bind(transform, vsa.bind(man, king))
# Note: Similarity scores are typically low (~0.0) due to
# multiplication binding not being ideal for analogiesKey Concept: VSA can learn and apply relational transformations.
class KnowledgeBase:
def add_fact(self, subject, predicate, object):
# Store as role-filler structure
fact = vsa.bundle([
vsa.bind(SUBJECT_ROLE, subject),
vsa.bind(PREDICATE_ROLE, predicate),
vsa.bind(OBJECT_ROLE, object)
])Applications:
- Semantic networks
- Question answering
- Inference systems
# Nested structures
red_car = vsa.bundle([
vsa.bind(COLOR, red),
vsa.bind(TYPE, car)
])
scene = vsa.bundle([
vsa.bind(OBJECT1, red_car),
vsa.bind(OBJECT2, blue_house)
])Capabilities:
- Arbitrary nesting depth
- Role-based access
- Graceful degradation
# Fuzzy logic with VSA
true = vsa.encode('TRUE')
false = vsa.encode('FALSE')
maybe = vsa.bundle([true, false], weights=[0.5, 0.5])Features:
- Continuous truth values
- Probabilistic reasoning
- Soft logic operations
# Query knowledge base
def query(self, role, fact_vector):
result = vsa.unbind(fact_vector, role)
# Find closest match in vocabulary
return find_closest_concept(result)Example Queries:
- "What is John's occupation?"
- "Who lives in New York?"
- "Which doctors live in Boston?"
# Attention mechanism
attention_query = vsa.bind(COLOR, red)
for object in scene:
relevance = vsa.similarity(object, attention_query)
# Higher relevance = more attentionCognitive Models:
- Working memory (limited capacity)
- Attention (similarity-based selection)
- Priming (spreading activation)
Location: examples/vsa/data_encoding.py
Comprehensive guide to encoding different data types.
# Character-level encoding
word = "hello"
char_vectors = []
for i, char in enumerate(word):
pos_vec = vsa.encode(f'pos_{i}')
char_vec = vsa.encode(f'char_{char}')
char_vectors.append(vsa.bind(pos_vec, char_vec))
word_vec = vsa.bundle(char_vectors)Techniques:
- Character-level: Fine-grained control
- Word-level: Semantic units
- N-grams: Local context
- Random indexing: Dimensionality reduction
# Continuous values with levels
level_encoder = LevelEncoder(
vsa,
num_levels=10,
min_value=0.0,
max_value=100.0
)
temp_vec = level_encoder.encode(25.5)Strategies:
- Discretization: Map to levels
- Magnitude-phase: Complex representation
- Thermometer coding: Cumulative activation
# 2D coordinates
spatial_encoder = SpatialEncoder(vsa, grid_size=(100, 100))
location = spatial_encoder.encode_2d(x=45, y=67)
# Scene representation
scene = vsa.bundle([
vsa.bind(car, location1),
vsa.bind(tree, location2)
])Applications:
- Image representation
- Spatial reasoning
- Navigation tasks
# Time series
temporal_encoder = TemporalEncoder(vsa, max_lag=5)
series_vec = vsa.zero()
for t, value in enumerate(time_series):
time_vec = temporal_encoder.encode_time_point(t)
value_vec = encode_value(value)
series_vec = vsa.bundle([
series_vec,
vsa.bind(time_vec, value_vec)
])Use Cases:
- Sensor data
- Event sequences
- Periodic patterns
# Graph structure
graph_encoder = GraphEncoder(vsa)
edges = [('A', 'B'), ('B', 'C'), ('C', 'D')]
graph_vec = vsa.bundle([
graph_encoder.encode_edge(
vsa.encode(src),
vsa.encode(dst)
)
for src, dst in edges
])Capabilities:
- Node embeddings
- Edge relationships
- Path encoding
- Attributed graphs
# IoT sensor reading
sensor_data = {
'device_id': 'sensor_42',
'timestamp': 1234567890,
'location': (37.7749, -122.4194),
'temperature': 22.5,
'status': 'active'
}
# Encode each component appropriately
sensor_vec = encode_mixed_data(sensor_data)Best Practices:
- Choose appropriate encoder for each field
- Maintain consistent dimensionality
- Use role-filler for structure
- Consider sparsity for efficiency
To run all examples:
# Run individual examples
python examples/vsa/basic_vsa_demo.py
python examples/vsa/binding_comparison.py
python examples/vsa/vector_types_demo.py
python examples/vsa/symbolic_reasoning.py
python examples/vsa/data_encoding.py
# Run with custom parameters
python examples/vsa/basic_vsa_demo.py --dimension 5000
python examples/vsa/binding_comparison.py --num-trials 100- Vector Types: Choose based on hardware, sparsity, and mathematical needs
- Binding Operations: Select based on properties and noise requirements
- Encoding Strategies: Match encoder to data type and structure
- Capacity Limits: Respect √dimension rule for reliable storage
- Compositional Power: Build complex structures from simple operations
- Experiment with different dimensions and parameters
- Combine techniques for your specific application
- Explore the API Reference for advanced features
- Read the Performance Guide for optimization tips
- VSA Overview - Conceptual introduction
- Theory Guide - Mathematical foundations
- API Reference - Complete API documentation
- Performance Guide - Optimization strategies