Automaty stosowe

Wstęp

W tym wykładzie poznamy model obliczeń odpowiadający gramatykom bezkontekstowym (tak jak automaty skończone odpowiadały wzorcom). Ten model, to automaty stosowe. Automaty stosowe możemy sobie wyobrazić jako automaty skończone wyposażone w dodatkową nieograniczoną pamięć, ale działającą na zasadzie stosu.
\includegraphics{rys-12-a}
To znaczy, na wierzch stosu można zawsze włożyć nowy element. Jeśli stos nie jest pusty, to można zawsze zobaczyć jaki element jest na wierzchu i ew. zdjąć ten element. Nie można natomiast oglądać ani wyjmować elementów z wnętrza stosu.

Zobaczymy na przykładach jak można konstruować automaty stosowe i pokażemy, że faktycznie ich siła wyrazu jest taka sama jak gramatyk bezkontekstowych.

Pod względem siły wyrazu automaty stosowe są też równoważne imperatywnym językom programowania bez plików (pomocniczych) dynamicznych struktur danych, wskaźników i parametrów proceduralnych. Przy tych ograniczeniach dane globalne w programie są stałego rozmiaru, a danych dynamicznych nie ma. Można korzystać z rekurencji i nie ma ograniczenia na rozmiar stosu, jednak wielkość danych związanych z każdym poziomem rekurencji jest ograniczona przez stałą i nie ma możliwości wyciągania danych z głębi stosu. Jak zobaczymy dokładnie odpowiada to automatom stosowym.

Automaty stosowe

Automat stosowy, podobnie jak automat skończony, ma skończony zbiór stanów i stan początkowy. Dodatkowo jest on wyposażony w stos, na który może wkładać elementy, podglądać element znajdujący się na wierzchu i zdejmować elementy. Przejścia automatu stosowego są trochę bardziej skomplikowane niż przejścia w automacie skończonym, gdyż oprócz wczytywania znaków z wejścia i zmiany stanów obejmują również operacje na stosie. Automat taki może być niedeterministyczny i może zawierać $\varepsilon$-przejścia, tzn. wykonaniu przejścia nie musi towarzyszyć wczytanie znaku z wejścia. Natomiast przedstawione tutaj automaty stosowe będą pozbawione stanów akceptujących -- automat będzie sygnalizował akceptację wejścia opróżniając stos2.

Chcąc opisać działanie automatów stosowych musimy wprowadzić pojęcie konfiguracji. Konfiguracja będzie obejmować stan automatu (ze skończonego zbioru stanów), zawartość stosu i pozostałe do wczytania wejście. Automat stosowy w jednym kroku obliczeń wykonuje następujące czynności:

  1. Podgląda znak czekający na wczytanie na wejściu.
  2. Podgląda element na wierzchołku stosu.
  3. Na podstawie tych informacji wybiera jedno z przejść do wykonania.
  4. Jeśli to nie jest $\varepsilon$-przejście, to wczytywany jest jeden znak z wejścia.
  5. Zdejmowany jest element z wierzchołku stosu.
  6. Pewna liczba określonych elementów może być włożona na stos.
  7. Zgodnie z przejściem zmieniany jest stan.
Może wydawać się nienaturalne, że w każdym kroku zdejmujemy element z wierzchołka stosu. Jednak dzięki temu, opisany powyżej krok automatu jest na tyle elastyczny, że może zdejmować elementy ze stosu, wkładać nowe, podmieniać element na wierzchołku lub nie zmieniać stosu. Jeżeli chcemy zdjąć element z wierzchołku stosu, to wystarczy, że nie będziemy nic wkładać. Jeżeli chcemy podmienić element na wierzchołku, to wystarczy, że włożymy jeden element, który zastąpi element zdjęty z wierzchołka. Jeżeli chcemy włożyć elementy na stos, to wkładamy na stos właśnie zdjęty element, wraz z elementami, które mają być umieszczone na stosie. Jeśli nie chcemy zmieniać zawartości stosu, to po prostu wkładamy dokładnie ten sam element, który właśnie został zdjęty. Możemy włożyć na stos kilka elementów w jednym kroku, ale niestety nie możemy w jednym kroku zdjąć więcej niż jeden element.

