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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sank (dyskusja | edycje)
Sank (dyskusja | edycje)
Linia 16: Linia 16:
* dzielić wielomiany w czasie <math>O(n \log^3 n)</math>.
* dzielić wielomiany w czasie <math>O(n \log^3 n)</math>.


== Szybkie Mnożenie wielomianów ==
== Mnożenie wielomianów w punktach ==


Niech <math>A(x) = \sum_{i=0}^{n-1} a_i x^i</math> i
Niech <math>A(x) = \sum_{i=0}^{n-1} a_i x^i</math> i
Linia 25: Linia 25:
sformułowane w ramach wykładu z Metod Numerycznych.
sformułowane w ramach wykładu z Metod Numerycznych.


{{twierdzenie|[Twierdzenie o interpolacji
{{ twierdzenie|[Twierdzenie o interpolacji
wielomianów]|interpolacja| Dla dowolnego zbioru <math>n</math> par <math>X = \{(x_0, y_0), (x_1, y_1), \ldots, (x_{n-1}, y_{n-1})\}</math> takiego, że wszystkie wartości <math>x_i</math> są parami różne, istnieje jedyny wielomian <math>C(x)</math> stopnia <math>n</math> taki, że <math>C(x_i) = y_i</math> dla <math>i = 0,1,\ldots, n-1.</math>}}
wielomianów]|interpolacja| Dla dowolnego zbioru <math>n</math> par
<math>X = \{(x_0, y_0), (x_1, y_1), \ldots, (x_{n-1},
y_{n-1})\}</math> takiego, że wszystkie wartości <math>x_i</math> są
parami różne, istnieje jedyny wielomian <math>C(x)</math> stopnia <math>n</math>
taki, że <math>C(x_i) = y_i</math> dla <math>i = 0,1,\ldots, n-1.</math>
}}
 
Niech <math>X</math> będzie ustalonym zbiorem parami różnych punktów
<math>x_0, \ldots, x_{2n-1} \in F</math>. Dla tego zbioru punktów
możemy wyznaczyć zbiory wartości wielomianów:
 
