@keystonehq/alias-sampling
Advanced tools
Comparing version 0.0.5 to 0.0.6
type RNGFunction = () => number; | ||
declare class Sample { | ||
private alias; | ||
private prob; | ||
private outcomes; | ||
private rng; | ||
constructor(probabilities: number[], outcomes?: any[], rng?: RNGFunction); | ||
next(numOfSamples?: number): any | any[]; | ||
private precomputeAlias; | ||
private indexedOutcomes; | ||
randomInt(min: number, max: number): number; | ||
} | ||
export default function createSample(probabilities: number[], outcomes?: any[] | null, rng?: RNGFunction | null): Sample; | ||
export default function sample(probabilities: number[], outcomes?: any[], rng?: RNGFunction): { | ||
next: (numOfSamples?: number) => any | any[]; | ||
}; | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Sample = /** @class */ (function () { | ||
function Sample(probabilities, outcomes, rng) { | ||
this.alias = []; | ||
this.prob = []; | ||
this.outcomes = outcomes !== null && outcomes !== void 0 ? outcomes : this.indexedOutcomes(probabilities.length); | ||
this.rng = rng !== null && rng !== void 0 ? rng : Math.random; | ||
this.precomputeAlias(probabilities); | ||
var precomputeAlias = function (p, n) { | ||
var sum = p.reduce(function (acc, val) { | ||
if (val < 0) { | ||
throw new Error('Probabilities must be positive.'); | ||
} | ||
return acc + val; | ||
}, 0); | ||
if (sum <= 0) { | ||
throw new Error('Probability sum must be greater than zero.'); | ||
} | ||
Sample.prototype.next = function (numOfSamples) { | ||
if (numOfSamples === void 0) { numOfSamples = 1; } | ||
var out = []; | ||
for (var i = 0; i < numOfSamples; i++) { | ||
var c = Math.floor(this.rng() * this.prob.length); | ||
out[i] = this.outcomes[(this.rng() < this.prob[c]) ? c : this.alias[c]]; | ||
} | ||
return (numOfSamples > 1) ? out : out[0]; | ||
var scaledProbabilities = p.map(function (prob) { return (prob * n) / sum; }); | ||
var aliasData = { | ||
prob: new Array(n), | ||
alias: new Array(n), | ||
}; | ||
Sample.prototype.precomputeAlias = function (p) { | ||
var n = p.length; | ||
var sum = 0; | ||
var nS = 0; | ||
var nL = 0; | ||
var P = []; | ||
var S = []; | ||
var L = []; | ||
for (var i = 0; i < n; ++i) { | ||
if (p[i] < 0) { | ||
throw new Error("Probability must be a positive: p[".concat(i, "]=").concat(p[i])); | ||
} | ||
sum += p[i]; | ||
var small = []; | ||
var large = []; | ||
for (var i = 0; i < n; i++) { | ||
if (scaledProbabilities[i] < 1) { | ||
small.push(i); | ||
} | ||
if (sum === 0) { | ||
throw new Error('Probability cannot be zero.'); | ||
else { | ||
large.push(i); | ||
} | ||
for (var i = 0; i < n; ++i) { | ||
P[i] = p[i] * n / sum; | ||
} | ||
while (small.length > 0 && large.length > 0) { | ||
var less = small.pop(); | ||
var more = large.pop(); | ||
aliasData.prob[less] = scaledProbabilities[less]; | ||
aliasData.alias[less] = more; | ||
scaledProbabilities[more] -= 1 - scaledProbabilities[less]; | ||
if (scaledProbabilities[more] < 1) { | ||
small.push(more); | ||
} | ||
for (var i = n - 1; i >= 0; --i) { | ||
if (P[i] < 1) | ||
S[nS++] = i; | ||
else | ||
L[nL++] = i; | ||
else { | ||
large.push(more); | ||
} | ||
while (nS && nL) { | ||
var a = S[--nS]; | ||
var g = L[--nL]; | ||
this.prob[a] = P[a]; | ||
this.alias[a] = g; | ||
P[g] = P[g] + P[a] - 1; | ||
if (P[g] < 1) | ||
S[nS++] = g; | ||
else | ||
L[nL++] = g; | ||
} | ||
large.concat(small).forEach(function (g) { | ||
aliasData.prob[g] = 1; | ||
}); | ||
return aliasData; | ||
}; | ||
var draw = function (aliasData, outcomes, rng) { | ||
var c = Math.floor(rng() * aliasData.prob.length); | ||
return outcomes[(rng() < aliasData.prob[c]) ? c : aliasData.alias[c]]; | ||
}; | ||
var next = function (aliasData, outcomes, rng, numOfSamples) { | ||
if (numOfSamples === void 0) { numOfSamples = 1; } | ||
if (numOfSamples === 1) { | ||
return draw(aliasData, outcomes, rng); | ||
} | ||
var samples = []; | ||
for (var i = 0; i < numOfSamples; i++) { | ||
samples.push(draw(aliasData, outcomes, rng)); | ||
} | ||
return samples; | ||
}; | ||
function sample(probabilities, outcomes, rng) { | ||
if (rng === void 0) { rng = Math.random; } | ||
if (!Array.isArray(probabilities)) { | ||
throw new Error('Probabilities must be an array.'); | ||
} | ||
var n = probabilities.length; | ||
var indexedOutcomes = outcomes !== null && outcomes !== void 0 ? outcomes : Array.from({ length: n }, function (_, i) { return i; }); | ||
var aliasData = precomputeAlias(probabilities, n); | ||
return { | ||
next: function (numOfSamples) { | ||
if (numOfSamples === void 0) { numOfSamples = 1; } | ||
return next(aliasData, indexedOutcomes, rng, numOfSamples); | ||
} | ||
while (nL) | ||
this.prob[L[--nL]] = 1; | ||
while (nS) | ||
this.prob[S[--nS]] = 1; | ||
}; | ||
Sample.prototype.indexedOutcomes = function (n) { | ||
var o = []; | ||
for (var i = 0; i < n; i++) | ||
o[i] = i; | ||
return o; | ||
}; | ||
Sample.prototype.randomInt = function (min, max) { | ||
return Math.floor(this.rng() * (max - min)) + min; | ||
}; | ||
return Sample; | ||
}()); | ||
function createSample(probabilities, outcomes, rng) { | ||
return new Sample(probabilities, outcomes, rng); | ||
} | ||
exports.default = createSample; | ||
exports.default = sample; |
{ | ||
"name": "@keystonehq/alias-sampling", | ||
"version": "0.0.5", | ||
"version": "0.0.6", | ||
"description": "A Node.js module for efficient sampling from a discrete probability distribution using the alias method.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -26,3 +26,3 @@ # Alias Method for Sampling | ||
```javascript | ||
import { sample } from '@keystonehq/alias-sampling'; | ||
import sample from '@keystonehq/alias-sampling'; | ||
@@ -39,3 +39,3 @@ // Create a sampler with specified probabilities and outcomes | ||
```javascript | ||
import { sample } from '@keystonehq/alias-sampling'; | ||
import sample from '@keystonehq/alias-sampling'; | ||
@@ -52,3 +52,3 @@ // Create a sampler with specified probabilities | ||
```javascript | ||
import { sample } from '@keystonehq/alias-sampling'; | ||
import sample from '@keystonehq/alias-sampling'; | ||
@@ -65,3 +65,3 @@ // Create a sampler without specifying outcomes (defaults to indices) | ||
```javascript | ||
import { sample } from '@keystonehq/alias-sampling'; | ||
import sample from '@keystonehq/alias-sampling'; | ||
@@ -68,0 +68,0 @@ // Custom random generator function |
6733
81