\documentstyle[12pt,twoside,amssymb,amstex]{article}

\input{macros-course-lectures}

\newcommand{\iocode}[2]{\begin{center}\footnotesize
\begin{minipage}[t]{.45\linewidth}
\hbox to\linewidth{}
#1
\end{minipage}
\hspace{.05\linewidth} 
\begin{minipage}[t]{.45\linewidth}
\hbox to\linewidth{}
#2
\end{minipage}
\end{center}}

 \newcommand{\prcef}[3]{\begin{tabbing}       
XX\=  XX\=XX\=XX\=XX\=  \kill
\protect #1\\
\>Precondition: \+ \+ \\ 
  #2  \-  \- \\ 
\>Effect: \+  \+ \\
  #3 \- \- 
\end{tabbing}} 

\def\given{\mid}

\setcounter{section}{7}

\parskip1.5ex
\parindent0pt

\begin{document}
\lecture{notes8}{Notes 8}{March 4, 1996}

\subsection{Why do Proofs?}

\begin{itemize}
\item
Convince yourself that your reasoning is correct -- that you haven't
made mistakes.
\item
Convince others. 
\item
A good proof has considerable structure, like a good program.
Much of it can be reused for other related results (like a
well-written program).
\item
A proof pins down {\em why} something is true, so you can know whether
it will stay true when things change.
\item
A failure to prove something often reveals the reason it is false.
\end{itemize}

Program verification: proof that a program does the right thing.
\begin{itemize}
\item Pentium
\item Airbus A300 (early version of control software had a bug that
  caused plane to head straight down if a certain configuration was reached)
\item Therac 25
\end{itemize}

In programming, the current state of the art is that people do not
actually prove correctness of running programs.
There has been a lot of research directed toward making this possible,
but it hasn't yet gotten far enough to be practical.
The problem is that the concepts that have to be reasoned about seem
too low-level, complicated in their details.

In contrast, people do know how to model programs/systems 
abstractly, and prove correctness of the abstract versions.
E.g., the {\em algorithm} used in a communication protocol can be
described formally, and its correctness proved.
But there is still a gap between what is verified and the actual code
that runs on real systems -- programmers implement algorithms in a
rather ad hoc manner, and errors can creep in there.
There isn't much available now to help programmers bridge this gap.

The high-level algorithm proofs are usually done as sketches.
Some are very complicated, and some errors have been found in
published proofs.
There is also considerable research in actually doing complete
algorithm proofs axiomatically, and having a computer tool (an
``automatic theorem-prover'') help in checking or even filling in the
low-level steps.
This sort of work is becoming practical.

Whether done by hand or with computer assistance, algorithm proofs are
of great help in getting your programs right (and understanding why).
This will probably be done much more in the future.
It will become an important part of quality assurance for programs.
It takes a lot of work to do it,
and you have to understand formal logic proofs before you do it.

Other examples:
\begin{itemize}
\item
Kaashoek's Orca system, for which Alan Fekete and Nancy Lynch helped to verify
the main algorithm (and found a significant logical error in the
process of doing the proof).
\item 
Current chip designs -- companies like Intel, HP are now
investing in verification people and computer tools.
\item
Communication protocols, AT\&T. 
\item
Practical verification efforts are also beginning for real-time
process control systems, e.g., those systems that control nuclear
power plants and airplanes.  Still preliminary.
\end{itemize}

Program verification is a nice complement to testing -- testing can
often detect bugs quickly.  Verification is harder, but it does help
to find deeper logical mistakes.  And when you're done, you know there
are {\em no more} errors (which testing alone can never guarantee).


\section{Distributed Algorithms}

The technique of modeling programs as state machines in order to
reason about their behavior (reachable states, invariants) extends to
parallel programs as well as sequential. \\
Even to {\em distributed algorithms}, in which there are many programs
running independently at different nodes of a network. \\
\\

\subsection{Leader Election}

