cs205: engineering software?
05 April 2010
Midterm Exam Out: 29 September 2006
Due: Monday, 2 October, 1:01pm

Name: _________________________________________________________


Work alone. You may not discuss these problems or anything related to the material covered by this exam with anyone except for the course staff between receiving this exam and class Monday.

Open non-human resouces. You may use any books you want, lecture notes and slides, your notes, websites, and problem sets. If you use anything other than the course books and notes, cite what you used. You may not use other people.

Closed tools. You may not run a Java compiler for this exam. For questions that expect you to write code, you will not lose points for minor syntactic mistakes.

Think. Unlike the quizzes, all of the questions on this exam are intended to make you think, not just repeat something you already know. You shouldn't expect to find the exact answers to the questions here in the course materials (or any other resources you find), but should be able to deduce good answers based on your understanding of the course material and ability to reason using that understanding.

Answer well. Write your answers on this exam. You should not need more space than is provided to write good answers, but if you want more space you may attach extra sheets. If you do, make sure the answers are clearly marked. If you prefer to type your answers instead of writing on this exam, that is fine as long as your answers are clearly marked. Some of the pages of this exam contain specifications or code with no questions. You should feel free to tear those pages out of the exam so you can look at them while you answer the questions on the following page.

This exam has 10 graded questions, in addition to two non-credit questions. The questions are not necessarily in order of increasing difficulty, so if you get stuck on one question you should continue on to the next question. There is no time limit on this exam.

Full credit depends on the clarity and elegance of your answer, not just correctness. Your answers should be as short and simple as possible, but not simpler.


Consider the histogram specification from problem set 2 (question 4):
public static int [] histogram (int [] a) throws NegativeValue
   // EFFECTS:  If a contains any negative values, throws NegativeValue.
   //    If a is null, throws a NullPointerException.
   //    Otherwise, returns an array, result, where result[x] is the
   //    number of times x appears in a.  The result array has
   //    maxval(a) + 1 elements.  For example, 
   //      histogram ({1, 1, 2, 5}) = { 0, 2, 1, 0, 0, 1 }
1. (10) Describe a good set of black box test cases for the histogram procedure, as specified above.

2. (10) If an implementation of histogram successfully passes all of your test cases, what can you say about the implementation?

Data Abstraction

Patty Page is implementing a new web search engine. Similar to popular search engines, her search engine will rank pages in response to a query based on the number of times the query word appears on the page, as well as a measure of its popularity based on the number of other pages that link to this page (and how popular they are).

Her design involves two datatypes: WordIndex, a reverse index that maps words to the pages on which they appear, and PageGraph, a graph representing the links between pages.

Consider the specification below for the WordIndex datatype:

public class WordIndex
   // OVERVIEW: A WordIndex is a mutable datatype for representing
   //    the words appearing in a collecting of pages.  For each
   //    word entry, there is an occurance list of < page, count >
   //    entries where page is the URL of a page containing the word,
   //    and count is the number of times the word appears on that page.
   //    A typical WordIndex is:
   //       { < word_1, [ < page_1_1, count_1_1 >, 
   //                        ..., < page_1_m, count_1,m> ] >,
   //         ...
   //         < word_n, [ < page_n_1, count_n_1 >, 
   //                        ..., < page_n_k, count_n_k> ] > }
   //    A given page may appear in a word's associated list at most once.  
   //    A given word may not appear as a key in the WordIndex more 
   //        than once.

   public WordIndex()
      // EFFECTS: Initializes this to an empty WordIndex: {}

   public void addInstance(String word, String page)
      // MODIFIES: this
      // EFFECTS: If word is not a word in this, adds a new entry 
      //   to this:
      //     this_post = this_pre U { < word, [ < page, 1 > ] }
      //   Otherwise, if the occurance list associated with word does not
      //     include page, adds and entry for page with count 1 to word's 
      //     occurance list.
      //   Otherwise, adds one to the count associated with word for page.

   public int getCount(String word, String page)
      // EFFECTS: Returns the number of times page contains the word 
      //     in this.
      //   If this has no entry for word, the result is 0.
      //   If there is an entry for word, but the occurance list does not
      //      include page, the result is 0.
      //   Otherwise, the result is the count value associated with the
      //      entry for page in the occurance list for word.

3. Suppose an implementation that satisfies this specification is available. Will this be useful for Patty's search engine implementation? (Either explain how Patty would use this datatype, or what essential functionality she needs is missing and cannot be created using the abstract operations provided.)