Zauważmy, że powyższy schemat postępowania wymaga, żeby stos nie był pusty. Inaczej nie ma czego podglądać ani zdejmować ze stosu. Dlatego też, w momencie uruchomienia automatu stos nie jest pusty. Zawiera jeden wyróżniony element, który będziemy nazywać ,,pinezką'' i oznaczać przez $\perp$. Jak tylko stos zostaje opróżniony, automat zatrzymuje się i dalsze jego działanie nie jest możliwe. Jeżeli automat zatrzymuje się z pustym stosem po wczytaniu całego słowa z wejścia, to przyjmujemy, że słowo to zostało zaakceptowane.

Zanim formalnie zdefiniujemy automaty stosowe i akceptowane przez nie języki, zobaczmy prosty nieformalny przykład:

Przykład

Zbudujemy automat akceptujący słowa postaci anbn, dla $n \ge 0$. Automat taki będzie miał dwa stany, s i q, przy czym s będzie stanem początkowym. Na stosie będziemy trzymać dwa rodzaje elementów: $\perp$ i A. Będąc w stanie s automat ma dwa przejścia do wyboru: może wczytać z wejścia znak a i włożyć na stos A, lub nic nie wczytywać, ani nie zmieniać zawartości stosu i przejść do stanu q. W stanie q automat ma również dwa przejścia do wyboru: jeżeli na wejściu czeka na wczytanie znak b i na wierzchołku stosu jest A, to może wczytać z wejścia b i zdjąć ze stosu A. Jeżeli natomiast na wierzchołku stosu jest $\perp$, to automat może zdjąć ze stosu $\perp$ i tym samym zakończyć działanie.

Jedyna możliwość, żeby zaakceptować słowo wygląda tak: Automat wczytuje sekwencję an i umieszcza na stosie An. Następnie przechodzi do stanu q i wczytuje znaki b zdejmując ze stosu A. Jednych i drugich musi być tyle samo, czyli wczytana zostaje sekwencja bn. Po wczytaniu tej sekwencji odsłania się $\perp$ i jest zdejmowana ze stosu. Jeżeli automat ma zaakceptować słowo, to musi ono być w tym momencie całe wczytane, czyli było to słowo anbn.

Poniższy diagram przedstawia obliczenie akceptujące słowo aaabbb. Widać na nim kolejne zawartości stosu i stany, w których jest automat.

 
 

Definicja

Automat stosowy to dowolna taka piątka $M = \angles{Q, \Sigma, \Gamma, \delta, s}$, w której:

Notacja:

W przypadku automatów stosowych, przedstawienie przejść w postaci diagramu nie jest czytelne. Nie będziemy jednak pisać:

\begin{displaymath}
\delta = \{
((s, a, A), (s, AA)),
((s, a, \perp), (s, A \perp)), \dots
\}
\end{displaymath}

jakby wynikało z definicji, gdyż byłoby to zupełnie nieczytelne. Zamiast tego będziemy przedstawiać przejścia jako reguły postaci:

\begin{eqnarray*}
(s, A) & \stackrel{a}{\to} & (s, AA)\\
(, \perp) & \stackrel{a}{\to} & (s, A \perp)
\end{eqnarray*}


lub w postaci skrótów:

\begin{displaymath}
(s, x) \stackrel{a}{\to} (s, Ax)
\mbox{ dla }
x = A, \perp
\end{displaymath}

Konfiguracje automatów stosowych definiujemy następująco:

Definicja

Niech $M = \angles{Q, \Sigma, \Gamma, \delta, s}$ będzie ustalonym automatem stosowym. Konfiguracja takiego automatu stosowego, to dowolna trójka:

\begin{displaymath}
\angles{q, \alpha, \beta} \in Q \times \Sigma^* \times \Gamma^*
\end{displaymath}

gdzie q reprezentuje aktualny stan, $\alpha$ pozostałe do wczytania wejście, a $\beta$ zawartość stosu (czytaną od wierzchołka w głąb).

Konfiguracja początkowa dla słowa x, to $\angles{s, x, \perp}$.

Jeden krok obliczeń automatu stosowego opisujemy relacją $\to$ określoną na konfiguracjach.

Definicja

