def test_epsilon(self): """ Generic tests for epsilon """ eps0 = Epsilon() eps1 = Epsilon() symb = Symbol(0) self.assertEqual(eps0, eps1) self.assertNotEqual(eps0, symb)
def test_intersection(self): """ Tests the intersection of two enfas """ enfa0 = get_enfa_example0() symb_a = Symbol("a") symb_b = Symbol("b") eps = Epsilon() enfa1 = EpsilonNFA() state0 = State(10) state1 = State(11) state2 = State(12) state3 = State(13) state4 = State(14) enfa1.add_start_state(state0) enfa1.add_final_state(state3) enfa1.add_final_state(state4) enfa1.add_transition(state0, eps, state1) enfa1.add_transition(state1, symb_a, state2) enfa1.add_transition(state2, eps, state3) enfa1.add_transition(state3, symb_b, state4) enfa = enfa0 & enfa1 self.assertEqual(len(enfa.start_states), 4) self.assertEqual(len(enfa.final_states), 2) self.assertEqual(len(enfa.symbols), 2) self.assertTrue(enfa.accepts([symb_a, symb_b])) self.assertFalse(enfa.accepts([symb_b])) self.assertFalse(enfa.accepts([symb_a])) self.assertFalse(enfa.accepts([])) self.assertFalse(enfa.accepts([symb_a, symb_a, symb_b]))
def test_check_intersection(): # Declare NFAs enfa0 = EpsilonNFA() enfa1 = EpsilonNFA() # Declare the states states = [State("q" + str(x)) for x in range(7)] # Declare the symbols epsilon = Epsilon() symb_a = Symbol("a") symb_b = Symbol("b") symb_c = Symbol("c") # epsilonNFA 0 # Add a start state enfa0.add_start_state(states[0]) # Add a final state enfa0.add_final_state(states[1]) # Add the transitions enfa0.add_transition(states[0], symb_a, states[1]) enfa0.add_transition(states[1], symb_a, states[1]) # epsilonNFA 1 # Add a start states enfa1.add_start_state(states[0]) enfa1.add_final_state(states[4]) # Add a final states enfa1.add_final_state(states[5]) enfa1.add_final_state(states[6]) # Add the transitions enfa1.add_transition(states[0], symb_a, states[1]) enfa1.add_transition(states[0], symb_b, states[2]) enfa1.add_transition(states[0], symb_c, states[3]) enfa1.add_transition(states[1], symb_a, states[4]) enfa1.add_transition(states[2], symb_b, states[5]) enfa1.add_transition(states[3], symb_c, states[6]) # Now enfa0 accepts a* \ {epsilon} # enfa1 accepts aa, bb, cc # Intersection of enfa0 and enfa1 enfa_res = enfa0.get_intersection(enfa1) # Check if a word is accepted assert enfa_res.accepts([symb_a, symb_a]), "Should accept aa" # Check non-correct words assert not enfa_res.accepts([epsilon]), "Accepts empty word, but it mustn't" assert not enfa_res.accepts([symb_a, symb_a, symb_a]), "Accepts aaa, but it mustn't" assert not enfa_res.accepts([symb_a]), "Accepts a, but it mustn't" assert not enfa_res.accepts([symb_b, symb_b]), "Accepts bb, but it mustn't" assert not enfa_res.accepts([symb_c, symb_c]), "Accepts cc, but it mustn't"
def test_cyclic(self): enfa = EpsilonNFA() state0 = State(0) state1 = State(1) symb_a = Symbol('a') enfa.add_start_state(state0) enfa.add_transition(state0, symb_a, state1) enfa.add_transition(state1, Epsilon(), state0) self.assertFalse(enfa.is_acyclic())
def test_to_regex3(self): """ Tests the transformation to regex """ enfa = EpsilonNFA() state0 = State(0) state1 = State(1) symb_a = Symbol("0") symb_b = Symbol("1") enfa.add_start_state(state0) enfa.add_final_state(state1) enfa.add_transition(state0, symb_a, state0) enfa.add_transition(state1, symb_b, state0) enfa.add_transition(state1, symb_b, state1) regex = enfa.to_regex() enfa2 = regex.to_epsilon_nfa() self.assertFalse(enfa2.accepts([symb_a])) self.assertFalse(enfa2.accepts([symb_a, symb_a])) self.assertFalse(enfa2.accepts([symb_a, symb_a, symb_b])) self.assertFalse( enfa2.accepts([symb_a, symb_a, symb_b, symb_b, symb_a])) self.assertFalse( enfa2.accepts([symb_a, symb_a, symb_b, symb_b, symb_a, symb_b])) self.assertFalse(enfa2.accepts([symb_b])) epsilon = Epsilon() enfa.add_transition(state0, epsilon, state1) regex = enfa.to_regex() enfa2 = regex.to_epsilon_nfa() self.assertTrue(enfa.accepts([])) self.assertTrue(enfa.accepts([symb_a])) self.assertTrue(enfa2.accepts([symb_a])) self.assertTrue(enfa2.accepts([symb_a, symb_a])) self.assertTrue(enfa2.accepts([symb_a, symb_a, symb_b, symb_b])) self.assertTrue( enfa2.accepts([symb_a, symb_a, symb_b, symb_b, symb_a, symb_b])) self.assertTrue(enfa2.accepts([symb_b])) self.assertTrue(enfa2.accepts([])) enfa.remove_transition(state0, symb_a, state0) regex = enfa.to_regex() enfa2 = regex.to_epsilon_nfa() self.assertFalse(enfa2.accepts([symb_a])) self.assertFalse(enfa2.accepts([symb_a, symb_a])) self.assertFalse(enfa2.accepts([symb_a, symb_a, symb_b])) self.assertFalse( enfa2.accepts([symb_a, symb_a, symb_b, symb_b, symb_a])) self.assertFalse( enfa2.accepts([symb_a, symb_a, symb_b, symb_b, symb_a, symb_b])) self.assertTrue(enfa2.accepts([symb_b])) self.assertTrue(enfa2.accepts([])) enfa.remove_transition(state1, symb_b, state1) regex = enfa.to_regex() enfa2 = regex.to_epsilon_nfa() self.assertTrue(enfa2.accepts([symb_b, symb_b])) enfa.add_transition(state0, symb_a, state0) regex = enfa.to_regex() enfa2 = regex.to_epsilon_nfa() self.assertTrue(enfa2.accepts([symb_a, symb_b]))
def get_enfa_example0_bis(): """ A non minimal NFA, equivalent to example0 """ enfa0 = EpsilonNFA() state3 = State(3) state4 = State(4) state0 = State(0) state1 = State(1) state2 = State(2) symb_a = Symbol("a") symb_b = Symbol("b") enfa0.add_start_state(state0) enfa0.add_final_state(state2) enfa0.add_final_state(state4) enfa0.add_transition(state0, symb_a, state0) enfa0.add_transition(state0, Epsilon(), state1) enfa0.add_transition(state1, symb_b, state2) # New part enfa0.add_transition(state0, Epsilon(), state3) enfa0.add_transition(state3, symb_a, state3) enfa0.add_transition(state3, symb_b, state4) return enfa0
def graph_to_dfa(g: Graph): nfa = EpsilonNFA() state_count = 0 for tup in g: sub, pred, obj = map(str, tup) # nfa.add_transition(State(sub), Symbol(pred), State(obj)) nfa.add_start_state(State(sub)) nfa.add_start_state(State(obj)) nfa.add_final_state(State(sub)) nfa.add_final_state(State(obj)) nfa.add_transition(State(sub), Epsilon(), State(state_count)) for c in pred: nfa.add_transition(State(state_count), Symbol(c), State(state_count+1)) state_count += 1 nfa.add_transition(State(state_count), Epsilon(), State(obj)) return nfa.to_deterministic()
def add_transitions(self, member, enter_state, exit_state): self.prefix += 1 if member == None: self.add_transition(enter_state, Epsilon(), exit_state) return if member["type"] == "BLANK": self.add_transition(enter_state, Epsilon(), exit_state) if member["type"] == "SYMBOL": if member["name"][0] == "_" and member["name"] not in self.externals: self.add_transitions(self.node_types[member["name"]], enter_state, exit_state) else: symbol = Symbol(member["name"]) self.add_transition(enter_state, symbol, exit_state) if member["type"] == "STRING": symbol = Symbol(member["value"]) self.add_transition(enter_state, symbol, exit_state) # memb = regex_to_member(member["value"]) # self.add_transitions(memb, enter_state, exit_state) if member["type"] == "PATTERN": # symbol = Symbol("regex:"+member["value"]) memb = regex_to_member(member["value"]) self.add_transitions(memb, enter_state, exit_state) # self.add_transition(enter_state, symbol, exit_state) if member["type"] in ["FIELD", "PREC","PREC_LEFT","PREC_RIGHT","ALIAS", "TOKEN"]: self.add_transitions(member["content"], enter_state, exit_state) if member["type"] == "SEQ": prev_state = enter_state for i, SEQ_member in enumerate(member["members"]): next_state = State(f"SEQ{self.prefix}_St_{i}") self.add_transitions(SEQ_member, prev_state, next_state) prev_state = next_state self.add_transition(next_state, Epsilon(), exit_state) if member["type"] == "CHOICE": for i, CHOICE_member in enumerate(member["members"]): choice_state = State(f"CH{self.prefix}_St_{i}") self.add_transitions(CHOICE_member, enter_state, choice_state) self.add_transition(choice_state, Epsilon(), exit_state) if member["type"] == "REPEAT": self.add_transition(enter_state, Epsilon(), exit_state) self.add_transition(exit_state, Epsilon(), enter_state) self.add_transitions(member["content"], enter_state, exit_state) if member["type"] == "REPEAT1": self.add_transition(exit_state, Epsilon(), enter_state) self.add_transitions(member["content"], enter_state, exit_state)
def test_get_as_dict(self): enfa0 = EpsilonNFA() state0 = State("0") state1 = State(1) symb_a = Symbol('a') enfa0.add_start_state(state0) enfa0.add_final_state(state1) enfa0.add_transition(state0, symb_a, state1) enfa0.add_transition(state1, Epsilon(), state0) d_enfa = enfa0.to_dict() self.assertIn(state0, d_enfa) self.assertIn(symb_a, d_enfa[state0]) self.assertIn(state1, d_enfa[state0][symb_a])
def test_complement(self): """ Tests the complement operation """ enfa = EpsilonNFA() state0 = State(0) state1 = State(1) state2 = State(2) symb_a = Symbol("a") enfa.add_start_state(state0) enfa.add_final_state(state2) enfa.add_transition(state0, Epsilon(), state1) enfa.add_transition(state1, symb_a, state2) enfa_comp = -enfa self.assertFalse(enfa_comp.accepts([symb_a]))
def test_import_networkx(self): enfa = EpsilonNFA() state0 = State("0") state1 = State(1) symb_a = Symbol('a') enfa.add_start_state(state0) enfa.add_final_state(state1) enfa.add_transition(state0, symb_a, state1) enfa.add_transition(state1, Epsilon(), state0) graph = enfa.to_networkx() enfa_from_nx = EpsilonNFA.from_networkx(graph) self.assertTrue(enfa_from_nx.accepts([symb_a])) self.assertTrue(enfa_from_nx.accepts([symb_a, symb_a])) self.assertFalse(enfa_from_nx.accepts([]))
def test_non_equivalent(self): enfa0 = EpsilonNFA() state0 = State("0") state1 = State(1) symb_a = Symbol('a') enfa0.add_start_state(state0) enfa0.add_final_state(state1) enfa0.add_transition(state0, symb_a, state1) enfa0.add_transition(state1, Epsilon(), state0) enfa1 = EpsilonNFA() enfa1.add_start_state(state0) enfa1.add_final_state(state1) enfa1.add_transition(state0, symb_a, state1) enfa1.add_transition(state1, symb_a, state0) self.assertFalse(enfa0.is_equivalent_to(enfa1))
def get_enfa_example0(): """ Gives an example ENFA Accepts a*b """ enfa0 = EpsilonNFA() state0 = State(0) state1 = State(1) state2 = State(2) symb_a = Symbol("a") symb_b = Symbol("b") enfa0.add_start_state(state0) enfa0.add_final_state(state2) enfa0.add_transition(state0, symb_a, state0) enfa0.add_transition(state0, Epsilon(), state1) enfa0.add_transition(state1, symb_b, state2) return enfa0
def test_iter(self): enfa = EpsilonNFA() state0 = State("0") state1 = State(1) symb_a = Symbol('a') enfa.add_start_state(state0) enfa.add_final_state(state1) enfa.add_transition(state0, symb_a, state1) enfa.add_transition(state1, Epsilon(), state0) counter = 0 for s_from, symb, s_to in enfa: counter += 1 self.assertIn((s_from, symb, s_to), enfa) self.assertNotIn((state1, symb_a, state1), enfa) self.assertIn(("0", "a", 1), enfa) self.assertEqual(counter, 2)
def test_export_networkx(self): enfa = EpsilonNFA() state0 = State("0") state1 = State(1) symb_a = Symbol('a') enfa.add_start_state(state0) enfa.add_final_state(state1) enfa.add_transition(state0, symb_a, state1) enfa.add_transition(state1, Epsilon(), state0) graph = enfa.to_networkx() self.assertTrue(isinstance(graph, networkx.MultiDiGraph)) self.assertTrue("0" in graph) self.assertTrue(("0", 1) in graph.edges) self.assertIn("a", [x["label"] for x in graph["0"][1].values()]) self.assertTrue(graph.nodes["0"]["is_start"]) self.assertFalse(graph.nodes["0"]["is_final"]) self.assertFalse(graph.nodes[1]["is_start"]) self.assertTrue(graph.nodes[1]["is_final"]) enfa.write_as_dot("enfa.dot")
def test_eclose(self): """ Test of the epsilon closure """ states = [State(x) for x in range(8)] epsilon = Epsilon() symb_a = Symbol("a") symb_b = Symbol("b") enfa = EpsilonNFA() enfa.add_transition(states[1], epsilon, states[2]) enfa.add_transition(states[1], epsilon, states[4]) enfa.add_transition(states[2], epsilon, states[3]) enfa.add_transition(states[3], epsilon, states[6]) enfa.add_transition(states[5], epsilon, states[7]) enfa.add_transition(states[4], symb_a, states[5]) enfa.add_transition(states[5], symb_b, states[6]) self.assertEqual(len(enfa.eclose(states[1])), 5) self.assertEqual(len(enfa.eclose(states[2])), 3) self.assertEqual(len(enfa.eclose(states[5])), 2) self.assertEqual(len(enfa.eclose(states[6])), 1) self.assertEqual(len(list(enfa._transition_function.get_edges())), 7) self.assertEqual(enfa.remove_transition(states[1], epsilon, states[4]), 1) self.assertFalse(enfa.is_deterministic())
def get_digits_enfa(): """ An epsilon NFA to recognize digits """ epsilon = Epsilon() plus = Symbol("+") minus = Symbol("-") point = Symbol(".") digits = [Symbol(x) for x in range(10)] states = [State("q" + str(x)) for x in range(6)] enfa = EpsilonNFA() enfa.add_start_state(states[0]) enfa.add_final_state(states[5]) enfa.add_transition(states[0], epsilon, states[1]) enfa.add_transition(states[0], plus, states[1]) enfa.add_transition(states[0], minus, states[1]) for digit in digits: enfa.add_transitions([(states[1], digit, states[1]), (states[1], digit, states[4]), (states[2], digit, states[3]), (states[3], digit, states[3])]) enfa.add_transitions([(states[1], point, states[2]), (states[4], point, states[3]), (states[3], epsilon, states[5])]) return enfa, digits, epsilon, plus, minus, point
def test_to_fst(self): """ Tests to turn a ENFA into a FST """ enfa = EpsilonNFA() fst = enfa.to_fst() self.assertEqual(len(fst.states), 0) self.assertEqual(len(fst.final_states), 0) self.assertEqual(len(fst.start_states), 0) self.assertEqual(len(fst.input_symbols), 0) self.assertEqual(len(fst.output_symbols), 0) self.assertEqual(fst.get_number_transitions(), 0) state0 = State("q0") s0bis = State("q0bis") enfa.add_start_state(state0) enfa.add_start_state(s0bis) fst = enfa.to_fst() self.assertEqual(len(fst.states), 2) self.assertEqual(len(fst.final_states), 0) self.assertEqual(len(fst.start_states), 2) self.assertEqual(len(fst.input_symbols), 0) self.assertEqual(len(fst.output_symbols), 0) self.assertEqual(fst.get_number_transitions(), 0) sfinal = State("qfinal") sfinalbis = State("qfinalbis") enfa.add_final_state(sfinal) enfa.add_final_state(sfinalbis) fst = enfa.to_fst() self.assertEqual(len(fst.states), 4) self.assertEqual(len(fst.final_states), 2) self.assertEqual(len(fst.start_states), 2) self.assertEqual(len(fst.input_symbols), 0) self.assertEqual(len(fst.output_symbols), 0) self.assertEqual(fst.get_number_transitions(), 0) enfa.add_transition(state0, Symbol("a"), sfinal) enfa.add_transition(sfinal, Symbol("b"), sfinal) enfa.add_transition(state0, Symbol("c"), sfinalbis) fst = enfa.to_fst() self.assertEqual(len(fst.states), 4) self.assertEqual(len(fst.final_states), 2) self.assertEqual(len(fst.start_states), 2) self.assertEqual(len(fst.input_symbols), 3) self.assertEqual(len(fst.output_symbols), 3) self.assertEqual(fst.get_number_transitions(), 3) enfa.add_transition(state0, Epsilon(), sfinalbis) fst = enfa.to_fst() self.assertEqual(len(fst.states), 4) self.assertEqual(len(fst.final_states), 2) self.assertEqual(len(fst.start_states), 2) self.assertEqual(len(fst.input_symbols), 3) self.assertEqual(len(fst.output_symbols), 3) self.assertEqual(fst.get_number_transitions(), 4) trans0 = list(fst.translate(["a"])) self.assertEqual(trans0, [["a"]]) trans0 = list(fst.translate(["a", "b", "b"])) self.assertEqual(trans0, [["a", "b", "b"]]) trans0 = list(fst.translate(["b", "b"])) self.assertEqual(trans0, []) trans0 = list(fst.translate(["c"])) self.assertEqual(trans0, [["c"]])
def test_invalid_epsilon(self): """ Tests invalid transition """ transition_function = TransitionFunction() with self.assertRaises(InvalidEpsilonTransition): transition_function.add_transition("1", Epsilon(), "2")
def test_epsilon_refused(self): dfa = NondeterministicFiniteAutomaton() state0 = State(0) state1 = State(1) with self.assertRaises(InvalidEpsilonTransition): dfa.add_transition(state0, Epsilon(), state1)