Programowanie Równoległe i Rozproszone Lucjan Stapp Wydział Matematyki i Nauk Informacyjnych Politechnika Warszawska (l.stapp@mini.pw.edu.pl) 1/34 PRiR Algorytm Kunga Dany jest odcinek [a,b] i ciągła funkcja f nad [a,b] taka, że f(a) * f(b) < 0. Z tw. Bolzano Cauchy ego wynika, że istnieje punkt x 0 (a,b), taki że f(x 0 ) = 0 Istnieje wiele metod numerycznych odszukiwania punktu x 0. Najprostsza z nich to metoda bisekcji. 2/34 PRiR ALGORYTM bisekcji len= b a; fa = f(a); while (len > Eps) { len=len/2; x=a+len; y=f(x); if (y==0) { result = x; stop; } if (fa *fx > 0) a=x; /* rozwiązanie jest w prawym podprzedziale, więc ograniczamy się do prawej połowy; gdy rozwiązanie jest w lewym podprzedziale, wystarczy zmniejszyć długość rozważanego przedziału */ } result = a+len/2; /*the middle of the segment */ Algorytm bisekcji jest typowym algorytmem sekwencyjnym. 3/34 PRiR 1
Jak go zrównoleglić na dwuprocesorową maszynę? 4/34 PRiR Podzielmy przedział [a,b] na 3 części: x= a+len/3 y= a+ 2*len /3 Niech nasze dwa procesory liczą wartości funkcji f odpowiednio w punktach x i y. Niech fa= f(a). 5/34 PRiR Załóżmy, że lewy (ten liczący wartość f w punkcie x) policzy pierwszy oraz fa * f(x) > 0 Szukany punkt (== rozwiązanie) jest w przedziale (x, b). Niech len = b x (== 2*len/3) Nowe punkty, w których będziemy teraz liczyć wartość funkcji f to: x = x +len /3 y = x +2*len /3 Oczywiście oba są różne od y. 6/34 PRiR 2
Załóżmy, że lewy procesor - ten liczący wartość funkcji f w punkcie x - policzy pierwszy oraz fa * f(x) < 0 Wtedy rozwiązanie jest w przedziale (a, x) i zupełnie nie interesuje nas rezultat wyliczany przez drugi procesor. Gdy prawy procesor skończy szybciej, otrzymujemy analogiczne sytuacje. Tym samym tak naprawdę używamy tylkowartości wyliczanych przez szybszy procesor drugi nie ma wpływu na obliczenia. 7/34 PRiR Złoty Podział Złoty Podział to geometryczna proporcja, w której odcinek jest dzielony tak, by stosunek długości dłuższego odcinka do całości był równy stosunkowi krótszego odcinka do dłuższego. Punkt C wyznacza złoty podział odcinka AB wtw 8/34 PRiR Złoty Podział Jeżeli AB = 1 i długość AC oznaczymy przez θ, to AC/AB = CB/AC przekształca się do θ/1 = (1 - θ)/θ. Stąd θ 2 = 1 - θ; (**) I otrzymujemy θ 2 + θ - 1 = 0. Rozwiązując to równanie kwadratowe, otrzymujemy θ = (- 1 + sqrt(5))/2 = 0.6180339887. Na mocy (**) mamy θ 2 = 0.3819660113... 9/34 PRiR 3
Złoty Podział Niektórzy historycy podejrzewają, że Pitagoras wykorzystał złoty podział odcinka, gdy odkrywał tzw. linie niewspółmierne, geometryczny odpowiednik liczb niewymiernych. Z całą pewnością można powiedzieć, że od czasów antyku wielu filozofów, artystów, matematyków próbowało wyjaśnić boskie znaczenie złotego podziału odcinka, nazwanego tak w czasach renesansu. Powszechnie przyjmuje się, że trójkąt, którego boki spełniają warunek złotego podziału jest nad wyraz piękny. 10/34 PRiR Podzielmy przedział [a,b] na 3 części definiując punkty x oraz y następująco: len = b - a x= a+θ 2 * len y= a+ θ * len Mamy 6 możliwości, które należy przedyskutować: 11/34 PRiR 1. Prawy procesor pierwszy skończył liczyć wartość f w punkcie y. a) f(y) == 0 y jest rozwiązaniem. Koniec działania programu. b) fa *f(y) < 0 Rozwiązanie jest w podprzedziale [a, y]. Obliczmy nowe punkty x oraz y len = y a =a+θ * len a = θ * len x = a+θ 2 * len y = a+θ * len = a + θ 2 * len (= = x) Tym samym, procesor który liczy w lewym punkcie, może kontynuować obliczenia. Różnica jest taka, że robił to w lewym punkcie, a teraz liczy w prawym. 12/34 PRiR 4
1. Prawy procesor pierwszy skończył liczyć wartość f w punkcie y. c. fa *f(y) > 0 Rozwiązanie jest w prawym podprzedziale [y,b]. Obliczmy nowe punkty x oraz y len = b y =a + len (a+ θ * len ) = len (1 - θ ) = θ 2 * len a = y x = a +θ 2 *len y = a +θ * len W tym przypadku mamy 2 nowe punkty, ten procesor zaczyna w nowym punkcie y', obliczenia drugiego są spoza przedziału. 13/34 PRiR 2. Lewy procesor skończył pierwszy liczyć wartość f w punkcie x. a. f(x) = 0 x jest rozwiązaniem. Koniec programu. b. fa *f(x) < 0 Rozwiązanie jest w lewym podprzedziale [a,x]. Obliczamy nowe punkty x oraz y len = x a =a+ θ 2 * len - a = θ 2 * len x = a +θ 2 *len y = a +θ * len Tym samym mamy dwa nowe punkty, ten procesor kontynuuje obliczenia w punkcie x, drugi jest poza przedziałem. 14/34 PRiR 3. Lewy procesor skończył pierwszy liczyć wartość f w punkcie x. c. fa *f(x) > 0 Rozwiązanie jest w prawym podprzedziale [x,b]. Obliczamy nowe punkty x oraz y a = x = a + θ 2 *len len = b a =b- x = a + len (a + θ 2 * len) = len - θ 2 *len = =len * (1 - θ 2 )= θ * len x = a +θ 2 *len = x+θ 2 *len + θ 2 θ *len = =a + θ 2 *(1 + θ) * len ={because θ 2 ==(1 - θ )} =a+ (1 - θ) * (1 + θ) *len = =a+(1 - θ 2 ) * len = {1 - θ 2 == θ } = =a + θ *len (== y) y = a +θ * len = a + θ 2 * len Tym samym procesor, który liczył w punkcie x, może kontynuować swoje obliczenia (jako nowy y ); z prawego stał się lewym. 15/34 PRiR 5
Skalarność systemu opisuje, jak dodatkowy procesor wpływa na wydajność systemu. Wnioski: Porównanie bisekcji i algorytmu Kunga 1. Jest możliwe, że bisekcja potrzebuje jednej iteracji, Kung wielu (x 0 = (a+b)/2) (skalarność 0); 2. Jest możliwe, że bisekcja potrzebuje wielu iteracji, Kung jednej (x 0 = a*(1+θ)) (skalarność + ); 3. Dla danych losowych przy dwuprocesorowej maszynie i dość skomplikowanej funkcji f (czas potrzebny do wyliczenia f(x) wynosi około 0.05 sekundy na Pentium 233 ) skalarność jest z przedziału 1.5-1.8. Zależy to od liczby niepotrzebnych obliczeń. 16/34 PRiR (Divide-and-conquer) Algorytm konstruowany jest następująco: Podziel problem na dwa lub więcej bardziej niezależnych podproblemów tego samego typu (i o tej samej strukturze). Rozwiąż podzielone problemy. Uwagi: Algorytmy typu dziel i rządź są pewną formą rekursji. Krok podziału definiuje pewną liczbę niezależnych pod-problemów, które mogą być rozwiązywane równocześnie. 17/34 PRiR OBLICZENIA NA WEKTORACH I MACIERZACH Dodawanie n skalarów Algorytm sekwencyjny wymaga n-1 operacji. Algorytm równoległy. Zakładamy, że n jest potęgą 2. Rozdzielamy n skalarów pomiędzy n/2 procesorów, aby dodawać je parami. Potem powtarzamy ten schemat i po log 2 n krokach kończymy obliczenia. 18/34 PRiR 6
Dodawanie N skalarów Algorytm równoległy Schemat ten dla 16 liczb przedstawiony jest na poniższym grafie: Równoległe obliczanie sumy n=16 skalarów. Potrzeba 8 (=n/2) procesorów i 4 (=log n) etapów. 19/34 PRiR Dodawanie N skalarów Algorytm równoległy Jeżeli liczba procesorów jest ograniczona, możemy inaczej podzielić problem: Równoległe obliczanie sumy n=16 skalarów mając 4 procesory konieczne jest 5 etapów. 20/34 PRiR Standardowym algorytmem do szacowania wielomianu jest reguła Hornera, w której obliczamy p(x) = a n * x n +... + a 0 Wyliczamy kolejno p n = a npi = p i+1 * x + a i dla i=n-1,...,0. Jako wynik p(x) = p 0 Jest to typowa metoda sekwencyjna. 21/34 PRiR 7
Algorytm Estrina. Obliczamy p n (x) jako: gdzie p n (x) = q n (x) * x (n/2)+1 + r n/2 (x) q n (x) = a n * x n/2 +... + a (n/2)+1 r n/2 (x) = a n/2 * x n/2 +... + a 0 i wtedy q n (x) i r n/2 (x) są obliczane w analogiczny sposób przy użyciu podziału binarnego. 22/34 PRiR Algorytm Estrina. Obliczenia rozpoczynamy więc od: r 1 (x) = a 1 * x + a 0 q 3 (x) = a 3 * x + a 2 i następnie q 3 (x) * x 2 + r 1 (x) = (a 3 * x + a 2 ) * x 2 + (a 1 x + a 0 ) itd. Jeżeli dostępna jest nieograniczona liczba procesorów, algorytm ten ma złożoność czasową około 2log 2 n. 23/34 PRiR Algorytm Estrina. Przykład p 5 (x) = a 5 *x 5 + a 4 *x 4 + a 3 *x 3 + a 2 *x 2 + a 1 *x + a 0 Krok 1 p n (x) = q n (x) * x (n/2)+1 + r n/2 (x) p 5 (x) = q 5 (x) * x 3 + r 2 (x) gdzie q 5 (x) = a 5 * x 2 + a 4 * x + a 3 r 2 (x) = a 2 * x 2 + a 1 * x + a0 24/34 PRiR 8
Algorytm Estrina. Przykład cd. Krok 2 q 5 (x) = p 2 (x)= a 5 x 2 + a 4 x + a 3 p n (x) = q n (x) * x (n/2)+1 + r n/2 (x) p 2 (x) = q 2 (x) * x 2 + r 1 (x) q 2 (x)= a 5 r 1 (x)= a 4 * x + a 3.. 25/34 PRiR Algorytm Estrina. Przykład cd. a 5 x 5 + a 4 x 4 + a 3 x 3 + a 2 x 2 + a 1 x + a 0 (a 5 x 2 + a 4 x + a 3 )*x 3 a 2 x 2 + a 1 x + a 0 a 5 x 2 + a 4 x + a 3 x 3 a 2 x 2 + a 1 x + a 0 a 5 x 2 a 4 x + a 3 x 2 a 2 * x 2 a 1 x + a 0 a 5 * x a 4 * x a 3 a 2 * x a 1 * x a 0 26/34 PRiR Algorytm Dorna. Używając reguły Hornera k-tego rzędu obliczamy q 0 (x k ) = a 0 + a k * x k + a 2k * x 2k +... q 1 (x k ) = a 1 + a k+1 * x k + a 2k+1 * x 2k +...... q k-1 (x k ) = a k-1 + a 2k-1 * x k + a 3k-1 * x 2k +... i następnie p (x) = q 0 (x k ) + x * q 1 (x k ) +... + x k-1 * q k-1 (x k ) Mając k procesorów, algorytm ten ma złożoność czasową równą co najmniej 2 n/k + 2 log k. 27/34 PRiR 9
Algorytm Dorna. Przykład p(x) = a 6 x 6 + a 5 x 5 + a 4 x 4 + a 3 x 3 + a 2 x 2 + a 1 x + a 0 Dla k=2: q 0 (x 2 ) = a 0 + a 2 * x 2 + a 4 * x 4 + a 6 * x 6 q 1 (x 2 ) = a 1 + a 3 * x 2 + a 5 * x 4 i wtedy p(x) = q 0 (x 2 ) + x * q 1 (x 2 ) 28/34 PRiR Algorytm Dorna. Przykład cd. p(x) = a 6 x 6 + a 5 x 5 + a 4 x 4 + a 3 x 3 + a 2 x 2 + a 1 x + a 0 Dla k=3: q 0 (x 3 ) = a 0 + a 3 * x 3 + a 6 * x 6 q 1 (x 3 ) = a 1 + a 4 * x 3 q 2 (x 3 ) = a 2 + a 5 * x 3 i wtedy p(x) = q 0 (x 3 ) + x * q 1 (x 3 ) + x 2 * q 2 (x 3 ) 29/34 PRiR Estrin s Nieograniczona liczba procesorów Dorn s k procesorów 2 *log 2 n 2 * n/k + 2 * log 2 k Dla wielomianu stopnia n 30/34 PRiR 10
Równoległy quicksort Bibliografia: Knuth, D.E., The Art of Computer Programming. Volume 3, Sorting and Searching, Addison-Wesley,1973. 31/34 PRiR Równoległy quicksort Mamy do posortowania listę rekordów: R 1, R 2,..., R N 1. Wybieramy dowolny element z listy i używamy go jako klucza do podziału. Załóżmy, że wybieramy R i i że po posortowaniu element ten będzie na pozycji s. Oznacza to, że jest s-1 elementów mniejszych od R i oraz N-s elementów większych od R i. 32/34 PRiR Równoległy quicksort 2. Przesuwamy R i na pozycję s na liście oraz przesuwamy wszystkie mniejsze od R i elementy na pozycje, a wszystkie elementy większe od R i na pozycje s+1,s+2,...,n; 3. Oznaczamy nową listę przez R 1 (2 ), R 2,..., R N ; 4. Dzielimy listę R 1, R 2,..., R N na listy R 1, R 2,..., R s-1 R s+1, R s+2,..., R N Powtarzamy kroki1-4 na obu listach aż do list jednoelementowych. 33/34 PRiR 11
Równoległy quicksort Przykład: 601 405 305 300 900 700 405 305 300 601 900 700 po podziale mamy do posortowania 2 listy : 405 305 300 900 700 305 300 405 700 900 po podziale pierwszej listy mamy tylko jedną listę do posortowania : 305 300 300 305 W wyniku otrzymujemy 300 305 405 601 700 900 34/34 PRiR 12