Niech $M = \angles{Q, \Sigma, \Gamma, \delta, s}$ będzie ustalonym automatem stosowym. Relacja przejścia między konfiguracjami tego automatu $\to$ to najmniejsza relacja spełniająca następujące warunki:

Przez $\to^*$ będziemy oznaczać zwrotnio-przechodnie domknięcie relacji $\to$.

Inaczej mówiąc, $(p, A) \stackrel{a}{\to} (q, \gamma)$ oznacza, że możemy będąc w stanie p i mając na wierzchołku stosu A przejść do stanu q wczytując z wejścia a i zastępując na stosie A przez $\gamma$. Podobnie $(p, A) \stackrel{\varepsilon}{\to} (q, \gamma)$ oznacza, że możemy będąc w stanie p i mając na wierzchołku stosu A przejść do stanu q nie wczytując nic z wejścia i zastępując na stosie A przez $\gamma$.

Relacja $\to$ opisuje pojedyncze kroki obliczenia, a relacja $\to^*$ dowolnie długie obliczenia.

Definicja

Niech $M = \angles{Q, \Sigma, \Gamma, \delta, s}$ będzie ustalonym automatem stosowym. Język akceptowany przez automat stosowy M jest określony następująco:

\begin{displaymath}
L(M) = \{x \in \Sigma^* : \exists_{q \in Q}\
\angles{s, x, \perp} \to^* \angles{q, \varepsilon, \varepsilon}\}
\end{displaymath}

Inaczej mówiąc, automat stosowy akceptuje takie słowa x, dla których istnieją obliczenia prowadzące od konfiguracji początkowej (dla słowa x) do konfiguracji, w której całe słowo zostało wczytane, a stos opróżniony. Pamiętajmy, że automat stosowy może być niedeterministyczny, a więc wystarczy żeby istniało jedno obliczenie akceptujące, żeby słowo było akceptowane przez automat.

Przykład

Skonstruujemy automat akceptujący słowa zawierające tyle samo liter a, co b. Automat ten będzie używać stosu jako licznika. Z każdym wczytanym a licznik zwiększa się o 1, a z każdym wczytanym b zmniejsza się o 1. Dodatnie wartości licznika reprezentujemy jako $\perp$ i stos A, a ujemne, jako $\perp$ i stos B. Dodatkowo, w momentach gdy odsłonięta jest pinezka, automat może ją zdjąć ze stosu. Automat akceptuje tylko takie słowa x, po których wczytaniu licznik jest wyzerowany, czyli #a(x) = #b(x).

Automat ten ma jeden stan s i działa w następujący sposób:

\begin{displaymath}
\begin{array}[t]{rcl}
(s, \perp) &\stackrel{a}\to& (s, A\p...
...) \\
(s, A) &\stackrel{b}\to& (s, \varepsilon)
\end{array} \end{displaymath}

Przykładowe obliczenie dla aabbba:
 
 
Oczywiście taki automat może usunąć pinezkę gdy jeszcze nie całe słowo jest wczytane. Takie obliczenie nie doprowadzi do zaakceptowania słowa. Pamiętajmy jednak, że automaty stosowe są niedeterministyczne i wystarczy, aby istniało choć jedno obliczenie akceptujące dane słowo, aby należało ono do języka akceptowanego przez automat stosowy.

Przykład

Skonstruujemy automat akceptujący wyrażenia nawiasowe zbudowane z kwadratowych nawiasów [ i ]. Automat ten działa podobnie jak poprzedni, ale licznik może przyjmować tylko dodatnie wartości. Na stosie trzymamy pinezkę i tyle nawiasów zamykających ile wynosi wartość licznika. Z wczytaniem każdego nawiasu otwierającego licznik jest zwiększany o 1, a z wczytaniem każdego nawiasu zamykającego zmniejszany o 1.

\begin{eqnarray*}
(s, x) &\stackrel{[}\to& (s, ]x)
\mbox{\ dla\ } x = ],\perp...
...n) \\
(s, \perp) &\stackrel{\varepsilon}\to& (s, \varepsilon)
\end{eqnarray*}


Przykładowe obliczenie dla [[][[]]]:
 
 

Przykład

