mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-23 11:42:49 -06:00
Print slf_graphviz with subgraphs.
This commit is contained in:
@@ -88,6 +88,12 @@ lookup' x = fromJust . lookup x
|
|||||||
find' :: (a -> Bool) -> [a] -> a
|
find' :: (a -> Bool) -> [a] -> a
|
||||||
find' p = fromJust . find p
|
find' p = fromJust . find p
|
||||||
|
|
||||||
|
-- | Set a value in a lookup table.
|
||||||
|
tableSet :: Eq a => a -> b -> [(a,b)] -> [(a,b)]
|
||||||
|
tableSet x y [] = [(x,y)]
|
||||||
|
tableSet x y (p@(x',_):xs) | x' == x = (x,y):xs
|
||||||
|
| otherwise = p:tableSet x y xs
|
||||||
|
|
||||||
-- * equality functions
|
-- * equality functions
|
||||||
|
|
||||||
-- | Use an ordering function as an equality predicate.
|
-- | Use an ordering function as an equality predicate.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ module GF.Speech.FiniteState (FA, State, NFA, DFA,
|
|||||||
oneFinalState,
|
oneFinalState,
|
||||||
moveLabelsToNodes, minimize,
|
moveLabelsToNodes, minimize,
|
||||||
dfa2nfa,
|
dfa2nfa,
|
||||||
|
unusedNames, renameStates,
|
||||||
prFAGraphviz, faToGraphviz) where
|
prFAGraphviz, faToGraphviz) where
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
@@ -84,6 +85,20 @@ mapTransitions f = onGraph (emap f)
|
|||||||
minimize :: Ord a => NFA a -> DFA a
|
minimize :: Ord a => NFA a -> DFA a
|
||||||
minimize = determinize . reverseNFA . dfa2nfa . determinize . reverseNFA
|
minimize = determinize . reverseNFA . dfa2nfa . determinize . reverseNFA
|
||||||
|
|
||||||
|
unusedNames :: FA n a b -> [n]
|
||||||
|
unusedNames (FA (Graph names _ _) _ _) = names
|
||||||
|
|
||||||
|
-- | Give new names to all nodes.
|
||||||
|
renameStates :: Ord x => [y] -- ^ Infinite supply of new names
|
||||||
|
-> FA x a b
|
||||||
|
-> FA y a b
|
||||||
|
renameStates supply (FA g s fs) = FA (renameNodes newName rest g) s' fs'
|
||||||
|
where (ns,rest) = splitAt (length (nodes g)) supply
|
||||||
|
newNodes = Map.fromList (zip (map fst (nodes g)) ns)
|
||||||
|
newName n = Map.findWithDefault (error "FiniteState.newName") n newNodes
|
||||||
|
s' = newName s
|
||||||
|
fs' = map newName fs
|
||||||
|
|
||||||
onGraph :: (Graph n a b -> Graph n c d) -> FA n a b -> FA n c d
|
onGraph :: (Graph n a b -> Graph n c d) -> FA n a b -> FA n c d
|
||||||
onGraph f (FA g s ss) = FA (f g) s ss
|
onGraph f (FA g s ss) = FA (f g) s ss
|
||||||
|
|
||||||
@@ -138,7 +153,7 @@ determinize (FA g s f) = let (ns,es) = h (Set.singleton start) Set.empty Set.emp
|
|||||||
(ns',es') = (Set.toList ns, Set.toList es)
|
(ns',es') = (Set.toList ns, Set.toList es)
|
||||||
final = filter isDFAFinal ns'
|
final = filter isDFAFinal ns'
|
||||||
fa = FA (Graph undefined [(n,()) | n <- ns'] es') start final
|
fa = FA (Graph undefined [(n,()) | n <- ns'] es') start final
|
||||||
in numberStates fa
|
in renameStates [0..] fa
|
||||||
where out = outgoing g
|
where out = outgoing g
|
||||||
-- reach = nodesReachable out
|
-- reach = nodesReachable out
|
||||||
start = closure out $ Set.singleton s
|
start = closure out $ Set.singleton s
|
||||||
@@ -158,13 +173,6 @@ determinize (FA g s f) = let (ns,es) = h (Set.singleton start) Set.empty Set.emp
|
|||||||
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]
|
||||||
|
|
||||||
numberStates :: (Ord x,Enum y) => FA x a b -> FA y a b
|
|
||||||
numberStates (FA g s fs) = FA (renameNodes newName rest g) s' fs'
|
|
||||||
where (ns,rest) = splitAt (length (nodes g)) $ [toEnum 0 .. ]
|
|
||||||
newNodes = Map.fromList (zip (map fst (nodes g)) ns)
|
|
||||||
newName n = Map.findWithDefault (error "FiniteState.newName") n newNodes
|
|
||||||
s' = newName s
|
|
||||||
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 :: Ord n => Outgoing n a (Maybe b) -> Set n -> Set n
|
closure :: Ord n => Outgoing n a (Maybe b) -> Set n -> Set n
|
||||||
@@ -213,14 +221,14 @@ dfa2nfa = mapTransitions Just
|
|||||||
--
|
--
|
||||||
|
|
||||||
prFAGraphviz :: (Eq n,Show n) => FA n String String -> String
|
prFAGraphviz :: (Eq n,Show n) => FA n String String -> String
|
||||||
prFAGraphviz = Dot.prGraphviz . faToGraphviz ""
|
prFAGraphviz = Dot.prGraphviz . faToGraphviz
|
||||||
|
|
||||||
prFAGraphviz_ :: (Eq n,Show n,Show a, Show b) => FA n a b -> String
|
prFAGraphviz_ :: (Eq n,Show n,Show a, Show b) => FA n a b -> String
|
||||||
prFAGraphviz_ = Dot.prGraphviz . faToGraphviz "" . mapStates show . mapTransitions show
|
prFAGraphviz_ = Dot.prGraphviz . faToGraphviz . mapStates show . mapTransitions show
|
||||||
|
|
||||||
faToGraphviz :: (Eq n,Show n) => String -- ^ Graph ID
|
faToGraphviz :: (Eq n,Show n) => FA n String String -> Dot.Graph
|
||||||
-> FA n String String -> Dot.Graph
|
faToGraphviz (FA (Graph _ ns es) s f)
|
||||||
faToGraphviz i (FA (Graph _ ns es) s f) = Dot.Graph Dot.Directed i [] (map mkNode ns) (map mkEdge es) []
|
= Dot.Graph Dot.Directed Nothing [] (map mkNode ns) (map mkEdge es) []
|
||||||
where mkNode (n,l) = Dot.Node (show n) attrs
|
where mkNode (n,l) = Dot.Node (show n) attrs
|
||||||
where attrs = [("label",l)]
|
where attrs = [("label",l)]
|
||||||
++ if n == s then [("shape","box")] else []
|
++ if n == s then [("shape","box")] else []
|
||||||
|
|||||||
@@ -62,13 +62,25 @@ slfGraphvizPrinter :: Ident -- ^ Grammar name
|
|||||||
-> Options -> CGrammar -> String
|
-> Options -> CGrammar -> String
|
||||||
slfGraphvizPrinter name opts cfg = Dot.prGraphviz g
|
slfGraphvizPrinter name opts cfg = Dot.prGraphviz g
|
||||||
where MFA main subs = cfgToMFA opts cfg
|
where MFA main subs = cfgToMFA opts cfg
|
||||||
g = Dot.addSubGraphs (map (uncurry gvSLFFA) subs) $ gvSLFFA "" main
|
g = STM.evalState (liftM2 Dot.addSubGraphs ss m) [0..]
|
||||||
|
ss = mapM (\ (c,f) -> gvSLFFA (Just c) f) subs
|
||||||
|
m = gvSLFFA Nothing main
|
||||||
|
|
||||||
gvSLFFA :: String -> DFA (MFALabel String) -> Dot.Graph
|
gvSLFFA :: Maybe String -> DFA (MFALabel String) -> STM.State [State] Dot.Graph
|
||||||
gvSLFFA n = faToGraphviz n . mapStates (maybe "" mfaLabelToGv)
|
gvSLFFA n fa =
|
||||||
. mapTransitions (const "") . slfStyleFA
|
liftM (mkCluster n . faToGraphviz . mapStates (maybe "" mfaLabelToGv)
|
||||||
|
. mapTransitions (const "")) (rename $ slfStyleFA fa)
|
||||||
where mfaLabelToGv (MFASym s) = s
|
where mfaLabelToGv (MFASym s) = s
|
||||||
mfaLabelToGv (MFASub s) = "<" ++ s ++ ">"
|
mfaLabelToGv (MFASub s) = "#" ++ s
|
||||||
|
mkCluster Nothing = id
|
||||||
|
mkCluster (Just x)
|
||||||
|
= Dot.setName ("cluster_"++x) . Dot.setAttr "label" x
|
||||||
|
rename fa = do
|
||||||
|
names <- STM.get
|
||||||
|
let fa' = renameStates names fa
|
||||||
|
names' = unusedNames fa'
|
||||||
|
STM.put names'
|
||||||
|
return fa'
|
||||||
|
|
||||||
mapMFA :: (DFA (MFALabel a) -> b) -> MFA a -> (b,[(String,b)])
|
mapMFA :: (DFA (MFALabel a) -> b) -> MFA a -> (b,[(String,b)])
|
||||||
mapMFA f (MFA main subs) = (f main, [(c, f fa) | (c,fa) <- subs])
|
mapMFA f (MFA main subs) = (f main, [(c, f fa) | (c,fa) <- subs])
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ module GF.Visualization.Graphviz (
|
|||||||
Node(..), Edge(..),
|
Node(..), Edge(..),
|
||||||
Attr,
|
Attr,
|
||||||
addSubGraphs,
|
addSubGraphs,
|
||||||
|
setName,
|
||||||
|
setAttr,
|
||||||
prGraphviz
|
prGraphviz
|
||||||
) where
|
) where
|
||||||
|
|
||||||
@@ -25,7 +27,14 @@ import Data.Char
|
|||||||
import GF.Data.Utilities
|
import GF.Data.Utilities
|
||||||
|
|
||||||
-- | Graph type, graph ID, graph attirbutes, graph nodes, graph edges, subgraphs
|
-- | Graph type, graph ID, graph attirbutes, graph nodes, graph edges, subgraphs
|
||||||
data Graph = Graph GraphType String [Attr] [Node] [Edge] [Graph]
|
data Graph = Graph {
|
||||||
|
gType :: GraphType,
|
||||||
|
gId :: Maybe String,
|
||||||
|
gAttrs :: [Attr],
|
||||||
|
gNodes :: [Node],
|
||||||
|
gEdges :: [Edge],
|
||||||
|
gSubgraphs :: [Graph]
|
||||||
|
}
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
data GraphType = Directed | Undirected
|
data GraphType = Directed | Undirected
|
||||||
@@ -44,7 +53,13 @@ type Attr = (String,String)
|
|||||||
--
|
--
|
||||||
|
|
||||||
addSubGraphs :: [Graph] -> Graph -> Graph
|
addSubGraphs :: [Graph] -> Graph -> Graph
|
||||||
addSubGraphs nss (Graph t i at ns es ss) = Graph t i at ns es (nss++ss)
|
addSubGraphs gs g = g { gSubgraphs = gs ++ gSubgraphs g }
|
||||||
|
|
||||||
|
setName :: String -> Graph -> Graph
|
||||||
|
setName n g = g { gId = Just n }
|
||||||
|
|
||||||
|
setAttr :: String -> String -> Graph -> Graph
|
||||||
|
setAttr n v g = g { gAttrs = tableSet n v (gAttrs g) }
|
||||||
|
|
||||||
--
|
--
|
||||||
-- * Pretty-printing
|
-- * Pretty-printing
|
||||||
@@ -52,11 +67,11 @@ addSubGraphs nss (Graph t i at ns es ss) = Graph t i at ns es (nss++ss)
|
|||||||
|
|
||||||
prGraphviz :: Graph -> String
|
prGraphviz :: Graph -> String
|
||||||
prGraphviz g@(Graph t i _ _ _ _) =
|
prGraphviz g@(Graph t i _ _ _ _) =
|
||||||
graphtype t ++ " " ++ esc i ++ " {\n" ++ prGraph g ++ "}\n"
|
graphtype t ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}\n"
|
||||||
|
|
||||||
prSubGraph :: Graph -> String
|
prSubGraph :: Graph -> String
|
||||||
prSubGraph g@(Graph _ i _ _ _ _) =
|
prSubGraph g@(Graph _ i _ _ _ _) =
|
||||||
"subgraph" ++ " " ++ esc i ++ " {\n" ++ prGraph g ++ "}"
|
"subgraph" ++ " " ++ maybe "" esc i ++ " {\n" ++ prGraph g ++ "}"
|
||||||
|
|
||||||
prGraph :: Graph -> String
|
prGraph :: Graph -> String
|
||||||
prGraph (Graph t id at ns es ss) =
|
prGraph (Graph t id at ns es ss) =
|
||||||
|
|||||||
Reference in New Issue
Block a user