def applyTransition(self, t): """Apply the given transition to the current configuration. This implements one computational step of the Turing machine, following the given transition to its destination state, writing a symbol onto the tape if necessary, and moving the head if necessary. Args: t (Transition): the Transition to be followed. If t is None and implicit rejection is permitted, the machine will transition into the project state. """ if TuringMachine.verbose: print('Applying transition', t) self.steps = self.steps + 1 if not t: if self.allowImplicitReject: self.state = TuringMachine.rejectState else: message = '***Error***: No valid transition was found, and implicit rejects are disabled.\n' + \ 'Current configuration:\n' + str(self) raise utils.WcbcException(message) else: self.state = t.destState if self.isAHaltingState(self.state): self.halted = True if t: if t.writeSymbol: self.writeSymbol(t.writeSymbol) if t.direction == TuringMachine.leftDir: if self.headPos > 0: self.headPos = self.headPos - 1 elif self.allowLeftFromCell0: pass # we remain in cell 0 else: message = '***Error***: Tried to move left ' + \ 'from cell 0, which is disallowed by ' + \ 'this Turing machine.\n' + \ 'Current configuration:\n' + str(self) raise utils.WcbcException(message) elif t.direction == TuringMachine.rightDir: self.headPos = self.headPos + 1 if self.headPos == len(self.tape): self.tape.append(TuringMachine.blank) if self.keepHistory: self.history.append(str(self))
def __init__(self, description = None, tapeStr = '', name = None, \ keepHistory = False): """Initialize NDTuringMachine object. Args: description (str): A string describing the states and transitions of the nondeterministic Turing machine, according to the specification described in the textbook. For examples, see the files containsGAGA.tm and binaryIncrementer.tm. tapeStr (str): The initial content of the Turing machine's tape. name (str): A string that gives a meaningful name to the machine, e.g. 'binary incrementer'. This can be used for debugging and meaningful output. keepHistory (bool): If True, keep a complete record of the history of this machine's computation. This is useful for certain experiments, but costly in terms of storage. """ self.rootClone = self.createRootClone(description, tapeStr, 'root', \ keepHistory) """TuringMachine object: The root clone of this nondeterministic Turing machine, which is itself a (deterministic) Turing machine. """ if len(self.rootClone.blocks) > 0: msg = "Sorry, blocks aren't supported for nondeterministic machines" raise utils.WcbcException(msg) self.clones = set([self.rootClone]) """set of TuringMachine objects: the set of clones that comprise this nondeterministic Turing machine. """ self.steps = 0 """int: The number of computational steps taken so far in the computation.""" self.nextCloneID = 1 """int: Each clone is assigned an ID number sequentially, beginning with zero for the root clone. This stores the ID that will be assigned to the next clone created. """ self.name = name self.keepHistory = keepHistory self.acceptingClone = None """TuringMachine object: mostly for debugging, remember which clone
def step(self): """Perform one computational step for this Turing machine.""" ts = self.getValidTransitions() if len(ts) > 1: message = '***Error***: multiple valid transitions in deterministic Turing machine.\n' + \ 'Current state:' + self.state + '\n' + \ 'Valid transitions:' + str(ts) raise utils.WcbcException(message) if len(ts) == 0: t = None else: t = ts[0] self.applyTransition(t) if self.state in self.blocks: self.runBlock()
def checkSymbolIsValid(self, t, c): """Check if a given symbol is permitted in Turing machines. Nothing is returned, but a WcbcException is raised if the symbol is invalid. Args: t (Transition): the Transition in which c is used. c (str): a single character which is the symbol to be checked """ if c not in TuringMachine.validSymbols: message = '''***Error***: The symbol {0} (ASCII value {1}) is not permitted in Turing machine alphabets. The full transition containing this error is:\n{2}'''.format(c, ord(c), t) raise utils.WcbcException(message)
def revertSolution(cliqueSoln): if cliqueSoln == 'no': return 'no' nodes = cliqueSoln.split(',') if cliqueSoln != '' else [] # Remove everything after the 'C' in each node name nodes = [n[:n.index('C')] for n in nodes] # build truth assignment truthAssignment = dict() for node in nodes: variableName = node[:-1] posNeg = node[-1:] if posNeg == 'p': truthAssignment[variableName] = True elif posNeg == 'n': truthAssignment[variableName] = False else: raise utils.WcbcException('Unexpected node name' + node) return truthAssignment
def write(self): """Convert the current Turing machine into description format. Returns: str: description format of the current machine, suitable for storing in a .tm file. """ if len(self.blocks)>0: raise utils.WcbcException("Error: writing Turing machines is not implemented for blocks.") if self.transitions == None: return '[No transitions]' lines = [] for tList in self.transitions.values(): for t in tList: line = self.writeTransition(t) lines.append(line) lines.sort() return '\n'.join(lines)
def run(self): """Run the nondeterministic Turing machine until it halts. For practical reasons, the machine will also stop once it exceeds its maximum number of steps. """ while True: if NDTuringMachine.verbose: print(self) print() self.step() allReject = True retVal = None for tm in self.clones: if tm.state != TuringMachine.rejectState: allReject = False if tm.state == TuringMachine.acceptState: retVal = 'yes' elif tm.state == TuringMachine.haltState: retVal = ''.join(tm.tape) # Mostly for debugging, remember which clone accepted # (if any). Also, we break so that the first clone to # accept is the one whose return value is used. if tm.state == TuringMachine.acceptState or \ tm.state == TuringMachine.haltState: self.acceptingClone = tm break if allReject: retVal = 'no' if retVal != None: return retVal if self.steps >= NDTuringMachine.maxSteps: self.rootClone.raiseExceededMaxSteps() # return NDTuringMachine.exceededMaxStepsMsg if len(self.clones) > self.maxClones: raise utils.WcbcException(NDTuringMachine.exceededMaxClonesMsg)
def raiseExceededMaxSteps(self): """Raise an exception indicating that the maximum number of steps was exceeded. """ raise utils.WcbcException(TuringMachine.exceededMaxStepsMsg + \ '. Current output: ' + self.getOutput())