# Solutions to Second Midterm Exam

### Directions:

• Answer the problems on the exam pages.
• There are three problems for 100 total points plus 10 extra credit. Actual scale is A = 93, C = 65.
• If you need extra space use the back of a page.
• No books, notes, calculators, or collaboration.
• In case of a numerical answer, an arithmetic expression like "32× 26 + 13 × 41" need not be reduced to a single integer.

```  Q1: 35 points
Q2: 25+10 points
Q3: 40 points
Total: 100+10 points
```

Question text is in black, solutions in blue.

Here are several definitions used on the exam.

Remember that natural always means "non-negative integer".

Generalized Fibonacci Numbers:: If a and b are any two naturals, we define the function Ga,b by the rules (1) Ga,b(0) = a, (2) Ga,b(1) = b, and (3) (for n ≥ 1) Ga,b(n+1) = Ga,b(n) + Ga,b(n-1). Note that the ordinary Fibonacci numbers, as defined in Discussion #7, are defined by F(n) = G0,1(n).

A Function From Binary Strings to Integers: Let Σ = {0, 1}, so that Σ* is the set of all binary strings, including the empty string λ. We define the function f from Σ* to the integers, recursively by the rules (1) f(λ) = 0, (2) for any string w, f(w0) = 1 - f(w), and (3) for any string w, f(w1) = 1 + f(w). (Here "w0" is the string made by appending a 0 to w, and similarly for "w1".)

A Labelled Directed Graph: We will look at several searches of the following labelled directed graph G. Each edge goes in only one direction and is labelled by its cost.

``````
1           2
[a] -----> [b] -----> [c]
^          |          |
| 1        | 1        | 3
|          |          |
|    5     V    4     V
[s] -----> [d] -----> [g]
|          |          ^
| 6        | 1        | 1
|          |          |
V    3     V    1     |
[e] -----> [f] -----> [j]
``````

A Heuristic: For an A* search of G with goal node g, we will use the following heuristic. For any node x in g, the function h(x) will give the smallest number of edges on any path from x to g. Thus h(a) = h(e) = 3, h(b) = h(s) = h(f) = 2, h(c) = h(d) = h(j) = 1, and h(g) = 0.

• Question 1 (20): These questions all deal with the generalized Fibonacci numbers defined above.

