Suma języków regularnych
Kapitoly: Domkniętość języków regularnych, Suma, Przecięcie, Różnica, Dopełnienie, Konkatenacja, Domknięcie Kleene’ego
Weźmy dwa języki regularne L1, L2. Udowodnimy, że ich suma L = L1 ∪ L2 też jest językiem regularnym.
Konstrukcja za pomocą automatu deterministycznego
Główna idea
Mamy dwa języki regularne L1 i L2 i chcemy udowodnić, że ich suma L1 ∪ L2 jest znowu językiem regularnym. Ponieważ L1 i L2 są językami regularnymi, istnieją automaty skończone A1 i A2, które akceptują języki L1 i L2, czyli zachodzi L(A1) = L1 i L(A2) = L2. Dalej zbudujemy automat skończony A, który będzie akceptował język L1 ∪ L2, i w ten sposób udowodnimy, że język L1 ∪ L2 jest regularny.
Jak to zrobimy? Mamy pod ręką automaty skończone A1 i A2, które akceptują poszczególne języki. Możemy powiedzieć, że słowo w należy do języka L1 ∪ L2 wtedy i tylko wtedy, gdy akceptuje je co najmniej jeden z automatów A1 i A2.
Automat A mógłby działać tak, że dla wejścia w będzie symulował obliczenie automatu A1 dla wejścia w. Jeśli A1 zaakceptuje słowo w, to słowo w zaakceptuje też A. Jeśli A1 odrzuci słowo w, to A spróbuje jeszcze zasymulować obliczenie A2 dla wejścia w. Jeśli A2 zaakceptuje słowo w, to A też zaakceptuje słowo w. W przeciwnym razie je odrzuci.
Zostaje nam sformalizować, co to znaczy, że automat A „symuluje” obliczenie innego automatu.
Formalizacja
Mamy dwa języki regularne L1 i L2, które są akceptowane przez automaty skończone
\begin{eqnarray} A_1 &=& \left<Q_1, \Sigma_1, \delta_1, q_1, F_1\right>\\ A_2 &=& \left<Q_2, \Sigma_2, \delta_2, q_2, F_2\right>. \end{eqnarray}
Zbudujemy automat skończony $A=\left<Q, \Sigma, \delta, q, F\right>$, który będzie akceptował język L = L1∪ L2. Wykorzystamy ideę symulowania dwóch automatów A1, A2. Wyobraźmy sobie, że na wejściu mamy słowo w = w1w2… wn i teraz będziemy jednocześnie symulować przebieg automatów A1 i A2 dla słowa w. Konfiguracja początkowa automatu A1 to <q1, w1w2… wn>, konfiguracja początkowa A2 to <q2, w1w2… wn>. W każdym automacie wykonamy teraz krok obliczenia i w ten sposób dostaniemy się do konfiguracji <δ1(q1, w1), w2… wn> i <δ2(q2, w1), w2… wn>.
Widzimy, że te konfiguracje różnią się tylko pierwszą składową, drugą – nieprzeczytaną część słowa – mają zawsze taką samą. Podczas symulacji nie musimy więc przechowywać dwóch konfiguracji dwóch automatów, wystarczy nam jedna konfiguracja postaci <<qi, qj>, wl… wn>, gdzie qi ∈ Q1 i qj ∈ Q2. Innymi słowy, budowany automat A będzie miał konfigurację początkową <<q1, q2>, w>. Pierwsza część pary <q1, q2> przedstawia stan, w którym aktualnie znajduje się automat A1, a druga składowa przedstawia aktualny stan automatu A2.
Możemy więc napisać, że budowany automat A będzie miał zbiór stanów równy Q = Q1 × Q2. Będzie to iloczyn kartezjański zbiorów stanów obu poprzednich automatów. Dalej idea jest taka, że automat A będzie miał stan początkowy <q1, q2>, a jeśli automat A1 przejdzie dla symbolu w1 do stanu qi, a automat A2 przejdzie dla symbolu w1 do stanu qj, to automat A przejdzie dla symbolu w1 do stanu <qi, qj>.
Funkcję przejścia δ zapiszemy tak (tutaj już zakładamy, że jesteśmy aktualnie w stanach qi i qj):
$$ \delta\left(\left<q_i, q_j\right>,w\right) = \left<\delta_1(q_i,w), \delta_2(q_j,w)\right> $$
Zostają już tylko drobiazgi. Dla alfabetu zachodzi $\Sigma = \Sigma_1 \cup \Sigma_2$. Stan początkowy jest równy q = <q1, q2>. A stanami akceptującymi są wszystkie pary <qi, qj> takie, że qi ∈ F1 albo qj ∈ F2.
Ilustracja konstrukcji
Weźmy dwa automaty. Pierwszy to automat A1, który akceptuje wszystkie słowa (łącznie ze słowem pustym), w których przeplatają się zera i jedynki, czyli słowa postaci 01, 0101, 010101, …
Drugi automat A2 akceptuje słowa, które zawierają co najmniej jedno zero:
Sumą tych języków są słowa, które albo zawierają zero, albo są postaci 01, 0101, … Teraz zbudujemy automat skończony $A=\left<Q, \Sigma, \delta, q, F\right>$, który będzie akceptował właśnie tę sumę języków. Najpierw pokażemy, jak będą wyglądać stany tego nowego automatu A. Będzie to iloczyn kartezjański zbiorów stanów pierwszego i drugiego automatu:
$$ Q = Q_1 \times Q_2 = \left\{\left<q_0, p_0\right>, \left<q_0, p_1\right>, \left<q_1, p_0\right>, \left<q_1, p_1\right>, \left<q_2, p_0\right>, \left<q_2, p_1\right>\right\} $$
Tak wygląda sześć stanów automatu A, który akceptuje sumę języków L(A1) ∪ L(A2). Na diagramie wyglądałyby tak:
Nie przestrasz się, że mamy tu stany złożone z par stanów – służy to tylko do lepszej orientacji w tym, co się właściwie w automacie dzieje. Stany mogłyby się spokojnie nazywać klasycznie q0, …, q5. Stany akceptujące to te stany, które zawierają stan q0 albo p1, czyli stany akceptujące pierwotnych automatów. Stan początkowy to <q0, p0>.
Teraz musimy znaleźć wszystkie przejścia. Zapiszemy sobie taką tabelę:
$$ \begin{array}{c|c|c} &0&1\\\hline \left<q_0, p_0\right>\\ \left<q_0, p_1\right>\\ \left<q_1, p_0\right>\\ \left<q_1, p_1\right>\\ \left<q_2, p_0\right>\\ \left<q_2, p_1\right>\\ \end{array} $$
I stopniowo będziemy ją uzupełniać. Najpierw sprawdzimy, dokąd prowadzi przejście ze stanu <q0, p0> dla wejścia 0. Sprawdzimy, dokąd prowadzi przejście ze stanu q0 dla wejścia 0 w automacie A1: prowadzi do stanu q1. W automacie A2 przejście z p0 dla zera prowadzi do stanu p1. Do tabeli wpiszemy więc <q1, p1>:
$$ \begin{array}{c|c|c} &0&1\\\hline \left<q_0, p_0\right>&\left<q_1, p_1\right>\\ \left<q_0, p_1\right>\\ \left<q_1, p_0\right>\\ \left<q_1, p_1\right>\\ \left<q_2, p_0\right>\\ \left<q_2, p_1\right>\\ \end{array} $$
Dla wejścia 1 dostaniemy: dla automatu A1 mamy δ1(q0, 1) = q2, a dla automatu A2 mamy δ2(p0, 1) = p0. Otrzymujemy więc stan <q2, p0>.
$$ \begin{array}{c|c|c} &0&1\\\hline \left<q_0, p_0\right>&\left<q_1, p_1\right>&\left<q_2, p_0\right>\\ \left<q_0, p_1\right>\\ \left<q_1, p_0\right>\\ \left<q_1, p_1\right>\\ \left<q_2, p_0\right>\\ \left<q_2, p_1\right>\\ \end{array} $$
Dopiszemy resztę tabeli:
$$ \begin{array}{c|c|c} &0&1\\\hline \left<q_0, p_0\right>&\left<q_1, p_1\right>&\left<q_2, p_0\right>\\ \left<q_0, p_1\right>&\left<q_1, p_1\right>&\left<q_2, p_1\right>\\ \left<q_1, p_0\right>&\left<q_2, p_1\right>&\left<q_0, p_0\right>\\ \left<q_1, p_1\right>&\left<q_2, p_1\right>&\left<q_0, p_1\right>\\ \left<q_2, p_0\right>&\left<q_2,p_1\right>&\left<q_2, p_0\right>\\ \left<q_2, p_1\right>&\left<q_2,p_1\right>&\left<q_2,p_1\right>\\ \end{array} $$
I według tej tabeli już tylko dorysujemy resztę diagramu.
Możemy sprawdzić, że automat działa, jak powinien. Spróbujemy zaakceptować słowo 0100. Automat po kolei przejdzie przez stany
$$ \left<q_0, p_0\right>, \left<q_1, p_1\right>, \left<q_0, p_1\right>, \left<q_1, p_1\right>, \left<q_2, p_1\right> $$
Ponieważ stan <q2, p1> jest stanem akceptującym, automat A akceptuje słowo 0100. Jak by to wyglądało, gdybyśmy spróbowali zaakceptować słowo 0100 automatami A1 i A2? Automat A1 przeszedłby po kolei przez takie stany:
$$ q_0, q_1, q_0, q_1, q_2 $$
Automat skończył w stanie q2, który nie jest akceptujący, więc automat A1 tego słowa by nie zaakceptował. A automat A2?
$$ p_0, p_1, p_1, p_1, p_1 $$
Stan p1 jest akceptujący, więc automat A2 słowo 0100 by zaakceptował. Zauważ, że automaty A1 i A2 skończyły w stanach q2 i p1, co zgadza się z tym, że automat A skończył w stanie <q2, p1>.
Konstrukcja za pomocą automatu niedeterministycznego
Przykład
To, że zbiór języków regularnych jest domknięty ze względu na sumę, możemy udowodnić także, budując automat niedeterministyczny, co będzie dużo prostsze.
Mamy więc dwa języki regularne L1, L2 i chcemy udowodnić, że ich suma L = L1 ∪ L2 też jest językiem regularnym. Ponieważ L1, L2 są językami regularnymi, muszą istnieć automaty A1, A2, które te języki akceptują. Czyli zachodzi L(A1) = L1 i L(A2) = L2. Za pomocą tych automatów zbudujemy automat A, który będzie akceptował język L, czyli L(A) = L.
Załóżmy, że automaty skończone A1 i A2 wyglądają tak:
i
Automat, który akceptowałby sumę obu języków, zbudowalibyśmy tak, że utworzylibyśmy nowy stan początkowy i z tego stanu poprowadzilibyśmy dwa epsilon-przejścia do pierwotnych stanów początkowych. To wszystko. Automat wyglądałby tak:
Formalizacja
Mamy dwa automaty $A_1=\left<Q_1, \Sigma, \delta_1, q_1, F_1\right>$ i $A_2=\left<Q_2, \Sigma, \delta_2, q_2, F_2\right>$. Zbudujemy automat $A=\left<Q, \Sigma, \delta, q_0, F\right>$, który będzie akceptował sumę języków akceptowanych przez poprzednie automaty, czyli L(A) = L(A1)∪ L(A2). Przy tym zachodzi:
- Q = Q1 ∪ Q2 ∪ {q0}
- F = F1 ∪ F2
A funkcję przejścia δ definiujemy tak:
$$ \delta(q,a)= \begin{cases} \delta_1(q,a)&\mbox{jeśli}&q\in Q_1\\ \delta_2(q,a)&\mbox{jeśli}&q\in Q_2\\ \left\{q_1, q_2\right\}&\mbox{jeśli}&q=q_0 \wedge a=\varepsilon\\ \emptyset&\mbox{jeśli}&q=q_0\wedge a\ne\varepsilon \end{cases} $$