Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Symbolic Math with SymPy

Open in Colab
Source
import sympy as sp
from sympy import diff, exp, expand, factor, integrate, lambdify, oo, series, simplify, sin, solve, symbols
from sympy.physics.hydrogen import R_nl
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.dpi"] = 150

SymPy is the SciPy ecosystem’s library for symbolic mathematics: it manipulates expressions exactly, like a free Mathematica built on Python. Where NumPy gives you numbers, SymPy gives you formulas: it can expand, factor, differentiate, integrate, and solve algebraically. Before a variable can appear in an expression it must be declared a symbol with symbols().

x, y, a, b = symbols('x y a b')
x
Loading...

Algebra

The everyday manipulations are expand, factor, and simplify.

expand((x + 1) * (x + 2) * (x + 3))
Loading...
factor(x**3 + 6 * x**2 + 11 * x + 6)
Loading...
simplify((x**3 + x**2 - x - 1) / (x**2 + 2 * x + 1))
Loading...

To solve an equation (SymPy sets the expression equal to zero), use solve:

solve(x**2 + 1.4 * x - 5.76, x)
[-3.20000000000000, 1.80000000000000]

Calculus

Differentiate with diff: the first argument is the expression, the rest are the variables to differentiate by. Repeating a variable (or giving a number) takes higher derivatives.

diff(sin(x) * exp(-x), x)
Loading...
diff(x**4, x, 2)   # second derivative
Loading...

Integrate with integrate. With no limits you get an antiderivative; with limits, a definite integral. The symbol oo means infinity, so the Gaussian integral central to quantum mechanics is one line:

integrate(x * exp(-x), x)
Loading...
integrate(exp(-x**2), (x, -oo, oo))
Loading...

A Taylor series expansion uses series. By default it expands about x=0x = 0; extra arguments set the center and the order.

series(exp(x), x, 0, 6)
Loading...

A quantum-mechanical example: hydrogen radial functions

SymPy ships the hydrogen atom’s exact wavefunctions in its physics module. Here we pull the 2p2p radial function R21(r)R_{21}(r), find the radius where the radial probability density r2R212r^2 R_{21}^2 peaks, and plot it. This is a worked symbolic-to-numeric pipeline: solve exactly, then lambdify into a NumPy function to plot.

r = symbols('r', positive=True)
R_21 = R_nl(n=2, l=1, r=r, Z=1)
R_21
Loading...
# radius of maximum radial probability: solve d/dr [ r^2 R^2 ] = 0
density = r**2 * R_21**2
r_max = float(max(solve(diff(density, r), r)))   # largest (nonzero) root
r_max
4.0
f = lambdify(r, density, modules='numpy')
rr = np.linspace(0, 20, 200)

plt.plot(rr, f(rr))
plt.axvline(r_max, color='r', ls='--', label=f'peak at r = {r_max:.1f} a0')
plt.xlabel('radius r  ($a_0$)')
plt.ylabel('radial probability density  $r^2 R^2$')
plt.legend()
<Figure size 960x720 with 1 Axes>

The peak of the 2p2p radial density sits at r=4a0r = 4\,a_0, exactly the Bohr-model radius of the n=2n = 2 orbit.

Exercises

  1. Factor x2+x6x^2 + x - 6.

  2. Expand (x2)(x+5)x(x - 2)(x + 5)\,x.

  3. Evaluate 0ln4exe2x+9dx\displaystyle\int_0^{\ln 4} \frac{e^x}{\sqrt{e^{2x} + 9}}\,dx with integrate (use log(4) for the upper limit).

  4. The reversible isothermal work of a gas is w=ViVfnRTVdVw = \int_{V_i}^{V_f} -\frac{nRT}{V}\,dV. Integrate it symbolically, then evaluate for n=2.44n = 2.44 mol, T=298T = 298 K, Vi=0.552V_i = 0.552 L, Vf=1.32V_f = 1.32 L.

Try it live

x = sp.symbols("x")
sp.integrate(sp.sin(x) ** 2, (x, 0, sp.pi))   # try your own integral
Loading...