UNPKG

simsimd

Version:

Portable mixed-precision BLAS-like vector math library for x86 and ARM

207 lines (206 loc) 7.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.jensenshannon = exports.kullbackleibler = exports.jaccard = exports.hamming = void 0; exports.inner = inner; exports.dot = dot; exports.sqeuclidean = sqeuclidean; exports.euclidean = euclidean; exports.cosine = cosine; /** * @brief Computes the inner product of two vectors (dot product). * @param {Float64Array|Float32Array} a - The first vector. * @param {Float64Array|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 result; } /** * @brief Computes the dot product of two vectors (same as inner product). * @param {Float64Array|Float32Array} a - The first vector. * @param {Float64Array|Float32Array} b - The second vector. * @returns {number} The dot product of vectors a and b. */ function dot(a, b) { return inner(a, b); } /** * @brief Computes the squared Euclidean distance between two vectors. * @param {Float64Array|Float32Array|Int8Array|Uint8Array} a - The first vector. * @param {Float64Array|Float32Array|Int8Array|Uint8Array} 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; } /** * @brief Computes the L2 Euclidean distance between two vectors. * @param {Float64Array|Float32Array|Int8Array | Uint8Array} a - The first vector. * @param {Float64Array|Float32Array|Int8Array | Uint8Array} b - The second vector. * @returns {number} The L2 Euclidean distance between vectors a and b. */ function euclidean(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 Math.sqrt(result); } /** * @brief Computes the cosine distance between two vectors. * @param {Float64Array|Float32Array|Int8Array} a - The first vector. * @param {Float64Array|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) return 0; // distance when both zero if (magnitudeA === 0 || magnitudeB === 0) return 1; // distance when one is zero return 1 - dotProduct / (magnitudeA * magnitudeB); } /** * @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 distance between two vectors. * @param {Uint8Array} a - The first vector. * @param {Uint8Array} b - The second vector. * @returns {number} The Jaccard distance 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 Kullback-Leibler divergence between two probability distributions. * @param {Float64Array|Float32Array} a - The first vector. * @param {Float64Array|Float32Array} b - The second vector. * @returns {number} The Kullback-Leibler divergence 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 || b[i] < 0) { throw new Error("Negative values are not allowed in probability distributions"); } 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 Jensen-Shannon distance between two probability distributions. * @param {Float64Array|Float32Array} a - The first probability distribution. * @param {Float64Array|Float32Array} b - The second probability distribution. * @returns {number} The Jensen-Shannon distance between distributions a and b. */ const jensenshannon = (a, b) => { if (a.length !== b.length) { throw new Error("Arrays must be of the same length"); } let divergence = 0; for (let i = 0; i < a.length; i++) { if (a[i] < 0 || b[i] < 0) { throw new Error("Negative values are not allowed in probability distributions"); } const m = (a[i] + b[i]) / 2; if (m > 0) { if (a[i] > 0) divergence += a[i] * Math.log(a[i] / m); if (b[i] > 0) divergence += b[i] * Math.log(b[i] / m); } } divergence /= 2; return Math.sqrt(divergence); }; exports.jensenshannon = jensenshannon; exports.default = { sqeuclidean, euclidean, cosine, inner, hamming: exports.hamming, jaccard: exports.jaccard, kullbackleibler: exports.kullbackleibler, jensenshannon: exports.jensenshannon, };