Skip to content

Instantly share code, notes, and snippets.

@kristopolous
Created November 22, 2016 01:00
Show Gist options
  • Save kristopolous/293c33ddb8ff303e9ae47ff1e103387d to your computer and use it in GitHub Desktop.
Save kristopolous/293c33ddb8ff303e9ae47ff1e103387d to your computer and use it in GitHub Desktop.
An effecient random selector observing weighted sets
(function(){
function verify(weights, chosen, trialCount) {
var variance = 0, ttl = chosen.length;
for(var ix = 0; ix < ttl; ix++) {
console.log(weights[ix], chosen[ix] / trialCount);
variance += Math.sqrt(Math.abs(Math.pow(weights[ix], 2) - Math.pow(chosen[ix] / trialCount, 2)));
}
console.log(variance / ttl);
}
function array(count, fn) {
return Array.apply(0, Array(count)).map(fn);
}
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
function Sequence(max) {
var
ix = 0,
current = max - 1,
slosh,
list = array(max, function(){ return ix++ });
return function() {
var index = (current === 0) ? 0 : getRandomInt(0, current);
res = list[index];
slosh = list[index];
list[index] = list[current];
list[current] = slosh;
if(current == 0) {
current = max;
}
current --;
return res;
}
}
var number_of_weights = 0,
number_of_trials = 1000,//0000,
scaling_factor = 1/30,
weights = [],
ttl = 0,
index = 0,
max_weight;
while(true) {
index = scaling_factor * Math.random();
if(ttl + index > 1.0) {
index = 1.0 - ttl;
weights.push(index);
break;
}
weights.push(index);
ttl += index;
}
number_of_weights = weights.length;
max_weight = 0.99 * weights.reduce(function(a, b) { return a > b ? a : b });
/*
var buckets = new Array(10).map(function() { return [] });
weights.forEach(function(sample) {
buckets[sample.toString()[2]].push( sample );
});
*/
var attempt_machine = Sequence(number_of_weights);
// For the bucket we need to make sure that the things in the '9' bucket
// get chosen more than the '8' and so on.
//
// so first we have a sample, this will be our sample for the duration
// of our choice.
var sample, attempt, trials = 0, ix, chosen = array(number_of_weights, function() { return 0 });
for(ix = 0; ix < number_of_trials; ix ++) {
sample = Math.random() * max_weight;
while(true){
attempt = attempt_machine();
if(weights[attempt] > sample) {
break;
}
trials++;
};
chosen[attempt] ++;
}
verify(weights, chosen, number_of_trials);
console.log(trials / number_of_trials);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment