fpsのニュートン法高速化(簡易版)

概要

サイズnnのFFTを行うときの計算量をF(n)と表します。

唐突ですが、ffのinvを計算するニュートン法は次のようなものでした。

g2n=gnϵngng_{2n}=g_n-\epsilon_ng_n
ここで、
ϵn=fngn1\epsilon _n =f_ng_n-1


上記の式をナイーブに計算すると、ϵn\epsilon_nの計算で3F(4n)3F(4n)g2ng_{2n}の計算で3F(4n)3F(4n)かかるので、トータル6F(4n)6F(4n)回の計算が行われます。


寄り道

ところで、演算の順序を工夫すると、かなり速くなります(noshiさんが教えてくれた):
g2n=2gn(gn)2fng_{2n}=2g_n-(g_n)^2f_n

(gn)2(g_n)^2の計算を長さ4nのDFTでやることにすると、F(4n)F(4n)(gn)2(g_n)^2のDFTが手に入って、deg(gn)2<2ndeg (g_n)^2 < 2nであることから、そのまま(gn)2fn(g_n)^2 f_nの計算に使えます。
fnf_nのDFTと、最後のIDFTで2F(4n)2F(4n)使うので、トータルで3F(4n)3F(4n)となります。
これ実装楽だしかなり速いので、とりあえずこの実装を採用するとコスパよい

本題

gng_nからg2ng_{2n}5F(2n)5F(2n)で得る方法を紹介します。(先ほどの方法と比べると、こちらのほうがサイズ2n2nのFFT 1回分くらいお得です。また、ここで紹介する手法を転用すると、他の演算(quotient,sqrt,log,exp)が2倍くらい速くなったりします。


まずはϵn=fngn1   mod   x2n\epsilon_n=f_ng_n-1 \ \ \ mod \ \ \ x^{2n}を計算します:
GnG_nFnF_nを、それぞれgng_nfnf_nのサイズ2n2nのDFTとします。これらは、2F(2n)2F(2n)回のFFTで計算できます。
次に、GnG_nFnF_nの要素ごとの積をとります。このとき、deg(fngn)2ndeg (f_n g_n) \geq 2nであることから、循環が発生します。演算結果をIDFTします。(得られた多項式をhnh_nとおきます(deghn<2ndeg h_n <2n))

hnh_n[0,n)[0,n)次の係数は、実際にはfngnf_ng_n[0,n)[0,n)次の係数と[2n,3n)[2n,3n)次の係数の重ね合わせとなっています(循環畳み込みなので!)
同様に、hnh_n[n,2n)[n,2n)次の係数は、fngnf_ng_n[n,2n)[n,2n)次の係数と[3n,4n)[3n,4n)次の係数の重ね合わせになっています。

今、fngnf_ng_n[0,2n)[0,2n)次の係数だけが欲しいので、困ってしまいます。
ところが、fngn1 mod xnf_ng_n \equiv 1 \ mod \ x^nなので、[0,n)[0,n)の係数は1,0,0,...1,0,0,...です。
また、deg gn<ndeg \ g_n < nよりdeg fngn<3ndeg \ f_ng_n < 3nなので、hnh_n[n,2n)[n,2n)次の係数(fngnf_ng_n[n,2n)[n,2n)次の係数と[3n,4n)[3n,4n)次の係数の重ね合わせ)は、実際にはfngnf_ng_n[n,2n)[n,2n)次の係数と一致します。

上記の計算量は3F(2n)3F(2n)です。

→解決


上記の手法の本質は、fngnf_ng_n[0,n)[0,n)次と[3n,4n)[3n,4n)次の係数が分かっているおかげで、(サイズを2倍せずに)普通に循環畳み込みをやっても、各係数を復元できることです。

次に、
g2n=gnϵngng_{2n}=g_n-\epsilon_n g_n
の計算を考えます。先ほどと同様にdeg gn<ndeg \ g_n < nなので、ϵngn\epsilon _n g_n[3n,4n)[3n,4n)次の係数は0です。また、
ϵn\epsilon_n[0,n)[0,n)次の係数は0(これは、すぐにわかります)なので、ϵngn\epsilon_ng_n[0,n)[0,n)次の係数は0です。
従って先ほどと同様に循環畳み込みを用いることができて、3F(2n)3F(2n)回の計算で出来ます。
ところで、gng_nのサイズ2n2nのDFTは使いまわせるので、F(2n)F(2n)回の計算を削減することができて、全体で5F(2n)5F(2n)回でできます。