FFT
算法描述,求解对于 A(x)B(x) 的卷积,对于某一个多项式 A(x) 而言
插值多项式的唯一性
对于 n 个点值对组成的集合 {(x0,y0),(x1,y1),⋯,(xn−1,yn−1)}
其中所有的 xk 均不同,那么可以唯一确定次数为 n 的多项式 A(x),满足 yk=A(xk)
带入多项式,等价于方程
⎝⎜⎜⎜⎜⎛11⋮1x0x1⋮xn−1x02x12⋱xn−12⋯⋯⋮⋯x0n−1x1n−1xn−1n−1⎠⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎛a0a1⋮an−1⎠⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎛y0y1⋮yn−1⎠⎟⎟⎟⎟⎞
对于 ak 有唯一解,其中左边的矩阵表示为范德蒙行列式,该行列式值为
0⩽j<k⩽n−1∏(xk−xj)
矩阵可逆,求出唯一的 a 为 V(x0,x1,⋯,xn−1)−1y
给定 n 次多项式,取 n+1 个点可以将行列式唯一表示出来
根据点表示法,对于 C(x)=A(x)B(x),可以用 A(x),B(x) 的点表示法,假设 A,B 的次数分别为 n,m
取 n+m+1 个点
{(x1,A(x1)),(x2,A(x2))⋯,(xn+m+1,A(xn+m+1))}{(x1,B(x1)),(x2,B(x2))⋯,(xn+m+1,B(xn+m+1))}{(x1,A(x1)B(x1)),(x2,A(x2)B(x2))⋯,(xn+m+1,A(xn+m+1)B(xn+m+1))}
这样可以在 O(n+m) 的时间复杂度内求出多项式 C(x)
普通乘法和点值乘法快速转换
如果能将普通多项式乘法转换成为点值乘法,那么 FFT 是很容易实现的,为此取单位复数根
即满足 ωn=1 的复数 ω,n 次单位根恰好有 n 个,对于 k=0,1,⋯,n−1
这些根是 e2πik/n,利用复数的指数表达,可以写成
eiu=cos(u)+isin(u)
n 个单位根均匀分布在圆周上,值 ωn=e2πi/n 为主 n 次单位根
所有其他负数根均为 ωn 的幂次,这些根构成了一个模 n 意义下的乘法群,结构如下
ωnjωnk=ωnj+k=ωn(j+k)modn,类似地
ωn−1=ωnn−1
消去引理
对于任意 n⩾0,k⩾0,d>0,我们有
ωdndk=ωnk
这是显然的,因为 (e2πi/dn)dk=(e2πi/n)k=ωnk
那么可以根据消去引理,推出折半引理
对于任意偶数 n>0,有 ωnn/2=ω2=−1
证明也很简单,ωnn/2=ωn/2n/4=⋯=ωn/(n/2)n/((n/2)⋅2)=ω2
根据折半引理
ωnk+n/2=−ωnk
求和引理
对于任意整数 n⩾1 和不能被 n 整除的非负整数 k,有
j=0∑n−1(ωnk)j=0
可以用等比数列求和
j=0∑n−1(ωnk)j=ωnk−1(ωnk)n−1=ωnk−1(ωnn)k−1=ωnk−1(1)k−1=0
DFT
假设 n 为 2 的整数幂
根据 A(x) 中偶数下标和奇数下标的系数,定义最高次数为 n/2−1 的多项式 A[0](x) 和 A[1](x)
A[0](x)=a0+a2x+a4x2+⋯+an−2xn/2−1A[1](x)=a1+a3x+a5x2+⋯+an−1xn/2−1
那么有 A(x)=A[0](x2)+x⋅A[1](x2)
那么可以采用分治策略,对于 k∈[0,n/2−1],可以得到
A(ωnk)=A0(ωn2k)+ωnkA1(ωn2k)=A0(ωn/2k)+ωnkA1(ωn/2k)
而对于 k∈[n/2,n−1],令 k′←k+n/2,k∈[0,n/2−1],问题可以转为上述情况,即求 A(ωnk+n/2)
A(ωnk+n/2)=A0(ωn2k+n)−ωnkA1(ωn2k+n)=A0(ωn/2k)−ωnkA1(ωn/2k)
这里用了折半引理
IDFT
接下来需要根据点表示法,逆变换求出卷积系数
已知点表示 (ωnk,A(ωnk)),令 yk←A(ωnk)
则 A(x)=a0+a1x+a2x2+⋯+an−1xn−1,推导出
ak=n1⋅i=0∑n−1yi(ωn−k)i
求出 ak,实际上也是在求多项式,构造 B(x)=y0+y1x+y2x2+⋯yn−1xn−1
则 ak=n1B(ωn−k)
只要求出 B(x) 在 (ωn0,ωn−1,⋯,ωn−(n−1)) 上的值
这也可以通过 DFT 求出
下面给出证明
ck=i=0∑n−1yi(ωn−k)i=i=0∑n−1(j=0∑n−1aj(ωni)j)⋅(ωn−k)i=i=0∑n−1(j=0∑n−1aj(ωnj)i(ωn−k)i)=i=0∑n−1(j=0∑n−1aj(ωnj−k)i)=j=0∑n−1aj(i=0∑n−1(ωnj−k)i)
注意到项 S(ωnk′)=(i=0∑n−1(ωnj−k)i)
其中 ωnk′←ωnj−k,根据求和引理,当
k′=0,S(ωnk′)=0
k′=0 时,ωn0=1,那么 S(1)=n
也就是对应 ck 表达式中,j=k 时才有贡献,我们有 ck=nak,证毕
证明 2,可以考虑用矩阵来证明
根据 yk=A(ωnk),系数 ak 对应的项就是 ωnk
⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛1111⋮11ωnωn2ωn3⋮ωnn−11ωn2ωn4ωn6⋱ωn2(n−1)1ωn3ωn6ωn9⋱ωn3(n−1)⋯⋯⋯⋯⋮⋯1ωnn−1ωn2(n−1)ωn3(n−1)⋮ωn(n−1)(n−1)⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛a0a1a2a3⋮an−1⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛y0y1y2y3⋮yn−1⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞
不妨设 DFT 的 ωnk 对应的矩阵是 Vn,只需要证明
引理,对于 j,k∈[0,1,⋯,n−1],Vn−1 的 (j,k) 处元素为 ωn−kj/n
考虑矩阵乘法,Vn−1Vn,对应 (j,k)×(k,j′)=(j,j′),考虑 (j,j′) 的元素
只要证明,我们有 (j,k) 元素为 ωn−kj/n 的矩阵 V′,能推出该矩阵 V′ 为 Vn−1 即可
[Vn−1Vn]jj′=k=0∑n−1(ωn−kj/n)⋅ωnkj′=k=0∑n−1ωnk(j−j′)/n
注意此时 −(n−1)⩽j′−j⩽n−1,可以用求和引理
(说明,如果此时 −(n−1)⩽j′−j<0,可以用 ωn−p=ωnn−p 变换)
如果 j=j′,右边等于 1,否则根据求和引理,和为 0
所以 Vn−1Vn 为单位矩阵 In,证毕
FFT 实现
蝴蝶变换
输入向量下标为 (0,1,2,3,4,5,6,7),那么 DFT 递归树叶子结点的下标是 (0,4,2,6,1,5,3,7)
这是根据之前的分析,奇数项写在前面,偶数项写在后面
恰好是二进制表示的位逆序置换,比如 6=110,位逆序置换成 011=3
这个很好证明,假设最终系数 x 二进制表示是 (⋯ 1),那么它是奇数项,一定在 [n/2,n−1] 这一半的区间
这一半区间中,对应回原来未打乱顺序的数,是较大的一半,最高位都是 1
如果二进制表示最低位是 0,即 (⋯ 0),那么是偶数项
对应回原来的前一半,此时最高位为 0
那么核心是位翻转的实现,这可以递归来做
ri=(ri≫1≫1)∣(i & 1)≪(bit−1)
bit 表示最高位的 1 在第几位上
综上所述,FFT 实现的过程如下
- 预处理出卷积多项式有 tot 项,其中 tot 满足 2 的 b 次幂,不足可以补 0
比如 A(x) 有 n+1 项(最高次幂为 n),B(x) 有 m+1 项,那么必须满足 (1≪b)⩾m+n+2
tot=(1≪b),则卷积多项式的系数下标范围是 [0,tot)
- [mid=1,2,22⋯,tot] 逐层归并计算,对于每一层,分治区间起始点是 [i=0,i+2mid,i+4mid,⋯,tot)
接下来计算 DFT(v1) 和 DFT(v2),根据如上所述的 DFT 公式
用折半引理,j 遍历长度为 mid 的前后两半区间,其中前一半下标是 i+j,后一半下标是 i+j+mid
v1=Ai+j+ω2midk⋅Ai+j+mid,v2=Ai+j−ω2midk⋅Ai+j+mid
具体来说,在算法实现上
每一次迭代循环 mid 的时候,令 ωn=ω2mid=e2πi/2mid=eπi/mid=cos(π/mid)−i⋅sin(π/mid)
x=A(i+j), y=ωnk⋅A(i+j+mid)
然后令 A(i+j)←x+y, A(i+j+mid)←x−y,特别注意,这里 ωnk 是可以实时计算的
只要在归并的开始,即对 j 循环 for j∈[0,mid) 前,令 ωnk=1,然后每一次 j++ 的时候,令 ωnk←ωnk⋅ωn