Fast, type-safe utilities for vector embedding comparison and search.
Works in Node.js, browsers β supports ESM, CommonJS, and UMD
- β¨ Features
- π οΈ Installation
- π Quick Usage Examples
- π API Reference
- π§ͺ Tests
- π Related Projects
- π€ Contributing
- π Find nearest neighbors by cosine similarity, or Euclidean/Manhattan distance
- π Compute, normalize, and verify vector similarity
- β‘ Lightweight and fast vector operations
# Yarn
yarn add @allemandi/embed-utils
# NPM
npm install @allemandi/embed-utilsESM
import { computeCosineSimilarity } from '@allemandi/embed-utils';CommonJS
const { findNearestNeighbors } = require('@allemandi/embed-utils');
const samples = [
{ embedding: [0.1, 0.2, 0.3], label: 'sports' },
{ embedding: [0.9, 0.8, 0.7], label: 'finance' },
{ embedding: [0.05, 0.1, 0.15], label: 'sports' },
];
const query = [0.09, 0.18, 0.27];
// Find top 2 neighbors with similarity β₯ 0.5
// (default method: cosine similarity)
const resultsCosine = findNearestNeighbors(query, samples, { topK: 2, threshold: 0.5 });
console.log(resultsCosine);
// [ { embedding: [0.1, 0.2, 0.3], label: "sports", similarityScore: 1 },
// { embedding: [0.05, 0.1, 0.15], label: "sports", similarityScore: 1 } ]
// Find top 3 neighbors with Euclidean distance β€ 1.1
const resultsEuclidean = findNearestNeighbors(query, samples, {
topK: 3,
threshold: 1.1,
method: 'euclidean',
});
console.log(resultsEuclidean.length);
// 2
// only 2 results that pass threshold conditionsUMD (Browser)
<script src="https://unpkg.com/@allemandi/embed-utils"></script>
<script>
const vectorsToNormalize = [3, 4];
const result = window.allemandi.embedUtils.normalizeVector(vectorsToNormalize);
console.log(result);
</script>Calculates cosine similarity between two vectors. Measures how similar their directions are, ignoring magnitude. Use for comparing semantic or normalized vectors (e.g., text embeddings).
Parameters:
vecA(number[]): First vector.vecB(number[]): Second vector.
Returns: number β Cosine similarity score between vecA and vecB.
Examples:
computeCosineSimilarity([1, 2, 3], [1, 2, 3]);
// => 1 (identical vectors)
computeCosineSimilarity([1, 0], [0, 1]);
// => 0 (orthogonal vectors)
computeCosineSimilarity([1, 2], [2, 3]);
// => 0.992...
computeCosineSimilarity([1, 0], [-1, 0]);
// => -1 (vectors diametrically opposed)
computeCosineSimilarity([0, 0], [1, 2]);
// => 0 (one vector has zero magnitude)Calculates Euclidean distance between two vectors. Measures straight-line distance considering both magnitude and direction. Use for raw numeric data or spatial coordinates.
Parameters:
vecA(number[]): First vector.vecB(number[]): Second vector.
Returns: number β Euclidean distance between vecA and vecB.
Examples:
computeEuclideanDistance([1, 2], [4, 6]);
// => 5 (distance between (1,2) and (4,6))
computeEuclideanDistance([0, 0], [0, 0]);
// => 0 (identical vectors)
computeEuclideanDistance([1, 0], [0, 1]);
// => 1.414...
computeEuclideanDistance([1, 2, 3], [4, 5, 6]);
// => 5.196...Calculates Manhattan distance between two vectors. Measures sum of absolute differences. Use for grid-like data or when less sensitive to large differences.
Parameters:
vecA(number[]): First vector.vecB(number[]): Second vector.
Returns: number β Manhattan distance between vecA and vecB.
Examples:
computeManhattanDistance([1, 2, 3], [4, 5, 6]);
// => 9
computeManhattanDistance([1, 0], [0, 1]);
// => 2
computeManhattanDistance([1, 2], [1, 2]);
// => 0 (identical vectors)
computeManhattanDistance([1, -1], [-1, 1]);
// => 4Normalizes a vector to unit length. If the vector has zero magnitude, returns the original vector.
Parameters:
vec(number[]): Input vector.
Returns: number[] β A new vector scaled to unit length.
Examples:
normalizeVector([3, 4]);
// => [0.6, 0.8] (vector normalized to length 1)
normalizeVector([0, 0]);
// => [0, 0] (zero vector remains unchanged)
normalizeVector([1, 1, 1]);
// => [0.5773502691896258, 0.5773502691896258, 0.5773502691896258]Efficiently checks if a vector is L2-normalized (unit length).
Parameters:
vec(number[]): Input vector.epsilon(number, optional, default:1e-6): Tolerance for floating-point comparison.
Returns: boolean β True if the L2 norm is within epsilon of 1.
Examples:
isNormalized([1, 0]);
// => true (vector length is exactly 1)
isNormalized([0.6, 0.8]);
// => true (approximately unit length)
isNormalized([3, 4]);
// => false (length is 5)
isNormalized([0, 0]);
// => false (length is 0)Computes the mean (centroid) vector from an array of vectors. Assumes all vectors are of equal length.
Parameters:
vectors(number[][]): An array of vectors.
Returns: number[] β The mean vector.
Examples:
meanVector([[1, 2], [3, 4], [5, 6]]);
// => [3, 4]
meanVector([]);
// => []Finds the nearest neighbors to a given query embedding from a list of samples based on the specified distance/similarity method.
'cosine': Cosine similarity (higher = more similar, range: [-1, 1]).'euclidean': Euclidean distance (lower = closer, β₯ 0).'manhattan': Manhattan distance (lower = closer, β₯ 0).
Parameters:
queryEmbedding(number[]): The embedding vector to compare against.samples(Array<{ embedding: number[], label: string }>): An array of samples, each with anembeddingand alabel.options(object, optional, default:{}):options.topK(number, optional, default:1): Number of top results to return.options.threshold(number, optional): Minimum similarity score threshold for results (cosine) or maximum distance threshold (euclidean/manhattan).options.method('cosine' | 'euclidean' | 'manhattan', optional, default:'cosine'): The metric to compute.
Examples:
const samples = [
{ embedding: [1, 0], label: 'A' },
{ embedding: [0, 1], label: 'B' },
{ embedding: [1, 1], label: 'C' },
];
// Default cosine similarity
findNearestNeighbors([1, 0], samples);
// => [{ embedding: [1, 0], label: 'A', similarityScore: 1 }]
// Euclidean distance
findNearestNeighbors([1, 0], samples, { method: 'euclidean', topK: 2 });
// => [
// { embedding: [1, 0], label: 'A', distance: 0 },
// { embedding: [1, 1], label: 'C', distance: 1 }
// ]
// Manhattan distance with threshold
findNearestNeighbors([1, 0], samples, { method: 'manhattan', threshold: 1.5 });
// => [{ embedding: [1, 0], label: 'A', distance: 0 }, { embedding: [1, 1], label: 'C', distance: 1 }]
// Cosine with threshold
findNearestNeighbors([1, 0], samples, { threshold: 0.9 });
// => [{ embedding: [1, 0], label: 'A', similarityScore: 1 }]Ranks all samples by similarity/distance to the query embedding. Does NOT apply threshold or topK filtering.
Parameters:
queryEmbedding(number[]): The embedding vector to compare against.samples(Array<{ embedding: number[], label: string }>): Samples with embeddings and labels.options(object, optional, default:{}):options.method('cosine' | 'euclidean' | 'manhattan', optional, default:'cosine'): Distance/similarity method to use.
Examples:
const samples = [
{ embedding: [1, 0], label: 'A' },
{ embedding: [0, 1], label: 'B' },
{ embedding: [1, 1], label: 'C' },
];
// Default cosine similarity
rankBySimilarity([1, 0], samples);
// => [
// { embedding: [1, 0], label: 'A', similarityScore: 1 },
// { embedding: [1, 1], label: 'C', similarityScore: 0.707... },
// { embedding: [0, 1], label: 'B', similarityScore: 0 }
// ]
// Euclidean distance
rankBySimilarity([1, 0], samples, { method: 'euclidean' });
// => [
// { embedding: [1, 0], label: 'A', distance: 0 },
// { embedding: [1, 1], label: 'C', distance: 1 },
// { embedding: [0, 1], label: 'B', distance: 1.414... }
// ]
// Manhattan distance
rankBySimilarity([0, 1], samples, { method: 'manhattan' });
// => [
// { embedding: [0, 1], label: 'B', distance: 0 },
// { embedding: [1, 1], label: 'C', distance: 1 },
// { embedding: [1, 0], label: 'A', distance: 2 }
// ]Available in the GitHub repo only.
# Run the test suite with Jest
yarn test
# or
npm testCheck out these related projects that might interest you:
- Node.js CLI tool for local text classification using word embeddings.
- A minimalist command-line knowledge system with semantic memory capabilities using vector embeddings for information retrieval.
If you have ideas, improvements, or new features:
- Fork the project
- Create your feature branch (git checkout -b feature/amazing-feature)
- Commit your changes (git commit -m 'Add some amazing feature')
- Push to the branch (git push origin feature/amazing-feature)
- Open a Pull Request