Wednesday, August 14, 2013

Fibonacci Sequence and Linear Recurrences: Part II

This post is mostly concerned with solving recurrences through programming. More specifically, given a homogeneous linear recurrence:

$f(n)=\sum\limits_{i=1}^{d} a_i f(n - i)$

we want to compute the value of $f(n)$ for any given integer $n$.

Fibonacci Sequence

We will use the Fibonacci sequence as a starting point: $F(n) = F(n - 1) + F(n - 2)$, with $F(1) = 1$, $F(0) = 0$. Last time we discovered a closed form solution for $F(n)$:

$F(n) = \frac{1}{\sqrt{5}} (\frac{1 + \sqrt{5}}{2})^n - \frac{1}{\sqrt{5}} (\frac{1 - \sqrt{5}}{2})^n$

This would allow us to compute $F(n)$ in $O(1)$ time, but suffers from precision errors when $n$ gets high. We want a solution that does not need to deal with irrational numbers. The first approach is to write the recurrence explicitly:

FIBONACCI(n):
  if n = 0
      return 0
  if n = 1
      return 1
  return FIBONACCI(n - 1) + FIBONACCI(n - 2)

This works, but has the disadvantage of being very slow. If we let $T(n)$ denote the number of steps it takes to compute FIBONACCI(n), then $T(n)$ satisfies the recurrence:

$T(n) = T(n - 1) + T(n - 2)$

which, as we saw last time, has exponential growth. If we look at the recursion tree generated by the FIBONACCI function we see that we do a lot of unnecessary computation:

Recursion Tree

From the above, we see that we are computing some quantities several times. For instance, $F(n-2)$ will be called twice in the computation of $F(n)$. To avoid unnecessary computation, we introduce two variables $a$, and $b$, that will maintain intermediate results:

FIBONACCI(n, a, b):
  if n = 0:
      return b
  if n = 1:
      return a
  return FIBONACCI(n - 1, a + b, a)

We just need to figure out what the initial values of $a$ and $b$ should be. But since $F(0) = 0$, we have that $b = 0$, and since $F(1) = 1$, we require $a = 1$.

As it turns out, although there is little difference between the two code blocks, the performance difference is huge. If we let $T(n)$ be the number of operations required to compute FIBONACCI(n), we have $T(n) = T(n - 1) + 1$, the $1$ coming from the evaluation of $a+b$ in the recursive call. A solution to that recurrence relation is $T(n) = n$.

Although linear is oftentimes the best we can hope for, in this case we can do better. For the extra performance boost, we have to notice the following identity:

Theorem 1. Define the $2x2$ matrix $C$ as:

$C = \begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}$

Then the following identity holds:

$$ \begin{equation}\label{id} C \begin{bmatrix} F(n-1) \\ F(n) \end{bmatrix} = \begin{bmatrix} F(n) \\ F(n + 1) \end{bmatrix} \end{equation}$$

Moreover, a natural extension of this fact is:

$$ \begin{equation}\label{pow} C^n \begin{bmatrix} F(0) \\ F(1) \end{bmatrix} = \begin{bmatrix} F(n) \\ F(n + 1) \end{bmatrix} \end{equation}$$

Proof. The first half is immediate if we multiply the two. For the second half, we will proceed by induction. Denote the statement by $P(n)$. Then:

$P(0): C^0 \begin{bmatrix} F(0) \\ F(1) \end{bmatrix} = I_{2} \begin{bmatrix} F(0) \\ F(1) \end{bmatrix} = \begin{bmatrix} F(0) \\ F(1) \end{bmatrix}$

Suppose $P(n - 1)$ holds. We write $P(n)$ as:

$$ \begin{eqnarray*} P(n): C^n \begin{bmatrix} F(0) \\ F(1) \end{bmatrix} &=& C \left( C^{n-1} \begin{bmatrix} F(0) \\ F(1) \end{bmatrix} \right)\\ &=& C \begin{bmatrix} F(n - 1) \\ F(n) \end{bmatrix} = \begin{bmatrix} F(n) \\ F(n + 1) \end{bmatrix} \end{eqnarray*}$$

