@@ -25,7 +25,7 @@ import qualified Data.List as List
25
25
-- choose and remove a set A from Q
26
26
-- for each c in ∑ do
27
27
-- let X be the set of states for which a transition on c leads to a state in A
28
- -- for each set Y in P for which X ∩ Y is nonempty do
28
+ -- for each set Y in P for which X ∩ Y is nonempty and Y \ X is nonempty do
29
29
-- replace Y in P by the two sets X ∩ Y and Y \ X
30
30
-- if Y is in Q
31
31
-- replace Y in Q by the same two sets
@@ -35,6 +35,25 @@ import qualified Data.List as List
35
35
-- end;
36
36
-- end;
37
37
38
+ -- observation : Q is always subset of P
39
+ -- let R = P \ Q. then following algorithm is the equivalent of the Hopcroft's Algorithm
40
+ --
41
+ -- R := {{all nonaccepting states}};
42
+ -- Q := {{all accepting states}};
43
+ -- while (Q is not empty) do
44
+ -- choose and remove a set A from Q
45
+ -- for each c in ∑ do
46
+ -- let X be the set of states for which a transition on c leads to a state in A
47
+ -- for each set Y in R for which X ∩ Y is nonempty and Y \ X is nonempty do
48
+ -- replace Y in R by the greater of the two sets X ∩ Y and X \ Y
49
+ -- add the smaller of the two sets to Q
50
+ -- end;
51
+ -- for each set Y in Q for which X ∩ Y is nonempty and Y \ X is nonempty do
52
+ -- replace Y in Q by the two sets X ∩ Y and X \ Y
53
+ -- end;
54
+ -- end;
55
+ -- end;
56
+
38
57
minimizeDFA :: forall a . Ord a => DFA Int a -> DFA Int a
39
58
minimizeDFA dfa@ (DFA { dfa_start_states = starts,
40
59
dfa_states = statemap
@@ -93,7 +112,7 @@ type EquivalenceClass = IntSet
93
112
94
113
groupEquivStates :: forall a . Ord a => DFA Int a -> [EquivalenceClass ]
95
114
groupEquivStates DFA { dfa_states = statemap }
96
- = go init_p init_q
115
+ = go init_r init_q
97
116
where
98
117
accepting , nonaccepting :: Map Int (State Int a )
99
118
(accepting, nonaccepting) = Map. partition acc statemap
@@ -112,57 +131,48 @@ groupEquivStates DFA { dfa_states = statemap }
112
131
accept_groups :: [EquivalenceClass ]
113
132
accept_groups = map IS. fromList (Map. elems accept_map)
114
133
115
- init_p , init_q :: [EquivalenceClass ]
116
- init_p -- Issue #71: each EquivalenceClass needs to be a non-empty set
117
- | IS. null nonaccepting_states = accept_groups
118
- | otherwise = nonaccepting_states : accept_groups
134
+ init_r , init_q :: [EquivalenceClass ]
135
+ init_r -- Issue #71: each EquivalenceClass needs to be a non-empty set
136
+ | IS. null nonaccepting_states = []
137
+ | otherwise = [ nonaccepting_states]
119
138
init_q = accept_groups
120
139
121
- -- map token T to
122
- -- a map from state S to the list of states that transition to
123
- -- S on token T
124
- -- This is a cache of the information needed to compute x below
125
- bigmap :: IntMap (IntMap [SNum ])
126
- bigmap = IM. fromListWith (IM. unionWith (++) )
127
- [ (i, IM. singleton to [from])
140
+ -- elements of
141
+ -- a map from token T to
142
+ -- a map from state S to the set of states that transition to
143
+ -- S on token T
144
+ -- This is a cache of the information needed to compute xs below
145
+ bigmap :: [IntMap EquivalenceClass ]
146
+ bigmap = IM. elems $ IM. fromListWith (IM. unionWith IS. union)
147
+ [ (i, IM. singleton to (IS. singleton from))
128
148
| (from, state) <- Map. toList statemap,
129
149
(i,to) <- IM. toList (state_out state) ]
130
150
131
- -- incoming I A = the set of states that transition to a state in
132
- -- A on token I.
133
- incoming :: Int -> IntSet -> IntSet
134
- incoming i a = IS. fromList (concat ss)
135
- where
136
- map1 = IM. findWithDefault IM. empty i bigmap
137
- ss = [ IM. findWithDefault [] s map1
138
- | s <- IS. toList a ]
139
-
140
- -- The outer loop: recurse on each set in Q
141
- go :: [EquivalenceClass ] -> [EquivalenceClass ] -> [EquivalenceClass ]
142
- go p [] = p
143
- go p (a: q) = go1 0 p q
144
- where
145
- -- recurse on each token (0..255)
146
- go1 256 p q = go p q
147
- go1 i p q = go1 (i+ 1 ) p' q'
151
+ -- The outer loop: recurse on each set in R and Q
152
+ go :: [EquivalenceClass ] -> [EquivalenceClass ] -> [EquivalenceClass ]
153
+ go r [] = r
154
+ go r (a: q) = uncurry go $ List. foldl' go0 (a: r,q) xs
155
+ where
156
+ xs :: [EquivalenceClass ]
157
+ xs = filter (not . IS. null )
158
+ . map (IS. unions . flip IM. restrictKeys a)
159
+ $ bigmap
160
+
161
+ go0 (r,q) x = go1 r [] []
148
162
where
149
- (p',q') = go2 p [] q
150
-
151
- x = incoming i a
163
+ go1 [] r' q' = (r', go2 q q')
164
+ go1 (y: r) r' q'
165
+ | IS. null y1 || IS. null y2 = go1 r (y: r') q'
166
+ | IS. size y1 <= IS. size y2 = go1 r (y2: r') (y1: q')
167
+ | otherwise = go1 r (y1: r') (y2: q')
168
+ where
169
+ y1 = IS. intersection x y
170
+ y2 = IS. difference y x
152
171
153
- -- recurse on each set in P
154
- go2 [] p' q = (p',q)
155
- go2 (y: p) p' q
156
- | IS. null i || IS. null d = go2 p (y: p') q
157
- | otherwise = go2 p (i: d: p') q1
172
+ go2 [] q' = q'
173
+ go2 (y: q) q'
174
+ | IS. null y1 || IS. null y2 = go2 q (y: q')
175
+ | otherwise = go2 q (y1: y2: q')
158
176
where
159
- i = IS. intersection x y
160
- d = IS. difference y x
161
-
162
- q1 = replaceyin q
163
- where
164
- replaceyin [] =
165
- if IS. size i < IS. size d then [i] else [d]
166
- replaceyin (z: zs)
167
- | z == y = i : d : zs
168
- | otherwise = z : replaceyin zs
177
+ y1 = IS. intersection x y
178
+ y2 = IS. difference y x
0 commit comments