def test_print_configs(self, print_config): """Should print each machine configuration to stdout.""" tape1 = TMTape( tape='01010101', blank_symbol='.', current_position=0, ) tape2 = TMTape( tape='x1010101', blank_symbol='.', current_position=-1, ) tape3 = TMTape( tape='yx1010101', blank_symbol='.', current_position=-2, ) configs = [ TMConfiguration(tape1, 'q0'), TMConfiguration(tape2, 'q1'), TMConfiguration(tape3, 'q2') ] tmtools.print_configs(configs) nose.assert_equal(print_config.call_args_list, [ call(), call(), call() ])
def test_print_configs(self, print_config): """Should print each machine configuration to stdout.""" tape1 = TMTape( tape='01010101', blank_symbol='.', current_position=0, position_offset=0 ) tape2 = TMTape( tape='x1010101', blank_symbol='.', current_position=-1, position_offset=0 ) tape3 = TMTape( tape='yx1010101', blank_symbol='.', current_position=-2, position_offset=1 ) tmtools.print_configs([ ('q0', tape1), ('q1', tape2), ('q2', tape3) ]) nose.assert_equal(print_config.call_args_list, [ call('q0', tape1, 1), call('q1', tape2, 1), call('q2', tape3, 1) ])
def test_print_configs(self, print_config): """Should print each machine configuration to stdout.""" tape1 = TMTape( tape='01010101', blank_symbol='.', current_position=0, ) tape2 = TMTape( tape='x1010101', blank_symbol='.', current_position=-1, ) tape3 = TMTape( tape='yx1010101', blank_symbol='.', current_position=-2, ) configs = [ TMConfiguration(tape1, 'q0'), TMConfiguration(tape2, 'q1'), TMConfiguration(tape3, 'q2'), MTMConfiguration('q1', (tape1, tape2, tape3)) ] out = io.StringIO() with contextlib.redirect_stdout(out): tmtools.print_configs(configs) self.assertEqual(print_config.call_args_list, [ call(), call(), call() ])
def test_get_symbols_as_str(self): """Should print tape contents as a string without spaces.""" tape = TMTape( tape='abcdef', blank_symbol='.', current_position=2, ) self.assertEqual(tape.get_symbols_as_str(), 'abcdef')
def read_input_stepwise(self, input_str): """ Check if the given string is accepted by this Turing machine. Yield the current configurations of the machine at each step. """ current_configurations = { TMConfiguration(self.initial_state, TMTape(input_str, blank_symbol=self.blank_symbol)) } yield current_configurations # The initial state cannot be a final state for a NTM, so the first # iteration is always guaranteed to run (as it should) while current_configurations: new_configurations = set() for config in current_configurations: if self._has_accepted(config): # One accepting configuration is enough. return new_configurations.update( self._get_next_configurations(config)) current_configurations = new_configurations yield current_configurations raise exceptions.RejectionException( 'the NTM did not reach an accepting configuration')
def test_tape_iteration(self): """Should be able to iterate over a Turing machine tape.""" tape = TMTape( tape='abcdef', blank_symbol='.', current_position=2, ) nose.assert_equal(tuple(tape), ('a', 'b', 'c', 'd', 'e', 'f'))
def setup(self): """Provide a configuration for testing.""" self.config = TMConfiguration( 'q2', TMTape( tape='abcdefghij', blank_symbol='.', current_position=2, ) )
def test_print_config(self): """Should print the given configuration to stdout.""" out = io.StringIO() with contextlib.redirect_stdout(out): tmtools.print_config( current_state='q2', tape=TMTape( tape='abcdefghij', blank_symbol='.', current_position=2, position_offset=1), max_position_offset=3) nose.assert_equal(out.getvalue().rstrip(), '{}: {}\n{}'.format( 'q2', '..abcdefghij', '^'.rjust(10)))
def setUp(self): """Provide a configuration for testing.""" self.config = TMConfiguration( 'q2', TMTape( tape='abcdefghij', blank_symbol='.', current_position=2, ) ) self.config2 = MTMConfiguration( 'q1', (TMTape( tape='abcdefghij', blank_symbol='.', current_position=2, ), TMTape( tape='klmnopq', blank_symbol='.', current_position=5, )) )
def read_input_stepwise(self, input_str): """ Check if the given string is accepted by this Turing machine. Yield the current configuration of the machine at each step. """ current_configuration = TMConfiguration( self.initial_state, TMTape(input_str, blank_symbol=self.blank_symbol)) yield current_configuration # The initial state cannot be a final state for a DTM, so the first # iteration is always guaranteed to run (as it should) while not self._has_accepted(current_configuration): current_configuration = self._get_next_configuration( current_configuration) yield current_configuration
def __init__(self, *, states, input_symbols, tape_symbols, n_tapes, transitions, initial_state, blank_symbol, final_states, tapes=None, current_state=None): """Initialize a complete Turing machine.""" self.states = states.copy() self.input_symbols = input_symbols.copy() self.tape_symbols = tape_symbols.copy() self.transitions = copy.deepcopy(transitions) self.initial_state = initial_state self.blank_symbol = blank_symbol self.final_states = final_states.copy() self.n_tapes = n_tapes if tapes is not None: self.tapes = [tape.copy() for tape in tapes] else: self.tapes = [ TMTape(self.blank_symbol, blank_symbol=self.blank_symbol) for _ in range(n_tapes) ] if current_state is not None: self.current_state = current_state else: self.current_state = self.initial_state self.validate()
def read_input_stepwise(self, input_str): """ Check if the given string is accepted by this Turing machine. Yield the current configuration of the machine at each step. """ current_state = self.initial_state current_direction = None tape = TMTape(input_str, blank_symbol=self.blank_symbol) yield current_state, tape # The initial state cannot be a final state for a DTM, so the first # iteration is always guaranteed to run (as it should) while current_state not in self.final_states: input_symbol = tape.read_symbol() (current_state, new_tape_symbol, current_direction) = self._get_transition(current_state, input_symbol) tape.write_symbol(new_tape_symbol) tape.move(current_direction) yield current_state, tape
def _validate_input_yield(self, input_str): """ Check if the given string is accepted by this Turing machine. Yield the current configuration of the machine at each step. """ current_state = self.initial_state current_direction = None tape = TMTape(input_str, blank_symbol=self.blank_symbol) yield current_state, tape # The initial state cannot be a final state for a DTM, so the first # iteration is always guaranteed to run (as it should) while current_state not in self.final_states: input_symbol = tape.read_symbol() (current_state, new_tape_symbol, current_direction) = self._get_transition( current_state, input_symbol) tape.write_symbol(new_tape_symbol) tape.move(current_direction) yield current_state, tape
def read_input_as_ntm(self, input_str): """Simulates the machine as a single-tape Turing machine. Yields the configuration at each step.""" self._restart_configuration(input_str) head_symbol = '^' tape_separator_symbol = '_' extended_tape = '' tapes_copy = self.tapes.copy() for tape_copy in tapes_copy: tape_str = tape_copy.get_symbols_as_str() extended_tape += tape_str[0] + head_symbol + \ tape_str[1:] + tape_separator_symbol current_state = self.initial_state yield { TMConfiguration( current_state, TMTape(extended_tape, blank_symbol=self.blank_symbol, current_position=0)) } # If the machine has not reached an accepting state. while current_state not in self.final_states: i = 0 # current position virtual_heads = self._read_extended_tape(extended_tape, head_symbol, tape_separator_symbol) try: next_config = self.transitions[current_state][virtual_heads] except KeyError: raise exceptions.RejectionException( 'the multitape NTM did not reach an accepting ' 'configuration') next_state, moves = next_config[0] for move in moves: new_head, direction = move executing_changes = True while executing_changes: if extended_tape[i] == head_symbol: # Head has been found (previous symbol is the head). # This replaces the previous symbol with the new_head. extended_tape = (extended_tape[:i - 1] + new_head + extended_tape[i:]) extended_tape = extended_tape[:i] + \ '' + extended_tape[i + 1:] # After replacing, the machine must change the # position of the virtual head of the current virtual # tape. if direction == 'R': i += 1 elif direction == 'L': i -= 1 else: # direction == 'N' i += 0 if extended_tape[i - 1] == tape_separator_symbol: i -= 1 extended_tape = extended_tape[:i] + \ self.blank_symbol + \ head_symbol + extended_tape[i:] i += 1 else: extended_tape = (extended_tape[:i] + head_symbol + extended_tape[i:]) elif extended_tape[i] == tape_separator_symbol: executing_changes = False i += 1 current_state = next_state yield { TMConfiguration( current_state, TMTape(extended_tape, blank_symbol=self.blank_symbol, current_position=i - 1)) }