From: Ulya Trofimovich Date: Mon, 8 Apr 2019 12:21:50 +0000 (+0100) Subject: Paper: updated "TNFA construction" section. X-Git-Tag: 1.2~77 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b640359e9c81c04465797cc093865165683d3fd;p=re2c Paper: updated "TNFA construction" section. --- diff --git a/doc/tdfa_v2/img/tnfa_construction.tex b/doc/tdfa_v2/img/tnfa_construction.tex index 495b875f..3adfeb12 100644 --- a/doc/tdfa_v2/img/tnfa_construction.tex +++ b/doc/tdfa_v2/img/tnfa_construction.tex @@ -15,124 +15,101 @@ \begin{document} -\def\offs{-0.65in} -\def\widd{1in} -\def\dist{1in} +\def\offs{-0.5in} +\def\widd{1.6in} +\def\dist{1.15in} \begin{tikzpicture}[>=stealth, ->, auto, node distance=\dist] \tikzstyle{every node}=[draw=none] -\tikzstyle{every state}=[rectangle, rounded corners = 6, minimum size=0.18in, inner sep = 3pt] +\tikzstyle{every state}=[rectangle, rounded corners = 6, minimum size=0.2in, inner sep = 2pt] \tikzset{style1/.style={draw, rectangle, rounded corners = 11, minimum width = \widd, minimum height = 0.3in, xshift = \offs}} \tikzset{style2/.style={state, accepting, xshift = \offs}} -%\newcommand \retonfa {re \Xund to \Xund n\!f\!a} -%\newcommand \ntag {neg \Xund tag} -\newcommand \retonfa {F} -\newcommand \ntag {N} +\newcommand \tnfa {tn\!f\!a} +\newcommand \ntags {ntags} \begin{scope}[xshift=0in, yshift=0in] -\begin{scope}[xshift=0in, yshift=0in] - \node[draw=none] (a) {$\hphantom{\hspace{1in}}$}; -\end{scope} +%\begin{scope}[xshift=0in, yshift=0in] +% \node[draw=none] (a) {$\hphantom{\hspace{1in}}$}; +%\end{scope} \begin{scope}[xshift=0in, yshift=0in] \node[state, accepting] (a) {$y$}; - \node [label={[label distance=0.1in, below left]270:\large{(a)}}] (a) {}; - \node [label={[label distance=0.1in, below right]270: - $\retonfa \big( (0, 0, \epsilon), y \big) $}] (a) {}; + \node [label={[label distance=0.1in, below right]270:\large{(a) \;} + $\tnfa \big( (0, 0, \epsilon), y \big) $}] (a) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-0.7in] +\begin{scope}[xshift=0in, yshift=-0.8in] \node[state] (a) {$x$}; \node[state, accepting, right of=a] (b) {$y$}; \path (a) edge node {$\alpha / \epsilon$} (b); - \node [label={[label distance=0.1in, below left]270:\large{(b)}}] (a) {}; - \node [label={[label distance=0.1in, below right]270: - $\retonfa \big( (0, 0, a), y \big) $}] (a) {}; + \node [label={[label distance=0.1in, below right]270:\large{(b) \;} + $\tnfa \big( (0, 0, a), y \big) $}] (a) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-1.4in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-1.6in] \node[state] (a1) {$z$}; - \node[style1, right of = a1] (a) {$F(s)$}; + \node[style1, right of = a1] (a) {$\tnfa(r_1, x)$}; \node[style2, right of = a] (a2) {$x$}; - \node[style1, right of = a2] (b) {$F(u)$}; + \node[style1, right of = a2] (b) {$\tnfa(r_2, y)$}; \node[style2, right of = b] (b2) {$y$}; - \node [label={[label distance=0.2in, below left]270:\large{(c)}}] (a) {}; - \node [label={[label distance=0.2in, below right]270: - $\retonfa \big( (0, 0, s \cdot u), y \big) $}] (a1) {}; + \node [label={[label distance=0.2in, below right]270:\large{(c) \;} + $\tnfa \big( (0, 0, r_1 \cdot r_2), y \big) $}] (a1) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-2.6in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-2.9in] \node[state] (a) {$x$}; - \node[state, above right of = a, yshift = -0.35in] (b1) {$x_2$}; - \node[style1, right of = b1] (b) {$F(s)$}; - \node[style2, right of = b] (b2) {$x_1$}; - \node[style1, right of = b2, rotate around={-21:(b2)}] (d) {$N(u)$}; - - \node[state, below right of=a, yshift = 0.35in] (c1) {$x_4$}; - \node[style1, right of = c1] (c2) {$N(s)$}; - \node[style2, right of = c2] (c3) {$x_3$}; - \node[style1, right of = c3, rotate around={21:(c3)}] (c) {$F(u)$}; - \node[style2, right of = c, rotate around={21:(c)}] (d) {$y$}; + \node[state, above right of = a, yshift = -0.45in] (b1) {$x_1$}; + \node[style1, right of = b1] (b) {$\tnfa(r_1, x'_2)$}; + \node[style2, right of = b] (b2) {$x'_2$}; + \node[style1, right of = b2, rotate around={-16:(b2)}] (d) {$\ntags(T_2, y)$}; + + \node[state, below right of=a, yshift = 0.45in] (c1) {$x'_1$}; + \node[style1, right of = c1] (c2) {$\ntags(T_1, x_2)$}; + \node[style2, right of = c2] (c3) {$x_2$}; + \node[style1, right of = c3, rotate around={16:(c3)}] (c) {$\tnfa(r_2, y)$}; + \node[style2, right of = c, rotate around={16:(c)}] (d) {$y$}; \path (a) edge [bend left] node {$1 / \epsilon$} (b1) (a) edge [bend right] node [below left] {$2 / \epsilon $} (c1) ; - \node [label={[label distance=0.5in, below left]270:\large{(d)}}] (a) {}; - \node [label={[label distance=0.5in, below right]270: - $\retonfa \big( (0, 0, s \mid u), y \big) $}] (a) {}; + \node [label={[label distance=0.5in, below right]270:\large{(d) \;} + $\tnfa \big( (0, 0, r_1 \mid r_2), y \big) $}] (a) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-3.8in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-4.2in] \node[state] (a1) {$z$}; - \node[style1, right of = a1] (a) {$F(r)$}; + \node[style1, right of = a1] (a) {$\tnfa(r_1, x)$}; \node[style2, right of = a] (a2) {$x$}; - \node[style1, right of = a2, minimum width = 1.9in, xshift = 0.3in] (b) {$F( (0, 0, r^{n-1, m-1}))$}; - \node[style2, right of = b, xshift = 0.3in] (b2) {$y$}; - \node [label={[label distance=0.2in, below left]270:\large{(e)}}] (a1) {}; - \node [label={[label distance=0.2in, below right]270: - $\retonfa \big( (0, 0, r^{n, m}), y \big) \mid_{n \;>\; 1} $}] (a1) {}; + \node[style1, right of = a2, minimum width = 2in, xshift = 0.2in] (b) {$\tnfa( (0, 0, r_1^{n-1, m-1}), y)$}; + \node[style2, right of = b, xshift = 0.2in] (b2) {$y$}; + \node [label={[label distance=0.2in, below right]270:\large{(e) \;} + $\tnfa \big( (0, 0, r_1^{n, m}), y \big) \mid_{1 \,<\, n \,\leq\, m \,\leq\, \infty} $}] (a1) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-5in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-5.5in] \node[state] (a) {$x$}; - \node[state, above right of = a, yshift = -0.35in] (b1) {$x_1$}; - \node[style1, right of = b1, rotate around={-21:(b1)}] (d) {$F( (0, 0, r^{1,m}))$}; + \node[state, above right of = a, yshift = -0.45in] (b1) {$x_1$}; + \node[style1, right of = b1, rotate around={-16:(b1)}] (d) {$\tnfa( (0, 0, r_1^{1,m}), y)$}; - \node[state, below right of=a, yshift = 0.35in] (c1) {$x_2$}; - \node[style1, right of = c1, rotate around={21:(c1)}] (c) {$N(r)$}; - \node[style2, right of = c, rotate around={21:(c)}] (d) {$y$}; + \node[state, below right of=a, yshift = 0.45in] (c1) {$x'_1$}; + \node[style1, right of = c1, rotate around={16:(c1)}] (c) {$\ntags(T_1, y)$}; + \node[style2, right of = c, rotate around={16:(c)}] (d) {$y$}; \path (a) edge [bend left] node {$1 / \epsilon$} (b1) (a) edge [bend right] node [below left] {$2 / \epsilon $} (c1) ; - \node [label={[label distance=0.5in, below left]270:\large{(f)}}] (a) {}; - \node [label={[label distance=0.5in, below right]270: - $\retonfa \big( (0, 0, r^{0, m}), y \big) $}] (a) {}; + \node [label={[label distance=0.5in, below right]270:\large{(f) \;} + $\tnfa \big( (0, 0, r_1^{0, m}), y \big) $}] (a) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-6.6in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-7.2in] \node[state] (b1) {$z$}; - \node[style1, right of = b1] (b) {$F(r)$}; + \node[style1, right of = b1] (b) {$\tnfa(r_1, x)$}; \node[style2, right of = b] (b2) {$x$}; \node[state, accepting, right of = b2] (c) {$y$}; @@ -141,83 +118,56 @@ (b2) edge node {$2 / \epsilon$} (c) ; \draw (b2) .. controls ($ (b2) + (0.7, 1.5) $) and ($ (b1) + (-0.7, 1.5) $) .. node [above] {$1 / \epsilon$} (b1); - \node [label={[label distance=0.2in, below left]270:\large{(g)}}] (b1) {}; - \node [label={[label distance=0.2in, below right]270: - $\retonfa \big( (0, 0, r^{1, \infty}), y \big) $}] (b1) {}; -\end{scope} - -\begin{scope}[xshift=0in, yshift=-7.4in] - \def\offs{-0.5in} - \def\widd{1.3in} - - \node[state] (b1) {$x$}; - \node[style1, right of = b1] (b) {$F(r)$}; - \node[style2, right of = b] (b2) {$y$}; - - \node [label={[label distance=0.2in, below left]270:\large{(h)}}] (b1) {}; - \node [label={[label distance=0.2in, below right]270: - $\retonfa \big( (0, 0, r^{1, 1}), y \big) $}] (b1) {}; + \node [label={[label distance=0.2in, below right]270:\large{(g) \;} + $\tnfa \big( (0, 0, r_1^{1, \infty}), y \big) $}] (b1) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-8.6in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-8.5in] \node[state] (b1) {$w$}; - \node[style1, right of = b1] (b) {$F(r)$}; + \node[style1, right of = b1] (b) {$\tnfa(r_1, z)$}; \node[style2, right of = b] (b2) {$z$}; - \node[state, right of = b2] (c1) {$x$}; - \node[style1, right of = c1, minimum width = 1.7in, xshift = 0.2in] (c) {$F((0, 0, r^{1, m-1}))$}; - \node[style2, right of = c, xshift = 0.2in] (c2) {$y$}; + \node[state, right of = b2, xshift = -0.2in] (c1) {$x$}; + \node[style1, right of = c1, xshift = 0.1in, minimum width = 1.8in] (c) {$\tnfa((0, 0, r_1^{1, m-1}), y)$}; + \node[style2, right of = c, xshift = 0.1in] (c2) {$y$}; \path (b2) edge node {$2 / \epsilon$} (c1) ; \draw (b2) .. controls ($ (b2) + (0, 2) $) and ($ (c2) + (0, 2) $) .. node [very near start] {$1 / \epsilon$} (c2); - \node [label={[label distance=0.2in, below left]270:\large{(h)}}] (b1) {}; - \node [label={[label distance=0.2in, below right]270: - $\retonfa \big( (0, 0, r^{1, m}), y \big) \mid_{1 < m < \infty} $}] (b1) {}; + \node [label={[label distance=0.2in, below right]270:\large{(h) \;} + $\tnfa \big( (0, 0, r_1^{1, m}), y \big) \mid_{1 \,<\, m \,<\, \infty} $}] (b1) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-10in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-9.8in] \node[state] (a) {$w$}; - \node[state, above right of=a, xshift=-0.2in, yshift=-0.2in] (b1) {$z$}; - \node[style1, right of = b1] (b) {$F ( (0, 0, r) )$}; + \node[state, right of=a] (b1) {$z$}; + \node[style1, right of = b1] (b) {$\tnfa ( (0, 0, r_1), x )$}; \node[style2, right of = b] (b2) {$x$}; - \node[state, accepting, below right of=b2, xshift=-0.2in, yshift=0.2in] (d) {$y$}; + \node[state, accepting, right of=b2] (d) {$y$}; \path (a) edge node {$1 / 2i \!-\! 1 $} (b1) (b2) edge node {$1 / 2i $} (d) ; - \node [label={[label distance=0.1in, below left]270:\large{(i)}}] (a) {}; - \node [label={[label distance=0.1in, below right]270: - $\retonfa \big( (i, \Xund, r) \big) \mid_{i \;\neq\; 0} $}] (a) {}; + \node [label={[label distance=0.1in, below right]270:\large{(i) \;} + $\tnfa \big( (i, j, r_1), y \big) \mid_{i \,\neq\, 0} $ + }] (a) {}; \end{scope} -\begin{scope}[xshift=0in, yshift=-10.8in] - \def\offs{-0.5in} - \def\widd{1.3in} - +\begin{scope}[xshift=0in, yshift=-10.9in] \node[state] (a) {$x_0$}; \node[state, right of = a] (a1) {$x_1$}; \node[draw=none, right of = a1, xshift=-0.5in] (b) {\large{$\dots$}}; - \node[state, right of = b, xshift=-0.5in] (b1) {$x_{2n-1}$}; - \node[state, accepting, right of = b1] (b2) {$x_{2n}$}; + \node[state, right of = b, xshift=-0.5in] (b1) {$x_{n}$}; + \node[state, accepting, right of = b1] (b2) {$y$}; \path - (a) edge node {$1 / 1\!-\!2i $} (a1) + (a) edge node {$1 / -t_1 $} (a1) (a1) edge node {} (b) (b) edge node {} (b1) - (b1) edge node {$1 / -\! 2i $} (b2) + (b1) edge node {$1 / -t_n $} (b2) ; - \node [label={[label distance=0.1in, below left]270:\large{(j)}}] (a) {}; - \node [label={[label distance=0.1in, below right]270: - $\begin{aligned} - N \big( (i, \Xund, r) \big) - \end{aligned}$ + \node [label={[label distance=0.1in, below right]270:\large{(j) \;} + $\ntags \big( T, y \big)$ }] (a) {}; \end{scope} diff --git a/doc/tdfa_v2/part_1_tnfa.tex b/doc/tdfa_v2/part_1_tnfa.tex index eccc9a04..699b6b37 100644 --- a/doc/tdfa_v2/part_1_tnfa.tex +++ b/doc/tdfa_v2/part_1_tnfa.tex @@ -31,6 +31,9 @@ \SetCommentSty{Xcommentfont} \SetNoFillComment +\let\oldnl\nl % Store \nl in \oldnl +\newcommand{\nonl}{\renewcommand{\nl}{\let\nl\oldnl}} % Remove line number for one line + \SetNlSty{textnormal}{}{} \renewcommand{\algorithmcfname}{ALGORITHM} @@ -48,6 +51,7 @@ \usepackage{enumitem} \usepackage[justification=centering]{caption} \usepackage{url} +\usepackage{vwcol} \usepackage[section]{placeins} \newcommand{\Xl}{\langle} @@ -296,6 +300,7 @@ only Kuklewicz considers histories of each tag separately. \\ Our contributions are the following: +\\[-0.5em] \begin{itemize}[itemsep=0.5em] @@ -418,7 +423,7 @@ In later sections we fill in all the details and provide connection between diff \begin{itemize} \item[] $\Sigma$ is a finite set of symbols (\emph{alphabet}) \item[] $Q$ is a finite set of \emph{states} - \item[] $T\subset\YN$ is a finite set of \emph{tags} + \item[] $T \subset \YN \times \YZ$ is a mapping of \emph{tags} to their submatch groups \item[] $\Delta = \Delta^\Sigma \sqcup \Delta^\epsilon$ is the \emph{transition} relation, consisting of two parts: \begin{itemize} @@ -460,8 +465,8 @@ which allows us to impose specific order of TNFA traversal \BlankLine \While {$i \leq n \wedge X \neq \emptyset$} { $X = closure(N, X, U, B, D)$ \; - $X = update \Xund result(X, i, \alpha_i)$ \; - $(B, D) = update \Xund ptables(X, U, B, D)$ \; + $X = update \Xund result(T, X, U, i, \alpha_i)$ \; + $(B, D) = update \Xund ptables(N, X, U, B, D)$ \; $X = \big\{ (q, o, u_0, r) \mid (o, \Xund, \Xund, r) \in X \wedge (o, \alpha_i, \epsilon, q) \in \Delta^\Sigma \big\}$ \; $i = i + 1$ \; } @@ -469,7 +474,7 @@ which allows us to impose specific order of TNFA traversal \BlankLine $X = closure(N, X, U, B, D)$ \; \If {$(q_f, \Xund, u, r) \in X$} { - \Return $f\!inal \Xund result (U, u, r, n)$ + \Return $f\!inal \Xund result (T, U, u, r, n)$ } \lElse { \Return $\varnothing$ } @@ -954,33 +959,22 @@ The problem of constructing $\epsilon$-closure with POSIX disambiguation can be formulated as a shortest path problem on directed graph with weighted arcs. In our case \emph{weight} corresponds to PE fragment induced by the path. % -We give two algorithms: GOR1 (named after the well-known Goldberg-Radzik algorithm [GRC??]) -and GTOP (named after ``global topological order''). -Both algorithms have the usual structure of shortest-path finding algorithms. +We give two algorithms: GOR1, named after the well-known Goldberg-Radzik algorithm [GRC??], +and GTOP, named after ``global topological order''. % -The algorithm starts with a queue (of some sort) that contains initial configurations, and loops until the queue becomes empty. -At each step of the loop it dequeues some configuration and scans $\epsilon$-transitions from its $q$-state. -For each scanned transition the algorithm constructs a new configuration that combines transition and the old configuration. -If transition goes to a state that has not been explored yet, -the new configuration is added to the resulting set. -Otherwise the algorithm compares the new configuration with the one in resulting set -and choses one that is better from POSIX perspective. +Both have the usual structure of shortest-path finding algorithms. +The algorithm starts with initial set of configurations, empty queue of some sort and an empty set of resulting configurations. +Initial configurations are enqueued and the algorithm loops until the queue becomes empty. +At each iteration it dequeues configuration $(q, o, u, r)$ and scans $\epsilon$-transitions from state $q$. +For transition $(q, \Xund, \gamma, p)$ it constructs a new configuration $(p, o, v, r)$ +that combines $u$ and $\gamma$ in an extended path $v$. +If the resulting set contains another configuration for state $p$, +then the algorithm choses configuration which has a better path from POSIX perspective. +Otherwise it adds the new configuration to the resulting set. If the resulting set was changed, the new configuration is enqueued for further scanning. Eventually all states in $\epsilon$-closure are explored, no improvements can be made, and the algorithm terminates. \\ -%The $\epsilon$-closure algorithm has the usual structure of shortest-path finding algorithms. -%It starts with initial set of configurations, empty queue of some sort and an empty set of resulting configurations $R$. -%All initial configurations are enqueued and the algorithm loops until the queue becomes empty. -%At each iteration of the loop it dequeues some configuration $(q, o, u, r)$ and scans $\epsilon$-transitions from state $q$. -%For each transition $(q, \Xund, \gamma, p)$ it constructs a new configuration $(p, o, v, r)$, where $v$ combines $u$ and $\gamma$. -%If $R$ already has another configuration for state $p$, -%then the algorithm compares configurations and choses one that is better from POSIX perspective. -%Otherwise it just adds the new configuration to $R$. -%If $R$ was changed, the new configuration is enqueued for further scanning. -%Eventually all states in $\epsilon$-closure are explored, no improvements can be made, and the algorithm terminates. -%\\ - \begin{algorithm}[] \DontPrintSemicolon \SetKwProg{Fn}{}{}{} \SetAlgoInsideSkip{medskip} \begin{multicols}{2} @@ -1158,7 +1152,7 @@ Eventually all states in $\epsilon$-closure are explored, no improvements can be \BlankLine \Fn {$\underline{less (x, y, C)} \smallskip$} { - $(\Xund, \Xund, l) = compare (x, y, H, B, D)$ \; + $(\Xund, \Xund, l) = compare (x, y, N, U, B, D)$ \; \Return $l < 0$ } \BlankLine @@ -1182,22 +1176,25 @@ $\YC$ is the set of all configurations.} \end{algorithm} -An important property of the algorithm is that it finds non-looping paths before looping ones (as many graph traversal algorithms do). +Importantly, the algorithm finds non-looping paths before looping ones. Given that, and using lemma \ref{lemma_closure_minpaths}, we can show by induction on path length that the paths constructed at each step of the algorithm do not contain $\epsilon$-loops. This means that for any two paths explored by the algorithm, at most one path may contain tagged $\epsilon$-loop (and only one loop), which justifies the application of lemma \ref{lemma_closure_rightdist}. % -Note that for paths with multiple $\epsilon$-loops right distributivity may not hold: -it is possible to have paths +(Note that for paths with multiple $\epsilon$-loops right distributivity may not hold: +we may have paths $\pi_\alpha = q_0 \overset {u | \alpha} {\rightsquigarrow} q_1$, $\pi_\beta = q_1 \overset {\epsilon | \beta} {\rightsquigarrow} q_1$ and $\pi_\gamma = q_1 \overset {\epsilon | \gamma} {\rightsquigarrow} q_1$, -where $\pi_\beta$ and $\pi_\gamma$ are two different $\epsilon$-loops through the same subautomaton -and $\pi_\alpha \pi_\beta < \pi_\alpha \pi_\gamma$. -In this case, on one hand $\pi_\alpha < \pi_\alpha \pi_\beta$ because the first is a proper prefix of the second, -but on the other hand $\pi_\alpha \pi_\gamma < \pi_\alpha \pi_\beta \pi_\gamma$ by assumption that $\pi_\beta < \pi_\gamma$. +such that $\pi_\beta$ and $\pi_\gamma$ are two different $\epsilon$-loops through the same subautomaton +and $\pi_\alpha \pi_\beta < \pi_\alpha \pi_\gamma$: +in this case $\pi_\alpha \pi_\beta \pi_\gamma < \pi_\alpha \pi_\gamma$, +but $\pi_\alpha \pi_\beta > \pi_\alpha$, because the first is a proper prefix of the second.) +% +Lemma \ref{lemma_closure_rightdist} allows us to skip comparison in non-join states (with in-degree 1), because +any path to such state is formed by concatenation of the unique transition and the shortest known path to the previous state. \\ @@ -1358,7 +1355,10 @@ In this section we show two ways to construct match results: POSIX offsets and a In the first case, $r$-component of configurations is an array of offset pairs $pmatch$. Offsets are updated incrementally at each step by scanning the corresponding path fragment and setting negative tags to $-1$ and positive tags to the current step number. -We need the the most recent value of each tag, therefore we take care to update each tag at most once. +We need the most recent value of each tag, therefore we take care to update tags at most once. +Negative tags allow us to skip initialization of offsets. +Helper function $sub(T, t)$ maps each tag to the corresponding submatch group +(it returns the second component $k$ for $(t, k) \in T$). % In the second case, $r$-component of configurations is a tagged string that is accumulated at each step, and eventually converted to a parse tree at the end of match. @@ -1374,37 +1374,38 @@ but this is more complex and the partial trees may require even more space than \setstretch{0.8} \Fn {$\underline{initial \Xund result (T)} \smallskip$} { - \For {$i = \overline {0, |T| / 2}$} { - $pmatch[i].rm \Xund so = -1$ \; - $pmatch[i].rm \Xund eo = -1$ \; - } - \Return $pmatch$ \; + $n = max \{ sub(T, t) \mid t \in \YN \}$ \; + \Return uninitialized $n$-array of pairs $(rm \Xund so, rm \Xund eo)$\; } \BlankLine + \BlankLine - \Fn {$\underline{update \Xund result (X, U, k, \Xund)} \smallskip$} { - \Return $\big\{ (q, o, u, set \Xund tags (U, u, r, k)) \mid (q, o, u, r) \in X \big\}$ \; + \Fn {$\underline{update \Xund result (T, X, U, k, \Xund)} \smallskip$} { + \Return $\big\{ (q, o, u, set \Xund tags (T, U, u, r, k))$ \; + \Indp\Indp\Indp\Indp\Indp\Indp\Indp\Indp $\mid (q, o, u, r) \in X \big\}$ \; \Indm\Indm\Indm\Indm\Indm\Indm\Indm\Indm } \BlankLine + \BlankLine - \Fn {$\underline{f\!inal \Xund result (u, r, k)} \smallskip$} { - $pmatch = set \Xund tags (U, u, r, k)$ \; + \Fn {$\underline{f\!inal \Xund result (T, U, u, r, k)} \smallskip$} { + $pmatch = set \Xund tags (T, U, u, r, k)$ \; $pmatch[0].rm \Xund so = 0$ \; $pmatch[0].rm \Xund eo = k$ \; \Return $pmatch$ \; } \BlankLine + \BlankLine - \Fn {$\underline{set \Xund tags (U, n, pmatch, k)} \smallskip$} { - $done(t) \equiv f\!alse$ \; + \Fn {$\underline{set \Xund tags (T, U, n, pmatch, k)} \smallskip$} { + $done(\Xund) \equiv f\!alse$ \; \While {$n \neq 0$} { - $t = tag(U, n)$ \; - \If {$\neg done(|t|)$} { - $done(|t|) = true$ \; - \lIf {$t_i < 0$} {$l = -1$} + $t = tag(U, n), \; s = sub(T, |t|)$ \; + \If {$s \neq 0 \wedge \neg done(s)$} { + $done(s) = true$ \; + \lIf {$t < 0$} {$l = -1$} \lElse {$l = k$} - \lIf {$t_i mod \, 2 \equiv 0$} {$pmatch[|t_i|/2].rm \Xund eo = l$} - \lElse {$pmatch[(|t_i| \!+\! 1)/2].rm \Xund so = l$} + \lIf {$t \, mod \, 2 \equiv 1$} {$pmatch[s].rm \Xund so = l$} + \lElse {$pmatch[s].rm \Xund eo = l$} } $n = pred(U, n)$ \; } @@ -1422,13 +1423,14 @@ but this is more complex and the partial trees may require even more space than \BlankLine \BlankLine - \Fn {$\underline{update \Xund result (X, U, \Xund, \alpha)} \smallskip$} { - \Return $\big\{ (q, o, u, r \cdot unroll \Xund path (U, u) \cdot \alpha) \mid (q, o, u, r) \in X \big\}$ \; + \Fn {$\underline{update \Xund result (\Xund, X, U, \Xund, \alpha)} \smallskip$} { + \Return $\big\{ (q, o, u, r \cdot unroll \Xund path (U, u) \cdot \alpha)$ \; + \Indp\Indp\Indp\Indp\Indp\Indp\Indp\Indp $\mid (q, o, u, r) \in X \big\}$ \; \Indm\Indm\Indm\Indm\Indm\Indm\Indm\Indm } \BlankLine \BlankLine - \Fn {$\underline{f\!inal \Xund result (U, u, r, \Xund)} \smallskip$} { + \Fn {$\underline{f\!inal \Xund result (\Xund, U, u, r, \Xund)} \smallskip$} { \Return $parse \Xund tree (r \cdot unroll \Xund path (U, u), 1)$ \; } \BlankLine @@ -1471,18 +1473,25 @@ but this is more complex and the partial trees may require even more space than \section{Disambiguation procedures}\label{section_comparison} -Now that we have defined comparison of TNFA paths through comparison of their induced PE fragments -(definition \ref{pe_order}) -and specified path representation (section \ref{section_pathtree}), -we can finally give disambiguation procedures $compare ()$ and $update \Xund ptables ()$. +In this section we define disambiguation procedures $compare ()$ and $update \Xund ptables ()$. +The pseudocode follows definition \ref{pe_order} closely +and relies on the prefix tree representation of paths given in section \ref{section_results}. +% +In order to find fork of two paths in $compare ()$ we use so-called ``two-fingers'' algorithm, +which is based on the observation that parent index is always less than child index. +Given two indices $n_1$ and $n_2$, we continuously set the greater index to its parent until the indices become equal, +at which point we have either found fork or the root of $U$-tree. +We track minimal height of each path along the way +and memorize the pair of indices right after the fork --- they are used to determine the leftmost path in case of equal heights. % +We assume the existence of helper function $height(T, t)$ that maps each tag to its height. \\ \begin{algorithm}[H] \DontPrintSemicolon \SetKwProg{Fn}{}{}{} \SetAlgoInsideSkip{medskip} \begin{multicols}{2} \setstretch{0.8} - \Fn {$\underline {compare ((\Xund, o_1, n_1, \Xund), (\Xund, o_2, n_2, \Xund), U, B, D)} \smallskip$} { + \Fn {$\underline {compare (N, (\Xund, o_1, n_1, \Xund), (\Xund, o_2, n_2, \Xund), U, B, D)} \smallskip$} { \If { $o_1 = o_2 \wedge n_1 = n_2$ } { \Return $(\infty, \infty, 0)$ } @@ -1499,17 +1508,17 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta $m_1 = m_2 = \bot$ \; \While {$n_1 \neq n_2$} { \If {$n_1 > n_2$} { - $h_1 = min(h_1, height(U, n_1))$ \; + $h_1 = min(h_1, height(T, tag(U, n_1)))$ \; $m_1 = n_1, n_1 = pred(U, n_1)$ \; } \Else { - $h_2 = min(h_2, height(U, n_2))$ \; + $h_2 = min(h_2, height(T, tag(U, n_2)))$ \; $m_2 = n_2, n_2 = pred(U, n_2)$ \; } } \If {$n_1 \neq \bot$} { - $h_1 = min(h_1, height(U, n_1))$ \; - $h_2 = min(h_2, height(U, n_1))$ \; + $h = height(T, tag(U, n_1))$ \; + $h_1 = min(h_1, h), \; h_2 = min(h_2, h)$ \; } \BlankLine @@ -1548,10 +1557,10 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta \BlankLine \BlankLine - \Fn {$\underline {update \Xund ptables (X, U, B, D)} \smallskip$} { + \Fn {$\underline {update \Xund ptables (N, X, U, B, D)} \smallskip$} { \For {$x_1 = (q_1, \Xund, \Xund, \Xund) \in X$} { \For {$x_2 = (q_2, \Xund, \Xund, \Xund) \in X$} { - $(h_1, h_2, l) = compare (x_1, x_2, U, B, D)$ \; + $(h_1, h_2, l) = compare (x_1, x_2, N, U, B, D)$ \; $B' [q_1] [q_2] = h_1, \; D' [q_1] [q_2] = l$ \; $B' [q_2] [q_1] = h_2, \; D' [q_2] [q_1] = -l$ } @@ -1563,25 +1572,24 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta \vfill \columnbreak - \Fn {$\underline {update \Xund ptables (X, U, B, D)} \smallskip$} { - $n_0 = root(H), \; i = 0, \; next(n) = 1 \; \forall n$ \; - $push(S, n_0)$ \; + \Fn {$\underline {update \Xund ptables (N, X, U, B, D)} \smallskip$} { + $i = 0, \; next(n) \equiv 1, \; \text{empty stack } S, \; \text{empty array } L$ \; + $push(S, 0)$ \; \BlankLine \While {$S$ is not empty} { $n = pop(S)$ \; - $\{m_1, \hdots, m_k \} = succ(H, n)$ \; \BlankLine \If {$next(n) < k$} { $push(S, n)$ \; - $push(S, m_{next(n)})$ \; + $push(S, succ(U, n)_{next(n)})$ \; $next(n) = next(n) + 1$ \; $continue$ \; } \BlankLine - $h = height(U, n), \; i_1 = i$ \; + $h = height(T, tag(U, n)), \; i_1 = i$ \; \BlankLine \For {$(q, o, n_1, \Xund) \in X \mid n_1 = n$} { @@ -1593,7 +1601,7 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta $(q_2, o_2, \Xund, \Xund) = L[j_2]$ \; \BlankLine - \If {$n = n_0 \wedge o_1 \neq o_2$} { + \If {$n = 0 \wedge o_1 \neq o_2$} { $h_1 = B[o_1][o_2]$ \; $h_2 = B[o_2][o_1]$ \; $l = D[o_1][o_2]$ \; @@ -1609,7 +1617,7 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta } \BlankLine - \For {$m \in \{m_k, \dots, m_1 \}$} { + \For {$m \in succ(U, n)$ in reverse} { $i_2 = i_1$ \; \lWhile {$i_2 > 0 \wedge L[i_2].n = m$} { $i_2 = i_2 - 1$ @@ -1625,7 +1633,7 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta $(q_2, o_2, n_2, h_2) = L[j_2]$ \; \BlankLine - \If {$n = n_0 \wedge o_1 \neq o_2$} { + \If {$n = 0 \wedge o_1 \neq o_2$} { $h_1 = min(h_1, B[o_1][o_2])$ \; $h_2 = min(h_2, B[o_2][o_1])$ \; } @@ -1654,47 +1662,77 @@ we can finally give disambiguation procedures $compare ()$ and $update \Xund pta \end{multicols} \vspace{1em} -\caption{Comparison of tag histories.} +\caption{Disambiguation procedures.} \end{algorithm} \medskip We give two alternative algorithms for $update \Xund ptables ()$: -a simple one with $O(m^2 \, t)$ complexity and a complex one with $O(m^2)$ complexity. -Worst case is demonstrated by RE $((a|\epsilon)^{0,n})^{0,\infty}$ where $n \in \YN$, -for which simple algorithms takes $O(n^3)$ time and complex algorithms takes $O(n^2)$ time. +a simple one with $O(m^2 \, t)$ complexity (on the left) and a complex one with $O(m^2)$ complexity (on the right). +Worst case is demonstrated by RE $((a|\epsilon)^{0,k})^{0,\infty}$ where $n \in \YN$, +for which the simple algorithm takes $O(k^3)$ time and the complex algorithm takes $O(k^2)$ time. % The idea of complex algorithm is to avoid repeated rescanning of path prefixes in the $U$-tree. It makes one pass over the tree, -constructing an array $L$ of \emph{level items} $(q, o, n, h)$, where +constructing an array $L$ of \emph{level items} $(q, o, u, h)$, where $q$ and $o$ are state and origin as in configurations, -$n$ is the current tree index and $h$ is the current minimal height. +$u$ is the current tree index and $h$ is the current minimal height. One item is added per each closure configuration $(q, o, u, r)$ when traversal reaches tree node with index $u$. After a subtree has been traversed, -the algorithm scans level items corresponding to this subtree, -sets their $h$-component to the minimum of $h$ and the height of current node, -and updates $B$ and $D$ matrices for each pair of $q$-states in items from different branches. -After that, $n$-component of all scanned items is downgraded to tree index of current node +the algorithm scans level items added during traversal of this subtree (such items are distinguished by their $u$-component), +sets their $h$-component to the minimum of $h$ and the height of tag at the current node, +and computes the new value of $B$ and $D$ matrices for each pair of $q$-states in items from different branches. +After that, $u$-component of all scanned items is downgraded to the tree index of current node (erasing the difference between items from different branches). \\ \section{TNFA construction}\label{section_tnfa} -TNFA construction is given by the $F$ function defined on figure \ref{fig_tnfa}. +TNFA construction is given by the function $tn\!f\!a()$ +that accepts IRE $r$ and state $y$, and returns TNFA for $r$ with final state $y$ +(algorithm \ref{alg_tnfa}). +% +This precise construction is not necessary for the algorithms to work, +but it has a number of important properties. +\\[-0.5em] -\begin{figure*} -\begin{multicols}{2} -\fontsize{8}{10} - \setstretch{0.8} +\begin{itemize}[itemsep=0.5em] + \item Non-essential $\epsilon$-transitions are reduced, as they make closure algorithms slower. + + \item Bounded repetition $r^{n,m}$ is unrolled in a way + that duplicates $r$ exactly $m$ times %(fewer is not possible, unless automata with counters are used) + and factors out common path prefixes: + subautomaton for $(k+1)$-th iteration is only reachable from subautomaton for $k$-th iteration. + For example, $a^{2,5}$ is unrolled as $aa(\epsilon | a (\epsilon | a (\epsilon | a)))$, not as $aa(\epsilon|a|aa|aaa)$. + This ensures that the tag tree build by $\epsilon$-closure is a prefix tree. + + \item Priorities are assigned so as to make it more likely + that depth-first traversal of the $\epsilon$-closure will find short paths before long paths. + POSIX has four main rules: (1) longest, (2) leftmost, (3) no optional empty repetitions, and (4) empty match is better than no match. + We cannot accommodate (1) with priorities, but we can accommodate (2), (4) and to some extent (3). + This makes a great difference for GOR1 in pathological cases + like $(((\epsilon)^{0,100})^{0,100})^{0,100})$, + where there are many ambiguous paths with equal height. + If GOR1 finds the shortest path early, then all other paths are just cancelled at the nearest join point, + but in the opposite case GOR1 has to schedule configurations for re-scan after every improvement. + Arguably this bias is a weakness of GOR1, and GTOP is more robust in this respect. + + \item Negative tags include tags for all nested subexpressions, in no particular order. + Such tags are not needed for disambiguation (only the topmost pair is used), + but they are necessary to reset submatch values that remain from previous iterations. + + \item Passing the final state $y$ in $tn\!f\!a()$ function + allows to link subautomata in a simple way. + \\ +\end{itemize} - %\fontsize{9.5pt}{11.5pt}\selectfont +\begin{algorithm}[] \DontPrintSemicolon \SetKwProg{Fn}{}{}{} \label{alg_tnfa} +\begin{multicols}{2} +\setstretch{0.9} - %\newcommand \retonfa {re \Xund to \Xund n\!f\!a} - %\newcommand \ntag {neg \Xund tag} - \newcommand \retonfa {F} - \newcommand \ntag {N} + \newcommand \retonfa {tn\!f\!a} + \newcommand \ntag {ntags} - \begin{algorithm}[H] \DontPrintSemicolon \SetKwProg{Fn}{}{}{} \Fn {$\underline{\retonfa(r, y)} \smallskip$} { \If {$r = (0, 0, \epsilon)$} { \Return $(\Sigma, \{y\}, \emptyset, \emptyset, y, y)$ @@ -1704,115 +1742,83 @@ TNFA construction is given by the $F$ function defined on figure \ref{fig_tnfa}. \Return $(\Sigma, \{x,y\}, \emptyset, \{(x, \alpha, \epsilon, y)\}, x, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s \cdot u)$} { - $(\Sigma, Q_s, T_s, \Delta_1, x, y) = \retonfa (s, y)$ \; - $(\Sigma, Q_u, T_u, \Delta_2, z, x) = \retonfa (u, x)$ \; - \Return $(\Sigma, Q_s \cup Q_u, T_s \cup T_u, \Delta_s \cup \Delta_u, z, y)$ + \ElseIf {$r = (0, 0, r_1 \cdot r_2)$} { + $(\Sigma, Q_2, T_2, \Delta_2, x, y) = \retonfa (r_2, y)$ \; + $(\Sigma, Q_u, T_u, \Delta_2, z, x) = \retonfa (r_1, x)$ \; + \Return $(\Sigma, Q_1 \cup Q_2, T_1 \cup T_2, \Delta_1 \cup \Delta_2, z, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s \mid u)$} { - $(\Sigma, Q_1, T_1, \Delta_1, x_1, y) = \ntag (u, y)$ \; - $(\Sigma, Q_2, T_2, \Delta_2, x_2, x_1) = \retonfa (s, x_1)$ \; - $(\Sigma, Q_3, T_3, \Delta_3, x_3, y) = \retonfa (u, y)$ \; - $(\Sigma, Q_4, T_4, \Delta_4, x_4, x_3) = \ntag (s, x_3)$ \; - $Q = Q_1 \cup Q_2 \cup Q_3 \cup Q_4 \cup \{x\}$ \; - $T = T_1 \cup T_2 \cup T_3 \cup T_4$ \; - $\Delta = \Delta_1 \cup \Delta_2 \cup \Delta_3 \cup \Delta_4 \cup \{(x,1,\epsilon,x_2), (x,2,\epsilon,x_4)\}$ \; - \Return $(\Sigma, Q, T, \Delta, x, y)$ + \ElseIf {$r = (0, 0, r_1 \mid r_2)$} { + $(\Sigma, Q_2, T_2, \Delta_2, x_2, y) = \retonfa (r_2, y)$ \; + $(\Sigma, Q'_2, T_2, \Delta'_2, x'_2, y) = \ntag (T_2, y)$ \; + $(\Sigma, Q_1, T_1, \Delta_1, x_1, x'_2) = \retonfa (r_2, x'_2)$ \; + $(\Sigma, Q'_1, T_1, \Delta'_1, x'_1, x_2) = \ntag (T_1, x_2)$ \; + $Q = Q_1 \cup Q'_1 \cup Q_2 \cup Q'_2 \cup \{x\}$ \; + $\Delta = \Delta_1 \cup \Delta'_1 \cup \Delta_2 \cup \Delta'_2 \cup \big\{ (x,1,\epsilon,x_1), (x,2,\epsilon,x'_1) \big\}$ \; + \Return $(\Sigma, Q, T_1 \cup T_2, \Delta, x, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s^{n,m}) \mid_{n > 0}$} { - $(\Sigma, Q_1, T_1, \Delta_1, x, y) = \retonfa ((0, 0, s^{n-1,m}), y)$ \; - $(\Sigma, Q_2, T_2, \Delta_2, z, x) = \retonfa (s, x)$ \; + \ElseIf {$r = (0, 0, r_1^{n,m}) \mid_{1 < n \leq m \leq \infty}$} { + $(\Sigma, Q_1, T_1, \Delta_1, x, y) = \retonfa ((0, 0, r_1^{n-1,m-1}), y)$ \; + $(\Sigma, Q_2, T_2, \Delta_2, z, x) = \retonfa (r_1, x)$ \; \Return $(\Sigma, Q_1 \cup Q_2, T_1 \cup T_2, \Delta_1 \cup \Delta_2, z, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s^{0,m})$} { - $(\Sigma, Q_1, T_1, \Delta_1, x_1, y) = \retonfa ((0, 0, s^{1,m}), y)$ \; - $(\Sigma, Q_2, T_2, \Delta_2, x_2, y) = \ntag (s, y)$ \; - $Q = Q_1 \cup Q_2 \cup \{x\}$ \; - $\Delta = \Delta_1 \cup \Delta_2 \cup \{(x,1,\epsilon,x_1), (x,2,\epsilon,x_2)\}$ \; - \Return $(\Sigma, Q, T_1 \cup T_2, \Delta, x, y)$ + \ElseIf {$r = (0, 0, r_1^{0,m})$} { + $(\Sigma, Q_1, T_1, \Delta_1, x_1, y) = \retonfa ((0, 0, r_1^{1,m}), y)$ \; + $(\Sigma, Q'_1, T_1, \Delta'_1, x'_1, y) = \ntag (T_1, y)$ \; + $Q = Q_1 \cup Q'_1 \cup \{x\}$ \; + $\Delta = \Delta_1 \cup \Delta'_1 \cup \big\{ (x, 1, \epsilon, x_1), (x, 2, \epsilon, x'_1) \big\}$ \; + \Return $(\Sigma, Q, T_1, \Delta, x, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s^{1,\infty})$} { - $(\Sigma, Q_1, T_1, \Delta_1, z, x) = \retonfa (s, \Xund)$ \; + \ElseIf {$r = (0, 0, r_1^{1,\infty})$} { + $(\Sigma, Q_1, T_1, \Delta_1, z, x) = \retonfa (r_1, \Xund)$ \; $Q = Q_1 \cup \{y\}$ \; - $\Delta = \Delta_1 \cup \{(x,1,\epsilon,z), (x,2,\epsilon,y)\}$ \; + $\Delta = \Delta_1 \cup \big\{ (x, 1, \epsilon, z), (x, 2, \epsilon, y) \big\}$ \; \Return $(\Sigma, Q, T_1, \Delta, z, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s^{1,1})$} { - \Return $\retonfa (s, y)$ + \ElseIf {$r = (0, 0, r_1^{1,1})$} { + \Return $\retonfa (r_1, y)$ } \BlankLine - \ElseIf {$r = (0, 0, s^{1,m}) \mid_{1 < m < \infty}$} { - $(\Sigma, Q_1, T_1, \Delta_1, x, y) = \retonfa ((0, 0, s^{1,m-1}), y)$ \; - $(\Sigma, Q_2, T_2, \Delta_2, w, z) = \retonfa (r_1, \Xund)$ \; - $\Delta = \Delta_1 \cup \Delta_2 \cup \{(z,1,\epsilon,y), (z,2,\epsilon,x)\}$ \; + \ElseIf {$r = (0, 0, r_1^{1,m}) \mid_{1 < m < \infty}$} { + $(\Sigma, Q_1, T_1, \Delta_1, x, y) = \retonfa ((0, 0, r_1^{1,m-1}), y)$ \; + $(\Sigma, Q_2, T_2, \Delta_2, w, z) = \retonfa (r_1, z)$ \; + $\Delta = \Delta_1 \cup \Delta_2 \cup \big\{ (z, 1, \epsilon, y), (z, 2, \epsilon, x) \big\}$ \; \Return $(\Sigma, Q_1 \cup Q_2, T_1 \cup T_2, \Delta, w, y)$ } \BlankLine - \ElseIf {$r = (i, \Xund, s) \mid_{i \neq 0}$} { - $(\Sigma, Q_1, T_1, \Delta_1, z, x) = \retonfa (s, \Xund)$ \; + \ElseIf {$r = (i, j, r_1) \mid_{i \neq 0}$} { + $(\Sigma, Q_1, T_1, \Delta_1, z, x) = \retonfa ((0, 0, r_1), x)$ \; $Q = Q_1 \cup \{w, y\}$ \; - $T = T_1 \cup \{2i\!-\!1, 2i\}$ \; - $\Delta = \Delta_1 \cup \{(w,1,2i\!-\!1,z), (x,1,2i,y)\}$ \; + $T = T_1 \cup \big\{ (2i\!-\!1, j), (2i, j) \big\}$ \; + $\Delta = \Delta_1 \cup \big\{ (w, 1, 2i\!-\!1, z), (x, 1, 2i, y) \big\}$ \; \Return $(\Sigma, Q, T, \Delta, w, y)$ } } - \end{algorithm} - - - \begin{algorithm}[H] \DontPrintSemicolon \SetKwProg{Fn}{}{}{} - \Fn {$\underline{\ntag(r)} \smallskip$} { - $T = \{ t_1, \dots, t_n \} = T(r), n \geq 0$ \; - $Q = \{x_0, \dots, x_{2n}\}$ \; - $\Delta = \{(x_{2i-2},1,1\!-\!2t_i, x_{2i-1}), (x_{2(n-i)-1}, 1, -\!2t_i, x_{2(n - i)})\}_{i=1}^{n}$ \; - \Return $(\Sigma, Q, T, \Delta, x_0, x_{2n})$ \; - } - \end{algorithm} - + \BlankLine + \BlankLine - \begin{algorithm}[H] \DontPrintSemicolon \SetKwProg{Fn}{}{}{} - \Fn {$\underline{T((i, \Xund, r))} \smallskip$} { - \lIf {$i = 0$} { - \Return $\emptyset$ - } - \lElseIf {$r = s \mid u \vee r = s \cdot u$} { - \Return $\{i\} \cup T(s) \cup T(u)$ - } - \lElseIf {$r = s^{n,m}$} { - \Return $\{i\} \cup T(s)$ - } - \lElse { - \Return $\{i\}$ - } + \Fn {$\underline{\ntag(T, y)} \smallskip$} { + $\big\{ (t_1, \Xund), \hdots, (t_n, \Xund) \big\} = T$ \; + $Q = \{x_0, \dots, x_n, y\}$ \; + $\Delta = \big\{ (x_{i-1},1,-t_i, x_{i}) \big\}_{i=1}^{n}$ \; + \Return $(\Sigma, Q, T, \Delta, x_0, y)$ \; } - \end{algorithm} - - - \columnbreak + \vfill - \includegraphics[width=\linewidth]{img/tnfa_construction.pdf} +\columnbreak + \nonl \includegraphics[width=\linewidth]{img/tnfa_construction.pdf} \end{multicols} -\vspace{-2em} +\vspace{0em} \caption{TNFA construction.} -\end{figure*} - +\end{algorithm} -\iffalse -\begin{figure}\label{fig_tnfa_example} -\includegraphics[width=\linewidth]{img/tnfa_example.pdf} -\vspace{-2em} -\caption{ - Example TNFA for RE $(a|\epsilon)^{0,3}((a^{0,\infty})|(\epsilon))$. -} -\end{figure} -\fi \section*{Appendix}