Zaawansowane algorytmy i struktury danych/Wykład 4: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sank (dyskusja | edycje)
Nie podano opisu zmian
Sank (dyskusja | edycje)
Nie podano opisu zmian
Linia 126: Linia 126:


{{algorytm|Algorytm Szybkiej Transformaty Fouriera|algorytm_fft|
{{algorytm|Algorytm Szybkiej Transformaty Fouriera|algorytm_fft|
aaa
3=
}}
  STF(<math>a = (a_0,\ldots,a_{n-1})</math>)
 
  RECURSIVE-STF(a = (a_0,\ldots,a_{n-1}))
   '''if''' <math>n</math> nieparzyste '''then'''
   '''if''' <math>n</math> nieparzyste '''then'''
     dodaj wyraz <math>a_n</math> do <math>a</math>
     dodaj wyraz <math>a_n</math> do <math>a</math>
     zwiększ <math>n</math>
     zwiększ <math>n</math>
   '''if''' <math>n=1</math> '''then''' '''return''' a
   '''if''' <math>n=1</math> '''then''' '''return''' a
     <math>\omega_n = e^{\frac{2\pi i}{n}}</math>
  <math>\omega_n = e^{\frac{2\pi i}{n}}</math>
  <math>\omega = 1</math>
  <math>a^{[0]} = (a_0, a_2, \ldots, a_{n-2})</math>
  <math>a^{[1]} = (a_1, a_3, \ldots, a_{n-1})</math>
  <math>y^{[0]} = SFT(a^{[0]})</math>
  <math>y^{[1]} = SFT(a^{[1]})</math>
  '''for''' k=0 '''to''' <math>\frac{n}{2}-1</math> '''do'''
    <math>y_k = y_k^{[0]} + \omega y_k^{[1]}</math>
     <math>y_{k+\frac{n}{2}} = y_k^{[0]} - \omega y_k^{[1]}</math>
    \omega = \omega \omega_n
  '''return''' y
}}
 
