\documentstyle[12pt,/nfs/thor/thor/6826/92/macros/times]{article}

\input{/nfs/thor/thor/6826/92/macros/lecture}

\Scribe{Keith M. Swartz}
\Lecturer{Bill Weihl}
\LectureNumber{2}
\LectureDate{September 16, 1992}
\begin{document}
\MakeScribeTop

\section{Administrative Note}

Bring your old handouts to class, particularly those handed out in the
last lecture.

\section{Examples of Specifications and Implementations}

\subsection{Search Specification}

The first example (from Handout 5) is a procedure for searching through an
array for a given element:

\begin{verbatim}
APROC Search (a: SEQ INT, x: INT) -> INT RAISES {NotFound} =
   << VAR i: INT | (0 <= i /\ i < a.size /\ a[i]=x) => RET i
      [*] RAISE NotFound >>
\end{verbatim}

It is important to note the distinction between this---a
specification---and an implementation.  A specification may generally be
non-deterministic: for example, the behavior of this code is undefined for
the case where the element {\tt x} appears more than once in the array.
The specification indicates that {\em any\/} {\tt i} satisfying these
constraints may be returned.

The first line of the specification is the {\em header}.  This contains
the name of the procedure or function, the names and types of its
arguments, the type of its result, and any exceptions it may raise. 

\noindent The next two lines form the {\em body}, which is enclosed in
{\em atomicity brackets}.\footnote{Until the course turns toward
concurrency and crashes, all operations may be considered to be atomic.}
The body is of the form:

\begin{verbatim}
  VAR i: INT | ..(a)..
    =>  ..(b)..
    [*] ..(c)..
\end{verbatim}

In English, this may be read as ``Choose an integer {\tt i}, such that
{\tt (a)}, then execute {\tt (b)} if one is found, otherwise execute {\tt
(c)}.'' 


The important question raised by this specification is what the actual
relation is between input and output.  The type of relation may be denoted
as:

\vskip\baselineskip

\hspace*{1.5in}\parbox{3in}{Inputs: seq int $\times$ int \hfil\break
Output: int $\cup$ \{NotFound\}}

\vskip\baselineskip

The relation itself is:

\begin{displaymath}
a,x \mapsto \{i |  a[i]=x\} \cup \{\mbox{NotFound} |
\exists\hspace*{-1.2ex}/ i \mbox{\ s.t.\ } a[i]=x\}
\end{displaymath}

\subsection{Search Implementation}

Whereas a specification merely lists the constraints on the results, an
implementation actually determines how to {\em compute\/} the results.  An
implementation may be non-deterministic too, but in the
example below, it is deterministic and returns the first result it
finds, starting at the beginning of the array, and progressing 
to the end. 

\begin{verbatim}
APROC Search (a: SEQ[INT], x: INT) -> INT RAISES {NotFound} =
  << VAR i: INT := 0 |
     DO
       i < a.size /\ a[i]#x => i:=i+1
     OD;
     i = a.size => RAISE Notfound
     [*] RET i
  >>
\end{verbatim}

This example introduces a {\tt DO} loop.  In general, it is of the form:

\begin{verbatim}
    DO          
      S         
    OD;         
\end{verbatim}

\noindent If {\tt S} has an outcome in the current state, that is, if it
relates the current state to some final state, it is executed. This is
done repeatedly, until {\tt S} fails,
at which point the loop is exited. A common form in which the loop
appears is :

\begin{verbatim}
    DO          
      P => S'  
    OD;         
\end{verbatim}

 This is equivalent to a ``while''
loop: as long as {\tt P} is true and {\tt S'} has an outcome in the
current state, it is executed.  At the
end of the loop in the example, {\em either\/} {\tt i} is equal to {\tt
a.size}, which raises the exception {\tt NotFound}, or $a[i]=x$, when it
returns {\tt i}.

Here, the implementation represents a different input-output relation
than the specification, namely,

\begin{displaymath}
a,x \mapsto \{\mbox{\sc least\ } i | 0 \leq i < a.size \wedge a[i]=x\} \cup
\{\mbox{NotFound} | \exists\hspace*{-1.2ex}/ i \mbox{\ s.t.\ } a[i]=x\}
\end{displaymath}

Testing whether or not the implementation satisfies the specification
requires passing two constraints:

\begin{displaymath}
\bullet\ \ R_{I} \subseteq R_{S}
\end{displaymath}
\vspace*{-1.8\baselineskip}
\begin{displaymath}
\bullet\ \ \mbox{Dom}(I) = \mbox{Dom}(S)
\end{displaymath}

\noindent In other words, 1) the set of all possible outcomes of the
implementation must be a subset of the outcomes the specification allows,
and 2) the domains of the implementation and specification should be
equivalent.  In this example, the implementation does satisfy the
specification, by passing these two requirements.  However, whether or not
it is the {\em right\/} specification cannot be determined: this is wholly
dependent on what the client {\em wants}, i.e.: does he want any or the
least or the greatest {\tt i}, etc.

\subsection{Binary Search Implementation}

The example above can be easily modified to allow for different details,
such as the search method used.  For instance, the user may wish to use a
binary search.  In such a case, however, the array must be sorted before
the search can be carried out.  In order to indicate this, the following
must be added to the original specification:

\begin{verbatim}
APROC Search (a: SEQ INT, x: INT) -> INT RAISES {NotFound} =
   << ~Sorted(a) => HAVOC
      [*] VAR i: INT | (0 <= i /\ i < a.size /\ a[i]=x) => RET i
          [*] RAISE NotFound >>
\end{verbatim}

Note that the routine will cause {\tt HAVOC} if the array is not sorted
first.  (The {\tt Sorted} function can be found in Handout 5.)  {\tt
HAVOC} implies that literally anything can happen.  This is the chief
method for specifying requirements or preconditions on the caller.  We
don't want to check the array to make sure it's sorted, because this would
throw away the advantage of using a binary search algorithm since the
check itself would take linear time.

Another faulty specification would be:

\begin{verbatim}
    Sorted(A) ==> VAR i: INT | ...
\end{verbatim}

\noindent This specifies that no outcome be produced in the event the array is
not sorted --- it may not return an INT or signal {\tt NotFound}.

\section{Data Abstractions}

Data abstraction allows us to encapsulate multiple operations as well as
state.  Abstraction
 removes unnecessary details from the users of the
system (i.e.: they need not be concerned with the details of the
implementation, only the manner in which the data structures change
according to the specification).  Without data abstraction it would be
quite difficult to understand systems as they become larger and their data
structures grow in complexity.

\subsection{The Simple Memory Module}

As an example, consider the simple memory module (Example 4 in Handout 5)
that keeps track of a data value for each of some domain of addresses.  In
Spec, we have several different {\em levels\/} in which to write.  Modules
are essentially a building block for name and procedure encapsulation.
Modules may have the following:

\begin{itemize}
  \setlength{\itemsep}{-4pt}
  \item Types
  \item Variables (containing the state of the module)
  \item Operations (procedures and functions)
\end{itemize}

Modules may be {\em parameterized\/}, which implies that the module may be
instantiated with different values for the different type variables; in
this case, A and D represent the address and data types in the simple
memory module.  We have a type {\tt M} that maps
addresses to data.   Declarations
of variables, unless explicitly specified, take on the (implicit) type of
its capitalized equivalent, e.g.: {\tt m} takes on the type {\tt M.}
(This is simply a convention of SPEC; for further information, read the
SPEC Reference Manual---Handout 4.)  The state of the simple memory module
is simply one of these functions---at any point in time one can think of
the state as being a function of addresses to data.

There are five procedures in this example:

\begin{itemize}
  \setlength{\itemsep}{-4pt}
  \item Init (chooses an {\em arbitrary\/} TOTAL mapping, so that {\tt m} is
        defined over all addresses).
  \item Reset (reset state of memory with value {\tt d}, e.g.: for zeroing
        out space).\footnote{Introduces  the mapping constructor {\tt *
        ->}, which appears in the form {\tt S\{ * -> q\}}, and maps all
        elements of sequence {\tt S} to the value {\tt q}.}
  \item Read (returns the current state of the memory for the given
        address {\tt a}).
  \item Write (writes value of {\tt d} to address {\tt a}).
  \item Swap (swaps the value of address {\tt a} with the new value {\tt
        d} and returns the old one).
\end{itemize}

It is required that {\tt Init} be called before any of the other routines.
Spec does not have a formal method of stating such requirements, so we
simply list it as a comment.  Note that a write can be expressed by the
expression {\tt m := m\{a->d\}}, which is a function constructor that takes
in a function {\tt m} and sets it to another function that has the same
values as the original {\tt m} except with the value of {\tt a} mapped to
the value {\tt d}.

This a simple example of data abstraction.  For {\em procedures\/} we use
relations between input and output in which the input and output may
include state.  What is the abstract behavior, or what do the users {\em
depend\/} on?  Users care about the responses to a sequence of invocations
of the various routines (e.g.: initialize followed by some sequence of
reads, writes, and swaps).  Initialize and write simply return without
passing any information back to the user, while read and swap pass back
data to the user.

A {\em transition} between states is labelled by the invocation/response
pair, and a {\em trace} is a sequence of such transitions.
 In a configuration where {\tt A} is the set \{1,2,3,4\}
and the domain of possible data values {\tt D} is \{a,b,c\}, any
single state may be represented as four values, each being one of a, b, c,
or nothing.\footnote{Actually, it can be shown that no reachable state
ever has a value of ``nothing''; a valid initial state has all locations full,
and no function exists for ``erasing'' a location.} Below are
illustrations of a few possible transitions:

\vskip\baselineskip
\begin{tabular}{|l|l|c|l|l|c|l|l|}
\cline{1-2} \cline{4-5} \cline{7-8}
A & D & & A & D & & A & D \\ \cline{1-2} \cline{4-5}  \cline{7-8}
1 & a & & 1 & b & & 1 & / \\ \cline{1-2} \cline{4-5}  \cline{7-8}
2 & c & $\longrightarrow$ & 2 & b & $\longleftarrow$ & 2 & / \\
  \cline{1-2} \cline{4-5}  \cline{7-8}
