Języki, automaty i obliczenia/Wykład 13: Złożoność obliczeniowa.: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Linia 563: Linia 563:
{{twierdzenie|4.2||}}
{{twierdzenie|4.2||}}
Rodziny  <math>\displaystyle \mathcal{L}_{0}  </math>  i  <math>\displaystyle \mathcal{L}_{1}  </math>  są zamknięte
Rodziny  <math>\displaystyle \mathcal{L}_{0}  </math>  i  <math>\displaystyle \mathcal{L}_{1}  </math>  są zamknięte
ze względu na
ze względu na:
#  {{kotwica|pkt.1|}}sumę mnogościową,
#  {{kotwica|pkt.1|}}sumę mnogościową,
#  {{kotwica|pkt.2|}}iloczyn mnogościowy,
#  {{kotwica|pkt.2|}}iloczyn mnogościowy,
Linia 573: Linia 573:


[[#pkt.1|1.]] Niech dla  <math>\displaystyle i=1,2  \displaystyle G_{i}=(V_{N}^{i},V_{T},v_{0}^{i},P_{i})  </math>  będą gramatykami
[[#pkt.1|1.]] Niech dla  <math>\displaystyle i=1,2  \displaystyle G_{i}=(V_{N}^{i},V_{T},v_{0}^{i},P_{i})  </math>  będą gramatykami
typu  <math>\displaystyle (1)  </math>  (odpowiednio typu  <math>\displaystyle (0)  </math> ), takimi, że  <math>\displaystyle V_{N}^{1}\cap V_{N}^{2}=\emptyset  </math> . I niech  <math>\displaystyle L_{i}=L(G_{i})  </math> .
typu  <math>\displaystyle (1)  </math>  (odpowiednio typu  <math>\displaystyle (0)  </math> ) takimi, że  <math>\displaystyle V_{N}^{1}\cap V_{N}^{2}=\emptyset  </math> . I niech  <math>\displaystyle L_{i}=L(G_{i})  </math> .
Określamy gramatykę  <math>\displaystyle G  </math>  typu  <math>\displaystyle (1)  </math>  (typu  <math>\displaystyle (0)  </math> )
Określamy gramatykę  <math>\displaystyle G  </math>  typu  <math>\displaystyle (1)  </math>  (typu  <math>\displaystyle (0)  </math> )
generującą język  <math>\displaystyle L_{1}\cup L_{2}  </math> .
generującą język  <math>\displaystyle L_{1}\cup L_{2}  </math> .


Jeśli  <math>\displaystyle 1\notin L_{1}\cup L_{2}  </math> , to przyjmujemy
Jeśli  <math>\displaystyle 1\notin L_{1}\cup L_{2}  </math> , to przyjmujemy:


<center><math>\displaystyle G=(V_{N}^{1}\cup V_{N}^{2}\cup \left\{ v_{0}\right\}
<center><math>\displaystyle G=(V_{N}^{1}\cup V_{N}^{2}\cup \left\{ v_{0}\right\}
Linia 596: Linia 596:


Niech dla  <math>\displaystyle i=1,2  \displaystyle G_{i}=(V_{N}^{i},V_{T},v_{0}^{i},P_{i})  </math>  
Niech dla  <math>\displaystyle i=1,2  \displaystyle G_{i}=(V_{N}^{i},V_{T},v_{0}^{i},P_{i})  </math>  
będą gramatykami typu  <math>\displaystyle (0)  </math> , takimi, że  <math>\displaystyle V_{N}^{1}\cap
będą gramatykami typu  <math>\displaystyle (0)  </math> takimi, że  <math>\displaystyle V_{N}^{1}\cap
V_{N}^{2}=\emptyset  </math> . Niech  <math>\displaystyle L_{i}=L(G_{i})  </math> . Określamy
V_{N}^{2}=\emptyset  </math> . Niech  <math>\displaystyle L_{i}=L(G_{i})  </math> . Określamy
gramatykę  <math>\displaystyle G  </math>  typu  <math>\displaystyle (0)  </math>  generującą język  <math>\displaystyle L_{1}\cap L_{2}
gramatykę  <math>\displaystyle G  </math>  typu  <math>\displaystyle (0)  </math>  generującą język  <math>\displaystyle L_{1}\cap L_{2}
</math>  przyjmując
</math>, przyjmując:


<center><math>\displaystyle G=(V_{N}^{1}\cup V_{N}^{2}\cup V_{N},V_{T},v_{0},P_{1}\cup P_{2}\cup
<center><math>\displaystyle G=(V_{N}^{1}\cup V_{N}^{2}\cup V_{N},V_{T},v_{0},P_{1}\cup P_{2}\cup
Linia 605: Linia 605:


gdzie:  <math>\displaystyle V_{N}=\left\{ v_{a}\, :\, a\in V_{T}\right\} \cup \left\{ v_{0},\overline{v}_{1},\overline{v}_{2}\right\}  </math> ,
gdzie:  <math>\displaystyle V_{N}=\left\{ v_{a}\, :\, a\in V_{T}\right\} \cup \left\{ v_{0},\overline{v}_{1},\overline{v}_{2}\right\}  </math> ,
a do zbioru  <math>\displaystyle P  </math>  należą prawa <br>
a do zbioru  <math>\displaystyle P  </math>  należą prawa: <br>
(1)  <math>\displaystyle v_{0}\rightarrow \overline{v}_{1}v_{0}^{1}\overline{v}_{2}v_{0}^{2}\overline{v}_{1}  </math> <br>
(1)  <math>\displaystyle v_{0}\rightarrow \overline{v}_{1}v_{0}^{1}\overline{v}_{2}v_{0}^{2}\overline{v}_{1}, </math> <br>
(2)  <math>\displaystyle \overline{v}_{2}a\rightarrow v_{a}\overline{v}_{2}  </math>  dla  <math>\displaystyle \forall a\in V_{T}  </math> <br>
(2)  <math>\displaystyle \overline{v}_{2}a\rightarrow v_{a}\overline{v}_{2}  </math>  dla  <math>\displaystyle \forall a\in V_{T}, </math> <br>
(3)  <math>\displaystyle bv_{a}\rightarrow v_{a}b  </math>  dla  <math>\displaystyle \forall a,b\in V_{T}  </math> <br>
(3)  <math>\displaystyle bv_{a}\rightarrow v_{a}b  </math>  dla  <math>\displaystyle \forall a,b\in V_{T}, </math> <br>
(4)  <math>\displaystyle \overline{v}_{1}v_{a}a\rightarrow a\overline{v}_{1}  </math>  dla  <math>\displaystyle \forall a\in V_{T}  </math> <br>
(4)  <math>\displaystyle \overline{v}_{1}v_{a}a\rightarrow a\overline{v}_{1}  </math>  dla  <math>\displaystyle \forall a\in V_{T}, </math> <br>
(5)  <math>\displaystyle \overline{v}_{1}\overline{v}_{2}\overline{v}_{1}\rightarrow 1  </math> <br>
(5)  <math>\displaystyle \overline{v}_{1}\overline{v}_{2}\overline{v}_{1}\rightarrow 1. </math> <br>
Przy pomocy prawa (1) i wszystkich praw ze zbioru  <math>\displaystyle P_{1}\cup P_{2}
Przy pomocy prawa (1) i wszystkich praw ze zbioru  <math>\displaystyle P_{1}\cup P_{2}
</math>  można wygenerować zbiór słów
</math>  można wygenerować zbiór słów:


<center><math>\displaystyle \left\{ \overline{v}_{1}w_{1}\overline{v}_{2}w_{2}\overline{v}_{1}\,
<center><math>\displaystyle \left\{ \overline{v}_{1}w_{1}\overline{v}_{2}w_{2}\overline{v}_{1}\,
Linia 618: Linia 618:


Z dowolnego słowa należącego do tego zbioru, korzystając
Z dowolnego słowa należącego do tego zbioru, korzystając
z praw (2)-(4) można wyprowadzić słowo  <math>\displaystyle w_{1}\overline{v}_{1}\overline{v}_{2}\overline{v}_{1}  </math>  wtedy i
z praw (2)-(4), można wyprowadzić słowo  <math>\displaystyle w_{1}\overline{v}_{1}\overline{v}_{2}\overline{v}_{1}  </math>  wtedy i
tylko wtedy, gdy  <math>\displaystyle w_{1}=w_{2}  </math> . Korzystając z prawa (5)
tylko wtedy, gdy  <math>\displaystyle w_{1}=w_{2}  </math> . Korzystając z prawa (5), dostajemy słowo  <math>\displaystyle w_{1}  </math> . A więc  <math>\displaystyle L(\overline{G})=L_{1}\cap
dostajemy słowo  <math>\displaystyle w_{1}  </math> . A więc  <math>\displaystyle L(\overline{G})=L_{1}\cap
L_{2}  </math> .
L_{2}  </math> .


Linia 629: Linia 628:
język  <math>\displaystyle L_{1}L_{2}  </math> .
język  <math>\displaystyle L_{1}L_{2}  </math> .


Jeśli  <math>\displaystyle 1\notin L_{1}\cup L_{2}  </math> , to przyjmujemy
Jeśli  <math>\displaystyle 1\notin L_{1}\cup L_{2}  </math> , to przyjmujemy:


<center><math>\displaystyle G=(V_{N}^{1}\cup V_{N}^{2}\cup \left\{ v_{0}\right\}
<center><math>\displaystyle G=(V_{N}^{1}\cup V_{N}^{2}\cup \left\{ v_{0}\right\}
Linia 636: Linia 635:


Jeśli  <math>\displaystyle 1\in L_{1}\cup L_{2}  </math> , to oznaczamy  <math>\displaystyle L_{1}'=L_{1}\setminus \left\{ 1\right\} ,\; \; L_{2}'=L_{2}\setminus
Jeśli  <math>\displaystyle 1\in L_{1}\cup L_{2}  </math> , to oznaczamy  <math>\displaystyle L_{1}'=L_{1}\setminus \left\{ 1\right\} ,\; \; L_{2}'=L_{2}\setminus
\left\{ 1\right\}  </math> . Wówczas
\left\{ 1\right\}  </math> . Wówczas:


<center><math>\displaystyle L_{1}L_{2}=\left\{ \begin{array} {lll}
<center><math>\displaystyle L_{1}L_{2}=\left\{ \begin{array} {lll}
L_{1}'L_{2}'\cup L_{1}' & gdy & 1\in L_{2},\: 1\notin L_{1}\\
L_{1}'L_{2}'\cup L_{1}', & gdy & 1\in L_{2},\: 1\notin L_{1},\\
L_{1}'L_{2}'\cup L_{2}' & gdy & 1\in L_{1},\: 1\notin L_{2}\\
L_{1}'L_{2}'\cup L_{2}', & gdy & 1\in L_{1},\: 1\notin L_{2},\\
L_{1}'L_{2}'\cup L_{1}'\cup L_{2}'\cup \left\{ 1\right\}  & gdy &
L_{1}'L_{2}'\cup L_{1}'\cup L_{2}'\cup \left\{ 1\right\}, & gdy &
1\in L_{1},\: 1\in L_{2}
1\in L_{1},\: 1\in L_{2}.
\end{array} \right. </math></center>
\end{array} \right. </math></center>


Wykorzystując poprzednią konstrukcję i zamkniętość
Wykorzystując poprzednią konstrukcję i zamkniętość
ze względu na sumę w każdym z tych przypadków otrzymujemy gramatykę
ze względu na sumę w każdym z tych przypadków, otrzymujemy gramatykę
generującą katenację języków  <math>\displaystyle L_{1}  </math>  i  <math>\displaystyle L_{2}  </math> .
generującą katenację języków  <math>\displaystyle L_{1}  </math>  i  <math>\displaystyle L_{2}  </math> .


Linia 684: Linia 683:
zamknięta ze względu na uzupełnienie.
zamknięta ze względu na uzupełnienie.
Stwierdzenie to
Stwierdzenie to
wynika z przyjęcia jako obowiązujacej Tezy Churcha, która w tym
wynika z przyjęcia jako obowiązujacej tezy Churcha, która w tym
wypadku implikuje równość rodziny języków  <math>\displaystyle \mathcal{L}_{0}  </math>  i
wypadku implikuje równość rodziny języków  <math>\displaystyle \mathcal{L}_{0}  </math>  i
rodziny języków rekurencyjnie przeliczalnych oraz z faktu, iż
rodziny języków rekurencyjnie przeliczalnych oraz z faktu, iż
Linia 696: Linia 695:
Podsumowanie własności zamkniętości ze względu na działania dla
Podsumowanie własności zamkniętości ze względu na działania dla
różnych klas języków hierarchii Chomsky'ego zawarte jest w poniższej
różnych klas języków hierarchii Chomsky'ego zawarte jest w poniższej
tabeli.
tabeli:


{| border=1 align=center
{| border=1 align=center
Linia 721: Linia 720:
wynika w&nbsp;części  z definicji typów gramatyk wprowadzonych na wykładzie 2, a w części
wynika w&nbsp;części  z definicji typów gramatyk wprowadzonych na wykładzie 2, a w części
z udowodnionych własności poszczególnych rodzin języków z
z udowodnionych własności poszczególnych rodzin języków z
hierarchii Chomsky'ego (zakładając obowiązywanie Tezy Churcha).
hierarchii Chomsky'ego (zakładając obowiązywanie tezy Churcha).


{{twierdzenie|4.3||
{{twierdzenie|4.3||
Rodziny języków  hierarchii Chomsky'ego spełniają następujące relacje
Rodziny języków  hierarchii Chomsky'ego spełniają następujące relacje:


<center><math>\displaystyle \mathcal{L}_{0}\subseteq \! \! \! \! \! \! _{/}\, \mathcal{L}_{1}
<center><math>\displaystyle \mathcal{L}_{0}\subseteq \! \! \! \! \! \! _{/}\, \mathcal{L}_{1}
\subseteq \! \! \! \! \! \! _{/}\, \mathcal{L}_{2}
\subseteq \! \! \! \! \! \! _{/}\, \mathcal{L}_{2}
\subseteq \! \! \! \! \! \! _{/}\, \mathcal{L}_{3}
\subseteq \! \! \! \! \! \! _{/}\, \mathcal{L}_{3}.
</math>.</center>
</math></center>


}}
}}

Wersja z 19:37, 2 wrz 2006

Sformułujemy definicje podstawowych klas złożoności w języku maszyn Turinga oraz metodę ich porównywania. Przeanalizujemy związki między rodziną języków określonych przez maszyny Turinga a rodziną języków typu (0) z hierarchii Chomsky'ego. Podamy dalsze własności języków kontekstowych i typu (0). Wprowadzimy pojęcie języka rekurencyjnie przeliczalnego oraz przedstawimy tezę Churcha. Następnie omówimy teoretyczne podstawy teorii rozstrzygalności oraz przeanalizujemy kilka problemów nierozstrzygalnych w teorii języków.

1. Klasy złożoności obliczeniowej

Jednym z podstawowych celów wprowadzania maszyn Turinga jest dążenie do formalnej definicji złożoności obliczeniowej. Na podstawie wcześniejszych uwag możemy utożsamiać akceptację słowa przez maszynę Turinga z jej zatrzymaniem się. Intuicyjnie, można takie zachowanie maszyny Turinga utożsamić z wykonaniem programu, który zwraca odpowiedź "Tak" na postawione przez nas pytanie.

Definicja 1.1

Ustalmy funkcje t,s:. Mówimy, że maszyna Turinga 𝒯 (deterministyczna lub niedeterministyczna) akceptuje słowo wΣI* w czasie t(|w|), jeśli istnieje ciąg kt(|w|) konfiguracji d1,d2,,dk takich, że d1=s0w, dk=w1sFw2 dla pewnych w1,w2ΣT*,sFSF oraz didi+1 dla i=1,,k1.

Jeśli istnieje ciąg konfiguracji d1d2dm, gdzie d1=s0w, dm jest konfiguracją akceptującą (tzn. dm=w1sFw2 dla pewnych w1,w2ΣT*,sFSF) oraz dodatkowo |di|s(|w|)+2, to mówimy, że maszyna 𝒯 akceptuje słowo wΣI* w pamięci s(|w|).

Mówimy, że język L jest akceptowany w czasie t(n) (pamięci s(n)), jeśli istnieje maszyna Turinga 𝒯, dla której L(𝒯)=L oraz każde słowo wL jest akceptowane w czasie t(|w|) (pamięci s(|w|) odpowiednio).

Uwaga 1.1

W niektórych podejściach wykorzystuje się, do definicji złożoności pamięciowej, tak zwanych maszyn Turinga off-line. Pomysł polega na tym, aby nie uwzględniać komórek taśmy, z których maszyna czytała informacje, a jedynie te, do których następował zapis. Dzięki temu zabiegowi można w sposób "rozsądny" mówić o akceptacji słowa w pamięci logn itp. W ujęciu prezentowanym w tym wykładzie zajmujemy się akceptacją w pamięci nk, dla k1, zatem nie ma potrzeby dodatkowego definiowania maszyn Turinga off-line.

Definicja 1.2

Oznaczmy przez Dtime(t(n)) oraz Dspace(s(n)) rodzinę języków akceptowanych w czasie t(n) i odpowiednio pamięci s(n) przez deterministyczną maszynę Turinga. Dla maszyn niedeterministycznych wprowadzamy w identyczny sposób klasy Ntime(t(n)) oraz Nspace(s(n)).

Określamy następujące klasy złożoności (klasy języków):

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \textbd{P} \displaystyle =\bigcup_{k=0}^\infty Dtime(n^k), &\qquad\qquad& \textbd{NP} \displaystyle =\bigcup_{k=0}^\infty Ntime(n^k), \\ \textbd{PSPACE} \displaystyle =\bigcup_{k=0}^\infty Dspace(n^k), && \textbd{NSPACE} \displaystyle =\bigcup_{k=0}^\infty Nspace(n^k). \endaligned}

Wprost z definicji otrzymujemy zależności P NP oraz PSPACE NPSPACE . W dalszej części wykładu udowodnimy kilka mniej oczywistych zależności.

Przykład 1.1

Rozważmy język:

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle L=\left\{1^i 2^j 3^k\: k=i\cdot j,\: i,j\geqslant 1\right\}. }

Język L P . Deterministyczna maszyna Turinga MT3 akceptująca taki język może wyglądać następująco (zaczynamy od konfiguracji s0w):

  1. Jeśli symbol pod głowicą, to 1 zamień go na . Inaczej odrzuć.
  2. Przejdź od lewego ogranicznika do prawego, sprawdzając, czy po 1 występuje 1 lub 2, po 2 tylko 2 lub 3, a po 3 kolejny symbol 3 lub ogranicznik. Jeśli ta zależność nie jest spełniona, odrzuć. Gdy osiągniesz ogranicznik wykonaj następny krok.
  3. Gdy przed ogranicznikiem nie znajduje się symbol 3, odrzuć. W przeciwnym razie zamień symbol 3 na , a następnie poruszaj się w lewo, aż dotrzesz do symbolu innego niż 3 i .
  4. Jeśli symbol do którego dotarłeś to 2, zamień go na . Sprawdź symbol po lewej. Jeśli to 2, poruszaj się w prawo aż do ogranicznika. Następnie przejdź do kroku 3.
  5. Jeśli dotarłeś do symbolu 1, poruszaj się w lewo aż do ogranicznika. Zamień symbol 1 przy ograniczniku na , a następnie idź w prawo, zamieniając wszystkie symbole na 2. Gdy dojdziesz do ogranicznika, przejdź do kroku 3.
  6. Jeśli dotarłeś do ogranicznika, oznacza to, że skasowano już wszystkie symbole 1. Przejdź w prawo aż do ogranicznika. Jeśli natrafisz na symbol 3, odrzuć. W przeciwnym przypadku, akceptuj.

Nietrudno zaobserwować, że maszyna MT3 przechodzi przez taśmę w prawo i w lewo tyle razy, ile symboli 3 zawiera taśma oraz wykonuje jeden dodatkowy przebieg na starcie. Zatem słowa z L są akceptowane w czasie ograniczonym wielomianowo.

Przykład 1.2

Rozważmy teraz język

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle L=\left\{3^k\: : \: k=i\cdot j } dla pewnych i,j>1}.

Najprostszą metodą uzasadnienia, że L NP jest konstrukcja tak zwanej wyroczni. Polega ona na następującej dwuetapowej procedurze:

  1. Skonstruuj niedeterministyczną maszynę Turinga (wyrocznia) generującą pewne słowo (certyfikat).
  2. Zweryfikuj w sposób deterministyczny spełnienie założeń przez certyfikat.

W naszym przykładzie Etap 1 wygląda następująco:

  1. Użyj dwóch taśm. Na pierwszej z nich znajduje się 3k.
  2. Idź po pierwszej taśmie, wykorzystując niedeterministyczną funkcję przejść. Napotykając 3, możesz wypisać 1 na taśmie drugiej i przejść o jedną komórkę w prawo na taśmie pierwszej lub przejść do następnego kroku. Jeśli dotarłeś do prawego ogranicznika taśmy pierwszej, przejdź do kroku 3.
  3. Powróć do początku pierwszej taśmy. Wykonaj sekwencję jak w kroku 2, z tą różnicą, że teraz na drugiej taśmie wypisuj symbole 2.
  4. Jako ostatnią część tego etapu przekopiuj symbole 3 z pierwszej taśmy na drugą (po symbolach 1 i 2).

W konstrukcji wykorzystaliśmy dwie taśmy, ale oczywiście w nawiązaniu do wcześniejszych uwag, całą konstrukcję można wykonać na jednej taśmie (z odpowiednio rozszerzonym alfabetem i bardziej skomplikowaną funkcją przejść).

Etap 2 polega na weryfikacji, czy na taśmie drugiej znajduje się słowo postaci 1i2j3k, gdzie i,j>1 oraz k=ij. Jeśli tak, to słowo wejściowe 3k pochodziło z języka L i akceptujemy. Można do tego wykorzystać deterministyczną maszynę Turinga, niemal identyczną z opisaną w przykładzie poprzednim.

Jeśli słowo wejściowe pochodzi z języka L, to jedno z obliczeń maszyny niedeterministycznej z Etapu 1. prowadzi do konstrukcji odpowiedniego słowa na drugiej taśmie. Nie wiemy, jaka dokładnie ścieżka obliczeń ma być wykorzystana, ale dla akceptacji języka L nie ma to znaczenia.

Zastanów się, czy da się wykazać, że także L P (Ćwiczenie 1.3, do tego wykładu).

Definicja 1.3

Funkcja s(n) jest konstruowalna pamięciowo, jeśli istnieje maszyna Turinga 𝒯=(ΣT,S,f,s0,SF), dla której d1*d2, gdzie d1=s01n, d2=s11s(n)w dla s1SF, w(ΣT{1})* oraz dodatkowo d2 jest konfiguracją końcową.

Inaczej mówiąc, funkcję s(n) nazywamy konstruowalną pamięciowo, jeśli istnieje maszyna Turinga 𝒯, otrzymując na wejściu słowo w długości |w|=n, zaznacza na taśmie roboczej s(n) klatek i zatrzymuje się (akceptując słowo w).

Przykład 1.3

Funkcja s(n)=2n jest konstruowalna pamięciowo. Maszyna MT4, która konstruuje s(n) działa według schematu:

  1. Przejdź do prawego markera. Jeśli napotkano symbol inny niż 1, to odrzuć.
  2. Idź w lewo aż do pierwszego symbolu 1 lub markera
  3. Jeśli napotkałeś symbol 1, zamień go na i przejdź do prawego markera. Dopisz do słowa symbol (zwiększając tym samym długość słowa na taśmie o 1). Następnie powtórz cykl od 2.
  4. Jeśli napotkałeś marker, idź w prawo, zamieniając wszystkie wystąpienia na 1. Następnie wracaj do lewego markera i zatrzymaj się, akceptując.

Twierdzenie 1.1 liniowa kompresja pamięci

Niech będzie dany język L oraz maszyna Turinga 𝒯 akceptująca L w pamięci s(n). Dla dowolnego ε>0 istnieje maszyna Turinga 𝒯 akceptująca L w pamięci max{n,εs(n)}.

Dowód

(Szkic) Ustalamy liczbę naturalną k, dla której εk2. Maszynę 𝒯 definiujemy następująco:

  1. Przekoduj słowo wejściowe, łącząc po r kolejnych symboli w jeden blok stanowiący nowy symbol na taśmie.
  2. Symuluj maszynę 𝒯 na skompresowanej taśmie. Położenie głowicy wewnątrz bloku zakoduj w stanach maszyny 𝒯.

Zauważmy, że w kroku 1. maszyna 𝒯 wykorzystuje n komórek pamięci do odczytania słowa wejściowego. Kompresja taśmy zapewnia, że podczas symulowania maszyny 𝒯 nie wykorzystamy więcej niż s(n)kεs(n) komórek. Jednocześnie można założyć, że 𝒯 akceptuje słowa wejściowe z języka L o długości mniejszej niż k bez symulowania 𝒯.

Twierdzenie 1.2 Savitch

Dla dowolnej funkcji s(n) konstruowalnej pamięciowo spełniającej warunek s(n)log2n prawdziwa jest inkluzja Nspace(s(n))DSpace(s2(n)).

Dowód

Niech 𝒩𝒯 będzie niedeterministyczną maszyną Turinga akceptującą język L=L(𝒩𝒯) w pamięci s(n). Niech k(n) oznacza liczbę konfiguracji potrzebną do zaakceptowania słowa o długości n. Istnieje liczba c>1, dla której k(n)cs(n), co z kolei oznacza, że każde słowo o długości n jest akceptowane w cs(n) krokach czasowych.

Rozważmy algorytm:

Algorytm


  1  Wejście: słowo w długości |w|=n
  2  oblicz s(n)
  3  for każda konfiguracja akceptująca dA dla której |dA|s(n)
  4    do if Test(s0w, dA, s(n)log2c) then akceptuj

gdzie procedura Test ma następującą postać:

Algorytm Procedure Test(d,d,i)


  1  if i=0 and [ (d=d) or (dd)] then return true
  2    else for każda konfiguracja d dla której |d|s(n)
  3      do if Test(d,d,i1) and Test d,d,i1)
  4        then return true;
  5  return false

Przedstawiony algorytm można zrealizować za pomocą wielotaśmowej maszyny Turinga. Założenie dotyczące konstruowalności pamięciowej jest istotnie wykorzystywane w tej konstrukcji przy implementacji linii 3 algorytmu i linii 2 procedury Test. Musimy zaznaczyć s(n) komórek taśmy, aby móc konstruować konfiguracje o długości ograniczonej przez s(n) i móc następnie wykonywać na nich symulację maszyny 𝒩𝒯.

Zauważmy, że ilość konfiguracji jest ograniczona przez s(n), a głębokość rekursji przez logcs(n). Oznacza to, że jesteśmy w stanie skonstruować maszynę Turinga, która wymaga cs2(n) pamięci, gdzie c jest pewną stałą. Na mocy Twierdzenia 1.1 jesteśmy w stanie określić maszynę 𝒯 działającą w pamięci s2(n).

Wniosek 1.1

PSPACE = NPSPACE

Lemat 1.1

Jeśli g(n)n, to Dtime(g(n))Dspace(g(n)) oraz Ntime(g(n))Nspace(g(n)).

Dowód

Niech będzie dana maszyna deterministyczna 𝒯 akceptująca dany język L w czasie g(n). Do akceptacji słowa w o długości n maszyna wykorzystuje co najwyżej g(n) kroków czasowych, czyli odwiedza co najwyżej g(n)+1 komórek taśmy.

Na podstawie Twierdzenia 1.1 istnieje maszyna Turinga 𝒯 wykorzystująca

max{n,12(g(n)+1)}g(n)

komórek pamięci. Dla niedeterministycznych maszyn Turinga argumentacja jest identyczna.

Wniosek 1.2

P NP PSPACE = NPSPACE
Uwaga 1.2

Nie jest znany przykład wykazujący silną inkluzję P NP ani dowód wykluczający istnienie takiego przykładu. Powszechnie uznawana hipoteza głosi:

P NP.

Rozstrzygnięcie jej prawdziwości lub fałszywości stanowi jeden z najważniejszych, a zarazem najtrudniejszych problemów współczesnej informatyki. Jak widzieliśmy w Przykładzie 1.2, nawet w przypadku konkretnego języka L NP, problem uzasadnienia, że także L P, jest nietrywialny, gdyż wymaga zazwyczaj konstrukcji całkiem nowej maszyny Turinga niż ta do weryfikacji L NP .

2. Redukcja i problemy zupełne

Definicja 2.1 transformacja wielomianowa

Niech L1,L2 będą dowolnymi językami nad pewnym alfabetem ΣI. Mówimy, że L1 redukuje się do L2 w czasie wielomianowym, co oznaczamy L1L2, gdy istnieje deterministyczna maszyna Turinga 𝒯=(ΣT,S,f,s0,SF) taka, że dla dowolnego wΣI* istnieje wΣI* i stan s1SF o własności

s0w*s1w

oraz

wL1wL2.

Lemat 2.1

Załóżmy, że L1L2. Wtedy zachodzą implikacje:

  1. L2 P      L1 P,
  2. L2 NP      L1 NP,
  3. L2 PSPACE      L1 PSPACE.

Dowód

Dane słowo w transformujemy do w w czasie wielomianowym, co gwarantuje założenie L1L2. Dzięki założeniu L2 P możemy rozstrzygnąć, czy wL2 (tzn. jeśli akceptujemy w, to robimy to w czasie wielomianowym). Tym sposobem (korzystając z definicji transformacji wielomianowej) akceptujemy w w czasie wielomianowym, o ile tylko wL1. Dowód dla pozostałych implikacji jest identyczny.

Definicja 2.2

Niech 𝒞 oznacza pewną klasę języków. Język L nazywamy 𝒞-trudnym, jeśli spełniony jest warunek:

L𝒞LL.

Jeżeli dodatkowo spełniony jest warunek L𝒞, to język L nazywamy 𝒞-zupełnym.

Intuicyjnie, fakt, że język jest 𝒞-zupełny, oznacza, że jest on najbardziej skomplikowany (pod względem obliczeniowym) wśród języków z klasy 𝒞, natomiast język 𝒞-trudny jest bardziej skomplikowany niż każdy z klasy 𝒞, choć sam nie musi do niej należeć.

Uwaga 2.1

Rozważając klasę P , NP i PSPACE, możemy mówić o językach (problemach) P -zupełnych, NP -zupełnych, czy też PSPACE -zupełnych. To samo odnosi się do języków trudnych (tzn. klasa języków P -trudnych, itd.).

Przykład 2.1

Rozważmy języki:

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle L_1=\left\{1^i 2^j 3^k\: k=i\cdot j,\: i,j\geqslant 1\right\}\quad,\quad L_2=\left\{1^i 2^j 4^{2k}\: k=i\cdot j,\: i,j\geqslant 1\right\}. }

Języki: L1 oraz L2 wyglądają na bardzo podobne, zatem wydaje się, że L1L2 oraz L2L1. Uzasadnienie tego faktu jest prawie natychmiastowe.

Konstruujemy deterministyczną maszynę Turinga która działa w następujący sposób:

  1. Jeśli słowo wejściowe jest puste, to stop.
  2. Przejdź do prawego ogranicznika. Jeśli przy ograniczniku nie występuje symbol 4, to wykonaj krok 1.
  3. Jeśli w słowie wejściowym występuje symbol 4, to sprawdź, czy słowo przetwarzane jest postaci w4s, gdzie s1 oraz w(ΣI{4})* oraz czy dodatkowo s jest liczbą parzystą. Jeśli nie, to wykonaj krok 1.
  4. Zamień słowo 4s na słowo 3s2s2 i wykonaj krok 1.
  5. Przejdź nad pierwszy symbol po lewym ograniczniku i zatrzymaj się.

W ten sposób zawsze przeprowadzamy konfigurację s0w na konfigurację s1w, przy czym w=1i2j3k tylko, gdy w=1i2j42k. Zatem wL2 wtedy i tylko wtedy, gdy wL1. Wykazaliśmy, że L2L1.

Warunek L1L2 otrzymujemy w sposób identyczny. Trzeba tylko wypisać odpowiednią ilość symboli 4 (a wiemy już, jak konstruować liczbę 2n, mając dane n).

3. Języki maszyn Turinga i rodzina 0

Powstaje naturalne pytanie o związki pomiędzy klasą języków rozpoznawanych przez maszyny Turinga a klasami zadanymi poprzez gramatyki. Odpowiemy na to pytanie w tej części wykładu.

Twierdzenie 3.1

Każdy język akceptowany przez maszynę Turinga jest typu (0).

(MT)0.

Dowód

Niech L będzie językiem akceptowanym przez maszynę Turinga 𝐌𝐓=(ΣT,S,f,s0,SF) , o której założymy, że f(s0,#)=(s,#,1) , jeśli para (s0,#) należy do dziedziny funkcji przejść f maszyny Turinga. Założenie to nie ogranicza ogólności rozważań. Wyróżnimy pewien podzbiór SF zbioru stanów S , którego elementy, jak wskazuje oznaczenie, skojarzone są ze stanami końcowymi. Do zbioru SF należy każdy stan sS , dla którego istnieje ciąg stanów s1=s,...,sk dla k1 taki, że (si,#)(si+1,#,0) dla k=1,...,k1 oraz (sk,#)(s,#,1) , gdzie sSF . Zauważmy, iż wraz ze stanem s do zbioru SF należą wszystkie elementy ciągu s1=s,...,sk .

Określamy teraz gramatykę G=(VN,VT,v0,P) . Zbiór symboli nieterminalnych VN zawiera wyłącznie następujące symbole:

  1. dla każdego stanu sS i aΣT{#} symbole Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle v_{sa},\: ^{\#}v_{sa},\: v_{sa}^{\#},\: ^{\#}v_{sa}^{\#}, }
  2. dla każdej litery aΣT{#} symbole #a i a#,
  3. wszystkie elementy zbioru ΣT(ΣI{#}),
  4. symbole Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle v_{0},\: v_{1} } nie należące do ΣT.

Zbiór praw P składa się z praw wymienionych poniżej:

  1. v0#vsa# , v0v1vsa#, jeśli f(s,a)=(s,b,1) dla pewnego bΣT{#} , sSF ,
  2. v1#a , v1v1a dla każdego aΣT{#} ,
  3. vs1cbcvsa , #vs1cb#cvsa , vs1cb#cvsa# , #vs1cb##cvsa#, jeśli f(s,a)=(s1,b,1) i cΣT{#} ,
  4. bvs1cvsac , #bvs1c#vsac , bvs1c#vsac# , #bvs1c##vsac#, jeśli f(s,a)=(s1,b,1) i cΣT{#} ,
  5. vs1bvsa , #vs1b#vsa , vs1b#vsa# , #vs1b##vsa#, jeśli f(s,a)=(s1,b,0) ,
  6. vs1b#vsa# , #vs1b##vsa# , jeśli istnieją s1,...,skS dla k1, takie że f(s,a)=(s1,b,1) , f(si,#)=(si+1,#,0) dla i=1,...,k1 oraz f(sk,#)=(s1,#,1) ,
  7. #vs1b#vsa , #vs1b##vsa# , jeśli istnieją s1,...,skS dla k1 takie, że f(s,a)=(s1,b,1) , f(si,#)=(si+1,#,0) dla i=1,...,k1 oraz f(sk,#)=(s1,#,1) ,
  8. a#a dla wszystkich aΣT{#} ,
  9. #vsaa , #vsa#a , jeśli f(s0,#)=(s,#,1) (porównaj założenie na początku dowodu),
  10. v01, jeśli 1L .

Określona powyżej gramatyka G jest gramatyką typu (0). Rozważmy teraz dowolne słowo w , dla którego istnieje wyprowadzenie w gramatyce G ze stanu początkowego v0 przy użyciu praw 1-7. Słowo w zawiera dokładnie jeden z następujących symboli vsa,#vsa,vsa# lub #vsa# . Pierwsza litera słowa w oznaczona jest markerem # z lewej strony, a ostatnia litera słowa w oznaczona jest markerem # ze strony prawej. Ponadto żadna z liter występujących pomiędzy pierwszą a ostatnią nie jest oznaczona markerem # . Z każdym takim słowem kojarzymy konfigurację poprzez zastąpienie symbolu vsa przez sa oraz przez dopisanie symbolu # po lewej lub prawej stronie znaczonej przez ten marker litery, zgodnie z jego występowaniem. Jeśli np. w=#vsa# , to skojarzona konfiguracja jest postaci #sa# . Zauważmy, że jeśli słowa u i w są w powyższej formie, to fakt, iż u*w , jest równoważny stwierdzeniu, że z konfiguracji skojarzonej ze słowem w maszyna Turinga MT może przejść (bezpośrednie następstwo) do konfiguracji skojarzonej ze słowem u . Każdy krok obliczenia realizowanego przez MT ma swój odpowiednik - krok w wyprowadzeniu w gramatyce G . Z tym, że wobec praw 6 i 7 sekwencja obliczeń

vsa#vbs1#...vbsk#vs1b#

jest traktowana jako jeden krok w obliczeniu prowadzonym przez maszynę Turinga. Analogicznie traktujemy sekwencję z markerem # występującym po lewej stronie. Ze stanu początkowego v0 gramatyki G można wyprowadzić wszystkie słowa w , dla których konfiguracja jest równa #vsa#, dla pewnego v(ΣI{#})* oraz maszyna Turinga realizuje obliczenie:

sa#bs1#...bsk#b#s1,s1SF.

Wynika to z praw 1 i 2 skonstruowanej gramatyki G . Z kolei prawa typu 9 służą do zastąpienia symboli nieterminalnych typu #vsa,#vsa# przez litery terminalne, a prawa typu 8 eliminują symbole nieterminalne typu a# . A zatem dla niepustego słowa w(ΣI{#})* spełniona jest równoważność

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle v_{0}\mapsto_{G}^{*}w\: \Leftrightarrow \: s_{0}\#w\#\rightarrow _{TM}^{*}\#u\#s_{1}, }

gdzie u(ΣI{#})* oraz s1SF . Prawo 10. zapewnia, że powyższa równoważność prawdziwa jest także dla słowa pustego 1 . A to kończy dowód tego twierdzenia.

Język L nazywamy rekurencyjnie przeliczalnym, jeśli istnieje efektywny algorytm wyliczający wyłącznie słowa z L . Przez efektywny algorytm rozumiemy skończony zbiór instrukcji, który w jednoznaczny sposób opisuje działanie tego algorytmu. Klasę języków rekurencyjnie przeliczalnych oznaczamy symbolem 𝒫 .

Zauważmy, że każda gramatyka G typu (0) jest algorytmem wyliczającym wyłącznie słowa z L=L(G) . Dla każdej liczby naturalnej k można bowiem rozważyć skończony zbiór wyprowadzeń w G, rozpoczynających się od symbolu początkowego v0 i o długości równej k . Z tego zbioru można z kolei wybrać wyłącznie te wyprowadzenia, które kończą się słowem nad alfabetem terminalnym gramatyki G i tylko te słowa dodawać do listy składającej się na język L . Są to, jak łatwo zauważyć, wszystkie słowa języka L i nic ponadto. A zatem

Twierdzenie 3.2

Każdy język typu (0) jest językiem rekurencyjnie przeliczalnym, czyli 0𝒫 .

Język L nazywamy rekurencyjnym, jeśli istnieje efektywny algorytm rozstrzygający dla każdego słowa wA* jego przynależność do języka L . Klasę języków rekurencyjnych oznaczamy symbolem .

Klasa języków kontekstowych zawiera się istotnie w klasie języków rekurencyjnych, o czym przekonuje poniższe twierdzenie.

Twierdzenie 3.3

Każdy język kontekstowy jest językiem rekurencyjnym, czyli 1.

Dowód

Niech L będzie dowolnym językiem kontekstowym. Istnieje więc gramatyka kontekstowa G=(VN,VT,v0,P) taka, że L=L(G) . Bezpośrednio z definicji gramatyki kontekstowej wynika, iż słowo puste 1L wtedy i tylko wtedy, gdy v01P . Załóżmy teraz, że dane jest słowo wVT* , o którym mamy zadecydować, czy należy do języka L . W tym celu rozważmy wszystkie ciągi słów

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle y_{0}=v_{0},\: y_{1},...,y_{n-1},\: y_{n}=w}

o tej własności, że yi(VNVT)* są parami różne, dla i=0,...,n , n1 oraz yiyi+1 . Ilość takich ciągów jest skończona i słowo wL wtedy i tylko wtedy, gdy wśród powyższych ciągów znajdziemy choć jeden taki, że tworzy wyprowadzenie w gramatyce G . Czyli

y0=v0y1...yn1yn=w.

Ponieważ ilość ciągów podlegających rozważaniom jest skończona oraz ponieważ stwierdzenie, czy pomiędzy dowolnymi słowami zachodzi relacja , sprowadza się do przeszukania skończonego zbioru praw P , efektywnie rozstrzygniemy, czy w należy do języka L, czy też nie.

Uzyskane dotąd rezultaty możemy podsumować następująco:

(MT)0𝒫.

W określeniu języka rekurencyjnie przeliczalnego oraz języka rekurencyjnego wystąpiło pojęcie efektywnego algorytmu, efektywnej procedury. Pojęcie to, intuicyjnie dość jasne, nie zostało precyzyjnie określone. Co za tym idzie, dla matematycznie poprawnych definicji języka rekurencyjnie przeliczalnego i języka rekurencyjnego należałoby sformalizować pojęcie algorytmu. W dotychczasowych rozważaniach intuicja efektywnej procedury była o tyle wystarczająca, że naszym celem było wskazanie istnienia takiej procedury. W sytuacji, gdyby naszym celem było wykazanie, że taka procedura nie istnieje, formalizacja tego pojęcia byłaby wręcz konieczna. We wszystkich takich przypadkach powszechnie przyjmuje się, że maszyna Turinga jest właśnie taką formalizacją. Na zdefiniowaną w poprzednim wykładzie maszynę Turinga można spojrzeć jako na algorytm, efektywną procedurę dającą odpowiedź pozytywną lub negatywną w zależności od akceptacji lub nieakceptowania słowa wejściowego. Proces obliczenia prowadzony przez maszynę Turinga zgadza się z intuicyjnym rozumieniem algorytmu. O tym, że każda efektywna procedura jest reprezentowana przez pewną maszynę Turinga, mówi, powszechnie przyjęta jako prawdziwa, teza Churcha.

Teza Churcha

Każda efektywna procedura (algorytm) da się opisać przez maszynę Turinga.

Konsekwencją przyjęcia tezy Churcha jest inkluzja 𝒫(MT) . Biorąc pod uwagę udowodnione powyżej twierdzenia, mamy:

(MT)0𝒫,

co ostatecznie prowadzi do równości 0=(MT) .

4. Rodziny 1 i 0 - zamkniętość na działania

Dla kompletności tej części wykładu przedstawimy własności zamkniętości rodziny języków kontekstowych 1 i języków typu (0) 0 ze względu na najczęściej używane operacje. W niektórych przypadkach dowody dotyczące obu klas są takie same. W dowodach posłużymy się specjalną postacią gramatyk, a mianowicie taką, w której symbole terminalne występują tylko po prawej stronie. Prawdziwe bowiem jest twierdzenie

Twierdzenie 4.1

Dla każdej gramatyki istnieje równoważna gramatyka tego samego typu taka, że każda produkcja, w której występuje symbol terminalny a , jest postaci va .

Elementarny dowód tej własności pozostawiamy jako zadanie domowe.

Twierdzenie 4.2

Rodziny 0 i 1 są zamknięte ze względu na:

  1. sumę mnogościową,
  2. iloczyn mnogościowy,
  3. katenację,
  4. iterację *,
  5. odbicie zwierciadlane.

Dowód

1. Niech dla i=1,2Gi=(VNi,VT,v0i,Pi) będą gramatykami typu (1) (odpowiednio typu (0) ) takimi, że VN1VN2= . I niech Li=L(Gi) . Określamy gramatykę G typu (1) (typu (0) ) generującą język L1L2 .

Jeśli 1L1L2 , to przyjmujemy:

G=(VN1VN2{v0},VT,v0,P1P2{v0v01,v0v02}).

Zauważmy, że wówczas w żadnej z gramatyk nie ma prawa wymazującego. Jeśli natomiast 1L1L2 , to konstruujemy gramatykę G dla języków L1{1} i L2{1} , jak powyżej, a następnie dodajemy nowy symbol początkowy v0 i prawa v0v0,v01 .

2. Przecięcie udowodnimy tylko dla języków typu (0) . Dowód dla języków kontekstowych został przeprowadzony wcześniej.

Niech dla i=1,2Gi=(VNi,VT,v0i,Pi) będą gramatykami typu (0) takimi, że VN1VN2= . Niech Li=L(Gi) . Określamy gramatykę G typu (0) generującą język L1L2, przyjmując:

G=(VN1VN2VN,VT,v0,P1P2P),

gdzie: VN={va:aVT}{v0,v1,v2} , a do zbioru P należą prawa:
(1) v0v1v01v2v02v1,
(2) v2avav2 dla aVT,
(3) bvavab dla a,bVT,
(4) v1vaaav1 dla aVT,
(5) v1v2v11.
Przy pomocy prawa (1) i wszystkich praw ze zbioru P1P2 można wygenerować zbiór słów:

{v1w1v2w2v1:w1L1,w2L2}.

Z dowolnego słowa należącego do tego zbioru, korzystając z praw (2)-(4), można wyprowadzić słowo w1v1v2v1 wtedy i tylko wtedy, gdy w1=w2 . Korzystając z prawa (5), dostajemy słowo w1 . A więc L(G)=L1L2 .

3. Niech dla i=1,2Gi=(VNi,VT,v0i,Pi) będą tak jak poprzednio gramatykami typu (1) ( (0) ) takimi, że VN1VN2= oraz spełniającymi warunki powyższego twierdzenia. Niech Li=L(Gi) . Określamy gramatykę G odpowiednio typu (1) ( (0) ) generującą język L1L2 .

Jeśli 1L1L2 , to przyjmujemy:

G=(VN1VN2{v0},VT,v0,P1P2{v0v01v02}).

Jeśli 1L1L2 , to oznaczamy L1=L1{1},L2=L2{1} . Wówczas:

Parser nie mógł rozpoznać (nieznana funkcja „\begin{array}”): {\displaystyle \displaystyle L_{1}L_{2}=\left\{ \begin{array} {lll} L_{1}'L_{2}'\cup L_{1}', & gdy & 1\in L_{2},\: 1\notin L_{1},\\ L_{1}'L_{2}'\cup L_{2}', & gdy & 1\in L_{1},\: 1\notin L_{2},\\ L_{1}'L_{2}'\cup L_{1}'\cup L_{2}'\cup \left\{ 1\right\}, & gdy & 1\in L_{1},\: 1\in L_{2}. \end{array} \right. }

Wykorzystując poprzednią konstrukcję i zamkniętość ze względu na sumę w każdym z tych przypadków, otrzymujemy gramatykę generującą katenację języków L1 i L2 .

4. Niech G=(VN,VT,v0,P) będzie gramatyką typu (1) (typu (0) ) taką, że symbole terminalne nie występują po lewej stronie żadnej produkcji z P . Załóżmy też, że 1L=L(G) . Gramatyka

G=(VN{v0,v1},VT,v0,P),

gdzie

Parser nie mógł rozpoznać (nieznana funkcja „\begin{array}”): {\displaystyle \displaystyle \overline{P}=P\cup \begin{array} [t]{l} \left\{ \overline{v}_{0}\rightarrow 1,\: \overline{v}_{0}\rightarrow v_{0},\: \overline{v}_{0}\rightarrow \overline{v}_{1}v_{0}\right\} \cup \\ \left\{ \overline{v}_{1}a\rightarrow \overline{v}_{1}v_{0}a\, :\, a\in V_{T}\right\} \cup \\ \left\{ \overline{v}_{1}a\rightarrow v_{0}a\, :\, a\in V_{T}\right\} \end{array} }

generuje język L* . Jeśli 1L , to usuwamy prawo wymazujące v01 i dla języka L{1} konstruujemy gramatykę G . Z faktu, że (L{1})*=L* , wynika, że również L(G)=L* .

5. Jeśli G=(VN,VT,v0,P) jest gramatyką typu (1) (typu (0) ) taką, że L(G)=L , to gramatyka G=(VN,VT,v0,P) , gdzie P={xy:xyP} generuje język L .

Zauważmy na koniec, że rodzina 0 nie jest zamknięta ze względu na uzupełnienie. Stwierdzenie to wynika z przyjęcia jako obowiązujacej tezy Churcha, która w tym wypadku implikuje równość rodziny języków 0 i rodziny języków rekurencyjnie przeliczalnych oraz z faktu, iż istnieje język rekurencyjnie przeliczalny, którego uzupełnienie nie jest rekurencyjnie przeliczalne. Ten ostatni fakt podajemy bez dowodu. Dodajmy, że własność zamkniętości ze względu na uzupełnienie dla rodziny 1 przez długi czas pozostawała problemem otwartym. Dopiero w roku 1987 udowodniono, iż własność ta jest spełniona dla języków kontekstowych. Podsumowanie własności zamkniętości ze względu na działania dla różnych klas języków hierarchii Chomsky'ego zawarte jest w poniższej tabeli:

          3       2       1       0   
          T       T       T       T   
          T       T       T       T   
          T       T       T       T   
          T       N       T       N   
          T       N       T       T   

Na koniec podamy twierdzenie o wzajemnych relacjach pomiędzy rodzinami języków z hierarchii Chomsky'ego. Dowód tego twierdzenia wynika w części z definicji typów gramatyk wprowadzonych na wykładzie 2, a w części z udowodnionych własności poszczególnych rodzin języków z hierarchii Chomsky'ego (zakładając obowiązywanie tezy Churcha).

Twierdzenie 4.3

Rodziny języków hierarchii Chomsky'ego spełniają następujące relacje:

0/1/2/3.

5. Problemy rozstrzygalne

W poprzednim wykładzie uzasadniliśmy, że dla każdej deterministycznej maszyny Turinga jesteśmy w stanie wskazać taką która akceptuje dany język i jednocześnie zatrzymuje się tylko na słowach akceptowanych. Wymagało to przejścia przez maszynę niedeterministyczną a następnie jej symulację na maszynie deterministycznej. Z tego powodu ograniczamy się w dalszej części wykładu tylko do tego typu maszyn Turinga (akceptacja=stop). Jak to uzasadniono wcześniej, przy założeniu Tezy Churcha, maszyna Turinga może być rozpatrywana jako matematycznie ścisła definicja algorytmu.

Pojęcie rozstrzygalnego problemu zostało wprowadzone wcześniej, na innym wykładzie i jest ono znane. Przypomnijmy więc tylko, że rozstrzygalność czy też nierozstrzygalność odnosi się do pewnej klasy, którą tworzą określone przypadki ustalonego problemu. Jeśli istnieje algorytm, który rozwiązuje taki problem dla wszystkich przypadków w tej klasy, to mówimy, że problem jest rozstrzygalny (w tej klasie). Zatem taki algorytm jest uniwersalnym sposobem rozwiązywania problemu dla wszystkich danych wejściowych określających poszczególne przypadki w tej klasie. Jak łatwo zauważyć dla ustalenia rozstrzygalności problemu wystarczy się opierać na intuicyjnym pojęciu algorytmu. Są jednak takie problemy, dla których nie istnieje, w rozważanej klasie przypadków, uniwersalny sposób ich rozwiazywania. Takie problemy nazywamy nierozstrzygalnymi w danej klasie. Aby wykazać nierozstrzygalność jakiegoś problemu, nieodzownym jest sformalizowanie pojęcia algorytmu. Standardowo taką formalizacją jest, o czym wspomniano już wcześniej, maszyna Turinga.

Zwróćmy uwagę, że maszyna Turinga akceptuje języki, gdy tym czasem przyzwyczajeni jesteśmy, że algorytmy (programy) rozwiązują pewne, niekiedy bardzo skomplikowane problemy (określone przy pomocy list, kolejek, grafów itp.). Zwracamy zatem uwagę na fakt, że w przypadku maszyny Turinga musimy wykonać wstępne umowne kodowanie naszego problemu. W tym przypadku rozważany język określa te spośród "sensownych" kodowań, które stanowią rozwiązanie postawionego problemu. Z drugiej strony maszyna akceptując słowo w1$w2 może informować nas o tym, że wynikiem obliczeń numerycznych na danych zakodowanych w w1 rzeczywiście jest liczba zakodowana w w2 itp.

Dla ilustracji powyższych dywagacji rozważmy problem skończoności w klasie jezyków regularnych. Problem ten jest rozstrzygalny, bo w oparciu o lemat o pompowaniu można skonstruować algorytm, który dla dowolnego języka regularnego rozstrzygnie, czyli odpowie twierdząco lub przecząco na pytanie o jego skończoność. W tym przypadku można np. przyjąć, że jako słowo wejściowe podajemy zakodowany opis gramatyki generującej język.

Nierozstrzygalność algorytmiczna problemu w ustalonej klasie nie oznacza, podkreślmy, niemożliwości rozwiazania konkretnego zadania z tej klasy. Nierostrzygalność oznacza niemożliwość rozwiązania za pomocą tego samego algorytmu, tej samej metody, wszystkich przypadków tego problemu należących do danej klasy.

W zamieszczonej poniżej tabeli przedstawiamy najczęściej rozważane pod kątem rozstrzygalności problemy z dziedziny języków formalnych w ramach hierarchii Chomsky'ego. Litera R oznacza rozstrzygalność problemu, N nierostrzygalność, a znak - pojawiający się przy problemie jednoznaczności oznacza, że problemu tego nie formułuje się dla gramatyk kontekstowych i typu (0).

własność (3) (2) (1) (0)
należenie wL R R R N
inkluzja L1L2 R N N N
równoważność R N N N
pustość L= R R N N
nieskończoność cardL=0 R R N N
jednoznaczność gramatyki R N - -

Najczęściej używaną metodą dowodzenia nierozstrzygalności problemu P jest redukcja tego problemu do innego, powiedzmy P , dla którego nierozstrzygalność została ustalona wcześniej. Redukcja taka prowadzi do sformułowania implikacji:

jeśli P byłby rozstrzygalny, to i P byłby rozstrzygalny.

A ponieważ to ostatnie (następnik implikacji) nie jest prawdą, więc problem P nie jest rozstrzygalny.

Należy w tym miejscu podkreślić fakt, że dowody nierozstrzygalności problemów uniwersalnych (takich jak problem Posta rozważany dalej) wiążą się z konstrukcją odpowiednich maszyn Turinga, kodowaniem problemu, a następnie dowodem uzasadniającym, że problem jest rzeczywiście nierozstrzygalny. Tematyka ta wykracza poza ramy wykładu. Z tego też powodu ograniczymy się tutaj do zaprezentowania jednego ze znanych problemów nierozstrzygalnych bez dowodu nierozstrzygalności.

Najczęściej występującym w literaturze problemem nierozstrzygalnym jest, bez wątpienia, problem Posta przedstawiony poniżej.

 

Problem Posta

Dla dowolnego alfabetu A , o co najmniej dwóch elementach ( A2 ), załóżmy, iż dana jest, tak zwana, lista słów, a dokładniej par słów Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle \left( u_{1},w_{1}\right) \: \left( u_{2},w_{2}\right) \: \ldots \left( u_{n},w_{n}\right), } gdzie ui,wiA+ , n . Mówimy, że taka lista ma własność Posta (problem Posta ma rozwiązanie), jeśli istnieje ciąg indeksów i1,,ik{1,...,n} taki, że

ui1uik=wi1wik.

Jest to w ogólnym przypadku problem nierozstrzygalny.

Problem ten można sformułować równoważnie następująco. Niech A będzie alfabetem interpretowanym jako zbiór indeksów, a B dowolnym alfabetem. Niech Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle h:A^{*}\longrightarrow B^{*},\: g:A^{*}\longrightarrow B^{*} } będą dowolnymi homomorfizmami. Problem Posta, inaczej sformułowany, polega na odpowiedzi na pytanie, czy istnieje słowo xA+ takie, że h(x)=g(x) .

Dwa kolejne przykłady ilustrują technikę redukcji pewnych problemów do problemu Posta. W efekcie uzyskujemy nierozstrzygalność w sposób opisany powyżej.

Twierdzenie 5.1

W klasie gramatyk bezkontekstowych problem niejednoznaczności jest nierozstrzygalny.

Dowód

Udowodnimy, że problem jest nierozstrzygalny dla gramatyk bezkontekstowych generujących jązyki nad alfabetem dwuelementowym A={a,b} . Oznaczmy B={d,e} i określmy homomorfizm h:B*A* , przyjmując h(d)=ba2 oraz h(e)=ba3 . Niech u będzie ciągiem u1,...,unB+ dowolnie wybranych i ustalonych słów. Dla dowolnej liczby naturalnej i>0 niech i=dei . Określony poniżej język

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle L_{u}=\{h(\overline{i_{1}}).....h(\overline{i_{k}})bah(u_{i_{k}}),...,h(u_{i_{1}})\in A^{*}\: :\: k\geqslant 1,\: 1\leqslant i_{j}\leqslant n\}}

jest językiem bezkontekstowym, jako generowany przez gramatykę Gu=(VN,VT,v0,Pu) , dla której

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle V_{N}=\{v_{u}\},\: V_{T}=\{a,b\},\: v_{0}=v_{u} } oraz Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle P_{x}=\{v_{u}\rightarrow h(\overline{i})v_{u}h(u_{i}),\: v_{u}\rightarrow h(\overline{i})bah(u_{i})\} } .

Niech teraz u i w oznaczają ciągi dowolnie wybranych i ustalonych słów u1,...,unB+ i w1,...,wnB+ . Tworzą one listę słów Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle \left( u_{1},w_{1}\right) \: \left( u_{2},w_{2}\right) \: \ldots \left( u_{n},w_{n}\right), } . Zatem zasadne jest postawienie pytania, czy lista ta ma własność Posta. Niech Gu oraz Gw będą gramatykami bezkontekstowymi określonymi tak jak powyżej. Gramatyka G=({v0,vu,vw},{a,b},v0,P) , gdzie Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle P=\{v_{0}\rightarrow v_{u},\: v_{0}\rightarrow v_{w}\}\cup P_{u}\cup P_{w} } jest bezkontekstowa. Gramatyka ta jest niejednoznaczna wtedy i tylko wtedy, gdy LuLy . Ten ostatni warunek równoważny jest istnieniu liczb i1,...,ik takich, że ui1.....uik=wi1.....wik , czyli własności Posta listy Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle \left( u_{1},w_{1}\right) \: \left( u_{2},w_{2}\right) \: \ldots \left( u_{n},w_{n}\right) } .Ostatecznie więc rozstrzygalność problemu niejednoznaczności w klasie gramatyk bezkontekstowych prowadziłaby do rozstrzygalności własności Posta.

Dla drugiego przykładu przyjmijmy jako alfabety Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle A_{2}=\left\{ a,b\right\} ,\: A_{3}=\left\{ a,b,c\right\} } oraz określmy język

L={v1cv2cv2cv1:v1,v2A2*}.

Ustalmy listę Posta Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle \left( u_{1},w_{1}\right) \: \left( u_{2},w_{2}\right) \: \ldots \left( u_{n},w_{n}\right) } nad alfabetem A2 , gdzie ui,wiA2+ . Wprowadzamy teraz języki Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle L_{u},\: L_{w}\: L_{PP} } nad alfabetem A3 przyjmując:

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned L_{u} &= \left\{ ba^{i_{k}}b\ldots ba^{i_{1}}cu_{i_{1}}\ldots u_{i_{k}}\, :\, k\geqslant 1,1\leqslant i_{j}\leqslant n\right\} \\ L_{w} &= \left\{ ba^{i_{k}}b\ldots ba^{i_{1}}cw_{i_{1}}\ldots w_{i_{k}}\, :\, k\geqslant 1,1\leqslant i_{j}\leqslant n\right\} \endaligned}

oraz definiujemy język

LPP=LucLw.

Określone powyżej języki nad alfabetem A3 mają własności konieczne do zastosowania lematu, który przytoczymy bez dowodu.

Lemat 5.1

Języki Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle L,\: L_{PP},\: A_{3}^{*}\setminus L,\: A_{3}^{*}\setminus L_{PP} } są bezkontekstowe.

Dla języków L i LPP uzasadnienie ich bezkontekstowości jest proste poprzezkonstrukcję odpowiednich gramatyk. Aby uzyskać bezkontekstowość ich uzupełnień, należy podzielić rozważane języki na rozłączne podzbiory i konstruować gramatyki bezkontekstowe dla tych wyróżnionych podzbiorów, a w końcu wykorzystać fakt, że suma języków bezkontekstowych jest językiem bezkontekstowym.

Zauważmy teraz, że istnienie rozwiązania problemu Posta nad alfabetem A3 jest równoważne temu, że LPPL .

Jeśli bowiem LPPLbaikbai1cui1uikcwi1wikcai1baikb , gdzie k1,1ijn , to oczywiście ui1uik=wi1wik . Jeśli ciąg i1,,ik jest rozwiązaniem problemu Posta, to (i1,,ik)(i1,,ik) też. Zatem jeśli LPPL , to język LPPL jest nieskończony.

Wobec nierozstrzygalności problemu Posta wnioskujemy, że nierozstrzygalny jest problem pustości i problem nieskończoności przecięcia L1L2 w klasie języków bezkontekstowych.