Fixed-Point Iteration and Dynamic Programming
http://iailab.kaist.ac.kr/
Industrial AI Lab at KAIST
Source
- By Prof. David J. Malan from Harvard University
- By Prof. Erik Demaine from MIT online lecture
Table of Contents
1. Recursive Algorithm¶
one of the central ideas of computer science
depends on solutions to smaller instances of the same problem ( = subproblem)
function to call itself (it is impossible in the real world)
factorial example
- $n! = n\cdot(n-1) \cdots 2\cdot 1$
- watch Harvard CS50 lecture on recursion (https://cs50.harvard.edu/)
%%html
<center><iframe width="560" height="315" src="https://www.youtube.com/embed/t4MSwiqfLaY"
frameborder="0" allowfullscreen></iframe></center>
1.1. foo example¶
print ('{c}\n'.format(c="Hello class"))
def foo(str):
print(str)
foo('Hello class')
def foo_recursion(str):
print('{s}\n'.format(s=str))
foo_recursion(str)
# Do not run. It falls into infinite loop.
#foo_recursion('Hello Class')
# base line
def foo_recursion_correct(n):
if n <= 0:
return
else:
print('Hi! \n')
foo_recursion_correct(n-1)
foo_recursion_correct(4)
1.2. Factorial example¶
- factorial example
- $n! = n\cdot(n-1) \cdots 2\cdot 1$
n = 5
m = 1
for i in range(n):
m = m*(i+1)
print (m)
def fac(n):
if n == 1:
return 1
else:
return n*fac(n-1)
# recursive
fac(5)
2. Dynamic Programming¶
Dynamic Programming: general, powerful algorithm design technique
Fibonacci numbers:
$$ \begin{align*} F_1 &= F_2 = 1 \\ F_n &= F_{n-1} + F_{n-2} \end{align*} $$
2.1. Naive Recursive algorithm¶
$$ \begin{align*} \text{fib}(n):&\\ &\text{if } n \leq 2:\; f = 1\\ &\text{else}:\; f = \text{fib}(n-1) + \text{fib}(n-2)\\ &\text{return } f \end{align*}$$
it works, Is it good?
2.2. Memorized DP algorithm¶
$$ \begin{align*} \text{memo }= [\;]&\\ \text{fib}(n):&\\ & \text{if $n$ in memo : return memo}[n]\\ \\ & \text{if } n\leq 2 :\; f = 1\\ & \text{else}: \;f = \text{fib}(n-1) + \text{fib}(n-2)\\ \\ &\text{memo}[n] = f\\ &\text{return } f \end{align*}$$
Benefit?
- fib$(n)$ only recurses the first time it's called
- memorize (remember) & re-use solutions to subproblems that helps solve the problem.
$\quad \implies$ DP $\simeq$ recursion + memorization
%%html
<center><iframe width="560" height="315"src="https://www.youtube.com/embed/OQ5jsbhAv_M"
frameborder="0" allowfullscreen></iframe></center>
# naive Fibonacci
def fib(n):
if n <= 2:
return 1
else:
return fib(n-1) + fib(n-2)
fib(10)
# Memorized DP Fibonacci
def mfib(n):
global memo
if memo[n-1] != 0:
return memo[n-1]
elif n <= 2:
return 1
else:
memo[n-1] = mfib(n-1) + mfib(n-2)
return memo[n-1]
import numpy as np
n = 10
memo = np.zeros(n)
mfib(n)
memo
n = 30
%timeit fib(30)
memo = np.zeros(n)
%timeit mfib(30)
2.3.2. Climbing a stair¶
You are climbing a stair case. Each time you can either make 1 step, 2 steps, or 3 steps. How many distinct ways can you climb if the stairs has $n = 30$ steps?
import numpy as np
def stair(n):
global memo
if memo[n] != 0:
m = memo[n]
elif n == 1:
m = 1
elif n == 2:
m = 2
elif n == 3:
m = 4
else:
m = stair(n-1) + stair(n-2) + stair(n-3)
memo[n] = m
return m
n = 5
global memo
memo = np.zeros(n+1)
stair(n)
print(memo)
2.3.3. Knapsack problem using Dynamic Programming (DP)¶
From MIT's Introduction to Computer Science and Programming
Knapsack problem
burglar (or thief) can carry at most 20 kg (i.e., maximum capacity = 20)
Quickly decide which item to carry
items | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
weight | 10 | 9 | 4 | 2 | 1 | 20 |
value | 175 | 90 | 20 | 50 | 10 | 200 |
Approach
guess (or trial and error)
Exhaustive search if possible
"smarter way" $\implies$ Recursive or dynamic programming
$$ \text{key ideas} = \text{original problem} \rightarrow \begin{cases} \text{subproblem} \rightarrow & \begin{cases} \text{subproblem} \rightarrow \\ \text{subproblem} \rightarrow \end{cases}\\ \text{subproblem} \rightarrow & \begin{cases} \text{subproblem} \rightarrow\\ \text{subproblem} \rightarrow\end{cases}\end{cases} $$
Suppose we have the following function:
$\quad$[value, taken] = chooseBest(items(1:6),maxWeight)
- item 1 is not taken
$\quad$[v_1,t_1] = chooseBest(items(2:6),maxWeight)
- item 1 is taken
$\quad$[v_2,t_2] = chooseBest(items(2:6),maxWeight - weights(1))
$\quad\qquad\;\;\,$v_2 = v_2 + values(1)
$\qquad\quad\;\;\,$t_2 = [items(1),t_2]
def chooseBest(items,maxWeight):
global weights
global values
if len(items) == 0 or maxWeight <= 0:
value = 0
taken = []
return value, taken
else:
first = items[0]
w = weights[first]
rest = items[1:]
# do not take the first item
v1,t1 = chooseBest(rest,maxWeight)
# do take the first item
v2,t2 = chooseBest(rest,maxWeight - w)
v2 = v2 + values[first]
t2 = [first] + t2
if maxWeight - w >= 0 and v2 >= v1:
value = v2
taken = t2
else:
value = v1
taken = t1
return value, taken
n = 6
weights = [10, 9, 4, 2, 1, 20]
values = [175, 90, 20, 50, 10, 200]
items = range(n)
maxWeight = 20
chooseBest(items,maxWeight)
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')