Skip to content

Inner Product of Functions

Everything so far treated a vector as a finite list of numbers, and every inner product as a finite sum. But nothing in Definition 3.3 mentions finiteness: an inner product needs to be bilinear, symmetric and positive definite, and that is all.

So take a function uu on an interval, think of it as a vector with one entry for every point of that interval, and replace the sum by an integral. All three axioms survive, and with them length, distance, angle and orthogonality. Two functions can now be perpendicular — and the family of functions that are mutually perpendicular in this sense is exactly the family Fourier analysis is built on.

  • Equation 3.37: the inner product of two functions as a definite integral, and why the interval is part of the definition.
  • The book’s Example 3.9: sin\sin and cos\cos are orthogonal on [π,π][-\pi, \pi], by exact cancellation rather than approximate smallness.
  • The trigonometric family of Equation 3.38, measured to be orthogonal, with its Gram matrix computed.
  • How a square wave is rebuilt from its projections, and why each coefficient can be computed independently of all the others.
  • Parseval’s identity again, now predicting the truncation error exactly — and the Gibbs overshoot that will not go away.

Intuition: a vector with uncountably many entries

Section titled “Intuition: a vector with uncountably many entries”

Sample a function at nn points and you get a vector in Rn\mathbb{R}^n. Its dot product with another sampled function is iu(xi)v(xi)\sum_i u(x_i)v(x_i). Multiply by the spacing Δx\Delta x and that sum is a Riemann approximation to u(x)v(x)dx\int u(x)v(x)\,dx.

Now let nn grow. The vector gets longer, the sum gets more terms, and the limit is the integral. The integral is the dot product of the two functions; the only difference is that the index set is a continuum instead of {1,,n}\{1, \dots, n\}.

diagram Diagram mermaid

Three things the notation hides.

The interval is part of the inner product. sin\sin and cos\cos are orthogonal on [π,π][-\pi,\pi] and not on [0,π/2][0, \pi/2], where 0π/2sinxcosxdx=12\int_0^{\pi/2}\sin x\cos x\,dx = \tfrac{1}{2}. Changing [a,b][a,b] changes the geometry exactly as changing the matrix A\mathbf{A} did in §3.2.

Positive definiteness needs care. abu(x)2dx=0\int_a^b u(x)^2\,dx = 0 does not force u(x)=0u(x) = 0 at every point — a function that is zero except at one point still integrates to zero. The clean statement is that it forces u=0u = 0 almost everywhere, and the honest fix is to work in a space where functions differing on a measure-zero set are treated as the same vector. That is what L2[a,b]L^2[a,b] means, and it is the only place in this chapter where the finite and infinite cases genuinely differ.

The integral must converge. Not every function pair has a finite inner product; u(x)=v(x)=1/xu(x) = v(x) = 1/x on [0,1][0,1] does not. The space of functions for which it does is the space you work in.

The induced norm and everything downstream

Section titled “The induced norm and everything downstream”
u=u,u=abu(x)2dx,d(u,v)=uv,cosω=u,vuv\lVert u \rVert = \sqrt{\langle u, u\rangle} = \sqrt{\int_a^b u(x)^2\,dx}, \qquad d(u,v) = \lVert u - v\rVert, \qquad \cos\omega = \frac{\langle u, v\rangle}{\lVert u\rVert\,\lVert v\rVert}

Nothing new is being defined — these are §3.3 and §3.4 verbatim with the new inner product substituted in. That reuse is the point of having stated those sections abstractly.

Their Gram matrix is diagonal rather than the identity, because these functions are orthogonal but not of unit length. Measured on the first seven members:

1,1=2π6.283185,coskx,coskx=sinkx,sinkx=π3.141593\langle 1, 1\rangle = 2\pi \approx 6.283185, \qquad \langle \cos kx, \cos kx\rangle = \langle \sin kx, \sin kx\rangle = \pi \approx 3.141593

with every off-diagonal entry below 4.5×10164.5\times10^{-16}. So this is an orthogonal basis, not an orthonormal one, and the coordinate formula needs the division that §3.5’s pitfall warned about:

ck=f, sinkxsinkx, sinkx=1πππf(x)sin(kx)dxc_k = \frac{\langle f,\ \sin kx\rangle}{\langle \sin kx,\ \sin kx\rangle} = \frac{1}{\pi}\int_{-\pi}^{\pi} f(x)\sin(kx)\,dx

Dividing by π\pi is not a convention plucked from nowhere — it is 1/sinkx21/\lVert\sin kx\rVert^2.

