Skip to content
Easy conversions between different styles of expressions
Branch: master
Clone or download
chrisburr Merge pull request #22 from scikit-hep/add-subvariables
Add rudimentary support for nested variables
Latest commit ea7703d Oct 15, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
formulate Version bump Oct 15, 2018
tests Improve test and ensure the README is actually valid Feb 27, 2018
.coveragerc
.gitignore Initial commit for selections v3 Feb 10, 2018
.travis.yml Add numexpr to travis Feb 27, 2018
LICENSE
Makefile Add more tests, operators and initial to_string method Feb 11, 2018
README.rst Update README to reflect move to scikit-hep Feb 27, 2018
conftest.py Fix order of operations and add some extreme tests Feb 11, 2018
setup.cfg Add travis config Feb 10, 2018
setup.py

README.rst

Formulate

Build Status Coverage Status PyPI

Easy conversions between different styles of expressions. Formulate currently supports converting between ROOT and numexpr style expressions.

Installation

Install formulate like any other Python package:

pip install --user formulate

or similar (use `sudo, `virtualenv, or `conda` if you wish).

Usage

Command line usage

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

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

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

$ python -m formulate --from-root '(A && B) || TMath::Sqrt(1.23) * e**1.2 + 5*pi' --named-constants
E
PI

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

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
Expression<SQRT>(Expression<ADD>(Expression<POW>(Variable(X_PX), UnnamedConstant(2)), Expression<POW>(Variable(X_PY), UnnamedConstant(2)), Expression<POW>(Variable(X_PZ), UnnamedConstant(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))'

If the the type of expression isn't known in advance formulate can also auto detect it:

>>> my_sum = formulate.from_auto('True + False')
>>> my_sum.to_root()
'true + false'
>>> my_sum.to_numexpr()
'True + False'

The Expression Object

When calling from_* the returned object is derived from formulate.ExpressionComponent. From this object you can inspect the expression to find it's dependencies:

>>> my_check = formulate.from_auto('(X_THETA*TMath::DegToRad() > pi/4) && D_PE > 9.2')
>>> my_check.variables
{'D_PE', 'X_THETA'}
>>> my_check.named_constants
{'DEG2RAD', 'PI'}
>>> my_check.unnamed_constants
{'4', '9.2'}

Additionally ExpressionComponent s can be combined using both operators and numpy functions:

>>> new_selection = (momentum > 100) and (my_check or (numpy.sqrt(my_sum) < 1))
>>> new_selection.to_numexpr()
'((X_THETA * 0.017453292519943295) > (3.141592653589793 / 4)) & (D_PE > 9.2)'

As the == operator returns a new expression, it can't be used to check for equality. Instead the .equivalent method should be used:

TODO: Implement this using expression.equivalent !

You can’t perform that action at this time.