Test GR3: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 366: | Linia 366: | ||
abstrakcji; pierwsza zawiera stany końcowe, a druga -- wszystkie | abstrakcji; pierwsza zawiera stany końcowe, a druga -- wszystkie | ||
pozostałe, czyli uzyskujemy dwa zbiory </math>s_1,s_2,s_4<math> oraz | pozostałe, czyli uzyskujemy dwa zbiory </math>s_1,s_2,s_4<math> oraz | ||
</math>s_0, s_3, s_5<math>. | </math>s_0, s_3, s_5<math>.Obliczmy </math>{}_2<math> (pierwszy przebieg pętli w liniach 5.-20. algorytmu). Aby dwa elementy | ||
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ą | (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ć | być ze sobą w relacji </math>{}_1<math> oraz musi zachodzić |
Wersja z 12:50, 17 sie 2006
{stre}{Streszczenie} {wsk}{Wskazówka} {rozw}{Rozwiązanie} {textt}{} {thm}{Twierdzenie}[section] {stw}[thm]{Stwierdzenie} {lem}[thm]{Lemat} {uwa}[thm]{Uwaga} {exa}[thm]{Example} {dfn}[thm]{Definicja} {wn}[thm]{Wniosek} {prz}[thm]{Przykład} {zadan}[thm]{Zadanie}
{} {}
{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 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 . Prezentację poprzedzimy wprowadzeniem pewnej operacji na słowach zwanej pochodną J.Brzozowskiego.
Niech będzie dowolnym językiem, a dowolnym słowem. Pochodną Brzozowskiego (residuum) z języka względem słowa nazywamy język
Podczas obliczeń pochodnych Brzozowskiego (residuów języka ) można wykorzystać poniższe równości.
Niech będą dowolnymi językami, dowolną literą, a dowolnymi słowami. Prawdziwe są następujące równości:
Ćwiczenie [Uzupelnij]
Obliczmy wszystkie pochodne dla języka . Okazuje się, że są tylko
cztery różne pochodne liczone względem , , i słowa pustego . Mianowicie:
,
,
,
.
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ń:
,
,
.
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ą:
Rozpisując z definicji lewą stronę tej równoważności, otrzymujemy, iż dla dowolnego słowa słowo wtedy i tylko wtedy, gdy . A to równoważnie oznacza (znów z definicji), że
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 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 , ustanawiamy stan początkowy automatu jako , wpisujemy go na listę i obliczamy dla każdej litery . 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:
gdzie
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 .
dla dociekliwych - end ----
Automatem minimalnym dla automatu będzie zatem automat
gdzie:
- ,
- ,
- ,
- .
Jeśli zdefiniujmy odwzorowanie , kładąc:
to można dowieść,
że jest dobrze określone, jest epimorfizmem oraz - porównaj twierdzenie 3.1 z wykładu 4. Prawdą jest też, iż wtedy i tylko wtedy, gdy oraz że następujący diagram komutuje:
Formalny zapis algorytmu przedstawiony jest poniżej.
{{Minimalizuj1} - algorytm minimalizacji wykorzystujący pochodne Brzozowskiego} [1] Wejście: - automat taki, że
Wyjście: automat minimalny dla ;
włóż;
{}
zdejmij;
{each }
;
{ }
;
włóż;
{each }
{each }
;
;
;
;
Funkcja zdejmij, występująca w linii 6., zdejmuje z kolejki pierwszy element i zwraca go jako swoją wartość. Procedura włóż, występująca w liniach 4. oraz 11., wstawia na koniec kolejki element .
Ćwiczenie [Uzupelnij]
Dla języka z przykładu 1.1 w wyniku działania powyższego algorytmu
otrzymamy czterostanowy automat
gdzie
,
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 .
dla dociekliwych - start -----
Algorytm oblicza również monoid syntaktyczny języka .
dla dociekliwych - end -----
Analogicznie do konstrukcji relacji , przedstawionej w wykładzie 4, możemy określić ciąg odpowiednich relacji na zbiorze stanów dowolnego automatu rozpoznającego język . 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})
_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
S T
{}_i
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
i = 2,...
{}_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}}) .
s, t Ss _Szablon:A t (s T t T) (s S T t S T).
s_1 {}_i
s_2 (s_1 {}_{i-1} s_2) (
a Af(s_1, a) {}_{i-1} f(s_2,a)).
T'){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 } {}_is_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 } {}_1SParser 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_4s_0, s_3, s_5{}_2Parser nie mógł rozpoznać (błąd składni): {\displaystyle (pierwszy przebieg pętli w liniach 5.-20. algorytmu). Aby dwa elementy (stany) } stParser 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).
s_1, s_2, s_4, s_0, s_3, s_5.
s_4Parser nie mógł rozpoznać (błąd składni): {\displaystyle . Rozważmy teraz zbiór } s_0, s_3, s_5f(s_3, a)=f(s_5, a)f(s_3, b)=s_3f(s_5, b)=s_5Parser nie mógł rozpoznać (błąd składni): {\displaystyle i wiadomo, że } s_3 {}_2
s_5s_3s_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_2f(s_3, a)=s_1s_2s_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{}_3Parser nie mógł rozpoznać (błąd składni): {\displaystyle dzieli więc zbiór } s_0, s_3, s_5s_0s_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.
s_4s_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)4Parser 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_5T=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)|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).
(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_5s_2, s_8s_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.}