Commit f3f53c84 authored by Ben Glocker's avatar Ben Glocker
Browse files

added fibonacci challenge

parent 8f48c8b2
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# CO202 - Software Engineering - Algorithms"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Fibonacci Challenge: Dynamic Programming vs. Divide-and-Conquer"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### DP Fibonacci - Bottom-up (space efficient)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fib_dp_bottom_up(n):\n",
" if n == 0:\n",
" return 0\n",
" f = [0]*(n+1)\n",
" f[0] = 0\n",
" f[1] = 1\n",
" for i in range(2,n+1):\n",
" f[i] = f[i-1] + f[i-2]\n",
" return f[n]\n",
"\n",
"print(fib_dp_bottom_up(10))\n",
"%timeit fib_dp_bottom_up(10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fib_dp_bottom_up(n):\n",
" i,j = 1,0\n",
" for k in range(1,n + 1):\n",
" i,j = j, i + j\n",
" return j\n",
"\n",
"print(fib_dp_bottom_up(10))\n",
"%timeit fib_dp_bottom_up(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### DP Fibonacci - Top-down with Memoization"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"m = {0: 0, 1: 1}\n",
"def fib_dp_top_down(n):\n",
" m.clear()\n",
" m[0] = 0\n",
" m[1] = 1\n",
" return fib_dp_top_down_aux(n)\n",
"\n",
"def fib_dp_top_down_aux(n):\n",
" if n not in m: \n",
" m[n] = fib_dp_top_down_aux(n-1) + fib_dp_top_down_aux(n-2)\n",
" return m[n]\n",
"\n",
"print(fib_dp_top_down_aux(10))\n",
"%timeit fib_dp_top_down(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### D&C Fibonacci"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"\n",
"def fib_dc(n):\n",
" if n == 0:\n",
" return 0\n",
" elif n == 1:\n",
" return 1\n",
" else:\n",
" a = fib_dc(math.ceil(n / 2))\n",
" b = fib_dc(math.ceil(n / 2) - 1)\n",
" if n % 2 == 0:\n",
" return a * (a + 2 * b)\n",
" else:\n",
" return a * a + b * b \n",
" \n",
"print(fib_dc(10))\n",
"%timeit fib_dc(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### D&C Fast Fibonacci (v1) - provided by Jacek Burys"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"\n",
"dt = np.int64\n",
"\n",
"def fib_dc_fast(n):\n",
" init = np.matrix([[1], [0]], dtype=dt )\n",
" transform = matrix_pow(np.matrix([[1,1],[1,0]], dtype=dt), n)\n",
" return (transform * init).item(1)\n",
"\n",
"def matrix_pow(m, n):\n",
" if n == 0:\n",
" return np.matrix([[1,0],[0,1]], dtype=dt)\n",
" if n == 1:\n",
" return m\n",
" temp = matrix_pow(m, n // 2)\n",
" if n % 2 == 0:\n",
" return temp * temp\n",
" else:\n",
" return temp * temp * m\n",
" \n",
"print(fib_dc_fast(10))\n",
"%timeit fib_dc_fast(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### D&C Fast Fibonacci (v2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def fib_dc_fast2(n):\n",
" init = [1,0]\n",
" transform = matrix_pow2([1,1,1,0], n)\n",
" return matrix_vec_mul(transform,init)[1]\n",
"\n",
"def matrix_pow2(m, n):\n",
" if n == 0:\n",
" return [1,0,0,1]\n",
" if n == 1:\n",
" return m\n",
" temp = matrix_pow2(m, n // 2)\n",
" if n % 2 == 0:\n",
" return matrix_mul(temp,temp)\n",
" else:\n",
" return matrix_mul(matrix_mul(temp,temp),m)\n",
" \n",
"def matrix_vec_mul(m,v):\n",
" r = [0]*2\n",
" r[0] = m[0]*v[0] + m[2] * v[1]\n",
" r[1] = m[1]*v[0] + m[3] * v[1]\n",
" return r\n",
"\n",
"def matrix_mul(m1,m2):\n",
" r = [0]*4\n",
" r[0] = m1[0]*m2[0] + m1[2] * m2[1]\n",
" r[1] = m1[1]*m2[0] + m1[3] * m2[1]\n",
" r[2] = m1[0]*m2[2] + m1[2] * m2[3]\n",
" r[3] = m1[1]*m2[2] + m1[3] * m2[3]\n",
" return r\n",
"\n",
"print(fib_dc_fast2(10))\n",
"%timeit fib_dc_fast2(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Closed form expression - Binet's formula"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import math\n",
"\n",
"def fib_binet(n):\n",
" f = (1 + math.sqrt(5))/2\n",
" return (f**n - (-f)**-n)/math.sqrt(5)\n",
"\n",
"print(fib_binet(10))\n",
"%timeit fib_binet(10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Sanity check"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"n = 500\n",
"print(\"DP Bottom-up\\t\" + str(fib_dp_bottom_up(n)))\n",
"print(\"DP Top-down\\t\" + str(fib_dp_top_down(n)))\n",
"print(\"D&C\\t\\t\" + str(fib_dc(n)))\n",
"print(\"D&C Fast\\t\" + str(fib_dc_fast(n)))\n",
"print(\"D&C Fast v2\\t\" + str(fib_dc_fast2(n)))\n",
"print(\"Binet\\t\\t\" + str(int(fib_binet(n))))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Comparison"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"\n",
"def time_f(f):\n",
" before = time.clock()\n",
" f()\n",
" after = time.clock()\n",
" return after - before\n",
"\n",
"n_max = 10000\n",
"samples = 50\n",
"step = int(n_max/samples)\n",
"data = range(1,n_max,step)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"t1 = []\n",
"for i in data:\n",
" t1.append(time_f(lambda: fib_dp_bottom_up(i)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"t2 = []\n",
"\n",
"for i in data:\n",
" t2.append(time_f(lambda: fib_dc(i)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"plt.scatter(data, t1, c='green')\n",
"plt.scatter(data, t2, c='red')\n",
"plt.xlabel('n')\n",
"plt.ylabel('time (/s)')\n",
"plt.legend(['dp bottom-up','d&c'],loc='upper left')\n",
"plt.xlim(0)\n",
"plt.ylim(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"t3 = []\n",
"\n",
"for i in data:\n",
" t3.append(time_f(lambda: fib_dc_fast2(i)))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"plt.scatter(data, t1, c='green')\n",
"plt.scatter(data, t2, c='red')\n",
"plt.scatter(data, t3, c='blue')\n",
"plt.xlabel('n')\n",
"plt.ylabel('time (/s)')\n",
"plt.legend(['dp bottom-up','d&c','d&c fast'],loc='upper left')\n",
"plt.xlim(0)\n",
"plt.ylim(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"n_max = 1000000\n",
"samples = 50\n",
"step = int(n_max/samples)\n",
"data = range(1,n_max,step)\n",
"\n",
"t3 = []\n",
"for i in data:\n",
" t3.append(time_f(lambda: fib_dc_fast2(i)))\n",
" \n",
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"plt.scatter(data, t3, c='blue')\n",
"plt.xlabel('n')\n",
"plt.ylabel('time (/s)')\n",
"plt.legend(['d&c fast'],loc='upper left')\n",
"plt.xlim(0)\n",
"plt.ylim(0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
}
},
"nbformat": 4,
"nbformat_minor": 1
}
%% Cell type:markdown id: tags:
# CO202 - Software Engineering - Algorithms
%% Cell type:markdown id: tags:
## Fibonacci Challenge: Dynamic Programming vs. Divide-and-Conquer
%% Cell type:markdown id: tags:
### DP Fibonacci - Bottom-up (space efficient)
%% Cell type:code id: tags:
``` python
def fib_dp_bottom_up(n):
if n == 0:
return 0
f = [0]*(n+1)
f[0] = 0
f[1] = 1
for i in range(2,n+1):
f[i] = f[i-1] + f[i-2]
return f[n]
print(fib_dp_bottom_up(10))
%timeit fib_dp_bottom_up(10)
```
%% Cell type:code id: tags:
``` python
def fib_dp_bottom_up(n):
i,j = 1,0
for k in range(1,n + 1):
i,j = j, i + j
return j
print(fib_dp_bottom_up(10))
%timeit fib_dp_bottom_up(10)
```
%% Cell type:markdown id: tags:
### DP Fibonacci - Top-down with Memoization
%% Cell type:code id: tags:
``` python
m = {0: 0, 1: 1}
def fib_dp_top_down(n):
m.clear()
m[0] = 0
m[1] = 1
return fib_dp_top_down_aux(n)
def fib_dp_top_down_aux(n):
if n not in m:
m[n] = fib_dp_top_down_aux(n-1) + fib_dp_top_down_aux(n-2)
return m[n]
print(fib_dp_top_down_aux(10))
%timeit fib_dp_top_down(10)
```
%% Cell type:markdown id: tags:
### D&C Fibonacci
%% Cell type:code id: tags:
``` python
import math
def fib_dc(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
a = fib_dc(math.ceil(n / 2))
b = fib_dc(math.ceil(n / 2) - 1)
if n % 2 == 0:
return a * (a + 2 * b)
else:
return a * a + b * b
print(fib_dc(10))
%timeit fib_dc(10)
```
%% Cell type:markdown id: tags:
### D&C Fast Fibonacci (v1) - provided by Jacek Burys
%% Cell type:code id: tags:
``` python
import numpy as np
dt = np.int64
def fib_dc_fast(n):
init = np.matrix([[1], [0]], dtype=dt )
transform = matrix_pow(np.matrix([[1,1],[1,0]], dtype=dt), n)
return (transform * init).item(1)
def matrix_pow(m, n):
if n == 0:
return np.matrix([[1,0],[0,1]], dtype=dt)
if n == 1:
return m
temp = matrix_pow(m, n // 2)
if n % 2 == 0:
return temp * temp
else:
return temp * temp * m
print(fib_dc_fast(10))
%timeit fib_dc_fast(10)
```
%% Cell type:markdown id: tags:
### D&C Fast Fibonacci (v2)
%% Cell type:code id: tags:
``` python
def fib_dc_fast2(n):
init = [1,0]
transform = matrix_pow2([1,1,1,0], n)
return matrix_vec_mul(transform,init)[1]
def matrix_pow2(m, n):
if n == 0:
return [1,0,0,1]
if n == 1:
return m
temp = matrix_pow2(m, n // 2)
if n % 2 == 0:
return matrix_mul(temp,temp)
else:
return matrix_mul(matrix_mul(temp,temp),m)
def matrix_vec_mul(m,v):
r = [0]*2
r[0] = m[0]*v[0] + m[2] * v[1]
r[1] = m[1]*v[0] + m[3] * v[1]
return r
def matrix_mul(m1,m2):
r = [0]*4
r[0] = m1[0]*m2[0] + m1[2] * m2[1]
r[1] = m1[1]*m2[0] + m1[3] * m2[1]
r[2] = m1[0]*m2[2] + m1[2] * m2[3]
r[3] = m1[1]*m2[2] + m1[3] * m2[3]
return r
print(fib_dc_fast2(10))
%timeit fib_dc_fast2(10)
```
%% Cell type:markdown id: tags:
### Closed form expression - Binet's formula
%% Cell type:code id: tags:
``` python
import math
def fib_binet(n):
f = (1 + math.sqrt(5))/2
return (f**n - (-f)**-n)/math.sqrt(5)
print(fib_binet(10))
%timeit fib_binet(10)
```
%% Cell type:markdown id: tags:
### Sanity check
%% Cell type:code id: tags:
``` python
n = 500
print("DP Bottom-up\t" + str(fib_dp_bottom_up(n)))
print("DP Top-down\t" + str(fib_dp_top_down(n)))
print("D&C\t\t" + str(fib_dc(n)))
print("D&C Fast\t" + str(fib_dc_fast(n)))
print("D&C Fast v2\t" + str(fib_dc_fast2(n)))
print("Binet\t\t" + str(int(fib_binet(n))))
```
%% Cell type:markdown id: tags:
### Comparison
%% Cell type:code id: tags:
``` python
import time
def time_f(f):
before = time.clock()
f()
after = time.clock()
return after - before
n_max = 10000
samples = 50
step = int(n_max/samples)
data = range(1,n_max,step)
```
%% Cell type:code id: tags:
``` python
t1 = []
for i in data:
t1.append(time_f(lambda: fib_dp_bottom_up(i)))
```
%% Cell type:code id: tags:
``` python
t2 = []
for i in data:
t2.append(time_f(lambda: fib_dc(i)))
```
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter(data, t1, c='green')
plt.scatter(data, t2, c='red')
plt.xlabel('n')
plt.ylabel('time (/s)')
plt.legend(['dp bottom-up','d&c'],loc='upper left')
plt.xlim(0)
plt.ylim(0)
```
%% Cell type:code id: tags:
``` python
t3 = []
for i in data:
t3.append(time_f(lambda: fib_dc_fast2(i)))
```
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter(data, t1, c='green')
plt.scatter(data, t2, c='red')
plt.scatter(data, t3, c='blue')
plt.xlabel('n')
plt.ylabel('time (/s)')
plt.legend(['dp bottom-up','d&c','d&c fast'],loc='upper left')
plt.xlim(0)
plt.ylim(0)
```
%% Cell type:code id: tags:
``` python
n_max = 1000000
samples = 50
step = int(n_max/samples)
data = range(1,n_max,step)