Endelig automat
En endelig automat (på engelsk finite state machine eller finite automaton) er en beregningsmodel for en primitiv computer, som består af nogle tilstande og nogle overgange, og som kan acceptere eller afvise et ord, den får givet.
Eksempel
Uformelt beskriver vi en endelig automat ved hjælp af et tilstandsdiagram, som beskriver den endelige automat:
Automaten består af tilstande, på figuren er det tre runde tilstande q0, q1 og q2. Mellem disse tilstande er der overgange, det er pilene. I automaten skal der desuden være en starttilstand, det er tilstanden q0. Starttilstanden tegner man ofte, så der peger en pil ind i den, som ikke udgår fra nogen tilstand. Desuden har automaten typisk en accepttilstand, den tegner vi med en dobbelt streg, så på figuren er det tilstanden q2.
En automat opbygget på denne måde accepterer nogle ord. Vi giver automaten nogle ord, og automaten forsøger at acceptere dem. Hvis den accepterer dem, svarer automaten JA, hvis ikke, svarer den NEJ. Vores automat forsøger at acceptere ord, der består af bogstaverne »a, b, c«, så vi kan prøve at acceptere ordet »abbc«.
Vi begynder i starttilstanden q0, og inputtet er ordet »abbc«. Derefter følger vi pilene.
Ordet gennemgår vi som sædvanlig fra venstre mod højre, det vil sige, at vi først tager symbolet »a«. Pilen for input »a« går til tilstanden q1, så vi går derhen og fjerner symbolet »a« fra ordet. Som input har vi ordet »bbc«:
Pilen for input »b« peger tilbage til knuden q1. Igen fjerner vi det første bogstav, og som input har vi ordet »bc«. Igen bliver vi i tilstanden q1. Til sidst har vi som input ordet »c«. Fra tilstanden q1 sender pilen for input »c« os til tilstanden q2.
Nu har vi brugt alle bogstaverne i inputordet, og vi er i tilstanden q2, som er en accepttilstand. Denne endelige automat accepterer altså ordet »abbc«.
Hvis vi ikke var i en accepttilstand til sidst, ville automaten ikke acceptere ordet. På samme måde ville automaten ikke acceptere ordet, hvis vi i en tilstand ikke havde noget sted at gå hen. For inputtet »ab« ville vi for eksempel nå til tilstanden q1 og ende der — automaten accepterer ikke et sådant ord. Hvis vi testede ordet »aabbc«, ville vi igen være uheldige, for fra tilstanden q1 går der ingen pil for bogstavet »a«.
En endelig automat tjener altså til at genkende en mængde af ord. I praksis kunne vi bruge automaten til for eksempel at afgøre, om et givet inputord er en gyldig e-mail.
Definition af en endelig automat
Den foregående intuitive forestilling om, hvad en endelig automat er, må vi formalisere, for at vi kan arbejde videre og bedre med automater.
Vi siger, at en endelig (deterministisk) automat er et femtupel ⟨Q, Σ, δ, q0, F⟩, hvor
- Q er en endelig mængde af tilstande,
- Σ (stort sigma) er alfabetet (en endelig mængde af symboler/bogstaver),
- δ: Q × Σ ⟶ Q er overgangsfunktionen,
- q0 ∈ Q er starttilstanden,
- F ⊆ Q er mængden af accepttilstande.
Hvis vi vender tilbage til den foregående automat,
kan vi sige, at der i mængden af tilstande Q er tre tilstande Q = {q0, q1, q2}. Alfabetet Σ indeholder de bogstaver, som vi kan sætte ord sammen af, og som automaten så vil acceptere eller afvise. Her er det formentlig alfabetet Σ= {a, b, c}, men det kan også være en vilkårlig overmængde. Starttilstanden q0 er tilstanden q0, det ændrer sig ikke. Mængden af accepttilstande har i denne automat kun én tilstand F = {q2}.
Ved overgangsfunktionen forstår vi så de tre pile med bogstaver. Hvis notationen δ: Q × Σ ⟶ Q forvirrer dig, betyder den bare, at δ er en funktion (måske bedre en afbildning), som tager to parametre: en tilstand fra Q og et bogstav fra Σ. Når funktionen kaldes, returnerer den en ny tilstand. Vores overgangsfunktion kunne vi definere med en tabel sådan:
Hvis vi kalder δ(q1, c), anvender vi den tredje række, og funktionen svarer med tilstanden q2 — ligesom diagrammet. Hvis vi er i tilstanden q1, og inputtet er bogstavet »c«, havner vi i tilstanden q2. Før vi formelt definerer, hvad det vil sige, at en automat accepterer et ord, bruger vi den intuitive forståelse af dette begreb og ser nogle flere eksempler.
Flere eksempler
-
Lav en automat, der arbejder over det binære alfabet, dvs. Σ= {0, 1}, og kun accepterer ord, der ender på et ettal. Den accepterer f.eks. ordene 1, 01, 000001, 0101011.
Vores automat har to tilstande — starttilstanden q0 og accepttilstanden q1. Hver gang inputtet er cifferet 1, går vi til accepttilstanden q1 og bliver i den. Er inputtet derimod cifferet 0, går vi til den ikke-accepterende tilstand q0 og bliver også i den.
-
Konstruér en automat over det binære alfabet, der kun accepterer ord, hvis første bogstav er forskelligt fra det sidste bogstav.
Automaten deler sig allerede i det første skridt i to »delautomater«. Hvis ordet begynder med nul, går automaten ind i den venstre del og bliver der, hvis det begynder med et, flytter den sig til den højre del. Derefter er det klassisk: hvis vi er i den venstre del, og inputtet er 1, flytter vi os til accepttilstanden og bliver der. Hvis inputtet er 0, flytter vi os til tilstanden q1, som ikke er accepterende.
I modsætning til de foregående automater har denne automat flere accepttilstande, dvs. F = {q3, q4}.
-
Konstruér en automat over det binære alfabet, der kun accepterer ord, som ikke indeholder to nuller i træk.
Denne automat er interessant af to grunde: den første er, at den accepterer det tomme ord. Vi kan prøve at give automaten det tomme ord, og automaten accepterer det, hvis starttilstanden samtidig er en accepttilstand, hvilket er tilfældet for denne automat. Da det tomme ord er et ord, der ikke indeholder to nuller i træk, er det den rigtige opførsel. Den anden mærkværdighed er, at alle tilstande i denne automat er accepterende. Det eneste tilfælde, hvor automaten ikke ville acceptere ordet, er, når der fra en tilstand ikke går nogen overgang. Det sker i tilstanden q1, som ikke har nogen overgang for 0, for så ville ordet indeholde to nuller i træk.
-
Konstruér en automat over alfabetet {-,+,.,0,1,…,9}, der kun accepterer ord, som repræsenterer et tal. Det betyder enten et helt tal som f.eks. 2, 548, 98263, eller et decimaltal som f.eks. 5584.48, 3.14 og begge dele også med en version for negative tal med minustegn -2, -548, -3.14 og også med eksplicit angivet plus, dvs. +2, +548, +3.14. Samtidig skal vi kunne skrive tallet 0.123 bare som .123 (uden nullet i begyndelsen), og det med begge fortegn. Vi indfører en hjælpenotation, hvor vi i stedet for at skrive ti overgange for ti cifre bruger symbolet N.
-
Konstruér en automat over det binære alfabet, der kun accepterer ord af formen 0n1n, hvilket betyder, at ordene har et vist antal nuller i begyndelsen efterfulgt af lige så mange enere. Eksempler på sådanne ord er 0011, 00001111, 01.
En sådan automat kan ikke konstrueres, fordi vi ingen steder kan »huske« antallet af nuller. Vi ville skulle lave flere »delautomater«, ligesom i det andet eksempel, men der skulle være uendeligt mange »delautomater«, én for hver værdi af n.
Formalisering af automatens beregning
Vi har allerede formelt defineret selve den endelige automat. Nu mangler vi at definere, hvad en sådan automat egentlig gør, dvs. vi definerer automatens beregning.
Automatens konfiguration: Vi siger, at parret ⟨q, w⟩ ∈ Q × Σ∗ er en konfiguration af automaten, hvor q er den aktuelle tilstand, som automaten befinder sig i, og w er den hidtil ulæste del af ordet. Σ∗ betegner afslutningen af alfabetet Σ, altså mængden af alle ord, der kan sættes sammen af bogstaverne i alfabetet Σ. Afslutningen indeholder også det tomme ord, som vi betegner ε.
Hvis vi har automaten ⟨Q, Σ, δ, q0, F⟩ og forsøger at acceptere ordet w, befinder automaten sig i startkonfigurationen ⟨q0, w⟩. Hvis vi vender tilbage til automaten
og vil acceptere ordet w = abbc, er startkonfigurationen ⟨q0, abbc⟩.
Beregningstrin definerer vi som en relation ↦ mellem mængderne (Q × Σ∗) × (Q × Σ∗), dvs. mellem automatens konfigurationer. Lad w = w0w1… wn være den hidtil ulæste del af ordet w. Så siger vi, at parrene ⟨q1, w0w1… wn⟩ og ⟨q2, w1… wn⟩ står i relationen ↦, hvilket vi skriver som
netop hvis δ(q1, w0) = q2. Hvis vi vender tilbage til vores eksempel, er startkonfigurationen ⟨q0, abbc⟩. Af diagrammet ser vi, at vi for input »a« kan flytte os til tilstanden q1. Vi kan derfor skrive
fordi δ(q0, a) = q1. Dermed har vi udført ét beregningstrin — vi har set, hvilken tilstand vi skal gå til for det givne input (= det første bogstav i den hidtil ulæste del af ordet), vi er gået derhen og har fjernet det første bogstav fra den ulæste del af ordet. Dermed har vi fået en ny konfiguration.
Den refleksive og transitive afslutning af relationen beregningstrin betegner vi ↦ ∗. Hvis vi skriver K1 ↦ ∗ K2, hvor K1, K2 er konfigurationer af automaten, betyder det, at vi fra konfigurationen K1 kan nå til konfigurationen K2 gennem nogle beregningstrin, eller med andre ord, at der findes en endelig følge af konfigurationer, således at:
I vores automat gælder for eksempel ⟨q0, abbc⟩ ↦ ∗ ⟨q1,bc⟩, fordi når vi udfører to beregningstrin, er ordet »bc« tilbage, og vi er i tilstanden q1. Dvs. der findes denne følge af konfigurationer:
Automaten accepterer ordet w netop hvis der findes qf ∈ F, således at
og tilstanden q2 er en accepttilstand, q2 ∈ F.
Det sprog, som automaten accepterer, er mængden af alle ord, som automaten accepterer. Sproget for automaten A betegner vi L(A). Der gælder således, at L(A) ⊆ Σ∗ og
Et regulært sprog er et sprog, som accepteres af en endelig automat.
To endelige automater er ækvivalente, hvis de accepterer samme sprog. Dvs. automaterne A1 og A2 er ækvivalente, hvis L(A1) = L(A2).
Kilder
Kapitler: Endelig automat, Total automat, Ikke-deterministisk endelig automat, Simulering af en NFA, Omdannelse af NFA til DFA