\documentclass[11pt,twoside]{scrartcl}

%opening
\newcommand{\lecid}{15-414}
\newcommand{\leccourse}{Bug Catching: Automated Program Verification}
\newcommand{\lecdate}{} %e.g. {October 21, 2013}
\newcommand{\lecnum}{20}
\newcommand{\lectitle}{Emptiness Checking, LTL B\"uchi Automata}
\newcommand{\lecturer}{Matt Fredrikson}

\usepackage{lecnotes}

\usepackage[irlabel]{bugcatch}

\usepackage{tikz}
\usetikzlibrary{automata,shapes,positioning,matrix,shapes.callouts,decorations.text,patterns,trees}

\usepackage{listings}
\definecolor{mygray}{rgb}{0.5,0.5,0.5}
\definecolor{backgray}{gray}{0.95}
\lstdefinestyle{whyml}{
  belowcaptionskip=1\baselineskip,
  breaklines=true,
  language=[Objective]Caml,
  showstringspaces=false,
  numbers=left,
  xleftmargin=2em,
  framexleftmargin=1.5em,
  numbersep=5pt,
  numberstyle=\tiny\color{mygray},
  basicstyle=\footnotesize\ttfamily,
  keywordstyle=\color{blue},
  commentstyle=\itshape\color{purple!40!black},
  tabsize=2,
  backgroundcolor=\color{backgray},
  escapechar=\%,
  morekeywords={predicate,invariant}
}


%% \traceget{v}{i}{\zeta} is the state of trace v at time \zeta of the i-th discrete step
\newcommand{\traceget}[3]{{#1}_{#2}(#3)}
\def\limbo{\mathrm{\Lambda}}
%% the last state of a trace
\DeclareMathOperator{\tlast}{last}
%% the first state of a trace
\DeclareMathOperator{\tfirst}{first}

\begin{document}
\lstset{  
  basicstyle=\ttfamily,
  mathescape
}
%% the name of a trace
\newcommand{\atrace}{\sigma}%
%% the standard interpretation naming conventions
\newcommand{\stdI}{\dTLint[state=\omega]}%
\newcommand{\Ip}{\dTLint[trace=\atrace]}%
\def\I{\stdI}%
% \let\tnext\ctnext
% \let\tbox\ctbox
% \let\tdiamond\ctdiamond

\maketitle
\thispagestyle{empty}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\section{Introduction}

We've seen how to check Computation Tree Logic (CTL) formulas against computation structures. The algorithm for doing so directly computes the semantics of formulas, and makes use of the fixpoint properties of monotone functions to derive the set of states in a transition structure that satisfy the formula. We saw in a previous lecture that LTL formulas are defined over traces, of where there are infinitely many in a computation structure, so a similar approach will not work for LTL. 

In this lecture, we will see how to check LTL formulas against computation structures by reducing the problem to checking whether the language defined by a finite automaton is empty. However, because the traces of a computation structure are infinite, we cannot use the familiar tools available for nondeterministic finite automata (NFAs), and instead need to define a new type of automata that can recognize infinite words. These are called B\"uchi automata, and we will see that they have useful properties that can be used to construct effective model checking algorithms for LTL~\cite{Vardi86}.

\section{Review: Transition structures, LTL}

Several lectures ago, we introduced Linear Temporal Logic (LTL). Like CTL, the temporal modalities of LTL allow us to formalize properties that involve time and sequencing. While the semantics of CTL formulas are defined over the states of a transition structure, the truth value of LTL formulas is defined over traces. Definition~\ref{def:ltl-semantics} gives the meaning of an LTL formula over a trace. Definition~\ref{def:ltl-semantics-ts} extends the semantics to transition systems, where we require that for all traces $\atrace$ obtained by running a computation structure $K$, $\atrace \models \ausfml$.

\begin{definition}[LTL semantics (traces)]
  \label{def:ltl-semantics}
  The truth of LTL formulas in a trace $\atrace$ is defined inductively as follows:
  \begin{enumerate}
  \item \(\atrace \models p\) iff \(\atrace_0 \models p\) for atomic propositions $p$ provided that $\atrace_0\neq\limbo$
  \item \(\atrace \models \lnot\ausfml\) iff \(\atrace \nonmodels \ausfml\), i.e. it is not the case that \(\atrace \models \ausfml\)
  \item \(\atrace \models \ausfml\land\busfml\) iff \(\atrace \models \ausfml\) and \(\atrace \models \busfml\)
  \item \(\atrace \models \tnext{\ausfml}\) iff \(\atrace^1 \models \ausfml\)
  \item \(\atrace \models \tbox{\ausfml}\) iff \(\atrace^i \models \ausfml\) for all $i\geq0$
  \item \(\atrace \models \tdiamond{\ausfml}\) iff \(\atrace^i \models \ausfml\) for some $i\geq0$
  \item \(\atrace \models \tuntil{\ausfml}{\busfml}\) iff there is an $i\geq0$ such that \(\atrace^i \models \busfml\) and \(\atrace^j \models \ausfml\) for all $0\leq j<i$
  \end{enumerate}
  In all cases, the truth-value of a formula is, of course, only defined if the respective suffixes of the traces are defined.
\end{definition}

\begin{definition}[LTL semantics (computation structure)]
  \label{def:ltl-semantics-ts}
  Given an LTL formula $\ausfml$ and computation structure $K=(W,\stepto,v)$, $K \models \ausfml$ if and only if $\atrace \models \ausfml$ for all $\atrace$ where $\atrace_i = v(s_i)$ for some path $s_0,s_1,s_2,\ldots$ in $K$.
\end{definition}

\begin{definition}[LTL Semantics (language over traces)]
\label{def:ltl-lang}
Let $\ausfml$ be an LTL formula and $\Sigma$ a set of atomic propositions. Then the language of $\ausfml$ is defined as:
\[
\flang{\ausfml} = \{\atrace \in \Sigma^\omega \with \atrace \models \ausfml\}
\]
where $\Sigma^\omega$ is the set of infinite strings over $\Sigma$, and the truth relation $\models$ is defined inductively in Definition~\ref{def:ltl-semantics}.
\end{definition}

\begin{definition}[Language of a computation structure]
Let $K = (W,\stepto,v)$ be a computation structure defined over a set of atomic propositions $\Sigma$. Then the language of $K$, denoted $\ttraces{K}$, is:
$
\ttraces{K} = \{\atrace \in \Sigma^\omega \with s_0,s_1,\ldots~\text{a path in}~K~\text{and}~\atrace_i=v(s_i)\}
$.
\end{definition}

By defining languages for LTL formulas and computation structures, we can case the LTL model checking problem as one of language inclusion.

\begin{equation}
\label{eq:inclusion}
\ttraces{K} \subseteq \flang{\ausfml}
\end{equation}
Equation~\ref{eq:inclusion} equivalent to saying that all of the behaviors of $K$ are among the set of behaviors that are allowed by $\ausfml$.
How can we check whether Equation~\ref{eq:inclusion} holds for a given $K$ and $\ausfml$? Suppose for the moment that $\ttraces{K}$ and $\flang{\ausfml}$ were regular languages containing only finite words. Then we could exploit the fact that regular languages are closed under intersection and complementation, in addition to the following fact (see \cite{BaierKL08} or for a proof):
\begin{equation}
\label{eq:inclusion-empty}
\ttraces{K} \subseteq \flang{\ausfml}~\text{if and only if}~\ttraces{K} \cap \overline{\flang{\ausfml}} = \emptyset
\end{equation}

We then defined a type of automaton that characterizes languages with infinite words.

\begin{definition}[Nondeterministic B\"uchi Automaton (NBA)]
\label{def:buchi}
A nondeterministic B\"uchi automaton $A$ is a tuple $A = (Q, \Sigma, \delta, Q_0, F)$ where:
\begin{enumerate}
\item $Q$ is a \textbf{finite} set of states.
\item $\Sigma$ is an alphabet.
\item $\delta : Q \times \Sigma \to \powerset{Q}$ is a transition function.
\item $Q_0 \subseteq Q$ is a set of initial states
\item $F \subseteq Q$ is a set of accepting states, which we sometimes call the \emph{acceptance set}.
\end{enumerate}
A run for (infinite) trace $\sigma = \sigma_0,\sigma_1,\sigma_2,\ldots$ is an infinite sequence of states $q_0,q_1,q_2,\ldots$ in $Q$ such that $q_0 \in Q_0$ and $q_{i+1} \in \delta(q_i,\sigma_i)$ for all $i \ge 0$. A run $q_0,q_1,q_2,\ldots$ is accepting if $q_i \in F$ for \textbf{infinitely many indices} $i \ge 0$. The language of $A$ is:
\[
\flang{A} = \{\sigma \in \Sigma^\omega \with \text{there exists an accepting run for}~\sigma~\text{in}~A\}
\]
In the above, $\Sigma^\omega$ is the set of all infinite words over alphabet symbols in $\Sigma$.
\end{definition}

\paragraph{Running example}

We demonstrated the concepts and ideas from the previous lecture on a running example of a mutual exclusion protocol. The computation corresponded to the following NBA.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={accepting,draw,black,circle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140},
   level 1/.style={sibling distance=50mm},
   level 2/.style={sibling distance=40mm},
   level 3/.style={sibling distance=30mm},
   level 4/.style={sibling angle=-30}]
  \node[state node] (iota) {$\iota$}
  child {
    node[state node] (q0) {$q_0$}
    child {
      node[state node] (q1) {$q_1$}
      child { node[state node] (q2) {$q_2$} child[missing] {node{}} child {node[state node] (q4) {$q_4$}} }
      child { node[state node] (q3) {$q_3$} }
    }
    child {
      node[state node] (q5) {$q_5$}
      child { node[state node] (q6) {$q_6$} child[missing] {node{}}  child {node[state node] (q8) {$q_8$}}  }
      child { node[state node] (q7) {$q_7$} }
    }
  };
  \draw[<-] (iota) -- +(90:1);
  \draw (iota) to node[left] {nn} (q0);
  \draw (q0) to node[left] {tn} (q1);
  \draw (q0) to node[right] {nt} (q5);
  \draw (q3) to node[right] {ct} (q4);
  \draw (q6) to node[left] {tc} (q8);
  \draw (q7) to node[right] {tc} (q8);
  \draw (q1) to node[right] {cn} (q2);
  \draw (q1) to node[left] {tt} (q3);
  \draw (q2) to node[left] {ct} (q4);
  \draw (q5) to node[right] {tt} (q6);
  \draw (q5) to node[left] {nc} (q7);
  \draw (q4) to[bend left=40] node[right] {nt} (q5);
  \draw (q8) to[bend right=40] node[left] {tn} (q1);
  \draw (q2) to[bend left=40] node[left] {nn} (q0);
  \draw (q7) to[bend right=40] node[right] {nn} (q0);
\end{tikzpicture}
\end{center}

We wrote two useful properties for this computation.
\begin{itemize}
\item The mutual exclusion safety property $\tbox{(\lnot c_1 \lor \lnot c_2)}$ characterizes traces where it is never the case that both processes are in the critical section at the same time. Equivalently, traces where at all times it is true that either $\lnot c_1$ or $\lnot c_2$.

\item The liveness property $\tbox{(t_1 \limply \tdiamond{c_1})} \land \tbox{(t_2 \limply \tdiamond{c_2})}$ characterizes traces that satisfy the requirement that whenever a process tries to enter its critical section ($t_i$ is true), it eventually succeeds ($c_i$ becomes true).
\end{itemize}

We found that the safety property gives the following NBA.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node,accepting] (q0) {$q_0$};
  \node[state node,right=7em of q0] (q1) {$q_1$};
  % \node[label=above right:0] (m) {nn}
  \draw[<-] (q0) -- +(90:1);
  \draw (q0) to node [above] {$c_1 \land c_2$} (q1);
  \draw (q0) to [out=290,in=250,looseness=8] node [below] {$\lnot c_1 \lor \lnot c_2$} (q0);
  \draw (q1) to [out=290,in=250,looseness=8] node [below] {$\ltrue$} (q1);
\end{tikzpicture}
\end{center}

Its complement was easy to obtain as well.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) {$q_0$};
  \node[state node,right=7em of q0,accepting] (q1) {$q_1$};
  % \node[label=above right:0] (m) {nn}
  \draw[<-] (q0) -- +(90:1);
  \draw (q0) to node [above] {$c_1 \land c_2$} (q1);
  \draw (q0) to [out=290,in=250,looseness=8] node [below] {$\lnot c_1 \lor \lnot c_2$} (q0);
  \draw (q1) to [out=290,in=250,looseness=8] node [below] {$\ltrue$} (q1);
\end{tikzpicture}
\end{center}

In order to determine whether the mutual exclusion protocol models this property, we need to construct an automaton for the intersection of their languages.

\section{Intersecting B\"uchi automata with Kripke structures}

As it turns out, NBAs are closed under intersection just as are their NFA counterparts over finite words. The proof of this fact is given directly by construction of a product automaton that accepts exactly the language of the intersection of its components~\cite{ClarkeGrumberg_MC_1999,BaierKL08}. 

While this construction is straightforward, one does need to be careful about the acceptance set of the product NBA. In particular, when taking the product of $A_1 = (Q_1, \Sigma_1, \delta_1, Q^0_1, F_1)$ and $A_2 = (Q_2, \Sigma_2, \delta_2, Q^0_2, F_2)$, we need to ensure that words accepted by $A_1 \cap A_2$ go through states corresponding to $F_1$ and $F_2$ an infinite number of times. To accomplish this, the product construction splits states into three distinct parts ${0,1,2}$ function intuitively as follows:
\begin{enumerate}
\item The product construction has all its initial states in part 0.
\item When entering a state corresponding to $F_1$, the product moves to a state in part 1.
\item When entering a state corresponding to $F_2$, the product moves to a state in part 2.
\item When the product is in a state from part 2, and enters a state not in $F_2$, transition back to a state in part 0.
\end{enumerate}

Further details of this construction are given in \cite{ClarkeGrumberg_MC_1999}. For the purposes of our goals, we can use a simplified product construction that relies on the fact that the NBA obtained from a computation structure has an acceptance set corresponding to its entire state space.

\begin{theorem}
\label{thm:intersect-special}
Given two nondeterministic B\"uchi automata $A_1 = (Q_1, \Sigma, \delta_1, Q^0_1, Q_1)$ and $A_2 = (Q_2, \Sigma, \delta_2, Q^0_2, F)$, the product $A_{1 \cap 2} = (Q_1 \times Q_2, \Sigma, \delta', Q_1^0 \times Q_2^0, Q_1 \times F)$, where $(q_1', q_2') \in \delta'((q_1, q_2), \sigma)$ iff $(q_i') \in \delta_i(q_i, \sigma)$ for $i=1,2$, satisfies $\flang{A_{1 \cap 2}} = \flang{A_1} \cap \flang{A_2}$.
\end{theorem}

To see Theorem~\ref{thm:intersect-special} in action, let's return to the task of checking the mutual exclusion safety property on the NBA corresponding to the mutual exclusion computation structure. We'll start by renaming the states in the NBA for the safety property, and updating the transition labels to make them consistent with those used in the computation structure's NBA.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) {$r_0$};
  \node[state node,right=7em of q0,accepting] (q1) {$r_1$};
  % \node[label=above right:0] (m) {nn}
  \draw[<-] (q0) -- +(90:1);
  \draw (q0) to node [above] {cc} (q1);
  \draw (q0) to [out=290,in=250,looseness=8] node [below] {\{nn,tn,nt,cn,nc,tt,ct,tc\}} (q0);
  \draw (q1) to [out=290,in=250,looseness=8] node [below] {$\ltrue$} (q1);
\end{tikzpicture}
\end{center}
We can now proceed with the intersection. The resulting automaton shown below consists of two disconnected components, the first corresponding to states containing $r_0$ and the second to states containing $r_1$. They are disconnected because in the property NBA, the only transition between $r_0$ and $r_1$ is labeled \textbf{cc}. However, the computation NBA has no transitions labeled \textbf{cc}, and the $\delta'$ from Theorem~\ref{thm:intersect-special} requires corresponding transitions in \emph{both} constituent NBA.
\begin{center}
\begin{minipage}{0.49\textwidth}
\resizebox{\textwidth}{!}{%
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rounded rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140},
   level 1/.style={sibling distance=60mm},
   level 2/.style={sibling distance=55mm},
   level 3/.style={sibling distance=40mm},
   level 4/.style={sibling angle=-30}]
  \node[state node] (iota) {$\iota,r_0$}
  child {
    node[state node] (q0) {$q_0,r_0$}
    child {
      node[state node] (q1) {$q_1,r_0$}
      child { node[state node] (q2) {$q_2,r_0$} child[missing] {node{}} child {node[state node] (q4) {$q_4,r_0$}} }
      child { node[state node] (q3) {$q_3,r_0$} }
    }
    child {
      node[state node] (q5) {$q_5,r_0$}
      child { node[state node] (q6) {$q_6,r_0$} child[missing] {node{}}  child {node[state node] (q8) {$q_8,r_0$}}  }
      child { node[state node] (q7) {$q_7,r_0$} }
    }
  };
  \draw[<-] (iota) -- +(90:1);
  \draw (iota) to node[left] {nn} (q0);
  \draw (q0) to node[left] {tn} (q1);
  \draw (q0) to node[right] {nt} (q5);
  \draw (q3) to node[right] {ct} (q4);
  \draw (q6) to node[left] {tc} (q8);
  \draw (q7) to node[right] {tc} (q8);
  \draw (q1) to node[right] {cn} (q2);
  \draw (q1) to node[left] {tt} (q3);
  \draw (q2) to node[left] {ct} (q4);
  \draw (q5) to node[right] {tt} (q6);
  \draw (q5) to node[left] {nc} (q7);
  \draw (q4) to[bend left=40] node[right] {nt} (q5);
  \draw (q8) to[bend right=40] node[left] {tn} (q1);
  \draw (q2) to[bend left=40] node[left] {nn} (q0);
  \draw (q7) to[bend right=40] node[right] {nn} (q0);
\end{tikzpicture}
}
\end{minipage}
\begin{minipage}{0.49\textwidth}
\resizebox{\textwidth}{!}{%
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={accepting,draw,black,rounded rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140},
   level 1/.style={sibling distance=60mm},
   level 2/.style={sibling distance=55mm},
   level 3/.style={sibling distance=40mm},
   level 4/.style={sibling angle=-30}]
  \node[state node] (iota) {$\iota,r_1$}
  child {
    node[state node] (q0) {$q_0,r_1$}
    child {
      node[state node] (q1) {$q_1,r_1$}
      child { node[state node] (q2) {$q_2,r_1$} child[missing] {node{}} child {node[state node] (q4) {$q_4,r_1$}} }
      child { node[state node] (q3) {$q_3,r_1$} }
    }
    child {
      node[state node] (q5) {$q_5,r_1$}
      child { node[state node] (q6) {$q_6,r_1$} child[missing] {node{}}  child {node[state node] (q8) {$q_8,r_1$}}  }
      child { node[state node] (q7) {$q_7,r_1$} }
    }
  };
  \draw (iota) to node[left] {nn} (q0);
  \draw (q0) to node[left] {tn} (q1);
  \draw (q0) to node[right] {nt} (q5);
  \draw (q3) to node[right] {ct} (q4);
  \draw (q6) to node[left] {tc} (q8);
  \draw (q7) to node[right] {tc} (q8);
  \draw (q1) to node[right] {cn} (q2);
  \draw (q1) to node[left] {tt} (q3);
  \draw (q2) to node[left] {ct} (q4);
  \draw (q5) to node[right] {tt} (q6);
  \draw (q5) to node[left] {nc} (q7);
  \draw (q4) to[bend left=40] node[right] {nt} (q5);
  \draw (q8) to[bend right=40] node[left] {tn} (q1);
  \draw (q2) to[bend left=40] node[left] {nn} (q0);
  \draw (q7) to[bend right=40] node[right] {nn} (q0);
