redscript-mc 2.2.1 → 2.3.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 (43) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +18 -2
  3. package/dist/src/__tests__/tuner/engine.test.d.ts +4 -0
  4. package/dist/src/__tests__/tuner/engine.test.js +232 -0
  5. package/dist/src/tuner/adapters/ln-polynomial.d.ts +23 -0
  6. package/dist/src/tuner/adapters/ln-polynomial.js +142 -0
  7. package/dist/src/tuner/adapters/sqrt-newton.d.ts +28 -0
  8. package/dist/src/tuner/adapters/sqrt-newton.js +125 -0
  9. package/dist/src/tuner/cli.d.ts +5 -0
  10. package/dist/src/tuner/cli.js +168 -0
  11. package/dist/src/tuner/engine.d.ts +17 -0
  12. package/dist/src/tuner/engine.js +215 -0
  13. package/dist/src/tuner/metrics.d.ts +15 -0
  14. package/dist/src/tuner/metrics.js +51 -0
  15. package/dist/src/tuner/simulator.d.ts +35 -0
  16. package/dist/src/tuner/simulator.js +78 -0
  17. package/dist/src/tuner/types.d.ts +32 -0
  18. package/dist/src/tuner/types.js +6 -0
  19. package/docs/STDLIB_ROADMAP.md +142 -0
  20. package/editors/vscode/package-lock.json +3 -3
  21. package/editors/vscode/package.json +1 -1
  22. package/package.json +1 -1
  23. package/src/__tests__/tuner/engine.test.ts +260 -0
  24. package/src/stdlib/bigint.mcrs +155 -192
  25. package/src/stdlib/bits.mcrs +158 -0
  26. package/src/stdlib/color.mcrs +160 -0
  27. package/src/stdlib/geometry.mcrs +124 -0
  28. package/src/stdlib/list.mcrs +125 -0
  29. package/src/stdlib/math.mcrs +90 -0
  30. package/src/stdlib/math_hp.mcrs +65 -0
  31. package/src/stdlib/random.mcrs +67 -0
  32. package/src/stdlib/signal.mcrs +112 -0
  33. package/src/stdlib/vec.mcrs +27 -0
  34. package/src/tuner/adapters/ln-polynomial.ts +147 -0
  35. package/src/tuner/adapters/sqrt-newton.ts +135 -0
  36. package/src/tuner/cli.ts +158 -0
  37. package/src/tuner/engine.ts +272 -0
  38. package/src/tuner/metrics.ts +66 -0
  39. package/src/tuner/simulator.ts +69 -0
  40. package/src/tuner/types.ts +44 -0
  41. package/docs/ARCHITECTURE.zh.md +0 -1088
  42. package/docs/COMPILATION_STATS.md +0 -142
  43. package/docs/IMPLEMENTATION_GUIDE.md +0 -512
package/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  All notable changes to RedScript will be documented in this file.
4
4
 
5
+ ## [2.3.0] - 2026-03-17
6
+
7
+ ### Added
8
+ - `stdlib/math.mcrs`: `ln` (SA-tuned atanh series, max_error < 0.0006), `sqrt_fx` (×10000 scale), `exp_fx` (Horner Taylor + 2^k scaling)
9
+ - `stdlib/math_hp.mcrs`: `sin_hp`/`cos_hp` using MC entity rotation trick (double precision), `init_trig()` bootstrap
10
+ - `stdlib/random.mcrs`: LCG (`next_lcg`, `random_range`, `random_bool`) + PCG (`pcg_next_lo/hi`, `pcg_output`)
11
+ - `stdlib/color.mcrs`: RGB packing/unpacking, `rgb_lerp`, HSL↔RGB conversion (`hsl_to_r/g/b`, `rgb_to_h/s/l`)
12
+ - `stdlib/bits.mcrs`: bitwise AND/OR/XOR/NOT, left/right shift, bit get/set/clear/toggle, popcount (all integer-simulated)
13
+ - `stdlib/list.mcrs`: `sort3`, min/max/avg for 3 and 5 values, weighted choice utilities
14
+ - `stdlib/geometry.mcrs`: AABB/sphere/cylinder contains checks, parabola physics, grid/tile helpers, angle normalization, MC sun angle
15
+ - `stdlib/signal.mcrs`: uniform, normal (12-sample approximation), exponential distribution, bernoulli trial, weighted2/3 choice
16
+ - `stdlib/bigint.mcrs`: 96-bit base-10000 arithmetic (add, sub, mul, div, cmp, int32↔bigint3 conversion)
17
+ - `src/tuner/`: hyperparameter search framework (Nelder-Mead + Simulated Annealing) for stdlib coefficient optimization
18
+ - `adapters/ln-polynomial.ts`: atanh series adapter
19
+ - `adapters/sqrt-newton.ts`: Newton iteration adapter
20
+ - CLI: `redscript tune --adapter <name> [--strategy nm|sa] [--budget N] [--out path]`
21
+
22
+ ### Changed
23
+ - `stdlib/vec.mcrs`: added 2D/3D add/sub/scale/neg component helpers
24
+
5
25
  ## [2.1.1] - 2026-03-16
