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_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_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_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_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_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_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 ajax_simulate(): tm = TuringMachine(request.form["machine"]) for el in range(3000): tm.move() return jsonify(tm.tape)
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_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"