Celem jest utworzenie DFA z wyrażenia regularnego, a użycie opcji „Regular exp> NFA> Konwersja DFA” nie jest opcją. Jak należy to zrobić?
Zadałem to pytanie naszemu profesorowi, ale powiedział mi, że możemy korzystać z intuicji i uprzejmie odmówił podania jakichkolwiek wyjaśnień. Więc chciałem cię zapytać.
Opcja „Regular exp> NFA> Konwersja DFA” nie jest opcją, ponieważ taka konwersja zajmuje dużo czasu, aby przekonwertować dość złożone wyrażenie regularne. Na przykład dla pewnego wyrażenia regularnego „wyrażenie regularne> NFA> DFA” zajmuje człowiekowi 1 godzinę. Muszę przekonwertować wyrażenie regularne na DFA w mniej niż 30 minut.
a(a|ab|ac)*a+
. Możesz albo bezpośrednio przetłumaczyć to na NDFA, które redukujesz do DFA, albo możesz znormalizować to do czegoś, co mapuje natychmiast do DFA.Odpowiedzi:
Ponieważ chcesz „przekonwertować wyrażenie regularne na DFA w mniej niż 30 minut”, przypuszczam, że pracujesz ręcznie na stosunkowo małych przykładach.
W tym przypadku można zastosować algorytm Brzozowskiego , który bezpośrednio oblicza automat Nerode języka (o którym wiadomo, że jest równy minimalnemu automatowi deterministycznemu). Opiera się na bezpośrednim obliczeniu pochodnych, a także działa na rozszerzone wyrażenia regularne, umożliwiające przecięcie i uzupełnienie. Wadą tego algorytmu jest to, że wymaga sprawdzenia równoważności wyrażeń obliczanych po drodze, kosztownego procesu. Ale w praktyce i dla małych przykładów jest bardzo wydajny.[ 1 ]
Lewe ilorazy . Niech będzie językiem A * i niech u być słowo. Następnie u - 1 L = { v ∈ * | u , v ∈ L } Język u - 1 l nazywa się lewy iloraz (lub po pochodnej ) z L .L. ZA∗ u
Automat Nerode . Automat Nerode z jest deterministyczny automat ( L ) = ( P , , ⋅ , L , F ) , gdzie P = { u - 1 l | u ∈ * } , M = { u - 1 l | u ∈ L } i funkcja przejścia jest zdefiniowana dla każdego a ∈L. ZA( L ) = ( Q , A , ⋅ , L , F) Q = { u- 1L ∣ u ∈ A∗} fa= { u- 1L ∣ u ∈ L } według wzoru
( u - 1 L ) ⋅ a = a - 1 ( u - 1 L ) = ( u a ) - 1 L
Strzeż się tej raczej abstrakcyjnej definicji. Każdy stan A jest lewym ilorazem L słowa, a zatem jest językiem A ∗ . Początkowy stan jest język L i zbiorem stanów końcowych jest zbiorem wszystkich pozostawionych ilorazów L przez słowo L .a∈A
Edit . (5 kwietnia 2015 r.) Właśnie odkryłem, że podobne pytanie: jakie algorytmy istnieją do budowy DFA, który rozpoznaje język opisany przez dane wyrażenie regularne? został zapytany na cstheory. Odpowiedź częściowo rozwiązuje problemy ze złożonością.
źródło
J.-E. Pin zapewnia lepszą odpowiedź pod względem formalności i kompletności, ale myślę, że można powiedzieć coś o „intuicji”, na którą wskazuje twój profesor.
W większości tych przypadków najłatwiej jest spojrzeć na wyrażenie regularne, zrozumieć, jaki język akceptuje, a następnie wykorzystać swoją kreatywność / spryt, aby zbudować DFA akceptujący ten język.
Nie ma prostego sposobu, aby to zrobić, oprócz algorytmów podanych przez innych, ale oto kilka wskazówek, które mogą się okazać przydatne.
Zadaj sobie pytanie, czy mógłbym napisać program, który akceptuje to RE, używając tylko zmiennych boolowskich lub bardzo małych liczb całkowitych? Następnie napisz ten program i przekonwertuj go na DFA, w którym istnieje stan dla każdej kombinacji wartości.
Poszukaj części wyrażenia regularnego, które możesz zaakceptować deterministycznie, gdzie wiesz, że „Jeśli to widzę, to muszę dopasować tę część RE”. Nie zawsze będzie ich mnóstwo, ale identyfikacja tych części może pokazać części, które będą łatwe do stworzenia DFA, dzięki czemu możesz spędzić więcej czasu na częściach, które naprawdę wymagają niedeterminizmu.
Konstrukcja podzbioru dla NFA-> DFA nie jest tak skomplikowana jak algorytm. Więc jeśli jest to zadanie, a nie pytanie egzaminacyjne, może być szybsze kodowanie implementacji i pozwolenie Twojemu programowi na konwersję NFA na DFA. Jeśli użyłeś własnego kodu, nie powinno być żadnych problemów z plagaryzmem.
Spróbuj „patrzeć przed siebie”, skracając rogi, gdy możesz używać intuicji w miejscach, w których algorytm wymagałby wielu kroków, ale jego wynik jest jasny.
źródło
Chociaż nie jest to właściwy sposób, ale działa przez większość czasu.
Pierwszy krok : znajdź najmniejszy ciąg znaków, który może zostać zaakceptowany przez wyrażenie regularne. Drugi krok : narysuj niezbędne stany za pomocą transakcji minimalnego ciągu akceptującego ciąg. Trzeci krok : dla wszystkich stanów narysuj pozostałe transakcje alfabetyczne.
Na przykład: Wyrażenie regularne (0 + 1) * 1 ”Łańcuch kończący się na 1” Krok 1: Najmniejszy ciąg: 1 Krok 2: dwa stany Q0 i Q1. z transakcją 1 od Q0 do Q1. a Q1 to stan akceptujący. Krok 3: dla stanu Q0 transakcja Q0 1 odbywa się do pierwszego kwartału. Teraz dokonaj transakcji 0 w samym Q0. Dla stanu w pierwszym kwartale transakcja w pierwszym kwartale pozostanie w pierwszym kwartale. I 0 transakcji pójdzie w Q0.
źródło