@cloudglides/nox 1.1.5 → 2.0.0
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/README.md +9 -9
- package/example/src/App.css +89 -84
- package/example/src/App.jsx +375 -151
- package/package.json +7 -6
- package/src/core.browser.js +10 -2
- package/src/core.js +32 -4
- package/src/generators/logistic.js +30 -25
- package/src/generators/mixer.js +7 -7
- package/src/generators/mt19937.js +10 -7
- package/src/generators/pcg64.js +23 -12
- package/src/generators/splitmix64.js +12 -6
- package/src/generators/tent.js +12 -7
- package/src/generators/xorshift64.js +6 -3
- package/src/index.d.ts +68 -4
- package/src/index.js +154 -2
- package/src/rng.browser.js +21 -10
- package/src/rng.js +95 -82
- package/src/utils/arrays.js +149 -0
- package/src/utils/bits.js +146 -21
- package/src/utils/categorical.js +68 -31
- package/src/utils/combinatorics.js +113 -69
- package/src/utils/confidence.js +145 -0
- package/src/utils/decomposition.js +204 -0
- package/src/utils/distributions-advanced.js +122 -0
- package/src/utils/distributions-extra.js +102 -11
- package/src/utils/distributions-special.js +77 -20
- package/src/utils/distributions.js +99 -35
- package/src/utils/effects.js +172 -0
- package/src/utils/entropy.browser.js +29 -26
- package/src/utils/entropy.js +18 -8
- package/src/utils/helpers.js +64 -0
- package/src/utils/hypothesis.js +167 -0
- package/src/utils/integration.js +137 -0
- package/src/utils/interpolation.js +221 -0
- package/src/utils/matrix.js +242 -0
- package/src/utils/noise.js +36 -22
- package/src/utils/odesolvers.js +176 -0
- package/src/utils/optimization.js +215 -0
- package/src/utils/precomputed.js +166 -0
- package/src/utils/probability.js +199 -0
- package/src/utils/regression.js +170 -0
- package/src/utils/resampling.js +112 -0
- package/src/utils/rootfinding.js +158 -0
- package/src/utils/sampling.js +86 -77
- package/src/utils/seed.js +10 -4
- package/src/utils/seeding.js +24 -12
- package/src/utils/sequence.js +116 -32
- package/src/utils/state.js +48 -36
- package/src/utils/statistics.js +64 -2
- package/src/utils/stochastic.js +91 -31
- package/src/utils/stratified.js +108 -0
- package/src/utils/timeseries.js +166 -0
- package/src/utils/transforms.js +146 -0
- package/test/comprehensive-new.js +126 -0
- package/test/comprehensive.js +4 -3
- package/test/error-handling.js +49 -0
- package/test/new-features.js +52 -0
- package/IMPROVEMENTS.md +0 -58
|
@@ -1,85 +1,129 @@
|
|
|
1
1
|
export const combinations = (arr, k) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
if (!Array.isArray(arr)) {
|
|
3
|
+
throw new TypeError('arr must be an array');
|
|
4
|
+
}
|
|
5
|
+
if (typeof k !== 'number' || !Number.isInteger(k)) {
|
|
6
|
+
throw new TypeError('k must be an integer');
|
|
7
|
+
}
|
|
8
|
+
if (k <= 0) {
|
|
9
|
+
throw new RangeError('k must be positive');
|
|
10
|
+
}
|
|
11
|
+
if (k > arr.length) {
|
|
12
|
+
throw new RangeError('k cannot exceed array length');
|
|
13
|
+
}
|
|
5
14
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
if (k === 1) return arr.map(x => [x]);
|
|
16
|
+
if (k === arr.length) return [arr];
|
|
17
|
+
|
|
18
|
+
const result = [];
|
|
19
|
+
const combine = (start, current) => {
|
|
20
|
+
if (current.length === k) {
|
|
21
|
+
result.push([...current]);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
for (let i = start; i < arr.length; i++) {
|
|
25
|
+
current.push(arr[i]);
|
|
26
|
+
combine(i + 1, current);
|
|
27
|
+
current.pop();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
18
30
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
};
|
|
31
|
+
combine(0, []);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
22
34
|
|
|
23
35
|
export const permutations = (arr) => {
|
|
24
|
-
|
|
36
|
+
if (!Array.isArray(arr)) {
|
|
37
|
+
throw new TypeError('arr must be an array');
|
|
38
|
+
}
|
|
39
|
+
if (arr.length <= 1) return [arr];
|
|
25
40
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
const result = [];
|
|
42
|
+
const permute = (arr, start) => {
|
|
43
|
+
if (start === arr.length - 1) {
|
|
44
|
+
result.push([...arr]);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (let i = start; i < arr.length; i++) {
|
|
48
|
+
[arr[start], arr[i]] = [arr[i], arr[start]];
|
|
49
|
+
permute(arr, start + 1);
|
|
50
|
+
[arr[start], arr[i]] = [arr[i], arr[start]];
|
|
51
|
+
}
|
|
52
|
+
};
|
|
38
53
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
54
|
+
permute([...arr], 0);
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
42
57
|
|
|
43
58
|
export const kPermutations = (arr, k) => {
|
|
44
|
-
|
|
45
|
-
|
|
59
|
+
if (!Array.isArray(arr)) {
|
|
60
|
+
throw new TypeError('arr must be an array');
|
|
61
|
+
}
|
|
62
|
+
if (typeof k !== 'number' || !Number.isInteger(k)) {
|
|
63
|
+
throw new TypeError('k must be an integer');
|
|
64
|
+
}
|
|
65
|
+
if (k <= 0) {
|
|
66
|
+
throw new RangeError('k must be positive');
|
|
67
|
+
}
|
|
68
|
+
if (k > arr.length) {
|
|
69
|
+
throw new RangeError('k cannot exceed array length');
|
|
70
|
+
}
|
|
71
|
+
if (k === 1) return arr.map(x => [x]);
|
|
46
72
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
73
|
+
const result = [];
|
|
74
|
+
const perm = (available, current) => {
|
|
75
|
+
if (current.length === k) {
|
|
76
|
+
result.push([...current]);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
for (let i = 0; i < available.length; i++) {
|
|
80
|
+
const item = available[i];
|
|
81
|
+
const remaining = available.slice(0, i).concat(available.slice(i + 1));
|
|
82
|
+
perm(remaining, [...current, item]);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
59
85
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
};
|
|
86
|
+
perm(arr, []);
|
|
87
|
+
return result;
|
|
88
|
+
};
|
|
63
89
|
|
|
64
90
|
export const randomCombination = (arr, k, rng) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
if (!Array.isArray(arr)) {
|
|
92
|
+
throw new TypeError('arr must be an array');
|
|
93
|
+
}
|
|
94
|
+
if (typeof k !== 'number' || !Number.isInteger(k)) {
|
|
95
|
+
throw new TypeError('k must be an integer');
|
|
96
|
+
}
|
|
97
|
+
if (k <= 0) {
|
|
98
|
+
throw new RangeError('k must be positive');
|
|
99
|
+
}
|
|
100
|
+
if (k > arr.length) {
|
|
101
|
+
throw new RangeError('k cannot exceed array length');
|
|
102
|
+
}
|
|
103
|
+
if (!rng || typeof rng.nextInt !== 'function') {
|
|
104
|
+
throw new TypeError('rng must be an RNG instance');
|
|
72
105
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
106
|
+
const indices = new Set();
|
|
107
|
+
const n = arr.length;
|
|
108
|
+
|
|
109
|
+
while (indices.size < k) {
|
|
110
|
+
indices.add(rng.nextInt(n));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return Array.from(indices).sort((a, b) => a - b).map(i => arr[i]);
|
|
114
|
+
};
|
|
77
115
|
|
|
78
116
|
export const randomPermutation = (arr, rng) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
117
|
+
if (!Array.isArray(arr)) {
|
|
118
|
+
throw new TypeError('arr must be array');
|
|
119
|
+
}
|
|
120
|
+
if (!rng || typeof rng.nextInt !== 'function') {
|
|
121
|
+
throw new TypeError('rng must be an RNG instance');
|
|
122
|
+
}
|
|
123
|
+
const copy = [...arr];
|
|
124
|
+
for (let i = copy.length - 1; i > 0; i--) {
|
|
125
|
+
const j = rng.nextInt(i + 1);
|
|
126
|
+
[copy[i], copy[j]] = [copy[j], copy[i]];
|
|
127
|
+
}
|
|
128
|
+
return copy;
|
|
129
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
export function bootstrapCI(r, data, statistic, level = 0.95, n = 1000) {
|
|
2
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
3
|
+
throw new TypeError('data must be non-empty array');
|
|
4
|
+
}
|
|
5
|
+
if (typeof statistic !== 'function') {
|
|
6
|
+
throw new TypeError('statistic must be function');
|
|
7
|
+
}
|
|
8
|
+
if (typeof level !== 'number' || level <= 0 || level >= 1) {
|
|
9
|
+
throw new RangeError('level must be in (0, 1)');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const samples = new Array(n);
|
|
13
|
+
const size = data.length;
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < n; i++) {
|
|
16
|
+
const resample = new Array(size);
|
|
17
|
+
for (let j = 0; j < size; j++) {
|
|
18
|
+
resample[j] = data[r.nextInt(size)];
|
|
19
|
+
}
|
|
20
|
+
samples[i] = statistic(resample);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
samples.sort((a, b) => a - b);
|
|
24
|
+
|
|
25
|
+
const alpha = 1 - level;
|
|
26
|
+
const lower = Math.floor(alpha / 2 * n);
|
|
27
|
+
const upper = Math.ceil((1 - alpha / 2) * n);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
lower: samples[lower],
|
|
31
|
+
upper: samples[upper],
|
|
32
|
+
estimate: statistic(data),
|
|
33
|
+
level
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function meanCI(data, stddev, level = 0.95, variance = null) {
|
|
38
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
39
|
+
throw new TypeError('data must be non-empty array');
|
|
40
|
+
}
|
|
41
|
+
if (typeof level !== 'number' || level <= 0 || level >= 1) {
|
|
42
|
+
throw new RangeError('level must be in (0, 1)');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const n = data.length;
|
|
46
|
+
const mean = data.reduce((a, b) => a + b, 0) / n;
|
|
47
|
+
|
|
48
|
+
if (variance !== null) {
|
|
49
|
+
if (typeof variance !== 'number' || variance <= 0) {
|
|
50
|
+
throw new RangeError('variance must be positive');
|
|
51
|
+
}
|
|
52
|
+
const se = Math.sqrt(variance / n);
|
|
53
|
+
const z = invNormal((1 + level) / 2);
|
|
54
|
+
return {
|
|
55
|
+
mean,
|
|
56
|
+
lower: mean - z * se,
|
|
57
|
+
upper: mean + z * se,
|
|
58
|
+
level
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (typeof stddev !== 'number' || stddev <= 0) {
|
|
63
|
+
throw new RangeError('stddev must be positive');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const se = stddev / Math.sqrt(n);
|
|
67
|
+
const df = n - 1;
|
|
68
|
+
const t = invT((1 + level) / 2, df);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
mean,
|
|
72
|
+
lower: mean - t * se,
|
|
73
|
+
upper: mean + t * se,
|
|
74
|
+
level,
|
|
75
|
+
df
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function proportionCI(successes, n, level = 0.95, method = 'wilson') {
|
|
80
|
+
if (typeof successes !== 'number' || successes < 0 || successes > n) {
|
|
81
|
+
throw new RangeError('successes must be in [0, n]');
|
|
82
|
+
}
|
|
83
|
+
if (typeof n !== 'number' || n <= 0) {
|
|
84
|
+
throw new RangeError('n must be positive');
|
|
85
|
+
}
|
|
86
|
+
if (typeof level !== 'number' || level <= 0 || level >= 1) {
|
|
87
|
+
throw new RangeError('level must be in (0, 1)');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const p = successes / n;
|
|
91
|
+
const z = invNormal((1 + level) / 2);
|
|
92
|
+
const z2 = z * z;
|
|
93
|
+
|
|
94
|
+
if (method === 'wilson') {
|
|
95
|
+
const center = (successes + z2 / 2) / (n + z2);
|
|
96
|
+
const margin = z * Math.sqrt(p * (1 - p) / n + z2 / (4 * n * n)) / (1 + z2 / n);
|
|
97
|
+
return {
|
|
98
|
+
estimate: p,
|
|
99
|
+
lower: Math.max(0, center - margin),
|
|
100
|
+
upper: Math.min(1, center + margin),
|
|
101
|
+
level
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (method === 'normal') {
|
|
106
|
+
const se = Math.sqrt(p * (1 - p) / n);
|
|
107
|
+
return {
|
|
108
|
+
estimate: p,
|
|
109
|
+
lower: Math.max(0, p - z * se),
|
|
110
|
+
upper: Math.min(1, p + z * se),
|
|
111
|
+
level
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
throw new RangeError(`unknown method: ${method}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function invNormal(p) {
|
|
119
|
+
if (p <= 0.5) {
|
|
120
|
+
const t = Math.sqrt(-2 * Math.log(p));
|
|
121
|
+
const c0 = 2.515517;
|
|
122
|
+
const c1 = 0.802853;
|
|
123
|
+
const c2 = 0.010328;
|
|
124
|
+
const d1 = 1.432788;
|
|
125
|
+
const d2 = 0.189269;
|
|
126
|
+
const d3 = 0.001308;
|
|
127
|
+
return -(t - (c0 + c1 * t + c2 * t * t) / (1 + d1 * t + d2 * t * t + d3 * t * t * t));
|
|
128
|
+
} else {
|
|
129
|
+
const t = Math.sqrt(-2 * Math.log(1 - p));
|
|
130
|
+
const c0 = 2.515517;
|
|
131
|
+
const c1 = 0.802853;
|
|
132
|
+
const c2 = 0.010328;
|
|
133
|
+
const d1 = 1.432788;
|
|
134
|
+
const d2 = 0.189269;
|
|
135
|
+
const d3 = 0.001308;
|
|
136
|
+
return t - (c0 + c1 * t + c2 * t * t) / (1 + d1 * t + d2 * t * t + d3 * t * t * t);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function invT(p, df) {
|
|
141
|
+
const t = invNormal(p);
|
|
142
|
+
const t2 = t * t;
|
|
143
|
+
const g = (0.196 * t2 * t2 + 0.196 * t2 + 0.55) * (Math.exp(-0.0008 * t2 * t2 - 0.24 * t2 - 1.2)) + t * (1 + 0.0000092 * t2 * t2 + 0.00014 * t2);
|
|
144
|
+
return t + g / df;
|
|
145
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
export function svd(A, maxIter = 100) {
|
|
2
|
+
if (!Array.isArray(A) || A.length === 0) {
|
|
3
|
+
throw new TypeError('A must be non-empty matrix');
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const m = A.length;
|
|
7
|
+
const n = A[0].length;
|
|
8
|
+
const k = Math.min(m, n);
|
|
9
|
+
|
|
10
|
+
const U = A.map(row => [...row]);
|
|
11
|
+
const VT = new Array(n);
|
|
12
|
+
for (let i = 0; i < n; i++) {
|
|
13
|
+
VT[i] = new Array(n);
|
|
14
|
+
for (let j = 0; j < n; j++) {
|
|
15
|
+
VT[i][j] = i === j ? 1 : 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const S = new Array(k);
|
|
20
|
+
for (let i = 0; i < k; i++) {
|
|
21
|
+
S[i] = 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
25
|
+
for (let i = 0; i < Math.min(m, n); i++) {
|
|
26
|
+
for (let j = i + 1; j < Math.min(m, n); j++) {
|
|
27
|
+
const x = new Array(m);
|
|
28
|
+
const y = new Array(m);
|
|
29
|
+
|
|
30
|
+
for (let p = 0; p < m; p++) {
|
|
31
|
+
x[p] = U[p][i];
|
|
32
|
+
y[p] = U[p][j];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const xNorm = Math.sqrt(x.reduce((a, b) => a + b * b, 0));
|
|
36
|
+
const yNorm = Math.sqrt(y.reduce((a, b) => a + b * b, 0));
|
|
37
|
+
const xy = x.reduce((a, b, p) => a + b * y[p], 0);
|
|
38
|
+
|
|
39
|
+
if (xNorm < 1e-10 || yNorm < 1e-10 || Math.abs(xy) < 1e-10) continue;
|
|
40
|
+
|
|
41
|
+
const cos = xy / (xNorm * yNorm);
|
|
42
|
+
const angle = Math.acos(Math.min(1, Math.max(-1, cos)));
|
|
43
|
+
const sin = Math.sin(angle);
|
|
44
|
+
const cosTheta = Math.cos(angle);
|
|
45
|
+
const sinTheta = Math.sin(angle);
|
|
46
|
+
|
|
47
|
+
for (let p = 0; p < m; p++) {
|
|
48
|
+
const up_i = U[p][i];
|
|
49
|
+
const up_j = U[p][j];
|
|
50
|
+
U[p][i] = cosTheta * up_i + sinTheta * up_j;
|
|
51
|
+
U[p][j] = -sinTheta * up_i + cosTheta * up_j;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (let i = 0; i < k; i++) {
|
|
58
|
+
let colNorm = 0;
|
|
59
|
+
for (let j = 0; j < m; j++) {
|
|
60
|
+
colNorm += U[j][i] * U[j][i];
|
|
61
|
+
}
|
|
62
|
+
S[i] = Math.sqrt(colNorm);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { U, S, VT };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function qr(A) {
|
|
69
|
+
if (!Array.isArray(A) || A.length === 0) {
|
|
70
|
+
throw new TypeError('A must be non-empty matrix');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const m = A.length;
|
|
74
|
+
const n = A[0].length;
|
|
75
|
+
|
|
76
|
+
const Q = A.map(row => [...row]);
|
|
77
|
+
const R = new Array(n);
|
|
78
|
+
for (let i = 0; i < n; i++) {
|
|
79
|
+
R[i] = new Array(n);
|
|
80
|
+
for (let j = 0; j < n; j++) {
|
|
81
|
+
R[i][j] = 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (let j = 0; j < n; j++) {
|
|
86
|
+
let normCol = 0;
|
|
87
|
+
for (let i = 0; i < m; i++) {
|
|
88
|
+
normCol += Q[i][j] * Q[i][j];
|
|
89
|
+
}
|
|
90
|
+
R[j][j] = Math.sqrt(normCol);
|
|
91
|
+
|
|
92
|
+
if (R[j][j] > 1e-10) {
|
|
93
|
+
for (let i = 0; i < m; i++) {
|
|
94
|
+
Q[i][j] /= R[j][j];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
for (let k = j + 1; k < n; k++) {
|
|
99
|
+
R[j][k] = 0;
|
|
100
|
+
for (let i = 0; i < m; i++) {
|
|
101
|
+
R[j][k] += Q[i][j] * A[i][k];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < m; i++) {
|
|
105
|
+
Q[i][k] -= R[j][k] * Q[i][j];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { Q, R };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function cholesky(A) {
|
|
114
|
+
if (!Array.isArray(A) || A.length !== A[0].length) {
|
|
115
|
+
throw new TypeError('A must be square matrix');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const n = A.length;
|
|
119
|
+
const L = new Array(n);
|
|
120
|
+
for (let i = 0; i < n; i++) {
|
|
121
|
+
L[i] = new Array(n);
|
|
122
|
+
for (let j = 0; j < n; j++) {
|
|
123
|
+
L[i][j] = 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
for (let i = 0; i < n; i++) {
|
|
128
|
+
for (let j = 0; j <= i; j++) {
|
|
129
|
+
let sum = 0;
|
|
130
|
+
for (let k = 0; k < j; k++) {
|
|
131
|
+
sum += L[i][k] * L[j][k];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (i === j) {
|
|
135
|
+
const val = A[i][i] - sum;
|
|
136
|
+
if (val <= 0) {
|
|
137
|
+
throw new RangeError('matrix must be positive definite');
|
|
138
|
+
}
|
|
139
|
+
L[i][j] = Math.sqrt(val);
|
|
140
|
+
} else {
|
|
141
|
+
L[i][j] = (A[i][j] - sum) / L[j][j];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return L;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function lu(A) {
|
|
150
|
+
if (!Array.isArray(A) || A.length !== A[0].length) {
|
|
151
|
+
throw new TypeError('A must be square matrix');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const n = A.length;
|
|
155
|
+
const LU = A.map(row => [...row]);
|
|
156
|
+
const P = new Array(n);
|
|
157
|
+
for (let i = 0; i < n; i++) {
|
|
158
|
+
P[i] = i;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
for (let i = 0; i < n; i++) {
|
|
162
|
+
let maxRow = i;
|
|
163
|
+
for (let k = i + 1; k < n; k++) {
|
|
164
|
+
if (Math.abs(LU[k][i]) > Math.abs(LU[maxRow][i])) {
|
|
165
|
+
maxRow = k;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
[LU[i], LU[maxRow]] = [LU[maxRow], LU[i]];
|
|
170
|
+
[P[i], P[maxRow]] = [P[maxRow], P[i]];
|
|
171
|
+
|
|
172
|
+
if (Math.abs(LU[i][i]) < 1e-10) {
|
|
173
|
+
throw new RangeError('matrix is singular');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
for (let k = i + 1; k < n; k++) {
|
|
177
|
+
LU[k][i] /= LU[i][i];
|
|
178
|
+
for (let j = i + 1; j < n; j++) {
|
|
179
|
+
LU[k][j] -= LU[k][i] * LU[i][j];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const L = new Array(n);
|
|
185
|
+
const U = new Array(n);
|
|
186
|
+
for (let i = 0; i < n; i++) {
|
|
187
|
+
L[i] = new Array(n);
|
|
188
|
+
U[i] = new Array(n);
|
|
189
|
+
for (let j = 0; j < n; j++) {
|
|
190
|
+
if (j < i) {
|
|
191
|
+
L[i][j] = LU[i][j];
|
|
192
|
+
U[i][j] = 0;
|
|
193
|
+
} else if (j === i) {
|
|
194
|
+
L[i][j] = 1;
|
|
195
|
+
U[i][j] = LU[i][j];
|
|
196
|
+
} else {
|
|
197
|
+
L[i][j] = 0;
|
|
198
|
+
U[i][j] = LU[i][j];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return { L, U, P };
|
|
204
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { gamma } from './distributions-extra.js';
|
|
2
|
+
|
|
3
|
+
export function dirichlet(r, alpha) {
|
|
4
|
+
if (!Array.isArray(alpha) || alpha.length === 0) {
|
|
5
|
+
throw new TypeError('alpha must be a non-empty array');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const k = alpha.length;
|
|
9
|
+
const samples = new Array(k);
|
|
10
|
+
let sum = 0;
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < k; i++) {
|
|
13
|
+
if (typeof alpha[i] !== 'number' || alpha[i] <= 0) {
|
|
14
|
+
throw new RangeError('all alpha values must be positive');
|
|
15
|
+
}
|
|
16
|
+
samples[i] = gamma(r, alpha[i], 1);
|
|
17
|
+
sum += samples[i];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < k; i++) {
|
|
21
|
+
samples[i] /= sum;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return samples;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function dirichlets(r, alpha, n) {
|
|
28
|
+
if (typeof n !== 'number' || n < 1) {
|
|
29
|
+
throw new RangeError('n must be a positive integer');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const samples = new Array(n);
|
|
33
|
+
for (let i = 0; i < n; i++) {
|
|
34
|
+
samples[i] = dirichlet(r, alpha);
|
|
35
|
+
}
|
|
36
|
+
return samples;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function mixture(r, distributions, weights) {
|
|
40
|
+
if (!Array.isArray(distributions) || distributions.length === 0) {
|
|
41
|
+
throw new TypeError('distributions must be a non-empty array');
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(weights) || weights.length !== distributions.length) {
|
|
44
|
+
throw new TypeError('weights length must match distributions');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let sum = weights.reduce((a, b) => a + b, 0);
|
|
48
|
+
if (sum <= 0) {
|
|
49
|
+
throw new RangeError('weights must sum to positive value');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const normalized = weights.map(w => w / sum);
|
|
53
|
+
let u = r.nextFloat();
|
|
54
|
+
let cumsum = 0;
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < normalized.length; i++) {
|
|
57
|
+
cumsum += normalized[i];
|
|
58
|
+
if (u < cumsum) {
|
|
59
|
+
return distributions[i](r);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return distributions[distributions.length - 1](r);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function mixtures(r, distributions, weights, n) {
|
|
67
|
+
if (typeof n !== 'number' || n < 1) {
|
|
68
|
+
throw new RangeError('n must be a positive integer');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const samples = new Array(n);
|
|
72
|
+
for (let i = 0; i < n; i++) {
|
|
73
|
+
samples[i] = mixture(r, distributions, weights);
|
|
74
|
+
}
|
|
75
|
+
return samples;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function studentT(r, df) {
|
|
79
|
+
if (typeof df !== 'number' || df <= 0) {
|
|
80
|
+
throw new RangeError('degrees of freedom must be positive');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const z = r.normal();
|
|
84
|
+
const u = r.nextFloat();
|
|
85
|
+
const chi2Val = -2 * Math.log(u) + (df - 1) * Math.log(1 - 2 * u / df);
|
|
86
|
+
const v = Math.sqrt((df * chi2Val) / (df + z * z));
|
|
87
|
+
|
|
88
|
+
return z / v;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function studentTs(r, df, n) {
|
|
92
|
+
if (typeof n !== 'number' || n < 1) {
|
|
93
|
+
throw new RangeError('n must be a positive integer');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const samples = new Array(n);
|
|
97
|
+
for (let i = 0; i < n; i++) {
|
|
98
|
+
samples[i] = studentT(r, df);
|
|
99
|
+
}
|
|
100
|
+
return samples;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function betaBinomial(r, n, alpha, beta) {
|
|
104
|
+
if (typeof n !== 'number' || n < 0 || n !== Math.floor(n)) {
|
|
105
|
+
throw new RangeError('n must be a non-negative integer');
|
|
106
|
+
}
|
|
107
|
+
if (typeof alpha !== 'number' || alpha <= 0) {
|
|
108
|
+
throw new RangeError('alpha must be positive');
|
|
109
|
+
}
|
|
110
|
+
if (typeof beta !== 'number' || beta <= 0) {
|
|
111
|
+
throw new RangeError('beta must be positive');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const p = gamma(r, alpha, 1) / (gamma(r, alpha, 1) + gamma(r, beta, 1));
|
|
115
|
+
let count = 0;
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < n; i++) {
|
|
118
|
+
if (r.nextFloat() < p) count++;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return count;
|
|
122
|
+
}
|