Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Ben Glocker
algo202
Commits
9474c0be
Commit
9474c0be
authored
Jan 24, 2018
by
Ben Glocker
Browse files
added divide and conquer notebook
parent
046828c7
Changes
1
Hide whitespace changes
Inline
Side-by-side
01-Divide-and-Conquer.ipynb
0 → 100644
View file @
9474c0be
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# CO202 - Algorithms 2"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Tutorial on Divide-and-Conquer: Integer Multiplication"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Some helper functions"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import math\n",
"\n",
"# calculates the number of digits of an integer\n",
"def digits(x):\n",
" return int(math.log(x, 10) + 1)\n",
"\n",
"# alternative\n",
"digits_alt = lambda i: len(str(i))\n",
"\n",
"\n",
"# splits an integer into two parts after digit i\n",
"def split(x, i):\n",
" left = int(x / (10 ** i)) # ** is the power operator\n",
" right = int(x % (10 ** i))\n",
" return left, right\n",
"\n",
"print(digits(1234) == digits_alt(1234))\n",
"print(split(1234, 2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Recursive Multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# recursive multiplication breaks down the problem into four subproblems\n",
"def recursive_mul(x, y):\n",
" if x < 10 or y < 10:\n",
" return x * y\n",
" \n",
" # Tuple unpacking can be nice for repeated function calls..\n",
" nx, ny = digits(x), digits(y)\n",
" n = max(nx, ny)\n",
" n2 = int(math.floor(n / 2))\n",
" \n",
" a, b = split(x, n2)\n",
" c, d = split(y, n2)\n",
" \n",
" ac = recursive_mul(a, c)\n",
" ad = recursive_mul(a, d)\n",
" bc = recursive_mul(b, c)\n",
" bd = recursive_mul(b, d)\n",
" \n",
" return ac * (10 ** (2 * n2)) + (ad + bc) * (10 ** n2) + bd\n",
"\n",
"x = 1234\n",
"y = 5678\n",
"print(recursive_mul(x,y))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Karatsuba Multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def karatsuba_mul(x, y):\n",
" if x < 10 or y < 10:\n",
" return x * y\n",
" \n",
" nx, ny = digits(x), digits(y)\n",
" n = max(nx, ny)\n",
" n2 = int(math.floor(n / 2))\n",
" \n",
" a, b = split(x, n2)\n",
" c, d = split(y, n2)\n",
" \n",
" ac = karatsuba_mul(a, c)\n",
" bd = karatsuba_mul(b, d)\n",
" abcd = karatsuba_mul(a + b, c + d)\n",
" adbc = abcd - ac - bd;\n",
" \n",
" return ac * (10 ** (2 * n2)) + adbc * (10 ** n2) + bd\n",
"\n",
"print(karatsuba_mul(x, y))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Baseline Multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def baseline_mul(x, y):\n",
" return x * y\n",
"\n",
"# alternative using lambda\n",
"baseline_mul_alt = lambda x, y: x * y\n",
"\n",
"print(baseline_mul(x, y))\n",
"\n",
"print(baseline_mul(x, y) == baseline_mul_alt(x, y))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Comparison"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Generate some test data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from random import randint\n",
"\n",
"# Generate an integer with n digits\n",
"def randint_of_len(n):\n",
" return randint(10 ** n, (10 ** (n + 1)) - 1)\n",
"\n",
"\n",
"def rand_pair(n):\n",
" m = randint(2, n) # choose a random length\n",
" return randint_of_len(m), randint_of_len(m)\n",
"\n",
"n = 200\n",
"\n",
"# '_' is commonly used when you don't care about a variable\n",
"random_pairs = [rand_pair(n) for _ in range(200)]\n",
"\n",
"print(rand_pair(n))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Timer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import time\n",
"\n",
"def time_f(f):\n",
" before = time.clock()\n",
" f()\n",
" after = time.clock()\n",
" return after - before"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Running Recursive Multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"tr = []\n",
"nr = []\n",
"\n",
"for r_pair in random_pairs:\n",
" tr.append(time_f(lambda: recursive_mul(r_pair[0], r_pair[1])))\n",
" nr.append(digits(r_pair[0]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Running Karatsuba Multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"tk = []\n",
"nk = []\n",
"\n",
"for r_pair in random_pairs:\n",
" tk.append(time_f(lambda: karatsuba_mul(r_pair[0], r_pair[1])))\n",
" nk.append(digits(r_pair[0]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Plot Recursive vs Karatsuba"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"plt.scatter(nr, tr, c='red')\n",
"plt.scatter(nk, tk, c='blue')\n",
"plt.xlabel('n')\n",
"plt.ylabel('time (/s)')\n",
"plt.xlim(0)\n",
"plt.ylim(0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Running Baseline Multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"tb = []\n",
"nb = []\n",
"\n",
"for r_pair in random_pairs:\n",
" tb.append(time_f(lambda: baseline_mul(r_pair[0], r_pair[1])))\n",
" nb.append(digits(r_pair[0]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"plt.scatter(nr, tr, c='red')\n",
"plt.scatter(nk, tk, c='blue')\n",
"plt.scatter(nb, tb, c='green')\n",
"plt.xlabel('n')\n",
"plt.ylabel('time (/s)')\n",
"plt.xlim(0)\n",
"plt.ylim(0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Exploring built-in multiplication"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"random_pairs = [rand_pair(200) for _ in range(200)]\n",
"#andom_pairs = [rand_pair(2000) for _ in range(200)]\n",
"#random_pairs = [rand_pair(200000) for _ in range(200)]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"tb = []\n",
"nb = []\n",
"\n",
"for r_pair in random_pairs:\n",
" tb.append(time_f(lambda: baseline_mul(r_pair[0], r_pair[1])))\n",
" nb.append(digits(r_pair[0]))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"plt.scatter(nb, tb, c='green')\n",
"plt.xlabel('n')\n",
"plt.ylabel('time (/s)')\n",
"plt.xlim(0)\n",
"plt.ylim(0)"
]
}
],
"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 - 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
)
```
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment