Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

Midterm 1 Exam

15-122 Principles of Imperative Computation

Thursday 3rd October, 2019

Name:

Andrew ID:

Recitation Section:

Instructions
• This exam is closed-book with one sheet of notes permitted.

• You have 80 minutes to complete the exam.

• There are 4 problems on 18 pages (including 2 blank pages at the end).

• Use a dark pen or pencil to write your answers.

• Read each problem carefully before attempting to solve it.

• Do not spend too much time on any one problem.

• Consider if you might want to skip a problem on a first pass and return to it later.

• You can assume the presence of #use <util> and the arrayutil.c0 library throughout the
exam. The interface for some of these functions is repeated at the end of this exam.

Max Score
The Maximum of an Array 35
Printing Binary 30
Flippable Stacks 35
Short Answers 25
Total: 125

1
15-122 (Fall 2019) Midterm 1 Page 2/18

1 The Maximum of an Array (35 points)


The function
1 int MAX_SEG(int[] A, int lo, int hi)
2 /*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

returns the maximum value of the array segment A[lo,hi) — or int_min() if it is empty.
Note in particular that if the segment contains a single element, then it returns this element.
We will not be implementing MAX_SEG.
The next few tasks are about the function max_two_ways given below, which uses MAX_SEG as
a specification function.
3 int max_two_ways(int[] A, int n)
4 //@requires n == \length(A);
5 //@requires n > 0;
6 //@ensures \result == MAX_SEG(A, 0, n);
7 {
8 int i = 0;
9 int j = n;
10 while (i < j-1)
11 //@loop_invariant 0 <= i && i < j && j <= n;
12 //@loop_invariant MAX_SEG(A, i, j) == MAX_SEG(A, 0, n);
13 {
14 if (A[i] > A[j-1])
15 j = j - 1;
16 else
17 i = i + 1;
18 }
19 return A[i];
20 }

3pts Task 1.1 What is the outcome of executing each of the following two lines of code in coin with
contracts enabled? If a contract fails, indicate the line at which this occurs.
 
--> max_two_ways(alloc_array(int,0), 0);

Outcome:

--> max_two_ways(alloc_array(int,1), 1);

Outcome:
 


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 3/18

6pts Task 1.2 Using point-to reasoning, prove that the function call MAX_SEG(A,i,j) on line 12 is safe.
You may assume the loop invariant on line 11 valid. (You may not need all lines provided.)

To show:

A by

B by

C by

D by

E by

F by

G by

3pts Task 1.3 Which of the following would also be valid loop invariants for the loop on lines 10–18?

//@loop_invariant MAX_SEG(A, i, j) <= MAX_SEG(A, 0, n);

//@loop_invariant MAX_SEG(A, i, j) >= MAX_SEG(A, 0, n);

//@loop_invariant MAX_SEG(A, i+1, j) == MAX_SEG(A, 0, n);

//@loop_invariant i <= n;

//@loop_invariant ge_seg(MAX_SEG(A,i,j), A,0,i);

//@loop_invariant lt_seg(MAX_SEG(A,i,j), A,j,n);

7pts Task 1.4 Assume that the loop invariants on lines 11–12 are valid. Show that the function max_two_ways
is correct. (You may not need all lines provided.)

To show:

A by

B by

C by

D by

E by

F by

G by


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 4/18

3pts Task 1.5 List only the line number(s) needed to show that the loop invariant on line 12 is true
initially.

Line(s)

7pts Task 1.6 Using point-to reasoning, prove that the loop invariant on line 11 is preserved. (You may
not need all lines provided.)

To show: if
then

Case A[i] > A[j-1]:

A by

B by

C by

D by

E by

F by

G by

Case A[i] <= A[j-1]: Similar — trust us!

3pts Task 1.7 Using the format seen in class, show that the loop on lines 10–18 terminates.

3pts Task 1.8 Assuming that max_two_ways is called with an array of length k, what is its worst-case
asymptotic complexity?

O( )


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 5/18

2 Printing Binary (30 points)


In this task, we will develop code that prints a C0 integer in binary to the Unix terminal. We
will do this in several steps.
Our first step will be to write a function int_to_boolarray that converts an integer into an
array of booleans. Specifically, if
bool[] B = int_to_boolarray(x);
then B[i] == true if the ith bit of x is 1, and B[i] == false if the ith bit of x is 0.
For example, if x is 6, its binary representation as a C0 integer is

and the returned boolean array will look like

Note that bit positions are numbered from right to left while array positions from left to right.
6pts Task 2.1 Complete the code of the function int_to_boolarray. Include sufficient contracts to
allow a caller to reason about the safety of their code. On line 9, you may only use
bitwise operations (not arithmetic operations).

1 bool[] int_to_boolarray(int x)
2

3 //@ ;
4 {
5 bool[] B = ;
6

7 for (int i = ; ; i++)


8 {
9 B[i] = == 1;
10 }
11 return B;
12 }

3pts Task 2.2 What is the worst-case asymptotic complexity of int_to_boolarray. Give a brief expla-
nation.

Cost: O( )

because


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 6/18

3pts Task 2.3 Writing int_to_boolarray is tricky. Here’s a broken implementation:


1 bool[] BAD_int_to_boolarray(int x)
2 // ... contracts omitted ...
3 {
4 bool[] B = // omitted code that correctly initializes the array B
5

6 int i = 0;
7 while (x != 0) {
8 if (x % 2 != 0) B[i] = true;
9 else B[i] = false;
10 x = x >> 1;
11 i++;
12 }
13 return B;
14 }

What is wrong with this code? Give an example of an input where this manifests.

Problem(s):

Example input that causes the problem: x =

6pts Task 2.4 Hmm. . . better test int_to_boolarray vigorously. Complete the code of the function
check_bit_is_valid that returns
• true when B[i] == true and the ith bit of x is 1,
or when B[i] == false and the ith bit of x is 0.
• false in all other situations.
Include sufficient contracts to prove the safety of your code.

bool check_bit_is_valid(bool[] B, int i, int x)

//@requires ;

//@requires ;
{
int mask = ;
bool b = (x & mask) != 0;

return ;
}


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 7/18

6pts Task 2.5 Using check_bit_is_valid, write concrete test cases that will catch each of the following
possible issues with a buggy implementation of int_to_boolarray. If a test fails, the
program should abort.
a. Write a test that fails on a buggy implementation of int_to_boolarray that always
returns the array with true at every index.

int x = ;
bool[] B = ;
assert( ;

b. Write a test that fails on a buggy implementation of int_to_boolarray that returns


an array shifted by one position to the right.

c. Write a test that fails on buggy implementations of int_to_boolarray that return


the same array on every input.

6pts Task 2.6 Complete the code of the function print_boolarray_segment_as_binary that prints a
boolean array B as a sequence of n binary digits (either 0 or 1). Specifically, if B[i] is true
it should print 1 in position i, and print 0 otherwise. Include sufficient contracts to allow
you to prove the safety of this function.
Be particularly careful of the order in which bit values get printed: bit position 0 is the
rightmost in a bit pattern, but we view it as the leftmost index when drawing arrays.

void print_boolarray_segment_as_binary(bool[] B, int n)


//@requires n <= \length(B);
{
for (int i = ; ; )

//@loop_invariant i && i ;
{

}
print("\n");
}


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 8/18

3 Flippable Stacks (35 points)


Flippable stacks extend the stack interface seen in class with one additional operation
void stack_flip(stack_t S) /* O(1) */
/*@requires S != NULL; @*/ ;