Here is a partial implementation of the specified WordIndex datatype:
    // Rep:
    class PageRecord {
       String url;
       int count;
       PageRecord (String url, int count) {
          this.url = url;
          this.count = count;
    class WordRecord {
        String word;
        Vector<PageRecord> occurences;
        WordRecord (String word) {
           this.word = word;
           this.occurences = new Vector<PageRecord>();

    private Vector<WordRecord> entries;

    // Abstraction Function (r) = 
    // { < word_i, [ < page_i_j, count_i_j > ] > |
    // where  
    //    word_i = entries.elementAt(i).word
    //    page_i_j = entries.elementAt(i).occurences.elementAt(j).url
    //    count_i_j = entries.elementAt(i).occurences.elementAt(j).count
    //    forall 0 ≤ i < entries.size ()
    //    forall 0 ≤ j < entries.elementAt(i).occurences.size()

    public void addInstance(String word, String page) {
       for (WordRecord r : entries) {
           if (r.word.equals(word)) {
              for (PageRecord p : r.occurences) {
                 if (p.url.equals(page)) {
                    p.count = p.count + 1;
              // No page record found, add a new one with count 1
              r.occurences.add (new PageRecord (page, 1));
      WordRecord wr = new WordRecord (word);
      wr.occurences.add (new PageRecord (page, 1));
      entries.add (wr);

4. (10) Define an adequate rep invariant for the WordIndex implementation shown.

5. (10) Assuming the rep invariant from your previous answer, provide a correct implementation of the getCount method.
public int getCount(String word, String page) {

To represent the link structure, Page proposes to use the PageGraph abstract datatype, partially specified below:
public class PageGraph
   // OVERVIEW: A PageGraph is a mutable datatype that represents a
   //    set of hypertext pages including links between the pages.
   //    A typical PageGraph is:
   //     { <url_1, [ <tag_1_1, target_1_1>, 
   //                    ..., < tag_1_m, target_1_m > ],
   //       ...
   //       <url_n, [ <tag_n,1, target_n_1>, 
   //                    ..., <tag_n_k, target_n_k> ] }
   //    where the target_i_j's are URLs that may or may not 
   //    correspond to url_k's in the PageGraph.

   public PageGraph() 
      // EFFECTS: Initializes this to a new, empty PageGraph: { }

   public void addPage(String url, String [] tags, String [] targets)
      throws DuplicateException
      // MODIFIES: this
      // EFFECTS: If url is a url in this, throws DuplicateException.  
      //    Otherwise, adds a new page to the page graph with URL url:
      //      this.post = this.pre U
      //         { < url,
      //              [ < tags[0], targets[0] >, ... <
      //                < tags[tags.length - 1], 
      //                            targets[targets.length - 1 > ]
      //           >  }
   public String [] getTargets(String url)
      // EFFECTS: If url is a url in this, returns an array
      //    representing the targets of links from url.

6. (10) Patty wants to add an addLink method to PageGraph so links can be added to pages in the PageGraph. The addLink method should take three String parameters: the URL, the tag, and the target. It should add < tag, target > to the link list associated with the URL. Write a declarative, total specification of addLink. Your specification should cover all possible inputs, making reasonable assumptions for what to do in cases that are not clear from this description.

Patty proposes to implement PageGraph using the following representation:
   // rep:
   class LinkRecord {
      String tag;
      String target;

   class PageRecord {
      String url;
      Vector<LinkRecord> links;

   private Vector<PageRecord> pages;
7. (10) Write a plausible abstraction function for Patty's representation.

8. (10) Write a rep invariant for the PageGraph implementation.

Suppose the overview specification was changed to use a different abstract notation for the PageGraph:
   // ... A typical PageGraph is:
   //  < [ url_1, ..., url_n ];,
   //       [ <url_k1, tag_k1, target_k1>, 
   //         ..., <url_km, tag_km, target_km ] >
   // where the target_i_j's are URLs that may or may not 
   // correspond to url_k's in the PageGraph.
9. (10) Write a plausible abstraction function for the new specification, assuming the same representation as in questions 7 and 8, but the new overview specification.


Consider the two interfaces defined below:
public interface Animal {
   public void eat(Object food) 
      throws CannibalismException, 
         InedibleException, OvereatingException; 

public interface Vegetarian {
   public void eat(Object food) 
      throws NonVegetableException, OvereatingException;

You may assume all the exception datatypes are direct subtypes of Exception.

10. (10) Suppose we implement a datatype Cow that is a subtype of both Animal and Vegetarian (that is, it implements both interfaces). Assuming Java follows the substitution principle correctly, what exceptions can the eat(Object) method for Cow throw? Explain why.

11. (no credit) Do you feel your performance on this exam will fairly reflect your understanding of the course material so far? If not, explain why.

12. (no credit) Do you prefer lectures that use mostly slides or mostly chalk?