\end{tikzpicture}
}
\end{minipage}
\end{center}
Importantly, the initial state in the product is one containing $r_0$, and the acceptance set consists entirely of those containing $r_1$. It is evident that the language of this NBA is the empty set, which confirms our expectation that the original computation structure satisfies the mutual exclusion safety property.

\section{Emptiness checking via cycle detection}

The previous example was easy to check ``visually'' by inspection, because none of the accepting states were reachable from the single initial state. In general of course this heuristic will not apply, so we need a more general algorithm for determining whether the product NBA corresponds to the empty language.

Consider an NBA $A$ and accepting run $\rho = q_0,q_1,\ldots$. Because $\rho$ is accepting, it contains infinitely many accepting states from $F$, and moreover, because $F \subseteq Q$ is finite, there is some suffix $\rho'$ of $\rho$ such that every state on it appears infinitely many times. In order for this to happen each state in $\rho'$ must be reachable from every other state in $\rho'$, which means that these states comprise a strongly-connected component in $A$. From this we can conclude that any strongly connected component in $A$ that \emph{(1)} is reachable from the initial state, and \emph{(2)} contains at least one accepting state, will generate an accepting run of the automaton. Exploiting this observation, we see that it suffices to use any algorithm for detecting strongly-connected components, such as Tarjan's depth-first search algorithm~\cite{Tarjan72}, for LTL model checking.

The asymptotic complexity of Tarjan's algorithm is $O(|Q|+|\delta|)$, i.e., linear in the number of states and transitions. We can't expect to do better than this in the worst case, but in practice it is not an ideal solution because it always constructs the entire product automaton in memory, and returns each strongly-connected component. This functionality is more than we need for LTL model checking, because it suffices to find just one counterexample to demonstrate that the computation structure fails to satisfy a property.

A notable alternative approach is based on nested depth-first cycle detection algorithm~\cite{Courcoubetis1992}. To see why detecting cycles solves LTL model checking, observe that whenever a reachable strongly-connected component with an accepting state exists in the product NBA, there will necessarily be a cycle from some accepting state back to itself. Given a strongly-connected component with an accepting state, it is always possible to find such a cycle, and the converse clearly holds.

The nested depth-first search routine for emptiness checking, \texttt{isempty} proceeds by enumerating over all of the initial states, calling the \texttt{outerdfs} algorithm on each one. If a cycle is reachable from one of these states, then \texttt{outerdfs} will raise a \texttt{Found} exception terminating execution early. If no exception is raised throughout this enumeration, then \texttt{isempty} returns \texttt{false} to signify that no such cycle exists.
\begin{lstlisting}
    let isempty A =
      let (Q, $\Sigma$, $\delta$, Q${}_0$, F) = A in
      foreach q${}_0$ in Q${}_0$ do
        try
          outerdfs q${}_0$ Nil A
        with Found -> false
      done;
      true
\end{lstlisting}
The first depth-first search implemented in \texttt{outerdfs}, which takes a state from which to begin the search, a list of states that have already been visited in this phase of the search, and the original automaton.
\begin{lstlisting}
    let rec outerdfs q visited A =
      let (Q, $\Sigma$, $\delta$, Q${}_0$, F) = A in
      let visited' = Cons q visited in
      foreach q' in $\delta$(q) do
        if not (mem q visited') then (outerdfs q' visited' A);
      done;
      if (mem q F) then (innerdfs q visited' Nil A)
\end{lstlisting}
\texttt{outerdfs} proceeds recursively in typical depth-first fashion, exploring all immediate successors that have not already been visited by the outer search. When it is ready to backtrack, it calls the nested \texttt{innerdfs} if the state currently being considered is accepting.

Finally, the second DFS search \texttt{innerdfs} takes a state from which to begin searching, the list of states visited by the outer DFS that invoked it, the list of states visited by the current inner DFS, and the automaton.
\begin{lstlisting}
    let rec innerdfs q outervisited innervisited A =
      let (Q, $\Sigma$, $\delta$, Q${}_0$, F) = A in
      let innervisited' = Cons q innervisited in
      foreach q' in $\delta$(q) do
        if (mem q' outervisited) then 
          raise Found
        else 
          if not (mem q' innervisited') then 
            (innerdfs q' outervisited innervisited' A);
      done
\end{lstlisting}
If \texttt{innerdfs} ever encounters a state visited by the invoking \texttt{outerdfs}, then it terminates the search with the result \texttt{Found}. This is correct, because \texttt{innerdfs} is only called from accepting states; because it reached a previously-visited state following transitions, there must be a reachable cycle back to the accepting state from which \texttt{innerdfs} was called. 

We can construct a counterexample to the emptiness claim by extracting a finite prefix from an initial state to a cycle by traversing the visited list of \texttt{outerdfs}. Let $q_1$ be the state from which the call to \texttt{innerdfs} was started, and $q_2$ the state that terminates it. Then the visited list of \texttt{innerdfs} contains cyclical path from $q_1$ to $q_2$. Concatenating this cycle to the finite prefix yields a cycle through an accepting state that is rechable from an initial state, and serves as the counterexample.

Otherwise, \texttt{innerdfs} continues again in recursive depth-first fashion avoiding work by not descending on states which have already been visited by this level of the DFS. If it never encounters a state visited by \texttt{outerdfs}, then it returns without raising an exception.

\section{Translating LTL into B\"uchi automata}

Let's look at how we can convert arbitrary LTL formulas into B\"uchi automata that accept the same language. The approach that we take, which is due to \cite{Gerth1996}, uses some ideas that reduce reasoning about a formula's satisfaction to local reasoning about the current state, along with eventual reasoning about future states. In particular, it makes use of the following expansion axioms.
\begin{align}
\label{eq:until-expand}
\tuntil{\ausfml_1}{\ausfml_2} & \lbisubjunct \ausfml_2 \lor (\ausfml_1 \land \tnext{(\tuntil{\ausfml_1}{\ausfml_2})}) \\
\tdiamond{\ausfml} & \lbisubjunct \ausfml \lor \tnext{\tdiamond{\ausfml}} \\
\tbox{\ausfml} & \lbisubjunct \ausfml \land \tnext{\tbox{\ausfml}}
\end{align}

To perform the LTL-B\"uchi conversion, we will first construct a directed graph whose nodes contain information about the truth value of formulas. To keep track of this information, each node is labeled with three sets of formulas that we will call \old, \now, and \future. The nodes of this graph will become the states in the final NBA, and the formulas in these sets correspond to properties that must be satisfied by traces that enter the corresponding nodes. The distinction between the sets is described as follows.
\begin{description}
\item[\old:] Formulas that have already been processed. As the conversion proceeds, \old will grow to contain all of the formulas relevant to the state corresponding to this node.
\item[\now:] Formulas that have not yet been processed. Eventually, all of the formulas in \now will be processed, and subsequently moved to \old.
\item[\future:] Formulas that must be satisfied by direct successors of states satisfying the properties in \old.
\end{description}
We also keep track of the set of incoming edges at each node.

We'll first see how the conversion works by considering the example formula $R \equiv \tuntil{\ausfml}{\busfml}$. To begin, we create a single node, setting its incoming edges to the special symbol \texttt{init}, as well as $\now = \{\tuntil{\ausfml}{\busfml}\}$, and $\old = \future = \emptyset$.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\emptyset$ \\
      \now: $\{\tuntil{\ausfml}{\busfml}\}$ \\
      \future: $\emptyset$
      \end{tabular}
    };
    \draw[<-] (q0) -- +(90:1);
\end{tikzpicture}
\end{center}

Then at each step, we check the current set of nodes to see if there are remaining formulas to process in $\now$. If there are, then we select a formula from \now to remove from the set and proceed with updating the graph. In the current example, we have one node with one formula $\tuntil{\ausfml}{\busfml}$ in \now. The expansion axiom shown in Eq. \ref{eq:until-expand} tells us that this formula is true either when $\busfml$ holds in the current instant, or $\ausfml$ holds in the current instant and $\tuntil{\ausfml}{\busfml}$ holds at the next instant. We encode this disjunction by splitting the current node into two:
\begin{itemize}
\item In one of the new nodes, $\busfml$ is added to \now. This corresponds to the case where $\busfml$ holds in the current instant.
\item In the other new node, $\ausfml$ is added to \now, and $\tuntil{\ausfml}{\busfml}$ is added to \future. This corresponds to the case where $\ausfml$ holds in the current instant, and $\tuntil{\ausfml}{\busfml}$ in the next.
\end{itemize}
The new state of our graph is:

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}\}$ \\
      \now: $\{\busfml\}$ \\
      \future: $\emptyset$
      \end{tabular}
    };
  \node[state node,right=of q0] (q1) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}\}$ \\
      \now: $\{\ausfml\}$ \\
      \future: $\{\tuntil{\ausfml}{\busfml}\}$
      \end{tabular}
    };   
    \draw[<-] (q0) -- +(90:1);
    \draw[<-] (q1) -- +(90:1);
