Substitution and numeric evaluation

SymPy · Essentials · 8 min

Plugging in numbers and getting a decimal answer is the bridge from a derived formula to a usable result.

expr.subs(old, new) returns a new expression with old replaced. new can be a number or any expression, so substitution also composes formulas. Pass a dict or list of pairs to replace several symbols at once: expr.subs({x: 2, y: 1}). The original expression is unchanged, because expressions are immutable.

Substituting numbers gives an exact result when the numbers are exact: sqrt(x).subs(x, 8) is 2*sqrt(2), not 2.828.... To get a decimal, call evalf() (or the function N()). Both take a number of significant digits: pi.evalf(50). SymPy evaluates with arbitrary precision (via mpmath), so asking for 50 digits really gives 50 correct digits.

For evaluating at a numeric point, expr.evalf(subs={x: 1.5}) is better than expr.subs(x, 1.5).evalf(): it substitutes during numeric evaluation, which avoids building a large intermediate exact expression and can be more accurate.

Substitution is also about structure. subs is mathematically aware: (x**4).subs(x**2, y) gives y**2. If you want a purely literal replacement of exact subtrees, xreplace does that (covered later).

Evaluating a formula at thousands of points with subs and evalf is slow, because each call walks the tree. For bulk numeric work, convert the expression to a NumPy function with lambdify.

Example

from sympy import symbols, sqrt, pi, N

x, y = symbols("x y")
expr = x**2 + y

print(expr.subs(x, 3))             # y + 9
print(expr.subs({x: 2, y: 1}))     # 5
print(expr.subs(x, y + 1))         # y + (y + 1)**2
print((x**4).subs(x**2, y))        # y**2
print(sqrt(x).subs(x, 8))          # 2*sqrt(2)
print(sqrt(8).evalf())             # 2.82842712474619
print(N(pi, 20))                   # 3.1415926535897932385
print(expr.evalf(subs={x: 1.5, y: 0}))  # 2.25000000000000
print(expr)                        # x**2 + y  (unchanged)

Remember

  • subs returns a new expression; pass a dict for several symbols
  • evalf(n) / N(expr, n) give n significant digits
  • Use evalf(subs=...) for numeric points and lambdify for many points

Watch out for

  • Expecting expr.subs(...) to modify expr in place: assign the result.

Check yourself

  1. After e = x + 1; e.subs(x, 2), what is e?

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

Official docs: docs.sympy.org/latest/tutorials/intro-tutorial/basic_operations.html