\documentclass[11pt,twoside]{scrartcl}
\usepackage{caption}
\usepackage{subcaption}
%opening
\newcommand{\lecid}{15-414}
\newcommand{\leccourse}{Bug Catching: Automated Program Verification}
\newcommand{\lecdate}{} %e.g. {October 21, 2013}
\newcommand{\lecnum}{15}
\newcommand{\lectitle}{Real-world SMT}
\newcommand{\lecturer}{Matt Fredrikson}
\usepackage{listings}
\usepackage{lecnotes}
\usepackage{tikz}
\usepackage[irlabel]{bugcatch}
\usepackage{xcolor}
\definecolor{mGreen}{rgb}{0,0.6,0}
\definecolor{mGray}{rgb}{0.5,0.5,0.5}
\definecolor{mPurple}{rgb}{0.58,0,0.82}
\definecolor{backgroundColour}{rgb}{0.95,0.95,0.92}
\usetikzlibrary{automata,shapes,positioning,matrix,shapes.callouts,decorations.text}
\tikzset{onslide/.code args={<#1>#2}{%
\only<#1>{\pgfkeysalso{#2}} % \pgfkeysalso doesn't change the path
}}
\tikzset{
invisible/.style={opacity=0,text opacity=0},
visible on/.style={alt={#1{}{invisible}}},
alt/.code args={<#1>#2#3}{%
\alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
},
}
\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}
}
\lstdefinestyle{CStyle}{
backgroundcolor=\color{backgroundColour},
commentstyle=\color{mGreen},
keywordstyle=\color{magenta},
numberstyle=\tiny\color{mGray},
stringstyle=\color{mPurple},
basicstyle=\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2,
language=C
}
\newcommand\bigforall{\mbox{\Large $\mathsurround0pt\forall$}}
\newcommand\tequal{$T_{\textrm{\textsf E}}$\xspace}
\newcommand\tint{$T_{\mathbb{R}}$\xspace}
\newcommand\tintz{$T_{\mathbb{Z}}$\xspace}
\newcommand\myeq{\stackrel{\mathclap{\footnotesize\mbox{def}}}{=}}
\begin{document}
\lstset{style=whyml}
\maketitle
\thispagestyle{empty}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Introduction}
In the previous lecture we studied the Nelson-Oppera procedure and the DPLL(T) framework that allows us to build decision procedures for formulas that use multiple theories. In this lecture, we will take a closer look to the theory of equality with uninterpreted functions and show how it can be used to abstract complex functions that may be hard to verify. As a real-world example, we will show how the theory of equality with uninterpreted functions can be used to prove equivalence of programs and how to use SMT solvers. Finally, we will present a decision procedure for the theory of equality with uninterpreted functions based on congruence closure.\footnote{This lecture was written by Ruben Martins, who adapted content from~\cite{Bradley2007} and~\cite{kroening}}
\section{Preliminaries}
We start by reviewing the signature and axioms of the theory of equality with uninterpreted functions.
\[
\Sigma_{\textrm{\textsf E}} : \{=, a, b, c, \ldots, f, g, h, \ldots, p, q , r, \ldots\}
\]
consists of
\begin{itemize}
\item = (equality), a binary predicate;
\item and all constant, function and predicate symbols.
\end{itemize}
The axioms of \tequal are the following:
\begin{enumerate}
\item $\forall x. x = x$ \hfill (reflexivity)
\item $\forall x, y. x = y \rightarrow y = x$ \hfill (symmetry)
\item $\forall x, y, z. x = y \wedge y = z \rightarrow x = z$ \hfill (transitivity)
\item $\forall \bar{x},\bar{y}. (\bigwedge^n_{i=1} x_i = y_i) \rightarrow f(\bar x) = f(\bar y)$ \hfill (congruence)
\item $\forall \bar{x},\bar{y}. (\bigwedge^n_{i=1} x_i = y_i) \rightarrow (p(\bar x) \leftrightarrow p(\bar y))$ \hfill (equivalence)
\end{enumerate}
Consider the $\Sigma$-formula $\varphi$
\[
f(f(f(a))) = a \wedge f(f(f(f(f(a)))))= a \wedge f(a) \neq a
\]
$\varphi$ is \tequal-unsatisfiable. We can make the following intuitive argument: substituting $a$ for $f(f(f(a)))$ in $f(f(f(f(f(a))))) = a$ by the first equality yields $f(f(a)) = a$; substituting $a$ for $f(f(a))$ in $f(f(f(a))) = a$ according to this new equality yields $f(a)=a$, contradicting the literal $f(a)\neq a$.
%
More formally, we can apply the axioms of \tequal and derive the same contradiction:
\begin{enumerate}
\item $f(f(f(f(a)))) = f(a)$ \hfill first literal of $\varphi$ (congruence)
\item $f(f(f(f(f(f(a)))))) = f(f(a))$ \hfill step 1 (congruence)
\item $f(f(a)) = f(f(f(f(f(f(a))))))$ \hfill step 2 (symmetry)
\item $f(f(a)) = a$ \hfill step 3 and second literal of $\varphi$ (transitivity)
\end{enumerate}
Note that even though we have the \textsf{equivalence} axiom, we can transform an instance of this axiom to an instance of the congruence axiom. This transformation allows us to disregard the equivalence axiom. For example, given $\Sigma$-formula:
\[
x = y \rightarrow (p(x) \leftrightarrow p(y))
\]
introduce a fresh constant $c$ and a fresh function $f_p$, and write
\[
x = y \rightarrow ((f_p(x) = c)) \leftrightarrow (f_p(y) = c))
\]
In the rest of this lecture, we will consider $\Sigma$-formulae without predicates other than $=$.
\section{Proving equivalence of programs}
Replacing functions with uninterpreted functions in a given formula is a common technique for making it easier to reason about (e.g., to prove its validity) At the same time, this process makes the formula \textit{weaker} which means that it can make a valid formula invalid. This observation is summarized in the following relation, where $\varphi^{UF}$ is derived from a formula $\varphi$ by replacing some or all of its functions with uninterpreted functions:
\[
\models \varphi^{UF} \rightarrow \varphi
\]
Uninterpreted functions are widely used in calculus and other branches of mathematics, but in the context of reasoning and verification, they are mainly used for simplifying proofs. Under certain conditions, uninterpreted functions let us reason about systems while ignoring the semantics of all functions, assuming they are not necessary for the proof.
Assume that we have a method for checking the validity of a $\Sigma$-formula in \tequal.~\footnote{Later in this lecture we will show how to check the validity of a $\Sigma$-formula in \tequal with congruence closure.} Relying on this assumption, the basic scheme for using uninterpreted functions is the following:
\begin{enumerate}
\item Let $\varphi$ denote a formula of interest that has interpreted functions. Assume that a validity check of $\varphi$ is too hard (computationally), or even impossible.
\item Assign an uninterpreted function to each interpreted function in $\varphi$. Substitute each function in $\varphi$ with the uninterpreted function to which it is mapped. Denote the new formula by $\varphi^{UF}$.
\item Check the validity of $\varphi^{UF}$. If it is valid then $\varphi$ is valid. Otherwise, we do not know anything about the validity of $\varphi$.
\end{enumerate}
As a motivating example consider the problem of proving the equivalence of two C functions shown in Figure~\ref{fig:equiv}. In general, proving the equivalence of two programs is undecidable, which means there is no sound and complete to prove such an equivalence. However, in this case equivalence can be decided since the program does not have unbounded memory usage. A key observation about these programs is that they have only bounded loops, and therefore it is possible to compute their input/output relations. The derivation of these relations from these two programs can be as follows:
\begin{figure}
\centering
\begin{subfigure}{.45\textwidth}
\begin{lstlisting}[style=CStyle]
int power3(int in)
{
int i, out_a;
out_a = in;
for (i = 0; i < 2; i++)
out_a = out_a * in;
return out_a;
}
\end{lstlisting}
\caption{}
\end{subfigure}
\begin{subfigure}{.45\textwidth}
\begin{lstlisting}[style=CStyle]
int power3_new(int in)
{
int out_b;
out_b = (in * in) * in;
return out_b;
}
\end{lstlisting}
\caption{}
\end{subfigure}
\caption{Two C functions. We can simplify the proof of their equivalence by replacing the multiplication operator by an uninterpreted function.}\label{fig:equiv}
\end{figure}
\begin{enumerate}
\item Remove the variable declarations and ``return statements''.
\item Unroll the \textbf{for} loop.
\item Replace the left-hand side variable in each assignment with a new auxiliary variable.
\item Whenever a variable is read, replace it with the auxiliary variable that replaced it in the last place where it was assigned.
\item Conjoin all program statements.
\end{enumerate}
\begin{figure}
\centering
\begin{subfigure}{.45\textwidth}
\begin{align*}
out0\_a =& in0\_a ~\wedge\\
out1\_a =& out0\_a * in0\_a ~\wedge\\
out2\_a =& out1\_a * in0\_a
\end{align*}
\caption{$(\varphi_a)$}
\end{subfigure}
\begin{subfigure}{.45\textwidth}
\begin{align*}
~\\
out0\_b =& (in0\_b * in0\_b) * in0\_b\\
~
\end{align*}
\caption{$(\varphi_a)$}
\end{subfigure}
\caption{Two formulas corresponding to the programs (a) and (b) in Figure~\ref{fig:equiv}.}\label{fig:formulas}
\end{figure}
These operations result in the two formulas $\varphi_a$ and $\varphi_b$ which are shown in Figure~\ref{fig:formulas}.
This procedure to transform code into a first-order formula is known as \textbf{static single assignment} (SSA). A generalization of this form to programs with ``if'' branches and other constructs will be further explored in future lectures when discussing bounded model checking. For this lecture, we apply a limited form of SSA to illustrate how uninterpreted functions can be used to abstract the multiplication operator.
To show that these programs are equivalent with respect to their input-outputs, we must show that the following formula $\Phi$ is valid:
\[
in0\_a = in0\_b \wedge \varphi_a \wedge \varphi_b \rightarrow out2\_a = out0\_b
\]
Showing the validity of $\Phi$ is equivalent to show the unsatisfiability of $\neg \Phi$. We can show that $\neg \Phi$ is unsatisfiable by using SMT solvers.
\section{Using SMT solvers}
SMT solvers take as input a formula in a standardize format (SMT2-Lib format). A detailed description of the SMT2-Lib format is available at:
\[
\textrm{\url{http://smtlib.cs.uiowa.edu}}
\]
SMT solvers support a variety of theories, namely: the theory of arrays with extensionality, the theory of bit vectors with arbitrary size, the core theory defining the basic Boolean operators, the theory of floating point numbers, the theory of integer number and the theory of reals.~\footnote{Further details on each theory are available at \url{http://smtlib.cs.uiowa.edu/theories.shtml}.}
If you want to try SMT solving, we recommend doing the \textsf{z3} tutorial at:
\[
\textrm{\url{https://rise4fun.com/z3/tutorial}}
\]
and trying \textsf{z3} online at:
\[
\textrm{\url{https://rise4fun.com/z3/}}
\]
Before using SMT solvers to show that $\neg \Phi$ is unsatisfiable, we must decide how we will model integers since this will restrict the underlying theories used by the SMT solver.
\subsection{Modeling integers as mathematical integers}
\begin{figure}
\centering
\begin{lstlisting}[language=Haskell]
(declare-fun out0_a () (Int))
(declare-fun out1_a () (Int))
(declare-fun in0_a () (Int))
(declare-fun out2_a () (Int))
(declare-fun out0_b () (Int))
(declare-fun in0_b () (Int))
(define-fun phi_a () Bool
(and (= out0_a in0_a) ; out0_a = in0_a
(and (= out1_a (* out0_a in0_a)) ; out1_a = out0_a * in0_a
(= out2_a (* out1_a in0_a))))) ; out2_a = out1_a * in0_a
(define-fun phi_b () Bool
(= out0_b (* (* in0_b in0_b) in0_b))) ; out0_b = in0_b * in0_b * in0_b
(define-fun phi_input () Bool
(= in0_a in0_b))
(define-fun phi_output () Bool
(= out2_a out0_b))
(assert (not (=> (and phi_input phi_a phi_b) phi_output)))
(check-sat)
\end{lstlisting}
\caption{SMT encoding of $\Phi$ using mathematical integers to model integers.}\label{fig:int}
\end{figure}
If we model integers as mathematical integer than the SMT solver will use the theory of integers and will be able to show that both programs are equivalent. Figure~\ref{fig:int} shows the SMT encoding of $\Phi$ when using integers:
%
You can try this encoding online at:
\[
\textrm{\url{https://rise4fun.com/Z3/BLQpl}}
\]
However, integers are not represented as mathematical integers in C. If we want to model integers as the ones being used in C then we should model them using bit vectors (of size 32 or 64).
\subsection{Modeling integers as bit vectors}
Modeling integers as bit vectors as the advantage of capturing the C model and being able to detect potential overflows. However, using the bit vector theory is not as efficient as using the theory of integers. In particular, assume we want to show that the programs are equivalent for a bit width of 512. The SMT encoding when using bit vectors is shown in the Figure~\ref{fig:bv}.
You can try this encoding online at:
\[
\textrm{\url{https://rise4fun.com/Z3/ibsw3}}
\]
\begin{figure}
\centering
\begin{lstlisting}[language=Haskell]
(declare-fun out0_a () (_ BitVec 512))
(declare-fun out1_a () (_ BitVec 512))
(declare-fun in0_a () (_ BitVec 512))
(declare-fun out2_a () (_ BitVec 512))
(declare-fun out0_b () (_ BitVec 512))
(declare-fun in0_b () (_ BitVec 512))
(define-fun phi_a () Bool
(and (= out0_a in0_a) ; out0_a = in0_a
(and (= out1_a (bvmul out0_a in0_a)) ; out1_a = out0_a * in0_a
(= out2_a (bvmul out1_a in0_a))))) ; out2_a = out1_a * in0_a
(define-fun phi_b () Bool
(= out0_b (bvmul (bvmul in0_b in0_b) in0_b))) ; out0_b = in0_b * in0_b * in0_b
(define-fun phi_input () Bool
(= in0_a in0_b))
(define-fun phi_output () Bool
(= out2_a out0_b))
(assert (not (=> (and phi_input phi_a phi_b) phi_output)))
(check-sat)
\end{lstlisting}
\caption{SMT encoding of $\Phi$ using bit vectors to model integers.}\label{fig:bv}
\end{figure}
This formula is much more challenging to be solved than the previous one and will become harder as the bit with increases. For example, if you try it online you will get an out of memory error. You can also try it in your own computer (since you should have \textsf{z3} installed) by running the following command:
\begin{verbatim}
$ z3 -smt2 formula
\end{verbatim}
where formula is a file with the contents of Figure~\ref{fig:bv}.
%
The reason for the memory blowup is the multiplication operator when using bit vectors. Can we avoid this issue altogether? What if we consider the multiplication operator as an uninterpreted function?
\subsection{Using uninterpreted functions}
\begin{figure}
\centering
\begin{lstlisting}[language=Haskell]
(declare-fun out0_a () (_ BitVec 512))
(declare-fun out1_a () (_ BitVec 512))
(declare-fun in0_a () (_ BitVec 512))
(declare-fun out2_a () (_ BitVec 512))
(declare-fun out0_b () (_ BitVec 512))
(declare-fun in0_b () (_ BitVec 512))
(declare-fun f ((_ BitVec 512) (_ BitVec 512)) (_ BitVec 512))
(define-fun phi_a () Bool
(and (= out0_a in0_a) ; out0_a = in0_a
(and (= out1_a (f out0_a in0_a)) ; out1_a = out0_a * in0_a
(= out2_a (f out1_a in0_a))))) ; out2_a = out1_a * in0_a
(define-fun phi_b () Bool
(= out0_b (f (f in0_b in0_b) in0_b))) ; out0_b = in0_b * in0_b * in0_b
(define-fun phi_input () Bool
(= in0_a in0_b))
(define-fun phi_output () Bool
(= out2_a out0_b))
(assert (not (=> (and phi_input phi_a phi_b) phi_output)))
(check-sat)
\end{lstlisting}
\caption{SMT encoding of $\Phi$ using an uninterpreted function for multiplication.}\label{fig:bv}
\end{figure}
If we consider an uninterpreted function $f$ that takes as input two bit vectors and returns a bit vector than we can replace the bit vector multiplication operator (\textsf{bvmul}) by $f$. If we are able to prove that this formula is unsatisfiable, then we can conclude that the original formula is also unsatisfiable and we are able to show the equivalence between the two programs when representing integers by bit vectors of width 512. This formula is much easier to be solved than the one using bit vector multiplication since we abstracted the multiplication function and the SMT solver will not need to reason about what $f$ does but only that it is a function.
%
You can try this encoding online at:
\[
\textrm{\url{https://rise4fun.com/Z3/V7Sf}}
\]
But how can we show the satisfiability of a formula with equality and uninterpreted functions? In the next section, we will show a procedure based on congruence closure to determine the satisfiability of a formula with equality and uninterpreted functions.
\section{Congruence closure}
Each positive positive literal $s = t$ of a $\Sigma$-formula $\varphi$ over \tequal asserts an equality between two terms $s$ and $t$. Applying the axioms of \tequal produces more equalities over terms that occur in $\varphi$. Since there are only a finite number of terms in $\varphi$, only a finite number of equalities among these terms are possible. Hence, one of two situations eventually occurs: either some equality is formed that directly contradicts a negative literal $s' \neq t'$ of $\varphi$; or the propagation of equalities ends without finding a contradiction. These cases correspond to \tequal-unsatisfiability and \tequal-satisfiability, respectively, of $\varphi$. In this section, we will formally describe this procedure as forming the \textbf{congruence closure} of the equality relation over terms asserted by $\varphi$.
\begin{definition}[Equivalence relation]
A binary relation $R$ over a set $S$ is an equivalence relation if:
\begin{enumerate}
\item Reflexive: $\forall_s \in S. s R s$;
\item Symmetric: $\forall_{s_1,s_2} \in S. s_1 R s_2 \rightarrow s_2 R s_1$;
\item Transitive: $\forall_{s_1,s_2,s_3} \in S. s_1 R s_2 \wedge s_2 R s_3 \rightarrow s_1 R s_3$.
\end{enumerate}
\end{definition}
For example, the relation $=$ is an equivalence relation over real numbers and $\equiv_2$ is an equivalence relation over $\mathbb{Z}$.
\begin{definition}[Congruence relation]
Consider a set $S$ equipped with functions $F = \{f_1 , \ldots, f_n\}$. A relation $R$ over $S$ is a congruence relation if it is an equivalence relation and for every $n$-ary function $f \in F$:
\[
\forall_{\bar{s},\bar{t}} \bigwedge^n_{i=1} s_i R t_i \rightarrow f(\bar s) R f(\bar t)
\]
\end{definition}
\begin{definition}[Equivalence and congruence classes]
For a given equivalence relation over $S$, every member of $S$ belongs to an equivalence class. The equivalence class of $s \in S$ under R is the set:
\[
[s]_R \myeq \{s' \in S : s R s'\}
\]
If R is a congruence relation then this set is called a congruence class.
\end{definition}
For example, the equivalence class of 1 under $\equiv_2$ are the odd numbers and the equivalence class f 6 under $\equiv_3$ the multiples of 3.
\begin{definition}[Equivalence closure]
The equivalence closure $R^E$ of the binary relation $R$ over $S$ is the equivalence relation such that:
\begin{itemize}
\item $R \subseteq R^E$;
\item for all other equivalence relations $R'$ s.t. $R \subseteq R'$, $R^E \subseteq R'$.
\end{itemize}
Thus, $R^E$ is the smallest equivalence relation that includes $R$.
\end{definition}
Let $S = \{a, b, c, d\}$ and $R = \{aRb, bRc, dRd\}$ then
\begin{itemize}
\item $aRb$, $bRc$, $dRd$ $\in R^E$ \hfill since $R \subseteq R^E$;
\item $aRa$, $bRb$, $cRc$ $\in R^E$ \hfill by reflexivity;
\item $bRa$, $cRb$ $\in R^E$ \hfill by symmetry;
\item $aRc$ $\in R^E$ \hfill by transitivity;
\item $cRa$ $\in R^E$ \hfill by symmetry;
\end{itemize}
Hence,
\[
R^E = \{aRb, bRa, aRz, bRb, bRc, cRb, cRc, aRc, cRa, dRd\}.
\]
\begin{definition}[Subterm set]
The subterm set $S_\varphi$ of $\Sigma$-formula $\varphi$ is the set that contains precisely the subterms of $\varphi$.
\end{definition}
For example, the subterm set of $\varphi$:
\[
\varphi: f(a,b) = a \wedge f(f(a,b),b) \neq a
\]
is
\[
S_\varphi = \{a, b, f(a,b), f(f(a,b),b)\}.
\]
Now we relate the congruence closure of a $\Sigma$-formula's subterm set with its \tequal-satisfiability. Given $\Sigma$-formula $\varphi$
\[
\varphi : s_1 = t_1 \wedge \ldots \wedge s_m = t_m \wedge s_{m+1} \neq t_{m+1} \wedge \ldots \wedge s_n \neq t_n
\]
with subterm set $S_\varphi$, $\varphi$ is \tequal-satisfiable iff there exists a congruence relation $\sim$ over $S_\varphi$ such that
\begin{itemize}
\item for each $i \in \{1, \ldots, m\}, s_i \sim t_i$;
\item for each $i \in \{m+1, \ldots, n\}, s_i \not\sim t_i$.
\end{itemize}
The goal of the congruence closure algorithm is to construct the congruence relation of a formula's subterm set, or to prove that no congruence relation exists. The algorithm performs the following steps:
\begin{enumerate}
\item Construct the congruence closure $\sim$ of
\[
\{s_1 = t_1, \ldots, s_m = t_m\}
\]
over the subterm set $S_\varphi$. Then
\[
\sim \models s_1 = t_1 \wedge \ldots \wedge s_m = t_m
\]
\item If $s_i \sim t_i$ for any $i \in \{m+1, \ldots, n\}$ then $\varphi$ is unsatisfiable;
\item Otherwise, $\sim \models \varphi$ and $\varphi$ is satisfiable.
\end{enumerate}
How do we actually construct the congruence closure in Step 1? Initially, begin with the finest congruence relation $\sim_0$ given by the partition
\[
\{\{s\} : s \in S_\varphi\}
\]
in which each term of $S_\varphi$ is its own congruence class. Then, for each $i \in \{1, \ldots, m\}$, impose $s_i = t_i$ by merging the congruence classes
\[
[s_i] \sim_{i-1} \textrm{~~and~~} [t_i]\sim_{i-1}
\]
to form a new congruence relation $\sim_i$. To accomplish this merging, first form the union of $[s_i]\sim_{i-1}$ and $[t_i]\sim_{i-1}$. Then propagate any new congruence that arise within this union.
Consider the $\Sigma$-formula $\varphi$
\[
\varphi : f(a,b) = a \wedge f(f(a,b),b) \neq a
\]
Construct the following initial partition by letting each member of the subterm set $S_\varphi$ be its own class:
\[
\{\{a\},\{b\},\{f(a,b)\},\{f(f(a,b),b)\}\}.
\]
According to the first literal $f(a,b) = a$, merge
\[
\{f(a,b), \{a\}\}
\]
to form partition
\[
\{\{a, f(a,b)\},\{b\},\{f(f(a,b),b)\}\}.
\]
According to the congruence axiom,
\[
f(a,b) \sim a, b \sim b \textrm{~~implies~~} f(f(a,b),b) \sim f(a,b),
\]
resulting in the new partition
\[
\{\{a, f(a,b),f(f(a,b),b)\},\{b\}\}.
\]
This partition represents the congruence closure of $S_\varphi$. Now, it is the case that
\[
\{\{a, f(a,b),f(f(a,b),b)\},\{b\}\} \models \varphi ~~?
\]
No! Since $f(f(a,b),b) \sim a$ but $\varphi$ asserts that $f(f(a,b),b) \neq a$. Therefore, $\varphi$ is \tequal-unsatisfiable.
\newpage
\section{Summary}
\begin{itemize}
\item Uninterpreted functions can be used to simplify proofs by replacing (complex) interpreted functions by uninterpreted functions;
\item Let $\varphi^{UF}$ be $\varphi$ with all its interpreted functions replaced by uninterpreted functions. Then:
\[
\models \varphi^{UF} \rightarrow \varphi
\]
\item We can use SMT solvers to check if two programs are equivalent:
\begin{itemize}
\item If we represent integers as mathematical integers than the problem is relatively easy to be solved;
\item If we represent integers as bit vectors than the problem becomes more challenging because of bit vector multiplication;
\item If we abstract bit vector multiplication with uninterpreted functions than we can achieve scalability and prove that two programs are equivalent for any bit width.
\end{itemize}
\item Congruence closure can be use to check the satisfiability of a formula with equality and uninterpreted functions.
\end{itemize}
\bibliography{platzer,bibliography}
\end{document}