3 & b & (Reset(b),RET) & 3 & b & (Reset(b),RET) & 3 & / \\
  \cline{1-2} \cline{4-5}  \cline{7-8}
4 & a & & 4 & b & & 4 & / \\ \cline{1-2} \cline{4-5}  \cline{7-8}
\end{tabular}

\setlength{\unitlength}{1in}
\begin{picture}(1.5,.6)(0,0)
\put(.25,.2){\oval(.35,.4)[b]}
\put(.6,.35){\makebox(0,0)[tl]{(Read(3),b)}}
\put(.075,.45){\line(0,-1){.25}}
\put(.425,.2){\vector(0,1){.3}}
\end{picture}

\vskip\baselineskip

Note how the resulting state is unchanged for operations without side
effect (e.g.: {\tt Read}).

\subsection{Memory Module with Write-back Cache Implementation}

The memory module specification may now be used to create an
implementation; particularly, one that uses a write-back cache.  The
implementation requires that the number of entries defined in the cache
(effectively, the size of the cache) be a built-in constant; for the
purposes of this example, we will assume that size ({\tt CSIZE}) is 2.
The implementation basically says:

\begin{enumerate}
  \setlength{\itemsep}{-4pt}
  \item if the data corresponding to the requested memory address is 
        in the cache, return that value
  \item otherwise return the value value stored in the main memory
\end{enumerate}

\noindent Similarly, the cache is written to first, then this value is
moved into memory when the cache needs to be flushed.

Because it would be impossible to enumerate all sequences, proofs are done
inductively.  The {\em state machine\/} is a useful abstraction.  For the
memory example, suppose that {\tt A} and {\tt D} are defined as before,
and we have a two-location cache.  The state of memory prior to
initialization could also be undefined.  It is interesting to note that
there is
non-determinism in the system; for example, the state returned when a
value is read from a memory address that is not cached.  There are several
possibilities as to which cache item is actually flushed.  (See
Figure~\ref{caches}.)  All of these instances must be restricted in order
to have a correct implementation.\footnote{Correctness: next lecture.}

\begin{figure}
\label{caches}
\vskip\baselineskip
\hspace*{1.8in}
\begin{tabular}{|l|l|l|c|l|l|l|}
\cline{1-3} \cline{5-7}
A & D & C & & A & D & C \\ \cline{1-3} \cline{5-7}
1 & a & a & & 1 & a & / \\ \cline{1-3} \cline{5-7}
2 & c & c & $\longrightarrow$ & 2 & c & c \\ \cline{1-3} \cline{5-7}
3 & b & / & (Read(3),b) & 3 & b & b \\
  \cline{1-3} \cline{5-7}
4 & a & / & & 4 & a & / \\ \cline{1-3} \cline{5-7}
\end{tabular}
\vskip\baselineskip

\hspace{2.18in}\vrule height 6.6ex \kern-.035in\lower1ex\hbox{$\downarrow$}
\raise1.8ex\hbox{(Read(3),b)}

\vskip\baselineskip
\hspace*{1.8in}
\begin{tabular}{|l|l|l|}
\hline
A & D & C \\ \hline
1 & a & a \\ \hline
2 & c & / \\ \hline
3 & b & b \\ \hline
4 & a & / \\ \hline
\end{tabular}
\caption{Non-deterministic state transition of {\tt Read}.}
\vskip\baselineskip
\end{figure}

One way of viewing these state machines ``abstractly'' is simply as a set
of traces.  These traces describe the behavior of the interface between
the user and the module.  The user has no knowledge about how these
results are generated and cannot access the internal state of the module.
A sample set of traces for the above example might be:

\begin{center}
\begin{tabular}{l|l}
Invocation/Response & Description \\ \hline
(Reset(c),RET)	& Reset all values to c (returns nothing) \\
(Read(1),c)	& Read location 1 (returns ``c'') \\
(Write(2,b),RET) & Write {\tt b} to location 2 (returns nothing) \\
(Read(2),b) & Read location 2 (returns ``b'')
\end{tabular}
\end{center}

This specification is deterministic in that, given a set of invocations,
there is a single set of responses that is acceptable.  This {\bf is not}
true in the general case---there may often be multiple responses.  So, the
specification can be thought of as a relation of invocation sequences to
response sequence.  In real life, this will be executed as one invocation
at a time, but abstractly it is possible to model it as giving the module
a set of invocations and looking at the sequence of return values.

So, if we consider a module as just a set of traces of input sequences to
output sequences, it is very abstract.  This is useful when we think about
{\em correctness}---our abstract view of our module, and exactly what the
specification denotes---which is also the information provided to a client
(i.e.: what the client can depend on).  The text of the implementation can
be abstracted in the same way to a set of traces that the implementation
will generate.

\vfil

\noindent\rule{1in}{.4pt}

{\small {\bf Acknowledgements} to Carl G. Heinzl for the excerpts in
sections 3.1 and 3.2 that are from his notes last year.}

\end{document}