The second equality follows from the inductive hypothesis, while the third follows from \eqref{id}.

Corollary.

$$ \begin{equation} C^n = \begin{bmatrix} F(n-1) & F(n) \\ F(n) & F(n + 1) \end{bmatrix} \end{equation}$$

The good thing about powers is that you can compute them in logarithmic time by exploiting the following identities:

$$ \begin{eqnarray*} x^n &=& (x^{\frac{n}{2}})^2, &\forall n, \text{ n even}\\ x^n &=& x (x^\left\lfloor \frac{n}{2} \right\rfloor)^2, &\forall n, \text{ n odd} \end{eqnarray*}$$

Here is some pseudocode. In the following, $X$ can be any type that supports multiplication (including an $nxn$ matrix), and $I$ is the identity element with respect to multiplication.

FAST-POWER(X, n)
  if n = 0
      return I

  Z <- FAST-POWER(X, n/2)
  if n mod 2 = 0
      return Z * Z
  else
      return X * Z * Z

If we let $T(n)$ denote the number of operations, we have $T(n) = T(n/2) + O(1)$, if the multiplication can be performed in constant time. This recurrence has a solution $T(n) = O(log(n))$. I will not prove this now, but intuitively, the problem size gets halved at each step.

With this, we can now proceed to our final algorithm. This computes the $n$-th Fibonacci number in $O(log(n))$ time by exploiting the properties above. $C$ is the matrix from Theorem 1.

FIBONACCI(n)
  Z <- FAST-POWER(C, n)
  return Z[1, 2]

Multiplying two $nxn$ takes $O(n^3)$ time, but since $C$ is a $2x2$ matrix, this is $O(1)$, so all we care about is the time complexity of FAST-POWER, which is $O(log(n))$.


This concludes part II of this series. In part III, we will generalize these results to other linear recurrences.

Friday, August 9, 2013

Fibonacci Sequence and Linear Recurrences: Part I

In this series of short blog posts, I will try to go into detail regarding the Fibonacci sequence in particular, and linear recurrences in general. This first part discusses the Fibonacci sequence, ending with a closed form solution. Part two will go into detail regarding implementation in code, and part three will generalize the first two parts for general linear recurrences.


You probably all know the Fibonacci sequence, but just in case you've forgotten, let me refresh your memories. The classic example is about rabbit populations, so we will use that as a starting point.

Let's say we release two rabbits (a male and female) into the wild. Rabbits are able to mate at the age of 1 month, so that at the end of 2 months the female can produce another pair of rabbits. Rabbits will never die, and mating always produces another pair (a male and a female).

How many rabbit pairs will there be at the end of one year?

Working it out on a piece of scratch paper, we get something like this:

  • After one month, the rabbits mate, but there is still only one pair.
  • After two months, the female produces another pair, so there are now 2 rabbit pairs in the field.
  • After three months, the original female produces another pair, leading to 3 rabbit pairs.
  • At the end of four months, the original female produces yet another pair, and the female born two months ago also produces a pair, making 5 pairs total.

It seems that at the end of each month the number of rabbit pairs is the sum of the number of rabbit pairs in the previous two months. This makes sense, as rabbits do not die, so the population of the previous month is still alive, and all females that are at least two months old give birth to a pair of rabbits.

We can write this formally as:

$F(n) = F(n-1) + F(n-2), \forall n \geq 2$

with $F(1) = 1$, $F(0) = 0$.

The first 10 terms of this sequence are: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34.

Definition 1. A linear homogeneous recurrence relation is an equation of the form:

$f(n) = \sum\limits_{i=1}^{d} a_{i} f(n-i)$

where all the $a_{i}$ are constants.

