Ich muss lernen, wie man einen DFA so entwirft, dass er bei einer beliebigen Zahl 'n' binäre Zeichenfolgen {0, 1} akzeptiert, deren dezimale Äquivalentzahl durch 'n' teilbar ist.
Es wird verschiedene DFAs für verschiedene 'n' geben, aber kann jemand einen grundlegenden Ansatz nennen, dem ich folgen sollte, um mit einer beliebigen Zahl 0 <n <10 fortzufahren.
n
das ist trivial, oder?n
musslog(n)
nachgestellte Nullen haben.Antworten:
Im Folgenden habe ich eine Antwort für
n
gleich 5 geschrieben, aber Sie können denselben Ansatz anwenden, um DFAs für jeden Wertn
und jedes Positionsnummernsystem zu zeichnen , z. B. binär, ternär ...Zuerst den Begriff 'Vollständiger DFA' verwenden. Ein DFA , der für die vollständige Domäne in δ: Q × Σ → Q definiert ist, wird als 'Vollständiger DFA' bezeichnet. Mit anderen Worten können wir sagen; Im Übergangsdiagramm des vollständigen DFA fehlt keine Kante (z. B. ist von jedem Zustand in Q für jedes Sprachsymbol in Σ eine ausgehende Kante vorhanden). Hinweis: Manchmal definieren wir partielle DFA als δ ⊆ Q × Σ → Q (Lesen: Wie liest „δ: Q × Σ → Q“ in der Definition einer DFA ).
Design DFA akzeptiert Binärzahlen, die durch die Zahl 'n' teilbar sind:
Schritt 1 : Wenn Sie eine Zahl ω durch dividieren,
n
kann die Erinnerung entweder 0, 1, ..., (n - 2) oder (n - 1) sein. Wenn der Rest ist0
, bedeutet dies, dass ω durchn
sonst nicht teilbar ist . In meinem DFA gibt es also einen Zustand q r , der einem Restwert entsprichtr
, wobei0 <= r <= (n - 1)
und die Gesamtzahl der Zustände in DFA istn
.Nach der Verarbeitung einer Zahlenfolge ω über Σ impliziert der Endzustand q r , dass ω% n => r (% Erinnerungsoperator).
In allen Automaten ist der Zweck eines Zustands wie ein Speicherelement. Ein Zustand in einem Atomata speichert einige Informationen wie den Schalter des Lüfters, die erkennen können, ob sich der Lüfter im Zustand "Aus" oder "Ein" befindet. Für n = 5 entsprechen fünf Zustände in DFA fünf Erinnerungsinformationen wie folgt:
Unter Verwendung der obigen Informationen können wir mit dem Zeichnen des Übergangsdiagramms TD von fünf Zuständen wie folgt beginnen:
Also 5 Zustände für 5 Restwerte. Nach der Verarbeitung einer Zeichenfolge ω, wenn der Endzustand zu q 0 wird , bedeutet dies, dass das Dezimaläquivalent der Eingabezeichenfolge durch 5 teilbar ist. In der obigen Abbildung ist q 0 als Endzustand als zwei konzentrische Kreise markiert.
Zusätzlich habe ich eine Übergangsregel δ definiert: (q 0 , 0) → q 0 als Selbstschleife für das Symbol
'0'
im Zustand q 0 , weil das Dezimaläquivalent einer Zeichenfolge nur aus'0'
0 besteht und 0 durch teilbar istn
.Schritt 2 : TD oben ist unvollständig; und kann nur Strings von
'0'
s verarbeiten. Fügen Sie nun einige weitere Kanten hinzu, damit die Zeichenfolgen der nachfolgenden Zahlen verarbeitet werden können. Die folgende Tabelle zeigt neue Übergangsregeln, die im nächsten Schritt hinzugefügt werden können:'1'
zu verarbeiten, sollte es eine Übergangsregel δ geben: (q 0 , 1) → q 1'10'
, der Endzustand sollte q 2 sein , und um zu verarbeiten'10'
, müssen wir nur eine weitere Übergangsregel hinzufügen δ: (q 1 , 0) → q 2Pfad : → (q 0 ) ─1 → ( q 1 ) ─0 → (q 2 )
'11'
q 3 , und wir müssen eine Übergangsregel δ hinzufügen: (q 1 , 1) → q 3Pfad : → (q 0 ) ─1 → (q 1 ) ─1 → (q 3 )
'100'
ist der Endzustand q 4 . TD verarbeitet bereits die Präfixzeichenfolge'10'
und wir müssen nur eine neue Übergangsregel δ hinzufügen: (q 2 , 0) → q 4Pfad : → (q 0 ) ─ 1 → (q 1 ) ─ 0 → (q 2 ) ─ 0 → (q 4 )
Schritt 3 : Fünf = 101 Das
obige Übergangsdiagramm in Abbildung 2 ist noch unvollständig und es fehlen viele Kanten. Für ein Beispiel ist kein Übergang für δ definiert: (q 2 , 1) - ? . Und die Regel sollte vorhanden sein, um Strings wie zu verarbeiten
'101'
.Weil
'101'
= 5 durch 5 teilbar ist, und um zu akzeptieren'101'
, füge ich δ hinzu: (q 2 , 1) → q 0 in der obigen Abbildung-2.Pfad: → (q 0 ) ─1 → (q 1 ) ─0 → (q 2 ) ─1 → (q 0 )
Mit dieser neuen Regel wird das Übergangsdiagramm wie folgt:
Unten in jedem Schritt wähle ich die nächste nachfolgende Binärzahl aus, um eine fehlende Kante hinzuzufügen, bis ich TD als 'vollständigen DFA' erhalte.
Schritt 4 : Sechs = 110.
Wir können
'11'
TD in Abbildung 3 wie folgt verarbeiten : → (q 0 ) ─11 → (q 3 ) ─0 → ( ? ). Da 6% 5 = 1 ist, bedeutet dies, eine Regel δ hinzuzufügen: (q 3 , 0) → q 1 .Schritt 5 : Sieben = 111
Schritt 6 : Acht = 1000
Schritt 7 : Neun = 1001
In TD-7 beträgt die Gesamtzahl der Kanten 10 == Q × Σ = 5 × 2. Und es ist ein vollständiger DFA, der alle möglichen binären Zeichenfolgen akzeptieren kann, deren Dezimaläquivalent durch 5 teilbar ist.
Design DFA akzeptiert ternäre Zahlen, die durch die Zahl n teilbar sind:
Schritt-1 Verwenden Sie genau wie für binär Abbildung-1.
Schritt 2 Fügen Sie Null, Eins, Zwei hinzu
Schritt 3 Fügen Sie drei, vier, fünf hinzu
Schritt 4 Fügen Sie sechs, sieben, acht hinzu
Schritt 5 Fügen Sie neun, zehn, elf hinzu
Schritt 6 Addiere zwölf, dreizehn, vierzehn
Die Gesamtzahl der Kanten im Übergangsdiagramm in Abbildung 12 beträgt 15 = Q × Σ = 5 * 3 (ein vollständiger DFA). Und dieser DFA kann akzeptieren, dass alle Zeichenfolgen über {0, 1, 2} bestehen. Diese Dezimaläquivalente sind durch 5 teilbar.
Wenn Sie bei jedem Schritt feststellen, gibt es in der Tabelle drei Einträge, da ich bei jedem Schritt alle möglichen ausgehenden Flanken aus einem Zustand hinzufüge um einen vollständigen DFA zu erstellen (und ich füge eine Kante hinzu, damit q r state für den Rest erhalten wird
r
)!Denken Sie daran, dass die Vereinigung zweier regulärer Sprachen ebenfalls eine reguläre ist. Wenn Sie einen DFA entwerfen müssen, der binäre Zeichenfolgen akzeptiert, ist dieses Dezimaläquivalent entweder durch 3 oder 5 teilbar. Zeichnen Sie dann zwei separate DFAs für teilbar durch 3 und 5, und vereinigen Sie dann beide DFAs, um das Ziel-DFA zu erstellen (für 1 <= n <= 10) Sie müssen 10 DFAs vereinen).
Wenn Sie aufgefordert werden, DFA zu zeichnen, das binäre Zeichenfolgen so akzeptiert, dass das Dezimaläquivalent durch 5 und 3 teilbar ist, suchen Sie nach DFA, das durch 15 teilbar ist (aber was ist mit 6 und 8?).
Hinweis: Mit dieser Technik gezeichnete DFAs werden nur dann minimiert, wenn es keinen gemeinsamen Faktor zwischen Zahl
n
und Basis gibt, z. B. gibt es im ersten Beispiel keinen zwischen 5 und 2 oder im zweiten Beispiel zwischen 5 und 3, daher werden beide oben konstruierten DFAs minimiert DFAs. Wenn Sie mehr über mögliche Mini-Zustände für Zahlenn
und Basisb
lesen möchten, lesen Sie das Papier: Teilbarkeit und Zustandskomplexität .Unten habe ich ein Python-Skript hinzugefügt. Ich habe es zum Spaß geschrieben, während ich die Python-Bibliothek pygraphviz gelernt habe. Ich füge es hinzu. Ich hoffe, es kann irgendwie für jemanden hilfreich sein.
Entwerfen Sie den DFA für die durch die Zahl 'n' teilbaren Zeichenfolgen der Basis 'b':
Wir können also den obigen Trick anwenden, um DFA zu zeichnen, um Zahlenfolgen in jeder Basis zu erkennen,
'b'
die durch eine bestimmte Zahl teilbar sind'n'
. In diesem DFA ist die Gesamtzahl der Zuständen
(fürn
Reste) und die Anzahl der Kanten sollte gleich 'b' * 'n' sein - das ist vollständig. DFA: 'b' = Anzahl der Symbole in der Sprache des DFA und 'n' = Anzahl der Staaten.Mit dem obigen Trick habe ich unten ein Python-Skript geschrieben, um DFA für die Eingabe
base
und zu zeichnennumber
. Im Skriptdivided_by_N
füllt die Funktion die Übergangsregeln von DFAbase * number
schrittweise aus. In jeder Schrittnummer konvertiere ich mit der Funktionnum
in eine Zahlenfolge . Um zu vermeiden, dass jede Zahlenfolge verarbeitet wird, habe ich eine temporäre Datenstruktur verwendet . In jedem Schritt wird der Endzustand für die Zahlenzeichenfolge ausgewertet und gespeichert , um im nächsten Schritt verwendet zu werden.num_s
baseN()
lookup_table
num_s
lookup_table
Für den Übergangsgraphen von DFA habe ich eine Funktion
draw_transition_graph
mit der Pygraphviz-Bibliothek geschrieben (sehr einfach zu bedienen). Um dieses Skript verwenden zu können, müssen Sie es installierengraphviz
. Um dem Übergangsdiagramm farbige Kanten hinzuzufügen, generiere ich zufällig Farbcodes für jede Symbolfunktionget_color_dict
.#!/usr/bin/env python import pygraphviz as pgv from pprint import pprint from random import choice as rchoice def baseN(n, b, syms="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"): """ converts a number `n` into base `b` string """ return ((n == 0) and syms[0]) or ( baseN(n//b, b, syms).lstrip(syms[0]) + syms[n % b]) def divided_by_N(number, base): """ constructs DFA that accepts given `base` number strings those are divisible by a given `number` """ ACCEPTING_STATE = START_STATE = '0' SYMBOL_0 = '0' dfa = { str(from_state): { str(symbol): 'to_state' for symbol in range(base) } for from_state in range(number) } dfa[START_STATE][SYMBOL_0] = ACCEPTING_STATE # `lookup_table` keeps track: 'number string' -->[dfa]--> 'end_state' lookup_table = { SYMBOL_0: ACCEPTING_STATE }.setdefault for num in range(number * base): end_state = str(num % number) num_s = baseN(num, base) before_end_state = lookup_table(num_s[:-1], START_STATE) dfa[before_end_state][num_s[-1]] = end_state lookup_table(num_s, end_state) return dfa def symcolrhexcodes(symbols): """ returns dict of color codes mapped with alphabets symbol in symbols """ return { symbol: '#'+''.join([ rchoice("8A6C2B590D1F4E37") for _ in "FFFFFF" ]) for symbol in symbols } def draw_transition_graph(dfa, filename="filename"): ACCEPTING_STATE = START_STATE = '0' colors = symcolrhexcodes(dfa[START_STATE].keys()) # draw transition graph tg = pgv.AGraph(strict=False, directed=True, decorate=True) for from_state in dfa: for symbol, to_state in dfa[from_state].iteritems(): tg.add_edge("Q%s"%from_state, "Q%s"%to_state, label=symbol, color=colors[symbol], fontcolor=colors[symbol]) # add intial edge from an invisible node! tg.add_node('null', shape='plaintext', label='start') tg.add_edge('null', "Q%s"%START_STATE,) # make end acception state as 'doublecircle' tg.get_node("Q%s"%ACCEPTING_STATE).attr['shape'] = 'doublecircle' tg.draw(filename, prog='circo') tg.close() def print_transition_table(dfa): print("DFA accepting number string in base '%(base)s' " "those are divisible by '%(number)s':" % { 'base': len(dfa['0']), 'number': len(dfa),}) pprint(dfa) if __name__ == "__main__": number = input ("Enter NUMBER: ") base = input ("Enter BASE of number system: ") dfa = divided_by_N(number, base) print_transition_table(dfa) draw_transition_graph(dfa)
Führ es aus:
~/study/divide-5/script$ python script.py Enter NUMBER: 5 Enter BASE of number system: 4 DFA accepting number string in base '4' those are divisible by '5': {'0': {'0': '0', '1': '1', '2': '2', '3': '3'}, '1': {'0': '4', '1': '0', '2': '1', '3': '2'}, '2': {'0': '3', '1': '4', '2': '0', '3': '1'}, '3': {'0': '2', '1': '3', '2': '4', '3': '0'}, '4': {'0': '1', '1': '2', '2': '3', '3': '4'}} ~/study/divide-5/script$ ls script.py filename.png ~/study/divide-5/script$ display filename
Ausgabe:
In ähnlicher Weise geben Sie base = 4 und number = 7 ein, um zu generieren - dfa akzeptiert Zahlenzeichenfolge in base '4', die durch '7' teilbar sind.
Versuchen Sie,
filename
zu.png
oder zu wechseln.jpeg
.Verweist auf diejenigen, die ich zum Schreiben dieses Skripts verwende: ➊ Funktion
baseN
von "Ganzzahl in eine Zeichenfolge in einer bestimmten numerischen Basis in Pythonkonvertieren " ➋ So installieren Sie "pygraphviz": "Python sieht pygraphviz nicht"
➌ So lernen Sie die Verwendung von Pygraphviz: "Python- FSM "
➍ So generieren Sie zufällige Hex-Farbcodes für jedes Sprachsymbol: " Wie würde ich einen zufälligen Hexdigit-Code-Generator mit .join und for-Schleifen erstellen? "
quelle
Ich weiß, dass ich ziemlich spät dran bin, aber ich wollte der bereits korrekten Antwort von @Grijesh nur ein paar Dinge hinzufügen. Ich möchte nur darauf hinweisen, dass die Antwort von @Grijesh nicht den minimalen DFA ergibt. Während die Antwort sicherlich der richtige Weg ist, um einen DFA zu erhalten, müssen Sie, wenn Sie den minimalen DFA benötigen, in Ihren Divisor schauen.
Wie zum Beispiel bei Binärzahlen beträgt die Mindestanzahl der erforderlichen Zustände n + 1, wenn der Divisor eine Potenz von 2 (dh 2 ^ n) ist. Wie würden Sie einen solchen Automaten entwerfen? Sehen Sie sich nur die Eigenschaften von Binärzahlen an. Für eine Zahl, sagen wir 8 (das ist 2 ^ 3), haben alle ihre Vielfachen die letzten 3 Bits als 0. Zum Beispiel ist 40 in binär 101000. Damit eine Sprache eine durch 8 teilbare Zahl akzeptiert, brauchen wir nur eine Automat, der sieht, ob die letzten 3 Bits 0 sind, was wir in nur 4 Zuständen anstelle von 8 Zuständen tun können. Das ist die halbe Komplexität der Maschine.
Tatsächlich kann dies auf jede Basis erweitert werden. Wenn wir für ein ternäres Basisnummernsystem beispielsweise einen Automaten für die Teilbarkeit mit 9 entwerfen müssen, müssen wir nur sehen, ob die letzten 2 Zahlen der Eingabe 0 sind. Dies kann wiederum in nur 3 Zuständen erfolgen.
Wenn der Divisor nicht so besonders ist, müssen wir nur die Antwort von @ Grijesh durchgehen. Wie zum Beispiel in einem binären System, wenn wir die Teiler von 3 oder 7 oder vielleicht 21 nehmen, müssen wir nur so viele Zustände haben. Für jede ungerade Zahl n in einem Binärsystem benötigen wir n Zustände, um die Sprache zu definieren, die alle Vielfachen von n akzeptiert. Wenn andererseits die Zahl gerade, aber keine Zweierpotenz ist (nur bei Binärzahlen), müssen wir die Zahl durch 2 teilen, bis wir eine ungerade Zahl erhalten, und dann können wir die minimale Anzahl von Zuständen durch finden Addiere die ungerade erzeugte Zahl und die Häufigkeit, mit der wir durch 2 geteilt haben.
Wenn wir zum Beispiel die Mindestanzahl von Zuständen eines DFA finden müssen, der alle durch 20 teilbaren Binärzahlen akzeptiert, tun wir Folgendes:
20/2 = 10 10/2 = 5
Daher lautet unsere Antwort
5 + 1 + 1 = 7
. (Die 1 + 1, weil wir die Zahl 20 zweimal geteilt haben).quelle
Sie können DFA mithilfe einfacher modularer Arithmetik erstellen. Wir können
w
eine Folge von k-ary-Zahlen anhand einer folgenden Regel interpretierenV[0] = 0 V[i] = (S[i-1] * k) + to_number(str[i])
V[|w|]
ist eine Zahl,w
die darstellt. Wenn Sie diese Regel ändern, um sie zu findenw mod N
, wird die Regel zu dieser.V[0] = 0 V[i] = ((S[i-1] * k) + to_number(str[i])) mod N
und jedes
V[i]
ist eine von einer Zahl von 0 bis N-1, die jedem Zustand in DFA entspricht. Wir können dies als Zustandsübergang verwenden.Siehe ein Beispiel.
k = 2, N = 5
| V | (V*2 + 0) mod 5 | (V*2 + 1) mod 5 | +---+---------------------+---------------------+ | 0 | (0*2 + 0) mod 5 = 0 | (0*2 + 1) mod 5 = 1 | | 1 | (1*2 + 0) mod 5 = 2 | (1*2 + 1) mod 5 = 3 | | 2 | (2*2 + 0) mod 5 = 4 | (2*2 + 1) mod 5 = 0 | | 3 | (3*2 + 0) mod 5 = 1 | (3*2 + 1) mod 5 = 2 | | 4 | (4*2 + 0) mod 5 = 3 | (4*2 + 1) mod 5 = 4 |
k = 3, N = 5
| V | 0 | 1 | 2 | +---+---+---+---+ | 0 | 0 | 1 | 2 | | 1 | 3 | 4 | 0 | | 2 | 1 | 2 | 3 | | 3 | 4 | 0 | 1 | | 4 | 2 | 3 | 4 |
Jetzt können Sie ein sehr einfaches Muster sehen. Sie können tatsächlich einen DFA-Übergang erstellen, indem Sie einfach sich wiederholende Zahlen von links nach rechts, von oben nach unten, von 0 nach N-1 schreiben.
quelle