@sroussey/simsimd
Version:
Fastest SIMD-Accelerated Vector Similarity Functions for x86 and Arm
166 lines (165 loc) • 5.57 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.jensenshannon = exports.kullbackleibler = exports.jaccard = exports.hamming = exports.cosine = exports.sqeuclidean = exports.inner = void 0;
/**
* @brief Computes the inner product of two vectors.
* @param {Float32Array} a - The first vector.
* @param {Float32Array} b - The second vector.
* @returns {number} The inner product of vectors a and b.
*/
function inner(a, b) {
if (a.length !== b.length) {
throw new Error("Vectors must have the same length");
}
let result = 0;
for (let i = 0; i < a.length; i++) {
result += a[i] * b[i];
}
return 1 - result;
}
exports.inner = inner;
/**
* @brief Computes the squared Euclidean distance between two vectors.
* @param {Float32Array|Int8Array} a - The first vector.
* @param {Float32Array|Int8Array} b - The second vector.
* @returns {number} The squared Euclidean distance between vectors a and b.
*/
function sqeuclidean(a, b) {
if (a.length !== b.length) {
throw new Error("Vectors must have the same length");
}
let result = 0;
for (let i = 0; i < a.length; i++) {
result += (a[i] - b[i]) * (a[i] - b[i]);
}
return result;
}
exports.sqeuclidean = sqeuclidean;
/**
* @brief Computes the cosine distance between two vectors.
* @param {Float32Array|Int8Array} a - The first vector.
* @param {Float32Array|Int8Array} b - The second vector.
* @returns {number} The cosine distance between vectors a and b.
*/
function cosine(a, b) {
if (a.length !== b.length) {
throw new Error("Vectors must have the same length");
}
let dotProduct = 0;
let magnitudeA = 0;
let magnitudeB = 0;
for (let i = 0; i < a.length; i++) {
dotProduct += a[i] * b[i];
magnitudeA += a[i] * a[i];
magnitudeB += b[i] * b[i];
}
magnitudeA = Math.sqrt(magnitudeA);
magnitudeB = Math.sqrt(magnitudeB);
if (magnitudeA === 0 || magnitudeB === 0) {
console.warn("Warning: One of the magnitudes is zero. Cosine similarity is undefined.");
return 0;
}
return 1 - dotProduct / (magnitudeA * magnitudeB);
}
exports.cosine = cosine;
/**
* @brief Computes the bitwise Hamming distance between two vectors.
* @param {Uint8Array} a - The first vector.
* @param {Uint8Array} b - The second vector.
* @returns {number} The Hamming distance between vectors a and b.
*/
const hamming = (a, b) => {
if (a.length !== b.length) {
throw new Error("Arrays must be of the same length");
}
let distance = 0;
for (let i = 0; i < a.length; i++) {
let xor = a[i] ^ b[i]; // XOR operation to find differing bits
// Count the number of set bits (differing bits)
while (xor > 0) {
distance += xor & 1;
xor >>= 1;
}
}
return distance;
};
exports.hamming = hamming;
/**
* @brief Computes the bitwise Jaccard similarity coefficient between two vectors.
* @param {Uint8Array} a - The first vector.
* @param {Uint8Array} b - The second vector.
* @returns {number} The Jaccard similarity coefficient between vectors a and b.
*/
const jaccard = (a, b) => {
if (a.length !== b.length) {
throw new Error("Arrays must be of the same length");
}
let intersection = 0;
let union = 0;
for (let i = 0; i < a.length; i++) {
let ai = a[i];
let bi = b[i];
// Count the number of set bits in a AND b for intersection
let and = ai & bi;
while (and > 0) {
intersection += and & 1;
and >>= 1;
}
// Count the number of set bits in a OR b for union
let or = ai | bi;
while (or > 0) {
union += or & 1;
or >>= 1;
}
}
if (union === 0)
return 0; // Avoid division by zero
return 1 - intersection / union;
};
exports.jaccard = jaccard;
/**
* @brief Computes the kullbackleibler similarity coefficient between two vectors.
* @param {Float32Array} a - The first vector.
* @param {Float32Array} b - The second vector.
* @returns {number} The Jaccard similarity coefficient between vectors a and b.
*/
const kullbackleibler = (a, b) => {
if (a.length !== b.length) {
throw new Error("Arrays must be of the same length");
}
let divergence = 0.0;
for (let i = 0; i < a.length; i++) {
if (a[i] > 0) {
if (b[i] === 0) {
throw new Error("Division by zero encountered in KL divergence calculation");
}
divergence += a[i] * Math.log(a[i] / b[i]);
}
}
return divergence;
};
exports.kullbackleibler = kullbackleibler;
/**
* @brief Computes the jensenshannon similarity coefficient between two vectors.
* @param {Float32Array} a - The first vector.
* @param {Float32Array} b - The second vector.
* @returns {number} The Jaccard similarity coefficient between vectors a and b.
*/
const jensenshannon = (p, q) => {
if (p.length !== q.length) {
throw new Error("Arrays must be of the same length");
}
const m = p.map((value, index) => (value + q[index]) / 2);
const divergence = 0.5 * (0, exports.kullbackleibler)(p, m) + 0.5 * (0, exports.kullbackleibler)(q, m);
return Math.sqrt(divergence);
};
exports.jensenshannon = jensenshannon;
exports.default = {
sqeuclidean,
cosine,
inner,
hamming: exports.hamming,
jaccard: exports.jaccard,
kullbackleibler: exports.kullbackleibler,
jensenshannon: exports.jensenshannon,
};