SimpliPy Documentation¶
SimpliPy is a high-throughput symbolic simplifier built for workloads where classic tools like SymPy struggle—think millions of expressions in the pre-training of prefix-based transformer models. Instead of converting tokens into heavyweight objects and back again, SimpliPy keeps expressions as lightweight prefix lists, enabling rapid rewriting and direct integration with machine learning pipelines.
SimpliPy is the shared expression-engine leaf of a four-package family:
simplipy ◄── symbolic-data ◄── { flash-ansr, srbf }. Its direct
downstream is symbolic-data, the model-agnostic symbolic-regression data
layer, and through it SimpliPy feeds Flash-ANSR training and the srbf benchmark
framework.
Why SimpliPy Exists¶
SymPy excels at exact algebra, but its object graph and string parsing introduce costs that dominate at scale. SimpliPy was created to remove those bottlenecks:
- Prefix-first representation – Expressions stay as token lists the entire time, so there's no repeated parsing or AST allocation.
- Deterministic pipelines – Rule application, operand sorting, and literal masking always produce the same layout, which keeps downstream caches warm.
- ML-pipeline integration – Outputs stay in the prefix token space consumed
by the
symbolic-datalayer (and through it by Flash-ANSR training) without any conversion step, making it practical to simplify millions of candidates per minute.
Performance¶
As of 0.3.0 the inline phase (simplify, conversions, validation) runs in a compiled Rust
extension (simplipy._core), a large speed-up over the previous pure-Python engine at identical
simplification behaviour.
ECDFs of simplification wall-clock time (left) and simplification ratio (right) across maximum
pattern lengths L_max = 0–7. Top: SimpliPy 0.3.0 (Rust, green); bottom: SimpliPy
0.2.15 (pure Python, blue); the SymPy baseline is orange/red. The Rust inline engine is roughly
5× to 100× faster than the pure-Python engine at the same L_max (≈ 15× at L_max = 4) and orders
of magnitude faster than SymPy, while producing near-identical simplification ratios.
Simplification Pipeline (Pseudo-Algorithm)¶
function simplify(expr, max_iter=5):
tokens = parse(expr) # infix→prefix or validate existing prefix
tokens = normalize(tokens) # power folding, unary handling
for _ in range(max_iter):
tokens = cancel_terms(tokens) # additive/multiplicative multiplicities
tokens = apply_rules(tokens) # compiled rewrite patterns
tokens = sort_operands(tokens) # canonical order for commutative ops
tokens = mask_literals(tokens) # collapse trivial numerics to <constant>
if converged(tokens):
break
return finalize(tokens) # prefix list or infix string, caller's choice
This loop is intentionally lightweight: each pass performs a handful of pure list transformations, giving you predictable performance even on nested or noisy expressions.
Key Components¶
- Parsing & normalization –
SimpliPyEngine.parseandSimpliPyEngine.convert_expressionconvert infix input, harmonize power operators, and propagate unary negation without losing prefix fidelity. - Term cancellation –
SimpliPyEngine.collect_multiplicitiesandSimpliPyEngine.cancel_termsidentify subtrees that appear with opposite parity or redundant factors, pruning them before any rules run. - Rule execution –
SimpliPyEngine.compile_rulesturns machine-discovered or human-authored simplifications into tree patterns.SimpliPyEngine.apply_simplifcation_rulesthen performs fast top-down matching in each iteration. - Canonical ordering –
SimpliPyEngine.sort_operandsimposes a stable ordering for commutative operators, ensuring identical expressions share identical token layouts. - Rule discovery workflow –
SimpliPyEngine.find_rulesexplores expression space in parallel worker processes, confirms identities with numeric sampling, and writes back deduplicated rulesets that future engines can load instantly.
Quickstart¶
import simplipy as sp
engine = sp.SimpliPyEngine.load("dev_7-3", install=True)
# 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'
Available engines can be browsed and downloaded from Hugging Face. The SimpliPy Asset Manager handles listing, installing, and uninstalling assets:
sp.list_assets("engine")
# --- Available Assets ---
# - dev_7-3 [installed] Development engine 7-3 for mathematical expression simplification.
# - dev_7-2 Development engine 7-2 for mathematical expression simplification.
Normalization¶
Besides the engine, SimpliPy exports pure-string normalization helpers at the
package root: normalize_skeleton, normalize_expression, and
normalize_variable_token (also available as simplipy.normalization). They
canonicalize a prefix token sequence so that two expressions that are "the same"
up to variable renaming / constant values compare equal, giving downstream
consumers (holdout matching, symbolic-recovery scoring) 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)
See the Normalization API reference for details.
Where to go next¶
- Explore the API reference for function-level details.
- Read the rule authoring guide to build simplification rule sets.
Happy simplifying!