Symbolic vs Numeric Integration¶

This notebook demonstrates Maxima's symbolic-numeric bridge by comparing exact symbolic integration (integrate()) with numeric trapezoidal approximation (np_trapz()). We explore convergence, special functions, oscillatory integrands, and the Fundamental Theorem of Calculus.

In [10]:
load("numerics")$
load("ax-plots")$

Exact Symbolic Integration¶

Maxima computes closed-form antiderivatives using its powerful symbolic engine. No discretisation, no approximation -- just exact algebra.

In [11]:
/* Polynomial: integral of x^2 from 0 to 1 */
exact1 : integrate(x^2, x, 0, 1);

/* Trigonometric: integral of sin(x) from 0 to pi */
exact2 : integrate(sin(x), x, 0, %pi);
1/3
Out[11]:

Numeric Approximation with np_trapz¶

The trapezoidal rule approximates the integral by summing trapezoids under a sampled curve. With np_linspace we create a grid, evaluate the function, and feed both arrays to np_trapz.

In [12]:
/* Approximate integral of x^2 on [0,1] with 10 points */
xs : np_linspace(0, 1, 10)$
ys : np_pow(xs, 2)$
numeric1 : np_trapz(ys, xs);
print("Exact:", 1/3, "  Numeric:", numeric1)$
0.3353909465020576
Exact: 1/3   Numeric: 0.3353909465020576
In [13]:
/* Approximate integral of sin(x) on [0, pi] with 50 points */
xs2 : np_linspace(0, float(%pi), 50)$
ys2 : np_map(sin, xs2)$
numeric2 : np_trapz(ys2, xs2);
print("Exact: 2", "  Numeric:", numeric2)$
1.9993148493240624
Exact: 2   Numeric: 1.9993148493240624

Convergence Study¶

How does the trapezoidal error decrease as we add more sample points? For $f(x) = e^{-x^2}$ on $[0, 3]$, the trapezoidal rule has error $O(h^2) = O(1/n^2)$. We verify this by computing the error at several resolutions and plotting on a log-log scale.

In [14]:
/* Exact value via symbolic integration + float conversion */
exact_gauss : float(integrate(exp(-t^2), t, 0, 3))$
print("Exact integral of exp(-x^2) on [0,3]:", exact_gauss)$

/* Sweep over increasing number of points */
ns : [10, 20, 50, 100, 200, 500, 1000]$
errors : makelist(
  block([xg, yg, approx],
    xg : np_linspace(0, 3, ns[i]),
    yg : np_map(lambda([z], exp(-z^2)), xg),
    approx : np_trapz(yg, xg),
    abs(approx - exact_gauss)),
  i, 1, length(ns))$
print("Errors:", errors)$
Exact integral of exp(-x^2) on [0,3]: 0.8862073482595211
Errors:
       [6.495944890105854e-6,1.5194130239537529e-6,2.308643267667776e-7,
        5.663598212635179e-8,1.402189420129929e-8,2.2302486524239384e-9,
        5.564541050162575e-10]
In [15]:
/* Log-log convergence plot */
log_ns : map(lambda([n], float(log(n))), ns)$
log_errs : map(lambda([e], float(log(e))), errors)$
ax_draw2d(
  color=blue, name="measured error",
  points(log_ns, log_errs),
  color=red, dash="dash", name="O(1/n^2) reference",
  lines([float(log(10)), float(log(1000))],
        [log_errs[1], log_errs[1] - 2*(float(log(1000))-float(log(10)))]),
  title="Trapezoidal Rule Convergence",
  xlabel="log(n)", ylabel="log(error)", grid=true
)$
No description has been provided for this image

Integrating Special Functions¶

Maxima can evaluate improper integrals that would be difficult or impossible to compute numerically. For example, $\int_0^\infty \frac{1}{1+x^4}\,dx$ has an exact closed form involving radicals.

In [16]:
/* Exact symbolic result for an improper integral */
exact_special : integrate(1/(1+x^4), x, 0, inf);
print("Exact:", float(exact_special))$

/* Numeric approximation on [0, 100] (truncated tail) */
xs3 : np_linspace(0, 100, 5000)$
ys3 : np_map(lambda([z], 1/(1+z^4)), xs3)$
print("np_trapz on [0,100]:", np_trapz(ys3, xs3))$
%pi/2^(3/2)
Exact: 1.1107207345395913
np_trapz on [0,100]: 1.110720401206242

