-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.html
More file actions
134 lines (134 loc) · 8.86 KB
/
Copy pathREADME.html
File metadata and controls
134 lines (134 loc) · 8.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<h1 id="eml-all-elementary-functions-from-a-single-operator">eml — all
elementary functions from a single operator</h1>
<p>A Python implementation of the EML (Exp-Minus-Log) operator from</p>
<blockquote>
<p>A. Odrzywołek, <em>All elementary functions from a single
operator</em>, arXiv:<a
href="https://arxiv.org/abs/2603.21852">2603.21852</a>, April 2026.</p>
</blockquote>
<p>The paper shows that the binary operator</p>
<pre><code>eml(x, y) = exp(x) - ln(y)</code></pre>
<p>paired with the constant <code>1</code>, suffices to construct every
primitive of a scientific calculator: integers and fractions, the
constants <code>e</code>, <code>π</code>, <code>i</code>, the four
arithmetic operations, the trig / inverse-trig / hyperbolic /
inverse-hyperbolic family, exponentiation and logarithms to arbitrary
base, <code>√</code>, <code>sigmoid</code>, and so on.</p>
<p>This package gives that operator the full Python toolchain: an
expression-tree compiler, a single-instruction stack machine, a sympy
bridge, gradient-based symbolic regression, exhaustive search for
shortest chains, mpmath verification at arbitrary precision, and a
matplotlib renderer that draws each chain as the EML circuit symbol from
the paper.</p>
<h2 id="quickstart">Quickstart</h2>
<div class="sourceCode" id="cb2"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> eml <span class="im">import</span> eml, parse_rpn</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Two canonical identities:</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>eml(<span class="dv">1</span>, <span class="dv">1</span>) <span class="co"># 2.718281828459045 (the constant e)</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>parse_rpn(<span class="st">"11xE1EE"</span>)(x<span class="op">=</span><span class="fl">7.5</span>)</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="co"># 2.0149030205422647 (== math.log(7.5); the ln chain from Eq. (5))</span></span></code></pre></div>
<p>Every Table-1 primitive is one call away:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> eml.library <span class="im">import</span> build_unary, build_constant</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>build_unary(<span class="st">"sin"</span>, <span class="st">"x"</span>)(x<span class="op">=</span><span class="fl">1.0</span>) <span class="co"># sin(1) via EML</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>build_constant(<span class="st">"pi"</span>)() <span class="co"># π via EML (K=233)</span></span></code></pre></div>
<p>Verify the whole library at 40-digit mpmath precision:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python</span> examples/07_verify_library.py</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co"># ...</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># 41/41 passed</span></span></code></pre></div>
<h2 id="modules">Modules</h2>
<table>
<colgroup>
<col style="width: 17%" />
<col style="width: 82%" />
</colgroup>
<thead>
<tr>
<th>module</th>
<th>what it does</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>eml.core</code></td>
<td>scalar / NumPy ufunc / mpmath implementations of <code>eml</code>,
<code>edl</code>, <code>−eml</code></td>
</tr>
<tr>
<td><code>eml.tree</code></td>
<td>AST for the grammar <code>S → 1 \| eml(S, S)</code>, RPN round-trip,
sympy bridge</td>
</tr>
<tr>
<td><code>eml.library</code></td>
<td>every primitive of Table 1 expressed as a concrete EML chain
(verified)</td>
</tr>
<tr>
<td><code>eml.sympy_eml</code></td>
<td>a SymPy <code>Function</code> <code>EmlFn</code>, with auto-eval,
<code>fdiff</code>, <code>evalf</code>, <code>rewrite</code></td>
</tr>
<tr>
<td><code>eml.vm</code></td>
<td>single-instruction stack VM (compile / disassemble / trace /
bytestream)</td>
</tr>
<tr>
<td><code>eml.search</code></td>
<td>brute-force shortest-EML search (the <em>Direct search</em> column
of Table 4)</td>
</tr>
<tr>
<td><code>eml.regression</code></td>
<td>the level-<code>n</code> master formula (<code>5·2ⁿ − 6</code>
simplex parameters), Adam, snap-to-vertex</td>
</tr>
<tr>
<td><code>eml.verify</code></td>
<td>Schanuel-witness verification (γ, A) at arbitrary mpmath
precision</td>
</tr>
<tr>
<td><code>eml.viz</code></td>
<td>ASCII tree + matplotlib EML-circuit renderer (Fig. 2)</td>
</tr>
<tr>
<td><code>eml.cousins</code></td>
<td>EDL (<code>exp/ln</code>, paired with <code>e</code>) and
<code>−eml(y,x)</code> (<code>ln−exp</code>, paired with
<code>−∞</code>)</td>
</tr>
</tbody>
</table>
<h2 id="examples">Examples</h2>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/01_canonical_identities.py <span class="co"># ln, exp, e, 0</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/02_compile_function.py <span class="co"># build any primitive</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/03_visualise.py <span class="co"># render Fig.-2-style trees</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/04_vm_bytecode.py <span class="co"># run on the EML stack VM</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/05_search.py <span class="co"># find shortest chains</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/06_symbolic_regression.py <span class="co"># recover exp(x) from data</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/07_verify_library.py <span class="co"># verify all 41 primitives</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/08_sympy_calculus.py <span class="co"># symbolic diff/simplify</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> examples/09_cousins.py <span class="co"># EDL and −EML in action</span></span></code></pre></div>
<h2 id="tests">Tests</h2>
<div class="sourceCode" id="cb6"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="va">PYTHONPATH</span><span class="op">=</span>. <span class="ex">python</span> <span class="at">-m</span> pytest tests/</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="co"># 77 passed</span></span></code></pre></div>
<h2 id="notes-on-numerical-edge-cases">Notes on numerical edge
cases</h2>
<p>EML chains intentionally route through <code>ln(0) = −∞</code> and
<code>exp(−∞) = 0</code> when constructing the constant <code>0</code>,
the negation function <code>−x</code>, and a few of their dependents
(cf. Table 4 column “without extended reals”). NumPy honours this via
signed zeros and infinities, so the chains “just work” in IEEE-754; the
<code>core.eml</code> implementation suppresses the benign
divide-by-zero RuntimeWarning that the principal <code>log(0)</code>
raises.</p>
<p>The principal-branch convention means the chain that the paper writes
for <code>i</code> lands on <code>−i</code> — see §4.1 (“manually
correct i sign”). The helper <code>eml.core.fix_i_sign</code> performs
that one-line correction.</p>