def test_complete_when_dfa_is_not_complete(self): """Test that when we try to make complete a non-complete SimpleDFA then the returned SimpleDFA is complete.""" dfa = SimpleDFA( {"q0", "q1"}, MapAlphabet({"a", "b"}), "q0", set(), {"q0": {"a": "q0", "b": "q1"}}, ) expected_dfa = SimpleDFA( {"q0", "q1", "sink"}, MapAlphabet({"a", "b"}), "q0", set(), { "q0": {"a": "q0", "b": "q1"}, "q1": {"a": "sink", "b": "sink"}, "sink": {"a": "sink", "b": "sink"}, }, ) actual_dfa = dfa.complete() assert actual_dfa == expected_dfa
def graph_automata(states, alphabet, initial_state, accepting_states, transition_function, name, minimize = False): dfa = SimpleDFA(states, alphabet, initial_state, accepting_states, transition_function) if minimize: graph = dfa.minimize().trim().to_graphviz() else: graph = dfa.to_graphviz() graph.render(name)
def test_is_complete_when_dfa_is_not_complete(self): """Test that the is_complete method return False if the SimpleDFA is not complete.""" dfa = SimpleDFA( {"q0", "q1"}, MapAlphabet({"a", "b"}), "q0", set(), {"q0": {"a": "q0", "b": "q1"}}, ) assert not dfa.is_complete()
def test_complete_when_dfa_is_already_complete(self): """Test that when we try to make complete an already complete SimpleDFA then the returned SimpleDFA is equal to the previous one.""" complete_dfa = SimpleDFA( {"q"}, MapAlphabet({"a"}), "q", set(), {"q": {"a": "q"}} ) new_dfa = complete_dfa.complete() assert complete_dfa == new_dfa
def test_reachable_no_transitions(self): """Test that the reachable SimpleDFA of a SimpleDFA without transitions is the SimpleDFA with only the initial state.""" dfa = SimpleDFA({"q0", "q1", "q2"}, MapAlphabet({"a1", "a2"}), "q0", {"q1"}, {}) actual_reachable_dfa = dfa.reachable() expected_reachable_dfa = SimpleDFA( {"q0"}, MapAlphabet({"a1", "a2"}), "q0", set(), {} ) assert actual_reachable_dfa == expected_reachable_dfa
def GraphDFA(self): states = set(self.trans_func.keys()) alphabet = set(self.symbols) dfa = SimpleDFA(states, alphabet, self.initial_state, self.accepting_states, self.trans_func) graph = dfa.trim().to_graphviz() graph.attr(rankdir='LR') source = graph.source WriteToFile('./output/DirectDFA.gv', source) graph.render('./output/DirectDFA.gv', format='pdf', view=True)
def test_to_graphviz(self): dfa = SimpleDFA( {"q0", "q1", "q2", "q3", "q4", "q5"}, MapAlphabet({"a", "b"}), "q0", {"q0"}, {}, ) dfa.to_graphviz() dfa = SimpleDFA( {"q0", "q1", "q2", "q3", "q4", "q5"}, MapAlphabet({"a", "b"}), "q0", {"q3"}, { "q0": {"a": "q0", "b": "q1"}, "q1": {"a": "q0", "b": "q2"}, "q2": {"a": "q3", "b": "q4"}, "q3": {"a": "q3", "b": "q4"}, "q4": {"a": "q3", "b": "q5"}, }, ) dfa.to_graphviz()
def test_coreachable_no_accepting_states_gives_empty_dfa(self): dfa = SimpleDFA( {"q0", "q1", "q2"}, MapAlphabet({"a1", "a2"}), "q0", set(), {"q0": {"a1": "q0", "a2": "q1"}}, ) actual_coreachable = dfa.coreachable() expected_coreachable = EmptyDFA(MapAlphabet({"a1", "a2"})) assert actual_coreachable == expected_coreachable
def test_coreachable_simple_case(self): dfa = SimpleDFA( {"q0", "q1", "q2"}, MapAlphabet({"a1", "a2"}), "q0", {"q0"}, {"q0": {"a1": "q0", "a2": "q1"}}, ) actual_coreachable = dfa.coreachable() expected_coreachable = SimpleDFA( {"q0"}, MapAlphabet({"a1", "a2"}), "q0", {"q0"}, {"q0": {"a1": "q0"}} ) assert actual_coreachable == expected_coreachable
def setup_class(cls): """Set the test up.""" cls.dfa = SimpleDFA( {0, 1, 2}, MapAlphabet(["a", "b", "c"]), 0, {2}, {0: {"a": 0, "b": 1}, 1: {"b": 1, "c": 2}, 2: {"c": 2}}, )
def test_dfa_from_transitions(): """Test that the constructor "from_transitions" works correctly.""" states = {"q0", "q1", "q2"} actions = MapAlphabet({"a0", "a1"}) initial_state = "q0" final_states = {"q2"} transition_function = {"q0": {"a0": "q1"}, "q1": {"a1": "q2"}} expected_dfa = SimpleDFA( states, actions, initial_state, final_states, transition_function ) actual_dfa = SimpleDFA.from_transitions( initial_state, final_states, transition_function ) assert expected_dfa == actual_dfa
def setup_class(cls): """Set the test up.""" cls.dfa = SimpleDFA( {0, 1, 2}, ["a", "b", "c"], 0, {2}, { 0: {"a": 0, "b": 1, "c": 2}, 1: {"a": 0, "b": 1, "c": 2}, 2: {"a": 0, "b": 1, "c": 2}, }, )
def test_transition_function_with_invalid_symbols_raises_error(self): """Test that if a symbol of some transitions is invalid we raise an error.""" with pytest.raises( ValueError, match="Transition function not valid: symbols .* are not in the alphabet.", ): SimpleDFA( {"q0", "q1"}, MapAlphabet({"a"}), "q0", set(), {"q0": {"a": "q1"}, "q1": {"b": "q1"}}, )
def test_minimize(self): dfa = SimpleDFA( {"q0", "q1", "q2", "q3", "q4"}, MapAlphabet({"a", "b", "c"}), "q0", {"q3", "q4"}, { "q0": {"a": "q1", "b": "q2"}, "q1": {"c": "q3"}, "q2": {"c": "q3"}, "q3": {"c": "q4"}, "q4": {"c": "q4"}, }, ) actual_minimized_dfa = dfa.minimize() # the renaming of the states is non deterministic, so we need to compare every substructure. assert len(actual_minimized_dfa._states) == 4 assert actual_minimized_dfa._alphabet == ArrayAlphabet(["a", "b", "c"]) assert actual_minimized_dfa.is_complete()
def test_level_to_accepting_states(self): dfa = SimpleDFA( {"q0", "q1", "q2", "q3", "q4", "q5"}, MapAlphabet({"a", "b"}), "q0", {"q3"}, { "q0": {"a": "q0", "b": "q1"}, "q1": {"a": "q0", "b": "q2"}, "q2": {"a": "q3", "b": "q4"}, "q3": {"a": "q3", "b": "q4"}, "q4": {"a": "q3", "b": "q5"}, }, ) assert dfa.levels_to_accepting_states() == { "q0": 3, "q1": 2, "q2": 1, "q3": 0, "q4": 1, "q5": -1, }
def problem_dfa(): """ Create DFA for problem domain. :return: SimpleDFA object """ alphabet = { "wait,s0", "wait,s1", "wait,s2", "wait,s3", "wait,s4", "wait,s5", "wait,s6", "mov_hw1,s5", "mov_hw2,s6", "mov_w1w2,s3", "mov_w1h,s1", "mov_w2h,s2", "mov_w2w1,s3", "mov_w12h,s4", "start,s0" } states = {"s0", "s1", "s2", "s3", "s4", "s5", "s6", 's_init'} initial_state = "s_init" accepting_states = {"s0", "s1", "s2", "s3", "s4", "s5", "s6"} transition_function = { "s_init": { "start,s0": "s0", }, "s0": { "mov_hw1,s5": "s5", "mov_hw2,s6": "s6", "wait,s0": "s0" }, "s5": { "mov_w1w2,s3": "s3", "mov_w1h,s1": "s1", "wait,s5": "s5" }, "s6": { "mov_w2w1,s3": "s3", "mov_w2h,s2": "s2", "wait,s6": "s6" }, "s3": { "mov_w12h,s4": "s4", "wait,s3": "s3" }, "s1": { "wait,s1": "s1" }, "s2": { "wait,s2": "s2" }, "s4": { "wait,s4": "s4" } } dfa = SimpleDFA(states, alphabet, initial_state, accepting_states, transition_function) return dfa
def intersection(prb_dfa, ltl_dfa): """ Build the intersection DFA automaton between problem DFA and LTL DFA. :param prb_dfa: problem DFA :param ltl_dfa: LTL formula DFA :return: SimpleDFA object """ parser = LTLfParser() alphabet = prb_dfa.alphabet states = set({}) initial_state = "[" + prb_dfa.initial_state + "," + str( ltl_dfa.initial_state) + "]" accepting_states = set({}) transition_function = {} explore = {(prb_dfa.initial_state, str(ltl_dfa.initial_state))} while len(explore) is not 0: state = explore.pop() state_intersection = "[" + state[0] + "," + state[1] + "]" states.add(state_intersection) if prb_dfa.is_accepting(state[0]) and ltl_dfa.is_accepting( int(state[1])): accepting_states.add(state_intersection) for letter in alphabet: successor = prb_dfa.get_successors(state[0], letter) if len(successor) is not 0: prob_state = successor.pop() ltl_state = state[1] props = [propositions[prob_state]] transitions = ltl_dfa.get_transitions_from(int(state[1])) for transition in transitions: formula = ltl_extract_formula(transition) if parser(str(formula).replace("~", "!")).truth(props, 0): ltl_state = str(ltl_extract_next_state(transition)) break new_state_intersection = "[" + prob_state + "," + ltl_state + "]" if new_state_intersection not in states: explore.add((prob_state, ltl_state)) if state_intersection not in transition_function: transition_function[state_intersection] = { letter: new_state_intersection } else: transition_function[state_intersection][ letter] = new_state_intersection return SimpleDFA(states, alphabet, initial_state, accepting_states, transition_function)
def test_trim_simple_case(self): dfa = SimpleDFA( {"q0", "q1", "q2", "sink"}, MapAlphabet({"a", "b"}), "q0", {"q1"}, { "q0": {"a": "q0", "b": "q1"}, "q1": {"a": "sink", "b": "sink"}, "sink": {"a": "sink", "b": "sink"}, }, ) actual_trimmed_dfa = dfa.trim() expected_trimmed_dfa = SimpleDFA( {"q0", "q1"}, MapAlphabet({"a", "b"}), "q0", {"q1"}, {"q0": {"a": "q0", "b": "q1"}}, ) assert actual_trimmed_dfa == expected_trimmed_dfa
def serverGateway(alphabet, states, initialState, acceptingState, transitionList): transitionFunction = _getTransitionFunction(states, transitionList) alphabet = set(alphabet) states = set(states) acceptingState = set(acceptingState) dfa = SimpleDFA(states, alphabet, initialState, acceptingState, transitionFunction) initialDFAGraph = dfa.to_graphviz() initialDFAGraph.render("initial", view=False, format='png') minimizedDFA = dfa.minimize() graph = minimizedDFA.trim().to_graphviz() graph.render("graph", view=False, format='png') with open("initial.png", "rb") as image_file: initialGraphEncoded = base64.b64encode(image_file.read()) with open("graph.png", "rb") as image_file: finalGraphEncoded = base64.b64encode(image_file.read()) return [initialGraphEncoded, finalGraphEncoded]
def test_transition_function_with_invalid_end_states_raises_error(self): """Test that if some of the ending states of the transitions is not in the set of states we raise an error.""" with pytest.raises( ValueError, match="Transition function not valid: states .* " "are not in the set of states.", ): SimpleDFA( {"q0", "q1"}, MapAlphabet({"a"}), "q0", set(), {"q0": {"a": "q1"}, "q1": {"a": "q2"}}, )
def test_equality(self): """Test that the equality between two SimpleDFA works correctly.""" assert self.dfa == self.dfa another_dfa = SimpleDFA( {0, 1, 2}, MapAlphabet(["a", "b", "c"]), 0, {2}, { 0: {"a": 0, "b": 1, "c": 2}, 1: {"a": 0, "b": 1, "c": 2}, 2: {"a": 0, "b": 1, "c": 2}, }, ) assert self.dfa == another_dfa
def test_accepts(self): dfa = SimpleDFA( {"q0", "q1"}, MapAlphabet({"a", "b"}), "q0", {"q1"}, {"q0": {"a": "q0", "b": "q1"}}, ) assert not dfa.accepts([]) assert not dfa.accepts(["a"]) assert not dfa.accepts(["a"]) assert dfa.accepts(["b"]) assert dfa.accepts(["a", "b"]) assert not dfa.accepts(["a", "a"]) assert not dfa.accepts(["b", "b"])
def test_even_01_automaton(): """Test the even-01 automaton in the documentation.""" states = {"q0", "q1", "q2", "q3"} alphabet = {"0", "1"} initial_state = "q0" accepting_states = {"q0"} transition_function = { "q0": { "0": "q2", "1": "q1" }, "q1": { "0": "q3", "1": "q0" }, "q2": { "0": "q0", "1": "q3" }, "q3": { "0": "q1", "1": "q2" }, } automaton = SimpleDFA( states=states, alphabet=alphabet, initial_state=initial_state, accepting_states=accepting_states, transition_function=transition_function, ) assert automaton.is_complete() assert automaton.accepts("") # True assert not automaton.accepts("0") # False - only one '0' assert not automaton.accepts("1") # False - only one '1' assert automaton.accepts("00") # True assert automaton.accepts("11") # True assert automaton.accepts("01" * 42) # True
def test_is_complete_when_dfa_is_complete(self): """Test that the is_complete method return True if the SimpleDFA is complete.""" dfa = SimpleDFA({"q"}, MapAlphabet({"a"}), "q", set(), {"q": {"a": "q"}}) assert dfa.is_complete()
def test_initial_state_not_in_states_raises_error(self): """Test that if the initial state is not in the set of states we raise an error.""" with pytest.raises( ValueError, match="Initial state .* not in the set of states." ): SimpleDFA(set("q1"), MapAlphabet({"a"}), "q0", set(), {})
def test_empty_set_of_states_raises_error(self): """Test that when we try to instantiate a DFA with an empty set of states we raise an error.""" with pytest.raises(ValueError, match="The set of states cannot be empty."): SimpleDFA(set(), MapAlphabet({"a"}), "q0", set(), {})
def test_some_accepting_states_not_in_states_raises_error(self): """Test that if some accepting states are not in the set of states we raise an error.""" with pytest.raises( ValueError, match="Accepting states .* not in the set of states." ): SimpleDFA({"q0", "q1"}, MapAlphabet({"a"}), "q0", {"q2", "q3"}, {})