UNPKG

pandemonium

Version:

Typical random-related functions for JavaScript.

1,293 lines (1,021 loc) 29.4 kB
/** * Pandemonium Library Unit Tests * =============================== */ var assert = require('assert'); var seedrandom = require('seedrandom'); var lib = require('./'); var utils = require('./utils.js'); var rng = function () { return seedrandom('shawarma'); }; var vec = function (size, fill) { var array = new Array(size); for (var i = 0; i < size; i++) array[i] = fill; return array; }; describe('utils', function () { describe('triu conversions', function () { // n = 5 // Matrix representation // 0. 1. 2. 3. 4. // 0. 0 a0 a1 a2 a3 // 1. 0 0 a4 a5 a6 // 2 0 0 0 a7 a8 // 3. 0 0 0 0 a9 // 4. 0 0 0 0 0 // Linear representation // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] // [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9] // Row representation // [0, 1, 2, 3, 4] var coords = [ [0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4] ]; var linear = utils.indices(10); it('should be possible to assess the linear length of a triu matrix.', function () { var l = utils.triuLinearLength(5); assert.strictEqual(l, linear.length); }); it('should be possible to convert to triu coordinates.', function () { var results = linear.map(function (i) { return utils.linearIndexToTriuCoords(5, i); }); assert.deepStrictEqual(results, coords); }); it('should be possible to convert from triu coordinates.', function () { var results = coords.map(function (pair) { return utils.triuCoordsToLinearIndex(5, pair[0], pair[1]); }); assert.deepStrictEqual(results, linear); }); it('should be possible to convert efficiently to triu coordinates.', function () { var results = linear.map(function (i) { return utils.linearIndexToTriuCoordsFast(i); }); assert.deepStrictEqual(results, [ [1, 0], [2, 0], [2, 1], [3, 0], [3, 1], [3, 2], [4, 0], [4, 1], [4, 2], [4, 3] ]); results = utils.indices(utils.triuLinearLength(6)).map(function (i) { return utils.linearIndexToTriuCoordsFast(i); }); assert.deepStrictEqual(results, [ [1, 0], [2, 0], [2, 1], [3, 0], [3, 1], [3, 2], [4, 0], [4, 1], [4, 2], [4, 3], [5, 0], [5, 1], [5, 2], [5, 3], [5, 4] ]); }); }); describe('pair keys', function () { it('should return correct numerical keys.', function () { var matrix = [ [0, 1, 2], [3, 4, 5], [6, 7, 8] ]; var key = utils.createPairKeyFunction(matrix[0].length); matrix.forEach(function (row, j) { row.forEach(function (linearIndex, i) { assert.strictEqual(key(i, j), linearIndex); }); }); }); it('should fallback to string keys when numerical precision is overflown.', function () { var n = 94906265 * 2; var key = utils.createPairKeyFunction(n); assert.strictEqual(key(4, 7), '4,7'); }); }); }); describe('#.createRandom', function () { var createRandom = lib.createRandom; it('should be possible to create a random function using supplied rng.', function () { var random = createRandom(rng()); var numbers = vec(10, 0).map(function () { return random(1, 3); }); assert.deepStrictEqual(numbers, [2, 1, 1, 2, 2, 1, 2, 3, 2, 3]); }); }); describe('#.createRandomBoolean', function () { var createRandomBoolean = lib.createRandomBoolean; it('should be possible to create a random function using supplied rng.', function () { var randomBoolean = createRandomBoolean(rng()); var bools = vec(10, 0).map(function () { return randomBoolean(); }); assert.deepStrictEqual(bools, [ true, true, true, true, false, true, true, false, true, false ]); }); }); describe('#.createRandomFloat', function () { var createRandomFloat = lib.createRandomFloat; it('should be possible to create a random function using supplied rng.', function () { var randomFloat = createRandomFloat(rng()); var numbers = vec(10, 0).map(function () { return randomFloat(-5, 5); }); assert.deepStrictEqual( numbers, [ -1.3882625149887873, -2.6951281957879387, -2.0503955872813586, -0.4793171781490271, 0.12873486129402423, -2.3493674464758856, -0.17451351278587435, 2.0272152885286534, -1.4110661264160034, 4.861209836885362 ] ); }); }); describe('#.createRandomIndex', function () { var createRandomIndex = lib.createRandomIndex; it('should be possible to create a random index function using the supplied rng.', function () { var randomIndex = createRandomIndex(rng()); var fruits = ['apple', 'pear', 'orange']; var tests = vec(10, 0).map(function () { return randomIndex(fruits); }); assert.deepStrictEqual(tests, [1, 0, 0, 1, 1, 0, 1, 2, 1, 2]); }); it('should be possible to pass the length of the array instead of the array itself.', function () { var randomIndex = createRandomIndex(rng()); var fruits = ['apple', 'pear', 'orange']; var tests = vec(10, 0).map(function () { return randomIndex(fruits.length); }); assert.deepStrictEqual(tests, [1, 0, 0, 1, 1, 0, 1, 2, 1, 2]); }); }); describe('#.createChoice', function () { var createChoice = lib.createChoice; it('should be possible to create a choice function using the supplied rng.', function () { var choice = createChoice(rng()); var fruits = ['apple', 'pear', 'orange']; var tests = vec(10, 0).map(function () { return choice(fruits); }); assert.deepStrictEqual( tests, [1, 0, 0, 1, 1, 0, 1, 2, 1, 2].map(function (index) { return fruits[index]; }) ); }); }); describe('#.createFisherYatesSample', function () { var createFisherYatesSample = lib.createFisherYatesSample; var data = [13, 14, 15, 8, 20]; it('should be possible to create a sample function using the supplied rng.', function () { var fisherYatesSample = createFisherYatesSample(rng()); var tests = vec(5, 0).map(function () { return fisherYatesSample(2, data); }); assert.deepStrictEqual(tests, [ [14, 13], [14, 15], [15, 13], [15, 8], [14, 20] ]); }); it('should work when k >= n.', function () { var numbers = [1, 2, 3]; assert.deepStrictEqual( new Set(numbers), new Set(lib.fisherYatesSample(3, numbers)) ); assert.deepStrictEqual( new Set(numbers), new Set(lib.fisherYatesSample(14, numbers)) ); }); }); describe('#.createGeometricReservoirSample', function () { var createGeometricReservoirSample = lib.createGeometricReservoirSample; var data = [13, 14, 15, 8, 20]; it('should be possible to create a sample function using the supplied rng.', function () { var geometricReservoirSample = createGeometricReservoirSample(rng()); var tests = vec(10, 0).map(function () { return geometricReservoirSample(2, data); }); assert.deepStrictEqual(tests, [ [8, 14], [13, 20], [8, 20], [13, 14], [13, 20], [15, 8], [13, 20], [13, 20], [20, 8], [15, 14] ]); }); it('should always return coherent results.', function () { vec(50, 0).forEach(function () { var sample = lib.geometricReservoirSample(500, utils.indices(5000)); assert.strictEqual(sample.length, 500); assert.strictEqual(new Set(sample).size, 500); }); }); it("should be possible to give the sequence's length and get indices back.", function () { var sample = createGeometricReservoirSample(rng()); var numbers = [13, 14, 15, 8, 20, 20]; var tests = vec(7, 0).map(function () { return sample(2, numbers.length); }); assert.deepStrictEqual(tests, [ [5, 1], [0, 5], [5, 2], [3, 5], [2, 3], [5, 4], [0, 3] ]); }); it('should work when k >= n.', function () { var numbers = [1, 2, 3]; assert.deepStrictEqual( new Set(numbers), new Set(lib.geometricReservoirSample(3, numbers)) ); assert.deepStrictEqual( new Set(numbers), new Set(lib.geometricReservoirSample(14, numbers)) ); }); it('should work when k >= n with indices.', function () { var sample = createGeometricReservoirSample(rng()); var indices = sample(5, 3); assert.deepStrictEqual(indices, [0, 1, 2]); }); }); describe('#.createReservoirSample', function () { var createReservoirSample = lib.createReservoirSample; var data = [13, 14, 15, 8, 20]; it('should be possible to create a sample function using the supplied rng.', function () { var reservoirSample = createReservoirSample(rng()); var tests = vec(10, 0).map(function () { return reservoirSample(2, data); }); assert.deepStrictEqual(tests, [ [8, 20], [15, 20], [15, 20], [13, 15], [13, 15], [15, 14], [15, 14], [13, 8], [8, 14], [15, 14] ]); }); it('should always return coherent results.', function () { vec(50, 0).forEach(function () { var sample = lib.reservoirSample(500, utils.indices(5000)); assert.strictEqual(sample.length, 500); assert.strictEqual(new Set(sample).size, 500); }); }); it('should work when k >= n.', function () { var numbers = [1, 2, 3]; assert.deepStrictEqual( new Set(numbers), new Set(lib.reservoirSample(3, numbers)) ); assert.deepStrictEqual( new Set(numbers), new Set(lib.reservoirSample(14, numbers)) ); }); }); describe('ReservoirSampler', function () { it('should work as expected.', function () { var sampler = new lib.ReservoirSampler(10, rng()); utils.indices(100).forEach(function (i) { sampler.process(i); }); assert.deepStrictEqual( sampler.end(), [34, 70, 82, 15, 80, 79, 56, 16, 63, 91] ); // Cannot use after end assert.throws(function () { sampler.process(45); }); sampler = new lib.ReservoirSampler(15, rng()); utils.indices(15).forEach(function (i) { sampler.process(i); }); assert.deepStrictEqual(sampler.end(), utils.indices(15)); sampler = new lib.ReservoirSampler(15, rng()); utils.indices(5).forEach(function (i) { sampler.process(i); }); assert.deepStrictEqual(sampler.end(), utils.indices(5)); sampler = new lib.ReservoirSampler(15, rng()); assert.deepStrictEqual(sampler.end(), []); }); }); describe('#.createSampleWithReplacements', function () { var createSampleWithReplacements = lib.createSampleWithReplacements; var data = [13, 14, 15, 8, 20]; it('should be possible to create a sample function using the supplied rng.', function () { var sample = createSampleWithReplacements(rng()); var tests = vec(3, 0).map(function () { return sample(4, data); }); assert.deepStrictEqual(tests, [ [14, 14, 14, 15], [15, 14, 15, 8], [14, 20, 8, 8] ]); }); }); describe('#.createShuffle', function () { var createShuffle = lib.createShuffle; it('should be possible to create a shuffle function using the supplied rng.', function () { var shuffle = createShuffle(rng()); var shuffled = shuffle([1, 2, 3, 4, 5]); assert.deepStrictEqual(shuffled, [2, 1, 3, 4, 5]); }); }); describe('#.createDangerouslyMutatingSample', function () { var createDangerouslyMutatingSample = lib.createDangerouslyMutatingSample; var data = [13, 14, 15, 8, 20], copy = data.slice(); it('should be possible to create a sample function using the supplied rng.', function () { var sample = createDangerouslyMutatingSample(rng()); var tests = vec(7, 0).map(function () { return sample(2, data); }); assert.deepStrictEqual(tests, [ [14, 13], [14, 15], [15, 13], [15, 8], [14, 20], [8, 13], [20, 13] ]); // Ensuring the state of the array did not change assert.deepStrictEqual(copy, data); }); it('should work when k >= n.', function () { var numbers = [1, 2, 3]; assert.deepStrictEqual( new Set(numbers), new Set(lib.dangerouslyMutatingSample(3, numbers)) ); assert.deepStrictEqual( new Set(numbers), new Set(lib.dangerouslyMutatingSample(14, numbers)) ); }); }); describe('#.naiveSample', function () { var createNaiveSample = lib.createNaiveSample; it('should be possible to create a sample function using the supplied rng.', function () { var sample = createNaiveSample(rng()); var data = [13, 14, 15, 8, 20, 20]; var tests = vec(7, 0).map(function () { return sample(2, data); }); assert.deepStrictEqual(tests, [ [15, 14], [14, 15], [8, 14], [15, 20], [15, 20], [20, 8], [20, 15] ]); }); it("should be possible to give the sequence's length and get indices back.", function () { var sample = createNaiveSample(rng()); var data = [13, 14, 15, 8, 20, 20]; var tests = vec(7, 0).map(function () { return sample(2, data.length); }); assert.deepStrictEqual(tests, [ [2, 1], [1, 2], [3, 1], [2, 4], [2, 5], [4, 3], [4, 2] ]); }); it('should work when k >= n.', function () { var numbers = [1, 2, 3]; assert.deepStrictEqual( new Set(numbers), new Set(lib.naiveSample(3, numbers)) ); assert.deepStrictEqual( new Set(numbers), new Set(lib.naiveSample(14, numbers)) ); }); it('should work when k >= n with indices.', function () { var sample = createNaiveSample(rng()); var indices = sample(5, 3); assert.deepStrictEqual(indices, [0, 1, 2]); }); }); describe('#.createShuffleInPlace', function () { var createShuffleInPlace = lib.createShuffleInPlace; it('should be possible to create a shuffle in place function using the supplied rng.', function () { var shuffle = createShuffleInPlace(rng()), array = [1, 2, 3, 4, 5]; shuffle(array); assert.deepStrictEqual(array, [2, 1, 3, 4, 5]); }); }); describe('#.createWeightedRandomIndex', function () { var createWeightedRandomIndex = lib.createWeightedRandomIndex; function freq(fn, target) { var sample = 10 * 1000, af = {}, rf = {}, r; for (var i = 0; i < sample; i++) { r = fn(target); af[r] = af[r] || 0; af[r]++; } for (var k in af) { rf[k] = af[k] / sample; } return {absolute: af, relative: rf}; } it('should correctly return a random index from weighted list.', function () { var weightedRandomIndex = createWeightedRandomIndex(rng()), weights = [0.1, 0.1, 0.8]; var f = freq(weightedRandomIndex, weights); assert.deepStrictEqual(f.relative, { 0: 0.0977, 1: 0.0947, 2: 0.8076 }); }); it('should also work with absolute weights.', function () { var weightedRandomIndex = createWeightedRandomIndex(rng()), weights = [4, 4, 32]; var f = freq(weightedRandomIndex, weights); assert.deepStrictEqual(f.relative, { 0: 0.0977, 1: 0.0947, 2: 0.8076 }); }); it('should also work with a weight getter.', function () { var getter = function (item) { return item.weight; }; var mapper = function (value, index) { return { weight: value, index: index }; }; var relativeWeightedRandomIndex = createWeightedRandomIndex({ rng: rng(), getWeight: getter }), absoluteWeightedRandomIndex = createWeightedRandomIndex({ rng: rng(), getWeight: getter }); var relativeWeights = [0.1, 0.1, 0.8].map(mapper), absoluteWeights = [4, 4, 32].map(mapper); var relativeF = freq(relativeWeightedRandomIndex, relativeWeights), absoluteF = freq(absoluteWeightedRandomIndex, absoluteWeights); assert.deepStrictEqual(relativeF.relative, { 0: 0.0977, 1: 0.0947, 2: 0.8076 }); assert.deepStrictEqual(absoluteF.relative, { 0: 0.0977, 1: 0.0947, 2: 0.8076 }); }); }); describe('#.createCachedWeightedRandomIndex', function () { var createCachedWeightedRandomIndex = lib.createCachedWeightedRandomIndex; var RELATIVE_WEIGHTS = [0.1, 0.1, 0.8], ABSOLUTE_WEIGHTS = [4, 4, 32]; function freq(fn) { var sample = 10 * 1000, af = {}, rf = {}, r; for (var i = 0; i < sample; i++) { r = fn(); af[r] = af[r] || 0; af[r]++; } for (var k in af) { rf[k] = af[k] / sample; } return {absolute: af, relative: rf}; } it('should correctly return a random index from weighted list.', function () { var weightedRandomIndex = createCachedWeightedRandomIndex( rng(), RELATIVE_WEIGHTS ); var f = freq(weightedRandomIndex); assert.deepStrictEqual(f.relative, { 0: 0.1012, 1: 0.0999, 2: 0.7989 }); }); it('should also work with absolute weights.', function () { var weightedRandomIndex = createCachedWeightedRandomIndex( rng(), ABSOLUTE_WEIGHTS ); var f = freq(weightedRandomIndex); assert.deepStrictEqual(f.relative, { 0: 0.1012, 1: 0.0999, 2: 0.7989 }); }); it('should also work with a weight getter.', function () { var getter = function (item) { return item.weight; }; var mapper = function (value, index) { return { weight: value, index: index }; }; var relativeWeights = RELATIVE_WEIGHTS.map(mapper), absoluteWeights = ABSOLUTE_WEIGHTS.map(mapper); var relativeWeightedRandomIndex = createCachedWeightedRandomIndex( {rng: rng(), getWeight: getter}, relativeWeights ), absoluteWeightedRandomIndex = createCachedWeightedRandomIndex( {rng: rng(), getWeight: getter}, absoluteWeights ); var relativeF = freq(relativeWeightedRandomIndex), absoluteF = freq(absoluteWeightedRandomIndex); assert.deepStrictEqual(relativeF.relative, { 0: 0.1012, 1: 0.0999, 2: 0.7989 }); assert.deepStrictEqual(absoluteF.relative, { 0: 0.1012, 1: 0.0999, 2: 0.7989 }); }); }); describe('#.createWeightedChoice', function () { var createWeightedChoice = lib.createWeightedChoice; function freq(fn, target) { var sample = 10 * 1000, af = {}, rf = {}, r; for (var i = 0; i < sample; i++) { r = fn(target)[0]; af[r] = af[r] || 0; af[r]++; } for (var k in af) { rf[k] = af[k] / sample; } return {absolute: af, relative: rf}; } it('should correctly return a random item from weighted list.', function () { var weightedChoice = createWeightedChoice({ rng: rng(), getWeight: function (item) { return item[1]; } }); var weights = [ ['pear', 0.1], ['apple', 0.1], ['cherry', 0.8] ]; var f = freq(weightedChoice, weights); assert.deepStrictEqual(f.relative, { pear: 0.0977, apple: 0.0947, cherry: 0.8076 }); }); }); describe('#.createCachedWeightedChoice', function () { var createCachedWeightedChoice = lib.createCachedWeightedChoice; function freq(fn) { var sample = 10 * 1000, af = {}, rf = {}, r; for (var i = 0; i < sample; i++) { r = fn()[0]; af[r] = af[r] || 0; af[r]++; } for (var k in af) { rf[k] = af[k] / sample; } return {absolute: af, relative: rf}; } it('should correctly return a random item from weighted list.', function () { var weights = [ ['pear', 0.1], ['apple', 0.1], ['cherry', 0.8] ]; var weightedChoice = createCachedWeightedChoice( { rng: rng(), getWeight: function (item) { return item[1]; } }, weights ); var f = freq(weightedChoice); assert.deepStrictEqual(f.relative, { pear: 0.1012, apple: 0.0999, cherry: 0.7989 }); }); }); describe('#.createRandomString', function () { var createRandomString = lib.createRandomString; it('should be able to produce random string of fixed length.', function () { var randomString = createRandomString(rng()); var tests = [ '', 'w', 'os', 'CFq', 'DRw', '9TLYZ', 'QD02aP', 'VXNLajS', 'l07VLFXK' ]; var results = tests.map(function (s) { return randomString(s.length); }); assert.deepStrictEqual(results, tests); }); it('should be able to produce random string of variable length.', function () { var randomString = createRandomString(rng()); var tests = [ [0, 0, ''], [0, 2, ''], [0, 3, 'C'], [0, 3, 'qD'], [0, 3, 'w9'], [0, 10, 'LYZQD02a'], [4, 7, 'VXNLaj'], [5, 5, 'l07VL'], [3, 14, 'XKuVG2i18'] ]; var results = tests.map(function (s) { return randomString(s[0], s[1]); }); assert.deepStrictEqual( results, tests.map(function (s) { return s[2]; }) ); var batch = new Array(1000); for (var i = 0; i < 1000; i++) batch[i] = randomString(3, 14); assert( batch.every(function (s) { return s.length >= 3 && s.length <= 14; }) ); }); it('should produce random strings based on a custom alphabet.', function () { var randomString = createRandomString(rng(), 'ATGC'); var tests = [ '', 'T', 'AT', 'TGT', 'TGT', 'CGGCC', 'GTCCAG', 'CCGGAAG', 'ACCCGGCG' ]; var results = tests.map(function (s) { return randomString(s.length); }); assert.deepStrictEqual(results, tests); }); }); describe('#.createRandomPair', function () { it('should throw when working on length < 2.', function () { var randomPair = lib.createRandomPair(rng()); assert.throws(function () { randomPair([0]); }); assert.throws(function () { randomPair(0); }); }); it('should properly return valid pairs.', function () { var randomPair = lib.createRandomPair(rng()); var target = ['apple', 'pear', 'tomato', 'olive']; var test = [ ['pear', 'tomato'], ['pear', 'olive'], ['tomato', 'olive'], ['apple', 'pear'], ['apple', 'pear'], ['apple', 'tomato'], ['tomato', 'olive'], ['apple', 'tomato'], ['tomato', 'olive'], ['apple', 'olive'] ]; var pairs = vec(10).map(function () { return randomPair(target); }); assert.deepStrictEqual(pairs, test); randomPair = lib.createRandomPair(rng()); pairs = vec(10).map(function () { return randomPair(4); }); assert.deepStrictEqual(pairs, [ [1, 2], [1, 3], [2, 3], [0, 1], [0, 1], [0, 2], [2, 3], [0, 2], [2, 3], [0, 3] ]); assert.deepStrictEqual( pairs.map(function (pair) { return [target[pair[0]], target[pair[1]]]; }), test ); }); }); describe('#.createOrderedRandomPair', function () { it('should throw when working on length < 2.', function () { var randomOrderedPair = lib.createRandomOrderedPair(rng()); assert.throws(function () { randomOrderedPair([0]); }); assert.throws(function () { randomOrderedPair(0); }); }); it('should properly return valid ordered pairs.', function () { var randomOrderedPair = lib.createRandomOrderedPair(rng()); var target = ['apple', 'pear', 'tomato', 'olive']; var test = [ ['pear', 'tomato'], ['pear', 'olive'], ['tomato', 'olive'], ['pear', 'apple'], ['pear', 'apple'], ['tomato', 'apple'], ['olive', 'tomato'], ['tomato', 'apple'], ['olive', 'tomato'], ['apple', 'olive'] ]; var pairs = vec(10).map(function () { return randomOrderedPair(target); }); assert.deepStrictEqual(pairs, test); randomOrderedPair = lib.createRandomOrderedPair(rng()); pairs = vec(10).map(function () { return randomOrderedPair(4); }); assert.deepStrictEqual(pairs, [ [1, 2], [1, 3], [2, 3], [1, 0], [1, 0], [2, 0], [3, 2], [2, 0], [3, 2], [0, 3] ]); assert.deepStrictEqual( pairs.map(function (pair) { return [target[pair[0]], target[pair[1]]]; }), test ); }); }); describe('#.createSamplePairs', function () { it('should return a correct sample.', function () { var samplePairs = lib.createSamplePairs(rng()); var target = [ 'apple', 'pear', 'tomato', 'olive', 'watermelon', 'orange', 'strawberry' ]; var expected = [ ['tomato', 'watermelon'], ['tomato', 'orange'], ['olive', 'orange'], ['pear', 'olive'], ['pear', 'tomato'] ]; var sample = samplePairs(5, target); assert.deepStrictEqual(sample, expected); samplePairs = lib.createSamplePairs(rng()); sample = samplePairs(5, target.length); assert.deepStrictEqual( sample.map(function (pair) { return [target[pair[0]], target[pair[1]]]; }), expected ); }); it('should return unordered pairs.', function () { var pairs = lib.samplePairs(25, 1000); pairs.forEach(function (pair) { assert(pair[0] < pair[1]); }); }); }); describe('#.createSampleOrderedPairs', function () { it('should return a correct sample.', function () { var samplePairs = lib.createSampleOrderedPairs(rng()); var target = [ 'apple', 'pear', 'tomato', 'olive', 'watermelon', 'orange', 'strawberry' ]; var expected = [ ['tomato', 'watermelon'], ['tomato', 'orange'], ['olive', 'orange'], ['olive', 'pear'], ['tomato', 'pear'] ]; var sample = samplePairs(5, target); assert.deepStrictEqual(sample, expected); samplePairs = lib.createSampleOrderedPairs(rng()); sample = samplePairs(5, target.length); assert.deepStrictEqual( sample.map(function (pair) { return [target[pair[0]], target[pair[1]]]; }), expected ); }); }); describe('#.createWeightedReservoirSample', function () { var items = [0.4, 0.4, 0.1, 0.001, 0.187, 0.3, 0.25, 0.5, 92]; it('should work properly.', function () { var weightedReservoirSample = lib.createWeightedReservoirSample(rng()); var sample = weightedReservoirSample(3, items); assert.deepStrictEqual(sample, [92, 0.5, 0.4]); assert.deepStrictEqual( new Set(weightedReservoirSample(100, items)), new Set(items) ); }); it('should be possible to sample arbitrary items.', function () { var weightedReservoirSample = lib.createWeightedReservoirSample({ rng: rng(), getWeight: function (n) { return 1 / n; } }); var sample = weightedReservoirSample(3, items); assert.deepStrictEqual(sample, [0.001, 0.1, 0.187]); }); it('should be possible to use a sampler.', function () { var sampler = new lib.WeightedReservoirSampler(3, rng()); items.forEach(function (n) { sampler.process(n); }); assert.deepStrictEqual(sampler.end(), [92, 0.5, 0.4]); }); }); describe('#.createRandomUint32', function () { it('should return uint32 numbers.', function () { var i; for (i = 0; i < 1000; i++) { assert(lib.randomUint32() < Math.pow(2, 32) - 1); } var randomUint32 = lib.createRandomUint32(rng()); var result = []; for (i = 0; i < 10; i++) { result.push(randomUint32()); } assert.deepStrictEqual( result, [ 1551229437, 989934901, 1266845448, 1941618487, 2202774849, 1138438012, 2072530664, 3018165983, 1541435361, 4235357373 ] ); }); }); describe('FisherYatesPermutation', function () { it('should throw when exhausted.', function () { var p = new lib.FisherYatesPermutation(2, rng()); p.permute(); p.permute(); assert.throws(function () { p.permute(); }, /exhaust/); }); it('should work on a basic case.', function () { var p = new lib.FisherYatesPermutation(5, rng()); var result = []; for (var i = 0; i < 5; i++) { result.push(p.permute()); } assert.deepStrictEqual(result, [1, 0, 3, 2, 4]); }); it('should always give good permutations.', function () { for (var i = 0; i < 100; i++) { var p = new lib.FisherYatesPermutation(10); var result = new Set(); for (var j = 0; j < 10; j++) { result.add(p.permute()); } assert.strictEqual(result.size, 10); } }); });