Metadata-Version: 2.1
Name: formulate
Version: 0.1.1
Summary: Convert between different style of formulae
Home-page: https://github.com/scikit-hep/formulate
Author: Chris Burr
Author-email: c.b@cern.ch
Maintainer: The Scikit-HEP admins
Maintainer-email: scikit-hep-admins@googlegroups.com
License: BSD 3-Clause License
Keywords: formula,conversion,ROOT,numexpr,HEP
Platform: Any
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX
Classifier: Operating System :: Unix
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7
Description-Content-Type: text/x-rst
Requires-Dist: numpy (>=1.13.3)
Requires-Dist: pyparsing (>=2.1.9)
Requires-Dist: colorlog
Requires-Dist: aenum
Requires-Dist: scipy
Provides-Extra: all
Requires-Dist: pytest (>=4.6) ; extra == 'all'
Requires-Dist: numexpr ; extra == 'all'
Provides-Extra: dev
Requires-Dist: pytest (>=4.6) ; extra == 'dev'
Requires-Dist: numexpr ; extra == 'dev'
Provides-Extra: test
Requires-Dist: pytest (>=4.6) ; extra == 'test'
Requires-Dist: numexpr ; extra == 'test'

Formulate
=========

|Build Status| |Coverage Status| |PyPI| |Scikit-HEP Project|

Easy conversions between different styles of expressions. Formulate
currently supports converting between
`ROOT <https://root.cern.ch/doc/master/classTFormula.html>`__ and
`numexpr <https://numexpr.readthedocs.io/en/latest/user_guide.html>`__
style expressions.

.. |Build Status| image:: https://github.com/scikit-hep/formulate/workflows/Python%20package/badge.svg
   :target: https://github.com/scikit-hep/formulate/actions
.. |Coverage Status| image:: https://coveralls.io/repos/github/scikit-hep/formulate/badge.svg?branch=master&service=github
   :target: https://coveralls.io/github/scikit-hep/formulate?branch=master
.. |PyPI| image:: https://badge.fury.io/py/formulate.svg
   :target: https://pypi.python.org/pypi/formulate/
.. |Scikit-HEP Project| image:: https://scikit-hep.org/assets/images/Scikit--HEP-Project-blue.svg
   :target: https://scikit-hep.org

Installation
------------

Install formulate like any other Python package:

.. code-block:: bash

    pip install --user formulate

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


Usage
-----

Command line usage
""""""""""""""""""

.. code-block:: bash

    $ 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:

.. code-block:: python

    >>> 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:

.. code-block:: python

    >>> 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:

.. code-block:: python

    >>> 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:

.. code-block:: python

    >>> 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:

.. code-block:: python

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