\end{tikzpicture}
\end{center}

Continuing on, both of the nodes in our graph now contain \now sets comprised of a single literal. When processing a literal from \now, we first check to see if its negation is in \old. If it is, then we discard the current node, because it is a contradiction: no trace can satisfy both $\ausfml \land \lnot\ausfml$. If the negation of the literal is not in \old, then we simply update the graph by removing the literal from \now and adding it to old. This brings our running example to the following graph.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \busfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };
  \node[state node,right=of q0] (q1) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \ausfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\{\tuntil{\ausfml}{\busfml}\}$
      \end{tabular}
    };    
    \draw[<-] (q0) -- +(90:1);
    \draw[<-] (q1) -- +(90:1);    
\end{tikzpicture}
\end{center}

At this point both of the nodes in our graph have empty \now sets. We proceed by selecting a node for which to create a successor, by setting the \now set of the successor to the \future set of the selected node. The \old and \future sets of the successor are initialized to be empty. In the following graph, we have taken this step for both nodes.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \busfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };
  \node[state node,right=of q0] (q1) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \ausfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\{\tuntil{\ausfml}{\busfml}\}$
      \end{tabular}
    }; 
    \node[state node,below=of q1] (q2) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\emptyset$ \\
      \now: $\{\tuntil{\ausfml}{\busfml}\}$ \\
      \future: $\emptyset$
      \end{tabular}
    };
    \node[state node,left=of q0] (q3) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\emptyset$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };    
    \draw[<-] (q0) -- +(90:1);
    \draw[<-] (q1) -- +(90:1);    
    \draw (q1) -- (q2);
    \draw (q0) -- (q3);
\end{tikzpicture}
\end{center}

We continue processing nodes with non-empty \now sets just as we did before. Because the new node with $\now=\{\tuntil{\ausfml}{\busfml}\}$ is exactly the same as the one we started out with, we arrive at the following after multiple steps of processing.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \busfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };
  \node[state node,right=of q0] (q1) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \ausfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\{\tuntil{\ausfml}{\busfml}\}$
      \end{tabular}
    }; 
  \node[state node,below left=of q1] (q2) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \busfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };
  \node[state node,below=of q1] (q3) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \ausfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\{\tuntil{\ausfml}{\busfml}\}$
      \end{tabular}
    }; 
    \node[state node,left=of q0] (q4) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\emptyset$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };
    \node[state node, below=of q4] (q5)
    { \footnotesize
      \begin{tabular}{l}
      \old: $\emptyset$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };

    \draw[<-] (q0) -- +(90:1);
    \draw[<-] (q1) -- +(90:1);
    \draw (q1) -- (q2);
    \draw (q1) -- (q3);
    \draw (q0) -- (q4);
    \draw (q4) -- (q5);
\end{tikzpicture}
\end{center}

We currently have a graph with nodes that share \old and \future sets, and have empty \now sets. These are redundant, and we remove the more recent copy of each such redundant node by adding its incoming edges to the other's incoming set.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,rectangle,fill=blue!10,minimum width=12pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (q0) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \busfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };
  \node[state node,right=of q0] (q1) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\{\tuntil{\ausfml}{\busfml}, \ausfml\}$ \\
      \now: $\emptyset$ \\
      \future: $\{\tuntil{\ausfml}{\busfml}\}$
      \end{tabular}
    }; 
    \node[state node,left=of q0] (q4) 
    { \footnotesize
      \begin{tabular}{l}
      \old: $\emptyset$ \\
      \now: $\emptyset$ \\
      \future: $\emptyset$
      \end{tabular}
    };        

    \draw[<-] (q0) -- +(90:1);
    \draw[<-] (q1) -- +(90:1);
    \draw (q1) -- (q0);
    \draw (q1) to [out=290,in=250,looseness=8] (q1);
    \draw (q0) -- (q4);
    \draw (q4) to [out=290,in=250,looseness=8] (q4);
\end{tikzpicture}
\end{center}

At this point, none of the nodes in our graph have non-empty \now sets. There is no further processing to be done, so we can finish by constructing a generalized B\"uchi automaton corresponding to the graph. We clearly want the alphabet to consist of sets of atomic propositions from $\Sigma$. The set of states in the automaton will correspond exactly to the set of states in the graph above, in addition to a new initial state. Likewise, the edges will also remain the same, except with the addition of edges from the new initial state to the states that represent nodes with \texttt{init} in their set of incoming edges.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=20pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (init) {};
  \node[state node, below=of init] (q0) {};
  \node[state node,right=of q0] (q1) {};
  \node[state node,left=of q0] (q4) {};
  \draw (init) -- (q0);
  \draw (init) -- (q1);
  \draw[<-] (init) -- +(90:1);
  \draw (q1) -- (q0);
  \draw (q1) to [out=290,in=250,looseness=8] (q1);
  \draw (q0) -- (q4);
  \draw (q4) to [out=290,in=250,looseness=8] (q4);
