Hand-tracing is an effective way to debug a program. As programs get large, it is best to debug (hand-trace) the program function by function. Once a particular function, say F, has been thoroughly debugged, one can go on to debug (hand-trace) the function(s) that call F.
In the last lab, you wrote a function to compute the n-th Fibonacci number. Your function probably looked like:
      // PRE: num = n >= 0
      // POST: RV = the n-th Fibonacci number, 
      //              where the 0-th Fibonacci number = 1
      //              and the 1st Fibonacci number = 1
      int fibo (int num) {
        int answer;
        if (num <= 1) {
          // ASSERT: n = 0 or n = 1
          answer = 1;		 
          // ASSERT: answer = 1
        }
        else {
          // ASSERT: n > 1
          answer = fibo(num-1) + fibo(num-2);
          // ASSERT: answer = fibo(n-1) + fibo(n-2)
        }
        // ASSERT: answer = the n-th Fibonacci number.
        return (answer);
      }
    
  
  A hand-trace of the function call:
      int aNumber = 3;
      int theAnswer = fibo(aNumber);
    
	
	will tell us that the function is called with the value 3. Thus, the function is recursively called with the value 2, and when that incarnation returns, the function is recursively called with the value 1. The incarnation that was called with the value 2, will first recursively call the function with the value 1, and when that incarnation returns, the function is recursively called with the value 0. And so on. This can be concisely written as a trace of the function calls and their returned values:
      fibo(3)     <- the first call
      calls fibo(2)
      calls fibo(1)
      fibo(1) returns 1
      calls fibo(0)
      fibo(0) returns 1
      fibo(2) returns 2
      calls fibo(1)
      fibo(1) returns 1
      fibo(3) returns 3
    
	
	One has to carefully look at this trace to see the order in which the recursive functions were called, and then to see which incarnation returned which value. A better way to hand-write this trace using indentation would be:
      fibo(3)     <- the first call
        fibo(2) called
          fibo(1) called
          fibo(1) returns 1
          fibo(0) called
          fibo(0) returns 1
        fibo(2) returns 2
        fibo(1) called
        fibo(1) returns 1
      fibo(3) returns 3
    
	
	
    We get a better sense of the order of the function calls and their
    corresponding return values. Essentially, the indentation (number
    of spaces) helps up determine which function was called at
    which level. One could say that the first call
    to fibo(3) is a level 0 (thus 0 spaces of
    indentation), the next call to fibo(2) is at level 1
    (thus 2*1 = 2 spaces of indentation), etc. Below is the above
    trace annotated with the levels of the calls:
	
      fibo(3)                    <- level 0
        fibo(2) called           <- level 1
          fibo(1) called         <- level 2
          fibo(1) returns 1      <- level 2
          fibo(0) called         <- level 2
          fibo(0) returns 1      <- level 2
        fibo(2) returns 2        <- level 1
        fibo(1) called           <- level 1
        fibo(1) returns 1        <- level 1
      fibo(3) returns 3          <- level 0
       
  
  It is always useful to compare our hand-trace with what the
    program actually does when it is run. We can use debugging output
    statements to accomplish this. Consider the following version of
    the function fibo:
    
      // PRE: num = n >= 0
      // POST: RV = the n-th Fibonacci number, 
      //              where the 0-th Fibonacci number = 1
      //              and the 1st Fibonacci number = 1
      int fibo (int num) {
        cout << "fibo(" <<  num << ") called" << endl;
        int answer;
        if (num <= 1) {
          // ASSERT: n = 0 or n = 1
          answer = 1;		 
          // ASSERT: answer = 1
        }
        else {
          // ASSERT: n > 1
          int previous1 = fibo(num-1);
          int previous2 = fibo(num-2);
          answer = previous1 + previous2;
          // ASSERT: answer = fibo(n-1) + fibo(n-2)
        }
        // ASSERT: answer = the n-th Fibonacci number.
        cout << "fibo(" << num << ") returns " << answer << endl;
        return (answer);
      }
    
  
  Try running a program with a suitable
  function main and the above fibo function
    so that the program outputs the 3-rd Fibonacci number. What do you
    see as the trace? Is it helpful?
