본문 바로가기

자료구조 알고리즘

<자료구조 알고리즘> FFT를 이용한 다항식 곱셈 알고리즘

반응형

 

다항식 곱셈은 수학에서 아주 기본적으로 하는 연산 중에 하나이다.
A(x)=5x+2

B(x)=x2+2x+3
이 두식을 곱한 C(x)를 구한다고 하면
C(x)=(5x+2)(x2+2x+3)=5x×x2+5x×2x+2×x2+5x×3+2×2x+2×3=5x3+14x2+19x+6
이렇게 쉽게 계산할 수 있다. 하지만 컴퓨터로 짜려면 어떻게 해야 할까?

다항식을 나타내는 방법에는 대표적으로 coefficient representation과 value representation 이 있다.
coefficient representation으로 위의 A(x)와 B(x)를 나타내 보자면
A(x)=[5,2]
B(x)=[1,2,3]
으로 나타낼 수 있다.이를 간단하게 곱하면 C(x)=[5,14,19,6]을 구할 수 있다. 하지만 이러한 방식의 시간 복잡도는O(n2)이 된다.

이를 조금 더 빠르게 할 수 있을까?

가장 중요한 것은 좌표평면 위에 n+1개의 점이 주어진다면 이 점들을 모두 지나는 n차 함수는 유일하게 정해진다는 것이다.
(자세한 증명은 여기서:https://math.stackexchange.com/questions/426932/why-are-vandermonde-matrices-invertible)

이를 이용하여 대략적인 방식을 간단하게 정리해 보자면

a-1차 다항식 A(x) 와 b-1차 다항식 B(x)를 곱하여 n-1차 다항식 C(x)를 구한다고 하자 (n = a + b - 1)
1. A(x)에 n개의 값을 대입하여 n개의 함숫값을 계산하고 B(x)에 n개의 값을 대입하여 n개의 함숫값을 계산하여 두 다항식을 value representaition으로 나타낸다.
2. 계산한 두 함수의 함수값을 곱하여 C(x)의 함수값을 구한다.
3. 구한 C(x)의 함숫값들을 이용하여 C(x)를 구한다.

 

 

1. FFT (A(x)에 n개의 값을 대입하여 n개의 함숫값을 계산하고 B(x)에 n개의 값을 대입하여 n개의 함숫값을 계산하여 두 다항식을 value representaition으로 나타낸다.)

첫번째 과정부터 해보도록 하겠다.
a차의 A(x)에 b차의 B(x)에 n개의 값을 단순히 대입하여 계산한다고 하면 O(n2)의 시간복잡도가 걸린다. 이렇게 된다면 위의 방식에 비해 빠르지 않을 것이다. 그러면 어떻게 더 빠르게 할 수 있을까?

어떤 다항식에 한개의 값을 대입했을 때 바로 알 수 있는 다른 한 값이 무엇인지 생각해 보자
x8+x6+x4+x2 이라는 식에 m을 대입하면 m8+m6+m4+m2된다 여기서 우리는 이 식에 m을 대입했을 때의 값도 m8+m6+m4+m2일 것이라고 계산하지 않고도 알 수 있다.
x7+x5+x3+x1이라는 식에 n을 대입하면 m7+m5+m3+m1이 된다. 여기서도 우리는 이식에 m 을 대입했을 때의 값이 m7m5m3m1 이라는 것을 -1만 곱하여 알 수 있다.
이러한 성질을 이용하면 다항식 A(x) B(x)에 n개의 값을 대입해 함숫값을 구하는 과정을 더 빠르게 할 수 있을 것이다.

간단하게 하기 위해 A(x)의 계수가 모두 1이라고 하겠다.
A(x)=xa+xa1+xa2++x2+x+1
위 식을 차수가 홀수인 항과 짝수인 항으로 나누어 보자
A(x)=(xa1+xa3++x2+1)+x(xa1+xa3++x2+1)
A(x)=P0(x2)+xP1(x2)
그러면 A(x)를 두 함수로 나타낼 수 있다.
이때 x1,x1,x2,x2,xa+1/2,xa+1/2의 함숫값을 구한다고 한다면
A(x1)=P0(x12)+x1P1(x12)A(x1)=P0(x12)x1P1(x12)

A(x2)=P0(x22)+x2P1(x22)A(x2)=P0(x22)x2P1(x22)
.
.
.
A(x(a+1)/2)=P0(x(a+1)/22)+x(a+1)/2P1(x(a+1)/22)A(x(a+1)/2)=P0(x(a+1)/22)x(a+1)/2P1(x(a+1)/22)
으로 구할 수 있다. 여기서 P0(x12)의 값과 P1(x12)의 값을 다시 쓸 수 있는 것이다!!

그리고 이는 P0(x)P1(x)x12,x22,xa+12를 대입한 함숫값을 찾는 문제로 이어지고
다시 위의 방법을 사용하여 재귀적으로 구할 수 있을 것 같다.
그런데 여기서 문제가 생겼다.
위에서 속도가 빨라질 수 있었던 이유는 +-짝을 이룬 값들을 이용하였기 때문인데 x12,x22,xa+12도 +-짝으로 이루어 질수 있을까?


N-th root of uinity
를 이용하면 된다.

 

 


이 수들은 다음과 같은 성질을 가진다

즉 항상 원점 대칭인 점이 있다는 이야기 이고 이 모든 수를 제곱하여도 절댓값이 같고 부호가 다른 수들끼리 짝을 지을 수 있다는 이야기이다. 이 수들을 대입하여 함숫값을 구하면 위에 방법을 통해 재귀적으로 구할 수 있다. 

(단, n는 2의 제곱수)
xk=ωnk=e2πikn=cos(2πkn)+sin(2πkn)
ωnk=ωnk+n2

그런데 만약 n이 2의 제곱수가 아니라면 어떻게 해야 할까? 더 많은 값을 집어 넣는 것은 상관이 없기 때문에 n을 보다 큰 2의 제곱수로 만들고 함숫값을 구해주면 된다. 예를들어 3차 다항식 두개를 곱한다고 하면 곱했을 때 6차 다항식이 나오므로 n을 8이라고 하고 8개의 값으로 진행하면 된다. 이렇게 첫 번째 단계가 끝났다. 

 

시간복잡도 O(n log n)

2. 계산한 두 함수의 함수값을 곱하여 C(x)의 함수값을 구한다.

fft를 이용해 value representation 으로 바꾼 다항식 두개를 곱해준다. 

시간복잡도 O(n)

(단, n는 2의 제곱수)
xk=ωnk=e2πikn=cos(2πkn)+sin(2πkn)
ωnk=ωnk+n2

 

3. IFFT (구한 C(x)의 함숫값들을 이용하여 C(x)를 구한다.)

마지막 역변환 단계이다.

C(x)=1n(f(xn1¯)xn1+f(xn2¯)xn2++f(x1¯)x+f(x0¯))

으로 구할 수 있다.

시간복잡도 O(n)

 

어떤 함수 f(x)를 푸리에 변환하는 과정을 행렬로 표현해 보자면 다음과 같다.(Ck는 k차 항의 계수)

 

 

(1111111ωω2ω3ωn2ωn11ω2ω4ω6ω2(n2)ω2(n1)1ω(n2)ω2(n2)ω3(n2)ω(n2)(n2)ω(n1)(n2))[C0C1C2Cn1]=[f(x0)f(x1)f(x2)f(xn1)]

 

 

[C0C1C2Cn1]=(1111111ωω2ω3ωn2ωn11ω2ω4ω6ω2(n2)ω2(n1)1ω(n2)ω2(n2)ω3(n2)ω(n2)(n2)ω(n1)(n2))1[f(x0)f(x1)f(x2)f(xn1)]

V·V¯=n·I

라는 것만 증명하면 되는 것이다.

P=V·V¯

이라고 하자

 Pij=(row i of V)(column j of V¯)

 

(저 오메가들의 행렬을 V라고 하자)

Pij=(row i of V)(column j ofV¯)

=m=0n1eij2πmnei2πkmn=m=0n1ei2πmn(jk)

 

j = k 일 때,

Pij=n

j != k 일때

Pij=m=0n1(ei2π(jk)n)m

=(ei2π(jk)n)n1ei2π(jk)n1=11ei2π(jk)n1=0

따라서 V¯/n은 V의 역행렬이다.

 

이로써 증명이 완료 되었다.

이 또한 같은 방식을 사용하므로 시간복잡도는 O(n log n)이다.

 

 

 

 

반응형