- Saegert & Köthe 2026, Breaking the Simplification Bottleneck in Amortized Neural Symbolic Regression (preprint, under review) https://arxiv.org/abs/2602.08885
pip install simplipyThe compiled Rust extension (
simplipy._core) is required: the inline phase (simplify, conversions, validation) runs on it exclusively, and there is no pure-Python fallback. Prebuilt wheels are published for Linux (x86_64/aarch64), macOS (x86_64/arm64) and Windows (x64) on CPython ≥ 3.11, sopip install simplipydoes not compile anything for most users. Installing from the source distribution (an unsupported platform, or--no-binary) requires a Rust toolchain (rustup, MSRV 1.83). If the extension is missing at runtime, constructing an engine raisesImportError.
import simplipy as sp
engine = sp.SimpliPyEngine.load("4-3", install=True) # a published ruleset artifact
# Simplify prefix expressions
engine.simplify(('/', '<constant>', '*', '/', '*', 'x3', '<constant>', 'x3', 'log', 'x3'))
# > ('/', '<constant>', 'log', 'x3')
# Simplify infix expressions
engine.simplify('x3 * sin(<constant> + 1) / (x3 * x3)')
# > '<constant> / x3'The root-exported normalize_skeleton, normalize_expression, and
normalize_variable_token helpers (also available as simplipy.normalization)
canonicalize a prefix token sequence so that two expressions that are "the same"
up to variable renaming / constant values compare equal. They are pure-string
helpers with no engine state, so consumers such as holdout matching and
symbolic-recovery scoring share identical behavior by construction.
import simplipy as sp
# Skeleton form: variables -> x{n}, numeric literals -> <constant>
sp.normalize_skeleton(['+', 'v1', '2.5'])
# > ['+', 'x1', '<constant>']
# Expression form: variables canonicalized, numeric literals kept intact
sp.normalize_expression(['+', 'V1', '2.5'])
# > ['+', 'x1', '2.5']
# Classify / canonicalize a single token -> (normalized_token, is_variable)
sp.normalize_variable_token('X3')
# > ('x3', True)
sp.normalize_variable_token('sin')
# > ('sin', False)More examples can be found in the documentation.
As of 0.6.0 the simplify hot path defers match-time certificates to completed matches
(memoized generationally, never stopping memoization), memoizes whole fixpoint passes and
rule-normal subtrees, and runs on interned token ids (~20× fewer allocations per call) —
all at byte-identical outputs. On a 65,536-expression training-prior benchmark, large
certificate-bearing rulesets simplify ~59× faster than 0.5.0 and certificate-free
rulesets ~2.3× faster; see the CHANGELOG
for details. Since 0.7.0 there is a single compiled engine line; the published ruleset
artifacts (2-1, 3-2, 4-3, …) are the distinguishing factor between engines. Rule
application always considers every pattern in the loaded artifact (the former
max_pattern_length knob was removed in 0.10.0). (To reproduce the historical dev_7-3 /
v23.0-era behavior byte-for-byte, install simplipy<=0.6.0.)
|
Empirical Cumulative Distribution Functions (ECDFs) of simplification wall-clock time (top row) and simplification ratio |
To set up the development environment, run the following commands:
pip install -e .[dev]
pre-commit installTest the package with pytest:
pytest tests --cov src --cov-report htmlor to skip integration tests,
pytest tests --cov src --cov-report html -m "not integration"@misc{saegert2026breakingsimplificationbottleneckamortized,
title = {Breaking the Simplification Bottleneck in Amortized Neural Symbolic Regression},
author = {Paul Saegert and Ullrich Köthe},
year = {2026},
eprint = {2602.08885},
archivePrefix = {arXiv},
primaryClass = {cs.LG},
url = {https://arxiv.org/abs/2602.08885},
}
% Optionally
@software{simplipy-2025,
author = {Paul Saegert},
title = {Efficient Simplification of Mathematical Expressions},
year = 2026,
publisher = {GitHub},
version = {0.9.1},
url = {https://github.com/psaegert/simplipy}
}