As seen above, it would have been more useful if the debugging
  output was indented according to the level of the function
  calls. One way to accomplish this is to pass the level of a function
  call as an additional parameter to the function. Then, write a
  function printSpaces that gets the level number as a
  parameter and prints the appropriate number of spaces to indent the
  debugging output for that function call. Modify your program to
  print the n-th Fibonacci number so that the debugging output
  looks like the last version of the trace shown above (you do not
  need to print out the annotations, e.g., <- level
      0).
    
Note that just such debugging output is not sufficient for efficient debugging. There is no substitute for a careful hand-trace before running a program to verify if the program will do what you expect it to do.
Consider the following problem:
Write a C++ program that reads from the user a set of (distinct) integers and prints out a subset of these integers so that the sum of the integers in the subset is half the sum of the integers in the entire set. If no such subset is found the program prints out a suitable message. You may assume that the first number the user enters is the number of numbers in the set of integers, and that the number of integers in the user-given set is no more than 20.
We will walk through the process of developing a program, and see how recursion and the technique of backtracking can be used effectively, to solve this problem.
The first step in solving this problem is to understand the problem, and working out some examples will help. These examples can then become our test cases for our program.
Clearly, we can see that if the sum, of the entire set of integers
  given to us, is odd, then there cannot be a solution to the
    problem. So, let us first construct such an example. Consider the
  set of integers: 3 5 8 2 1. The sum of the integers is 19, and thus
    odd. So, no solution can be found for this instance. We can go
  ahead and create an input file for this
  instance. Test1.txt is this
  input file. We 
  can also start our TestCases.txt
  file. 
  
Since the user can give us a set of integers, 0 and negative
  numbers may be a part of the set too. Construct an
  example that contains only negative numbers such that the sum of
  the numbers is odd. Create the file Test2.txt, and add
    to the file TestCases.txt an explanation for this test.
  
It will be useful to also test the program with a set of integers
  that contains 0, positive integers and negative integers, and such
  that the sum of the set of integers is odd. Construct
  such an
  example, create the file Test3.txt, and add
    to the file TestCases.txt an explanation for this test.
  
Now, we can work out examples for sets of integers where the sum
  of the integers is even. Is it possible to have a set of positive
  integers whose sum is even, say S, and such that there is a
  subset whose sum is S/2? Consider the set: 4 1 2 3. In this
  case the sum of the integers is 10, and the subsets 4, 1 and 2, 3,
  each have a sum of 5. Our program needs to output any one of
  these subsets. Create a test file Test4.txt, and
  include the explanation in the TestCases.txt file. For
  example, the explanation could be:
      
	4. Test for a set of positive integers whose sum is even.
           Input set: 4 1 2 3
           Expect that the program prints out "4 1" or "2 3".
           Test file: Test4.txt
      
    
  We should also test for a set of positive integers whose sum
  is even, say S, a subset whose sum is S/2 exists, and
  the number of integers in the set is odd. Construct
  such an example, create the file Test5.txt, and include
      an explanation in the file TestCases.txt.
  
Similar to the above two examples, we should test for sets
  that have only negative numbers. Construct such examples, create the
  files Test6.txt and Test7.txt for these
  examples, and include the explanations in the
  file TestCases.txt. 
  
Now construct an example with a set of integers that contains
  0, positive integers and negative integers, such that the sum of
  the set of integers is even, say S, and such that there is a
      subset whose sum is S/2, create the
  file Test8.txt, and include an explanation in the
  file TestCases.txt. 
  
Test9.txt, and include an explanation in the
  file TestCases.txt. 
  Is it possible to have a set of positive
  integers whose sum is even, say S, and such that there is no
  subset whose sum is S/2? Consider the set: 4 5 6 1. The sum of
  these integers is 16, but there is no subset that will add up to
  8. Thus there is no solution for this instance. Create the
  file Test10.txt, and include an explanation in the
      file TestCases.txt.
  
