Your name __________________________

Harvey Mudd College

CS 60 Final Exam

Spring semester, 1998

Closed book

3 hours

6 problems

250 points

Instructions

The exam is given under the conditions of the HMC honor code. You are allowed to use one 8.5" x 11" sheet, double-sided, of your own notes, but no other reference materials. Consulting with others during the examination is forbidden.

Please provide solutions to the attached problems directly on these pages. It is suggested that you look over the exam first to get an idea of how to apportion your time. Work so as to maximize total points. Do not get stuck on one problem at the expense of others.

The action items in each problem are shown in boldface.

Use the back of the previous page if you need more space for a given problem.

There is virtue in concise answers. Think before you write.


  1. [25 points]
  2. Derive a tight "O" upper bound on the computational complexity of the following program, as a function of N, an int:

    for( int i = 1; i <= N; i *= 2 )
      for( int j = 0; j < i; j++ )
        for( int k = 0; k < j; k += 2 )
          {
          … some computation using O(1) time …
          }

    answer


  3. [50 points]
  4. We wish to construct a program to simulate an arbitrary finite-state transducer. The program implements a function having three arguments: a description of the transducer, the initial state of the transducer, and an input sequence to the transducer (as a list of symbols). The program is to produce the output of the machine on the specified input sequence.

    Describe a data representation for finite-state machines in general, then construct a simulator based on your representation. You may wish to choose the representation so that you can exploit standard functions such as assoc to simplify your program. Assume that the input does not have to be checked for syntactic correctness.

    answer


  5. [50 points]
  6. A tautology checker works using a tree representation of the input data. The trees are defined by the following definition:

    The only trees are those derivable by the above rules.

    For example, the following is a tree by this definition:

    [ '+' , 'a', ['*', ['!', 'a'], 'b' ], 'c' ]

    In infix form, this tree would represent the logical expression

    a + (a' * b) + c

    Write rules for the tautology checker function, isTaut, assuming the functions hasVar, findVar, and subst are available (you do not have to code them):

    hasVar(E) returns true if E is a tree containing a variable.

    findVar(E) returns some variable in E; assume it is called only when hasVar(E) is known to be true.

    subst(C, V, E) where E is a tree, C is either '0' or '1', and V is a variable, is the tree resulting from replacing all occurrences of V in E with C, leaving other symbols unchanged.

    Assume that the input does not have to be checked for syntactic correctness.

    [Hint: When isTaut is given an expression, the first test it probably should do is check whether hasVar is true.]

    Extra credit [25 points]: Construct the recurrence for the run-time of your program and solve for an upper-bound.

    answer


  7. [50 points]
  8. Consider the following list-reversal algorithm:

    R = nil;
    while( !isEmpty(L) )
      {
      R = cons(first(L), R);
      L = rest(L);
      }

    Give the invariant, verification conditions, energy function, and proof which shows that this algorithm correctly ends up with R == reverse(L0), where L0 is the initial value of L. You may wish to make use of the functions append, reverse, and length in your invariant or energy function. [Hint: Simulate the program for a list, say L= [x1, x2, x3, …., xn]. What can you say about the value of append(reverse(L), R)?]

    answer


  9. [25 points]

    Another use of invariants is to represent properties of objects in a class which are preserved by each method. By "preserve" we mean that it is assumed that the property is true before the method is called, and the property still holds after the method calls (although it might be temporarily violated in the course of performing the method). Thus the invariant is an enabler for the method to work properly, as well as an obligation for the method to restore.

    For example, a heap (as the term is used in heapsort), is implementable as an array-like object with a particular invariant maintained by each method: Viewing the array A as a tree, A[0] is the root, and for general i, A[i] has A[2*i+1] as its left child (if any) and A[2*i+2] as its right child (if any), and also A[i] >= A[2*i+1] and A[i] >= A[2*i+2] if these respective children exist. Finally, if one or more childrent do not exist for an A[I], then no children exist for A[j] where j > i. Typical methods on a heap are max, which returns the maximum element, remove, which removes the maximum element, and insert, which inserts a new element. A heap is therefore usable as a "priority queue", in that it always returns the maximum element.

    answer


  10. [50 points]
  11. A newspaper vending machine vends papers for 25 cents each. The machine will permit nickels, dimes, and quarters to be inserted, one at a time. The machine will continue admitting coins until the quota of 25 cents is reached, at which point it will admit no further coins until the door is lifted to vend the newspaper. Further coins inserted at this point will just pass through to the return chamber. If more than the quota is inserted, for example if the customer inserts dime, dime, quarter in that order, no change is returned.

    Design an acceptor to control whether the machine will admit a coin. Please use n, d, q, and v for inputs (representing nickel, dime, quarter, and vend, respectively) and a, b, c, f, g, … for state names. Choose a state encoding (e.g. one-hot code) and show the corresponding logic equations for the next-state functions for each flip-flop you use.

    answer