@thi.ng/random 3.6.17 → 3.6.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-09T19:12:03Z
3
+ - **Last updated**: 2023-12-18T13:41:20Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/api.js CHANGED
@@ -1 +0,0 @@
1
- export {};
package/arandom.js CHANGED
@@ -1,29 +1,32 @@
1
1
  const INV_MAX = 1 / 2 ** 32;
2
- export class ARandom {
3
- float(norm = 1) {
4
- return this.int() * INV_MAX * norm;
5
- }
6
- probability(p) {
7
- return this.float() < p;
8
- }
9
- norm(norm = 1) {
10
- return (this.int() * INV_MAX - 0.5) * 2 * norm;
11
- }
12
- normMinMax(min, max) {
13
- const x = this.minmax(min, max);
14
- return this.float() < 0.5 ? x : -x;
15
- }
16
- minmax(min, max) {
17
- return this.float() * (max - min) + min;
18
- }
19
- minmaxInt(min, max) {
20
- min |= 0;
21
- const range = (max | 0) - min;
22
- return range ? min + (this.int() % range) : min;
23
- }
24
- minmaxUint(min, max) {
25
- min >>>= 0;
26
- const range = (max >>> 0) - min;
27
- return range ? min + (this.int() % range) : min;
28
- }
2
+ class ARandom {
3
+ float(norm = 1) {
4
+ return this.int() * INV_MAX * norm;
5
+ }
6
+ probability(p) {
7
+ return this.float() < p;
8
+ }
9
+ norm(norm = 1) {
10
+ return (this.int() * INV_MAX - 0.5) * 2 * norm;
11
+ }
12
+ normMinMax(min, max) {
13
+ const x = this.minmax(min, max);
14
+ return this.float() < 0.5 ? x : -x;
15
+ }
16
+ minmax(min, max) {
17
+ return this.float() * (max - min) + min;
18
+ }
19
+ minmaxInt(min, max) {
20
+ min |= 0;
21
+ const range = (max | 0) - min;
22
+ return range ? min + this.int() % range : min;
23
+ }
24
+ minmaxUint(min, max) {
25
+ min >>>= 0;
26
+ const range = (max >>> 0) - min;
27
+ return range ? min + this.int() % range : min;
28
+ }
29
29
  }
30
+ export {
31
+ ARandom
32
+ };
package/coin.js CHANGED
@@ -1,30 +1,14 @@
1
1
  import { SYSTEM } from "./system.js";
2
- /**
3
- * Returns true w/ a (theoretical) probability of 50% (obviously depending on
4
- * quality of given {@link IRandom}) PRNG.
5
- *
6
- * @remarks
7
- * Also see {@link fairCoin} and {@link IRandom.probability}.
8
- *
9
- * @param rnd -
10
- */
11
- export const coin = (rnd = SYSTEM) => rnd.float() < 0.5;
12
- /**
13
- * Similar to {@link coin}, but more strict. Calls {@link coin} in a pairwise
14
- * manner as long as both results are equal (and discarding results). Otherwise
15
- * returns result of first call.
16
- *
17
- * @remarks
18
- * Reference:
19
- * https://en.m.wikipedia.org/wiki/Fair_coin#Fair_results_from_a_biased_coin
20
- *
21
- * @param rnd -
22
- */
23
- export const fairCoin = (rnd = SYSTEM) => {
24
- let a, b;
25
- do {
26
- a = coin(rnd);
27
- b = coin(rnd);
28
- } while (a === b);
29
- return a;
2
+ const coin = (rnd = SYSTEM) => rnd.float() < 0.5;
3
+ const fairCoin = (rnd = SYSTEM) => {
4
+ let a, b;
5
+ do {
6
+ a = coin(rnd);
7
+ b = coin(rnd);
8
+ } while (a === b);
9
+ return a;
10
+ };
11
+ export {
12
+ coin,
13
+ fairCoin
30
14
  };
package/constants.js CHANGED
@@ -1,5 +1,13 @@
1
- export const DEFAULT_SEED_32 = 0xdecafbad;
2
- export const DEFAULT_SEED_128 = [
3
- 0xdecafbad, 0x2fa9d75b, 0xe41f67e3, 0x5c83ec1a,
1
+ const DEFAULT_SEED_32 = 3737844653;
2
+ const DEFAULT_SEED_128 = [
3
+ 3737844653,
4
+ 799659867,
5
+ 3827263459,
6
+ 1552149530
4
7
  ];
5
- export const DEFAULT_SEED_160 = [...DEFAULT_SEED_128, 0xf69a5c71];
8
+ const DEFAULT_SEED_160 = [...DEFAULT_SEED_128, 4137311345];
9
+ export {
10
+ DEFAULT_SEED_128,
11
+ DEFAULT_SEED_160,
12
+ DEFAULT_SEED_32
13
+ };
package/crypto.js CHANGED
@@ -1,43 +1,34 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { randomBytes } from "./random-bytes.js";
3
- /**
4
- * Currently browser only, a `window.crypto` backed {@link IRandom}
5
- * implementation. Random values are buffered to minimize overhead. Buffer size
6
- * is configurable via ctor.
7
- *
8
- * @remarks
9
- * Internally uses {@link randomBytes} to source values, which falls back to
10
- * using {@link SYSTEM} iff `window.crypto` is not available.
11
- *
12
- */
13
- export class Crypto extends ARandom {
14
- buffer;
15
- u32;
16
- i;
17
- /**
18
- * @param size - buffer size in bytes (will be rounded to next multiple of 4)
19
- */
20
- constructor(size = 1024) {
21
- super();
22
- this.buffer = new Uint8Array((size + 3) & ~3);
23
- this.u32 = new Uint32Array(this.buffer.buffer);
24
- this.i = size >>> 2;
25
- }
26
- copy() {
27
- return new Crypto(this.buffer.length);
28
- }
29
- bytes() {
30
- return new Uint8Array(this.buffer.buffer);
31
- }
32
- int() {
33
- if (this.i >= this.u32.length) {
34
- randomBytes(this.buffer);
35
- this.i = 0;
36
- }
37
- return this.u32[this.i++];
3
+ class Crypto extends ARandom {
4
+ buffer;
5
+ u32;
6
+ i;
7
+ /**
8
+ * @param size - buffer size in bytes (will be rounded to next multiple of 4)
9
+ */
10
+ constructor(size = 1024) {
11
+ super();
12
+ this.buffer = new Uint8Array(size + 3 & ~3);
13
+ this.u32 = new Uint32Array(this.buffer.buffer);
14
+ this.i = size >>> 2;
15
+ }
16
+ copy() {
17
+ return new Crypto(this.buffer.length);
18
+ }
19
+ bytes() {
20
+ return new Uint8Array(this.buffer.buffer);
21
+ }
22
+ int() {
23
+ if (this.i >= this.u32.length) {
24
+ randomBytes(this.buffer);
25
+ this.i = 0;
38
26
  }
27
+ return this.u32[this.i++];
28
+ }
39
29
  }
40
- /**
41
- * Default instance for {@link Crypto} PRNG.
42
- */
43
- export const CRYPTO = new Crypto();
30
+ const CRYPTO = new Crypto();
31
+ export {
32
+ CRYPTO,
33
+ Crypto
34
+ };
@@ -1,12 +1,5 @@
1
1
  import { SYSTEM } from "../system.js";
2
- /**
3
- * Higher order function. Returns no-arg function, yielding values in
4
- * exponential distribution based on given rate `lambda`.
5
- *
6
- * @remarks
7
- * https://en.wikipedia.org/wiki/Exponential_distribution
8
- *
9
- * @param rnd -
10
- * @param lambda - event interval [0,Inf)
11
- */
12
- export const exponential = (rnd = SYSTEM, lambda = 10) => lambda === 0 ? () => Infinity : () => -Math.log(1 - rnd.float(1)) / lambda;
2
+ const exponential = (rnd = SYSTEM, lambda = 10) => lambda === 0 ? () => Infinity : () => -Math.log(1 - rnd.float(1)) / lambda;
3
+ export {
4
+ exponential
5
+ };
@@ -1,24 +1,11 @@
1
1
  import { SYSTEM } from "../system.js";
2
- /**
3
- * Higher order function. Takes a {@link IRandom} instance and returns a no-arg
4
- * function which produces values with approx. normal distribution using CLT
5
- * (Central Limit Theorem).
6
- *
7
- * @remarks
8
- * The default configuration produces samples in the approx. [-0.5,0.5] range
9
- * with a ~12% standard deviation.
10
- *
11
- * Reference: https://en.wikipedia.org/wiki/Central_limit_theorem
12
- *
13
- * @param rnd - default `SYSTEM`
14
- * @param n - num samples, default 24
15
- * @param offset - center offset / bias, default 0
16
- * @param scale - scale, default 1
17
- */
18
- export const gaussian = (rnd = SYSTEM, n = 24, offset = 0, scale = 1) => () => {
19
- let sum = 0;
20
- let m = n;
21
- while (m-- > 0)
22
- sum += rnd.norm(scale);
23
- return sum / n + offset;
2
+ const gaussian = (rnd = SYSTEM, n = 24, offset = 0, scale = 1) => () => {
3
+ let sum = 0;
4
+ let m = n;
5
+ while (m-- > 0)
6
+ sum += rnd.norm(scale);
7
+ return sum / n + offset;
8
+ };
9
+ export {
10
+ gaussian
24
11
  };
@@ -1,20 +1,5 @@
1
1
  import { SYSTEM } from "../system.js";
2
- /**
3
- * HOF. Returns zero-arg function, yielding values in geometric distribution,
4
- * aka the number of independent trials required for the first occurrence of
5
- * success, and each trial using the given success probability `p`.
6
- *
7
- * @remarks
8
- * Returns 0 for p <= 0 and 1 for p >= 1.
9
- *
10
- * Reference: https://en.wikipedia.org/wiki/Geometric_distribution
11
- *
12
- * @param rnd -
13
- * @param p - probability (0,1]
14
- */
15
- export const geometric = (rnd = SYSTEM, p = 0.5) => p <= 0
16
- ? () => Infinity
17
- : p >= 1
18
- ? () => 1
19
- : ((p = Math.log(1 - p)),
20
- () => Math.floor(Math.log(1 - rnd.float(1)) / p) + 1);
2
+ const geometric = (rnd = SYSTEM, p = 0.5) => p <= 0 ? () => Infinity : p >= 1 ? () => 1 : (p = Math.log(1 - p), () => Math.floor(Math.log(1 - rnd.float(1)) / p) + 1);
3
+ export {
4
+ geometric
5
+ };
@@ -1,31 +1,22 @@
1
1
  import { SYSTEM } from "../system.js";
2
- /**
3
- * HOF. Returns zero-arg function, yielding values with normal distribution
4
- * for given `bias` and standard deviation `sigma`.
5
- *
6
- * @remarks
7
- * Also see {@link gaussian} for alternative implementation.
8
- *
9
- * @param rnd -
10
- * @param bias -
11
- * @param sigma -
12
- */
13
- export const normal = (rnd = SYSTEM, bias = 0, sigma = 1) => {
14
- let a;
15
- let b;
16
- let r;
17
- return () => {
18
- if (a != null) {
19
- b = a;
20
- a = null;
21
- }
22
- else {
23
- do {
24
- a = rnd.norm();
25
- b = rnd.norm();
26
- r = a * a + b * b;
27
- } while (r > 1 || r === 0);
28
- }
29
- return bias + sigma * b * Math.sqrt((-2 * Math.log(r)) / r);
30
- };
2
+ const normal = (rnd = SYSTEM, bias = 0, sigma = 1) => {
3
+ let a;
4
+ let b;
5
+ let r;
6
+ return () => {
7
+ if (a != null) {
8
+ b = a;
9
+ a = null;
10
+ } else {
11
+ do {
12
+ a = rnd.norm();
13
+ b = rnd.norm();
14
+ r = a * a + b * b;
15
+ } while (r > 1 || r === 0);
16
+ }
17
+ return bias + sigma * b * Math.sqrt(-2 * Math.log(r) / r);
18
+ };
19
+ };
20
+ export {
21
+ normal
31
22
  };
@@ -1,13 +1,5 @@
1
1
  import { SYSTEM } from "../system.js";
2
- /**
3
- * HOF. Returns zero-arg function, yielding uniformly distributed values in the
4
- * `[min,max)` interval (default: `[0,1)`).
5
- *
6
- * @remarks
7
- * This function is syntax sugar for `rnd.minmax()`.
8
- *
9
- * @param rnd -
10
- * @param min -
11
- * @param max -
12
- */
13
- export const uniform = (rnd = SYSTEM, min = 0, max = 1) => () => rnd.minmax(min, max);
2
+ const uniform = (rnd = SYSTEM, min = 0, max = 1) => () => rnd.minmax(min, max);
3
+ export {
4
+ uniform
5
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/random",
3
- "version": "3.6.17",
3
+ "version": "3.6.19",
4
4
  "description": "Pseudo-random number generators w/ unified API, distributions, weighted choices, ID generation",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -24,7 +24,9 @@
24
24
  "author": "Karsten Schmidt (https://thi.ng)",
25
25
  "license": "Apache-2.0",
26
26
  "scripts": {
27
- "build": "yarn clean && tsc --declaration",
27
+ "build": "yarn build:esbuild && yarn build:decl",
28
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
29
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
28
30
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc distributions",
29
31
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
30
32
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -33,13 +35,14 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@thi.ng/api": "^8.9.11",
37
- "@thi.ng/checks": "^3.4.11",
38
- "@thi.ng/errors": "^2.4.5",
39
- "@thi.ng/hex": "^2.3.23"
38
+ "@thi.ng/api": "^8.9.13",
39
+ "@thi.ng/checks": "^3.4.13",
40
+ "@thi.ng/errors": "^2.4.7",
41
+ "@thi.ng/hex": "^2.3.25"
40
42
  },
41
43
  "devDependencies": {
42
44
  "@microsoft/api-extractor": "^7.38.3",
45
+ "esbuild": "^0.19.8",
43
46
  "rimraf": "^5.0.5",
44
47
  "tools": "^0.0.1",
45
48
  "typedoc": "^0.25.4",
@@ -67,7 +70,7 @@
67
70
  "access": "public"
68
71
  },
69
72
  "engines": {
70
- "node": ">=12.7"
73
+ "node": ">=18"
71
74
  },
72
75
  "files": [
73
76
  "./*.js",
@@ -154,5 +157,5 @@
154
157
  "ksuid"
155
158
  ]
156
159
  },
157
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
160
+ "gitHead": "25a42a81fac8603a1e440a7aa8bc343276211ff4\n"
158
161
  }
package/pick-random.js CHANGED
@@ -1,19 +1,7 @@
1
1
  import { SYSTEM } from "./system.js";
2
- /**
3
- * Returns a random element from `src` using given {@link IRandom} instance
4
- * (default: {@link SYSTEM}). The index selection will be constrained to the
5
- * `[start,end)` interval (default: entire array).
6
- *
7
- * @param src -
8
- * @param rnd -
9
- * @param start -
10
- * @param end -
11
- */
12
- export const pickRandom = (src, rnd = SYSTEM, start = 0, end = src.length) => src[rnd.minmax(start, end) | 0];
13
- /**
14
- * Returns a random key from given `object`.
15
- *
16
- * @param obj
17
- * @param rnd
18
- */
19
- export const pickRandomKey = (obj, rnd = SYSTEM) => pickRandom(Object.keys(obj), rnd);
2
+ const pickRandom = (src, rnd = SYSTEM, start = 0, end = src.length) => src[rnd.minmax(start, end) | 0];
3
+ const pickRandomKey = (obj, rnd = SYSTEM) => pickRandom(Object.keys(obj), rnd);
4
+ export {
5
+ pickRandom,
6
+ pickRandomKey
7
+ };
package/random-bytes.js CHANGED
@@ -1,29 +1,13 @@
1
1
  import { hasCrypto } from "@thi.ng/checks/has-crypto";
2
2
  import { SYSTEM } from "./system.js";
3
- /**
4
- * Fills given byte array with random values sourced from given {@link IRandom}
5
- * instance.
6
- *
7
- * @param rnd -
8
- * @param buf -
9
- * @param start -
10
- * @param end -
11
- */
12
- export const randomBytesFrom = (rnd, buf, start = 0, end = buf.length) => {
13
- for (let i = start; i < end; i++) {
14
- buf[i] = rnd.int() & 0xff;
15
- }
16
- return buf;
3
+ const randomBytesFrom = (rnd, buf, start = 0, end = buf.length) => {
4
+ for (let i = start; i < end; i++) {
5
+ buf[i] = rnd.int() & 255;
6
+ }
7
+ return buf;
8
+ };
9
+ const randomBytes = hasCrypto() ? (buf, start = 0, end = buf.length) => (window.crypto.getRandomValues(buf.subarray(start, end)), buf) : (buf, start, end) => randomBytesFrom(SYSTEM, buf, start, end);
10
+ export {
11
+ randomBytes,
12
+ randomBytesFrom
17
13
  };
18
- /**
19
- * Fills given byte array with random values. Wrapper for
20
- * `crypto.getRandomValues()` with automatic fallback to using `Math.random` if
21
- * platform doesn't provide global crypto instance.
22
- *
23
- * @param buf -
24
- * @param start -
25
- * @param end -
26
- */
27
- export const randomBytes = hasCrypto()
28
- ? (buf, start = 0, end = buf.length) => (window.crypto.getRandomValues(buf.subarray(start, end)), buf)
29
- : (buf, start, end) => randomBytesFrom(SYSTEM, buf, start, end);
package/random-id.js CHANGED
@@ -1,31 +1,11 @@
1
1
  import { SYSTEM } from "./system.js";
2
- /**
3
- * Generates and returns a random string of `len` characters (default 4), plus
4
- * optional given `prefix` and using only provided `syms` characters (default
5
- * lowercase a-z).
6
- *
7
- * @remarks
8
- * See [thi.ng/ksuid](https://thi.ng/thi.ng/ksuid) for a more advanced and
9
- * collision-free approach.
10
- *
11
- * @example
12
- * ```ts
13
- * randomID()
14
- * "qgdt"
15
- *
16
- * randomID(8, "id-", "0123456789ABCDEF")
17
- * "id-94EF6E1A"
18
- * ```
19
- *
20
- * @param len -
21
- * @param prefix -
22
- * @param syms -
23
- * @param rnd -
24
- */
25
- export const randomID = (len = 4, prefix = "", syms = "abcdefghijklmnopqrstuvwxyz", rnd = SYSTEM) => {
26
- const n = syms.length;
27
- for (; len-- > 0;) {
28
- prefix += syms[rnd.int() % n];
29
- }
30
- return prefix;
2
+ const randomID = (len = 4, prefix = "", syms = "abcdefghijklmnopqrstuvwxyz", rnd = SYSTEM) => {
3
+ const n = syms.length;
4
+ for (; len-- > 0; ) {
5
+ prefix += syms[rnd.int() % n];
6
+ }
7
+ return prefix;
8
+ };
9
+ export {
10
+ randomID
31
11
  };
package/sfc32.js CHANGED
@@ -1,36 +1,32 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { DEFAULT_SEED_128 } from "./constants.js";
3
- /**
4
- * Simple Fast Counter PRNG (32bit version)
5
- *
6
- * @remarks
7
- * References:
8
- * - http://pracrand.sourceforge.net/
9
- */
10
- export class SFC32 extends ARandom {
11
- buffer;
12
- constructor(seed = DEFAULT_SEED_128) {
13
- super();
14
- this.buffer = new Uint32Array(4);
15
- this.seed(seed);
16
- }
17
- copy() {
18
- return new SFC32(this.buffer);
19
- }
20
- bytes() {
21
- return new Uint8Array(this.buffer.buffer);
22
- }
23
- int() {
24
- const s = this.buffer;
25
- const t = (((s[0] + s[1]) >>> 0) + s[3]) >>> 0;
26
- s[3] = (s[3] + 1) >>> 0;
27
- s[0] = s[1] ^ (s[1] >>> 9);
28
- s[1] = (s[2] + (s[2] << 3)) >>> 0;
29
- s[2] = (((s[2] << 21) | (s[2] >>> 11)) + t) >>> 0;
30
- return t;
31
- }
32
- seed(seed) {
33
- this.buffer.set(seed);
34
- return this;
35
- }
3
+ class SFC32 extends ARandom {
4
+ buffer;
5
+ constructor(seed = DEFAULT_SEED_128) {
6
+ super();
7
+ this.buffer = new Uint32Array(4);
8
+ this.seed(seed);
9
+ }
10
+ copy() {
11
+ return new SFC32(this.buffer);
12
+ }
13
+ bytes() {
14
+ return new Uint8Array(this.buffer.buffer);
15
+ }
16
+ int() {
17
+ const s = this.buffer;
18
+ const t = (s[0] + s[1] >>> 0) + s[3] >>> 0;
19
+ s[3] = s[3] + 1 >>> 0;
20
+ s[0] = s[1] ^ s[1] >>> 9;
21
+ s[1] = s[2] + (s[2] << 3) >>> 0;
22
+ s[2] = (s[2] << 21 | s[2] >>> 11) + t >>> 0;
23
+ return t;
24
+ }
25
+ seed(seed) {
26
+ this.buffer.set(seed);
27
+ return this;
28
+ }
36
29
  }
30
+ export {
31
+ SFC32
32
+ };
package/smush32.js CHANGED
@@ -1,32 +1,28 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { DEFAULT_SEED_32 } from "./constants.js";
3
- /**
4
- * @remarks
5
- * References:
6
- * -
7
- * - https://github.com/thi-ng/ct-head/blob/master/random.h
8
- * - https://gist.github.com/voidqk/d112165a26b45244a65298933c0349a4
9
- */
10
- export class Smush32 extends ARandom {
11
- buffer;
12
- constructor(seed = DEFAULT_SEED_32) {
13
- super();
14
- this.buffer = new Uint32Array([seed, 0]);
15
- }
16
- copy() {
17
- const gen = new Smush32();
18
- gen.buffer.set(this.buffer);
19
- return gen;
20
- }
21
- seed(s) {
22
- this.buffer.set([s, 0]);
23
- return this;
24
- }
25
- int() {
26
- const b = this.buffer;
27
- const m = 0x5bd1e995;
28
- const k = (b[1]++ * m) >>> 0;
29
- const s = (b[0] = ((k ^ (k >> 24) ^ ((b[0] * m) >>> 0)) * m) >>> 0);
30
- return (s ^ (s >>> 13)) >>> 0;
31
- }
3
+ class Smush32 extends ARandom {
4
+ buffer;
5
+ constructor(seed = DEFAULT_SEED_32) {
6
+ super();
7
+ this.buffer = new Uint32Array([seed, 0]);
8
+ }
9
+ copy() {
10
+ const gen = new Smush32();
11
+ gen.buffer.set(this.buffer);
12
+ return gen;
13
+ }
14
+ seed(s) {
15
+ this.buffer.set([s, 0]);
16
+ return this;
17
+ }
18
+ int() {
19
+ const b = this.buffer;
20
+ const m = 1540483477;
21
+ const k = b[1]++ * m >>> 0;
22
+ const s = b[0] = (k ^ k >> 24 ^ b[0] * m >>> 0) * m >>> 0;
23
+ return (s ^ s >>> 13) >>> 0;
24
+ }
32
25
  }
26
+ export {
27
+ Smush32
28
+ };
package/system.js CHANGED
@@ -1,22 +1,18 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  const random = Math.random;
3
- /**
4
- * A `Math.random()` based {@link IRandom} implementation. Also @see
5
- * {@link SYSTEM}.
6
- */
7
- export class SystemRandom extends ARandom {
8
- int() {
9
- return (random() * 4294967296) /* 2**32 */ >>> 0;
10
- }
11
- float(norm = 1) {
12
- return random() * norm;
13
- }
14
- norm(norm = 1) {
15
- return (random() - 0.5) * 2 * norm;
16
- }
3
+ class SystemRandom extends ARandom {
4
+ int() {
5
+ return random() * 4294967296 >>> 0;
6
+ }
7
+ float(norm = 1) {
8
+ return random() * norm;
9
+ }
10
+ norm(norm = 1) {
11
+ return (random() - 0.5) * 2 * norm;
12
+ }
17
13
  }
18
- /**
19
- * Used as default PRNG throughout most other thi.ng projects, though usually is
20
- * configurable.
21
- */
22
- export const SYSTEM = new SystemRandom();
14
+ const SYSTEM = new SystemRandom();
15
+ export {
16
+ SYSTEM,
17
+ SystemRandom
18
+ };
package/unique-indices.js CHANGED
@@ -1,67 +1,27 @@
1
1
  import { assert } from "@thi.ng/errors/assert";
2
2
  import { SYSTEM } from "./system.js";
3
- /**
4
- * Attempts to draw `k` unique values from given zero-arg function `fn`
5
- * (presumably a PRNG of sorts) and adds them to `existing` array of unique
6
- * samples (or creates a new one). Returns the array. Gives up after
7
- * `maxTrials`.
8
- *
9
- * @remarks
10
- * Internally uses `Array.includes()` to check for duplicates.
11
- *
12
- * @param k -
13
- * @param fn -
14
- * @param existing -
15
- * @param maxTrials -
16
- */
17
- export const uniqueValuesFrom = (k, fn, existing = [], maxTrials = 100) => {
18
- let n = 0;
19
- while (n < k) {
20
- let i;
21
- let trials = maxTrials;
22
- do {
23
- i = fn();
24
- } while (existing.includes(i) && --trials > 0);
25
- if (trials <= 0)
26
- break;
27
- existing.push(i);
28
- n++;
29
- }
30
- return existing;
3
+ const uniqueValuesFrom = (k, fn, existing = [], maxTrials = 100) => {
4
+ let n = 0;
5
+ while (n < k) {
6
+ let i;
7
+ let trials = maxTrials;
8
+ do {
9
+ i = fn();
10
+ } while (existing.includes(i) && --trials > 0);
11
+ if (trials <= 0)
12
+ break;
13
+ existing.push(i);
14
+ n++;
15
+ }
16
+ return existing;
31
17
  };
32
- /**
33
- * Similar to (and based on) {@link uniqueValuesFrom}. Attempts to add `k`
34
- * unique integer indices in the `[0, max)` interval to the (optional) array of
35
- * pre-`existing` indices (which will never be picked again and new indices will
36
- * be added to). Returns updated array.
37
- *
38
- * @remarks
39
- * Candidates are drawn from the provided `rnd` {@link IRandom} (default:
40
- * {@link SYSTEM}) and only `maxTrials` are attempted before giving up.
41
- *
42
- * @param k -
43
- * @param max -
44
- * @param existing -
45
- * @param maxTrials -
46
- * @param rnd -
47
- */
48
- export const uniqueIndices = (k, max, existing, maxTrials = max, rnd = SYSTEM) => {
49
- assert(k >= 0 && k <= max, `k must be in [0, ${max}] interval`);
50
- return uniqueValuesFrom(k, () => rnd.int() % max, existing, maxTrials);
18
+ const uniqueIndices = (k, max, existing, maxTrials = max, rnd = SYSTEM) => {
19
+ assert(k >= 0 && k <= max, `k must be in [0, ${max}] interval`);
20
+ return uniqueValuesFrom(k, () => rnd.int() % max, existing, maxTrials);
21
+ };
22
+ const pickRandomUnique = (k, src, existing, maxTrials = 100, rnd = SYSTEM) => uniqueValuesFrom(k, () => src[rnd.int() % src.length], existing, maxTrials);
23
+ export {
24
+ pickRandomUnique,
25
+ uniqueIndices,
26
+ uniqueValuesFrom
51
27
  };
52
- /**
53
- * Combination of {@link pickRandom} and {@link uniqueValuesFrom}. Picks up to
54
- * `k` unique values from `src` array (each with `maxTrials`) and adds them to
55
- * given `existing` array (or creates a new one by default) and returns it. Uses
56
- * given `rnd` instance (default: {@link SYSTEM} to randomly select candidates.
57
- *
58
- * @remarks
59
- * Internally uses `Array.includes()` to check for duplicates.
60
- *
61
- * @param k
62
- * @param src
63
- * @param existing
64
- * @param maxTrials
65
- * @param rnd
66
- */
67
- export const pickRandomUnique = (k, src, existing, maxTrials = 100, rnd = SYSTEM) => uniqueValuesFrom(k, () => src[rnd.int() % src.length], existing, maxTrials);
package/uuid.js CHANGED
@@ -1,27 +1,15 @@
1
1
  import { uuid as $uuid } from "@thi.ng/hex";
2
2
  import { randomBytes, randomBytesFrom } from "./random-bytes.js";
3
- /**
4
- * Depending on if `rnd` is given, uses {@link randomBytesFrom} or
5
- * {@link randomBytes} to fill given (optional) byte array with a new UUIDv4.
6
- * Creates new Uint8Array if none given.
7
- *
8
- * @param buf -
9
- * @param rnd -
10
- */
11
- export const uuidv4Bytes = (buf, rnd) => {
12
- buf = buf || new Uint8Array(16);
13
- buf = rnd ? randomBytesFrom(rnd, buf) : randomBytes(buf);
14
- buf[6] = 0x40 | (buf[6] & 0x0f);
15
- buf[8] = 0x80 | (buf[8] & 0x3f);
16
- return buf;
3
+ const uuidv4Bytes = (buf, rnd) => {
4
+ buf = buf || new Uint8Array(16);
5
+ buf = rnd ? randomBytesFrom(rnd, buf) : randomBytes(buf);
6
+ buf[6] = 64 | buf[6] & 15;
7
+ buf[8] = 128 | buf[8] & 63;
8
+ return buf;
17
9
  };
18
- /** @internal */
19
10
  const __buf = new Uint8Array(16);
20
- /**
21
- * Returns a UUID string, either from given byte array, or if omitted, using a
22
- * new UUID v4 produced by {@link uuidv4Bytes}.
23
- *
24
- * @param id - byte array
25
- * @param i - start index
26
- */
27
- export const uuid = (id, i = 0) => $uuid(id || uuidv4Bytes(__buf), i);
11
+ const uuid = (id, i = 0) => $uuid(id || uuidv4Bytes(__buf), i);
12
+ export {
13
+ uuid,
14
+ uuidv4Bytes
15
+ };
@@ -1,54 +1,32 @@
1
1
  import { assert } from "@thi.ng/errors/assert";
2
2
  import { SYSTEM } from "./system.js";
3
- /**
4
- * Returns a no-arg function which produces a random choice of given weighted
5
- * `choices` and using given {@link IRandom} instance (default {@link SYSTEM}.
6
- * If `weights` are given, it must be the same size as `choices` (else missing
7
- * weights will be assumed zero). If omitted entirely, each choice will have
8
- * same probability.
9
- *
10
- * @remarks
11
- * Throws an error if the `choices` array is empty (requires at least 1 item).
12
- * If the total sum of `weights` is <= 0 a warning is printed to the console and
13
- * the resulting function will only ever return the first `choice`.
14
- *
15
- * Based on:
16
- * https://www.electricmonk.nl/log/2009/12/23/weighted-random-distribution/
17
- *
18
- * @param choices -
19
- * @param weights - optional weights
20
- */
21
- export const weightedRandom = (choices, weights, rnd = SYSTEM) => {
22
- const n = choices.length;
23
- assert(n > 0, "no choices given");
24
- const opts = weights
25
- ? choices
26
- .map((x, i) => [weights[i] || 0, x])
27
- .sort((a, b) => b[0] - a[0])
28
- : choices.map((x) => [1, x]);
29
- const total = opts.reduce((acc, o) => acc + o[0], 0);
30
- total <= 0 && console.warn("total weights <= 0");
31
- return () => {
32
- const r = rnd.float(total);
33
- let sum = total;
34
- for (let i = 0; i < n; i++) {
35
- sum -= opts[i][0];
36
- if (sum <= r) {
37
- return opts[i][1];
38
- }
39
- }
40
- return undefined;
41
- };
3
+ const weightedRandom = (choices, weights, rnd = SYSTEM) => {
4
+ const n = choices.length;
5
+ assert(n > 0, "no choices given");
6
+ const opts = weights ? choices.map((x, i) => [weights[i] || 0, x]).sort((a, b) => b[0] - a[0]) : choices.map((x) => [1, x]);
7
+ const total = opts.reduce((acc, o) => acc + o[0], 0);
8
+ total <= 0 && console.warn("total weights <= 0");
9
+ return () => {
10
+ const r = rnd.float(total);
11
+ let sum = total;
12
+ for (let i = 0; i < n; i++) {
13
+ sum -= opts[i][0];
14
+ if (sum <= r) {
15
+ return opts[i][1];
16
+ }
17
+ }
18
+ return void 0;
19
+ };
42
20
  };
43
- /**
44
- * Alt version of {@link weightedRandom}, accepting an object of weights
45
- * instead. The returned function will return keys of given `choices` object,
46
- * taking into account the weights given for each key.
47
- *
48
- * @param choices
49
- * @param rnd
50
- */
51
- export const weightedRandomKey = (choices, rnd = SYSTEM) => {
52
- const keys = Object.keys(choices);
53
- return weightedRandom(keys, keys.map((x) => choices[x]), rnd);
21
+ const weightedRandomKey = (choices, rnd = SYSTEM) => {
22
+ const keys = Object.keys(choices);
23
+ return weightedRandom(
24
+ keys,
25
+ keys.map((x) => choices[x]),
26
+ rnd
27
+ );
28
+ };
29
+ export {
30
+ weightedRandom,
31
+ weightedRandomKey
54
32
  };
package/xorshift128.js CHANGED
@@ -1,35 +1,34 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { DEFAULT_SEED_128 } from "./constants.js";
3
- /**
4
- * @remarks
5
- * Reference: https://en.wikipedia.org/wiki/Xorshift
6
- */
7
- export class XorShift128 extends ARandom {
8
- buffer;
9
- constructor(seed = DEFAULT_SEED_128) {
10
- super();
11
- this.buffer = new Uint32Array(4);
12
- this.seed(seed);
13
- }
14
- copy() {
15
- return new XorShift128(this.buffer);
16
- }
17
- bytes() {
18
- return new Uint8Array(this.buffer.buffer);
19
- }
20
- seed(seed) {
21
- this.buffer.set(seed);
22
- return this;
23
- }
24
- int() {
25
- const s = this.buffer;
26
- let t = s[3];
27
- let w;
28
- t ^= t << 11;
29
- t ^= t >>> 8;
30
- s[3] = s[2];
31
- s[2] = s[1];
32
- w = s[1] = s[0];
33
- return (s[0] = (t ^ w ^ (w >>> 19)) >>> 0);
34
- }
3
+ class XorShift128 extends ARandom {
4
+ buffer;
5
+ constructor(seed = DEFAULT_SEED_128) {
6
+ super();
7
+ this.buffer = new Uint32Array(4);
8
+ this.seed(seed);
9
+ }
10
+ copy() {
11
+ return new XorShift128(this.buffer);
12
+ }
13
+ bytes() {
14
+ return new Uint8Array(this.buffer.buffer);
15
+ }
16
+ seed(seed) {
17
+ this.buffer.set(seed);
18
+ return this;
19
+ }
20
+ int() {
21
+ const s = this.buffer;
22
+ let t = s[3];
23
+ let w;
24
+ t ^= t << 11;
25
+ t ^= t >>> 8;
26
+ s[3] = s[2];
27
+ s[2] = s[1];
28
+ w = s[1] = s[0];
29
+ return s[0] = (t ^ w ^ w >>> 19) >>> 0;
30
+ }
35
31
  }
32
+ export {
33
+ XorShift128
34
+ };
package/xorwow.js CHANGED
@@ -1,38 +1,37 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { DEFAULT_SEED_160 } from "./constants.js";
3
- /**
4
- * @remarks
5
- * Reference: https://en.wikipedia.org/wiki/Xorshift#xorwow
6
- */
7
- export class XorWow extends ARandom {
8
- buffer;
9
- constructor(seed = DEFAULT_SEED_160) {
10
- super();
11
- this.buffer = new Uint32Array(5);
12
- this.seed(seed);
13
- }
14
- copy() {
15
- return new XorWow(this.buffer);
16
- }
17
- seed(seed) {
18
- this.buffer.set(seed);
19
- return this;
20
- }
21
- bytes() {
22
- return new Uint8Array(this.buffer.buffer);
23
- }
24
- int() {
25
- const s = this.buffer;
26
- let t = s[3];
27
- let w;
28
- t ^= t >>> 2;
29
- t ^= t << 1;
30
- s[3] = s[2];
31
- s[2] = s[1];
32
- w = s[1] = s[0];
33
- t ^= w;
34
- t ^= w << 4;
35
- s[0] = t;
36
- return (t + (s[4] += 0x587c5)) >>> 0;
37
- }
3
+ class XorWow extends ARandom {
4
+ buffer;
5
+ constructor(seed = DEFAULT_SEED_160) {
6
+ super();
7
+ this.buffer = new Uint32Array(5);
8
+ this.seed(seed);
9
+ }
10
+ copy() {
11
+ return new XorWow(this.buffer);
12
+ }
13
+ seed(seed) {
14
+ this.buffer.set(seed);
15
+ return this;
16
+ }
17
+ bytes() {
18
+ return new Uint8Array(this.buffer.buffer);
19
+ }
20
+ int() {
21
+ const s = this.buffer;
22
+ let t = s[3];
23
+ let w;
24
+ t ^= t >>> 2;
25
+ t ^= t << 1;
26
+ s[3] = s[2];
27
+ s[2] = s[1];
28
+ w = s[1] = s[0];
29
+ t ^= w;
30
+ t ^= w << 4;
31
+ s[0] = t;
32
+ return t + (s[4] += 362437) >>> 0;
33
+ }
38
34
  }
35
+ export {
36
+ XorWow
37
+ };
package/xoshiro128.js CHANGED
@@ -1,40 +1,37 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { DEFAULT_SEED_128 } from "./constants.js";
3
- /**
4
- * @remarks
5
- * References:
6
- * - http://prng.di.unimi.it/
7
- * - http://prng.di.unimi.it/xoshiro128plusplus.c
8
- */
9
- export class Xoshiro128 extends ARandom {
10
- buffer;
11
- constructor(seed = DEFAULT_SEED_128) {
12
- super();
13
- this.buffer = new Uint32Array(4);
14
- this.seed(seed);
15
- }
16
- copy() {
17
- return new Xoshiro128(this.buffer);
18
- }
19
- bytes() {
20
- return new Uint8Array(this.buffer.buffer);
21
- }
22
- seed(seed) {
23
- this.buffer.set(seed);
24
- return this;
25
- }
26
- int() {
27
- const s = this.buffer;
28
- let t = s[0] + s[3];
29
- const res = ((t << 7) | (t >>> 25)) >>> 0;
30
- t = s[1] << 9;
31
- s[2] ^= s[0];
32
- s[3] ^= s[1];
33
- s[1] ^= s[2];
34
- s[0] ^= s[3];
35
- s[2] ^= t;
36
- t = s[3];
37
- s[3] = ((t << 11) | (t >>> 21)) >>> 0;
38
- return res;
39
- }
3
+ class Xoshiro128 extends ARandom {
4
+ buffer;
5
+ constructor(seed = DEFAULT_SEED_128) {
6
+ super();
7
+ this.buffer = new Uint32Array(4);
8
+ this.seed(seed);
9
+ }
10
+ copy() {
11
+ return new Xoshiro128(this.buffer);
12
+ }
13
+ bytes() {
14
+ return new Uint8Array(this.buffer.buffer);
15
+ }
16
+ seed(seed) {
17
+ this.buffer.set(seed);
18
+ return this;
19
+ }
20
+ int() {
21
+ const s = this.buffer;
22
+ let t = s[0] + s[3];
23
+ const res = (t << 7 | t >>> 25) >>> 0;
24
+ t = s[1] << 9;
25
+ s[2] ^= s[0];
26
+ s[3] ^= s[1];
27
+ s[1] ^= s[2];
28
+ s[0] ^= s[3];
29
+ s[2] ^= t;
30
+ t = s[3];
31
+ s[3] = (t << 11 | t >>> 21) >>> 0;
32
+ return res;
33
+ }
40
34
  }
35
+ export {
36
+ Xoshiro128
37
+ };
package/xsadd.js CHANGED
@@ -1,44 +1,43 @@
1
1
  import { ARandom } from "./arandom.js";
2
2
  import { DEFAULT_SEED_32 } from "./constants.js";
3
- /**
4
- * @remarks
5
- * Reference: https://github.com/MersenneTwister-Lab/XSadd/blob/develop/xsadd.h
6
- */
7
- export class XsAdd extends ARandom {
8
- buffer;
9
- constructor(seed = DEFAULT_SEED_32) {
10
- super();
11
- this.buffer = new Uint32Array(4);
12
- this.seed(seed);
13
- }
14
- bytes() {
15
- return new Uint8Array(this.buffer.buffer);
16
- }
17
- copy() {
18
- const gen = new XsAdd();
19
- gen.buffer.set(this.buffer);
20
- return gen;
21
- }
22
- seed(seed) {
23
- const s = this.buffer;
24
- s.set([seed, 0, 0, 0]);
25
- for (let j = 0, i = 1; i < 8; j = i++) {
26
- let x = (s[j & 3] ^ (s[j & 3] >>> 30)) >>> 0;
27
- x = (0x8965 * x + (((0x6c07 * x) & 0xffff) << 16)) >>> 0;
28
- s[i & 3] ^= (i + x) >>> 0;
29
- }
30
- return this;
31
- }
32
- int() {
33
- const s = this.buffer;
34
- let t = s[0];
35
- t ^= t << 15;
36
- t ^= t >>> 18;
37
- t ^= s[3] << 11;
38
- s[0] = s[1];
39
- s[1] = s[2];
40
- s[2] = s[3];
41
- s[3] = t;
42
- return (t + s[2]) >>> 0;
3
+ class XsAdd extends ARandom {
4
+ buffer;
5
+ constructor(seed = DEFAULT_SEED_32) {
6
+ super();
7
+ this.buffer = new Uint32Array(4);
8
+ this.seed(seed);
9
+ }
10
+ bytes() {
11
+ return new Uint8Array(this.buffer.buffer);
12
+ }
13
+ copy() {
14
+ const gen = new XsAdd();
15
+ gen.buffer.set(this.buffer);
16
+ return gen;
17
+ }
18
+ seed(seed) {
19
+ const s = this.buffer;
20
+ s.set([seed, 0, 0, 0]);
21
+ for (let j = 0, i = 1; i < 8; j = i++) {
22
+ let x = (s[j & 3] ^ s[j & 3] >>> 30) >>> 0;
23
+ x = 35173 * x + ((27655 * x & 65535) << 16) >>> 0;
24
+ s[i & 3] ^= i + x >>> 0;
43
25
  }
26
+ return this;
27
+ }
28
+ int() {
29
+ const s = this.buffer;
30
+ let t = s[0];
31
+ t ^= t << 15;
32
+ t ^= t >>> 18;
33
+ t ^= s[3] << 11;
34
+ s[0] = s[1];
35
+ s[1] = s[2];
36
+ s[2] = s[3];
37
+ s[3] = t;
38
+ return t + s[2] >>> 0;
39
+ }
44
40
  }
41
+ export {
42
+ XsAdd
43
+ };