SE 504 Final Exam Spring 2009 Postmortem

1. Problem A.3 asks for a specification of a program that, given a fixed array B, sets integer variables start and len to values such that len is the length of a longest segment of B in which no value occurs more than once, and such a segment begins at location start.

The problem did not mention the type of values in B, nor did it specify what predicate characterizes "equality" (or "sameness", or "non-distinctness", or whatever) of two such values. For our purposes, suppose that this type is T and that = serves as the predicate in question.

Here is (an edited version of) one student's answer:

|[ con B : array of T;
   var p,q,i,j : int;

   longest_distinct_segment

   { Q0 ∧ Q1 }
]| 
where
Q0: len = (MAX p,q | 0≤p≤q≤#B ∧ allDiff.p.q : q-p) and
Q1: start = len.p,

where
allDiff.p.q ::= (∀i,j | p≤i<j<q : B.i ≠ B.j)

Questions:

  1. Which variables ought to be declared but are not?
  2. Which variables are declared but ought not be?
  3. What's wrong with Q1?
  4. Q1 ought to be an application of allDiff(). Specifically, what should that application be (i.e., what should the arguments be)?

Another student had this postcondition:

Q: z = (MAX start,len | 0≤start≤len≤#B : noDup.start.len)

where noDup.p.q ::= (∀i | p≤i≤q : B.i ≠ B.(i+1))

Questions:

  1. Which variables ought to occur free in Q but do not?
  2. Which variables occur free in Q but should not?
  3. The quantification in Q makes no sense. Why not?
  4. The noDup() predicate is far too weak. Explain.


2. Problem A.4 asks for a specification of a program that, given a fixed integer N>2, sets integer variable p to the smallest perfect number that is greater than N.

  1. Which entities (variables and constants) ought to be declared in the formal specification?

Assume that the predicate perfect.k is satisfied if (and only if) k meets the definition of "perfect".

One student's postcondition was

Q: z = (∀i | N<i : perfect.i<perfect.(i+1) ∧ perfect.i>N)

  1. Which variable occurs free that should not?
  2. Identify all the data type incompatibilities present in this expression (and which render it meaningless).

Here's another postcondition (which is a combination of those given by two students):

Q: (∀j | j < p : ¬perfect.p)

  1. Point out its errors/omissions.

A perfect number is a positive integer that is equal to the sum of its positive divisors, excluding itself. Surprisingly, not a single student gave a correct formal definition. Here's one attempt, with some details omitted:

perfect.k ::= (∀k | ... )

  1. How can we tell, without seeing the missing details, that the definition is wrong?

Here is another attempt:

perfect.k ::= (+j | 0<j<k ∧ k%j=0 : j)

  1. By this definition, what is the "signature" of perfect (i.e., the data types of its domain and range)?
  2. To make the definition correspond to the intended meaning of perfect(), something has to be added to it. What?


3. Problem A.5 asks for a specification of a program that, given an integer array b and a constant integer K, rearranges the elements of b so that all occurrences in b of values less than K precede all occurrences in b of values greater than K.

Startlingly, only one student included in her/his postcondition the need for b's final value to be in a certain relationship to its original value.

  1. What is that relationship?

Here is one student's postcondition:

Q: (∀i,j | 0≤i≤j<#b : b.i≤K ∧ b.j≥K)

  1. Suppose that K = 8. Try to devise two different values of b, both satisfying #b = 3, say, that satisfy Q. Is it possible?

Here is another student's postcondition, which is slightly different from the one above:

Q: (∀i,j | 0≤i<j<#b : b.i≤K ∧ b.j>K)

  1. Suppose that K = 8. Try to devise a value of b, of length at least three, satisfying this Q. Is it possible?

A correct answer to the next question will put you well on your way towards formulating a "correct" postcondition:

  1. Suppose that b satisfies the (informally stated) postcondition and that b.i>K and b.j<K. What relationship must hold between i and j?


4. What stuck out most about students' answers to Problem B.1 was the incorrect usage (and omission) of square brackets. Recall from HW#9 that [k] is simply a shorthand notation for k ⊕ empty, where

⊕ : Elem × List of Elem → List of Elem

was defined in HW#7 (and where Elem is, as it were, a "generic" type that can be anything we want it to be). The other relevant operator is | (list catenation), which is associative and has signature

| : List of Elem × List of Elem → List of Elem

In Problem B.1, Elem corresponds to int and INSERT has signature

INSERT : int × List of int → List of int

Suppose that k is of type int and both x and y are of type List of int. For each of the following expressions, insert/remove square brackets where necessary in order to make the expression meaningful:

  1. k | x
  2. y | k | x
  3. y | head.x
  4. INSERT.[k].(tail.x)
  5. [k | [head.x]] | [tail.x]