Metadata-Version: 2.5
Name: numbafy
Version: 1.0.0
Summary: Turn a (huge) SymPy expression into a Numba-compiled function: constants, common subexpressions and a @jit-decorated function as source code.
Project-URL: homepage, https://github.com/jankoslavic/numbafy
Project-URL: source, https://github.com/jankoslavic/numbafy
Project-URL: issues, https://github.com/jankoslavic/numbafy/issues
Project-URL: changelog, https://github.com/jankoslavic/numbafy/blob/master/CHANGELOG.md
Author-email: Janko Slavič <janko.slavic@fs.uni-lj.si>
Maintainer-email: Janko Slavič <janko.slavic@fs.uni-lj.si>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Keywords: code generation,jit,lambdify,numba,symbolic,sympy
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Code Generators
Requires-Python: >=3.10
Requires-Dist: numba>=0.55
Requires-Dist: sympy>=1.6
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# numbafy

[![PyPI](https://img.shields.io/pypi/v/numbafy.svg)](https://pypi.org/project/numbafy/)
[![Tests](https://github.com/jankoslavic/numbafy/actions/workflows/test.yml/badge.svg)](https://github.com/jankoslavic/numbafy/actions/workflows/test.yml)
[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jankoslavic/numbafy/master?filepath=Showcase.ipynb)

Turn a SymPy expression into a [Numba](https://numba.pydata.org/)-compiled function.

`sympy.lambdify` builds one Python lambda from the whole expression. For very
large expressions (hundreds of thousands of operations, e.g. equations of motion
of a multibody system) that lambda is slow to evaluate and practically
impossible to compile with Numba. `numbafy` instead writes the expression as
the **source code of a plain Python function**: constants become local
assignments, common subexpressions (`sympy.cse`) become intermediate variables
and the function is decorated with `@jit`. Numba compiles that code in seconds
and evaluates it in microseconds.

## Installation

```
pip install numbafy
```

Requires Python 3.10+, SymPy and Numba.

## Basic example

```python
import sympy as sym
from numbafy import numbafy_function

a, b, c = sym.symbols('a, b, c')
expression = c * a**b

f = numbafy_function(expression, parameters=(a, b), constants={c: 1.4}, use_cse=True)
f(2.0, 3.0)   # 11.2
```

`numbafy_function` returns the compiled function; Numba compiles it on the first
call. The generated source code is kept in `f.numbafy_source`:

```python
import math
from numba import jit

@jit
def numbafy_func(a, b):
    c = 1.4
    return a**b*c
```

If you prefer to handle the code yourself (inspect it, save it to a module,
`exec` it), `numbafy` returns the same code as a string:

```python
from numbafy import numbafy

code = numbafy(expression, parameters=(a, b), constants={c: 1.4}, use_cse=True)
exec(code)
numbafy_func(a=2.0, b=3.0)   # 11.2
```

## A large expression

`examples/large_model.json.gz` holds an equation of motion with 8 parameters,
36 constants and about 290 000 operations. See `Showcase.ipynb`
([run it on Binder](https://mybinder.org/v2/gh/jankoslavic/numbafy/master?filepath=Showcase.ipynb)).

```python
import gzip, json
import sympy as sym
from numbafy import numbafy_function

with gzip.open('examples/large_model.json.gz', 'rt') as fh:
    model = json.load(fh)
symbols = {name: sym.Symbol(name) for name in model['parameters'] + list(model['constants'])}
expression = sym.parse_expr(model['expression'], local_dict=symbols)
parameters = [symbols[n] for n in model['parameters']]
constants = {symbols[n]: v for n, v in model['constants'].items()}

f = numbafy_function(expression, parameters=parameters, constants=constants, use_cse=True)
f(1., 1., 1., 1., 1., 1., 1., 1.)
```

Measured on a laptop (Python 3.13, SymPy 1.14, Numba 0.67):

| step | time |
|---|---|
| `sympy.cse` + code generation (11 kB of code) | 0.7 s |
| Numba compilation (first call) | 0.7 s |
| every further call | 0.4 µs |
| the same value with `expression.subs(...)` in SymPy | 73 s |

Without `use_cse=True` the generated function is a single 1.4 MB expression
and Numba does not finish compiling it in a reasonable time.

## Options

```python
numbafy(expression, parameters=None, constants=None, use_cse=False,
        new_function_name='numbafy_func', jit_options=None, header=True,
        module='math')
```

- `expression` – a SymPy expression, or a list/tuple/`Matrix` of expressions
  (the function then returns a tuple).
- `parameters` – the arguments of the function, in order (symbols or names).
- `constants` – `{symbol: value}`; values may be numbers or SymPy expressions.
- `use_cse` – common subexpression elimination; recommended for large expressions.
- `new_function_name` – name of the generated function.
- `jit_options` – keyword arguments for `numba.jit`, e.g. `{'cache': True}` or
  `{'fastmath': True}`.
- `header` – prepend `import math` / `import numpy` and `from numba import jit`
  (default `True`, so the code is self-contained).
- `module` – `'math'` (default; scalar arguments, fastest) or `'numpy'` (the
  compiled function also accepts NumPy arrays element-wise).

A free symbol that is neither a parameter nor a constant raises `ValueError`.

## Background

The package was written in 2018 while discussing
[sympy/sympy#14714](https://github.com/sympy/sympy/issues/14714)
(lambdify of huge expressions). Version 1.0 (2026) modernises the packaging,
adds `numbafy_function`, self-contained code, tests and CI; see
[CHANGELOG.md](CHANGELOG.md).

## License

GPL-3.0-or-later. Author: Janko Slavič (janko.slavic@fs.uni-lj.si).
