#Turing machine simulation #Transition table is a dictionary of key-value pairs (q,c):(q',c',D) where #D is -1 or 1, for left and right, tape symbols c, c' are characters, #states q,q' are integers. #Conventions: If a state,symbol pair is not in the dictionary, # transition to reject state. 0 is intial state, -1 is accept and #halt, -2 is reject and halt, -n with n>2 is halt without specifying #decision. #The tape is a list of 20000 chars. The configuration is a tuple #of the tape, an index start giving the location of first nonblank symbol #an index end giving the location of the last nonblank symbol #an index current giving the location of the reading head, and the state. #In bidirectional mode, the simulation will start at cell 10000, so in practice #it should never run off the end of the tape. #In unidirectional mode, we start at 0. The way the current position is updated #keeps the reading head at 0 on a left move (the same happens in bidirectional #mode, but this behavior will never be encountered in practice) def nextconfig(table,present_config): (tape,start,end,current,state)=present_config symbol=tape[current] if (state,symbol) in table: (newstate,newsymbol,direction)=table[(state,symbol)] tape[current]=newsymbol newcurrent=max(current+direction,0) if currentend and tape[current]!=' ': newend=current else: newend=end elif state>=0: newstate=-2 newcurrent=current newstart=start newend=end else: newstate=state newcurrent=current newstart=start newend=end return (tape,newstart,newend,newcurrent,newstate) #pretty-print a configuration def printconfig(config): tape=config[0] lowindex=min(config[1],config[3]) highindex=max(config[2]+1,config[3]+1) print 'state:',config[4] for j in range(lowindex,highindex): if tape[j]==' ': print 'B', else: print tape[j], print for j in range(lowindex,highindex): if config[3]==j: print '^', else: print ' ', print #read the transition table in from a specification file. #Conventions: The filename is the second argument followed by '.tm'. It #is assumed to be in the current directory. #Lines are formatted as #q a q' b' D #where q,q' are integers, a,b characters, and D is the character 'L' or 'R' #The initial state is always to be 0, accept, reject and halt -1,-2,-3. #The blank symbol is indicated by the character B,which must not be used as #a separate symbol of the tape alphabet. #Lines that start with the symbol # are treated as comments def read_transition_table(filename): f=open(filename+'.tm','r') d={} for line in f: seq=line.split() #print seq if (len(seq)>0) and (seq[0][0]!='#'): state=int(seq[0]) sym=seq[1] if sym=='B': sym=' ' newstate=int(seq[2]) newsym=seq[3] if newsym=='B': newsym=' ' if seq[4]=='L': direction=-1 else: direction=1 d[(state,sym)]=(newstate,newsym,direction) return d #Simulate the Turing machine specified in the filename on the input string #We don't let the simulation continue more than 1000 steps. If you want, #you can modify the code so that it shuts up and does not print the #configuration at each step. def runtm(filename,inputstring,verbose=True,bidirectional=True): d=read_transition_table(filename) #print d if bidirectional: table=[' ']*10000+list(inputstring)+[' ']*10000 config=(table,10000,10000+len(inputstring)-1,10000,0) else: table=list(inputstring)+[' ']*20000 config=(table,0,len(inputstring)-1,0,0) count=0 print count+1,'.', printconfig(config) while config[4]>=0: if count > 200000000: print 'Maximum number of steps exceeded.' break count+=1 config=nextconfig(d,config) if verbose: print count+1,'.', printconfig(config) if config[4]<0: if config[4]==-1: print 'accept' elif config[4]==-2: print 'reject' else: print 'halt' print count+1,'steps' for j in range(config[1],config[2]+1): print config[0][j], print