Test GR: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Gracja (dyskusja | edycje)
Nie podano opisu zmian
Rogoda (dyskusja | edycje)
Nie podano opisu zmian
Linia 9: Linia 9:
{prf}{DOWÓD}
{prf}{DOWÓD}


{algorithm}{Algorytm}  
{algorithm}{Algorytm}


{ automat skończenie stanowy}
{procedure}{Procedura}
 
{ Algorytmy konstrukcji automatu minimalnego }


; Wprowadzenie
; Wprowadzenie
:  W rozdziale tym zdefiniujemy automat - drugi, obok gramatyki, model
:  W tym wykładzie podamy  algorytmy konstrukcji  automatu minimalnego
obliczeń. Określimy język rozpoznawany przez automat i podamy warunki równoważne na to,
i twierdzenia dowodzące ich poprawności.<br>
by język był rozpoznawany.


; Słowa kluczowe
; Słowa kluczowe
: automat skończenie stanowy, język rozpoznawany, prawa kongruencja
:   automat minimalny, pochodna Brzozowskiego, algorytmy
automatowa, homomorfizm automatów, monoid przejść automatu.
minimalizacji.


==AUTOMATY==
==algorytmy konstrukcji automatu minimalnego==


Wprowadzimy teraz pojęcie automatu. Jak już wspomnieliśmy w wykładzie drugim
Dla języka rozpoznawanego <math>L</math> konstrukcję automatu minimalnego można
automat to drugi, obok gramatyki, model obliczeń będący przedmiotem badań
rozpocząć, startując z opisu języka danego na przykład przez
teorii języków i automatów. Model realizujący warunek efektywności analitycznej,
wyrażenie regularne lub też jakiegoś automatu rozpoznającego ten
czyli taki na podstawie którego możliwe jest sformułowanie algorytmu rozstrzygającego
język. W niniejszym wykładzie przedstawimy algorytmy konstrukcji
w skończonej liczbie kroków, czy dowolne słowo należy
automatu minimalnego obejmujące oba wspomniane punkty startu. Jako
czy też nie należy do języka rozpoznawanego przez ten automat. Lub inaczej możemy
pierwszy, nawiązując do rezulatów przedstawionych w poprzednim
powiedzieć, że taki automat daje algorytm efektywnie rozstrzygający  czy dowolne
wykładzie, prezentujemy algorytm, dla którego punktem wyjścia jest
obliczenie sformułowane nad alfabetem automatu jest poprawne.
język <math>L</math>. Prezentację poprzedzimy wprowadzeniem pewnej operacji na
słowach zwanej pochodną J.Brzozowskiego.


Wprowadzony w tym wykładzie automat, zwany automatem skończenie stanowym, jest jednym
Niech <math>\; L \subset A^* \;</math> będzie dowolnym językiem, a  <math>\; u \in A^* \;</math>  dowolnym
z najprostszych modeli obliczeń. Jest to model z bardzo istotnie ograniczoną pamięcią.
słowem. '''Pochodną Brzozowskiego''' (residuum) z języka <math>L</math> względem słowa <math>u</math> nazywamy
Działanie takiego automatu sprowadza się do zmiany stanu  pod
język
wpływem określonego zewnętrznego sygnału czy impulsu.
<center><math> u^{-1}L=\{w \in A^*\;\; :\;\;\; uw \in L \}.</math></center>


Pomimo tych ograniczeń urządzenia techniczne oparte o modele takich automatów spotkać
Podczas obliczeń  pochodnych Brzozowskiego
możemy dość często. Jako przykład służyć mogą automatyczne drzwi, automaty sprzedające
(residuów języka <math>L</math>) można wykorzystać poniższe równości.
napoje, winda czy też urządzenia sterujące taśmą produkcyjną.


{{cwiczenie|[Uzupelnij]||
Niech <math>L_1, L_2\subset A^* \;</math> będą
dowolnymi językami, <math>a \in A</math> dowolną literą, a <math> u,v \in A^*</math> dowolnymi słowami.
Prawdziwe są  następujące równości:


Drzwi automatycznie otwierane są sterowane automatem, którego działanie opisać
<center><math>\aligned\nonumber u^{-1}(L_1 \cup L_2) & = & u^{-1}L_1 \cup u^{-1}L_2, \\
można, przyjmując następujące oznaczenia. Fakt, że osoba chce wejść do pomieszczenia
\nonumber u^{-1}(L_1 \backslash L_2) & = & u^{-1}L_1 \backslash
zamykanego przez takie drzwi, identyfikowany przez odpowiedni czujnik, opiszemy symbolem
u^{-1}L_2, \\
<math>WE</math>. Zamiar wyjścia symbolem <math>WY</math>. Symbol <math>WEWY</math> będzie związany z równoczesnym zamiarem
\nonumber u^{-1}(L_1 \cap L_2) & = & u^{-1}L_1 \cap u^{-1}L_2, \\
wejścia jakiejś osoby i wyjścia innej. Wreszcie symbol <math>BRAK</math> oznaczał będzie brak osób, które
\nonumber a^{-1}(L_1L_2) & = & (a^{-1}L_1)L_2 \mbox{, jeśli }
chcą wejść lub wyjść. Zatem zbiór <math>\{ WE, WY,WEWY,BRAK \}</math>, to alfabet nad którym określimy automat
1 \notin L_1, \\
o <math>2</math> stanach: <math>OTWARTE, ZAMKNIĘTE</math> poniższym grafem.
\nonumber a^{-1}(L_1L_2) & = & (a^{-1}L_1)L_2 \cup a^{-1}L_2 \mbox{,
jeśli } 1 \in L_1, \\
\nonumber a^{-1}L^* & = & (a^{-1}L)L^*, \\
\nonumber v^{-1}(u^{-1}L) & = & (uv)^{-1}L.
\endaligned</math></center>


RYSUNEK  ja-lekcja3-w-rys6
{{cwiczenie|[Uzupelnij]||
 
ANIMACJA ja-lekcja-w-rys7 działania drzwi


Obliczmy wszystkie pochodne dla języka <math>L=a^+b^+</math>. Okazuje się, że są tylko
cztery różne pochodne liczone względem <math>a</math>, <math>b</math>, <math>ab</math> i słowa pustego <math>1</math>. Mianowicie:<br>
<math> a^{-1}L=a^*b^+ </math>,<br>
<math> b^{-1}L= \emptyset </math>,<br>
<math>ab^{-1} L=b^*</math>,<br>
<math>1^{-1}L=L</math>.<br>
Dla wszystkich innych słów
otrzymujemy uzyskane powyżej języki, co wynika z własności pochodnych (patrz wyżej
wypisane równości) i z następujacych obliczeń: <br>
<math>\forall n \in \mathbb{N} (a^n)^{-1}L=a^*b^+  </math>,<br>
<math>\forall n \in \mathbb{N} (b^n)^{-1}L= \emptyset </math>,<br>
<math>\forall n \in \mathbb{N}(ab^n)^{-1} L=b^*</math>.
}}
}}


Automaty reagują więc na określone sygnały zewnętrzne reprezentowane przez
Zauważmy również, nawiązując raz jeszcze do rezulatów
litery alfabetu <math>A</math> zmieniając swój
przedstawionych w poprzednim wykładzie, że prawdziwa jest
stan. Jeśli ustalimy  stan początkowy automatu oraz dopuszczalne stany
następująca równoważność wiążąca wprowadzone pojęcie pochodnej
końcowe, to automat będzie testował dowolne słowo z <math>A^{*} </math> startując ze
Brzozowskiego z prawą kongruencją syntaktyczną:
stanu początkowego. Jeśli rezultatem finalnym działania automatu (obliczenia)
<center><math>u \;P{^r}_L\; v \Longleftrightarrow u^{-1}L=v^{-1}L.</math></center>
będzie stan końcowy, to słowo będzie
rozpoznawane przez automat, a obliczenie określone takim słowem poprawne.
 
Podamy teraz definicję automatu. Niech <math>A</math> oznacza dowolny alfabet.
Od tego momentu wykładu zakładamy, że alfabet jest zbiorem skończonym.


'''Automatem''' nad alfabetem <math>A </math> nazywamy system <math>\mathcal{A} =(S,f)</math>,
Rozpisując z definicji lewą stronę tej równoważności, otrzymujemy,
w którym
iż dla dowolnego słowa <math>z \in A^*</math> słowo <math>uz \in L</math> wtedy i tylko
wtedy, gdy  <math>vz \in L</math>. A to równoważnie oznacza (znów z definicji),
że  <math>u^{-1}L=v^{-1}L.</math>


<math>S</math> - jest dowolnym skończonym zbiorem zwanym zbiorem stanów,
Z uzasadnionej równoważności oraz twierdzenia 3.4 o prawej kongruencji syntaktycznej z
poprzedniego wykładu wnioskujemy równoważność rozpoznawalności języka <math>L</math>
i skończonej ilości różnych pochodnych Brzozowskiego tego języka.


<math>f: S \times A \rightarrow S</math> - jest funkcją przejść.
Pierwszy z przedstawianych algorytmów będzie konstruował automat
minimalny, wyznaczając prawą kongruencję automatową poprzez
zastosowanie metody pochodnych Brzozowskiego. Metoda ta umożliwia
przeprowadzanie odpowiednich obliczeń bezpośrednio na wyrażeniach
regularnych. Ogólny opis algorytmu jest następujący.  Stany
konstruowanego automatu minimalnego etykietowane są  zbiorami
odpowiadającymi pewnym językom. Mając dany język <math>L</math>, ustanawiamy
stan początkowy automatu jako <math>L</math>, wpisujemy go na listę
<math>\mathcal{L}</math> i obliczamy <math>a^{-1}L</math> dla każdej litery <math>a \in A</math>.
Jeśli wśród obliczonych wartości znajduje się język niewystępujący
na liście, dodajemy go do listy. Obliczenia pochodnych Brzozowskiego
wykonujemy, dopóki będziemy uzyskiwać nowe języki (nowe stany).
Funkcja przejść konstruowanego automatu minimalnego zdefiniowana
jest następująco:
<center><math>f(X, a)=a^{-1}X,</math></center> gdzie <math>X</math> jest pewnym językiem  z listy <math>\mathcal{L}</math>.
Obliczone języki określają stany automatu minimalnego.


Automat będąc w stanie <math>s_{i} </math> po przeczytaniu litery <math>a </math> zmienia
---- dla dociekliwych - start ----
stan na <math>s_{j} </math> zgodnie z funkcją przejścia <math>f(s_{i},a)=s_{j} </math>.


Funkcję przejść rozszerzamy na cały wolny monoid <math>A^{*} </math> do postaci <center><math>f: S \times A^* \rightarrow S</math></center> przyjmując:
Obliczone języki określające stany automatu minimalnego  to
elementy monoidu syntaktycznego języka <math>L</math>.


dla każdego <math> s \in S\;\;\;f(s,1) = s </math> oraz
---- dla dociekliwych - end ----


dla każdego <math>s \in S,\;\;a \in A</math> i dla dowolnego <math>w \in A^*</math>
Automatem minimalnym dla automatu <math>\mathcal{A}=(S, A, f, s_0, T)</math>
będzie zatem automat
<center><math>\mathcal{A}_L=(S_L, A, f_L, s_0^L, T_L),</math></center>
gdzie:


<center><math>
* <math>S_L=\{u^{-1}L:\ u \in A^*\}</math>,
f(s,wa) = f(f(s,w),a).
</math></center>


Działanie automatu pokazane jest na rysunku.
* <math>s_0^L = L </math>,


rys3.1
* <math>T_L = \{u^{-1}L:\ u \in L\}</math>,


Zdefiniowany powyżej automat <math>\mathcal{A} </math> nazywamy '''skończonym''' lub
* <math>f_L(u^{-1}L,a) = a^{-1}(u^{-1}L)=(ua)^{-1}L</math>.
'''skończenie stanowym''' ze względu na założenie skończoności zbioru stanów <math>S</math>.<br>


