SICP Exercise 1.19

Question

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 1.2.2: aa+b and ba. 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 Tn, the nth 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 Tpq where Tpq transforms the pair (a,b) according to abq+aq+ap and bbp+aq. Show that if we apply such a transformation Tpq twice, the effect is the same as using a single transformation Tpq 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 Tn 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)))))

Answer

(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
                   (+ (* q q) (* p p))
                   (+ (* 2 p q) (* q q))
                   (/ count 2)))
        (else
         (fib-iter (+ (* b q)
                      (* a q)
                      (* a p))
                   (+ (* b p)
                      (* a q))
                   p
                   q
                   (- count 1)))))

As specified in the question, let us first see what the result is if we apply Tpq twice in a row:

abq+aq+apbbp+aqa(bp+aq)q+(bq+aq+ap)q+(bq+aq+ap)pb(bp+aq)p+(bq+aq+ap)q

We can rewrite a as:

abpq+aqq+bqq+aqq+apq+bpq+apq+appa2bpq+bqq+2apq+2aqq+app

Which we can then bring into the same shape as our original transformation abq+aq+ap:

ab(2pq+q2)+a(2pq+q2)+a(p2+q2)

This gives us the values for p and q:

p=p2+q2q=2pq+q2

We can verify this by using these new values for b:

bb(p2+q2)+a(2pq+q2)

And then rewriting our original definition for b to come to the exact same equation:

b(bp+aq)p+(bq+aq+ap)qbbpp+apq+bqq+aqq+apqbbpp+bqq+2apq+aqqbb(p2+q2)+a(2pq+q2)