Commit 9474c0be authored by Ben Glocker's avatar Ben Glocker
Browse files

added divide and conquer notebook

parent 046828c7
%% Cell type:markdown id: tags:
# CO202 - Algorithms 2
%% Cell type:markdown id: tags:
## Tutorial on Divide-and-Conquer: Integer Multiplication
%% Cell type:markdown id: tags:
### Some helper functions
%% Cell type:code id: tags:
``` python
import math
# calculates the number of digits of an integer
def digits(x):
return int(math.log(x, 10) + 1)
# alternative
digits_alt = lambda i: len(str(i))
# splits an integer into two parts after digit i
def split(x, i):
left = int(x / (10 ** i)) # ** is the power operator
right = int(x % (10 ** i))
return left, right
print(digits(1234) == digits_alt(1234))
print(split(1234, 2))
```
%% Cell type:markdown id: tags:
### Recursive Multiplication
%% Cell type:code id: tags:
``` python
# recursive multiplication breaks down the problem into four subproblems
def recursive_mul(x, y):
if x < 10 or y < 10:
return x * y
# Tuple unpacking can be nice for repeated function calls..
nx, ny = digits(x), digits(y)
n = max(nx, ny)
n2 = int(math.floor(n / 2))
a, b = split(x, n2)
c, d = split(y, n2)
ac = recursive_mul(a, c)
ad = recursive_mul(a, d)
bc = recursive_mul(b, c)
bd = recursive_mul(b, d)
return ac * (10 ** (2 * n2)) + (ad + bc) * (10 ** n2) + bd
x = 1234
y = 5678
print(recursive_mul(x,y))
```
%% Cell type:markdown id: tags:
### Karatsuba Multiplication
%% Cell type:code id: tags:
``` python
def karatsuba_mul(x, y):
if x < 10 or y < 10:
return x * y
nx, ny = digits(x), digits(y)
n = max(nx, ny)
n2 = int(math.floor(n / 2))
a, b = split(x, n2)
c, d = split(y, n2)
ac = karatsuba_mul(a, c)
bd = karatsuba_mul(b, d)
abcd = karatsuba_mul(a + b, c + d)
adbc = abcd - ac - bd;
return ac * (10 ** (2 * n2)) + adbc * (10 ** n2) + bd
print(karatsuba_mul(x, y))
```
%% Cell type:markdown id: tags:
### Baseline Multiplication
%% Cell type:code id: tags:
``` python
def baseline_mul(x, y):
return x * y
# alternative using lambda
baseline_mul_alt = lambda x, y: x * y
print(baseline_mul(x, y))
print(baseline_mul(x, y) == baseline_mul_alt(x, y))
```
%% Cell type:markdown id: tags:
### Comparison
%% Cell type:markdown id: tags:
#### Generate some test data
%% Cell type:code id: tags:
``` python
from random import randint
# Generate an integer with n digits
def randint_of_len(n):
return randint(10 ** n, (10 ** (n + 1)) - 1)
def rand_pair(n):
m = randint(2, n) # choose a random length
return randint_of_len(m), randint_of_len(m)
n = 200
# '_' is commonly used when you don't care about a variable
random_pairs = [rand_pair(n) for _ in range(200)]
print(rand_pair(n))
```
%% Cell type:markdown id: tags:
#### Timer
%% Cell type:code id: tags:
``` python
import time
def time_f(f):
before = time.clock()
f()
after = time.clock()
return after - before
```
%% Cell type:markdown id: tags:
#### Running Recursive Multiplication
%% Cell type:code id: tags:
``` python
tr = []
nr = []
for r_pair in random_pairs:
tr.append(time_f(lambda: recursive_mul(r_pair[0], r_pair[1])))
nr.append(digits(r_pair[0]))
```
%% Cell type:markdown id: tags:
#### Running Karatsuba Multiplication
%% Cell type:code id: tags:
``` python
tk = []
nk = []
for r_pair in random_pairs:
tk.append(time_f(lambda: karatsuba_mul(r_pair[0], r_pair[1])))
nk.append(digits(r_pair[0]))
```
%% Cell type:markdown id: tags:
#### Plot Recursive vs Karatsuba
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter(nr, tr, c='red')
plt.scatter(nk, tk, c='blue')
plt.xlabel('n')
plt.ylabel('time (/s)')
plt.xlim(0)
plt.ylim(0)
```
%% Cell type:markdown id: tags:
#### Running Baseline Multiplication
%% Cell type:code id: tags:
``` python
tb = []
nb = []
for r_pair in random_pairs:
tb.append(time_f(lambda: baseline_mul(r_pair[0], r_pair[1])))
nb.append(digits(r_pair[0]))
```
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter(nr, tr, c='red')
plt.scatter(nk, tk, c='blue')
plt.scatter(nb, tb, c='green')
plt.xlabel('n')
plt.ylabel('time (/s)')
plt.xlim(0)
plt.ylim(0)
```
%% Cell type:markdown id: tags:
#### Exploring built-in multiplication
%% Cell type:code id: tags:
``` python
random_pairs = [rand_pair(200) for _ in range(200)]
#andom_pairs = [rand_pair(2000) for _ in range(200)]
#random_pairs = [rand_pair(200000) for _ in range(200)]
```
%% Cell type:code id: tags:
``` python
tb = []
nb = []
for r_pair in random_pairs:
tb.append(time_f(lambda: baseline_mul(r_pair[0], r_pair[1])))
nb.append(digits(r_pair[0]))
```
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter(nb, tb, c='green')
plt.xlabel('n')
plt.ylabel('time (/s)')
plt.xlim(0)
plt.ylim(0)
```
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment