def test_is_automata_completely_defined(self):
        q0 = State("q0")
        q1 = State("q1")
        automaton = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q1})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q1, 'a', q0)

        self.assertFalse(automaton.is_completely_defined())
    def test_insert_transition(self):
        q0 = State("q0")
        q1 = State("q1")
        automaton = FiniteAutomaton({q0, q1}, {'a'}, q0, set())

        automaton.insert_transition(q0, 'a', q1)

        self.assertTrue(automaton.has_transition(q0, 'a', q1))
    def test_rename_all_states(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        automaton = FiniteAutomaton({q0, q1, q2}, {'a', 'b'}, q0, {q1, q2})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q1, 'b', q2)
        automaton.insert_transition(q1, '&', q2)

        automaton.rename_states()

        self.assertTrue(automaton.recognize_sentence("ab"))
        self.assertFalse(automaton.recognize_sentence("b"))
    def test_remove_transition(self):
        q0 = State("q0")
        q1 = State("q1")
        automaton = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q1})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q0, 'b', q1)
        automaton.insert_transition(q1, 'a', q0)
        automaton.insert_transition(q1, 'b', q0)

        automaton.remove_transition(q0, 'a', q1)

        self.assertFalse(automaton.has_transition(q0, 'a', q1))
        self.assertTrue(automaton.has_transition(q0, 'b', q1))
        self.assertTrue(automaton.has_transition(q1, 'a', q0))
Example #5
0
def test_determinization(source_automaton, tests):
    automaton = FiniteAutomaton.from_dict(source_automaton)
    automaton.determinize_minimal()

    for test in tests:
        word, result = test
        assert(automaton.check(word) == result)
    def test_recognize_sentence_with_epsilon_transition(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        automaton = FiniteAutomaton({q0, q1, q2}, {'a', 'b'}, q0, {q2})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q1, 'a', q0)
        automaton.insert_transition(q1, '&', q2)
        automaton.insert_transition(q2, 'b', q2)

        self.assertTrue(automaton.recognize_sentence("aaab"))
        self.assertTrue(automaton.recognize_sentence("aaaaabbbbbbbb"))
        self.assertFalse(automaton.recognize_sentence("aaaabbb"))
    def test_insert_false_transition(self):
        q0 = State("q0")
        q1 = State("q1")
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton({q0}, alphabet, q0, {q0})

        self.assertRaises(Exception, automaton.insert_transition, q0, 'c', q0)
        self.assertRaises(Exception, automaton.insert_transition, q0, 'a', q1)
    def test_automata_subtraction(self):
        q0 = State("q0")
        q1 = State("q1")
        abstar = FiniteAutomaton({q0}, {'a', 'b'}, q0, {q0})
        abstar.insert_transition(q0, 'a', q0)
        abstar.insert_transition(q0, 'b', q0)

        evena = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q0})
        evena.insert_transition(q0, 'b', q0)
        evena.insert_transition(q0, 'a', q1)
        evena.insert_transition(q1, 'b', q1)
        evena.insert_transition(q1, 'a', q0)

        subtraction = abstar - evena

        self.assertTrue(subtraction.recognize_sentence("babbbaba"))
        self.assertTrue(subtraction.recognize_sentence("a"))
        self.assertFalse(subtraction.recognize_sentence("abababa"))
    def test_dont_recognize_false_sentence(self):
        q0 = State("q0")
        q1 = State("q1")
        states = {q0, q1}
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q0, {q1})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q0, 'b', q1)
        automaton.insert_transition(q1, 'a', q0)
        automaton.insert_transition(q1, 'b', q0)
        #L(M) = odd sized sentences

        self.assertFalse(automaton.is_nondeterministic())
        self.assertFalse(automaton.recognize_sentence("abaa"))
        self.assertFalse(automaton.recognize_sentence("abc"))
    def test_add_nondeterministic_transition(self):
        q0 = State("q0")
        q1 = State("q1")
        automaton = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q1})
        automaton.insert_transition(q0, 'a', q0)
        automaton.insert_transition(q1, 'b', q1)

        automaton.insert_transition(q0, 'a', q1)

        self.assertTrue(automaton.is_nondeterministic())
        self.assertTrue(automaton.has_transition(q0, 'a', q0))
        self.assertTrue(automaton.has_transition(q0, 'a', q1))
    def test_minimization_on_the_automaton_language_epsilon_word(self):
        q0 = State("q0")
        q1 = State("q1")
        epsilon_word = FiniteAutomaton({q0, q1}, set(), q0, {q1})
        epsilon_word.insert_transition(q0, '&', q1)

        epsilon_word.minimize()

        self.assertTrue(epsilon_word.recognize_sentence(""))
    def test_automaton_complement(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton({q0, q1, q2}, alphabet, q0, {q0})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q0, 'b', q0)
        automaton.insert_transition(q1, 'b', q1)
        automaton.insert_transition(q1, 'a', q2)
        automaton.insert_transition(q2, 'b', q2)
        automaton.insert_transition(q2, 'a', q0)
        #L(M) = {x | x in (a,b)* ^ #a's is divisible by 3}

        complement = automaton.complement()

        self.assertTrue(automaton.recognize_sentence("baabbababaabb"))
        self.assertFalse(automaton.recognize_sentence("abbabababbba"))
        self.assertTrue(complement.recognize_sentence("abbabababbba"))
        self.assertFalse(complement.recognize_sentence("baabbababaabb"))