sin,cos=ππsin(x)cos(x)dx\langle \sin, \cos \rangle = \int_{-\pi}^{\pi} \sin(x)\cos(x)\,dx

There are two ways to see that this is zero, and both are worth having.

By antiderivative. The double-angle identity gives sinxcosx=12sin2x\sin x\cos x = \tfrac{1}{2}\sin 2x, whose antiderivative is 14cos2x-\tfrac{1}{4}\cos 2x. So

ππsinxcosxdx=[14cos2x]ππ=14cos2π+14cos(2π)=14+14=0\int_{-\pi}^{\pi}\sin x\cos x\,dx = \left[-\tfrac{1}{4}\cos 2x\right]_{-\pi}^{\pi} = -\tfrac{1}{4}\cos 2\pi + \tfrac{1}{4}\cos(-2\pi) = -\tfrac{1}{4} + \tfrac{1}{4} = 0

By symmetry, which is the book’s argument and the better one. The product w(x)=sinxcosxw(x) = \sin x \cos x satisfies w(x)=sin(x)cos(x)=sinxcosx=w(x)w(-x) = \sin(-x)\cos(-x) = -\sin x\cos x = -w(x): it is odd. The integral of an odd function over an interval symmetric about the origin is zero, because every positive contribution on the right has an exactly equal negative partner on the left.

That is not “small”, it is cancellation. Measured, the positive area is +0.9999999997+0.9999999997 and the negative area is 0.9999999997-0.9999999997 — the same ten digits — and the integral comes out at exactly 00 in floating point. The oddness itself is measured too: maxxw(x)+w(x)=1.1×1015\max_x \lvert w(x) + w(-x)\rvert = 1.1\times10^{-15}.

Take f(x)=sign(sinx)f(x) = \mathrm{sign}(\sin x) on [π,π][-\pi,\pi]: +1+1 on (0,π)(0,\pi), 1-1 on (π,0)(-\pi,0).

Coefficient on sinkx\sin kx. Both ff and sinkx\sin kx are odd, so their product is even and the integral is twice the right half:

