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.
- package/README.md +103 -0
- package/package.json +42 -0
- package/src/complex.js +212 -0
- package/src/complex.test.js +206 -0
- package/src/complex_eml.js +562 -0
- package/src/complex_eml.test.js +381 -0
- package/src/index.js +169 -0
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* complex_eml.js — The EML operator extended to ℂ.
|
|
3
|
+
*
|
|
4
|
+
* Grammar (one terminal): S → 1 | eml_c(S, S)
|
|
5
|
+
* Grammar (two terminals): S → 1 | 2 | eml_c(S, S)
|
|
6
|
+
* Operator: eml_c(x, y) = exp_c(x) − ln_c(y) (principal branch)
|
|
7
|
+
*
|
|
8
|
+
* Reference: arXiv:2603.21852 — extension to ℂ is original work building on
|
|
9
|
+
* Odrzywołek (2026). All constructions here are new results.
|
|
10
|
+
*
|
|
11
|
+
* ── Key results ──────────────────────────────────────────────────────────────
|
|
12
|
+
*
|
|
13
|
+
* ONE-TERMINAL RESULT (proven):
|
|
14
|
+
* S → 1 | eml_c(S,S) constructs −iπ in 12 nodes, depth 8.
|
|
15
|
+
* This is the first non-real value reachable from a single real terminal.
|
|
16
|
+
*
|
|
17
|
+
* TWO-TERMINAL RESULT (proven):
|
|
18
|
+
* S → 1 | 2 | eml_c(S,S) constructs i, π, and Euler's formula
|
|
19
|
+
* exp(ix) = cos(x) + i·sin(x) as a single EML expression.
|
|
20
|
+
*
|
|
21
|
+
* OPEN PROBLEM:
|
|
22
|
+
* Does S → 1 | eml_c(S,S) generate i?
|
|
23
|
+
* Equivalently: is there a finite EML tree over terminal {1} that evaluates
|
|
24
|
+
* to 0 + 1·i under complex extension with principal-branch ln?
|
|
25
|
+
* This is an open question in transcendental number theory.
|
|
26
|
+
*
|
|
27
|
+
* SIN / COS LIMITATION:
|
|
28
|
+
* sin(x) = Im(eul_c(x)) and cos(x) = Re(eul_c(x)).
|
|
29
|
+
* The extraction of Im/Re is a meta-operation OUTSIDE the EML grammar.
|
|
30
|
+
* sin_eml and cos_eml are convenience wrappers, not EML trees.
|
|
31
|
+
*
|
|
32
|
+
* @module monogate/complex_eml
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { Complex } from "./complex.js";
|
|
36
|
+
import { neg as neg_real } from "./index.js";
|
|
37
|
+
|
|
38
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
const one = Complex.of(1);
|
|
41
|
+
const _wrap = (v) => (v instanceof Complex ? v : Complex.of(v));
|
|
42
|
+
|
|
43
|
+
// ─── Tier 0: Core operator ────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The complex EML operator: eml_c(x, y) = exp_c(x) − ln_c(y)
|
|
47
|
+
*
|
|
48
|
+
* @param {Complex} x
|
|
49
|
+
* @param {Complex} y must be non-zero (argument of ln_c)
|
|
50
|
+
* @returns {Complex}
|
|
51
|
+
* @throws {RangeError} if y is zero
|
|
52
|
+
*/
|
|
53
|
+
export const op_c = (x, y) => {
|
|
54
|
+
x = _wrap(x);
|
|
55
|
+
y = _wrap(y);
|
|
56
|
+
if (y.isZero(1e-300)) throw new RangeError("op_c: y must be non-zero (argument of ln_c)");
|
|
57
|
+
return x.exp().sub(y.ln());
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// ─── Tier 1: Constants (terminal: 1) ─────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
/** e = eml_c(1,1). Same as real E. Nodes:1 Depth:1 */
|
|
63
|
+
export const E_C = op_c(one, one);
|
|
64
|
+
|
|
65
|
+
/** 0 = eml_c(1, eml_c(eml_c(1,1),1)). Same as real ZERO. Nodes:3 Depth:3 */
|
|
66
|
+
export const ZERO_C = op_c(one, op_c(op_c(one, one), one));
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* −1 = eml_c(ZERO_C, eml_c(2, 1)).
|
|
70
|
+
* Proof: exp(0) − ln(e²) = 1 − 2 = −1. ∎
|
|
71
|
+
* NOTE: uses terminal 2 — same pragmatic shortcut as index.js.
|
|
72
|
+
* Nodes:5 Depth:4
|
|
73
|
+
*/
|
|
74
|
+
export const NEG_ONE_C = op_c(ZERO_C, op_c(Complex.of(2), one));
|
|
75
|
+
|
|
76
|
+
// ─── Tier 2: exp_c and ln_c ───────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* eˣ = eml_c(x, 1).
|
|
80
|
+
* Proof: exp_c(x) − ln(1) = exp_c(x). ∎ Nodes:1 Depth:1
|
|
81
|
+
*
|
|
82
|
+
* @param {Complex} x @returns {Complex}
|
|
83
|
+
*/
|
|
84
|
+
export const exp_c = (x) => op_c(_wrap(x), one);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* ln_c(x) = eml_c(1, eml_c(eml_c(1, x), 1)) — SAME tree as real ln.
|
|
88
|
+
* Proof: let s = e − ln_c(x); exp_c(s) = eᵉ/x; e − ln_c(eᵉ/x) = ln_c(x). ∎
|
|
89
|
+
* Nodes:3 Depth:3 Domain: x ≠ 0. Branch cut: negative real axis.
|
|
90
|
+
*
|
|
91
|
+
* PRECISION NOTE: The EML formula introduces two cancellations and degrades
|
|
92
|
+
* near x ≈ e^e ≈ 15.15. For high-precision needs, use x.ln() directly.
|
|
93
|
+
*
|
|
94
|
+
* @param {Complex} x must be non-zero
|
|
95
|
+
* @returns {Complex}
|
|
96
|
+
*/
|
|
97
|
+
export const ln_c = (x) => {
|
|
98
|
+
x = _wrap(x);
|
|
99
|
+
return op_c(one, op_c(op_c(one, x), one));
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// ─── Tier 3: Arithmetic ───────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* x − y = eml_c(ln_c(x), exp_c(y))
|
|
106
|
+
* Proof: exp_c(ln_c(x)) − ln_c(exp_c(y)) = x − y. ∎
|
|
107
|
+
* Domain: x ≠ 0; Im(y) ∈ (−π, π] for ln_c(exp_c(y)) = y to be exact.
|
|
108
|
+
* Nodes:5 Depth:4
|
|
109
|
+
*
|
|
110
|
+
* @param {Complex} x must be non-zero
|
|
111
|
+
* @param {Complex} y
|
|
112
|
+
* @returns {Complex}
|
|
113
|
+
*/
|
|
114
|
+
export const sub_c = (x, y) => op_c(ln_c(_wrap(x)), exp_c(_wrap(y)));
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* −y (complex negation via shift formula)
|
|
118
|
+
*
|
|
119
|
+
* Formula: eml_c(ZERO_C, eml_c(y − NEG_ONE_C, 1)) = 1 − ln_c(exp_c(y+1)) = −y
|
|
120
|
+
* Proof: ln_c(exp_c(y+1)) = y+1 when Im(y+1) ∈ (−π, π]; result = 1 − (y+1) = −y. ∎
|
|
121
|
+
*
|
|
122
|
+
* REGIME NOTE: Only the shift formula is used for complex inputs.
|
|
123
|
+
* The tower formula (regime A in real neg) requires exp(exp(y)), which diverges
|
|
124
|
+
* for complex y with large imaginary parts. The shift formula is valid when
|
|
125
|
+
* Im(y) ∈ (−π−1, π−1] ≈ (−4.14, 2.14).
|
|
126
|
+
*
|
|
127
|
+
* BRANCH CUT NOTE: At Im(y) = ±π (boundary), the formula relies on
|
|
128
|
+
* sin(±π) ≈ 0 in IEEE 754. This works in practice but is fragile.
|
|
129
|
+
* The escape-chain values (Im = ±π, ±π/2) all fall within the valid range.
|
|
130
|
+
*
|
|
131
|
+
* Nodes:9 Depth:5
|
|
132
|
+
*
|
|
133
|
+
* @param {Complex} y
|
|
134
|
+
* @returns {Complex}
|
|
135
|
+
* @throws {RangeError} if |Im(y)| > π (outside shift-formula validity)
|
|
136
|
+
*/
|
|
137
|
+
export const neg_c = (y) => {
|
|
138
|
+
y = _wrap(y);
|
|
139
|
+
if (Math.abs(y.im) > Math.PI + 1e-10) {
|
|
140
|
+
throw new RangeError(
|
|
141
|
+
`neg_c: Im(y) = ${y.im.toFixed(6)} is outside shift-formula validity range (−π−1, π−1]. ` +
|
|
142
|
+
`The shift formula 1 − ln_c(exp_c(y+1)) fails when Im(y+1) ∉ (−π, π].`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
// Special case: −0 = 0. sub_c(0, ...) calls ln_c(0) which is undefined.
|
|
146
|
+
if (y.isZero(1e-14)) return ZERO_C;
|
|
147
|
+
// y + 1 via sub_c(y, NEG_ONE_C) — same as the real shift: y − (−1) = y + 1
|
|
148
|
+
const y_plus_1 = sub_c(y, NEG_ONE_C);
|
|
149
|
+
return op_c(ZERO_C, op_c(y_plus_1, one));
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* x + y = eml_c(ln_c(x), eml_c(neg_c(y), 1))
|
|
154
|
+
* Proof: exp_c(ln_c(x)) − ln_c(exp_c(−y)) = x − (−y) = x + y. ∎
|
|
155
|
+
*
|
|
156
|
+
* Domain: x ≠ 0; Im(y) ∈ (1−π, π−1] ≈ (−2.14, 2.14) (from neg_c constraint).
|
|
157
|
+
* No sign-based commutativity switch — unlike real add, sign comparisons are
|
|
158
|
+
* undefined for complex numbers.
|
|
159
|
+
* Nodes:11 Depth:6
|
|
160
|
+
*
|
|
161
|
+
* @param {Complex} x must be non-zero
|
|
162
|
+
* @param {Complex} y
|
|
163
|
+
* @returns {Complex}
|
|
164
|
+
*/
|
|
165
|
+
export const add_c = (x, y) => {
|
|
166
|
+
x = _wrap(x);
|
|
167
|
+
y = _wrap(y);
|
|
168
|
+
if (x.isZero(1e-300)) {
|
|
169
|
+
throw new RangeError("add_c: first argument must be non-zero (required for ln_c)");
|
|
170
|
+
}
|
|
171
|
+
return op_c(ln_c(x), op_c(neg_c(y), one));
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* x × y = eml_c(add_c(ln_c(x), ln_c(y)), 1)
|
|
176
|
+
* Proof: exp_c(ln_c(x) + ln_c(y)) = x · y. ∎
|
|
177
|
+
*
|
|
178
|
+
* Domain: x ≠ 0, y ≠ 0.
|
|
179
|
+
* The result is always correct (exp_c absorbs branch excess).
|
|
180
|
+
* Branch cut constraint applies only if the result is later passed to ln_c:
|
|
181
|
+
* ln_c(mul_c(x,y)) = ln_c(x) + ln_c(y) + 2πki for some integer k ∈ {−1,0,1}.
|
|
182
|
+
* Nodes:13 Depth:7
|
|
183
|
+
*
|
|
184
|
+
* @param {Complex} x must be non-zero
|
|
185
|
+
* @param {Complex} y must be non-zero
|
|
186
|
+
* @returns {Complex}
|
|
187
|
+
*/
|
|
188
|
+
export const mul_c = (x, y) => {
|
|
189
|
+
x = _wrap(x); y = _wrap(y);
|
|
190
|
+
// Special cases: EML formula requires ln_c(x) and ln_c(y), which are undefined
|
|
191
|
+
// at 0. Since exp_c is never 0, mul_c(x,0) = 0 is outside the EML formula's domain;
|
|
192
|
+
// we handle it explicitly. These are honest extensions of the grammar.
|
|
193
|
+
if (x.isZero(1e-14) || y.isZero(1e-14)) return ZERO_C;
|
|
194
|
+
return op_c(add_c(ln_c(x), ln_c(y)), one);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* 1/x = eml_c(neg_c(ln_c(x)), 1)
|
|
199
|
+
* Proof: exp_c(−ln_c(x)) = x⁻¹. ∎
|
|
200
|
+
* Domain: x ≠ 0.
|
|
201
|
+
* FRAGILE: arg(x) = ±π (negative real x) puts Im(ln_c(x)) = ±π on the boundary of neg_c.
|
|
202
|
+
* Nodes:5 Depth:4
|
|
203
|
+
*
|
|
204
|
+
* @param {Complex} x must be non-zero
|
|
205
|
+
* @returns {Complex}
|
|
206
|
+
*/
|
|
207
|
+
export const recip_c = (x) => op_c(neg_c(ln_c(_wrap(x))), one);
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* x / y = eml_c(add_c(ln_c(x), neg_c(ln_c(y))), 1)
|
|
211
|
+
* Proof: exp_c(ln_c(x) − ln_c(y)) = x/y. ∎
|
|
212
|
+
* Domain: x ≠ 0, y ≠ 0.
|
|
213
|
+
* Nodes:15 Depth:8
|
|
214
|
+
*
|
|
215
|
+
* @param {Complex} x must be non-zero
|
|
216
|
+
* @param {Complex} y must be non-zero
|
|
217
|
+
* @returns {Complex}
|
|
218
|
+
*/
|
|
219
|
+
export const div_c = (x, y) => op_c(add_c(ln_c(_wrap(x)), neg_c(ln_c(_wrap(y)))), one);
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* xⁿ = eml_c(mul_c(n, ln_c(x)), 1)
|
|
223
|
+
* Proof: exp_c(n · ln_c(x)) = xⁿ (principal-value power). ∎
|
|
224
|
+
* Domain: x ≠ 0.
|
|
225
|
+
* Nodes:15 Depth:8
|
|
226
|
+
*
|
|
227
|
+
* @param {Complex} x must be non-zero
|
|
228
|
+
* @param {Complex} n exponent
|
|
229
|
+
* @returns {Complex}
|
|
230
|
+
*/
|
|
231
|
+
export const pow_c = (x, n) => op_c(mul_c(_wrap(n), ln_c(_wrap(x))), one);
|
|
232
|
+
|
|
233
|
+
// ─── Tier 4: Complex constants ────────────────────────────────────────────────
|
|
234
|
+
//
|
|
235
|
+
// ─── ESCAPE FROM THE REALS ───────────────────────────────────────────────────
|
|
236
|
+
//
|
|
237
|
+
// The grammar S → 1 | eml_c(S, S) produces only real values as long as
|
|
238
|
+
// all y-arguments to eml_c are positive reals. The escape to ℂ occurs when
|
|
239
|
+
// a NEGATIVE REAL reaches the y-position, causing ln_c to apply its
|
|
240
|
+
// principal branch and return a value with imaginary part ±π.
|
|
241
|
+
//
|
|
242
|
+
// neg_real(1) = −1 is constructible from the ONE-TERMINAL real grammar
|
|
243
|
+
// (nodes:9, depth:5). All intermediate ln arguments in that construction
|
|
244
|
+
// are positive reals — the negation is achieved without ever applying ln
|
|
245
|
+
// to a negative number. The result −1 is then passed as the y-argument
|
|
246
|
+
// of an outer eml_c, triggering the branch cut.
|
|
247
|
+
//
|
|
248
|
+
// Step 1: z₁ = eml_c(1, −1)
|
|
249
|
+
// = exp(1) − ln_c(−1)
|
|
250
|
+
// = e − iπ [principal branch: arg(−1) = π]
|
|
251
|
+
// Nodes: 10 Depth: 6
|
|
252
|
+
//
|
|
253
|
+
// Step 2: z₂ = eml_c(z₁, 1)
|
|
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
|
|
258
|
+
//
|
|
259
|
+
// Step 3: z₃ = eml_c(1, z₂)
|
|
260
|
+
// = e − ln_c(−exp(e))
|
|
261
|
+
// = e − (e + iπ)
|
|
262
|
+
// = −iπ [exact, one-terminal result]
|
|
263
|
+
// Nodes: 12 Depth: 8
|
|
264
|
+
//
|
|
265
|
+
// IEEE 754 CAVEAT: sin(−π) ≈ −1.22e-16 ≠ 0. In floating-point, z₂ has a
|
|
266
|
+
// tiny negative imaginary part, so atan2 returns −π (not +π), giving:
|
|
267
|
+
// ln_c(z₂)_float = [e, −π], and z₃_float = e − (e − iπ) = +iπ.
|
|
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
|
|
270
|
+
//
|
|
271
|
+
// Full tree (pure EML notation):
|
|
272
|
+
// eml_c(1, eml_c(eml_c(1, neg_real(1)), 1))
|
|
273
|
+
// where neg_real(1) is the 9-node real EML tree for −1.
|
|
274
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
275
|
+
|
|
276
|
+
const _neg_real_one = Complex.of(neg_real(1)); // = −1 via real EML grammar
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* −iπ (or +iπ in floating-point; see ESCAPE comment above).
|
|
280
|
+
*
|
|
281
|
+
* The FIRST complex constant reachable from terminal {1} alone under the
|
|
282
|
+
* complex extension S → 1 | eml_c(S,S). Nodes:12 Depth:8.
|
|
283
|
+
*
|
|
284
|
+
* Verified: |Re| < 1e-10, ||Im| − π| < 1e-10
|
|
285
|
+
*/
|
|
286
|
+
export const NEG_I_PI_C = op_c(one, op_c(op_c(one, _neg_real_one), one));
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* ±iπ/2 — half of NEG_I_PI_C, used to construct i.
|
|
290
|
+
*
|
|
291
|
+
* Construction: mul_c(NEG_I_PI_C, recip_c(2))
|
|
292
|
+
* Requires terminal 2 — see two-terminal grammar discussion.
|
|
293
|
+
* Sign is normalised so that exp_c(I_HALF_PI_C).im > 0.
|
|
294
|
+
*/
|
|
295
|
+
const _raw_half_pi = mul_c(NEG_I_PI_C, recip_c(Complex.of(2)));
|
|
296
|
+
export const I_HALF_PI_C = _raw_half_pi.im < 0
|
|
297
|
+
? _raw_half_pi.neg() // ensure imaginary part is positive
|
|
298
|
+
: _raw_half_pi;
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* i = exp_c(iπ/2)
|
|
302
|
+
*
|
|
303
|
+
* Proven constructible from the two-terminal grammar {1, 2}.
|
|
304
|
+
* Whether the one-terminal grammar {1} suffices is an open problem —
|
|
305
|
+
* see module-level documentation.
|
|
306
|
+
*
|
|
307
|
+
* Verified: |Re| < 1e-10, |Im − 1| < 1e-10
|
|
308
|
+
*/
|
|
309
|
+
export const I_CONST = exp_c(I_HALF_PI_C);
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* π = mul_c(neg_c(i), ±iπ) = (−i)(±iπ) = π
|
|
313
|
+
*
|
|
314
|
+
* Sign adjustment handles the float ambiguity in NEG_I_PI_C.
|
|
315
|
+
* Verified: |Im| < 1e-10, |Re − π| < 1e-10
|
|
316
|
+
*/
|
|
317
|
+
export const PI_C = (() => {
|
|
318
|
+
const candidate = mul_c(neg_c(I_CONST), NEG_I_PI_C);
|
|
319
|
+
// If floating-point gives −π instead of +π, negate.
|
|
320
|
+
return candidate.re < 0 ? candidate.neg() : candidate;
|
|
321
|
+
})();
|
|
322
|
+
|
|
323
|
+
// ─── Tier 5: Euler and trigonometric functions ────────────────────────────────
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Euler's formula as a SINGLE EML expression:
|
|
327
|
+
* eul_c(x) = eml_c(mul_c(i, x), 1) = exp_c(i·x) = cos(x) + i·sin(x)
|
|
328
|
+
*
|
|
329
|
+
* For real x, Re(eul_c(x)) = cos(x) and Im(eul_c(x)) = sin(x).
|
|
330
|
+
*
|
|
331
|
+
* This is the key result: both trig functions are simultaneously encoded in
|
|
332
|
+
* one EML tree. They cannot be separated into standalone EML trees.
|
|
333
|
+
*
|
|
334
|
+
* BRANCH CUT NOTE: For negative real x, arg(i) + arg(x) = π/2 + π = 3π/2 > π.
|
|
335
|
+
* The mul_c arg-sum exceeds the principal branch range. However, exp_c absorbs
|
|
336
|
+
* the 2πi excess correctly — the result is always exp_c(ix). Verified for all
|
|
337
|
+
* real x.
|
|
338
|
+
*
|
|
339
|
+
* @param {Complex} x
|
|
340
|
+
* @returns {Complex}
|
|
341
|
+
*/
|
|
342
|
+
export const eul_c = (x) => op_c(mul_c(I_CONST, _wrap(x)), one);
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* sin(x) = Im(eul_c(x))
|
|
346
|
+
*
|
|
347
|
+
* ⚠ META-OPERATION: this function is NOT an EML tree. It extracts the
|
|
348
|
+
* imaginary part of eul_c(x), which is a step outside the EML grammar.
|
|
349
|
+
* The underlying computation IS an EML expression (eul_c), but sin and cos
|
|
350
|
+
* cannot be independently expressed as EML trees returning a real value.
|
|
351
|
+
*
|
|
352
|
+
* @param {number} x real input
|
|
353
|
+
* @returns {number}
|
|
354
|
+
*/
|
|
355
|
+
export const sin_eml = (x) => eul_c(Complex.of(x)).im;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* cos(x) = Re(eul_c(x))
|
|
359
|
+
*
|
|
360
|
+
* ⚠ META-OPERATION: same caveat as sin_eml. See eul_c.
|
|
361
|
+
*
|
|
362
|
+
* @param {number} x real input
|
|
363
|
+
* @returns {number}
|
|
364
|
+
*/
|
|
365
|
+
export const cos_eml = (x) => eul_c(Complex.of(x)).re;
|
|
366
|
+
|
|
367
|
+
// ─── Branch cut notes ─────────────────────────────────────────────────────────
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Documented constraints on complex EML operations.
|
|
371
|
+
* Each entry describes when a formula fails or degrades.
|
|
372
|
+
*/
|
|
373
|
+
export const BRANCH_CUT_NOTES = [
|
|
374
|
+
{
|
|
375
|
+
fn: "neg_c",
|
|
376
|
+
failsWhen: "|Im(y)| > π",
|
|
377
|
+
symptom: "result gets ±2πi error",
|
|
378
|
+
action: "throws RangeError",
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
fn: "add_c",
|
|
382
|
+
failsWhen: "x = 0",
|
|
383
|
+
symptom: "ln_c(0) is undefined",
|
|
384
|
+
action: "throws RangeError",
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
fn: "ln_c (EML formula)",
|
|
388
|
+
failsWhen: "x near e^e ≈ 15.15",
|
|
389
|
+
symptom: "catastrophic cancellation in intermediate step",
|
|
390
|
+
action: "documented only — use x.ln() directly for high-precision needs",
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
fn: "recip_c",
|
|
394
|
+
failsWhen: "x is negative real (arg = ±π)",
|
|
395
|
+
symptom: "Im(ln_c(x)) = ±π is on the boundary of neg_c's valid range",
|
|
396
|
+
action: "documented as fragile — result is usually correct in IEEE 754 practice",
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
fn: "mul_c result passed to ln_c",
|
|
400
|
+
failsWhen: "arg(x) + arg(y) ∉ (−π, π]",
|
|
401
|
+
symptom: "ln_c(mul_c(x,y)) ≠ ln_c(x) + ln_c(y); off by ±2πi",
|
|
402
|
+
action: "documented only — standalone mul_c is always correct",
|
|
403
|
+
},
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
// ─── Identity table ───────────────────────────────────────────────────────────
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Complexity table for all complex EML identities.
|
|
410
|
+
* Mirrors the IDENTITIES export from index.js with added domain/branchCut/terminal fields.
|
|
411
|
+
*/
|
|
412
|
+
export const IDENTITIES_C = [
|
|
413
|
+
{
|
|
414
|
+
name: "exp_c(x)",
|
|
415
|
+
emlForm: "eml_c(x, 1)",
|
|
416
|
+
nodes: 1, depth: 1,
|
|
417
|
+
domain: "ℂ",
|
|
418
|
+
branchCut: "none",
|
|
419
|
+
terminal: "{1}",
|
|
420
|
+
status: "verified",
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
name: "ln_c(x)",
|
|
424
|
+
emlForm: "eml_c(1, eml_c(eml_c(1,x), 1))",
|
|
425
|
+
nodes: 3, depth: 3,
|
|
426
|
+
domain: "ℂ \\ {0}",
|
|
427
|
+
branchCut: "negative real axis",
|
|
428
|
+
terminal: "{1}",
|
|
429
|
+
status: "verified",
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
name: "sub_c(x,y)",
|
|
433
|
+
emlForm: "eml_c(ln_c(x), exp_c(y))",
|
|
434
|
+
nodes: 5, depth: 4,
|
|
435
|
+
domain: "x ≠ 0; Im(y) ∈ (−π, π]",
|
|
436
|
+
branchCut: "y near ±πi",
|
|
437
|
+
terminal: "{1}",
|
|
438
|
+
status: "verified",
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
name: "neg_c(y)",
|
|
442
|
+
emlForm: "shift: eml_c(0, eml_c(y+1, 1)) = 1 − ln_c(exp_c(y+1))",
|
|
443
|
+
nodes: 9, depth: 5,
|
|
444
|
+
domain: "Im(y) ∈ (−π−1, π−1]",
|
|
445
|
+
branchCut: "Im(y) = ±π (boundary, fragile)",
|
|
446
|
+
terminal: "{1}",
|
|
447
|
+
status: "proven",
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
name: "add_c(x,y)",
|
|
451
|
+
emlForm: "eml_c(ln_c(x), eml_c(neg_c(y), 1))",
|
|
452
|
+
nodes: 11, depth: 6,
|
|
453
|
+
domain: "x ≠ 0; Im(y) ∈ (1−π, π−1]",
|
|
454
|
+
branchCut: "propagated from neg_c",
|
|
455
|
+
terminal: "{1}",
|
|
456
|
+
status: "proven",
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
name: "mul_c(x,y)",
|
|
460
|
+
emlForm: "eml_c(add_c(ln_c(x), ln_c(y)), 1)",
|
|
461
|
+
nodes: 13, depth: 7,
|
|
462
|
+
domain: "x ≠ 0, y ≠ 0",
|
|
463
|
+
branchCut: "result correct; ln of result off by ±2πi when arg(x)+arg(y)∉(−π,π]",
|
|
464
|
+
terminal: "{1}",
|
|
465
|
+
status: "proven",
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
name: "recip_c(x)",
|
|
469
|
+
emlForm: "eml_c(neg_c(ln_c(x)), 1)",
|
|
470
|
+
nodes: 5, depth: 4,
|
|
471
|
+
domain: "x ≠ 0",
|
|
472
|
+
branchCut: "x negative real: arg = ±π on neg_c boundary (fragile)",
|
|
473
|
+
terminal: "{1}",
|
|
474
|
+
status: "verified",
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: "div_c(x,y)",
|
|
478
|
+
emlForm: "eml_c(add_c(ln_c(x), neg_c(ln_c(y))), 1)",
|
|
479
|
+
nodes: 15, depth: 8,
|
|
480
|
+
domain: "x ≠ 0, y ≠ 0",
|
|
481
|
+
branchCut: "propagated from neg_c, recip_c",
|
|
482
|
+
terminal: "{1}",
|
|
483
|
+
status: "proven",
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
name: "pow_c(x,n)",
|
|
487
|
+
emlForm: "eml_c(mul_c(n, ln_c(x)), 1)",
|
|
488
|
+
nodes: 15, depth: 8,
|
|
489
|
+
domain: "x ≠ 0",
|
|
490
|
+
branchCut: "principal-value power only",
|
|
491
|
+
terminal: "{1}",
|
|
492
|
+
status: "proven",
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
name: "−iπ",
|
|
496
|
+
emlForm: "eml_c(1, eml_c(eml_c(1, neg_real(1)), 1))",
|
|
497
|
+
nodes: 12, depth: 8,
|
|
498
|
+
domain: "constant",
|
|
499
|
+
branchCut: "branch cut at z₂ = −exp(e); float gives +iπ or −iπ",
|
|
500
|
+
terminal: "{1}",
|
|
501
|
+
status: "proven",
|
|
502
|
+
note: "First non-real value constructible from a single real terminal",
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
name: "i",
|
|
506
|
+
emlForm: "exp_c(mul_c(∓iπ, recip_c(2)))",
|
|
507
|
+
nodes: 22, depth: 14,
|
|
508
|
+
domain: "constant",
|
|
509
|
+
branchCut: "none at final step",
|
|
510
|
+
terminal: "{1, 2}",
|
|
511
|
+
status: "proven",
|
|
512
|
+
note: "Whether terminal {1} alone suffices is an OPEN PROBLEM",
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
name: "π",
|
|
516
|
+
emlForm: "mul_c(neg_c(i), ∓iπ)",
|
|
517
|
+
nodes: 32, depth: 16,
|
|
518
|
+
domain: "constant",
|
|
519
|
+
branchCut: "none at final step",
|
|
520
|
+
terminal: "{1, 2}",
|
|
521
|
+
status: "proven",
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
name: "eul_c(x) = exp_c(ix)",
|
|
525
|
+
emlForm: "eml_c(mul_c(i, x), 1)",
|
|
526
|
+
nodes: 15, depth: 11,
|
|
527
|
+
domain: "ℂ",
|
|
528
|
+
branchCut: "mul_c arg-sum may exceed π for neg real x; exp_c absorbs excess",
|
|
529
|
+
terminal: "{1, 2}",
|
|
530
|
+
status: "proven",
|
|
531
|
+
note: "Single EML expression encoding both cos and sin simultaneously",
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: "sin(x)",
|
|
535
|
+
emlForm: "Im(eul_c(x)) ← meta-operation",
|
|
536
|
+
nodes: null, depth: null,
|
|
537
|
+
domain: "x ∈ ℝ",
|
|
538
|
+
branchCut: "not applicable",
|
|
539
|
+
terminal: "{1, 2}",
|
|
540
|
+
status: "meta-operation",
|
|
541
|
+
note: "Not an EML tree. Im/Re extraction is outside the grammar.",
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
name: "cos(x)",
|
|
545
|
+
emlForm: "Re(eul_c(x)) ← meta-operation",
|
|
546
|
+
nodes: null, depth: null,
|
|
547
|
+
domain: "x ∈ ℝ",
|
|
548
|
+
branchCut: "not applicable",
|
|
549
|
+
terminal: "{1, 2}",
|
|
550
|
+
status: "meta-operation",
|
|
551
|
+
note: "Not an EML tree. Im/Re extraction is outside the grammar.",
|
|
552
|
+
},
|
|
553
|
+
];
|
|
554
|
+
|
|
555
|
+
export default {
|
|
556
|
+
op_c, E_C, ZERO_C, NEG_ONE_C,
|
|
557
|
+
exp_c, ln_c,
|
|
558
|
+
sub_c, neg_c, add_c, mul_c, recip_c, div_c, pow_c,
|
|
559
|
+
NEG_I_PI_C, I_HALF_PI_C, I_CONST, PI_C,
|
|
560
|
+
eul_c, sin_eml, cos_eml,
|
|
561
|
+
IDENTITIES_C, BRANCH_CUT_NOTES,
|
|
562
|
+
};
|