Token-based leader election, in a ring of processes. \\
\\
Imagine a collection of processes numbered $1,\ldots, n$, arranged in
a ring (mod $n$). \\
Want to elect exactly one as a leader. \\
Each starts with a {\em unique identifier}, say a natural number. \\
(Any combination of identifiers can appear in the ring, as long as
there are no repeats.) \\
\\
Each process sends its own identifier clockwise to its neighbor, pass
around ring. \\
But: Each process only passes on identifiers greater than its own. \\
If a process receives its own identifer, it elects self leader. \\
(The idea is that only the max uid will succeed in getting all the way
around the ring.) \\
\\
Formally, state consists of: \\
For each $i$, $1 \leq i \leq n$: \\
$\ms{val}(i)$, $i$'s identifier (initially, all are unique) \\
$\ms{buffer}(i,i+1 \bmod n)$, a finite sequence, initially containing
just $\ms{val}(i)$ \\
(Communication buffer for messages from process $i$ to process $i+1$.) \\
$\ms{leader}(i)$, a Boolean, initially $\ms{false}$ \\
\\
\\
$\ms{move}(i)$ \\
Pre: \\
$\ms{buffer}(i-1,i)$ is nonempty \\
Eff: \\
let $t = \ms{head}(\ms{buffer}(i-1,i))$ \\
remove $\ms{head}$ of $\ms{buffer}$ \\
if $t > \ms{val}(i)$ then add $t$ to end of $\ms{buffer}(i,i+1)$ \\
if $t = \ms{val}(i)$ then $\ms{leader}(i) := \ms{true}$ \\
\\
\\
We would like to prove that exactly one $\ms{leader}(i)$ flag gets
set. \\
For now, we'll content ourselves with just showing that {\em at
most\/} one flag is set. \\ 
\\
Invt1: At most one $\ms{leader}(i)$ is $\ms{true}$. \\
\\
Needs strengthening: \\
\\
Invt2: \\
Loosely: ``A uid in a buffer is greater than the uids of all processes
that it has passed.'' \\
More formally:  If $\ms{val}(i)$ is in $\ms{buffer}(j,j+1)$, then
$\ms{val}(i)$ is greater than all of $\ms{val}(i+1), \ms{val}(i+2),
\ldots, \ms{val}(j)$. \\
\\
Can prove by induction. \\
Key is that a node only lets the value pass if it's greater. \\
\\
\\
Showing some leader is eventually elected is a liveness property;
however, showing it uses an auxiliary invariant saying that the
maximum uid is always {\em somewhere} in the state. \\
(Conservation of max uid). \\
\\

\subsection{Alternating Bit Protocol}

A common communication protocol. \\
Sending a sequence of messages from a set $M$, from process $1$ to
process $2$. \\
Using underlying FIFO communication channels, can lose or duplicate
messages. \\
Process $1$ keeps sending first message tagged with $1$. \\
When process $2$ receives, accepts and outputs. \\
Acks (repeatedly) with tag $1$. \\
When process $1$ receives $1$, starts sending next message, tagged
with $0$. \\
Process $2$ ignores tag $1$, until it sees first $0$; then accepts and
outputs, and then acks repeatedly with $0$. \\
Process $1$ now waits to receive $0$, then goes back to tag $1$. \\
Alternates. \\
\\
The claim is that this causes process $2$ to output a {\em prefix\/}
of the sequence of process $1$. \\
(To see that it gives all requires a liveness argument.) \\
\\
States: \\
$\ms{buf}_1$, a finite sequence of $M$ elements, initially arbitrary,\\
$\ms{work-buf}_1$, same, initially equal to $\ms{buf}_1$ \\
(This represents the remaining messages to be sent, whereas
$\ms{buf}_1$ represents all the messages ever submitted.) \\
$\ms{tag}_1 \in \{ 0, 1 \}$, initially $1$. \\
\\
$\ms{buf}_2$, a finite sequence of $M$ elements, initially empty,\\
$\ms{tag}_2  \in \{ 0, 1 \}$, initially $0$. \\
\\
$\ms{channel}_{1,2}$, a finite sequence of elements of $M \times \{ 0, 1 \}$, 
  initially empty, \\
$\ms{channel}_{2,1}$, a finite sequence of elements of 
  $\{ 0, 1 \}$, initially empty \\
\\


\iocode{

\prcef{$\ms{send}(m,b)_{1,2}$}
{% Pre: 
   $m = \ms{head}(\ms{work-buf}_1)$ \\
   $b = \ms{tag}_1$}
{% Eff: 
   add $(m,b)$ to end of $\ms{channel}_{1,2}$, \\
   \hspace{2mm} any number $\geq 0$ of times}

\prcef{$\ms{send}(b)_{2,1}$}
{% Pre: 
   $b = \ms{tag}_2$}
{% Eff: 
   add $b$ to end of $\ms{channel}_{2,1}$, \\
   \hspace{2mm} any number $\geq 0$ of times}

\prcef{$\ms{lose}_{2,1}$}
{% Pre: 
   $(\ms{channel}_{2,1})$ nonempty}
{% Eff: 
   remove $\ms{head}$ of $\ms{channel}_{2,1}$ \\
}

\prcef{$\ms{copy}_{2,1}$}
{% Pre: 
   $(\ms{channel}_{2,1})$ nonempty}
{% Eff: 
   copy $\ms{head}$ of $\ms{channel}_{2,1}$ \\
}

}{

\prcef{$\ms{receive}(m,b)_{1,2}$}
{% Pre: 
   $(m,b) = \ms{head}(\ms{channel}_{1,2})$}
{% Eff: 
   remove $\ms{head}$ of $\ms{channel}_{1,2}$ \\
   if $b \neq \ms{tag}_2$ then \\
   \hspace{2mm} add $m$ to $\ms{buf}_2$ \\
   \hspace{2mm} $\ms{tag}_2 := \ms{tag}_2 + 1 \bmod 2$}

\prcef{$\ms{receive}(b)_{2,1}$}
{% Pre: 
   $b = \ms{head}(\ms{channel}_{2,1})$}
{% Eff: 
   remove $\ms{head}$ of $\ms{channel}_{2,1}$ \\
   if $b = \ms{tag}_1$ then \\
   \hspace{2mm} remove head of $\ms{work-buf}_1$ (if nonempty) \\
   \hspace{2mm} $\ms{tag}_1 := \ms{tag}_1 + 1 \bmod 2$}

\prcef{$\ms{lose}_{1,2}$}
{% Pre: 
   $(\ms{channel}_{1,2})$ nonempty}
{% Eff: 
   remove $\ms{head}$ of $\ms{channel}_{2,1}$ \\
}

\prcef{$\ms{copy}_{1,2}$}
{% Pre: 
   $(\ms{channel}_{1,2})$ nonempty}
{% Eff: 
   copy $\ms{head}$ of $\ms{channel}_{1,2}$ \\
}

}