6
26
 
7
27
  ### Added
package/README.md CHANGED
@@ -306,8 +306,16 @@ redscript validate <file> Validate MC commands
306
306
  RedScript ships a built-in standard library. Use the short form — no path needed:
307
307
 
308
308
  ```rs
309
- import "stdlib/math" // fixed-point math
310
- import "stdlib/vec" // 2D/3D vector geometry
309
+ import "stdlib/math" // fixed-point math: ln, sqrt_fx, exp_fx, sin_fixed, cos_fixed...
310
+ import "stdlib/math_hp" // high-precision trig via entity rotation (init_trig required)
311
+ import "stdlib/vec" // 2D/3D vector: dot, cross, length, distance, atan2, rotate...
312
+ import "stdlib/random" // LCG & PCG random number generators
313
+ import "stdlib/color" // RGB/HSL color packing, blending, conversion
314
+ import "stdlib/bits" // bitwise AND/OR/XOR/NOT/shift/popcount (integer-simulated)
315
+ import "stdlib/list" // sort3, min/max/avg, weighted utilities
316
+ import "stdlib/geometry" // AABB/sphere contains, parabola physics, angle helpers
317
+ import "stdlib/signal" // normal/exponential distributions, bernoulli, weighted choice
318
+ import "stdlib/bigint" // 96-bit base-10000 arithmetic (add/sub/mul/div/cmp)
311
319
  import "stdlib/combat" // damage, kill-check helpers
312
320
  import "stdlib/player" // health, alive check, range
313
321
  import "stdlib/cooldown" // per-player cooldown tracking
@@ -319,6 +327,8 @@ Custom library paths can be added with `--include <dir>` so your own modules wor
319
327
 
320
328
  All stdlib files use `module library;` — only the functions you actually call are compiled in.
321
329
 
330
+ > Parts of the standard library are inspired by [kaer-3058/large_number](https://github.com/kaer-3058/large_number), a comprehensive math library for Minecraft datapacks.
331
+
322
332
  ```rs
323
333
  import "stdlib/math" // abs, sign, min, max, clamp, lerp, isqrt, sqrt_fixed,
324
334
  // pow_int, gcd, lcm, sin_fixed, cos_fixed, map, ceil_div,
@@ -444,6 +454,12 @@ See [CHANGELOG.md](./CHANGELOG.md) for the full release notes.
444
454
 
445
455
  ---
446
456
 
