Concrete Abstractions: Chapter 4

Exercise 4.2 In this exercise you will show that this version of mod-expt does \Theta (e) multiplications, as we claimed.
a. Use induction to prove each of the following about this latest version of mod-expt:
(1) e is a nonnegative integer, (mod-expt b e m) does at least e multiplications.
(2) When e is a positive integer, (mod-expt b e m) does at most 2e – 1 multiplications.

Solution: At first I wrote the function mathematically. mod^* = m^*(x, y) = xy \text{ mod } m.
\text{mod-expt} = m(b, e, m)
m(b, 0, m) = 1
m(b, e, m) = \begin{cases} m^*(m(b, e/2, m), m(b, e/2, m) & \text{ if e is even}\\ m^*(m(b, e-1, m), b) & \text{ if e is odd }\\ \end{cases}

(1) Ok, now let’s start with the first assumption: m(b, e, m) does at least e multiplications. For e=0 follows that m(b, 0, m) = 1. So that’s true. Therefore we can assume that this holds to e+1.
If e+1 is odd:
m(b, e+1, m) = m^*(m(b, e, m), b), we assumed that m(b, e, m) does e multiplications. If we look back at the definition of m^*(x,y), we can see that there’s one multiplication. Therefore there are e + 1 multiplications. That was the best case, let’s look at the worst one.

(2) The assumption is that m(b, e, m) needs 2e-1 multiplications at most. Let’s check the base case for e=1. m(b, 1, m) = m^*(m(b, 0, m), b). Here we get one multiplication from m^*, so the maximum limit holds. If e+1 is even, it follows that:
m(b, e+1, m) = m^*(m(b, (e+1)/2, m), m(b, (e+1)/2, m)). Each nested m(b, (e+1)/2, m) needs at most 2* \frac{(e+1)}{2} -1 multiplications and we got another from m^*. That is, there are 2 * (2*\frac{(e+1)}{2} -1) + 1 = 2(e+1) - 1 multiplications.

You can check the even case in (1) and the odd case in (2) for yourself and see that these are bigger and respectively smaller than the other ones.

Exercise 4.11 Consider the following procedures:

In answering the following, assume that n is a nonnegative integer. Also, justify your answers.
a. Give a formula for how many multiplications the procedure factorial does as a function of its argument n.
b. Give a formula for how many multiplications the procedure factorial-sum1 does (implicitly through factorial) as a function of its argument n.
c. Give a formula for how many multiplications the procedure factorial-sum2 does as a function of its argument n.

Solution:
a. \text{factorial}(0) = 1, \text{factorial}(n) = n * \text{factorial}(n-1)
What happens for n = 1, 2, 3,..? Let’s see:
\text{factorial}(1) = 1 * \text{factorial}(0) = 1 * 1
\text{factorial}(2) = 2 * \text{factorial}(1) = 2 * 1 * \text{factorial}(0) = 2 * 1 * 1
\text{factorial}(3) = 3 * \text{factorial}(2) = 3 * 2 * \text{factorial}(1)
= 3 * 2 * 1 * \text{factorial}(0) = 3 * 2 * 1 * 1
We can see that there are probably n+1 multiplications. We can prove that by induction.
\text{factorial}(n+1) = (n+1) * \text{factorial}(n). We assumed that \text{factorial}(n) multiplies (n+1) times. Therefore we have 1 + (n+1) = (n+1) + 1 multiplications.
b. And again written mathematically:
\text{factorial-sum1}(0) = 0
\text{factorial-sum1}(n) = \text{factorial}(n) + \text{factorial-sum1}(n-1)
So was happens here here for n = 1, 2, ..?
\text{factorial-sum1}(1) = \text{factorial}(1) + \text{factorial-sum1}(0)
= (1 * 1) + 0
\text{factorial-sum1}(2) = \text{factorial}(2) + \text{factorial-sum1}(1)
= (2 * 1 * 1) + \text{factorial}(1) + \text{factorial-sum1}(0)
= (2 * 1 * 1) + (1 * 1) + 0
For n=1 we need 2 multiplications, for n=2 we need 2 + 3 multiplications. In general we need \sum_{i=1}^n (i+1) multiplications. This can be simplified: \sum_{i=1}^n i + sum_{i=1}^n 1 = \frac{n(n+1)}{2} + n = \frac{n^2 + 3n}{2}.
c. This is pretty straight forward. You can see that each iteration k is increased by one. It starts at k = 1 and stops if k > n. So it runs n times.

Exercise 4.12 How many ways are there to factor n into two or more numbers (each of which must be no smaller than 2)? We could generalize this to the problem of finding how many ways there are to factor n into two or more numbers, each of which is no smaller than m. That is, we write

Your job is to write ways-to-factor-using-no-smaller-than.

Solution: An easy way to find factors is just to try every number if it divides n, starting with m. If a number divides n, take the division and find its factors.

Exercise 4.13 Consider the following procedure:

How many multiplications (expressed in \Theta notation) will the computation of (bar n) do? Justify your answer. You may assume that n is a nonnegative integer.

Solution: The definition of bar is:
\text{bar}(0) = 5
\text{bar}(1) = 7
\text{bar}(n) = n*\text{n-2}
For n = 0, 1, 2, 3, ... we get:
\text{bar}(0) = 5 \text{ | (0 multiplications)}
\text{bar}(1) = 7 \text{ | (0 multiplications)}
\text{bar}(2) = 2 * \text{bar}(0) = 2 * 5 \text{ | (1 multiplications)}
\text{bar}(3) = 3 * \text{bar}(1) = 3 * 7 \text{ | (1 multiplications)}
\text{bar}(4) = 4 * \text{bar}(2) = 4 * 2 * 5 \text{ | (2 multiplications)}
\text{bar}(5) = 5 * \text{bar}(3) = 5 * 3 * 7 \text{ | (2 multiplications)}
You can see that there are between \frac{n-1}{2} and \frac{n}{2} multiplications. Therefore there are \Theta(n) multiplications at general.

Exercise 4.14 Consider the following procedures:

How many multiplications (expressed in \Theta notation) will the computation of (foo n) do? Justify your answer.

Solution: It’s basically the same schema as the other exercises. If we look at foo it looks like this:
\text{foo}(n) = \text{fac}(n) + \text{bar}(n, n) We already know that \text{fac}(n) needs (n+1) multiplications. If we look at bar, we can see how it works.
\text{bar}(i,j) = \text{fac}(i) * \text{bar}(i,j-1) we can simplify this because foo which calls bar only uses the argument n.
\text{bar}(n,n) = \text{fac}(n) * \text{bar}(n,n-1). Because we already know how many multiplications fac needs, we can concentrate on bar. Let’s see what it does for n = 1, 2, 3, ...:
\text{bar}(0, 0) = 1 \text{ | 0 multipl. }
\text{bar}(1, 1) = \text{fac}(1) * \text{bar}(0, 0) text { | 2 + 1 + 0 multipl.}
\text{bar}(2, 2) = \text{fac}(2) * \text{bar}(1, 1) \text { | 3 + 1 + (2 + 1) multipl.}
We can generalize this as \sum_{k=3}^{n+2} k = \sum_{k=1}^{n+2} - 3 which can be simplified as: \frac{(n+2)(n+3)}{2} - 3 = \frac{(n+2)(n+3) - 6}{2} = \frac{n^2 + 5n}{2} therefore we have \Theta(n^2) multiplications.

Exercise 4.17 Consider the following enumeration problem: How many ways can you choose k objects from n distinct objects, assuming of course that 0 \leq k \leq n? For example, how many different three-topping pizzas can be made if you have six toppings to choose from?
The number that is the answer to the problem is commonly written as C(n, k). Here is an algorithm for computing C(n, k): […]
Using this algorithm, write a tree-recursive procedure that calculates the numbers C(n, k) described above.

Solution:

Exercise 4.18 One way to sum the integers from a up to b is to divide the interval in half, recursively sum the two halves, and then add the two sums together. Of course, it may not be possible to divide the interval exactly in half if there are an odd number of integers in the interval. In this case, the interval can be divided as nearly in half as possible.
a. Write a procedure implementing this idea.
b. Let’s use n as a name for the number of integers in the range from a up to b. What is the order of growth (in \Theta notation) of the number of additions your procedure does, as a function of n? Justify your answer.

Solution: a.

b. It’s basically the same as in mod-expt because both split up the calculation in two branches each time. Therefore it needs \Theta(\text{log } n) additions.

Concrete Abstractions: Chapter 3

Let’s call the number of people in the circle n and number the positions from 1 to n. We’ll assume that the killing of every third person starts with killing the person in position number 3. […]
As we saw above, if the person we care about is in position 3, that person is the one killed and hence definitely not a survivor:

Suppose we aren’t interested in the person in position number 3 but rather in some other person—let’s say J. Doe. The person in position number 3 got killed, so now we only have n – 1 people left. Of that smaller group of n – 1, there will still be two survivors, and we still want to know if J. Doe is one of them.

Exercise 3.9 How about the people who were in positions 1 and 2; what position numbers are they in after the renumbering?

Solution: In the example there were 8 persons at the start. After killing #3, the new #1 is #4, the new #2 is #5*, etc. #2 is #(n-1) and #1 is #(n-2).

*: clearly a reference to the Prisoner ;)

