/ formulate Public

Easy conversions between different styles of expressions

# scikit-hep/formulate

Switch branches/tags
Nothing to show

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

## Files

Failed to load latest commit information.
Type
Name
Commit time

# Formulate

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
>>> 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` !

Easy conversions between different styles of expressions

## Releases 9

Minor bug fixes Latest
Apr 15, 2021

## Packages 0

No packages published