Handout 9: Imperative Programs and State

Similar documents
3.7 Denotational Semantics

Lecture 1 Contracts : Principles of Imperative Computation (Fall 2018) Frank Pfenning

Polymorphic lambda calculus Princ. of Progr. Languages (and Extended ) The University of Birmingham. c Uday Reddy

Lecture 1 Contracts. 1 A Mysterious Program : Principles of Imperative Computation (Spring 2018) Frank Pfenning

Handout 10: Imperative programs and the Lambda Calculus

Propositional Logic. Part I

Fundamental Concepts. Chapter 1

Programming Languages Third Edition

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS522 Programming Language Semantics

CS 125 Section #4 RAMs and TMs 9/27/16

Chapter 3. Describing Syntax and Semantics

SOFTWARE ENGINEERING DESIGN I

This book is licensed under a Creative Commons Attribution 3.0 License

3.4 Deduction and Evaluation: Tools Conditional-Equational Logic

Note that in this definition, n + m denotes the syntactic expression with three symbols n, +, and m, not to the number that is the sum of n and m.

Programming Lecture 3

CS422 - Programming Language Design

Lecture Notes on Contracts

MITOCW watch?v=kz7jjltq9r4

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS422 Programming Language Semantics

introduction to Programming in C Department of Computer Science and Engineering Lecture No. #40 Recursion Linear Recursion

2 Introduction to operational semantics

Semantics via Syntax. f (4) = if define f (x) =2 x + 55.

A Semantics to Generate the Context-sensitive Synchronized Control-Flow Graph (extended)

6. Hoare Logic and Weakest Preconditions

1 Introduction. 3 Syntax

This is already grossly inconvenient in present formalisms. Why do we want to make this convenient? GENERAL GOALS

Goals: Define the syntax of a simple imperative language Define a semantics using natural deduction 1

Discrete Mathematics Lecture 4. Harper Langston New York University

2 Sets. 2.1 Notation. last edited January 26, 2016

CPS122 Lecture: From Python to Java last revised January 4, Objectives:

Review of Sets. Review. Philippe B. Laval. Current Semester. Kennesaw State University. Philippe B. Laval (KSU) Sets Current Semester 1 / 16

CMSC 330: Organization of Programming Languages. Operational Semantics

Mathematically Rigorous Software Design Review of mathematical prerequisites

CS4215 Programming Language Implementation. Martin Henz

Framework for Design of Dynamic Programming Algorithms

Semantics. A. Demers Jan This material is primarily from Ch. 2 of the text. We present an imperative

Imperative Functional Programming

Trees. 3. (Minimally Connected) G is connected and deleting any of its edges gives rise to a disconnected graph.

Introduction to Denotational Semantics. Class Likes/Dislikes Survey. Dueling Semantics. Denotational Semantics Learning Goals. You re On Jeopardy!

STUDENT LESSON A12 Iterations

Chapter 3. Describing Syntax and Semantics ISBN

axiomatic semantics involving logical rules for deriving relations between preconditions and postconditions.

AXIOMS FOR THE INTEGERS

Complexity Theory. Compiled By : Hari Prasad Pokhrel Page 1 of 20. ioenotes.edu.np

6.001 Notes: Section 15.1

Reading 1 : Introduction

Chapter 3. Describing Syntax and Semantics

AXIOMS OF AN IMPERATIVE LANGUAGE PARTIAL CORRECTNESS WEAK AND STRONG CONDITIONS. THE AXIOM FOR nop

A Small Interpreted Language

Introduction to Denotational Semantics. Brutus Is An Honorable Man. Class Likes/Dislikes Survey. Dueling Semantics

To prove something about all Boolean expressions, we will need the following induction principle: Axiom 7.1 (Induction over Boolean expressions):

Denotational semantics

Lecture 1. 1 Notation

1KOd17RMoURxjn2 CSE 20 DISCRETE MATH Fall

SECTION 5.1. Sequences

1.3. Conditional expressions To express case distinctions like

Complexity Classes and Polynomial-time Reductions

CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS422 Programming Language Design

[Ch 6] Set Theory. 1. Basic Concepts and Definitions. 400 lecture note #4. 1) Basics

6.001 Notes: Section 6.1