Example #13
0
def test_one_letter_transitions(source_automaton, tests):
    automaton = FiniteAutomaton.from_dict(source_automaton)
    automaton.one_letter_transitions()

    for test in tests:
        word, result = test
        assert(automaton.check(word) == result)

    for state in automaton.states:
        for tr in state.transitions:
            assert(len(tr.string) == 1)
Example #14
0
 def __init__(self, file):
     self.__symbols_table = SymbolsTable()
     self.__types = [
         'int', 'real', 'char', 'string', 'bool', 'array', 'none'
     ]
     self.__operators = [
         '<', '>', '=', '!', '+', '-', '/', '%', '*', ':=', '&', '|'
     ]
     self.__reserved_words = self.__types + [
         'if', 'else', 'while', 'then', 'do', 'print', 'read', 'return',
         'main'
     ]
     self.__separators = ['[', ']', '(', ')', '.', '{', '}', ';', ':']
     self.__pif = PIF()
     self.__file = file
     self.__set_files()
     self.__errors = set()
     self.__check_integer = FiniteAutomaton('constants/integer_const.in')
     self.__check_bool = FiniteAutomaton('constants/bool_const.in')
     self.__check_char = FiniteAutomaton('constants/char_const.in')
     self.__check_string = FiniteAutomaton('constants/string_const.in')
    def test_intersection_disjoint_languages(self):
        q0 = State("q0")
        q1 = State("q1")
        evena = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q0})
        evena.insert_transition(q0, 'b', q0)
        evena.insert_transition(q0, 'a', q1)
        evena.insert_transition(q1, 'b', q1)
        evena.insert_transition(q1, 'a', q0)

        empty = evena.intersection(evena.complement())

        empty.minimize()

        self.assertTrue(empty.is_empty())
    def test_is_the_empty_language(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        q3 = State("q3")
        automaton = FiniteAutomaton({q0, q1, q2, q3}, {'a', 'b'}, q0, {q3})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q1, 'b', q2)
        automaton.insert_transition(q3, 'a', q2)

        self.assertTrue(automaton.is_empty())