In the Fibonacci example, $a_{1} = 1, a_{2} = 1$. To solve a linear recurrence relation, one thing we could try to do is guess the solution. The Fibonacci example looks as if it was increasing exponentially, so we can try the guess $F(n) = cx^n$ for some constant $c$.

Replacing in the recurrence relation, we get $cx^n = cx^{n-1} + cx^{n-2}$. Dividing by $cx^{n-2}$ throughout, we are left with the quadratic $x^2 - x - 1 = 0$, which has solutions $\frac{1 \pm \sqrt{5}}{2}$.

So we have two solutions to the recurrence relation:

$F(n) = c(\frac{1 + \sqrt{5}}{2})^n$     $F(n) = c(\frac{1 - \sqrt{5}}{2})^n$

We will digress a bit before arriving at a closed form solution.

Theorem 1. If $f(n)$ and $g(n)$ are two solutions to a recurrence relation, then any linear combination of the two is also a recurrence relation.

Proof. We know that $f(n)$ and $g(n)$ both satisfy the recurrence relation:

$f(n) = \sum\limits_{i=1}^{d} a_{i} f(n-i)$     $g(n) = \sum\limits_{i=1}^{d} a_{i} g(n-i)$

A linear combination of the two yields:

$cf(n)+dg(n) = \sum\limits_{i=1}^{d} a_{i}(c f(n-i) + d g(n-i))$

Using this theorem we can write $F(n) = c_1 (\frac{1 + \sqrt{5}}{2})^n + c_2 (\frac{1 - \sqrt{5}}{2})^n$. Substituting $n=0$ gives us:

$F(0) = c_1 (\frac{1 + \sqrt{5}}{2})^0 + c_2 (\frac{1 + \sqrt{5}}{2})^0 = c_1 + c_2 = 0$

The second boundary condition ($n=1$) yields:

$F(1) = c_1 (\frac{1 + \sqrt{5}}{2}) + c_2(\frac{1 - \sqrt{5}}{2}) = 1$

Solving the system of linear equations gives us $c_1 = \frac{1}{\sqrt{5}}$, $c_2 = -\frac{1}{\sqrt{5}}$. We thus have a closed form solution for the Fibonacci sequence:

$F(n) = \frac{1}{\sqrt{5}} (\frac{1 + \sqrt{5}}{2})^n - \frac{1}{\sqrt{5}} (\frac{1 - \sqrt{5}}{2})^n$


Part two will be about solving recurrences in code.

Saturday, October 22, 2011

Nim

Nim is a mathematical game where two players take turns removing objects from heaps. The mathematical theory behind the game was fully developed in [1] by C. Bouton. What follows is a rough description of the game and a proof that gives the winning strategy.

Description

Given $n$ heaps, each with a number $k_{i}$ of objects in it, two players take turns removing as many objects as desired from one heap. A player is forced to remove at least one object, but it is possible to take all the objects in a heap. The winner of the game is the person who takes the last object off the table.

Given heaps of sizes $(1, 2, 3),$ Ligia and Paul decide to play a game of Nim, and Bob, being the gentleman that he is, lets Ligia start.
  • Ligia takes 1 from the first heap, leaving $(0, 2, 3)$
  • Paul takes 1 from heap 3, leaving $(0, 2, 2)$
  • Ligia takes 1 from heap 2, leaving $(0, 1, 2)$
  • Paul takes 1 from heap 3, leaving $(0, 1, 1)$
At this point, Paul has won the game. We shall see that, if Paul doesn't make any mistakes, he will win from that initial position only if he goes second. First, some preliminary remarks:
  1. From any position with only one heap, the player that starts will always win (he can take the entire heap).
  2. Any position with two heaps of equal size constitutes a loss for the player that has to move. If player A takes $k$ pieces from one of the two heaps, player B can take $k$ pieces from the second and reestablish equality.
  3. Any position with two heaps of unequal sizes constitutes a win for the first player. He can just equalise the two heaps, and from (2) we know that position is a loss for player B.