Goal invariant, Invt1: \\
$\ms{buf}_2$ is a prefix of $\ms{buf}_1$ \\
\\
Needs intermediate invariant: \\
\\
Let $\ms{tag-sequence}$ be the sequence consisting of elements of
$\ms{channel}_{2,1}$, \\
followed by $\ms{tag}_2$, \\
followed by the tag components of the elements of $\ms{channel}_{1,2}$, \\
followed by $\ms{tag}_1$. \\
\\
Use sequence concatenation notation. \\
\\
Invt2: \\
$\ms{tag-sequence}$ consists of one of the following:
\begin{enumerate}
\item
All $0$'s.
\item
All $1$'s. 
\item
A positive number of $0$'s followed by a positive number of $1$'s.
\item
A positive number of $1$'s followed by a positive number of $0$'s.
\end{enumerate}
What is being ruled out is more than one switch of tag value. \\
\\
This is proved easily by induction (no extra hypotheses needed);
\\
\\
Also need: \\
\\
Invt3: \\
If $(m,\ms{tag}_1)$ is in $\ms{channel}_{1,2}$ then $m =
\ms{head}(\ms{work-buf}_1)$. \\
\\
This again follows by induction.  Uses Invt2 in the proof. \\
(BASE:  Obvious, since no message is in the channel initially. \\
INDUCTIVE: \\
If add new message to channel, obvious.  \\
Only interesting case is if $\ms{tag}_1$ changes and there is something
else already in $\ms{channel}_{1,2}$ with the same tag. \\
But this can't happen, by Invt2 applied before the step -- since
incoming tag $= \ms{tag}_1$, all the tags in the state must be the same.) \\
\\
Finally, need: \\
Invt4: \\
1. If $\ms{tag}_1 \neq \ms{tag}_2$ then: \\
$\ms{buf}_2 \cdot \ms{work-buf}_1 = \ms{buf}_1$. \\
2. If $\ms{tag}_1 = \ms{tag}_2$ then \\
$\ms{work-buf}_1$ and $\ms{buf}_2$ are nonempty, \\
$\ms{head}(\ms{work-buf}_1) = \ms{last}(\ms{buf}_2)$, and \\
$\ms{buf}_2 \cdot \ms{tail}(\ms{work-buf}_1) = \ms{buf}_1$. \\
\\
$\ms{tail} =$ all but head. \\
\\
Invt4, part 2, easily implies the goal Invt1. \\
Also implies that $\ms{work-buf}_2$ is always nonempty when the
$\ms{receive}_1$ occurs for equal tags. \\
(So parenthetical check is always true.)
\\
Prove Invt4 by induction. \\
BASE:  \\
tags unequal, $\ms{work-buf}_1 = \ms{buf}_1$ and $\ms{buf}_2$
empty. \\
Suffices. \\
INDUCTIVE STEP: \\
When send, don't change tags or buffers. \\
So can't change the truth of the invariants. \\
So only consider receives.\\
\\
$\ms{receive}(m,b)_{1,2}$: \\
If $b = \ms{tag}_2$, nothing happens, so preserved. \\
If $b \neq \ms{tag}_2$, arriving message is same as first on
$\ms{work-buf}_1$, by Invt3. \\
Change tag to make equal, replicate $\ms{first}(\ms{work-buf}_1)$ at
end of $\ms{buf}_2$. \\
Since concatenation previously held (by inductive hypothesis),
now the modified concat does. \\
\\
$\ms{receive}(b)_{2,1}$ \\
Similar argument. \\
If $b \neq \ms{tag}_1$, nothing happens, preserved. \\
If $b = \ms{tag}_1$, change tag to make unequal, remove first element
of work-buf. \\
Since modified concat previously held (by inductive hypothesis), now
ordinary concat does. 

\end{document}
