initial commit

This commit is contained in:
Jonas Weinz 2016-09-12 15:22:50 +02:00
commit 0f15e187e1
7 changed files with 597 additions and 0 deletions

1
README.md Normal file
View File

@ -0,0 +1 @@
Kommentiertes Beispielprogramm ist in der Datei testProgram.tur

125
TuringInterpreter.py Executable file
View File

@ -0,0 +1,125 @@
#!/usr/bin/env python3
from Turingmachine import *
import sys
def getLinesFromFile(filename):
content = []
with open(filename, "r") as f:
content = f.read().splitlines()
return content
def createTuringmachineFromLines(lineArray, userInput):
k = None
F = None
S = None
I = None
inputStr = userInput
d = []
lineCounter = 0
for line in lineArray:
lineCounter += 1
line = line.replace(" ","")
if len(line) > 0:
if line[0] == 'k' and line[-1] == ';':
#hole k:
l = line[1:-1] #entferne k und ;
kStr = l.replace("=","") #entferne whitespaces und =
k = int(kStr)
elif line[0] == 'F' and line[-1] == ';':
#hole Endzustände:
l = line[1:-1] #entferne F und ;
FStr = l.replace("=","") #entferne whitespaces und =
F = FStr.split(",")
elif line[0] == 'S' and line[-1] == ';':
#hole Startzustand:
l = line[1:-1] #entferne S und ;
S = l.replace("=","") #entferne whitespaces und =
elif line[0] == 'I' and line[-1] == ';':
#hole Input:
l = line[1:-1] #entferne S und ;
I = l.replace("=","") #entferne whitespaces und =
elif line[0] == '$' and line[-1] == ';':
#hole Zustandsübergang:
l = line[1:-1] #entferne $ und ;
tmp = l.replace("=","") #entferne whitespaces und =
splittedLine = tmp.split(",")
#parse orientations:
orientations = []
for i in range(len(splittedLine[4])):
if splittedLine[4][i] == 'l':
orientations.append (-1)
elif splittedLine[4][i] == 'r':
orientations.append (1)
elif splittedLine[4][i] == 'n':
orientations.append (0)
else:
print("ERROR in line " + str(lineCounter) + ": " + line)
return None
d.append((splittedLine[0],splittedLine[1],splittedLine[2],splittedLine[3],orientations))
elif line[0] == '#':
#bei Kommentaren tu nix
None
else:
print("ERROR in line " + str(lineCounter) + ": " + line)
return None
if k is None:
print("ERROR: no k defined in Turing Program!")
return None
if F is None:
print("ERROR: no F defined in Turing Program!")
return None
if S is None:
print("ERROR: no S defined in Turing Program!")
return None
if inputStr is None:
if I is None:
print("WARNING: there is no input string defined. Machine will use an empty input string")
inputStr = ""
else:
inputStr = I
return Turingmachine(d, S, F, k, inputStr)
if __name__ == "__main__":
try:
filename = sys.argv[1]
except:
print("ERROR: no input file. \n"
+ "usage: python TuringInterpreter.py [TuringProgramFile] [InputString] [SleepTimePerStep] \n"
+ "(Default value for SleepTimePerStep is 0.3)")
sys.exit(0)
try:
inputStr = sys.argv[2]
except:
inputStr = None
try:
sleepTime = float(sys.argv[3])
except:
sleepTime = 0.3
tm = createTuringmachineFromLines(getLinesFromFile(filename), inputStr)
if tm is None:
print("ERROR: Bad Program!")
sys.exit(0)
tm.run(sleepTime)

200
Turingmachine.py Executable file
View File

