def test_move_one_rule_no_tape(self): tm = TuringMachine("q4 -> q3") assert tm.mconf == "q4" # First m-conf in code is first in simulation tm.move() assert tm.mconf == "q3" with raises(TMLocked): tm.move()
def test_tape_str_assignment(self): tm = TuringMachine() # Without rules tape = __import__("string").ascii_letters tm.tape = tape assert tm.tape == dict(enumerate(tape)) for symbol in tape: assert tm.scan() == symbol tm.perform("R")
def test_scan(self): tm = TuringMachine() msg = "It's only a test" msg_dict = dict(enumerate(msg, -2)) tm.tape = msg_dict pairs = list(msg_dict.items()) __import__("random").shuffle(pairs) for idx, el in pairs: tm.index = idx assert tm.scan() == el
def test_perform_one_task(self, task, index_delta, tape_list_before, tape_dict_after): tm = TuringMachine() # Without rules assert tm.index == 0 assert tm.tape == {} tm.tape = tape_list_before assert tm.tape == dict(enumerate(tape_list_before)) tm.perform(task) assert tm.index == index_delta assert tm.tape == tape_dict_after
def test_init_empty(self): tm = TuringMachine() assert tm.index == 0 assert tm.tape == {} assert len(tm) == 0 assert len(tm.inv_dict) == 0 assert not hasattr(self, "mconf") with raises(TMLocked): tm["a", "0"] # Rule querying with raises(TMLocked): tm.move()
def test_tape_list_assignment_with_blank(self, blank_index): tm = TuringMachine() # Without rules tape = list(__import__("string").ascii_letters) tape[blank_index] = "None" expected_tape = {k: v for k, v in enumerate(tape) if k != blank_index % len(tape)} tm.tape = tape assert len(tm.tape) == len(tape) - 1 assert tm.tape == expected_tape for symbol in tape: assert tm.scan() == symbol tm.perform("R")
def test_perform_and_move_unknown_task(self, task): tm_perform = TuringMachine() # Without rules with raises(ValueError): tm_perform.perform(task) if task.strip(): # Parsing rule makes sense tm_move_parsed = TuringMachine("a None -> {} a".format(task)) with raises(ValueError): tm_move_parsed.move() tm_move_setitem = TuringMachine() tm_move_setitem.mconf = "a" tm_move_setitem["a", "None"] = ([task], "a") with raises(ValueError): tm_move_setitem.move()
def test_move_two_rules_no_tape(self): tm = TuringMachine("a -> b\nb None -> R c\n") assert tm.mconf == "a" tm.move() assert tm.mconf == "b" assert tm.scan() == "None" tm.move() assert tm.mconf == "c" with raises(TMLocked): tm.move()
def test_tape_list_and_dict_assignment_without_blank(self, tape_list): tape_dict = dict(enumerate(tape_list)) tm_list = TuringMachine() # Without rules tm_dict = TuringMachine() assert tm_list.index == tm_dict.index == 0 assert tm_list.tape == tm_dict.tape == {} tm_list.tape = tape_list tm_dict.tape = tape_dict assert tm_list.index == tm_dict.index == 0 assert tm_list.tape == tm_dict.tape == tape_dict for symbol in tape_list: assert tm_list.scan() == tm_dict.scan() == symbol tm_list.perform("R") tm_dict.perform("R")
def test_move_zero_one_zero_one(self): tm = TuringMachine( "a -> P0 R b\n" "b -> P1 R a\n" ) for unused in range(40): assert tm.mconf == "a" tm.move() assert tm.mconf == "b" tm.move() tape = tm.tape assert len(tape) == 80 for idx in range(80): assert tape[idx] == str(idx % 2)
def test_copy(self): tm = TuringMachine("q1 -> P0 R q2\n" "q2 None -> P1 R q1") tm.tape = "Test" tm.perform("R") tm.perform("P1") tmcp = tm.copy() # Rules and inverted rules assert list(tmcp.items()) == list(tm.items()) assert list(tmcp.inv_dict.items()) == list(tm.inv_dict.items()) # Complete configuration assert tmcp.tape == dict(enumerate("T1st")) == tm.tape assert tmcp.index == 1 == tm.index assert tmcp.mconf == "q1" == tm.mconf tm.move() assert tmcp.tape != tm.tape assert tmcp.index != tm.index assert tmcp.mconf != tm.mconf assert tm.tape == dict(enumerate("T0st")) assert tm.index == 2 assert tm.mconf == "q2"
def test_tape_dict_assignment(self, blank_index, delta): tm = TuringMachine() # Without rules tape = list(__import__("string").ascii_letters) tape[blank_index] = "None" expected_tape = { k + delta: v for k, v in enumerate(tape) if k != blank_index % len(tape) } tape_dict = dict(enumerate(tape, delta)) tm.tape = tape_dict assert tm.tape == expected_tape assert tm.index == 0 assert tm.scan() == tape[-delta] if delta <= 0 else "None" for task in delta * "R" + -delta * "L": tm.perform(task) assert tm.index == delta for symbol in tape: assert tm.scan() == symbol tm.perform("R")
def test_copy_without_mconf_nor_rules(self): tm = TuringMachine() tm.tape = dict(enumerate("TestTestTest", -2)) tm.perform("L") tm.perform("P0") tmcp = tm.copy() # Rules and inverted rules assert list(tmcp.items()) == list(tm.items()) == [] assert list(tmcp.inv_dict.items()) == list(tm.inv_dict.items()) == [] # Complete configuration assert tmcp.tape == dict(enumerate("T0stTestTest", -2)) == tm.tape assert tmcp.index == -1 == tm.index tmcp.perform("L") tmcp.perform("P1") assert tmcp.tape != tm.tape assert tmcp.index != tm.index assert tmcp.tape == dict(enumerate("10stTestTest", -2)) assert tmcp.index == -2 assert not hasattr(tm, "mconf") assert not hasattr(tmcp, "mconf")
def test_tape_dict_assignment(self, blank_index, delta): tm = TuringMachine() # Without rules tape = list(__import__("string").ascii_letters) tape[blank_index] = "None" expected_tape = {k + delta: v for k, v in enumerate(tape) if k != blank_index % len(tape)} tape_dict = dict(enumerate(tape, delta)) tm.tape = tape_dict assert tm.tape == expected_tape assert tm.index == 0 assert tm.scan() == tape[-delta] if delta <= 0 else "None" for task in delta * "R" + -delta * "L": tm.perform(task) assert tm.index == delta for symbol in tape: assert tm.scan() == symbol tm.perform("R")
def test_move_zero_one_zero_one(self): tm = TuringMachine("a -> P0 R b\n" "b -> P1 R a\n") for unused in range(40): assert tm.mconf == "a" tm.move() assert tm.mconf == "b" tm.move() tape = tm.tape assert len(tape) == 80 for idx in range(80): assert tape[idx] == str(idx % 2)
def test_tape_list_assignment_with_blank(self, blank_index): tm = TuringMachine() # Without rules tape = list(__import__("string").ascii_letters) tape[blank_index] = "None" expected_tape = { k: v for k, v in enumerate(tape) if k != blank_index % len(tape) } tm.tape = tape assert len(tm.tape) == len(tape) - 1 assert tm.tape == expected_tape for symbol in tape: assert tm.scan() == symbol tm.perform("R")
def test_turing_first_example(self): tm1 = TuringMachine( # On p. 233 of his article "b None -> P0 R c\n" "c None -> R e\n" "e None -> P1 R f\n" "f None -> R b\n" ) tm2 = TuringMachine( # On p. 234 of his article, the same idea "b None -> P0 b\n" " 0 -> R R P1 b\n" " 1 -> R R P0 b\n" ) assert tm1.mconf == tm2.mconf == "b" assert tm1.index == tm2.index == 0 tm1.move() # Syncronizing them tm2.move() for idx in range(50): assert tm2.mconf == "b" assert tm1.index == 2 * idx + 1 tm1.move() assert tm1.index == 2 * idx + 2 tm1.move() assert tm1.index == 2 * idx + 3 assert tm2.index == 2 * idx tm2.move() assert tm2.index == 2 * idx + 2 assert tm1.tape == tm2.tape tape = tm1.tape tape_length = abs(max(tm1.tape) - min(tm1.tape)) assert tape_length == 100 for idx in range(100): if idx % 2 == 0: assert tape[idx] == str(idx // 2 % 2) else: assert idx not in tape # "None"
def test_turing_first_example(self): tm1 = TuringMachine( # On p. 233 of his article "b None -> P0 R c\n" "c None -> R e\n" "e None -> P1 R f\n" "f None -> R b\n") tm2 = TuringMachine( # On p. 234 of his article, the same idea "b None -> P0 b\n" " 0 -> R R P1 b\n" " 1 -> R R P0 b\n") assert tm1.mconf == tm2.mconf == "b" assert tm1.index == tm2.index == 0 tm1.move() # Syncronizing them tm2.move() for idx in range(50): assert tm2.mconf == "b" assert tm1.index == 2 * idx + 1 tm1.move() assert tm1.index == 2 * idx + 2 tm1.move() assert tm1.index == 2 * idx + 3 assert tm2.index == 2 * idx tm2.move() assert tm2.index == 2 * idx + 2 assert tm1.tape == tm2.tape tape = tm1.tape tape_length = abs(max(tm1.tape) - min(tm1.tape)) assert tape_length == 100 for idx in range(100): if idx % 2 == 0: assert tape[idx] == str(idx // 2 % 2) else: assert idx not in tape # "None"
def test_mod_3_equals_zero(self, binary_number_string): code = "\n".join( # Starting with an empty tape, adds the digits to the tape ["pre-start -> L"] + [" R P{}".format(el) for el in binary_number_string] + [ " goto-start", # Go back with the "cursor" to the first symbol in tape "goto-start", " None -> R start", " -> L goto-start", # Starts with zero in mind, so modulo is zero "start -> mod0", # Every digit d appended to x makes the new number y = x * 2 + d, # and the same follows in modulo 3 "mod0", " 0 -> R mod0", " 1 -> R mod1", " None -> L return_T", "mod1", " 0 -> R mod2", " 1 -> R mod0", " None -> L return_F", "mod2", " 0 -> R mod1", " 1 -> R mod2", " None -> L return_F", # Clears the tape and "prints" to it the desired result "return_T", " [0 1] -> E L return_T", " None -> R PT loop", "return_F", " [0 1] -> E L return_F", " None -> R PF loop", # Deadlock "loop -> loop", ]) number = int(binary_number_string, base=2) all_numbers_tape = dict(enumerate(binary_number_string)) result = "T" if number % 3 == 0 else "F" tm = TuringMachine(code) print(code) assert tm.tape == {} assert tm.index == 0 assert tm.mconf == "pre-start" # Puts the digits into the machine tm.move() assert tm.tape == all_numbers_tape assert tm.index == len(binary_number_string) - 1 assert tm.mconf == "goto-start" # Go back to the beginning for digit in reversed(binary_number_string): assert tm.scan() == digit old_idx = tm.index tm.move() assert tm.tape == all_numbers_tape assert tm.index == old_idx - 1 assert tm.mconf == "goto-start" assert tm.scan() == "None" assert tm.index == -1 tm.move() assert tm.tape == all_numbers_tape assert tm.index == 0 assert tm.mconf == "start" # Initialization tm.move() assert tm.tape == all_numbers_tape assert tm.index == 0 assert tm.mconf == "mod0" # Follow the digits mod_value = 0 for idx, digit in enumerate(binary_number_string, 1): assert tm.scan() == digit tm.move() mod_value = (mod_value * 2 + int(digit, base=2)) % 3 assert tm.tape == all_numbers_tape assert tm.index == idx assert tm.mconf == "mod{}".format(mod_value) # After last digit return_mconf = "return_" + result assert tm.scan() == "None" tm.move() assert tm.tape == all_numbers_tape assert tm.index == len(binary_number_string) - 1 assert tm.mconf == return_mconf # Erases digit per digit for digit in reversed(binary_number_string): assert tm.scan() == digit old_idx = tm.index tm.move() assert tm.tape == { k: v for k, v in all_numbers_tape.items() if k < old_idx } assert tm.index == old_idx - 1 assert tm.mconf == return_mconf # Returns! assert tm.scan() == "None" for unused in range(5): tm.move() assert tm.tape == {0: result} assert tm.index == 0 assert tm.mconf == "loop"
def test_init_no_first_m_configuration(self): with raises(TMSyntaxError): TuringMachine(" -> q2")
def test_mod_3_equals_zero(self, binary_number_string): code = "\n".join( # Starting with an empty tape, adds the digits to the tape ["pre-start -> L"] + [" R P{}".format(el) for el in binary_number_string] + [" goto-start", # Go back with the "cursor" to the first symbol in tape "goto-start", " None -> R start", " -> L goto-start", # Starts with zero in mind, so modulo is zero "start -> mod0", # Every digit d appended to x makes the new number y = x * 2 + d, # and the same follows in modulo 3 "mod0", " 0 -> R mod0", " 1 -> R mod1", " None -> L return_T", "mod1", " 0 -> R mod2", " 1 -> R mod0", " None -> L return_F", "mod2", " 0 -> R mod1", " 1 -> R mod2", " None -> L return_F", # Clears the tape and "prints" to it the desired result "return_T", " [0 1] -> E L return_T", " None -> R PT loop", "return_F", " [0 1] -> E L return_F", " None -> R PF loop", # Deadlock "loop -> loop", ] ) number = int(binary_number_string, base=2) all_numbers_tape = dict(enumerate(binary_number_string)) result = "T" if number % 3 == 0 else "F" tm = TuringMachine(code) print(code) assert tm.tape == {} assert tm.index == 0 assert tm.mconf == "pre-start" # Puts the digits into the machine tm.move() assert tm.tape == all_numbers_tape assert tm.index == len(binary_number_string) - 1 assert tm.mconf == "goto-start" # Go back to the beginning for digit in reversed(binary_number_string): assert tm.scan() == digit old_idx = tm.index tm.move() assert tm.tape == all_numbers_tape assert tm.index == old_idx - 1 assert tm.mconf == "goto-start" assert tm.scan() == "None" assert tm.index == -1 tm.move() assert tm.tape == all_numbers_tape assert tm.index == 0 assert tm.mconf == "start" # Initialization tm.move() assert tm.tape == all_numbers_tape assert tm.index == 0 assert tm.mconf == "mod0" # Follow the digits mod_value = 0 for idx, digit in enumerate(binary_number_string, 1): assert tm.scan() == digit tm.move() mod_value = (mod_value * 2 + int(digit, base=2)) % 3 assert tm.tape == all_numbers_tape assert tm.index == idx assert tm.mconf == "mod{}".format(mod_value) # After last digit return_mconf = "return_" + result assert tm.scan() == "None" tm.move() assert tm.tape == all_numbers_tape assert tm.index == len(binary_number_string) - 1 assert tm.mconf == return_mconf # Erases digit per digit for digit in reversed(binary_number_string): assert tm.scan() == digit old_idx = tm.index tm.move() assert tm.tape == {k: v for k, v in all_numbers_tape.items() if k < old_idx} assert tm.index == old_idx - 1 assert tm.mconf == return_mconf # Returns! assert tm.scan() == "None" for unused in range(5): tm.move() assert tm.tape == {0: result} assert tm.index == 0 assert tm.mconf == "loop"
def ajax_simulate(): tm = TuringMachine(request.form["machine"]) for el in range(3000): tm.move() return jsonify(tm.tape)