April 16, 2026 @ TACAS
NFA analysis
NFA canonization
A nondeterministic finite automaton (NFA) is a tuple $A = (S, \Sigma, \delta, S_0, F)$ such that
A deterministic finite automaton (DFA) is an NFA $A' = (S', \Sigma, \delta', S_0', F')$ such that $\vert S'_0 \vert = 1$ and $\delta'$ is functional.
def determinize(nfa):
dfa = DFA()
dfa.S_0 = State(nfa.isAccepting(nfa.S_0))
mapping = {nfa.S_0: dfa.S_0}
queue = [nfa.S_0]
while len(queue) > 0:
curr_nfa = queue.pop()
curr_dfa = mapping[curr_nfa]
for i in nfa.sigma:
succ_nfa = nfa.delta[curr_nfa][i]
succ_dfa = mapping[succ_nfa]
if succ_dfa is None:
succ_dfa = State(nfa.isAccepting(succ_nfa))
mapping[succ_nfa] = succ_dfa
queue.append(succ_nfa)
dfa.delta[curr_dfa][i] = succ_dfa
return dfa
def determinize(nfa, reg):
dfa = DFA()
dfa.S_0 = State(nfa.isAccepting(nfa.S_0))
reg.put(nfa.S_0, dfa.S_0)
queue = [nfa.S_0]
while len(queue) > 0:
curr_nfa = queue.pop()
curr_dfa = reg.get(curr_nfa)
for i in nfa.sigma:
succ_nfa = nfa.delta[curr_nfa][i]
succ_dfa = reg.get(succ_nfa)
if succ_dfa is None:
succ_dfa = State(nfa.isAccepting(succ_nfa))
reg.put(succ_nfa, succ_dfa)
queue.append(succ_nfa)
dfa.delta[curr_dfa][i] = succ_dfa
return dfa
def determinize(nfa, reg, threshold):
dfa = DFA()
dfa.S_0 = State(nfa.isAccepting(nfa.S_0))
reg.put(nfa.S_0, dfa.S_0)
queue = [nfa.S_0]
while len(queue) > 0:
curr_nfa = queue.pop()
curr_dfa = reg.get(curr_nfa)
for i in nfa.sigma:
succ_nfa = nfa.delta[curr_nfa][i]
succ_dfa = reg.get(succ_nfa)
if succ_dfa is None:
succ_dfa = State(nfa.isAccepting(succ_nfa))
reg.put(succ_nfa, succ_dfa)
queue.append(succ_nfa)
dfa.delta[curr_dfa][i] = succ_dfa
if threshold(dfa):
equiv = minimize(dfa)
for (s,t) in equiv:
reg.unify(s,t)
return dfa
A datastructure that supports the following operations:
Central observation by Bonchi & Pous: Let $A, B \subseteq S$, then we have
$$L(A \cup B) = L(A) \cup L(B)$$
In case of $L(A) = L(B)$, we have
$$L(A \cup B) = L(A) \cup L(B) = L(A) = L(B)$$
Generalized to any $X$ with $A \subseteq X \subseteq A \cup B$, we have
$$L(A \cup B) = L(X) = L(A)$$
Let $a, b \in S$. If $b$ simulates $a$, i.e., $a \preceq b$, then
$$L(\{a\}) \subseteq L(\{b\})$$
Applied to our previous setting, this means
$$L(\{a,b\}) = L(\{a\}) \cup L(\{b\}) = L(\{b\})$$
Idea:
Prune (e.g., $\{a,b\} \mapsto \{b\}$) and saturate (e.g., $\{b\} \mapsto \{a,b\}$) $Q$ when invoking PUT($Q, q'$).
https://github.com/jn1z/OTF