f,sinkx=20πsin(kx)dx=2[coskxk]0π=2k(1coskπ)={4/kk odd0k even\langle f, \sin kx\rangle = 2\int_0^{\pi}\sin(kx)\,dx = 2\left[-\frac{\cos kx}{k}\right]_0^{\pi} = \frac{2}{k}\big(1 - \cos k\pi\big) = \begin{cases} 4/k & k \text{ odd} \\ 0 & k \text{ even}\end{cases}

Dividing by sinkx2=π\lVert \sin kx\rVert^2 = \pi:

kkck=4kπc_k = \dfrac{4}{k\pi} for odd kkmeasured
14/π4/\pi1.2732401.273240
20.0-0.0
34/(3π)4/(3\pi)0.4244130.424413
40.0-0.0
54/(5π)4/(5\pi)0.2546480.254648
60.0-0.0
74/(7π)4/(7\pi)0.1818910.181891

The even coefficients are exactly 0.0-0.0, not small: coskπ=1\cos k\pi = 1 for even kk, so the bracket is identically zero.

Coefficient on coskx\cos kx and on the constant. ff is odd and coskx\cos kx is even, so every product is odd and every one of those coefficients is zero. A square wave needs sines only, which is a statement about symmetry rather than about square waves.

functions_worked.py
import numpy as np
 
x = np.linspace(-np.pi, np.pi, 200001)          # odd count, so 0 is a sample
ip = lambda u, v: float(np.trapezoid(u * v, x))
 
# Example 3.9
w = np.sin(x) * np.cos(x)
print("<sin, cos>       =", f"{ip(np.sin(x), np.cos(x)):.3e}")
print("positive area    =", f"{float(np.trapezoid(np.where(w > 0, w, 0), x)):+.10f}")
print("negative area    =", f"{float(np.trapezoid(np.where(w < 0, w, 0), x)):+.10f}")
print("odd? max|w(x)+w(-x)| =", f"{np.max(np.abs(w + w[::-1])):.1e}")
 
# The Gram matrix of the first seven members of the trigonometric family.
fam = [("1", np.ones_like(x))]
fam += [(f"cos {k}x", np.cos(k * x)) for k in (1, 2, 3)]
fam += [(f"sin {k}x", np.sin(k * x)) for k in (1, 2, 3)]
G = np.array([[ip(a, b) for _, b in fam] for _, a in fam])
print("diagonal:", np.round(np.diag(G), 6))
print("largest off-diagonal:", f"{np.max(np.abs(G - np.diag(np.diag(G)))):.3e}")
print("2*pi =", round(2 * np.pi, 6), "  pi =", round(np.pi, 6))
 
# Square-wave coefficients, one independent integral each.
f = np.sign(np.sin(x))
print("||f||^2 =", round(ip(f, f), 6), " and 2*pi =", round(2 * np.pi, 6))
c = {k: ip(f, np.sin(k * x)) / ip(np.sin(k * x), np.sin(k * x)) for k in range(1, 8)}
print("coefficients:", {k: round(v, 6) for k, v in c.items()})
print("4/(k pi):    ", {k: round(4 / (k * np.pi), 6) for k in (1, 3, 5, 7)})
output
<sin, cos>       = 0.000e+00
positive area    = +0.9999999997
negative area    = -0.9999999997
odd? max|w(x)+w(-x)| = 1.1e-15
diagonal: [6.283185 3.141593 3.141593 3.141593 3.141593 3.141593 3.141593]
largest off-diagonal: 4.441e-16
2*pi = 6.283185   pi = 3.141593
||f||^2 = 6.283185  and 2*pi = 6.283185
coefficients: {1: 1.27324, 2: -0.0, 3: 0.424413, 5: 0.254648, 4: -0.0, 6: -0.0, 7: 0.181891}

The first sketch is Example 3.9 with both frequencies on knobs. Set them equal and the cancellation stops.

sketch Two frequencies, and when the areas cancel p5.js
The top panel draws sin(mx) and cos(nx) — or sin(nx), via the second toggle — on the interval from minus pi to pi. The bottom panel is their product, with the positive area shaded green and the negative area red. The readout integrates both. They cancel for every pair except the ones where the two functions coincide.

The second sketch rebuilds the square wave one term at a time, and shows Parseval predicting the error.

sketch A square wave from its projections p5.js
Drag the term count. Each coefficient is one independent integral, so adding a term never changes an earlier one. The readout gives the measured squared error and the value Parseval predicts from the coefficients kept, and they agree. Watch the overshoot at the jump: it shrinks in width but not in height.

The third sketch is the sum-to-integral limit, which is what justifies calling a function a vector.

sketch A function is a vector once you sample it p5.js
Drag the sample count. The bars are the sampled values of two functions and the readout is their discrete dot product multiplied by the spacing. As the sample count grows that number converges to the integral, which is printed for comparison — so the integral inner product is the limit of the finite one, not a different kind of object.
function_space.py
import numpy as np
 
def make_space(a, b, n=200001):
    """An inner product space of functions on [a, b], sampled for numerics."""
    x = np.linspace(a, b, n)
    def ip(u, v):
        return float(np.trapezoid(u(x) * v(x), x))
    def norm(u):
        return np.sqrt(ip(u, u))
    def angle_deg(u, v):
        c = np.clip(ip(u, v) / (norm(u) * norm(v)), -1.0, 1.0)
        return float(np.degrees(np.arccos(c)))
    return x, ip, norm, angle_deg
 
x, ip, norm, angle = make_space(-np.pi, np.pi)
 
sin, cos = np.sin, np.cos
print("<sin, cos> on [-pi, pi]:", f"{ip(sin, cos):.3e}", " angle:", round(angle(sin, cos), 6))
print("||sin|| =", round(norm(sin), 6), " sqrt(pi) =", round(np.sqrt(np.pi), 6))
 
# The interval is part of the inner product.
_, ip2, norm2, angle2 = make_space(0.0, np.pi / 2)
print("<sin, cos> on [0, pi/2]:", round(ip2(sin, cos), 6),
      " angle:", round(angle2(sin, cos), 4), "deg")
 
# Distance between two functions, and the triangle inequality on functions.
f = lambda t: np.sin(t)
g = lambda t: np.sin(t) + 0.3 * np.sin(3 * t)
h = lambda t: np.sin(t) + 0.3 * np.sin(3 * t) - 0.2 * np.cos(2 * t)
d = lambda p, q: norm(lambda t: p(t) - q(t))
print("d(f,g) =", round(d(f, g), 6), " d(g,h) =", round(d(g, h), 6), " d(f,h) =", round(d(f, h), 6))
print("triangle inequality holds:", d(f, h) <= d(f, g) + d(g, h) + 1e-12)
output
<sin, cos> on [-pi, pi]: 0.000e+00  angle: 90.0
||sin|| = 1.772454  sqrt(pi) = 1.772454
<sin, cos> on [0, pi/2]: 0.5  angle: 50.4598 deg
d(f,g) = 0.531736  d(g,h) = 0.354491  d(f,h) = 0.639067
triangle inequality holds: True

Two results worth reading. On [π,π][-\pi,\pi] the angle between sin\sin and cos\cos is exactly 90°90°; on [0,π/2][0,\pi/2] it is 50.46°50.46° and the inner product is 12\tfrac{1}{2}. Same two functions, different interval, different geometry — the interval plays precisely the role the matrix A\mathbf{A} played in §3.2.

And sin=π1.772454\lVert\sin\rVert = \sqrt{\pi} \approx 1.772454, not 11. Sine is a unit vector under no particularly natural normalisation, which is why Fourier coefficients carry a 1/π1/\pi.

figure Example 3.9, with the two areas measured matplotlib
Two stacked panels. The top plots sine and cosine over minus pi to pi. The bottom plots their product with the positive lobes filled green and the negative lobes filled red, annotated with the two measured areas and the integral. Two stacked panels. The top plots sine and cosine over minus pi to pi. The bottom plots their product with the positive lobes filled green and the negative lobes filled red, annotated with the two measured areas and the integral.
The positive area is +0.9999999997 and the negative area is -0.9999999997 — agreement to ten digits, so the integral is exactly zero in floating point. The last line is an independent check that the product is odd, which is the book's actual argument.
figure One coefficient at a time matplotlib
Left, a square wave with four partial sums of increasing length drawn over it. Right, a log-log plot of the squared error against the number of terms, with a panel listing the first several coefficients and the exact values four over k pi. Left, a square wave with four partial sums of increasing length drawn over it. Right, a log-log plot of the squared error against the number of terms, with a panel listing the first several coefficients and the exact values four over k pi.
The coefficients are measured integrals, and the odd ones match 4/(k pi) to six figures while the even ones are exactly minus zero. The error falls from 1.190227 at one term to 0.039786 at sixty-four — a slow decay, and the plot shows why on the left.

From the cancellation figure. The green and red areas are visibly the same size, and the printed values agree to ten digits. That is what orthogonality of functions looks like: not a small residue but exact cancellation forced by symmetry.

The line to notice is the last one in the panel — maxxw(x)+w(x)=1.1×1015\max_x\lvert w(x) + w(-x)\rvert = 1.1\times10^{-15}. That is a check on the reason, not the result. The integral could be zero by accident; the product being odd is why it cannot be otherwise, and it is the argument the book gives.

From the partial sums. Three separate things are measured here.

The coefficients match the closed form. c1=1.273240c_1 = 1.273240 against 4/π=1.2732404/\pi = 1.273240; c3=0.424413c_3 = 0.424413 against 4/(3π)4/(3\pi); c5=0.254648c_5 = 0.254648 against 4/(5π)4/(5\pi). And the even ones are exactly 0.0-0.0 rather than 101610^{-16}, because the bracket 1coskπ1 - \cos k\pi is identically zero for even kk rather than nearly zero.

The error decays slowly, and Parseval says exactly how slowly. Measured: 1.1902271.190227 at one term, 0.6243430.624343 at three, 0.2538110.253811 at nine, 0.0748750.074875 at thirty-three, 0.0397860.039786 at sixty-four. That is roughly O(1/n)O(1/n), which is bad as convergence rates go — and Parseval predicts it without running the approximation. The total energy is f2=2π=6.283185\lVert f\rVert^2 = 2\pi = 6.283185, and the energy captured by the first nine terms is πk9ck2=6.029375\pi\sum_{k\leq 9} c_k^2 = 6.029375. The difference is 0.2538110.253811 — exactly the measured error at nine terms.

That is §3.5’s Parseval identity doing predictive work: the truncation error is the energy you did not keep, and you can compute it from the coefficients without ever forming the approximation. It is the same statement as “the reconstruction error of a PCA truncation is the sum of the discarded eigenvalues”, which Chapter 10 will make.

The overshoot does not go away. The peak of the partial sum is 1.2732401.273240 at one term, 1.2004221.200422 at three, 1.1823281.182328 at nine, 1.1792681.179268 at thirty-three and 1.1790611.179061 at sixty-four. It is converging — to about 1.17901.1790, not to 11. This is the Gibbs phenomenon: near a jump discontinuity the partial sums overshoot by roughly 9%9\% of the jump, and adding terms makes the overshoot narrower without making it shorter.

Which is not a contradiction with L2L^2 convergence. The squared error does go to zero, because the region where the overshoot lives is shrinking. Convergence in the norm this page defines says nothing about convergence at any individual point — a distinction that matters the moment you use a truncated basis to reconstruct something with edges.

finite vectorsfunctions on [a,b][a,b]
the vectorxRn\mathbf{x} \in \mathbb{R}^nu:[a,b]Ru : [a,b] \to \mathbb{R}
inner productixiyi\sum_i x_i y_iabu(x)v(x)dx\int_a^b u(x)v(x)\,dx
normixi2\sqrt{\sum_i x_i^2}abu(x)2dx\sqrt{\int_a^b u(x)^2\,dx}
dimensionnninfinite
an orthogonal basiseigenvectors, singular vectors{1,coskx,sinkx}\{1, \cos kx, \sin kx\}
coordinatesnn inner productscountably many integrals
truncation errordiscarded squared coordinatesdiscarded squared coefficients
what can go wrongconditioningconvergence, and pointwise behaviour

The middle rows are identical in substance. The last row is where the two genuinely part company.

pch.quizTag Check your understanding
  1. The book's argument that sin and cos are orthogonal on [-pi, pi] is not 'compute the antiderivative'. What is it?

    pch.quizShowAnswer

    B — That their product is an odd function and the interval is symmetric about the origin, so every positive contribution has an exactly equal negative partner — Measured, the positive area is +0.9999999997 and the negative area -0.9999999997. The oddness is checked independently: the largest value of |w(x) + w(-x)| across the interval is 1.1e-15.

  2. Why do Fourier coefficients carry a factor of 1/pi?

    pch.quizShowAnswer

    B — Because the trigonometric family is orthogonal but not orthonormal: the squared norm of sin kx is pi, so the coordinate formula divides by it — and the constant function, with squared norm 2pi, divides by 2pi instead — Measured, the Gram matrix of the first seven members is diag(6.283185, 3.141593, ...) with the largest off-diagonal entry at 4.4e-16. The factor-of-two difference on the constant term is a classic bug.

  3. For the square wave, the measured squared error at nine terms is 0.253811. Where does that number also appear?

    pch.quizShowAnswer

    B — Parseval predicts it: the total energy is 2 pi = 6.283185 and the energy in the first nine coefficients is 6.029375, and the difference is 0.253811 exactly — the truncation error is the energy you did not keep — This is the same statement Chapter 10 makes about PCA: the reconstruction error of a truncation is the sum of the discarded squared coordinates. It lets you price a truncation without ever computing the approximation.

  4. The peak of the partial sum converges to about 1.179 rather than to 1, while the squared error converges to zero. How are both true?

    pch.quizShowAnswer

    B — The overshoot occupies an ever-narrower region near the jump, so it contributes ever less to the integral — convergence in this norm says nothing about convergence at any individual point — This is the Gibbs phenomenon: the overshoot is about nine percent of the jump and it gets narrower without getting shorter. Measured peaks: 1.273240 at one term, 1.182328 at nine, 1.179061 at sixty-four.

Exercise 1 – Reproduce Example 3.9 twice over

Section titled “Exercise 1 – Reproduce Example 3.9 twice over”

Exercise 2 – The Gram matrix of the Fourier family

Section titled “Exercise 2 – The Gram matrix of the Fourier family”

Exercise 3 – The interval changes the geometry

Section titled “Exercise 3 – The interval changes the geometry”

Exercise 4 – Fourier coefficients, one integral each

Section titled “Exercise 4 – Fourier coefficients, one integral each”

Exercise 5 – Parseval predicts the truncation error

Section titled “Exercise 5 – Parseval predicts the truncation error”
  • The inner product of two functions is the integral of their product over an interval, Equation 3.37 — and the interval is part of the definition, not a detail.
  • All three axioms survive, so length, distance, angle and orthogonality carry over unchanged from sections 3.3 and 3.4.
  • Sine and cosine are orthogonal on the symmetric interval because their product is odd, so the positive and negative areas cancel exactly. The book’s argument is the symmetry, not the antiderivative.
  • The trigonometric family is orthogonal but not orthonormal: squared norms are two pi for the constant and pi for every sine and cosine, which is where the one-over-pi in a Fourier coefficient comes from.
  • Each coefficient is one independent integral, so adding a term never changes an earlier one — the same property an orthonormal basis has in finite dimensions.
  • Parseval predicts the truncation error exactly: total energy minus the energy of the coefficients kept. Measured on a square wave at nine terms, both come to 0.253811.
  • Convergence in this norm is not pointwise convergence. The Gibbs overshoot near a jump converges to about 1.179 rather than to 1, while the squared error still goes to zero, because the overshoot gets narrower rather than shorter.
  • A function is a vector once you sample it, and the integral inner product is the limit of the finite dot product weighted by the spacing.

Next: Orthogonal Projections — the computation the whole chapter has been building towards.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading