@cloudglides/nox 1.1.6 → 3.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/package.json +1 -1
- package/example/src/App.css +38 -7
- package/example/src/App.jsx +328 -25
- package/package.json +7 -6
- package/pnpm-workspace.yaml +3 -0
- package/src/core.browser.js +37 -4
- package/src/core.js +37 -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.browser.js +168 -1
- package/src/index.d.ts +68 -4
- package/src/index.js +169 -1
- package/src/rng.browser.js +5 -6
- package/src/rng.js +95 -94
- package/src/utils/arrays.js +149 -0
- package/src/utils/bits.js +146 -21
- package/src/utils/categorical.js +68 -31
- package/src/utils/clustering.js +143 -0
- package/src/utils/combinatorics.js +113 -69
- package/src/utils/confidence.js +145 -0
- package/src/utils/decomposition.js +204 -0
- package/src/utils/diagnostics.js +309 -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/logistic.js +91 -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/polynomial.js +136 -0
- package/src/utils/precomputed.js +166 -0
- package/src/utils/probability.js +199 -0
- package/src/utils/pvalues.js +142 -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.js +4 -3
- package/test/new-features.js +52 -0
- package/IMPROVEMENTS.md +0 -58
- package/PERFORMANCE.md +0 -69
- package/example/pnpm-lock.yaml +0 -1006
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
export function tTestPValue(t, df, twoTailed = true) {
|
|
2
|
+
if (typeof t !== 'number' || typeof df !== 'number') {
|
|
3
|
+
throw new TypeError('t and df must be numbers');
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const tAbs = Math.abs(t);
|
|
7
|
+
let p = 2 * (1 - tCDF(tAbs, df));
|
|
8
|
+
|
|
9
|
+
return twoTailed ? p : p / 2;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function zTestPValue(z, twoTailed = true) {
|
|
13
|
+
if (typeof z !== 'number') {
|
|
14
|
+
throw new TypeError('z must be number');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const zAbs = Math.abs(z);
|
|
18
|
+
const p = 2 * (1 - normalCDF(zAbs));
|
|
19
|
+
|
|
20
|
+
return twoTailed ? p : p / 2;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function fTestPValue(f, df1, df2) {
|
|
24
|
+
if (typeof f !== 'number' || typeof df1 !== 'number' || typeof df2 !== 'number') {
|
|
25
|
+
throw new TypeError('f, df1, df2 must be numbers');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (f < 0) return 1;
|
|
29
|
+
|
|
30
|
+
const alpha = df2 / (df1 * f + df2);
|
|
31
|
+
return 1 - incompleteBeta(alpha, df2 / 2, df1 / 2);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function chi2PValue(chi2, df) {
|
|
35
|
+
if (typeof chi2 !== 'number' || typeof df !== 'number') {
|
|
36
|
+
throw new TypeError('chi2 and df must be numbers');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (chi2 < 0) return 1;
|
|
40
|
+
|
|
41
|
+
return 1 - incompleteBeta(chi2 / (chi2 + 1), 1, df / 2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function uTestPValue(u, n1, n2) {
|
|
45
|
+
if (typeof u !== 'number' || typeof n1 !== 'number' || typeof n2 !== 'number') {
|
|
46
|
+
throw new TypeError('u, n1, n2 must be numbers');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const mean = (n1 * n2) / 2;
|
|
50
|
+
const std = Math.sqrt((n1 * n2 * (n1 + n2 + 1)) / 12);
|
|
51
|
+
const z = Math.abs((u - mean) / std);
|
|
52
|
+
|
|
53
|
+
return 2 * (1 - normalCDF(z));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function pearsonPValue(r, n) {
|
|
57
|
+
if (typeof r !== 'number' || typeof n !== 'number') {
|
|
58
|
+
throw new TypeError('r and n must be numbers');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (Math.abs(r) >= 1) return 0;
|
|
62
|
+
|
|
63
|
+
const t = r * Math.sqrt((n - 2) / (1 - r * r));
|
|
64
|
+
const df = n - 2;
|
|
65
|
+
|
|
66
|
+
return tTestPValue(t, df, true);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalCDF(z) {
|
|
70
|
+
return 0.5 * (1 + erf(z / Math.sqrt(2)));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function tCDF(t, df) {
|
|
74
|
+
const x = df / (df + t * t);
|
|
75
|
+
return 1 - incompleteBeta(x, df / 2, 0.5);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function erf(x) {
|
|
79
|
+
const a1 = 0.254829592;
|
|
80
|
+
const a2 = -0.284496736;
|
|
81
|
+
const a3 = 1.421413741;
|
|
82
|
+
const a4 = -1.453152027;
|
|
83
|
+
const a5 = 1.061405429;
|
|
84
|
+
const p = 0.3275911;
|
|
85
|
+
|
|
86
|
+
const sign = x < 0 ? -1 : 1;
|
|
87
|
+
const absX = Math.abs(x);
|
|
88
|
+
const t = 1 / (1 + p * absX);
|
|
89
|
+
const t2 = t * t;
|
|
90
|
+
const t3 = t2 * t;
|
|
91
|
+
const t4 = t3 * t;
|
|
92
|
+
const t5 = t4 * t;
|
|
93
|
+
|
|
94
|
+
return sign * (1 - (a1 * t + a2 * t2 + a3 * t3 + a4 * t4 + a5 * t5) * Math.exp(-absX * absX));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function incompleteBeta(x, a, b, maxIter = 100) {
|
|
98
|
+
if (x <= 0) return 0;
|
|
99
|
+
if (x >= 1) return 1;
|
|
100
|
+
|
|
101
|
+
let sum = 1;
|
|
102
|
+
let term = 1;
|
|
103
|
+
|
|
104
|
+
for (let i = 1; i <= maxIter; i++) {
|
|
105
|
+
term *= (a + b - 1) * x / ((a + i - 1) * (1 - x / (a + i)));
|
|
106
|
+
const nextSum = sum + term;
|
|
107
|
+
|
|
108
|
+
if (Math.abs(nextSum - sum) < 1e-14) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
sum = nextSum;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return sum * Math.exp(a * Math.log(x) + b * Math.log(1 - x) - logBeta(a, b)) / a;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function logBeta(a, b) {
|
|
118
|
+
return logGamma(a) + logGamma(b) - logGamma(a + b);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function logGamma(x) {
|
|
122
|
+
const coefficients = [
|
|
123
|
+
676.5203681218851,
|
|
124
|
+
-1259.1392167224028,
|
|
125
|
+
771.32342877765313,
|
|
126
|
+
-176.61502916214059,
|
|
127
|
+
12.507343278686905,
|
|
128
|
+
-0.13857109526572012,
|
|
129
|
+
9.9843695780195716e-6,
|
|
130
|
+
1.5056327351493116e-7
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
const g = 7;
|
|
134
|
+
const z = x - 1;
|
|
135
|
+
let sum = 0.99999999999980993;
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < coefficients.length; i++) {
|
|
138
|
+
sum += coefficients[i] / (z + i + 1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return 0.5 * Math.log(2 * Math.PI) + (z + 0.5) * Math.log(z + g + 0.5) - (z + g + 0.5) + Math.log(sum);
|
|
142
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
export class LinearRegression {
|
|
2
|
+
constructor(x, y) {
|
|
3
|
+
if (!Array.isArray(x) || !Array.isArray(y)) {
|
|
4
|
+
throw new TypeError('x and y must be arrays');
|
|
5
|
+
}
|
|
6
|
+
if (x.length !== y.length || x.length < 2) {
|
|
7
|
+
throw new RangeError('x and y must have same length >= 2');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const n = x.length;
|
|
11
|
+
const sumX = x.reduce((a, b) => a + b, 0);
|
|
12
|
+
const sumY = y.reduce((a, b) => a + b, 0);
|
|
13
|
+
const sumXY = x.reduce((sum, xi, i) => sum + xi * y[i], 0);
|
|
14
|
+
const sumX2 = x.reduce((sum, xi) => sum + xi * xi, 0);
|
|
15
|
+
|
|
16
|
+
const meanX = sumX / n;
|
|
17
|
+
const meanY = sumY / n;
|
|
18
|
+
|
|
19
|
+
this.slope = (sumXY - n * meanX * meanY) / (sumX2 - n * meanX * meanX);
|
|
20
|
+
this.intercept = meanY - this.slope * meanX;
|
|
21
|
+
|
|
22
|
+
const yPred = x.map(xi => this.slope * xi + this.intercept);
|
|
23
|
+
|
|
24
|
+
let ssRes = 0, ssTot = 0;
|
|
25
|
+
for (let i = 0; i < n; i++) {
|
|
26
|
+
ssRes += (y[i] - yPred[i]) ** 2;
|
|
27
|
+
ssTot += (y[i] - meanY) ** 2;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.rSquared = 1 - ssRes / ssTot;
|
|
31
|
+
this.rmse = Math.sqrt(ssRes / n);
|
|
32
|
+
this.residuals = y.map((yi, i) => yi - yPred[i]);
|
|
33
|
+
this.predictions = yPred;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
predict(x) {
|
|
37
|
+
if (typeof x === 'number') {
|
|
38
|
+
return this.slope * x + this.intercept;
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(x)) {
|
|
41
|
+
return x.map(xi => this.slope * xi + this.intercept);
|
|
42
|
+
}
|
|
43
|
+
throw new TypeError('x must be number or array');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class MultipleRegression {
|
|
48
|
+
constructor(X, y) {
|
|
49
|
+
if (!Array.isArray(X) || !Array.isArray(y)) {
|
|
50
|
+
throw new TypeError('X and y must be arrays');
|
|
51
|
+
}
|
|
52
|
+
if (X.length !== y.length || X.length < 2) {
|
|
53
|
+
throw new RangeError('X and y must have same length >= 2');
|
|
54
|
+
}
|
|
55
|
+
if (!Array.isArray(X[0])) {
|
|
56
|
+
throw new TypeError('X must be array of arrays (features)');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const n = X.length;
|
|
60
|
+
const p = X[0].length;
|
|
61
|
+
|
|
62
|
+
const matX = X.map(row => [1, ...row]);
|
|
63
|
+
|
|
64
|
+
const XtX = matmul(transpose(matX), matX);
|
|
65
|
+
const Xty = matmul(transpose(matX), y.map(yi => [yi]));
|
|
66
|
+
|
|
67
|
+
this.coefficients = solve(XtX, Xty).flat();
|
|
68
|
+
this.intercept = this.coefficients[0];
|
|
69
|
+
|
|
70
|
+
const yPred = X.map((row, i) => {
|
|
71
|
+
let pred = this.intercept;
|
|
72
|
+
for (let j = 0; j < p; j++) {
|
|
73
|
+
pred += this.coefficients[j + 1] * row[j];
|
|
74
|
+
}
|
|
75
|
+
return pred;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const meanY = y.reduce((a, b) => a + b, 0) / n;
|
|
79
|
+
let ssRes = 0, ssTot = 0;
|
|
80
|
+
|
|
81
|
+
for (let i = 0; i < n; i++) {
|
|
82
|
+
ssRes += (y[i] - yPred[i]) ** 2;
|
|
83
|
+
ssTot += (y[i] - meanY) ** 2;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.rSquared = 1 - ssRes / ssTot;
|
|
87
|
+
this.adjRSquared = 1 - (1 - this.rSquared) * (n - 1) / (n - p - 1);
|
|
88
|
+
this.rmse = Math.sqrt(ssRes / n);
|
|
89
|
+
this.predictions = yPred;
|
|
90
|
+
this.residuals = y.map((yi, i) => yi - yPred[i]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
predict(X) {
|
|
94
|
+
if (typeof X[0] === 'number') {
|
|
95
|
+
let pred = this.intercept;
|
|
96
|
+
for (let i = 0; i < X.length; i++) {
|
|
97
|
+
pred += this.coefficients[i + 1] * X[i];
|
|
98
|
+
}
|
|
99
|
+
return pred;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return X.map(row => {
|
|
103
|
+
let pred = this.intercept;
|
|
104
|
+
for (let i = 0; i < row.length; i++) {
|
|
105
|
+
pred += this.coefficients[i + 1] * row[i];
|
|
106
|
+
}
|
|
107
|
+
return pred;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function transpose(matrix) {
|
|
113
|
+
const result = [];
|
|
114
|
+
for (let j = 0; j < matrix[0].length; j++) {
|
|
115
|
+
result[j] = [];
|
|
116
|
+
for (let i = 0; i < matrix.length; i++) {
|
|
117
|
+
result[j].push(matrix[i][j]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function matmul(A, B) {
|
|
124
|
+
const result = [];
|
|
125
|
+
for (let i = 0; i < A.length; i++) {
|
|
126
|
+
result[i] = [];
|
|
127
|
+
for (let j = 0; j < B[0].length; j++) {
|
|
128
|
+
let sum = 0;
|
|
129
|
+
for (let k = 0; k < A[0].length; k++) {
|
|
130
|
+
sum += A[i][k] * B[k][j];
|
|
131
|
+
}
|
|
132
|
+
result[i][j] = sum;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function solve(A, b) {
|
|
139
|
+
const n = A.length;
|
|
140
|
+
const aug = A.map((row, i) => [...row, b[i][0]]);
|
|
141
|
+
|
|
142
|
+
for (let i = 0; i < n; i++) {
|
|
143
|
+
let maxRow = i;
|
|
144
|
+
for (let k = i + 1; k < n; k++) {
|
|
145
|
+
if (Math.abs(aug[k][i]) > Math.abs(aug[maxRow][i])) {
|
|
146
|
+
maxRow = k;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
[aug[i], aug[maxRow]] = [aug[maxRow], aug[i]];
|
|
151
|
+
|
|
152
|
+
for (let k = i + 1; k < n; k++) {
|
|
153
|
+
const factor = aug[k][i] / aug[i][i];
|
|
154
|
+
for (let j = i; j < n + 1; j++) {
|
|
155
|
+
aug[k][j] -= factor * aug[i][j];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const x = new Array(n);
|
|
161
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
162
|
+
x[i] = aug[i][n];
|
|
163
|
+
for (let j = i + 1; j < n; j++) {
|
|
164
|
+
x[i] -= aug[i][j] * x[j];
|
|
165
|
+
}
|
|
166
|
+
x[i] /= aug[i][i];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return x.map(xi => [xi]);
|
|
170
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export function bootstrap(r, data, n, statistic) {
|
|
2
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
3
|
+
throw new TypeError('data must be a non-empty array');
|
|
4
|
+
}
|
|
5
|
+
if (typeof n !== 'number' || n < 1) {
|
|
6
|
+
throw new RangeError('n must be a positive integer');
|
|
7
|
+
}
|
|
8
|
+
if (typeof statistic !== 'function') {
|
|
9
|
+
throw new TypeError('statistic must be a function');
|
|
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
|
+
return samples;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function jackknife(data, statistic) {
|
|
27
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
28
|
+
throw new TypeError('data must be a non-empty array');
|
|
29
|
+
}
|
|
30
|
+
if (typeof statistic !== 'function') {
|
|
31
|
+
throw new TypeError('statistic must be a function');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const n = data.length;
|
|
35
|
+
const samples = new Array(n);
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < n; i++) {
|
|
38
|
+
const subset = data.slice(0, i).concat(data.slice(i + 1));
|
|
39
|
+
samples[i] = statistic(subset);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return samples;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function crossValidation(r, data, k, trainFn, testFn) {
|
|
46
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
47
|
+
throw new TypeError('data must be a non-empty array');
|
|
48
|
+
}
|
|
49
|
+
if (typeof k !== 'number' || k < 2 || k !== Math.floor(k)) {
|
|
50
|
+
throw new RangeError('k must be an integer >= 2');
|
|
51
|
+
}
|
|
52
|
+
if (typeof trainFn !== 'function' || typeof testFn !== 'function') {
|
|
53
|
+
throw new TypeError('trainFn and testFn must be functions');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const n = data.length;
|
|
57
|
+
const foldSize = Math.floor(n / k);
|
|
58
|
+
const shuffled = [...data];
|
|
59
|
+
|
|
60
|
+
for (let i = n - 1; i > 0; i--) {
|
|
61
|
+
const j = r.nextInt(i + 1);
|
|
62
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const scores = new Array(k);
|
|
66
|
+
|
|
67
|
+
for (let fold = 0; fold < k; fold++) {
|
|
68
|
+
const start = fold * foldSize;
|
|
69
|
+
const end = fold === k - 1 ? n : (fold + 1) * foldSize;
|
|
70
|
+
|
|
71
|
+
const testSet = shuffled.slice(start, end);
|
|
72
|
+
const trainSet = shuffled.slice(0, start).concat(shuffled.slice(end));
|
|
73
|
+
|
|
74
|
+
const model = trainFn(trainSet);
|
|
75
|
+
scores[fold] = testFn(model, testSet);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return scores;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function permutationTest(r, data1, data2, testStatistic, n) {
|
|
82
|
+
if (!Array.isArray(data1) || !Array.isArray(data2)) {
|
|
83
|
+
throw new TypeError('data1 and data2 must be arrays');
|
|
84
|
+
}
|
|
85
|
+
if (typeof testStatistic !== 'function') {
|
|
86
|
+
throw new TypeError('testStatistic must be a function');
|
|
87
|
+
}
|
|
88
|
+
if (typeof n !== 'number' || n < 1) {
|
|
89
|
+
throw new RangeError('n must be a positive integer');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const observed = testStatistic(data1, data2);
|
|
93
|
+
const combined = [...data1, ...data2];
|
|
94
|
+
const n1 = data1.length;
|
|
95
|
+
let count = 0;
|
|
96
|
+
|
|
97
|
+
for (let i = 0; i < n; i++) {
|
|
98
|
+
for (let j = combined.length - 1; j > 0; j--) {
|
|
99
|
+
const k = r.nextInt(j + 1);
|
|
100
|
+
[combined[j], combined[k]] = [combined[k], combined[j]];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const perm1 = combined.slice(0, n1);
|
|
104
|
+
const perm2 = combined.slice(n1);
|
|
105
|
+
|
|
106
|
+
if (Math.abs(testStatistic(perm1, perm2)) >= Math.abs(observed)) {
|
|
107
|
+
count++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return count / n;
|
|
112
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
export function bisection(f, a, b, tol = 1e-6, maxIter = 100) {
|
|
2
|
+
if (typeof f !== 'function') {
|
|
3
|
+
throw new TypeError('f must be function');
|
|
4
|
+
}
|
|
5
|
+
if (typeof a !== 'number' || typeof b !== 'number') {
|
|
6
|
+
throw new TypeError('a and b must be numbers');
|
|
7
|
+
}
|
|
8
|
+
if (a >= b) {
|
|
9
|
+
throw new RangeError('a must be less than b');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const fa = f(a);
|
|
13
|
+
const fb = f(b);
|
|
14
|
+
|
|
15
|
+
if (fa * fb > 0) {
|
|
16
|
+
throw new RangeError('f(a) and f(b) must have opposite signs');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let c, fc;
|
|
20
|
+
for (let i = 0; i < maxIter; i++) {
|
|
21
|
+
c = (a + b) / 2;
|
|
22
|
+
fc = f(c);
|
|
23
|
+
|
|
24
|
+
if (Math.abs(fc) < tol || Math.abs(b - a) / 2 < tol) {
|
|
25
|
+
return { root: c, iterations: i + 1, residual: Math.abs(fc) };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (fa * fc < 0) {
|
|
29
|
+
b = c;
|
|
30
|
+
fb = fc;
|
|
31
|
+
} else {
|
|
32
|
+
a = c;
|
|
33
|
+
fa = fc;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { root: c, iterations: maxIter, residual: Math.abs(fc) };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function newtonRaphson(f, df, x0, tol = 1e-6, maxIter = 100) {
|
|
41
|
+
if (typeof f !== 'function' || typeof df !== 'function') {
|
|
42
|
+
throw new TypeError('f and df must be functions');
|
|
43
|
+
}
|
|
44
|
+
if (typeof x0 !== 'number') {
|
|
45
|
+
throw new TypeError('x0 must be number');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let x = x0;
|
|
49
|
+
for (let i = 0; i < maxIter; i++) {
|
|
50
|
+
const fx = f(x);
|
|
51
|
+
const dfx = df(x);
|
|
52
|
+
|
|
53
|
+
if (Math.abs(dfx) < 1e-14) {
|
|
54
|
+
throw new RangeError('derivative too close to zero');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const xNew = x - fx / dfx;
|
|
58
|
+
|
|
59
|
+
if (Math.abs(xNew - x) < tol) {
|
|
60
|
+
return { root: xNew, iterations: i + 1, residual: Math.abs(f(xNew)) };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
x = xNew;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { root: x, iterations: maxIter, residual: Math.abs(f(x)) };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function secant(f, x0, x1, tol = 1e-6, maxIter = 100) {
|
|
70
|
+
if (typeof f !== 'function') {
|
|
71
|
+
throw new TypeError('f must be function');
|
|
72
|
+
}
|
|
73
|
+
if (typeof x0 !== 'number' || typeof x1 !== 'number') {
|
|
74
|
+
throw new TypeError('x0 and x1 must be numbers');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let xPrev = x0;
|
|
78
|
+
let xCurr = x1;
|
|
79
|
+
let fPrev = f(xPrev);
|
|
80
|
+
let fCurr = f(xCurr);
|
|
81
|
+
|
|
82
|
+
for (let i = 0; i < maxIter; i++) {
|
|
83
|
+
if (Math.abs(fCurr - fPrev) < 1e-14) {
|
|
84
|
+
throw new RangeError('denominator too close to zero');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const xNext = xCurr - fCurr * (xCurr - xPrev) / (fCurr - fPrev);
|
|
88
|
+
|
|
89
|
+
if (Math.abs(xNext - xCurr) < tol) {
|
|
90
|
+
return { root: xNext, iterations: i + 1, residual: Math.abs(f(xNext)) };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
xPrev = xCurr;
|
|
94
|
+
xCurr = xNext;
|
|
95
|
+
fPrev = fCurr;
|
|
96
|
+
fCurr = f(xCurr);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return { root: xCurr, iterations: maxIter, residual: Math.abs(fCurr) };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function falsePosition(f, a, b, tol = 1e-6, maxIter = 100) {
|
|
103
|
+
if (typeof f !== 'function') {
|
|
104
|
+
throw new TypeError('f must be function');
|
|
105
|
+
}
|
|
106
|
+
if (typeof a !== 'number' || typeof b !== 'number') {
|
|
107
|
+
throw new TypeError('a and b must be numbers');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let fa = f(a);
|
|
111
|
+
let fb = f(b);
|
|
112
|
+
|
|
113
|
+
if (fa * fb > 0) {
|
|
114
|
+
throw new RangeError('f(a) and f(b) must have opposite signs');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < maxIter; i++) {
|
|
118
|
+
const c = a - (fa * (b - a)) / (fb - fa);
|
|
119
|
+
const fc = f(c);
|
|
120
|
+
|
|
121
|
+
if (Math.abs(fc) < tol) {
|
|
122
|
+
return { root: c, iterations: i + 1, residual: Math.abs(fc) };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (fa * fc < 0) {
|
|
126
|
+
b = c;
|
|
127
|
+
fb = fc;
|
|
128
|
+
} else {
|
|
129
|
+
a = c;
|
|
130
|
+
fa = fc;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const c = a - (fa * (b - a)) / (fb - fa);
|
|
135
|
+
return { root: c, iterations: maxIter, residual: Math.abs(f(c)) };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function fixedPoint(g, x0, tol = 1e-6, maxIter = 100) {
|
|
139
|
+
if (typeof g !== 'function') {
|
|
140
|
+
throw new TypeError('g must be function');
|
|
141
|
+
}
|
|
142
|
+
if (typeof x0 !== 'number') {
|
|
143
|
+
throw new TypeError('x0 must be number');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let x = x0;
|
|
147
|
+
for (let i = 0; i < maxIter; i++) {
|
|
148
|
+
const xNew = g(x);
|
|
149
|
+
|
|
150
|
+
if (Math.abs(xNew - x) < tol) {
|
|
151
|
+
return { root: xNew, iterations: i + 1, residual: Math.abs(xNew - x) };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
x = xNew;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { root: x, iterations: maxIter, residual: Math.abs(g(x) - x) };
|
|
158
|
+
}
|