@graphty/algorithms
Version:
Graph algorithms library for browser environments implemented in TypeScript
123 lines • 3.4 kB
JavaScript
/**
* Seeded random number generator for reproducible results
*/
export class SeededRandom {
constructor(seed) {
this.m = 0x80000000; // 2**31
this.a = 1103515245;
this.c = 12345;
// Handle negative seeds correctly
this.seed = ((seed % this.m) + this.m) % this.m;
}
/**
* Generate next random number between 0 and 1
*/
next() {
this.seed = ((this.a * this.seed) + this.c) % this.m;
return this.seed / (this.m - 1);
}
/**
* Create a generator function for backward compatibility
*/
static createGenerator(seed) {
const rng = new SeededRandom(seed);
return () => rng.next();
}
}
/**
* Fisher-Yates shuffle algorithm
* @param array - Array to shuffle (will be modified in place)
* @param rng - Optional random number generator (defaults to Math.random)
* @returns The shuffled array (same reference as input)
*/
export function shuffle(array, rng = Math.random) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(rng() * (i + 1));
const temp = array[i];
const tempJ = array[j];
if (temp !== undefined && tempJ !== undefined) {
array[i] = tempJ;
array[j] = temp;
}
}
return array;
}
/**
* Calculate Euclidean distance between two vectors
* @param a - First vector
* @param b - Second vector
* @returns Euclidean distance
* @throws Error if vectors have different lengths
*/
export function euclideanDistance(a, b) {
if (a.length !== b.length) {
throw new Error("Vectors must have same length");
}
let sum = 0;
for (let i = 0; i < a.length; i++) {
const aVal = a[i];
const bVal = b[i];
if (aVal !== undefined && bVal !== undefined) {
const diff = aVal - bVal;
sum += diff * diff;
}
}
return Math.sqrt(sum);
}
export const normalize = {
/**
* Min-max normalization to [0, 1] range
*/
minMax(values) {
const vals = Array.from(values.values());
const min = Math.min(...vals);
const max = Math.max(...vals);
const range = max - min;
if (range === 0) {
return;
}
for (const [key, value] of values) {
values.set(key, (value - min) / range);
}
},
/**
* Normalize by maximum value
*/
byMax(values) {
const max = Math.max(...values.values());
if (max === 0) {
return;
}
for (const [key, value] of values) {
values.set(key, value / max);
}
},
/**
* L2 (Euclidean) normalization
*/
l2Norm(values) {
const sumSquares = Array.from(values.values())
.reduce((sum, val) => sum + (val * val), 0);
const norm = Math.sqrt(sumSquares);
if (norm === 0) {
return;
}
for (const [key, value] of values) {
values.set(key, value / norm);
}
},
/**
* Normalize to sum to 1
*/
sumToOne(values) {
const sum = Array.from(values.values())
.reduce((acc, val) => acc + val, 0);
if (sum === 0) {
return;
}
for (const [key, value] of values) {
values.set(key, value / sum);
}
},
};
//# sourceMappingURL=math-utilities.js.map