The call stack_flip(S) reverses the stack S in constant time. For example, if initially S is the
stack >1 2 3 4 5 where 1 is at the top and 5 is at the bottom, after this call S will be the
stack >5 4 3 2 1 whose top is 5 and bottom 1.
The full interface of flippable stacks with integer data is given on page 17 of this exam. This
deluxe stack interface also replaces the function stack_empty seen in class with stack_size
which returns the number of elements in a stack.

Flipping a stack enables us to insert elements at either end. With this insight, we can use flip-
pable stacks to implement queues of integers, whose interface is recalled page 17 of this exam.
Here’s the beginning of this implementation (contracts have been omitted for succinctness):
typedef stack_t queue;
bool queue_empty(queue Q) { return stack_size(Q) == 0; }
queue queue_new() { return stack_new(); }

6pts Task 3.1 Complete the implementation of the functions enq and deq using flippable stacks. Recall
that they need to have constant-time complexity.

void enq(queue Q, int s) // O(1)


//@requires is_queue(Q);
//@ensures is_queue(Q);
//@ensures !queue_empty(Q);
{

int deq(queue Q) // O(1)


//@requires is_queue(Q);
//@requires !queue_empty(Q);
//@ensures is_queue(Q);
{


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 9/18

3pts Task 3.2 Complete the data structure representation function is_queue for this implementation of
queues.

bool is_queue(queue Q) {

2pts Task 3.3 Assume that the flippable stack library was written in file fstack.c0, that the above
queue library implementation is in file queue.c0 and that you have been developing a
fancy queue-based application in file main.c0. Write down the exact command you will
need to type at the Linux prompt to successfully compile your application to a.out.
 

Linux prompt>
 


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 10/18

We can also use flippable stacks as the temporary data structure in an implementation of
quicksort’s partition function. Given an array A, the idea is to store all elements smaller
than the pivot on one side of a flippable stack and all the elements larger than or equal to the
pivot on the other side. Popping the elements back into A will yield a correctly partitioned
array relative to the pivot.
8pts Task 3.4 Using flippable stacks (but not the queue library you just implemented), complete the
code of the function partition. Its contracts are exactly what we saw in class. (You may
not need all lines.)

1 int partition(int[] A, int lo, int hi)


2 //@requires 0 <= lo && lo < hi && hi <= \length(A);
3 //@ensures lo <= \result && \result < hi;
4 //@ensures ge_seg(A[\result], A, lo, \result);
5 //@ensures le_seg(A[\result], A, \result+1, hi);
6 {
7 int pivot = A[lo]; // the pivot is the first element of A[lo,hi)

9 stack_t S = ;
10 int num_smaller = 0; // number of elements smaller than the pivot

12 for (int i = lo; i < hi; i++) // Store elements in S


13 //@loop_invariant lo <= i && i <= hi;
14 {
15 if (A[i] < pivot) {

17

19

21

22 } else {
23

25

27

28 }
29 }

31 for (int i = lo; i < hi; i++) // Put elements back into A
32 //@loop_invariant lo <= i && i <= hi;
33 {
34 A[i] = pop(S);
35 }
36 return ;
37 }


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 11/18

5pts Task 3.5 What is the asymptotic complexity of this version of partition in simplest and tightest
form? What kind of bound is this?

O(log n) O(n) O(n log n) O(n2 )

O(lo) O(hi ) O(hi − lo) O(hi + lo)

O( hi−lo
2 ) O(n log(hi − lo)) O((hi − lo)2 ) O(hi 2 − lo 2 )

Which type of complexity of partition is this? (Select all that apply.)

best case average case worst case

3pts Task 3.6 Is an implementation of quicksort that uses this version of partition in-place? Briefly
explain why.

Yes No because

8pts Task 3.7 For each of the two expressions on line 34 of partition, say whether it is provably safe.
If your answer is “yes”, give a succinct point-to proof. If your answer is “no”. Give an
additional, provably valid loop invariant that would allow you to prove it is safe.

Is A[i] safe? To show:

Yes, and here’s the proof:

A by

B by

C by

No, but it would if we added the following loop invariant:

//@loop_invariant ;

Is pop(S) safe? To show:

Yes, and here’s the proof:

A by

B by

C by

No, but it would if we added the following loop invariant:

//@loop_invariant ;


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 12/18

4 Short Answers (25 points)


4pts Task 4.1 If p points to an integer x, the following function is intended to return x+1. Fill in the
body so that it compiles,it is safe, but there is a contract exploit: one can prove the post-
conditions from the preconditions but the function does not do what is intended.

int f(int* p)
//@requires p != NULL;
//@ensures \result == *p + 1;
{
;

;
}

4pts Task 4.2 Complete the contract below so that it is impossible to write an implementation that com-
piles and that is provably correct. Explain the reason in one sentence.

int g(int y)
//@requires y >= 0;
//@ensures ;

No implementation of g can be correct because

4pts Task 4.3 The function sum below returns the sum of the elements in a given int array. Fill in the
blank with one statement such that the calls
int s1 = sum(A, 10);
int s2 = sum(A, 10);

where A is any 10-element array, leads to s2 to always be equal to s1+10. Write IMPOSSIBLE
if no such statement exists.

int sum(int[] A, int n) //returns the sum of elements in A;


//@requires \length(A) == n;
{
int sum = 0;
for (int i = 0; i < n; i++) {
sum = sum + A[i];

;
}
return sum;
}


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 13/18

4pts Task 4.4 Write a precondition for the function below that allows you to prove that the body of the
function is safe. The precondition itself should be safe (it shouldn’t be possible for the
precondition to do something besides returning true or false). It should also be as weak
as possible: it should only fail when the lines in the function body would definitely cause
an error.

void h(int n, int m, int* p)

//@requires ;
{
int*[] A = alloc_array(int*, n);
for (int i = 0; i < m; i++) {
A[i] = p;
}
*A[0] = 3;
}

3pts Task 4.5 Consider the following C0 program:


int avg_and_reset_to_default(int[] A, int n) {
int sum = 0;
for (int i=0; i < n; i++) sum += A[i];
A = alloc_array(int, n);
return sum/n;
}

int main() {
// Omitted code that correctly creates array A containing [3,3,3,3]
int avg = avg_and_reset_to_default(A, 4);
//@assert avg == 3;
return A[0];
}

What will happen when running this program?

It fails to compile

It aborts with a safety error

It aborts with an arithmetic error

It aborts with an assertion error

It returns 3

It returns 0

It runs forever


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 14/18

6pts Task 4.6 Consider the following correct C0 code


int*[] A = alloc_array(int*, 3);
int* p = alloc(int);
for (int i = 0; i < 3; i++) {
*p = *p + 2;
A[i] = p;
}
p = alloc(int);
*p = 42;
Assuming the memory is empty when this code starts executing, draw the diagram of
memory at the end of this execution.


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 15/18

(This page intentionally left blank.)


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 16/18

(This page intentionally left blank.)


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 17/18

Flippable Stacks
// typedef ______* stack_t;

int stack_size(stack_t S) // O(1) // REPLACES stack_empty


/*@requires S != NULL; @*/
/*@ensures \result >= 0; @*/;

stack_t stack_new() // O(1)


/*@ensures \result != NULL; @*/
/*@ensures stack_size(\result) == 0 ; @*/ ;

void push(stack_t S, int x) // O(1)


/*@requires S != NULL; @*/ ;

int pop(stack_t S) // O(1)


/*@requires S != NULL; @*/
/*@requires stack_size(S) > 0 ; @*/ ;

void stack_flip(stack_t S) // O(1) // ADDED


/*@requires S != NULL; @*/ ;

Queues
// typedef ______* queue_t;

bool queue_empty(queue_t Q) // O(1)


/*@requires Q != NULL; @*/ ;

queue_t queue_new() // O(1)


/*@ensures \result != NULL; @*/
/*@ensures queue_empty(\result); @*/ ;

void enq(queue_t Q, int e) // O(1)


/*@requires Q != NULL; @*/ ;

int deq(queue_t Q) // O(1)


/*@requires Q != NULL; @*/
/*@requires !queue_empty(Q); @*/ ;

YOU MAY TEAR THIS PAGE OFF


c Carnegie Mellon University 2022
15-122 (Fall 2019) Midterm 1 Page 18/18

Selected arrayutil library functions

/* is_in: x in A[lo,hi) */
bool is_in(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* is_sorted: A[lo..hi) SORTED */


bool is_sorted(int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* lt_seg: x < A[lo..hi) */


bool lt_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* le_seg: x <= A[lo..hi) */


bool le_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* gt_seg: x > A[lo..hi) */


bool gt_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* ge_seg: x >= A[lo..hi) */


bool ge_seg(int x, int[] A, int lo, int hi)
/*@requires 0 <= lo && lo <= hi && hi <= \length(A); @*/ ;

/* ge_segs: A[lo1,hi1) >= B[lo2,hi2) */


bool ge_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
/*@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A); @*/
/*@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B); @*/ ;

/* le_segs: A[lo1,hi1) <= B[lo2,hi2) */


bool le_segs(int[] A, int lo1, int hi1, int[] B, int lo2, int hi2)
/*@requires 0 <= lo1 && lo1 <= hi1 && hi1 <= \length(A); @*/
/*@requires 0 <= lo2 && lo2 <= hi2 && hi2 <= \length(B); @*/ ;

YOU MAY TEAR THIS PAGE OFF


c Carnegie Mellon University 2022

You might also like