summaryrefslogtreecommitdiff
path: root/edit-lens/src/Control/FST.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'edit-lens/src/Control/FST.lhs')
-rw-r--r--edit-lens/src/Control/FST.lhs161
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
21import Data.Map.Lazy (Map, (!?), (!)) 21import Data.Map.Lazy (Map, (!?), (!))
@@ -38,6 +38,11 @@ import Control.Monad.State.Strict
38import Text.PrettyPrint.Leijen (Pretty(..)) 38import Text.PrettyPrint.Leijen (Pretty(..))
39import qualified Text.PrettyPrint.Leijen as PP 39import qualified Text.PrettyPrint.Leijen as PP
40 40
41import Data.Bool (bool)
42import Data.Monoid ((<>))
43
44import 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
50Zudem speichern wir die Transitionsrelation als multimap um effiziente lookups von Zustand-Eingabe-Paaren zu ermöglichen. 55Zudem speichern wir die Transitionsrelation als multimap um effiziente lookups von Zustand-Eingabe-Paaren zu ermöglichen.
51 56
52\begin{code} 57\begin{code}
53dFSeata FST state input output = FST 58data 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}
63instance (Show state, Show input, Show output) => Pretty (FST state input output) where 110instance (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]
83Wir definieren die Auswertung von finite state transducers induktiv indem wir zunächst angeben wie ein einzelner Auswertungs-Schritt erfolgt. 133Wir definieren die Auswertung von finite state transducers induktiv indem wir zunächst angeben wie ein einzelner Auswertungs-Schritt erfolgt.
84 134
85Hierzu kommentieren wir die Haskell-Implementierung eines Auswertungs-Schritts. 135Hierzu 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
149Es ist gelegentlich nützlich nur die möglichen Ausgaben eines FST auf gegebener 200Es ist gelegentlich nützlich nur die möglichen Ausgaben eines FST auf gegebener
150Eingabe zu bestimmen, wir führen eine Hilfsfunktion auf Basis von 201Eingabe 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
165Wir können das Produkt zweier FSTs definieren. 216Wir können das Produkt zweier FSTs definieren.
166Intuitiv 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.}. 217Intuitiv 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
168Hierfür berechnen wir das Graphen-Produkt der FSTs: 219Hierfü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
221Da 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. 272Da 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
223Zur Konstruktion eines derartigen \emph{Wort-FST}s nehmen wir Indizes im Ausgabe-Wort (natürliche Zahlen) als Zustände. 274Zur 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).
225Weiter ist $0$ initial und $\text{length}(\text{Ausgabe})$ der einzige akzeptierende Endzustand. 276Weiter 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
254Da \texttt{wordFST} zur Konstruktion eine komprehensive Menge aller Eingabesymbole benötigt verwenden wir im folgenden eine optimierte Variante des Produkts mit einem Wort-FST. 334Da \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}
263restrictOutput out FST{..} = FST 383restrictOutput 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
305liveFST fst@FST{..} = flip execState Set.empty $ mapM_ (depthSearch Set.empty) stInitial 425liveFST 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
439dotFST :: forall state input output. (Ord state, Ord input, Ord output, Show state, Show input, Show output) => FST state input output -> Dot ()
440dotFST 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}