lambdify: fast numeric functions

SymPy · Practical · 10 min

The usual workflow is derive symbolically, then evaluate numerically; lambdify is the hand-off.

lambdify(args, expr, modules) generates the source code of a Python function that computes expr, with symbolic functions mapped to a numeric library. When NumPy is installed the default backend uses it (plus SciPy if available), so the resulting function accepts arrays and evaluates element-wise at NumPy speed:

f = lambdify(x, sin(x) * x**2)
f(np.linspace(0, 1, 1_000_000))

That is orders of magnitude faster than looping with subs and evalf.

Details worth knowing:

  • args is a symbol, a list of symbols, or nested lists; the generated function takes them as positional arguments in that order.
  • modules selects the backend: "numpy", "math", "mpmath", "scipy", "jax" and others, or a dict mapping names to your own implementations.
  • An expression can return several outputs: pass a list or a Matrix.
  • inspect.getsource(f) shows exactly what was generated, which is invaluable when debugging.
  • lambdify(..., cse=True) factors out common subexpressions, which speeds up large expressions.

Precision changes too. Inside the generated function, numbers are ordinary floats, so Rational(1, 3) becomes 1/3 as a float. If you need high precision, use the "mpmath" backend.

Example

import inspect
import numpy as np
from sympy import symbols, lambdify, sin, diff

x, y = symbols("x y")
expr = sin(x) * x**2
f = lambdify(x, expr, "numpy")
df = lambdify(x, diff(expr, x), "numpy")

xs = np.array([0.0, 1.0, 2.0])
print(f(xs))    # [0.         0.84147098 3.63718971]
print(df(1.0))  # 2.2232442754839328

g = lambdify([x, y], [x + y, x * y])
print(g(2, 3))  # [5, 6]

print(inspect.getsource(f))
# def _lambdifygenerated(x):
#     return x**2*sin(x)

Remember

  • lambdify(args, expr) builds a fast NumPy-backed function
  • Use it instead of subs/evalf loops for numeric evaluation
  • inspect.getsource shows the generated code; cse=True speeds up large expressions

Watch out for

  • Using the math backend and then passing NumPy arrays to the function.

Check yourself

  1. Why is lambdify much faster than calling expr.subs(x, v).evalf() for each of a million values?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.sympy.org/latest/modules/utilities/lambdify.html