CSE 222 Homework Problems

Spring 2012


  1. Visit the Software Component Engineering Home Page (http://www.cse.ohio-state.edu/sce/now) and read the "Must-Read Information". Then answer the following questions:
    1. Do you currently plan to talk regularly with any other CSE 222 students about homework and lab assignments?  What acts constitute "going over the line" between acceptable collaboration and academic misconduct?
    2. Suppose you submitted for a lab assignment a "correct" program that was sloppily done and poorly documented, and was generally not something you'd want to show to, say, your boss.  Approximately what mark would you expect to receive for it?

  2. Visit the CSE 222 Home Page (http://www.cse.ohio-state.edu/sce/now/222/index.html), explore briefly what's there -- including the CSE 222 Syllabus (http://www.cse.ohio-state.edu/sce/now/222/syllabus.html) -- and read the syllabus. Then answer the following questions:
    1. Of the course's intended learning outcomes, which is the most surprising one, in the sense that you might not have expected to see it as an objective for this course?  Why?
    2. What special relationship is there between your final exam grade and your course grade?

  3. For review, read or skim Chapter 1 of Software Component Engineering With Resolve/C++, Volume 2: The Client's View and answer the following questions:
    1. What is the main problem with trying to design a software component catalog using only global operations (a.k.a. subroutines)?
    2. Suppose a concrete instance you need is a class named Timer_1 in the Timer component family.  What #include statement would you use to bring it into scope?
    3. Write a line of code to declare an object of the type defined by Timer_1.
    4. Would it matter in the Monte_Carlo.cpp code if the code to check for a point's inclusion in the quarter circle used "<=" rather than "<" for the comparison?  Why or why not?
    5. What problem does the #ifndef-#define-#endif idiom solve?
    6. What does the keyword public mean in a Resolve/C++ component?
    7. What are the "standard operations" for a Resolve/C++ component?
    8. What does the keyword is_abstract mean in a Resolve/C++ operation declaration?
    9. What is the default parameter mode of self for a procedure operation?  For a function operation?

  4. For review, read or skim Chapter 2 of Software Component Engineering With Resolve/C++, Volume 2: The Client's View and answer the following questions:
    1. What is the key difference between a template and an instance?
    2. There is one minor difference in behavior between the Add operation for Sequence<Character> and the Add operation for the built-in type Text.  What is it?  Hint: Look closely at the specifications of the two operations.
    3. Explain in English the meaning of the declaration of Polynomial_Coefficients in Poly_Eval.cpp.
    4. In the body of operation Horner_Recursive_Evaluation, why is it necessary to store the result in a local object, as opposed to using this code:
    5. a.Remove (0, y);
      return x * Horner_Recursive_Evaluation (a, x) + y;
      a.Add (0, y);
    6. Select any of the bullets at the end of Section 2.2.3 that requires you to think seriously before answering, answer the question(s) for that bullet item, and explain the thinking that went into your answer(s).  (If none requires you to think hard, then select the last bullet.)
    7. In what circumstances, if any, is it appropriate for the body of an operation not to clear a produces-mode parameter before using it?

  5. Read the client-view appendix for Sequence, which should be review from CSE 221, and suggest an application program in which Sequences might be useful.

  6. Read the client-view appendix for Set, and suggest an application program in which Sets might be useful.

  7. Read the client-view appendix for Queue, and suggest an application program in which Queues might be useful.

  8. Write code to create, consecutively, the following three concrete instances, assuming the names are appropriate descriptions of intent:
    1. Set_Of_Integer
    2. Set_Of_Set_Of_Integer
    3. Queue_Of_Set_Of_Integer

  9. What is the mathematical model of the value of an object of type Queue_Of_Set_Of_Integer?  Write an example of such a value.  For instance, the mathematical model of an object of type Set_Of_Integer is a (mathematical) set of (mathematical) integers -- written in the specification notation as finite set of integer -- and an example of a value of this type is {23,14,-6,87}; the mathematical model of an object of type Sequence_Of_Text is string of string of character, and an example of a value of this type is <"abc","","xy">.

  10. For this week's closed lab you will, as usual, team up with a partner.  If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.

    An operation you'll need for Lab #1 is Get_Words.  The meaning of the specification is that the operation should read one line at a time from input into a Text object; and if that Text value is not already in words, then it should add it to words.  Assume that Set_Of_Text is an appropriately named concrete instance that has been previously declared.

    /*!
        math operation LINES (
                s: string of character
            ): string of string of character satisfies
            if s = empty_string
            then LINES(s) = empty_string
            else if "\n" is not substring of s
            then LINES(s) = <s>
            else there exists a, b: string of character
                     (s = a * "\n" * b  and
                      "\n" is not substring of a  and
                      LINES(s) = <a> * LINES(b))
    !*/ global_procedure Get_Words (
            alters Character_IStream& input,
            produces Set_Of_Text& words
        );
    /*!
        requires
            input.is_open = true
        ensures
            input.is_open = true  and
            input.ext_name = #input.ext_name  and
            input.content = empty_string  and
            words = elements (LINES (#input.content))
    !*/
    1. Design and code the body of this procedure.
    2. Review your understanding of the formal specification as compared to the informal specification.  Pay special attention to the difference between the mathematical model types string of character (the parameter to LINES) and string of string of character (the result of LINES).  If you follow the inductive (i.e., recursive) definition of LINES, you should be able to figure out why LINES("Here is a line\nand another.") = <"Here is a line", "and another.">  Then determine the values of the following expressions:
      1. LINES("")
      2. LINES("Hello")
      3. LINES("Hello there!")
      4. LINES("Here is a line\nand another\nand another...\n")

  11. Read the client-view appendix for Record and answer the following questions:
    1. Suppose you decide to use an instance of Record to store each entry in an electronic appointment book.  Such a record (say, concrete instance Apptmt_Entry) consists of a deadline -- a day of the week, an hour, a minute, and an AM/PM flag -- along with a short piece of text that describes the appointment.
      1. Write the Resolve/C++ declaration to create this new concrete instance by instantiating concrete template Record with fields of the built-in types.  (In practice, you might want to define types such as Day_Of_Week and Time_Of_Day and then create a Record instance with fields of these types.  But for this exercise, just use the built-in types.)
      2. Write the Resolve/C++ declarations of appropriate field names for Apptmt_Entry.
      3. One of the things you might want to do with a Apptmt_Entry object is to print it, appropriately labelled.  For example, if the value of such an object is (6, 10, 30, false, "CSE 222 closed lab") then you might want to print something like this:
        Friday, 10:30 AM: CSE 222 closed lab
        Write a body for the following operation:

        global_procedure Print_Entry (
                alters Character_OStream& out,
                preserves Apptmt_Entry& x
            );
        /*!
            requires
                out.is_open = true
            ensures
                out.is_open = true  and
                out.ext_name = #out.ext_name  and
                out.content = #out.content * [x printed as above]
        !*/

  12. Read Chapter 3 of Software Component Engineering With Resolve/C++, Volume 2: The Client's View through Section 3.1, and answer the following questions about it:
    1. What is a transitive relation?  Give an example of a transitive relation from everyday life, not from software engineering.  (Hint: Think about a family tree.)
    2. Speaking of trees, suppose the dependency graph in Figure 3-3 were not quite so complicated.  Suppose instead it were a dependency tree.  To be specific, suppose the "top-level" (in the diagram, right-most) concrete component depended on exactly two other concrete components, and that each of those depended on two other different concrete components, and so on through three levels of dependency arrows.  Draw the resulting tree.  How many components are in it?  If you changed something in one of the bottom-level components, how many other components potentially would be affected by the change (i.e., how many components depend on a bottom-level component)?  To understand the top-level component, how many other components might you need to understand (i.e., how many components does the top-level component depend on)?
    3. Why does dependence on an abstract component tend to be less of a problem than dependence on a concrete component?

  13. Read Chapter 3 of Software Component Engineering With Resolve/C++, Volume 2: The Client's View through Section 3.2, and answer the following questions about it:
    1. What is the "defensiveness dilemma"?
    2. In Resolve/C++ programs (i.e., under the "design-by-contract" or "programming-by-contract" discipline), who is reponsible for making sure that the precondition is true at the time of the call to an operation: the implementer of the operation, or the client of the operation, neither, or both?
    3. What is a "checking component"?
    4. What benefits accrue from using templates for decoupling checks?
    5. What does a parameter box stand for in a CCD?
    6. In order to be consistent with the code it summarizes, what name should the parameter box have in the CCD that shows how to decouple a checks relationship?  (This name normally is not shown in the CCD because it is entirely arbitrary; but you should be able to say which name in the code the parameter box in the CCD corresponds to.)

  14. Suppose you have a client program that needs concrete instance Set_Of_Text.  This instance should implement Set_Kernel <Text> using the implementation Set_Kernel_1 and it should check the preconditions of the Set_Kernel operations.  One way to achieve this is simply to declare a concrete instance of Set_Kernel_1_C (see also the client-view appendix Set or the on-line Resolve/C++ Component Catalog):
    concrete_instance
    class
    Set_Of_Text :
        instantiates
            Set_Kernel_1_C <Text>
    {};
    A second way to achieve this is as follows.  You can instantiate Set_Kernel_1 with Item bound to Text, and then instantiate Set_Kernel_C with Item bound to Text and with Set_Base bound to the instance of Set_Kernel_1 you just created.  Write the two template instantiations needed to do this.

  15. Read Chapter 3 of Software Component Engineering With Resolve/C++, Volume 2: The Client's View through Section 3.3, and answer the following questions about it:
    1. What benefits accrue from using templates for decoupling extends?
    2. In order to be consistent with the code it summarizes, what name should the parameter box have in the CCD that shows how to decouple an extends relationship?  (This name normally is not shown in the CCD because it is entirely arbitrary; but you should be able to say which name in the code the parameter box in the CCD corresponds to.)

  16. In the Resolve/C++ Component Catalog, which is available through the SCE Home Page, find the component Set_Put_To_1.  Note that it is an extension, designed in the style recommended in the reading: it is decoupled from the implementation of Set_Kernel that it extends.
    1. Rewrite the body of Put_To so self is swapped with temp after the loop, not before it.
    2. Why don't you need to know anything about the behavior of Open_Scope and Close_Scope in order to complete part A?  That is, how do you know there are no "weird interactions" between those calls and the code you just modified?

  17. Read the client-view appendix for Sorting_Machine and answer the following questions:
    1. Suggest an application program in which Sorting_Machines might be useful.
    2. Which operations of Sorting_Machine would be overridden in a checking component for it?

  18. For this week's closed lab you will, as usual, team up with a partner.  If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.
    1. Write a body for the following operation:
      global_procedure Remove_Min (
              alters Queue_Of_Text& q,
              produces Text& min
          );
      /*!
          requires
              q /= empty_string
          ensures
              (q * <min>) is permutation of #q  and
              for all x: string of character
                      where (x is in elements (q))
                  (min <= x)
      !*/
    2. Write a body for the global procedure Sort for an object q of type Queue_Of_Text, using the "selection sort" algorithm.  This algorithm repeatedly calls Remove_Min until q is empty, placing the items it returns one-by-one into a temporary queue, and then finally swapping this temporary object with q.

  19. Consider the Find_Min_And_Max operation, shown below:
    global_procedure Find_Min_And_Max (
            preserves Queue_Of_Integer& q,
            produces Integer& min,
            produces Integer& max
        );
     /*!
         requires
             q /= empty_string
         ensures
             {min, max} is subset of elements (q)  and
             for all x: integer
                     where (x is in elements (q))
                 (min <= x <= max)
     !*/
    1. Show a tracing table with one statement, a call to this operation, that illustrates what the operation would do for some choice of legal values for the arguments.
    2. Why do you need the requires clause?
    3. Show a tracing table with one statement, a call to this operation, that illustrates the importance of the first line of the ensures clause (not the requires clause).  That is, show how a correct implementation of the specification without that line might not do what the operation name suggests it does.
    4. Write a body for this operation that uses the "Noah's Ark" algorithm. This algorithm takes entries from q in pairs, first comparing them to each other, then comparing the smaller of the pair to the minimum so far and the larger of the pair to the maximum so far.

  20. In the Resolve/C++ Component Catalog, find the interface contract specification in Set_Unite, and an implementation of it in Set_Unite_1. What is the purpose of the if-statement at the beginning of the code?

  21. Write a body for the Reverse operation of the concrete template class Queue_Reverse_1:
    abstract_template <
            concrete_instance class Item
        >
    class Queue_Reverse :
        extends
            abstract_instance Queue_Kernel <Item>
    {
    public:

        procedure Reverse () is_abstract;
        /*!
            ensures
                self = reverse (#self)
        !*/
    };

    concrete_template <
            concrete_instance class Item,
            concrete_instance class Queue_Base
            /*!
                implements
                    abstract_instance Queue_Kernel <Item>
            !*/
        >
    class Queue_Reverse_1 :
        extends
            concrete_instance Queue_Base,
        implements
            abstract_instance Queue_Reverse <Item>
    {
    public:

        procedure Reverse ()
    {
        //-------- for students to fill in --------
    }
    };
  22. Read the client-view appendix for Stack.  Then write a body for the following operation, which you should assume to be in the interface of abstract template Stack_Reverse, which extends Stack_Kernel:
    procedure Reverse () is abstract;
    /*!
        ensures
            self = reverse (#self)
    !*/
  23. Consider the following recursive function operation:
    function_body Integer Foo (
            preserves Integer n
        )
    {
        if (n <= 1)
        {
            return 1;
        }
        else if (n mod 2 == 0)
        {
            return Foo (n/2) + 1;
        }
        else
        {
            return Foo (3*n+1) + 1;
        }
    }
    1. How many tracing tables would you need to trace the call "Foo(3)" if you decided to trace into the body of each recursive call?
    2. What value is returned by "Foo(3)"?
    3. (Significant extra credit)  Prove that the call "Foo(n)" terminates for every value of n.

  24. Read the client-view appendix for Partial_Map and answer the following questions:
    1. Suggest an application program in which Partial_Maps might be useful.
    2. In discussing how to implement a certain feature of a new product your company is developing, you suggest that a Partial_Map could be used.  A co-worker scoffs at the suggestion, claiming that Partial_Maps are completely superfluous and should never have been invented.  His reason is that you can always just instantiate a Record with two fields whose types are the D_Item and R_Item types you would have used to instantiate your Partial_Map, and then instantiate Set with this Record as the entry type.  In other words, to use a bastardized C++-like notation, he claims:
    3. Partial_Map <D_Item, R_Item> = Set <Record <D_Item, R_Item> >
      Is he right?  Why or why not?

  25. Read "How To Draw A CCD From Code" in the CSE 222 Course Packet.  Write down, and come prepared to ask, any questions you have about it.  Explain why should you be interested in drawing a CCD (other than to answer an annoying homework or exam question).

  26. For each situation below, imagine yourself designing and implementing an application program.  Which component family from the Resolve/C++ Catalog (e.g., Record, Stack, Sequence, Partial_Map, ...) do you think would be most useful in each case, and why?
    1. You need to keep track of the assignments of guests to hotel rooms in a program that is used by the front desk, so the program can look up what room number a guest is in, given the guest's name.
    2. You need to keep track of a deck of playing cards in a program that plays a card game, so the program can shuffle the deck and deal the cards.
    3. You need to keep track of the times (possibly several per day) that the alarm should go off in an alarm clock utility program.

  27. For this week's closed lab you will, as usual, team up with a partner.  If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.

    Software Originals, Inc., has been hired by Eaton Wright, the "pizza king", to help automate a new chain of pizza delivery stores.  SOI's system engineering staff have asked you to implement a prototype for the telephone operator's console.  To start the project they have assigned you to implement the following two operations (the first of which will be used to read files containing menus of pizza sizes and their prices, and pizza toppings and their prices; and the second of which will be used to read the first order from a file containing pizza orders whose total prices are to be calculated).  They haven't had time to write formal specifications; hence the informal nature of the descriptions.  The type Price_Map is an instance of some implementation of Partial_Map_Kernel where D_Item is bound to Text and R_Item is bound to Integer.

    global_procedure Get_Price_Map (
            preserves Text file_name,
            produces Price_Map& p_map
        );
    /*!
        requires
            [file named file_name exists but is not open, and has the
             format of one "word" and one price (in cents) per line,
             with word and price separated by '\t'; the "word" may
             contain whitespace other than '\t']
        ensures
            [p_map contains word -> price mapping from file file_name]
    !*/
    global_procedure Get_One_Order (
            alters Character_IStream& input,
            preserves Price_Map& sp_map,
            preserves Price_Map& tp_map,
            produces Integer& price
        );
    /*!
        requires
            input.is_open = true  and
            [input.content begins with a pizza order consisting of a
             size (something defined in sp_map) on the first line,
            followed by zero or more toppings (something defined in
             tp_map) each on a separate line, followed by an empty line]
        ensures
            input.is_open = true  and
            input.ext_name = #input.ext_name  and
            #input.content = [one pizza order (as described
                        in the requires clause)] * input.content  and
            price = [total price (in cents) of that pizza order]
    !*/
    Design and code the bodies of the operations Get_Price_Map and Get_One_Order.  Review your code carefully -- with someone else in the class if you can -- and trace it on some examples, but do not try to compile it until closed lab.  The objective is to have code that works the first time you compile it (except perhaps for typos).  Note that some useful detailed information about input/output and converting from one Resolve Foundation type to another (e.g., from Text to Integer) is available via this link.

  28. Read Chapter 1 of Software Component Engineering With Resolve/C++, Volume 3: The Implementer's View, through Section 1.4, and answer the following questions:
    1. Figure 1-1 shows the data representation selected for Natural_Kernel_18 to be a mathematical string of digits.  Rather than using a Sequence, could you have chosen to use a Queue or a Stack to hold the digits for this representation?  Explain your answer.
    2. The design described in Section 1.1 rules out <4,69,2> as a possible representation string.  Is there a different design for the data representation in which this string should be allowed?  Explain your answer in terms of convention and correspondence, even if only informally in English.
    3. Redraw Figure 1-7 with the sample operation Divide_By_Radix and the same two starting abstract values for self. (By now, you should know how to find the contract for this operation both in the textbook and in the on-line component catalog.)

  29. Read Chapter 1 of Software Component Engineering With Resolve/C++, Volume 3: The Implementer's View, through Section 1.6, and answer the following questions:
    1. Draw a commutative diagram for Set_Kernel_1 that you could use to illustrate the Add operation.   (Because Add changes its argument as well as the receiver object, you should invent some way to include that changed argument value in the diagram.  There is no wrong answer on this part; make up something that you consider sensible.)  Label a point in the "before" abstract state space {13,47,-694}, label the top arrow across the diagram "s.Add (x)", and suppose x = 75 at the time of this call.  Then clearly label the following additional things:
      1. The new value of s in the "after" abstract state space.
      2. The point in the "before" concrete state space that stands for the representation of the original s.
      3. The point in the "after" concrete state space that stands for the representation of the new s.
      4. The arrow between these points in the "before" and "after" concrete state spaces that stands for what the Add operation body does to achieve the desired effect on the representation of s.
    2. Do the same thing as above in the same starting configuration, but this time for the Set_Kernel_1 operation "s.Size ()".   (Because Size is a function, you should invent some way to include the return value in the diagram.  Again, there is no wrong answer on this part; make up something that you consider sensible.)
    3. Copy the Set_Kernel_1 CCD from the transparency that shows it.  Label each box and arrow in the CCD -- except the "uses" arrow -- with a number, in any order.  Print the first page of CT/Set/Kernel_1.h (from the Resolve/C++ Catalog), or copy either the first page of the code of CT/Set/Kernel_1_Part.h from the CSE 222 Course Packet or the first full page of Figure 1-11 from Software Component Engineering With Resolve/C++, Volume 3: The Implementer's View.  On it, circle and label with the same number the Resolve/C++ encoding of the corresponding box or arrow of the CCD.  (Note that the "uses" arrow doesn't match up with a Resolve/C++ keyword.  The meaning of "uses" in the CCD is this: The component at the tail of the arrow depends on the component at the head of the arrow, but it holds no other specific named relationship with that component.  In other words, "uses" is a catch-all dependency relationship that applies when nothing more specific -- implements, extends, checks, etc. -- is appropriate.)

  30. For this week's closed lab you will, as usual, team up with a partner.  If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.

    Test Plans, Test Cases, and the Test Driver

    As you know, a test plan consists of a set of test cases, each of which is intended to exercise a single call of a single operation.  For each test case you should basically have three rows of a tracing table: the first row shows the state before the call, with values for all the operation's actual parameters including the distinguished object; the second row shows the call itself; and the third row shows the expected state after the call, again with values for all the operation's actual parameters including the distinguished object.  You should review your notes from 221 for some hints on how to select test cases based on the specifications of the operations to be tested.  As part of this homework, i.e., before closed lab, you should create a file that encodes the test plan in a format that greatly facilitates testing; see "Test Script" below.

    The method to be used to test an implementation of Sequence_Kernel is as follows.  We provide a test driver main program that allows you to manipulate two special test objects of type Sequence_Of_Text (which is an instance of some implementation of Sequence_Kernel <Text> extended with the Put_To operation).  You tell the test driver which operation you wish to perform and, where appropriate, on which of the two special test objects you wish to invoke it (pretend their names are s1 and s2) and which values the other parameters should have.  The test driver then performs the operation and reports the values of the other parameters -- but not the value of the special test object. In order to see that value, you have to ask the test driver to print it.  For example, suppose you want to conduct the following test case:
     

      s1 = <>, pos = 0, x = "Foo"
    s1.Add (pos, x);  
      s1 = <"Foo">, pos = 0, x = ""

    If the operations so far executed for s1 have left s1 empty (as claimed in the first row of the tracing table) then you can respond to the test driver's prompts with the following lines:

    The "a" means "execute the Add operation".  The "1" means to do this operation on special test object s1.  The "0" means the first argument to the operation has the value 0, and the "Foo" means the next argument to the operation has the value "Foo".  (Note that on both input and output for this test driver, a Text value does not have double quote marks around it.)  After reading these lines, the test driver executes the operation and tells you that it has done so; it also reports the new values of pos and x.  If you want to see the new value of s1, you have to ask the test driver to print it: Here, "p" means "execute the Put_To operation" and "1" means to do this operation on test object s1.

    Test Script

    The test driver gets input from stdin.  This gives you the option of redirecting its input from a test script file in which you have encoded your entire test plan.  So the "easy" way to test is to create a file whose first line contains only an "n" -- this is the appropriate response to the first question asked by the test driver.  Following that you can put into the test script file all the commands you would have had to type into the test driver if you were using it interactively.  In other words, you can encode in this file your entire test plan.  This will save you a lot of typing during closed lab.

    Although it might not be evident when you try it, the test driver simply "echoes" any line that it doesn't understand as one of the menu options when you are selecting an operation to perform.  You can use this feature to put comments into your test script.  For example, just before the line containing the "a" in the above example, you might put the following line into your test script:

    This line of input is treated as a comment because the first character of the line ('/') is not one of the menu options the test driver recognizes.  Such comments can help you identify where you are as you wade through the output of the test driver, and also can help you organize and read your test script file.

    1. Review the functionality of abstract template class Sequence_Kernel by consulting the Sequence appendix.  Use this information to create a specification-based test plan for an implementation of Sequence_Kernel, and encode it into a test script as described below.  Make sure you annotate it with comments so the grader can understand it.  If you enter this test script into a file before coming to closed lab, then you'll get a jump on closed lab and you can simply turn in a printout of the file for this homework problem.  An executable test driver that uses a correct implementation of Sequence_Kernel, where Item is replaced by Text, is provided for you to use:
    2. /class/sce/now/222/closed-labs/closed-lab04/Closed_Lab04/Sequence_Test_Sample
      Run it and answer "y" to the first question ("Run in interactive mode (y/n)?").  You will see what you need to type in to get it to execute each of the available operations.  You also will see what output the test driver produces, and what you need to tell it in order to conduct your testing.
    3. Study the file CT/Sequence/Kernel_3.h (also in the code section of the CSE 222 Course Packet) and make sure you understand how a Sequence object is to be represented using two Stack objects.  Then design and code the bodies of the operations Add, Remove, Length, and Set_Length_Of_Before (a private operation).  The body of the accessor is provided in this file as a guide, partly because this is the first time you've seen how an accessor is implemented.  Review your code carefully -- with someone else in the class if you can -- and trace it on some examples, type it into a file if you want to save closed lab time, but do not try to compile it until closed lab.  The objective is to have code that works the first time you compile and run it.

  31. Study CT/Partial_Map/Kernel_1_Part.h (also in the code section of the CSE 222 Course Packet) to see how one simple implementation of Partial_Map_Kernel might be done.  Then fill in the bodies of Undefine and Undefine_Any.

  32. Read the client-view appendices for Static_Array and Array.  Assume there are already declarations of concrete instance Array_Of_Text and an object of this type.  Suppose you have many Text objects stored in this object, and that you want to sort them into alphabetical order.
    1. Write the header for a global procedure Sort that you could use to solve this problem.  If you're ambitious, write a formal specification of Sort; but in any case write at least informal requires and ensures clauses.
    2. Write a body for Sort using any sorting algorithm you like.  There are a couple restrictions just to make it interesting, however:
      • It is not acceptable to copy a Text value using the assignment operator or Copy_To.  This is actually quite a rational restriction, because if you were sorting an Array of an arbitrary type Item you could not assume that Items could be copied; and in any event, there is no need to copy Items in order to sort them.
      • It is not acceptable to move the Text values from the Array_Of_Text into a Queue_Of_Text, sort there using something you wrote earlier this quarter, and then move them back.  In other words, no tricks to avoid solving the real problem...

  33. Read the rest of Chapter 1 of Software Component Engineering With Resolve/C++, Volume 3: The Implementer's View, and answer the following questions:
    1. There are many implementations of Hash that might seem reasonable when the argument type is Integer, as in the example of Section 1.7.1.  For example, if you don't know anything in advance about the Integer values that might be likely to be put into a Set_Kernel_13 object, then this implementation for Hash is quite reasonable:
    2. {
          return x;
      }
      Show how the elements in Figure 1-12 are distributed among the buckets by this hash function.
    3. Write any qualitatively different implementation of Hash for this situation that might seem "reasonable" (again, without thinking in advance about the particular elements of Figure 1-12).  Then show how the elements in Figure 1-12 are distributed among the buckets by this hash function.
    4. (Extra credit)  A student once wrote a solution to part (B) above as follows:
      {
          return x * x;
      }
      Forget for a moment that this might overflow, and consider instead his astute observation: for a hash table of size 10 as shown in the notes, this hash function results in at least 4 of the 10 buckets remaining empty.  The reason is that there is no square whose last digit is 2, 3, 7, or 8.  Prove that, for any hash table of size greater than 2, this hash function will always leave some buckets empty.

  34. Write the code for computing a hash function that returns an Integer value, given a Text value which is known to contain a 7-digit phone number in the form "XXX-XXXX" for a phone in the immediate OSU area.  That is, you may assume the length of the Text value is 8 and that each "X" is a digit '0'-'9'.  Hint: You might use, among other things, the built-in To_Integer function that converts a Character-valued expression to an Integer value which is its ASCII code; and/or the built-in To_Integer function that converts a Text-valued expression to an Integer value (but be careful since this one works only if the Text value "looks like" an integer).  These operations are explained in one of the CSE 221 Handouts (note: CSE 221, not CSE 222) How To Convert Between Built-in Types, which is also available from the SCE Home Page.

  35. Some people have phone numbers such as 292-OHIO.  Certain solutions to the previous problem couldn't necessarily be applied to the Text value "292-OHIO" because it has non-digits.  Furthermore, even if your particular implementation could be applied to this Text value, it almost certainly would not do "the right thing" in an application program because the hash function probably would not give the same Integer result as it does for the numeric version of the phone number, "292-6446".
    1. Explain exactly what problem this would cause; i.e., explain what problem would arise if "292-OHIO" and "292-6446" were both considered legal phone numbers and your hash function from the previous problem could be applied to both of them, and therefore you actually decided to use that hash function for both of them.
    2. Explain how you could change the hash function to correct this problem; i.e., explain what the hash function would have to do to handle phone numbers like "292-OHIO" and "292-6446" in a proper way.
    3. While you're at it, you might as well also handle smoothly the case where the phone number is typed in as "292-ohio".  Explain how you could further change the hash function to handle this situation, too.

  36. Read the client-view appendix for Binary_Tree. On page Binary_Tree-2, you will find an informal definition of the height of a binary tree. Here is a formal definition:
        math definition HEIGHT (
                t: binary tree of Item
            ): integer satisfies
            if t = empty_tree
            then HEIGHT (t) = 0
            else there exists x: Item, left, right: binary tree of Item
                     (t = compose (x, left, right)  and
                      HEIGHT (t) = 1 + max (HEIGHT (left), HEIGHT (right)))

    Without using the Height kernel operation, provide an implementation for the following global function.

        global_function Integer Height (
                preserves Binary_Tree_Of_Item& t
            );
        /*!
            ensures
                Height = HEIGHT (t)
        !*/

  37. Provide an implementation for the following global function:
  38.     global_function Boolean Is_In_Tree (
                preserves Binary_Tree_Of_Integer& t,
                preserves Integer i
            );
        /*!
            ensures
                Is_In_Tree = [i is an element in t]
        !*/

  39. Provide an implementation for the following global procedure:
  40.     global_procedure Copy_It (
                preserves Binary_Tree_Of_Integer& t1,
                produces Binary_Tree_Of_Integer& t2
            );
        /*!
            ensures
                t1 = t2
        !*/

  41. A Fibonacci tree is a variety of binary tree restricted to have special structure. This special structure is defined recursively as follows:

    Here are some examples of Fibonacci trees. As you can see, they do have special structure; that is, they are not just any old binary trees.



    Provide a function body for the global operation Is_Fibonacci_Tree.

        global_function Boolean Is_Fibonacci_Tree (
                preserves Binary_Tree_Of_Item& t,
                preserves Integer n
            );
        /*!
            requires
                n >= 0
            ensures
                Is_Fibonacci_Tree = [t is a Fibonacci tree of order n]
        !*/

  42. In this question, suppose ARE_IN_ORDER is defined as follows:
        math definition ARE_IN_ORDER (
                s1: string of character,
                s2: string of character
            ): boolean is
            s1 <= s2
    

    Note that "s1 <= s2" means that s1 = s2 or s1 < s2; and "s1 < s2" means -- because s1 and s2 are strings of characters -- that s1 comes before s2 in lexicographic order using the ASCII collating sequence for characters. Operationally, you can think of "s1 <= s2" as follows -- though you don't have to write code to do this because the built-in "<=" operator for Text does it for you. First, remove any common prefix of s1 and s2, calling the remaining strings s1' and s2'. Then there are four possibilities. If s1' and s2' are both empty, then s1 = s2. If s1' is empty and s2' is not empty, then s1 < s2. If s1' is not empty and s2' is empty, then s2 < s1. If s1' and s2' are both non-empty, then they differ in their first characters, and s1 < s2 iff the first character of s1' precedes the first character of s2' in the ASCII code.

    Using the binary search tree algorithms discussed in class:

    1. Draw the binary search tree that would result from inserting the following sequence of items into an initially empty binary search tree:
      Matt, Zeke, Pete, Lon, John, Mei, Larry, Bess, Merv, Adam, Kate, Lon
    2. Draw the binary search tree resulting from deleting Pete from the binary search tree in A.
    3. Draw the binary search tree resulting from deleting John from the binary search tree in B.
    4. Draw the binary search tree resulting from deleting Lon from the binary search tree in C.
    5. Draw the binary search tree resulting from deleting Matt from the binary search tree in D.
    6. Assume that t is a Binary_Tree_Of_Text. Implement the following operation that prints the items in t in sorted order (in this case, ARE_IN_ORDER dictates that this is according to the ASCII collating sequence).
          global_procedure Print_Sorted_Items (
                  preserves Binary_Tree_Of_Text& t,
                  alters Character_OStream& outs
              );
          /*!
              requires
                  IS_BST_ORDERED (t)  and
                  outs.is_open = true
              ensures
                  outs.is_open = true  and
                  out.ext_name = #outs.ext_name  and
                  outs.contents = #outs.contents *
                                  [the items in t in sorted order and
                                   separated by newlines]
          !*/

  43. Write the body of the Boolean function Is_Binary_Search_Tree which returns true if and only if the given binary tree of integers, t, is a binary search tree. Assume that ARE_IN_ORDER is defined to be the usual <= relation on integers.
        global_function Boolean Is_Binary_Search_Tree (
                preserves Binary_Tree_Of_Integer& t
            );
        /*!
            ensures
                Is_Binary_Search_Tree = IS_BST_ORDERED (t)
        !*/

    The math definitions below are included for completeness and to provide you with a precise definition of the binary search tree property. Note that the implementation of Is_Binary_Search_Tree is an interesting, non-trivial task. Plan to spend some time thinking about this. Also, note that you may want/need to declare and implement some extra auxiliary operations. Finally, remember that good design (e.g., readability and maintainability) and efficiency (don't copy Items--even integers--unless it is really necessary) are important concerns in the design of good software.

        math definition OCCURS_COUNT (
                t: binary tree of integer,
                i: integer
            ): integer satisfies
            if t = empty_tree
            then OCCURS_COUNT (t, i) = 0
            else there exists root: integer
                              left, right: binary tree of integer
                     (t = compose (root, left, right) and
                      (if i = root
                       then OCCURS_COUNT (t, i) =
                                1 + OCCURS_COUNT (left, i) +
                                    OCCURS_COUNT (right, i)
                       else OCCURS_COUNT (t, i) =
                                OCCURS_COUNT (left, i) +
                                OCCURS_COUNT (right, i)))
    
        math definition IS_BST_ORDERED (
                t: binary tree of integer
            ): boolean satisfies
            if t = empty_tree
            then IS_BST_ORDERED (t) = true
            else there exists root: integer
                              left, right: binary tree of integer
                    (t = compose (root, left, right) and
                     IS_BST_ORDERED (t) =
                         IS_BST_ORDERED (left)  and
                         IS_BST_ORDERED (right)  and
                         for all i: integer
                                 where (OCCURS_COUNT (left, i) > 0)
                             (not ARE_IN_ORDER (root, i))  and
                         for all i: integer
                                 where (OCCURS_COUNT (right, i) > 0)
                             (ARE_IN_ORDER (root, i)))
  44. For this week's closed lab you will, as usual, team up with a partner.  If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.

    You will be implementing two global_procedures, Get_Tree and Put_Tree, in a provided test driver. Working with your partner and before closed lab, carefully read the math definitions below and the specifications of Get_Tree and Put_Tree. Then design and code the bodies of the two procedures. Review your code carefully and trace it on some examples. The objective is to have code that works the first time you type it in (except perhaps for typos).

    The math operation PREFIX_DISPLAY explains the format to be used when displaying a binary tree through the Put_Tree operation, and also explains the format to be used when typing in a binary tree for the Get_Tree operation. Here are five examples of PREFIX_DISPLAY applied to binary trees. See if you can figure out the binary trees being described.

    (By the way, you should assume that the characters "(" and ")" do not appear as items in trees.)

        /*!
            math definition PREFIX_DISPLAY (
                    t: binary tree of character
                ): string of character satisfies
                if t = empty_tree
                then PREFIX_DISPLAY (t) = "()"
                else there exists ch: character,
                                 t0, t1: binary tree of character
                        (t = compose (ch, t0, t1) and
                         PREFIX_DISPLAY (t) = <ch> * "(" *
                                              PREFIX_DISPLAY (t0) *
                                              PREFIX_DISPLAY (t1) * ")")
        !*/
    
        global_procedure Put_Tree(
                preserves Binary_Tree_Of_Character& t,
                alters Character_OStream& outs
            );
        /*!
            requires
                outs.is_open = true
            ensures
                outs.is_open = true and
                outs.ext_name = #outs.ext_name and
                outs.content = #outs.content * PREFIX_DISPLAY (t)
        !*/
    
    
        global_procedure Get_Tree(
                alters Text& tree_as_text,
                produces Binary_Tree_Of_Character& t
            );
        /*!
            requires
                there exists t1: binary tree of character
                    (PREFIX_DISPLAY (t1) is prefix of tree_as_text)
            ensures
                #tree_as_text = PREFIX_DISPLAY (t) * tree_as_text
        !*/

  45. We would like a concise but thoughtful report, nominally a page or two long, with two sections.  The process of writing the report is designed to let you reflect on some things you have learned during the first half of the software component engineering course sequence.  Of course, your instructor will be pleased if you conclude that you have learned a lot in CSE 221 and 222!  But your grade on the assignment will not depend on reaching that conclusion.  We're interested in honest answers that demonstrate you've thought carefully about each point.

    Section A: How Would You Have Met Lab #2's Requirements Before Taking CSE 221/222?

    Suppose you had been hired -- before you took CSE 221 or CSE 222 -- to write a program meeting the basic requirements of CSE 222 Lab #2.
    1. What programming language and/or other application development systems would you have used?
    2. What data structures would you have used to keep track of the terms and their definitions?
    3. What algorithms would you have used to accomplish the following tasks?
      1. Determine whether a given word is a term.
      2. Find the definition, given a term.
      3. Output the terms in alphabetical order.
    It is not reasonable to answer that you wouldn't have had any idea how to write this program before CSE 221; nor is it reasonable to joke (or really mean) that you'd hire a subcontractor to do it.  For some of you, it might be that certain pieces would have been hard or impossible to have done; perhaps you didn't know any HTML at the time (assume you could have learned it).  But all of you are supposed to have had enough previous programming experience prior to CSE 221 that you should have been able to have made a decent stab at most parts of this application program.

    Section B: How Important Are Some Ideas You Have Learned In CSE 221/222?

    Briefly explain, by relating your answers to those above, how you rate the significance of each of the following concepts. Please don't try to rank them in order of importance; just say how significant you think the individual ideas are.
    1. Component-based software construction
    2. Unambiguous specifications for operations
    3. Templates
    4. Partial_Map

  46. Read the paper entitled "Experience Report: Using RESOLVE/C++ for Commercial Software", in the CSE 222 Course Packet, and answer the following questions:
    1. The paper claims that "the key feature supporting easy evolution [changes to the software] was our confidence that the modular reasoning property would hold."  Briefly explain this claim -- not the claim about the technical importance of the modular reasoning property itself, but the claim about the importance of having confidence that modular reasoning could be used.
    2. Most experienced software developers would not change their software after testing but before delivery, fearing that any untested change could cause the system to "break".  In light of this, what do you think about the decision in this project to remove checking components after development and internal testing but before product delivery?  Briefly support your conclusion.
    3. How does the swapping paradigm differ from traditional approaches to data movement?

  47. For this week's closed lab you will, as usual, team up with a partner. If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.
    1. Review the functionality of abstract template Stack_Kernel by consulting the client-view appendix for Stack.  Use this information to create a specification-based test plan for Stack_Kernel, and encode it into a test script as you did for closed lab #4.  Make sure you annotate it with comments as explained in an earlier homework problem so the grader can understand your test plan.  As before, if you enter this test script into a file before coming to closed lab, then you'll get a jump on closed lab and you can simply turn in a printout of this file for this homework problem.  An executable test driver that uses a correct implementation of Stack_Kernel, where Item is replaced by Text, is provided for you to play with:
    2. /class/sce/now/222/closed-labs/closed-lab07/Closed_Lab07/Stack_Test_Sample
      Run it and answer "y" to the first question ("Run in interactive mode (y/n)?").  You will see what you need to type in to get it to execute each of the available operations.  You also will see what output the test driver produces, and what you need to tell it in order to conduct your various test cases.
    3. Study the file CT/Stack/Kernel_1_Part.h (also in the CSE 222 Course Packet ) and make sure you understand how a Stack object is to be represented using a linked list of nodes and "raw C++" pointers.  Then design and code the bodies of the operations Push, Pop, Length, and Finalize (a private operation).  Review your code carefully -- with someone else in the class if you can -- and trace it on some examples, type it into a file if you want to save closed lab time, but do not try to compile it until closed lab.  The objective is to have code that works the first time you compile and run it.

  48. Read the client-view appendix for List.  Then write a body for the following operation from an extension of List_Kernel, assuming that you can call List_Kernel operations as a client in the usual layered approach to implementing an extension.  (That is, do not assume you have access to the List_Kernel representation!)  Read the specification carefully.  Notice that it matters where the fence ends up!
    procedure Reverse () is_abstract;
    /*!
        ensures
            self = (reverse (#self.right), reverse (#self.left))
    !*/

  49. Think about the similarities and differences between Queue_Kernel and List_Kernel, then answer the following questions.
    1. Write a short but convincing argument that any problem you can solve using a Queue could be solved using a List.  Hint: Focus on the operations of Queue_Kernel, since anything a client program can do with a Queue must be done using only these operations.
    2. You should be able to convince yourself that if you are successful in making the above argument, then you must realize how to implement Queue_Kernel by layering it on top of List_Kernel.  This implies you wouldn't have to implement Queue_Kernel using pointers -- which is the only Queue_Kernel implementation we've seen to date.  Here is one possible way to do this:
      concrete_template <
      	concrete_instance class Item,
              concrete_instance class List_Of_Item =
                  List_Kernel_1a <Item>,
              concrete_instance class Rep =
                  Representation <List_Of_Item>
          >
      class Queue_Kernel_3 :
          implements
      	abstract_instance Queue_Kernel <Item>,
          encapsulates
      	concrete_instance Rep
      {
      private:
      
          rep_field_name (Rep, 0, List_Of_Item, item_list);
      
          /*!
      	correspondence
      	    self = self.item_list.left * self.item_list.right
          !*/
      
      public:
      
          standard_concrete_operations (Queue_Kernel_3);
      
          procedure_body Enqueue (
      	    consumes Item& x
      	)
          {
              //------ for students to fill in ------
          }
      
          procedure_body Dequeue (
      	    produces Item& x
      	)
          {
              //------ for students to fill in ------
          }
      
          function_body Item& operator [] (
      	    preserves Accessor_Position& current
      	)
          {
              //------ for students to fill in ------
          }
      
          function_body Integer Length ()
          {
              //------ for students to fill in ------
          }
      
      };

      Fill in appropriate bodies for the kernel methods that respect both the representation invariant given in the convention clause (there is none, so this means that every List represents some Queue), and the abstraction relation given in the correspondence clause.


  50. Consider the implementation CT/List/Kernel_1.h that serves as the starting point for the last lab assignment.  Suppose List_Kernel had one additional operation, i.e.:
    procedure Prepend (
            consumes Item& x
        ) is_abstract;
    /*!
        ensures 
            self.left = <#x> * #self.left  and
            self.right = #self.right
    !*/
    1. Draw before-and-after pictures of a List_Kernel_1 object where the original value is self = (< >, <13, 7>), and the next call is to Prepend with x = 25.
    2. Write the body of Prepend as if it were part of List_Kernel_1, i.e., using pointers and full access to the representation (not layered).  Your implementation should execute in constant time.  Hint: there are two ways to do this, one of which requires code to handle two special cases while the other is straight-line code with no "if" statements at all.  See whether you can discover the second way.  It requires a little "out of the box" thinking about the smart node at the beginning of the list.

  51. For this week's closed lab you will, as usual, team up with a partner.  If you wish, you may find a partner early and work together on this homework exercise, too.  If you do this you may turn in one homework submission with both names on it and you will both receive the same grade for it.
    1. Write a Resolve/C++ version of Names_1_C++.cpp from the CSE 222 Course Packet, and call it Names_1.cpp.  You can get the value of an upper-case ASCII character in lower-case by invoking the global function To_Lower on a Character value; this is similar to tolower in the normal C++ version.
    2. Modify your Resolve/C++ program from above, creating Names_2.cpp, to make a simple change the boss has requested: "Modify the program so that it also prints out the names in reverse order."  For example, if Names_1 were given input containing the three names Ed, Fred, Ted, it would print out:
    3. Ed
      ed
      Fred
      fred
      Ted
      ted
      If Names_2 were given the same input, it should output:
      Ed
      ed
      Fred
      fred
      Ted
      ted
      Names in reverse order:
      ted
      Ted
      fred
      Fred
      ed
      Ed
    4. Look carefully through the code in Stack.h from the CSE 222 Course Packet, which is a template designed in a normal C++ style.  Next examine the introductory comments and code in Names_2.1_C++.cpp-bug, then Names_2.2_C++.cpp, then Names_2.3_C++.cpp, which document the musings of a (semi-experienced?) C++ programmer during successive attempts to make the same "simple" change starting with Names_1_C++.cpp.  Complete the code in Names_2.4_C++.cpp (the starting point provided in this file is identical to Names_2.3_C++.cpp) and make the modified program work as the boss wanted.  Look up what you need in a C++ book or consult a C++ guru if you need help.
    5. Compare and contrast:
      1. The original normal C++ program Names_1_C++.cpp and the Resolve/C++ program Names_1.cpp.
      2. The revised normal C++ program Names_2.4_C++.cpp and the Resolve/C++ program Names_2.cpp.
      3. The changes in the code required to get from Names_1_C++.cpp to Names_2.4_C++.cpp (the normal C++ versions), vs. the changes in the code required to get from Names_1.cpp to Names_2.cpp (the Resolve/C++ versions).

  52. There is nothing to turn in for this assignment. But if you have about 20-30 minutes to read the 3-page paper at the "PDF" link below, you will gain some insight into the thinking of arguably one of the most important computer scientists of all time, Sir C. Anthony R. (Tony) Hoare. In addition to inventing Quicksort and several other important algorithms in an amazing flurry of inventiveness a half-century ago, Hoare is generally credited as the originator of many of the foundational ideas we have been discussing in this course. These include using mathematics to describe what computer programs are supposed to do, and adapting standard logic to prove the correctness of program code. We hope you enjoy this paper and feel free to ask questions about it in class:

    Hoare, C.A.R. "Retrospective: An Axiomatic Basis for Computer Programming", Communications of the ACM 52, 10 (October 2009), 30-32. [PDF]


  53. Consider concrete template Stack_Reverse_1, which implements abstract template Stack_Reverse (specified in an earier homework problem). Here is what the body of Reverse might look like:
    1. procedure_body Reverse ()
      {
          object catalyst Stack_Reverse_1 temp;
          while (self.Length () > 0)
          /*!
              alters self, temp
              maintains
                  reverse (temp) * self = reverse (#temp) * #self
              decreases
                  ...
          !*/
          {
              ...
          }
          self &= temp;
      }
    1. Suppose Stack_Reverse_1 is instantiated with Item = Integer. Trace the code for self = <9, 6, 90, -6, 6, 18, 92, -4>, assuming that the loop invariant is correct. That is, use the loop invariant to trace over the loop without tracing any statements in the loop body.
    2. Complete the loop body and argue that the loop invariant in the above procedure_body Reverse is correct for your code, i.e., explain why it holds at the two places where a loop invariant must hold.

  54. Answer the following questions about this implementation of a global procedure that manipulates objects of type Partial_Map_Text_To_Integer. Partial_Map_Text_To_Integer is an instance of some implementation of abstract_template class Partial_Map_Kernel, with D_Item bound to Text and R_Item bound to Integer.
    1. procedure_body Mystery (
              preserves Partial_Map_Text_To_Integer& m1,
              produces Partial_Map_Text_To_Integer& m2
          )
      {
          object Partial_Map_Text_To_Integer temp;
          m2.Clear ();
          while (m1.Size () > 0)
          /*!
              alters m1, m2, temp
              maintains
                  for all t: string of character
                      (if IS_DEFINED_IN (m1, t)
                        then not IS_DEFINED_IN (m2, t))  and
                  m1 union temp = #m1 union #temp  and
                  m2 = temp
              decreases
                  ...     !*/
          {
              ...
          }
          temp &= m1;
      }
    2. Before writing a body for the while loop, trace this code to the end for m1 = {("May", 5), ("day", -31)} and m2 = { ("Columbus", 1492)}.  Explain how the loop invariant allows you to do this.
    3. Write a specification for Mystery; i.e., what do you think it does?
    4. Write an appropriate loop body.
    5. Explain why the loop invariant is correct for the body you just wrote.