Algorytm ten najpierw oblicza SFT wielomianów
<math>A^{[0]}(x)</math> i <math>A^{[1]}(x)</math> a następnie łączy
te wyniki w celu wyliczenia SFT dla wielomianu <math>A(x)</math>.
Przeanalizujmy teraz wykonanie pętli. Zauważmy najpierw, że w
<math>k</math>'tym  kroku pętli mamy <math>\omega = \omega_n^k =
= e^{\frac{2\pi i k}{n}} = x_k.</math>. Czyli:
 
 
<center><math>
y_k = y_k^{[0]} + x_k y_k^{[1]} = A^{[0]}(e^{\frac{2\pi i k}{n/2}}) +
x_k A^{[1]}(e^{\frac{2\pi i k}{n/2}})
= A^{[0]}(e^{\frac{2\pi i k}{n}}^2) +
x_k A^{[1]}(e^{\frac{2\pi i k}{n}}^2)
= A^{[0]}(x_k^2) +
x_k A^{[1]}(x_k^2) = A(x_k),
</math></center>
 
 
oraz
 
 
<center><math>
y_{k+\frac{n}{2}} = y_k^{[0]} - x_k y_k^{[1]} =
= A^{[0]}(e^{\frac{2\pi i k}{n/2}}) -
e^{\frac{2\pi i k}{n}} A^{[1]}(e^{\frac{2\pi i k}{n/2}})
= A^{[0]}(e^{\frac{2\pi i (k + n/2)}{n/2}}) +
e^{\frac{2\pi i k + n/2}{n}} A^{[1]}(e^{\frac{2\pi i (k + n/2)}{n/2}})
= A^{[0]}(x_{k + n/2}^2) +
x_{k + n/2}^2 A^{[1]}(x_{k + n/2}^2)
= A(x_{k+\frac{n}{2}).
</math></center>


Równanie rekurencyjne na czas działania procedury STF wygląda następująco:
Gdzie w ostatniej równości skorzystaliśmy ze wzoru
[[wzor|wzor_1|(1)]]. Widzimy zatem, że algorytm poprawnie oblicza
wartość STF dla wielomianu <math>A(x)</math>. Równanie rekurencyjne
na czas działania procedury STF wygląda następująco:





Wersja z 14:22, 19 lip 2006

Abstrakt

Naturalna metoda dodawania dwóch wielomianów wymaga czasu Θ(n), natomiast prosty algorytm mnożenia dwóch wielomianów stopnia n wymaga czasu Θ(n2). W wykładzie tym pokażemy, jak z wykorzystaniem szybkiej transformaty Fouriera (STF), wykonać wszystkie podstawowe operacje na wielomianach w czasie większym niż Θ(n) o czynnik polilogarytmiczny. Pokażemy jak dla wielomianów stopnia n:

  • mnożyć je w czasie O(nlogn),
  • obliczać wielomian interpolacyjny w czasie O(nlog2n),
  • obliczać wartość wielomianu w n punktach w czasie O(nlog2n),
  • dzielić wielomiany w czasie O(nlog3n).

Mnożenie wielomianów w punktach

Niech A(x)=i=0n1aixi i B(x)=i=0n1bixi będzą wielomianami stopnia n nad ciałem F. Wielomiany te możemy jednoznaczne reprezentować poprzez ich wartości w n punktach. Następujące twierdzenie zostało sformułowane w ramach wykładu z Metod Numerycznych.

Twierdzenie [Twierdzenie o interpolacji wielomianów]

Dla dowolnego zbioru n par X={(x0,y0),(x1,y1),,(xn1,yn1)} takiego, że wszystkie wartości xi są parami różne, istnieje jedyny wielomian C(x) stopnia n taki, że C(xi)=yi dla i=0,1,,n1.


Niech X będzie ustalonym zbiorem parami różnych punktów x0,,x2n1F. Dla tego zbioru punktów możemy wyznaczyć zbiory wartości wielomianów:


XA={(x0,A(x0)),(x1,A(x1),,(x2n1,A(x2n1))}

XB={(x0,B(x0)),(x1,B(x1),,(x2n1,B(x2n1))}


Niech C będzie wynikiem mnożenia wielomianów A i B, mamy wtedy


C(xi)=A(xi)B(xi).


Ponieważ stopień wielomianu C jest nie większy niż 2n to z Twierdzenia o interpolacji zbiór wartości


XA×B={(x0,A(x0)B(x0)),(x1,A(x1)B(x1),,(2xn1,A(x2n1)B(x2n1))},


jednoznacznie wyznacza wielomian A×B. Mając zbiory XA i XB możemy wyznaczyć zbiór XC w czasie O(n). Procedura ta jest przedstawiona na następującym rysunku:


<flash>file=Zasd_fft1.swf|width=460|height=350</flash>


Jednak aby ostatecznie otrzymać szybszy algorytm niż algorytm naiwny musimy pokazać jak rozwiązać problem obliczania wartości wielomianu w n punktach w czasie szybszym niż Θ(n2). Podobnie musimy umieć obliczać wielomian interpolacyjny dla danego zbioru punktów.

Szybka transformata Fouriera (STF)

Problem obliczania wartości wielomianu w n punktach i problem jego interpolacji rozwiążemy wykorzystując szybką transformatę Fouriera. W poprzednim rozdziale nie zakładaliśmy nic na temat zbioru punktów X. Głównym pomysłem w konstrukcji algorytmu STF będzie właśnie wybór odpowiedniego zbioru punktów X tak, aby jak największa ilość wykonywanych obliczeń powtarzała się.

Założymy chcemy obliczyć wartości wielomianu A(x)=i=0n1aixi oraz n jest parzyste. Jeżeli n jest nieparzyste to dodajemy na początek A(x) jednomian 0xn+1 co nie zmienia nam wyniku działania algorytmu. Punkty Xn={x0,x1,,xn1} zdefiniujemy w następujący sposób:


xi=e2πin.


Dla wielomianu A(x) definiujemy dwa nowe wielomiany A[0](x) i A[1](x) poprzez wybranie do nich współczynników A(x) o numerach odpowiednio parzystych i nieparzystych:


A[0](x)=a0+a2x+a4x2++an2xn21,

A[1](x)=a1+a3x+a5x2++an1xn21.


Wielomiany A[0](x) oraz A[1](x) są stopnia co najwyżej n2. Co więcej zachodzi:

A(x)=A[0](x2)+xA[1](x2)      (1)

Widzimy teraz, że problem ewaluacji wielomianu A(x) w punktach ωn0,ωn1,,ωnn1 sprowadza się do:

  • ewaluacji wielomianów A[0](x) i A[1](x)

w punktach


X={x02,x12,,xn12}.


  • a następnie obliczenie wartości A(x)wyniku zgodnie ze wzorem (1).

Zauważmy, że z definicji punktów $x_i$ mamy:


xi2=(e2πin)2=e2πin/2.


Możemy teraz zauważyć, że zachodzi xi2=xi+n22, a więc X=Xn2. Udało nam się więc zredukować problem rozmiaru n - obliczenia wartości wielomianu A(x) stopnia n w ndo punktach, do dwóch problemów rozmiaru n2 - obliczenia wartości wielomianów A[0](x) i A[1](x) stopnia n2 w n2 punktach. Możemy teraz zastosować tą technikę rekurencyjne otrzymując następujący algorytm.

Algorytm Algorytm Szybkiej Transformaty Fouriera


 STF(a=(a0,,an1))
 if n nieparzyste then
   dodaj wyraz an do a
   zwiększ n
 if n=1 then return a
 ωn=e2πin
 ω=1
 a[0]=(a0,a2,,an2)
 a[1]=(a1,a3,,an1)
 y[0]=SFT(a[0])
 y[1]=SFT(a[1])
 for k=0 to n21 do
   yk=yk[0]+ωyk[1]
   yk+n2=yk[0]ωyk[1]
   \omega = \omega \omega_n
 return y

Algorytm ten najpierw oblicza SFT wielomianów A[0](x) i A[1](x) a następnie łączy te wyniki w celu wyliczenia SFT dla wielomianu A(x). Przeanalizujmy teraz wykonanie pętli. Zauważmy najpierw, że w k'tym kroku pętli mamy ω=ωnk==e2πikn=xk.. Czyli:


yk=yk[0]+xkyk[1]=A[0](e2πikn/2)+xkA[1](e2πikn/2)=A[0](e2πikn2)+xkA[1](e2πikn2)=A[0](xk2)+xkA[1](xk2)=A(xk),


oraz


Parser nie mógł rozpoznać (błąd składni): {\displaystyle y_{k+\frac{n}{2}} = y_k^{[0]} - x_k y_k^{[1]} = = A^{[0]}(e^{\frac{2\pi i k}{n/2}}) - e^{\frac{2\pi i k}{n}} A^{[1]}(e^{\frac{2\pi i k}{n/2}}) = A^{[0]}(e^{\frac{2\pi i (k + n/2)}{n/2}}) + e^{\frac{2\pi i k + n/2}{n}} A^{[1]}(e^{\frac{2\pi i (k + n/2)}{n/2}}) = A^{[0]}(x_{k + n/2}^2) + x_{k + n/2}^2 A^{[1]}(x_{k + n/2}^2) = A(x_{k+\frac{n}{2}). }

Gdzie w ostatniej równości skorzystaliśmy ze wzoru wzor_1|(1). Widzimy zatem, że algorytm poprawnie oblicza wartość STF dla wielomianu A(x). Równanie rekurencyjne na czas działania procedury STF wygląda następująco:


T(n)=2T(n2)+Θ(n)=Θ(nlogn).


Odwrotna transformata Fouriera

Aby zakończyć konstrukcję algorytmu dla szybkiego mnożenia wielomianów pozostaje nam pokazanie jak wykonać obliczyć wielomian interpolujący dla zbioru punktów Xn. Obliczenie wykonane w czasie szybkiej transformaty Fouriera możemy przedstawić w postaci macierzowej jako mnożenie macierzy przez wektor (A(x0),A(x1),,A(xn1))T=Vn(a0,a1,,an1)T, gdzie Vn=V(x0,,xn1) jest macierzą Vandermonde'a zawierającą potęgi xj


(A(x0)A(x1)A(x2)A(xn1))=[x00x01x02x03x0n1x10x11x12x13x1n1x20x21x22x23x2n1xn10xn11xn12xn13xn1n1](a0a1a2an1)


Element macierzy V(x0,,xn1) dany jest jako


(Vn)j,k=V(x0,,xn1)j,k=xjk.


Korzystając z definicji zbioru Xn otrzymujemy


V(x0,,xn1)j,k=(e2πijn)k=e2πijkn.

W celu wykonania operacji odwrotnej do SFT, czyli obliczenia wielomianu interpolacyjnego, musimy wykonać mnożenie Vn1(A(x0),A(x1),,A(xn1))T.

{{lemat||| Niech macierz Wn będzie zdefiniowana jako


(Wn)j,k=1ne2πijkn,


jest macierzą odwrotną do macierzy Vn. } Dowód

Pokażemy, że VnWn=I. Rozważmy pozycję (j,k) macierzy VnWn:


(VnWn)j,k=l=0n1(Vn)j,l(Wn)l,k=l=0n1e2πijln1ne2πilkn=l=0n11ne2πl(jk)n=


Jeżeli j=k to e2πk(jk)n=1 i suma ta jest równa 1. W przeciwnym przypadku możemy skorzystać ze wzoru na sumę szeregu geometrycznego:


=1n1e2πn(jk)n1e2π(jk)n=1n11(jk)1e2π(jk)n=0.


Czyli rzeczywiście VnWn=I. \qed

Porównując postać macierzy Vn oraz macierzy Wn widzimy, że w celu obliczenia transformaty odwrotnej możemy użyć Algorytmu Szybkiej Transformaty Fouriera, musimy tylko zamienić linijkę ωm=e2πin na ωm=e2πin i podzielić otrzymany wynik przez n.