Skip to content

Instantly share code, notes, and snippets.

@SgtPooki
Last active December 11, 2015 11:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SgtPooki/4595870 to your computer and use it in GitHub Desktop.
Save SgtPooki/4595870 to your computer and use it in GitHub Desktop.
Converted https://gist.github.com/3171981 to JavaScript. Used a few functions from http://phpjs.org/ to simplify refactoring.
/*
* Implementation of Vose's Alias Method
* Pass in an array of probabilities such as [.1, .2, .4, .7],
* probabilities do not have to add up to 1.
* Returned will be the selected index based on the probabilities.
*
* show statistics with
* aliasMethod(yourArray, true);
*
* use with
* aliasMethod(yourArray);
* @author Russell Dempsey
* Original code by Tyler Stroud for PHP
* @see https://gist.github.com/3171981
* @param array probabilities An array of probabilities
*
* @return int
*
* @version 1
*/
function aliasMethod(probabilities, test)
{
//we need to ensure the probabilities are scaled properly.
probabilities = scaleForAliasMethod(probabilities);
if (test === true) {
var wins = [];
var maxPicks = 100000;
for (i = 0; i < probabilities.length; i++)
{
wins[i] = 0;
}
for (i = 0; i < maxPicks; i++)
{
wins[aliasMethod(probabilities)]++;
}
console.log("Probabilities: " + arr + "\n Number of picks out of "
+ maxPicks + ": " + wins);
return;
}
var small = [];
var large = [];
var prob = [];
var alias = [];
var n = probabilities.length;
probabilities = array_map(function(p) {
return p * n; // Scale each probability by n
}, probabilities);
for (i = 0; i < n; ++i) {
if (probabilities[i] < 1) {
small.push(i);
} else {
large.push(i);
}
}
while ((small.length !== 0) && (large.length !== 0)) {
var l = small.shift();
var g = large.shift();
prob[l] = probabilities[l];
alias[l] = g;
probabilities[g] = (probabilities[g] + probabilities[l]) - 1;
if (probabilities[g] < 1) {
small.push(g);
} else {
large.push(g);
}
}
while (large.length !== 0) {
prob[large.shift()] = 1;
}
while (small.length !== 0) {
prob[small.shift()] = 1;
}
// Coin Toss and die roll
var i = mt_rand(0, n-1);
coinToss = 1 * mt_rand() / mt_getrandmax() < prob[i];
return coinToss ? i : alias[i];
}
function array_map (callback) {
// http://kevin.vanzonneveld.net
// + original by: Andrea Giammarchi (http://webreflection.blogspot.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Brett Zamir (http://brett-zamir.me)
// % note 1: Takes a function as an argument, not a function's name
// % note 2: If the callback is a string, it can only work if the function name is in the global context
// * example 1: array_map( function (a){return (a * a * a)}, [1, 2, 3, 4, 5] );
// * returns 1: [ 1, 8, 27, 64, 125 ]
var argc = arguments.length,
argv = arguments;
var j = argv[1].length,
i = 0,
k = 1,
m = 0;
var tmp = [],
tmp_ar = [];
while (i < j) {
while (k < argc) {
tmp[m++] = argv[k++][i];
}
m = 0;
k = 1;
if (callback) {
if (typeof callback === 'string') {
callback = this.window[callback];
}
tmp_ar[i++] = callback.apply(null, tmp);
} else {
tmp_ar[i++] = tmp;
}
tmp = [];
}
return tmp_ar;
}
function mt_rand (min, max) {
var argc = arguments.length;
if (argc === 0) { min = 0;
max = mt_getrandmax();
} else if (argc === 1) {
throw new Error('Warning: mt_rand() expects exactly 2 parameters, or none, 1 given');
}
var score = Math.floor(Math.random() * (max - min + 1));
score = parseInt(score) + parseInt(min);
return score;
}
function mt_getrandmax () {
// http://kevin.vanzonneveld.net
// + original by: Onno Marsman
// * example 1: mt_getrandmax();
// * returns 1: 2147483647
return 2147483647;
}
function scaleForAliasMethod (probabilities)
{
var total = 0;
var newProbabilities = probabilities;
for (var i = 0; i < newProbabilities.length; i++)
{
total += newProbabilities[i];
}
if (total > 1 )
{
for (i = 0; i < newProbabilities.length; i++)
{
newProbabilities[i] = newProbabilities[i] / total;
}
}
return newProbabilities;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment