Złożoność obliczeniowa/Wykład 10: Algorytmy probabilistyczne

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

Algorytmy probabilistyczne

  • probabilistyczne klasy złożoności,
  • rozpoznawanie liczb pierwszych.

Probabilistyczne klasy złożoności

W tym module podejmujemy próbę teoretycznej analizy obliczeń, w których pojawia się losowość. Rozpoczynamy od wprowadzenia losowości do naszego modelu obliczeń.

Załóżmy, że M jest zwykłą niedeterministyczną maszyną Turinga. Przypomnijmy, że M ma podczas każdego kroku obliczeń możliwość wyboru wielu ścieżek obliczeń. W pojęciu akceptacji słowa bierzemy pod uwagę zachowanie M na wszystkich jej ścieżkach. Taka konstrukcja sprawia, że niedeterministyczny model obliczeń jest przydatny z czysto teoretycznego punktu widzenia, albowiem w praktyce takich maszyn zbudować nie umiemy.

Prosty pomysł, który pozwala zaadaptować ideę wielu możliwości, polega właśnie na losowaniu. Bez straty ogólności przyjmijmy, że na każdym kroku maszyna M wybiera spośród dwóch możliwości wyboru ścieżki. Wyobraźmy sobie, że maszyna M może rzucić monetą i na podstawie wyniku wybrać jedną z dwóch ścieżek. Prawidłową realizację takiego losowania i problemy jakie się z tym wiążą omówimy w dalszej części. W tym momencie jest dla nas najważniejsze, że jest to podejście jak najbardziej praktyczne.

Opisaną powyżej maszynę Turinga M nazywamy probabilistyczną. Maszyna probabilistyczna akceptuje słowo wejściowe x wtedy, gdy dojdzie do stanu akceptującego. Ponieważ na każdym kroku dokonuje ona losowania, to akceptacja odbywa się z pewnym prawdopodobieństwem. Podobnie jest z odrzucaniem słowa wejściowego:

Definicja 1.1.

Dla probabilistycznej maszyny Turinga M i słowa wejściowego x definiujemy PM(x) jako prawdopodobieństwo, że maszyna M zaakceptuje słowo x.

Powyższe prawdopodobieństwo jest obliczane w sposób naturalny, na podstawie analizy możliwych ścieżek obliczeń.

Zauważmy, że maszyna deterministyczna jest szczególnym przypadkiem maszyny probabilistycznej -- to po prostu maszyna probabilistyczna, która nie wykonuje rzutów monetą w żadnym kroku (lub nie mają one wpływu na wynik obliczeń). Dla konkretnej maszyny deterministycznej M, jej języka L=L(M) i słowa wejściowego x zachodzi zatem:

  • xLPM(x)=1
  • xLPM(x)=0

Naszym obiektem zainteresowania jest powiązanie prawdopodobieństwa akceptacji słowa z jego przynależnością do konkretnego języka L. W ten sposób będziemy mogli używać maszyny probabilistycznej do akceptowania L podobnie jak maszyny deterministycznej. Nie będziemy wymagać tak ścisłej zależności pomiędzy przynależnością do języka a prawdopodobieństwem akceptacji jak podana powyżej. Dzięki rozluźnieniu warunków okaże się, że łatwiej znaleźć maszynę probabilistyczną dla pewnych języków. Jednocześnie jednak rezygnując z determinizmu, badanie przynależności słowa do języka będzie wymagać szczególnej uwagi. Będzie bowiem dochodzić do sytuacji, że maszyna probabilistyczna będzie się mylić.

Błąd maszyny probabilistycznej M może być dwojakiego rodzaju. Ustalmy L. Jeśli xL to M akceptuje x z prawdopodobieństwem PM(x). Jeśli nie jest ono równe 1, to może się okazać, że M odrzuci x. Mówimy wtedy o fałszywej odpowiedzi negatywnej. Maszyna odrzuca poprawne słowo z języka L!

W drugim przypadku xL i M akceptuje x z prawdopodobieństwem PM(x). Jeśli nie jest ono równe 0, to może się okazać, że M zaakceptuje x. Mówimy wtedy o fałszywej odpowiedzi pozytywnej. Maszyna akceptuje słowo spoza języka L!

Na pierwszy rzut oka taka maszyna może wydawać się bezużyteczna. Jeśli jednak jej omylność uda nam się okiełznać, to może to dać bardzo interesujące efekty praktyczne.

Za sztandarowy przykład służy problem decyzyjny rozpoznawania liczb pierwszych. Mimo, iż od niedawna znany jest algorytm deterministyczny, to w praktyce używa się właśnie (znacznie starszych) metod probabilistycznych, gdyż są zdecydowanie szybsze, a prawdopodobieństwo błędu jest z praktycznego punktu widzenia zaniedbywalne. W literaturze można znaleźć w tym miejscu często odwołanie do faktu, że każdy algorytm deterministyczny w praktyce działa na komputerze, w którym może wystąpić błąd natury fizycznej lub inne zdarzenie losowe, stąd w praktyce prawdziwego determinizmu nie ma. Rozpoznawaniem pierwszości zajmiemy się precyzyjnie w następnym rozdziale.

Kolejnym krokiem naszej analizy jest wprowadzenie probabilistycznych klas złożoności. Za podstawową z nich można uznać:

Definicja 1.2.[Klasa RP]]

Klasa RP (ang. Randomized Polynomial) to klasa tych języków L, dla których istnieje maszyna probabilistyczna M, działająca w czasie wielomianowym, o następującej własności:

  • xLPM(x)12,
  • xLPM(x)=0.

Innymi słowy, maszyna nie daje fałszywych odpowiedzi pozytywnych, a prawdopodobieństwo fałszywej odpowiedzi negatywnej wynosi co najwyżej 12. Co dla Nas oznacza to w praktyce?

Wyobraźmy sobie, że mamy język L z klasy RP i maszynę M dla niego. Uruchamiamy M na x. Maszyna działa w czasie wielomianowym. Gdy dostajemy odpowiedź ""TAK"" to jest super, bo nie daje ona fałszywych odpowiedzi pozytywnych, więc słowo na pewno należy do L.

Gdy otrzymujemy odpowiedź ""NIE"" to mamy kłopot. Maszyna mogła bowiem dać fałszywą odpowiedź negatywną z prawdopodobieństwem ograniczonym z góry przez 12. W tym momencie wykonujemy jednak genialny w swojej prostocie manewr - uruchamiamy M jeszcze raz!

W idealnej sytuacji obliczenie wykonane za drugim razem jest kompletnie niezależne od pierwszego. Gdy otrzymamy odpowiedź ""TAK"" to po kłopocie. Gdy ponownie ""NIE"" to próba nie poszła na marne, gdyż prawdopodobieństwo błędu jest teraz ograniczone z góry przez 14.

W tym miejscu dokładnie widać dlaczego odwoływaliśmy się wcześniej do zastosowań praktycznych. Jeśli bowiem powtórzymy próbę 100 razy, to prawdopodobieństwo błędu nie przekracza 12100 co jest według prostego szacunku równie prawdopodobne, co trafienie komputera przez spadający meteoryt podczas obliczeń. W tym momencie możemy przerwać powtarzanie i uznać, że odpowiedź brzmi ""NIE"". Aby trochę ostudzić zapał zwróćmy uwagę, że niezależność kolejnych obliczeń i wiążąca się z tym niezależność losowych wyborów jest istotnym wyzwaniem praktycznym, do czego jeszcze wrócimy.

Monte Carlo

Algorytmy o powyższej własności są też nazywane algorytmami Monte Carlo od słynnego kasyna w Monaco, którego odwiedzanie wiąże się z procesem losowania i powtarzania kolejnych prób aż do upragnionego skutku w postaci wygranej. Algorytmy Monte Carlo to określenie na szerszą klasę metod, w których określone jest prawdopodobieństwo błędu.

Poniższy fakt jest dosyć zaskakujący. Okazuje się, że stała 12 w definicji klasy RP nie ma żadnego znaczenia i wystarczy nam, żeby była dodatnia:

Ćwiczenie 1.3.

Pokaż, że stała 12 w definicji klasy RP może zostać zamieniona na dowolną stałą z przedziału (0,1] lub nawet zależeć od x poprzez 1p(|x|), gdzie p jest wielomianem.

Wskazówka
Rozwiązanie

Zaznaczyliśmy już wcześniej, że maszyna probabilistyczna stanowi uogólnienie maszyny deterministycznej, stąd PRP. Jak zwykle ani o tym, ani o poniższym zawieraniu nie wiemy czy jest ścisłe:

Ćwiczenie 1.4.

Pokaż, że RPNP.

Wskazówka
Rozwiązanie

Maszyny z klasy RP w swojej definicji posiadają pewną asymetrię. Określa się również ich błąd jako jednostronny (ang. one-sided error). Gdy rozważymy klasę komplementarną coRP, to otrzymamy symetryczne własności maszyn. Ich błąd w dalszym ciągu jest jednostronny, lecz tym razem maszyny nie dają fałszywych odpowiedzi negatywnych, czyli gdy maszyna z klasy coRP daje odpowiedź ""NIE"" to słowo na pewno do języka nie należy. Natomiast prawdopodobieństwo fałszywej odpowiedzi pozytywnej jest ograniczone przez 12. Wszystkie własności są dualne, w szczególności coRPcoNP.

Definicja 1.5. [Klasa coRP]

Klasa coRP to klasa tych języków L, dla których istnieje maszyna probabilistyczna M, działająca w czasie wielomianowym, o następującej własności:

  • xLPM(x)=1.
  • xLPM(x)12,

Klasa ZPP

Odpowiedź na pytanie, czy RP=coRP nie jest znana. Bez tej odpowiedzi możemy jednak rozważyć klasę RPcoRP. Problemy, które znajdują się w tej klasie posiadają dwa algorytmy Monte Carlo z błędami jednostronnymi, ale różnymi. Możemy zatem uruchomić je jednocześnie. Działamy tak długo, aż otrzymamy od przynajmniej jednego z nich odpowiedź, która jest z całą pewnością dobra (może to być zarówno ""TAK"" jak i ""NIE""), a następnie zwracamy ją jako wynik.

Taka konstrukcja powoduje, że nasz algorytm zawsze da odpowiedź poprawną, jednak jego czas działania jest dla nas nieokreślony. Możemy jedynie policzyć czas oczekiwany, który okazuje się być wielomianowy. Prawdopodobieństwo, że trzeba będzie dokonać k prób obu algorytmów wynosi 2k, czyli maleje wykładniczo.

Las Vegas

Algorytmy o powyższej własności również doczekały się swojej nazwy i są określane jako algorytmy Las Vegas. Dla takich algorytmów wiemy, że zawsze dają poprawną odpowiedź, jednak ich czas działania określamy z pewnym prawdopodobieństwem. Nawiązuje to do słynnego miasta, w którym nigdy nie przegrywamy, jednak nie wiadomo jak długo będziemy grać.

Definicja 1.6. [Klasa ZPP]

Klasa ZPP (ang. Zero-error Probabilistic Polynomial) to klasa tych języków L, dla których istnieje maszyna probabilistyczna M działająca w oczekiwanym czasie wielomianowym, która akceptuje L nie popełniając błędu.

Nietrudno pokazać, że ZPP=RPcoRP. W niektórych zastosowaniach znacznie cenniejsza od czasu działania jest absolutna poprawność odpowiedzi, stąd algorytmy Las Vegas również znajdują swoje zastosowanie w praktyce.

Klasa PP

Rozważając kolejne klasy zrezygnujemy z jednostronności błędu, która występowała w RP.

Definicja 1.7. [Klasa PP]

Klasa PP (ang. Probabilistic Polynomial) to klasa tych języków L, dla których istnieje maszyna probabilistyczna M działająca w czasie wielomianowym o następującej własności:

  • xLPM(x)>12,
  • xLPM(x)12.

Ponieważ występujące w definicji prawdopodobieństwo błędu może być dowolnie bliskie 12, to skutecznie utrudnia to wydedukowanie prawidłowej odpowiedzi na podstawie wyniku losowych obliczeń maszyny. Może się bowiem zdarzyć, że prawdopodobieństwo różni się od 12 tylko o 12p(n), gdzie p jest wielomianem. Dzieje się tak wtedy, gdy przewaga liczby ścieżek akceptujących nad odrzucającymi poprawne słowo jest stała.

Jeśli chcielibyśmy powtarzać kolejne wywołania maszyny, tak jak to się zrobiliśmy w przypadku klasy RP to w sytuacji odchylenia 12p(n) będziemy musieli wykonać wykładniczą liczbę powtórzeń, aby uzyskać prawdopodobieństwo błędu ograniczone przez 14. Prześledzimy to dokładnie w następnym rozdziale, w którym rozważana klasa będzie mieć prawdopodobieństwo błędu oddalone od 12 o stałą.

Taka sytuacja sprawia, że odpowiedź maszyny z klasy PP przypominać może rzut monetą o bardzo niewielkim odchyleniu od symetrii. Zwróćmy uwagę, że w sytuacji granicznej, gdy oba prawdopodobieństwa występujące w definicji są dokładnie równe 12, to maszyna nie różni się niczym od pojedynczego rzutu monetą, który nie niesie żadnej informacji o języku L. To wszystko sprawia, że maszyny z klasy PP nie są atrakcyjne w praktycznych obliczeniach.

Dzięki rozluźnieniu warunków możemy jednak udowodnić więcej o samej klasie:

Ćwiczenie 1.8.

Udowodnij, że NPPP

Wskazówka
Rozwiązanie

Rozważmy następujący problem:

Definicja 1.9.

Problem MAJSAT:
Wejście: formuła logiczna ϕ jak dla SAT o n zmiennych
Wyjście: czy większość spośród możliwych 2n wartościowań spełnia ϕ?

Ćwiczenie 1.10

Pokaż, że MAJSAT należy do PP.

Wskazówka
Rozwiązanie

MAJSAT jest nawet problemem zupełnym dla klasy PP. Nie wiemy o nim natomiast czy należy do NP. To pokazuje, jak silna jest klasa PP -- maszyn akceptujących większością.

Klasa BPP

W tym rozdziale prezentujemy najszerszą z klas, która odpowiada praktycznym obliczeniom losowym:.

Definicja 1.11 [Klasa BPP]

Klasa BPP (ang. Bounded-error Probabilistic Polynomial) to klasa tych języków L, dla których istnieje maszyna probabilistyczna M działająca w czasie wielomianowym o następującej własności:

  • xLPM(x)34,
  • xLPM(x)14.

Niecodziennym faktem jest, że nie wiadomo nic na temat zawierania się pomiędzy klasami NP i BPP w żadną stronę. Klasa BPP zawiera w sobie natomiast RP oraz coRP, co wynika wprost z definicji.

Patrząc na definicję klasy BPP możemy w sposób równoważny powiedzieć, że prawdopodobieństwo popełnienia błędu przez maszynę z tej klasy jest ograniczone dla obu przypadków przez 14. Podobnie jak dla klasy RP ta stała może zostać wybrana dowolnie z przedziału (0,12), lecz jest to fakt trudniejszy:

Twierdzenie 1.12

Niech α(0,12). Dla dowolnej maszyny probabilistycznej M działającej w czasie wielomianowym, o prawdopodobieństwie błędu ograniczonym przez 12α, istnieje równoważna wielomianowa maszyna probabilistyczna M o prawdopodobieństwie błędu ograniczonym przez 12p(n), gdzie p jest wielomianem.

Dowód

Mamy do dyspozycji maszynę M, która wykazuje skłonność do częstszego akceptowania słów z języka L niż spoza niego. Dla słowa xL prawdopodobieństwo akceptacji wynosi 12+α a odrzucenia 12α. Przewaga prawdopodobieństwa wynosi 2α, więc możemy mieć nadzieje, że przy odpowiednio dużej liczbie prób zdarzenie bardziej prawdopodobne będzie pojawiać się częściej.

Maszyna M dla słowa wejściowego x wykonuje 2k+1 iteracji maszyny M. Następnie daje taką odpowiedź, która występowała najczęściej. Policzmy jak prawdopodobieństwo błędu popełnianego przez maszynę M zależy od k.

Oprzemy dowód twierdzenia na nierówności Chernoffa znanej z rachunku prawdopodobieństwa:

Niech xi, dla i=1n będą niezależnymi zmiennymi losowymi przyjmującymi wartości 1 i 0 z prawdopodobieństwem odpowiednio p oraz 1p, natomiast X=i=1nxi. Wówczas dla 0θ1 zachodzi:

P(X(1θ)pn)eθ22pn

Innymi słowy, prawdopodobieństwo odchylenia binarnej zmiennej losowej X od jej wartości oczekiwanej maleje wykładniczo od wartości odchylenia.

Załóżmy, że xL. Wiemy, że PM(x)12+α. Nasze zmienne losowe xi to wyniki kolejnych obliczeń M na słowie x, prawdopodobieństwo p wynosi 12+α, natomiast n - liczba prób jest równa 2k+1. Weźmy θ=α12+α. Z nierówności Chernoffa mamy, że P(Xn2)e2α2k (asymptotycznie).

Wprost z definicji maszyny M wiemy, że akceptuje ona, gdy ponad połowa wywołań M zakończy się akceptacją, czyli wtedy, gdy X>n2. Jest to zdarzenie przeciwne do Xn2, zatem PM(x)1e2α2k. Gdy podstawimy k=p(n)ln22α2, to otrzymamy wykładnicze małe prawdopodobieństwo błędu 12p(n). Maszyna M wykonuje tylko wielomianową liczbę powtórzeń. Przypadek xL jest analogiczny.

Probabilistyczne klasy złożoności

Podobnie jak dla klasy RP stała α może być równa nawet 1p(n) i dalej pozwoli nam to uzyskać ten sam efekt wykładniczego ograniczenia popełnianego błędu przy zachowaniu wielomianowej liczby powtórzeń.

Powróćmy na chwilę do klasy PP. Stwierdziliśmy, że dla maszyn z tej klasy prawdopodobieństwo błędu może być ograniczone przez 1212p(n). Gdy przyjrzymy się dowodowi powyższego twierdzenia, to zauważymy, że aby uzyskać ten sam efekt musielibyśmy dokonać wykładniczej liczby powtórzonych obliczeń, co nie jest akceptowalne w praktyce.

Animacja Probabilistyczne klasy złożoności podsumowuje poznane wcześniej klasy złożoności i relacje pomiędzy nimi:

Rozpoznawanie liczb pierwszych

Zaznaczyliśmy na początku, że algorytmy probabilistyczne okazały się bardzo przydatne przy rozpoznawaniu liczb pierwszych. Mimo, iż w 2002 roku Agrawal, Kayal oraz Saxena odkryli wielomianowy algorytm deterministyczny dla tego problemu, wciąż używane są metody probabilistyczne, gdyż są znacznie szybsze, a prawdopodobieństwo błędu, który mogą popełnić, jest bardzo niewielkie.

Problem stwierdzenia czy liczba jest pierwsza oznaczany jest przez PRIMES. W sposób oczywisty jest to problem z klasy coNP. Dzieje się tak ze względu na fakt, że łatwo jest poświadczyć, iż liczba nie jest pierwsza, poprzez podanie jej dzielników.

Podobnie, choć nie z tej samej przyczyny, znane metody probabilistyczne opierają się na algorytmach z klasy coRP. Opierają się one na poświadczeniu złożoności liczby, które nie polega jednak na podawaniu jej dzielników (problem faktoryzacji jest bowiem dużo trudniejszy).

Jak wymaga tego klasa coRP, odpowiedź negatywna jest zawsze prawdziwa, natomiast mogą występować fałszywe odpowiedzi pozytywne. Poprzez odpowiednio dużą liczbę iteracji prawdopodobieństwo takiego faktu można uczynić dowolnie małym. Podsumowując, probabilistyczne testy pierwszości mogą popełnić błąd oceniając liczbę złożoną jako pierwszą.

Test Millera-Rabina

Poniżej prezentujemy najbardziej znany z testów probabilistycznych odkryty niezależnie przez Gary'ego Millera i Michaela Rabina około roku 1975. Na wejściu dana jest liczba naturalna n. Jedna iteracja algorytmu przedstawia się następująco:

Algorytm


Przedstaw n1 jako 2sd, d - nieparzysta 
Wybierz losową liczbę a z przedziału [1,n1] 
if ad mod  n1 i a2rd  mod  n1 dla wszystkich r[0,s1]  then
  return""NIE"" 
else 
  return""TAK"" 
end if


Gdy przypatrzymy się algorytmowi, to widzimy, że kluczem do sukcesu jest wylosowanie właściwej liczby a, która poświadcza złożoność n. W takim przypadku algorytm się nie myli - można bowiem udowodnić (patrz kurs Matematyki Dyskretnej), że sprawdzany warunek implikuje złożoność liczby n.

Jeśli a nie świadczy złożoności, to możemy spróbować wylosować je jeszcze raz. Niestety nie możemy spróbować wszystkich możliwych wartości a, których liczba jest liniowa względem n, czyli wykładnicza względem rozmiaru wejścia, które tradycyjnie zapisujemy binarnie.

Jeśli n jest pierwsza, to oczywiście świadek a nie istnieje. Poniższe twierdzenie, które przedstawiamy bez dowodu, stanowi teoretyczną podstawę analizy probabilistycznej algorytmu:

Twierdzenie 2.1.

Jeśli n jest nieparzystą liczbą złożoną, to przynajmniej 34 spośród możliwych wartości a świadczą o złożoności n.

Jeśli poprzez M oznaczymy maszynę realizującą pojedynczy test Millera-Rabina, a poprzez L język PRIMES, to nasze dotychczasowe uwagi możemy podsumować w sposób następujący:

  • xL (n pierwsza) PM(x)=1,
  • xL (n złożona) PM(x)14.

Spełnione są zatem założenia algorytmu z klasy coRP. Gdy otrzymujemy odpowiedź ""NIE"", to liczba jest złożona, gdy otrzymujemy odpowiedź ""TAK"", to liczba jest pierwsza z prawdopodobieństwem błędu 14. Gdy wykonamy k iteracji, to gdy w którymkolwiek momencie otrzymamy odpowiedź ""NIE"", to liczba jest złożona, w przeciwnym razie jest pierwsza z prawdopodobieństwem błędu ograniczonym przez 14k, czyli wykładniczo małym.

Co interesujące, Miller przedstawił ten test w wersji deterministycznej, w której podstawa a przebiega przedział o wielkości O( ln 2(n)). Stąd potrzebna liczba iteracji testu jest wielomianowa. Nie ma jednak dowodu, że takie postępowanie jest prawidłowe. Poprawność tego podejścia wynika jednak z rozszerzonej hipotezy Riemanna. Ten fakt sprawia, że test Millera-Rabina jest w pewnym sensie "zabezpieczony podwójnie".

Generowanie bitów losowych

Kluczowym elementem praktycznych realizacji opisywanych do tej pory algorytmów probabilistycznych jest losowanie. Okazuje się, że teoretycznie prosty rzut monetą to bardzo wymagający problem praktyczny.

Generowanie bitów losowych w teorii, to zadanie polegające na obliczeniu ciągu n bitów tak, aby każdy z ciągów był jednakowo prawdopodobny, czyli aby każdy bit zachowywał się jak niezależna próba losowa. Źródło, które generuje taki ciąg nazywamy idealnym.

Mając do dyspozycji źródło idealne moglibyśmy z powodzeniem używać algorytmów z klasy RP, czy BPP w praktycznych zastosowaniach. Niestety nie jest znane idealne fizyczne źródło bitów losowych. Choć istnieją lepsze i gorsze metody generowania losowych bitów, to każdy proces fizyczny wykazuje tendencję do uzależnienia kolejnych wartości od wcześniej występujących, co zaburza pożądaną przez nas niezależność.

Idealne źródło bitów losowych jest także symetryczne, to znaczy prawdopodobieństwo 0 i 1 w każdym kroku jest jednakowe. Tę własność można jednak stosunkowo łatwo uzyskać, przez grupowanie kolejnych prób.

W praktyce często stosuje się generatory bitów pseudolosowych, które generują ciągi bitów "nieprzewidywalnych". Zwykle jednak rozpoczynają one obliczenia od ziarna złożonego z niewielkiej liczby bitów, co z teoretycznego punktu widzenia jest dyskwalifikujące.

W literaturze wyróżnia się także źródła lekko losowe, które dosyć dobrze opisują dostępne w praktyce wysoce losowe zjawiska fizyczne. Nie jest niestety znana metoda symulowania przy ich pomocy idealnych źródeł losowych. Mogą one być jednak zastosowane do symulowania znanych nam algorytmów losowych z wielomianowym wzrostem czasu. Powyższy temat znajduje osobne miejsce w analizie teoretycznej algorytmów probabilistycznych.

Ćwiczenia dodatkowe

Ćwiczenie 4.1.

Uzasadnij, że klasy BPP oraz PP są zamknięte na dopełnienie.

Wskazówka
Rozwiązanie

Ćwiczenie 4.2.

Pokaż, że PPPSPACE

Wskazówka
Rozwiązanie

Ćwiczenie 4.3.

Pokaż, że jeśli NPBPP, to RP=NP

Wskazówka
Rozwiązanie

Testy końcowe