Exercise 3.10 Write a procedure for doing the renumbering. It should take two arguments: the old position number and the old number of people (n). (It can assume that the old position number won’t ever be 3, because that person is killed and hence doesn’t get renumbered.) It should return the new position number.

Solution:

Exercise 3.11 Finish writing the survives? procedure, and carefully test it with a number of cases that are small enough for you to check by hand but that still cover an interesting range of situations.

Solution:

I made a table for testing if the program works correctly. Each line represents a new round, i.e. somebody got killed. The killed person is labeled with X.

Exercise 3.15 Consider the following two procedures:

a. Use the substitution model to evaluate each of (f 1), (f 2), and (f 3).
b. Can you predict (f 4)? (f 5)? In general, which arguments cause f to return 0 and which cause it to return 1? (You need only consider nonnegative integers.)
c. Is the process generated by f iterative or recursive? Explain.

Solution: a. I started to define each function mathematically. f(0) = 0, f(n) = g(n-1) and g(0) = 1, g(n) = f(n-1). Now we can see what’s happening.
f(1) = g(0) = 1
f(2) = g(1) = f(0) = 0
f(3) = g(2) = f(1) = g(0) = 1
b. You see that odd numbers lead to g(0) = 1 and even numbers lead to f(0) = 0.
c. I would say that f’s process iterative because you could stop at any time and just continue later with the saved parameters.

