Visualize the automata using GraphViz
This commit is contained in:
parent
34a3a2027c
commit
10db66edc0
5 changed files with 98 additions and 2 deletions
|
|
@ -23,6 +23,8 @@ dependencies:
|
||||||
- base >= 4.7 && < 5
|
- base >= 4.7 && < 5
|
||||||
- transformers >= 0.5.6 && < 0.6
|
- transformers >= 0.5.6 && < 0.6
|
||||||
- containers >= 0.6 && < 0.7
|
- containers >= 0.6 && < 0.7
|
||||||
|
- graphviz >= 2999.20 && < 2999.21
|
||||||
|
- fgl >= 5.7 && < 5.8
|
||||||
# algebraic-graphs >= 0.4 && < 0.5
|
# algebraic-graphs >= 0.4 && < 0.5
|
||||||
|
|
||||||
library:
|
library:
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,10 @@ dfaStateToNfaState s =
|
||||||
dfaToNfa :: (Ord s, Ord t) => Dfa.Dfa s t -> Nfa.Nfa s t
|
dfaToNfa :: (Ord s, Ord t) => Dfa.Dfa s t -> Nfa.Nfa s t
|
||||||
dfaToNfa dfa =
|
dfaToNfa dfa =
|
||||||
let stateMap = Dfa.stateMap dfa
|
let stateMap = Dfa.stateMap dfa
|
||||||
exitingStates = map fst . filter (\(s, state) -> Dfa.accepting state) $ Map.assocs stateMap
|
exitStates = Dfa.exitStates dfa
|
||||||
nfaStateMap = Map.map dfaStateToNfaState stateMap
|
nfaStateMap = Map.map dfaStateToNfaState stateMap
|
||||||
-- The NFA was created from a valid DFA, so it will be valid too.
|
-- The NFA was created from a valid DFA, so it will be valid too.
|
||||||
in fromJust $ Nfa.nfa nfaStateMap (Dfa.entryState dfa) (Set.fromList exitingStates)
|
in fromJust $ Nfa.nfa nfaStateMap (Dfa.entryState dfa) exitStates
|
||||||
|
|
||||||
{-
|
{-
|
||||||
- Converting a NFA to a DFA
|
- Converting a NFA to a DFA
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ module Rextra.Dfa (
|
||||||
-- ** Properties
|
-- ** Properties
|
||||||
, stateMap
|
, stateMap
|
||||||
, entryState
|
, entryState
|
||||||
|
, exitStates
|
||||||
-- ** Executing
|
-- ** Executing
|
||||||
, transition
|
, transition
|
||||||
, execute
|
, execute
|
||||||
|
|
@ -34,6 +35,13 @@ data Dfa s t = Dfa
|
||||||
getState :: (Ord s) => Dfa s t -> s -> State s t
|
getState :: (Ord s) => Dfa s t -> s -> State s t
|
||||||
getState dfa s = stateMap dfa Map.! s
|
getState dfa s = stateMap dfa Map.! s
|
||||||
|
|
||||||
|
exitStates :: (Ord s) => Dfa s t -> Set.Set s
|
||||||
|
exitStates dfa = Set.fromList
|
||||||
|
. map fst
|
||||||
|
. filter (accepting . snd)
|
||||||
|
. Map.assocs
|
||||||
|
$ stateMap dfa
|
||||||
|
|
||||||
data State s t = State
|
data State s t = State
|
||||||
{ transitions :: Map.Map t s
|
{ transitions :: Map.Map t s
|
||||||
, defaultTransition :: s
|
, defaultTransition :: s
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ module Rextra.Nfa (
|
||||||
import Data.List
|
import Data.List
|
||||||
import qualified Data.Map.Strict as Map
|
import qualified Data.Map.Strict as Map
|
||||||
import qualified Data.Set as Set
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
import Rextra.Util
|
import Rextra.Util
|
||||||
|
|
||||||
{-
|
{-
|
||||||
|
|
|
||||||
85
src/Rextra/Visualize.hs
Normal file
85
src/Rextra/Visualize.hs
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
{-# LANGUAGE TupleSections #-}
|
||||||
|
|
||||||
|
module Rextra.Visualize where
|
||||||
|
|
||||||
|
import Data.Graph.Inductive
|
||||||
|
import Data.GraphViz
|
||||||
|
import Data.List
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
|
||||||
|
import qualified Rextra.Dfa as Dfa
|
||||||
|
import qualified Rextra.Nfa as Nfa
|
||||||
|
import Rextra.Util
|
||||||
|
|
||||||
|
{-
|
||||||
|
- Visualizing DFAs
|
||||||
|
-}
|
||||||
|
|
||||||
|
convertDfaState :: (Int, Dfa.State Int Char) -> [LEdge String]
|
||||||
|
convertDfaState (from, state) =
|
||||||
|
let normalEdges = map (\(t, to) -> (from, to, [t])) . Map.assocs $ Dfa.transitions state
|
||||||
|
defaultEdge = (from, Dfa.defaultTransition state, "default")
|
||||||
|
in defaultEdge : normalEdges
|
||||||
|
|
||||||
|
dfaToGraph :: Dfa.Dfa Int Char -> Gr () String
|
||||||
|
dfaToGraph dfa =
|
||||||
|
let stateMap = Dfa.stateMap dfa
|
||||||
|
nodes = map (\k -> (k, ())) $ Map.keys stateMap
|
||||||
|
edges = concatMap convertDfaState $ Map.assocs stateMap
|
||||||
|
in mkGraph nodes edges
|
||||||
|
|
||||||
|
dfaAttributes :: Labellable el => Dfa.Dfa Int t -> GraphvizParams Int nl el () nl
|
||||||
|
dfaAttributes dfa =
|
||||||
|
let exitStates = Dfa.exitStates dfa
|
||||||
|
fmtNode (n, l) = if n `Set.member` exitStates
|
||||||
|
then [shape DoubleCircle]
|
||||||
|
else [shape Circle]
|
||||||
|
fmtEdge (n1, n2, l) = [toLabel l]
|
||||||
|
in nonClusteredParams { fmtNode = fmtNode, fmtEdge = fmtEdge }
|
||||||
|
|
||||||
|
showDfa :: Dfa.Dfa Int Char -> IO ()
|
||||||
|
showDfa dfa = runGraphvizCanvas' (graphToDot (dfaAttributes dfa) (dfaToGraph dfa)) Gtk
|
||||||
|
|
||||||
|
{-
|
||||||
|
- Visualizing NFAs
|
||||||
|
-}
|
||||||
|
|
||||||
|
labelFromSet :: Set.Set Char -> String
|
||||||
|
labelFromSet charSet = "{" ++ intersperse ',' (Set.toList charSet) ++ "}"
|
||||||
|
|
||||||
|
labelFromCondition :: Nfa.TransitionCondition Char -> String
|
||||||
|
labelFromCondition (Nfa.Only charSet) = labelFromSet charSet
|
||||||
|
labelFromCondition (Nfa.AllExcept charSet)
|
||||||
|
| Set.null charSet = "Σ"
|
||||||
|
| otherwise = "Σ\\" ++ labelFromSet charSet
|
||||||
|
|
||||||
|
convertNfaState :: (Int, Nfa.State Int Char) -> [LEdge String]
|
||||||
|
convertNfaState (from, state) =
|
||||||
|
let transitions = Nfa.transitions state
|
||||||
|
transitionEdges = map (\(cond, to) -> (from, to, labelFromCondition cond)) transitions
|
||||||
|
epsilonTransitions = Set.toList $ Nfa.epsilonTransitions state
|
||||||
|
epsilonEdges = map (\to -> (from, to, "ε")) epsilonTransitions
|
||||||
|
in transitionEdges ++ epsilonEdges
|
||||||
|
|
||||||
|
nfaToGraph :: Nfa.Nfa Int Char -> Gr () String
|
||||||
|
nfaToGraph nfa =
|
||||||
|
let stateMap = Nfa.stateMap nfa
|
||||||
|
nodes = map (\k -> (k, ())) $ Map.keys stateMap
|
||||||
|
edges = concatMap convertNfaState $ Map.assocs stateMap
|
||||||
|
in mkGraph nodes edges
|
||||||
|
|
||||||
|
anyNfaToGraph :: (Ord s) => Nfa.Nfa s Char -> Gr () String
|
||||||
|
anyNfaToGraph = nfaToGraph . Nfa.rename
|
||||||
|
|
||||||
|
nfaAttributes :: Labellable el => Nfa.Nfa Int t -> GraphvizParams Int nl el () nl
|
||||||
|
nfaAttributes nfa =
|
||||||
|
let exitStates = Nfa.exitStates nfa
|
||||||
|
fmtNode (n, l) = if n `Set.member` exitStates
|
||||||
|
then [shape DoubleCircle]
|
||||||
|
else [shape Circle]
|
||||||
|
fmtEdge (n1, n2, l) = [toLabel l]
|
||||||
|
in nonClusteredParams { fmtNode = fmtNode, fmtEdge = fmtEdge }
|
||||||
|
|
||||||
|
showNfa :: Nfa.Nfa Int Char -> IO ()
|
||||||
|
showNfa nfa = runGraphvizCanvas' (graphToDot (nfaAttributes nfa) (nfaToGraph nfa)) Gtk
|
||||||
Loading…
Add table
Add a link
Reference in a new issue