Last active
December 11, 2015 11:48
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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