Skip to content

Commit 4f0b51b

Browse files
committed
renew groupEquivStates
1 parent 35f07a1 commit 4f0b51b

File tree

1 file changed

+58
-48
lines changed

1 file changed

+58
-48
lines changed

src/DFAMin.hs

+58-48
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import qualified Data.List as List
2525
-- choose and remove a set A from Q
2626
-- for each c in ∑ do
2727
-- 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
2929
-- replace Y in P by the two sets X ∩ Y and Y \ X
3030
-- if Y is in Q
3131
-- replace Y in Q by the same two sets
@@ -35,6 +35,25 @@ import qualified Data.List as List
3535
-- end;
3636
-- end;
3737

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+
3857
minimizeDFA :: forall a. Ord a => DFA Int a -> DFA Int a
3958
minimizeDFA dfa@(DFA { dfa_start_states = starts,
4059
dfa_states = statemap
@@ -93,7 +112,7 @@ type EquivalenceClass = IntSet
93112

94113
groupEquivStates :: forall a. Ord a => DFA Int a -> [EquivalenceClass]
95114
groupEquivStates DFA { dfa_states = statemap }
96-
= go init_p init_q
115+
= go init_r init_q
97116
where
98117
accepting, nonaccepting :: Map Int (State Int a)
99118
(accepting, nonaccepting) = Map.partition acc statemap
@@ -112,57 +131,48 @@ groupEquivStates DFA { dfa_states = statemap }
112131
accept_groups :: [EquivalenceClass]
113132
accept_groups = map IS.fromList (Map.elems accept_map)
114133

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]
119138
init_q = accept_groups
120139

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))
128148
| (from, state) <- Map.toList statemap,
129149
(i,to) <- IM.toList (state_out state) ]
130150

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 [] []
148162
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
152171

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')
158176
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

Comments
 (0)