✖

Endelig automat

En endelig automat (på engelsk finite state machine eller finite automaton) er en beregningsmodell for en primitiv datamaskin. Den består av noen tilstander og noen overganger, og den kan akseptere eller avvise et ord den får oppgitt.

Eksempel

Uformelt beskriver vi en endelig automat ved hjelp av et tilstandsdiagram:

Eksempel på en enkel endelig automat

Automaten er bygd opp av tilstander. På figuren er det tre runde tilstander q0, q1 og q2. Mellom tilstandene går det overganger, det er pilene. I automaten må det dessuten finnes en starttilstand, og det er tilstanden q0. Starttilstanden tegnes ofte slik at en pil som ikke kommer fra noen tilstand, peker på den. Videre har automaten vanligvis en sluttilstand, som vi tegner med dobbel strek, så på figuren er det tilstanden q2.

En slik automat aksepterer visse ord. Vi sender ord inn i automaten, og automaten prøver å akseptere dem. Hvis den aksepterer ordet, svarer den JA, og hvis den ikke gjør det, svarer den NEI. Automaten vår prøver å akseptere ord som består av bokstavene «a, b, c», så vi kan prøve ordet «abbc».

Vi begynner i starttilstanden q0, og input er ordet «abbc». Videre følger vi pilene.

Vi går gjennom ordet på vanlig måte fra venstre til høyre, så det første symbolet vi tar, er «a». Pilen for input «a» går til tilstanden q1, så dit går vi over, og vi fjerner symbolet «a» fra ordet. Som input har vi nå ordet «bbc»:

Pilen for input «b» peker tilbake til noden q1. Vi fjerner igjen den første bokstaven, og som input har vi ordet «bc». Vi blir igjen i tilstanden q1. Til slutt har vi ordet «c» som input. Fra tilstanden q1 sender pilen for input «c» oss til tilstanden q2.

Nå har vi brukt opp alle bokstavene i inputordet, og vi er i tilstanden q2, som er en sluttilstand. Denne endelige automaten aksepterer altså ordet «abbc».

Hvis vi ikke hadde vært i en aksepterende tilstand til slutt, ville automaten ikke ha akseptert ordet. På samme måte ville automaten ikke ha akseptert ordet hvis vi i en tilstand ikke hadde noe sted å gå. For input «ab» ville vi for eksempel ha kommet til tilstanden q1 og blitt stående der — automaten aksepterer ikke et slikt ord. Hvis vi prøver ordet «aabbc», har vi igjen uflaks, for fra tilstanden q1 går det ingen pil for bokstaven «a».

En endelig automat brukes altså til å gjenkjenne en mengde ord. I praksis kunne vi brukt en automat til å finne ut om et gitt inputord er en gyldig e-postadresse.

Definisjon av endelig automat

Den forrige intuitive forestillingen om hva en endelig automat er, må vi formalisere for at vi skal kunne arbeide videre og bedre med automater.

Vi sier at en endelig (deterministisk) automat er et femtuppel ⟨Q, Σ, δ, q0, F⟩, der

  • Q er en endelig mengde av tilstander,
  • Σ (stor sigma) er alfabetet (en endelig mengde av symboler/bokstaver),
  • δ: Q × Σ ⟶ Q er overgangsfunksjonen,
  • q0 ∈ Q er starttilstanden,
  • F ⊆ Q er mengden av sluttilstander (aksepterende tilstander).

Hvis vi går tilbake til den forrige automaten,

kan vi si at mengden av tilstander Q inneholder tre tilstander, Q = {q0, q1, q2}. Alfabetet Σ inneholder bokstavene vi kan sette sammen til ord som automaten så skal akseptere eller avvise. Her er det sannsynligvis alfabetet Σ= {a, b, c}, men det kan også være en vilkårlig supermengde. Starttilstanden q0 er tilstanden q0, her er det ingenting å legge til. Mengden av sluttilstander har i denne automaten bare én tilstand, F = {q2}.

Med overgangsfunksjonen mener vi de tre pilene med bokstaver. Hvis du blir forvirret av skrivemåten δ: Q × Σ ⟶ Q, betyr den bare at δ er en funksjon (kanskje bedre: en avbildning) som tar to parametere: en tilstand fra Q og en bokstav fra Σ. Når vi kaller funksjonen, returnerer den en ny tilstand. Overgangsfunksjonen vår kunne vi definert med en tabell slik:

