| Crates.io | micro-hnsw-wasm |
| lib.rs | micro-hnsw-wasm |
| version | 2.3.0 |
| created_at | 2025-12-02 03:21:15.225152+00 |
| updated_at | 2025-12-02 03:21:15.225152+00 |
| description | Neuromorphic HNSW vector search with spiking neural networks - 11.8KB WASM for edge AI, ASIC, and embedded systems. Features LIF neurons, STDP learning, winner-take-all, dendritic computation. |
| homepage | https://ruv.io |
| repository | https://github.com/ruvnet/ruvector |
| max_upload_size | |
| id | 1961092 |
| size | 91,483 |
GitHub | Documentation | ruv.io | Crates.io
A 11.8KB neuromorphic computing core that fuses graph-based vector search (HNSW) with biologically-inspired spiking neural networks. Designed for 256-core ASIC deployment, edge AI, and real-time similarity-driven neural processing.
Vector search meets brain-inspired computing β query vectors trigger neural spikes, enabling attention mechanisms, winner-take-all selection, and online learning through spike-timing dependent plasticity (STDP).
no_std Rust, zero allocationsThis release introduces groundbreaking neuromorphic computing features:
| Discovery | Description | Application |
|---|---|---|
| Spike-Timing Vector Encoding | Convert vectors to temporal spike patterns using first-spike coding | Energy-efficient similarity matching |
| Homeostatic Plasticity | Self-stabilizing network that maintains target activity levels | Robust long-running systems |
| Oscillatory Resonance | Gamma-rhythm (40Hz) synchronization for phase-based search | Attention and binding |
| Winner-Take-All Circuits | Competitive selection via lateral inhibition | Hard decision making |
| Dendritic Computation | Nonlinear local processing in dendritic compartments | Coincidence detection |
| Temporal Pattern Recognition | Spike history matching using Hamming similarity | Sequence learning |
Traditional vector databases return ranked results. Micro HNSW v2.2 goes further: similarity scores become neural currents that drive a spiking network. This enables:
no_std Rust| Parameter | Value | Notes |
|---|---|---|
| Vectors/Core | 32 | Static allocation |
| Total Vectors | 8,192 | 256 cores Γ 32 vectors |
| Max Dimensions | 16 | Per vector |
| Neighbors (M) | 6 | Graph connectivity |
| Beam Width | 3 | Search beam size |
| Node Types | 16 | 4-bit packed |
| SNN Neurons | 32 | One per vector |
| WASM Size | ~11.8KB | After wasm-opt -Oz |
| Gate Count | ~45K | Estimated for ASIC |
# Add wasm32 target
rustup target add wasm32-unknown-unknown
# Build with size optimizations
cargo build --release --target wasm32-unknown-unknown
# Optimize with wasm-opt (required for SNN features)
wasm-opt -Oz --enable-nontrapping-float-to-int -o micro_hnsw.wasm \
target/wasm32-unknown-unknown/release/micro_hnsw_wasm.wasm
# Check size
ls -la micro_hnsw.wasm
const response = await fetch('micro_hnsw.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes);
const wasm = instance.exports;
// Initialize: init(dims, metric, core_id)
// metric: 0=L2, 1=Cosine, 2=Dot
wasm.init(8, 1, 0); // 8 dims, cosine similarity, core 0
// Insert vectors
const insertBuf = new Float32Array(wasm.memory.buffer, wasm.get_insert_ptr(), 16);
insertBuf.set([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
const idx = wasm.insert(); // Returns 0, or 255 if full
// Set node type (for Cypher-style queries)
wasm.set_node_type(idx, 3); // Type 3 = e.g., "Person"
// Search
const queryBuf = new Float32Array(wasm.memory.buffer, wasm.get_query_ptr(), 16);
queryBuf.set([0.95, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
const resultCount = wasm.search(5); // k=5
// Read results
const resultPtr = wasm.get_result_ptr();
const resultView = new DataView(wasm.memory.buffer, resultPtr);
for (let i = 0; i < resultCount; i++) {
const idx = resultView.getUint8(i * 8);
const coreId = resultView.getUint8(i * 8 + 1);
const dist = resultView.getFloat32(i * 8 + 4, true);
// Filter by type if needed
if (wasm.type_matches(idx, 0b1000)) { // Only type 3
console.log(`Result: idx=${idx}, distance=${dist}`);
}
}
// Reset SNN state
wasm.snn_reset();
// Inject current into neurons (simulates input)
wasm.snn_inject(0, 1.5); // Strong input to neuron 0
wasm.snn_inject(1, 0.8); // Weaker input to neuron 1
// Run simulation step (dt in ms)
const spikeCount = wasm.snn_step(1.0); // 1ms timestep
console.log(`${spikeCount} neurons spiked`);
// Propagate spikes to neighbors
wasm.snn_propagate(0.5); // gain=0.5
// Apply STDP learning
wasm.snn_stdp();
// Or use combined tick (step + propagate + optional STDP)
const spikes = wasm.snn_tick(1.0, 0.5, 1); // dt=1ms, gain=0.5, learn=true
// Get spike bitset (which neurons fired)
const spikeBits = wasm.snn_get_spikes();
for (let i = 0; i < 32; i++) {
if (spikeBits & (1 << i)) {
console.log(`Neuron ${i} spiked!`);
}
}
// Check individual neuron
if (wasm.snn_spiked(0)) {
console.log('Neuron 0 fired');
}
// Get/set membrane potential
const v = wasm.snn_get_membrane(0);
wasm.snn_set_membrane(0, 0.5);
// Get simulation time
console.log(`Time: ${wasm.snn_get_time()} ms`);
// Vector search activates matching neurons
// Search converts similarity to neural current
const queryBuf = new Float32Array(wasm.memory.buffer, wasm.get_query_ptr(), 16);
queryBuf.set([0.9, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
// hnsw_to_snn: search + inject currents based on distance
const found = wasm.hnsw_to_snn(5, 2.0); // k=5, gain=2.0
// Now run SNN to see which neurons fire from similarity
wasm.snn_tick(1.0, 0.5, 1);
const spikes = wasm.snn_get_spikes();
console.log(`Similar vectors that spiked: 0b${spikes.toString(2)}`);
// ========== SPIKE-TIMING VECTOR ENCODING ==========
// Convert vectors to temporal spike patterns (first-spike coding)
const pattern0 = wasm.encode_vector_to_spikes(0);
const pattern1 = wasm.encode_vector_to_spikes(1);
// Compare patterns using Jaccard-like spike timing similarity
const similarity = wasm.spike_timing_similarity(pattern0, pattern1);
console.log(`Temporal similarity: ${similarity.toFixed(3)}`);
// Search using spike patterns instead of distance
const queryPattern = 0b10101010101010101010101010101010;
const found = wasm.spike_search(queryPattern, 5);
// ========== HOMEOSTATIC PLASTICITY ==========
// Self-stabilizing network maintains target activity (0.1 spikes/ms)
for (let i = 0; i < 1000; i++) {
wasm.snn_step(1.0); // 1ms timestep
wasm.homeostatic_update(1.0); // Adjust thresholds
}
console.log(`Spike rate neuron 0: ${wasm.get_spike_rate(0).toFixed(4)} spikes/ms`);
// ========== OSCILLATORY RESONANCE (40Hz GAMMA) ==========
// Phase-synchronized search for attention mechanisms
wasm.oscillator_step(1.0); // Advance oscillator phase
const phase = wasm.oscillator_get_phase();
console.log(`Oscillator phase: ${phase.toFixed(2)} radians`);
// Compute resonance (phase alignment) for each neuron
const resonance = wasm.compute_resonance(0);
console.log(`Neuron 0 resonance: ${resonance.toFixed(3)}`);
// Search with phase modulation (results boosted by resonance)
const phaseResults = wasm.resonance_search(5, 0.5); // k=5, weight=0.5
// ========== WINNER-TAKE-ALL CIRCUITS ==========
// Hard decision: only strongest neuron survives
const winner = wasm.wta_compete();
if (winner !== 255) {
console.log(`Winner: neuron ${winner}`);
}
// Soft competition (softmax-like proportional inhibition)
wasm.wta_soft();
// ========== DENDRITIC COMPUTATION ==========
// Nonlinear local processing in dendritic branches
wasm.dendrite_reset();
// Inject current to specific dendritic branch
wasm.dendrite_inject(0, 0, 1.5); // Neuron 0, branch 0, current 1.5
wasm.dendrite_inject(0, 1, 1.2); // Neuron 0, branch 1, current 1.2
// Nonlinear integration (coincident inputs get amplified)
const totalCurrent = wasm.dendrite_integrate(0);
console.log(`Dendritic current to soma: ${totalCurrent.toFixed(3)}`);
// Propagate spikes through dendritic tree (not just soma)
wasm.snn_step(1.0);
wasm.dendrite_propagate(0.5); // gain=0.5
// ========== TEMPORAL PATTERN RECOGNITION ==========
// Record spike history as shift register
for (let t = 0; t < 32; t++) {
wasm.snn_step(1.0);
wasm.pattern_record(); // Shift spikes into buffer
}
// Get spike pattern (32 timesteps encoded as bits)
const pattern = wasm.get_pattern(0);
console.log(`Neuron 0 spike history: 0b${pattern.toString(2).padStart(32, '0')}`);
// Find neuron with most similar spike history
const matchedNeuron = wasm.pattern_match(pattern);
console.log(`Best pattern match: neuron ${matchedNeuron}`);
// Find all neurons with correlated activity (Hamming distance β€ 8)
const correlated = wasm.pattern_correlate(0, 8);
console.log(`Correlated neurons: 0b${correlated.toString(2)}`);
// ========== FULL NEUROMORPHIC SEARCH ==========
// Combined pipeline: HNSW + SNN + oscillation + WTA + patterns
queryBuf.set([0.9, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]);
const neuroResults = wasm.neuromorphic_search(5, 1.0, 20); // k=5, dt=1ms, 20 iterations
console.log(`Found ${neuroResults} matches via neuromorphic search`);
// Monitor network activity
const activity = wasm.get_network_activity();
console.log(`Network activity: ${activity.toFixed(3)} total spike rate`);
// Set edge weights for nodes (0-255, higher = more important)
wasm.set_edge_weight(0, 255); // Node 0: full weight
wasm.set_edge_weight(1, 128); // Node 1: half weight
// Aggregate neighbors (GNN-style)
wasm.aggregate_neighbors(0); // Aggregates neighbors of node 0
// Read aggregated embedding from DELTA buffer
const deltaBuf = new Float32Array(wasm.memory.buffer, wasm.get_delta_ptr(), 16);
console.log('Aggregated:', Array.from(deltaBuf));
// Update vector: v = v + alpha * delta
wasm.update_vector(0, 0.1); // 10% update toward neighbors
const cores = [];
for (let i = 0; i < 256; i++) {
const { instance } = await WebAssembly.instantiate(wasmBytes);
instance.exports.init(8, 1, i);
cores.push(instance.exports);
}
// Parallel search with merging
async function searchAll(query, k) {
for (const core of cores) {
new Float32Array(core.memory.buffer, core.get_query_ptr(), 16).set(query);
}
const results = await Promise.all(cores.map(c => c.search(k)));
cores[0].clear_global();
for (let i = 0; i < cores.length; i++) {
cores[0].merge(cores[i].get_result_ptr(), results[i]);
}
return cores[0].get_global_ptr();
}
// Core API
void init(uint8_t dims, uint8_t metric, uint8_t core_id);
float* get_insert_ptr(void);
float* get_query_ptr(void);
SearchResult* get_result_ptr(void);
SearchResult* get_global_ptr(void);
uint8_t insert(void);
uint8_t search(uint8_t k);
uint8_t merge(SearchResult* results, uint8_t count);
void clear_global(void);
// Info
uint8_t count(void);
uint8_t get_core_id(void);
uint8_t get_metric(void);
uint8_t get_dims(void);
uint8_t get_capacity(void);
// Cypher Node Types
void set_node_type(uint8_t idx, uint8_t type); // type: 0-15
uint8_t get_node_type(uint8_t idx);
uint8_t type_matches(uint8_t idx, uint16_t type_mask);
// GNN Edge Weights
void set_edge_weight(uint8_t node, uint8_t weight); // weight: 0-255
uint8_t get_edge_weight(uint8_t node);
void aggregate_neighbors(uint8_t idx); // Results in DELTA buffer
// Vector Updates
float* get_delta_ptr(void);
float* set_delta_ptr(void); // Mutable access
void update_vector(uint8_t idx, float alpha); // v += alpha * delta
// Spiking Neural Network (NEW in v2.2)
void snn_reset(void); // Reset all SNN state
void snn_set_membrane(uint8_t idx, float v); // Set membrane potential
float snn_get_membrane(uint8_t idx); // Get membrane potential
void snn_set_threshold(uint8_t idx, float t); // Set firing threshold
void snn_inject(uint8_t idx, float current); // Inject current
uint8_t snn_spiked(uint8_t idx); // Did neuron spike?
uint32_t snn_get_spikes(void); // Spike bitset (32 neurons)
uint8_t snn_step(float dt); // LIF step, returns spike count
void snn_propagate(float gain); // Propagate spikes to neighbors
void snn_stdp(void); // STDP weight update
uint8_t snn_tick(float dt, float gain, uint8_t learn); // Combined step
float snn_get_time(void); // Get simulation time
uint8_t hnsw_to_snn(uint8_t k, float gain); // Search β neural activation
// ========== NOVEL NEUROMORPHIC API (NEW in v2.3) ==========
// Spike-Timing Vector Encoding
uint32_t encode_vector_to_spikes(uint8_t idx); // Vector β temporal spike pattern
float spike_timing_similarity(uint32_t a, uint32_t b); // Jaccard spike similarity
uint8_t spike_search(uint32_t query_pattern, uint8_t k); // Temporal code search
// Homeostatic Plasticity
void homeostatic_update(float dt); // Adjust thresholds for target rate
float get_spike_rate(uint8_t idx); // Running average spike rate
// Oscillatory Resonance
void oscillator_step(float dt); // Update gamma oscillator phase
float oscillator_get_phase(void); // Current phase (0 to 2Ο)
float compute_resonance(uint8_t idx); // Phase alignment score
uint8_t resonance_search(uint8_t k, float weight); // Phase-modulated search
// Winner-Take-All Circuits
void wta_reset(void); // Reset WTA state
uint8_t wta_compete(void); // Hard WTA, returns winner
void wta_soft(void); // Soft competition (softmax-like)
// Dendritic Computation
void dendrite_reset(void); // Clear dendritic compartments
void dendrite_inject(uint8_t n, uint8_t b, float i); // Inject to branch
float dendrite_integrate(uint8_t neuron); // Nonlinear integration
void dendrite_propagate(float gain); // Spike to dendrite routing
// Temporal Pattern Recognition
void pattern_record(void); // Shift current spikes into buffer
uint32_t get_pattern(uint8_t idx); // Get spike history (32 timesteps)
uint8_t pattern_match(uint32_t target); // Find best matching neuron
uint32_t pattern_correlate(uint8_t idx, uint8_t thresh); // Find correlated neurons
// Combined Neuromorphic Search
uint8_t neuromorphic_search(uint8_t k, float dt, uint8_t iters); // Full pipeline
float get_network_activity(void); // Total spike rate across network
// SearchResult structure (8 bytes)
typedef struct {
uint8_t idx;
uint8_t core_id;
uint8_t _pad[2];
float distance;
} SearchResult;
Run semantic search on microcontrollers, IoT devices, or edge servers without external dependencies.
// Semantic search on edge device
// Each core handles a shard of your embedding space
const cores = await initializeCores(256);
// Insert document embeddings (from TinyBERT, MiniLM, etc.)
for (const doc of documents) {
const embedding = await encoder.encode(doc.text);
const coreId = hashToCoreId(doc.id);
cores[coreId].insertVector(embedding, doc.type);
}
// Query: "machine learning tutorials"
const queryVec = await encoder.encode(query);
const results = await searchAllCores(queryVec, k=10);
// Results ranked by cosine similarity across 8K vectors
// Total memory: 7.2KB Γ 256 = 1.8MB for 8K vectors
Why SNN helps: After search, run snn_tick() with inhibition β only the most relevant results survive the neural competition. Better than simple top-k.
Build typed property graphs with vector-enhanced traversal.
// Define entity types for a biomedical knowledge graph
const GENE = 0, PROTEIN = 1, DISEASE = 2, DRUG = 3, PATHWAY = 4;
// Insert entities with embeddings
insertVector(geneEmbedding, GENE); // "BRCA1" β type 0
insertVector(proteinEmbedding, PROTEIN); // "p53" β type 1
insertVector(diseaseEmbedding, DISEASE); // "breast cancer" β type 2
// Cypher-like query: Find proteins similar to query, connected to diseases
const proteinMask = 1 << PROTEIN;
const results = wasm.search(20);
for (const r of results) {
if (wasm.type_matches(r.idx, proteinMask)) {
// Found similar protein - now traverse edges
wasm.aggregate_neighbors(r.idx);
// Check if neighbors include diseases
}
}
Why SNN helps: Model spreading activation through the knowledge graph. A query about "cancer treatment" activates DISEASE nodes, which propagate to connected DRUG and GENE nodes via snn_propagate().
Systems that learn patterns from experience without retraining.
// Anomaly detection that learns normal patterns
class SelfLearningAnomalyDetector {
async processEvent(sensorVector) {
// Find similar past events
wasm.hnsw_to_snn(5, 2.0); // Top-5 similar β neural current
// Run SNN with STDP learning enabled
const spikes = wasm.snn_tick(1.0, 0.5, 1); // learn=1
if (spikes === 0) {
// Nothing spiked = no similar patterns = ANOMALY
return { anomaly: true, confidence: 0.95 };
}
// Normal: similar patterns recognized and reinforced
// STDP strengthened the connection for next time
return { anomaly: false };
}
}
// Over time, the system learns what "normal" looks like
// New attack patterns won't match β no spikes β alert
How it works: STDP increases edge weights between vectors that co-activate. Repeated normal patterns build strong connections; novel anomalies find no matching pathways.
k-mer embeddings enable similarity search across genomic data.
// DNA sequence similarity with neuromorphic processing
const KMER_SIZE = 6; // 6-mer embeddings
// Embed reference genome k-mers
for (let i = 0; i < genome.length - KMER_SIZE; i++) {
const kmer = genome.slice(i, i + KMER_SIZE);
const embedding = kmerToVector(kmer); // One-hot or learned embedding
wasm.insert();
wasm.set_node_type(i % 32, positionToType(i)); // Encode genomic region
}
// Query: Find similar sequences to a mutation site
const mutationKmer = "ATCGTA";
const queryVec = kmerToVector(mutationKmer);
wasm.hnsw_to_snn(10, 3.0);
// SNN competition finds the MOST similar reference positions
wasm.snn_tick(1.0, -0.2, 0); // Lateral inhibition
const matches = wasm.snn_get_spikes();
// Surviving spikes = strongest matches
// Spike timing = match confidence (earlier = better)
Why SNN helps:
Microsecond pattern matching for market microstructure.
// Real-time order flow pattern recognition
class TradingPatternMatcher {
constructor() {
// Pre-load known patterns: momentum, mean-reversion, spoofing, etc.
this.patterns = [
{ name: 'momentum_breakout', vector: [...], type: 0 },
{ name: 'mean_reversion', vector: [...], type: 1 },
{ name: 'spoofing_signature', vector: [...], type: 2 },
{ name: 'iceberg_order', vector: [...], type: 3 },
];
for (const p of this.patterns) {
insertVector(p.vector, p.type);
}
}
// Called every tick (microseconds)
onMarketData(orderBookSnapshot) {
const features = extractFeatures(orderBookSnapshot);
// [bid_depth, ask_depth, spread, imbalance, volatility, ...]
// Find matching patterns
setQuery(features);
wasm.hnsw_to_snn(5, 2.0);
// SNN decides which pattern "wins"
wasm.snn_tick(0.1, -0.5, 0); // Fast tick, strong inhibition
const winner = wasm.snn_get_spikes();
if (winner & (1 << 0)) return 'GO_LONG'; // Momentum
if (winner & (1 << 1)) return 'GO_SHORT'; // Mean reversion
if (winner & (1 << 2)) return 'CANCEL'; // Spoofing detected
return 'HOLD';
}
}
Why SNN helps:
Predictive maintenance and anomaly detection at the edge.
// Vibration analysis for rotating machinery
class PredictiveMaintenance {
constructor() {
// Reference signatures: healthy, bearing_wear, misalignment, imbalance
this.signatures = loadVibrationSignatures();
for (const sig of this.signatures) {
insertVector(sig.fftFeatures, sig.condition);
}
}
// Called every 100ms from accelerometer
analyzeVibration(fftSpectrum) {
setQuery(fftSpectrum);
// Match against known conditions
wasm.hnsw_to_snn(this.signatures.length, 1.5);
wasm.snn_tick(1.0, 0.3, 1); // Learn new patterns over time
const spikes = wasm.snn_get_spikes();
// Check which condition matched
if (spikes & (1 << HEALTHY)) {
return { status: 'OK', confidence: wasm.snn_get_membrane(HEALTHY) };
}
if (spikes & (1 << BEARING_WEAR)) {
return {
status: 'WARNING',
condition: 'bearing_wear',
action: 'Schedule maintenance in 72 hours'
};
}
if (spikes & (1 << CRITICAL)) {
return { status: 'ALARM', action: 'Immediate shutdown' };
}
// No match = unknown condition = anomaly
return { status: 'UNKNOWN', action: 'Flag for analysis' };
}
}
Why SNN helps:
Combine LIDAR, camera, and IMU embeddings for navigation.
// Multi-modal sensor fusion for autonomous navigation
class SensorFusion {
// Each sensor type gets dedicated neurons
LIDAR_NEURONS = [0, 1, 2, 3, 4, 5, 6, 7]; // 8 neurons
CAMERA_NEURONS = [8, 9, 10, 11, 12, 13, 14, 15]; // 8 neurons
IMU_NEURONS = [16, 17, 18, 19, 20, 21, 22, 23]; // 8 neurons
fuseAndDecide(lidarEmbed, cameraEmbed, imuEmbed) {
wasm.snn_reset();
// Inject sensor readings as currents
for (let i = 0; i < 8; i++) {
wasm.snn_inject(this.LIDAR_NEURONS[i], lidarEmbed[i] * 2.0);
wasm.snn_inject(this.CAMERA_NEURONS[i], cameraEmbed[i] * 1.5);
wasm.snn_inject(this.IMU_NEURONS[i], imuEmbed[i] * 1.0);
}
// Run competition β strongest signals propagate
for (let t = 0; t < 5; t++) {
wasm.snn_tick(1.0, 0.4, 0);
}
// Surviving spikes = fused representation
const fusedSpikes = wasm.snn_get_spikes();
// Decision: which direction is clear?
// Spike pattern encodes navigable directions
return decodeSpikePattern(fusedSpikes);
}
}
Why SNN helps:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β APPLICATION LAYER β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Trading β Genomics β Robotics β Industrial β Knowledge β
β Signals β k-mers β Sensors β Vibration β Graphs β
βββββββ¬βββββββ΄ββββββ¬βββββββ΄ββββββ¬βββββββ΄βββββββ¬ββββββββ΄βββββββ¬ββββββββ
β β β β β
βΌ βΌ βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EMBEDDING LAYER β
β Convert domain data β 16-dimensional vectors β
β (TinyBERT, k-mer encoding, FFT features, one-hot, learned, etc.) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MICRO HNSW v2.2 CORE (7.2KB) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β HNSW βββββΆβ GNN βββββΆβ SNN β β
β β (Search) β β (Propagate)β β (Decide) β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β Cosine β β Neighbor β β LIF β β
β β L2, Dot β β Aggregateβ β Dynamics β β
β ββββββββββββ ββββββββββββ ββββββββββββ β
β β β
β βΌ β
β ββββββββββββ β
β β STDP β β
β β Learning β β
β ββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OUTPUT: SPIKE PATTERN β
β β’ Which neurons fired β Classification/Decision β
β β’ Spike timing β Confidence ranking β
β β’ Membrane levels β Continuous scores β
β β’ Updated weights β Learned associations β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Use Case | Key Functions | Pattern |
|---|---|---|
| Vector DB | insert(), search(), merge() |
Insert β Search β Rank |
| Knowledge Graph | set_node_type(), type_matches(), aggregate_neighbors() |
Type β Filter β Traverse |
| Self-Learning | snn_tick(..., learn=1), snn_stdp() |
Process β Learn β Adapt |
| Anomaly Detection | hnsw_to_snn(), snn_get_spikes() |
Match β Spike/NoSpike β Alert |
| Trading | snn_tick() with inhibition, snn_get_spikes() |
Compete β Winner β Signal |
| Industrial | snn_inject(), snn_tick(), snn_get_membrane() |
Sense β Fuse β Classify |
| Sensor Fusion | Multiple snn_inject(), snn_propagate() |
Inject β Propagate β Bind |
// Define node types
const PERSON = 0, COMPANY = 1, PRODUCT = 2;
// Insert typed nodes
insertVector([...], PERSON);
insertVector([...], COMPANY);
// Search only for PERSON nodes
const personMask = 1 << PERSON; // 0b001
for (let i = 0; i < resultCount; i++) {
if (wasm.type_matches(results[i].idx, personMask)) {
// This is a Person node
}
}
// One GNN propagation step across all nodes
function gnnStep(alpha = 0.1) {
for (let i = 0; i < wasm.count(); i++) {
wasm.aggregate_neighbors(i); // Mean of neighbors
wasm.update_vector(i, alpha); // Blend with self
}
}
// Run 3 GNN layers
for (let layer = 0; layer < 3; layer++) {
gnnStep(0.5);
}
// Use SNN for attention: similar vectors compete via lateral inhibition
function spikingAttention(queryVec, steps = 10) {
wasm.snn_reset();
const queryBuf = new Float32Array(wasm.memory.buffer, wasm.get_query_ptr(), 16);
queryBuf.set(queryVec);
wasm.hnsw_to_snn(wasm.count(), 3.0); // Strong activation from similarity
// Run SNN dynamics - winner-take-all emerges
for (let t = 0; t < steps; t++) {
wasm.snn_tick(1.0, -0.3, 0); // Negative gain = inhibition
}
// Surviving spikes = attention winners
return wasm.snn_get_spikes();
}
// Present pattern sequence, learn associations
function learnSequence(patterns, dt = 10.0) {
wasm.snn_reset();
for (const pattern of patterns) {
// Inject current for active neurons
for (const neuron of pattern) {
wasm.snn_inject(neuron, 2.0);
}
// Run with STDP learning enabled
wasm.snn_tick(dt, 0.5, 1);
}
// Edge weights now encode sequence associations
}
The verilog/ directory contains synthesizable RTL for direct ASIC implementation.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 256-Core ASIC Layout β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β SNN Controller β β
β β (Membrane, Threshold, Spike Router, STDP Engine) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β βββββββ βββββββ βββββββ βββββββ βββββββ βββββββ β
β βCore β βCore β βCore β βCore β ... βCore β βCore β β
β β 0 β β 1 β β 2 β β 3 β β 254 β β 255 β β
β β 32 β β 32 β β 32 β β 32 β β 32 β β 32 β β
β β vec β β vec β β vec β β vec β β vec β β vec β β
β β LIF β β LIF β β LIF β β LIF β β LIF β β LIF β β
β ββββ¬βββ ββββ¬βββ ββββ¬βββ ββββ¬βββ ββββ¬βββ ββββ¬βββ β
β β β β β β β β
β βββββββββ΄ββββββββ΄ββββββββ΄ββββββββββββ΄ββββββββ β
β βΌ β
β βββββββββββββββββββββββ β
β β Result Merger β β
β β (Priority Queue) β β
β βββββββββββββββββββββββ β
β βΌ β
β βββββββββββββββββββββββ β
β β AXI-Lite I/F β β
β βββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The v2.3 neuromorphic features map to dedicated hardware units:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NEUROMORPHIC ASIC ARCHITECTURE β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ β
β β SPIKE ENCODER β β GAMMA OSCILLATORβ β WTA CIRCUIT β β
β β VectorβSpikes β β 40Hz Phase Gen β β Lateral Inhib β β
β β 8-bit temporal β β sin/cos LUT β β Max detector β β
β ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ ββββββββββ¬βββββββββ β
β β β β β
β ββββββββββββββββββββββΌβββββββββββββββββββββ β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β DENDRITIC TREE PROCESSOR β β
β β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β β
β β β Branch 0 β β Branch 1 β β Branch 2 β β Branch 3 β ... Γ6 β β
β β β Ο nonlin β β Ο nonlin β β Ο nonlin β β Ο nonlin β β β
β β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ β β
β β ββββββββββββββΌβββββββββββββΌβββββββββββββ β β
β β βΌ βΌ β β
β β βββββββββββββββββββββββ β β
β β β SOMA INTEGRATOR β β β
β β βββββββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β HOMEOSTATIC CONTROLLER β β
β β Target rate: 0.1 spikes/ms | Threshold adaptation: Ο=1000ms β β
β β Sliding average spike counter β PID threshold adjustment β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β PATTERN RECOGNITION UNIT β β
β β 32-bit shift registers Γ 32 neurons = 128 bytes β β
β β Hamming distance comparator (parallel XOR + popcount) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Block | Gate Count | Area (ΞΌmΒ²) | Power (mW) | Notes |
|---|---|---|---|---|
| Spike Encoder | ~2K | 800 | 0.02 | Vectorβtemporal conversion |
| Gamma Oscillator | ~500 | 200 | 0.01 | Phase accumulator + LUT |
| WTA Circuit | ~1K | 400 | 0.05 | Parallel max + inhibit |
| Dendritic Tree (Γ32) | ~8K | 3200 | 0.4 | Nonlinear branches |
| Homeostatic Ctrl | ~1.5K | 600 | 0.03 | PID + moving average |
| Pattern Unit | ~3K | 1200 | 0.1 | 32Γ32 shift + Hamming |
| v2.3 Total | ~60K | 24,000 | 1.0 | Full neuromorphic |
| v2.2 Baseline | ~45K | 18,000 | 0.7 | SNN + HNSW only |
module neuromorphic_hnsw (
input clk_core, // 500 MHz
input clk_snn, // 1 kHz
input clk_gamma, // 40 Hz
input rst_n,
// AXI-Lite interface
input [31:0] axi_addr,
input [31:0] axi_wdata,
output [31:0] axi_rdata,
// Spike I/O
output [31:0] spike_out,
input [31:0] spike_in
);
// Core instances
hnsw_core #(.CORE_ID(i)) cores[255:0] (...);
// Neuromorphic additions (v2.3)
spike_encoder enc (.clk(clk_core), ...);
gamma_oscillator osc (.clk(clk_gamma), ...);
wta_circuit wta (.clk(clk_core), ...);
dendritic_tree dend[31:0] (.clk(clk_snn), ...);
homeostatic_ctrl homeo (.clk(clk_snn), ...);
pattern_recognizer pat (.clk(clk_core), ...);
result_merger merge (...);
endmodule
For Xilinx Zynq-7000 / Artix-7:
| Version | Size | Features |
|---|---|---|
| v1 | 4.6KB | L2 only, single core, greedy search |
| v2 | 7.3KB | +3 metrics, +multi-core, +beam search |
| v2.1 | 5.5KB | +node types, +edge weights, +GNN updates, wasm-opt |
| v2.2 | 7.2KB | +LIF neurons, +STDP learning, +spike propagation, +HNSW-SNN bridge |
| v2.3 | 15KB | +Spike-timing encoding, +Homeostatic plasticity, +Oscillatory resonance, +WTA circuits, +Dendritic computation, +Temporal pattern recognition, +Neuromorphic search pipeline |
| Operation | Complexity | Notes |
|---|---|---|
| Insert | O(n Γ dims) | Per core |
| Search | O(beam Γ M Γ dims) | Beam search |
| Merge | O(k Γ cores) | Result combining |
| Aggregate | O(M Γ dims) | GNN message passing |
| Update | O(dims) | Vector modification |
| SNN Step | O(n) | Per neuron LIF |
| Propagate | O(n Γ M) | Spike routing |
| STDP | O(spikes Γ M) | Only for spiking neurons |
| Parameter | Value | Description |
|---|---|---|
| TAU_MEMBRANE | 20.0 | Membrane time constant (ms) |
| TAU_REFRAC | 2.0 | Refractory period (ms) |
| V_RESET | 0.0 | Reset potential after spike |
| V_REST | 0.0 | Resting potential |
| STDP_A_PLUS | 0.01 | LTP magnitude |
| STDP_A_MINUS | 0.012 | LTD magnitude |
| TAU_STDP | 20.0 | STDP time constant (ms) |
| Parameter | Value | Description |
|---|---|---|
| HOMEOSTATIC_TARGET | 0.1 | Target spike rate (spikes/ms) |
| HOMEOSTATIC_TAU | 1000.0 | Homeostasis time constant (slow) |
| OSCILLATOR_FREQ | 40.0 | Gamma oscillation frequency (Hz) |
| WTA_INHIBITION | 0.8 | Winner-take-all lateral inhibition |
| DENDRITIC_NONLIN | 2.0 | Dendritic nonlinearity exponent |
| SPIKE_ENCODING_RES | 8 | Temporal encoding resolution (bits) |
Contributions are welcome! Please see our Contributing Guide for details.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)If you use Micro HNSW in your research, please cite:
@software{micro_hnsw_wasm,
title = {Micro HNSW: Neuromorphic Vector Search Engine},
author = {rUv},
year = {2024},
url = {https://github.com/ruvnet/ruvector},
version = {2.3.0}
}
MIT OR Apache-2.0