Numerical integration (like `scipy.integrate.quad`) gives a decimal answer for a specific integral. Symbolic integration gives you the formula — the antiderivative — so you can evaluate it at any point, differentiate it back, or analyze how it depends on parameters. SymPy's `integrate` function applies standard integration techniques: substitution, integration by parts, partial fractions, and special function recognition. It handles indefinite integrals (antiderivatives), definite integrals with numeric or symbolic limits, improper integrals over infinite ranges, and double integrals. ### Indefinite Integration `integrate(f, x)` computes the antiderivative of `f` with respect to `x`. SymPy omits the integration constant `+C` — it's implied.
from sympy import symbols, integrate, sin, cos, exp, log, sqrt
x = symbols('x')
expressions = [
x**3 - 2*x + 1,
sin(x) * cos(x),
x * exp(x),
1 / (x**2 + 1),
log(x),
]
for f in expressions:
F = integrate(f, x)
print(f"∫ {f} dx = {F}")- `integrate(f, x)` applies the appropriate technique automatically: power rule, substitution, or integration by parts. - `∫ x·eˣ dx = (x−1)·eˣ` requires integration by parts — SymPy handles this without any hint. - `∫ 1/(x²+1) dx = arctan(x)` — SymPy recognizes the standard form and returns `atan(x)`. ### Definite Integrals Pass a tuple `(x, a, b)` as the second argument to compute a definite integral from a to b. SymPy evaluates the antiderivative at both limits and returns the exact result.
from sympy import symbols, integrate, sin, pi, sqrt, Rational, N
x = symbols('x')
integrals = [
(sin(x), (x, 0, pi)),
(x**2, (x, 0, 1)),
(sqrt(1 - x**2), (x, -1, 1)), # area of semicircle
(x**Rational(3,2),(x, 0, 4)),
]
for f, bounds in integrals:
result = integrate(f, bounds)
print(f"∫ {f} dx from {bounds[1]} to {bounds[2]} = {result} ≈ {float(N(result)):.6f}")- `integrate(sqrt(1 - x**2), (x, -1, 1))` returns `pi/2` — the area of a unit semicircle, confirming the geometric interpretation. - `N(result)` converts a symbolic result like `pi/2` to its floating-point value for comparison. - `Rational(3, 2)` creates the exact fraction ³⁄₂, so `x**Rational(3, 2)` is x^(3/2) symbolically. ### Visualizing the Definite Integral Plotting the function and shading the area under it connects the symbolic result to its geometric meaning.
from sympy import symbols, integrate, sin, pi, lambdify
import numpy as np
import matplotlib.pyplot as plt
x = symbols('x')
f = sin(x)
a, b = 0, float(pi)
area = integrate(f, (x, a, b))
f_num = lambdify(x, f, modules='numpy')
xs = np.linspace(-0.5, float(pi) + 0.5, 400)
xs_fill = np.linspace(a, b, 300)
plt.figure(figsize=(8, 4))
plt.plot(xs, f_num(xs), color="steelblue", linewidth=2, label="sin(x)")
plt.fill_between(xs_fill, f_num(xs_fill), alpha=0.3, color="steelblue",
label=f"Area = {area}")
plt.axhline(0, color="gray", linewidth=0.8)
plt.title(f"∫₀^π sin(x) dx = {area}")
plt.xlabel("x")
plt.ylabel("f(x)")
plt.legend()
plt.tight_layout()
plt.show()- `float(pi)` converts SymPy's symbolic `pi` to a NumPy-compatible float for use in `np.linspace`. - `fill_between` shades the region between the curve and the x-axis — exactly the area that the definite integral computes. - The result `2` (exact integer) means the sine curve encloses area 2 between 0 and π — a clean, memorable result. ### Improper Integrals Pass `oo` (SymPy's infinity) as a limit to compute improper integrals over infinite ranges. SymPy evaluates the limit analytically.
from sympy import symbols, integrate, exp, oo, sqrt, pi
x = symbols('x')
improper = [
(exp(-x), (x, 0, oo)), # ∫₀^∞ e^-x dx = 1
(exp(-x**2), (x, -oo, oo)), # Gaussian: √π
(1 / (1 + x**2), (x, -oo, oo)), # ∫ arctan derivative = π
]
for f, bounds in improper:
result = integrate(f, bounds)
print(f"∫ {f} from {bounds[1]} to {bounds[2]} = {result}")- `oo` is SymPy's symbolic infinity — passing it as a limit triggers limit-based evaluation of the integral. - `∫₋∞^∞ e^(−x²) dx = √π` is the Gaussian integral — a fundamental result in probability and physics that SymPy evaluates exactly. - If SymPy can't find a closed form, it returns an unevaluated `Integral` object rather than raising an error. ### Double Integrals Call `integrate` twice (once for each variable) to compute a double integral. The order of integration matches the nesting: inner integral first.
from sympy import symbols, integrate, sin, cos, pi
x, y = symbols('x y')
# ∫₀^π ∫₀^1 x * sin(y) dx dy
inner = integrate(x * sin(y), (x, 0, 1))
result = integrate(inner, (y, 0, pi))
print(f"∫₀^π ∫₀^1 x·sin(y) dx dy = {result}")
# ∫₀^1 ∫₀^x (x + y) dy dx (triangular region)
inner2 = integrate(x + y, (y, 0, x))
result2 = integrate(inner2, (x, 0, 1))
print(f"∫₀^1 ∫₀^x (x+y) dy dx = {result2}")- `integrate(x * sin(y), (x, 0, 1))` treats `y` as a constant and integrates over `x`, returning a function of `y`. - The second `integrate` then integrates that result over `y`, completing the double integral. - For the triangular region, `(y, 0, x)` makes the inner limit depend on the outer variable — SymPy handles variable limits seamlessly. SymPy's symbolic integration pairs naturally with [symbolic differentiation](/tutorials/symbolic-differentiation-with-sympy) — integrate a derivative to recover the original function, or differentiate an integral to verify the fundamental theorem of calculus. For numerical integration when no closed form exists, see [numerical integration with SciPy](/tutorials/numerical-integration-with-scipy).