\end{tikzpicture}
\end{center}

What about the transition labels and accepting states? To assign transition labels, we look to the \old sets of each node in the graph. The labels on each edge will correspond to the conjunction of all of the atomic propositions in the \old set of the post-state. The only ``corner case'' to deal with appears in our example, where one of the node has an empty \old set. The meaning of such a node is that there are no conditions on the traces reaching the corresponding state; in these cases the transition is labeled with $\ltrue$ to reflect this fact. We are left with the following automaton.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=20pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (init) {};
  \node[state node, below=of init] (q0) {};
  \node[state node,right=of q0] (q1) {};
  \node[state node,left=of q0] (q4) {};
  \draw (init) to node[left] {$\busfml$} (q0);
  \draw (init) to node[right] {$\ausfml$} (q1);
  \draw[<-] (init) -- +(90:1);
  \draw (q1) to node[below] {$\busfml$} (q0);
  \draw (q1) to [out=290,in=250,looseness=8] node[below] {$\ausfml$} (q1);
  \draw (q0) to node[below] {$\ltrue$} (q4);
  \draw (q4) to [out=290,in=250,looseness=8] node[below] {$\ltrue$} (q4);
\end{tikzpicture}
\end{center}

Finally, we need to assign the accepting states. Notice that not every infinite path through the automaton belongs in the language of $\tuntil{\ausfml}{\busfml}$. In particular, the word $\ausfml,\ausfml,\ldots$ follows transitions on the automaton, staying in the rightmost state. Indeed, although the node in our graph construction for this state contained $\tuntil{\ausfml}{\busfml}$, this word does not traverse a successor state at any point that contains $\busfml$ as required for inclusion in $\flang{\tuntil{\ausfml}{\busfml}}$. This is solved by setting as accepting any node for which $\tuntil{\ausfml}{\busfml} \not\in \old$, or $\busfml \in \old$. This leaves us with the following automaton.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=20pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node] (init) {};
  \node[state node, below=of init,accepting] (q0) {};
  \node[state node,right=of q0] (q1) {};
  \node[state node,left=of q0,accepting] (q4) {};
  \draw (init) to node[left] {$\busfml$} (q0);
  \draw (init) to node[right] {$\ausfml$} (q1);
  \draw[<-] (init) -- +(90:1);
  \draw (q1) to node[below] {$\busfml$} (q0);
  \draw (q1) to [out=290,in=250,looseness=8] node[below] {$\ausfml$} (q1);
  \draw (q0) to node[below] {$\ltrue$} (q4);
  \draw (q4) to [out=290,in=250,looseness=8] node[below] {$\ltrue$} (q4);
\end{tikzpicture}
\end{center}

Note that this is by no means the simplest automaton that accepts the language. It is not hard to see that we can simplify the structure to the following, which is perhaps more natural.

\begin{center}
\begin{tikzpicture}[thick,->,> =stealth,
   state node/.style={draw,black,circle,fill=blue!10,minimum width=20pt},
   every label/.style={draw=none,fill=none,text=red!140}]
  \node[state node, below=of init,accepting] (q0) {};
  \node[state node,right=of q0] (q1) {};
  \draw[<-] (q1) -- +(90:1);
  \draw (q1) to node[below] {$\busfml$} (q0);
  \draw (q1) to [out=290,in=250,looseness=8] node[below] {$\ausfml$} (q1);
  \draw (q0) to [out=290,in=250,looseness=8] node[below] {$\ltrue$} (q0);
\end{tikzpicture}
\end{center}

\paragraph{Other operators}

We just saw how to systematically convert the LTL formula $\tuntil{\ausfml}{\busfml}$ into a nondeterministic B\"uchi automaton. In order to generalize the approach to other formulas, we need to consider how to process other operators that appear in the \now sets of nodes. When processing a formula consisting of until, we split the current node into two new ones using the expansion axiom for $\tuntil{\ausfml}{\busfml}$. We can handle the remaining cases by considering the temporal operator $\tnext{\ausfml}$, the Boolean operators $\ausfml \land \busfml$, $\ausfml \lor \busfml$, and a new temporal operator $\trelease{\ausfml}{\busfml}$. The release operator is defined to be exactly the dual of until:
\begin{equation}
\label{eq:release}
\trelease{\ausfml}{\busfml} \equiv \lnot(\tuntil{\lnot\ausfml}{\lnot\busfml})
\end{equation}
The addition of the release operator to LTL formulas allows us to define a useful negation normal form.

\begin{definition}[LTL negation normal form]
An LTL formula $\ausfml$ is said to be in negation normal form if it contains the operators $\tnext{}$, $\tuntil{}{}$, $\trelease{}{}$, $\land$, $\lor$, and $\lnot$. Additionally, negation in $\ausfml$ only occurs over atomic propositions.
\end{definition}
\begin{theorem}
Any LTL formula has an equivalent representation in negation normal form.
\end{theorem}
\begin{proof}
Much as in the case of propositional logic, an LTL formula can be converted to its NNF equivalent with the use of DeMorgan's law and the following equivalences.
\begin{align}
\tdiamond{\ausfml} &\lbisubjunct \tuntil{\ltrue}{\ausfml} \\
\tbox{\ausfml} &\lbisubjunct \trelease{\lfalse}{\ausfml} \\
\lnot\tnext{\ausfml} &\lbisubjunct \tnext{\lnot\ausfml} \\
\lnot(\tuntil{\ausfml}{\busfml}) &\lbisubjunct \trelease{\lnot\ausfml}{\lnot\busfml} \\
\lnot(\trelease{\ausfml}{\busfml}) &\lbisubjunct \tuntil{\lnot\ausfml}{\lnot\busfml}
\end{align}
Proving the validity of these equivalences is a good exercise.
\end{proof}

