多项式/形式幂级数相关
定义
多项式(polynomial)(A(x)=sum_{i=0}^{ ext{deg}(A)}ig[x^iig]Ax^i),一般习惯把(ig[x^iig]A)记作(a_i),即多项式的系数,而( ext{deg})函数即多项式最高次项指数(度数degree).
形式幂级数(formal power series)(A(x)=sum_{i=0}^{inf}ig[x^iig]Ax^i),与多项式的区别就是它能取无穷项.关于形式幂级数显然我们难以直接操作,但是我们关注的一般是它指数最低的几项,即(Amod x^n).
形式幂级数不要求收敛(converge),它的具体值并不是最主要的关注点.
因为多项式是形式幂级数的截断,因此我们将多项式看成(x^{> ext{deg}(A)})项系数为0的形式幂级数,而统称多项式(因为比较短).
记号
为了减少(写起来相当麻烦的)(TeX)公式的使用,我们规定一些记号.
x^z
x的z次(其中x可以是符号(symbol),或者表达式(expression))[x^z]A
A的x^z次项.简写为A_z.其中A应该是一个多项式的符号或表达式.[cond]p
如果cond则p否则为0.deg(A)
A的度数,其中A应该是一个多项式的符号或者表达式.sum(i,lb,ub){expr}
对满足lb<=i<=ub的非负整数i求和expr,其中i是一个符号,expr应该是一个(可以包含i的)表达式或者一个展开中包含i的符号.sum(cond){expr}
对于满足cond的在cond中出现的符号(除非写明都认为应该是非负整数)求和,expr应该是一个(可以包含cond中出现的符号的)表达式或者一个展开中包含cond中出现的符号的符号.F(x)=expr
定义一个函数F(x),函数F(x)在特定情况下可以看成是多项式,即存在它在0点的泰勒展开(taylor expansion)时认为它在0点的泰勒展开是它的多项式(formal power series)表示.F(x,...)
定义一个多参数函数(multivariate function),可以在特定情况下认为是多参数多项式(multivariate polynomial).多参数多项式即多项式对于多个变量的幂的积乘上对应的系数求和.F_z(x)
对F(x)在x=z点泰勒展开.int(F,x)
F对变量x积分(integrate).也写成sFdx
.deriv(F,x)
F对变量x求导(derivate).也写成dFdx
(省略了/号).在单变量情形下可以写作F'
sum(F,x)
F对变量x求不定和(summuation).也写成zFdx
.对于多项式情况默认x>=0
,这样的不定和我们写作gFdx
和poly(F,x)
.diff(F,x)
F对变量x求差分(difference).也写成DFdx
.(F(x+1)-F(x))
运算规则
A+B=gA_z+B_z*x^zdz
A-B=gA_z-B_z*x^zdz
A*B=ggA_zB_t*x^{z+t}dzdt
即对系数的离散卷积.A'=g(z+1)A_{z+1}*x^zdz
sAdx=gA_{z}/z*x^{z+1}dz+C
一般可以忽略常数项C的存在(但是最好不要这么做).A mod x^n=g[z<n]A_z*x^zdz
即截断.A mod B
按照一般的多项式取模的定义,即A=Q*B+(A mod B)
,Q是多项式且deg(A mod B)<deg(B)
.可以看出在mod x^n
上等价.deg(A*B)=deg(A)+deg(B)
A^t
为t个A连乘.deg(A^t)=t*deg(A)
.A(B)=gA_zB^zdz
为多项式的嵌套.
计算
对于这里叙述的所有复杂度,都假设在一个word machine(类似于现实中的计算机)上执行,而且都假设是单变量多项式.
A+B
和A-B
的计算都是Theta(deg(A+B))的,不必多说了.
A*B
直接计算是Theta(deg(A)*deg(B))的,优化这部分的复杂度会在后面叙述,这是一个相当经典的问题.
sFdx
与F'
都是Theta(deg(F))的.
A mod B
直接计算的复杂度是Theta(deg(A)*deg(B))的,后面也会讲到如何优化这部分的复杂度.
A^t
直接做的复杂度是Theta(t^2*deg(A)^2)
的,使用快速幂的技巧是T(t)=t*deg(A)*t*deg(A)+T(t/2)=Theta(t^2*deg(A)*2)
的,所以没有区别.
A(B)
(polynomial embedding) 直接做的复杂度是Theta(deg(A)^3*deg(B)^2)
的,在模意义下做可以获得更好的复杂度.
但是我们一般关注的是A^t mod B
,这个复杂度就在后面分析了(显而易见的是这下t可以很大了).
多项式乘法
多项式乘法的优化总体上来说都是计算成点值后转换回去.
对于一个多项式,我们有(虽然不止)以下两种表示法:
- 系数表示法 即将多项式表示为
A(x)=gA_t*x^tdt
. - 点值表示法 即储存
deg(A)+1
个求值点与对应的点值,容易发现对应的多项式是唯一的.
点值表示法并不直观,然而在几乎各种运算上都很有优势.那是不是系数表示法就没用了呢?当然不是,因为我们关注的并不是值而是多项式的系数啊..
点值表示法可以做到:
- 在O(n)时间内进行多项式的加法、减法以及在O(M*n)的时间内乘法.(M是乘法的复杂度)
- 对于特殊的求指点,可以在O(M*n)时间内进行求值(应用Lagrange插值法加上一些小技巧可以做到).
几乎所有卷积的加速都运用了点值表示和系数表示的转换.这样的算法大致上分为两类,虽然分类得不太严谨.
toom-cook类算法
toom-cook类算法的复杂度得益于一个思考:如果在大的情况下乘法远比加法更耗时间,那么考虑使用更多的加法来减少乘法的使用量.
对于两个长度(deg+1)为n的多项式相乘,理想情况下我们只需要使用2*n-1个乘法(求值时的乘法是可以忽略掉的,因为它乘的数是常数).剩下的我们如果要重新转换为系数表示我们相当于在给一个方程组消元,最多需要n^3个加减法和乘除常数,而且这个步骤是固定的.
我们假定n是一个常数,那么n3也就只是一个常数而已(听起来像诡辩),但是考虑下,我们多项式的每一项系数并不一定是一个数,而可以是一个多项式.这样我们就可以把一个大小为`tn*tn`的多项式乘法拆成`(2t-1)`个`n*n`的乘法和最多`n^3`个`n`的加法/乘除常数实现(实际上完全可以更少,大概可以做到n2级别,我猜).
这样叙述太抽象了,让我们随便给个例子:
Karatsuba's Algorithm
(Ax+B)(Cx+D)=ACxx+(AD+BC)x+BD
u1:AC,u2:AD+BC,u3:BD
求值
(x,y)=1,0,0/1
值为v1:AC,v2:(A+B)(C+D),v3:BD
重组v1xx+(v2-v1-v3)x+v3
具体的推导过程:
根据求值的过程我们可以得到
/ 0 0 1 / u3 / v3
| 1 1 1 || u2 |=| v2 |
1 0 0 / u1 / v1 /
然后就是简单的高斯消元
考虑一下复杂度大概是T(n)=(2t-1)T(n/t)+O(t^3*n/t)
.通过加上一些优化可以做到T(n)=(2t-1)T(n/t)+O(t^2*n/t*log(t))
.通过对不同的n采取不同的t可以做到大约O(n*log(n)*2^sqrt(2*log(n)))
的复杂度(小于O(n^(1+epsilon))
)(来源:TAOCP Vol2 P302).
DFT类算法
影响toom-cook类算法效率的有一个大问题:对于固定的t我们可以认为它的复杂度是O(n^log(t,2t-1))
,但是随着t的增长它的常数因子增长得过快使得更大的t马上变得不实用.然而考虑如果有一类特殊的点值,它的求值和插值都能很方便的进行,那么我们是不是就可以将这个t放得比较大了.