From 4653cec0302542aebe75e41327ef18f84fb03cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 6 Apr 2021 17:44:15 +0200 Subject: [PATCH 1/6] :test_tube: test(sample): Simplify. --- package.json | 1 + test/src/sample.js | 80 ++++++++++++++++++++++------------------------ yarn.lock | 5 +++ 3 files changed, 45 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 12c72af..73e3946 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "dependencies": {}, "devDependencies": { "@aureooms/js-array": "4.0.0", + "@aureooms/js-compare": "^2.0.1", "@aureooms/js-functools": "2.0.3", "@aureooms/js-itertools": "5.0.1", "@aureooms/js-memory": "4.0.0", diff --git a/test/src/sample.js b/test/src/sample.js index c17c37c..c1c05e3 100644 --- a/test/src/sample.js +++ b/test/src/sample.js @@ -1,54 +1,50 @@ import test from 'ava'; -import * as random from '../../src/index.js'; +import {sample, _fisheryates, randint} from '../../src/index.js'; -import * as mem from '@aureooms/js-memory'; -import * as array from '@aureooms/js-array'; -import operator from '@aureooms/js-operator'; +import {_calloc} from '@aureooms/js-memory'; +import {iota, copy} from '@aureooms/js-array'; +import {increasing} from '@aureooms/js-compare'; -function one(type, sample_name, sample) { - const type_name = type.toString().split(' ')[1].slice(0, -2); - - const calloc = mem._calloc(type); - - const n = 100; +const macro = (t, type, _sample_name, sample, n, k, i, j) => { + const calloc = _calloc(type); const a = calloc(n); const b = calloc(n); - array.iota(a, 0, n, 0); - - const range = function (k, i, j) { - const name = `sample ( ${type_name}, ${sample_name}, ${k}, ${i}, ${j} )`; - - test(name, (t) => { - array.copy(a, 0, n, b, 0); - sample(k, b, i, j); + iota(a, 0, n, 0); - for (let it = 0; it < i; ++it) { - const msg = `b[${it}] === a[${it}]`; - t.deepEqual(b[it], a[it], msg); - } + copy(a, 0, n, b, 0); + sample(k, b, i, j); - const _a = Array.prototype.slice.call(a, i, j).sort(operator.sub); - const _b = Array.prototype.slice.call(b, i, j).sort(operator.sub); + for (let it = 0; it < i; ++it) { + const msg = `b[${it}] === a[${it}]`; + t.deepEqual(b[it], a[it], msg); + } - const msg = 'shuffled region contains same elements as original'; + const _a = Array.prototype.slice.call(a, i, j).sort(increasing); + const _b = Array.prototype.slice.call(b, i, j).sort(increasing); - t.deepEqual(_b, _a, msg); + const msg = 'shuffled region contains same elements as original'; - for (let it = j; it < n; ++it) { - const msg = `b[${it}] === a[${it}]`; - t.deepEqual(b[it], a[it], msg); - } - }); - }; + t.deepEqual(_b, _a, msg); - range(n, 0, n); - range(n - 20, 20, n); - range(n - 20, 0, n - 20); - range(n - 20, 10, n - 10); - range(n - 30, 10, n - 10); -} + for (let it = j; it < n; ++it) { + const msg = `b[${it}] === a[${it}]`; + t.deepEqual(b[it], a[it], msg); + } +}; + +macro.title = (title, type, sample_name, _sample, n, k, i, j) => + title || `[${n}] sample ( ${type.name}, ${sample_name}, ${k}, ${i}, ${j} )`; + +const n = 100; +const params = [ + [n, n, 0, n], + [n, n - 20, 20, n], + [n, n - 20, 0, n - 20], + [n, n - 20, 10, n - 10], + [n, n - 30, 10, n - 10], +]; const types = [ Array, @@ -64,12 +60,14 @@ const types = [ ]; const algorithms = [ - ['Fisher-Yates', random._fisheryates(random.randint)], - ['API', random.sample], + ['Fisher-Yates', _fisheryates(randint)], + ['API', sample], ]; for (const type of types) { for (const [name, algorithm] of algorithms) { - one(type, name, algorithm); + for (const [n, k, i, j] of params) { + test(macro, type, name, algorithm, n, k, i, j); + } } } diff --git a/yarn.lock b/yarn.lock index f8ebf2e..037dcad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,6 +14,11 @@ dependencies: "@aureooms/js-error" "^5.0.2" +"@aureooms/js-compare@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@aureooms/js-compare/-/js-compare-2.0.1.tgz#4636ea0736945abbcca38d5bd56a1f405034b2f9" + integrity sha512-J+gG1wlwF401ySv0mOYhIIVUuoukvZaRkIwYNH9xZTLhRyI4VxoaFi3k8GA0ebjHqndLGYJS9uEeG3cuQcg+7w== + "@aureooms/js-error@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@aureooms/js-error/-/js-error-5.0.2.tgz#dc2ad2fc2b10365581c32c28222daccc5c3c9600" From 0a5277244662cf39f5f63509ef3fde9d3958eeb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 6 Apr 2021 17:52:53 +0200 Subject: [PATCH 2/6] :test_tube: test(shuffle): Simplify. --- test/src/shuffle.js | 86 +++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/test/src/shuffle.js b/test/src/shuffle.js index 455f0e2..d52a639 100644 --- a/test/src/shuffle.js +++ b/test/src/shuffle.js @@ -1,53 +1,56 @@ import test from 'ava'; -import * as random from '../../src/index.js'; +import { + shuffle, + _shuffle, + sample, + _fisheryates, + randint, +} from '../../src/index.js'; -import * as mem from '@aureooms/js-memory'; -import * as array from '@aureooms/js-array'; -import operator from '@aureooms/js-operator'; +import {_calloc} from '@aureooms/js-memory'; +import {iota, copy} from '@aureooms/js-array'; +import {increasing} from '@aureooms/js-compare'; -function one(type, shuffle_name, shuffle) { - const type_name = type.toString().split(' ')[1].slice(0, -2); - - const calloc = mem._calloc(type); - - const n = 100; +const macro = (t, type, _, shuffle, n, i, j) => { + const calloc = _calloc(type); const a = calloc(n); const b = calloc(n); - array.iota(a, 0, n, 0); + iota(a, 0, n, 0); - const range = function (i, j) { - const name = `shuffle ( ${type_name}, ${shuffle_name}, ${i}, ${j} )`; + copy(a, 0, n, b, 0); + shuffle(b, i, j); - test(name, (t) => { - array.copy(a, 0, n, b, 0); - shuffle(b, i, j); + for (let it = 0; it < i; ++it) { + const msg = `b[${it}] === a[${it}]`; + t.deepEqual(b[it], a[it], msg); + } - for (let it = 0; it < i; ++it) { - const msg = `b[${it}] === a[${it}]`; - t.deepEqual(b[it], a[it], msg); - } + const _a = Array.prototype.slice.call(a, i, j).sort(increasing); + const _b = Array.prototype.slice.call(b, i, j).sort(increasing); - const _a = Array.prototype.slice.call(a, i, j).sort(operator.sub); - const _b = Array.prototype.slice.call(b, i, j).sort(operator.sub); + const msg = 'shuffled region contains same elements as original'; - const msg = 'shuffled region contains same elements as original'; + t.deepEqual(_b, _a, msg); - t.deepEqual(_b, _a, msg); + for (let it = j; it < n; ++it) { + const msg = `b[${it}] === a[${it}]`; + t.deepEqual(b[it], a[it], msg); + } +}; - for (let it = j; it < n; ++it) { - const msg = `b[${it}] === a[${it}]`; - t.deepEqual(b[it], a[it], msg); - } - }); - }; +macro.title = (title, type, shuffle_name, _, n, i, j) => + title || `[${n}] shuffle ( ${type.name}, ${shuffle_name}, ${i}, ${j} )`; - range(0, n); - range(20, n); - range(0, n - 20); - range(10, n - 10); -} +const n = 100; + +const params = [ + [n, 0, n], + [n, 20, n], + [n, 0, n - 20], + [n, 10, n - 10], +]; const types = [ Array, @@ -63,16 +66,15 @@ const types = [ ]; const algorithms = [ - [ - 'shuffle based on Fisher-Yates', - random._shuffle(random._fisheryates(random.randint)), - ], - ['shuffle based on random.sample', random._shuffle(random.sample)], - ['API', random.shuffle], + ['shuffle based on Fisher-Yates', _shuffle(_fisheryates(randint))], + ['shuffle based on sample', _shuffle(sample)], + ['API', shuffle], ]; for (const type of types) { for (const [name, algorithm] of algorithms) { - one(type, name, algorithm); + for (const [n, i, j] of params) { + test(macro, type, name, algorithm, n, i, j); + } } } From 2cebdbc578c3af6e17d2a5d41e267f885c9e4ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 6 Apr 2021 17:54:42 +0200 Subject: [PATCH 3/6] :package: deps: Remove unused @aureooms/js-operator. --- package.json | 1 - yarn.lock | 5 ----- 2 files changed, 6 deletions(-) diff --git a/package.json b/package.json index 73e3946..3e17743 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,6 @@ "@aureooms/js-functools": "2.0.3", "@aureooms/js-itertools": "5.0.1", "@aureooms/js-memory": "4.0.0", - "@aureooms/js-operator": "1.0.2", "@aureooms/js-type": "1.0.4", "@babel/core": "7.13.10", "@babel/preset-env": "7.13.10", diff --git a/yarn.lock b/yarn.lock index 037dcad..1ddc104 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,11 +42,6 @@ resolved "https://registry.yarnpkg.com/@aureooms/js-memory/-/js-memory-4.0.0.tgz#db87dc64b948f672d73b434ebde047b05869712c" integrity sha1-24fcZLlI9nLXO0NOveBHsFhpcSw= -"@aureooms/js-operator@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@aureooms/js-operator/-/js-operator-1.0.2.tgz#0786d77d9977823ae7bc04360a315c45bb4c1e65" - integrity sha1-B4bXfZl3gjrnvAQ2CjFcRbtMHmU= - "@aureooms/js-type@1.0.4": version "1.0.4" resolved "https://registry.yarnpkg.com/@aureooms/js-type/-/js-type-1.0.4.tgz#7f9de5f5f8506ff9c8958731744b7427b62e92b7" From 5e33aa171f1618fed9d14ce8bbdc6a5753607e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 6 Apr 2021 18:03:37 +0200 Subject: [PATCH 4/6] :sparkles: feat(api): Add choice and _choice functions. Fixes #16. --- src/api/choice.js | 14 +++++++++++ src/index.js | 2 ++ src/kernel/_choice.js | 24 +++++++++++++++++++ test/src/choice.js | 56 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 src/api/choice.js create mode 100644 src/kernel/_choice.js create mode 100644 test/src/choice.js diff --git a/src/api/choice.js b/src/api/choice.js new file mode 100644 index 0000000..be5e463 --- /dev/null +++ b/src/api/choice.js @@ -0,0 +1,14 @@ +import _choice from '../kernel/_choice.js'; +import randint from './randint.js'; + +/** + * Sample a single element from an array. + * + * @function + * @param {Array} a The input array. + * @param {number} i Inclusive left bound. + * @param {number} j Non-inclusive right bound. + * @return {any} The sampled element. + */ +const choice = _choice(randint); +export default choice; diff --git a/src/index.js b/src/index.js index b10c69a..fe17915 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,11 @@ +export {default as choice} from './api/choice.js'; export {default as randfloat} from './api/randfloat.js'; export {default as randint} from './api/randint.js'; export {default as random} from './api/random.js'; export {default as randrange} from './api/randrange.js'; export {default as sample} from './api/sample.js'; export {default as shuffle} from './api/shuffle.js'; +export {default as _choice} from './kernel/_choice.js'; export {default as _fisheryates} from './kernel/_fisheryates.js'; export {default as _randfloat} from './kernel/_randfloat.js'; export {default as _randint} from './kernel/_randint.js'; diff --git a/src/kernel/_choice.js b/src/kernel/_choice.js new file mode 100644 index 0000000..8ec686b --- /dev/null +++ b/src/kernel/_choice.js @@ -0,0 +1,24 @@ +/** + * Builds a choice function given a randint function. + * + * @param {Function} randint The randint function. + * @return {Function} The choice function. + */ +const _choice = (randint) => { + /** + * Sample a single element from an array. + * + * @param {Array} a The input array. + * @param {number} i Inclusive left bound. + * @param {number} j Non-inclusive right bound. + * @return {any} The sampled element. + */ + const choice = (a, i, j) => { + const x = randint(i, j); + return a[x]; + }; + + return choice; +}; + +export default _choice; diff --git a/test/src/choice.js b/test/src/choice.js new file mode 100644 index 0000000..e1a90f7 --- /dev/null +++ b/test/src/choice.js @@ -0,0 +1,56 @@ +import test from 'ava'; +import {choice, _choice, randint} from '../../src/index.js'; + +import {_calloc} from '@aureooms/js-memory'; +import {iota, copy} from '@aureooms/js-array'; + +const macro = (t, type, _, choice, n, i, j) => { + const calloc = _calloc(type); + const a = calloc(n); + const b = calloc(n); + + iota(a, 0, n, 0); + copy(a, 0, n, b, 0); + + const x = choice(b, i, j); + + t.deepEqual(b, a); + t.true(a.slice(i, j).includes(x)); +}; + +macro.title = (title, type, choice_name, _, n, i, j) => + title || `[${n}] choice ( ${type.name}, ${choice_name}, ${i}, ${j} )`; + +const n = 100; +const params = [ + [n, 0, n], + [n, 20, n], + [n, 0, n - 20], + [n, 10, n - 10], +]; + +const types = [ + Array, + Int8Array, + Int16Array, + Int32Array, + Uint8Array, + Uint16Array, + Uint32Array, + Uint8ClampedArray, + Float32Array, + Float64Array, +]; + +const algorithms = [ + ['kernel', _choice(randint)], + ['API', choice], +]; + +for (const type of types) { + for (const [name, algorithm] of algorithms) { + for (const [n, i, j] of params) { + test(macro, type, name, algorithm, n, i, j); + } + } +} From 0c685b46e408e4167a9cd0f2dc325c188918e614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 6 Apr 2021 18:07:06 +0200 Subject: [PATCH 5/6] :test_tube: test(sample): Shorten unused argument names. --- test/src/sample.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/sample.js b/test/src/sample.js index c1c05e3..23106fd 100644 --- a/test/src/sample.js +++ b/test/src/sample.js @@ -5,7 +5,7 @@ import {_calloc} from '@aureooms/js-memory'; import {iota, copy} from '@aureooms/js-array'; import {increasing} from '@aureooms/js-compare'; -const macro = (t, type, _sample_name, sample, n, k, i, j) => { +const macro = (t, type, _, sample, n, k, i, j) => { const calloc = _calloc(type); const a = calloc(n); @@ -34,7 +34,7 @@ const macro = (t, type, _sample_name, sample, n, k, i, j) => { } }; -macro.title = (title, type, sample_name, _sample, n, k, i, j) => +macro.title = (title, type, sample_name, _, n, k, i, j) => title || `[${n}] sample ( ${type.name}, ${sample_name}, ${k}, ${i}, ${j} )`; const n = 100; From 67bdac4520f8431eb0a165631f15211acd36f349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Ooms?= Date: Tue, 6 Apr 2021 18:19:34 +0200 Subject: [PATCH 6/6] :hatching_chick: release: Bumping to v3.2.0. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e17743..9971ed6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@aureooms/js-random", "description": "Randomness algorithms for JavaScript", - "version": "3.1.0", + "version": "3.2.0", "license": "AGPL-3.0", "author": "Aurélien Ooms ", "homepage": "https://aureooms.github.io/js-random",