Chapter 2 The Language PCF

9. MATHEMATICIANS ARE FOND OF COLLECTIONS

Lecture Notes on Induction and Recursion

To prove something about all Boolean expressions, we will need the following induction principle: Axiom 7.1 (Induction over Boolean expressions):

Chapter 3 (part 3) Describing Syntax and Semantics

Module 2: Choice and Iteration

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011

CS 275 Automata and Formal Language Theory. First Problem of URMs. (a) Definition of the Turing Machine. III.3 (a) Definition of the Turing Machine

Verifying Safety Property of Lustre Programs: Temporal Induction

15 212: Principles of Programming. Some Notes on Induction

How invariants help writing loops Author: Sander Kooijmans Document version: 1.0

6.001 Notes: Section 4.1

Lectures 20, 21: Axiomatic Semantics

Program Analysis: Lecture 02 Page 1 of 32

, has the form T i1i 2 i m. = κ i1i 2 i m. x i1. 1 xi2 2 xim m (2)

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

Semantics. There is no single widely acceptable notation or formalism for describing semantics Operational Semantics

Lesson 20: Every Line is a Graph of a Linear Equation

EC121 Mathematical Techniques A Revision Notes

Shell CSCE 314 TAMU. Haskell Functions

Reflection in the Chomsky Hierarchy

CPS122 Lecture: From Python to Java

CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011

Formal semantics of loosely typed languages. Joep Verkoelen Vincent Driessen

Semantics of programming languages

Bootcamp. Christoph Thiele. Summer An example of a primitive universe

6.001 Notes: Section 8.1

6.001 Notes: Section 1.1

Flat (Draft) Pasqualino Titto Assini 27 th of May 2016

Distributed minimum spanning tree problem

Solution Set 8 Date: 1 December, 1992

Lecture 2: Big-Step Semantics

Lecture Notes on Arrays

Characterization of Boolean Topological Logics

SAT-CNF Is N P-complete

Z Notation. June 21, 2018

CSC Discrete Math I, Spring Sets

DEMO A Language for Practice Implementation Comp 506, Spring 2018

Transcription:

