Norms¶
This notebook accompanies Chapter 2, section on norms.
A single number has to stand for the size of an error function, and the plain integral fails in that role, because positive and negative gaps cancel. The mode $0.3\sin(16\pi x)$ integrates to zero exactly while reaching $0.3$ at every crest. The sup norm ignores cancellation by taking the largest magnitude, and the $L^2$ norm defeats it by squaring the gaps before integrating. The first lab measures the distance between the displacement and a copy of itself slid sideways, plus a small sixth mode. Yellow bars mark the pointwise gaps; squaring, averaging, and taking the root turns the bars into one number, and a finite set of measurement points approaches the integral as the set grows. A small slide produces a large distance, the same fact the chapter measures with the shifted spike.
The measure that sees slopes¶
The second lab plots a displacement $A\sin(2\pi n x)$ beside its derivative. Raising the frequency $n$ barely changes the sup and $L^2$ norms and multiplies the $H^1$ seminorm by $n$, because differentiation multiplies each oscillation by its frequency.
The book's numbers¶
The cell below reproduces the measured values of the chapter, the three norms of the $m = 5$ reconstruction error and the spike and wiggle on which the norms disagree.
import numpy as np
base = (0.8, 0.4, 0.2)
x = np.linspace(0.0, 1.0, 8001)
u = base[0]*np.sin(np.pi*x) + base[1]*np.sin(2*np.pi*x) + base[2]*np.sin(3*np.pi*x)
du = np.pi*(base[0]*np.cos(np.pi*x) + 2*base[1]*np.cos(2*np.pi*x) + 3*base[2]*np.cos(3*np.pi*x))
def l2(f):
return np.sqrt(np.trapezoid(f**2, x))
m = 5
xi = np.linspace(0, 1, m)
ui = base[0]*np.sin(np.pi*xi) + base[1]*np.sin(2*np.pi*xi) + base[2]*np.sin(3*np.pi*xi)
v = np.interp(x, xi, ui)
slopes = np.diff(ui) / np.diff(xi)
dv = slopes[np.clip((x*(m-1)).astype(int), 0, m-2)]
e, de = u - v, du - dv
print(f"m = 5 error: sup = {np.max(np.abs(e)):.3f}, L2 = {l2(e):.4f}, H1 = {l2(de):.3f}")
print(f"relative: sup = {np.max(np.abs(e))/np.max(np.abs(u)):.1%}, "
f"L2 = {l2(e)/l2(u):.1%}, H1 = {l2(de)/l2(du):.1%}")
for w in (0.04, 0.01, 0.0025):
s_ = np.maximum(0.0, 1.0 - np.abs(x - 0.5)/(w/2))
print(f"spike base {w}: sup = {np.max(s_):.0f}, L2 = {l2(s_):.4f}, "
f"H1 = {2/np.sqrt(w):.0f}, energy = {2/w:.0f}")
spike = np.maximum(0.0, 1.0 - np.abs(x - 0.5)/0.02)
shifted = np.maximum(0.0, 1.0 - np.abs(x - 0.56)/0.02)
print(f"spike shifted by 0.06: L2 distance = {l2(spike - shifted):.4f} (sqrt(2) x 0.1155)")
for n in (10, 20, 40):
wig = 0.05*np.sin(n*np.pi*x)
dwig = 0.05*n*np.pi*np.cos(n*np.pi*x)
print(f"wiggle n = {n:2d}: sup = {np.max(np.abs(wig)):.3f}, L2 = {l2(wig):.4f}, H1 = {l2(dwig):.3f}")
m = 5 error: sup = 0.223, L2 = 0.0930, H1 = 1.200 relative: sup = 20.1%, L2 = 14.4%, H1 = 42.2% spike base 0.04: sup = 1, L2 = 0.1155, H1 = 10, energy = 50 spike base 0.01: sup = 1, L2 = 0.0577, H1 = 20, energy = 200 spike base 0.0025: sup = 1, L2 = 0.0289, H1 = 40, energy = 800 spike shifted by 0.06: L2 distance = 0.1633 (sqrt(2) x 0.1155) wiggle n = 10: sup = 0.050, L2 = 0.0354, H1 = 1.111 wiggle n = 20: sup = 0.050, L2 = 0.0354, H1 = 2.221 wiggle n = 40: sup = 0.050, L2 = 0.0354, H1 = 4.443
What comes next¶
Each norm evaluates a description after it is chosen. The next notebook asks for the best description within a family, and the answer is a projection.