\documentclass[11pt]{article}
\usepackage{palatino}
\usepackage{latexsym}
\usepackage{verbatim}
\usepackage{alltt}
\usepackage{amsmath,proof,amsthm,amssymb,enumerate}
\usepackage{math-cmds}
% FIXME be more precise about parens in question 2
\newcommand{\question}[2]
{\bigskip \noindent
{\bf Question #1} (#2 points).}
\newcommand{\minisec}[1]{\vspace{0.5cm}\noindent\textbf{#1}}
\newcommand{\extracreditquestion}[1]
{\bigskip \noindent
{\bf Question #1} (EXTRA CREDIT).}
\newcommand{\definition}[2]
{\bigskip
\begin{tabular}{p{1.5in}p{4.0in}}
\textbf{#1} & #2 \\
\end{tabular}
}
\def\prop{\textsf{\,\,prop}}
\def\thm{\textsf{\,\,thm}}
\def\implies{\Rightarrow}
\title{Lecture Notes:\\
Semantics of \textsc{While}}
\author{17-654/17-754: Analysis of Software Artifacts \\
Jonathan Aldrich ({\tt jonathan.aldrich@cs.cmu.edu})}
\date{Lectures 7-8}
\begin{document}
\newtheorem{theorem}{Theorem}
\newtheorem{lemma}[theorem]{Lemma}
\maketitle
In order to analyze programs rigorously, we need a clear definition of
what a program means. There are many ways of giving such definitions;
the most common technique for industrial languages is an English
document, such as the Java Language Specification. However, natural
language specifications, while accessible to all programmers, are often
imprecise. This imprecision can lead to many problems, such as incorrect
or incompatible compiler implementions, but more importantly for our
purposes, analyses that give incorrect results.
A better alternative, from the point of view of reasoning precisely
about programs, is a formal definition of program semantics. In this
class we will deal with \textit{operational semantics}, so named
because they show how programs operate.
\section{The \textsc{While} Language}
In this course, we will study the theory of analyses using a simple
programming language called \textsc{While}. The \textsc{While} language
is at least as old as Hoare's 1969 paper on a logic for proving
program properties (see Lecture 9). It is a simple imperative language,
with assignment to local variables, if statements, while loops, and simple
integer and boolean expressions.
We will use the following metavariables to describe several different
categories of syntax. The letter on the left will be used as a variable
representing a piece of a program; the word in bold represents the set of
all program pieces of that kind; and on the right, we describe the kind
of program piece we are describing:
\[
\begin{array}{lcll}
S & \in & \mathbf{Stmt} & \mbox{statements}\\
a & \in & \mathbf{AExp} & \mbox{arithmetic expressions}\\
x,y & \in & \mathbf{Var} & \mbox{program variables}\\
n & \in & \mathbf{Num} & \mbox{number literals}\\
P & \in & \mathbf{PExp} & \mbox{boolean predicates}\\
\end{array}
\]
The syntax of \textsc{While} is shown below. Statements $S$ can be an
assignment $x := a$, a $skip$ statement which does nothing (similar to
a lone semicolon or open/close bracket in C or Java), and if and while
statements whose condition is a boolean predicate $P$. Arithmetic
expressions $a$ include variables $x$, numbers $n$, and one of several
arithmetic operators, abstractly represented by $op_a$. Boolean
expressions include true, false, the negation of another boolean
expression, boolean operators $op_b$ applied to other boolean
expressions, and relational operators $op_r$ applied to arithmetic
expressions.
\[
\begin{array}{lll}
S & \bnfdef & x := a \\
& \bnfalt & skip \\
& \bnfalt & S_1;~ S_2 \\
& \bnfalt & \mbox{if}~ P ~\mbox{then}~ S_1 ~\mbox{else}~ S_2 \\
& \bnfalt & \mbox{while}~ P ~\mbox{do}~ S \\[1ex]
a & \bnfdef & x \\
& \bnfalt & n \\
& \bnfalt & a_1 ~op_a~ a_2 \\[1ex]
op_a & \bnfdef & + \bnfalt - \bnfalt * \bnfalt / \bnfalt \ldots \\[1ex]
P & \bnfdef & \mbox{true} \\
& \bnfalt & \mbox{false} \\
& \bnfalt & \mbox{not}~ P \\
& \bnfalt & P_1 ~op_b~ P_2 \\
& \bnfalt & a_1 ~op_r~ a_2 \\[1ex]
op_b & \bnfdef & \mbox{and} \bnfalt \mbox{or} \bnfalt * \bnfalt / \bnfalt \ldots \\[1ex]
op_r & \bnfdef & <~ \bnfalt ~\le~ \bnfalt ~=~ \bnfalt ~>~ \bnfalt ~\ge~ \bnfalt \ldots
\end{array}
\]
\section{Big-Step Expression Semantics}
We will first describe the semantics of arithmetic and boolean
expressions using big-step semantics. Big-step semantics use
judgments to describe how an expression reduces to a value. In
general, our judgments may depend on certain assumptions, such as the
values of variables. We will write our assumptions about variable
values down in an environment $E$, which maps each variable to a
value. For example, the environment $E=\{x{\mapsto}3,y{\mapsto}5\}$
states that the value of $x$ is $3$ and the value of $y$ is $5$.
Variables not in the mapping have undefined values.
We will use the judgment form $E \vdash a \Downarrow v$, read, ``In
the environment $E$, expression $a$ reduces to value $v$.'' Values
in \textsc{While} are integers $n$ and booleans (true and false).
We define valid judgments about expression semantics using a set of
inference rules. As shown below, an inference rule is made up of a
set of judgments above the line, known as premises, and a judgment
below the line, known as the conclusion. The meaning of an inference
rule is that the conclusion holds if all of the premises hold.
\[
\infer{conclusion}{premise_1 & premise_2 & \ldots & premise_n}
\]
An inference rule with no premises is called an axiom. Axioms are
always true. An example of an axiom is that integers always evaluate
to themselves:
\[
\infer[$eval-num$]{E \vdash n \Downarrow \mathbf{n}}{}
\]
In the rule above, we have written the $\mathbf{n}$ on the right hand
side of the judgment in bold to denote that the program text $n$ has
reduced to a mathematical integer $\mathbf{n}$. This distinction is
somewhat pedantic and sometimes we will omit the boldface, but it is
useful to remember that program semantics are given in terms of
mathematics, whereas mathematical numbers and operations also appear
as program text.
On the other hand, if we wish to define the meaning of an arithemetic
operator like $+$ in the source text, we need to rely on premises that
show how the operands to $+$ reduce to values. Thus we use an
induction rule with premises:
\[
\infer[$eval-plus$]
{E \vdash a + a' \Downarrow v \textbf{+} v'}
{E \vdash a \Downarrow v
& E \vdash a' \Downarrow v'
%& v'' = v \textbf{+} v'
}
\]
This rule states that if we want to evaluate an expression $a+a'$,
we need to first evaluate $a$ to some value $v$, then evaluate $a'$
to some value $v'$. Then, we can use the mathematical operator
$\mathbf{+}$ on the resulting values to find the final result $v''$.
Note that we are using the mathematic operator $\textbf{+}$ (in bold)
to define the program operator $+$. Of course the definition of $+$
could in principle be different from $\textbf{+}$--for example, the
operator $+$ in C, defined on the \texttt{\textbf{unsigned int}} type,
could be defined as follows:
\[
\infer[$eval-plus32$]
{E \vdash_C a + a' \Downarrow v''}
{E \vdash_C a \Downarrow v
& E \vdash_C a' \Downarrow v'
& v'' = (v \textbf{+} v') ~\mathbf{mod}~ 2^{32}}
\]
This definition takes into consideration that \texttt{\textbf{int}}
values are represented with 32 bits, so addition wraps around after it
reaches $2^{32}-1$--while of course the mathematical $+$ operator does
not wrap around. Here we have used the C subscript on the turnstile
$\vdash_C$ to remind ourselves that this is a definition for the C
language, not the \textsc{While} language.
Once we have defined a rule that has premises, we must think about
how it can be used. The premises themselves have to be proven with
other inference rules in order to ensure that the conclusion is
correct. A complete proof of a judgment using multiple inference
rules is called a derivation. A derivation can be represented as
a tree with the conclusion at the root and axioms at the leaves.
For example, an axiom is also a derivation, so it is easy to prove
that $5$ reduces to $\mathbf{5}$:
\[
\infer{E \vdash 5 \Downarrow \mathbf{5}}{}
\]
Here we have just applied the axiom for natural numbers, substituting
the actual number $5$ for the variable $n$ in the axiom. To prove that
$1+2$ evaluates to $\mathbf{3}$, we must use the axiom for numbers twice
to prove the two premises of the rule for $+$:
\[
\infer
{E \vdash 1 + 2 \Downarrow \mathbf{3}}
{\infer{E \vdash 1 \Downarrow \mathbf{1}}{}
& \infer{E \vdash 2 \Downarrow \mathbf{2}}{}
%& \mathbf{3} = \mathbf{1} \textbf{+} \mathbf{2}
}
\]
%The third premise, $\mathbf{3} = \mathbf{1} \textbf{+} \mathbf{2}$,
%can be established using ordinary mathematics; we do not need to
%explicitly cite an inference rule to justify this judgment.
We can write the addition rule above in a more general way to define
the semantics of all of the operators in \textsc{While} in terms of
the equivalent mathematical operators. Here we have also simplified
things slightly by evaluating the mathematical operator in the
conclusion.
\[
\infer[$eval-op$]
{E \vdash a ~op~ a' \Downarrow v ~\mathbf{op}~ v'}
{E \vdash a \Downarrow v & E \vdash a' \Downarrow v'}
\]
As stated above, the evaluation of a \textsc{While} expression may
depend on the value of variables in the environment $E$. We
use $E$ in the rule for evaluating variables. The notation
$E\{x\}$ means looking up the value that $x$ maps to in the
environment $E$:
\[
\infer[$eval-var$]
{E \vdash x \Downarrow v}
{E\{x\} = v} \\[1ex]
\]
We complete our definition of \textsc{While} expression semantics
with axioms for true, false, and an evaluation rule for not. As
before, items in regular font denote program text, whereas items in
bold represent mathematical objects and operators:
\[
\begin{array}{c}
\infer[$eval-true$]{E \vdash true \Downarrow \mathbf{true}}{} \\[1ex]
\infer[$eval-false$]{E \vdash false \Downarrow \mathbf{false}}{} \\[1ex]
\infer[$eval-not$]{E \vdash \mbox{not}~ P \Downarrow \mathbf{not}~ v}
{E \vdash P \Downarrow v}
\end{array}
\]
As a side note, instead of defining not in terms of the mathematical
operator $\mathbf{not}$, we could have defined the semantics more
directly with a pair of inference rules:
\[
\begin{array}{c}
\infer[$eval-nottrue$]
{E \vdash \mbox{not}~ P \Downarrow \mathbf{false}}
{E \vdash P \Downarrow \mathbf{true}}\\[1ex]
\infer[$eval-notfalse$]
{E \vdash \mbox{not}~ P \Downarrow \mathbf{true}}
{E \vdash P \Downarrow \mathbf{false}}
\end{array}
\]
\newcommand{\pfalse}{\mbox{false}}
\newcommand{\ptrue}{\mbox{true}}
\newcommand{\pand}{\mbox{and}}
\newcommand{\por}{\mbox{or}}
\newcommand{\pskip}{\mbox{skip}}
\newcommand{\pif}{\mbox{if}}
\newcommand{\pthen}{\mbox{then}}
\newcommand{\pelse}{\mbox{else}}
\newcommand{\pdo}{\mbox{do}}
\newcommand{\pwhile}{\mbox{while}}
%\newcommand{\p}{\mbox{}}
\newcommand{\mtrue}{\mathbf{true}}
\newcommand{\mfalse}{\mathbf{false}}
\section{Example Derivation}
Consider the following expression, evaluated in the variable
environment $E = \{x{\mapsto}5, y{\mapsto}2\}$: $(\pfalse~ \pand~
\ptrue) ~\por~ (x < ((3*y) + 1))$. I use parentheses to describe how
the expression should parse; the precedence of the operators is
standard, but as this is not a class on parsing I will generally leave
out the parentheses and assume the right thing will be done. We can
produce a derivation that reduces this to a value as follows:
\[
\infer
{E \vdash (\pfalse~ \pand~ \ptrue) ~\por~ (x < 3*y + 1) \Downarrow \mtrue}
{
\infer
{E \vdash \pfalse~ \pand~ \ptrue \Downarrow \mfalse}
{
\infer
{E \vdash \pfalse \Downarrow \mfalse}{}
& \infer
{E \vdash \ptrue \Downarrow \mtrue}{}
}
& \infer
{E \vdash x < 3*y + 1 \Downarrow \mtrue}
{
\infer
{E \vdash x \Downarrow \mathbf{5}}
{E\{x\} = \mathbf{5}}
& \infer
{E \vdash 3*y + 1 \Downarrow \mathbf{7}}
{
\infer
{E \vdash 3*y \Downarrow \mathbf{6}}
{
\infer
{E \vdash 3 \Downarrow \mathbf{3}}
{}
& \infer
{E \vdash y \Downarrow \mathbf{2}}
{E\{y\} = \mathbf{2}}
}
& \infer
{E \vdash 1 \Downarrow \mathbf{1}}
{}
}
}
}
\]
\section{Big-Step Statement Semantics}
We will use the judgment form $E \vdash S \Downarrow E'$, read,
``In the environment $E$, statement $S$ executes to produce
a new environment $E'$.''
For example, consider the rule for evaluating an assignment statement:
\[
\infer[$reduce-assign$]
{E \vdash x{:=}a \Downarrow E\{x{\mapsto}v\}}
{E \vdash a \Downarrow v} \\[1ex]
\]
This rule uses as its premise a big-step judgment evaluating the
right-hand-side expression $a$ to a value $v$. It then produces a new
environment which is the same as the old environment $E$ except
that the mapping for $x$ is updated to refer to $v$. The notation
$E\{x{\mapsto}v\}$ means exactly this.
Of course, realistic programs are made up of more than one statement.
For a sequence of two statements, we simply reduce the first and
then later the second, and thread the environment through this execution
order.
\[
\begin{array}{c}
\infer[$reduce-sequence$]
{E \vdash S_1; S_2 \Downarrow E''}
{E \vdash S_1 \Downarrow E' & E' \vdash S_2 \Downarrow E''} \\[1ex]
\infer[$reduce-skip$]{E \vdash \pskip \Downarrow E}{}
\end{array}
\]
For if statements, we evaluate the boolean condition using big-step
semantics. If the result is $\mtrue$, we evaluate the then clause of
the if statement.
Of course, we need another rule stating that if the result of the
condition is $\mfalse$, we evaluate the
statement in the else clause.
\[
\begin{array}{c}
\infer[$reduce-iftrue$]
{E \vdash \pif~ P ~\pthen~ S_1 ~\pelse~ S_2 \Downarrow E'}
{E \vdash P \Downarrow \mathbf{true} & E \vdash S_1 \Downarrow E'} \\[1ex]
\infer[$reduce-iffalse$]
{E \vdash \pif~ P ~\pthen~ S_1 ~\pelse~ S_2 \Downarrow E'}
{E \vdash P \Downarrow \mathbf{false} & E \vdash S_2 \Downarrow E'} \\[1ex]
\end{array}
\]
While loops work much like if statements. If the loop condition evaluates
to true, we replace the while loop with the loop body. However, because
the loop must evaluate again if the condition is still true after execution
of the body, we copy the entire while loop after the loop body statement.
Thus, the rewriting rules produce a copy of the loop body for each iteration
of the loop until the loop guard evaluates to false, at which point the
loop is replaced with skip.
\[
\begin{array}{c}
\infer[$reduce-whiletrue$]
{E \vdash \pwhile~ P ~\pdo~ S \Downarrow E'}
{E \vdash P \Downarrow \mathbf{true} & E \vdash S;~ \pwhile~ P ~\pdo~ S \Downarrow E'} \\[1ex]
\infer[$reduce-whilefalse$]
{E \vdash \pwhile~ P ~\pdo~ S \Downarrow E}
{E \vdash P \Downarrow \mathbf{false}} \\[1ex]
\end{array}
\]
\section{Inductive Proof for Factorial}
We would like to prove that:
\[
\forall n \ge 1 .
\{y \mapsto 1, x \mapsto n\} \vdash
\mathit{while}~ x > 1 ~\mathit{do}~ y := y*x; x := x-1 \Downarrow
\{ y \mapsto n!, x \mapsto 1 \}
\\[1ex]
\]
As discussed in class, we need to prove this by induction, but this will
only work if we strengthen the induction hypothesis. So we have the
lemma:
\[
\forall n \ge 1,m .
\{y \mapsto m, x \mapsto n\} \vdash
\mathit{while}~ x > 1 ~\mathit{do}~ y := y*x; x := x-1 \Downarrow
\{ y \mapsto m*n!, x \mapsto 1 \}
\\[1ex]
\]
We prove the lemma by induction on $n$:
\minisec{Base case:} $n = 1$
\[
\begin{array}{lll}
(1) & \{y \mapsto m, x \mapsto 1\} \vdash x > 1 \Downarrow \mathbf{false}
& $by expression evaluation$ \\[1ex]
(2) & \{y \mapsto m, x \mapsto 1\} \vdash
\mathit{while}~ x > 1 ~\mathit{do}\\
& y := y*x; x := x-1 \Downarrow
\{ y \mapsto m, x \mapsto 1 \}
& $by rule reduce-whilefalse on $(1) \\[1ex]
\end{array}
\]
\minisec{Inductive case:} $n = n' + 1$ for some $n' \ge 1$:
\[
\begin{array}{lll}
(1) & \{y \mapsto m, x \mapsto n' {+} 1\} \vdash x > 1 \Downarrow \mathbf{true}
& $by expression evaluation$ \\[1ex]
(2) & \{y \mapsto m, x \mapsto n' {+} 1\} \vdash y*x \Downarrow m*n
& $by expression evaluation$ \\[1ex]
(3) & \{y \mapsto m, x \mapsto n' {+} 1\} \vdash
y := y*x \\
& \Downarrow \{ y \mapsto m*n, x \mapsto n' {+} 1 \}
& $by rule reduce-assign on $(2) \\[1ex]
(4) & \{y \mapsto m*n, x \mapsto n' {+} 1\} \vdash x-1 \Downarrow n'
& $by expression evaluation$ \\[1ex]
(5) & \{y \mapsto m*n, x \mapsto n' {+} 1\} \vdash
x := x-1 \\
& \Downarrow \{ y \mapsto m*n, x \mapsto n' \}
& $by rule reduce-assign on $(4) \\[1ex]
(6) & \{y \mapsto m, x \mapsto n' {+} 1\} \vdash
y := y*x; x := x-1 \\
& \Downarrow \{ y \mapsto m*n, x \mapsto n' \}
& $by rule reduce-sequence on $(3), (5) \\[1ex]
(7) & \{y \mapsto m*n, x \mapsto n'\} \vdash
\mathit{while}~ x > 1 ~\mathit{do}\\
& y := y*x; x := x-1 \Downarrow \{ y \mapsto m*n*n'!, x \mapsto 1 \}
& $by induction hypothesis$ \\[1ex]
(8) & \{y \mapsto m, x \mapsto n' {+} 1\} \vdash
(y := y*x; x := x-1); \\
& \mathit{while}~ x > 1 ~\mathit{do} y := y*x; x := x-1 \\
& \Downarrow \{ y \mapsto m*n*n'!, x \mapsto 1 \}
& $by rule reduce-sequence on $(6), (7) \\[1ex]
(9) & \{y \mapsto m, x \mapsto n' {+} 1\} \vdash
\mathit{while}~ x > 1 ~\mathit{do}\\
& y := y*x; x := x-1 \Downarrow
\{ y \mapsto m*n*n'!, x \mapsto 1 \}
& $by rule reduce-whiletrue on $(1), (8) \\[1ex]
\end{array}
\]
Now the theorem will follow directly from the lemma, taking $m=1$:
\[
\begin{array}{ll}
\{y \mapsto 1, x \mapsto n\} \vdash
\mathit{while}~ x > 1 ~\mathit{do}~ y := y*x; x := x-1 \\
\Downarrow
\{ y \mapsto n!, x \mapsto 1 \} & $by the lemma above where $n=n, m=1
\end{array}
\]
\minisec{Discussion.} If we were being more rigorous, we would show
expression evaluation explicitly through rules instead of just saying
``by expression evaluation.'' However, for the assignment, we
allow you to do the inductive proof without explicitly following all
the expression evaluation rules, so I have left them out of the notes
here as well.
\end{document}