Similar to the above, construct one example with only negative
  numbers, and one example with 0, negative numbers and positive
  numbers, such that, in each case, the integers add up to an even
    number, say S, and there is no subset whose sum
  is S/2. Create the files Test11.txt
  and Test12.txt, and include the explanations in the
      file TestCases.txt.
  
Are there other cases that need to be considered? If so,
  construct those examples, the corresponding input test files, and
  include explanations in the file TestCases.txt.
  
Now that we have an exhaustive collection of test cases, covering all the possible scenarios, we can start working on the solution. We know we have to read in the set of integers, and then find if there is a subset whose sum is half that of the sum of the original set. We need to have one array to store the user-given set, and an integer to store the number of integers in this set. We also need to store the solution subset, if any, and the number of integers in the solution subset. Finally, we need a boolean variable to indicate if a solution subset was found. So, we can write our function main as:
        // PRE: IS contains n, 0 < n < MAXNUMBERS, followed by
        //        a1, a2, ..., an
        // POST: OS contains b1, b2, ..., bk such that
        //        {b1, b2, ..., bk} subset of {a1, a2, ..., an} and
        //        SUM{b1, b2, ..., bk} = SUM{a1, a2, ..., an}/2.	       
        //       If such a subset does not exist, 
        //        OS contains "No solution found."
	int main () {
          int Set[MAXNUMBERS];  // holds the user-given set
          int numInSet;         // holds the number of elements in the
                                // user-given set
	  readSet (Set, numInSet);
          // ASSERT: numInSet = n				       
          //         Set[0] = a1, Set[1] = a2, ..., Set[n-1] = an.
          printSet (Set, numInSet);
          // ASSERT: OS contains Set[0]..Set[numInSet-1]
          int subset[MAXNUMBERS]; // holds the solution subset, if any
          int numInSubset = 0;    // holds the number of elements in the
                                  // solution subset, if any.
                                  // Currently 0 elements.
          bool foundSolution = false; // true iff there is a solution
                                      // for the given instance
	  findSubset (Set, numInSet, subset, numInSubset, foundSolution);
	  // ASSERT: if foundSolution is true then  
          //            numInSubset = k, 0 < k < n and
          //            subset[0]..subset[k-1] is defined and
          //            subset contains elements from Set and
          //            SUM(subset) = SUM(Set)/2
          if (foundSolution) {
            printSet (subset, numInSubset);
            // ASSERT: OS contains subset[0]..subset[numInSubset-1]
          }
          else {
	    cout << "No soulution was found" << endl;
          }
          return (0);
	}
           
    If each of the
    functions readSet, findSubset,
    and printSet are written so that the assertions
b    written after each of these calls is true, then our program above
      is guaranteed to work correctly.
    
    Write the above function main in a file,
    say subset.cc. Add all the necessary include
    pre-processor directives. Write a
    file subsetHelper.h that contains the declarations
    (just the headers), along with precise pre and post conditions for each,
    for each of the three
    functions readSet, findSubset,
    and printSet. Start a suitable Makefile
    that, for now, contains a target for subset.o and an
      executable called subset.
  
subsetHelper.cc and add the
  definitions for the functions readSet
  and printSet. Add all the necessary include
  pre-processor directives in this file. Do you need the
  constant MAXNUMBERS to be accessible in this file? Do
  you need it accessible in the file subset.cc? Where
  would you add the pre-processor directive to define this constant?
  Make the appropriate additions. Add to the Makefile as
  necessary. 
  findSubset has
  not been defined. So, if you comment out the code in the function
  main from the declaration of subset until
  the return statement, then you should be able to use
  the Makefile to create the
  exectable subset, and run it. The program should simply
  output the user-given set. Make sure this is the case.
  findSubset. The purpose of findSubset
  is to compute a suitable subset, from the user given set. (You
  should already have precise pre/post conditions for this function
  that clearly state what the function needs to accomplish.) As we
  noted earlier, if the sum of the elements of the user-given set is
  an odd number, then there is no solution for the given instance of
      the problem. So, we could start our function as:
  
    void findSubset(int given[], int numInGiven,
                    int solution[], int & numInSolution,
                    bool & foundSolution) {
      int givenSetSum = Sum(given, numInGiven);
      // ASSERT: givenSetSum = SUM (given)
      if (odd(givenSetSum)) {
        foundSolution = false;
      }
      else {
        // ASSERT: SUM(given) is even.
        //         Thus, a solution may be possible.
      }
    }
  
  Why is the parameter numInSolution passed by reference?
  Why is the parameter foundSolution passed by reference?
    Now we can consider the process for finding a solution when
	the sum of the given set is even. Since we have already
	computed the sum of the given set and stored it in the
	variable givenSetSum, our task is now to find a
	subset whose sum is givenSetSum/2, say S -
	we will call
	this value the target sum.
      
