Metadata-Version: 2.4
Name: emltree
Version: 0.1.1
Summary: Compile elementary-function formulas into pure EML (Exp-Minus-Log) form
Project-URL: Homepage, https://github.com/gba3124/emltree
Project-URL: Repository, https://github.com/gba3124/emltree
Project-URL: Paper, https://arxiv.org/abs/2603.21852
Author: Wei-Chien Hsiao
License: MIT
License-File: LICENSE
Keywords: eml,math,sheffer,symbolic,symbolic-regression,sympy
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Python: >=3.10
Requires-Dist: numpy>=1.26
Requires-Dist: sympy>=1.12
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# emltree

Compile elementary-function formulas into pure **EML (Exp-Minus-Log)** form,
where the only operator is

```
eml(x, y) = exp(x) − ln(y)
```

and the only constant is `1`.

## Paper

This project is an implementation of ideas introduced in:

> **Andrzej Odrzywolek.** *All elementary functions from a single operator.*
> arXiv:2603.21852 (2026).
> [https://arxiv.org/abs/2603.21852](https://arxiv.org/abs/2603.21852)

The paper proves that the single binary operator `eml(x, y) = exp(x) − ln(y)`
together with the constant `1` generates the entire scientific-calculator
basis (arithmetic, roots, logs, all trig and hyperbolic functions, the
constants `e`, `π`, `i`). Every elementary expression becomes a binary
tree whose only internal node is `eml`. This package is the inverse
direction: it **takes an ordinary formula and compiles it into that
tree**. A sibling Rust crate, [OxiEML](https://github.com/cool-japan/oxieml),
covers the Rust ecosystem; a zero-dependency JS/TypeScript port lives in
[`js/`](./js) (npm: `emltree`); this package is the Python side.

## Quick start

```bash
uv venv --python 3.11
uv pip install -e ".[dev]"

# Compile a formula
uv run emltree "sin(x) + exp(y)" -v x -v y

# ASCII tree
uv run emltree "log(x)" -v x -f tree

# Numerical sanity check
uv run emltree "sin(x)**2 + cos(x)**2" -v x=0.9 --verify
```

## Library use

```python
from emltree import compile_formula, evaluate

tree = compile_formula("sqrt(x**2 + y**2)", variables=["x", "y"])
print(tree.to_nested())
print(evaluate(tree, {"x": 3.0, "y": 4.0}))   # ≈ 5+0j
```

The returned tree is an immutable ADT (`One` / `Var` / `Eml`) — walk it,
hash it, render as RPN (`exp(x)` is `x 1 E`), or ship it into an
FPGA/analog circuit as the paper suggests.

Evaluation is vectorised: pass numpy arrays as bindings and the tree
evaluates elementwise.

```python
import numpy as np
xs = np.linspace(-2, 2, 1000)
evaluate(tree, {"x": xs, "y": xs})   # array of 1000 values
```

## Why the trees are large

This compiler is **compositional**, not optimal. Every primitive bottoms
out in `exp / ln / sub`, so `sin(x)` produces a tree with hundreds of
nodes. The paper's direct-search results (Table 4) are vastly shorter —
integrating that search is one of the open directions below.

## Numerical caveats

- **Branch cuts**: outside their real domains (`asin(2)`, `acosh(-2)`,
  `log` of negatives, …) results flow through complex branch cuts and may
  land on a non-principal branch — or, where float fuzz compounds,
  off-sheet entirely (paper §4.1). On the usual real domains everything
  matches sympy to ~1e-7.
- **Addition overflow**: `add_`'s expansion applies `exp()` to its second
  operand, so adding values past ~709 overflows float64. Integer/decimal
  constants avoid this internally (binary decomposition with a
  multiplicative odd step), but `x + y` with huge `y` is an inherent
  ceiling of the encoding.

## Tests

```bash
uv run pytest
```

## Contributing

Contributions are very welcome — this is an early-stage package and
there's plenty of room to improve. A few directions that would make a
great first PR:

- **Shorter trees** — hand-curated or searched EML identities to
  replace the naive compositional expansions (see paper Table 4).
- **More primitives** — `abs`, `sign`, `floor`, `ceil`, `erf`, etc.
  (many require tricks; see the paper's supplementary).
- **Better output** — LaTeX, GraphViz / Mermaid, Jupyter rich repr.
- **Torch evaluation** — numpy bindings already vectorise; a torch
  evaluator would make EML trees differentiable end-to-end.
- **Optional Rust backend** — PyO3 bindings to
  [OxiEML](https://github.com/cool-japan/oxieml) for expensive search
  and symbolic regression.
- **Docs & examples** — walk-throughs of the paper's identities,
  notebooks showing symbolic-regression use cases.

Please open an issue to discuss before sending a large PR. Bug reports,
documentation fixes, and additional test cases are also very welcome —
no contribution is too small.

### Development

```bash
uv venv --python 3.11
uv pip install -e ".[dev]"
uv run pytest
```

## License

MIT — see [LICENSE](./LICENSE).

## Citation

If you use `emltree` in academic work, please cite **both** the paper and
the software:

```bibtex
@article{odrzywolek2026eml,
  title   = {All elementary functions from a single operator},
  author  = {Odrzywolek, Andrzej},
  journal = {arXiv preprint arXiv:2603.21852},
  year    = {2026}
}

@software{hsiao2026emltree,
  author  = {Hsiao, Wei-Chien},
  title   = {emltree: a Python compiler from elementary formulas to EML trees},
  year    = {2026},
  url     = {https://github.com/gba3124/emltree},
  version = {0.1.1}
}
```
