Zaawansowane algorytmy i struktury danych/Wykład 13
\noindent \Large Moduł ZASD:\ Algorytmy równoległe I \myskip W module tym zajmiemy się przyspieszaniem obliczeń za pomocš korzystania z wielu procesrów (maszyn) działajšcych równolegle. Niestety nie ma ogólnie przyjętego modelu obliczeń równoległych, rozważymy w tym module dwa modele: maszynę PRAM i układy arytmetyczne (logiczne). O ile maszyna PRAM jest modelem wysoko-poziomowym, to układy arytmetyczne sš modelem niskopoziomowym, ale niewštpliwie bardzo istotnym niskopoziomowym, ale niewštpliwie bardzo istotnym. Na poczštku rozważymy wyidealizowany model obleczeń równoległych zwany Równoległš Maszynš ze Swobodnym Dostępem do Pamięci, w skrócie PRAM (od ang. {\em Parallel Random Access Machine}, wymawiany {\em piram}).
\begin{figure}[bhtp] \begin{center} \mbox{\ } \includegraphics[width=10.5cm]{parallel_fig1.eps} \caption{Struktura koncepycyjna PRAMu }
\end{center} \end{figure}
\noindent Maszyna PRAM {\em składa się} z wielu procesorów pracujšcych synchronicznie, korzystšcych ze wspólnej pamięci (która oprócz przechowywania danych służy do komunikacji między procesorami). Każdy procesor jest standardowym komputerm typu RAM (ang. {\em Random Access Machine}). Zakładamy, że procesory sš ponumerowane liczbami naturalnymi. Procesory wykonujš jeden wspólny program, ale wykonanie poszczególnych instrukcji zależy od indeksu procesora. W jednym kroku procesor pobiera dane z pamięci, potem wykonuje operację, którš może być wpisanie pewnych danych. Wszystkie procesory wykonujš jeden krok jednocze�nie. Rówoległo�ć jest wyrażona poprzez następujšcš instrukcję: \myskip \begin{center} \textbf{for all} \textbf{do in parallel}\ akcja. \end{center} \myskip \noindent Wykonanie tej instrukcji polega na wykonaniu dwóch równoległych operacji:
- przydzielenie procesora do każdego elementu ze zbioru ,
- jednoczesne wykonanie przez każdy procesor operacji akcja.
Przeważnie zapis `` jest w rodzaju\ `` je�li jest zbiorem liczb naturalnych. Litera C (od ang. concurrent) oznacza możliwo�ć jednoczesnego wykonania operacji przez wiele procesorów, E (od ang. exclusive) wyklucza takš możliwo�ć. Operacjami sš R (czytanie, od ang. read) oraz W (zapis, od ang. write) w tej samej komórce przez wiele procesorów w tym samym momencie. Mamy zatem EREW PRAM, CREW PRAM, CRCW PRAM (modelu ERCW nie rozważamy jako zupełnie sztuczny).
Podstawowym naszym mdoelem PRAMu będzie CREW PRAM: wiele procesrów może jednocze�nie czytać z tej samej komórki, ale tylko jeden może zapisywać. \myskip Prostym przykładem obliczenia na CREW jest liczenie kolejnych wierszy trójkšta Pasacala. Poczštkowo zakładamy, że . Wykonujemy: \vskip 0.2cm \begin{center} \begin{minipage}{10cm} repeat 6 times
for each do in parallel \\ \hspace*{1cm} \end{minipage} \end{center} \vskip 0.2cm \noindent Kolejnymi warto�ciami tablicy A sš wektory: \vskip 0.2cm \begin{center} \noindent 0\ \ 0\ \ 0\ \ 0\ \ 0\ \ 1
\noindent 0\ \ 0\ \ 0\ \ 0\ \ 0\ \ 1
\noindent 0\ \ 0\ \ 0\ \ 0\ \ 1\ \ 1
\noindent 0\ \ 0\ \ 0\ \ 1\ \ 2\ \ 1
\noindent 0\ \ 0\ \ 1\ \ 3\ \ 3\ \ 1
\noindent 0\ \ 1\ \ 4\ \ 6 \ \ 4\ \ 1
\noindent 1\ \ 5\ 10 \ 10\ \ 5\ \ 1 \end{center}
Najważniejszš klasš problemów algorytmicznych stanowiš problemy które można obliczyć w czasie wielomianowo-logarytmicznym używajšc wielomianowej liczby procesorów. Klasę tę oznaczamy przez NC, odpowiadajšce algorytmy nazywamy algorytmami typu NC.
Niech oznacza klasę problemów wykonywanych w deterministycznym czasie wielomianowym na maszynie sekwencyjnej. Podstawowym problemem teoretycznym algorytmiki równoległej jest pytanie:
\centerline{?} \myskip Podobnie jak problemy NP-zupełne można zdefiniować probly P-zupełne. Sš to te problemy , takie że dla każdego innego problemu istnieje NC-redukcja Y do X. Inaczej mówišc
\centerline{ wtedy i tylko wtedy gdy \ } \myskip Przykłady problemów P-zupełnych:\ programowanie liniowe, maksymalny przepływ w grafie, konstrukcja drzewa DFS, obliczanie warto�ci układów logicznych, sprawdzanie czy gramatyka bezkontekstowa generuje język pusty. \myskip Przez pracę algorytmu równoległego rozumiemy liczbę procesorów pomnożonš orzez czas. Algorytm jest optymalny gdy jego praca jest tego samego rzędu co czas najlepszego znanego algorytmu sekwencyjnego dla danego problemu.
W szczególno�ci interesujš nas algorytmy, które sš jednocze�nie optymalne i sš typu NC. Z praktycznego punku widzenia czynnik przy liczbie procesorów i przy pracy algorytmu nie jest zbyt istotny. Natomiast czynnik logarytmiczny jest istotny je�li chodzi o równoległy czas. W tym przypadku potęga logarytmu odgrywa podobnš rolę co potęga wielomianu opisujšcego czas obliczenia sekwencyjnego. Różnica między CRCW i CREW PRAMem w aspekcie klasy NC polega przeważnie na dodaniu jednego czynnika logarytmicznego w funkcji równoległego czasu obliczenia. W przypadku CRCW PRAM założymy, że procesory, je�li wpisujš jednocze�nie do tej samej komórki pamięci, to wpisujš to samo. Na przykład je�li poczštkowo wówczas następujšcy algorytm obliczy logicznš alternatywę w czasie stałym na CRCW PRAM. \myskip for each do in parallel \\ \hspace*{1cm} if then output=1; \vskip 0.6cm Na CREW potrzebujemy logarytmicznego czasu równoległego aby to zrobić. Pokażemy jeszcze dwa proste problemy, które można na CRCW PRAM wykonać w czasei stałym. Następujšcy algorytm liczy pierwszš pozycję minimalnego elementu w tablicy C[1 . . n] w czasie O(1). \vskip 0.4cm for each do in parallel := 0;
for each do in parallel \\ \hspace*{1cm} if and then :=1;
for each do in parallel \\ \hspace*{1cm} if = 0 then output :=i ; \myskip Oznaczmy ten algorytm przez . Algorytm korzysta z procesorów. Spróbujemy zmniejszyć tę liczbę do zachowujšc czas , dla dowolnie małego .
\noindent Niech
\centerline{, gdzie .} \myskip \noindent Przypu�ćmy, że mamy algorytm liczenia minimum w czasie z procesorami. Skonstruujemy algorytm który działa w czasie stałym i używa tylko procesorów. \vskip 0.5cm \noindent Algorytm}\ Parser nie mógł rozpoznać (błąd składni): {\displaystyle A_{k+1'''} :
niech ;
podziel tablicę C na rozłšczne bloki rozmiaru każdy;
równolegle zastosuj algorytm do każdego z tych bloków;
zastosuj algorytm do tablicy C' składajšcej się z minimów w blokach. \vskip 0.5cm \noindent Algorithm działa w czasie korzystajšc z procesorów. Uzasadnienie pozostawiamy jako ćwiczenie. \vskip 0.3cm \noindent Algorytmy używajš odpowiednio następujšcš (asymptotycznie) liczbę procesorów
. \myskip Rozważmy jeszcze na CRCW PRAM następujšcy problem pierwszej jedynki: \ dana tablica zerojedynkowa, znale�ć pozycję pierwszej jedynki (od lewej). \myskip Następujšcy algorytm rozwišzuje problem w czasie stałym z kwadratowš liczbš procesorów. Zakładamy na razie, że w cišgu jest jakašs jedynka. \vskip 0.3cm Algorytm Pierwsza-Jedynka-1;
for each do in parallel
\hspace*{0.6cm} if A[i]=1] and A[j]=1 then A[j]:= 0;
for each do in parallel
\hspace*{0.6cm} if A[i]=1 then FirstOne :=i. \vskip 0.3cm \noindent Możemy podobnie łatwo sprawdzić czy w ogóle jest jedynka. \vskip 0.3cm Algorytm CzyJestJedynka;
jest-jedynka := 0;
for each do in parallel
\hspace*{0.6cm} if A[i]=1 then jest-jedynka := 1;
\vskip 0.2cm \noindent Oba powyższe algorytmy korzystajš z procesorów. Możemy łatwo tę liczbę zmniejszyć do liniowej. \myskip Algorytm Pierwsza-Jedynka; \vskip 0.1cm (1)\ Podziel tablicę A na segmenty długo�ći ;
(2)\ W każdym segmencie zastosuj algorytm CzyJestJedynka;
(3)\ } Otrzymujemy cišg zerojedynkowy długo�ci Parser nie mógł rozpoznać (błąd składni): {\displaystyle \sqrt{n'''} jako wynik kroku (2);
(4)\ znajd� pierwszš jedynkę w cišgu C za pomocš algorytmu Pierwsza-Jedynka-1;;
(5)\ Zastosuj algorytm Pierwsza-Jedynka-1 do segmentu odpowiadajšcego \\ \hspace*{1.4cm} pierwszej jedynce w C; \myskip W ten sposób stosujemy trzy razy algorytm o pracy kwadratowej do segmentu długo�ci , otrzymujemy złożono�ć . Czas jest . Do szybkich obliczeń równoległych najbardziej nadajš się problemy zwišzane z drzewami, chociaż czasami w tych problemach nie widać od razu struktury drzewiastej. Struktura taka odpowiada również drzewu rekursji. Jako przykład rozważmy problem obliczenia sumy . Dla uproszczenia załóżmy, że n jest potęgš dwójki.
\begin{figure}[htbp] \begin{center} \mbox{\ } \includegraphics[width=10.cm]{parallel_fig2.eps} \caption{ Metoda pełnego zrównoważonego drzewa binarnego:\ układ arytmetyczny obliczania sumy. Maksymalny poziom .}
\end{center} \end{figure}
\noindent Wysoko�ciš węzła jest jego maksymalna odległo�ć od li�cia, wysoko�ć li�cia wynosi 0. Przez -ty poziom rozumiemy zbiór węzłów o wysoko�ci . Załóżmy, że elementy sš umieszczone w li�ciach pełnego zrównoważonego drrzewa binarnego, następnie wykonujemy (patrz rysunek): \vskip 0.4cm for to do
\hspace*{0.5cm} oblicz jedmocze�nie warto�ci węzłów na poziomie -tym; \myskip Drzewo jest strukturš koncepcyjnš, każdemu węzłowi możemy przypisać miejsce w pamięci. W naszym przypadku węzły na poziomie -tym mogš odpowiadać elementom \\ \centerline{. } Poprzedni algorytm można zapisać w formie: \vskip 0.4cm \noindent for to do\\ \hspace*{0.5cm} ; \\ \hspace*{0.5cm} for each do in parallel \\ \hspace*{0.9cm} ; \\ wynik := ; \myskip \begin{figure}[hbtp] \begin{center} \mbox{\ } \includegraphics[width=9.cm]{parallel_fig3.eps} \caption{Koncepcyjna struktura równoległej wersji metody {\em dziel i zwycieżaj}. }
\end{center} \end{figure}
Drzewa odpowiadajš w pewnym sensie rekursji. Wysoko�ć drzew odpowiada czasowi równoległemu. Podobnie głęboko�ć rekursji odpowiada też czasowi równoległemu. Równoległa wersja tzw. metody dziel i zwyciężaj polega na tym że wywołania rekurencyjne wykonujemy jednocze�nie (patrz rysunek). Oczywi�cie może się zdarzyć, że jedno z nich zakończy się wcze�niej. Tym niemniej algorytm czeka na zakończenie obu wywołań.
Pokażemy dwa przykłady zastosowania metody dziel i zwyciężaj w wersji równoległej. Zaczniemy od sumy elementów tablicy . Wynik obliczamy jako . Zakładamy znowu, że jest potęgš dwójki. \myskip \begin{center} \begin{minipage}{12cm} \vskip0.3cm \hspace*{0.6cm}\textbf{funkcja} ; \\ \hspace*{1.2cm}\textbf{if} \textbf{then return} \textbf{else }\\ \hspace*{1.8cm}{do in parallel} \\ \hspace*{2.5cm} wynik1 := ;\\ \hspace*{2.5cm} wynik2 := ;\\ \hspace*{1.8cm}\textbf{return} wynik1 + wynik2; \vskip0.4cm \end{minipage} \end{center} \myskip \noindent Podobny jest schemat sortowania na PRAMie. Niech będzie algorytmem który, otrzymawszy tablicę z posortowanymi lewš i prawš połowš da wyniku tablicę posortowanš. łatwo to zrobić w czasie z procesorami. Dla -ty procesor znajduje w pierwszej połówce sekwencyjnie metodš {\em binary search} najmniejszy element większy od . Wymaga to czasu . Potem każdy procesor{\em wie} gdzie wstawić {\em swój} element. W sumie otrzymujemy algorytm sortowania w czasie z procesorami. \begin{center} \begin{minipage}{12cm} \vskip0.3cm \hspace*{0.6cm}\textbf{funkcja} ; \\ \hspace*{1.2cm};\\ \hspace*{1.2cm}\textbf{if} \textbf{then } \\ \hspace*{1.8cm}\textbf{do in parallel}\\ \hspace*{2.5cm} ;\\ \hspace*{2.5cm} ;\\ \hspace*{1.8cm} \vskip0.4cm \end{minipage} \end{center} \myskip Liczbę procesorów można zmniejszyc do . Natomiast nietrywialnym jest zmniejszenie czasu na CREW PRAM. Zostało to zrobione przez Richarda Cole'a, który skonstruował algorytm działający w czaie z procesorami maszyny EREW PRAM. Algorytm ten jest bardzo interesujący ale skomplikowany. \newpage Być może najbardziej podstawowym modelem obliczeń równoległych sš układy arytmetyczne (lub logiczne): acyckliczne grafy z przypisaniem pewnych operacji węzłom wewnętrznym. Każdy węzeł liczy pewnš warto�ć w momencie gdy warto�ci jego poprzedników sš policzone. Podobnie jak w drzewie możemy zdefinować pojęcie li�cia: węzeł bez poprzedników. Natomiast graf nie musi mieć jednego korzenia, zamiast korzenia w grafie wyróżniamy węzły wynikowe (na rysunku te z których wychodzi strzałka {\em do nikšd}).
Równoległy czas obliczenia odpowiada maksymalej wysoko�ci węzła. Poziomy definiujemy podobnie jak dla drzewa. Algorytm równoległy w jednym równoległym kroku oblicza kolejny poziom. Liczba procesorów odpowiada z reguły maksymalnemu roziarowi poziomu, chociaż możemy inaczej rozplanować obliczenie gdy jedne poziomy sš duże, a drugie małe (ale możemy wtedy zmienić strukturę grafu tak aby temu odpowiadała).
Przykładem układu arytmetycznego jest drzewo z rysunku powyżej, które opisuje sumowanie n elementów. Zajmiemy się teraz pewnym rozszerzeniem problemu sumowania. Niech będzie pewnš łšcznš operacjš arytmetycznš (np. suma, mnożenie, maksimum, minimum, pozycja pierwszej jedynki z lewej strony, podobnie z prawej strony).
\noindentProblem sum p[refiksowych.\ dany wektor rozmiaru , obliczyć cišg taki, gdzie \myskip \begin{center} , , , \ldots \end{center} gdzie \myskip Opiszemy dwa rekurencyjne algorytmy dla tego problemu. Niech , oznaczjš lewš i prawš (odpowiednio) połówkę cišgu. Zakładamy, że n jest potęgš dwójki. \myskip \begin{center} \begin{minipage}{12cm} \vskip0.3cm \hspace*{0.6cm}\textbf{Algorytm} ; \\ \hspace*{1.2cm};\\ \hspace*{1.2cm}\textbf{if} \textbf{then } \\ \hspace*{1.8cm}\textbf{do in parallel}\\ \hspace*{2.5cm} ;\\ \hspace*{2.5cm} ;\\ \hspace*{1.8cm}\textbf{for each } , \textbf{do in parallel} \\ \hspace*{2.4cm} ;\\ \vskip0.4cm \end{minipage} \end{center} \myskip
Układ arytmetyczny odpowiadajšcy algorytmowi PrefSums1 jest przedstawiony na Rysunku #parallel_fig5 dla i . Zauważmy, że zasadniczš czę�Ciš układu dla sš dwie kopie układu dla . Dodatkowo dodajemy węzły odpowiadajšcej ostatniej instrukcji w algorytmie PrefSums1.
\begin{figure}[bhtp] \begin{center} \mbox{\ } \includegraphics[width=11.5cm]{parallel_fig5.eps} \caption{Układ arytmetyczny odpowiadajšcy algorytmowi PrefSums1. Kolejne grafy powstajš jako podwójne kopie porzednich grafów (dla elementów) z dodanymi elementami odpowiadajšcymi operacji . }
\end{center} \end{figure}
\noindent Opiszemy teraz inny algorytm rekurencyjny, w którym mamy tylko jedno wywołanie rekurecyjne (w jednej instancji rekursji).
\myskip \begin{center} \begin{minipage}{12cm} \vskip0.3cm \hspace*{0.6cm}\textbf{Algorytm} ; \\ \hspace*{1.2cm};\\ \hspace*{1.2cm}\textbf{if} \textbf{then } \\ \hspace*{1.8cm} utwórz nowš tablicę y;\\ \hspace*{1.8cm} for each } \textbf{do in parallel\\ \hspace*{2.5cm} ;\\ \hspace*{1.8cm} ;\\ \hspace*{1.8cm} for each } \textbf{do in parallel\\ \hspace*{2.4cm} ;\\ \hspace*{2.4cm} if then \ ;\\ \vskip0.4cm \end{minipage} \end{center} \myskip Układ arytmetyczny odpowiadajšcy algorytmowi jest pokazany na rysunku #parallel_fig4. \begin{figure}[bhtp] \begin{center} \mbox{\ } \includegraphics[width=7.2cm]{parallel_fig4.eps} \caption{Układ arytmetyczny odpowiadajšcy PrefSums2. Kolejny graf składa się z pojedyńczej kopii poprzedniego grafu (dla ), oraz dodatkowych operacji. }
\end{center} \end{figure}