If we could somehow consider every possible subset of the user-given set, we could easily check if any of the subsets has the required target sum. A methodical way of constructing each possible subset of the user-given set is to look at two possibilities for each element of the user-given set: (1) include it in the subset, and (2) not include it in the subset. Given a current partial subset, say P, (having included some of the elements at indices less than i, we will include a number, say at index i, in the subset, and then try to include some of the numbers from the rest of the user-given set (i.e., starting at index i+1. If we could not find a solution, then we conclude that any subset that includes elements of P and the number at index i does not give us a required solution. So, we remove the number at index i from our subset and then try to extend P using elements from the user-given set at indices greater than i. This is the essence of the technique of backtracking - we first included the number at index i and then backtracked on our decision.
Suppose the next number to be considered for inclusion in our solution (subset) is p. If this number p is less than or equal to S, then we can add this number to the solution (because there is still hope that there is a solution), and try to find a solution in the rest of the array, but for the target sum S - p. This looks exactly like what we were doing when p was the next number to be considered, and S was the target sum. This suggests using recursion as the programmatic strategy. Moreover, the array size has reduced (since we don't need to consider p), so in the recursion we will be considering a smaller instance; this is a good, desirable thing, because this suggests that the recursion will eventually end with an empty instance.
So, it seems that it will be useful for the function, that
      calls itself recursively, to have access to the index of the
      next number in the set (or index of the next number in the
      array) to consider including in the solution. The first
      "incarnation" of this recursive function should start by
      considering the element at index 0 in the array with the target
	sum of S. Our function findSubset does not
      have these useful quantities as parameters, so it is useful to
      call a helper function that will recursively call itself with
      these additional parameters.
      
We can now add to our function findSubset thus:
  
    void findSubset(int given[], int numInGiven,
                    int solution[], int & numInSolution,
                    bool & foundSolution) {
      int givenSetSum = Sum(given, numInGiven);
      // ASSERT: givenSetSum = SUM (given)
      if (odd(givenSetSum)) {
        foundSolution = false;
      }
      else {
        // ASSERT: SUM(given) is even.
        //         Thus, a solution may be possible.
        int targetSum = givenSetSum/2; // Half of the sum of original set
        int indexToConsider = 0;       // Index of first numebr to consider
                                       //  to include in the solution
        findSubsetHelper (given, numInGiven,
                          solution, numInSolution,
                          foundSolution,
                          targetSum, indexToConsider);
        // ASSERT: foundSolution is true iff there is a subset, say T, of 
        //          given[indexToConsider] .. given[numInGiven-1]
        //          such that the sum of the subset is targetSum.
        //          If foundSolution is true, then the subset T is included
        //          in the array solution (at the end of the array)
      }
      // ASSERT: foundSolution is true iff there is a solution to the 
      //           given instance, and a solution subset is          
      //           solution[0]..solution[numInSolution-1]
    }
  
Consider the user-given data in Test4.txt. If we
    could look at the calls as they were made when the program is
    executed for this data, we expect that the call
    to findSubset would look like
    
      findSubset({4, 1, 2, 3}, 4, {}, 0, false);
    
    The {} indicates that we sent an empty array
    as the parameter solution,
    that numInSolution is 0
    and foundSolution is false when the function is
    called. This function would then compute givenSetSum
    to be 10, and thus, execute the else part of the
    conditional. There, targetSum would be computed as 5,
    and we would make the function call
    
      findSubsetHelper ({4, 1, 2, 3}, 4, {}, 0, false, 5, 0);
    
    i.e., look for a subset, starting at index 0, whose sum is 5.
  
  Now, since the index is 0, the next number to be considered is 4. So, we include 4 in the solution, and we would like the helper function to be recursively called as:
      findSubsetHelper ({4, 1, 2, 3}, 4, {4}, 1, false, 1, 1);
    
    Note that we included 4 in the solution, updated the target sum,
    and also updated the index of the next number to be considered.
  
  Using the same logic as above, we would now like the function to be recursively called as:
      findSubsetHelper ({4, 1, 2, 3}, 4, {4, 1}, 2, false, 0, 2);
    
    Verify that this is what we would like to happen.
  
  Note that in this recursive incarnation of the function, we are
  looking for a subset with a zero sum, i.e., the subset we have found
  is correct! So, we can set foundSolution to be true to
    indicate this, and the function is done with its work.
  
Suppose the user-given input is {4, 5, 6, 1}, verify that the trace of the calls that we would like is:
      findSubset({4, 5, 6, 1}, 4, {}, 0, false);
      ...
      findSubsetHelper ({4, 5, 6, 1}, 4, {}, 0, false, 8, 0);
      ...
      findSubsetHelper ({4, 5, 6, 1}, 4, {4}, 1, false, 4, 1);
      ...
      findSubsetHelper ({4, 5, 6, 1}, 4, {4, 5}, 2, false, -1, 2);
      ...
      findSubsetHelper ({4, 5, 6, 1}, 4, {4, 5, 6}, 3, false, -7, 3);
      ...
      findSubsetHelper ({4, 5, 6, 1}, 4, {4, 5, 6, 1}, 4, false, -8, 4);
      
    
	
	Note that at this stage, the function is given a target sum that is not zero, and the function is expected to consider the number at index 4. Nonetheless, index 4 is beyond the user-given input, since the user-given set has only 4 elements (indexed 0 through 3). Thus, the function finds that with the current solution set (i.e, {4, 5, 6, 1}), it is not possible to find a solution, and it completes, i.e., returns to the calling incarnation of the function. The calling incarnation had added the 1 to the solution before calling the failed incarnation. So, the calling incarnation removes the 1 from the solution to see if that allows the next incarnation to succeed. Thus, after the last function call in the above sequence will return having failed, the previous incarnation will call another incarnation as:
      findSubsetHelper ({4, 5, 6, 1}, 4, {4, 5, 1}, 3, false, -2, 4);
    
  
  In other words, each incarnation tries to find a solution in the two cases: (1) by including the number it is to consider, and (2) by not including the number it is to consider. This strategy must succeed since a solution, if it exists, is essentially some numbers in the given set included in the solution and some numbers not included.
In the above case, each incarnation
  of findSubsetHelper will fail for each of the two
  possibilities (including or not including the number corresponding
  to indexToConsider), and thus the
  function findSubset will complete with a value
    of false in foundSolution.
  
Work out a similar "hand-trace" of calls to findSubset
  and findSubsetHelper for one of your test cases where
  the sum of the given set is even, and there is a solution, and for
  one test case where the sum of the given set is odd, and there is no
    solution.
Write the function findSubsetHelper (header with
    pre/post in the .h file and the definition, i.e.,
    header and body, in the .cc
    file). Include cout statements and/or suitable
    function calls at the beginning of the
    functions findSubset
    and findSubsetHelper so that your program prints out
    the values of all the parameters to the function. This way you can
    compare your program's output to the "trace" you hand-wrote (in
    the item above) when you run your
    program on the same inputs.
Add any additional
    include pre-processor directives you may need in any of your
    program files, update
    the Makefile as necessary, and then make the
      executable. 
Run your executable to ensure that the parameters printed out match your hand-trace (from the item above). If the traces don't match, check your hand-trace from the item above, and then hand-trace your program to understand where, and why, the program deviates from your expected hand-trace.