COMP9101 从算法角度理解快速傅里叶变换FFT

如无必要,尽量使用通俗的定义
原则上只需要理解就可以。

1. 卷积的定义,计算,以及问题

1.1 卷积定义理解

数学定义

给定两个向量 a = ( a 0 , a 1 , . . . a n ) a = (a_0,a_1,...a_n) a=(a0,a1,...an) b = ( b 0 , b 1 . . . b n ) b = (b_0,b_1...b_n) b=(b0,b1...bn)
他们的卷积 a ∗ b = ( a 0 b 0 , a 0 b 1 + a 1 b 0 , a 0 b 2 + a 1 b 1 + a 2 b 0 , . . . a n − 2 b n − 1 + a n − 1 b n − 2 , a n − 1 b n − 1 ) a*b = (a_0b_0, a_0b_1 +a_1b_0, a_0b_2+a_1b_1+a_2b_0,...a_{n-2}b_{n-1} + a_{n-1}b_{n-2} , a_{n-1}b_{n-1}) ab=(a0b0,a0b1+a1b0,a0b2+a1b1+a2b0,...an2bn1+an1bn2,an1bn1)即对于卷积后形成的新的向量,第k项为: ∑ ( i , j ) , i + j = k a i b j \sum_{(i,j), i+j=k} a_ib_j (i,j),i+j=kaibj

通俗理解:(只看这里就够了)

卷积的结果

  1. 总共有 2n-1项 , 当然这里是为了方便,如果 a有n项,b有m项,那结果就是 m+n-1 项,之后为了讨论方便,我们预设 i < m , j < n i<m, j<n i<m,j<n
  2. 第k项为 所有下标 i , j 加起来等于k的a,b向量的和,比如 卷积结果的第三项 c 3 = a 0 b 3 + a 1 b 2 + a 2 b 1 + a 3 b 0 c_3 = a_0b_3 + a_1b_2 + a_2b_1 + a_3b_0 c3=a0b3+a1b2+a2b1+a3b0
类比理解:

对于多项式 A ( x ) = a 0 + a 1 x . . . + a m − 1 x m − 1 A(x) = a_0 + a_1x...+ a_{m-1}x^{m-1} A(x)=a0+a1x...+am1xm1 B ( x ) = b 0 + b 1 x . . . + b n − 1 x n − 1 B(x) = b_0 + b_1x...+ b_{n-1}x^{n-1} B(x)=b0+b1x...+bn1xn1
他们相乘的结果 C ( x ) = A ( x ) B ( x ) C(x) = A(x)B(x) C(x)=A(x)B(x)的系数向量就是 A ( x ) A(x) A(x) B ( x ) B(x) B(x)的系数向量卷积

1.2 卷积的计算

为方便讨论,我们只考虑等长向量 m=n 的情况
从1.1的定义我们知道了,对于卷积结果的第k项,我们计算 ∑ ( i , j ) , i + j = k a i b j \sum_{(i,j), i+j=k} a_ib_j (i,j),i+j=kaibj

让我们做一下算法分析:
结果总共有2n-1项,第一项我们要进行1次乘法(0,0),第二项 2次(0,1),(1,0),第n项 n次(0,n-1)…(n-1, 0) , 第2n-1项 2n-1次。
平均下来,对于每一项,我们都要计算n次乘法, 总共有2n-1项,即卷积的计算需要 O ( n 2 ) O(n^2) O(n2)的时间。
但是明明输入和输出都只有O(n)的规模, 我们能不能找到第一个更好的方法优化这个算法使其小于 O ( n 2 ) O(n^2) O(n2)呢?

1.2.1 快速傅里变换叶FFT

FFT只需要 O ( n l o g n ) O(nlogn) O(nlogn)次算术运算便可以完成两个向量的计算。

根据前文给出的类比理解我们可以这样理解:
我们把向量 a = ( a 0 , a 1 , . . . a n ) a = (a_0,a_1,...a_n) a=(a0,a1,...an) b = ( b 0 , b 1 . . . b n ) b = (b_0,b_1...b_n) b=(b0,b1...bn)理解成多项式 A ( x ) = a 0 + a 1 x . . . + a m − 1 x m − 1 A(x) = a_0 + a_1x...+ a_{m-1}x^{m-1} A(x)=a0+a1x...+am1xm1 B ( x ) = b 0 + b 1 x . . . + b n − 1 x n − 1 B(x) = b_0 + b_1x...+ b_{n-1}x^{n-1} B(x)=b0+b1x...+bn1xn1
则他们相乘的结果 C ( x ) = A ( x ) B ( x ) = c 0 + c 1 x . . . + c 2 n − 1 x 2 n − 1 C(x) = A(x)B(x)= c_0 + c_1x...+ c_{2n-1}x^{2n-1} C(x)=A(x)B(x)=c0+c1x...+c2n1x2n1的系数向量 c = ( c 0 , c 1 , . . . c 2 n − 1 ) c = (c_0,c_1,...c_{2n-1}) c=(c0,c1,...c2n1)正好就是 a ∗ b a * b ab
换句话说,我们想知道卷积的结果 c c c ,我们只需要知道 C ( x ) C(x) C(x),
那我们的思路就很清晰了,求 A ( x ) B ( x ) A(x)B(x) A(x)B(x)

求解多项式A(x)B(x)

首先,回想起一个关于多项式的基本事实:

任何d阶多项式可以由它在任意一组d+1个或者更多的点上的值重新构造出来,这叫做 多项式插值
也就是说如果要确定m-1阶多项式 A ( x ) = a 0 + a 1 x . . . + a m − 1 x m − 1 A(x) = a_0 + a_1x...+ a_{m-1}x^{m-1} A(x)=a0+a1x...+am1xm1, 需要导入至少m个x值
就像如果想求解2元一次方程ax+b=0,至少需要代入2个x值,列出两个方程式才可以解出来a和b.

所以我们要确定 C ( x ) = A ( x ) B ( x ) C(x) = A(x)B(x) C(x)=A(x)B(x)
我们就要得到 C ( x 1 ) , C ( x 2 ) . . . . . . C ( x 2 n ) C(x_1) , C(x_2)......C(x_{2n}) C(x1),C(x2)......C(x2n)
也就是 A ( x 1 ) , A ( x 2 ) . . . . . . A ( x 2 n ) A(x_1) , A(x_2)......A(x_{2n}) A(x1),A(x2)......A(x2n) B ( x 1 ) , B ( x 2 ) . . . . . . B ( x 2 n ) B(x_1) , B(x_2)......B(x_{2n}) B(x1),B(x2)......B(x2n)

所以设计算法

  1. 选择2n个值 x j = ( x 0 , x 1 , . . . x 2 n ) x_j = (x_0,x_1,...x_{2n}) xj=(x0,x1,...x2n), 然后分别求 A ( x j ) A(x_j) A(xj) B ( x j ) B(x_j) B(xj)
  2. 计算2n个 C ( x j ) = A ( x j ) B ( x j ) C(x_j) = A(x_j)B(x_j) C(xj)=A(xj)B(xj)
  3. 利用2n个 C ( x i ) C(x_i) C(xi)多项式插值求出多项式 C ( x ) C(x) C(x),系数向量即为卷积结果

分析算法:
第一步: 2n * n * 2 次乘法计算, 即O(n^2)运算
第二步:O(n)次运算
第三步:利用多项式插值求多项式是O(nlogn)次运算,这个我们暂且不提

可以看到,算法仍然被第一步限制在了O(n^2), 怎么解决?
我们注意到,这2n个x值是相互独立的,我们可以找到一组密切相关的2n个x值使得求值工作可以被继承。

单位1的复数根
我们可以把一个复数表示成在复平面上的一个用极坐标表示的点 r e θ i re^{\theta i} reθi其中 e π i = − 1 e^{\pi i}=-1 eπi=1
对于一个多项式方程 x k = 1 x^k=1 xk=1,存在k个不同的复根,即 w j , k = e 2 π j i k w_{j,k} = e^{\frac {2\pi ji}{k}} wj,k=ek2πji for j = 0,1,2…k-1
我们把这k个根叫做单位1的k次方根

同样的道理,我们把第一步中的2n个值选为 单位1的2n次方跟,即 x j = w j , 2 n = e 2 π j i 2 n = e π j i n x_j = w_{j,2n} = e^{\frac {2\pi ji}{2n}} = e^{\frac {\pi ji}{n}} xj=wj,2n=e2n2πji=enπji for j = 0,1,2…2n-1
然后再来计算 A ( x i ) A(x_i) A(xi)
为了达到 O ( n l o g n ) O(nlogn) O(nlogn),我们采用分治递归的方法,那怎么分?
我们定义
A e v e n ( x ) = a 0 + a 2 x + a 4 x 2 + . . . + a n − 2 x n − 2 2 A_{even} (x) = a_0 + a_2x + a_4x^2 + ...+a_{n-2}x^{\frac {n-2}{2}} Aeven(x)=a0+a2x+a4x2+...+an2x2n2
A o d d ( x ) = a 1 + a 3 x + a 5 x 2 + . . . + a n − 1 x n − 2 2 A_{odd} (x) = a_1 + a_3x + a_5x^2 + ...+a_{n-1}x^{\frac {n-2}{2}} Aodd(x)=a1+a3x+a5x2+...+an1x2n2
这样我们便可以拆分合并 A ( x ) = A e v e n ( x 2 ) + x A o d d ( x 2 ) A(x) = A_{even} (x^2) + xA_{odd} (x^2) A(x)=Aeven(x2)+xAodd(x2)

我们代入某一个单位根 w j , 2 n w_{j,2n} wj,2n求值,我们有: A ( w j , 2 n ) = A e v e n ( w j , 2 n 2 ) + w j , 2 n A o d d ( w j , 2 n 2 ) A(w_{j,2n}) =A_{even}(w_{j,2n}^2) + w_{j,2n}A_{odd}(w_{j,2n}^2) A(wj,2n)=Aeven(wj,2n2)+wj,2nAodd(wj,2n2)
,我们注意到 w j , 2 n 2 w_{j,2n}^2 wj,2n2,其实也是这2n个单位根之一( w j , 2 n 2 = 1 w_{j,2n}^2 = 1 wj,2n2=1),所以 A ( w j , 2 n 2 ) A(w_{j,2n}^2) A(wj,2n2)的求解在之前的递归中早就已经求过了,我们只需要获取它并且带到式子里面即可。这样,计算$ A ( w j , 2 n ) A(w_{j,2n}) A(wj,2n)的过程就变成了:

  1. 递归求解 A e v e n ( w j , 2 n 2 ) A_{even}(w_{j,2n}^2) Aeven(wj,2n2) A o d d ( w j , 2 n 2 ) A_{odd}(w_{j,2n}^2) Aodd(wj,2n2)
  2. O ( n ) O(n) O(n)次数得到 A ( w j , 2 n ) A(w_{j,2n}) A(wj,2n)

我们可以得到 T ( n ) ≤ 2 T ( n 2 ) + O ( n ) T(n) \leq 2T(\frac {n}{2}) + O(n) T(n)2T(2n)+O(n)
显然,第一步的得到了需要的 O ( n l o g n ) O(nlogn) O(nlogn)

因此整体快速傅里叶的算法只需要 O ( n l o g n ) O(nlogn) O(nlogn)次算术运算即可实现两个向量卷积的快速运算。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值