| name | ndarray-vector-math |
| description | High-performance N-dimensional array operations for vector math in agent memory systems. Cosine similarity, dot product, Euclidean distance, batch matrix ops, and typed array backends. Sources: hughsk/ndarray, scijs ecosystem. |
/ndarray-vector-math
When to Use
- Computing cosine similarity between embedding vectors in agent L1 memory
- Batch nearest-neighbor search without an external vector DB
- Matrix operations for PCA/dimensionality reduction on small embedding sets
- Fast typed-array math without Python/WASM dependency
Do NOT use for
-
100k vectors (use [[in-memory-vector-storage]] or pgvector instead)
- GPU-accelerated matrix math (use ONNX runtime or TensorFlow.js)
Cosine similarity
import ndarray from 'ndarray'
import ops from 'ndarray-ops'
type Vec = Float32Array
function cosine(a: Vec, b: Vec): number {
if (a.length !== b.length) throw new Error('dimension mismatch')
const n = a.length
let dot = 0, normA = 0, normB = 0
for (let i = 0; i < n; i++) {
dot += a[i] * b[i]
normA += a[i] * a[i]
normB += b[i] * b[i]
}
if (normA === 0 || normB === 0) return 0
return dot / (Math.sqrt(normA) * Math.sqrt(normB))
}
const queryVec = new Float32Array([0.1, 0.3, 0.8, ...])
const memVec = new Float32Array([0.2, 0.2, 0.9, ...])
const similarity = cosine(queryVec, memVec)
ndarray batch operations
import ndarray from 'ndarray'
import ops from 'ndarray-ops'
const N = 1000, D = 1536
const matrix = ndarray(new Float32Array(N * D), [N, D])
for (let i = 0; i < N; i++) {
for (let d = 0; d < D; d++) {
matrix.set(i, d, embeddings[i][d])
}
}
for (let i = 0; i < N; i++) {
const row = matrix.pick(i, null)
let norm = 0
for (let d = 0; d < D; d++) norm += row.get(d) ** 2
norm = Math.sqrt(norm)
if (norm > 0) ops.divseq(row, norm)
}
Top-K nearest neighbors (brute force)
function topK(
query: Float32Array,
corpus: Float32Array[],
k = 5,
threshold = 0.75
): { index: number; score: number }[] {
return corpus
.map((vec, index) => ({ index, score: cosine(query, vec) }))
.filter(r => r.score >= threshold)
.sort((a, b) => b.score - a.score)
.slice(0, k)
}
Anti-Fake-Pass Checklist
❌ Float64Array instead of Float32Array → 2× memory, no precision benefit for embeddings
❌ cosine computed on non-normalized vectors → results not in [-1, 1] range
❌ norm === 0 not checked → NaN propagates through all downstream comparisons
❌ N > 100k with brute force → O(N*D) scan too slow (use HNSW index)
❌ ndarray-ops not imported → ops.divseq silently undefined
❌ Dimension mismatch not caught → silent wrong results (no runtime error)