Example #17
0
class UI:
    def __init__(self):
        self.__fa = FiniteAutomaton("fa.in")

    @staticmethod
    def print_menu():
        print("Options: ")
        print("     Exit - 0")
        print("     Print states - 1")
        print("     Print alphabet - 2")
        print("     Print transitions - 3")
        print("     Print final states - 4")
        print("     Is deterministic - 5")
        print("     Check word - 6")

    def run(self):
        while True:
            UI.print_menu()
            option = int(input("Choose option: "))
            if option == 0:
                break
            elif option == 1:
                for i in self.__fa.q:
                    print(i)
            elif option == 2:
                for i in self.__fa.alphabet:
                    print(i)
            elif option == 3:
                print(self.__fa.transitions)
            elif option == 4:
                for i in self.__fa.F:
                    print(i)
            elif option == 5:
                print(self.__fa.is_deterministic())
            elif option == 6:
                word = input("Enter word: ")
                print(self.__fa.is_accepted(word))
            else:
                print("Incorrect option")
    def test_minimize_empty_complement_automaton(self):
        q0 = State("q0")
        q1 = State("q1")
        evena = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q0})
        evena.insert_transition(q0, 'b', q0)
        evena.insert_transition(q0, 'a', q1)
        evena.insert_transition(q1, 'b', q1)
        evena.insert_transition(q1, 'a', q0)

        complement = evena.complement()

        intersection = evena.intersection(complement)

        intersection = intersection.complement()

        intersection.minimize()

        self.assertFalse(intersection.is_empty())
    def test_remove_unreachable_states(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        states = {q0, q1}
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q0, {q1})
        automaton.insert_transition(q0, 'a', q1)

        automaton.remove_unreachable_states()

        self.assertSetEqual(automaton._states, {q0,q1})
Example #20
0
def process_finite_automaton(json):
    fa = FiniteAutomaton(json)
    while True:
        print_fa_menu()
        option = input()
        if option == "0":
            break
        elif option == "1":
            print(fa.get_states())
        elif option == "2":
            print(fa.get_alphabet())
        elif option == "3":
            print(fa.get_transitions())
        elif option == "4":
            print(fa.get_final_states())
        elif option == "5":
            print(fa.convert())
        else:
            print("Invalid option")
Example #21
0
def test_automaton_to_regexp(source_automaton, tests):
    source = FiniteAutomaton.from_dict(source_automaton)
    from_regexp = FiniteAutomaton.from_regexp(source.to_regexp())

    for test in tests:
        assert(source.check(test) == from_regexp.check(test))
    def test_remove_dead_states(self):
        q = []
        for i in range(0, 6):
            q.append(State("q" + str(i)))
        states = set(q)
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q[0], {q[2]})
        automaton.insert_transition(q[0], 'a', q[1])
        automaton.insert_transition(q[0], 'b', q[3])
        automaton.insert_transition(q[1], 'a', q[2])
        automaton.insert_transition(q[1], 'b', q[2])
        automaton.insert_transition(q[3], 'a', q[5])
        automaton.insert_transition(q[4], 'a', q[3])
        automaton.insert_transition(q[5], 'a', q[4])

        automaton.remove_dead_states()

        self.assertSetEqual(automaton._states, {q[0], q[1], q[2]})
Example #23
0
def test_regexp_to_automaton(regexp, tests):
    automaton = FiniteAutomaton.from_regexp(regexp)
    for case in tests:
        word, result = case
        assert (automaton.check(word) == result)
