Skip to content

Repository files navigation

Actions Status Documentation Status codecov

PyPI version Conda-Forge PyPI platforms

GitHub Discussion Scikit-HEP

Formulate

Easy conversions between different styles of expressions. Formulate converts in either direction between ROOT (TTreeFormula) and numexpr style expressions, and can also render a parsed expression as plain Python using NumPy functions.

It needs neither ROOT nor numexpr installed — it reads and writes their syntax, it does not evaluate anything — and it knows the places where the two languages disagree, such as && and & binding differently against comparisons, or ^ meaning exponentiation in one and XOR in the other.

Full documentation: https://formulate.readthedocs.io/

Installation

Install formulate like any other Python package, ideally inside a virtual environment:

pip install formulate

or using conda:

conda install -c conda-forge formulate

(-c conda-forge is only needed if you don't have the conda-forge channel already configured)

Roadmap and releases

For the roadmap, planned features, breaking changes and versioning please see the roadmap.

Usage

API

The most basic usage involves calling from_$BACKEND and then to_$BACKEND, for example when starting with a ROOT style expression:

>>> import formulate
>>> momentum = formulate.from_root("TMath::Sqrt(X_PX**2 + X_PY**2 + X_PZ**2)")
>>> momentum
Call(function='sqrt', arguments=[BinaryOperator(operator='add', left=BinaryOperator(operator='add', left=BinaryOperator(operator='pow', left=Symbol(name='X_PX'), right=Literal(value=2)), right=BinaryOperator(operator='pow', left=Symbol(name='X_PY'), right=Literal(value=2))), right=BinaryOperator(operator='pow', left=Symbol(name='X_PZ'), right=Literal(value=2)))])
>>> momentum.to_numexpr()
'sqrt((((X_PX ** 2) + (X_PY ** 2)) + (X_PZ ** 2)))'
>>> momentum.to_root()
'TMath::Sqrt((((X_PX ** 2) + (X_PY ** 2)) + (X_PZ ** 2)))'

Similarly, when starting with a numexpr style expression:

>>> my_selection = formulate.from_numexpr("(X_PT > 5) & ((Mu_NHits > 3) | (Mu_PT > 10))")
>>> my_selection.to_root()
'((X_PT > 5) && ((Mu_NHits > 3) || (Mu_PT > 10)))'
>>> my_selection.to_numexpr()
'((X_PT > 5) & ((Mu_NHits > 3) | (Mu_PT > 10)))'

Any parsed expression can also be rendered as Python, using NumPy for the functions. This direction is output-only — there is no from_python:

>>> momentum.to_python()
'np.sqrt((((X_PX ** 2) + (X_PY ** 2)) + (X_PZ ** 2)))'

Parsing is separate from rendering, so parse once and convert as many times as you like. An expression also reports what it refers to, which is how you work out what a selection needs to read:

>>> expression = formulate.from_root("TMath::Sqrt(px**2 + py**2) > 5 * TMath::Pi() + 1.5")
>>> list(expression.variables)
['px', 'py']
>>> list(expression.named_constants)
['pi']
>>> list(expression.unnamed_constants)
[2, 5, 1.5]

CLI

The package also provides a command-line interface for converting expressions between different styles. To use it, simply run the formulate command followed by the input expression and the desired output.

$ formulate --from-root '(A && B) || TMath::Sqrt(A)' --to-numexpr
((A & B) | sqrt(A))

$ formulate --from-numexpr '(A & B) | sqrt(A)' --to-root
((A && B) || TMath::Sqrt(A))

$ formulate --from-root 'TMath::Sqrt(A)' --to-python
np.sqrt(A)

$ formulate --from-root '(A && B) || TMath::Sqrt(1.23) * e_num**1.2 + 5*pi' --variables
A
B

$ formulate --from-root '(A && B) || TMath::Sqrt(1.23) * e_num**1.2 + 5*pi' --named-constants
exp1
pi

$ formulate --from-root '(A && B) || TMath::Sqrt(1.23) * e_num**1.2 + 5*pi' --unnamed-constants
1.23
1.2
5

Run formulate --help for the full list of options.

Documentation

About

Easy conversions between different styles of expressions

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages