@cloudglides/nox 1.1.4 → 1.1.5
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/package.json +1 -1
- package/src/generators/mt19937.js +3 -6
- package/src/generators/pcg64.js +8 -8
- package/src/generators/splitmix64.js +8 -8
- package/src/generators/xorshift64.js +8 -8
- package/src/rng.browser.js +63 -59
- package/src/rng.js +62 -58
- package/src/utils/distributions.js +21 -19
- package/src/utils/sampling.js +37 -32
- package/src/utils/sequence.js +45 -36
package/package.json
CHANGED
|
@@ -55,15 +55,12 @@ export class MT19937 {
|
|
|
55
55
|
if (max <= 0) {
|
|
56
56
|
throw new Error('max must be positive');
|
|
57
57
|
}
|
|
58
|
-
if (!Number.isInteger(max)) {
|
|
59
|
-
throw new TypeError('max must be an integer');
|
|
60
|
-
}
|
|
61
58
|
|
|
62
|
-
if (max
|
|
63
|
-
|
|
59
|
+
if (max < 65536) {
|
|
60
|
+
return this.next() & 0xFFFF % max;
|
|
64
61
|
}
|
|
65
62
|
|
|
66
|
-
const limit = Math.floor((0x100000000
|
|
63
|
+
const limit = Math.floor((0x100000000 / max)) * max;
|
|
67
64
|
let val;
|
|
68
65
|
|
|
69
66
|
do {
|
package/src/generators/pcg64.js
CHANGED
|
@@ -26,24 +26,24 @@ export class PCG64 {
|
|
|
26
26
|
if (max <= 0) {
|
|
27
27
|
throw new Error('max must be positive');
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
|
|
30
|
+
if (max < 65536) {
|
|
31
|
+
return Number(this.next() & 0xFFFFn) % max;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
const maxBig = BigInt(max);
|
|
34
|
-
const
|
|
35
|
-
const limit = (mask / maxBig) * maxBig;
|
|
35
|
+
const limit = ((1n << 64n) / maxBig) * maxBig;
|
|
36
36
|
|
|
37
|
-
let val = this.next()
|
|
37
|
+
let val = this.next();
|
|
38
38
|
while (val >= limit) {
|
|
39
|
-
val = this.next()
|
|
39
|
+
val = this.next();
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
return Number(val % maxBig);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
nextFloat() {
|
|
46
|
-
const val = this.next() &
|
|
47
|
-
return Number(val) / 9007199254740992.0;
|
|
46
|
+
const val = this.next() & 0x1FFFFFFFFFFFFFn;
|
|
47
|
+
return Number(val) * (1.0 / 9007199254740992.0);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -14,24 +14,24 @@ export class Splitmix64 {
|
|
|
14
14
|
if (max <= 0) {
|
|
15
15
|
throw new Error('max must be positive');
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
18
|
+
if (max < 65536) {
|
|
19
|
+
return Number(this.next() & 0xFFFFn) % max;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
const maxBig = BigInt(max);
|
|
22
|
-
const
|
|
23
|
-
const limit = (mask / maxBig) * maxBig;
|
|
23
|
+
const limit = ((1n << 64n) / maxBig) * maxBig;
|
|
24
24
|
|
|
25
|
-
let val = this.next()
|
|
25
|
+
let val = this.next();
|
|
26
26
|
while (val >= limit) {
|
|
27
|
-
val = this.next()
|
|
27
|
+
val = this.next();
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
return Number(val % maxBig);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
nextFloat() {
|
|
34
|
-
const val = this.next() &
|
|
35
|
-
return Number(val) / 9007199254740992.0;
|
|
34
|
+
const val = this.next() & 0x1FFFFFFFFFFFFFn;
|
|
35
|
+
return Number(val) * (1.0 / 9007199254740992.0);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
@@ -20,24 +20,24 @@ export class Xorshift64 {
|
|
|
20
20
|
if (max <= 0) {
|
|
21
21
|
throw new Error('max must be positive');
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
|
|
24
|
+
if (max < 65536) {
|
|
25
|
+
return Number(this.next() & 0xFFFFn) % max;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
const maxBig = BigInt(max);
|
|
28
|
-
const
|
|
29
|
-
const limit = (mask / maxBig) * maxBig;
|
|
29
|
+
const limit = ((1n << 64n) / maxBig) * maxBig;
|
|
30
30
|
|
|
31
|
-
let val = this.next()
|
|
31
|
+
let val = this.next();
|
|
32
32
|
while (val >= limit) {
|
|
33
|
-
val = this.next()
|
|
33
|
+
val = this.next();
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return Number(val % maxBig);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
nextFloat() {
|
|
40
|
-
const val = this.next() &
|
|
41
|
-
return Number(val) / 9007199254740992.0;
|
|
40
|
+
const val = this.next() & 0x1FFFFFFFFFFFFFn;
|
|
41
|
+
return Number(val) * (1.0 / 9007199254740992.0);
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/rng.browser.js
CHANGED
|
@@ -70,74 +70,78 @@ export class RNG {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
choice(arr) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
if (!Array.isArray(arr)) {
|
|
74
|
+
throw new TypeError('choice() requires array');
|
|
75
|
+
}
|
|
76
|
+
const len = arr.length;
|
|
77
|
+
if (len === 0) {
|
|
78
|
+
throw new TypeError('choice() requires non-empty array');
|
|
79
|
+
}
|
|
80
|
+
return arr[this.nextInt(len)];
|
|
81
|
+
}
|
|
78
82
|
|
|
79
83
|
batch(count, fn) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
85
|
+
throw new TypeError('count must be an integer');
|
|
86
|
+
}
|
|
87
|
+
if (count <= 0) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
if (typeof fn !== 'function') {
|
|
91
|
+
throw new TypeError('fn must be a function');
|
|
92
|
+
}
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const result = new Array(count);
|
|
95
|
+
for (let i = 0; i < count; i++) {
|
|
96
|
+
result[i] = fn(this, i);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
floats(count) {
|
|
102
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
103
|
+
throw new TypeError('count must be an integer');
|
|
104
|
+
}
|
|
105
|
+
if (count <= 0) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
104
108
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
const result = new Array(count);
|
|
110
|
+
for (let i = 0; i < count; i++) {
|
|
111
|
+
result[i] = this.nextFloat();
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
ints(count, max = 2147483647) {
|
|
117
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
118
|
+
throw new TypeError('count must be an integer');
|
|
119
|
+
}
|
|
120
|
+
if (count <= 0) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
const result = new Array(count);
|
|
125
|
+
for (let i = 0; i < count; i++) {
|
|
126
|
+
result[i] = this.nextInt(max);
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
126
130
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
bools(count, probability = 0.5) {
|
|
132
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
133
|
+
throw new TypeError('count must be an integer');
|
|
134
|
+
}
|
|
135
|
+
if (count <= 0) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
134
138
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
const result = new Array(count);
|
|
140
|
+
for (let i = 0; i < count; i++) {
|
|
141
|
+
result[i] = this.bool(probability);
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
export const rng = () => new RNG();
|
package/src/rng.js
CHANGED
|
@@ -70,74 +70,78 @@ export class RNG {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
choice(arr) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
if (!Array.isArray(arr)) {
|
|
74
|
+
throw new TypeError('choice() requires array');
|
|
75
|
+
}
|
|
76
|
+
const len = arr.length;
|
|
77
|
+
if (len === 0) {
|
|
78
|
+
throw new TypeError('choice() requires non-empty array');
|
|
79
|
+
}
|
|
80
|
+
return arr[this.nextInt(len)];
|
|
81
|
+
}
|
|
78
82
|
|
|
79
83
|
batch(count, fn) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
85
|
+
throw new TypeError('count must be an integer');
|
|
86
|
+
}
|
|
87
|
+
if (count <= 0) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
if (typeof fn !== 'function') {
|
|
91
|
+
throw new TypeError('fn must be a function');
|
|
92
|
+
}
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const result = new Array(count);
|
|
95
|
+
for (let i = 0; i < count; i++) {
|
|
96
|
+
result[i] = fn(this, i);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
96
100
|
|
|
97
101
|
floats(count) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
103
|
+
throw new TypeError('count must be an integer');
|
|
104
|
+
}
|
|
105
|
+
if (count <= 0) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
104
108
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
const result = new Array(count);
|
|
110
|
+
for (let i = 0; i < count; i++) {
|
|
111
|
+
result[i] = this.nextFloat();
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
ints(count, max = 2147483647) {
|
|
117
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
118
|
+
throw new TypeError('count must be an integer');
|
|
119
|
+
}
|
|
120
|
+
if (count <= 0) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
const result = new Array(count);
|
|
125
|
+
for (let i = 0; i < count; i++) {
|
|
126
|
+
result[i] = this.nextInt(max);
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
126
130
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
bools(count, probability = 0.5) {
|
|
132
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
133
|
+
throw new TypeError('count must be an integer');
|
|
134
|
+
}
|
|
135
|
+
if (count <= 0) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
134
138
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
const result = new Array(count);
|
|
140
|
+
for (let i = 0; i < count; i++) {
|
|
141
|
+
result[i] = this.bool(probability);
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
export const rng = () => new RNG();
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
+
const TWO_PI = 2 * Math.PI;
|
|
2
|
+
|
|
1
3
|
export const normal = (rng, mean = 0, stddev = 1) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
};
|
|
4
|
+
if (!rng || typeof rng.nextFloat !== 'function') {
|
|
5
|
+
throw new TypeError('First argument must be RNG instance');
|
|
6
|
+
}
|
|
7
|
+
if (typeof mean !== 'number' || typeof stddev !== 'number') {
|
|
8
|
+
throw new TypeError('mean and stddev must be numbers');
|
|
9
|
+
}
|
|
10
|
+
if (stddev <= 0) {
|
|
11
|
+
throw new Error('stddev must be positive');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let u1, u2;
|
|
15
|
+
do {
|
|
16
|
+
u1 = rng.nextFloat();
|
|
17
|
+
u2 = rng.nextFloat();
|
|
18
|
+
} while (u1 <= 0 || u2 <= 0);
|
|
19
|
+
|
|
20
|
+
const z0 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(TWO_PI * u2);
|
|
21
|
+
return z0 * stddev + mean;
|
|
22
|
+
};
|
|
21
23
|
|
|
22
24
|
export const exponential = (rng, lambda = 1) => {
|
|
23
25
|
if (!rng || typeof rng.nextFloat !== 'function') {
|
package/src/utils/sampling.js
CHANGED
|
@@ -34,38 +34,43 @@ export const weightedPick = (arr, weights, rng) => {
|
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
export const weightedSample = (arr, weights, count, rng) => {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
37
|
+
if (!Array.isArray(arr) || arr.length === 0) {
|
|
38
|
+
throw new TypeError('arr must be a non-empty array');
|
|
39
|
+
}
|
|
40
|
+
if (!Array.isArray(weights) || weights.length === 0) {
|
|
41
|
+
throw new TypeError('weights must be a non-empty array');
|
|
42
|
+
}
|
|
43
|
+
if (arr.length !== weights.length) {
|
|
44
|
+
throw new Error('arr and weights must have same length');
|
|
45
|
+
}
|
|
46
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
47
|
+
throw new TypeError('count must be an integer');
|
|
48
|
+
}
|
|
49
|
+
if (count <= 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
if (!rng || typeof rng.nextFloat !== 'function') {
|
|
53
|
+
throw new TypeError('rng must be an RNG instance');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const result = [];
|
|
57
|
+
const len = arr.length;
|
|
58
|
+
if (count >= len) {
|
|
59
|
+
return [...arr];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const remaining = [...arr];
|
|
63
|
+
const remainingWeights = [...weights];
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < count && remaining.length > 0; i++) {
|
|
66
|
+
const idx = weightedPickIndex(remainingWeights, rng);
|
|
67
|
+
result.push(remaining[idx]);
|
|
68
|
+
remaining.splice(idx, 1);
|
|
69
|
+
remainingWeights.splice(idx, 1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return result;
|
|
73
|
+
};
|
|
69
74
|
|
|
70
75
|
const weightedPickIndex = (weights, rng) => {
|
|
71
76
|
const total = weights.reduce((a, b) => a + b, 0);
|
package/src/utils/sequence.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
export const shuffle = (arr, rng, inPlace = false) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
2
|
+
if (!Array.isArray(arr)) {
|
|
3
|
+
throw new TypeError('First argument must be array');
|
|
4
|
+
}
|
|
5
|
+
if (!rng || typeof rng.nextInt !== 'function') {
|
|
6
|
+
throw new TypeError('RNG instance required');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const target = inPlace ? arr : [...arr];
|
|
10
|
+
const len = target.length;
|
|
11
|
+
for (let i = len - 1; i > 0; i--) {
|
|
12
|
+
const j = rng.nextInt(i + 1);
|
|
13
|
+
if (i !== j) {
|
|
14
|
+
const temp = target[i];
|
|
15
|
+
target[i] = target[j];
|
|
16
|
+
target[j] = temp;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
19
21
|
|
|
20
22
|
export const pick = (arr, rng) => {
|
|
21
23
|
if (!Array.isArray(arr)) {
|
|
@@ -32,22 +34,29 @@ export const pick = (arr, rng) => {
|
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
export const sample = (arr, count, rng) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
37
|
+
if (!Array.isArray(arr)) {
|
|
38
|
+
throw new TypeError('First argument must be array');
|
|
39
|
+
}
|
|
40
|
+
if (typeof count !== 'number' || !Number.isInteger(count)) {
|
|
41
|
+
throw new TypeError('Sample count must be an integer');
|
|
42
|
+
}
|
|
43
|
+
if (count <= 0) {
|
|
44
|
+
throw new Error('Sample count must be positive');
|
|
45
|
+
}
|
|
46
|
+
if (count > arr.length) {
|
|
47
|
+
throw new Error('Sample count exceeds array length');
|
|
48
|
+
}
|
|
49
|
+
if (!rng || typeof rng.nextInt !== 'function') {
|
|
50
|
+
throw new TypeError('RNG instance required');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const copy = [...arr];
|
|
54
|
+
const len = copy.length;
|
|
55
|
+
for (let i = len - 1; i >= len - count; i--) {
|
|
56
|
+
const j = rng.nextInt(i + 1);
|
|
57
|
+
const temp = copy[i];
|
|
58
|
+
copy[i] = copy[j];
|
|
59
|
+
copy[j] = temp;
|
|
60
|
+
}
|
|
61
|
+
return copy.slice(len - count);
|
|
62
|
+
};
|