Exercise 3.16 Consider the following two procedures:

a. Use the substitution model to illustrate the evaluation of (f 2), (f 3), and (f 4).
b. Is the process generated by f iterative or recursive? Explain. c. Predict the values of (f 5) and (f 6).

Solution: a. Same trick at last time.
f(0) = 0, f(n) = 1 + g(n-1) and g(0) = 1, g(n) = 1 + f(n - 1)
Therefore: f(2) = 1 + g(1) = 1 + (1 + f(0)) = 1 + 1 + 0 = 2
f(3) = 1 + g(2) = 1 + (1 + f(1)) = 1 + (1 + (1 + g(0))) 1 + (1 + (1 + 1) = 3
f(4) = 1 + g(3) = 1 + (1 + f(2)) = 1 + (1 + (1 + g(1))) = 1 + (1 + (1 + (1 + f(0)))) = 3

b. The process is recursive because you can’t just stop and continue later. This happens because of the (+ 1 f) which have to be saved on the stack.
c. The values of (f 5) and (f 6) are both 6.

Exercise 3.18 We’ve already seen how to raise a number to an integer power, provided that the exponent isn’t negative. We could extend this to allow negative exponents as well by using the following definition:
 b^n = \begin{cases} 1 & \text{ if } x=0 \\ b^{n-1}*b & \text{ if } n>0 \\ b^{n+1}/b & \text{ if } n<0 \end{cases}
a. Using this idea, write a procedure power such that (power b n) raises b to the n power for any integer n.
b. Use the substitution model to show how (power 2 -3) would be evaluated. (You can leave out steps that just determine which branch of a cond or if should be taken.) Does your procedure generate a recursive process or an iterative one?

Solution a.

b.

It’s an recursive one because you can’t determine the final solution without knowing the beginning parameters.

Exercise 3.19 Prove that, for all nonnegative integers n and numbers a, the following procedure computes the value 2^n *a:

Solution Let’s define the function again mathematically. f(0, a) = a, f(n, a) = f(n-1, 2a). The base case is correct:
f(0, a) = 2^0*a = a.
We assume that f(n+1, a) = 2^{n+1}*a = 2^n * 2a which can be written as 2^n * 2a = 2^n * b.
With our assumption it should follow that f(n+1, a) = f(n, b).
If we look at the definition, we see that f(n, a) = f(n-1, 2a) which implies f(n+1, a) = f(n, 2a) = f(n, b).

Concrete Abstractions: Chapter 2

At the moment I’m working through Concrete Abstractions which is so far pretty great. I enjoy the writing style and the difficulty of the exercises. You can buy a used copy for about 10 bucks or read it for free online.

I’m going to present solutions to some exercises. However, I recommend working through this book by yourself. You’ll learn a lot!

Exercise 2.9 Write a procedure that computes the number of 6s in the decimal representation of an integer. Generalize this to a procedure that computes the number of d’s, where d is another argument.

Solution: Idea behind this algorithm is to find the last digit, evaluate it and shorten the number by one digit. You can achieve the first one by taking the reminder of the number n and 10. For example: Reminder of 151 / 10 = 1, because 151 / 10 = 15.1 \implies 0.1 * 10 = 1.
The last thing to do is to shorten the number. It’s easy done by subtracting the reminder of the number and dividing it by ten: $latex 151 – 1 = 150 \implies 150 / 10 = 15

Exercise 2.12 Any positive integer i can be expressed as i=2^nk, where k is odd, that is, as a power of 2 times an odd number. We call n the exponent of 2 in i. For example, the exponent of 2 in 40 is 3 (because 40 = 2^35) whereas the exponent of 2 in 42 is 1. If i itself is odd, then n is zero. If, on the other hand, i is even, that means it can be divided by 2. Write a procedure for finding the exponent of 2 in its argument.

Solution: The trick here is quite easy. We know that k needs to be an integer. I just test this by comparing the results of i / 2^n. Furthermore, I calculated a upper limit for n which equals \log_2 (i). If you choose the smallest positive k, i.e. 1 then i = 2^n*1 \implies \log_2 i = n. This makes the implementation in Scheme a bit more convenient.

Exercise 2.16 Consider the following procedure foo:

Use induction to prove that (foo x n) terminates with the value \frac{x^{n+1} - 1}{x-1}
for all values of x \neq 1 and for all integers n \geq 0. You may assume that expt works correctly, (i.e., (expt b m) returns b^m).

Info: I show a inductive proof a bit more verbose in the following exercise.

Solution: The base case is foo(x, 0) = \frac{x^{0+1} - 1}{x-1} = 1.
We assume that foo(x, n) = \frac{x^{n+1} - 1}{x-1}.
Therefore foo(x, n+1) = x^{n+2} + foo(x, n) which is foo(x, n+1) = x^{n+2} + \frac{x^{n+1} - 1}{x-1}
= \frac{x^{n+2}(x-1)}{x-1} + \frac{x^{n+1} - 1}{x-1} = \frac{x^{n+1}(x-1) + x^{n+1} - 1}{x-1} = \frac{x^{n+2} - 1}{x-1}.

Exercise 2.18 Prove by induction that for every nonnegative integer n the following procedure computes 2n:

Solution: At first look at the definition. f(0) = 0 and f(n) = 2 + f(n-1).
Now we test the base case: f(0) = 2*0 = 0 which is true.
The inductive step is f(n+1) = 2 + f(n) where we assume that f(n) = 2n. Therefore f(n+1) = 2 + 2n = 2(1+n).

Exercise 2.20 Prove that the following procedure computes n/(n+1) for any nonnegative integer n. That is, (f n) computes n/(n+1) for any integer $latex n \geq 0.

Solution: The function is defined as f(0) = 0 and f(n) = f(n-1) + \frac{1}{n * (n+1)}. First we test the base case. f(0) = 0/(0+1) = 0. Afterwards the inductive step:
f(n+1) = f(n) + \frac{1}{(n+1) * ((n+1)+1)} where we assume that f(n) = n/(n+1). Therefore, f(n+1) = \frac{n}{n+1} + \frac{1}{(n+1) * ((n+1)+1)} = \frac{n(n+2)+1}{(n+1)(n+2)} = \frac{n^2+2n+1}{(n+1)(n+2)}. You can see that the numerator is the first binomial formula: \frac{(n+1)^2}{(n+1)(n+2)} = \frac{(n+1)}{(n+2)} = \frac{n+1}{(n+1) + 1}.

The one-layer thinking maxim: Don’t try to think recursively about a recursive process.