diff options
Diffstat (limited to 'edit-lens/src/Control/FST.lhs')
| -rw-r--r-- | edit-lens/src/Control/FST.lhs | 161 |
1 files changed, 149 insertions, 12 deletions
diff --git a/edit-lens/src/Control/FST.lhs b/edit-lens/src/Control/FST.lhs index 9aa5341..9357da7 100644 --- a/edit-lens/src/Control/FST.lhs +++ b/edit-lens/src/Control/FST.lhs | |||
| @@ -15,7 +15,7 @@ module Control.FST | |||
| 15 | -- * Operations on FSTs | 15 | -- * Operations on FSTs |
| 16 | , productFST, restrictOutput, restrictFST | 16 | , productFST, restrictOutput, restrictFST |
| 17 | -- * Debugging Utilities | 17 | -- * Debugging Utilities |
| 18 | , liveFST | 18 | , liveFST, dotFST |
| 19 | ) where | 19 | ) where |
| 20 | 20 | ||
| 21 | import Data.Map.Lazy (Map, (!?), (!)) | 21 | import Data.Map.Lazy (Map, (!?), (!)) |
| @@ -38,6 +38,11 @@ import Control.Monad.State.Strict | |||
| 38 | import Text.PrettyPrint.Leijen (Pretty(..)) | 38 | import Text.PrettyPrint.Leijen (Pretty(..)) |
| 39 | import qualified Text.PrettyPrint.Leijen as PP | 39 | import qualified Text.PrettyPrint.Leijen as PP |
| 40 | 40 | ||
| 41 | import Data.Bool (bool) | ||
| 42 | import Data.Monoid ((<>)) | ||
| 43 | |||
| 44 | import Text.Dot | ||
| 45 | |||
| 41 | \end{code} | 46 | \end{code} |
| 42 | \end{comment} | 47 | \end{comment} |
| 43 | 48 | ||
| @@ -50,7 +55,7 @@ In Haskell lockern wir die Anforderung, dass die Ein- und Ausgabe-Alphabete endl | |||
| 50 | Zudem speichern wir die Transitionsrelation als multimap um effiziente lookups von Zustand-Eingabe-Paaren zu ermöglichen. | 55 | Zudem speichern wir die Transitionsrelation als multimap um effiziente lookups von Zustand-Eingabe-Paaren zu ermöglichen. |
| 51 | 56 | ||
| 52 | \begin{code} | 57 | \begin{code} |
| 53 | dFSeata FST state input output = FST | 58 | data FST state input output = FST |
| 54 | { stInitial :: Set state | 59 | { stInitial :: Set state |
| 55 | , stTransition :: Map (state, Maybe input) (Set (state, Maybe output)) | 60 | , stTransition :: Map (state, Maybe input) (Set (state, Maybe output)) |
| 56 | , stAccept :: Set state | 61 | , stAccept :: Set state |
| @@ -58,13 +63,56 @@ dFSeata FST state input output = FST | |||
| 58 | \end{code} | 63 | \end{code} |
| 59 | \end{defn} | 64 | \end{defn} |
| 60 | 65 | ||
| 66 | \begin{eg} \label{eg:linebreak} | ||
| 67 | Als wiederkehrendes Beispiel betrachten wir einen Transducer $L_{80} = (\Sigma, \Delta, Q, I, F, E)$, der für ein beliebiges Alphabet $\Sigma \supseteq \{ \text{\tt ' '}, \text{\tt \textbackslash n} \}$ durch Umwandlung zwischen Leerzeichen und Zeilenumbrüchen sicherstellt, dass jede Zeile des Ausgabetextes mindestens 80 Zeichen enthält, jedoch nur an Wortgrenzen umbricht: | ||
| 68 | |||
| 69 | \begin{align*} | ||
| 70 | \Delta & = \Sigma \\ | ||
| 71 | Q & = \{ 0, 1, \ldots, 80 \} \\ | ||
| 72 | I & = \{ 0 \} \\ | ||
| 73 | F & = Q \\ | ||
| 74 | E & = \{ (q, \sigma, \sigma, q + 1) \mid q \in Q \mysetminus \{ 80 \}, \sigma \in \Sigma \mysetminus \{ \text{\tt \textbackslash n} \} \} \\ | ||
| 75 | & \cup \{ (q, \text{\tt \textbackslash n}, \text{\tt ' '}, q + 1) \mid q \in Q \mysetminus \{ 80 \}, \sigma \in \Sigma \} \\ | ||
| 76 | & \cup \{ (80, \text{\tt ' '}, \text{\tt \textbackslash n}, 0), (80, \text{\tt \textbackslash n}, \text{\tt \textbackslash n}, 0) \} \\ | ||
| 77 | & \cup \{ (80, \sigma, \sigma, 80) \mid \sigma \in \Sigma \mysetminus \{ \text{\tt ' '}, \text{\tt \textbackslash n} \} \} | ||
| 78 | \end{align*} | ||
| 79 | |||
| 80 | \begin{figure}[p] | ||
| 81 | \centering | ||
| 82 | \begin{tikzpicture}[->,auto,node distance=5cm] | ||
| 83 | \node[initial,state,accepting] (0) {$0$}; | ||
| 84 | \node[state,accepting] (1) [right of=0] {$1$}; | ||
| 85 | \node[] (rest) [below of=1] {$\ldots$}; | ||
| 86 | \node[state,accepting] (i) [right of=rest,xshift=-2cm] {$i$}; | ||
| 87 | \node[state,accepting] (si) [below of=rest,yshift=2cm] {$i + 1$}; | ||
| 88 | \node[state,accepting] (80) [left of=rest] {$80$}; | ||
| 89 | |||
| 90 | \path (0) edge node {$\{ (\sigma, \sigma) \mid \sigma \in \Sigma, \sigma \neq \text{\tt \textbackslash n} \}$} (1) | ||
| 91 | (1) edge [bend left=20] node {$\{ (\sigma, \sigma) \mid \sigma \in \Sigma, \sigma \neq \text{\tt \textbackslash n} \}$} (rest) | ||
| 92 | edge [bend right=20] node [left] {$(\text{\tt \textbackslash n}, \text{\tt ' '})$} (rest) | ||
| 93 | (rest) edge node [below] {$\{ (\sigma, \sigma) \mid \sigma \in \Sigma, \sigma \neq \text{\tt \textbackslash n} \}$} (80) | ||
| 94 | edge [bend right=20] node [above] {$(\text{\tt \textbackslash n}, \text{\tt ' '})$} (80) | ||
| 95 | (i) edge [bend left=45] node {$\{ (\sigma, \sigma) \mid \sigma \in \Sigma, \sigma \neq \text{\tt \textbackslash n} \}$} (si) | ||
| 96 | edge [bend left=10] node [left] {$(\text{\tt \textbackslash n}, \text{\tt ' '})$} (si) | ||
| 97 | (80) edge [loop below] node [below] {$\{ (\sigma, \sigma) \mid \sigma \in \Sigma, \sigma \neq \text{\tt \textbackslash n}, \sigma \neq \text{\tt ' '} \}$} (80) | ||
| 98 | edge [bend left=20] node {$(\text{\tt \textbackslash n}, \text{\tt \textbackslash n})$} (0) | ||
| 99 | edge [bend right=20] node [right] {$(\text{\tt ' '}, \text{\tt \textbackslash n})$} (0); | ||
| 100 | |||
| 101 | \draw[-] (rest)--(i.north); | ||
| 102 | \draw[-] (rest)--(si.west); | ||
| 103 | \end{tikzpicture} | ||
| 104 | \caption{Beispiel \ref{eg:linebreak} dargestellt als Graph} | ||
| 105 | \end{figure} | ||
| 106 | \end{eg} | ||
| 107 | |||
| 61 | \begin{comment} | 108 | \begin{comment} |
| 62 | \begin{code} | 109 | \begin{code} |
| 63 | instance (Show state, Show input, Show output) => Pretty (FST state input output) where | 110 | instance (Show state, Show input, Show output, Ord state, Ord input, Ord output) => Pretty (FST state input output) where |
| 64 | pretty FST{..} = PP.vsep | 111 | pretty fst@FST{..} = PP.vsep |
| 65 | [ PP.text "Initial states:" PP.</> PP.hang 2 (list . map (PP.text . show) $ Set.toAscList stInitial) | 112 | [ PP.text "Initial states:" PP.</> PP.hang 2 (list . map (PP.text . show) $ Set.toAscList stInitial) |
| 66 | , PP.text "State transitions:" PP.<$> PP.indent 2 (PP.vsep | 113 | , PP.text "State transitions:" PP.<$> PP.indent 2 (PP.vsep |
| 67 | [ PP.text (show st) | 114 | [ PP.text (bool " " "#" $ Set.member st live) |
| 115 | PP.<+> PP.text (show st) | ||
| 68 | PP.<+> (PP.text "-" PP.<> PP.tupled [label inS, label outS] PP.<> PP.text "→") | 116 | PP.<+> (PP.text "-" PP.<> PP.tupled [label inS, label outS] PP.<> PP.text "→") |
| 69 | PP.<+> PP.text (show st') | 117 | PP.<+> PP.text (show st') |
| 70 | | ((st, inS), to) <- Map.toList stTransition | 118 | | ((st, inS), to) <- Map.toList stTransition |
| @@ -77,9 +125,11 @@ instance (Show state, Show input, Show output) => Pretty (FST state input output | |||
| 77 | label = PP.text . maybe "ɛ" show | 125 | label = PP.text . maybe "ɛ" show |
| 78 | list :: [PP.Doc] -> PP.Doc | 126 | list :: [PP.Doc] -> PP.Doc |
| 79 | list = PP.encloseSep (PP.lbracket PP.<> PP.space) (PP.space PP.<> PP.rbracket) (PP.comma PP.<> PP.space) | 127 | list = PP.encloseSep (PP.lbracket PP.<> PP.space) (PP.space PP.<> PP.rbracket) (PP.comma PP.<> PP.space) |
| 128 | live = liveFST fst | ||
| 80 | \end{code} | 129 | \end{code} |
| 81 | \end{comment} | 130 | \end{comment} |
| 82 | 131 | ||
| 132 | \begin{defn}[Auswertung von FSTs] | ||
| 83 | Wir definieren die Auswertung von finite state transducers induktiv indem wir zunächst angeben wie ein einzelner Auswertungs-Schritt erfolgt. | 133 | Wir definieren die Auswertung von finite state transducers induktiv indem wir zunächst angeben wie ein einzelner Auswertungs-Schritt erfolgt. |
| 84 | 134 | ||
| 85 | Hierzu kommentieren wir die Haskell-Implementierung eines Auswertungs-Schritts. | 135 | Hierzu kommentieren wir die Haskell-Implementierung eines Auswertungs-Schritts. |
| @@ -145,6 +195,7 @@ akzeptierenden Endzustände liegt. | |||
| 145 | go (initial, nPath) ncs | 195 | go (initial, nPath) ncs |
| 146 | \end{code} | 196 | \end{code} |
| 147 | \end{comment} | 197 | \end{comment} |
| 198 | \end{defn} | ||
| 148 | 199 | ||
| 149 | Es ist gelegentlich nützlich nur die möglichen Ausgaben eines FST auf gegebener | 200 | Es ist gelegentlich nützlich nur die möglichen Ausgaben eines FST auf gegebener |
| 150 | Eingabe zu bestimmen, wir führen eine Hilfsfunktion auf Basis von | 201 | Eingabe zu bestimmen, wir führen eine Hilfsfunktion auf Basis von |
| @@ -163,7 +214,7 @@ runFST = fmap (map $ catMaybes . fmap (view _2) . view _2) . runFST' | |||
| 163 | \end{comment} | 214 | \end{comment} |
| 164 | 215 | ||
| 165 | Wir können das Produkt zweier FSTs definieren. | 216 | Wir können das Produkt zweier FSTs definieren. |
| 166 | Intuitiv wollen wir beide FSTs gleichzeitig ausführen und dabei sicherstellen, dass Ein- und Ausgabe der FSTs übereinstimmen\footnote{Da wir $\epsilon$-Transitionen in FSTs erlauben müssen wir uns festlegen wann eine $\epsilon$-Transition übereinstimmt mit einer anderen Transition. Wir definieren, dass $\epsilon$ als Eingabe mit jeder anderen Eingabe (inkl. einem weiteren $\epsilon$) übereinstimmt.}. | 217 | Intuitiv wollen wir beide FSTs gleichzeitig ausführen und dabei sicherstellen, dass Ein- und Ausgabe der FSTs übereinstimmen\footnote{Da wir $\epsilon$-Transitionen in FSTs erlauben müssen wir uns festlegen wann eine $\epsilon$-Transition übereinstimmt mit einer anderen Transition. Wir definieren, dass $\epsilon$ als Eingabe ausschließlich mit $\epsilon$ übereinstimmt.}. |
| 167 | 218 | ||
| 168 | Hierfür berechnen wir das Graphen-Produkt der FSTs: | 219 | Hierfür berechnen wir das Graphen-Produkt der FSTs: |
| 169 | 220 | ||
| @@ -221,7 +272,7 @@ Hierzu nehmen wir das FST-Produkt mit einem FST, der, ungeachtet der Eingabe, im | |||
| 221 | Da die Ausgaben der beiden FSTs übereinstimmen müssen produziert das Produkt mit einem derartigen FST (solange dessen Ausgabe in keinem Sinne von der Eingabe abhängt) die gewünschte Ausgabe. | 272 | Da die Ausgaben der beiden FSTs übereinstimmen müssen produziert das Produkt mit einem derartigen FST (solange dessen Ausgabe in keinem Sinne von der Eingabe abhängt) die gewünschte Ausgabe. |
| 222 | 273 | ||
| 223 | Zur Konstruktion eines derartigen \emph{Wort-FST}s nehmen wir Indizes im Ausgabe-Wort (natürliche Zahlen) als Zustände. | 274 | Zur Konstruktion eines derartigen \emph{Wort-FST}s nehmen wir Indizes im Ausgabe-Wort (natürliche Zahlen) als Zustände. |
| 224 | Übergänge sind immer entweder der Form $n \rightarrow \text{succ}(n)$, konsumieren keine Eingabe ($\epsilon$) und produzieren als Ausgabe das Zeichen am Index $n$ im Ausgabe-Wort, oder der Form $n \overset{(i, \epsilon)}{\rightarrow} n$, für jedes Eingabesymbol $i$ (um die Unabhängigkeit von der Eingabe sicherzustellen). | 275 | Übergänge sind immer entweder der Form $n \rightarrow \text{succ}(n)$, konsumieren keine Eingabe ($\epsilon$) und produzieren als Ausgabe das Zeichen am Index $n$ im Ausgabe-Wort, oder der Form $n \overset{(\sigma, \epsilon)}{\rightarrow} n$, für jedes Eingabesymbol $\sigma$ (um die Unabhängigkeit von der Eingabe sicherzustellen). |
| 225 | Weiter ist $0$ initial und $\text{length}(\text{Ausgabe})$ der einzige akzeptierende Endzustand. | 276 | Weiter ist $0$ initial und $\text{length}(\text{Ausgabe})$ der einzige akzeptierende Endzustand. |
| 226 | 277 | ||
| 227 | \begin{code} | 278 | \begin{code} |
| @@ -251,6 +302,35 @@ wordFST inps outs = FST | |||
| 251 | \end{code} | 302 | \end{code} |
| 252 | \end{comment} | 303 | \end{comment} |
| 253 | 304 | ||
| 305 | \begin{eg} \label{eg:w100} | ||
| 306 | Der zum Wort $w = 1\, 2\, \ldots\, 80\, \text{\tt \textbackslash n}\, 81\, \ldots\, 98$ gehörige Wort-FST $W_w = ( \Sigma, \Delta, Q, I, F, E)$ für ein beliebiges Eingabe-Alphabet $\Sigma$ ist: | ||
| 307 | |||
| 308 | \begin{align*} | ||
| 309 | \Delta & = \{ 1, 2, \ldots, 98, \text{\tt \textbackslash n} \} \\ | ||
| 310 | Q & = \{ 0, 1, \ldots, 99 \} \\ | ||
| 311 | I & = \{ 0 \} \\ | ||
| 312 | F & = \{ 99 \} \\ | ||
| 313 | E & = \{ (i, \sigma, w_i, i + 1) \mid \sigma \in \Sigma \cup \{ \epsilon \}, i \in Q \mysetminus \{ 99 \} \} \\ | ||
| 314 | & \cup \{ (i, \sigma, \epsilon, i) \mid \sigma \in \Sigma \cup \{ \epsilon \}, i \in Q \mysetminus \{ 99 \} \} | ||
| 315 | \end{align*} | ||
| 316 | |||
| 317 | \begin{figure}[p] | ||
| 318 | \centering | ||
| 319 | \begin{tikzpicture}[->,auto,node distance=5cm] | ||
| 320 | \node[initial,state] (0) {$0$}; | ||
| 321 | \node[] (rest) [right of=0] {$\ldots$}; | ||
| 322 | \node[state,accepting] (99) [right of=rest] {$99$}; | ||
| 323 | |||
| 324 | \path (0) edge [loop above] node {$\{(\sigma, \epsilon) \mid \sigma \in \Sigma \cup \{ \epsilon \} \}$} (0) | ||
| 325 | edge node {$\{ (\sigma, 1) \mid \sigma \in \Sigma \cup \{ \epsilon \} \}$} (rest) | ||
| 326 | (rest) edge node {$\{ \sigma, 100 \} \mid \sigma \in \Sigma \cup \{ \epsilon \}$} (99) | ||
| 327 | (99) edge [loop above] node {$\{(\sigma, \epsilon) \mid \sigma \in \Sigma \}$} (99); | ||
| 328 | \end{tikzpicture} | ||
| 329 | |||
| 330 | \caption{Beispiel \ref{eg:w100} dargestellt als Graph} | ||
| 331 | \end{figure} | ||
| 332 | \end{eg} | ||
| 333 | |||
| 254 | Da \texttt{wordFST} zur Konstruktion eine komprehensive Menge aller Eingabesymbole benötigt verwenden wir im folgenden eine optimierte Variante des Produkts mit einem Wort-FST. | 334 | Da \texttt{wordFST} zur Konstruktion eine komprehensive Menge aller Eingabesymbole benötigt verwenden wir im folgenden eine optimierte Variante des Produkts mit einem Wort-FST. |
| 255 | 335 | ||
| 256 | \begin{code} | 336 | \begin{code} |
| @@ -258,6 +338,46 @@ restrictOutput :: forall state input output. (Ord state, Ord input, Ord output) | |||
| 258 | -- ^ @restrictOutput out@ is equivalent to @productFST (wordFST inps out)@ where @inps@ is a comprehensive set of all input symbols @inp :: input@ | 338 | -- ^ @restrictOutput out@ is equivalent to @productFST (wordFST inps out)@ where @inps@ is a comprehensive set of all input symbols @inp :: input@ |
| 259 | \end{code} | 339 | \end{code} |
| 260 | 340 | ||
| 341 | \begin{eg} \label{eg:l80timesw100} | ||
| 342 | Der FST $L_{80}$ aus Beispiel \autoref{eg:linebreak} eingeschränkt auf das Wort $w$ aus Beispiel \autoref{eg:w100} (also $W_w \times L_{80}$) ist: | ||
| 343 | |||
| 344 | \begin{align*} | ||
| 345 | \Sigma^\times & = \{1, 2, \ldots, 99, \text{\tt \textbackslash n}, \text{\tt ' '} \} \\ | ||
| 346 | \Delta^\times & = \{1, 2, \ldots, 99, \text{\tt \textbackslash n} \} \\ | ||
| 347 | Q^\times & = \{ (\sigma, p) \mid \sigma \in \{ 0_{W_w}, \ldots, 99_{W_w} \}, p \in \{ 0_{L_{80}}, \ldots, 80_{L_{80}} \} \} \\ | ||
| 348 | I^\times & = \{ (0_{W_w}, 0_{L_{80}}) \} \\ | ||
| 349 | F^\times & = \{ (99_{W_w}, p) \mid p \in \{ 0_{L_{80}}, \ldots, 80_{L_{80}} \} \} \\ | ||
| 350 | E^\times & = \{ ((i, q), w_i, w_i, (i + 1, q + 1)) \mid q \in Q \mysetminus \{ 80 \}, i \in Q \mysetminus \{ 99 \} \} \\ | ||
| 351 | & \cup \{ ((80, 80), \text{\tt \textbackslash n}, \text{\tt \textbackslash n}, (81, 0)) \} | ||
| 352 | \end{align*} | ||
| 353 | |||
| 354 | \begin{figure}[p] | ||
| 355 | \centering | ||
| 356 | \begin{tikzpicture}[->,auto,node distance=5cm] | ||
| 357 | \node[initial,state] (0) {$0_{W_w}\, 0_{L_{80}}$}; | ||
| 358 | \node[] (rest1) [right of=0] {$\ldots$}; | ||
| 359 | \node[state] (80) [right of=rest1] {$80_{W_w}\, 80_{L_{80}}$}; | ||
| 360 | \node[state] (81) [below of=0] {$81_{W_w}\, 0_{L_{80}}$}; | ||
| 361 | \node[] (rest2) [right of=81] {$\ldots$}; | ||
| 362 | \node[state,accepting] (99) [right of=rest2] {$99_{W_w}\, 19_{L_{80}}$}; | ||
| 363 | |||
| 364 | \path (0) edge node {$(1, 1)$} (rest1) | ||
| 365 | (rest1) edge node {$(80, 80)$} (80) | ||
| 366 | (80) edge node {$(\text{\tt \textbackslash n}, \text{\tt \textbackslash n})$} (81) | ||
| 367 | (81) edge node {$(81, 81)$} (rest2) | ||
| 368 | (rest2) edge node {$(98, 98)$} (99); | ||
| 369 | \end{tikzpicture} | ||
| 370 | |||
| 371 | \caption{Beispiel \ref{eg:l80timesw100} dargestellt als Graph} | ||
| 372 | \end{figure} | ||
| 373 | \end{eg} | ||
| 374 | |||
| 375 | \begin{rem} | ||
| 376 | Es ist bemerkenswert, dass in Beispiel \ref{eg:l80timesw100} die Zirkuläre Struktur von $L_80$ durch Produkt mit einem Wort verloren geht. | ||
| 377 | |||
| 378 | I.\@A.\@ ist das Produkt eines beliebigen FST mit einem Wort-FST zwar nicht azyklisch, erbt jedoch die lineare Struktur des Wort-FST in dem Sinne, dass Fortschritt in Richtung der akzeptierenden Zustände nur möglich ist indem der $(i, \sigma, w_i, i + 1)$-Klasse von Transitionen des Wort-FSTs gefolgt wird. | ||
| 379 | \end{rem} | ||
| 380 | |||
| 261 | \begin{comment} | 381 | \begin{comment} |
| 262 | \begin{code} | 382 | \begin{code} |
| 263 | restrictOutput out FST{..} = FST | 383 | restrictOutput out FST{..} = FST |
| @@ -302,18 +422,35 @@ liveFST :: forall state input output. (Ord state, Ord input, Ord output, Show st | |||
| 302 | -- ^ Compute the set of "live" states (with no particular complexity) | 422 | -- ^ Compute the set of "live" states (with no particular complexity) |
| 303 | -- | 423 | -- |
| 304 | -- A state is "live" iff there is a path from it to an accepting state and a path from an initial state to it | 424 | -- A state is "live" iff there is a path from it to an accepting state and a path from an initial state to it |
| 305 | liveFST fst@FST{..} = flip execState Set.empty $ mapM_ (depthSearch Set.empty) stInitial | 425 | liveFST fst@FST{..} = flip execState (Set.empty) . depthSearch Set.empty $ Set.toList stInitial |
| 306 | where | 426 | where |
| 307 | stTransition' :: Map state (Set state) | 427 | stTransition' :: Map state (Set state) |
| 308 | stTransition' = Map.map (Set.map (\(st, _) -> st)) $ Map.mapKeysWith Set.union (\(st, _) -> st) stTransition | 428 | stTransition' = Map.map (Set.map (\(st, _) -> st)) $ Map.mapKeysWith Set.union (\(st, _) -> st) stTransition |
| 309 | depthSearch :: Set state -> state -> State (Set state) () | 429 | depthSearch :: Set state -> [state] -> State (Set state) () |
| 310 | depthSearch acc curr = do | 430 | depthSearch acc [] = return () |
| 431 | depthSearch acc (curr : queue) = do | ||
| 311 | let acc' = Set.insert curr acc | 432 | let acc' = Set.insert curr acc |
| 312 | next = fromMaybe Set.empty $ stTransition' !? curr | 433 | next = fromMaybe Set.empty $ stTransition' !? curr |
| 313 | alreadyLive <- get | 434 | alreadyLive <- get |
| 314 | when (curr `Set.member` Set.union stAccept alreadyLive) $ | 435 | when (curr `Set.member` Set.union stAccept alreadyLive) $ |
| 315 | modify $ Set.union acc' | 436 | modify $ Set.union acc' |
| 316 | alreadyLive <- get | 437 | depthSearch acc' $ filter (not . flip Set.member next) queue ++ Set.toList (next `Set.difference` acc') |
| 317 | mapM_ (depthSearch acc') $ next `Set.difference` alreadyLive | 438 | |
| 439 | dotFST :: forall state input output. (Ord state, Ord input, Ord output, Show state, Show input, Show output) => FST state input output -> Dot () | ||
| 440 | dotFST FST{..} = do | ||
| 441 | let | ||
| 442 | stTransition' = concatMap (\(f, ts) -> (f,) <$> Set.toList ts) $ Map.toList stTransition | ||
| 443 | states = stInitial <> stAccept <> foldMap (Set.singleton . fst . fst) stTransition' <> foldMap (Set.singleton . fst . snd) stTransition' | ||
| 444 | stateIds <- sequence . (flip Map.fromSet) states $ \st -> node | ||
| 445 | [ ("label", show st) | ||
| 446 | , ("peripheries", bool "1" "2" $ st `Set.member` stAccept) | ||
| 447 | ] | ||
| 448 | forM_ stInitial $ \st -> do | ||
| 449 | init <- node [ ("label", ""), ("shape", "none") ] | ||
| 450 | init .->. (stateIds ! st) | ||
| 451 | forM_ stTransition' $ \((f, inS), (t, outS)) -> do | ||
| 452 | edge (stateIds ! f) (stateIds ! t) | ||
| 453 | [ ("label", show (inS, outS)) | ||
| 454 | ] | ||
| 318 | \end{code} | 455 | \end{code} |
| 319 | \end{comment} | 456 | \end{comment} |