Automat akceptujący palindromy nad alfabetem {a,b}. Automat ten musi niedeterministycznie zgadnąć gdzie jest środek palindromu i czy jest on parzystej, czy nieparzystej długości.

Nasz automat będzie miał dwa stany: s i p. Na stosie będziemy przechowywać pinezkę i znaki alfabetu wejściowego. W pierwszej fazie (stan s) automat zapamiętuje pierwszą połowę słowa na stosie. W drugiej fazie (stan p) zdejmuje znaki ze stosu, sprawdzając, czy są one takie same jak wczytywane znaki. Jeżeli słowo jest nieparzystej długości, to przechodząc z pierwszej fazy do drugiej wczytujemy środkowy znak nie zmieniając zawartości stosu. Jeżeli zaś jest parzystej długości, to przechodząc do drugiej fazy nic nie wczytujemy.

\begin{displaymath}
\begin{array}[t]{rclll}
(s, x) &\stackrel{y}\to& (s, yx) &...
...rp) &\stackrel{\varepsilon}\to& (s, \varepsilon)
\end{array} \end{displaymath}

Przykładowe obliczenia akceptujące słowa abba i baabaab:
 
 
 
 

Przykład

W poprzednim wykładzie pokazaliśmy, że język $\{ww : w \in \{a,b\}^*\}$ nie jest bezkontekstowy. Za chwilę pokażemy, że automaty stosowe akceptują dokładnie języki bezkontekstowe. Teraz jednak skonstruujemy automat akceptujący język $\overline{\{ww: w \in \{a, b\}^* \}}$, pokazując tym samym, że jest on bezkontekstowy.

Słowo $x = a_1 a_2 \dots a_k$ należy do języka $\overline{\{ww: w \in \{a, b\}^* \}}$ w dwóch przypadkach. Albo jest nieparzystej długości. Albo jest parzystej długości i istnieje taka pozycja i ( $1 \le i \le \frac{k}{2}$) w pierwszej połowie tego słowa, że na i-tej pozycji w słowie x jest inny znak niż na odpowiadającej jej pozycji w drugiej połowie słowa, $a_i \neq a_{i+\frac{k}{2}}$.

Nasz automat będzie miał szereg stanów, przy czym stanem początkowym będzie s. Na stosie będziemy trzymać dwa rodzaje symboli: $\perp$ i $\circ$. Automat zgaduje najpierw, czy słowo jest parzystej (stan p), czy nieparzystej (stan n) długości. Jeśli nieparzystej, to tylko to sprawdza, że faktycznie tak jest.