QΣ→Qq0aq1q1bq1q1cq2

Hvis vi kaller δ(q1, c), bruker vi tredje rad, og funksjonen svarer med tilstanden q2 — akkurat som diagrammet. Hvis vi er i tilstanden q1 og bokstaven «c» står som input, kommer vi til tilstanden q2. Før vi definerer formelt hva det betyr at en automat aksepterer et ord, bruker vi den intuitive forståelsen av begrepet og viser noen flere eksempler.

Flere eksempler

  1. Lag en automat som arbeider over det binære alfabetet, altså Σ= {0, 1}, og som bare aksepterer ord som slutter på en ener. Den aksepterer for eksempel ordene 1, 01, 000001, 0101011.

    Automaten vår har to tilstander — starttilstanden q0 og sluttilstanden q1. Så snart vi har sifferet 1 som input, går vi over til sluttilstanden q1 og blir værende der. Hvis derimot sifferet 0 er input, går vi over til tilstanden q0, som ikke er en sluttilstand, og blir også værende der.

  2. Lag en automat over det binære alfabetet som bare aksepterer ord der den første bokstaven er forskjellig fra den siste bokstaven.

    Allerede i det første steget deler automaten seg i to «delautomater». Hvis ordet begynner med null, går automaten inn i den venstre delen og blir værende der, og hvis det begynner med en ener, flytter den seg til den høyre delen. Etter det er det helt vanlig: hvis vi er i den venstre delen og input er 1, flytter vi oss til sluttilstanden og blir værende der. Hvis input er 0, flytter vi oss til tilstanden q1, som ikke er en sluttilstand.

    I motsetning til de forrige automatene har denne automaten flere sluttilstander, altså F = {q3, q4}.

  3. Lag en automat over det binære alfabetet som bare aksepterer ord som ikke inneholder to nuller etter hverandre.

    Denne automaten er interessant av to grunner. Den første er at den aksepterer det tomme ordet. Vi kan prøve å sende det tomme ordet inn i automaten, og automaten aksepterer det hvis starttilstanden samtidig er en sluttilstand, og det er tilfellet for denne automaten. Siden det tomme ordet er et ord som ikke inneholder to nuller etter hverandre, er dette riktig. Den andre interessante tingen er at alle tilstandene i denne automaten er sluttilstander. Det eneste tilfellet der automaten ikke aksepterer et ord, er når det ikke går noen overgang ut av tilstanden. Det skjer i tilstanden q1, som ikke har noen overgang for 0, for da ville ordet inneholdt to nuller etter hverandre.

  4. Lag en automat over alfabetet {-,+,.,0,1,…,9} som bare aksepterer ord som representerer et tall. Det betyr enten et heltall, for eksempel 2, 548, 98263, eller et desimaltall, for eksempel 5584.48, 3.14 (her skrevet med punktum som desimaltegn, slik det gjøres i programmering), og begge deler også i en versjon for negative tall med minustegn -2, -548, -3.14 og med eksplisitt skrevet pluss, altså +2, +548, +3.14. Samtidig må vi kunne skrive tallet 0.123 bare som .123 (uten nullen først), også med begge fortegnene. Vi innfører en hjelpebetegnelse: i stedet for å skrive ti overganger for ti sifre bruker vi symbolet N.

  5. Lag en automat over det binære alfabetet som bare aksepterer ord på formen 0n1n, som betyr at ordene har et visst antall nuller først, etterfulgt av like mange enere. Eksempler på slike ord er 0011, 00001111, 01.

    En slik automat kan ikke bygges, fordi vi ikke har noe sted der vi kan «huske» antallet nuller. Vi måtte laget flere «delautomater», på samme måte som i det andre eksempelet, men det måtte vært uendelig mange «delautomater», én for hver verdi av n.

Formalisering av automatens beregning

Vi har nå definert selve den endelige automaten formelt. Videre må vi definere hva en slik automat egentlig gjør, altså vi definerer automatens beregning.

Automatens konfigurasjon: Vi sier at paret ⟨q, w⟩ ∈ Q × Σ∗ er en konfigurasjon av automaten, der q er tilstanden automaten befinner seg i nå, og w er den delen av ordet som ennå ikke er lest. Σ∗ betegner Kleene-stjernen av alfabetet Σ, mengden av alle ord som kan settes sammen av bokstavene i alfabetet Σ. Det tomme ordet, som vi betegner ε, er også med i Kleene-stjernen.

Hvis vi har automaten ⟨Q, Σ, δ, q0, F⟩ og prøver å akseptere ordet w, befinner automaten seg i startkonfigurasjonen ⟨q0, w⟩. Hvis vi går tilbake til automaten

og vil akseptere ordet w = abbc, blir startkonfigurasjonen ⟨q0, abbc⟩.

Beregningssteg definerer vi som en relasjon ↦ mellom mengdene (Q × Σ∗) × (Q × Σ∗), altså mellom konfigurasjoner av automaten. La w = w0w1… wn være den delen av ordet w som ennå ikke er lest. Da sier vi at parene ⟨q1, w0w1… wn⟩ og ⟨q2, w1… wn⟩ står i relasjonen ↦, og vi skriver

⟨q1,w0w1…wn⟩↦⟨q2,w1…wn⟩,

hvis og bare hvis δ(q1, w0) = q2. I eksempelet vårt er startkonfigurasjonen ⟨q0, abbc⟩. Fra diagrammet ser vi at vi for input «a» kan flytte oss til tilstanden q1. Vi kan derfor skrive

⟨q0,abbc⟩↦⟨q1,bbc⟩,

fordi δ(q0, a) = q1. Dermed har vi utført ett beregningssteg — vi har sett hvilken tilstand vi skal gå til for det gitte inputet (= den første bokstaven i den ikke leste delen av ordet), vi har gått dit, og vi har fjernet den første bokstaven fra den ikke leste delen av ordet. Slik har vi fått en ny konfigurasjon.

Den refleksive og transitive tillukningen av relasjonen beregningssteg betegner vi ↦ ∗. Hvis vi skriver K1 ↦ ∗ K2, der K1, K2 er konfigurasjoner av automaten, betyr det at vi fra konfigurasjonen K1 kan komme til konfigurasjonen K2 gjennom flere beregningssteg, eller med andre ord at det finnes en endelig følge av konfigurasjoner slik at:

K1↦K11↦K12↦K13↦⋯↦K2

I automaten vår gjelder for eksempel ⟨q0, abbc⟩ ↦ ∗ ⟨q1,bc⟩, for når vi utfører to beregningssteg, blir ordet «bc» igjen, og vi blir i tilstanden q1. Altså finnes denne følgen av konfigurasjoner:

⟨q0,abbc⟩↦⟨q1,bbc⟩↦⟨q1,bc⟩

Automaten aksepterer ordet w hvis og bare hvis det finnes en qf ∈ F slik at ⟨q0,w⟩↦∗⟨qf,ε⟩ Det betyr at automaten aksepterer ordet w hvis og bare hvis det finnes en følge av beregningssteg slik at vi på slutten av følgen har lest hele ordet og befinner oss i en sluttilstand i automaten. At vi har lest hele ordet, uttrykkes ved at det i konfigurasjonen står ε, det tomme ordet, der ordet skulle stått. Automaten vår aksepterer ordet abbc, fordi det finnes denne følgen av konfigurasjoner:

⟨q0,abbc⟩↦⟨q1,bbc⟩↦⟨q1,bc⟩↦⟨q1,c⟩↦⟨q2,ε⟩

og tilstanden q2 er en sluttilstand, q2 ∈ F.

Språket som automaten aksepterer, er mengden av alle ord som automaten aksepterer. Språket til automaten A betegner vi L(A). Da gjelder L(A) ⊆ Σ∗ og

L(A)={w∈Σ∗|A aksepterer ordet w}

Et regulært språk er et språk som aksepteres av en endelig automat.

To endelige automater er ekvivalente hvis de aksepterer det samme språket. Altså er automatene A1 og A2 ekvivalente hvis L(A1) = L(A2).

Kilder

Kapitler: Endelig automat, Total automat, Ikke-deterministisk endelig automat, Simulering av ikke-deterministisk automat, Omforming av NFA til DFA