{{cwiczenie|[Uzupelnij]||
Jeśli zdefiniujmy odwzorowanie <math>\nu: S \rightarrow S_L</math>, kładąc:
<center><math>\nu(s)=u^{-1}L, \mbox{ gdzie } s=f(s_0,u),</math></center> to można dowieść,
że <math>\nu</math> jest dobrze określone, jest epimorfizmem oraz <math>\nu(s_0) =
s_0^L</math> - porównaj twierdzenie 3.1 z wykładu 4. Prawdą jest też, iż 
<math>s \in T</math> wtedy i tylko wtedy, gdy <math>\nu(s) \in T_L</math> oraz że
następujący diagram komutuje:


Niech <math>A=\left\{ a,b\right\} </math> będzie alfabetem, a <math>\mathcal{A}=(S,f) </math>
<center><math>\beginCD
automatem takim, że
s @>{a}>> s' @. \ \ \ \ \mbox{ w } \mathcal{A} \\
@V{\nu}VV  @V{\nu}VV \\
u^{-1}L @>{a}>> (ua)^{-1}L @. \ \ \ \ \mbox{ w } \mathcal{A}_L.
\endCD  </math></center>


<math>S=\left\{ s_{0},s_{1},s_{2}\right\}  </math>, a funkcja przejść zadana jest przy
Formalny zapis algorytmu przedstawiony jest poniżej.
pomocy tabelki


{  
{{Minimalizuj1} - algorytm minimalizacji
wykorzystujący pochodne Brzozowskiego}
[1]
Wejście: <math>\mathcal{A}=(S, A, f, s_0, T)</math> - automat taki, że
<math>L=L(\mathcal{A})</math>


{| border=1
Wyjście: automat minimalny <math>\mathcal{A}'=(S_L, A, f_L, s_L,
|+ <span style="font-variant:small-caps">Uzupelnij tytul</span>
T_L)</math> dla <math>\mathcal{A}S_L \leftarrow \{L\}</math>;
|-
|
<math>f </math> ||
<math>s_{0} </math> ||
<math>s_{1} </math> ||
<math>s_{2} </math>
|-
|


<math>a </math> ||
'''włóż'''<math>(\mathcal{L},L)</math>;
<math>s_{1} </math> ||
<math>s_{2} </math> ||
<math>s_{2} </math>
|-
|
<math>b </math> ||
<math>s_{0} </math> ||
<math>s_{0} </math> ||
<math>s_{0} </math>
|-
|


|}
{<math>\mathcal{L} \not =</math>}


}
<math>M \leftarrow </math> '''zdejmij'''<math>(\mathcal{L})</math>;


Automat możemy również jednoznacznie określić przy pomocy grafu.<br>
{'''each''' <math>a \in A</math>}


rys3.2
<math>N \leftarrow a^{-1}M</math>;


}}
{<math>N \cap S_L = </math> }


Podamy teraz bardzo interesujący przykład zastosowania automatów  skończonych.
<math>S_L \leftarrow S_L \cup \{N\}</math>;
Przedstawimy mianowicie wykorzystanie  tak zwanych
automatów synchronizujących w przemyśle. Automat synchronizujący nad alfabetem <math>A</math> to
automat <math>(S,f)</math>  o
następującej własności: istnieje stan <math>t \in S</math> oraz słowo <math>w \in
A^*</math> takie, że dla każdego stanu <math>s</math> tego automatu <math>  f(s, w)=t</math>. Istnieje więc pewne uniwersalne
słowo <math>w</math>, pod wpływem którego wszystkie stany przechodzą w jeden,
ustalony stan automatu <math>t \in S</math>. Mówimy, że następuje wtedy synchronizacja
wszystkich stanów automatu.


Poniżej prezentujemy przykład zaczerpnięty z pracy Ananicheva i
'''włóż'''<math>(\mathcal{L},N)</math>;
Volkova (D. S. Ananichev, M. V. Volkov, Synchronizing Monotonic
Automata, ''Lecture Notes in Computer Science'', 2710(2003),
111--121.), ukazujący ideę użycia automatów synchronizujących w tej
dziedzinie.


{{cwiczenie|[Uzupelnij]||
{'''each''' <math>M \in S_L</math>}


RYSUNEK pojedynczego detalu - ja-lekcja3-w-rys-s1
{'''each''' <math>a \in A</math>}


Załóżmy, że pewna fabryka produkuje detale w kształcie kwadratu z
<math>f_L(M,a) \leftarrow a^{-1}M</math>;
"wypustką" na jednym boku
(patrz rys. [[##ja-lekcja3-w-rys-s1|Uzupelnic ja-lekcja3-w-rys-s1|]]).
Po wyprodukowaniu detale należy umieścić w opakowaniach w ten sposób,
by wszystkie były w tej samej orientacji - mianowicie "wypustką" w
lewo.


Załóżmy ponadto dla uproszczenia, że detale mogą przyjmować jedną z
<math>s_L \leftarrow L</math>;
czterech orientacji (rys. [[##ja-lekcja3-w-rys-s2|Uzupelnic ja-lekcja3-w-rys-s2|]]): "wypustką" w
górę, w dół, w lewo lub w prawo.


RYSUNEK ja-lekcja3-w-rys-s2
<math>T_L \leftarrow \{u^{-1}L:\ u \in L\}</math>;


Należy zatem skonstruować takie urządzenie (orienter), które będzie
<math>\mathcal{A}'</math>;
ustawiało wszystkie detale w żądanej orientacji. Oczywiście istnieje
wiele metod rozwiązania tego problemu, ale z praktycznego punktu
widzenia potrzebne jest rozwiązanie najprostsze i najtańsze. Jednym
z takich sposobów jest umieszczanie detali na pasie transmisyjnym z
zamontowaną wzdłuż niego pewną ilością przeszkód dwojakiego rodzaju:
niskich (''low'') oraz wysokich (''HIGH''). Wysoka
przeszkoda ma tę własność, że każdy detal, który ją napotka zostanie
obrócony o 90 stopni w prawo (zakładamy, że elementy jadą od lewej
do prawej strony). Przeszkoda niska obróci o 90 stopni w prawo tylko
te detale, które są ułożone "wypustką" w dół. Na rys.
[[##ja-lekcja3-w-rys-s3|Uzupelnic ja-lekcja3-w-rys-s3|]] przedstawione zostały przejścia pomiędzy
orientacjami detali w zależności od napotkania odpowiedniej
przeszkody.


RYSUNEK ja-lekcja3-w-rys-s3
Funkcja '''zdejmij'''<math>(\mathcal{L})</math>, występująca w linii 6.,
zdejmuje z kolejki <math>\mathcal{L}</math> pierwszy element  i zwraca go jako
swoją wartość. Procedura '''włóż'''<math>(\mathcal{L},L)</math>, występująca
w liniach 4. oraz 11., wstawia na koniec kolejki <math>\mathcal{L}</math>
element <math>L</math>.


Można zauważyć, że automat z rysunku [[##ja-lekcja3-w-rys-s3|Uzupelnic ja-lekcja3-w-rys-s3|]] jest
{{cwiczenie|[Uzupelnij]||
automatem synchronizującym. Słowem, które go synchronizuje jest
następująca sekwencja przeszkód:
 
low-HIGH-HIGH-HIGH-low-HIGH-HIGH-HIGH-low.


Niezależnie od tego, w jakiej orientacji początkowej znajduje się
Dla języka <math>L=a^+b^+</math> z przykładu 1.1 w wyniku działania powyższego algorytmu
detal, po przejściu przez powyższą sekwencję przeszkód zawsze będzie
otrzymamy czterostanowy automat
ułożony "wypustką" w lewo. Sytuację przedstawia poniższa animacja:
<math>\mathcal{A}_L=(S_L,A,  f, L, T),</math> gdzie<br>
<math>S_L= \{L, a^*b^+  ,\emptyset, b^*\}</math>,<br>
a funkcja
przejść zadana jest grafem: <br>


ANIMACJA ja-lekcja3-w-anim-s4
RYSUNEK ja-lekcja5-w-rys1


}}
}}


Rozszerzymy teraz wprowadzone pojęcie automatu w ten sposób by uzyskać możliwość
Prezentowane poniżej twierdzenie uzasadnia kolejny algorytm  konstrukcji automatu
efektywnego rozstrzygania czy dowolne słowo utworzone nad alfabetem <math>A</math>
minimalnego. Tym razem punktem wyjścia jest dowolny automat rozpoznający język
reprezentuje poprawne obliczenie,
<math>L </math>.
czyli spełnia kryteria określone przez rozszerzony automat.


'''Język''' <math>\; L~\subset A^* \;</math> jest '''rozpoznawany''' ('''akceptowany''')
---- dla dociekliwych - start -----
wtedy i tylko wtedy, gdy istnieje automat skończony <math>\mathcal{A} = (S,f) , \;</math> stan <math>\; s_0 \in S \;</math> oraz zbiór <math>\; T \subset S \;</math> takie, że
<center><math>L = \{ w \in A^* \; : \; f(s_0,w) \in T \}. </math></center> Stan <math>s_0 \;</math> nazywamy '''stanem początkowym''',
a <math>\; T \;</math> '''zbiorem stanów końcowych''' automatu <math>\mathcal{A} </math>.


Rozszerzony w powyższy sposób automat, poprzez dodanie stanu początkowgo i zbioru stanów końcowych, w dalszym ciągu
Algorytm oblicza również monoid syntaktyczny języka <math>L </math>.
nazywamy automatem i oznaczamy jako piątkę <math>\mathcal{A} = (S,A,f,s_0,T)</math> lub czwórkę <math>\mathcal{A} =(S,f,s_0,T)</math>, jeśli
wiadomo, nad jakim alfabetem rozważamy działanie automatu.


Fakt, że język <math>\; L \;</math> jest rozpoznawany przez automat <math>\mathcal{A}, </math> zapisujemy jako
---- dla dociekliwych - end -----


<center><math>L=L(\mathcal{A}). </math></center>
Analogicznie do konstrukcji relacji <math>\rho _{i} </math>, przedstawionej
w wykładzie 4, możemy określić ciąg odpowiednich relacji na
zbiorze stanów dowolnego automatu rozpoznającego język <math>L </math>.
Relacje te służą do efektywnego określenia automatu minimalnego,
równoważnego zadanemu.


Rodzinę wszystkich języków rozpoznawalnych nad alfabetem <math>A</math>
Niech <math>\mathcal{A} </math></center><nowiki>=</nowiki> (S,A,f,s_0,T)<math> będzie dowolnym automatem i
oznaczamy przez <math>\mathcal{REC}(\mathcal{A}^{*}) </math>.
niech </math>L<nowiki>=</nowiki>L({A}) <math>.
Przez </math>  _{{A}}  S  S  <math> oznaczmy relację
równoważności
zawierającą dwie klasy równoważności </math>T<math> i </math>S  T<math>. Przez </math>{}_i<math> dla </math>i { N} <math>
oznaczmy zstępujący ciąg relacji określony następująco:


Podobnie jak w przypadku gramatyk nie ma jednoznacznej odpowiedniości pomiędzy językami
</math>{}_1 <nowiki>=</nowiki>  _{{A}} <math>, a dla </math> i <nowiki>=</nowiki> 2,... <math> przyjmijmy
rozpoznawalnymi a automatami. Wprowadza się więc relację, która identyfikuje
automaty rozpoznające ten sam język.


Automaty <math>\mathcal{A}_{1} </math> i <math>\mathcal{A}_{2} </math> są '''równoważne''',
</math>{}_i <nowiki>=</nowiki> (s,t)  S  S  :  a  A  1  f(s,a) {}_{i-1} f(t,a) . <math>
jeśli rozpoznają ten sam język, czyli


<center><math>L(\mathcal{A}_{1})=L(\mathcal{A}_{2}).</math></center>
{\par\raggedright Wtedy </math> {}_i <math> jest największą prawą kongruencją automatową zawartą w relacji </math>{}_1 <nowiki>=</nowiki>  _{{A}} <math> i automat minimalny ma postać\par}


W dalszych rozważaniach języków rozpoznawanych ograniczymy się do automatów
</math></center>{A}_{L}<nowiki>=</nowiki>( S/_{ { }_{i}},A,f^{*},[s_{0}],T/_{ { }_{i}}) .<center><math>
<math>\mathcal{A} = (S,A,f,s_0,T)</math>,
które spełniają warunek  <math>f(s_0,A^*) = S.</math>
Nie zawęża to naszych rozważań. Jeśli bowiem język <math>\; L \;</math> jest rozpoznawany
przez pewien automat <math>\mathcal{A} = (S,A,f,s_0,T)</math>, to jest również
rozpoznawany przez automat


<center><math>\mathcal{B}=\left( f(s_{0},A^{*}),A,f|_{f(s_{0},A^{*})\times A^{*}},s_{0},T\cap f(s_{0},A^{*})\right) ,</math></center>
\endtheor


który spełnia powyższy warunek. Zauważmy, że przyjmując to założenie upraszczamy strukturę
Dowód tego twierdzenia przebiega analogicznie do dowodu twierdzenia 3.3 z
automatu. Z punktu widzenia grafu automatu można powiedzieć, że nie występują w nim
wykładu 4.
wierzchołki (stany) nieosiagalne ze z <math>s_0</math>.  Poniżej przedstawiamy algorytm usuwający
z automatu stany nieosiągalne ze stanu początkowego.


{{UsuńStanyNieosiągalne} - usuwa z automatu
Algorytm działajacy w oparciu o powyższe twierdzenie na podstawie
<math>\mathcal{A}</math> stany nieosiągalne}
zadanego automatu </math>{A}<nowiki>=</nowiki>(S, A, f, s_0, T)<math>, konstruuje
[1]
efektywnie automat minimalny dla </math>{A}<math>, obliczając ciąg 
Wejście: <math>\mathcal{A}=(S, A, f, s_0, T)</math> - automat
relacji </math>{}_i<math>. Proces konstrukcji przebiega w sposób
iteracyjny. Zaczynamy od zdefiniowania relacji
</math>_{{A}}<math>, która posiada tylko dwie klasy abstrakcji:  
do pierwszej z nich należą wszystkie stany końcowe, a do drugiej --
wszystkie pozostałe stany. Tak więc
</math></center> s, t  Ss _{{A}} t  (s  T  t  T)  (s  S  T  t  S T).<center><math>
Definiujemy pierwszą z relacji </math>{}<math>, czyli relację
</math>{}_1<math>  jako równą </math>_{{A}}<math>, a
następnie, dla każdej obliczonej już relacji
</math>{}_{i-1}<math>, obliczamy relację </math>{}_i<math> w
następujący sposób:
</math></center>s_1 {}_i
s_2  (s_1 {}_{i-1} s_2)  (
a  Af(s_1, a) {}_{i-1} f(s_2,a)).<center><math> Nowo obliczona
relacja </math>{}_i<math> albo podzieli jedną lub kilka klas
abstrakcji relacji </math>{}_{i-1}<math>, albo będzie identyczna z
relacją </math>{}_{i-1}<math>. Jeśli zajdzie ta druga sytuacja, to
znaczy, że dla każdego </math>j>i<math> w oczywisty sposób spełniona jest
równość </math>{_j}<nowiki>=</nowiki>{}_i<math>, czyli ciąg relacji
ustabilizuje się. W tym momencie algorytm kończy swoje działanie i
klasy abstrakcji relacji </math>{}_i<math> będą reprezentować
stany automatu minimalnego.


Wyjście: <math>\mathcal{A}'=(S', A, f', s_0, T')</math> - automat
\newpage
równoważny automatowi <math>\mathcal{A}</math> bez stanów nieosiągalnych.


'''procedure''' {Oznacz}<math>(x \in S)</math>
\beginalgorithm
\caption{\textsc{Minimalizuj2} -- algorytm minimalizacji automatu
wykorzystujący stabilizujący się ciąg relacji}


{<math>p \in S:\ \exists a \in A\ f(x,a)=p \wedge
\beginalgorithmic [1]
\mbox{\textbf{zaznaczone}}[p]==0</math>}
\STATE Wejście: </math>{A}<nowiki>=</nowiki>(S, A, f, s_0, T)<math> -- automat taki, że
</math>L<nowiki>=</nowiki>L({A})<math>.


'''zaznaczone'''<math>[p] \leftarrow 1</math>;
\STATE Wyjście: automat minimalny </math>{A}'<nowiki>=</nowiki>(S',A',f', s_0',
T')<math> dla </math>{A}<math>.


{Oznacz}<math>(p)</math>;
\STATE </math>{}_1_{{A}}<math>;


'''end procedure'''
\STATE </math>i  1<math>;


{<math>p \in S</math>}
\REPEAT


'''zaznaczone'''<math>[p] \leftarrow 0</math>;
\STATE  oblicz </math>{}_i<math>: </math>s_1
{}_i s_2  (s_1 {}_{i-1}
s_2)  ( a  Af(s_1, a) {}_{i-1}
f(s_2,a))<math>;


'''zaznaczone'''<math>[s_0] \leftarrow 1</math>;
\STATE </math>i  i+1<math>;


{Oznacz}<math>(s_0)</math>;
\STATE \textbf{empty}</math>({}_i)<math>  


<math>S' = \{s \in S:\ \mbox{\textbf{zaznaczone}}[s]==1\}</math>;
\FOR{\textbf{each} </math>(s_1,s_2) S S<math>}


<math>T' = T \cap S'</math>;
\STATE flag\textbf{true};


jeśli istnieje przynajmniej jeden stan, dla którego funkcja
\FOR{\textbf{each} </math>a A<math>}
przejścia <math>f</math> nie jest określona dla jakiejś litery <math>a \in A</math>, dodaj
stan <math>s_f</math> do <math>S'</math> i dla każdego stanu <math>s</math> i litery <math>a</math> jeśli <math>f(s,
a)</math> jest nieokreślone, to zdefiniuj <math>f(s,a)=s_f</math>;


<math>f' \leftarrow f</math>;
\IF{\textbf{not} </math>f(s_1, a) {}_{i-1} f(s_2,a)<math>}


<math>\mathcal{A}'=(S', A, f', s_0, T')</math>;
\STATE flag\textbf{false};


Powyższy algorytm, dla ustalonego alfabetu <math>A</math>, posiada złożoność <math>O(|A|
\ENDIF
\cdot |S|)</math>, czyli liniową względem liczby stanów.


{{cwiczenie|[Uzupelnij]||
\ENDFOR


Jeśli w przykładzie [[##ex.3.1.1|Uzupelnic ex.3.1.1|]] przyjmiemy stan <math>s_{0} </math> jako stan
\IF{flag=\textbf{true} \textbf{and} </math>s_1 {}_{i-1} s_2<math>}
początkowy, <math>T=\left\{ s_{2}\right\} </math> jako zbiór stanów końcowych, to
automat <math>\mathcal{A} = (S,A,f,s_0,T)</math> rozpoznaje język


<center><math>L(\mathcal{A})= A^{*}\left\{ a^2\right\}</math></center>
\STATE </math>{}_{i}  {}_{i}  
(s_1,s_2)<math>;


złożony ze słów, kończących się na <math>a^2 </math>.<br>
\ENDIF
Słowo <math>aba</math> nie jest akceptowane.
rys3.3<br>
Słowo <math>abaa</math>  jest akceptowane.
rys3.4
}}


Każdy automat <math>\mathcal{A} = (S,A,f,s_0,T)</math> wyznacza w wolnym monoidzie <math>A^*</math>
\ENDFOR
prawą kongruencję, nazywaną '''prawą kongruencją automatową''', określoną w następujący
sposób:<br>
<math>\forall u,v \in A^*</math>


<center><math>u\sim _{\mathcal{A}}v\Longleftrightarrow f(s_{0},u)=f(s_{0},v).</math></center>
\UNTIL{</math>{}_i <nowiki>=</nowiki> {}_{i-1}<math>}


Dla automatu skończonego ( o skończonym zbiorze stanów), a takie rozważamy,
\STATE </math>S'  S  {}_i<math>;
relacja <math>\sim _{A} </math> ma
skończony indeks, czyli skończoną liczbę klas równoważności.


{{cwiczenie|[Uzupelnij]||
\FOR{\textbf{each} </math>[s]_{{}_i}  S
{}_i<math>}


Automat z przykładu [[##ex.3.1.1|Uzupelnic ex.3.1.1|]] ze stanem <math>s_{0} </math> jako początkowym wyznacza
\FOR{\textbf{each} </math>a  A<math>}
relację równoważności o trzech klasach:


<math>[1]=A^*\left\{ b \right\}\cup \left\{ 1\right\}[a]=A^*\left\{ ba\right\}  \cup \left\{ a\right\} [a^2]=A^*\left\{ a^2 \right\} </math>
\STATE </math>f'([s]_{{}_i},a)
[f(s,a)]_{{}_i}<math>;


}}
\ENDFOR


Na odwrót, każda prawa kongruencja <math>\;\rho \subset (A^*)^2\;</math> wyznacza automat, zwany
\ENDFOR
'''ilorazowym''', w następujący sposób:


<center><math>\mathcal{A}_{\rho }=(A^{*}/_{\rho },f^{*}),\; \; gdzie\; \; f^{*}([w]_{\rho },u)=[wu]_{\rho }.</math></center>
\STATE </math>s_0'  [s_0]_{{}_i}<math>;


<math>\mathcal{A} </math></center>_<math> jest automatem ze stanem początkowym </math>[1]_<math>. </math>{A}_{ } <math> jest automatem skończonym
\STATE </math>T'  [t]_{{}_i}:t T<math>;
wtedy i~tylko wtedy, gdy relacja ma skończony indeks.\\
Z definicji prawej kongruencji wynika, że funkcja przejść </math>f^*<math> jest określona poprawnie.


\begindefin
\RETURN </math>{A}'<nowiki>=</nowiki>(S', A, f', s_0', T')<math>;


Niech </math>{A} <nowiki>=</nowiki>(S,f)<math> i </math> {B} <nowiki>=</nowiki>(T,g)<math> będą dowolnymi automatami.
\endalgorithmic
Odwzorowanie </math> :S T <math>
\endalgorithm
nazywamy \textbf{homomorfizmem automatów}\index{homomorfizm automatów}
wtedy i~tylko
wte\-dy, jeśli </math></center> s  S,  w  A^*(f(s,w))  <nowiki>=</nowiki>  g((s),w).<center><math> Homomorfizm
automatów oznaczamy </math> :{A} {B} <math>.


\enddefin
{{cwiczenie|[Uzupelnij]||


\begintheor  
Zminimalizujemy automat </math>{A}<nowiki>=</nowiki>(S,A,f,s_0,T)<math>, dla którego\\
</math>S<nowiki>=</nowiki> s_{0},s_{1},s_{2},s_{3},s_{4},s_5 , A<nowiki>=</nowiki>a,b,
T<nowiki>=</nowiki>s_1, s_{2},s_{4} <math>,
a funkcja przejść określona jest przy pomocy grafu.\\
RYSUNEK ja-lekcja5-w-rys2\\
Konstruujemy ciąg
relacji </math>{}_i<math>.


Prawdziwe są następujące fakty:
Na początku  </math>{}_1<math> dzieli </math>S<math> na dwie klasy
abstrakcji; pierwsza zawiera stany końcowe, a druga -- wszystkie
pozostałe, czyli uzyskujemy dwa zbiory </math>s_1,s_2,s_4<math> oraz
</math>s_0, s_3, s_5<math>.


#  Dla dowolnej prawej kongruencji </math>     (A^*)^2 </center> _{{A}_{ }}<nowiki>=</nowiki> ,<center><math>
Obliczmy </math>{}_2<math> (pierwszy przebieg pętli w liniach 5.-20. algorytmu). Aby dwa elementy
(stany) </math>s<math> i </math>t<math> były ze sobą w relacji </math>{}_2<math> muszą
być ze sobą w relacji </math>{}_1<math> oraz musi zachodzić
</math></center> a  A  f(s, a) {}_1 f(t,a).<center><math>
Czyli kolejna, nowa relacja może ewentualnie podzielić już
istniejące zbiory zdefiniowane przez poprzednią relację. Nie może
więc zajść taka sytuacja, że w jednej klasie abstrakcji relacji
</math>{}_{i+1}<math> znajdą się elementy z różnych klas
abstrakcji relacji </math>{}_i<math>.


#  Dowolny automat </math>{A} <nowiki>=</nowiki> (S,A,f,s_0,T)<math> jest izomorficzny z automatem </math>{A}_{ _{{A}}} <math>,
Rozważmy najpierw zbiór </math>s_1, s_2, s_4<math>. Oczywiście każde dwa
stany z tego zbioru są ze sobą w relacji </math>{}_1<math>.
Zauważmy, że </math>f(s_2, a)<nowiki>=</nowiki>f(s_4,a)<nowiki>=</nowiki>s_2<math>, </math>f(s_2,b)<nowiki>=</nowiki>f(s_4,b)<nowiki>=</nowiki>s_4<math>, więc
</math>s_2 {}_2 s_4<math> (bo </math>s_2 {}_1 s_2<math> oraz </math>s_4 {}_1 s_4<math>).
Ponieważ </math>f(s_1,b)<nowiki>=</nowiki>s_5<math> i </math>f(s_2,b)<nowiki>=</nowiki>s_4<math>, a wiemy, że </math>s_5<math> nie jest
w relacji </math>{}_1<math> z  </math>s_4<math>, zatem stany </math>s_1<math> i </math>s_2<math>
nie mogą być ze sobą w relacji </math>{}_2<math>, a to oznacza, że
także stany </math>s_1<math> i </math>s_4<math> nie mogą być ze sobą w relacji
</math>{}_2<math>.


#  Dla dowolnych automatów </math>{A}_1<nowiki>=</nowiki> (S_1,A,f_1,s^1_0,T_1)<math>
W analogiczny sposób można sprawdzić, że relacja </math>{}_2<math> nie
i </math>{A}_2 <nowiki>=</nowiki> (S_2,A,f_2,s^2_0,T_2)<math> prawdziwa jest równoważność
podzieli zbioru </math>s_0, s_3, s_5<math>. Ostatecznie, po pierwszym
wykonaniu pętli algorytmu minimalizacji obliczyliśmy relację
</math>{}_2<math>, która dzieli </math>S<math> na następujące podzbiory:
</math></center>s_1, s_2, s_4, s_0, s_3, s_5.<center><math>


{\par\centering </math> _{{A}_1}    _{{A}_2}     <math>
W kolejnym kroku obliczamy </math>{}_3<math>. Zbiór </math>s_1<math>
istnieje epimorfizm </math> :{A}_1 {A}_2 <math> taki,
oczywiście nie może być już podzielony na mniejsze podzbiory.
że </math>(s^1_0) <nowiki>=</nowiki> s^2_0<math>. \par}
Łatwo zauważyć, że </math>{}_3<math> nie podzieli także zbioru </math>s_2,
s_4<math>.


\endtheor
Rozważmy teraz zbiór </math>s_0, s_3, s_5<math>. Mamy </math>f(s_3, a)<nowiki>=</nowiki>f(s_5, a)<math> oraz
</math>f(s_3, b)<nowiki>=</nowiki>s_3<math>, </math>f(s_5, b)<nowiki>=</nowiki>s_5<math> i wiadomo, że </math>s_3 {}_2
s_5<math>, zatem </math>s_3<math> i </math>s_5<math> będą ze sobą w relacji
</math>{}_3<math>.


\beginprf \hfill
Ponieważ </math>f(s_0, a)<nowiki>=</nowiki>s_2<math> i </math>f(s_3, a)<nowiki>=</nowiki>s_1<math>, ale </math>s_2<math> i </math>s_1<math> nie są
ze sobą w relacji </math>{}_2<math>, zatem nie mogą być także ze
sobą w relacji </math>{}_3<math>. Relacja </math>{}_3<math>
dzieli więc zbiór </math>s_0, s_3, s_5<math> na zbiory </math>s_0<math> oraz
</math>s_3, s_5<math>.


# Identyczność relacji wynika wprost z~defi\-ni\-cji automatu ilorazowego </math>{A} <center><math>_\rho</math> oraz prawej kongruencji <math>\sim _{A_{\rho }} </math>.
Podział zbioru </math>S<math> przez relację </math>{}_3<math> wygląda więc
następująco: </math></center>s_0, s_1, s_2, s_4, s_3, s_5.<center><math>


# Rozważmy automat <math>\mathcal{A} = (S,A,f,s_0,T)</math> i odwzorowanie
Relacja </math>{}_4<math> nie podzieli już ani zbioru </math>s_2,  
s_4<math>, ani zbioru </math>s_3, s_5<math>, więc uzyskujemy równość
</math>{_4}<nowiki>=</nowiki>{}_3<math> i ponieważ ciąg relacji się
ustabilizował, algorytm kończy działanie.


<center><math>\psi :\mathcal{A}\longrightarrow \mathcal{A}_{\sim _{\mathcal{A}}}, </math></center>
Podsumowując, mamy:


gdzie
; </math>{} _{1}<math>
<math>\forall s\in S </math>   
</math>s_1, s_{2},s_{4}, s_{0},s_{3},s_5, <math>


<center><math>\psi (s)=[w]_{\sim _{\mathcal{A}}} \;\;\text{dla}\;\;  w\in A^{*} \;\;\text{i} \;\; f(s_{0},w)=s. </math></center>
; </math>{} _{2}<math>
:  </math>s_{1},s_2,s_{4}, s_{0},s_{3},s_5,<math>


Istnienie słowa <math>w</math> wynika z faktu, że <math>s_0</math> jest stanem początkowym, natomiast z definicji relacji <math>\sim _{\mathcal{A}}</math> wynika, że odwzorowanie <math>\psi</math> jest poprawnie określone.<br>
; </math>{} _{3}<math>
Odwzorowanie <math>\psi</math> ma być homomorfizmem, czyli dla każdego stanu <math>s\in S </math> i dowolnego
</math>s_{1},s_2,s_{4}, s_{0},s_{3},s_5.{} _{3}<nowiki>=</nowiki>{} _{4}<math> i równoważny minimalny automat </math>{A}_L<nowiki>=</nowiki>(S,f^*,s_0,T)<math> ma </math>4<math> stany. \\
słowa <math>w\in A^{*} </math> spełniać warunek
</math>q_0<nowiki>=</nowiki>s_{0}, q_1<nowiki>=</nowiki>s_{1}, q_2 <nowiki>=</nowiki> s_2,s_{4}, q_3
<nowiki>=</nowiki>s_{3},s_5<math>, </math>T<nowiki>=</nowiki>q_1 ,q_2<math>.
Jak łatwo zauważyć jest to automat z przykładu 3.1 zamieszczonego w wykładzie 4.


<center><math>\psi (f(s,w))=f^{*}(\psi (s),w). </math></center>
RYSUNEK ja-lekcja5-w-rys3


Warunek ten wynika z następujących równości
}}


<center><math>\begin{array} {c}
Jednym z najczęściej stosowanych algorytmów automatu minimalnego jest algorytm, który
f^{*}(\psi (s),w)=f^{*}([u]_{\sim_{\mathcal{A}}},w)=[uw]_{\sim _{\mathcal{A}}}=\\
buduje "tabelkę" na podstawie której określa się automat minimalny.
=\left\{ v\in A^{*}:f(s_{0},uw)=f(s_{0},v)\right\} = \\
Poprawność tego
\left\{ v\in A^{*}:f(f(s_{0},u),w)=f(s_{0},v)\right\} = \\
algorytmu również uzasadnia twierdzenie  [[##twrho|Uzupelnic twrho|]].
=\left\{ v\in A^{*}:f(s,w)=f(s_{0},v)\right\} =\psi (f(s,w))
\end{array} </math></center>


gdzie <math>f(s_0,u)=s</math>.
W algorytmie tym wyznaczać będziemy tzw. stany rozróżnialne.
Algorytm działa w czasie </math>O(|A|n^2)<math>, gdzie </math>|A|<math> jest mocą
alfabetu, a </math>n<math> -- liczbą stanów automatu wejściowego, czyli
podlegajacego  minimalizacji. Złożoność pamięciowa jest również
</math>O(|A|n^2)<math>. Prezentowany algorytm nosi nazwę algorytmu
Hopcrofta-Ullmana. Znana w literaturze jest pewna zmodyfikowana
wersja tego algorytmu. Jest to algorytm Aho-Sethiego-Ullmana, który
ma tę samą złożoność czasową, ale lepszą złożoność pamięciową -
</math>O(|A|n)<math>. Natomiast w ramach ćwiczeń prezentujemy jeszcze jeden
algorytm, znany jako algorytm minimalizacji Hopcrofta. Czas
działania  tego algorytmu wynosi </math>O(n  n)<math>.


Z prostych obserwacji wynika, że <math>\psi </math> jest suriekcją i iniekcją.
Niech będzie relacją zdefiniowaną przez funkcję przejść automatu
 
w następujący sposób:
# Dowód implikacji "<math>\Rightarrow</math>" <br>
</math></center>p  q  w  A^* (f(p,w) T
Załóżmy, że <math>\: \sim _{\mathcal{A}_1}\: \subseteq \: \sim _{\mathcal{A}_2 } </math>. Niech
f(q,w) T).<center><math>
 
<center><math>\varphi :\mathcal{A}_1\longrightarrow \mathcal{A}_2 </math></center>
 
będzie odwzorowaniem takim, że<br>
<math>\forall  s\in S_1 </math> <center><math> \varphi (s) = f_2(s^2_0,w),\;\;\text{gdzie}\;\;  w\in A^{*}\;\; i \;\; f_1(s^1_0,w) = s.</math></center>
Stąd, że <math>s^1_0 </math> jest stanem początkowym automatu <math>\mathcal{A}_1, </math>
wynika, że istnieje słowo <math>\; w \in A^* \;</math> potrzebne do określenia epimorfizmu <math> \varphi</math>.<br>
Z założenia <math>\: \sim _{\mathcal{A}_1}\: \subseteq \: \sim _{\mathcal{A}_2} </math>
wynika, że <math>\varphi \;</math> jest poprawnie zdefiniowaną funkcją. <br>
Uzasadnienie faktu, że <math>\varphi</math> jest
homomorfizmem, jest analogiczne jak w punkcie [[##tb|Uzupelnic tb|]] dla <math>\psi</math>.<br>
<math>\varphi</math> jest suriekcją, gdyż <math>\; s^2_0 \; </math>
jest stanem początkowym automatu <math>\mathcal{A}_2 </math>.<br>
<math>\; \varphi (s^1_0) = s^2_0, \;</math> ponieważ <math>\; f_1(s^1_0,1) = s^1_0</math>. <br>
Dowód implikacji "<math>\Leftarrow</math>" <br>
Niech <math>\varphi :\mathcal{A}_1\longrightarrow \mathcal{A}_2 </math> będzie epimorfizmem
takim, że <math>\; \varphi (s^1_0) = s^2_0 \;</math>.<br>
Wówczas prawdziwy jest następujący ciąg wnioskowań.
 
<center><math>\begin{array} {c}
u\sim _{\mathcal{A}_1}v \Leftrightarrow f_1(s^1_0,u)=f_1(s^1_0,v)
\Rightarrow\\
\Rightarrow \varphi (f_1(s^1_{0},u))=\varphi (f_1(s^1_{0},v))\Rightarrow f_2(s^2_{0},u)=f_2(s^2_{0}v)\Leftrightarrow
u\sim _{\mathcal{A}_2}v
\end{array}
</math></center>
 
To oznacza, że <math>\sim _{\mathcal{A}_1}\subseteq \sim _{\mathcal{A}_2} </math>.
 
<math>\diamondsuit</math>   
 
Symbolem <math>S^S</math> oznaczamy rodzinę wszystkich funkcji określonych na zbiorze <math>S</math> i przyjmujących
wartości w <math>S</math>. Łatwo zauważyć, iż  rodzina ta wraz ze składaniem odwzorowań jest
monoidem <math>(S^S,\circ)</math> .
 
Niech <math>\mathcal{A} = (S,f)</math> będzie dowolnym automatem.
'''Reprezentacją automatu''' <math>\mathcal{A} </math> nazywamy funkcję
<math>\tau _{\mathcal{A}}:A^{*}\longrightarrow S^{S} </math>
określoną dla dowolnych <math> w \in A^*</math> i <math>\; s \in S \;</math> równością
 
<center><math>\tau _{\mathcal{A}}(w)(s)=f(s,w). </math></center>
 
Reprezentacja automatu jest
homomorfizmem monoidu <math>A^*</math> w monoid <math>S^S</math>, bowiem dla dowolnych <math> v,w \in A^* </math>
spełnione są warunki
 
<center><math>\begin{array} {c}
\tau _{\mathcal{A}}(vw)=\tau _{\mathcal{A}}(w)\circ \tau _{\mathcal{A}}(v),\\
\tau _{\mathcal{A}}(1)=id_{S}.
\end{array} </math></center>
 
Niech <math>\mathcal{A} </math></center><nowiki>=</nowiki> (S,f)<math> będzie dowolnym automatem. \textbf{Monoidem przejść}\index{monoid przejść}
automatu </math>{A} <math> nazywamy monoid
 
</math></center>{M}({A})<nowiki>=</nowiki> _{{A}}(A^{*}) S^{S}.<center><math>


\begindefin 
Stany </math>p<math> i </math>q<math> są równoważne, jeśli </math>p  q<math>.
\enddefin  
\enddefin  


Następujace wnioski konsekwencjami rozważań przeprowadzonych powyżej.
Jeśli stany nie są równoważne, to będziemy mówić, że
\begincorol  \vspace{-5truemm}\\
rozróżnialne.
 
# Monoid przejść automatu </math>{A} <math> jest podmonoidem monoidu </math> S^S <math> i  zbiór
</math>  _{{A}}(a):a A  <math> jest zbiorem generatorów tego monoidu.
 
</math></center>{M}({A})<nowiki>=</nowiki>  _{{A}}(a):a A ^{*} <center><math>


Wynika to z faktu, że </math> _{{A}} <math> jest epimorfizmem i z twierdzenia~[[##tw:z|Uzupelnic tw:z|]].
Zadaniem algorytmu jest wyznaczenie stanów równoważnych, celem ich
utożsamienia ze sobą. Algorytm musi zdecydować, dla każdej pary
stanów </math>(p,q)<math>, czy są one rozróżnialne. Jeśli pod koniec działania
algorytmu okaże się, że nie stwierdziliśmy rozróżnialności tych
stanów, to znaczy, że są one równoważne; następuje ich utożsamienie,
czyli "połączenie" ich w jeden stan. Gdy takiego połączenia dokonamy
dla wszystkich par stanów, wobec których nie stwierdziliśmy ich
rozróżnialności, powstanie automat o minimalnej liczbie stanów.


# Monoid przejść automatu skończonego jest skończony.
W praktyce algorytm nie wyznacza stanów równoważnych, ale stany
rozróżnialne, gdyż jest to po prostu łatwiejsze. Po wyznaczeniu
wszystkich par stanów rozróżnialnych pozostałe pary stanowić będą
stany równoważne.


# Monoid przejść automatu </math>{A} <math> jest izomorficzny z monoidem ilorazowym </math>A^{*}/_{Ker_{ _{{A}}}} <math>.
W algorytmie wykorzystywać będziemy tablicę list </math>{L}[p,q]<math>,
Jest to wniosek z twierdzenia o rozkładzie epimorfizmu, które w tym przypadku ilustruje poniższy diagram.
po jednej liście dla każdej pary stanów. Funkcja
</math>'''initialize'''({L}[p,q])<math> inicjalizuje listę pustą,
funkcja </math>'''zdejmij'''({L}[p,q])<math> zdejmuje jeden z
elementów, natomiast funkcja
</math>'''włóż'''({L}[p,q],x)<math> wkłada element </math>x<math> na listę
</math>{L}[p,q]<math>. Funkcja </math>'''empty'''({L}[p,q])<math>
zwraca wartość </math>'''true'''<math> gdy lista jest pusta, oraz
</math>'''false'''<math> w przeciwnym wypadku. Zwróćmy uwagę, że elementami
każdej z list </math>{L}[p,q]<math> są pary stanów </math>(s,t) S S<math>.


rys3.5
\newpage
\endcorol
 
{{cwiczenie|[Uzupelnij]||
 
Określimy monoid przejść dla automatu z przykładu [[##ex.3.1.1|Uzupelnic ex.3.1.1|]]. Wypisujemy kolejne
funkcje </math> _{{A}}(w) <math> dla </math>w a,b^{*} <math>. Zauważmy,
że ze względu na występujące w tabelce powtórzenia będace wynikiem równości,
np. </math> _{{A}}(b^2)<nowiki>=</nowiki> _{{A}}(b), <math> nie ma potrzeby
określać funkcji </math> _{{A}}(b^{n}) <math> dla </math>n 3 <math>. Podobna
obserwacja ma miejsce w innych przypadkach, co sprawia, że tabelka zawiera skończoną
liczbę różnych funkcji.
 
\vspace{0.3cm}
{\centering \begintabular {|c||c|c|c|}
\hline
&
</math>s_{0} <math>&
</math>s_{1} <math>&
</math>s_{2} <math>\\
\hline
\hline
</math> _{{A}}(1) <math>&
</math>s_{0} <math>&
</math>s_{1} <math>&
</math>s_{2} <math>\\
\hline
</math> _{{A}}(a) <math>&
</math>s_{1} <math>&
</math>s_{2} <math>&
</math>s_{2} <math>\\
\hline
</math> _{{A}}(b) <math>&
</math>s_{0} <math>&
</math>s_{0} <math>&
</math>s_{0} <math>\\
\hline
</math> _{{A}}(a^{2}) <math>&
</math>s_{2} <math>&
</math>s_{2} <math>&
</math>s_{2} <math>\\
\hline
</math> _{{A}}(ab) <math>&
</math>s_{0} <math>&
</math>s_{0} <math>&
</math>s_{2} <math>\\
\hline
</math> _{{A}}(ba) <math>&
</math>s_{1} <math>&
</math>s_{1} <math>&
</math>s_{1} <math> \\
\hline
</math> _{{A}}(b^{2}) <math>&
</math>s_{0} <math>&
</math>s_{0} <math>&
</math>s_{0} <math>\\
\hline
</math> _{{A}}(aba) <math>&
</math>s_{1} <math>&
</math>s_{1} <math>&
</math>s_{2} <math>\\
\hline
...&
...&
...&
...\\
\hline
\endtabular \par}
\vspace{0.3cm}
 
</math></center>M({A})<nowiki>=</nowiki>  _{{A}}(1), _{{A}}(a), _{{A}}(b),
_{{A}}(a^2), _{{A}}(b),  _{{A}}(ba),  _{{A}}(aba)
.<center><math>
 
}}
 
Poniżej zamieszczamy algorytm obliczający monoid przejść dla automatu skończenie stanowego.


\beginalgorithm   
\beginalgorithm   
\caption{\textsc{WyznaczMonoidPrzejść} - wyznacza monoid przejść dla
\caption{\textsc{Minimalizuj3} -- algorytm minimalizacji
automatu}
wykorzystujący relację }
\beginalgorithmic [1]
\beginalgorithmic [1]
\STATE Wejście: </math>{A}<nowiki>=</nowiki>(S, A, f, s_0, T)<math> - automat
\STATE Wejście: </math>{A}<nowiki>=</nowiki>(S, A, f, s_0, T)<math> -- automat


\STATE Wyjście: </math>M<math> - monoid przejść dla </math>{A}<math>
\STATE Wyjście: </math>{A}'<nowiki>=</nowiki>(S', A, f', s_0', T')<math> -- automat
minimalny taki, że </math>L({A}')<nowiki>=</nowiki>L({A})<math>.


\STATE </math>L <math>; </math>  L<math> jest listą
\FOR{\textbf{each} </math>p T<math>}


\STATE </math>M <math>;
\FOR{\textbf{each} </math>q S  T<math>}


\FOR{</math>a  A 1<math>}
\STATE \textbf{zaznaczone}</math>[p,q] 1<math>;


\STATE \textbf{insert}</math>(L, _{{A}}(a))<math>;  gdzie
\STATE \textbf{initialize}(</math>{L}[p,q]<math>)
</math>_{{A}}(a)(s)<nowiki>=</nowiki>f(s, a)<math> dla każdego </math>s  S<math>


\ENDFOR
\ENDFOR


\WHILE{</math>L  <nowiki>=</nowiki> <math>;}
\ENDFOR


\STATE </math>_{{A}}(w)  '''first'''(L)<math>;
\FOR{</math>'''each'''(p,q)  (T  T)  ((S  T)
(S  T))<math>}


\STATE </math>M  M _{{A}}(w)<math>;
\STATE \textbf{zaznaczone}</math>[p,q] 0<math>;


\FOR{</math>a A<math>}
\ENDFOR
 
\FOR{</math>'''each ''' (p,q) (T  T)  ((S  T)
(S  T))<math>}


\STATE </math> s  S'_{{A}}(wa)(s)<nowiki>=</nowiki>f(_{{A}}(w)(s),a)<math>;
\STATE flag\textbf{false}


\IF{</math>'_{{A}}(wa)  L  M<math>}
\FOR{\textbf{each } </math>A<math>}


\STATE \textbf{insert}</math>(L, '_{{A}}(wa))<math>;
\IF{ \textbf{zaznaczone}</math>[f(p,a),f(q,a)]<nowiki>=</nowiki>1<math>}
\STATE flag\textbf{true};


\ENDIF
\ENDIF
\ENDFOR


\ENDFOR
\IF{flag=\textbf{true}}


\ENDWHILE
\STATE \textsc{Oznacz}</math>(p,q)<math>;\hfill  para
</math>(f(p,a),f(q,a))<math> była oznaczona dla pewnego </math>a<math>;


\RETURN </math>M<math>;
\ELSE


\endalgorithmic
\FOR{\textbf{each } </math>a  A<math>}
\endalgorithm


\eject
\IF{</math>f(p,a) f(q,a)<math>}


Procedura \textbf{insert}</math>(L, x)<math> wkłada na koniec listy </math>L<math> element
\STATE \textbf{włóż}</math>({L}[p,q],(f(p,a),f(q,a)))<math>;
</math>x<math>. Funkcja \textbf{first}</math>(L)<math> wyjmuje pierwszy element znajdujący
się na liście </math>L<math> i zwraca go. Algorytm działa w następujący sposób:
najpierw na listę </math>L<math> wkładane są elementy monoidu przejść
</math>_{{A}}(a)<math> dla każdej litery </math>a  A  1<math>. Te
funkcje można obliczyć bezpośrednio z tabelki reprezentującej
funkcję przejścia automatu </math>{A}<math>. Następnie z listy po kolei
ściągane są poszczególne funkcje </math>_{{A}}(w)<math>. Każda z
nich dodawana jest do zbioru </math>M<math>, a następnie algorytm sprawdza dla
każdej litery </math>a  A<math>, czy funkcja </math>_{{A}}(wa)<math>
istnieje już na liście </math>L<math> lub w zbiorze </math>M<math>. Jeśli nie, to funkcja
ta dodawana jest do listy. Procedura powyższa trwa do czasu, gdy
lista </math>L<math> zostanie pusta. Wtedy wszystkie elementy monoidu przejść
znajdą się w zbiorze </math>M<math>.


Przeanalizujmy działanie algorytmu dla automatu z przykładu
\ENDIF
[[##ex.3.1.1|Uzupelnic ex.3.1.1|]].


Na początku na listę </math>L<math> włożone zostaną funkcje
\ENDFOR
</math>_{{A}}(1)<math>, </math>_{{A}}(a)<math> oraz
</math>_{{A}}(b)<math>. Z listy zdejmujemy funkcję
</math>_{{A}}(1)<math> i dodajemy ją do zbioru </math>M<math>. Ponieważ
</math> a  A_{{A}}(1a)<nowiki>=</nowiki>_{{A}}(a)<math>, a
funkcje </math>_{{A}}(a)<math> oraz </math>_{{A}}(b)<math>
znajdują się już na liście, zatem nie dodajemy ich do </math>L<math>. Bierzemy
kolejny element listy, </math>_{{A}}(a)<math>, dodajemy go do </math>M<math> i
obliczamy funkcje </math>_{{A}}(aa)<math> oraz
</math>_{{A}}(ab)<math>. Ponieważ </math>_{{A}}(aa)<math> nie jest
tożsama z żadną funkcją ze zbioru </math>L  M<math>, dodajemy ją do listy.
Funkcja </math>_{{A}}(ab)<math> również nie jest równa żadnej z
funkcji należących do zbioru </math>L  M<math>, zatem wstawiamy ją na
koniec listy. Na liście </math>L<math> mamy zatem teraz następujące elementy:
</math>_{{A}}(b)<math>, </math>_{{A}}(a^2)<math> oraz
</math>_{{A}}(ab)<math>. Zdejmujemy z listy funkcję
</math>_{{A}}(b)<math>, dodajemy ją do </math>M<math> i obliczamy
</math>_{{A}}(ba)<math> oraz </math>_{{A}}(bb)<math>. Pierwsza z
tych funkcji jest nowa, tzn. nie jest tożsama z żadną funkcją ze
zbioru </math>L  M<math> więc dodajemy ją na koniec listy. Druga z nich
równa jest funkcji </math>_{{A}}(b)<math>, więc nie dodajemy jej do
listy. W tym momencie zbiór </math>M<math> zawiera następujące elementy:
</math>_{{A}}(1)<math>, </math>_{{A}}(a)<math>,
</math>_{{A}}(b)<math>, natomiast lista zawiera elementy
</math>_{{A}}(a^2)<math>, </math>_{{A}}(ab)<math>,
</math>_{{A}}(ba)<math>. Zdejmujemy z </math>L<math> funkcję
</math>_{{A}}(a^2)<math>, dodajemy ja do </math>M<math> i ponieważ
</math>_{{A}}(a^2a)<nowiki>=</nowiki>_{{A}}(a^2)<math> i
</math>_{{A}}(a^2b)<nowiki>=</nowiki>_{{A}}(b)<math> nic nie dodajemy do
</math>L<math>. Zdejmujemy teraz z listy funkcję </math>_{{A}}(ab)<math>,
dodajemy ją do </math>M<math> i ponieważ </math>_{{A}}(aba)<math> nie należy
do </math>L  M<math> dodajemy ją do listy.
</math>_{{A}}(abb)<nowiki>=</nowiki>_{{A}}(b)<math>, więc tej funkcji
nie dodajemy do </math>L<math>. Z </math>L<math> ściągamy </math>_{{A}}(ba)<math>,
dodajemy ją do </math>M<math> i widzimy, że
</math>_{{A}}(baa)<nowiki>=</nowiki>_{{A}}(a^2)<math> oraz
</math>_{{A}}(bab)<nowiki>=</nowiki>_{{A}}(b)<math>, więc nic nie
dodajemy do </math>L<math>. Na liście pozostała funkcja
</math>_{{A}}(aba)<math>. Ściągamy ją z listy i dodajemy do </math>M<math>.
Widzimy, że </math>_{{A}}(abaa)<nowiki>=</nowiki>_{{A}}(a^2)<math> i
</math>_{{A}}(abab)<nowiki>=</nowiki>_{{A}}(b)<math>, zatem nic nie
dodajemy do listy </math>L<math>. Lista jest w tym momencie pusta i działanie
algorytmu zakończyło się. Ostatecznie mamy
</math></center>M({A})<nowiki>=</nowiki> _{{A}}(1),_{{A}}(a),
_{{A}}(b),_{{A}}(a^2),_{{A}}(ab),
_{{A}}(ba),_{{A}}(aba).<center><math>
Co zgadza się z wynikiem otrzymanym w przykładzie.


Twierdzenie poniższe zbiera dotychczas uzyskane charakteryzacje języków rozpoznawanych.
\ENDIF


\begintheor 
\ENDFOR


Niech </math> L A^* <math> będzie dowolnym językiem. Równoważne są następujące warunki:
\STATE </math>S' S _<math>;\hfill
relacja  jest dopełnieniem tabeli </math>'''zaznaczone'''<math>


#  Język </math> L <math> jest rozpoznawalny,
\FOR{\textbf{each} </math>[s]_{ }  S _<math>}


#  Język </math> L <math> jest sumą wybranych klas równoważności pewnej prawej
\FOR{\textbf{each} </math>a A<math>}
kongruen\-cji na </math> A^* <math> o skończonym indeksie: </math></center>L <nowiki>=</nowiki> _{w L}[w]_.<center><math>


#  Język </math> L <math> jest sumą wybranych klas równoważności pewnej
\STATE </math>f'([s]_{},a)  [f(s,a)]_{}<math>;
kongruencji  na </math> A^* <math> o skończonym indeksie: </math></center>L <nowiki>=</nowiki> _{w L}[w]_.<center><math>


#  Istnie\-je skończony monoid </math> M <math> i istnie\-je epimorfizm </math> : A^*  M<math> taki,
\ENDFOR
że </math></center>L <nowiki>=</nowiki> ^{-1}( (L)).<center><math>


\endtheor
\ENDFOR


\beginprf
\STATE </math>s_0'  [s_0]_{}<math>;


Dowód równoważności czterech powyższych warunków przeprowa\-dzi\-my zgodnie z następującym schematem:
\STATE </math>T'  [t]_{}:t  T<math>;


</math></center>[[##tg|Uzupelnic tg|]][[##tf|Uzupelnic tf|]][[##te|Uzupelnic te|]][[##td|Uzupelnic td|]]  [[##tg|Uzupelnic tg|]]<center><math>
\RETURN </math>{A}'<nowiki>=</nowiki>(S', A, f', s_0', T')<math>;


[[##tg|Uzupelnic tg|]] [[##tf|Uzupelnic tf|]]
\endalgorithmic
\endalgorithm


Dany jest homomorfizm </math></center>: A^*  M, <center><math> gdzie </math>M<math> jest skończonym monoidem.\\
Występujaca w algorytmie procedura \textsc{Oznacz} opisana jest poniżej.
Określamy relację  na </math>A^*<math>, przyjmując dla dowolnych </math> u, v  A^* </center>u    v    (u) <nowiki>=</nowiki>  (v).<center><math>
Tak określona relacja jest kongruencją.  Natomiast jej skończony indeks wynika z faktu, że monoid </math> M <math> jest skończony.
Pokażemy teraz, że:


</math></center>L <nowiki>=</nowiki> _{w L}[w]_ .<center><math> Inkluzja  jest oczywista.\\
\beginalgorithm
Inkluzja w przeciwną stronę (</math>L  _{w L}[w]_,<math>) oznacza, że każda klasa równoważności relacji
\beginalgorithmic [1]
albo cała zawiera się w języku </math>L<math>, albo cała zawiera się w uzupełnieniu języka </math>L<math>.\\
Załóżmy, że </math> u  [w]_<math> dla pewnego </math> w  L. <math>
Oznacza to, że
</math></center>u    w  (u) <nowiki>=</nowiki>  (w)  (L)
u  ^{-1}( (u))  ^{-1}( (L)) <nowiki>=</nowiki> L.<center><math>
Implikuje to ostatecznie, że </math>u  L<math>.


[[##tf|Uzupelnic tf|]] [[##te|Uzupelnic te|]]
\STATE \textbf{procedure} \textsc{Oznacz}</math>(p,q  S)<math>


Każda kongruencja jest prawą kongruencją.
\IF{\textbf{zaznaczone}</math>[p,q]<nowiki>=</nowiki>1<math>}
\STATE{ \textbf{return}}
\ENDIF


[[##te|Uzupelnic te|]] [[##td|Uzupelnic td|]]
\STATE{\textbf{zaznaczone}</math>[p,q] 1<math>}


Niech  będzie prawą kongruencją o skończonym indeksie na </math> A^* <math> taką, że
\WHILE{\textbf{not empty}</math>({L}[p,q])<math>}
</math></center>L <nowiki>=</nowiki> _{w L}[w]_ .<center><math>
\STATE{\textsc{Oznacz}(\textbf{zdejmij}</math>({L}[p,q])<math>)}
Automat </math>{A}_{ } <nowiki>=</nowiki> (A^*/,f^*,[1]_,T),<math> dla którego
\ENDWHILE


</math></center>f^*([w]_,u) <nowiki>=</nowiki>[wu]_ ,  T <nowiki>=</nowiki>  [w]_  :  w  L <center><math> akceptuje język </math>L<math>.
\STATE \textbf{end procedure}
\endalgorithmic
\endalgorithm


[[##td|Uzupelnic td|]] [[##tg|Uzupelnic tg|]]
Działanie algorytmu łatwo przedstawić na tabelce, która
złożona jest z kwadratów -- pól, odpowiadających parom stanów automatu.
Fakt znalezienia przez algorytm pary stanów rozróżnialnych
zaznaczamy symbolem "x" w polu tabelki odpowiadającym tej parze, co
wykorzystamy w przykładzie.


Niech język </math> L<nowiki>=</nowiki>L({A}) <math>, gdzie  </math>{A} <nowiki>=</nowiki> (S,f,s_0,T)<math>.\\
{{cwiczenie|[Uzupelnij]||
Określamy odwzorowanie


</math></center> :A^{*} A^{*}/_{Ker _{{A}}}, <center><math>
Zminimalizujemy automat przedstawiony na rysunku
[[##ja-lekcja5-w-rys4|Uzupelnic ja-lekcja5-w-rys4|]], używając algorytmu \textsc{Minimalizuj3}.


przyjmując dla każdego </math>v A^{*} </center> (v)<nowiki>=</nowiki>[v]_{Ker _{{A}}}. <center><math>
RYSUNEK ja-lekcja5-w-rys4


Jest to odwzorowanie kanoniczne monoidu </math> A^* <math> na monoid ilorazowy, a więc jest to epimorfizm.\\
Proces działania algorytmu i konstrukcji tabelki przedstawiony jest
</math>A^{*}/_{Ker _{{A}}} <math> jest monoidem skończonym, ponieważ </math> S <math> jest zbiorem skończonym.
na poniższej animacji
}}


Dla dowodu równości </math>L <nowiki>=</nowiki> ^{-1}( (L))<math> wystarczy udowodnić
TUTAJ ANIMACJA. Opis animacji znajduje się w pliku
inkluzję </math>L  ^{-1}( (L))<math>. (Inkluzja </math> L  ^{-1}( (L))<math>
ja-lekcja5-w-anim1.pdf. Wygląd ekranu animacji znajduje się w pliku
wynika z~definicji przeciwobrazu.) \\
ja-lekcja5-w-anim1.jpg.\\
Niech </math> u  ^{-1}( (L)) .<math> Oznacz to, że


</math></center> {c}
Wypełniona tabelka po zakończeniu działania algorytmu przedstawiona
(u)  (L)  v L : (u)<nowiki>=</nowiki> (v)
jest na rysunku [[##ja-lekcja5-w-rys5|Uzupelnic ja-lekcja5-w-rys5|]].
v L : [u]_{_{Ker _{{A}}}}<nowiki>=</nowiki>[v]_{_{Ker _{{A}}}}  <br>
v L :  _{{A}}(u)<nowiki>=</nowiki> _{{A}}(v) ,
v L :  s  S f(s,u)<nowiki>=</nowiki>f(s,v)


<center><math>
RYSUNEK ja-lekcja5-w-rys5.


W szczególności  </math></center> f(s_0,u) <nowiki>=</nowiki> f(s_0,v)  T, <center><math> czyli  </math>u  L.<math>
Z tabelki odczytujemy, że stanami równoważnymi są stany </math>s_1, s_5<math>,
stany </math>s_2, s_8<math> oraz stany </math>s_4, s_6<math>. Automat minimalny
przedstawiony jest na rysunku [[##ja-lekcja5-w-rys6|Uzupelnic ja-lekcja5-w-rys6|]].


\begincenter  \endcenter  \endprf</math>
RYSUNEK ja-lekcja5-w-rys6.</math>

Wersja z 12:57, 15 sie 2006

{theor}{TWIERDZENIE}[section] {rem}{UWAGA}[section] {corol}{WNIOSEK}[section] {fact}{FAKT}[section] {ex}{PRZYKŁAD}[section] {defin}{DEFINICJA}[section] {lem}{LEMAT}[section]

{prf}{DOWÓD}

{algorithm}{Algorytm}

{procedure}{Procedura}

{ Algorytmy konstrukcji automatu minimalnego }

Wprowadzenie
W tym wykładzie podamy algorytmy konstrukcji automatu minimalnego

i twierdzenia dowodzące ich poprawności.

Słowa kluczowe
automat minimalny, pochodna Brzozowskiego, algorytmy

minimalizacji.

algorytmy konstrukcji automatu minimalnego

Dla języka rozpoznawanego L konstrukcję automatu minimalnego można rozpocząć, startując z opisu języka danego na przykład przez wyrażenie regularne lub też jakiegoś automatu rozpoznającego ten język. W niniejszym wykładzie przedstawimy algorytmy konstrukcji automatu minimalnego obejmujące oba wspomniane punkty startu. Jako pierwszy, nawiązując do rezulatów przedstawionych w poprzednim wykładzie, prezentujemy algorytm, dla którego punktem wyjścia jest język L. Prezentację poprzedzimy wprowadzeniem pewnej operacji na słowach zwanej pochodną J.Brzozowskiego.

Niech LA* będzie dowolnym językiem, a uA* dowolnym słowem. Pochodną Brzozowskiego (residuum) z języka L względem słowa u nazywamy język

u1L={wA*:uwL}.

Podczas obliczeń pochodnych Brzozowskiego (residuów języka L) można wykorzystać poniższe równości.

Niech L1,L2A* będą dowolnymi językami, aA dowolną literą, a u,vA* dowolnymi słowami. Prawdziwe są następujące równości:

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \aligned\nonumber u^{-1}(L_1 \cup L_2) & = & u^{-1}L_1 \cup u^{-1}L_2, \\ \nonumber u^{-1}(L_1 \backslash L_2) & = & u^{-1}L_1 \backslash u^{-1}L_2, \\ \nonumber u^{-1}(L_1 \cap L_2) & = & u^{-1}L_1 \cap u^{-1}L_2, \\ \nonumber a^{-1}(L_1L_2) & = & (a^{-1}L_1)L_2 \mbox{, jeśli } 1 \notin L_1, \\ \nonumber a^{-1}(L_1L_2) & = & (a^{-1}L_1)L_2 \cup a^{-1}L_2 \mbox{, jeśli } 1 \in L_1, \\ \nonumber a^{-1}L^* & = & (a^{-1}L)L^*, \\ \nonumber v^{-1}(u^{-1}L) & = & (uv)^{-1}L. \endaligned}

Ćwiczenie [Uzupelnij]

Obliczmy wszystkie pochodne dla języka L=a+b+. Okazuje się, że są tylko cztery różne pochodne liczone względem a, b, ab i słowa pustego 1. Mianowicie:
a1L=a*b+,
b1L=,
ab1L=b*,
11L=L.
Dla wszystkich innych słów otrzymujemy uzyskane powyżej języki, co wynika z własności pochodnych (patrz wyżej wypisane równości) i z następujacych obliczeń:
n(an)1L=a*b+,
n(bn)1L=,
n(abn)1L=b*.

Zauważmy również, nawiązując raz jeszcze do rezulatów przedstawionych w poprzednim wykładzie, że prawdziwa jest następująca równoważność wiążąca wprowadzone pojęcie pochodnej Brzozowskiego z prawą kongruencją syntaktyczną:

uPrLvu1L=v1L.

Rozpisując z definicji lewą stronę tej równoważności, otrzymujemy, iż dla dowolnego słowa zA* słowo uzL wtedy i tylko wtedy, gdy vzL. A to równoważnie oznacza (znów z definicji), że u1L=v1L.

Z uzasadnionej równoważności oraz twierdzenia 3.4 o prawej kongruencji syntaktycznej z poprzedniego wykładu wnioskujemy równoważność rozpoznawalności języka L i skończonej ilości różnych pochodnych Brzozowskiego tego języka.

Pierwszy z przedstawianych algorytmów będzie konstruował automat minimalny, wyznaczając prawą kongruencję automatową poprzez zastosowanie metody pochodnych Brzozowskiego. Metoda ta umożliwia przeprowadzanie odpowiednich obliczeń bezpośrednio na wyrażeniach regularnych. Ogólny opis algorytmu jest następujący. Stany konstruowanego automatu minimalnego etykietowane są zbiorami odpowiadającymi pewnym językom. Mając dany język L, ustanawiamy stan początkowy automatu jako L, wpisujemy go na listę i obliczamy a1L dla każdej litery aA. Jeśli wśród obliczonych wartości znajduje się język niewystępujący na liście, dodajemy go do listy. Obliczenia pochodnych Brzozowskiego wykonujemy, dopóki będziemy uzyskiwać nowe języki (nowe stany). Funkcja przejść konstruowanego automatu minimalnego zdefiniowana jest następująco:

f(X,a)=a1X,

gdzie

X

jest pewnym językiem z listy

.

Obliczone języki określają stany automatu minimalnego.


dla dociekliwych - start ----

Obliczone języki określające stany automatu minimalnego to elementy monoidu syntaktycznego języka L.


dla dociekliwych - end ----

Automatem minimalnym dla automatu 𝒜=(S,A,f,s0,T) będzie zatem automat

𝒜L=(SL,A,fL,s0L,TL),

gdzie:

  • SL={u1L: uA*},
  • s0L=L,
  • TL={u1L: uL},
  • fL(u1L,a)=a1(u1L)=(ua)1L.

Jeśli zdefiniujmy odwzorowanie ν:SSL, kładąc:

ν(s)=u1L, gdzie s=f(s0,u),

to można dowieść,

że ν jest dobrze określone, jest epimorfizmem oraz ν(s0)=s0L - porównaj twierdzenie 3.1 z wykładu 4. Prawdą jest też, iż sT wtedy i tylko wtedy, gdy ν(s)TL oraz że następujący diagram komutuje:

Parser nie mógł rozpoznać (nieznana funkcja „\beginCD”): {\displaystyle \beginCD s @>{a}>> s' @. \ \ \ \ \mbox{ w } \mathcal{A} \\ @V{\nu}VV @V{\nu}VV \\ u^{-1}L @>{a}>> (ua)^{-1}L @. \ \ \ \ \mbox{ w } \mathcal{A}_L. \endCD }

Formalny zapis algorytmu przedstawiony jest poniżej.

{{Minimalizuj1} - algorytm minimalizacji wykorzystujący pochodne Brzozowskiego} [1] Wejście: 𝒜=(S,A,f,s0,T) - automat taki, że L=L(𝒜)

Wyjście: automat minimalny 𝒜=(SL,A,fL,sL,TL) dla 𝒜SL{L};

włóż(,L);

{=}

M zdejmij();

{each aA}

Na1M;

{NSL= }

SLSL{N};

włóż(,N);

{each MSL}

{each aA}

fL(M,a)a1M;

sLL;

TL{u1L: uL};

𝒜;

Funkcja zdejmij(), występująca w linii 6., zdejmuje z kolejki pierwszy element i zwraca go jako swoją wartość. Procedura włóż(,L), występująca w liniach 4. oraz 11., wstawia na koniec kolejki element L.

Ćwiczenie [Uzupelnij]

Dla języka L=a+b+ z przykładu 1.1 w wyniku działania powyższego algorytmu otrzymamy czterostanowy automat 𝒜L=(SL,A,f,L,T), gdzie
SL={L,a*b+,,b*},
a funkcja przejść zadana jest grafem:

RYSUNEK ja-lekcja5-w-rys1

Prezentowane poniżej twierdzenie uzasadnia kolejny algorytm konstrukcji automatu minimalnego. Tym razem punktem wyjścia jest dowolny automat rozpoznający język L.


dla dociekliwych - start -----

Algorytm oblicza również monoid syntaktyczny języka L.


dla dociekliwych - end -----

Analogicznie do konstrukcji relacji ρi, przedstawionej w wykładzie 4, możemy określić ciąg odpowiednich relacji na zbiorze stanów dowolnego automatu rozpoznającego język L. Relacje te służą do efektywnego określenia automatu minimalnego, równoważnego zadanemu.

Niech

𝒜

= (S,A,f,s_0,T)Parser nie mógł rozpoznać (błąd składni): {\displaystyle będzie dowolnym automatem i niech } L=L({A})

.Przez

_Szablon:A S S Parser nie mógł rozpoznać (błąd składni): {\displaystyle oznaczmy relację równoważności zawierającą dwie klasy równoważności } T

i

S T

.Przez

{}_i

dla

i { N} Parser nie mógł rozpoznać (błąd składni): {\displaystyle oznaczmy zstępujący ciąg relacji określony następująco: } {}_1 = _Szablon:A

,adla

i = 2,...

przyjmijmy

{}_i = (s,t) S S  : a A 1 f(s,a) {}_{i-1} f(t,a) . Parser nie mógł rozpoznać (nieznana funkcja „\par”): {\displaystyle {\par\raggedright Wtedy } {}_i Parser nie mógł rozpoznać (błąd składni): {\displaystyle jest największą prawą kongruencją automatową zawartą w relacji } {}_1 = _Szablon:A Parser nie mógł rozpoznać (błąd składni): {\displaystyle i automat minimalny ma postać\par} } {A}_{L}=( S/_{ { }_{i}},A,f^{*},[s_{0}],T/_{ { }_{i}}) .

Parser nie mógł rozpoznać (nieznana funkcja „\endtheor”): {\displaystyle \endtheor Dowód tego twierdzenia przebiega analogicznie do dowodu twierdzenia 3.3 z wykładu 4. Algorytm działajacy w oparciu o powyższe twierdzenie na podstawie zadanego automatu } {A}=(S, A, f, s_0, T),konstruujeefektywnieautomatminimalnydla{A}Parser nie mógł rozpoznać (błąd składni): {\displaystyle , obliczając ciąg relacji } {}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle . Proces konstrukcji przebiega w sposób iteracyjny. Zaczynamy od zdefiniowania relacji } _Szablon:AParser nie mógł rozpoznać (błąd składni): {\displaystyle , która posiada tylko dwie klasy abstrakcji: do pierwszej z nich należą wszystkie stany końcowe, a do drugiej -- wszystkie pozostałe stany. Tak więc }

s, t Ss _Szablon:A t (s T t T) (s S T t S T).

Parser nie mógł rozpoznać (błąd składni): {\displaystyle Definiujemy pierwszą z relacji } {}Parser nie mógł rozpoznać (błąd składni): {\displaystyle , czyli relację } {}_1Parser nie mógł rozpoznać (błąd składni): {\displaystyle jako równą } _Szablon:AParser nie mógł rozpoznać (błąd składni): {\displaystyle , a następnie, dla każdej obliczonej już relacji } {}_{i-1}Parser nie mógł rozpoznać (błąd składni): {\displaystyle , obliczamy relację } {}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle w następujący sposób: }

s_1 {}_i

s_2 (s_1 {}_{i-1} s_2) (

a Af(s_1, a) {}_{i-1} f(s_2,a)).

Nowoobliczonarelacja{}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle albo podzieli jedną lub kilka klas abstrakcji relacji } {}_{i-1}Parser nie mógł rozpoznać (błąd składni): {\displaystyle , albo będzie identyczna z relacją } {}_{i-1}Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Jeśli zajdzie ta druga sytuacja, to znaczy, że dla każdego } j>iParser nie mógł rozpoznać (błąd składni): {\displaystyle w oczywisty sposób spełniona jest równość } {_j}={}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle , czyli ciąg relacji ustabilizuje się. W tym momencie algorytm kończy swoje działanie i klasy abstrakcji relacji } {}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle będą reprezentować stany automatu minimalnego. \newpage \beginalgorithm \caption{\textsc{Minimalizuj2} -- algorytm minimalizacji automatu wykorzystujący stabilizujący się ciąg relacji} \beginalgorithmic [1] \STATE Wejście: } {A}=(S, A, f, s_0, T)Parser nie mógł rozpoznać (błąd składni): {\displaystyle -- automat taki, że } L=L({A})Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle . \STATE Wyjście: automat minimalny } {A}'=(S',A',f', s_0',

T')dla{A}Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle . \STATE } {}_1_Szablon:AParser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle ; \STATE } i 1Parser nie mógł rozpoznać (nieznana funkcja „\REPEAT”): {\displaystyle ; \REPEAT \STATE oblicz } {}_i:s_1 {}_i s_2 (s_1 {}_{i-1} s_2) ( a Af(s_1, a) {}_{i-1} f(s_2,a))Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle ; \STATE } i i+1Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle ; \STATE \textbf{empty}} ({}_i)Parser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle \FOR{\textbf{each} } (s_1,s_2) S SParser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE flag\textbf{true}; \FOR{\textbf{each} } a AParser nie mógł rozpoznać (nieznana funkcja „\IF”): {\displaystyle } \IF{\textbf{not} } f(s_1, a) {}_{i-1} f(s_2,a)Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE flag\textbf{false}; \ENDIF \ENDFOR \IF{flag=\textbf{true} \textbf{and} } s_1 {}_{i-1} s_2Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE } {}_{i} {}_{i} (s_1,s_2)Parser nie mógł rozpoznać (nieznana funkcja „\ENDIF”): {\displaystyle ; \ENDIF \ENDFOR \UNTIL{} {}_i = {}_{i-1}Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE } S' S {}_iParser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle ; \FOR{\textbf{each} } [s]_{{}_i} S {}_iParser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle } \FOR{\textbf{each} } a AParser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE } f'([s]_{{}_i},a) [f(s,a)]_{{}_i}Parser nie mógł rozpoznać (nieznana funkcja „\ENDFOR”): {\displaystyle ; \ENDFOR \ENDFOR \STATE } s_0' [s_0]_{{}_i}Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle ; \STATE } T' [t]_{{}_i}:t TParser nie mógł rozpoznać (nieznana funkcja „\RETURN”): {\displaystyle ; \RETURN } {A}'=(S', A, f', s_0', T')Parser nie mógł rozpoznać (nieznana funkcja „\endalgorithmic”): {\displaystyle ; \endalgorithmic \endalgorithm {{cwiczenie|[Uzupelnij]|| Zminimalizujemy automat } {A}=(S,A,f,s_0,T)Parser nie mógł rozpoznać (błąd składni): {\displaystyle , dla którego\\ } S= s_{0},s_{1},s_{2},s_{3},s_{4},s_5 , A=a,b,

T=s_1, s_{2},s_{4} Parser nie mógł rozpoznać (błąd składni): {\displaystyle , a funkcja przejść określona jest przy pomocy grafu.\\ RYSUNEK ja-lekcja5-w-rys2\\ Konstruujemy ciąg relacji } {}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle . Na początku } {}_1dzieliSParser nie mógł rozpoznać (błąd składni): {\displaystyle na dwie klasy abstrakcji; pierwsza zawiera stany końcowe, a druga -- wszystkie pozostałe, czyli uzyskujemy dwa zbiory } s_1,s_2,s_4orazs_0, s_3, s_5.Obliczmy{}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle (pierwszy przebieg pętli w liniach 5.-20. algorytmu). Aby dwa elementy (stany) } sitParser nie mógł rozpoznać (błąd składni): {\displaystyle były ze sobą w relacji } {}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle muszą być ze sobą w relacji } {}_1Parser nie mógł rozpoznać (błąd składni): {\displaystyle oraz musi zachodzić }

a A f(s, a) {}_1 f(t,a).

Parser nie mógł rozpoznać (błąd składni): {\displaystyle Czyli kolejna, nowa relacja może ewentualnie podzielić już istniejące zbiory zdefiniowane przez poprzednią relację. Nie może więc zajść taka sytuacja, że w jednej klasie abstrakcji relacji } {}_{i+1}Parser nie mógł rozpoznać (błąd składni): {\displaystyle znajdą się elementy z różnych klas abstrakcji relacji } {}_iParser nie mógł rozpoznać (błąd składni): {\displaystyle . Rozważmy najpierw zbiór } s_1, s_2, s_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Oczywiście każde dwa stany z tego zbioru są ze sobą w relacji } {}_1Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Zauważmy, że } f(s_2, a)=f(s_4,a)=s_2,f(s_2,b)=f(s_4,b)=s_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle , więc } s_2 {}_2 s_4(bos_2 {}_1 s_2orazs_4 {}_1 s_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle ). Ponieważ } f(s_1,b)=s_5if(s_2,b)=s_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle , a wiemy, że } s_5niejestwrelacji{}_1zs_4,zatemstanys_1is_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle nie mogą być ze sobą w relacji } {}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle , a to oznacza, że także stany } s_1is_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle nie mogą być ze sobą w relacji } {}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle . W analogiczny sposób można sprawdzić, że relacja } {}_2niepodzielizbiorus_0, s_3, s_5Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Ostatecznie, po pierwszym wykonaniu pętli algorytmu minimalizacji obliczyliśmy relację } {}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle , która dzieli } SParser nie mógł rozpoznać (błąd składni): {\displaystyle na następujące podzbiory: }

s_1, s_2, s_4, s_0, s_3, s_5.

Wkolejnymkrokuobliczamy{}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Zbiór } s_1Parser nie mógł rozpoznać (błąd składni): {\displaystyle oczywiście nie może być już podzielony na mniejsze podzbiory. Łatwo zauważyć, że } {}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle nie podzieli także zbioru } s_2,

s_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Rozważmy teraz zbiór } s_0, s_3, s_5.Mamyf(s_3, a)=f(s_5, a)orazf(s_3, b)=s_3,f(s_5, b)=s_5Parser nie mógł rozpoznać (błąd składni): {\displaystyle i wiadomo, że } s_3 {}_2

s_5,zatems_3is_5Parser nie mógł rozpoznać (błąd składni): {\displaystyle będą ze sobą w relacji } {}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Ponieważ } f(s_0, a)=s_2if(s_3, a)=s_1,ales_2is_1Parser nie mógł rozpoznać (błąd składni): {\displaystyle nie są ze sobą w relacji } {}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle , zatem nie mogą być także ze sobą w relacji } {}_3.Relacja{}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle dzieli więc zbiór } s_0, s_3, s_5nazbiorys_0orazs_3, s_5Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Podział zbioru } SParser nie mógł rozpoznać (błąd składni): {\displaystyle przez relację } {}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle wygląda więc następująco: }

s_0, s_1, s_2, s_4, s_3, s_5.

Relacja{}_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle nie podzieli już ani zbioru } s_2,

s_4,anizbiorus_3, s_5Parser nie mógł rozpoznać (błąd składni): {\displaystyle , więc uzyskujemy równość } {_4}={}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle i ponieważ ciąg relacji się ustabilizował, algorytm kończy działanie. Podsumowując, mamy:  ; } {} _{1}:s_1, s_{2},s_{4}, s_{0},s_{3},s_5, ;{} _{2}:s_{1},s_2,s_{4}, s_{0},s_{3},s_5,;{} _{3}:s_{1},s_2,s_{4}, s_{0},s_{3},s_5.{} _{3}={} _{4}Parser nie mógł rozpoznać (błąd składni): {\displaystyle i równoważny minimalny automat } {A}_L=(S,f^*,s_0,T)ma4Parser nie mógł rozpoznać (błąd składni): {\displaystyle stany. \\ } q_0=s_{0}, q_1=s_{1}, q_2 = s_2,s_{4}, q_3

=s_{3},s_5,T=q_1 ,q_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Jak łatwo zauważyć jest to automat z przykładu 3.1 zamieszczonego w wykładzie 4. RYSUNEK ja-lekcja5-w-rys3 }} Jednym z najczęściej stosowanych algorytmów automatu minimalnego jest algorytm, który buduje "tabelkę" na podstawie której określa się automat minimalny. Poprawność tego algorytmu również uzasadnia twierdzenie [[##twrho|Uzupelnic twrho|]]. W algorytmie tym wyznaczać będziemy tzw. stany rozróżnialne. Algorytm działa w czasie } O(|A|n^2),gdzie|A|Parser nie mógł rozpoznać (błąd składni): {\displaystyle jest mocą alfabetu, a } nParser nie mógł rozpoznać (błąd składni): {\displaystyle -- liczbą stanów automatu wejściowego, czyli podlegajacego minimalizacji. Złożoność pamięciowa jest również } O(|A|n^2)Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Prezentowany algorytm nosi nazwę algorytmu Hopcrofta-Ullmana. Znana w literaturze jest pewna zmodyfikowana wersja tego algorytmu. Jest to algorytm Aho-Sethiego-Ullmana, który ma tę samą złożoność czasową, ale lepszą złożoność pamięciową - } O(|A|n)Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Natomiast w ramach ćwiczeń prezentujemy jeszcze jeden algorytm, znany jako algorytm minimalizacji Hopcrofta. Czas działania tego algorytmu wynosi } O(n n)Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Niech będzie relacją zdefiniowaną przez funkcję przejść automatu w następujący sposób: }

p q w A^* (f(p,w) T f(q,w) T).

Parser nie mógł rozpoznać (nieznana funkcja „\begindefin”): {\displaystyle \begindefin Stany } piqParser nie mógł rozpoznać (błąd składni): {\displaystyle są równoważne, jeśli } p qParser nie mógł rozpoznać (nieznana funkcja „\enddefin”): {\displaystyle . \enddefin Jeśli stany nie są równoważne, to będziemy mówić, że są rozróżnialne. Zadaniem algorytmu jest wyznaczenie stanów równoważnych, celem ich utożsamienia ze sobą. Algorytm musi zdecydować, dla każdej pary stanów } (p,q)Parser nie mógł rozpoznać (błąd składni): {\displaystyle , czy są one rozróżnialne. Jeśli pod koniec działania algorytmu okaże się, że nie stwierdziliśmy rozróżnialności tych stanów, to znaczy, że są one równoważne; następuje ich utożsamienie, czyli "połączenie" ich w jeden stan. Gdy takiego połączenia dokonamy dla wszystkich par stanów, wobec których nie stwierdziliśmy ich rozróżnialności, powstanie automat o minimalnej liczbie stanów. W praktyce algorytm nie wyznacza stanów równoważnych, ale stany rozróżnialne, gdyż jest to po prostu łatwiejsze. Po wyznaczeniu wszystkich par stanów rozróżnialnych pozostałe pary stanowić będą stany równoważne. W algorytmie wykorzystywać będziemy tablicę list } {L}[p,q]Parser nie mógł rozpoznać (błąd składni): {\displaystyle , po jednej liście dla każdej pary stanów. Funkcja } initialize({L}[p,q])Parser nie mógł rozpoznać (błąd składni): {\displaystyle inicjalizuje listę pustą, funkcja } zdejmij({L}[p,q])Parser nie mógł rozpoznać (błąd składni): {\displaystyle zdejmuje jeden z elementów, natomiast funkcja } włóż({L}[p,q],x)Parser nie mógł rozpoznać (błąd składni): {\displaystyle wkłada element } xParser nie mógł rozpoznać (błąd składni): {\displaystyle na listę } {L}[p,q].Funkcjaempty({L}[p,q])Parser nie mógł rozpoznać (błąd składni): {\displaystyle zwraca wartość } truegdylistajestpusta,orazfalseParser nie mógł rozpoznać (błąd składni): {\displaystyle w przeciwnym wypadku. Zwróćmy uwagę, że elementami każdej z list } {L}[p,q]Parser nie mógł rozpoznać (błąd składni): {\displaystyle są pary stanów } (s,t) S SParser nie mógł rozpoznać (nieznana funkcja „\newpage”): {\displaystyle . \newpage \beginalgorithm \caption{\textsc{Minimalizuj3} -- algorytm minimalizacji wykorzystujący relację } \beginalgorithmic [1] \STATE Wejście: } {A}=(S, A, f, s_0, T)Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle -- automat \STATE Wyjście: } {A}'=(S', A, f', s_0', T')Parser nie mógł rozpoznać (błąd składni): {\displaystyle -- automat minimalny taki, że } L({A}')=L({A})Parser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle . \FOR{\textbf{each} } p TParser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle } \FOR{\textbf{each} } q S TParser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE \textbf{zaznaczone}} [p,q] 1Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle ; \STATE \textbf{initialize}(} {L}[p,q]Parser nie mógł rozpoznać (nieznana funkcja „\ENDFOR”): {\displaystyle ) \ENDFOR \ENDFOR \FOR{} each(p,q) (T T) ((S T)

(S T))Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE \textbf{zaznaczone}} [p,q] 0Parser nie mógł rozpoznać (nieznana funkcja „\ENDFOR”): {\displaystyle ; \ENDFOR \FOR{} each (p,q) (T T) ((S T) (S T))Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE flag\textbf{false} \FOR{\textbf{each } } a AParser nie mógł rozpoznać (nieznana funkcja „\IF”): {\displaystyle } \IF{ \textbf{zaznaczone}} [f(p,a),f(q,a)]=1Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE flag\textbf{true}; \ENDIF \ENDFOR \IF{flag=\textbf{true}} \STATE \textsc{Oznacz}} (p,q)Parser nie mógł rozpoznać (nieznana funkcja „\hfill”): {\displaystyle ;\hfill para } (f(p,a),f(q,a))Parser nie mógł rozpoznać (błąd składni): {\displaystyle była oznaczona dla pewnego } aParser nie mógł rozpoznać (nieznana funkcja „\ELSE”): {\displaystyle ; \ELSE \FOR{\textbf{each } } a AParser nie mógł rozpoznać (nieznana funkcja „\IF”): {\displaystyle } \IF{} f(p,a) f(q,a)Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE \textbf{włóż}} ({L}[p,q],(f(p,a),f(q,a)))Parser nie mógł rozpoznać (nieznana funkcja „\ENDIF”): {\displaystyle ; \ENDIF \ENDFOR \ENDIF \ENDFOR \STATE } S' S _Parser nie mógł rozpoznać (nieznana funkcja „\hfill”): {\displaystyle ;\hfill relacja jest dopełnieniem tabeli } zaznaczoneParser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle \FOR{\textbf{each} } [s]_{ } S _Parser nie mógł rozpoznać (nieznana funkcja „\FOR”): {\displaystyle } \FOR{\textbf{each} } a AParser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE } f'([s]_{},a) [f(s,a)]_{}Parser nie mógł rozpoznać (nieznana funkcja „\ENDFOR”): {\displaystyle ; \ENDFOR \ENDFOR \STATE } s_0' [s_0]_{}Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle ; \STATE } T' [t]_{}:t TParser nie mógł rozpoznać (nieznana funkcja „\RETURN”): {\displaystyle ; \RETURN } {A}'=(S', A, f', s_0', T')Parser nie mógł rozpoznać (nieznana funkcja „\endalgorithmic”): {\displaystyle ; \endalgorithmic \endalgorithm Występujaca w algorytmie procedura \textsc{Oznacz} opisana jest poniżej. \beginalgorithm \beginalgorithmic [1] \STATE \textbf{procedure} \textsc{Oznacz}} (p,q S)Parser nie mógł rozpoznać (nieznana funkcja „\IF”): {\displaystyle \IF{\textbf{zaznaczone}} [p,q]=1Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE{ \textbf{return}} \ENDIF \STATE{\textbf{zaznaczone}} [p,q] 1Parser nie mógł rozpoznać (nieznana funkcja „\WHILE”): {\displaystyle } \WHILE{\textbf{not empty}} ({L}[p,q])Parser nie mógł rozpoznać (nieznana funkcja „\STATE”): {\displaystyle } \STATE{\textsc{Oznacz}(\textbf{zdejmij}} ({L}[p,q])Parser nie mógł rozpoznać (nieznana funkcja „\ENDWHILE”): {\displaystyle )} \ENDWHILE \STATE \textbf{end procedure} \endalgorithmic \endalgorithm Działanie algorytmu łatwo przedstawić na tabelce, która złożona jest z kwadratów -- pól, odpowiadających parom stanów automatu. Fakt znalezienia przez algorytm pary stanów rozróżnialnych zaznaczamy symbolem "x" w polu tabelki odpowiadającym tej parze, co wykorzystamy w przykładzie. {{cwiczenie|[Uzupelnij]|| Zminimalizujemy automat przedstawiony na rysunku [[##ja-lekcja5-w-rys4|Uzupelnic ja-lekcja5-w-rys4|]], używając algorytmu \textsc{Minimalizuj3}. RYSUNEK ja-lekcja5-w-rys4 Proces działania algorytmu i konstrukcji tabelki przedstawiony jest na poniższej animacji }} TUTAJ ANIMACJA. Opis animacji znajduje się w pliku ja-lekcja5-w-anim1.pdf. Wygląd ekranu animacji znajduje się w pliku ja-lekcja5-w-anim1.jpg.\\ Wypełniona tabelka po zakończeniu działania algorytmu przedstawiona jest na rysunku [[##ja-lekcja5-w-rys5|Uzupelnic ja-lekcja5-w-rys5|]]. RYSUNEK ja-lekcja5-w-rys5. Z tabelki odczytujemy, że stanami równoważnymi są stany } s_1, s_5,stanys_2, s_8orazstanys_4, s_6Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Automat minimalny przedstawiony jest na rysunku [[##ja-lekcja5-w-rys6|Uzupelnic ja-lekcja5-w-rys6|]]. RYSUNEK ja-lekcja5-w-rys6.}