06-02552 Princ. of Progr. Languages (and Extended ) The University of Birmingham Spring Semester 2016-17 School of Computer Science c Uday Reddy2016-17 Handout 9: Imperative Programs and State Imperative programs operate on what are called variables. This was a term introduced by Goldstein and von Neumann, who wrote first the first guide for programming, 1 for a new concept that arose in imperative programming. The variables of programming have some resemblances to the variables of algebra, but they are fundamentally different. Whereas variables of algebra stand for fixed, but arbitrary, values, the variables of programming vary during the execution of the program. A better term for them would be storage locations. We can store a value in a location and, during the execution of a program, modify it to another value. Thus, imperative programs are essentially built on a notion of change which is absent in functional programs. Having to deal with change makes imperative programs more interesting, from a scientific point of view, but also more challenging in trying to reason about them. In this chapter, we deal with simple imperative programs which operate on a collection of simple variables. Each variable stores a data value, such as an integer or a boolean value, and we give the variables symbolic names so that we can refer to them. For instance, here is a simple imperative program that calculates the value of a n for non-negative integers a and n. Variables: A, N, P, I; P := 1; I := 1; while (I N) do { P := P * A; I := I + 1 The input values a and n are stored in the variables A and N and, when the program finishes, the variable P contains the result a n. The additional variables I is used internally in the program for controlling the iteration of the while-loop. Remark. Note that, in thinking about the program, we have to distinguish between the variables A, N, P and I, and the values that they store, such as a, n a n etc. To keep the distinction clear, we will use the convention of capitalized names for variables and lower case names for values. This is just a convention. Once you are comfortable with the reasoning techniques, you can feel free to use either capitalized names or lower case names for both kinds of entities. 1 The language of simple imperative programs We will discuss how to reason about such programs, i.e., how to specify their function and how to verify them. But, first, we give a rigorous definition of the class of programs we are dealing with. A program is written to work with a (finite) collection of variables, which are given symbolic names such as A, N, P and I in the above example. For discussion purposes, we assume that every program operates on a fixed collection of variables V 1,..., V n. The collection of these variables is called the store of the program. The computations carried out by the program fall into two kinds: Expressions, which read the values of variables in the current state and compute some results using functional computation. Examples of such expressions are I N and P * A in the above program. We will use the letter E to stand for expressions in general and the letter B to stand for boolean-valued expressions. 1 Goldstine and von Neumann, Planning and Coding Problems for an Electronic Computing Instrument, 1947.

Commands, which change the values of variables. Such change is not just a mathematical computation. It has a physical effect on the variables of the store. We will use the letter C to stand for commands. To describe the meaning of commands, we need to describe their effect. Here are the effects of the commands we will deal with: skip is a command, which does nothing. In typical C-like languages, it is represented by an empty group of statements {. An assignment command is of the form V := E where V is a variable and E is an expression formed using variables, constants and basic operators. The effect of the assignment command is 1. to evaluate the expression E in the current state, and 2. modify the variable V to have the value obtained from E. A sequential composition of commands is of the form C 1 ; C 2, where C 1 and C 2 are commands. Its effect is to run C 1 and then C 2. A conditional command is of the form if B then C 1 else C 2, where B is a boolean-valued expression, and C 1 and C 2 are commands. Its effect is to first evaluate the boolean expression B in the current state. If the value is true, then C 1 is run. If it is false, then C 2 is run. An iteration command is of the form while B do C, where, again, B is a boolean expression and C is a command. Its effect is to first evaluate the expression B in the current state. If B evaluates to true, then C is run and then, the entire iteration command is run again. If B evaluates to false, then the iteration command does nothing and finishes immediately. We will use braces {... to group commands instead of the normal parentheses. (This is the convention started in the C programming language and adopted widely since then.) A complete description of the syntax of commands is as follows: C ::= skip V := E C 1 ; C 2 if B then C 1 else C 2 while B do C We don t expect this syntax to be cast in stone. We might envisage adding other forms of command constructions, e.g., if-then, (without an else-clause), repeat-until loops, for-loops etc. But none of them upset the basic structure of the language given above. Equivalences for commands. If two commands C 1 and C 2 have the same effect on the store, we say that they are equivalent, and write C 1 C 2. The following equivalences are straightforward from the informal description of the effects described above: C 1 ; skip C 1 skip; C 2 C 2 {C 1 ; C 2 ; C 3 C 1 ; {C 2 ; C 3 if (not B) then C 1 else C 2 if B then C 2 else C 1 (1) Because of the third property above (which is called associativity ), it is permissible to write a sequential composition of several commands without any bracketing: {C 1 ; C 2 ;... ; C n. From the textual description of the effect of the while loop, it is easy to see that the following equivalence holds: while B do C if B then {C; while B do C else skip This just encodes the fact that, if B is true, the effect of the while loop is to run C and the whole while loop all over again. Equivalences for expressions. Note that in our idealized programming language, expressions are only allowed to read the store; they are not allowed to modify it. In other words, our expressions do not have any side effects. This has the important consequence that all the normal mathematical equations for numbers and boolean values become valid equivalences for expressions, e.g., E 1 + E 2 = E 2 + E 1 B&&false = false Such equations are not valid in general in programming languages like C or Java, because of the possibility of side effects.

P := 1; I := 1; while (I N) do { P := P * A; i := I+1 Figure 1: Program to calculate a n Points of note. The key differences between functional programs and imperative programs, which will have an impact on reasoning methods for the latter, are the following: 1. In functional programs, variable symbols name values, whereas, imperative programs, variable symbols name storage locations. 2. Locations constantly change. So, the value of a variable, such as P, or an expression, such as P * A, differ from state to state. (In contrast, in functional programs, there is no notion of change. Variables refer to fixed, unchanging values.) 3. Every command nominally acts on the entire store (the collection of all the variables that make up the context for the command). In practice, each command acts on only a small portion of the store. We refer to this portion as the footprint of the command. The footprint of the command can be easily gathered, however, by looking through the command and listing all the variables that it changes. 2 State-based reasoning The most basic theory of imperative programming views the computer acting under the control of an imperative program as a system that has various components. (In the case of simple imperative programs, the components are just the variables in the store.) As the execution of the program progress, the system goes through states. We model the effect of the program as a computation on the states. The collection of all the variables that a command accesses is referred to as the store of the command. For the a n program, reproduced in Fig 1, the store is the tuple of variables (A, N, P, I) Every command in the programs reads and writes some or all of these variables. So, the store is constantly changing. An instantaneous description of the values in the store is referred to as its state. We can write a state as a tuple of values, e.g., (7, 3, 1, 0) corresponding to the variables in the store (A,N,P,I). In this particular state, the value of A is 7, that of N is 3, that of P is 1, and that of I is 0. We can also invent notation where we label the values in the state with the variables they correspond to, e.g., (A: 7, N: 3, P: 1, I: 0) In this notes, I use just the positional notation for writing states. However, you should feel free to use the labelled notation in your own work if it helps. We can also use symbolic variables for the values of variables to obtain symbolic states. For example, the tuple (a, n, p 0, i 0 ) is a symbolic state where the values of A, N, P and I are a, n, p 0 and i 0 respectively. Symbolic states are useful for dealing with general forms of states instead of specific states. State-transformation functions. A command C changes the store. The store may be in some state before the command runs, which we call the pre-state. After the command runs, the store will be left in a new state, which we call the post-state. Therefore, we can describe the effect of the command as a mathematical function from pre-states to post-states. The effect of command C is denoted [C ], which is a function of type: [C ] : State State

It is possible to describe the function [C ] by writing equations of the form [C ](a, n, p, i) = (a, n, p, i ) However, it is more convenient to use the mapping notation: [C ] : (a, n, p, i) (a, n, p, i ) It means that the function [C ] maps the state (a, n, p, i) to the state (a, n, p, i ). We can also read it as: the effect of running command C is to transform the store from the state (a, n, p, i) to (a, n, p, i ). This notation is more convenient to use because we are often interested in the effect of a command for particular forms of the pre-states rather than all possible pre-states. The mapping notation allows us to focus on the pre-states we are interested in and ignore the others. Here are example calculations for the commands appearing in our a n program. For the first block of assignment commands, we can calculate: [P := 1] : (a, n, p 0, i 0 ) (a, n, 1, i 0 ) [I := 1] : (a, n, 1, i 0 ) (a, n, 1, 1) [P := 1; I := 1] : (a, n, p 0, i 0 ) (a, n, 1, 1) (2) Starting from an arbitrary initial state (a, n, p o, i 0 ), the command P := 1 sets the value of P to 1. The command I := 1 then sets the value of I to 1. So, the combined effect is to set both the variables to 1. For the block of commands inside the while-loop, we can calculate: [P := P A] : (a, n, p, i) (a, n, p a, i) [I := I + 1] : (a, n, p a, i) (a, n, p a, i + 1) [P := P A; I := I + 1] : (a, n, p, i) (a, n, p a, i + 1) (3) So, the combined effect of the two assignment commands is to multiply P by the value a and to increment I by 1. So, the state of the variable P changes from p to p a. The state of the variable I changes from i to i + 1. It is straightforward to calculate the state-transformation functions for sequences of assignment commands. However, it is not so immediate for iteration commands because their state-transformation functions are recursive. Denote the state-transformation function of the while-loop in our a n program by W, i.e., W = [while (I N) do {P := P A; I := I + 1] (4) The structure of the while-loop now suggests the following recursive definition for W. W (a, n, p, i) = if i n then W (a, n, p a, i + 1) else (a, n, p, i) (5) If the loop test I N is true in the start state, then the loop-body is executed, taking the state to (a, n, p a, i + 1) and the entire loop is executed again. Hence the W transformation is applied again to the new state. ( Note here that iteration in imperative programming corresponds to a recursive call in the functional formalism.) If the loop test is false in the start state, then the loop exits immediately with the result that the state is unchanged. The problem now is to discover what the function W is. We can do so by considering what it does for an arbitrary values of i less than or equal to n + 1. Here are some instances: W (a, n, p, n + 1) = (a, n, p, n + 1) W (a, n, p, n) = (a, n, p a, n + 1) W (a, n, p, n 1) = (a, n, p a a, n + 1) W (a, n, p, n 2) = (a, n, p a a a, n + 1). W (a, n, p, 1) = (a, n, p a n, 1) These instances can be generalized to the following formula: W (a, n, p, n k) = (a, n, p a k+1, n + 1) (0 k n 1) We can rewrite the equation by replacing n k by a fresh variable i (with the correspondence i = n k) and add-in the case of i > n: W (a, n, p, i) = if i n then (a, n, p a n i+1, n + 1) else (a, n, p, i)

This is now a close dform solution to the recursive equation (5). Instantiating it for the state at the end of the initialization block (2), we obtain: W (a, n, 1, 1) = if 1 n then (a, n, 1 a n 1+1, n + 1) else (a, n, 1, 1) We leave it to the reader to make the final simplifications leading to the result that the entire program has the following state-transformation function P : { (a, n, a P : (a, n, p 0, i 0 ) n, n + 1), if 0 n (a, n, 1, 1), otherwise (6) Thus, we can conclude that the program in Fig. 1 leaves the variables A and N unchanged. It overwrites the values of P and I with the values a n and n + 1 in case the initial value of N is non-negative, and with the values 1 and 1 if the initial value of N is negative. Remark. While this method for calculating the effect of commands is quite straightforward in principle, many people would regard it as quite unnatural. The reason is that it requires us to consider the effect while-loop commands for arbitrary initial states. For example, a state such as (7, 3, 20, 2), where the value if I is a negative integer and the value of P is some arbitrary number 20, is a valid input state for the W function. The formula for W tells us that the resulting final state is W (7, 3, 20, 2) = (7, 3, 20 7 6, 4). But, why do we care? A state such as (7, 3, 20, 2) will never arise during the execution of the program. So, the method is needlessly general. In order to use it for reasoning, we might need to consider quite irrelevant cases, which makes it unnatural. Loop invariants To obtain a more natural reasoning technique for imperative programs, we think of a useful a pre-condition for the while-loop command, which characterizes exactly the states that arise during the while loop. Tracing through the program, we can see that these states will be of the form: I : 1 2 3 4... n n + 1 P : 1 a a 2 a 3... a n 1 a n (7) So, we can hypothesize that the relevant states for the W transformation (4) will satisfy the conditions: 1 i n + 1, and p = a i 1. These two conditions are said to constitute the loop invariant for the while-loop. A loop invariant is a property of the states that is true in the initial state before the loop begins, and true every time a loop-body is executed and we begin the next iteration. Using this idea, we can formulate the following statement for the effect of the while-loop: Lemma 1 (1 i n + 1) (p = a i 1 ) = W (a, n, p, i) = (a, n, a n, n + 1) Proof : Assume the left hand side condition (the loop invariant). We show the right hand side by mathematical induction on the quantity (n + 1) i, which will be a natural number whenever the loop invariant holds. Case (n + 1) i = 0, i.e., i = n + 1. In this case, i = n+1, and the recursive definition (5) shows that the final state is (a, n, p, i). Since i = n+1 and p = a n by the loop invariant, we have the desired result. Case (n + 1) i = k + 1, for some natural number k, i.e., i = n k. Note that i n in this case. So, W (a, n, p, i) = W (a, n, p a, i + 1). Because (n + 1) (i + 1) = k, we can use the inductive hypothesis to conclude that W (a, n, p a, i + 1) = (a, n, a n, n + 1). But, first, we need to verify that the loop invariant holds for the new state, i.e., (1 i + 1 n + 1) (p a = a (i+1) 1 )

1 i + 1 holds because 1 i; i + 1 n + 1 holds because i n. So, 1 i + 1 n + 1. p a = a (i+1) 1 holds because p = a i 1 and p a = a i 1 a = a i. Hence, W (a, n, p, i) = W (a, n, p a, i + 1) = (a, n, a n, n + 1). QED How did we know that we had to induction on (n + 1) i? By looking at the table of values (7), we notice that the quantity (n + 1) i decreases during the execution of the loop and eventually becomes 0. This quantity is called the termination function for the loop. In this case, the termination function maps the states of the program to a natural number. In general, it can map them to any set of values for which we can do structural induction. To complete the reasoning about the program using the invariant method, we apply the result of the Lemma to calculate W (a, n, 1, 1). Since 1 1 (trivially), assuming 0 n, we have the first condition of the invariant: 1 1 n + 1. Since 1 = a 0, we have the second condition of the invariant as well. Hence, we obtain the conclusion about the state-transformation function of the program (denoted P ): 0 n = P (a, n, p 0, i 0 ) = (a, n, a n, n + 1) (8) Note that this conclusion is the same as that obtained using the previous method in (6), except that it is specialized to the cases satisfying the pre-condition. It does not say what happens when the pre-condition is not satisfied. 1. Exercise. Consider the following program for swapping the values of two variables X and Y: T := X; X := Y; Y := T Calculate its state-transformation function so that you can establish that it swaps the values of X and Y. 2. Exercise. Consider the following program for finding the maximum of integers A and B: M := A; if (B > M) then { M := B Calculate its state-transformation function so that you can establish that M will contain the maximum of A and B upon termination. 3. Exercise. Here is an alternative program to calculate a n : P := 1; while (N > 0) do { P := P * A; N := N-1 Use state-based reasoning to show that the final value of P contains a n (where a and n are the initial values of variables A and N). You may use the pre-condition n 0 to simplify the problem. 3 Denotational semantics We now give a formal definition of the state-transformation functions of commands. This will closely follow the informal definition of the effect of commands given at the beginning of this chapter. We will assume a set State of states, without explicating its precise representation. (It is an abstract type in that sense.) Tuples of values as used earlier, corresponding to a particular order of program variables, form an adequate representation of states for small programs. We will use greek letter σ to stand for states. The set State is assumed to have two functions: lookup : State Variable Value update : State Variable Value State The function lookup σ V gives the value of the variable V in the state σ. The function update σ V x gives an updated state which is the same as σ except that the value of variable V is modified to x.

The meaning of an expression E, denoted [E ], is a function of type: State Value It gives the value of the expression E in a given state σ, using the values of variables found in σ. For example [P*A] (4, 3, 16, 3) is 64. Here are some sample cases for the expression meanings: [1]] σ = 1 [V ] σ = lookup σ V [E 1 + E 2 ]σ = ([E 1 ]σ) + ([[E 2 ]σ) The meaning of a command C, denoted [C ], is a partial function of type State State It is a state-transformation function which, given a state σ, returns the state obtained by running the command C. For example, [P := P*A] (4, 3, 16, 3) = (4, 3, 64, 3). Mathematically, [C ] is in general a partial function. That means that it may not be defined for all input states, but only some of them. Since commands are not guaranteed to terminate, [C ] σ is undefined whenever the execution of C fails to terminate for a pre-state σ. We define the meaning function [C ] : State State inductively on the structure of the command C. [skip] σ = σ [V := E ] σ = update σ V ([E ] σ) [C 1 ; C 2 ] σ = [C 2 ] ([[C 1 ] σ) [if B then C 1 else C 2 ] σ = if [B ]σ then [C 1 ]σ else [C 2 ]σ [while B do C ] σ = W σ where W is the recurisvely defined partial function given by W σ = if [B ]σ then W ([C ]σ) else σ A definition of the meaning of programming language terms given in this form is termed the denotational semantics of the programming language. (The term denotation literally means meaning borrowed from Philosophy of Language.) A key property of a denotational semantic definition is that it is compositional, i.e., the meaning of a term is expressed in terms of the meaning of its subterms. Put another way, it is defined inductively (or primitive recursively) on the structure of terms. The term recursively defined partial function W used in the semantic definition of while-loop must be intuitively clear. However, mathematically, there is more analysis to be performed because there is not always a unique partial function satisfying a given recursive definition. The required analysis was carried out by Dana Scott and goes by the name domain theory. 4. Exercise. Give the denotational semantics of the command form if B then C, which lacks an else branch. (It does nothing if the condition is false.) 5. Exercise. Give the denotational semantics of the command form do C while B, where the condition B is always evaluated after executing the loop body. 6. Exercise. Prove that the equivalences given in (1) are valid in the denotational semantics, i.e., both the sides of each equivalence have the same state-transformation function. 7. Exercise. Formulate an equivalence that relates while-do loops and do-while loops. Prove its validity using the denotational semantics you have defined in the previous exercise.