Oscillatory Integrals¶

When the integrand oscillates rapidly, numeric methods need many sample points to avoid aliasing. Symbolic integration handles this effortlessly. We compare np_trapz at two resolutions for $g(x) = \sin(10x)\,e^{-x}$.

In [17]:
/* Exact symbolic integral of sin(10*x)*exp(-x) on [0, 2*pi] */
exact_osc : float(integrate(sin(10*t)*exp(-t), t, 0, 2*%pi));

/* Numeric with n=100 (under-resolved) vs n=1000 */
xo1 : np_linspace(0, float(2*%pi), 100)$
yo1 : np_map(lambda([z], sin(10*z)*exp(-z)), xo1)$
xo2 : np_linspace(0, float(2*%pi), 1000)$
yo2 : np_map(lambda([z], sin(10*z)*exp(-z)), xo2)$
print("n=100:", np_trapz(yo1, xo1),
      "  n=1000:", np_trapz(yo2, xo2))$
0.09882500567012793
n=100: 0.09545259472279734   n=1000: 0.09879210054768726
In [18]:
/* Plot the oscillatory integrand with shaded area */
xp : np_linspace(0, float(2*%pi), 500)$
yp : np_map(lambda([z], sin(10*z)*exp(-z)), xp)$
ax_draw2d(
  color=blue, fill="tozeroy", opacity=0.3,
  name="sin(10x) exp(-x)",
  lines(xp, yp),
  title="Oscillatory Integrand",
  xlabel="x", ylabel="g(x)", grid=true
)$
No description has been provided for this image

The Fundamental Theorem of Calculus¶

The FTC says $\frac{d}{dx}\int_0^x f(t)\,dt = f(x)$. We verify this two ways: first symbolically — Maxima integrates $1/(1+t^2)$ to get $\arctan(x)$, then differentiates to recover the integrand — and then numerically — we accumulate np_trapz values at many points, take finite differences, and compare against $f(x)$.

In [19]:
/* Symbolic FTC: integrate then differentiate */
assume(x > 0)$
F_sym : integrate(1/(1+t^2), t, 0, x);
result : diff(F_sym, x);
is(ratsimp(result - 1/(1+x^2)) = 0);
atan(x)
1/(x^2+1)
Out[19]:
In [20]:
/* Numeric FTC: accumulate trapezoid sums F(x_k), then
   approximate F'(x_k) with finite differences */
npts : 500$
xf : np_linspace(0, 5, npts)$
yf : np_map(lambda([z], 1/(1+z^2)), xf)$
y_list : np_to_list(yf)$

/* F(x_k) = cumulative trapezoid sum from 0 to x_k */
dx : 5.0 / (npts - 1)$
F_vals : [0.0]$
for k : 2 thru npts do
  F_vals : endcons(last(F_vals) + dx * (y_list[k-1] + y_list[k]) / 2, F_vals)$

/* Numeric derivative: dF/dx via central differences */
dFdx : makelist(
  if i = 1 then (F_vals[2] - F_vals[1]) / dx
  elseif i = npts then (F_vals[i] - F_vals[i-1]) / dx
  else (F_vals[i+1] - F_vals[i-1]) / (2*dx),
  i, 1, npts)$

/* Compare against exact f(x) = 1/(1+x^2) */
x_list : np_to_list(xf)$
In [21]:
ax_draw2d(
  color="steelblue", line_width=2, name="f(x) = 1/(1+x^2)",
  lines(x_list, y_list),
  color="red", dash="dash", line_width=2, name="d/dx [trapz sum]",
  lines(x_list, dFdx),
  title="FTC Verification: Numeric Derivative of Numeric Integral",
  xlabel="x", ylabel="f(x)", grid=true
)$
No description has been provided for this image

Summary¶

  • Symbolic integration (integrate) gives exact, closed-form answers for a wide class of integrands, including improper integrals and special functions.
  • Numeric integration (np_trapz) is useful when symbolic methods fail, when data is empirical or tabulated, or when a quick numerical check is needed. Its accuracy improves as $O(1/n^2)$.
  • Maxima's symbolic-numeric bridge lets you derive formulas symbolically, then validate or visualise them numerically -- the best of both worlds.