• (a, 5) Compute the value of G4,2(5). (Hint: If you want to do some arithmetic, compute G4,2(10). If you don't get 246, your method is wrong. But only G4,2(5) is required for the answer.

(I'm going to leave off the subscripts on Ga,b throughout this problem, as we are never changing a or b during any part.) Here we have G(0) = 4, G(1) = 2, G(2) = 6, G(3) = 8, G(4) = 14, G(5) = 22, G(6) = 36, G(7) = 58, G(8) = 94, G(9) = 152, and G(10) = 246. So the answer is 22.

• (b, 10) Let a and b be any two naturals. Prove that for any natural n, Ga,b(n) is an natural (that is, it is an integer and is not negative). (Hint: Use strong induction on n as in the Fibonacci proofs on Discussion #7.)

Strong induction on n. Let P(n) be the statement "G(n) is a natural". First base case, G(0) = a, which is a natural. Second base case, G(1) = b, which is a natural. For the inductive case, let n be arbitrary and assume that n ≥ 1. The SIH says that for any i with i ≤ n, G(i) is a natural. So G(n) and G(n-1) are naturals, and G(n+1) = G(n) + G(n-1) is the sum of two naturals, which is a natural. This proves P(n+1) from the strong IH, completing the strong induction proof of ∀n:P(n).

• (c, 10) Again letting a and b be arbitrary naturals, prove that for all n with n ≥ 1, Ga,b(n+1) ≥ Ga,b(n). (Hint: There are two ways to do this. You could either use strong induction starting with n = 1, or use a direct proof from the definition of Ga,b and the result of part (b).)

Here is the non-inductive proof first. Let n be arbitrary and assume that n ≥ 1. (I generally took off a point for not saying "let n be arbitrary" or otherwise indicating the context of n.) We know that G(n+1) = G(n) + G(n-1). G(n-1) is a natural by part (b). So G(n+1) is equal to G(n) plus a natural, and must be ≥ G(n).

Here's the inductive proof, using strong induction starting with n = 1. Our P(n) is "G(n+1) ≥ G(n)". Note that P(0) could well be false. Base case: When n = 1, G(2) = a + b and G(1) = b, and G(2) ≥ G(1) because a is a natural. For the inductive case, let n be arbitrary and assume n ≥ 1. We could just ignore the SIH and say that G(n+1) = G(n) plus a natural, as above. But we could also use the SIH, which says that G(n+1) ≥ G(n) and G(n) ≥ G(n-1). (To get this latter fact we need that n-1 ≥ 1, but if n = 1 we are done by the base case.) If I take the two inequalities G(n+1) ≥ G(n) and G(n) ≥ G(n-1) and add them, I get G(n+1) + G(n) ≥ G(n) + G(n-1), which by applying the definition of G to both sides becomes G(n+2) ≥ G(n+1). This proves P(n+1) from the SIH and completes the strong induction.

• (d, 10) Again for arbitrary naturals a and b, prove that if n is any natural with n ≥ 2, then Ga,b(n+3) ≤ 5Ga,b(n). (Hint: You don't need induction, but use the result of part (c).)

Let n be arbitrary and assume that n ≥ 2. (Here the bounds on n are important, so you needed to say something about the context of n to get full credit.) Applying the definition, G(n+3) = G(n+2) + G(n+1) = G(n+1) + G(n) + G(n) + G(n-1) = G(n) + G(n-1) + 2G(n) + G(n-1) = 3G(n) + 2G(n-1). Since n ≥ 2, we know that n-1 ≥ 1, and thus by part (c) we know G(n) ≥ G(n-1). Thus 3G(n) + 2G(n-1) ≤ 3G(n) + 2G(n) = 5G(n), as desired. As n was arbitrary, we have completed a generalization proof of ∀n: (n ≥ 2) → G(n+3) ≤ 5G(n).

• Question 2 (25+10): These questions use the definition of the function f: Σ* → Z defined above. (Here Z is the integers -- it is conceivable that f(w) may be a negative integer.)

• (a, 5) Compute the integers f(0110) and f(01010) according to the recursive definition.

First, f(0110) = 1 - f(011) = 1 - (1 + f(01)) = 1 - (1 + (1 + f(0))). Since f(0) = 1 - f(λ) = 1, we have 1 - 3 = -2. If you treated the "-" operator as associative and left off the parentheses, you probably got the wrong answer.

For the other one, f(01010) = 1 - f(0101) = 1 - (1 + f(010)) = 1 - (1 + (1 - f(01))). From above, f(01) = 2, so we get 1 - (1 + (1 - 2) = 1.

• (b, 10) Write a pseudo-Java method ```public static int f (string w)``` to compute f(w) for any pseudo-Java binary string w. Remember that unlike real Java `String` objects, pseudo-Java `string` values are primitives. Use the methods `public static boolean isEmpty`, ```public static char last```, and ```public static string allButLast``` as given in the book. Each of these three methods takes a single argument of type `string`.

``````
public static int f (string w) {
if (isEmpty(w)) return 0;
if (last(w) == '0') return 1 - f(allButLast(w));
if (last(w) == '1') return 1 + f(allButLast(w));
throw new Exception ("f: invalid input string");}
``````

There were lots of syntax errors, mostly people ignoring the note about `string` values being primitive and writing `w.isEmpty( )` and so forth. Also, many people wrote code that would not compile because the compiler could not see a `return` statement or exception on every computation path. There were many ways to deal with the case where w is non-empty and `last(w)` is neither `'0'` nor `'1'` -- since this will never happen for valid input I don't care what you did, but you had to do something. I took off only a point for either or both of these errors. I didn't take off it the only error was `"0"` instead of `'0'`, but I did take off for just `0`.

• (c, 10) Prove by induction on all binary strings w that f(0w) = f(1w). Here "0w" is the string obtained by prepending a 0 to w. Remember that the Law of Induction for binary strings says that to prove ∀w:P(w), you must prove P(λ), ∀w: P(w) → P(w0), and ∀w: P(w) → P(w1). Note that "P(w1)", for example, means "f(0w1) = f(1w1)".

We define P(w) to be "f(0w) = f(1w)". P(λ) says that f(0λ) = f(1λ), which means f(0) = f(1), and this is true because f(0) = 1 - f(λ) = 1 and f(1) = 1 + f(λ) = 1. So now let w be arbitrary, assume that P(w) is true, and we will prove both P(w0) and P(w1). P(w0) says "f(0w0) = f(1w0)", which reduces by the definition to 1 - f(0w) = 1 - f(1w), which is true because f(0w) = f(1w) by the IH. Similarly P(w1) reduces to 1 + f(0w) = 1 + f(1w), and this also follows from the IH.

• (d, 10XC) Prove that for any string w, if f(w) = 0, then the length of w cannot be odd.

The proof is easy once you find the right statement to prove, which is that f(w) is odd if and only if the length of w is odd. We can prove this by induction for all strings, with P(w) being "f(w) and |w| are both odd or both even". P(λ) is true because f(λ) and |λ| are both 0 and thus both even. Assuming that f(w) and |w| are both odd or both even, we note that f(w0) = 1 - f(w), f(w1) = 1 + f(w), and |w| all have the opposite parity from f(w) and |w|, and thus have the same parity as each other.

You can use induction on odd numbers to prove that for any odd n, for any w of length n, f(w) is odd. This is easy to prove by assuming that f(w) is odd and calculating f(w00), f(w01), f(w10), and f(w11) and showing that each of these numbers is odd. Many of you tried to do this induction with the wrong P(w), trying to show that if |w| is odd, f(w) is nonzero. But just knowing that f(w) ≠ 0 does not tell you that f(w11) = f(w) + 2, for example, is also nonzero. The reason this problem was extra credit is that you have to not only prove something by induction but figure out the exact statement you need to prove -- the stronger statement is easier to prove by induction.

• Question 3 (40): These four questions involve four searches of the directed labelled graph G from above, each with start node s and goal node g. Note that the edge labels are only used in parts (c) and (d). In every case, when two nodes are eligible to come off the open list at the same time, the one whose name comes first in the alphabet comes off first. Also note that in all four searches, we do not put a node onto the open list if it has already come off the list. (Whether a node can go on the open list, when another copy of it is already on the open list, depends on which search you are doing.)

• (a, 10) Describe the action of a depth-first search of G, with start node s and goal node g. Which nodes go on the open list, and what path from s to g is found by the search?

The list begins as {s}. Then s comes off, a, d, and e go on, and the list is {a, d, e}. Then a comes off, b goes on, and the list is {b, d, e}. Then b comes off, c and d go on, and the list is {c, d, d, e}. Then c comes off and g goes on. We do not stop yet because the algorithm says to wait until g comes off. The list is now {g, d, d, e}. Finally g comes off and we declare victory with a path s → a → b → c → g.

• (b, 10) Describe the action of a breadth-first search of G, with start node s and goal node g. Which nodes go on the open list, and what path from s to g is found by the search?

The list begins as {s}. First s comes off, and a, d, and e go on. Then a comes off, and b goes on making the list {d, e, b}. Then d comes off and f and g go on, making the list {e, b, f, g}. Then e comes off and f goes on again (it is not yet on the closed list) making the list {b, f, g, f}. Then b comes off and j goes on, making the list {g, f, c, j}. Finally g comes off and we declare victory. The path is s → d → g, as we put d on for its edge from s and g on for its edge from d.

• (c, 10) Describe the action of a uniform-cost search of G, with start node s and goal node g. Which nodes go on the open list, and what path from s to g is found by the search?

The list begins as {s0}. We take s0 off and put on a1, d5, and e6. We take a1 off and put on b2, making the list {b2, d5, e6}. We take b2 off and put on c4 and d3, making the list {d3, c4, d5, e6}. We take d3 off and put on g7 and f4, making the list {c4, f4, d5, e6, g7}. We take off c4 (breaking the tie alphabetically) and put on another g7, making the list {f4, d5, e6, g7, g7}. We take off f4 and put on j5, making the list {d5, j5, e6, g7, g7}. We take off d5 and discard it because d is already on the closed list. We take off j5 and put on g6, making the list {e6, g6, g7, g7}. We take off e6 and put nothing on because f is already on the closed list. Finally we take g6 off and declare victory with the path s → a → b → d → f → j → g.

• (d, 10) Consider an A* search of G with start node s and goal node g. You do not have to carry out the entire search if you can answer the following three questions: (1) Explain how h meets the conditions for an admissible heuristic, (2) What path from s to g is returned by the search, and (3) Why does the node e never come off the open list in the A* search, while it does come off of it in the uniform-cost search?

All edges in G have cost at least 1. So the cost of the cheapest path from x to g is at least as great as the number of edges on that path, which is at least as great as the smallest number of edges on any path. The definition of "admissible heuristic" requires that h(x) ≥ 0 and h(x) ≤ d(x, g). We've shown the latter, and the former is true because a path must have a non-negative number of edges.

The path returned by the A* search is the same path as in uniform-cost search, in this case s → a → b → d → f → j → g.

The node e goes on the priority queue with priority 9, since its distance from s is 6 and h(e) = 3. Since there is a path of cost 6 from s to g, and h(g) = 0, g will go on the priority queue with priority 6, and come off before e does. In the uniform-cost search, e and g both have priority 6 and e comes off first by the alphabetical tiebreaker.

The A* search begins with {s2} on the priority queue, takes off s2 and puts on a4, d6, and e9, takes off a4 and puts on b4, takes off b4 and puts on c5 and d4, takes off d4 and puts on f6 and g7, takes off c5 and puts on g7, takes off f6 and puts on j6, takes off j6 and puts on g6, and finally takes off g6 and declares victory.