Assuming the formula we wish to convert is in NNF, we can use the following steps to process nodes with $\tnext{}$, $\trelease{}{}$, $\land$, and $\lor$ formulas in \now.
\begin{description}
\item[$\ausfml\land\busfml$:] On selecting a conjunction, $\ausfml\land\busfml$ is removed from \now and replaced with $\ausfml$ and $\busfml$.
\item[$\ausfml\lor\busfml$:] On selecting a disjunction, the current node $q$ is split into $q_1$ and $q_2$. $\ausfml$ is added to \now of $q_1$, and $\busfml$ to \now of $q_2$.
\item[$\tnext{\ausfml}$:] On selecting $\tnext{\ausfml}$ from \now in node $q$, simply remove $\tnext{\ausfml}$ from \now and add it to \future.
\item[$\trelease{\ausfml}{\busfml}$:] As in the case of $\tuntil{}{}$, when processing $\trelease{\ausfml}{\busfml}$ the current node $q$ is split into two new ones $q_1, q_2$. The expansion axiom for release is,
\begin{equation}
\trelease{\ausfml}{\busfml} \lbisubjunct \busfml \land (\ausfml \lor \tnext{(\trelease{\ausfml}{\busfml})})
\lbisubjunct (\busfml \land \ausfml) \lor (\busfml \land \tnext{(\trelease{\ausfml}{\busfml})})
\end{equation}
So, $\busfml$ is added to \now in both $q_1$ and $q_2$, $\ausfml$ is added to \now in $q_1$, and $\trelease{\ausfml}{\busfml}$ is added to \future of $q_2$.
\end{description}

Finally, to handle the general case of arbitrary LTL formulas, we need to expand the way in which accepting states are assigned as well. The most natural way to describe the construction constructs a \emph{generalized} B\"uchi automaton (GBA), which is exactly like a NBA but for the syntax and semantics of the accepting states. Namely, a GBA has potentially multiple distinct sets of accepting states; the acceptance criterion for a word then requires the existence of a run that visits each \emph{set} of accepting states infinitely often.

\begin{definition}[Generalized B\"uchi Automaton (GBA)]
\label{def:buchi}
A nondeterministic B\"uchi automaton $A$ is a tuple $A = (Q, \Sigma, \delta, Q_0, F)$ where:
\begin{enumerate}
\item $Q$ is a \textbf{finite} set of states.
\item $\Sigma$ is an alphabet.
\item $\delta : Q \times \Sigma \to \powerset{Q}$ is a transition function.
\item $Q_0 \subseteq Q$ is a set of initial states
\item $F \subseteq \powerset{Q}$ is a set of accepting sets.
\end{enumerate}
A run for (infinite) trace $\sigma = \sigma_0,\sigma_1,\sigma_2,\ldots$ is an infinite sequence of states $q_0,q_1,q_2,\ldots$ in $Q$ such that $q_0 \in Q_0$ and $q_{i+1} \in \delta(q_i,\sigma_i)$ for all $i \ge 0$. A run $q_0,q_1,q_2,\ldots$ is accepting if for each $F_j \in F$, $q_i \in F_j$ for \textbf{infinitely many indices} $i \ge 0$. The language of $A$ is:
\[
\flang{A} = \{\sigma \in \Sigma^\omega \with \text{there exists an accepting run for}~\sigma~\text{in}~A\}
\]
In the above, $\Sigma^\omega$ is the set of all infinite words over alphabet symbols in $\Sigma$.
\end{definition}

While the more complex syntax of GBA make it simpler to describe many algorithms, these automata are no more powerful than NBA. There is a straightforward translation from a GBA to a NBA that accepts the same language. Intuitively, if there are $n$ accepting sets in the GBA, then we make $n$ copies of the automaton each with a single acceptance set. There is a single accepting state in the NBA, which can only be entered when at least one state from all of the original GBA acceptance sets have been traversed.

\paragraph{General acceptance criteria, complexity}
Wrapping up the conversion algorithm, the general criteria for selecting acceptance conditions is as follows. For every subformula of the form $\tuntil{\ausfml}{\busfml}$, there is a new acceptance set $F_i \in F$ in the GBA containing the nodes where either $\tuntil{\ausfml}{\busfml} \not\in \old$, or $\busfml \in \old$. This results in an automaton whose size (i.e., number of states) is at most $2^{O(|\ausfml|)}$, i.e., exponential in the size of the number of subformulas of the original LTL formula. We will not prove the correctness of this algorithm or its complexity here, but please consult the original paper~\cite{Gerth1996} for a clearly-written proof of both.

The worst-case exponential time and space requirements may seem dire, and indeed they do pose a problem for some practical applications of the technique. However, two points bear mentioning. 

First, the worst-case behavior of the algorithm is oftentimes not encountered in practice. In the example we worked out, there are three subformulas ($\{\ausfml,\busfml,\tuntil{\ausfml}{\busfml}\}$, but the resulting automaton only had four states and we saw that simple heuristic optimizations could bring the number of states down to just two. Gerth et al.~\cite{Gerth1996} showed in their original publication of the approach that many useful commonly-used property formulas yielded small automata well below the worst-case bound. Second, LTL model checking is known to be a hard problem, so it is unlikely that one can do better. See \cite{BaierKL08} for a proof that the LTL model checking problem is PSPACE-complete.

\bibliography{platzer,bibliography}
\end{document}
