module PP.Builders.Dfa
(
) where
import qualified Data.Graph.Inductive.Graph as Gr
import qualified Data.List as L
import qualified Data.Map.Strict as Map
import Data.Maybe
import PP.Builder
instance DfaBuilder NfaGraph where
buildDfa nfa = removeDeadState $ Gr.mkGraph nodes edges
where
nodes = map (\k -> (k, findType k)) indices
indices = L.nub $ map (\((k, _), _) -> k) ilist
edges = map (\((k, NfaValue a), v) -> (k, v, DfaValue a)) ilist
ilist = map (\((k, a), v) -> ((index k, a), index v)) list
index = (Map.!) $ Map.fromList $ zip unique [0..]
rindex = (Map.!) $ Map.fromList $ zip [0..] unique
unique = L.nub $ map (\((k, _), _) -> k) list
list = Map.toList $ buildSubSet nfa
findType i = foldl findType' DfaNode $ map (toDfa . findType'') $ rindex i
findType' DfaInitial _ = DfaInitial
findType' _ DfaInitial = DfaInitial
findType' (DfaFinal n) _ = DfaFinal n
findType' _ (DfaFinal n) = DfaFinal n
findType' _ _ = DfaNode
findType'' i = fromMaybe NfaNode $ Gr.lab nfa i
toDfa NfaNode = DfaNode
toDfa NfaInitial = DfaInitial
toDfa (NfaFinal n) = DfaFinal n
buildSubSet :: NfaGraph -> Map.Map ([Gr.Node], NfaSymbol) [Gr.Node]
buildSubSet g = buildSubSet' (mark (emptyClosure [initial] g) Map.empty)
[emptyClosure [initial] g]
where
buildSubSet' acc [] = Map.filterWithKey isNotEmpty acc
buildSubSet' acc (x:xs) = buildSubSet'' acc x xs (symbols g)
buildSubSet'' acc _ xs [] = buildSubSet' acc xs
buildSubSet'' acc x xs (a:as) =
let u = emptyClosure (transition x a g) g in
if Map.notMember (u, NfaEmpty) acc then
buildSubSet'' (mark u $ ins x a u acc) x (u:xs) as
else
buildSubSet'' (ins x a u acc) x xs as
ins d a = Map.insert (d, a)
mark d = ins d NfaEmpty []
initial = let [(i, _)] = filter isInitial (Gr.labNodes g) in i
isInitial (_, NfaInitial) = True
isInitial _ = False
isNotEmpty (_, NfaEmpty) _ = False
isNotEmpty _ _ = True
symbols :: NfaGraph -> [NfaSymbol]
symbols = L.sort . L.nub . map (\(_, _, v) -> v) . filter isValue . Gr.labEdges
where
isValue (_, _, NfaValue _) = True
isValue _ = False
emptyClosure :: [Gr.Node] -> NfaGraph -> [Gr.Node]
emptyClosure ns g = emptyClosure' ns ns
where
emptyClosure' acc [] = L.sort acc
emptyClosure' acc (x:xs) = emptyClosure'' acc xs (suc x)
emptyClosure'' acc ns [] = emptyClosure' acc ns
emptyClosure'' acc ns (u:us) =
if u `notElem` acc then
emptyClosure'' (u:acc) (u:ns) us
else
emptyClosure'' acc ns us
suc n = transition [n] NfaEmpty g
transition :: [Gr.Node] -> NfaSymbol -> NfaGraph -> [Gr.Node]
transition ns s g = L.sort $ L.nub $ map fst $ filter (\(_, l) -> l == s) suc
where
suc = concat [Gr.lsuc g i | i <- ns]
removeDeadState :: DfaGraph -> DfaGraph
removeDeadState g = Gr.labnfilter isNotDead g
where
isNotDead (n, DfaNode) =
let (_, _, _, suc) = Gr.context g n in
any (\(_, i) -> i /= n) suc
isNotDead _ = True