What is the Discrete Fourier Transform?
If you have an n-degree polynomial, the polynomial is uniquely identified by
- its n+1 coefficients ai for i=0,1,…,n.
- its values at n+1 points.
As the points are arbitrary, let us choose the points to be the n+1 roots of unity. (i.e. x=e2πk/n for k=0,1,…,n)
The mapping from the coefficients to the values at these points is called the Discrete Fourier Transform (DFT).
Given a polynomial P(x)=a0+a1x+a2x2+⋯+anxn, the DFT is defined as:
DFT(a0,a1,…,an)=(P(1),P(e2π/n),P(e4π/n),…,P(e2(n−1)π/n),P(e2π))
Naturally, the inverse of the DFT would be the mapping from these n+1 points to the coefficients.
Multiplication of Polynomials
Suppose we have two polynomials P(x) and Q(x), each of degree n.
P(x)Q(x)=a0+a1x+a2x2+⋯+anxn=b0+b1x+b2x2+⋯+bnxn
Calculating (P⋅Q)(x) is rather arduous, as each term has to be multiplied with every term of the other polynomial. This will take O(n2) time.
(P⋅Q)(x)=(a0+a1x+a2x2+⋯+anxn)(b0+b1x+b2x2+⋯+bnxn)=k=0∑2n(i=max(0,k−n)∑naibk−i)xk
Now let us consider the the values of the P(x) and Q(x) at the n+1 roots of unity, then note that we can find the values of (P⋅Q)(x) at these points by simply multiplying the corresponding values of P(x) and Q(x) at these points. This will take O(n) time.
(P⋅Q)(e2πk/n)=P(e2πk/n)⋅Q(e2πk/n) for k=0,1,…,n−1
Since we know theres a correspondence between the values of the polynomials at the n+1 roots of unity and their coefficients through the DFT.
Maybe we calculate (P⋅Q)(e2πk/n) by
- Use the DFT to get the values of P(e2πk/n) and Q(e2πk/n) for k=0,1,…,n−1.
- At the roots of unity, get the values of (P⋅Q)(e2πk/n) by multiplying the values of P(e2πk/n) and Q(e2πk/n) for k=0,1,…,n−1.
- Use the inverse DFT to get the coefficients of (P⋅Q)(x) from these values.
We know step 2 takes O(n) time. But how long does step 1 and 3 take? With the Fast Fourier Transform (FFT), DFT and inverse DFT can be computed in O(nlogn) time!
This approach reduces the time complexity of multiplying 2 polynomials from O(n2) to O(nlogn) using the Fast Fourier Transform (FFT).
This is a powerful result that we can use to improve the efficiency of algorithms that reduces to polynomial multiplication, such as convolution and string searching.
To learn more about the Fast Fourier Transform (FFT), check out the cp-algorithms. Everything discussed on this page is from there.
(Quick Aside) Formula for polynomial multiplication
Recall the formula for polynomial multiplication for (m−1)-degree polynomial P(x) and (n−1)-degree polynomial Q(x) where m<n:
(P⋅Q)(x)(P⋅Q)[k]=(P[0]+P[1]x+P[2]x2+⋯+P[m−1]xm−1)(Q[0]+Q[1]x+Q[2]x2+⋯+Q[n−1]xn−1)=k=0∑m+n−2(i=max(0,k−n+1)∑min(m−1,k)P[i]Q[k−i])xk=i=max(0,k−n+1)∑min(m−1,k)P[i]Q[k−i]
Single character wildcard string searching
The problem of searching for a substring in a string is well studied and there are many algorithms that can do this efficiently.
However, when the substring contains single character wildcards, the problem becomes more complex. Naively, we check every possible substring of the text that matches the pattern, which takes O(mn) time, where m is the length of the pattern and n is the length of the text.
Let us see if we can do better than this.
Reducing the problem to polynomial multiplication
Suppose we have a pattern P of length m and a text T of length n such that
- P and T are arrays of non-negative numbers where each number represent a character.
- Define the single character wildcard to be 0.
- For simplicity, we will assume that n is infinite (this allows us to omit the boundary check).
Then there is a match at position a in the text if and only if (P[i]=0)∨(T[a+i]=P[i]) for i=0,1,…,m−1
Now if we interpret the P and T as polynomials, such that
P(x)T(x)=P[0]+P[1]x+P[2]x2+⋯+P[m]xm=T[0]+T[1]x+T[2]x2+⋯+T[n]xn
Then the condition for a match at position a can be rewritten as:
i=0∑m−1P[i](T[a+i]−P[i])2i=0∑m−1P[i]T[a+i]2−2P[i]2T[a+i]+P[i]3i=0∑m−1P[i]T′[n−1−a−i]2−2P[i]2T′[n−1−a−i]+P[i]3i=0∑m−1P[i]T′[a′−i]2−2P[i]2T′[a′−i]+P[i]3(P⋅T′2)[a′]−2(P2⋅T′)[a′]+S=0=0=0 where T′ is the reverse of T=0 where a′=n−1−a=0 where S=∑i=0m−1P[i]3
Wow, that was a lot of math! But we can see that we can reduce the problem to polynomial multiplication.
We can use Fast Fourier Transform (FFT) to compute the polynomial multiplication (P \cdot T'^2) and (P^2 \cdot T') efficiently
and look at the which coefficients of the resulting polynomial are 0, which will tell us the positions of the matches in the text.