def intersect_dfa(D1in, D2in): """In : D1in (consistent DFA) D2in (consistent DFA) Out: DFA for language intersection of D1in, D2in (consistent DFA). """ assert (is_consistent_dfa(D1in)), "Inconsist. DFA1 in intersect_dfa" assert (is_consistent_dfa(D2in)), "Inconsist. DFA2 in intersect_dfa" if (D1in["Sigma"] != D2in["Sigma"]): print("Intersection on DFA with different alphabets.") print("Making alphabets the same (taking unions).") Sigma = D1in["Sigma"] | D2in["Sigma"] D1 = copy.deepcopy(D1in) D2 = copy.deepcopy(D2in) D1["Sigma"] = Sigma D2["Sigma"] = Sigma D1 = totalize_dfa(D1) D2 = totalize_dfa(D2) else: D1 = totalize_dfa(D1in) D2 = totalize_dfa(D2in) Q = set(product(D1["Q"], D2["Q"])) # This is the only difference with the union: # The final states are those when both DFA accept F = set(product(D1["F"], D2["F"])) q0 = (D1["q0"], D2["q0"]) Delta = {((q1, q2), ch): (q1p, q2p) for q1 in D1["Q"] for q1p in D1["Q"] for q2 in D2["Q"] for q2p in D2["Q"] for ch in D1["Sigma"] if D1["Delta"][(q1, ch)] == q1p and D2["Delta"][(q2, ch)] == q2p} return pruneUnreach(mk_dfa(Q, D1["Sigma"], Delta, q0, F))
def iso_dfa(D1, D2): """Given consistent and total DFAs D1 and D2, check whether they are isomorphic. Two DFAs are isomorphic if they have the same number of states and are language-equivalent. (One would then be able to match-up state for state and transition for transition.) """ assert (is_consistent_dfa(D1)), "Inconsist. DFA1 in iso_dfa" assert (is_consistent_dfa(D2)), "Inconsist. DFA2 in iso_dfa" return (len(D1["Q"]) == len(D2["Q"]) and langeq_dfa(D1, D2))
def mk_dfa(Q, Sigma, Delta, q0, F): """In : Traits of a DFA Out: A DFA Check for structural consistency of the given DFA traits. If the check passes, make and return a DFA with a total Delta. """ newDFA = {"Q": Q, "Sigma": Sigma, "Delta": Delta, "q0": q0, "F": F} assert ( is_consistent_dfa(newDFA) ), "DFA given to mk_dfa is not consistent. Plz check its components." return (newDFA)
def union_dfa(D1in, D2in): """In : D1in (consistent DFA) D2in (consistent DFA) Out: DFA for language union of D1in, D2in (consistent DFA). """ assert (is_consistent_dfa(D1in)), "Inconsist. DFA1 in union_dfa" assert (is_consistent_dfa(D2in)), "Inconsist. DFA2 in union_dfa" if (D1in["Sigma"] != D2in["Sigma"]): print("Union on DFA with different alphabets.") print("Making alphabets the same (taking unions).") Sigma = D1in["Sigma"] | D2in["Sigma"] D1 = copy.deepcopy(D1in) D2 = copy.deepcopy(D2in) D1["Sigma"] = Sigma D2["Sigma"] = Sigma D1 = totalize_dfa(D1) D2 = totalize_dfa(D2) else: D1 = totalize_dfa(D1in) D2 = totalize_dfa(D2in) # The states can be anything in the cartesian product Q = set(product(D1["Q"], D2["Q"])) # Accept if one of the DFAs accepts F = (set(product(D1["F"], D2["Q"])) | set(product(D1["Q"], D2["F"]))) # Start a lock-step march from the respective q0 q0 = (D1["q0"], D2["q0"]) # The transition function attempts to march both # DFAs in lock-step per their own transition functions Delta = {((q1, q2), ch): (q1p, q2p) for q1 in D1["Q"] for q1p in D1["Q"] for q2 in D2["Q"] for q2p in D2["Q"] for ch in D1["Sigma"] if D1["Delta"][(q1, ch)] == q1p and D2["Delta"][(q2, ch)] == q2p} return pruneUnreach(mk_dfa(Q, D1["Sigma"], Delta, q0, F))