2026-04-19 theorem 5 min read

The Infinite Zeros Barrier

Why sin(x) cannot be expressed as a finite real EML tree — and why that matters.

Correction (2026-09-13): the two-step proof below does not work. A finite real EML tree is real-analytic with isolated zeros, but so is sin, and sin has only finitely many zeros on any bounded interval, so there is no contradiction. The zero-count route needs a bound on how many zeros a tree can have, which is open (T14). The theorem holds: it is proved in Lean by periodicity (MachLib, sin_not_in_eml_any_depth_unconditional). The search is re-run below up to 8 nodes; the 11- and 12-node figures are from the original run, which has no public script.

The EML operator eml(x, y) = exp(x) − ln(y) generates every elementary function as a finite binary tree. That's the claim in arXiv:2603.21852. So why isn't sin(x) on the easy list?

The answer is clean, though the proof this post first gave does not reach it.

The theorem

No finite real-valued EML tree with terminals {1, x} equals sin(x) for all x ∈ ℝ.

The proof first given here had two steps:

Step 1. Every finite EML tree is a composition of exp and ln applied to polynomials. Each such composition is real-analytic on its domain.

Step 2. By the analytic identity theorem, a non-zero real-analytic function has isolated zeros — which means finitely many on any bounded interval. But sin(x) has a zero at every integer multiple of π. No bounded interval avoids infinitely many of them. Contradiction.

Step 2 does not follow. sin is itself real-analytic with isolated zeros, and any bounded interval holds only finitely many of them, so nothing is contradicted. To finish this route you need a bound, uniform over the trees, on how many zeros a tree can have on an interval, and that bound is open (T14). MachLib's Lean proof avoids zero counting and uses periodicity instead.

A zero bound, if proved, would also rule out functions with infinitely many real zeros that are not periodic, such as Bessel J₀ and Airy Ai. The periodicity proof covers sin and cos.

Empirical confirmation

The search first reported here enumerated all EML trees up to 11 nodes — 281,026,468 trees total — against sin(x) at test points {0, π/6, π/4, π/2, π}, with zero candidates at tolerances 10⁻⁴, 10⁻⁶ and 10⁻⁹, and a Rust implementation extended it to N=12 (1.704 billion trees). The counts are right: there are Catalan(n)·2ⁿ⁺¹ trees with n nodes over {1, x}, which sum to 281,026,468 for n ≤ 11, and n = 12 adds 1,704,034,304. That run has no public script and was not repeated. The script below repeats it up to 8 nodes (862,116 trees), where the best tree misses sin by 0.33 at the five points.

A search is not a proof either; MachLib's theorem is.

The bypass

The barrier is specific to real-valued trees. Over the complex numbers, Euler's formula gives us an exact route in a single node:

Im(eml(ix, 1)) = Im(exp(ix)) = sin(x)

One node. Machine precision. The barrier doesn't disappear — it means you can't do it with real arithmetic. Complex arithmetic is not "cheating"; it's a different domain.

Why it matters

The barrier is a structural fact about function spaces. It says something precise about what finite tree computation can and cannot do. The EML depth hierarchy — where sin is depth 1 over ℂ (the one node above, with ix as the input) and has no finite tree over ℝ — is grounded in this structural distinction.

It also connects to open problems. The complex bypass works because ix is available as input. Whether i is constructible from {1} alone depends on the semantics: under strict real semantics it is not (T17), and under the complex principal branch it is open. It was posted as the i-constructibility challenge on monogate.dev's challenge board, which was archived on 2026-09-12.

Reproduce

Every EML tree over {1, x} with at most 8 nodes, evaluated at the five test points (a tree undefined at one of them is skipped), keeping each distinct vector of values:

import math, numpy as np                               # pip install numpy
np.seterr(all='ignore')
pts = np.array([0, math.pi/6, math.pi/4, math.pi/2, math.pi])
levels = [[np.ones(5), pts]]                            # levels[n]: distinct values of n-node EML trees over {1, x}
best, trees = math.inf, 0
for n in range(1, 9):
    vals, seen = [], set()
    for i in range(n):
        for a in levels[i]:
            for b in levels[n - 1 - i]:
                v = np.exp(a) - np.log(b)              # undefined where b <= 0: the tree is skipped
                k = tuple(np.round(v, 12))
                if np.all(np.isfinite(v)) and k not in seen:
                    seen.add(k); vals.append(v); best = min(best, float(np.max(np.abs(v - np.sin(pts)))))
    levels.append(vals)
    trees += math.comb(2 * n, n) // (n + 1) * 2 ** (n + 1)
    print(f'<= {n} nodes: {trees:,} trees; best max |T - sin| at the 5 points so far: {best:.3g}')

Output:

<= 1 nodes: 4 trees; best max |T - sin| at the 5 points so far: 2.72
<= 2 nodes: 20 trees; best max |T - sin| at the 5 points so far: 1.72
<= 3 nodes: 100 trees; best max |T - sin| at the 5 points so far: 1
<= 4 nodes: 548 trees; best max |T - sin| at the 5 points so far: 0.891
<= 5 nodes: 3,236 trees; best max |T - sin| at the 5 points so far: 0.541
<= 6 nodes: 20,132 trees; best max |T - sin| at the 5 points so far: 0.541
<= 7 nodes: 129,956 trees; best max |T - sin| at the 5 points so far: 0.528
<= 8 nodes: 862,116 trees; best max |T - sin| at the 5 points so far: 0.33

Code: pip install monogate · Paper: arXiv:2603.21852