<math>X_A = \{(x_0,A(x_0)), (x_1, A(x_1), \ldots, (x_{2n-1}, A(x_{2n-1}))\}</math>
 
<math>X_B = \{(x_0, B(x_0)), (x_1, B(x_1), \ldots, (x_{2n-1}, B(x_{2n-1}))\}</math>
 
Niech <math>C</math> będzie wynikiem mnożenia
wielomianów <math>A</math> i <math>B</math>, mamy wtedy
 
<math>C(x_i) = A(x_i)\cdot B(x_i)</math>.
 
Ponieważ stopień wielomianu <math>C</math> jest nie większy niż
<math>2n</math> to z [[Twierdzenie|interpolacja]] zbiór wartości
 
<math>X_{A\times B} = \{(x_0, A(x_0}B(x_0)), (x_1, A(x_1)B(x_1),
\ldots, (2x_{n-1}, A(x_{2n-1})B(x_{2n-1}))\}</math>,
 
jednoznacznie wyznacza wielomian <math>A \times B</math>. Mając
zbiory <math>X_A</math> i <math>X_B</math> możemy wyznaczyć zbiór
<math>X_C</math> w czasie <math>O(n)</math>. Procedura ta jest
przedstawiona na następującym rysunku:


<flash>file=Zasd_fft1.swf|width=460|height=350</flash>
<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 <math>n</math> punktach w czasie szybszym niż
<math>\Theta(n^2)</math>. Podobnie musimy umieć obliczać wielomian
interpolacyjny dla danego zbioru punktów.
== Szybka transformata Fouriera (STF) ==
Problem obliczania wartości wielomianu w <math>n</math> 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 <math>X</math>. 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 <math>A(x) =
\sum_{i=0}^{n-1} a_i x^i</math> oraz <math>n</math> jest parzyste.
Jeżeli <math>n</math> jest nieparzyste to dodajemy na początek
<math>A(x)</math> jednomian <math>0x^{n+1}</math> co nie zmienia nam
wyniku działania algorytmu. Punkty <math>X_n =
\{x_0,x_1,\lots,x_{n-1}\}</math> zdefiniujemy w następujący sposób:
<math>x_i = e^{\frac{2\pi i}{n}</math>.
Dla wielomianu <math>A(x)</math> definiujemy dwa nowe wielomiany
<math>A^{[0]}(x)</math> i <math>A^{[1])(x)</math> poprzez wybranie
do nich współczynników <math>A(x)</math> o numerach odpowiednio
parzystych i nieparzystych:
<math>A^{[0]}(x) = a_0 + a_2x + a_4x^2 + \ldots + a_{n-2}x^{\frac{n}{2}-1}</math>,
<math>A^{[1]}(x) = a_1 + a_3x + a_5x^2 + \ldots + a_{n-1}x^{\frac{n}{2}-1}</math>.
Wielomiany <math>A^{[0](x)</math> oraz <math>A^{[1]}(x)</math> są
stopnia co najwyżej <math>\frac{n}{2}</math>. Co więcej zachodzi:
<math>A(x) = A^{[0]}(x^2) + x A^{[1]}(x^2)</math> (1).
Widzimy teraz, że problem ewaluacji wielomianu <math>A(x)</math> w
punktach <math>\omega_n^0, \omega_n^1,\ldots, \omega_n^{n-1}</math> sprowadza się
do:
* ewaluacji wielomianów <math>A^{[0]}(x)</math> i <math>A^{[1]}(x)</math>
w punktach
<math>X' =\{x_0^2, x_1^2, \ldots, x_{n-1}^2\} </math>.
* a następnie obliczenie wartości <math>A(x) </math>wyniku zgodnie ze wzorem (1).
Zauważmy, że z definicji punktów $x_i$ mamy:
<math>x_i^2 = \left(e^{\frac{2\pi i}{n} \right)^2 = e^{\frac{2\pi i}{n/2}</math>.
Możemy teraz zauważyć, że zachodzi <math>x_i^2 =
x_{i+\frac{n}{2}}^2</math>, a więc <math>X' =
X_{\frac{n}{2}}</math>. Udało nam się więc zredukować problem
rozmiaru <math>n</math> --- obliczenia wartości wielomianu
<math>A(x)</math> stopnia <math>n</math> w <math>n</math>do
punktach, do dwóch problemów rozmiaru <math>\frac{n}{2}</math> ---
obliczenia wartości wielomianów <math>A^{[0]}(x)</math> i
<math>A^{[1]}(x)</math> stopnia <math>\frac{n}{2}</math> w
<math>\frac{n}{2}</math> punktach. Możemy teraz zastosować tą
technikę rekurencyjne otrzymując następujący algorytm.
Równanie rekurencyjne na czas działania procedury STF wygląda następująco:
<math>T(n) =2 T(\frac{n}{2}) + \Theta(n) = \Theta(n \log n)</math>.
=== 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 <math>X_n</math>. Obliczenie
wykonane w czasie szybkiej transformaty Fouriera możemy przedstawić
w postaci macierzowej jako mnożenie macierzy przez wektor
<math>(A(x_0), A(x_1), \ldots, A(x_{n-1}))^T = V_n (a_0, a_1,
\ldots, a_{n-1}</math>, gdzie <math>V(x_0,\ldots,x_{n-1})</math> jest macierzą
Vandermonde'a zawierającą potęgi <math>x_i</math>
<math>\left(
\begin{array}{c}
A(x_0)\\
A(x_1)\\
A(x_2)\\
\vdots\\
A(x_{n-1})
\end{array}
\right) =
\left[
\begin{array}
x_0^0 & x_0^1 & x_0^2 & x_0^3 & \hdots & x_0^{n-1} \\
x_1^0 & x_1^1 & x_1^2 & x_1^3 & \hdots & x_1^{n-1} \\
x_2^0 & x_2^1 & x_2^2 & x_2^3 & \hdots & x_2^{n-1} \\
\vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\
x_{n-1}^0 & x_{n-1}^1 & x_{n-1}^2 & x_{n-1}^3 & \hdots & x_{n-1}^{n-1} \\
\end{array}
\right]
\left(
\begin{array}{c}
a_0\\
a_1\\
a_2)\\
\vdots\\
a_{n-1)
\end{array}
\right)
</math>
Element macierzy <math>V(x_0,\ldots,x_{n-1})</math> dany jest jako
<math>V(x_0,\ldots,x_{n-1})_{i,j} = x_i^j</math>.
W celu wykonania operacji odwrotnej do SFT, czyli obliczenia
wielomianu interpolacyjnego, musimy wykonać mnożenie
<math>V(x_0,\ldots,x_{n-1})^{-1} (A(x_0), A(x_1), \ldots,
A(x_{n-1}))^T</math>.
Korzystając z definicji zbioru <math>X_n</math> otrzymujemy
<math>V(x_0,\ldots,x_{n-1})_{i,j} = \left(e^{\frac{2\pi i}{n}\right)^j
= e^{\frac{2\pi ij}{n}.</math>

Wersja z 22:34, 18 lip 2006

Template:twierdzenie

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 interpolacja zbiór wartości

Parser nie mógł rozpoznać (błąd składni): {\displaystyle X_{A\times B} = \{(x_0, A(x_0}B(x_0)), (x_1, A(x_1)B(x_1), \ldots, (2x_{n-1}, A(x_{2n-1})B(x_{2n-1}))\}} ,

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 Parser nie mógł rozpoznać (nieznana funkcja „\lots”): {\displaystyle X_n = \{x_0,x_1,\lots,x_{n-1}\}} zdefiniujemy w następujący sposób:

Parser nie mógł rozpoznać (błąd składni): {\displaystyle x_i = e^{\frac{2\pi i}{n}} .

Dla wielomianu A(x) definiujemy dwa nowe wielomiany A[0](x) i Parser nie mógł rozpoznać (błąd składni): {\displaystyle 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 Parser nie mógł rozpoznać (błąd składni): {\displaystyle 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:

Parser nie mógł rozpoznać (błąd składni): {\displaystyle x_i^2 = \left(e^{\frac{2\pi i}{n} \right)^2 = e^{\frac{2\pi i}{n/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.

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, gdzie V(x0,,xn1) jest macierzą Vandermonde'a zawierającą potęgi xi

Parser nie mógł rozpoznać (nieznana funkcja „\begin{array}”): {\displaystyle \left( \begin{array}{c} A(x_0)\\ A(x_1)\\ A(x_2)\\ \vdots\\ A(x_{n-1}) \end{array} \right) = \left[ \begin{array} x_0^0 & x_0^1 & x_0^2 & x_0^3 & \hdots & x_0^{n-1} \\ x_1^0 & x_1^1 & x_1^2 & x_1^3 & \hdots & x_1^{n-1} \\ x_2^0 & x_2^1 & x_2^2 & x_2^3 & \hdots & x_2^{n-1} \\ \vdots & \vdots & \vdots & \vdots & \ddots & \vdots \\ x_{n-1}^0 & x_{n-1}^1 & x_{n-1}^2 & x_{n-1}^3 & \hdots & x_{n-1}^{n-1} \\ \end{array} \right] \left( \begin{array}{c} a_0\\ a_1\\ a_2)\\ \vdots\\ a_{n-1) \end{array} \right) }

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

V(x0,,xn1)i,j=xij.

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

Korzystając z definicji zbioru Xn otrzymujemy

Parser nie mógł rozpoznać (błąd składni): {\displaystyle V(x_0,\ldots,x_{n-1})_{i,j} = \left(e^{\frac{2\pi i}{n}\right)^j = e^{\frac{2\pi ij}{n}.}