monogate 0.1.0 → 0.2.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 +8 -1
- package/package.json +4 -4
- package/src/complex_eml.js +58 -43
- package/src/index.js +256 -12
package/README.md
CHANGED
|
@@ -18,10 +18,17 @@ Live explorer: **https://monogate.dev** (or your deployed URL)
|
|
|
18
18
|
|
|
19
19
|
## Install
|
|
20
20
|
|
|
21
|
+
**JavaScript / Node**
|
|
21
22
|
```bash
|
|
22
23
|
npm install monogate
|
|
23
24
|
```
|
|
24
25
|
|
|
26
|
+
**Python**
|
|
27
|
+
```bash
|
|
28
|
+
pip install monogate # core only (no dependencies)
|
|
29
|
+
pip install "monogate[torch]" # + PyTorch differentiable ops + EMLTree / EMLNetwork
|
|
30
|
+
```
|
|
31
|
+
|
|
25
32
|
## Usage
|
|
26
33
|
|
|
27
34
|
```js
|
|
@@ -79,7 +86,7 @@ These functions have no known EML construction:
|
|
|
79
86
|
- **sin x** — no construction found
|
|
80
87
|
- **cos x** — no construction found
|
|
81
88
|
- **π** — no construction as a closed EML expression
|
|
82
|
-
- **i** (√−1) —
|
|
89
|
+
- **i** (√−1) — open under strict principal-branch grammar. Under the extended-reals convention (`ln(0) = −∞`), i is constructible from `{1}` alone in K=75 nodes ([pveierland/eml-eval](https://github.com/pveierland/eml-eval)). These are different grammars, not contradictory results.
|
|
83
90
|
|
|
84
91
|
Pull requests welcome. If you crack one, open an issue — it's publishable.
|
|
85
92
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monogate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A single binary operator eml(x,y) = exp(x) − ln(y) that generates all elementary functions. Implementation of arXiv:2603.21852 (Odrzywołek, 2026).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
27
|
-
"url": "https://github.com/
|
|
27
|
+
"url": "https://github.com/almaguer1986/monogate.git"
|
|
28
28
|
},
|
|
29
|
-
"homepage": "https://monogate
|
|
29
|
+
"homepage": "https://github.com/almaguer1986/monogate",
|
|
30
30
|
"bugs": {
|
|
31
|
-
"url": "https://github.com/
|
|
31
|
+
"url": "https://github.com/almaguer1986/monogate/issues"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=16"
|
package/src/complex_eml.js
CHANGED
|
@@ -11,18 +11,24 @@
|
|
|
11
11
|
* ── Key results ──────────────────────────────────────────────────────────────
|
|
12
12
|
*
|
|
13
13
|
* ONE-TERMINAL RESULT (proven):
|
|
14
|
-
* S → 1 | eml_c(S,S) constructs −iπ in
|
|
14
|
+
* S → 1 | eml_c(S,S) constructs −iπ in 11 nodes, depth 8.
|
|
15
15
|
* This is the first non-real value reachable from a single real terminal.
|
|
16
16
|
*
|
|
17
17
|
* TWO-TERMINAL RESULT (proven):
|
|
18
18
|
* S → 1 | 2 | eml_c(S,S) constructs i, π, and Euler's formula
|
|
19
19
|
* exp(ix) = cos(x) + i·sin(x) as a single EML expression.
|
|
20
20
|
*
|
|
21
|
-
* OPEN PROBLEM:
|
|
22
|
-
* Does S → 1 | eml_c(S,S) generate i?
|
|
21
|
+
* OPEN PROBLEM (strict principal-branch grammar):
|
|
22
|
+
* Does S → 1 | eml_c(S,S) generate i, where ln_c(0) is undefined?
|
|
23
23
|
* Equivalently: is there a finite EML tree over terminal {1} that evaluates
|
|
24
|
-
* to 0 + 1·i
|
|
25
|
-
*
|
|
24
|
+
* to 0 + 1·i without passing 0 through ln_c at any intermediate node?
|
|
25
|
+
*
|
|
26
|
+
* Note: Under the extended-reals convention (ln(0) = −∞, as in the original
|
|
27
|
+
* paper and pveierland/eml-eval), i IS constructible from {1} alone in
|
|
28
|
+
* K=75 nodes, depth=19, via exp(ln(−1)/2) where 2 = add(1,1).
|
|
29
|
+
* The two results are not contradictory — they characterize different grammars.
|
|
30
|
+
* This library uses strict principal-branch ln; whether i is reachable under
|
|
31
|
+
* that convention remains open.
|
|
26
32
|
*
|
|
27
33
|
* SIN / COS LIMITATION:
|
|
28
34
|
* sin(x) = Im(eul_c(x)) and cos(x) = Re(eul_c(x)).
|
|
@@ -239,51 +245,60 @@ export const pow_c = (x, n) => op_c(mul_c(_wrap(n), ln_c(_wrap(x))), one);
|
|
|
239
245
|
// a NEGATIVE REAL reaches the y-position, causing ln_c to apply its
|
|
240
246
|
// principal branch and return a value with imaginary part ±π.
|
|
241
247
|
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
246
|
-
//
|
|
248
|
+
// 11-NODE CONSTRUCTION (current best, pure one-terminal tree):
|
|
249
|
+
//
|
|
250
|
+
// eml(1, eml(eml(1, eml(eml(eml(eml(1,eml(1,1)),1),1),1)), eml(eml(eml(1,1),1),1)))
|
|
251
|
+
//
|
|
252
|
+
// Step 1: tower = eml(eml(eml(eml(1,eml(1,1)),1),1),1)
|
|
253
|
+
// Starting from e = eml(1,1):
|
|
254
|
+
// eml(1,e) = e−1 → eml(e−1,1) = exp(e−1) → eml(...,1) = exp(exp(e−1))
|
|
255
|
+
// → eml(...,1) = exp(exp(exp(e−1))) [≈ 3.45×10¹¹⁴]
|
|
247
256
|
//
|
|
248
|
-
// Step
|
|
249
|
-
//
|
|
250
|
-
// = e − iπ [principal branch: arg(−1) = π]
|
|
251
|
-
// Nodes: 10 Depth: 6
|
|
257
|
+
// Step 2: A = eml(1, tower) = e − ln(tower) ≈ e − exp(exp(e−1)) < 0
|
|
258
|
+
// (A is a large negative real)
|
|
252
259
|
//
|
|
253
|
-
// Step
|
|
254
|
-
// = exp_c(e − iπ) − 0
|
|
255
|
-
// = exp(e) · exp(−iπ)
|
|
256
|
-
// = −exp(e) [real, negative → second branch-cut trigger]
|
|
257
|
-
// Nodes: 11 Depth: 7
|
|
260
|
+
// Step 3: B = eml(eml(eml(1,1),1),1) = exp(exp(e)) [≈ 3.81×10⁶]
|
|
258
261
|
//
|
|
259
|
-
// Step
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
// = −iπ [exact, one-terminal result]
|
|
263
|
-
// Nodes: 12 Depth: 8
|
|
262
|
+
// Step 4: mid = eml(A, B) = exp_c(A) − ln_c(B)
|
|
263
|
+
// exp(A) ≈ 0 (A ≪ 0), ln(exp(exp(e))) = exp(e) = e^e
|
|
264
|
+
// mid ≈ −e^e [real, negative → branch-cut trigger]
|
|
264
265
|
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
// Both ±iπ are mathematically valid; code must not assume a sign.
|
|
269
|
-
// Assertion: abs(NEG_I_PI_C.re) < 1e-10 AND abs(|NEG_I_PI_C.im| − π) < 1e-10
|
|
266
|
+
// Step 5: result = eml(1, mid) = e − ln_c(−e^e)
|
|
267
|
+
// = e − (ln(e^e) + iπ) = e − (e + iπ) = −iπ ✓
|
|
268
|
+
// Nodes: 11 Depth: 8
|
|
270
269
|
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
270
|
+
// ADVANTAGE OVER PRIOR 12-NODE CONSTRUCTION:
|
|
271
|
+
// The 12-node construction (via neg_real(1) = −1) produces z₂ = −exp(e)
|
|
272
|
+
// with a floating-point imaginary part ≈ −1.22e−16, causing atan2 to return
|
|
273
|
+
// −π instead of +π and yielding +iπ rather than −iπ in floating-point.
|
|
274
|
+
// The 11-node construction avoids this: A is a large negative real with
|
|
275
|
+
// zero imaginary part, so −e^e is cleanly negative and ln_c gives exactly
|
|
276
|
+
// e + iπ with no sign ambiguity.
|
|
277
|
+
//
|
|
278
|
+
// Assertion: abs(NEG_I_PI_C.re) < 1e-10 AND NEG_I_PI_C.im < 0
|
|
279
|
+
// (imaginary part is reliably negative with this construction)
|
|
274
280
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
275
281
|
|
|
276
|
-
const _neg_real_one = Complex.of(neg_real(1)); // = −1 via real EML grammar
|
|
277
|
-
|
|
278
282
|
/**
|
|
279
|
-
* −iπ
|
|
283
|
+
* −iπ — first complex constant reachable from terminal {1} alone.
|
|
280
284
|
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
285
|
+
* Pure one-terminal construction: S → 1 | eml_c(S,S), nodes=11, depth=8.
|
|
286
|
+
* Expression: eml(1,eml(eml(1,eml(eml(eml(eml(1,eml(1,1)),1),1),1)),eml(eml(eml(1,1),1),1)))
|
|
283
287
|
*
|
|
284
|
-
* Verified: |Re| < 1e-10,
|
|
288
|
+
* Verified: |Re| < 1e-10, Im ≈ −π (sign is reliable, unlike the 12-node construction)
|
|
285
289
|
*/
|
|
286
|
-
|
|
290
|
+
// Build from inside out (see ESCAPE comment above)
|
|
291
|
+
const _e = op_c(one, one); // eml(1,1) = e
|
|
292
|
+
const _em1 = op_c(one, _e); // eml(1,e) = e−1
|
|
293
|
+
const _t1 = op_c(_em1, one); // eml(e−1,1) = exp(e−1)
|
|
294
|
+
const _t2 = op_c(_t1, one); // eml(...,1) = exp(exp(e−1))
|
|
295
|
+
const _tower = op_c(_t2, one); // eml(...,1) = exp(exp(exp(e−1))) [huge]
|
|
296
|
+
const _neg_br = op_c(one, _tower); // eml(1,tower) < 0 [negative real]
|
|
297
|
+
const _ee = op_c(one, one); // eml(1,1) = e (independent subtree)
|
|
298
|
+
const _exp_e = op_c(_ee, one); // eml(e,1) = exp(e)
|
|
299
|
+
const _exp_ee = op_c(_exp_e, one); // eml(exp(e),1) = exp(exp(e))
|
|
300
|
+
const _mid = op_c(_neg_br, _exp_ee); // eml(neg,B) ≈ −exp(e) [branch-cut trigger]
|
|
301
|
+
export const NEG_I_PI_C = op_c(one, _mid); // eml(1,−e^e) = −iπ
|
|
287
302
|
|
|
288
303
|
/**
|
|
289
304
|
* ±iπ/2 — half of NEG_I_PI_C, used to construct i.
|
|
@@ -493,13 +508,13 @@ export const IDENTITIES_C = [
|
|
|
493
508
|
},
|
|
494
509
|
{
|
|
495
510
|
name: "−iπ",
|
|
496
|
-
emlForm: "
|
|
497
|
-
nodes:
|
|
511
|
+
emlForm: "eml(1,eml(eml(1,eml(eml(eml(eml(1,eml(1,1)),1),1),1)),eml(eml(eml(1,1),1),1)))",
|
|
512
|
+
nodes: 11, depth: 8,
|
|
498
513
|
domain: "constant",
|
|
499
|
-
branchCut: "branch cut at
|
|
514
|
+
branchCut: "branch cut at mid = −exp(e); Im is reliably −π (no float sign ambiguity)",
|
|
500
515
|
terminal: "{1}",
|
|
501
516
|
status: "proven",
|
|
502
|
-
note: "First non-real value constructible from a single real terminal",
|
|
517
|
+
note: "First non-real value constructible from a single real terminal (improved from 12 nodes)",
|
|
503
518
|
},
|
|
504
519
|
{
|
|
505
520
|
name: "i",
|
package/src/index.js
CHANGED
|
@@ -149,21 +149,265 @@ export const pow = (x, n) => op(mul(n, ln(x)), 1);
|
|
|
149
149
|
*/
|
|
150
150
|
export const recip = (x) => op(neg(ln(x)), 1);
|
|
151
151
|
|
|
152
|
+
// ─── EDL operator ─────────────────────────────────────────────────────────────
|
|
153
|
+
//
|
|
154
|
+
// edl(x, y) = exp(x) / ln(y)
|
|
155
|
+
// Natural constant: Math.E (ln(e) = 1 → edl(x,e) = exp(x))
|
|
156
|
+
// Domain: y > 0, y ≠ 1 (ln(1) = 0 causes division by zero)
|
|
157
|
+
// EDL and EML are the two known complete operator families.
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The EDL operator: edl(x, y) = exp(x) / ln(y)
|
|
161
|
+
*
|
|
162
|
+
* @param {number} x
|
|
163
|
+
* @param {number} y must be > 0 and ≠ 1
|
|
164
|
+
* @returns {number}
|
|
165
|
+
*/
|
|
166
|
+
export const edl = (x, y) => Math.exp(x) / Math.log(y);
|
|
167
|
+
|
|
168
|
+
/** EDL natural constant: e (ln(e)=1 → edl(x,e)=exp(x)) */
|
|
169
|
+
export const EDL_E = Math.E;
|
|
170
|
+
|
|
171
|
+
// EDL exp: edl(x, e) = exp(x) / ln(e) = exp(x)
|
|
172
|
+
const _exp_edl = (x) => edl(x, EDL_E);
|
|
173
|
+
|
|
174
|
+
// EDL ln: edl(0, edl(edl(0,x), e)) — 3-node tree
|
|
175
|
+
// step 1: edl(0, x) = 1/ln(x)
|
|
176
|
+
// step 2: edl(s, e) = exp(1/ln(x))
|
|
177
|
+
// step 3: edl(0, t) = 1/(1/ln(x)) = ln(x) ✓
|
|
178
|
+
// Dead zone: x near 1 causes step 2 to overflow (ln(x) → 0)
|
|
179
|
+
const _ln_edl = (x) => edl(0, edl(edl(0, x), EDL_E));
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* x / y — EDL's natural 1-node operation: edl(ln(x), exp(y))
|
|
183
|
+
* Proof: exp(ln(x)) / ln(exp(y)) = x / y ∎
|
|
184
|
+
* Nodes: 1 (vs EML's 15) Domain: x > 0, y ≠ 0
|
|
185
|
+
*
|
|
186
|
+
* @param {number} x must be > 0
|
|
187
|
+
* @param {number} y must be ≠ 0
|
|
188
|
+
* @returns {number}
|
|
189
|
+
*/
|
|
190
|
+
export const div_edl = (x, y) => edl(_ln_edl(x), _exp_edl(y));
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 1/x — 2-node EDL tree: edl(0, edl(x, e))
|
|
194
|
+
* Proof: edl(x,e)=exp(x); edl(0,exp(x))=1/ln(exp(x))=1/x ∎
|
|
195
|
+
* Nodes: 2 (vs EML's 5) Domain: x ≠ 0
|
|
196
|
+
*
|
|
197
|
+
* @param {number} x must be ≠ 0
|
|
198
|
+
* @returns {number}
|
|
199
|
+
*/
|
|
200
|
+
export const recip_edl = (x) => edl(0, edl(x, EDL_E));
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* −x — 6-node EDL tree via ln(1/e) = −1
|
|
204
|
+
* Proof: edl(ln(x), 1/e) = x / ln(1/e) = x / (−1) = −x ∎
|
|
205
|
+
* Nodes: 6 (vs EML's 9)
|
|
206
|
+
*
|
|
207
|
+
* @param {number} x
|
|
208
|
+
* @returns {number}
|
|
209
|
+
*/
|
|
210
|
+
export const neg_edl = (x) => {
|
|
211
|
+
const recip_e = edl(0, edl(EDL_E, EDL_E)); // 1/e (2 nodes)
|
|
212
|
+
return edl(_ln_edl(x), recip_e); // edl(ln(x), 1/e) = −x
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* x × y — 7-node EDL tree: div_edl(x, recip_edl(y))
|
|
217
|
+
* Route: x * y = x / (1/y)
|
|
218
|
+
* Nodes: 7 (vs EML's 13) Domain: x > 0, y ≠ 0
|
|
219
|
+
*
|
|
220
|
+
* @param {number} x must be > 0
|
|
221
|
+
* @param {number} y must be ≠ 0
|
|
222
|
+
* @returns {number}
|
|
223
|
+
*/
|
|
224
|
+
export const mul_edl = (x, y) => div_edl(x, recip_edl(y));
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* xⁿ — 11-node EDL tree: edl(mul_edl(n, ln_edl(x)), e)
|
|
228
|
+
* Route: exp(n·ln(x)) via EDL mul and ln
|
|
229
|
+
* Nodes: 11 (vs EML's 15) Domain: x > 0, x ≠ 1
|
|
230
|
+
*
|
|
231
|
+
* @param {number} x must be > 0 and ≠ 1
|
|
232
|
+
* @param {number} n
|
|
233
|
+
* @returns {number}
|
|
234
|
+
*/
|
|
235
|
+
export const pow_edl = (x, n) => _exp_edl(mul_edl(n, _ln_edl(x)));
|
|
236
|
+
|
|
237
|
+
// ─── EXL operator ─────────────────────────────────────────────────────────────
|
|
238
|
+
//
|
|
239
|
+
// exl(x, y) = exp(x) * ln(y)
|
|
240
|
+
// Natural constant: Math.E (ln(e) = 1 → exl(x,e) = exp(x))
|
|
241
|
+
// INCOMPLETE: no finite EXL formula for addition or general subtraction.
|
|
242
|
+
// Best-in-class for: ln (1 node), pow (3 nodes).
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The EXL operator: exl(x, y) = exp(x) * ln(y)
|
|
246
|
+
*
|
|
247
|
+
* @param {number} x
|
|
248
|
+
* @param {number} y must be > 0 (argument of ln)
|
|
249
|
+
* @returns {number}
|
|
250
|
+
*/
|
|
251
|
+
export const exl = (x, y) => Math.exp(x) * Math.log(y);
|
|
252
|
+
|
|
253
|
+
/** EXL natural constant: e */
|
|
254
|
+
export const EXL_E = Math.E;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* ln(x) — 1-node EXL tree: exl(0, x)
|
|
258
|
+
* Proof: exp(0) * ln(x) = ln(x) ∎
|
|
259
|
+
* Nodes: 1 (vs EML/EDL's 3) Domain: x > 0
|
|
260
|
+
*
|
|
261
|
+
* @param {number} x must be > 0
|
|
262
|
+
* @returns {number}
|
|
263
|
+
*/
|
|
264
|
+
export const ln_exl = (x) => exl(0, x);
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* xⁿ — 3-node EXL tree: exl(exl(exl(0, n), x), e)
|
|
268
|
+
* Proof:
|
|
269
|
+
* step 1: exl(0, n) = ln(n)
|
|
270
|
+
* step 2: exl(ln(n), x) = exp(ln(n)) * ln(x) = n·ln(x)
|
|
271
|
+
* step 3: exl(n·ln(x), e) = exp(n·ln(x)) * 1 = xⁿ ∎
|
|
272
|
+
* Nodes: 3 (vs EML's 15, EDL's 11) Domain: x > 0, n > 0
|
|
273
|
+
*
|
|
274
|
+
* @param {number} x must be > 0
|
|
275
|
+
* @param {number} n must be > 0
|
|
276
|
+
* @returns {number}
|
|
277
|
+
*/
|
|
278
|
+
export const pow_exl = (x, n) => exl(exl(exl(0, n), x), EXL_E);
|
|
279
|
+
|
|
280
|
+
// ─── BEST: optimal per-operation routing ──────────────────────────────────────
|
|
281
|
+
//
|
|
282
|
+
// Routes each operation to the operator that uses fewest nodes.
|
|
283
|
+
// EML handles add/sub (only complete operator with these).
|
|
284
|
+
// EDL handles div/mul/recip/neg (multiplicative group — cheapest).
|
|
285
|
+
// EXL handles ln/pow (smallest known formulas).
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* BEST operator routing — minimum nodes per operation across EML/EDL/EXL.
|
|
289
|
+
*
|
|
290
|
+
* ln: EXL 1 node (vs EML/EDL 3)
|
|
291
|
+
* pow: EXL 3 nodes (vs EML 15, EDL 11)
|
|
292
|
+
* div: EDL 1 node (vs EML 15)
|
|
293
|
+
* recip: EDL 2 nodes (vs EML 5)
|
|
294
|
+
* mul: EDL 7 nodes (vs EML 13)
|
|
295
|
+
* neg: EDL 6 nodes (vs EML 9)
|
|
296
|
+
* exp: EML 1 node (tied)
|
|
297
|
+
* sub: EML 5 nodes (EML only)
|
|
298
|
+
* add: EML 11 nodes(EML only)
|
|
299
|
+
*/
|
|
300
|
+
export const BEST = {
|
|
301
|
+
/** ln(x) — EXL, 1 node */
|
|
302
|
+
ln: (x) => ln_exl(x),
|
|
303
|
+
/** xⁿ — EXL, 3 nodes */
|
|
304
|
+
pow: (x, n) => pow_exl(x, n),
|
|
305
|
+
/** x / y — EDL, 1 node */
|
|
306
|
+
div: (x, y) => div_edl(x, y),
|
|
307
|
+
/** 1/x — EDL, 2 nodes */
|
|
308
|
+
recip: (x) => recip_edl(x),
|
|
309
|
+
/** x * y — EDL, 7 nodes */
|
|
310
|
+
mul: (x, y) => mul_edl(x, y),
|
|
311
|
+
/** −x — EDL, 6 nodes */
|
|
312
|
+
neg: (x) => neg_edl(x),
|
|
313
|
+
/** eˣ — EML, 1 node */
|
|
314
|
+
exp: (x) => op(x, 1),
|
|
315
|
+
/** x − y — EML, 5 nodes */
|
|
316
|
+
sub: (x, y) => sub(x, y),
|
|
317
|
+
/** x + y — EML, 11 nodes */
|
|
318
|
+
add: (x, y) => add(x, y),
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* sin(x) via Taylor series using BEST operator routing.
|
|
323
|
+
*
|
|
324
|
+
* sin(x) = x − x³/3! + x⁵/5! − …
|
|
325
|
+
*
|
|
326
|
+
* Uses pow_exl (3 nodes per power — best known) for the power terms.
|
|
327
|
+
* Node counts per term: pow=3, plus additive combination via EML.
|
|
328
|
+
* At 8 terms: 63 nodes (BEST) vs 245 nodes (all-EML) — 74% saving.
|
|
329
|
+
*
|
|
330
|
+
* @param {number} x
|
|
331
|
+
* @param {number} [terms=8] number of Taylor terms (default 8, max error ~7.7e-7)
|
|
332
|
+
* @returns {number}
|
|
333
|
+
*/
|
|
334
|
+
export const sin_best = (x, terms = 8) => {
|
|
335
|
+
if (x === 0) return 0;
|
|
336
|
+
// pow_exl(x, n) requires x > 0. For odd powers: x^n = sign(x) * |x|^n.
|
|
337
|
+
const ax = Math.abs(x);
|
|
338
|
+
const sx = x < 0 ? -1 : 1;
|
|
339
|
+
let result = x; // first term: x¹ = x
|
|
340
|
+
for (let k = 1; k < terms; k++) {
|
|
341
|
+
const power = 2 * k + 1;
|
|
342
|
+
let f = 1;
|
|
343
|
+
for (let i = 2; i <= power; i++) f *= i;
|
|
344
|
+
// Odd power: sign = sx^power = sx (since power is odd)
|
|
345
|
+
const xp = sx * pow_exl(ax, power);
|
|
346
|
+
const sign = (k % 2 === 1) ? -1 : 1;
|
|
347
|
+
result += sign * xp / f;
|
|
348
|
+
}
|
|
349
|
+
return result;
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* cos(x) via Taylor series using BEST operator routing.
|
|
354
|
+
*
|
|
355
|
+
* cos(x) = 1 − x²/2! + x⁴/4! − …
|
|
356
|
+
*
|
|
357
|
+
* @param {number} x
|
|
358
|
+
* @param {number} [terms=8] number of Taylor terms
|
|
359
|
+
* @returns {number}
|
|
360
|
+
*/
|
|
361
|
+
export const cos_best = (x, terms = 8) => {
|
|
362
|
+
if (x === 0) return 1;
|
|
363
|
+
const ax = Math.abs(x);
|
|
364
|
+
let result = 1; // first term: x⁰/0! = 1
|
|
365
|
+
for (let k = 1; k < terms; k++) {
|
|
366
|
+
const power = 2 * k;
|
|
367
|
+
let f = 1;
|
|
368
|
+
for (let i = 2; i <= power; i++) f *= i;
|
|
369
|
+
// Even power: |x|^power (always positive, sign = +1)
|
|
370
|
+
const xp = pow_exl(ax, power);
|
|
371
|
+
const sign = (k % 2 === 1) ? -1 : 1;
|
|
372
|
+
result += sign * xp / f;
|
|
373
|
+
}
|
|
374
|
+
return result;
|
|
375
|
+
};
|
|
376
|
+
|
|
152
377
|
// ─── Identity table ───────────────────────────────────────────────────────────
|
|
153
378
|
|
|
154
379
|
/** Complexity table: each identity ranked by EML tree node count and depth. */
|
|
155
380
|
export const IDENTITIES = [
|
|
156
|
-
|
|
157
|
-
{ name: "
|
|
158
|
-
{ name: "
|
|
159
|
-
{ name: "
|
|
160
|
-
{ name: "
|
|
161
|
-
{ name: "
|
|
162
|
-
{ name: "
|
|
163
|
-
{ name: "
|
|
164
|
-
{ name: "x
|
|
165
|
-
{ name: "x
|
|
166
|
-
|
|
381
|
+
// EML family
|
|
382
|
+
{ name: "eˣ", operator:"EML", form: "eml(x,1)", nodes: 1, status: "verified" },
|
|
383
|
+
{ name: "ln x", operator:"EML", form: "eml(1,eml(eml(1,x),1))", nodes: 3, status: "verified" },
|
|
384
|
+
{ name: "x−y", operator:"EML", form: "eml(ln(x),exp(y))", nodes: 5, status: "verified" },
|
|
385
|
+
{ name: "−y", operator:"EML", form: "two-regime (see source)", nodes: 9, status: "proven" },
|
|
386
|
+
{ name: "x+y", operator:"EML", form: "eml(ln(x),eml(neg(y),1))", nodes: 11, status: "proven" },
|
|
387
|
+
{ name: "x×y", operator:"EML", form: "eml(add(ln(x),ln(y)),1)", nodes: 13, status: "proven" },
|
|
388
|
+
{ name: "x/y", operator:"EML", form: "eml(add(ln(x),neg(ln(y))),1)", nodes: 15, status: "proven" },
|
|
389
|
+
{ name: "xⁿ", operator:"EML", form: "eml(mul(n,ln(x)),1)", nodes: 15, status: "proven" },
|
|
390
|
+
{ name: "1/x", operator:"EML", form: "eml(neg(ln(x)),1)", nodes: 5, status: "verified" },
|
|
391
|
+
// EDL family
|
|
392
|
+
{ name: "x/y", operator:"EDL", form: "edl(ln(x),exp(y))", nodes: 1, status: "verified" },
|
|
393
|
+
{ name: "1/x", operator:"EDL", form: "edl(0,edl(x,e))", nodes: 2, status: "verified" },
|
|
394
|
+
{ name: "−x", operator:"EDL", form: "edl(ln(x),1/e)", nodes: 6, status: "proven" },
|
|
395
|
+
{ name: "x×y", operator:"EDL", form: "div_edl(x,recip_edl(y))", nodes: 7, status: "proven" },
|
|
396
|
+
{ name: "xⁿ", operator:"EDL", form: "edl(mul_edl(n,ln_edl(x)),e)", nodes: 11, status: "proven" },
|
|
397
|
+
// EXL family
|
|
398
|
+
{ name: "ln x", operator:"EXL", form: "exl(0,x)", nodes: 1, status: "verified" },
|
|
399
|
+
{ name: "xⁿ", operator:"EXL", form: "exl(exl(exl(0,n),x),e)", nodes: 3, status: "proven" },
|
|
167
400
|
];
|
|
168
401
|
|
|
169
|
-
export default {
|
|
402
|
+
export default {
|
|
403
|
+
// EML
|
|
404
|
+
op, E, ZERO, NEG_ONE, exp, ln, sub, neg, add, mul, div, pow, recip,
|
|
405
|
+
// EDL
|
|
406
|
+
edl, EDL_E, div_edl, recip_edl, neg_edl, mul_edl, pow_edl,
|
|
407
|
+
// EXL
|
|
408
|
+
exl, EXL_E, ln_exl, pow_exl,
|
|
409
|
+
// BEST routing
|
|
410
|
+
BEST, sin_best, cos_best,
|
|
411
|
+
// Metadata
|
|
412
|
+
IDENTITIES,
|
|
413
|
+
};
|