@ -0,0 +1,200 @@
#!/usr/bin/env python3
import numpy as np
import sys
import time
# Bezeichnungen:
# delta = Zustandsübergangsfunktion: eine Liste von Tupeln im Format:
# (aktuellerZustand, aktuelleZeichen[Tupel], nächsterZustand, zuSchreibendeZeichen[Tupel], orientation[Tupel])
# q0 = Startzustand
# F = Menge der Endzustände
#ein paar konstanten:
GO_LEFT = -1
GO_NOWHERE = 0
GO_RIGHT = 1
#zur vereinfachung: konstanten für indices in delta:
DELTA_CURRENT_STATE = 0
DELTA_CURRENT_CHARS = 1
DELTA_NEXT_STATE = 2
DELTA_NEXT_CHARS = 3
DELTA_ORIENTATIONS = 4
#Konstanten für die Ausgabe:
CURSOR_UP_ONE = '\x1b[1A'
ERASE_LINE = '\x1b[2K'
#hilfsfunktionen für die ausgabe:
def eraseLines(n):
for i in range(n):
print(CURSOR_UP_ONE + ERASE_LINE, end = "")
#und die eigentliche Turingmaschine:
class Turingmachine(object):
def __init__(self,delta, q0, F, n, inputStr):
self.delta = delta
self.q0 = q0
self.F = F
self.n = n
#zur internen Verwaltung der Turinmaschine brauchen wir folgendes:
self.stripes = []
self.positions = []
self.steps = 0 #counting the steps
for i in range(n):
self.stripes.append(['$'])
self.positions.append(0)
#schreibe unsere Eingabe auf das erste Band:
for c in inputStr:
self.stripes[0].append(c)
self.currentQ = q0
self.error = False
self.isInFinalState = False
self.firstPrint = True
# Lese char unter dem i-ten Lesekopf:
def readChar(self,i):
#erweitere Band, falls notwendig:
if len(self.stripes[i]) <= self.positions[i]:
self.stripes[i].append('_')
#und Zeichen zurückgeben:
return self.stripes[i][self.positions[i]]
# Schreibe char unter dem i-ten Lesekopf:
def writeChar(self,i, char):
#erweitere Band, falls notwendig:
if len(self.stripes[i]) <= self.positions[i]:
self.stripes[i].append('_')
#und setze Zeichen:
self.stripes[i][self.positions[i]] = char
#bewege den Lese-/Schreibkopf
def move(self, i, orientation):
self.positions[i] += orientation
#führe einen Zustandsübergang aus: (gibt true bei erfolg zurück, sonst false)
def runDelta(self):
#durchlaufe alle Übergänge in Delta
for d in self.delta:
#suche nach Übergängen für unseren Zustand:
if d[DELTA_CURRENT_STATE] == self.currentQ:
#prüfe Einganszeichen:
qInputChars = d[DELTA_CURRENT_CHARS]
isInputOK = True
for i in range(self.n):
if not ((qInputChars[i] == self.readChar(i)) or (qInputChars[i] == '*')):
#eingangszeichen stimmen nicht überein!
isInputOK = False
if isInputOK:
#jetzt haben wir den richtigen zustandsübergang gefunden!
qNextChars = d[DELTA_NEXT_CHARS]
qOrientations = d[DELTA_ORIENTATIONS]
for i in range(self.n):
#schreibe Zeichen:
if qNextChars[i] != '*':
self.writeChar(i, qNextChars[i])
#Bewege Lese-/Schreibkopf
self.move(i, qOrientations[i])
#prüfe auf underflows:
for j in range(self.n):
if self.positions[j] < 0:
return False
#setze nächsten Zustand:
self.currentQ = d[DELTA_NEXT_STATE]
self.steps+=1
#fertig!
return True
#wenn wir bis hierhin kommen, haben wir keinen Übergang gefunden!
return False
# mache einen einzelnen Schritt mit der Turing Maschine (gibt true bei erfolg zurück, sonst false)
def step(self):
#führe den Schritt nuraus, wenn wir noch nicht im Endzustand sind:
if not self.isInFinalState:
self.error = not self.runDelta()
#schaue, ob wir in einem Endzustand sind:
self.isInFinalState = (self.currentQ in self.F)
return self.error
return True
def printMachine(self):
if not self.firstPrint:
#Lösche voherige Ausgabe:
eraseLines(2 * self.n + 1)
self.firstPrint = False
#geben bänder aus:
for i in range(self.n):
print("[",end="")
for c in self.stripes[i]:
print(c,end = "")
print("]")
#drucke lese-/Schreibkopf
print (" " * (self.positions[i] +1) + "^")
#und gebe allgemeine Infos aus:
print("step: " + str(self.steps) + "\t currentState: " + str(self.currentQ))
#run the machine until it gets to a final state:
def run(self, delayInSeconds):
while not self.isInFinalState:
self.step()
self.printMachine()
if self.error:
print("ERROR! Please check your Turing Program") #TODO: aussagekräftigere Fehlermeldung?
break
time.sleep(delayInSeconds)
if not self.error:
self.printMachine()
print("Maschine terminatet!")
if __name__ == "__main__":
#Blatt13/Aufgabe01 zum testen:
F = ['finalState']
d = [('start',"$$$$",'init',"$$$$",(1,1,1,1)),
('init',"****",'a',"*!!!",(0,1,1,1)),
('a',"a***",'a',"aa**",(1,1,0,0)),
('a',"b***",'b',"b***",(0,0,0,0)),
('b',"b***",'b',"b*b*",(1,0,1,0)),
('b',"c***",'c',"c***",(0,0,0,0)),
('c',"c***",'c',"c**c",(1,0,0,1)),
('c',"_***",'counting',"_***",(-1,-1,-1,-1)),
('counting',"*abc",'counting',"*abc",(0,-1,-1,-1)),
('counting',"*!**",'checkCounter',"*!**",(0,0,0,0)),
('counting',"**!*",'checkCounter',"**!*",(0,0,0,0)),
('counting',"***!",'checkCounter',"***!",(0,0,0,0)),
('checkCounter','*!!!','wordAccepted','*!!!',(0,0,0,0)),
('checkCounter','****','wordNotAccepted','****',(0,0,0,0)),
('wordAccepted','$***','write1','$***',(1,0,0,0)),
('wordAccepted','****','wordAccepted','_***',(-1,0,0,0)),
('wordNotAccepted','$***','write0','$***',(1,0,0,0)),
('wordNotAccepted','****','wordNotAccepted','_***',(-1,0,0,0)),
('write0','****','finalState','0***',(0,0,0,0)),
('write1','****','finalState','1***',(0,0,0,0))
]
tm = Turingmachine(d, 'start', F, 4, "aaaaaaaaabbbbbbbbbccccccccc")
tm.run(0.15)

106
add.tur Executable file
View File

@ -0,0 +1,106 @@
#!./TuringInterpreter.py
#
#Ein Turingprogramm, das zwei Binärcodierte zahlen
#miteinander addiert
k = 4;
S = start;
F = end;
I = 101001+110;
#init:
$start,$$$$,readFirst,$$$$,rrrr;
#lese erste Zahl ein und schreibe die auf das 2. Band:
$readFirst,1***,readFirst,11**,rrnn;
$readFirst,0***,readFirst,00**,rrnn;
$readFirst,+***,readSecond,****,rnnn;
#lese zweite Zahl ein und schreibe die auf das 3. Band:
$readSecond,1***,readSecond,1*1*,rnrn;
$readSecond,0***,readSecond,0*0*,rnrn;
$readSecond,_***,clear,****,nnnn;
#Lösche das erste band:
$clear,$***,add,$***,rlln;
$clear,****,clear,_***,lnnn;
#-------------------------------------------------------------------------------
#und addiere. Konkret: laufe auf Band 2 und 3 rückwärts die Zahlen
# ab und schreibe das ergebnis in rückwärtiger Schreibweise
# auf das dritte Band.
# dabei gibt es folgende Möglichkeiten:
# 1. wir haben bei beiden inputs gerade eine null und keinen Übertrag
# vorher gehabt:
$add,*00_,add,*000,nllr;
# 2. wir haben bei beiden inputs gerade eine null und haben einen Übertrag:
$add,*001,add,*001,nllr;
# 3. beide inputs verschieden ohne übertrag vorher:
$add,*10_,add,*101,nllr;
$add,*01_,add,*011,nllr;
# 4. beide inputs verschieden mit übertrag vorher:
$add,*101,overflow,*100,nllr;
$add,*011,overflow,*010,nllr;
# 5. beide inputs gleich 1 ohne übertrag:
$add,*11_,overflow,*110,nllr;
# 6. beide inputs 1 mit übertrag vorher:
$add,*111,overflow,*111,nllr;
# 7. wir sind am ende von einem band (dann juss nur noch der inhalt vom anderen
# angehängt werden):
$add,*$**,addSecondInput,*$**,nnnn;
$add,**$*,addFirstInput,**$*,nnnn;
#-------------------------------------------------------------------------------
# anhängeFunktionen:
#sind wir fertig?
$addSecondInput,**$*,copyResult,**$*,nnnn;
#haben wir overflow?
$addSecondInput,**01,addSecondInput,**01,nnlr;
$addSecondInput,**11,overflow2,**10,nnlr;
#sonst:
$addSecondInput,**0_,addSecondInput,**00,nnlr;
$addSecondInput,**1_,addSecondInput,**11,nnlr;
#-------------------------------------------------------------------------------
# anhängeFunktionen:
#sind wir fertig?
$addFirstInput,*$**,copyResult,*$**,nnnn;
#haben wir overflow?
$addFirstInput,*0*1,addFirstInput,*0*1,nlnr;
$addFirstInput,*1*1,overflow1,*1*0,nlnr;
#sonst:
$addFirstInput,*0*_,addFirstInput,*0*0,nlnr;
$addFirstInput,*1*_,addFirstInput,*1*1,nlnr;
#-------------------------------------------------------------------------------
#overflow funktionen:
$overflow,****,add,***1,nnnn;
$overflow1,****,addFirstInput,***1,nnnn;
$overflow2,****,addSecondInput,***1,nnnn;
#-------------------------------------------------------------------------------
#und schreibe Ergebnis auf das erste Band:
$copyResult,***$,end,***$,nnnn;
$copyResult,***1,copyResult,1**1,rnnl;
$copyResult,***0,copyResult,0**0,rnnl;
$copyResult,***_,copyResult,***_,nnnl;

15
nachfolger.tur Executable file
View File

@ -0,0 +1,15 @@
#!./TuringInterpreter.py
k = 1;
S = start;
F = end;
I = 0100101011;
$start,$,runToEnd,$,r;
#laufe ans ende der eingabe:
$runToEnd,_,addOne,_,l;
$runToEnd,*,runToEnd,*,r;
#addiere eins:
$addOne,0,end,1,l;
$addOne,1,addOne,0,l;

108
testProgram.tur Executable file
View File

@ -0,0 +1,108 @@
#!./TuringInterpreter.py
#
# dies ist ein Beispielprogramm für die Turingmaschine
# (Hinweis: Kommentarzeilen können mit einer führenden Raute eingeleitet werden)
#
# Dieses Programm kann mit dem Python-Skript "TuringInterpreter.py" für einen beliebigen Input-String via
#
# "python TuringInterpreter.py <TuringProgramFile.tur> <InputString>"
#
# ausgeführt werden. der InputString wird dabei auf das oberste Band geschrieben
#
# Folgendes Turingprogramm prüft, ob eine eingabe Element
# der Sprache L = {a^n b^n c^n} ist. Es schreibt eine 1
# auf das erste Band, falls das Wort akzeptiert wird,
# und 0 sonst.
# definiere die Anzahl der Bänder:
k = 4;
# definiere Endzustand. Es können alternativ auch mehrere Enzustände (durch Kommata getrennt)
# angegeben werden
F = finalState;
# definiere Startzustand
S = start;
# definiere einen default input String, der benutzt wird, falls beim Programmaufruf
# keiner angegeben wird:
I = aaaaaabbbbbbcccccc;
# definiere Zustandsübergänge:
# Ein Zustandsübergang wird mit einem '$' eingeleitet und besteht durch Kommata getrennt aus folgenden Werten:
#
# 1. Ausgangszustand
#
# 2. Zeichen unter den Lese-/Schreibköpfen vor dem Zustandswechsel.
# '*' kann hier als Platzhalter genutzt werden, um jedes beliebige Zeichen zu akzeptieren
#
# 3. Zustand, zu dem gewechselt werden soll
#
# 4. Zeichen, die auf die Bänder geschrieben werden sollen.
# '*' bewirkt hier, dass kein Zeichen geschrieben wird
# (oder anders interpretiert: Es wird exakt das Zeichen geschrieben,
# das vorher gelesen wurde)
#
# 5. Anschließende Bewegungen der Lese-/Schreibköpfe. Zu verwenden ist folgende Notation:
#
# n: keine Bewegung
# l: Bewegung um ein Feld nach links
# r: Bewegung um ein Feld nach rechts
#
# Und noch ein Hinweis: die Turingmaschine sucht in der Reihenfolge nach dem richtigen Übergang,
# wie sie in der Programmdatei angegeben wurden. Das lässt sich in Verbindung mit Platzhaltern
# prima nutzen um if-else verzweigungen zu generieren, ohne dass dabei alle theoretisch denkbaren
# Zeichenkombinationen als eigener Zustandsübergang angegeben werden müssen ;)
# am Anfang stehen alle Köpfe auf dem $-Zeichen, dass immer am Anfang jedes Bandes steht, also
# bewegen wir alle Köpfe einen Schritt nach rechts:
$start, $$$$, init , $$$$, rrrr;
# die unteren drei köpfe schreiben ein !. (um nachher zu sehen, wo sie starteten):
$init,****,a,*!!!,nrrr;
# lese alle a-s auf dem ersten Band ein: (und schreibe exakt so viele auf das zweite Band):
$a , a*** , a , aa** ,rrnn;
$a , b*** , b , b*** ,nnnn;
$a , **** , badInput, ****, nnnn;
# verfahre genauso mit b:
$b , b*** , b , b*b* ,rnrn;
$b , c*** , c , c*** ,nnnn;
$b , **** , badInput, ****, nnnn;
# und mit c:
$c , c*** , c , c**c ,rnnr;
$c , _*** , counting , _*** ,llll;
$c , **** , badInput, ****, nnnn;
# lasse die unteren drei köpfe zurücklaufen, bis einer auf das ! trifft:
$counting , *abc , counting , *abc , nlll;
$counting , *!** , checkCounter , *!** , nnnn;
$counting , **!* , checkCounter , **!* , nnnn;
$counting , ***! , checkCounter , ***! , nnnn;
# sind alle beim Ausrufezeichen?
$checkCounter , *!!! , wordAccepted,*!!!,nnnn;
$checkCounter , **** , wordNotAccepted,****,nnnn;
# falls ja: löschen wir alles auf dem ersten Band und schreiben eine 1
$wordAccepted , $*** , write1,$***,rnnn;
$wordAccepted , **** , wordAccepted,_***,lnnn;
$write1 , **** , finalState , 1*** ,nnnn;
# falls nein: löschen wir alles auf dem ersten Band und schreiben eine 0
$wordNotAccepted , $*** , write0 , $*** ,rnnn;
$wordNotAccepted , **** , wordNotAccepted , _*** ,lnnn;
$write0 , **** , finalState , 0*** ,nnnn;
# hilfsfunktion, um das Band auch nach vornehin zu löschen:
$badInput, _***, wordNotAccepted, _****, nnnn;
$badInput, ****, badInput, _***, rnnn;

View File

@ -0,0 +1,42 @@
#!./TuringInterpreter.py
#
# dies ist ein Beispielprogramm für die Turingmaschine
# (Hinweis: Kommentarzeilen können mit einer führenden Raute eingeleitet werden)
#
# Dieses Programm kann mit dem Python-Skript "TuringInterpreter.py" für einen beliebigen Input-String via
#
# "python TuringInterpreter.py <TuringProgramFile.tur> <InputString>"
#
# ausgeführt werden. der InputString wird dabei auf das oberste Band geschrieben
#
# Folgendes Turingprogramm prüft, ob eine eingabe Element
# der Sprache L = {a^n b^n c^n} ist. Es schreibt eine 1
# auf das erste Band, falls das Wort akzeptiert wird,
# und 0 sonst.
k = 4;
F = finalState;
S = start;
I = aaaaaabbbbbbcccccc;
$start, $$$$, init , $$$$, rrrr;
$init,****,a,*!!!,nrrr;
$a , a*** , a , aa** ,rrnn;
$a , b*** , b , b*** ,nnnn;
$b , b*** , b , b*b* ,rnrn;
$b , c*** , c , c*** ,nnnn;
$c , c*** , c , c**c ,rnnr;
$c , _*** , counting , _*** ,llll;
$counting , *abc , counting , *abc , nlll;
$counting , *!** , checkCounter , *!** , nnnn;
$counting , **!* , checkCounter , **!* , nnnn;
$counting , ***! , checkCounter , ***! , nnnn;
$checkCounter , *!!! , wordAccepted,*!!!,nnnn;
$checkCounter , **** , wordNotAccepted,****,nnnn;
$wordAccepted , $*** , write1,$***,rnnn;
$wordAccepted , **** , wordAccepted,_***,lnnn;
$write1 , **** , finalState , 1*** ,nnnn;
$wordNotAccepted , $*** , write0 , $*** ,rnnn;
$wordNotAccepted , **** , wordNotAccepted , _*** ,lnnn;
$write0 , **** , finalState , 0*** ,nnnn;