\documentstyle[12pt,pocs-header]{article}
\Scribes{Jennifer Wu and Jory Tsai}
\Lecturer{William Weihl}
\LectureNumber{6}
\LectureDate{October 1, 1990}

\large
\newcommand{\PSbox}[3]{\mbox{\rule{0in}{#3}\special{psfile=#1}\hspace{#2}}}

\begin{document}
\MakeScribeTop



\section{Administrative Information}

\begin{itemize}
\item Handout 11, 12, and 13 are distributed
\item Students should learn SPEC language well in order to gain as much as possible from this class
\item T.A. will not set up another SPEC language seminar
\item Multi-level file directory wasn't covered in this lecture  
\end{itemize}

\begin{verbatim}
Correction in handout 11: on page 11, "~m!l" should be "~a.m!l"
\end{verbatim}


\section{More Semantics of Language SPEC}


\subsection{Routines and Invocations}

     In last lecture, Butler Lampson covered some semantics of the SPEC
language.  In this lecture we will discuss a little more about the semantics
of routines and invocations, which can be found in handout 11 revision 1.


     On page 10 of Handout 11, we can find routine invocation of the form
\begin{verbatim}
 
e1(e2)    (EXISTS r: Routine | r = ME(e1)(a) 
                                /\ (r,aTr) (a{v:= ME(e2)(a)},o)

\end{verbatim}

where both e1 and e2 are expressions. 
On the right hand side of the expression is the predicate
that relates initial states to final states. 
It says that if there exists some routine with
value r, which is the meaning of e1 in the initial state a, and the 
transition relation associated with r relates initial state a,
modified to record the value of e2 in the initial state a, put it in v..
The modified state a with value of e2 in v must be related to final state o, by
the transition relation of the routine r. 

\newpage
     On page 8 of handout 11, we'll find the type definition for routines:

\begin{verbatim}

TYPE Routine = RECORD[ aTrF: En->ATr,
                                 p,
                                 enLink: UNION[En,Id]]
               WITH {en:=RoutineEn, aTr:=RoutineATr}

\end{verbatim}

A routine is a record with three components, followed by the methods
associated with this record.  These three components are: 
\begin{itemize}
\item a mapping from environment to transition:  This is because an environment
is not defined statically in the text of the routine, but is defined 
dynamically as we figure out the locations the identifiers are going to be 
bound to;
\item program counter p:  this is used for concurrency purposes and we will
not discuss this in this lecture;
\item enLink is the environment of the routine. It's either an
environment or the id of the module in which the routine is defined
if it is a routine defined in a global declaration of a module.
\end{itemize}
The associated methods are:
\begin{itemize}
\item en :  if we say r.en, where r is a routine, then we invoke a procedure
RoutineEn with argument r which extracts the environment of that
routine by either taking it out of the En component of the record or
getting the environment of the module that it's in.
\item aTr :  this method applies the routine's aTrF component
to the routine's environment to get back the actual transition relation.
\end{itemize}


\subsection{Transition Relation for the Routine}

     On page 11 of handout 11, routine FUNC MR(r) is a meaning-of-the-routine
function that takes an environment En and returns the transition relation ATr.
ATr is a function that takes two arguments, initial state a and final state o,
and returns a boolean indicating whether there is a transition from a to o.
To return a boolean, it first check the types of the arguments, etc:

\begin{verbatim}

     "a.v IN t1" means that whether a.v is of type t1, since 
     variables of a type is represented as a set in SPEC.
 
     "~a.m!l" means that the memory of initial state a is not 
     defined on location l.

     The next line says to add l to state a's memory, and store 
     a.v in location l, and augment the environment.  Then take
     state a, augmented memory, augmented environment and add 
     to outcome o2.

     o1 = o2{en:=a.en} says that state o1 is the same as state o2
     except that o2 has the original environment back.

\end{verbatim}

     The rest of body deals with exceptions and failure checks.
At the end of the body, it checks if a.v is TYPE t1.  If it is not, 
then failure exception is raised at runtime.



\section{Abstraction Functions}

     Previously we proved the correctness of modules by showing all transitions
in the implementation correspond to the transitions in the specification 
by the means of abstraction functions.  In other words, if we can map each 
state in the state space for implementation $S_{I}$ to a state in state space 
for specification $S_{S}$  with an abstraction function as the mapping
function [see fig. 1] then we can prove the correctness of the module.


\PSbox{/mit/jnfrwu/6.826/fig.1 hoffset=10 voffset=-115}{3.0in}{3.0in}
\begin{center}
FIGURE 1
\end{center}

But it turns out that abstraction function alone is not always
enough to prove the correctness of a module.  
An example is shown on page 1 in handout 12, a statistical database 
module.  With operations of size, mean, and variance,
many distinguished states will look identical when calling those functions.  
 For instance, two sequences of the same elements in different order will 
 compute to the same size, mean, and variance even though they represent two
 different states.  That is because the order in which we add elements to a
 sequence is thrown away after we do each add operation.  Therefore we can 
build an implementation state that only represents part of the state and still
meet the specification.  Such an implementation is shown on bottom of page two
in handout 12.  Now given a state of implementation with three variables 
count, sum, and sumSquare we can not come up with an UNIQUE sequence of 
elements that correspond in $S_{S}$.  That is, there is no abstract function 
that can take a state in implementation to a SINGLE state in specification.
Normally when we can use abstraction functions to prove correctness, 
the specification is an abstraction of the state of implementation,
and the implementation would 
 contain more information than the specification.  But now we have an
 implementation that is an abstraction of the state of specification and the
 specification contains more information than implementation.  We can get 
 around this by saying that the specification is wrong.  If we modify the spec
 so that it uses the smallest state domain possible then the states can't be
 reduced by any implementation.  But that's not a convinient way of doing it.

      There are two other better ways of dealing with this problem:  multi-
 value abstraction mapping, and history variables.

 
\subsection{Multi-value Abstraction Mapping}

      Multi-value Abstraction Mapping is also called "possibility mapping" by
 some people.  The idea is that instead of using abstraction functions to prove
 correctness we have abstraction relations, where you relate each state of 
 implementation to possible states of specification that it might represent.
 The problem we have with using abstraction function comes down to the fact 
 that the implementation is throwing away informations that is useful to decide
 what state we are really in abstractly [see fig. 2].

\PSbox{/mit/jnfrwu/6.826/fig.2 hoffset=10 voffset=-115}{3.0in}{3.0in}
\begin{center}
FIGURE 2
\end{center}

 Let's define the abstraction relation for our statistical database module.
 $(c, s, sSq) \sim  db$ such that db.size = c; $\sum db[i]=s$; 
$ \sum (db[i])^{2}=sSq$

 To preserve the homomorphic property we had with abstraction function, we need
 to show two things:
\begin{itemize}
\item given an initial state in implementation, it corresponds to some 
          initial state in the specification, i.e. 
          if $c\in Init_{I},   s \in Init_{S}$ such that $c\sim s$
\item if $c\in S_{I}, c\sim s, s \in S_{S}$
          (this is where the name "possibility mapping" comes from)
\end{itemize}
 Or we can say [also see fig. 3]:
$\forall\: c'\:\forall$ transition  $\: OP_{I}\; OP_{I}\:(c,c')$,
$\exists s' \in S_{S}$ such that $OP_{S}\:(s,s')$ and $c'\sim s'$


\PSbox{/mit/jnfrwu/6.826/fig.3 hoffset=10 voffset=-115}{3.0in}{3.0in}
\begin{center}
FIGURE 3
\end{center}

 Even thought abstraction relation is not complete to prove the correctness of
 a module, it is better than abstraction function.  With abstraction relation,
 no history is recorded when transitions take place.  For each state we only
 know some possible states it might go to, but we don't know what state it was
 from.  This takes us to the discussion of history variables.


\subsection{History Variables}

 In the case of the statistical database module, abstract states contain
 more information then concrete states.  So to prove the module correct, we 
 need to put those extra information back to implementation states for purposes
 of proof.  In order to do that, we can augment the implementation with extra 
 states that record those extra information.  But we have to be careful not to
 have the components of existing states dependent on any of the added
 components:

\begin{itemize}
\item existing states are independent of added history variables; and
\item results of operations are independent of added history variables.
\end{itemize}

 If we add history variables to some module, we have not changed the external
 behavior of that module, but added some statements to some of the operations
 that cause extra information to be recorded in states periodically.  (Remember
 that the augmented implementation is strictly used for the purpose of proof.
 It is not wise to use it as an actual implementation of a specification.)  The
 idea is that if we can prove the augmented implementation correct then we can
 infer that the original implementation is correct.  See the augmented version
 of the module on page 4 of handout 12.

 By adding this history variable db, we can go back and use abstraction 
 function actually.  But now the rep invariant is a lot more complicated than
 before [refer to middle of page 5 in handout 12].


\subsection{Summary}
      These two techniques are equally powerful, and we can inter-convert
 between them freely.  To use history variables, we only need to throw in all
 states of specification as history variables of implementation, and find a
 rep invariant that says how the original implementation relates to the states
 of specification.  Then we can get abstraction functions by simply throwing
 away everything but history variables.  But this is not always the most
 convinient or the simplest thing to do.  There might be a lot of states in
 implementation that are in the specification states and there is actually very
 little history variables.  But we should keep in mind that 
 efficiency is not the issue here, but what is convinient for the proof.

 The problem we've been discussing rarely happens in sequential systems.  It
 starts to show up when we talk about concurrency and non-determinism.  In
 handout 13, an example is shown to illustrate the problems non-determinism
 can cause.



\section{Nondeterministic Specifications}

     The specification has 3 states:  a, b, and c, and there are 2 operations
 that changes states:  B, and C.  If you are in initial state a, the operation
 B takes you to state b, operation C takes you to state c.  The operation
 current is nondeterministic:  if you are in state a, it returns a; but if you
 are in state b or c, it returns d or the current state [see fig. 4].

\PSbox {/mit/jnfrwu/6.826/fig.4 hoffset=10 voffset=-115}{3.0in}{3.0in}
\begin{center}
FIGURE 4
\end{center}


 A possible implementation of this is let current always return its current 
 state, so d will never appear.   Such an implementation is shown in fig. 5.

\PSbox{/mit/jnfrwu/6.826/fig.5 hoffset=10 voffset=-115}{3.0in}{3.0in} 
\begin{center}
FIGURE 5
\end{center}


 But yet another implementation can be obtained since the states b and c can be
 combined into one state.  Operations B and C can take you from state a to 
 state bc and leave you in bc once you are there.  Apply current to state a
 would return a, to state bc would return d.  Notice that there is no
 abstraction function that maps from state bc in the implementation to states b
 and c in the specification.  But with abstraction relation or history 
 variables we can easily do this mapping.  Such an implementation is shown 
 on page 2 of handout 13, also in fig. 6.


\PSbox{/mit/jnfrwu/6.826/fig.6 hoffset=10 voffset=-115}{3.0in}{1.5in}
\begin{center}
FIGURE 6
\end{center}

 We will see in the next lecture more of the limitations of abstraction 
 function with concurrent systems when we explore concurrency.  Next time we
 will also talk about multi-level file directory structure, which is different
 from the simple file system we talked about previously.

\end{document}