Example #24
0
 def __init__(self):
     self.__fa = FiniteAutomaton("fa.in")
    def test_automata_union(self):
        q0 = State("q0")
        q1 = State("q1")
        states = {q0, q1}
        alphabet = {'a', 'b'}
        automaton1 = FiniteAutomaton(states, alphabet, q0, {q1})
        automaton1.insert_transition(q0, 'a', q1)
        automaton1.insert_transition(q0, 'b', q1)
        automaton1.insert_transition(q1, 'a', q0)
        automaton1.insert_transition(q1, 'b', q0)
        #L(M) = {x|x in (a,b)* ^ |x| is odd}
        s0 = State("s0")
        s1 = State("s1")
        states = {s0, s1}
        alphabet = {'a', 'b'}
        automaton2 = FiniteAutomaton(states, alphabet, s0, {s0})
        automaton2.insert_transition(s0, 'a', s1)
        automaton2.insert_transition(s0, 'b', s1)
        automaton2.insert_transition(s1, 'a', s0)
        automaton2.insert_transition(s1, 'b', s0)
        #L(M) = {x|x in (a,b)* ^ |x| is even}

        union = automaton1.union(automaton2)

        self.assertTrue(automaton1.recognize_sentence("abaab"))
        self.assertTrue(automaton2.recognize_sentence("ababba"))
        self.assertFalse(automaton1.recognize_sentence("ababba"))
        self.assertFalse(automaton2.recognize_sentence("abaab"))
        self.assertTrue(union.recognize_sentence("abaab"))
        self.assertTrue(union.recognize_sentence("ababba"))
        self.assertFalse(union.recognize_sentence("abc"))
    def test_automata_union_3(self):
        q0 = State("q0")
        q1 = State("q1")
        states = {q0, q1}
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q0, {q0, q1})
        automaton.insert_transition(q0, 'a', q0)
        automaton.insert_transition(q0, 'b', q1)
        automaton.insert_transition(q1, 'a', q0)
        #L(M) = {x|x in (a,b)* ^ bb not in x}
        q2 = State("q2")
        div3 = FiniteAutomaton({q0, q1, q2}, {'a', 'b'}, q0, {q0})
        div3.insert_transition(q0, 'a', q1)
        div3.insert_transition(q0, 'b', q1)
        div3.insert_transition(q1, 'a', q2)
        div3.insert_transition(q1, 'b', q2)
        div3.insert_transition(q2, 'a', q0)
        div3.insert_transition(q2, 'b', q0)

        union = automaton.union(div3)

        self.assertTrue(union.recognize_sentence("abbaaabba"))
        self.assertTrue(union.recognize_sentence("aaabaaabaa"))
        self.assertFalse(union.recognize_sentence("bbabbaa"))
    def test_insert_state(self):
        automaton = FiniteAutomaton(set(), set(), State(""), set())

        automaton.insert_state(State("q0"))

        self.assertEqual(1, automaton.state_quantity())
    def test_recognize_nondeterministic(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        q3 = State("q3")
        automaton = FiniteAutomaton({q0, q1, q2, q3}, {'a', 'b'}, q0, {q3})
        automaton.insert_transition(q0, 'a', q0)
        automaton.insert_transition(q0, 'b', q0)
        automaton.insert_transition(q0, 'b', q1)
        automaton.insert_transition(q1, 'a', q2)
        automaton.insert_transition(q2, 'b', q3)
        automaton.insert_transition(q3, 'a', q3)
        automaton.insert_transition(q3, 'b', q3)

        self.assertTrue(automaton.recognize_sentence("abaababaaaba"))
        self.assertFalse(automaton.recognize_sentence("aaaabaaab"))
    def test_remove_state(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        states = {q0, q1, q2}
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q0, {q1})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q0, 'b', q2)
        automaton.insert_transition(q1, 'a', q0)
        automaton.insert_transition(q1, 'b', q2)
        automaton.insert_transition(q2, 'a', q0)
        automaton.insert_transition(q2, 'a', q1)

        automaton.remove_state(q1)

        self.assertFalse(automaton.has_transition(q0, 'a', q1))
        self.assertFalse(automaton.has_transition(q1, 'a', q0))
        self.assertTrue(automaton.has_transition(q0, 'b', q2))
        self.assertSetEqual(automaton._states, {q0, q2})
    def test_automaton_intersection(self):
        q0 = State("q0")
        q1 = State("q1")
        states = {q0, q1}
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q0, {q0})
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q0, 'b', q1)
        automaton.insert_transition(q1, 'a', q0)
        automaton.insert_transition(q1, 'b', q0)
        #L(M) = {x|x in (a,b)* ^ |x| is even}
        other = FiniteAutomaton(states, alphabet, q0, {q0, q1})
        other.insert_transition(q0, 'a', q0)
        other.insert_transition(q0, 'b', q1)
        other.insert_transition(q1, 'a', q0)
        #L(M) = {x|x in (a,b)* ^ bb not in x}

        intersection = automaton.intersection(other)

        self.assertTrue(automaton.recognize_sentence("aabaab"))
        self.assertTrue(other.recognize_sentence("aabaab"))
        self.assertTrue(intersection.recognize_sentence("aabaab"))
        self.assertFalse(intersection.recognize_sentence("abbaaa"))
    def test_determinize_automaton(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        q3 = State("q3")
        automaton = FiniteAutomaton({q0, q1, q2, q3}, {'a', 'b'}, q0, {q3})
        automaton.insert_transition(q0, 'a', q0)
        automaton.insert_transition(q0, 'b', q0)
        automaton.insert_transition(q0, 'b', q1)
        automaton.insert_transition(q1, 'a', q2)
        automaton.insert_transition(q2, 'b', q3)
        automaton.insert_transition(q3, 'a', q3)
        automaton.insert_transition(q3, 'b', q3)
        #{x|x in (a,b)* and bab in x}
        determinized = automaton.copy()

        determinized.determinize()

        self.assertTrue(automaton.is_nondeterministic())
        self.assertFalse(determinized.is_nondeterministic())
        self.assertTrue(determinized.recognize_sentence("abaaababbbaaaab"))
        self.assertTrue(determinized.recognize_sentence("baaaaaabbbbbbbbabbaaaaaa"))
        self.assertFalse(determinized.recognize_sentence("aaaabaabaabaabaab"))
    def test_remove_equivalent_states(self):
        q = []
        for i in range(0, 6):
            q.append(State("q" + str(i)))
        states = set(q)
        alphabet = {'a', 'b'}
        automaton = FiniteAutomaton(states, alphabet, q[0], {q[0], q[5]})
        automaton.insert_transition(q[0], 'a', q[5])
        automaton.insert_transition(q[0], 'b', q[1])
        automaton.insert_transition(q[1], 'a', q[4])
        automaton.insert_transition(q[1], 'b', q[3])
        automaton.insert_transition(q[2], 'a', q[2])
        automaton.insert_transition(q[2], 'b', q[5])
        automaton.insert_transition(q[3], 'a', q[4])
        automaton.insert_transition(q[3], 'b', q[0])
        automaton.insert_transition(q[4], 'a', q[1])
        automaton.insert_transition(q[4], 'b', q[2])
        automaton.insert_transition(q[5], 'a', q[5])
        automaton.insert_transition(q[5], 'b', q[4])
        old = automaton.copy()

        automaton.remove_equivalent_states()

        self.assertTrue(old.recognize_sentence("aaaaaaababba"))
        self.assertTrue(automaton.recognize_sentence("aaaaaaababba"))
        self.assertFalse(old.recognize_sentence("baaaaba"))
        self.assertFalse(automaton.recognize_sentence("baaaaba"))
    def test_minimize_automaton(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        q3 = State("q3")
        automaton = FiniteAutomaton({q0, q1, q2, q3}, {'a', 'b'}, q0, {q0, q2})
        automaton.insert_transition(q0, 'b', q2)
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q1, 'b', q1)
        automaton.insert_transition(q1, 'a', q2)
        automaton.insert_transition(q2, 'b', q2)
        automaton.insert_transition(q2, 'a', q3)
        automaton.insert_transition(q3, 'b', q3)
        automaton.insert_transition(q3, 'a', q2)

        automaton.minimize()

        self.assertSetEqual(automaton._states, {q0, q1})
        self.assertTrue(automaton.recognize_sentence("baabaabaababab"))
    def test_equality_2(self):
        q0 = State("q0")
        q1 = State("q1")
        evena = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q0})
        evena.insert_transition(q0, 'b', q0)
        evena.insert_transition(q0, 'a', q1)
        evena.insert_transition(q1, 'b', q1)
        evena.insert_transition(q1, 'a', q0)
        q2 = State("q2")
        q3 = State("q3")
        amod4 = FiniteAutomaton({q0, q1, q2, q3}, {'a', 'b'}, q0, {q0})
        amod4.insert_transition(q0, 'b', q0)
        amod4.insert_transition(q0, 'a', q1)
        amod4.insert_transition(q1, 'b', q1)
        amod4.insert_transition(q1, 'a', q2)
        amod4.insert_transition(q2, 'b', q2)
        amod4.insert_transition(q2, 'a', q3)
        amod4.insert_transition(q3, 'b', q3)
        amod4.insert_transition(q3, 'a', q0)

        self.assertFalse(evena.is_equal(amod4))
    def test_change_state_name(self):
        q0 = State("q0")
        q1 = State("q1")
        evena = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q0})
        evena.insert_transition(q0, 'b', q0)
        evena.insert_transition(q0, 'a', q1)
        evena.insert_transition(q1, 'b', q1)
        evena.insert_transition(q1, 'a', q0)

        evena._change_state_name(q0, "q2")

        self.assertTrue(evena.recognize_sentence("bbabaabba"))
        self.assertTrue(evena.recognize_sentence("aaaa"))
        self.assertFalse(evena.recognize_sentence("abbabaabbab"))
