Exercise 1.19

Now, this question is not as easy as the last. This is the $19^{th}$ from Sicp.

The Question

Exercise 1.19 There is a clever algorithm for computing the Fibonacci numbers in a logarithmic number of steps. Recall the transformation of the state variables a and b in the fib-iter process of Section 1.2.2: $ a \leftarrow a + b $ and $ b \leftarrow a$. Call this transformation $T$ , and observe that applying $T$ over and over again $n$ times, starting with 1 and 0, produces the pair Fib( n + 1) and Fib( n ). In other words, the Fibonacci numbers are produced by applying $T^{n}$ , the $n^{th}$ power of the transformation $T$ , starting with the pair (1, 0). Now consider $T$ to be the special case of $p = 0$ and $q = 1$ in a family of transformations $T_{pq}$ , where $T_ {pq}$ transforms the pair $( a, b )$ according to $a \leftarrow bq + aq + ap$ and $b \leftarrow bp + aq$ . Show that if we apply such a transformation $T_{pq}$ twice, the effect is the same as using a single transformation $T_ {pq}$ of the same form, and compute $p’$ and $q’$ in terms of $p$ and $q$ . This gives us an explicit way to square these transformations, and thus we can compute $T_{n}$ using successive squaring, as in the fast-expt procedure. Put this all together to complete the following procedure, which runs in a logarithmic number of steps:

(define (fib n)
  (fib-iter 1 0 0 1 n))

(define (fib-iter a b p q count)
  (cond ((= count 0) b)
	((even? count)
	 (fib-iter a
		   b
		    ?? ; compute p’
		    ?? ; compute q’
		   (/ count 2)))
	(else (fib-iter (+ (* b q) (* a q) (* a p))
			(+ (* b p) (* a q))
			p
			q
			(- count 1)))))

The Explanation (not my thoughts)

In the previous attempts at the fibonacci sequence, we mostly computed it by adding the “inducting” to the number. With a changes like this:

$a \leftarrow a + b$ $b \leftarrow a$

Consider this “change” to be $T$. $T$ is called a Transformation. $T$ will happen n times. In proper notation, it would be $T_{pq}$. This means a certain transformation happens on p and q.

A different sytax for the same thing

Now consider $T$ to be the special case in a “family” of transformations, where $ p = 0 $ and $ q = 1$. p and q here are internal variables. Do not confuse them with $T_{pq}$.

Consider this transformation where the pair $(a, b)$ according to the following rules:

$$ a \leftarrow bq + aq + ap $$

and

$$ b \leftarrow bp + aq $$

A quick substitution shows us that it’s essentially the same algorithm:

$$ a \leftarrow b(1) + a(1) + a(0) \ a \leftarrow b + a $$

and

$$ b \leftarrow b(0) + a(1)\ b \leftarrow a $$

What the question means

The question wants use to find a way to apply 2 Transformations at once. This can be used to “square” the numbers like the previous fast-expt.

My Thoughts

Now, the reason why variables p and q were introduced is because, using the way we compute a and b, we can skip the computation of numbers inbetween by applying Transformations on p and q . Since, we are free to compute p and q however we want (There is no hard and fast rule to compute it yet) we could possibly use it to change a and b however we want. and when we reach count of one, we can take the values of p and q compute this a and b.

So, what is intended for us to do transform p and q, rather thana and b. You must have already deduced by looking at the missing code.

Now the question is how on Earth do we transform p and q so that we can transform to transform a and b.

How on Earth do we transform p and q (the answer)

Well, (that’s ben in french), the answer lies with a common enemy - Algebra (Or google)

One thing we can do is study how every iteration of the new algorithm changes. So, let’s do that. (And remeber we must focus on p and q )

Let’s give the first iteration a value ($a_{1}$, $b_{1}$):

$$ a{1} \leftarrow b_{0}q + a_{0}q + a_{0}p \ b_{1} \leftarrow b_{0}p + a_{0}q $$

We’ll just use this to refer to iteration 0.

Now, we can say that b in iteration 2 is the following:

$$ \begin{align} b_{2} &= b_{1}p + a_{1} \ &= (b_{0}p + a_{0}q) \times p + (b_{0}p + a_{0}q + a_{0}p) \times q\ &= b_{0}pp + a_{0}qp + b_{0}pq + a_{0}qq + a_{0}pq\ &= (b_{0}pp + b_{0}pq) + (2a_{0}pq + a_{0}qq)\ &= b_{0}(pp + qq) + a_{0}(2pq + qq)\ \end{align} $$

Compare this with our algorithm :

$$ b \leftarrow bp + aq $$

and

$$ b_{0}(pp + qq) + a_{0}(2pq + qq) $$

You begin to see the transformation. p is $p^{2} + q^{2}$ and q is $2pq + q^{2}$.

Write the scheme code

Now to write the scheme

(define (fib n)
  (fib-iter 1 0 0 1 n))
  
(define (fib-iter a b p q count)
  (cond ((= count 0) b)
	((even? count)
	 (fib-iter a
		   b
		   (+ (* p p) (* q q))
		   (+ (* 2 p q) (* q q))
		   (/ count 2)))
	(else (fib-iter (+ (* b q) (* a q) (* a p))
			(+ (* b p) (* a q))
			p
			q
			(- count 1)))))

A quick check in a REPL gives us the right answers

 => (fib 2)

;Value: 1

1 (user) => (fib 100)

;Value: 354224848179261915075

1 (user) => (fib 4)

;Value: 3

1 (user) => (fib 2)

;Value: 1

1 (user) => (fib 3)

;Value: 2

1 (user) => (fib 4)

;Value: 3

1 (user) => (fib 5)

;Value: 5

1 (user) => (fib 10)

;Value: 55

That’s it. Hope that helped