@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.
Files changed (58) hide show
  1. package/README.md +9 -9
  2. package/example/src/App.css +89 -84
  3. package/example/src/App.jsx +375 -151
  4. package/package.json +7 -6
  5. package/src/core.browser.js +10 -2
  6. package/src/core.js +32 -4
  7. package/src/generators/logistic.js +30 -25
  8. package/src/generators/mixer.js +7 -7
  9. package/src/generators/mt19937.js +10 -7
  10. package/src/generators/pcg64.js +23 -12
  11. package/src/generators/splitmix64.js +12 -6
  12. package/src/generators/tent.js +12 -7
  13. package/src/generators/xorshift64.js +6 -3
  14. package/src/index.d.ts +68 -4
  15. package/src/index.js +154 -2
  16. package/src/rng.browser.js +21 -10
  17. package/src/rng.js +95 -82
  18. package/src/utils/arrays.js +149 -0
  19. package/src/utils/bits.js +146 -21
  20. package/src/utils/categorical.js +68 -31
  21. package/src/utils/combinatorics.js +113 -69
  22. package/src/utils/confidence.js +145 -0
  23. package/src/utils/decomposition.js +204 -0
  24. package/src/utils/distributions-advanced.js +122 -0
  25. package/src/utils/distributions-extra.js +102 -11
  26. package/src/utils/distributions-special.js +77 -20
  27. package/src/utils/distributions.js +99 -35
  28. package/src/utils/effects.js +172 -0
  29. package/src/utils/entropy.browser.js +29 -26
  30. package/src/utils/entropy.js +18 -8
  31. package/src/utils/helpers.js +64 -0
  32. package/src/utils/hypothesis.js +167 -0
  33. package/src/utils/integration.js +137 -0
  34. package/src/utils/interpolation.js +221 -0
  35. package/src/utils/matrix.js +242 -0
  36. package/src/utils/noise.js +36 -22
  37. package/src/utils/odesolvers.js +176 -0
  38. package/src/utils/optimization.js +215 -0
  39. package/src/utils/precomputed.js +166 -0
  40. package/src/utils/probability.js +199 -0
  41. package/src/utils/regression.js +170 -0
  42. package/src/utils/resampling.js +112 -0
  43. package/src/utils/rootfinding.js +158 -0
  44. package/src/utils/sampling.js +86 -77
  45. package/src/utils/seed.js +10 -4
  46. package/src/utils/seeding.js +24 -12
  47. package/src/utils/sequence.js +116 -32
  48. package/src/utils/state.js +48 -36
  49. package/src/utils/statistics.js +64 -2
  50. package/src/utils/stochastic.js +91 -31
  51. package/src/utils/stratified.js +108 -0
  52. package/src/utils/timeseries.js +166 -0
  53. package/src/utils/transforms.js +146 -0
  54. package/test/comprehensive-new.js +126 -0
  55. package/test/comprehensive.js +4 -3
  56. package/test/error-handling.js +49 -0
  57. package/test/new-features.js +52 -0
  58. package/IMPROVEMENTS.md +0 -58