Example #36
0
def test_complement(source_regexp, alphabet, tests):
    automaton = FiniteAutomaton.from_regexp(source_regexp)
    automaton.complement()
    for test in tests:
        word, result = test
        assert(automaton.check(word) == result)
    def to_finite_automaton(self):
        """Retorna o resultado da conversão da Gramática para um NDFA
        @return Automato resultante
        """
        # get initial state as the initial symbol
        initial_state = State(self._initial_symbol)
        # create a 'final' state that will get the productions that go just for a terminal
        # as "A->a" or "A->b"
        final_state = State('final')

        # sets for the states and final states
        states = set()
        final_states = set()

        # add the initial and 'final' states to the sets
        states.add(initial_state)
        states.add(final_state)
        final_states.add(final_state)

        # dict that translates a nonterminal to a state, and add the initial state on it
        nonterminals_states = dict()
        nonterminals_states[self._initial_symbol] = initial_state

        # gather states and final states from the existing productions
        for production in self._productions:
            # verify that there is a state for certain nonterminal(on the left)
            # otherwise create it, and add to the states set and dict
            if production._left not in nonterminals_states:
                new_state = State(production._left)
                states.add(new_state)
                nonterminals_states[production._left] = new_state

            # if the nonterminal have a epsilon production, than its state is final
            # as "A->&" or "B->&"
            if production._right == '&':
                state = nonterminals_states[production._left]
                final_states.add(state)

        #print("initial_state",initial_state)
        #print("states",states)
        #print("final_states",final_states)
        #print("nonterminals_states",nonterminals_states)

        # create a ndfa from the states, terminals, initial state and final states gathered above
        ndfa = FiniteAutomaton(states, self._terminals, initial_state, final_states)

        # create the transitions from the productions
        for production in self._productions:
            # get the state correspondent to the nonterminal(on the left)
            state = nonterminals_states[production._left]

            # if the production is in the format "A->a", "A->b"
            # its state gonna have a transition to the 'final' state by its terminal
            if production._right in self._terminals:
                ndfa.insert_transition(state, production._right, final_state)
                #print(production._left, '--', production._right, '->', '[F]')
            # if the production is in the format "A->A", "A->B" ## PS: its not regular ##
            # its state gonna have a transition by epsilon to the other's state
            elif production._right in self._nonterminals:
                other_state = nonterminals_states[production._right]
                ndfa.insert_transition(state, '&', other_state)
                #print(production._left, '--', '&', '->', production._left)
            # if the production is in the format "A->aA", "A->aB"
            # its state gonna have a transition by the terminal to the other nonterminal's state
            elif production._right[0] in self._terminals and production._right[1] in self._nonterminals:
                other_state = nonterminals_states[production._right[1]]
                ndfa.insert_transition(state, production._right[0], other_state)
                #print(production._left, '--', production._right[0], '->', production._right[1])

        # determinize the ndfa and return it
        # ndfa.determinize()
        return ndfa
    def test_automata_equality(self):
        q0 = State("q0")
        q1 = State("q1")
        q2 = State("q2")
        q3 = State("q3")
        automaton = FiniteAutomaton({q0, q1, q2, q3}, {'a', 'b'}, q0, {q0, q2})
        automaton.insert_transition(q0, 'b', q2)
        automaton.insert_transition(q0, 'a', q1)
        automaton.insert_transition(q1, 'b', q1)
        automaton.insert_transition(q1, 'a', q2)
        automaton.insert_transition(q2, 'b', q2)
        automaton.insert_transition(q2, 'a', q3)
        automaton.insert_transition(q3, 'b', q3)
        automaton.insert_transition(q3, 'a', q2)

        evena = FiniteAutomaton({q0, q1}, {'a', 'b'}, q0, {q0})
        evena.insert_transition(q0, 'b', q0)
        evena.insert_transition(q0, 'a', q1)
        evena.insert_transition(q1, 'b', q1)
        evena.insert_transition(q1, 'a', q0)

        self.assertTrue(evena.is_equal(automaton))