A generalized cross-product constructor over two DFAs.
        The third argument is a binary boolean function f; a state (q1, q2) in the final
        DFA accepts if f(A[q1],A[q2]), where A indicates the acceptance-value of the state.
        Args:
            dfa_2: The second dfa
            accept_method: The boolean action
        Returns:
            None

def cross_product(self, dfa_2, accept_method):
        """A generalized cross-product constructor over two DFAs.
        The third argument is a binary boolean function f; a state (q1, q2) in the final
        DFA accepts if f(A[q1],A[q2]), where A indicates the acceptance-value of the state.
        Args:
            dfa_2: The second dfa
            accept_method: The boolean action
        Returns:
            None
        """
        dfa_1states = copy.deepcopy(self.states)
        dfa_2states = dfa_2.states
        self.states = []
        states = {}


        def _create_transitions_representation(graph, state):
            """
            In order to speedup the transition iteration using
            the alphabet, the function creates an index
            Args:
                graph (DFA): The input dfa
                state (DFA state): The examined state
            Returns:
                dict: The generated transition map
            """
            return {self.isyms.find(arc.ilabel): graph[arc.nextstate] for arc in state}


        def _add_state_if_nonexistent(state_a, state_b):
            """
            Adds a new state in the final dfa, which is the
            combination of the input states. The initial and final
            flag is also placed on the new state. If the state already
            exists, its identifier is being returned.
            Args:
                state_a: The fist state identifier
                state_b: The second state identifier
            Returns:
                int: The new state identifier
            """
            if (state_a.stateid, state_b.stateid) not in states:
                states[(state_a.stateid, state_b.stateid)] \
                    = self.add_state()
                self[states[(state_a.stateid, state_b.stateid)]].initial \
                    = state_a.initial and state_b.initial
                self[states[(state_a.stateid, state_b.stateid)]].final \
                    = accept_method(state_a.final, state_b.final)
            return states[(state_a.stateid, state_b.stateid)]

        for state1, state2 in product(dfa_1states, dfa_2states):
            sid1 = _add_state_if_nonexistent(state1, state2)
            transitions_s1 = _create_transitions_representation(dfa_1states, state1)
            transitions_s2 = _create_transitions_representation(dfa_2states, state2)
            for char in self.alphabet:
                sid2 = _add_state_if_nonexistent(
                    transitions_s1[char], transitions_s2[char])
                self.add_arc(sid1, sid2, char)