@@ -0,0 +1,242 @@
1
+ export function matrixAdd(A, B) {
2
+ if (!Array.isArray(A) || !Array.isArray(B)) {
3
+ throw new TypeError('A and B must be matrices');
4
+ }
5
+ if (A.length !== B.length || A[0].length !== B[0].length) {
6
+ throw new RangeError('matrices must have same dimensions');
7
+ }
8
+
9
+ const result = new Array(A.length);
10
+ for (let i = 0; i < A.length; i++) {
11
+ result[i] = new Array(A[0].length);
12
+ for (let j = 0; j < A[0].length; j++) {
13
+ result[i][j] = A[i][j] + B[i][j];
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+
19
+ export function matrixSub(A, B) {
20
+ if (!Array.isArray(A) || !Array.isArray(B)) {
21
+ throw new TypeError('A and B must be matrices');
22
+ }
23
+ if (A.length !== B.length || A[0].length !== B[0].length) {
24
+ throw new RangeError('matrices must have same dimensions');
25
+ }
26
+
27
+ const result = new Array(A.length);
28
+ for (let i = 0; i < A.length; i++) {
29
+ result[i] = new Array(A[0].length);
30
+ for (let j = 0; j < A[0].length; j++) {
31
+ result[i][j] = A[i][j] - B[i][j];
32
+ }
33
+ }
34
+ return result;
35
+ }
36
+
37
+ export function matrixMul(A, B) {
38
+ if (!Array.isArray(A) || !Array.isArray(B)) {
39
+ throw new TypeError('A and B must be matrices');
40
+ }
41
+ if (A[0].length !== B.length) {
42
+ throw new RangeError('incompatible dimensions for multiplication');
43
+ }
44
+
45
+ const result = new Array(A.length);
46
+ for (let i = 0; i < A.length; i++) {
47
+ result[i] = new Array(B[0].length);
48
+ for (let j = 0; j < B[0].length; j++) {
49
+ let sum = 0;
50
+ for (let k = 0; k < B.length; k++) {
51
+ sum += A[i][k] * B[k][j];
52
+ }
53
+ result[i][j] = sum;
54
+ }
55
+ }
56
+ return result;
57
+ }
58
+
59
+ export function elementwiseMul(A, B) {
60
+ if (!Array.isArray(A) || !Array.isArray(B)) {
61
+ throw new TypeError('A and B must be matrices');
62
+ }
63
+ if (A.length !== B.length || A[0].length !== B[0].length) {
64
+ throw new RangeError('matrices must have same dimensions');
65
+ }
66
+
67
+ const result = new Array(A.length);
68
+ for (let i = 0; i < A.length; i++) {
69
+ result[i] = new Array(A[0].length);
70
+ for (let j = 0; j < A[0].length; j++) {
71
+ result[i][j] = A[i][j] * B[i][j];
72
+ }
73
+ }
74
+ return result;
75
+ }
76
+
77
+ export function scalarMul(scalar, A) {
78
+ if (typeof scalar !== 'number') {
79
+ throw new TypeError('scalar must be number');
80
+ }
81
+ if (!Array.isArray(A)) {
82
+ throw new TypeError('A must be matrix');
83
+ }
84
+
85
+ const result = new Array(A.length);
86
+ for (let i = 0; i < A.length; i++) {
87
+ result[i] = new Array(A[0].length);
88
+ for (let j = 0; j < A[0].length; j++) {
89
+ result[i][j] = scalar * A[i][j];
90
+ }
91
+ }
92
+ return result;
93
+ }
94
+
95
+ export function transpose(A) {
96
+ if (!Array.isArray(A) || A.length === 0) {
97
+ throw new TypeError('A must be non-empty matrix');
98
+ }
99
+
100
+ const result = new Array(A[0].length);
101
+ for (let j = 0; j < A[0].length; j++) {
102
+ result[j] = new Array(A.length);
103
+ for (let i = 0; i < A.length; i++) {
104
+ result[j][i] = A[i][j];
105
+ }
106
+ }
107
+ return result;
108
+ }
109
+
110
+ export function determinant(A) {
111
+ if (!Array.isArray(A) || A.length !== A[0].length) {
112
+ throw new TypeError('A must be square matrix');
113
+ }
114
+
115
+ const n = A.length;
116
+ if (n === 1) return A[0][0];
117
+ if (n === 2) return A[0][0] * A[1][1] - A[0][1] * A[1][0];
118
+
119
+ const M = A.map(row => [...row]);
120
+ let det = 1;
121
+
122
+ for (let i = 0; i < n; i++) {
123
+ let maxRow = i;
124
+ for (let k = i + 1; k < n; k++) {
125
+ if (Math.abs(M[k][i]) > Math.abs(M[maxRow][i])) {
126
+ maxRow = k;
127
+ }
128
+ }
129
+
130
+ if (Math.abs(M[maxRow][i]) < 1e-10) {
131
+ return 0;
132
+ }
133
+
134
+ if (maxRow !== i) {
135
+ [M[i], M[maxRow]] = [M[maxRow], M[i]];
136
+ det *= -1;
137
+ }
138
+
139
+ det *= M[i][i];
140
+
141
+ for (let k = i + 1; k < n; k++) {
142
+ const factor = M[k][i] / M[i][i];
143
+ for (let j = i; j < n; j++) {
144
+ M[k][j] -= factor * M[i][j];
145
+ }
146
+ }
147
+ }
148
+
149
+ return det;
150
+ }
151
+
152
+ export function trace(A) {
153
+ if (!Array.isArray(A) || A.length !== A[0].length) {
154
+ throw new TypeError('A must be square matrix');
155
+ }
156
+
157
+ let sum = 0;
158
+ for (let i = 0; i < A.length; i++) {
159
+ sum += A[i][i];
160
+ }
161
+ return sum;
162
+ }
163
+
164
+ export function norm(A, type = 'frobenius') {
165
+ if (!Array.isArray(A)) {
166
+ throw new TypeError('A must be matrix');
167
+ }
168
+
169
+ if (type === 'frobenius') {
170
+ let sum = 0;
171
+ for (let i = 0; i < A.length; i++) {
172
+ for (let j = 0; j < A[0].length; j++) {
173
+ sum += A[i][j] * A[i][j];
174
+ }
175
+ }
176
+ return Math.sqrt(sum);
177
+ }
178
+
179
+ if (type === 'spectral') {
180
+ let maxNorm = 0;
181
+ for (let j = 0; j < A[0].length; j++) {
182
+ let colSum = 0;
183
+ for (let i = 0; i < A.length; i++) {
184
+ colSum += Math.abs(A[i][j]);
185
+ }
186
+ maxNorm = Math.max(maxNorm, colSum);
187
+ }
188
+ return maxNorm;
189
+ }
190
+
191
+ throw new RangeError('unknown norm type');
192
+ }
193
+
194
+ export function inverse(A) {
195
+ if (!Array.isArray(A) || A.length !== A[0].length) {
196
+ throw new TypeError('A must be square matrix');
197
+ }
198
+
199
+ const n = A.length;
200
+ const aug = A.map((row, i) => {
201
+ const augRow = [...row];
202
+ for (let j = 0; j < n; j++) {
203
+ augRow.push(i === j ? 1 : 0);
204
+ }
205
+ return augRow;
206
+ });
207
+
208
+ for (let i = 0; i < n; i++) {
209
+ let maxRow = i;
210
+ for (let k = i + 1; k < n; k++) {
211
+ if (Math.abs(aug[k][i]) > Math.abs(aug[maxRow][i])) {
212
+ maxRow = k;
213
+ }
214
+ }
215
+
216
+ if (Math.abs(aug[maxRow][i]) < 1e-10) {
217
+ throw new RangeError('matrix is singular');
218
+ }
219
+
220
+ [aug[i], aug[maxRow]] = [aug[maxRow], aug[i]];
221
+
222
+ const pivot = aug[i][i];
223
+ for (let j = 0; j < 2 * n; j++) {
224
+ aug[i][j] /= pivot;
225
+ }
226
+
227
+ for (let k = 0; k < n; k++) {
228
+ if (k !== i) {
229
+ const factor = aug[k][i];
230
+ for (let j = 0; j < 2 * n; j++) {
231
+ aug[k][j] -= factor * aug[i][j];
232
+ }
233
+ }
234
+ }
235
+ }
236
+
237
+ const result = new Array(n);
238
+ for (let i = 0; i < n; i++) {
239
+ result[i] = aug[i].slice(n);
240
+ }
241
+ return result;
242
+ }
@@ -1,17 +1,13 @@
1
- const permutation = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,
2
- 140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,
3
- 247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,
4
- 57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,
5
- 74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,
6
- 60,211,133,230,206,39,323,234,35,158,234,144,12,234,165,
7
- 35,38,112,106,43,23,147,126,65,189,235,64,211,205,230,108,
8
- 248,191,227,21,205,45,94,2,32,284,239,210,246,24,97,78,
9
- 101,40,71,224,255,326,167,21,213,2,223,166,205,57,130,180,
10
- 51,108,203,190,57,74,76,88,207,208,239,170,251,67,77,51,
11
- 133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,41,
12
- 244,8,51,153,78,130,83,142,46,168,134,55,63,160,166,56,
13
- 172,85,24,254,192,221,100,495,32,163,244,236,37,46,28,141,
14
- 149,34,69,193,70,199,154,159,147,12,130,199,10,154,27,112];
1
+ const permutation = [
2
+ 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,
3
+ 247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,
4
+ 74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,206,39,223,202,148,35,158,236,156,67,126,65,
5
+ 189,238,72,108,248,191,227,21,205,45,94,2,32,230,239,210,246,24,97,78,101,40,71,224,255,200,167,21,213,2,223,166,
6
+ 205,57,130,180,51,108,203,190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,
7
+ 143,146,157,41,244,8,51,153,78,130,83,142,46,168,134,55,63,160,166,56,172,85,24,254,192,221,100,73,32,163,244,236,
8
+ 37,46,28,141,149,34,69,193,70,199,154,159,147,12,130,199,10,154,27,112,44,135,58,137,73,109,35,199,17,92,107,203,
9
+ 190,57,74,76,88,207,208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,41,51,51,51,51
10
+ ];
15
11
 
16
12
  const fade = (t) => t * t * t * (t * (t * 6 - 15) + 10);
17
13
  const lerp = (t, a, b) => a + t * (b - a);
@@ -23,12 +19,21 @@ const grad = (hash, x, y) => {
23
19
  };
24
20
 
25
21
  export const perlin2D = (rng, x, y, octaves = 1) => {
26
- let value = 0;
27
- let amplitude = 1;
28
- let frequency = 1;
29
- let maxValue = 0;
30
-
31
- for (let i = 0; i < octaves; i++) {
22
+ if (typeof x !== 'number' || typeof y !== 'number') {
23
+ throw new TypeError('x and y must be numbers');
24
+ }
25
+ if (typeof octaves !== 'number' || !Number.isInteger(octaves)) {
26
+ throw new TypeError('octaves must be an integer');
27
+ }
28
+ if (octaves <= 0) {
29
+ throw new RangeError('octaves must be positive');
30
+ }
31
+ let value = 0;
32
+ let amplitude = 1;
33
+ let frequency = 1;
34
+ let maxValue = 0;
35
+
36
+ for (let i = 0; i < octaves; i++) {
32
37
  const xi = Math.floor((x * frequency) % 256);
33
38
  const yi = Math.floor((y * frequency) % 256);
34
39
 
@@ -60,8 +65,17 @@ export const perlin2D = (rng, x, y, octaves = 1) => {
60
65
  };
61
66
 
62
67
  export const valueNoise = (rng, x, y, scale = 1) => {
63
- const sx = Math.floor(x * scale);
64
- const sy = Math.floor(y * scale);
68
+ if (typeof x !== 'number' || typeof y !== 'number') {
69
+ throw new TypeError('x and y must be numbers');
70
+ }
71
+ if (typeof scale !== 'number') {
72
+ throw new TypeError('scale must be a number');
73
+ }
74
+ if (scale <= 0) {
75
+ throw new RangeError('scale must be positive');
76
+ }
77
+ const sx = Math.floor(x * scale);
78
+ const sy = Math.floor(y * scale);
65
79
 
66
80
  const n00 = Math.sin(sx * 12.9898 + sy * 78.233) * 43758.5453;
67
81
  const n10 = Math.sin((sx + 1) * 12.9898 + sy * 78.233) * 43758.5453;
@@ -0,0 +1,176 @@
1
+ export function eulerMethod(dydt, y0, t0, tf, h) {
2
+ if (typeof dydt !== 'function') {
3
+ throw new TypeError('dydt must be function');
4
+ }
5
+ if (typeof y0 !== 'number' || typeof t0 !== 'number' || typeof tf !== 'number') {
6
+ throw new TypeError('y0, t0, tf must be numbers');
7
+ }
8
+ if (typeof h !== 'number' || h <= 0) {
9
+ throw new RangeError('step size h must be positive');
10
+ }
11
+
12
+ const t = [];
13
+ const y = [];
14
+ let tCurrent = t0;
15
+ let yCurrent = y0;
16
+
17
+ while (tCurrent <= tf) {
18
+ t.push(tCurrent);
19
+ y.push(yCurrent);
20
+ yCurrent += h * dydt(tCurrent, yCurrent);
21
+ tCurrent += h;
22
+ }
23
+
24
+ return { t, y };
25
+ }
26
+
27
+ export function rk4(dydt, y0, t0, tf, h) {
28
+ if (typeof dydt !== 'function') {
29
+ throw new TypeError('dydt must be function');
30
+ }
31
+ if (typeof y0 !== 'number' || typeof t0 !== 'number' || typeof tf !== 'number') {
32
+ throw new TypeError('y0, t0, tf must be numbers');
33
+ }
34
+ if (typeof h !== 'number' || h <= 0) {
35
+ throw new RangeError('step size h must be positive');
36
+ }
37
+
38
+ const t = [];
39
+ const y = [];
40
+ let tCurrent = t0;
41
+ let yCurrent = y0;
42
+
43
+ while (tCurrent <= tf) {
44
+ t.push(tCurrent);
45
+ y.push(yCurrent);
46
+
47
+ const k1 = dydt(tCurrent, yCurrent);
48
+ const k2 = dydt(tCurrent + h / 2, yCurrent + (h / 2) * k1);
49
+ const k3 = dydt(tCurrent + h / 2, yCurrent + (h / 2) * k2);
50
+ const k4 = dydt(tCurrent + h, yCurrent + h * k3);
51
+
52
+ yCurrent += (h / 6) * (k1 + 2 * k2 + 2 * k3 + k4);
53
+ tCurrent += h;
54
+ }
55
+
56
+ return { t, y };
57
+ }
58
+
59
+ export function systemEuler(dydt, y0, t0, tf, h) {
60
+ if (typeof dydt !== 'function') {
61
+ throw new TypeError('dydt must be function');
62
+ }
63
+ if (!Array.isArray(y0)) {
64
+ throw new TypeError('y0 must be array');
65
+ }
66
+ if (typeof t0 !== 'number' || typeof tf !== 'number') {
67
+ throw new TypeError('t0, tf must be numbers');
68
+ }
69
+ if (typeof h !== 'number' || h <= 0) {
70
+ throw new RangeError('step size h must be positive');
71
+ }
72
+
73
+ const t = [];
74
+ const y = [];
75
+ let tCurrent = t0;
76
+ let yCurrent = [...y0];
77
+
78
+ while (tCurrent <= tf) {
79
+ t.push(tCurrent);
80
+ y.push([...yCurrent]);
81
+
82
+ const dydt_val = dydt(tCurrent, yCurrent);
83
+ for (let i = 0; i < yCurrent.length; i++) {
84
+ yCurrent[i] += h * dydt_val[i];
85
+ }
86
+ tCurrent += h;
87
+ }
88
+
89
+ return { t, y };
90
+ }
91
+
92
+ export function systemRK4(dydt, y0, t0, tf, h) {
93
+ if (typeof dydt !== 'function') {
94
+ throw new TypeError('dydt must be function');
95
+ }
96
+ if (!Array.isArray(y0)) {
97
+ throw new TypeError('y0 must be array');
98
+ }
99
+ if (typeof t0 !== 'number' || typeof tf !== 'number') {
100
+ throw new TypeError('t0, tf must be numbers');
101
+ }
102
+ if (typeof h !== 'number' || h <= 0) {
103
+ throw new RangeError('step size h must be positive');
104
+ }
105
+
106
+ const t = [];
107
+ const y = [];
108
+ let tCurrent = t0;
109
+ let yCurrent = [...y0];
110
+
111
+ while (tCurrent <= tf) {
112
+ t.push(tCurrent);
113
+ y.push([...yCurrent]);
114
+
115
+ const k1 = dydt(tCurrent, yCurrent);
116
+ const y_k2 = yCurrent.map((yi, i) => yi + (h / 2) * k1[i]);
117
+ const k2 = dydt(tCurrent + h / 2, y_k2);
118
+ const y_k3 = yCurrent.map((yi, i) => yi + (h / 2) * k2[i]);
119
+ const k3 = dydt(tCurrent + h / 2, y_k3);
120
+ const y_k4 = yCurrent.map((yi, i) => yi + h * k3[i]);
121
+ const k4 = dydt(tCurrent + h, y_k4);
122
+
123
+ for (let i = 0; i < yCurrent.length; i++) {
124
+ yCurrent[i] += (h / 6) * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]);
125
+ }
126
+ tCurrent += h;
127
+ }
128
+
129
+ return { t, y };
130
+ }
131
+
132
+ export function rk45Adaptive(dydt, y0, t0, tf, tol = 1e-6, hmax = (tf - t0) / 10, hmin = 1e-8) {
133
+ if (typeof dydt !== 'function') {
134
+ throw new TypeError('dydt must be function');
135
+ }
136
+ if (typeof y0 !== 'number') {
137
+ throw new TypeError('y0 must be number');
138
+ }
139
+
140
+ const t = [t0];
141
+ const y = [y0];
142
+ let tCurrent = t0;
143
+ let yCurrent = y0;
144
+ let h = hmax;
145
+
146
+ while (tCurrent < tf) {
147
+ if (tCurrent + h > tf) {
148
+ h = tf - tCurrent;
149
+ }
150
+
151
+ const k1 = dydt(tCurrent, yCurrent);
152
+ const k2 = dydt(tCurrent + h / 4, yCurrent + (h / 4) * k1);
153
+ const k3 = dydt(tCurrent + 3 * h / 8, yCurrent + (3 * h / 32) * k1 + (9 * h / 32) * k2);
154
+ const k4 = dydt(tCurrent + 12 * h / 13, yCurrent + (1932 * h / 2197) * k1 - (7200 * h / 2197) * k2 + (7296 * h / 2197) * k3);
155
+ const k5 = dydt(tCurrent + h, yCurrent + (439 * h / 216) * k1 - 8 * h * k2 + (3680 * h / 513) * k3 - (845 * h / 4104) * k4);
156
+ const k6 = dydt(tCurrent + h / 2, yCurrent - (8 * h / 27) * k1 + 2 * h * k2 - (3544 * h / 2565) * k3 + (1859 * h / 4104) * k4 - (11 * h / 40) * k5);
157
+
158
+ const y4 = yCurrent + (25 * h / 216) * k1 + (1408 * h / 2565) * k3 + (2197 * h / 4104) * k4 - (h / 5) * k5;
159
+ const y5 = yCurrent + (16 * h / 135) * k1 + (6656 * h / 12825) * k3 + (28561 * h / 56430) * k4 - (9 * h / 50) * k5 + (2 * h / 55) * k6;
160
+
161
+ const error = Math.abs(y5 - y4);
162
+ const hNew = h * Math.pow(tol / error, 0.2);
163
+
164
+ if (error <= tol) {
165
+ tCurrent += h;
166
+ yCurrent = y5;
167
+ t.push(tCurrent);
168
+ y.push(yCurrent);
169
+ h = Math.min(Math.max(hNew, hmin), hmax);
170
+ } else {
171
+ h = Math.max(hNew, hmin);
172
+ }
173
+ }
174
+
175
+ return { t, y };
176
+ }
@@ -0,0 +1,215 @@
1
+ export function gradientDescent(f, df, x0, learningRate = 0.01, iterations = 100, tol = 1e-6) {
2
+ if (typeof f !== 'function' || typeof df !== 'function') {
3
+ throw new TypeError('f and df must be functions');
4
+ }
5
+ if (typeof x0 !== 'number') {
6
+ throw new TypeError('x0 must be number');
7
+ }
8
+
9
+ let x = x0;
10
+ const history = [x];
11
+
12
+ for (let i = 0; i < iterations; i++) {
13
+ const grad = df(x);
14
+ const xNew = x - learningRate * grad;
15
+
16
+ if (Math.abs(xNew - x) < tol) {
17
+ history.push(xNew);
18
+ return { x: xNew, iterations: i + 1, value: f(xNew), history };
19
+ }
20
+
21
+ x = xNew;
22
+ history.push(x);
23
+ }
24
+
25
+ return { x, iterations, value: f(x), history };
26
+ }
27
+
28
+ export function momentumDescent(f, df, x0, learningRate = 0.01, momentum = 0.9, iterations = 100, tol = 1e-6) {
29
+ if (typeof f !== 'function' || typeof df !== 'function') {
30
+ throw new TypeError('f and df must be functions');
31
+ }
32
+ if (typeof x0 !== 'number') {
33
+ throw new TypeError('x0 must be number');
34
+ }
35
+
36
+ let x = x0;
37
+ let velocity = 0;
38
+ const history = [x];
39
+
40
+ for (let i = 0; i < iterations; i++) {
41
+ const grad = df(x);
42
+ velocity = momentum * velocity + learningRate * grad;
43
+ const xNew = x - velocity;
44
+
45
+ if (Math.abs(xNew - x) < tol) {
46
+ history.push(xNew);
47
+ return { x: xNew, iterations: i + 1, value: f(xNew), history };
48
+ }
49
+
50
+ x = xNew;
51
+ history.push(x);
52
+ }
53
+
54
+ return { x, iterations, value: f(x), history };
55
+ }
56
+
57
+ export function adam(f, df, x0, learningRate = 0.001, iterations = 100, beta1 = 0.9, beta2 = 0.999, eps = 1e-8, tol = 1e-6) {
58
+ if (typeof f !== 'function' || typeof df !== 'function') {
59
+ throw new TypeError('f and df must be functions');
60
+ }
61
+ if (typeof x0 !== 'number') {
62
+ throw new TypeError('x0 must be number');
63
+ }
64
+
65
+ let x = x0;
66
+ let m = 0;
67
+ let v = 0;
68
+ const history = [x];
69
+
70
+ for (let t = 1; t <= iterations; t++) {
71
+ const grad = df(x);
72
+
73
+ m = beta1 * m + (1 - beta1) * grad;
74
+ v = beta2 * v + (1 - beta2) * grad * grad;
75
+
76
+ const mHat = m / (1 - Math.pow(beta1, t));
77
+ const vHat = v / (1 - Math.pow(beta2, t));
78
+
79
+ const xNew = x - learningRate * mHat / (Math.sqrt(vHat) + eps);
80
+
81
+ if (Math.abs(xNew - x) < tol) {
82
+ history.push(xNew);
83
+ return { x: xNew, iterations: t, value: f(xNew), history };
84
+ }
85
+
86
+ x = xNew;
87
+ history.push(x);
88
+ }
89
+
90
+ return { x, iterations, value: f(x), history };
91
+ }
92
+
93
+ export function simplex(f, vertices, maxIter = 1000, tol = 1e-6) {
94
+ if (typeof f !== 'function') {
95
+ throw new TypeError('f must be function');
96
+ }
97
+ if (!Array.isArray(vertices) || vertices.length < 2) {
98
+ throw new TypeError('vertices must be array of points');
99
+ }
100
+
101
+ const n = vertices[0].length;
102
+ let currentVertices = vertices.map(v => [...v]);
103
+
104
+ for (let iter = 0; iter < maxIter; iter++) {
105
+ const values = currentVertices.map(f);
106
+
107
+ const sorted = currentVertices.map((v, i) => [v, values[i]])
108
+ .sort((a, b) => a[1] - b[1]);
109
+
110
+ if (sorted[sorted.length - 1][1] - sorted[0][1] < tol) {
111
+ return { min: sorted[0][0], value: sorted[0][1], iterations: iter };
112
+ }
113
+
114
+ const best = sorted.slice(0, n).map(x => x[0]);
115
+ const worst = sorted[sorted.length - 1][0];
116
+
117
+ const centroid = new Array(n);
118
+ for (let i = 0; i < n; i++) {
119
+ centroid[i] = best.reduce((sum, v) => sum + v[i], 0) / n;
120
+ }
121
+
122
+ const reflected = centroid.map((x, i) => x + (x - worst[i]));
123
+ const reflectedValue = f(reflected);
124
+
125
+ if (reflectedValue < sorted[0][1]) {
126
+ currentVertices = [...best, reflected];
127
+ } else if (reflectedValue < sorted[n - 1][1]) {
128
+ currentVertices = [...best, reflected];
129
+ } else {
130
+ const contracted = centroid.map((x, i) => x + 0.5 * (worst[i] - x));
131
+ currentVertices = [...best, contracted];
132
+ }
133
+ }
134
+
135
+ const values = currentVertices.map(f);
136
+ const minIdx = values.indexOf(Math.min(...values));
137
+ return { min: currentVertices[minIdx], value: values[minIdx], iterations: maxIter };
138
+ }
139
+
140
+ export function brent(f, a, b, tol = 1e-6, maxIter = 100) {
141
+ if (typeof f !== 'function') {
142
+ throw new TypeError('f must be function');
143
+ }
144
+
145
+ let fa = f(a);
146
+ let fb = f(b);
147
+
148
+ if (fa * fb > 0) {
149
+ throw new RangeError('f(a) and f(b) must have opposite signs');
150
+ }
151
+
152
+ if (Math.abs(fa) < Math.abs(fb)) {
153
+ [a, b] = [b, a];
154
+ [fa, fb] = [fb, fa];
155
+ }
156
+
157
+ let c = a;
158
+ let fc = fa;
159
+ let d = b - a;
160
+ let e = d;
161
+
162
+ for (let i = 0; i < maxIter; i++) {
163
+ if (Math.abs(fc) < Math.abs(fb)) {
164
+ a = b;
165
+ b = c;
166
+ c = a;
167
+ fa = fb;
168
+ fb = fc;
169
+ fc = fa;
170
+ }
171
+
172
+ const tol1 = tol * Math.abs(b) + 1e-12;
173
+ const xm = 0.5 * (c - b);
174
+
175
+ if (Math.abs(xm) <= tol1 || Math.abs(fb) < 1e-14) {
176
+ return { root: b, iterations: i + 1, residual: Math.abs(fb) };
177
+ }
178
+
179
+ if (Math.abs(e) >= tol1 && Math.abs(fa) > Math.abs(fb)) {
180
+ let s = fb / fa;
181
+ let p, q;
182
+
183
+ if (Math.abs(a - c) < 1e-14) {
184
+ p = 2 * xm * s;
185
+ q = 1 - s;
186
+ } else {
187
+ q = fa / fc;
188
+ const r = fb / fc;
189
+ p = s * (2 * xm * q * (q - r) - (b - a) * (r - 1));
190
+ q = (q - 1) * (r - 1) * (s - 1);
191
+ }
192
+
193
+ if (p > 0) q = -q;
194
+ else p = -p;
195
+
196
+ if (2 * p < 3 * xm * q - Math.abs(tol1 * q) && p < Math.abs(0.5 * e * q)) {
197
+ e = d;
198
+ d = p / q;
199
+ } else {
200
+ d = xm;
201
+ e = d;
202
+ }
203
+ } else {
204
+ d = xm;
205
+ e = d;
206
+ }
207
+
208
+ a = b;
209
+ fa = fb;
210
+ b += Math.abs(d) > tol1 ? d : (xm > 0 ? tol1 : -tol1);
211
+ fb = f(b);
212
+ }
213
+
214
+ return { root: b, iterations: maxIter, residual: Math.abs(fb) };
215
+ }