\begin{eqnarray*}
(s, \perp) &\stackrel{\varepsilon}\to& (n, \perp)\\
(s, \pe...
... b \\
(m, \perp) &\stackrel{\varepsilon}\to& (m, \varepsilon)
\end{eqnarray*}


Jeśli słowo jest parzystej, to automat stosowy musi zgadnąć niedeterministycznie na jakiej pozycji i istnieje niezgodność między pierwszą i drugą połową słowa, a następnie sprawdzić, że faktycznie tak jest. Inaczej mówiąc, słowo x musi być postaci uavbw lub ubvaw, przy czym |v| = |u|+|w|. To czy w pierwszej połowie na i-tej pozycji jest a czy b można zapamiętać w stanie automatu. Problemem jest natomiast odliczenie odpowiadających sobie pozycji w obu połówkach słowa. Zauważmy jednak, że automat nie musi wiedzieć gdzie jest połowa długości słowa. Wystarczy, że będzie zachodzić |v| = |u|+|w|.

Nasz automat najpierw wczytuje słowo u, wkładając na stos |u| znaków $\circ$.

\begin{eqnarray*}
(p, i) &\stackrel{j}\to& (p, \circ i)
\mbox{ dla } i = \perp,\circ,\ j = a,b
\end{eqnarray*}


Następnie niedeterministycznie zgaduje kiedy jest koniec u i wczytuje jeden znak, zapamiętując go na stanie.

\begin{eqnarray*}
(p, i) &\stackrel{j}\to& (q_j, i)
\mbox{ dla } i = \perp,\circ,\ j = a,b
\end{eqnarray*}


Następnie nasz automat wczytuje tyle znaków z wejścia, ile $\circ$ jest na stosie. W ten sposób wczytujemy prefiks v długości |u|. Po zdjęciu ze stosu wszystkich $\circ$ przechodzimy do kolejnej fazy.

\begin{eqnarray*}
(q_i, \circ) &\stackrel{j}\to& (q_i, \varepsilon)
\mbox{ dla...
...&\stackrel{\varepsilon}\to& (r_i, \perp)
\mbox{ dla } i = a,b
\end{eqnarray*}


Następnie nasz automat powinien wczytać z wejścia |w| = |v| - |u| znaków słowa v. Liczbę tę zgaduje niedeterministycznie, wkładając równocześnie |w| znaków $\circ$ na stos. W momencie gdy automat zgaduje niedeterministycznie, że całe słowo v zostało wczytane, wczytuje jeden znak z wejścia sprawdzając równocześnie, że jest on różny od znaku zapamiętanego na stanie.

\begin{eqnarray*}
(r_i, j) &\stackrel{l}\to& (r_i, \circ j)
\mbox{ dla } i = a...
...j)
\mbox{ dla } i = a,b,\ j = \perp,\circ,\ l = a,b,\ l \neq i
\end{eqnarray*}


Pozostało jeszcze do wczytania w, przy czym na stosie powinno być |w| znaków $\circ$. Po wczytaniu słowa w powinna odsłonić się pinezka, którą zdejmujemy.

\begin{eqnarray*}
(t, \circ) &\stackrel{i}\to& (t, \varepsilon)
\mbox{ dla } i...
...b \\
(t, \perp) &\stackrel{\varepsilon}\to& (t, \varepsilon)
\end{eqnarray*}


Oto przykładowe obliczenie akceptujące słowo abbaabaa.
 
 
Skonstruowany automat jest wysoce niedeterministyczny. Jeśli gdziekolwiek cokolwiek zostanie źle zgadnięte, to obliczenie nie doprowadzi do zaakceptowania słowa. Pamiętajmy jednak, iż wystarczy, że można tak zgadnąć, aby obliczenie było akceptujące, aby słowo było akceptowane przez automat.

Równoważność gramatyk bezkontekstowych i automatów stosowych

Pokażemy teraz, że siła wyrazu automatów stosowych jest dokładanie taka sama, jak gramatyk bezkontekstowych -- tzn. akceptują one dokładnie języki bezkontekstowe.


\begin{theorem}
Niech $A$\ będzie językiem nad alfabetem $\Sigma$.
Następując...
...automat stosowy $M$\ akceptujący $A$,
$A = L(M)$.
\end{itemize} \end{theorem}

Przedstawimy tu jedynie szkic dowodu -- oprzemy sie na trzech faktach. Pokażemy jak dla danej gramatyki bezkontekstowej skonstruować równoważny jej automat stosowy (z jednym stanem). Następnie pokażemy, że konstrukcję tę można odwrócić, tzn. dla danego automatu stosowego z jednym stanem można skonstruować równoważną mu gramatykę bezkontekstową. Na koniec pokażemy, jak zredukować liczbę stanów w automacie stosowym do jednego.

Automat stosowy równoważny danej gramatyce bezkontekstowej

Niech G będzie daną gramatyką bezkontekstową $G=\angles{N, \Sigma, P, S}$. Zbudujemy równoważny jej automat stosowy $M = \angles{Q, \Sigma, \Gamma, \delta, s}$. Automat ten będzie miał tylko jeden stan Q = {s}. Na stosie będzie przechowywał symbole terminalne i nieterminalne. $\Gamma = N \setsum \Sigma$. Przyjmujemy, że $S = \perp$. Dla każdej produkcji $X \to \alpha$ mamy przejście:

\begin{eqnarray*}
(s, X) &\stackrel{\varepsilon}\to& (s, \alpha)
\end{eqnarray*}


Dodatkowo, dla każdego $a \in \Sigma$ mamy przejście:

\begin{eqnarray*}
(s, a) &\stackrel{a}\to& (s, \varepsilon)
\end{eqnarray*}


Nasz automat będzie działa w następujący sposób: Jeśli na wierzchołku stosu jest terminal, to oczekujemy, że czeka on na wejściu, wczytujemy go i zdejmujemy ze stosu. Jeśli na wierzchołku stosu jest nieterminal, to należy wczytać pewne słowo, które można z niego wyprowadzić. Najpierw jednak należy zdecydować, jaka produkcja rozpoczyna wyprowadzenie takiego słowa. Zdejmujemy więc dany nieterminal ze stosu i wkładamy na stos prawą stronę wybranej produkcji dla tego nieterminala. Akceptujemy pustym stosem, gdy całe wyprowadzone słowo zostało wczytane.

Można pokazać (przez indukcję po długości wyprowadzenia), że M realizuje tzw. lewostronne wyprowadzenia, to znaczy takie, w których zawsze jest rozwijany skrajnie lewy nieterminal. Jeśli wczytywane słowo to x, x = yz, to konfiguracji $\angles{s, z, \alpha}$ odpowiada w wyprowadzeniu słowo $y\alpha$. Konfiguracja początkowa $\angles{s, x, S}$ odpowiada aksjomatowi S, a konfiguracja akceptująca $(s, \varepsilon, \varepsilon)$ odpowiada w wyprowadzeniu słowu x. Stąd L(M) = L(G).

Przykład

Weźmy, przedstawioną wcześniej, gramatykę bezkontekstową generującą wyrażenia nawiasowe:

\begin{displaymath}
S \to [S] \;\vert\;SS \;\vert\;\varepsilon
\end{displaymath}

Stosując przedstawioną powyżej metodę otrzymujemy następujący automat stosowy:

\begin{eqnarray*}
(s, S) &\stackrel{\varepsilon}\to& (s, [S])\\
(s, S) &\stac...
... (s, \varepsilon)\\
(s, ]) &\stackrel{]}\to& (s, \varepsilon)
\end{eqnarray*}


