Tutorials

Symbolic Differentiation with SymPy

Numerical differentiation approximates the derivative using finite differences — fast but imprecise. Symbolic differentiation computes the exact mathematical derivative as a formula. You'd use it when precision matters: deriving gradients for optimization, verifying analytical results, computing sensitivity functions, or building systems that need exact derivative expressions rather than numerical estimates. SymPy's `diff` function handles polynomials, trigonometric, exponential, and composite functions, as well as partial and higher-order derivatives.

### Basic Differentiation

`sympy.diff` takes a symbolic expression and the variable to differentiate with respect to. It returns the exact derivative as a SymPy expression that you can simplify, evaluate, or convert to a Python function.

from sympy import symbols, diff, sin, cos, exp, pprint

x = symbols('x')

expressions = [
    x**4 - 3*x**2 + 2*x,
    sin(x**2),
    exp(-x) * cos(x),
]

for f in expressions:
    df = diff(f, x)
    print(f"f  = {f}")
    print(f"f' = {df}")
    print()
f  = x**4 - 3*x**2 + 2*x
f' = 4*x**3 - 6*x + 2

f  = sin(x**2)
f' = 2*x*cos(x**2)

f  = exp(-x)*cos(x)
f' = -exp(-x)*sin(x) - exp(-x)*cos(x)

- `symbols('x')` creates a symbolic variable — it behaves like a mathematical symbol, not a number.
- `diff(f, x)` applies the standard differentiation rules (product rule, chain rule, etc.) exactly.
- `sin(x**2)` differentiates to `2*x*cos(x**2)` — the chain rule applied automatically.

### Higher-Order Derivatives

Pass an integer as the third argument to `diff` to compute the nth derivative in one call.

from sympy import symbols, diff, sin, pprint

x = symbols('x')
f = sin(x)

for n in range(1, 5):
    dn = diff(f, x, n)
    print(f"d^{n}/dx^{n} sin(x) = {dn}")
d^1/dx^1 sin(x) = cos(x)
d^2/dx^2 sin(x) = -sin(x)
d^3/dx^3 sin(x) = -cos(x)
d^4/dx^4 sin(x) = sin(x)
- `diff(f, x, n)` is equivalent to calling `diff` n times: `diff(diff(f, x), x)` and so on.
- The derivatives of `sin(x)` cycle: cos, −sin, −cos, sin — SymPy produces this cycle exactly, not as a numerical approximation.
- You can also write `diff(f, x, x, x)` (repeating the variable) as an alternative syntax for the third derivative.

### Partial Derivatives

For functions of multiple variables, specify which variable to differentiate with respect to. Passing multiple variables computes a mixed partial derivative.

from sympy import symbols, diff, exp

x, y = symbols('x y')
f = x**2 * y + exp(x * y)

df_dx = diff(f, x)
df_dy = diff(f, y)
df_dxdy = diff(f, x, y)   # mixed partial ∂²f/∂x∂y

print("f      =", f)
print("∂f/∂x  =", df_dx)
print("∂f/∂y  =", df_dy)
print("∂²f/∂x∂y =", df_dxdy)
f      = x**2*y + exp(x*y)
∂f/∂x  = 2*x*y + y*exp(x*y)
∂f/∂y  = x**2 + x*exp(x*y)
∂²f/∂x∂y = x*y*exp(x*y) + 2*x + exp(x*y)
- `diff(f, x, y)` computes the mixed partial: first differentiate with respect to x, then with respect to y.
- For smooth functions Schwarz's theorem guarantees `∂²f/∂x∂y = ∂²f/∂y∂x` — SymPy always returns the same result regardless of order.
- `exp(x * y)` contributes `y * exp(x * y)` to `∂f/∂x` and `x * exp(x * y)` to `∂f/∂y`.

### Visualizing a Function and Its Derivatives

Converting SymPy expressions to NumPy-compatible functions with `lambdify` lets you plot them alongside each other.

from sympy import symbols, diff, sin, cos, lambdify
import numpy as np
import matplotlib.pyplot as plt

x = symbols('x')
f   = sin(x) * (x**2) / 4
df  = diff(f, x)
d2f = diff(f, x, 2)

f_num   = lambdify(x, f,   modules='numpy')
df_num  = lambdify(x, df,  modules='numpy')
d2f_num = lambdify(x, d2f, modules='numpy')

xs = np.linspace(-4, 4, 400)
plt.figure(figsize=(9, 4))
plt.plot(xs, f_num(xs),   color="steelblue", linewidth=2.5, label="f(x)")
plt.plot(xs, df_num(xs),  color="crimson",   linewidth=2, linestyle="--", label="f′(x)")
plt.plot(xs, d2f_num(xs), color="orange",    linewidth=1.5, linestyle=":", label="f″(x)")
plt.axhline(0, color="gray", linewidth=0.8)
plt.title("Function and Its Derivatives")
plt.xlabel("x")
plt.legend()
plt.tight_layout()
plt.show()
- `lambdify(x, expr, modules='numpy')` converts the symbolic expression to a regular Python function that accepts NumPy arrays for fast numerical evaluation.
- The derivative (red dashed) crosses zero wherever the original function has a local extremum — this is the standard use of derivatives in optimization.
- The second derivative (orange dotted) is negative at maxima and positive at minima, confirming the second derivative test.

Symbolic differentiation pairs naturally with [solving equations with SymPy](/tutorials/solving-equations-with-sympy) — differentiate an expression, set the derivative to zero, and solve for critical points analytically.