For three heaps, it gets tricky. If the reader is so inclined, he can try and solve Nim for three heaps. Some interesting heap sizes to consider are $(1, 2, 2), (1, 2, 3), (2, 4, 6)$.

For those less inclined toward work, the following theorem states whether the player that starts has a winning strategy.

Theorem: The first player to move has a winning strategy iff the nim-sum of the heap-sizes is not 0.

A nim-sum of two elements is the sum of its bits neglecting carry. For those with a background in programming, a nim-sum is the same as a XOR operation. For instance:
$$3 \oplus 2 = 11 \oplus 10 = 01 = 1$$

Proof:
Let $x_{1}, x_{2}, x_{3},... , x_{n}$ be the initial heap-sizes, and suppose one player removed objects from heap $k$. Let $$s = x_{1} \oplus x_{2} \oplus ... x_{n}$$ $$t = y_{1} \oplus y_{2} \oplus ... y_{n}$$

where $y_{i}$ is the heap-size after the move was done. We know $x \oplus x = 0$ and we also know that the nim-sum is associative and commutative. Therefore
$$t = 0 \oplus t = (s \oplus s) \oplus t = s \oplus (s \oplus t) = s \oplus (x_{k} \oplus y_{k})$$
Because $x_{i} = y_{i}$ whenever $i \neq k$.

Lemma 1: If $s = 0$ then $t \neq 0$ no matter what move was made.
This follows immediately from $t = s \oplus x_{k} \oplus y_{k}$ since $x_{k} \neq y_{k}$

Lemma 2: If $s \neq 0$ then there is a move such that $t = 0$.
Let p be the position of the leftmost bit in the binary representation of $s$ and take $k$ such that $x_{k}$ has 1 on position p - such a choice is always possible since otherwise the p-th bit of $s$ would be 0. Let $y_{k} = x_{k} \oplus s$. We claim $y_{k} < x_{k}$ since the leftmost bit of $y_{k}$ is on a position less than the p, and every other change in bits amounts to at most $2^p - 1$. Then
$$t = s \oplus x_{k} \oplus (s \oplus x_{k}) = 0$$
So we can take $x_{k} - (s \oplus x_{k})$ objects from pile $k$.

This completes the proof, since we know $0, 0,... , 0$ is a position with nim-sum 0, and we can reduce any non-zero nim-sum to a zero nim-sum, and no 0 nim-sum can be taken into another 0 nim-sum.

Returning to Ligia and Paul, we see that $$1 \oplus 2 \oplus 3 = 0,$$ therefore the first player will lose, given perfect play on both sides. But let's say Ligia hasn't been paying attention to her brother when he tried explaining Game Theory to her, and she thinks she can win. Replicating the moves above, we have:

  • Ligia takes 1 object from the first pile. Position is now $(0, 2, 3)$
  • Paul knows his Game Theory, and he knows how to do nim-sums. He easily computes $$0 \oplus 2 \oplus 3 = 1$$ The most significant bit in the binary representation of $1$ is on the right-most position, and, out of $2$ and $3$, only $3$ has a 1-bit on the right-most position. We compute $1 \oplus 3 = 2,$ so we take $3 - 2 = 1$ objects from the last pile. Position is now $(0, 2, 2)$
  • We know $(0, 2, 2)$ is losing. Even if we didn't know, we could easily compute the next moves to see that Ligia's cause is indeed hopeless.
This shows that the starting player has a winning strategy only if the nim-sum of the starting elements is not zero, and the winning play on each turn is to reduce the current position to one with nim-sum zero. For more information, a good introductory article in game theory that covers Nim in sufficient detail is [2]. A more detailed approach can be found in either [3], or [4].

References:
[1] C. L. Bouton: Nim, a game with a complete mathematical theory, Annals of Mathematics 3 (1901–02), 35–39
[2] Thomas S. Ferguson, Game Theory
[3] Elwyn R. Berlekamp, John H. Conway, and Richard K. Guy: Winning Ways for your Mathematical Plays
[4] John H. Conway, On Numbers and Games