Jest to inny automat niż skonstruowany przez nas wcześniej automat stosowy akceptujący wyrażenia nawiasowe. Oto jego przykładowe obliczenie akceptujące [[][[]]].
 
 

Gramatyka bezkontekstowa równoważna danemu automatowi stosowemu z jednym stanem

Przedstawioną w poprzednim punkcie konstrukcję można odwrócić. Załóżmy, że mamy dany automat stosowy z jednym stanem $M = \angles{\{s\}, \Sigma, \Gamma, \delta, s, \perp}$. Bez zmniejszenia ogólności możemy założyć, że $\Gamma \setint \Sigma = \emptyset$. Nasza gramatyka ma postać $G = \angles{\Gamma, \Sigma, P, \perp}$, przy czym jeśli $\delta$ zawiera przejście $(s, A) \stackrel{a}{\to} (s, \gamma)$ (dla $a \in \Sigma \setsum \{\varepsilon\}$), to w P mamy produkcję $A \to a\gamma$.

Odpowiedniość jest taka jak poprzednio. Jeśli wczytywane słowo to x, x = yz, to konfiguracji $\angles{s, z, \alpha}$ odpowiada w wyprowadzenie lewostronne $\perp \to^* y\alpha$. Konfiguracja początkowa $\angles{s, x, \perp}$ odpowiada aksjomatowi $\perp$, a konfiguracja akceptująca $(s, \varepsilon, \varepsilon)$ odpowiada w wyprowadzeniu $\perp \to^* x$. Stąd L(M) = L(G).

Przykład

Weźmy, przedstawiony powyżej, automat stosowy akceptujący słowa zawierające tyle samo liter a, co b.

\begin{displaymath}
\begin{array}[t]{rcl}
(s, \perp) &\stackrel{a}\to& (s, A\p...
...) \\
(s, A) &\stackrel{b}\to& (s, \varepsilon)
\end{array} \end{displaymath}

Stosując przedstawioną powyżej metodę, uzyskujemy następującą równoważną mu gramatykę (dla czytelności $\perp$ zastąpiono przez S):

\begin{eqnarray*}
S &\to& aAS \;\vert\;bBS \;\vert\;\varepsilon \\
A &\to& b \;\vert\;aAA \\
B &\to& a \;\vert\;bBB
\end{eqnarray*}


Oto wyprowadzenie w tej gramatyce słowa aabbba:

