-
Notifications
You must be signed in to change notification settings - Fork 1
/
SubsetConstruction.py
68 lines (56 loc) · 2.15 KB
/
SubsetConstruction.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from DFA import *
class SubsetConstruction:
@staticmethod
def generate_state():
state = 0
while True:
yield state
state += 1
def __init__(self, nfa):
self.nfa = nfa
self.generator = SubsetConstruction.generate_state()
def gen_state(self):
return next(self.generator)
def eps_closure_of(self, states):
"""
Fetch a eps-closure set for all states in nfa
:param states: states list
:return: eps closure of this stats list
"""
stack = [] + states
eps = [] + states
# DFS search
while stack:
v = stack.pop()
for i in range(self.nfa.size):
if self.nfa.trans_tbl[v][i] == -1 and \
i not in eps:
eps.append(i)
stack.append(i)
return eps
def build_dfa(self, syms):
dfa = DFA()
start_set = self.eps_closure_of([self.nfa.start])
queue = list() # this is actually a BFS graph traverse algorithm
queue.append(start_set) # except that the vertex is a set
visited_set = []
dfa_states_map = dict()
dfa_states_map[repr(start_set)] = self.gen_state()
dfa.start = dfa_states_map[repr(start_set)]
while queue:
cur_set = queue[0]
queue = queue[1:] # de-queue
visited_set.append(cur_set)
# print('cur: {}'.format(cur_set))
if self.nfa.final in cur_set:
if dfa_states_map[repr(cur_set)] not in dfa.final:
dfa.final.append(dfa_states_map[(repr(cur_set))])
for c in syms:
next_set = self.eps_closure_of(list(self.nfa.move(cur_set, c)))
# print('next: {}'.format(next_set))
if next_set not in visited_set:
queue.append(next_set) # enqueue
if repr(next_set) not in dfa_states_map:
dfa_states_map[repr(next_set)] = self.gen_state()
dfa.add_trans(dfa_states_map[repr(cur_set)], dfa_states_map[repr(next_set)], c)
return dfa