Finite state networks: more strictness. alternative (still unused) implementation of reachable.

This commit is contained in:
bringert
2005-12-29 21:35:40 +00:00
parent d854890820
commit 14079a9d7c

View File

@@ -25,22 +25,18 @@ module GF.Speech.FiniteState (FA, State, NFA, DFA,
prFAGraphviz) where prFAGraphviz) where
import Data.List import Data.List
import Data.Maybe (catMaybes,fromJust,isNothing) import Data.Maybe
import Data.Map (Map) import Data.Map (Map)
import qualified Data.Map as Map import qualified Data.Map as Map
import Data.Set (Set) import Data.Set (Set)
import qualified Data.Set as Set import qualified Data.Set as Set
import qualified Data.Set as StateSet
import GF.Data.Utilities import GF.Data.Utilities
import GF.Speech.Graph import GF.Speech.Graph
import qualified GF.Visualization.Graphviz as Dot import qualified GF.Visualization.Graphviz as Dot
type State = Int type State = Int
type StateSet = StateSet.Set State
data FA n a b = FA !(Graph n a b) !n ![n] data FA n a b = FA !(Graph n a b) !n ![n]
type NFA a = FA State () (Maybe a) type NFA a = FA State () (Maybe a)
@@ -144,11 +140,12 @@ determinize (FA g s f) = let (ns,es) = h (Set.singleton start) Set.empty Set.emp
fa = FA (Graph undefined [(n,()) | n <- ns'] es') start final fa = FA (Graph undefined [(n,()) | n <- ns'] es') start final
in numberStates fa in numberStates fa
where out = outgoing g where out = outgoing g
start = closure out $ StateSet.singleton s -- reach = nodesReachable out
isDFAFinal n = not (StateSet.null (StateSet.fromList f `StateSet.intersection` n)) start = closure out $ Set.singleton s
isDFAFinal n = not (Set.null (Set.fromList f `Set.intersection` n))
h currentStates oldStates es h currentStates oldStates es
| Set.null currentStates = (oldStates,es) | Set.null currentStates = (oldStates,es)
| otherwise = h uniqueNewStates allOldStates es' | otherwise = ((h $! uniqueNewStates) $! allOldStates) $! es'
where where
allOldStates = oldStates `Set.union` currentStates allOldStates = oldStates `Set.union` currentStates
(newStates,es') = new (Set.toList currentStates) Set.empty es (newStates,es') = new (Set.toList currentStates) Set.empty es
@@ -157,7 +154,7 @@ determinize (FA g s f) = let (ns,es) = h (Set.singleton start) Set.empty Set.emp
-- by consuming one symbol, and the associated edges. -- by consuming one symbol, and the associated edges.
new [] rs es = (rs,es) new [] rs es = (rs,es)
new (n:ns) rs es = new ns rs' es' new (n:ns) rs es = new ns rs' es'
where cs = reachable out n where cs = reachable out n --reachable reach n
rs' = rs `Set.union` Set.fromList (map snd cs) rs' = rs `Set.union` Set.fromList (map snd cs)
es' = es `Set.union` Set.fromList [(n,s,c) | (c,s) <- cs] es' = es `Set.union` Set.fromList [(n,s,c) | (c,s) <- cs]
@@ -170,22 +167,37 @@ numberStates (FA g s fs) = FA (renameNodes newName rest g) s' fs'
fs' = map newName fs fs' = map newName fs
-- | Get all the nodes reachable from a list of nodes by only empty edges. -- | Get all the nodes reachable from a list of nodes by only empty edges.
closure :: Outgoing State a (Maybe b) -> StateSet -> StateSet closure :: Ord n => Outgoing n a (Maybe b) -> Set n -> Set n
closure out x = closure_ x x closure out x = closure_ x x
where closure_ acc check | StateSet.null check = acc where closure_ acc check | Set.null check = acc
| otherwise = closure_ acc' check' | otherwise = closure_ acc' check'
where where
reach = StateSet.fromList [y | x <- StateSet.toList check, reach = Set.fromList [y | x <- Set.toList check,
(_,y,Nothing) <- getOutgoing out x] (_,y,Nothing) <- getOutgoing out x]
acc' = acc `StateSet.union` reach acc' = acc `Set.union` reach
check' = reach StateSet.\\ acc check' = reach Set.\\ acc
-- | Get a map of labels to sets of all nodes reachable -- | Get a map of labels to sets of all nodes reachable
-- from a the set of nodes by one edge with the given -- from a the set of nodes by one edge with the given
-- label and then any number of empty edges. -- label and then any number of empty edges.
reachable :: Ord b => Outgoing State a (Maybe b) -> StateSet -> [(b,StateSet)] reachable :: (Ord n,Ord b) => Outgoing n a (Maybe b) -> Set n -> [(b,Set n)]
reachable out ns = Map.toList $ Map.map (closure out . StateSet.fromList) $ reachable1 out ns reachable out ns = Map.toList $ Map.map (closure out . Set.fromList) $ reachable1 out ns
reachable1 out ns = Map.fromListWith (++) [(c, [y]) | n <- StateSet.toList ns, (_,y,Just c) <- getOutgoing out n] reachable1 out ns = Map.fromListWith (++) [(c, [y]) | n <- Set.toList ns, (_,y,Just c) <- getOutgoing out n]
{-
-- Alternative implementation of reachable, seems to use too much memory.
type Reachable n b = Map n (Map b (Set n))
reachable :: (Ord n, Ord b) => Reachable n b -> Set n -> [(b,Set n)]
reachable r ns = Map.toList $ Map.unionsWith Set.union $ lookups (Set.toList ns) r
nodesReachable :: (Ord n, Ord b) => Outgoing n a (Maybe b) -> Reachable n b
nodesReachable out = Map.map (f . snd) out
where f = Map.map (closure out . Set.fromList) . edgesByLabel
edgesByLabel es = Map.fromListWith (++) [(c,[y]) | (_,y,Just c) <- es]
-}
reverseNFA :: NFA a -> NFA a reverseNFA :: NFA a -> NFA a
reverseNFA (FA g s fs) = FA g''' s' [s] reverseNFA (FA g s fs) = FA g''' s' [s]
@@ -214,3 +226,9 @@ toGraphviz (FA (Graph _ ns es) s f) = Dot.Graph Dot.Directed [] (map mkNode ns)
++ if n `elem` f then [("style","bold")] else [] ++ if n `elem` f then [("style","bold")] else []
mkEdge (x,y,l) = Dot.Edge (show x) (show y) [("label",l)] mkEdge (x,y,l) = Dot.Edge (show x) (show y) [("label",l)]
--
-- * Utilities
--
lookups :: Ord k => [k] -> Map k a -> [a]
lookups xs m = mapMaybe (flip Map.lookup m) xs