Definition (Convolution). Given sequences {aj}j=0m and {bk}k=0n of numbers, their convolutiona∗b is:
{cℓ}ℓ=0n+m given by cℓ=(a∗b)ℓ:=j=0∑ℓajbℓ−j.
This is just polynomial multiplication, or the PMF of the sum of two independent discrete random variables.
Problem. (FFT) Given {aj}j=0m and {bk}k=0n, compute their convolution a∗b in O((m+n)log(m+n)) time.
Remark. The naive brute-force algorithm runs in O(mn) time.
Let's black-box a solution to FFT for now. How might it be useful?
Problem. (String Matching) Fix a string s=(s0,…,sn)∈{0,1}n+1 and a pattern p=(p0,…,pm)∈{0,1}m+1. Find the set H of all indices k for which sk+i=pi for all i=0,…,m.
Solution. (String Matching) Switch to a ±1 encoding, reverse p, and compute s∗p. This is O(nlogn). ■
Now let's un-black-box the solution to FFT. How is FFT implemented in O((m+n)log(m+n)) time?
Solution. (FFT) It's equivalent to compute p(x)⋅q(x) for polynomials satisfying deg(p)=m and deg(q)=n.
The driving principle behind our solution is the following.
Fact. Any degree-n polynomial is uniquely determined by its evaluations on any n+1 distinct values.
A good choice of values to evaluate our polynomials on, it turns out, is the full set of (2t)th roots of unity.
Claim (Discrete Fourier Transform). Let n be a power of two, and let ω:=en2πi. For any polynomial p with degree (n−1) or lower, we can compute {p(ωk)}k=0n−1 in O(nlogn) time.
Proof: Divide and conquer. Say the runtime is T(n).
Denote peven(x) and podd(x) so that p(x)=peven(x2)+x⋅podd(x2).
In 2T(2n) time, compute {peven(ω2k)}k=0n/2−1 and {podd(ω2k)}k=0n/2−1.
This yields T(n)=2T(2n)+O(n), which solves to T(n)=O(nlogn). □
Thus, we select ω=eN2πi for some power-of-two N>m+n, then compute {p(ωk)⋅q(ωk)}k=0N−1 in O((m+n)log(m+n)) time. It remains to invert the DFT process above to extract p(x)⋅q(x) from here.
Claim (Inverse Discrete Fourier Transform). Given the values {p(ωk)}k=0n−1 for some polynomial p with degree (n−1) or lower, we can compute p(x) in O(nlogn) time.
Proof: The point is that the Inverse DFT is no harder than the DFT.
Say p(x)=a0+a1x+a2x2+⋯+an−1xn−1. Then the DFT computes a matrix product: