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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Rytter (dyskusja | edycje)
Rytter (dyskusja | edycje)
Nie podano opisu zmian
Linia 3: Linia 3:
__TOC__
__TOC__


W module tym  zajmiemy się  obliczaniem wyrażeń arytmetycznych i równoległymi obliczeniami na drzewach związanmi z tzw. ''kontrakcją drzew''
W module tym  zajmiemy się  obliczaniem wyrażeń arytmetycznych i równoległymi obliczeniami na drzewach związanymi z tzw. ''kontrakcją drzew''


==Obliczanie wyrażeń arytmetycznych: algorytm jednoczesnych podstawień ==
==Obliczanie wyrażeń arytmetycznych: algorytm jednoczesnych podstawień ==


Zakładamy, że wyrażenie zadane jest przez ''program sekwencyjny'' (w skrócie ''PS''). Program taki jest ''sztywną'' sekwencją operacji, bez instrukcji warunkowych. PS jest bardzo prostym modelem obliczeńsekwencyjnych. Bardziej precyzyjnie, definiujemy program sekwencyjny jako  ciąg instrukcji przypisań postaci<math>x_i := W_i</math>, gdzie <math>W_i</math> jest wyrażeniem arytmetycznym zawierającym <math>O(1)</math> operacji. W przypadku gdy operacjesą logiczne PS nazywamy obwodem logicznym (ang. boolean circuit). Ogólnie problem obliczenia wartości obwodulogiczngo jest P-zupełny, podobnie jest dla arytmetycznych programów sekwecyjnych. Problemy te są w klasie NC gdy graf związany z programem sekwencyjnym jest drzewem, a sam program odpowiada obliczaniu wyrażeniaarytmetycznego, co będziemy dalej zakładać.
Zakładamy, że wyrażenie zadane jest przez ''program sekwencyjny'' (w skrócie ''PS''). Program taki jest ''sztywną'' sekwencją operacji, bez instrukcji warunkowych. PS jest bardzo prostym modelem obliczeń sekwencyjnych. Bardziej precyzyjnie, definiujemy program sekwencyjny jako  ciąg instrukcji przypisań postaci <math>x_i := W_i</math>, gdzie <math>W_i</math> jest wyrażeniem arytmetycznym zawierającym <math>O(1)</math> operacji. W przypadku gdy operacje są logiczne PS nazywamy obwodem logicznym (ang. boolean circuit). Ogólnie problem obliczenia wartości obwodu logiczngo jest P-zupełny, podobnie jest dla arytmetycznych programów sekwencyjnych. Problemy te są w klasie NC gdy graf związany z programem sekwencyjnym jest drzewem, a sam program odpowiada obliczaniu wyrażenia  arytmetycznego, co będziemy dalej zakładać.


Zmienne w programie sekwencyjnym  są ponumerowane. Jeśli po lewej stronie instrukcji przypisaniajest zmienna <math>x_i</math> a po prawej zmienna <math>x_j</math> to wymagamy aby <math>j<i</math>. Zakładamy, że struktura obliczeń jest drzewem oraz operacje  są ze zbioru <math>\{+,-,*,/\}</math>.
Zmienne w programie sekwencyjnym  są ponumerowane. Jeśli po lewej stronie instrukcji przypisania jest zmienna <math>x_i</math> a po prawej zmienna <math>x_j</math> to wymagamy aby <math>j<i</math>. Zakładamy, że struktura obliczeń jest drzewem oraz operacje  są ze zbioru <math>\{+,-,*,/\}</math>.


'''Obserwacja''' Program sekwencyjny odpowiada układowi arytmetycznemu w sensie poprzedniego modułu. Mamy tutaj do czynienia z transformacją układu arytmetycznego na równoważny układ
'''Obserwacja''' Program sekwencyjny odpowiada układowi arytmetycznemu w sensie poprzedniego modułu. Mamy tutaj do czynienia z transformacją układu arytmetycznego na równoważny układ
który ma małą (logarytmiczną) wysokość. W przypadku układu arytmetycznego liczba węzłów odpowiada czasowi skwencyjnemu a wysokość czasowi rółnoległęmu.
który ma małą (logarytmiczną) wysokość. W przypadku układu arytmetycznego liczba węzłów odpowiada czasowi sekwencyjnemu a wysokość czasowi równoległęmu.
<br>
<br>




Sekwencyjna pojedyńcza operacja podstawiania polega na zastąpieniu zmiennej <math>x_j</math> w danym wyrażeniu <math>W_i</math>,gdzie <math>i>j</math> przez <math>W_j</math> oraz redukcji wyrażenia po podstawieniu. \myskip Mówimy, że zmienna <math>x_j</math> jest ''bezpieczna'' gdy jej prawa strona w programie sekwencyjnym (wyrażenie <math>W_j</math>) zawiera co najwyżej jednązmienną. W przykładzie poniżej pierwsze 5 zmiennych są  bezpieczne.  
Sekwencyjna pojedyncza operacja podstawiania polega na zastąpieniu zmiennej <math>x_j</math> w danym wyrażeniu <math>W_i</math>,gdzie <math>i>j</math> przez <math>W_j</math> oraz redukcji wyrażenia po podstawieniu. \myskip Mówimy, że zmienna <math>x_j</math> jest ''bezpieczna'' gdy jej prawa strona w programie sekwencyjnym (wyrażenie <math>W_j</math>) zawiera co najwyżej jedną zmienną. W przykładzie poniżej pierwsze 5 zmiennych są  bezpieczne.  


{{przyklad|||
{{przyklad|||
Linia 56: Linia 56:
&nbsp;&nbsp;&nbsp;<math>x8 =54</math>.<br>
&nbsp;&nbsp;&nbsp;<math>x8 =54</math>.<br>


Pokażemy, że algorytm wykonuje <math>O(\log n)</math> iteracji. Udwodnimy bardzo precyjne oszacowanie: rozmiar najmnieszego programu sekwencyjnego, który wmaga <math>k</math> iteracji jest równy <math>k</math>-tej liczbie Fibonacciego. Jest to zaskakująco podobne do analogicznego faktu dla drzew AVL, czas równoległy odpowiada wysokości drzewa.
Pokażemy, że algorytm wykonuje <math>O(\log n)</math> iteracji. Udowodnimy bardzo precyjne oszacowanie: rozmiar najmniejszego programu sekwencyjnego, który wmaga <math>k</math> iteracji jest równy <math>k</math>-tej liczbie Fibonacciego. Jest to zaskakująco podobne do analogicznego faktu dla drzew AVL, czas równoległy odpowiada wysokości drzewa.


==Równoległa kontrakcja drzew==
==Równoległa kontrakcja drzew==


Grafem obliczeń  <math>T=\cal{G}(P)</math> programu sekwencyjnego <math>P</math> jest skierowany graf acykliczny którego węzły odpowiadają zmiennych biorącym aktualnie udział w obliczeniu <math>x_n</math>. Synami węzła <math>x_i</math> (zmiennej) są zmiennewystępujące w danym momencie w <math>W_i</math>.  Graf <math>T</math> zawiera tylko węzły osiągalne z korzenia <math>x_n</math>. Przezrozmiar rozumiemy liczbę węzłów grafu  (liczbę zmiennych w przypadku PS).  
Grafem obliczeń  <math>T=\cal{G}(P)</math> programu sekwencyjnego <math>P</math> jest skierowany graf acykliczny którego węzły odpowiadają zmiennych biorącym aktualnie udział w obliczeniu <math>x_n</math>. Synami węzła <math>x_i</math> (zmiennej) są zmienne występujące w danym momencie w <math>W_i</math>.  Graf <math>T</math> zawiera tylko węzły osiągalne z korzenia <math>x_n</math>. Przez rozmiar rozumiemy liczbę węzłów grafu  (liczbę zmiennych w przypadku PS).  


Zauważmy, że w danej iteracji algorytmu JP rozmiar grafu <math>T</math> może być znacznie mniejszy niż <math>n</math>, ponieważ wiele zmiennych możebyć nieosiągalnych z  korzenia.  
Zauważmy, że w danej iteracji algorytmu JP rozmiar grafu <math>T</math> może być znacznie mniejszy niż <math>n</math>, ponieważ wiele zmiennych możebyć nieosiągalnych z  korzenia.  
Linia 69: Linia 69:




W rzeczywistości możemy  zapomnieć o  algorytmie  JP i maszynie PRAM. Obliczanie na drzewie jestsamo w sobie sensownym modelem obliczeń równoległych. Czas równoległy jest liczbą iteracji, któraprzekształca początkowe drzewo w drzewo jednoelementowe. Z każdą krawędzią <math>e=(x_i,x_j)</math> grafu <math>\cal{G}(P)</math> jest związana pewna funkcja <math>f_e(x)</math> postaci:
W rzeczywistości możemy  zapomnieć o  algorytmie  JP i maszynie PRAM. Obliczanie na drzewie jest samo w sobie sensownym modelem obliczeń równoległych. Czas równoległy jest liczbą iteracji, któraprzekształca początkowe drzewo w drzewo jednoelementowe. Z każdą krawędzią <math>e=(x_i,x_j)</math> grafu <math>\cal{G}(P)</math> jest związana pewna funkcja <math>f_e(x)</math> postaci:


<center><math> f_e(x)\ =\ \frac{ax+b}{cx+d},</math></center>   
<center><math> f_e(x)\ =\ \frac{ax+b}{cx+d},</math></center>   


gdzie <math>a,b,c,d</math> są pewnymi stałymi. Początkowo funkcja ta jest identycznościowa. Jeśli w danym momencie następnikami węzła <math>x_i</math> są<math>x_j,\ x_k</math>, oraz <math>e1=(x_i,x_j), e2=(x_i,x_k)</math> to wartością zmiennej <math>x_i</math> jest: <math>f_{e1}(x_j) \otimes f_{e2}(x_k)</math>, gdzie <math>\otimes</math> jest operacją arytmetyczną odpowiadającą węzłowi <math>x_i</math>, w grafie obliczeń operacja ta jest niezmienna, podstawianie wyrażeń za zmienne odbywa się na  funkcjeach na krawędziach. Jeśli wartości <math>x_j,x_k</math> są obliczone (zmienne te odpowiadają aktualnie liściom) to wartość <math>f_{e1}(x_j) \otimesf_{e2}(x_k)</math> jest konkretną końcową wartością zmiennej <math>x_i</math>.  
gdzie <math>a,b,c,d</math> są pewnymi stałymi. Początkowo funkcja ta jest identycznościowa. Jeśli w danym momencie następnikami węzła <math>x_i</math> są<math>x_j,\ x_k</math>, oraz <math>e1=(x_i,x_j), e2=(x_i,x_k)</math> to wartością zmiennej <math>x_i</math> jest: <math>f_{e1}(x_j) \otimes f_{e2}(x_k)</math>, gdzie <math>\otimes</math> jest operacją arytmetyczną odpowiadającą węzłowi <math>x_i</math>, w grafie obliczeń operacja ta jest niezmienna, podstawianie wyrażeń za zmienne odbywa się na  funkcjach na krawędziach. Jeśli wartości <math>x_j,x_k</math> są obliczone (zmienne te odpowiadają aktualnie liściom) to wartość <math>f_{e1}(x_j) \otimesf_{e2}(x_k)</math> jest konkretną końcową wartością zmiennej <math>x_i</math>.  


Rozważamy  też ''spłaszczoną'' wersję <math>T'=squash(T)</math>  drzewa T, odpowiadającą algorytmowi kontrakcji. W drzewie T' wewnętrzne węzły odpowiadają zmiennych programu sekwencyjnego lub krawędziom między zmiennymi, wartością krawędzi<math>e</math> jest funkcja <math>f_e</math> reprezentowana przez cztery stałe <math>a,b,c,d</math>. Jeśli krawędź <math>e1=(x,z)</math> jest kompozycją dwóch krawędzi <math>e1=(x,y), e2=(y,z)</math> to wartością <math>f_e</math> jest kompozycja funkcji <math>f_{e1},  f_{e2}</math>. Kompozycja ta polega na wykonaniu operacji na czterch stałych odpowiadających funkcjom. Jeśli zależność jest tylko odjednej krawędzi to automatycznie rozumiemy że funkcja odpowiadająca pominiętej krawędzi jest identycznościowa (a takie są początkowo wszystkie funkcje w początkowym grafie <math>\cal{G}(P)</math>). Na następującym przykładzie pokażemy jak działa operacja Contract i w jaki sposób związana jest ona zalgorytmem JP.
Rozważamy  też ''spłaszczoną'' wersję <math>T'=squash(T)</math>  drzewa T, odpowiadającą algorytmowi kontrakcji. W drzewie T' wewnętrzne węzły odpowiadają zmiennych programu sekwencyjnego lub krawędziom między zmiennymi, wartością krawędzi<math>e</math> jest funkcja <math>f_e</math> reprezentowana przez cztery stałe <math>a,b,c,d</math>. Jeśli krawędź <math>e1=(x,z)</math> jest kompozycją dwóch krawędzi <math>e1=(x,y), e2=(y,z)</math> to wartością <math>f_e</math> jest kompozycja funkcji <math>f_{e1},  f_{e2}</math>. Kompozycja ta polega na wykonaniu operacji na czterch stałych odpowiadających funkcjom. Jeśli zależność jest tylko odjednej krawędzi to automatycznie rozumiemy że funkcja odpowiadająca pominiętej krawędzi jest identycznościowa (a takie są początkowo wszystkie funkcje w początkowym grafie <math>\cal{G}(P)</math>). Na następującym przykładzie pokażemy jak działa operacja Contract i w jaki sposób związana jest ona z algorytmem JP.




<center>[[Grafika:Parallel2-2.png]]<br> Rysunek 2. Przykładowe drzewo <math>T</math> wyrażenia, początkowe wartości w liściach są podane w kwadracikach, numery węzłów  są w podane w nawiasach.<center>
<center>[[Grafika:Parallel2-2.png]]<br> Rysunek 2. Przykładowe drzewo <math>T</math> wyrażenia, początkowe wartości w liściach są podane w kwadracikach, numery węzłów  są w podane w nawiasach. <center>




Linia 87: Linia 87:




<center>[[Grafika:Parallel2-5.png]]<br> Rysunek 5. ''Spłaszczone'' drzewo <math>T'=squash(T)</math>  liczące to samo co drzewo T, ale mające mniejszą wysokość(ogólnie logarytmiczną). Drzewo to można jeszcze bardzij spłaszczyć kompresując łańcuchy dwukrawędziowe(eliminując węzły wewnętrzne  mające dokładnie  jednego syna. </center>
<center>[[Grafika:Parallel2-5.png]]<br> Rysunek 5. ''Spłaszczone'' drzewo <math>T'=squash(T)</math>  liczące to samo co drzewo T, ale mające mniejszą wysokość(ogólnie logarytmiczną). Drzewo to można jeszcze bardziej spłaszczyć kompresując łańcuchy dwukrawędziowe (eliminując węzły wewnętrzne  mające dokładnie  jednego syna. </center>


== Oszacowanie liczby kontrakcji==
== Oszacowanie liczby kontrakcji==


Załóżmy, że graf <math>\cal{G}(P)</math> programu sekwenycjnego P jest drzewem T. Wtedy liczba iteracji algorytmu JP jest równa liczbie kontrakcji drzewa T, po której korzeń T staje się liściem. Przez  <math>TIME(n)</math> oznaczmy  maksymalną liczbę kontrakcji potrzebnych do zredukowania  do jednego węzła drzewa o <math>n</math> węzłach. Niech <math>Fib_n</math> będziem <math>n</math>-tą liczbą Fibonacciego,gdzie <math>Fib_0=1, Fib_1=2</math>.Udowodnimy:
Załóżmy, że graf <math>\cal{G}(P)</math> programu sekwencyjnego P jest drzewem T. Wtedy liczba iteracji algorytmu JP jest równa liczbie kontrakcji drzewa T, po której korzeń T staje się liściem. Przez  <math>TIME(n)</math> oznaczmy  maksymalną liczbę kontrakcji potrzebnych do zredukowania  do jednego węzła drzewa o <math>n</math> węzłach. Niech <math>Fib_n</math> będziem <math>n</math>-tą liczbą Fibonacciego, gdzie <math>Fib_0=1, Fib_1=2</math>. Udowodnimy:


{{twierdzenie|||
{{twierdzenie|||
Linia 120: Linia 120:
}}
}}


Wprowadzamy pojęcie ''statycznego węzła'', jako liścia, który nigdy nie może być ''odcięty'',nie możemy usunąć krawędzi prowadzącej do niego. Poza tym operacja kontrakcji działa tak jak poprzednio. Narysunkach statyczny węzeł jest zaznaczony jako kwadracik. Jeśli drzewo ma dokładnie jeden statyczny węzeł,to po pewnej liczbie kontrakcji otrzymujemy drzewo składające się tylko z korzenia i tego węzła. Oznaczmy przez <math>TIME'(n)</math> maksymalną liczbę kontrakcji dla drzewa mającego n węzłów, które doprowadzają do takiej sytuacji. W liczbę n nie wliczamy węzła statycznego.  
Wprowadzamy pojęcie ''statycznego węzła'', jako liścia, który nigdy nie może być ''odcięty'', nie możemy usunąć krawędzi prowadzącej do niego. Poza tym operacja kontrakcji działa tak jak poprzednio. Na rysunkach statyczny węzeł jest zaznaczony jako kwadracik. Jeśli drzewo ma dokładnie jeden statyczny węzeł, to po pewnej liczbie kontrakcji otrzymujemy drzewo składające się tylko z korzenia i tego węzła. Oznaczmy przez <math>TIME'(n)</math> maksymalną liczbę kontrakcji dla drzewa mającego n węzłów, które doprowadzają do takiej sytuacji. W liczbę n nie wliczamy węzła statycznego.  


Pozostawiamy jako ćwiczenie dowód tego, że <math>TIME'(Fib_k+1)>k</math>.
Pozostawiamy jako ćwiczenie dowód tego, że <math>TIME'(Fib_k+1)>k</math>.
Linia 149: Linia 149:
<center><math>|T_ p|, |T_q| < FIB_{k-1}</math></center>
<center><math>|T_ p|, |T_q| < FIB_{k-1}</math></center>


Udowodnimy, że po <math>k-1</math>-szej kontrakcjikorzeń <math>T</math> staje się liściem.  Możliwe są dwa przypadki:  
Udowodnimy, że po <math>k-1</math>-szej kontrakcji korzeń <math>T</math> staje się liściem.  Możliwe są dwa przypadki:  


'''Przypadek I''':  Po kontrakcji<math>(k-2)</math>-giej węzeł <math>x</math> jest liściem. <br>Z założenia indukcyjnego wynika, że drzewo <math>T1</math> jest zredukowane do korzenia z jednym następnikiem, który jest wewnątrz <math>T_x</math>. Ponieważ wszystkie węzły w <math>T_x</math>stały się liśćmi (gdyż korzeń <math>T_x</math> stał się liściem) to w następnej kontrakcji wykonujemy operację Rake i korzeń całego drzewa staje się liściem.
'''Przypadek I''':  Po kontrakcji <math>(k-2)</math>-giej węzeł <math>x</math> jest liściem. <br>Z założenia indukcyjnego wynika, że drzewo <math>T1</math> jest zredukowane do korzenia z jednym następnikiem, który jest wewnątrz <math>T_x</math>. Ponieważ wszystkie węzły w <math>T_x</math> stały się liśćmi (gdyż korzeń <math>T_x</math> stał się liściem) to w następnej kontrakcji wykonujemy operację Rake i korzeń całego drzewa staje się liściem.


<center> [[Grafika:Parallel2-8.png]]<br> Rysunek 8. Drzewo  <math>T</math>  i jego dekompozycja:  <math>|T|<FIB_k</math>,<math>|T1|\le FIB_{k-2}</math>, <math>|T_x|\ge FIB_{k-1}</math>, <math>|T_p|<FIB_{k-1}</math>.</center>
<center> [[Grafika:Parallel2-8.png]]<br> Rysunek 8. Drzewo  <math>T</math>  i jego dekompozycja:  <math>|T|<FIB_k</math>,<math>|T1|\le FIB_{k-2}</math>, <math>|T_x|\ge FIB_{k-1}</math>, <math>|T_p|<FIB_{k-1}</math>.</center>


'''Przypadek II''':  Korzeń drzewa <math>T_x</math> wymaga co najmniej <math>k-1</math> kontrakcji by stał się liściem.<br> Dla drzewa <math>T</math> niech <math>v\notin R</math> będzie dodatkowym węzłem, a <math>R \otimes v</math> będzie nowym drzewemo korzeniu </math>v<math> mającym jednego następnka - korzeń R. łatwo widać, że co najmniej jedno z  drzew </math>T_p\otimesx</math> lub  <math>T_q\otimes  x</math> wymaga co najmniej <math>k-1</math> kontrakcji aby korzeń stał się liściem.  Przyjmijmy, bezstarty ogólności że jest to pierwsze z nich.
'''Przypadek II''':  Korzeń drzewa <math>T_x</math> wymaga co najmniej <math>k-1</math> kontrakcji by stał się liściem. <br> Dla drzewa <math>T</math> niech <math>v\notin R</math> będzie dodatkowym węzłem, a <math>R \otimes v</math> będzie nowym drzewem o korzeniu </math>v<math> mającym jednego następnika - korzeń R. łatwo widać, że co najmniej jedno z  drzew </math>T_p\otimesx</math> lub  <math>T_q\otimes  x</math> wymaga co najmniej <math>k-1</math> kontrakcji aby korzeń stał się liściem.  Przyjmijmy, bez straty ogólności że jest to pierwsze z nich.


Z założenia indukcyjnego wynika, że <math>|T_p\otimes x| \ge FIB_{k-1}</math> (zatem <math>|T_p|=FIB_{k-1}-1)</math>. Wynika stąd,że drzewo <math>T2</math>  z  węzłem statycznym, patrz Rysunek 8, jest ''małe'':  <math>|T2| \le  FIB_{k-2]]</math>.
Z założenia indukcyjnego wynika, że <math>|T_p\otimes x| \ge FIB_{k-1}</math> (zatem <math>|T_p|=FIB_{k-1}-1)</math>. Wynika stąd, że drzewo <math>T2</math>  z  węzłem statycznym, patrz Rysunek 8, jest ''małe'':  <math>|T2| \le  FIB_{k-2]]</math>.


W tej sytuacji z założenia indukcyjnego (b) wynika, że drzewo  <math>T2</math> jest zredukowane do korzenia z jednym liściem po <math>k-2</math>  kontrakcjach.  Wszystkie węzły <math>T_p</math>  stają się liścmi po<math>k-2</math> kontrakcjach na mocy założenia  indukcyjnego (a).Zatem, podobnie jak w przypadku I korzeń całego drzewa staje się liściem po k-1 kontrakcjach.
W tej sytuacji z założenia indukcyjnego (b) wynika, że drzewo  <math>T2</math> jest zredukowane do korzenia z jednym liściem po <math>k-2</math>  kontrakcjach.  Wszystkie węzły <math>T_p</math>  stają się liścmi po<math>k-2</math> kontrakcjach na mocy założenia  indukcyjnego (a).Zatem, podobnie jak w przypadku I korzeń całego drzewa staje się liściem po k-1 kontrakcjach.
Linia 163: Linia 163:
'''Dowód punktu (b)'''
'''Dowód punktu (b)'''


Przypadek ten rozpatruje się podobnie jak punkt (a), stosując odpowiednią dekompozycję drzewa <math>T</math>.Dowód ten pozostawiamy jako ćwiczenie.
Przypadek ten rozpatruje się podobnie jak punkt (a), stosując odpowiednią dekompozycję drzewa <math>T</math>. Dowód ten pozostawiamy jako ćwiczenie.


'''Obserwacja.'''Możliwe są różne inne definicje kontrakcji drzew. Na  przykład moglibyśmy rozważać że w jednej iteracji kontrakcji napierw wykonujemy Rake (usuń liście) a dopiero potem Compress. My wykonywaliśmy to w jednym kroku równocześnie, co wydaje się bardzoej naturalne.
'''Obserwacja.'''Możliwe są różne inne definicje kontrakcji drzew. Na  przykład moglibyśmy rozważać że w jednej iteracji kontrakcji najpierw wykonujemy Rake (usuń liście) a dopiero potem Compress. My wykonywaliśmy to w jednym kroku równocześnie, co wydaje się bardziej naturalne.

Wersja z 12:27, 15 wrz 2006

Algorytmy równoległe II

W module tym zajmiemy się obliczaniem wyrażeń arytmetycznych i równoległymi obliczeniami na drzewach związanymi z tzw. kontrakcją drzew

Obliczanie wyrażeń arytmetycznych: algorytm jednoczesnych podstawień

Zakładamy, że wyrażenie zadane jest przez program sekwencyjny (w skrócie PS). Program taki jest sztywną sekwencją operacji, bez instrukcji warunkowych. PS jest bardzo prostym modelem obliczeń sekwencyjnych. Bardziej precyzyjnie, definiujemy program sekwencyjny jako ciąg instrukcji przypisań postaci xi:=Wi, gdzie Wi jest wyrażeniem arytmetycznym zawierającym O(1) operacji. W przypadku gdy operacje są logiczne PS nazywamy obwodem logicznym (ang. boolean circuit). Ogólnie problem obliczenia wartości obwodu logiczngo jest P-zupełny, podobnie jest dla arytmetycznych programów sekwencyjnych. Problemy te są w klasie NC gdy graf związany z programem sekwencyjnym jest drzewem, a sam program odpowiada obliczaniu wyrażenia arytmetycznego, co będziemy dalej zakładać.

Zmienne w programie sekwencyjnym są ponumerowane. Jeśli po lewej stronie instrukcji przypisania jest zmienna xi a po prawej zmienna xj to wymagamy aby j<i. Zakładamy, że struktura obliczeń jest drzewem oraz operacje są ze zbioru {+,,*,/}.

Obserwacja Program sekwencyjny odpowiada układowi arytmetycznemu w sensie poprzedniego modułu. Mamy tutaj do czynienia z transformacją układu arytmetycznego na równoważny układ który ma małą (logarytmiczną) wysokość. W przypadku układu arytmetycznego liczba węzłów odpowiada czasowi sekwencyjnemu a wysokość czasowi równoległęmu.


Sekwencyjna pojedyncza operacja podstawiania polega na zastąpieniu zmiennej xj w danym wyrażeniu Wi,gdzie i>j przez Wj oraz redukcji wyrażenia po podstawieniu. \myskip Mówimy, że zmienna xj jest bezpieczna gdy jej prawa strona w programie sekwencyjnym (wyrażenie Wj) zawiera co najwyżej jedną zmienną. W przykładzie poniżej pierwsze 5 zmiennych są bezpieczne.

Przykład

Rozważmy następujący program sekwencyjny P:

x1=1, x2=2, x3=6, x4=4, x5=x3+2,

x6=x2+x1, x7=3*x6+2*x5, x8=2*x7+x4.

Na przykład po wykonaniu wszystkich bezpiecznych podstawień (w tym wypadku tylko zastąpienie x5 przez x3+2) do prawej strony dla x7 otrzymujemy

x7=3*x6+2*x3+4.

Operacja Reduce polega na wykonaniu jednocześnie wszystkich bezpiecznych podstawień we wszystkich wyrażeniach Wi. W programie rozważamy tylko te zmienne, które są istotne z punktu widzenia liczenia ostatecznego wyniku xn. Zmienne te nazywamy istotnymi, są one osiągalne ze zmiennej xn w grafie programu. Oznaczmy przez Reduce(P) nowy program sekwencyjny, bez zmiennych nieistotnych.

Algorytm JP


(Algorytm Jednoczesnych-Podstawien)

repeat {Operacja Reduce}

for each xi do in parallel

   wykonaj jednoczesnie wszystkie bezpieczne podstawienia w Wi.

until xn obliczone;


Historia algorytmu dla przykładowego programu P danego powyżej wygląda następująco, gdzie Parser nie mógł rozpoznać (nieznana funkcja „\textsl”): {\displaystyle P=P_0, P_{i+1}= \textsl{Reduce}(P_i)} .

P1:
   x3=6; x6=3;
   x7=3*x6+2*x3+4;
   x8=2*x7+4.

P2:
   x7=25, x8=2*x7+4.

P3:
   x8=54.

Pokażemy, że algorytm wykonuje O(logn) iteracji. Udowodnimy bardzo precyjne oszacowanie: rozmiar najmniejszego programu sekwencyjnego, który wmaga k iteracji jest równy k-tej liczbie Fibonacciego. Jest to zaskakująco podobne do analogicznego faktu dla drzew AVL, czas równoległy odpowiada wysokości drzewa.

Równoległa kontrakcja drzew

Grafem obliczeń T=𝒢(𝒫) programu sekwencyjnego P jest skierowany graf acykliczny którego węzły odpowiadają zmiennych biorącym aktualnie udział w obliczeniu xn. Synami węzła xi (zmiennej) są zmienne występujące w danym momencie w Wi. Graf T zawiera tylko węzły osiągalne z korzenia xn. Przez rozmiar rozumiemy liczbę węzłów grafu (liczbę zmiennych w przypadku PS).

Zauważmy, że w danej iteracji algorytmu JP rozmiar grafu T może być znacznie mniejszy niż n, ponieważ wiele zmiennych możebyć nieosiągalnych z korzenia.

Jedna iteracja Reduce (PiPi+1) odpowiada następującej operacji Contract(𝒢(Pi)),\ patrz rysunek.


Rysunek 1. Składowe operacje jednej iteracji Contract(T): Compress oraz Rake.


W rzeczywistości możemy zapomnieć o algorytmie JP i maszynie PRAM. Obliczanie na drzewie jest samo w sobie sensownym modelem obliczeń równoległych. Czas równoległy jest liczbą iteracji, któraprzekształca początkowe drzewo w drzewo jednoelementowe. Z każdą krawędzią e=(xi,xj) grafu 𝒢(𝒫) jest związana pewna funkcja fe(x) postaci:

fe(x) = ax+bcx+d,

gdzie a,b,c,d są pewnymi stałymi. Początkowo funkcja ta jest identycznościowa. Jeśli w danym momencie następnikami węzła xixj, xk, oraz e1=(xi,xj),e2=(xi,xk) to wartością zmiennej xi jest: fe1(xj)fe2(xk), gdzie jest operacją arytmetyczną odpowiadającą węzłowi xi, w grafie obliczeń operacja ta jest niezmienna, podstawianie wyrażeń za zmienne odbywa się na funkcjach na krawędziach. Jeśli wartości xj,xk są obliczone (zmienne te odpowiadają aktualnie liściom) to wartość Parser nie mógł rozpoznać (nieznana funkcja „\otimesf”): {\displaystyle f_{e1}(x_j) \otimesf_{e2}(x_k)} jest konkretną końcową wartością zmiennej xi.

Rozważamy też spłaszczoną wersję T=squash(T) drzewa T, odpowiadającą algorytmowi kontrakcji. W drzewie T' wewnętrzne węzły odpowiadają zmiennych programu sekwencyjnego lub krawędziom między zmiennymi, wartością krawędzie jest funkcja fe reprezentowana przez cztery stałe a,b,c,d. Jeśli krawędź e1=(x,z) jest kompozycją dwóch krawędzi e1=(x,y),e2=(y,z) to wartością fe jest kompozycja funkcji fe1,fe2. Kompozycja ta polega na wykonaniu operacji na czterch stałych odpowiadających funkcjom. Jeśli zależność jest tylko odjednej krawędzi to automatycznie rozumiemy że funkcja odpowiadająca pominiętej krawędzi jest identycznościowa (a takie są początkowo wszystkie funkcje w początkowym grafie 𝒢(𝒫)). Na następującym przykładzie pokażemy jak działa operacja Contract i w jaki sposób związana jest ona z algorytmem JP.



Rysunek 2. Przykładowe drzewo T wyrażenia, początkowe wartości w liściach są podane w kwadracikach, numery węzłów są w podane w nawiasach.



Rysunek 3. Drzewo T1=Contract(T) razem z dodatkowymi funkcjami na krawędziach. Brak funkcji oznacza funkcję identycznościową.



Rysunek 4. Kolejne drzewa T3,T4,T5. Algorytm wykonuje 4 kontrakcje.



Rysunek 5. Spłaszczone drzewo T=squash(T) liczące to samo co drzewo T, ale mające mniejszą wysokość(ogólnie logarytmiczną). Drzewo to można jeszcze bardziej spłaszczyć kompresując łańcuchy dwukrawędziowe (eliminując węzły wewnętrzne mające dokładnie jednego syna.

Oszacowanie liczby kontrakcji

Załóżmy, że graf 𝒢(𝒫) programu sekwencyjnego P jest drzewem T. Wtedy liczba iteracji algorytmu JP jest równa liczbie kontrakcji drzewa T, po której korzeń T staje się liściem. Przez TIME(n) oznaczmy maksymalną liczbę kontrakcji potrzebnych do zredukowania do jednego węzła drzewa o n węzłach. Niech Fibn będziem n-tą liczbą Fibonacciego, gdzie Fib0=1,Fib1=2. Udowodnimy:

Twierdzenie

(a) TIME(Fibn)=n.

(b) Parser nie mógł rozpoznać (błąd składni): {\displaystyle Fib_k \le n < Fib_{k+1'''\ \Rightarrow \ TIME(n)=k} .

Jako bezpośredni wniosek otrzymujemy:

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \log_{\phi}+c \le TIME(n) \le \log_{\phi}+c,\ \textrm{dla pewnej stałej c},}

gdzie Φ = 1+52 jest liczbą tzw. złotego podziału (w przybliżeniu Φ1.6).

Udowodnimy najpierw, że TIME(Fibk)k. Niech Tk będzie k-tym drzewem Fibonacciego, zdefiniowanym na rysunku. Drzewo Tk+2 powstaje przez utożsamienie korzeni dwóch początkowo rozłącznych wierzchołkowo drzew Tk i Tk+1, oraz dodanie nowego korzenia.


Rysunek 6. Drzewa Fibonacciego.

Pozostawiamy jako ćwiczenie uzasadnienie tego, że |Tk|=Fibk oraz Contract(Tk)=Tk1.

Wynika stąd, że TIME(Fibk)k.

Przejdziemy teraz do dowodu następującego faktu.

Lemat o kontrakcji

nFibk  TIME(n)k.

Wprowadzamy pojęcie statycznego węzła, jako liścia, który nigdy nie może być odcięty, nie możemy usunąć krawędzi prowadzącej do niego. Poza tym operacja kontrakcji działa tak jak poprzednio. Na rysunkach statyczny węzeł jest zaznaczony jako kwadracik. Jeśli drzewo ma dokładnie jeden statyczny węzeł, to po pewnej liczbie kontrakcji otrzymujemy drzewo składające się tylko z korzenia i tego węzła. Oznaczmy przez TIME(n) maksymalną liczbę kontrakcji dla drzewa mającego n węzłów, które doprowadzają do takiej sytuacji. W liczbę n nie wliczamy węzła statycznego.

Pozostawiamy jako ćwiczenie dowód tego, że TIME(Fibk+1)>k.

Następujący dosyć oczywisty fakt jest użyteczny w dalszym dowodzie Lematu o Kontrakcji.

Fakt. Niech xT, oraz T, Tx będą takie jak pokazane na Rysunku 7. Jeśli t kontrakcji redukuje< math>T'</math> do drzewa rozmiaru jeden (nie licząc węzła statycznego), to po t kontrakcjach drzewo T redukuje się do pojedyńczego węzła staje się drzewem złożonym tylko z korzenia któreggo jedynem następnikiem jest liść lub element drzewa Tx.


Rysunek 7. Graficzna definicja drzew T, Tx.

Udowodnimy lemat, który będzie rozszerzeniem Lematu o kontrakcji. Celowo wzmacniamy tezę aby ułatwić dowód przez indukcję.

Lemat Wzmocniony Lemat o kontrakcji

(a) n<FIBk  TIME(n)<k1;

(b)nFIBk  TIME(n)<k.


Dowód przeprowadzamy przez indukcję ze względu na k. Dla k=1, k=2 łatwo sprawdzić, że teza zachodzi. Załóżmy teraz, że teza zachodzi dla wszystich k mniejszych niż danek>2.


Dowód punktu (a)

Rozważmy drzewo T takie, że |T|<FIBk. Niech x będzie najniższym (o najmnieszej wysokości) węzłem,takim że |Tx|FIBk1. Niech p, q będą następnikami x, patrz Rysunek 8. (Jeślix ma tylko jednego następnika to nazwijmy go p). Zatem

|Tp|,|Tq|<FIBk1

Udowodnimy, że po k1-szej kontrakcji korzeń T staje się liściem. Możliwe są dwa przypadki:

Przypadek I: Po kontrakcji (k2)-giej węzeł x jest liściem.
Z założenia indukcyjnego wynika, że drzewo T1 jest zredukowane do korzenia z jednym następnikiem, który jest wewnątrz Tx. Ponieważ wszystkie węzły w Tx stały się liśćmi (gdyż korzeń Tx stał się liściem) to w następnej kontrakcji wykonujemy operację Rake i korzeń całego drzewa staje się liściem.


Rysunek 8. Drzewo T i jego dekompozycja: |T|<FIBk,|T1|FIBk2, |Tx|FIBk1, |Tp|<FIBk1.

Przypadek II: Korzeń drzewa Tx wymaga co najmniej k1 kontrakcji by stał się liściem.
Dla drzewa T niech vR będzie dodatkowym węzłem, a Rv będzie nowym drzewem o korzeniu </math>vParser nie mógł rozpoznać (błąd składni): {\displaystyle mającym jednego następnika - korzeń R. łatwo widać, że co najmniej jedno z drzew } T_p\otimesx</math> lub Tqx wymaga co najmniej k1 kontrakcji aby korzeń stał się liściem. Przyjmijmy, bez straty ogólności że jest to pierwsze z nich.

Z założenia indukcyjnego wynika, że |Tpx|FIBk1 (zatem |Tp|=FIBk11). Wynika stąd, że drzewo T2 z węzłem statycznym, patrz Rysunek 8, jest małe: Parser nie mógł rozpoznać (błąd składni): {\displaystyle |T2| \le FIB_{k-2]]} .

W tej sytuacji z założenia indukcyjnego (b) wynika, że drzewo T2 jest zredukowane do korzenia z jednym liściem po k2 kontrakcjach. Wszystkie węzły Tp stają się liścmi pok2 kontrakcjach na mocy założenia indukcyjnego (a).Zatem, podobnie jak w przypadku I korzeń całego drzewa staje się liściem po k-1 kontrakcjach.

Dowód punktu (b)

Przypadek ten rozpatruje się podobnie jak punkt (a), stosując odpowiednią dekompozycję drzewa T. Dowód ten pozostawiamy jako ćwiczenie.

Obserwacja.Możliwe są różne inne definicje kontrakcji drzew. Na przykład moglibyśmy rozważać że w jednej iteracji kontrakcji najpierw wykonujemy Rake (usuń liście) a dopiero potem Compress. My wykonywaliśmy to w jednym kroku równocześnie, co wydaje się bardziej naturalne.