simsimd
Version:
Portable mixed-precision BLAS-like vector math library for x86 and ARM
207 lines (206 loc) • 7.06 kB
JavaScript
;
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,
};