\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}{23}
\newcommand{\lectitle}{Model Checking Abstractions}
\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\small,
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}
So far we've focused on model checking algorithms that assume a computation structure is given. It should come as no surprise that our goal is to perform model checking of programs given as code, so today we'll describe techniques that allow us to apply model checking in this setting. There are several challenges to doing so, foremost among them the fact that the statespace of programs may be infinite. We'll describe an approach for dealing with this called \emph{predicate abstraction}.
Predicate abstraction computes an \emph{over}approximation of reachable states by constructing a transition structure that treats distinct program states identically, in a way that makes it possible to reason over a finite number of states.
The good news is that it is always feasible to do so, as there are a finite number of states and the transitions can be computed using familiar techniques. The bad news is that often it is the case that crucial information gets lost in the approximation, leaving us unable to find real bugs or verify their absence. We'll eventually see how to incrementally fix this using a technique called \emph{abstraction refinement}, which leads to interesting new questions about automated software verification.
\section{Review: trace semantics}
\begin{definition}[Trace semantics of programs] \label{def:program-trace}
\newcommand{\ws}{\omega}\newcommand{\wt}{\nu}%
\renewcommand{\I}{\iconcat[state=\ws]{\stdI}}%
\renewcommand{\It}{\iconcat[state=\wt]{\stdI}}%
The \dfn[valuation!of~programs]{trace semantics,
$\iaccess[\alpha]{\I}$, of a program}~$\alpha$, is
the set of all its possible traces and is defined inductively as follows:
\index{_\tau(\alpha)_@$\tau(\alpha)$}%
\begin{enumerate}
\item
\m{\iaccess[\pupdate{\umod{x}{\astrm}}]{\I}}
=
\m{\{(\iget[state]{\I},\iget[state]{\It}) \with
\iget[state]{\It}=\iget[state]{\I}~\text{except that}~ \iget[state]{\It}(x)=\ivaluation{\I}{\astrm}}
for~\m{\ws\in\linterpretations{\Sigma}{V}\}}
\item \(\iaccess[\ptest{\ivr}]{\I} = \{(\ws) \with
\imodels{\I}{\ivr}\} \cup
\{(\ws,\limbo) \with
\inonmodels{\I}{\ivr}\}\)
\index{$\ptest{}$}
\item \(\iaccess[\pif{\ivr}{\alpha}{\beta}]{\I} =
\{\atrace \in \iaccess[\alpha]{\I} \with \atrace_0 \models \ivr\} \cup
\{\atrace \in \iaccess[\beta]{\I} \with \atrace_0 \nonmodels \ivr\}\)
\item \(\iaccess[{\alpha};{\beta}]{\I} =
\{\atrace \compose \varsigma \with \atrace\in\iaccess[\alpha]{\I} \mand \varsigma\in\iaccess[\beta]{\I}\}\);\\
the composition of~\m{\atrace=(\atrace_0,\atrace_1,\atrace_2,\dots)} and~\m{\varsigma=(\varsigma_0,\varsigma_1,\varsigma_2,\dots)} is
\[
\atrace \compose \varsigma \eqdef
\begin{cases}
(\atrace_0,\dots,\atrace_n,\varsigma_1,\varsigma_2,\dots) &\mylpmi[\text{if}~] \text{$\atrace$ terminates in $\atrace_n$}~\text{and}~\atrace_n=\varsigma_0\\
\atrace &\mylpmi[\text{if}~] \atrace~\text{does not terminate}\\
\text{not defined} &\text{otherwise}
\end{cases}
\]
\item
\(\iaccess[\pwhile{\ivr}{\alpha}]{\I}\)
=\(\{\atrace^{(0)} \compose \atrace^{(1)} \compose \dots \compose \atrace^{(n)} \with\)
for some $n\geq0$
such that for all $0\leq i 0) {
b := *;
if(b >= 0) {
L := 1;
C := C + 1;
// critical section
}
if(C > 0)
L := 0;
t := t - 1;
}
\end{lstlisting}
This program uses nondeterminism to simulate the fact that a process may not be granted a lock when requested, in the event that another process already holds it. We begin by annotating the program with locations.
\begin{lstlisting}
$\ell_0$: L := 0;
$\ell_1$: C := 0;
$\ell_2$: while(t > 0) {
$\ell_3$: b := *;
$\ell_4$: if(b >= 0) {
$\ell_5$: L := 1;
$\ell_6$: C := C + 1;
// critical section
$\ell_7$: }
$\ell_8$: if(C > 0)
$\ell_9$: L := 0;
$\ell_{10}$: t := t - 1;
$\ell_{11}$: }
$\ell_{13}$:
\end{lstlisting}
The control flow transitions, with guards, are shown below. We omit the assignment statements on edges to avoid clutter in the diagram, but it is easy to find the appropriate statement for a transition if we need to.
Note that we can add a self-loop to the final location $\ell_{13}$ to ensure that all states in this structure have a post-state.
\begin{center}
\includegraphics[width=0.6\textwidth]{controlflow1.pdf}
\end{center}
% The control flow transitions depicted above are more or less faithful to the formal construction given earlier. However, it is often possible to use fewer program location labels to construct an equivalent set of transitions. For example, sequences of assignments without any conditionals or loops can be combined into a single location, the effect of which is (except in obvious corner cases) like a single multple-assignment statement. Similarly, where conditional and loop statements are composed with eachother, we can merge redundant initial and final location labels where they are adjacent; e.g., $\ell_7$ and $\ell_8$ in the above can be merged into one label. This leaves us with the following simpler representation.
% \begin{lstlisting}
% $\ell_0$: L := 0;
% C := 0;
% while(t > 0) {
% $\ell_1$: b := *;
% if(b >= 0) {
% $\ell_2$: L := 1;
% C := C + 1;
% // critical section
% }
% $\ell_3$: if(C > 0)
% $\ell_4$: L := 0;
% $\ell_5$: t := t - 1;
% }
% $\ell_6$:
% \end{lstlisting}
% From this we arrive at the following set of transitions.
% \begin{center}
% \includegraphics[width=0.6\textwidth]{controlflow2.pdf}
% \end{center}
% Note that when merging, we have changed the requirements on transitions slightly. When we take the product with the program states to compute the states of $K_\asprg$, we previously required that the transition guard hold in the pre-state of each transition. In the simplified labeling above, we've sometimes merged branching locations with locations that perform assignments. For example, $\ell_0,\ell_1,\ell_2$ from the first labeling were merged into $\ell_0$ in the second. To construct $K_\asprg$ correctly, we need to change the tran
The transitions we've constructed so far correspond to $\epsilon(\alpha)$. Now to construct $K_\asprg$, we need one state for each location paired with each possible program valuation. However, we cannot hope to compute such a structure in its entirety, or write it down because of its infinite size. To address this, we will need to approximate the infinite statespace of $K_\asprg$ with a finite one using a technique called \emph{predicate abstraction}.
\section{Predicate Abstraction}
Predicate abstraction gives an \emph{over}approximation to the program's computation structure $K_\asprg$ in the sense that for any path in $K_\asprg$, there exists a corresponding path in its abstraction.
However, the abstraction may contain some paths for which there is no correspondent in $K_\asprg$, as it is an approximation.
Thinking about what this means, model checking such an abstraction may result in finding bugs that do not correspond to real ones, but doing so will never miss an error that actually exists in the program.
The main idea used in predicate abstraction is to merge states in $K_\asprg$ that have the same labeling of atomic propositions. This may not seem to get us very far at first, as the labels used in Definition~\ref{def:programtransition} were the the original source of the infinite statespace problem. However, by selecting the set of atomic propositions wisely, we can sidestep this problem while at the same time, in many cases, significantly reducing the overall number of states that need to be explored.
\paragraph{By example.}
Consider the mutual exclusion program from before. Crucial to this sort of protocol is that the lock be taken ($\ell_2$) and released ($\ell_3$) in proper order: a process that does not own a lock should not release it, as this could lead to violation of mutual exclusion safety.
To check this, we want to ensure what whenever the lock is taken by assigning $\pumod{\texttt{L}}{1}$ on $\ell_2$, it is currently the case that $\texttt{L} = 0$. Likewise, whenever the lock is released on $\ell_3$, then it must be that $\texttt{L} = 1$. This gives us two LTL safety properties.
\begin{align}
\label{eq:mutex1}\tbox{\ell_2 \rightarrow \texttt{L} = 0} \\
\label{eq:mutex2}\tbox{\ell_4 \rightarrow \texttt{L} = 1}
\end{align}
In the above, we use the shorthand $\ell_i$ to denote any state $\langle\ell_i, \sigma\rangle$, for any $\sigma$. Likewise, $\texttt{L} = x$ denotes any state $\langle\ell, \texttt{L} = x\rangle$, for any $\ell$.
Let's consider these formulas one at a time. In order to check (\ref{eq:mutex1}), what states of $K_\asprg$ could we possibly need to explore? Before the first sequence of assignments are executed, \texttt{L} and \texttt{C} could take any values. It stands to reason that we must consider any initial state $s$ where $v(s) \models \ell_0$. But after executing these assignments, we know that both variables will take value 0, so we must only consider in addition at this stage states $s$ where $v(s) \models \ell_1 \land \texttt{L} = 0 \land \texttt{C} = 0$. Similarly, the only states that matter at $\ell_2$ are those where $v(s) \models \ell_2 \land \texttt{b} > 0$.
\subsection{Computing abstractions}
Following on the observations from this example, we come to the central idea of predicate abstraction: find a set of atomic predicates and corresponding \emph{abstract} labeling function that is concise but sufficient to capture all of the \emph{relevant} traces in the program.
We then merge all of the states in the ``concrete'' transition structure $K_\asprg$ that share the same abstract labeling into one, and allow transitions liberally.
In particular, if $\hat{s}$ and $\hat{s}'$ are abstract states and $\hat{v}$ an abstract labeling, then we draw a transition from $\hat{s} \hat{\stepto} \hat{s}'$ iff there are concrete states $s$ and $s'$ where $s \stepto s'$, and additionally $\hat{v}(s) = \hat{s}, \hat{v}(s') = \hat{s}'$.
% The central idea of predicate abstraction can be summarized as follows: define a set of abstract atomic predicates $\hat{\Sigma}$ that is concise, but still allows us to distinguish all of the traces relevant to our property. We then create a new transition structure whose states correspond to sets of abstract propositions (i.e., elements of $\powerset{\hat{\Sigma}}$) rather than program states.
Consider the first example from earlier, and suppose that we select $\hat{\Sigma} = \{0 \le i\}$.
Then the states in the abstraction will correspond to:
\[
\{\ell_0,\ell_1,\ell_2,\ell_3,\ell_4\} \times \{\emptyset,0\le i\}
\]
Intuitively, the state $\langle\ell_0, 0\le i\rangle$ corresponds to any state in $K_\asprg$ at $\ell_0$ where $0\le i$.
Generally, an abstract state that does \emph{not} contain a predicate $\asfml\in\hat{\Sigma}$ is interpreted as corresponding to concrete states in $K_\asprg$ that satisfy the negation of $\asfml$.
So for example, $\langle\ell_0, \emptyset\rangle$ corresponds to any state at $\ell_0$ where $0>i$.
If an abstract state corresponds to more than one predicate, then we interpret it as corresponding to concrete states that satisfy the conjunction of those predicates.
\begin{definition}\label{def:concret}
Given a set of predicates $A \in \hat{\Sigma}$, let $\gamma(A)$ be the set of program states $\sigma \in \mathcal{S}$ that satisfy the conjunction of predicates in $A$:
\[
\textstyle
\gamma(A) = \{\sigma\in\mathcal{S} : \sigma\models\bigwedge_{a\in A} a\}
\]
\end{definition}
\begin{definition}[Abstract Transition Structure]\label{def:abstrans}
Given a program $\asprg$, a set of abstract atomic predicates $\hat{\Sigma}$, and control flow transition relation $\epsilon(\asprg)$ (Def.~\ref{def:programtransition}), let $L$ be a set of \emph{locations} given by the inductively-defined function $\plocs{\asprg}$, $\ilocs{\asprg}$ be the \emph{initial} locations of $\asprg$, and $\flocs{\asprg}$ be the \emph{final} locations of $\asprg$ as given in Definition~\ref{def:programtransition}. The abstract transition structure $\hat{K_\asprg} = (\hat{W},\hat{I},\hat{\stepto},\hat{v})$ is a tuple containing:
\begin{itemize}
\item $\hat{W} = \plocs{\asprg} \times \powerset{\hat{\Sigma}}$ are the states defined as pairs of program locations and sets of abstraction predicates.
\item $\hat{I} = \{\langle\ell, A\rangle \in \hat{W} : \ell \in \ilocs{\asprg}\}$ are the initial states corresponding to initial program locations.
\item $\hat{\stepto} = \{(\langle\ell, A\rangle, \langle\ell', A'\rangle :~\text{for}~(\ell, \bsprg, \ell') \in \epsilon(\asprg)~\text{where there exist}~\sigma,\sigma'~\text{such that}~\sigma\in\gamma(A), \sigma'\in\gamma(A')~\text{and}~(\sigma,\sigma')\in\llbracket\bsprg\rrbracket\}$ is the transition relation.
\item $\hat{v}(\langle\ell, A\rangle) = \langle\ell, A\rangle$ is the labeling function, which is in direct correspondence with states.
\end{itemize}
\end{definition}
\begin{theorem}\label{thm:existential}
For any trace $\langle\ell_0,\sigma_0\rangle,\langle\ell_1,\sigma_1\rangle,\ldots$ of $K_\asprg$, there exists a corresponding trace of $\hat{K_\asprg}$ $\langle\hat{\ell}_0,A_0\rangle,\langle\hat{\ell}_1,A_1\rangle,\ldots$ such that for all $i\ge0$, $\ell_i = \hat{\ell}_i$ and $\sigma_i \in \gamma(A_i)$.
\end{theorem}
\begin{proof}
We proceed by induction on the length of the trace $\langle\ell_0,\sigma_0\rangle,\langle\ell_1,\sigma_1\rangle,\ldots$ of $K_\asprg$.
\begin{description}
\item[Length=1:] By Definition~\ref{def:programtransition}, the trace is $\langle\ell_0,\sigma_0\rangle$ where $\ell_0\in\ilocs{\asprg}$. Then let $A$ be such that $\sigma_0 \in \gamma(A)$; we know that such an $A$ exists, because $\powerset{\hat{\Sigma}}$ covers the entire statespace $\mathcal{S}$. Then $\langle\ell_0,A\rangle$ is an initial state of $\hat{K_\asprg}$ as well, so it is a trace of length 1 in $\hat{K_\asprg}$.
\item[Length=n+1:] We have that $\langle\ell_0,\sigma_0\rangle,\ldots,\langle\ell_{n+1},\sigma_{n+1}\rangle$ is a trace of $K_\asprg$. By the inductive hypothesis, there must exist a trace $\langle\hat{\ell}_0,A_0\rangle,\ldots,\langle\hat{\ell}_{n},A_{n}\rangle$ of $\hat{K_\asprg}$ such that for all $0 \le i \le n$, $\ell_i = \hat{\ell}_i$ and $\sigma_i \in \gamma(A_i)$. Then let $A_{n+1}$ be such that $\sigma_{n+1}\in\gamma(A_{n+1})$. Because $\langle\ell_n,\sigma_n\rangle\stepto\langle\ell_{n+1},\sigma_{n+1}\rangle$, we know that there exists $(\ell_n,\bsprg,\ell_{n+1} \in \epsilon(\asprg)$ where $(\sigma_n,\sigma_{n+1})\in\llbracket\bsprg\rrbracket$. Then by Definition~\ref{def:abstrans}, it must be that $\langle\hat{\ell}_n,A_n\rangle\hat{\stepto}\langle\hat{\ell}_{n+1},A_{n+1}\rangle$. So $\langle\hat{\ell}_0,A_0\rangle,\ldots,\langle\hat{\ell}_{n+1},A_{n+1}\rangle$ is a trace in $\hat{K_\asprg}$ where for $0 \le i \le n+1$ we have that $\sigma_i \in \gamma(A_i)$.
\end{description}
This completes the proof.
\end{proof}
Theorem~\ref{thm:existential} tells us that $\hat{K_\asprg}$ can be used to deduce properties about $K_\asprg$: any trace in $K_\asprg$ is also in $\hat{K_\asprg}$, so any property of $K_\asprg$ is also one of $\hat{K}_\asprg$. However, Theorem~\ref{thm:existential} also tells us that $\hat{K_\asprg}$ overapproximates $K_\asprg$, so some properties of $\hat{K_\asprg}$ may not be properties of $K_\asprg$.
Definition~\ref{def:abstrans} tells us what an abstract transition structure for a program is, given a set $\hat{\Sigma}$ of predicates. We are ultimately interested in computing the structure, for use in model checking. On initial inspection, this seems quite feasible as there are $|\plocs{\asprg}|\times2^{|\hat{\Sigma}|}$ states in $\hat{K_\asprg}$, so enumerating them is not an issue as long as we keep $\hat{\Sigma}$ small. But what about the transitions? There are still an infinite number of program states to contend with, so naive searching of $\sigma,\sigma'$ to satisfy the condition on $\hat{\stepto}$ is not feasible.
When deciding whether to add a transition to $\hat{K_\asprg}$, we only care about the existence of $\sigma,\sigma'$ that satisfy the requirements of Definition~\ref{def:abstrans}. It is thus sufficient for our purposes to determine whether there are \emph{any} $\sigma'\in\gamma(A')$ that are reachable from executing $\bsprg$ starting in $\sigma\in\gamma(A)$. Equivalently, we can determine whether it is always the case that when starting in $\sigma\in\gamma(A)$, we end up in $\sigma'\in\gamma(A')$ after executing $\bsprg$. Note that this is exactly the same as determining the validity of $\bigwedge_{a\in A} a \limply \dibox{\bsprg}{\bigvee_{a'\in A'} \lnot a'}$.
\begin{theorem}\label{thm:abstrans}
Let $A, B \subseteq \hat{\Sigma}$ be sets of predicates over program states, and $\bsprg$ be a program. Then for $\sigma\in\gamma(A)$, there exists a state $\sigma'\in\gamma(B)$ such that $(\sigma,\sigma')\in\llbracket\bsprg\rrbracket$ if and only if $\bigwedge_{a\in A} a \limply \dibox{\bsprg}{\bigvee_{b\in B} \lnot b}$ is not valid.
\end{theorem}
\begin{proof}
First we prove that $\bigwedge_{a\in A} a \limply \dibox{\bsprg}{\bigvee_{b\in B} \lnot b}$ not valid implies that $\exists \sigma,\sigma' . \sigma\in\gamma(A)\land\sigma'\in\gamma(B)\land(\sigma,\sigma')\in\llbracket\bsprg\rrbracket$. First we know that there is some $\sigma\in\gamma(A)$ because the formula is not valid, so $\bigwedge_{a\in A} a$ is not equivalent to false. Then by the semantics of $\dibox{\cdot}{}$, we know that there exists some $\sigma'\models\bigwedge_{b\in B}b$ reachable by running $\bsprg$ starting in a state $\sigma\models\bigwedge_{a\in A} a$, i.e., $(\sigma,\sigma')\in\llbracket\bsprg\rrbracket$. So then $\sigma\in\gamma(A)$, and $\sigma'\in\gamma(B)$, finishing the proof in this direction.
Now in the other direction, we show that if there exists $\sigma,\sigma'$ where $\sigma\in\gamma(A)\land\sigma'\in\gamma(B)\land(\sigma,\sigma')\in\llbracket\bsprg\rrbracket$, then $\bigwedge_{a\in A} a \limply \dibox{\bsprg}{\bigvee_{b\in B} \lnot b}$ is not valid. Because $\sigma'\in\gamma(B)$, we know that $\sigma'\models\bigwedge_{b\in B}b$ and like wise because $\sigma\in\gamma(A)$ that $\sigma\models\bigwedge_{a\in A}a$. So not all states $\sigma\models\bigwedge_{a\in A}$ reach a final state in $\bigvee_{b\in B}\lnot b$ after running $\bsprg$, which finishes the proof in this direction.
\end{proof}
Theorem~\ref{thm:abstrans} tells us that we can reason about transitions in $\hat{K_\asprg}$ by determining the validity of first order dynamic logic formulas. Moreover, looking at the construction of $\epsilon(\asprg)$ given in Definition~\ref{def:programtransition}, we see that the only programs forms that can appear on transitions in $\epsilon(\asprg)$ are assignments and tests; there are no loops, conditionals, or even composition operators. This means that by a single application if \irref{assignb} or \irref{testb}, the DL formula stipulated in Theorem~\ref{thm:abstrans} is reducible to an arithmetic formula that can be solved with a decision procedure.
\paragraph{Example}
Let us go back to the program from before, and again use $\hat{\Sigma} = \{0 \le i\}$. For clarity, we will be explicit about the abstract conjunctions in each state, and consider the state space of our abstraction $\hat{K_\asprg}$ to be $\{\ell_0,\ell_1,\ell_2,\ell_3,\ell_4\}\times\{0>i,0\le i\}$. Now we must decide the transitions. We will work out several of them in some detail to demonstrate the reasoning, but leave the rest as an exercise due to the large number of possible transitions.
\begin{itemize}
\item $\langle\ell_0,0>i\rangle\hat{\stepto}\langle\ell_1,0>i\rangle$: The program between $\ell_0$ and $\ell_1$ is $\pumod{i}{N}$. By Theorem~\ref{thm:abstrans}, we must decide the validity of $0>i\limply\dibox{\pumod{i}{N}}{0\le i}$. By \irref{assignb}, we can reduce this to $0>i\limply0\le N$, which is not valid: it is falsified by setting $i=-1,N=0$. So this edge is added to $\hat{\stepto}$.
\item $\langle\ell_2,0>i\rangle\hat{\stepto}\langle\ell_3,0\le i\rangle$: The program between $\ell_2$ and $\ell_3$ is $\pumod{i}{i-1}$. By Theorem~\ref{thm:abstrans}, we must decide the validity of $0>i\limply\dibox{\pumod{i}{i-1}}{0> i}$. By \irref{assignb}, we can reduce this to $0>i\limply0>i-1$, which is valid. So this edge is \emph{not} added to $\hat{\stepto}$.
\item $\langle\ell_1,0>i\rangle\hat{\stepto}\langle\ell_4,0>i\rangle$: The program between $\ell_1$ and $\ell_4$ is $\ptest{\lnot(0\le xi\limply\dibox{\ptest{\lnot(0\le xi \land \lnot(0\le xi\rangle\hat{\stepto}\langle\ell_1,0\le i\rangle$: The program between $\ell_0$ and $\ell_1$ is $\pumod{i}{N}$. By Theorem~\ref{thm:abstrans}, we must decide the validity of $0>i\limply\dibox{\pumod{i}{N}}{0 > i}$. By \irref{assignb}, we can reduce this to $0>i\limply0 > N$, which is not valid: it is falsified by setting $i=-1,N=-1$. So this edge is added to $\hat{\stepto}$.
\item $\langle\ell_1,0\le i\rangle\hat{\stepto}\langle\ell_2,0>i\rangle$: The program between $\ell_1$ and $\ell_2$ is $\ptest{0\le xi\rangle\hat{\stepto}\langle\ell_1,0>i\rangle\hat{\stepto}\langle\ell_4,0>i\rangle
\]
Because $\hat{K_\asprg}$ overapproximates the true transition structure $K_\asprg$, we need to determine whether this does in fact correspond to a path in $K_\asprg$, or whether it is merely an artifact of the overapproximation. If it is a spurious artifact, then we can reason that the corresponding path in $K_\asprg$ does \emph{not} violate the safety property. Equivalently, it would mean the the following formula must be valid:
\[
0 > i \limply \dibox{\pumod{i}{N};\ptest{\lnot(0\le xi\rangle\hat{\stepto}\langle\ell_1,0>i\rangle$. To see why, observe that from Theorem~\ref{thm:abstrans} we reason:
\[
(0>i \limply \dibox{\pumod{i}{\mathtt{abs}(N)+1}}{0\le i}) \lbisubjunct (0>i\limply0\le\mathtt{abs}(N)+1)~\text{is valid}
\]
But there is another counterexample, which we see taking the following steps.
\begin{enumerate}
\item $\langle\ell_0,0\le i\rangle\hat{\stepto}\langle\ell_1,0\le i\rangle$. This edge is in $\hat{K_\asprg}$ because $0\le i\limply\dibox{\pumod{i}{\mathtt{abs}(N)+1}}{0>i}$ is equivalent to $0\le i\limply0>\mathtt{abs}(N)+1$, which is not valid.
\item $\langle\ell_1,0\le i\rangle\hat{\stepto}\langle\ell_2,0\le i\rangle$. This edge exists because $0\le i\limply\dibox{\ptest{0\le xi}$ is equivalent to $0\le i\limply0\le xi$, which is not valid.
\item $\langle\ell_2,0\le i\rangle\hat{\stepto}\langle\ell_3,0>i\rangle$. This edge exists because $0\le i\limply\dibox{\pumod{i}{i-1}}{0\le i}$ is equivalent to $0\le i\limply0 \le i-1$ and is not valid, seen from the assignment $i=0$.
\item $\langle\ell_3,0>i\rangle\hat{\stepto}\langle\ell_1,0>i\rangle$. This edge exists because $0>i\limply\dibox{\pumod{x}{x+1}}{0\le i}$ is equivalent to $0>i\limply0\le i$, which is not valid.
\item $\langle\ell_1,0>i\rangle\hat{\stepto}\langle\ell_4,0>i\rangle$. This edge exists because $0>i\limply\dibox{\ptest{\lnot(0\le xi\limply\lnot(0\le xi$. This leads us to ask whether the following DL formula is valid:
\[
0 \le i \limply \dibox{\pumod{i}{\mathtt{abs}(N)+1};\ptest{0\le xi$ holds after the assignment. This is what gives rise to the spurious counterexamples in our abstraction.
We refine the abstraction by considering additional predicates to keep track of facts about the program state that are necessary to remove the counterexample. In the most recent counterexample trace, we know that after executing $\pumod{i}{i-1}$ it still holds that $0\le i$, because when the assignment occurs $i=\mathtt{abs}(N)+1$. Suppose that we add this predicate to our abstraction set in addition to $0\le i$. Then going back to what would occur on our counterexample trace, we have the following.
\begin{enumerate}
\item $\langle\ell_0,0\le i\rangle\hat{\stepto}\langle\ell_1,0\le i\land i=\mathtt{abs}(N)+1\rangle$. This edge is in $\hat{K_\asprg}$ because $0\le i\limply\dibox{\pumod{i}{\mathtt{abs}(N)+1}}{\lnot(0\le i\land i=\mathtt{abs}(N)+1\rangle)}$ is equivalent to $0\le i\limply\lnot(0\le \mathtt{abs}(N)+1)\land \mathtt{abs}(N)+1=\mathtt{abs}(N)+1)\rangle$, which is not valid.
\item $\langle\ell_1,0\le i\land i=\mathtt{abs}(N)+1\rangle\hat{\stepto}\langle\ell_2,0\le i\land i=\mathtt{abs}(N)+1\rangle$. This edge exists because $0\le i\land i=\mathtt{abs}(N)+1\limply\dibox{\ptest{0\le x i}$ is equivalent to $0\le i\land i=\mathtt{abs}(N)+1\limply0 > i-1$ and is not valid.
\item $\langle\ell_3,0\le i\rangle\hat{\stepto}\langle\ell_1,0\le i\rangle$. This edge exists because $0\le i\limply\dibox{\pumod{x}{x+1}}{0>i}$ is equivalent to $0\le i\limply0> i$, which is not valid.
\end{enumerate}
However, at this point $\hat{K_\asprg}$ is back in states where it is only true that $0\le i$. Another iteration of the loop will lead to entry of states there $0>i$ after the assignment to $i$, and we will find another spurious counterexample.
In order to derive an abstraction that is useful in proving the correctness of this program with respect to the property $\tbox{\ell_4\limply0\le i}$, we need to find a set of predicates that characterizes the relationship between $i$, $x$, and $N$. Consider the following:
\[
\begin{array}{ll}
a_0 &\equiv i \ge |N|-|x| \\
a_1 &\equiv i > |N|-|x| \\
a_2 &\equiv 0 \le x \le N \\
a_3 &\equiv 0 \le x < N \\
\end{array}
\]
Using these predicates, we can reason as follows.
\begin{itemize}
\item The only transition from an $\ell_0$ state to an $\ell_1$ state also contains predicate $a_1$ in the $\ell_1$ state. We see that $\ltrue\limply\dibox{\pumod{i}{\mathtt{abs}(N)+1}}{\lnot a_1}$ is equivalent to $|N|+1\le|N|-|x|$, which is not valid. Any state \emph{not} containing $a_1$ will result in a validity test of the form $\dibox{\pumod{i}{\mathtt{abs}(N)+1}}{\lnot (\lnot a_1 \land A')} \lbisubjunct \dibox{\pumod{i}{\mathtt{abs}(N)+1}}{a_1 \lor \lnot A'}$, which is valid.
\item The only transition from an $\ell_1$ state to an $\ell_2$ state is one in which $a_3$ holds, and if $a_0$ or $a_1$ held previously in the $\ell_1$ state, then they will also hold in the $\ell_2$ state. This is obvious because the test $\ptest{0\le x|N|-|x| \limply i-1 < |N|-|x|$, which is not valid. Furthermore, $a_0$ \emph{must} hold in the post-state, because $a_1\limply\dibox{\pumod{i}{i-1}}{a_0}$ is equivalent to $i>|N|-|x| \limply i-1 \ge |N|-|x|$, which is valid.
\item Any transition from $\ell_3$ to $\ell_1$ where $a_0$ holds in $\ell_3$ will result in $a_1$ holding in $\ell_1$. We have $a_0 \limply \dibox{\pumod{x}{x+1}}{\lnot a_1}$ is equivalent to $i \ge |N|-|x| \limply i \le |N|-|x+1|$ which is not valid.
\item Any transition from $\ell_3$ to $\ell_1$ where $a_3$ holds in $\ell_3$ will result in either $a_2$ or $a_3$ holding in $\ell_1$.
\item Any transition from $\ell_1$ to $\ell_4$ where $a_1$ and $a_2$ hold in $\ell_1$ will result in $a_0$ and $a_2$ at $\ell_4$. We see that $a_1 \land a_2 \limply \dibox{\ptest{\lnot(0\le x |N|-|x| \land 0 \le x \le N \limply \lnot(0\le x |N|-|x|$ and either $a_2$ or $a_3$. The only reachable $\ell_4$ states must go through $\ell_1 \land a_1 \land a_2$, and so must have $a_0 \land a_2$, which combined imply $0 \le i$. Thus, there are no counterexample traces in the abstraction. Because $\hat{K_\asprg}$ \emph{over}approximates $K_\asprg$, we know that any trace of $K_\asprg$ is also one of $\hat{K_\asprg}$. We can then conclude that there are no counterexamples in $K_\asprg$, and the program satisfies the property.
\paragraph{Automatic Refinement}
We've now shown that it's possible, at least in principle, to construct a predicate abstraction that is a close enough approximation to the true transition structure to conclude that there are no bugs in a system. But in the example we just saw, we needed to refine the set of predicates with those containing enough information about the inductive properties of the loop to rule out spurious counterexamples. It is not a coincidence that identifying those predicates felt a bit like coming up with a loop invariant for deductive verification, because that is essentially what we did.
When doing deductive verification, we did not expect to derive a procedure for automatically finding loop invariants. So how is abstraction refinement useful for model checking, where the primary goal is to verify programs (or find bugs) automatically? First of all, model checking is not a magic bullet: there is no guarantee that it will be able to prove the absence of bugs. And for good reason, because that problem is undecidable.
But in the next lecture we will look at techniques for automatic abstraction refinement that work well on many interesting programs and properties. The general approach is called \emph{Counterexample-Guided Abstraction Refinement} (CEGAR), and uses the information contained in spurious counterexamples to derive useful predicates for refinement.
% \bibliography{platzer,bibliography}
\end{document}