457
+ ## Acknowledgements
458
+
459
+ Parts of the standard library are inspired by [kaer-3058/large_number](https://github.com/kaer-3058/large_number), a comprehensive math library for Minecraft datapacks. RedScript provides a higher-level, type-safe API over similar algorithms.
460
+
461
+ ---
462
+
447
463
  <div align="center">
448
464
 
449
465
  MIT License · Copyright © 2026 [bkmashiro](https://github.com/bkmashiro)
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tests for the redscript tuner engine, simulator, and ln-polynomial adapter.
3
+ */
4
+ export {};
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for the redscript tuner engine, simulator, and ln-polynomial adapter.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const engine_1 = require("../../tuner/engine");
7
+ const simulator_1 = require("../../tuner/simulator");
8
+ const metrics_1 = require("../../tuner/metrics");
9
+ const ln_polynomial_1 = require("../../tuner/adapters/ln-polynomial");
10
+ const sqrt_newton_1 = require("../../tuner/adapters/sqrt-newton");
11
+ // ─── simulator tests ──────────────────────────────────────────────────────────
12
+ describe('simulator', () => {
13
+ test('i32 truncates to int32', () => {
14
+ expect((0, simulator_1.i32)(3.7)).toBe(3);
15
+ expect((0, simulator_1.i32)(-3.7)).toBe(-3);
16
+ expect((0, simulator_1.i32)(2147483648)).toBe(-2147483648); // overflow wraps
17
+ expect((0, simulator_1.i32)(0)).toBe(0);
18
+ });
19
+ test('fixedMul basic', () => {
20
+ // 10000 * 10000 / 10000 = 10000
21
+ expect((0, simulator_1.fixedMul)(10000, 10000, 10000)).toBe(10000);
22
+ // 5000 * 2 / 10000 = 1
23
+ expect((0, simulator_1.fixedMul)(5000, 2, 10000)).toBe(1);
24
+ });
25
+ test('fixedMul returns Infinity on overflow', () => {
26
+ expect((0, simulator_1.fixedMul)(2147483647, 2147483647, 1)).toBe(Infinity);
27
+ });
28
+ test('isOverflow detects out-of-range', () => {
29
+ expect((0, simulator_1.isOverflow)(2147483648)).toBe(true);
30
+ expect((0, simulator_1.isOverflow)(-2147483649)).toBe(true);
31
+ expect((0, simulator_1.isOverflow)(Infinity)).toBe(true);
32
+ expect((0, simulator_1.isOverflow)(NaN)).toBe(true);
33
+ expect((0, simulator_1.isOverflow)(0)).toBe(false);
34
+ expect((0, simulator_1.isOverflow)(2147483647)).toBe(false);
35
+ });
36
+ });
37
+ // ─── Nelder-Mead convergence test ────────────────────────────────────────────
38
+ describe('Nelder-Mead engine', () => {
39
+ test('converges to minimum of (x-3)^2', () => {
40
+ // Simple 1D minimization: minimize (x-3)^2
41
+ const mockAdapter = {
42
+ name: 'test-quadratic',
43
+ description: 'Minimize (x-3)^2',
44
+ params: [
45
+ { name: 'x', range: [-10, 10], integer: false },
46
+ ],
47
+ simulate(input, params) {
48
+ // Return the residual as a scaled integer
49
+ const x = params['x'];
50
+ return Math.round(x * 10000);
51
+ },
52
+ reference(_input) {
53
+ // Target: x = 3 → value 30000
54
+ return 30000;
55
+ },
56
+ sampleInputs() {
57
+ return [1]; // single input, target value is 3.0 (×10000 = 30000)
58
+ },
59
+ generateCode(params) {
60
+ return `// x = ${params['x']}`;
61
+ },
62
+ };
63
+ const result = (0, engine_1.search)(mockAdapter, 5000);
64
+ // Should converge close to x=3
65
+ expect(result.params['x']).toBeCloseTo(3.0, 1);
66
+ expect(result.maxError).toBeLessThan(0.1);
67
+ });
68
+ test('handles integer constraints', () => {
69
+ const mockAdapter = {
70
+ name: 'test-integer',
71
+ description: 'Integer parameter test',
72
+ params: [
73
+ { name: 'n', range: [0, 10], integer: true },
74
+ ],
75
+ simulate(input, params) {
76
+ // Should snap to integer 7
77
+ return Math.round(params['n'] * 10000);
78
+ },
79
+ reference(_input) {
80
+ return 70000; // 7.0 × 10000
81
+ },
82
+ sampleInputs() {
83
+ return [1];
84
+ },
85
+ generateCode() {
86
+ return '';
87
+ },
88
+ };
89
+ const result = (0, engine_1.search)(mockAdapter, 2000);
90
+ // Should find n close to 7
91
+ expect(Math.round(result.params['n'])).toBe(7);
92
+ });
93
+ test('i32 overflow penalization', () => {
94
+ const mockAdapter = {
95
+ name: 'test-overflow',
96
+ description: 'Test overflow penalization',
97
+ params: [
98
+ { name: 'scale', range: [1, 1000], integer: true },
99
+ ],
100
+ simulate(_input, params) {
101
+ // Always overflow for any scale >= 500
102
+ if (params['scale'] >= 500)
103
+ return Infinity;
104
+ return params['scale'] * 10000;
105
+ },
106
+ reference(_input) {
107
+ return 2000000; // target: scale=200 → 2000000
108
+ },
109
+ sampleInputs() {
110
+ return [1];
111
+ },
112
+ generateCode() {
113
+ return '';
114
+ },
115
+ };
116
+ const { maxError, mae, rmse } = (0, metrics_1.evaluate)(mockAdapter, { scale: 2147483647 });
117
+ expect(maxError).toBe(Infinity);
118
+ expect(mae).toBe(Infinity);
119
+ expect(rmse).toBe(Infinity);
120
+ });
121
+ });
122
+ // ─── ln-polynomial adapter tests ─────────────────────────────────────────────
123
+ describe('ln-polynomial adapter', () => {
124
+ const defaultParams = ln_polynomial_1.defaultParams; // { A1: 20000, A3: 6667, A5: 4000 }
125
+ test('sample inputs cover the valid range', () => {
126
+ const inputs = ln_polynomial_1.lnPolynomialAdapter.sampleInputs();
127
+ expect(inputs.length).toBeGreaterThan(50);
128
+ // All inputs should be positive
129
+ expect(inputs.every(x => x > 0)).toBe(true);
130
+ });
131
+ test('reference matches Math.log', () => {
132
+ const SCALE = 10000;
133
+ // ln(1.0) = 0
134
+ expect(ln_polynomial_1.lnPolynomialAdapter.reference(SCALE)).toBeCloseTo(0, 5);
135
+ // ln(2.0) ≈ 0.6931 → 6931
136
+ expect(ln_polynomial_1.lnPolynomialAdapter.reference(2 * SCALE)).toBeCloseTo(6931.47, 0);
137
+ // ln(0.5) ≈ -0.6931 → -6931
138
+ expect(ln_polynomial_1.lnPolynomialAdapter.reference(5000)).toBeCloseTo(-6931.47, 0);
139
+ });
140
+ test('simulate produces reasonable output for x=1 (no error)', () => {
141
+ const result = ln_polynomial_1.lnPolynomialAdapter.simulate(10000, defaultParams);
142
+ // ln(1.0) = 0; allow some approximation error
143
+ expect(Math.abs(result)).toBeLessThan(500); // within 0.05
144
+ });
145
+ test('simulate returns Infinity for invalid input', () => {
146
+ const result = ln_polynomial_1.lnPolynomialAdapter.simulate(0, defaultParams);
147
+ expect(result).toBeLessThan(0); // negative sentinel or -MAX_INT
148
+ });
149
+ test('max_error < 0.001 with default atanh coefficients', () => {
150
+ const metrics = (0, metrics_1.evaluate)(ln_polynomial_1.lnPolynomialAdapter, defaultParams);
151
+ expect(metrics.maxError).toBeLessThan(0.001);
152
+ }, 10000);
153
+ test('search improves over default params', () => {
154
+ // Run a short search and confirm it doesn't get worse
155
+ const baseMetrics = (0, metrics_1.evaluate)(ln_polynomial_1.lnPolynomialAdapter, defaultParams);
156
+ const result = (0, engine_1.search)(ln_polynomial_1.lnPolynomialAdapter, 500); // short budget for test speed
157
+ // Either same or better
158
+ expect(result.maxError).toBeLessThanOrEqual(baseMetrics.maxError * 2);
159
+ expect(result.maxError).toBeLessThan(0.01);
160
+ }, 30000);
161
+ test('generateCode produces valid output', () => {
162
+ const meta = {
163
+ maxError: 0.00003,
164
+ mae: 0.000012,
165
+ rmse: 0.000015,
166
+ estimatedCmds: 38,
167
+ tuneDate: '2026-03-17',
168
+ budgetUsed: 5000,
169
+ };
170
+ const code = ln_polynomial_1.lnPolynomialAdapter.generateCode(defaultParams, meta);
171
+ expect(code).toContain('AUTO-GENERATED');
172
+ expect(code).toContain('ln-polynomial');
173
+ expect(code).toContain('fn ln');
174
+ expect(code).toContain('A1');
175
+ expect(code).toContain('A3');
176
+ expect(code).toContain('A5');
177
+ expect(code).toContain('2026-03-17');
178
+ });
179
+ test('searchSA achieves max_error < 0.001 on ln-polynomial', () => {
180
+ const result = (0, engine_1.searchSA)(ln_polynomial_1.lnPolynomialAdapter, 3000);
181
+ expect(result.maxError).toBeLessThan(0.001);
182
+ }, 30000);
183
+ });
184
+ // ─── sqrt-newton adapter tests ────────────────────────────────────────────────
185
+ describe('sqrt-newton adapter', () => {
186
+ test('simulate(10000, defaultParams) ≈ 10000 (sqrt(1.0)=1.0)', () => {
187
+ const result = sqrt_newton_1.sqrtNewtonAdapter.simulate(10000, sqrt_newton_1.defaultParams);
188
+ // sqrt(1.0) * 10000 = 10000
189
+ expect(Math.abs(result - 10000)).toBeLessThan(10);
190
+ });
191
+ test('simulate(40000, defaultParams) ≈ 20000 (sqrt(4.0)=2.0)', () => {
192
+ const result = sqrt_newton_1.sqrtNewtonAdapter.simulate(40000, sqrt_newton_1.defaultParams);
193
+ // sqrt(4.0) * 10000 = 20000
194
+ expect(Math.abs(result - 20000)).toBeLessThan(10);
195
+ });
196
+ test('simulate(0) returns 0', () => {
197
+ expect(sqrt_newton_1.sqrtNewtonAdapter.simulate(0, sqrt_newton_1.defaultParams)).toBe(0);
198
+ expect(sqrt_newton_1.sqrtNewtonAdapter.simulate(-1, sqrt_newton_1.defaultParams)).toBe(0);
199
+ });
200
+ test('simulate(250000, defaultParams) ≈ 50000 (sqrt(25.0)=5.0)', () => {
201
+ const result = sqrt_newton_1.sqrtNewtonAdapter.simulate(250000, sqrt_newton_1.defaultParams);
202
+ expect(Math.abs(result - 50000)).toBeLessThan(10);
203
+ });
204
+ test('sample inputs are all positive', () => {
205
+ const inputs = sqrt_newton_1.sqrtNewtonAdapter.sampleInputs();
206
+ expect(inputs.length).toBeGreaterThan(50);
207
+ expect(inputs.every(x => x > 0)).toBe(true);
208
+ });
209
+ test('reference matches Math.sqrt', () => {
210
+ const SCALE = 10000;
211
+ expect(sqrt_newton_1.sqrtNewtonAdapter.reference(SCALE)).toBe(SCALE); // sqrt(1.0)
212
+ expect(sqrt_newton_1.sqrtNewtonAdapter.reference(4 * SCALE)).toBe(2 * SCALE); // sqrt(4.0)
213
+ expect(sqrt_newton_1.sqrtNewtonAdapter.reference(9 * SCALE)).toBe(3 * SCALE); // sqrt(9.0)
214
+ expect(sqrt_newton_1.sqrtNewtonAdapter.reference(0)).toBe(0);
215
+ });
216
+ test('generateCode contains fn sqrt_fx', () => {
217
+ const meta = {
218
+ maxError: 1.5,
219
+ mae: 0.5,
220
+ rmse: 0.8,
221
+ estimatedCmds: 30,
222
+ tuneDate: '2026-03-17',
223
+ budgetUsed: 3000,
224
+ };
225
+ const code = sqrt_newton_1.sqrtNewtonAdapter.generateCode(sqrt_newton_1.defaultParams, meta);
226
+ expect(code).toContain('AUTO-GENERATED');
227
+ expect(code).toContain('sqrt-newton');
228
+ expect(code).toContain('fn sqrt_fx');
229
+ expect(code).toContain('2026-03-17');
230
+ });
231
+ });
232
+ //# sourceMappingURL=engine.test.js.map
@@ -0,0 +1,23 @@
1
+ /**
2
+ * ln(x) polynomial approximation adapter — atanh series form.
3
+ *
4
+ * Algorithm:
5
+ * Input x: fixed-point integer (×10000), e.g. 10000 = 1.0
6
+ * 1. Range reduction: find k s.t. xr ∈ [10000, 20000)
7
+ * 2. s = (xr - 10000) * 10000 / (xr + 10000) → s ∈ [0, 3333]
8
+ * 3. ln(xr/10000) ≈ A1*s/SCALE + A3*s³/SCALE² + A5*s⁵/SCALE³
9
+ * (coefficients absorb the factor of 2; theoretical: A1=20000, A3=6667, A5=4000)
10
+ * 4. ln(x/10000) = k * LN2 + ln(xr/10000)
11
+ *
12
+ * Intermediate overflow analysis (s ≤ 3333, SCALE = 10000):
13
+ * s² = s*s ≤ 11M — fits int32 (max ~2.1B)
14
+ * s2 = s²/SCALE ≤ 1111
15
+ * s3 = s*s2 ≤ 3.7M — fits int32
16
+ * s5 = s3*s2 ≤ 4.1M — fits int32
17
+ * A1*s ≤ 22000*3333 ≤ 73M — fits int32
18
+ * A3*s3 ≤ 7000*3703 ≤ 26M — fits int32
19
+ * A5*s5 ≤ 5000*4115 ≤ 21M — fits int32
20
+ */
21
+ import { TunerAdapter } from '../types';
22
+ export declare const defaultParams: Record<string, number>;
23
+ export declare const lnPolynomialAdapter: TunerAdapter;
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * ln(x) polynomial approximation adapter — atanh series form.
4
+ *
5
+ * Algorithm:
6
+ * Input x: fixed-point integer (×10000), e.g. 10000 = 1.0
7
+ * 1. Range reduction: find k s.t. xr ∈ [10000, 20000)
8
+ * 2. s = (xr - 10000) * 10000 / (xr + 10000) → s ∈ [0, 3333]
9
+ * 3. ln(xr/10000) ≈ A1*s/SCALE + A3*s³/SCALE² + A5*s⁵/SCALE³
10
+ * (coefficients absorb the factor of 2; theoretical: A1=20000, A3=6667, A5=4000)
11
+ * 4. ln(x/10000) = k * LN2 + ln(xr/10000)
12
+ *
13
+ * Intermediate overflow analysis (s ≤ 3333, SCALE = 10000):
14
+ * s² = s*s ≤ 11M — fits int32 (max ~2.1B)
15
+ * s2 = s²/SCALE ≤ 1111
16
+ * s3 = s*s2 ≤ 3.7M — fits int32
17
+ * s5 = s3*s2 ≤ 4.1M — fits int32
18
+ * A1*s ≤ 22000*3333 ≤ 73M — fits int32
19
+ * A3*s3 ≤ 7000*3703 ≤ 26M — fits int32
20
+ * A5*s5 ≤ 5000*4115 ≤ 21M — fits int32
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.lnPolynomialAdapter = exports.defaultParams = void 0;
24
+ const simulator_1 = require("../simulator");
25
+ const SCALE = 10000;
26
+ const LN2_SCALED = 6931; // ln(2) * 10000
27
+ exports.defaultParams = {
28
+ A1: 20000,
29
+ A3: 6667,
30
+ A5: 4000,
31
+ };
32
+ exports.lnPolynomialAdapter = {
33
+ name: 'ln-polynomial',
34
+ description: 'ln(x) atanh series approximation using fixed-point int32 arithmetic',
35
+ params: [
36
+ { name: 'A1', range: [18000, 22000], integer: true },
37
+ { name: 'A3', range: [5000, 9000], integer: true },
38
+ { name: 'A5', range: [2000, 6000], integer: true },
39
+ ],
40
+ simulate(input, params) {
41
+ const A1 = (0, simulator_1.i32)(params['A1']);
42
+ const A3 = (0, simulator_1.i32)(params['A3']);
43
+ const A5 = (0, simulator_1.i32)(params['A5']);
44
+ let x = (0, simulator_1.i32)(input);
45
+ if (x <= 0)
46
+ return -2147483648;
47
+ // Step 1: range reduction to [10000, 20000)
48
+ let k = 0;
49
+ while (x < 10000) {
50
+ x = (0, simulator_1.i32)(x * 2);
51
+ k--;
52
+ }
53
+ while (x >= 20000) {
54
+ x = (0, simulator_1.i32)(x / 2);
55
+ k++;
56
+ }
57
+ // Step 2: s = (xr - SCALE) * SCALE / (xr + SCALE)
58
+ const num = (0, simulator_1.i32)((0, simulator_1.i32)(x - SCALE) * SCALE);
59
+ const den = (0, simulator_1.i32)(x + SCALE);
60
+ if (den === 0)
61
+ return Infinity;
62
+ const s = (0, simulator_1.i32)(num / den); // s ∈ [0, 3333]
63
+ // Step 3: atanh series (overflow-safe, each power divided by SCALE)
64
+ const s2 = (0, simulator_1.i32)((0, simulator_1.i32)(s * s) / SCALE); // s²/SCALE ∈ [0, 1111]
65
+ const s3 = (0, simulator_1.i32)((0, simulator_1.i32)(s * s2) / SCALE); // s³/SCALE² ∈ [0, 370]
66
+ const s5 = (0, simulator_1.i32)((0, simulator_1.i32)(s3 * s2) / SCALE); // s⁵/SCALE⁴ ∈ [0, 41]
67
+ const lnxr = (0, simulator_1.i32)((0, simulator_1.i32)(A1 * s / SCALE) +
68
+ (0, simulator_1.i32)(A3 * s3 / SCALE) +
69
+ (0, simulator_1.i32)(A5 * s5 / SCALE));
70
+ // Step 4: ln(x) = k*ln(2) + ln(xr)
71
+ return (0, simulator_1.i32)((0, simulator_1.i32)(k * LN2_SCALED) + lnxr);
72
+ },
73
+ reference(input) {
74
+ if (input <= 0)
75
+ return -Infinity;
76
+ return Math.log(input / SCALE) * SCALE;
77
+ },
78
+ sampleInputs() {
79
+ const inputs = [];
80
+ // logarithmic sampling from 0.01 to 100 (×10000: 100 to 1_000_000)
81
+ const logMin = Math.log10(100);
82
+ const logMax = Math.log10(1_000_000);
83
+ const steps = 200;
84
+ for (let i = 0; i <= steps; i++) {
85
+ const v = logMin + (i / steps) * (logMax - logMin);
86
+ inputs.push(Math.round(Math.pow(10, v)));
87
+ }
88
+ return inputs;
89
+ },
90
+ generateCode(params, meta) {
91
+ const A1 = Math.round(params['A1']);
92
+ const A3 = Math.round(params['A3']);
93
+ const A5 = Math.round(params['A5']);
94
+ return `// AUTO-GENERATED by redscript tune — DO NOT EDIT
95
+ // Adapter: ln-polynomial | Date: ${meta.tuneDate}
96
+ // max_error: ${meta.maxError.toFixed(6)} | mae: ${meta.mae.toFixed(6)} | estimated_cmds: ${meta.estimatedCmds}
97
+ // Run \`redscript tune --adapter ln-polynomial\` to regenerate
98
+ //
99
+ // atanh series coefficients (×10000 scale):
100
+ // A1 = ${A1} (theoretical 2×10000 = 20000)
101
+ // A3 = ${A3} (theoretical 2/3×10000 = 6667)
102
+ // A5 = ${A5} (theoretical 2/5×10000 = 4000)
103
+
104
+ fn ln(x: int): int {
105
+ // Input x: fixed-point ×10000; returns ln(x/10000)×10000
106
+ // Valid range: x ∈ [100, 1000000] (0.01 ~ 100.0)
107
+ // max_error: ${meta.maxError.toFixed(6)} (in ×10000 units, i.e. ${(meta.maxError / SCALE).toFixed(8)} in real units)
108
+
109
+ let scale: int = ${SCALE};
110
+ let ln2: int = ${LN2_SCALED};
111
+ let A1: int = ${A1};
112
+ let A3: int = ${A3};
113
+ let A5: int = ${A5};
114
+
115
+ // Step 1: range reduction — bring x into [scale, 2*scale)
116
+ let xr: int = x;
117
+ let k: int = 0;
118
+ while (xr < scale) {
119
+ xr = xr * 2;
120
+ k = k - 1;
121
+ }
122
+ while (xr >= scale * 2) {
123
+ xr = xr / 2;
124
+ k = k + 1;
125
+ }
126
+
127
+ // Step 2: s = (xr - scale) * scale / (xr + scale)
128
+ let s: int = (xr - scale) * scale / (xr + scale);
129
+
130
+ // Step 3: atanh series ln(xr/scale) ≈ A1*s + A3*s³ + A5*s⁵ (all /scale)
131
+ let s2: int = s * s / scale;
132
+ let s3: int = s * s2;
133
+ let s5: int = s3 * s2;
134
+ let lnxr: int = A1 * s / scale + A3 * s3 / scale + A5 * s5 / scale;
135
+
136
+ // Step 4: ln(x) = k*ln(2) + ln(xr/scale)
137
+ return k * ln2 + lnxr;
138
+ }
139
+ `;
140
+ },
141
+ };
142
+ //# sourceMappingURL=ln-polynomial.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * sqrt(x) Newton's method adapter — fixed-point ×10000 scale.
3
+ *
4
+ * Algorithm:
5
+ * Input x: fixed-point integer (×10000), e.g. 10000 = 1.0
6
+ * Target: return floor(sqrt(x/10000) * 10000)
7
+ *
8
+ * 1. If x <= 0, return 0
9
+ * 2. Initial guess: g = x >> INIT_SHIFT (default: x/2)
10
+ * 3. Newton iteration: g = (g + x * 10000 / g) / 2, repeated N times
11
+ * Overflow-safe: x * 10000 / g → (x * 100) / (g / 100)
12
+ * 4. Return g
13
+ *
14
+ * Valid range: x ∈ [1, 1_000_000] (real range 0.0001 to 100.0)
15
+ * Larger x needs more iterations; beyond 1M, convergence is not guaranteed
16
+ * within N=12 iterations from an x/2 initial guess.
17
+ *
18
+ * Overflow analysis (x ≤ 1_000_000, SCALE = 10000):
19
+ * x * 100 ≤ 100_000_000 — fits int32 (max ~2.1B) ✓
20
+ * g / 100 is never 0 for g ≥ 100 (guard included) ✓
21
+ *
22
+ * Parameters:
23
+ * N: iteration count, range [4, 12], integer
24
+ * INIT_SHIFT: initial guess right shift, range [0, 3], integer (1 → x/2)
25
+ */
26
+ import { TunerAdapter } from '../types';
27
+ export declare const defaultParams: Record<string, number>;
28
+ export declare const sqrtNewtonAdapter: TunerAdapter;
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * sqrt(x) Newton's method adapter — fixed-point ×10000 scale.
4
+ *
5
+ * Algorithm:
6
+ * Input x: fixed-point integer (×10000), e.g. 10000 = 1.0
7
+ * Target: return floor(sqrt(x/10000) * 10000)
8
+ *
9
+ * 1. If x <= 0, return 0
10
+ * 2. Initial guess: g = x >> INIT_SHIFT (default: x/2)
11
+ * 3. Newton iteration: g = (g + x * 10000 / g) / 2, repeated N times
12
+ * Overflow-safe: x * 10000 / g → (x * 100) / (g / 100)
13
+ * 4. Return g
14
+ *
15
+ * Valid range: x ∈ [1, 1_000_000] (real range 0.0001 to 100.0)
16
+ * Larger x needs more iterations; beyond 1M, convergence is not guaranteed
17
+ * within N=12 iterations from an x/2 initial guess.
18
+ *
19
+ * Overflow analysis (x ≤ 1_000_000, SCALE = 10000):
20
+ * x * 100 ≤ 100_000_000 — fits int32 (max ~2.1B) ✓
21
+ * g / 100 is never 0 for g ≥ 100 (guard included) ✓
22
+ *
23
+ * Parameters:
24
+ * N: iteration count, range [4, 12], integer
25
+ * INIT_SHIFT: initial guess right shift, range [0, 3], integer (1 → x/2)
26
+ */
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.sqrtNewtonAdapter = exports.defaultParams = void 0;
29
+ const simulator_1 = require("../simulator");
30
+ const SCALE = 10000;
31
+ exports.defaultParams = {
32
+ N: 8,
33
+ INIT_SHIFT: 1,
34
+ };
35
+ exports.sqrtNewtonAdapter = {
36
+ name: 'sqrt-newton',
37
+ description: 'sqrt(x) Newton iteration using fixed-point int32 arithmetic (×10000 scale)',
38
+ params: [
39
+ { name: 'N', range: [4, 12], integer: true },
40
+ { name: 'INIT_SHIFT', range: [0, 3], integer: true },
41
+ ],
42
+ simulate(input, params) {
43
+ const N = Math.round(params['N']);
44
+ const INIT_SHIFT = Math.round(params['INIT_SHIFT']);
45
+ let x = (0, simulator_1.i32)(input);
46
+ if (x <= 0)
47
+ return 0;
48
+ // Initial guess: x >> INIT_SHIFT
49
+ let g = (0, simulator_1.i32)(x >> INIT_SHIFT);
50
+ if (g <= 0)
51
+ g = 1; // guard against zero/negative guess
52
+ // Newton iterations: g = (g + x * 10000 / g) / 2
53
+ // Overflow-safe for x ≤ 1_000_000: split x*10000/g as (x*100)/(g/100)
54
+ for (let iter = 0; iter < N; iter++) {
55
+ const gDiv = (0, simulator_1.i32)(g / 100);
56
+ if (gDiv <= 0)
57
+ break; // guard: g is too small, stop
58
+ const xdivg = (0, simulator_1.i32)((0, simulator_1.i32)(x * 100) / gDiv); // ≈ x * 10000 / g
59
+ g = (0, simulator_1.i32)((0, simulator_1.i32)(g + xdivg) / 2);
60
+ if (g <= 0) {
61
+ g = 1;
62
+ break;
63
+ }
64
+ }
65
+ return g;
66
+ },
67
+ reference(input) {
68
+ if (input <= 0)
69
+ return 0;
70
+ return Math.floor(Math.sqrt(input / SCALE) * SCALE);
71
+ },
72
+ sampleInputs() {
73
+ const inputs = [];
74
+ // Logarithmic sampling from 0.01 to 100.0 (×10000: 100 to 1_000_000)
75
+ // Lower bound 100 avoids g/100=0 in overflow-safe Newton step.
76
+ const logMin = Math.log10(100);
77
+ const logMax = Math.log10(1_000_000);
78
+ const steps = 200;
79
+ for (let i = 0; i <= steps; i++) {
80
+ const v = logMin + (i / steps) * (logMax - logMin);
81
+ const x = Math.round(Math.pow(10, v));
82
+ inputs.push(x);
83
+ }
84
+ // Exact perfect squares (k=1..10 → x up to 100 * 10000 = 1_000_000)
85
+ for (let k = 1; k <= 10; k++) {
86
+ inputs.push(k * k * SCALE); // sqrt should be exactly k * SCALE
87
+ }
88
+ return inputs;
89
+ },
90
+ generateCode(params, meta) {
91
+ const N = Math.round(params['N']);
92
+ const INIT_SHIFT = Math.round(params['INIT_SHIFT']);
93
+ const iters = Array.from({ length: N }, (_, i) => ` g = (g + x * 100 / (g / 100)) / 2; // iteration ${i + 1}`).join('\n');
94
+ return `// AUTO-GENERATED by redscript tune — DO NOT EDIT
95
+ // Adapter: sqrt-newton | Date: ${meta.tuneDate}
96
+ // max_error: ${meta.maxError.toFixed(6)} | mae: ${meta.mae.toFixed(6)} | estimated_cmds: ${meta.estimatedCmds}
97
+ // Run \`redscript tune --adapter sqrt-newton\` to regenerate
98
+ //
99
+ // Parameters:
100
+ // N = ${N} (Newton iteration count)
101
+ // INIT_SHIFT = ${INIT_SHIFT} (initial guess = x >> ${INIT_SHIFT}, i.e. x / ${1 << INIT_SHIFT})
102
+
103
+ fn sqrt_fx(x: int): int {
104
+ // Input x: fixed-point ×10000, returns floor(sqrt(x/10000)*10000)
105
+ // Valid range: x ∈ [0, 1000000] (real range 0.0 to 100.0)
106
+ // max_error: ${meta.maxError.toFixed(6)} (in ×10000 units)
107
+ //
108
+ // Overflow-safe: x*10000/g computed as (x*100)/(g/100), valid for x ≤ 1_000_000
109
+
110
+ if (x <= 0) { return 0; }
111
+
112
+ // Initial guess: x / ${1 << INIT_SHIFT}
113
+ let g: int = x / ${1 << INIT_SHIFT};
114
+ if (g <= 0) { g = 1; }
115
+
116
+ // Newton iterations: g = (g + x * 10000 / g) / 2
117
+ // Split to avoid overflow: (x * 100) / (g / 100) ≈ x * 10000 / g
118
+ ${iters}
119
+
120
+ return g;
121
+ }
122
+ `;
123
+ },
124
+ };
125
+ //# sourceMappingURL=sqrt-newton.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * CLI entry point for `redscript tune`.
3
+ * Usage: redscript tune --adapter <name> [--budget N] [--out path]
4
+ */
5
+ export {};