\begin{displaymath}
S \to aAS \to aaAAS \to aabAS \to aabbS \to aabbbBS \to
aabbbaS \to aabbba
\end{displaymath}

Redukcja zbioru stanów do jednego

Pozostało nam pokazać, że dla każdego automatu stosowego $M = \angles{Q, \Sigma, \Gamma, \delta, s, \perp}$ istnieje równoważny mu automat z jednym stanem $M' = \angles{\{s\}, \Sigma, \Gamma', \delta' s}$. Bez zmniejszenia ogólności możemy założyć, że automat M w momencie opróżnienia stosu będzie zawsze w jednym stanie q.

Na stosie automaty M' będziemy trzymać trójki postaci $\angles{p,a,r} \in \Gamma' = Q \times \Gamma \times Q$. Jeżeli na wierzchołku stosu M' jest trójka $\angles{p, A, r}$, to odpowiada to sytuacji, gdy na wierzchołku stosu w M jest A, M jest w stanie p i po zdjęciu symbolu A ze stosu przejdzie do stanu r. Stany pamiętane na stosie M' muszą się ,,zazębiać'', tzn. pod trójką $\angles{p, A, r}$ musi być trójka postaci $\angles{r, B, t}$ (dla pewnych $B \in \Gamma$ i $t \in Q$) itd.

Automat M' na początku ma na stosie trójkę $\angles{s, \perp, q}$ i akceptuje słowo x wtw., gdy M zaczynając w stanie s i z symbolem $\perp$ na stosie, wczytuje x i kończy w stanie q z pustym stosem.

Relacja $\delta'$ jest określona następująco:

Automat ten jest wysoce niedeterministyczny. Wkładając trójki na stos musimy z góry przewidzieć w jakim stanie będzie automat M w momencie zdjęcia odpowiedniej trójki w M'. Oczywiście zgadnięcie odpowiednich stanów jest możliwe, a więc M' będzie mógł zasymulować każde obliczenie M (i tylko obliczenia M).

Podsumowanie

W tym wykładzie poznaliśmy automaty stosowe. Zobaczyliśmy na przykładach jak je można konstruować. Dowiedzieliśmy się też, że są one równoważne gramatykom bezkontekstowym.

Skorowidz

Praca domowa

  1. Skonstruuj automat stosowy akceptujący wyrażenia nawiasowe zawierające trzy rodzaje nawiasów: ()[]{},
  2. Przekształć gramatykę generującą palindromy (nad alfabetem {a,b}), na automat stosowy (stosując konstrukcję podaną w tym wykładzie).
  3. Przekształć automat stosowy akceptujący wyrażenia nawiasowe:

    \begin{eqnarray*}
(s, x) &\stackrel{[}\to& (s, ]x)
\mbox{\ dla\ } x = ],\perp...
...n) \\
(s, \perp) &\stackrel{\varepsilon}\to& (s, \varepsilon)
\end{eqnarray*}


    na równoważną mu gramatykę bezkontekstową (stosując konstrukcję podaną w tym wykładzie).

Ćwiczenia

Skonstruuj automaty stosowe akceptujące poniższe języki. Czy potrafisz skonstruować takie automaty, które mają tylko jeden stan? Jeśli tak, to przekształć je na równoważne im gramatyki bezkontekstowe.
  1. wyrażenia nawiasowe zawierające trzy rodzaje nawiasów: ()[]{}; przy tym: nawiasy okrągłe mogą otaczać tylko nawiasy okrągłe, nawiasy kwadratowe mogą otaczać nawiasy kwadratowe lub okrągłe, a nawiasy wąsate mogą otaczać nawiasy wąsate lub kwadratowe,
  2. palindromy nad alfabetem {a,b,c},
  3. {aib2i},
  4. {aibjajbi},
  5. {w : #a(w) >= 2#b(w)},
  6. $\{a^ib^jc^k : i \neq j \orelse j \neq k \}$,
  7. wyrażenia arytmetyczne w notacji polskiej (dla uproszczenia liczby mogą być tylko jednocyfrowe),
  8. wyrażenia arytmetyczne w odwrotnej notacji polskiej (dla uproszczenia liczby mogą być tylko jednocyfrowe).