numbafy
Turn a SymPy expression into a Numba-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
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:
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:
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).
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
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/Matrixof 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 fornumba.jit, e.g.{'cache': True}or{'fastmath': True}.header– prependimport math/import numpyandfrom numba import jit(defaultTrue, 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
(lambdify of huge expressions). Version 1.0 (2026) modernises the packaging,
adds numbafy_function, self-contained code, tests and CI; see
CHANGELOG.md.
License
GPL-3.0-or-later. Author: Janko Slavič (janko.slavic@fs.uni-lj.si).
Metadata
Release files for numbafy 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| numbafy-1.0.0.tar.gz | 39.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| numbafy-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.6 kB
Release files / numbafy-1.0.0.tar.gz
| Download URL | numbafy-1.0.0.tar.gz |
|---|---|
| Size | 39.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3fdec116b882caf347cdb18e802f398fcd9f244344b79a0d38314477764afde5
|
|
BLAKE2b-256 checksum How to use checksums |
f78cc55303cfb355ab335996a09712e175dd44bf5ee4ae243a228206c132d346
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency logRelease files / numbafy-1.0.0-py3-none-any.whl
| Download URL | numbafy-1.0.0-py3-none-any.whl |
|---|---|
| Size | 18.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
52a0caedf3f4d976a397af7db9039844937f573f421335c7c70232228dfa77de
|
|
BLAKE2b-256 checksum How to use checksums |
f3d9ed992ff6620192ba30b1f7b35ca00abf4863b32879951c5b49ddfe9849c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency log