monogate 0.1.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.
@@ -0,0 +1,381 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { Complex } from "./complex.js";
3
+ import {
4
+ op_c,
5
+ E_C, ZERO_C, NEG_ONE_C,
6
+ exp_c, ln_c,
7
+ sub_c, neg_c, add_c, mul_c, recip_c, div_c, pow_c,
8
+ NEG_I_PI_C, I_HALF_PI_C, I_CONST, PI_C,
9
+ eul_c, sin_eml, cos_eml,
10
+ IDENTITIES_C, BRANCH_CUT_NOTES,
11
+ } from "./complex_eml.js";
12
+
13
+ const TOL = 1e-10; // EML chain results
14
+ const DTOL = 1e-12; // direct Complex arithmetic reference comparisons
15
+
16
+ const near = (a, b, tol = TOL) => Math.abs(a - b) <= tol;
17
+ const nearC = (z, re, im, tol = TOL) =>
18
+ Math.abs(z.re - re) <= tol && Math.abs(z.im - im) <= tol;
19
+
20
+ // ─── Core constants ────────────────────────────────────────────────────────────
21
+
22
+ describe("complex EML — constants", () => {
23
+ it("E_C ≈ e", () => {
24
+ expect(near(E_C.re, Math.E)).toBe(true);
25
+ expect(near(E_C.im, 0)).toBe(true);
26
+ });
27
+
28
+ it("ZERO_C ≈ 0", () => {
29
+ expect(near(ZERO_C.re, 0)).toBe(true);
30
+ expect(near(ZERO_C.im, 0)).toBe(true);
31
+ });
32
+
33
+ it("NEG_ONE_C ≈ −1", () => {
34
+ expect(near(NEG_ONE_C.re, -1)).toBe(true);
35
+ expect(near(NEG_ONE_C.im, 0)).toBe(true);
36
+ });
37
+ });
38
+
39
+ // ─── exp_c and ln_c ───────────────────────────────────────────────────────────
40
+
41
+ describe("exp_c", () => {
42
+ it("exp_c(0) = 1", () => {
43
+ expect(nearC(exp_c(Complex.of(0)), 1, 0)).toBe(true);
44
+ });
45
+
46
+ it("exp_c(1) = e", () => {
47
+ expect(near(exp_c(Complex.of(1)).re, Math.E)).toBe(true);
48
+ });
49
+
50
+ it("exp_c(iπ) ≈ −1 (Euler's identity)", () => {
51
+ const r = exp_c(Complex.of(0, Math.PI));
52
+ expect(near(r.re, -1)).toBe(true);
53
+ expect(near(r.im, 0)).toBe(true);
54
+ });
55
+ });
56
+
57
+ describe("ln_c (EML formula)", () => {
58
+ it("ln_c(e) = 1", () => {
59
+ const r = ln_c(Complex.of(Math.E));
60
+ expect(near(r.re, 1)).toBe(true);
61
+ expect(near(r.im, 0)).toBe(true);
62
+ });
63
+
64
+ it("ln_c(1) = 0", () => {
65
+ const r = ln_c(Complex.of(1));
66
+ expect(near(r.re, 0, DTOL)).toBe(true);
67
+ expect(near(r.im, 0, DTOL)).toBe(true);
68
+ });
69
+
70
+ it("ln_c(−1) ≈ iπ (principal branch, may be −iπ; check |Im| = π)", () => {
71
+ const r = ln_c(Complex.of(-1));
72
+ expect(near(r.re, 0)).toBe(true);
73
+ expect(near(Math.abs(r.im), Math.PI)).toBe(true);
74
+ });
75
+
76
+ it("EML ln_c matches direct .ln() for various inputs (tol 1e-12)", () => {
77
+ const inputs = [
78
+ Complex.of(2),
79
+ Complex.of(0.5),
80
+ Complex.of(1, 1),
81
+ Complex.of(-0.5, 0.5),
82
+ Complex.of(10),
83
+ ];
84
+ for (const z of inputs) {
85
+ const eml = ln_c(z);
86
+ const direct = z.ln();
87
+ expect(near(eml.re, direct.re, DTOL)).toBe(true);
88
+ expect(near(eml.im, direct.im, DTOL)).toBe(true);
89
+ }
90
+ });
91
+
92
+ it("exp_c(ln_c(z)) ≈ z for Im(z) ∈ (−π, π)", () => {
93
+ const zs = [Complex.of(2, 1), Complex.of(0.5, -0.7), Complex.of(-1, 0.5)];
94
+ for (const z of zs) {
95
+ const r = exp_c(ln_c(z));
96
+ expect(near(r.re, z.re)).toBe(true);
97
+ expect(near(r.im, z.im)).toBe(true);
98
+ }
99
+ });
100
+ });
101
+
102
+ // ─── Arithmetic ───────────────────────────────────────────────────────────────
103
+
104
+ describe("sub_c", () => {
105
+ it("sub_c(3, 1) ≈ 2", () => {
106
+ expect(nearC(sub_c(Complex.of(3), Complex.of(1)), 2, 0)).toBe(true);
107
+ });
108
+
109
+ it("sub_c(3+4i, 1+2i) ≈ 2+2i", () => {
110
+ const r = sub_c(Complex.of(3, 4), Complex.of(1, 2));
111
+ expect(nearC(r, 2, 2)).toBe(true);
112
+ });
113
+ });
114
+
115
+ describe("neg_c", () => {
116
+ it("neg_c(1) ≈ −1", () => {
117
+ expect(nearC(neg_c(Complex.of(1)), -1, 0)).toBe(true);
118
+ });
119
+
120
+ it("neg_c(−1) ≈ 1", () => {
121
+ expect(nearC(neg_c(Complex.of(-1)), 1, 0)).toBe(true);
122
+ });
123
+
124
+ it("neg_c(3+2i) ≈ −3−2i", () => {
125
+ const r = neg_c(Complex.of(3, 2));
126
+ expect(nearC(r, -3, -2)).toBe(true);
127
+ });
128
+
129
+ it("neg_c(neg_c(z)) ≈ z", () => {
130
+ const z = Complex.of(2, 1);
131
+ const r = neg_c(neg_c(z));
132
+ expect(nearC(r, z.re, z.im)).toBe(true);
133
+ });
134
+
135
+ it("neg_c(z).add(z).isZero()", () => {
136
+ const z = Complex.of(1.5, 0.7);
137
+ const r = neg_c(z).add(z);
138
+ expect(r.isZero(TOL)).toBe(true);
139
+ });
140
+
141
+ it("neg_c throws for |Im(y)| > π", () => {
142
+ expect(() => neg_c(Complex.of(0, Math.PI + 0.1))).toThrow(RangeError);
143
+ expect(() => neg_c(Complex.of(0, -(Math.PI + 0.1)))).toThrow(RangeError);
144
+ });
145
+
146
+ it("neg_c does NOT throw at boundary |Im| = π", () => {
147
+ // At Im = ±π, the formula is fragile but works in IEEE 754 practice
148
+ expect(() => neg_c(Complex.of(0, Math.PI))).not.toThrow();
149
+ });
150
+ });
151
+
152
+ describe("add_c", () => {
153
+ it("add_c(2, 3) ≈ 5", () => {
154
+ expect(nearC(add_c(Complex.of(2), Complex.of(3)), 5, 0)).toBe(true);
155
+ });
156
+
157
+ it("add_c(1+2i, 3+1i) ≈ 4+3i", () => {
158
+ const r = add_c(Complex.of(1, 2), Complex.of(3, 1));
159
+ expect(nearC(r, 4, 3)).toBe(true);
160
+ });
161
+
162
+ it("add_c throws when first arg is zero", () => {
163
+ expect(() => add_c(Complex.of(0), Complex.of(1))).toThrow(RangeError);
164
+ });
165
+ });
166
+
167
+ describe("mul_c", () => {
168
+ it("mul_c(2, 3) ≈ 6", () => {
169
+ expect(nearC(mul_c(Complex.of(2), Complex.of(3)), 6, 0)).toBe(true);
170
+ });
171
+
172
+ it("mul_c(1+i, 1-i) ≈ 2", () => {
173
+ const r = mul_c(Complex.of(1, 1), Complex.of(1, -1));
174
+ expect(nearC(r, 2, 0)).toBe(true);
175
+ });
176
+
177
+ it("mul_c(z, z.recip()) ≈ 1", () => {
178
+ const z = Complex.of(3, 2);
179
+ const r = mul_c(z, z.recip());
180
+ expect(nearC(r, 1, 0)).toBe(true);
181
+ });
182
+ });
183
+
184
+ describe("recip_c", () => {
185
+ it("recip_c(2) ≈ 0.5", () => {
186
+ expect(nearC(recip_c(Complex.of(2)), 0.5, 0)).toBe(true);
187
+ });
188
+
189
+ it("recip_c(i) ≈ −i", () => {
190
+ const r = recip_c(Complex.of(0, 1));
191
+ expect(nearC(r, 0, -1)).toBe(true);
192
+ });
193
+
194
+ it("mul_c(z, recip_c(z)) ≈ 1", () => {
195
+ const z = Complex.of(2, 3);
196
+ const r = mul_c(z, recip_c(z));
197
+ expect(nearC(r, 1, 0)).toBe(true);
198
+ });
199
+ });
200
+
201
+ describe("div_c", () => {
202
+ it("div_c(6, 2) ≈ 3", () => {
203
+ expect(nearC(div_c(Complex.of(6), Complex.of(2)), 3, 0)).toBe(true);
204
+ });
205
+
206
+ it("div_c(z, z) ≈ 1", () => {
207
+ const z = Complex.of(2, 3);
208
+ expect(nearC(div_c(z, z), 1, 0)).toBe(true);
209
+ });
210
+ });
211
+
212
+ describe("pow_c", () => {
213
+ it("pow_c(2, 3) ≈ 8", () => {
214
+ expect(nearC(pow_c(Complex.of(2), Complex.of(3)), 8, 0)).toBe(true);
215
+ });
216
+
217
+ it("pow_c(i, 2) ≈ −1 (i² = −1)", () => {
218
+ const r = pow_c(Complex.of(0, 1), Complex.of(2));
219
+ expect(nearC(r, -1, 0)).toBe(true);
220
+ });
221
+ });
222
+
223
+ // ─── The escape from reals ────────────────────────────────────────────────────
224
+
225
+ describe("NEG_I_PI_C — escape from reals", () => {
226
+ it("Re(NEG_I_PI_C) ≈ 0", () => {
227
+ expect(near(NEG_I_PI_C.re, 0)).toBe(true);
228
+ });
229
+
230
+ it("|Im(NEG_I_PI_C)| ≈ π", () => {
231
+ expect(near(Math.abs(NEG_I_PI_C.im), Math.PI)).toBe(true);
232
+ });
233
+
234
+ it("NEG_I_PI_C is not real", () => {
235
+ expect(NEG_I_PI_C.isReal(TOL)).toBe(false);
236
+ });
237
+ });
238
+
239
+ // ─── i, π ────────────────────────────────────────────────────────────────────
240
+
241
+ describe("I_CONST (i)", () => {
242
+ it("Re(i) ≈ 0", () => expect(near(I_CONST.re, 0)).toBe(true));
243
+ it("Im(i) ≈ 1", () => expect(near(I_CONST.im, 1)).toBe(true));
244
+
245
+ it("i² ≈ −1", () => {
246
+ const r = mul_c(I_CONST, I_CONST);
247
+ expect(near(r.re, -1)).toBe(true);
248
+ expect(near(r.im, 0)).toBe(true);
249
+ });
250
+
251
+ it("i⁴ ≈ 1", () => {
252
+ const i2 = mul_c(I_CONST, I_CONST);
253
+ const i4 = mul_c(i2, i2);
254
+ expect(near(i4.re, 1)).toBe(true);
255
+ expect(near(i4.im, 0)).toBe(true);
256
+ });
257
+ });
258
+
259
+ describe("PI_C (π)", () => {
260
+ it("Im(π) ≈ 0", () => expect(near(PI_C.im, 0)).toBe(true));
261
+ it("Re(π) ≈ Math.PI", () => expect(near(PI_C.re, Math.PI)).toBe(true));
262
+ });
263
+
264
+ // ─── Euler's formula ──────────────────────────────────────────────────────────
265
+
266
+ describe("eul_c — Euler's formula", () => {
267
+ it("eul_c(0) = 1", () => {
268
+ expect(nearC(eul_c(Complex.of(0)), 1, 0)).toBe(true);
269
+ });
270
+
271
+ it("eul_c(π) ≈ −1 (Euler's identity)", () => {
272
+ const r = eul_c(Complex.of(Math.PI));
273
+ expect(near(r.re, -1)).toBe(true);
274
+ expect(near(r.im, 0)).toBe(true);
275
+ });
276
+
277
+ it("eul_c(π/2) ≈ i", () => {
278
+ const r = eul_c(Complex.of(Math.PI / 2));
279
+ expect(near(r.re, 0)).toBe(true);
280
+ expect(near(r.im, 1)).toBe(true);
281
+ });
282
+
283
+ it("eul_c(−π/2) ≈ −i", () => {
284
+ const r = eul_c(Complex.of(-Math.PI / 2));
285
+ expect(near(r.re, 0)).toBe(true);
286
+ expect(near(r.im, -1)).toBe(true);
287
+ });
288
+
289
+ it("|eul_c(x)| = 1 for real x", () => {
290
+ for (const x of [0, 1, 2, -1, Math.PI, -Math.PI / 3]) {
291
+ expect(near(eul_c(Complex.of(x)).abs(), 1)).toBe(true);
292
+ }
293
+ });
294
+ });
295
+
296
+ // ─── sin_eml and cos_eml ──────────────────────────────────────────────────────
297
+
298
+ describe("sin_eml / cos_eml", () => {
299
+ const cases = [
300
+ [0, 0, 1],
301
+ [Math.PI / 6, 0.5, Math.sqrt(3) / 2],
302
+ [Math.PI / 4, Math.SQRT1_2, Math.SQRT1_2],
303
+ [Math.PI / 3, Math.sqrt(3) / 2, 0.5],
304
+ [Math.PI / 2, 1, 0],
305
+ [Math.PI, 0, -1],
306
+ [-1, -Math.sin(1), Math.cos(1)],
307
+ [2, Math.sin(2), Math.cos(2)],
308
+ ];
309
+
310
+ for (const [x, sinX, cosX] of cases) {
311
+ it(`sin_eml(${x.toFixed(4)}) ≈ ${sinX.toFixed(4)}`, () => {
312
+ expect(near(sin_eml(x), sinX)).toBe(true);
313
+ });
314
+
315
+ it(`cos_eml(${x.toFixed(4)}) ≈ ${cosX.toFixed(4)}`, () => {
316
+ expect(near(cos_eml(x), cosX)).toBe(true);
317
+ });
318
+ }
319
+
320
+ it("sin² + cos² = 1 for x ∈ {0.3, 1, 2, π}", () => {
321
+ for (const x of [0.3, 1, 2, Math.PI]) {
322
+ const s = sin_eml(x);
323
+ const c = cos_eml(x);
324
+ expect(near(s * s + c * c, 1)).toBe(true);
325
+ }
326
+ });
327
+ });
328
+
329
+ // ─── IDENTITIES_C completeness ────────────────────────────────────────────────
330
+
331
+ describe("IDENTITIES_C", () => {
332
+ it("has at least 15 entries", () => {
333
+ expect(IDENTITIES_C.length).toBeGreaterThanOrEqual(15);
334
+ });
335
+
336
+ it("every entry has name, emlForm, domain, terminal, status", () => {
337
+ for (const id of IDENTITIES_C) {
338
+ expect(id).toHaveProperty("name");
339
+ expect(id).toHaveProperty("emlForm");
340
+ expect(id).toHaveProperty("domain");
341
+ expect(id).toHaveProperty("terminal");
342
+ expect(id).toHaveProperty("status");
343
+ }
344
+ });
345
+
346
+ it("NEG_I_PI entry uses terminal {1}", () => {
347
+ const entry = IDENTITIES_C.find((e) => e.name === "−iπ");
348
+ expect(entry).toBeDefined();
349
+ expect(entry.terminal).toBe("{1}");
350
+ });
351
+
352
+ it("i and π entries use terminal {1, 2}", () => {
353
+ const iEntry = IDENTITIES_C.find((e) => e.name === "i");
354
+ const piEntry = IDENTITIES_C.find((e) => e.name === "π");
355
+ expect(iEntry?.terminal).toBe("{1, 2}");
356
+ expect(piEntry?.terminal).toBe("{1, 2}");
357
+ });
358
+
359
+ it("sin and cos are marked as meta-operations", () => {
360
+ const sin = IDENTITIES_C.find((e) => e.name === "sin(x)");
361
+ const cos = IDENTITIES_C.find((e) => e.name === "cos(x)");
362
+ expect(sin?.status).toBe("meta-operation");
363
+ expect(cos?.status).toBe("meta-operation");
364
+ });
365
+ });
366
+
367
+ describe("BRANCH_CUT_NOTES", () => {
368
+ it("is an array with at least 4 entries", () => {
369
+ expect(Array.isArray(BRANCH_CUT_NOTES)).toBe(true);
370
+ expect(BRANCH_CUT_NOTES.length).toBeGreaterThanOrEqual(4);
371
+ });
372
+
373
+ it("every entry has fn, failsWhen, symptom, action", () => {
374
+ for (const note of BRANCH_CUT_NOTES) {
375
+ expect(note).toHaveProperty("fn");
376
+ expect(note).toHaveProperty("failsWhen");
377
+ expect(note).toHaveProperty("symptom");
378
+ expect(note).toHaveProperty("action");
379
+ }
380
+ });
381
+ });
package/src/index.js ADDED
@@ -0,0 +1,169 @@
1
+ /**
2
+ * monogate — Exp-Minus-Log arithmetic
3
+ *
4
+ * A single binary operator from which all elementary functions
5
+ * can be constructed, using only the constant 1 as a terminal node.
6
+ *
7
+ * eml(x, y) = exp(x) − ln(y)
8
+ * Grammar: S → 1 | eml(S, S)
9
+ *
10
+ * Reference:
11
+ * "All elementary functions from a single operator"
12
+ * Andrzej Odrzywołek, Jagiellonian University, 2026
13
+ * arXiv:2603.21852v2 [cs.SC] · CC BY 4.0
14
+ *
15
+ * @module monogate
16
+ */
17
+
18
+ // ─── Core operator ────────────────────────────────────────────────────────────
19
+
20
+ /**
21
+ * The EML operator: eml(x, y) = exp(x) − ln(y)
22
+ *
23
+ * @param {number} x
24
+ * @param {number} y must be > 0 (argument of ln)
25
+ * @returns {number}
26
+ */
27
+ export const op = (x, y) => Math.exp(x) - Math.log(y);
28
+
29
+ // ─── Constants ────────────────────────────────────────────────────────────────
30
+
31
+ /** e = eml(1,1). Proof: exp(1)−ln(1) = e−0 = e. Nodes:1 Depth:1 */
32
+ export const E = op(1, 1);
33
+
34
+ /** 0 = eml(1, eml(eml(1,1),1)). Proof: eml(1,1)=e → eml(e,1)=eᵉ → eml(1,eᵉ)=e−e=0. Nodes:3 Depth:3 */
35
+ export const ZERO = op(1, op(op(1, 1), 1));
36
+
37
+ /** −1 = eml(ZERO, eml(2,1)). Proof: exp(0)−ln(e²)=1−2=−1. Nodes:5 Depth:4 */
38
+ export const NEG_ONE = op(ZERO, op(2, 1));
39
+
40
+ // ─── Elementary functions ─────────────────────────────────────────────────────
41
+
42
+ /**
43
+ * eˣ = eml(x, 1)
44
+ * Proof: exp(x)−ln(1) = exp(x). ∎ Nodes:1 Depth:1
45
+ *
46
+ * @param {number} x
47
+ * @returns {number}
48
+ */
49
+ export const exp = (x) => op(x, 1);
50
+
51
+ /**
52
+ * ln(x) = eml(1, eml(eml(1,x), 1))
53
+ * Proof: let s=e−ln(x); eml(s,1)=eˢ=eᵉ/x; eml(1,eᵉ/x)=e−(e−ln(x))=ln(x). ∎
54
+ * Nodes:3 Depth:3 Domain: x > 0
55
+ *
56
+ * @param {number} x must be > 0
57
+ * @returns {number}
58
+ */
59
+ export const ln = (x) => op(1, op(op(1, x), 1));
60
+
61
+ // ─── Arithmetic ───────────────────────────────────────────────────────────────
62
+
63
+ /**
64
+ * x − y = eml(ln(x), exp(y))
65
+ * Proof: exp(ln(x))−ln(exp(y)) = x−y. ∎ Nodes:5 Depth:4 Domain: x > 0
66
+ *
67
+ * @param {number} x must be > 0
68
+ * @param {number} y
69
+ * @returns {number}
70
+ */
71
+ export const sub = (x, y) => op(ln(x), exp(y));
72
+
73
+ /**
74
+ * −y (negation — two-regime construction for numerical stability)
75
+ *
76
+ * REGIME A — y ≤ 0 (tower formula):
77
+ * Let α=eml(y,1)=eʸ. A=eml(α,α)=exp(eʸ)−y. B=eml(α,1)=exp(eʸ).
78
+ * sub(A,B) = A−B = −y. ∎ Stable: exp(eʸ) finite for all y ≤ 0.
79
+ *
80
+ * REGIME B — y > 0 (shift formula, stable to y < 708):
81
+ * y+1 = sub(y, NEG_ONE).
82
+ * −y = eml(ZERO, eml(y+1, 1)) = 1−ln(exp(y+1)) = 1−(y+1) = −y. ∎
83
+ *
84
+ * Valid for all y ∈ ℝ. Overflows IEEE 754 doubles only for y > 707.
85
+ *
86
+ * @param {number} y
87
+ * @returns {number}
88
+ */
89
+ export const neg = (y) => {
90
+ if (y <= 0) {
91
+ const a = op(y, 1); // eʸ
92
+ return op(ln(op(a, a)), op(op(a, 1), 1)); // sub(A, B)
93
+ }
94
+ const y1 = op(ln(y), op(NEG_ONE, 1)); // y + 1 [sub(y, −1)]
95
+ return op(ZERO, op(y1, 1)); // 1 − (y+1) = −y
96
+ };
97
+
98
+ /**
99
+ * x + y
100
+ * Proof: exp(ln(x))−ln(exp(−y)) = x−(−y) = x+y. ∎
101
+ * Generalised for any sign via commutativity and double-negation.
102
+ *
103
+ * @param {number} x
104
+ * @param {number} y
105
+ * @returns {number}
106
+ */
107
+ export const add = (x, y) => {
108
+ if (x > 0) return op(ln(x), op(neg(y), 1));
109
+ if (y > 0) return op(ln(y), op(neg(x), 1));
110
+ return neg(op(ln(neg(x)), op(neg(neg(y)), 1)));
111
+ };
112
+
113
+ /**
114
+ * x × y = exp(ln(x) + ln(y))
115
+ * Proof: exp(ln(x)+ln(y)) = exp(ln(xy)) = xy. ∎ Domain: x,y > 0
116
+ *
117
+ * @param {number} x must be > 0
118
+ * @param {number} y must be > 0
119
+ * @returns {number}
120
+ */
121
+ export const mul = (x, y) => op(add(ln(x), ln(y)), 1);
122
+
123
+ /**
124
+ * x / y = exp(ln(x) − ln(y))
125
+ * Proof: exp(ln(x)−ln(y)) = exp(ln(x/y)) = x/y. ∎ Domain: x,y > 0
126
+ *
127
+ * @param {number} x must be > 0
128
+ * @param {number} y must be > 0
129
+ * @returns {number}
130
+ */
131
+ export const div = (x, y) => op(add(ln(x), neg(ln(y))), 1);
132
+
133
+ /**
134
+ * xⁿ = exp(n · ln(x))
135
+ * Proof: exp(n·ln(x)) = exp(ln(xⁿ)) = xⁿ. ∎ Domain: x > 0, n ∈ ℝ
136
+ *
137
+ * @param {number} x must be > 0
138
+ * @param {number} n
139
+ * @returns {number}
140
+ */
141
+ export const pow = (x, n) => op(mul(n, ln(x)), 1);
142
+
143
+ /**
144
+ * 1/x = exp(−ln(x))
145
+ * Proof: exp(−ln(x)) = x⁻¹. ∎ Domain: x > 0
146
+ *
147
+ * @param {number} x must be > 0
148
+ * @returns {number}
149
+ */
150
+ export const recip = (x) => op(neg(ln(x)), 1);
151
+
152
+ // ─── Identity table ───────────────────────────────────────────────────────────
153
+
154
+ /** Complexity table: each identity ranked by EML tree node count and depth. */
155
+ export const IDENTITIES = [
156
+ { name: "eˣ", emlForm: "eml(x,1)", nodes: 1, depth: 1, status: "verified" },
157
+ { name: "ln x",emlForm: "eml(1,eml(eml(1,x),1))", nodes: 3, depth: 3, status: "verified" },
158
+ { name: "e", emlForm: "eml(1,1)", nodes: 1, depth: 1, status: "verified" },
159
+ { name: "0", emlForm: "eml(1,eml(eml(1,1),1))", nodes: 3, depth: 3, status: "verified" },
160
+ { name: "x−y", emlForm: "eml(ln(x),exp(y))", nodes: 5, depth: 4, status: "verified" },
161
+ { name: "−y", emlForm: "two-regime (see source)", nodes: 9, depth: 5, status: "proven" },
162
+ { name: "x+y", emlForm: "eml(ln(x),eml(neg(y),1))", nodes: 11, depth: 6, status: "proven" },
163
+ { name: "x×y", emlForm: "eml(add(ln(x),ln(y)),1)", nodes: 13, depth: 7, status: "proven" },
164
+ { name: "x/y", emlForm: "eml(add(ln(x),neg(ln(y))),1)", nodes: 15, depth: 8, status: "proven" },
165
+ { name: "xⁿ", emlForm: "eml(mul(n,ln(x)),1)", nodes: 15, depth: 8, status: "proven" },
166
+ { name: "1/x", emlForm: "eml(neg(ln(x)),1)", nodes: 5, depth: 4, status: "verified" },
167
+ ];
168
+
169
+ export default { op, exp, ln, E, ZERO, NEG_ONE, sub, neg, add, mul, div, pow, recip, IDENTITIES };