Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
AtCoder Typical Contest 001
C 高速フーリエ変換
AtCoder 株式会社
問題概要
AtCoder 食堂では,
円の主菜が 種類
円の副菜が 種類
i Ai
j Bj
ある.
ちょうど 円になる, 主菜と副菜一つずつの組合せがい
くつあるかを出力せよ.
k
畳込み
ちょうど 円になる組合せの数を とすると, 主菜で
円の物を選んだ時, 副菜として 円の物を選べばよ
く,
となる. 但し, とおく.
k Ck i
k − i
=Ck
∑
i=0
k
Ai Bk−i
= = 0A0 B0
このような ...
畳込みから多項式乗算へ
ここで, , を係数とする多項式
を考えると, その積は
で定まる.
A B
g(x) = ,
∑
i=0
N
Ai x
i
h(x) =
∑
j=0
N
Bj x
j
(g ∗ h)(x) = g(x) ∗ h(x)
...
畳込みから多項式乗算へ
ここで, とおいて
を書きなおすと,
i + j = k
(g ∗ h)(x) =
∑
i=0
N
∑
j=0
N
Ai Bj x
i+j
(g ∗ h)(x) =
( )
∑
k=0
2N
∑
i=0
k
Ai Bk−...
多項式乗算
を高速に求めたい.(g ∗ h)(x)
普通に書くと, こんな感じで .O (deg(g) ∗ deg(h))
def multiply(g, h):
  f = [ 0 for _ in range(len(g) + len(h)...
多項式の性質
は, 次の多項式.g(x) ∗ h(x) deg(g) + deg(h)
よって, 個の点 での値 が
求まっていれば, これを通る は一意.
deg(g) + deg(h) + 1 xi f ( )xi
h
例えば,
二点を決め...
高速多項式乗算の戦略
1. とし, 個の点 を,
計算しやすいようにうまく選ぶ.
2. と, を計算する.
3. を使って,
を計算する.
4. うまいこと何かして,
から を復元する.
n > deg(g) + deg(h) n , …,x0...
点の選び方
実際には, が の冪乗になるようにし, と
しては の 乗根全体を選ぶ.
n 2 , …,x0 xn−1
1 n
つまり, として, とする.= exp(2π /n)ζn −1‾‾‾√ =xi ζi
n
の性質ζn
には, 次の性質がある.= exp(2π /n)ζn −1‾‾‾√
.
"直交性" が成り立つ. すなわち,
(最後の は, 等比級数の和の公式から.)
= ⇔ i = j mod nζi
n ζj
n
=
∑
i=0
n−1
( ...
離散フーリエ変換
前述の通り, として, 評価と補間をする. こうする
と, 何がよいのかを見ていこう.
=xi ζi
n
多項式 に対し, を
で定める. つまり, 評価した各点での値を係数に持つ多項
式である.
f (x) (t)fˆ
(t...
離散フーリエ変換
とすると,f (x) = ∑n−1
j=0
cj x
j
(t)fˆ = f ( )
∑
i=0
n−1
ζi
n t
i
=
(
(
)
∑
i=0
n−1
∑
j=0
n−1
cj ζi
n )
j
t
i
= ( t
∑...
離散フーリエ逆変換
を求めてみると,
だが,
だったから,
( )fˆ ζ−k
n
( )fˆ ζ−k
n = (
∑
j=0
n−1
cj
∑
i=0
n−1
ζj
n ζ−k
n )
i
=
{∑
i=0
n−1
ζi(j−k)
n
n, ...
離散フーリエ逆変換
よって, の DFT
から,
と, を で置き換えた DFT で を復元出来る. こ
れを, 離散フーリエ逆変換と呼ぶ.
f
(t) = f ( )fˆ
∑
i=0
n−1
ζi
n t
i
f (x) = ( )
1
n ...
積の離散フーリエ変換 (DFT)
さて, "多項式を評価した値" を係数としたのだから当然
ではあるが, は,
と, と の係数毎の積で求められる.
(t)g ∗ hˆ
(t)g ∗ hˆ = (g ∗ h)( )
∑
i=0
n−1
ζi
n...
離散フーリエ変換を使った乗算
結局, 多項式の積を求めるには,
1. となる の冪乗を選ぶ.
2. 上の に DFT をして を計算する.
3. と を係数毎に掛け, を求める.
4. に inverse DFT をして を復元する.
n > ...
離散フーリエ変換を使った乗算
擬似コードで書くと,
def multiply(g, h):
  n = pow_2_at_least(deg(g) + deg(h) + 1)
  # g, h は n­1 次になるように 0 を詰めておく.
 ...
高速フーリエ変換
あとは, DFT, inverse DFT を高速に求められればよい.
高速に DFT を求めるアルゴリズムを "高速フーリエ変換"
(Fast Fourier Transformation, FFT) と呼ぶ.
invers...
高速フーリエ変換
の冪乗 と 次以下の多項式
に対し,
とすると,
で, , はそれぞれ 次以下の多項式.
2 n n − 1 f (x) = ∑n−1
i=0
ci x
i
(x)f0
(x)f1
= = + + + …,
∑
i=0
n/2...
高速フーリエ変換
を求めるには,fˆ
f ( ), f ( ), …, f ( )ζ0
n ζ1
n ζn−1
n
を求められればよかったが, だ
から,
f (x) = ( ) + x ( )f0 x
2
f1 x
2
( ), ( ), …...
高速フーリエ変換
だから,
= exp (2 ∗ 2π /n) = exp (2π /(n/2)) =ζ2
n −1‾‾‾√ −1‾‾‾√ ζn/2
( ), ( ), …, ( ),f0 ζ0
n f0 ζ2
n f0 ζ2(n−1)
n
(...
高速フーリエ変換
は 乗すると だから, . よって,ζn/2 n/2 1 =ζi+n/2
n/2
ζi
n/2
( ), ( ), …, ( ),f0 ζ0
n/2
f0 ζ1
n/2
f0 ζn−1
n/2
( ), ( ), …, ( )...
高速フーリエ変換
よって, 次以下の多項式 に対してn − 1 f
f ( ), f ( ), …, f ( )ζ0
n ζ1
n ζn−1
n
を求めるには, 二つの 次以下の多項式 に対
して
n/2 − 1 ,f0 f1
( ), ( )...
高速フーリエ変換
再帰的に行うと, 必要になる計算回数 は,T (n)
T (n) =
{
O(1),
2T (n/2) + O(n),
if n = 1,
otherwise
で, これを解くと になる.T (n) = O(n log n)
高速フーリエ変換
以上のアルゴリズムを擬似コードで書くと,
def dft(f, n):
  if n == 1:
    return f
  f0 = [ f[2*i + 0] for i in range(n / 2) ]
  f1 = ...
発展的な話題
複素数以外の "環" での FFT
上の FFT は, 複素数だけでなく, の原始 乗根(ちょうど
乗すると になるような要素)が存在する "可換環" で
出来る.
1 n
n 1
これから, 例えば で割ると 余る素数を法とする FFT
が出...
発展的な FFT アルゴリズム
今まで紹介した再帰的な FFT が基本だが, 他にも様々な
FFT アルゴリズムがある.
Cooley-Tukey FFT, Gentleman-Sande FFT
再帰的 FFT を非再帰, in-place(...
発展的な FFT アルゴリズム
分割基底 FFT
と のように二つに分割するのではなく, より多
くの個数に分割する.
つに分割する, -基底 FFT がよく用いられる.
four-step FFT, six-step FFT
約 個に分割し,...
参考文献
1. R. Crandall, C. Pomerance, 和田秀男 監訳,
"素数全書: 計算からのアプローチ",
朝倉書店, 2010, ISBN 978-4-254-11128-6.
2. R. Sedgewick,
野下 浩平...
Upcoming SlideShare
Loading in …5
×

高速フーリエ変換

23,504 views

Published on

高速フーリエ変換の解説です

Published in: Education
  • Be the first to comment

高速フーリエ変換

  1. 1. AtCoder Typical Contest 001 C 高速フーリエ変換 AtCoder 株式会社
  2. 2. 問題概要 AtCoder 食堂では, 円の主菜が 種類 円の副菜が 種類 i Ai j Bj ある. ちょうど 円になる, 主菜と副菜一つずつの組合せがい くつあるかを出力せよ. k
  3. 3. 畳込み ちょうど 円になる組合せの数を とすると, 主菜で 円の物を選んだ時, 副菜として 円の物を選べばよ く, となる. 但し, とおく. k Ck i k − i =Ck ∑ i=0 k Ai Bk−i = = 0A0 B0 このような を, と の畳込み (convolution) という.C A B
  4. 4. 畳込みから多項式乗算へ ここで, , を係数とする多項式 を考えると, その積は で定まる. A B g(x) = , ∑ i=0 N Ai x i h(x) = ∑ j=0 N Bj x j (g ∗ h)(x) = g(x) ∗ h(x) = ∑ i=0 N ∑ j=0 N Ai Bj x i+j
  5. 5. 畳込みから多項式乗算へ ここで, とおいて を書きなおすと, i + j = k (g ∗ h)(x) = ∑ i=0 N ∑ j=0 N Ai Bj x i+j (g ∗ h)(x) = ( ) ∑ k=0 2N ∑ i=0 k Ai Bk−i x k = ∑ k=0 2N Ck x k となるから, この が計算出来ればよい.(g ∗ h)(x)
  6. 6. 多項式乗算 を高速に求めたい.(g ∗ h)(x) 普通に書くと, こんな感じで .O (deg(g) ∗ deg(h)) def multiply(g, h):   f = [ 0 for _ in range(len(g) + len(h) ­ 1) ]   for i in range(len(g)):     for j in range(len(h)):       f[i+j] += g[i] * h[j]   return f
  7. 7. 多項式の性質 は, 次の多項式.g(x) ∗ h(x) deg(g) + deg(h) よって, 個の点 での値 が 求まっていれば, これを通る は一意. deg(g) + deg(h) + 1 xi f ( )xi h 例えば, 二点を決めると, それを同時に通る直線は一つ. 三点を決めると, それを同時に通る放物線は一つ.
  8. 8. 高速多項式乗算の戦略 1. とし, 個の点 を, 計算しやすいようにうまく選ぶ. 2. と, を計算する. 3. を使って, を計算する. 4. うまいこと何かして, から を復元する. n > deg(g) + deg(h) n , …,x0 xn−1 g( ), …, g( )x0 xn−1 h( ), …, h( )x0 xn−1 (g ∗ h)(x) = g(x) ∗ h(x) (g ∗ h)( ), …, (g ∗ h)( )x0 xn−1 (g ∗ h)( ), …, (g ∗ h)( )x0 xn−1 (g ∗ h)(x) 2 のように, 点での値を求めることを "評価" (evaluation), 4 のように, 点での値から元の多項式を復元することを "補間" (interpolation) と呼ぶ.
  9. 9. 点の選び方 実際には, が の冪乗になるようにし, と しては の 乗根全体を選ぶ. n 2 , …,x0 xn−1 1 n つまり, として, とする.= exp(2π /n)ζn −1‾‾‾√ =xi ζi n
  10. 10. の性質ζn には, 次の性質がある.= exp(2π /n)ζn −1‾‾‾√ . "直交性" が成り立つ. すなわち, (最後の は, 等比級数の和の公式から.) = ⇔ i = j mod nζi n ζj n = ∑ i=0 n−1 ( )ζj n i ( ) ζk n ⎯ ⎯⎯⎯⎯⎯ i ∑ i=0 n−1 ζi(j−k) n = { n, if j = k mod n, 0, otherwise. = 0 を で置き換えても, これらの性質は変わらない.ζn ζ−1 n
  11. 11. 離散フーリエ変換 前述の通り, として, 評価と補間をする. こうする と, 何がよいのかを見ていこう. =xi ζi n 多項式 に対し, を で定める. つまり, 評価した各点での値を係数に持つ多項 式である. f (x) (t)fˆ (t) = f ( )fˆ ∑ i=0 n−1 ζi n t i これを, の離散フーリエ変換 (Discrete Fourier Transformation, DFT) と呼ぶ. f
  12. 12. 離散フーリエ変換 とすると,f (x) = ∑n−1 j=0 cj x j (t)fˆ = f ( ) ∑ i=0 n−1 ζi n t i = ( ( ) ∑ i=0 n−1 ∑ j=0 n−1 cj ζi n ) j t i = ( t ∑ j=0 n−1 cj ∑ i=0 n−1 ζj n ) i
  13. 13. 離散フーリエ逆変換 を求めてみると, だが, だったから, ( )fˆ ζ−k n ( )fˆ ζ−k n = ( ∑ j=0 n−1 cj ∑ i=0 n−1 ζj n ζ−k n ) i = {∑ i=0 n−1 ζi(j−k) n n, if j = k mod n, 0, otherwise ( )fˆ ζ−k n = n .ck
  14. 14. 離散フーリエ逆変換 よって, の DFT から, と, を で置き換えた DFT で を復元出来る. こ れを, 離散フーリエ逆変換と呼ぶ. f (t) = f ( )fˆ ∑ i=0 n−1 ζi n t i f (x) = ( ) 1 n ∑ i=0 n−1 fˆ ζ−i n x i ζn ζ−1 n f (x)
  15. 15. 積の離散フーリエ変換 (DFT) さて, "多項式を評価した値" を係数としたのだから当然 ではあるが, は, と, と の係数毎の積で求められる. (t)g ∗ hˆ (t)g ∗ hˆ = (g ∗ h)( ) ∑ i=0 n−1 ζi n t i = g( )h( ) ∑ i=0 n−1 ζi n ζi n t i gˆ hˆ
  16. 16. 離散フーリエ変換を使った乗算 結局, 多項式の積を求めるには, 1. となる の冪乗を選ぶ. 2. 上の に DFT をして を計算する. 3. と を係数毎に掛け, を求める. 4. に inverse DFT をして を復元する. n > deg(g) + deg(h) 2 g, h (t), (t)gˆ hˆ (t)gˆ (t)hˆ (t)g ∗ hˆ (t)g ∗ hˆ (g ∗ h)(x) とすればよい.
  17. 17. 離散フーリエ変換を使った乗算 擬似コードで書くと, def multiply(g, h):   n = pow_2_at_least(deg(g) + deg(h) + 1)   # g, h は n­1 次になるように 0 を詰めておく.   gg = dft(g, n)   hh = dft(h, n)   ff = [ gg[i] * hh[i] for i in range(n) ]   return inverse_dft(ff, n)
  18. 18. 高速フーリエ変換 あとは, DFT, inverse DFT を高速に求められればよい. 高速に DFT を求めるアルゴリズムを "高速フーリエ変換" (Fast Fourier Transformation, FFT) と呼ぶ. inverse DFT は, DFT で出てくる を全て で置き換 え, 最後に で割ればよいだけなので, 以下では DFT につ いてのみ解説する. ζn ζ−1 n n
  19. 19. 高速フーリエ変換 の冪乗 と 次以下の多項式 に対し, とすると, で, , はそれぞれ 次以下の多項式. 2 n n − 1 f (x) = ∑n−1 i=0 ci x i (x)f0 (x)f1 = = + + + …, ∑ i=0 n/2−1 c2i x i c0 x 0 c2 x 1 c4 x 2 = = + + + …∑ i=0 n/2−1 c2i+1 x i c1 x 0 c3 x 1 c5 x 2 f (x) = ( ) + x ( )f0 x 2 f1 x 2 f0 f1 n/2 − 1
  20. 20. 高速フーリエ変換 を求めるには,fˆ f ( ), f ( ), …, f ( )ζ0 n ζ1 n ζn−1 n を求められればよかったが, だ から, f (x) = ( ) + x ( )f0 x 2 f1 x 2 ( ), ( ), …, ( ),f0 ζ0 n f0 ζ2 n f0 ζ2(n−1) n ( ), ( ), …, ( )f1 ζ0 n f1 ζ2 n f1 ζ2(n−1) n を求めればよい.
  21. 21. 高速フーリエ変換 だから, = exp (2 ∗ 2π /n) = exp (2π /(n/2)) =ζ2 n −1‾‾‾√ −1‾‾‾√ ζn/2 ( ), ( ), …, ( ),f0 ζ0 n f0 ζ2 n f0 ζ2(n−1) n ( ), ( ), …, ( )f1 ζ0 n f1 ζ2 n f1 ζ2(n−1) n は, ( ), ( ), …, ( ),f0 ζ0 n/2 f0 ζ1 n/2 f0 ζn−1 n/2 ( ), ( ), …, ( )f1 ζ0 n/2 f1 ζ1 n/2 f1 ζn−1 n/2 と同じ.
  22. 22. 高速フーリエ変換 は 乗すると だから, . よって,ζn/2 n/2 1 =ζi+n/2 n/2 ζi n/2 ( ), ( ), …, ( ),f0 ζ0 n/2 f0 ζ1 n/2 f0 ζn−1 n/2 ( ), ( ), …, ( )f1 ζ0 n/2 f1 ζ1 n/2 f1 ζn−1 n/2 は, それぞれ前半と後半が同じで, 前半だけの ( ), ( ), …, ( ),f0 ζ0 n/2 f0 ζ1 n/2 f0 ζn/2−1 n/2 ( ), ( ), …, ( )f1 ζ0 n/2 f1 ζ1 n/2 f1 ζn/2−1 n/2 を求めればよい.
  23. 23. 高速フーリエ変換 よって, 次以下の多項式 に対してn − 1 f f ( ), f ( ), …, f ( )ζ0 n ζ1 n ζn−1 n を求めるには, 二つの 次以下の多項式 に対 して n/2 − 1 ,f0 f1 ( ), ( ), …, ( ),f0 ζ0 n/2 f0 ζ1 n/2 f0 ζn/2−1 n/2 ( ), ( ), …, ( )f1 ζ0 n/2 f1 ζ1 n/2 f1 ζn/2−1 n/2 を求めればよいことになった. これは, サイズが半分になった同じ問題を二つ解けばよ いということ!!
  24. 24. 高速フーリエ変換 再帰的に行うと, 必要になる計算回数 は,T (n) T (n) = { O(1), 2T (n/2) + O(n), if n = 1, otherwise で, これを解くと になる.T (n) = O(n log n)
  25. 25. 高速フーリエ変換 以上のアルゴリズムを擬似コードで書くと, def dft(f, n):   if n == 1:     return f   f0 = [ f[2*i + 0] for i in range(n / 2) ]   f1 = [ f[2*i + 1] for i in range(n / 2) ]   f0 = dft(f0, n/2)   f1 = dft(f1, n/2)   zeta = complex(cos(2 * pi / n), sin(2 * pi / n))   pow_zeta = 1   for i in range(n)     # この時点で, pow_zeta = pow(zeta, i)     f[i] = f0[i % (n/2)] + pow_zeta * f1[i % (n/2)]     pow_zeta *= zeta   return f
  26. 26. 発展的な話題
  27. 27. 複素数以外の "環" での FFT 上の FFT は, 複素数だけでなく, の原始 乗根(ちょうど 乗すると になるような要素)が存在する "可換環" で 出来る. 1 n n 1 これから, 例えば で割ると 余る素数を法とする FFT が出来る事がわかる. n 1
  28. 28. 発展的な FFT アルゴリズム 今まで紹介した再帰的な FFT が基本だが, 他にも様々な FFT アルゴリズムがある. Cooley-Tukey FFT, Gentleman-Sande FFT 再帰的 FFT を非再帰, in-place(入力の領域を使い回 し, 余分な領域をあまり使わない)にしたもの. 競技プ ログラミングではよく用いられている. Stockham FFT 上の二つと異なり, "ビット反転" が不要で, メモリア クセスがシーケンシャル. その代わり, in-place でない.
  29. 29. 発展的な FFT アルゴリズム 分割基底 FFT と のように二つに分割するのではなく, より多 くの個数に分割する. つに分割する, -基底 FFT がよく用いられる. four-step FFT, six-step FFT 約 個に分割し, 組み合わせる時にも FFT を用い る. 並列化する時によいらしい. nine-step FFT 約 ずつ, 三次元的に分割する. f0 f1 4 4 n‾√ n 1/3
  30. 30. 参考文献 1. R. Crandall, C. Pomerance, 和田秀男 監訳, "素数全書: 計算からのアプローチ", 朝倉書店, 2010, ISBN 978-4-254-11128-6. 2. R. Sedgewick, 野下 浩平, 星 守, 佐藤 創, 田口 東 共訳, "アルゴリズムC <第3巻> グラフ・数理・トピックス", 近代科学社, 1996, ISBN 978-4-764-90257-2

×