Dynamic Programming
(動的計画法)
Data Structures and Algorithms
12th lecture, December 6, 2018
http://www.sw.it.aoyama.ac.jp/2018/DA/lecture12.html
Martin J. Dürst
© 2009-18 Martin
J. Dürst 青山学院大学
Today's Schedule
- Leftovers and summary of last lecture
- Algorithm design strategies
- Overview of dynamic programming
- Example application: Order of evaluation of chain matrix
multiplication
- Dynamic programming in Ruby
Leftovers and Summary of Last Lecture
(Boyer-Moore algorithm, string matching and character encoding)
Algorithm Design Strategies
- Simple/simplistic algorithms
- Divide and conquer
- Dynamic programming
Overview of Dynamic Programming
- Investigate and clarify the structure of the (optimal) solution
- Recursive definition of (optimal) solution
- Bottom-up calculation of (optimal) solution
- Construction of (optimal) solution from calculation results
- Proposed by Richard Bellman in the 1950ies
- Name now sounds arbitrary, but is firmly established
Simple Example of Dynamic Programming
Matrix Multiplication
- Multiplying a r0 by r1 matrix
0M1 and
a r1 by r2 matrix
1M2
(0M1·
1M2 ⇒
0M1M2)
results in a r0 by r2 matrix
0M2
- This multiplication needs
r0r1r2
scalar multiplications and
r0r1r2
scalar additions,
so its time complexity is O(r0r1r2)
- Actual example: r0=100, r1=2,
r2=200
⇒ Number of multiplications: 100×2×200 =
40,000
- Because the number of scalar multiplications and additions is the same,
we will only consider multiplications
Matrix Multiplication Program Skeleton
for (i=0; i<r0; i++)
for (j=0; j<r2; j++) {
sum = 0;
for (k=0; k<r1; k++)
sum += 0M1[i][k] * 1M2[k][j];
0M2[i][j] = sum;
}
Chain Multiplication of Reals
- A series of multiplications (e.g. 163·25·4) is called chain
multiplication
- Multiplication of reals is associative (i.e. (163·25)·4 =
163·(25·4))
- Not all multiplication orders have the same speed.
For humans, 163·(25·4) = 163·100 = 16300 is faster than (163·25)·4 = 4075·4
- Conclusion: Choosing a good multiplication order can be
Chain Multiplication of Matrices
Number of Matrix Multiplications Orders
Multiplications |
Orders |
0 |
1 |
1 |
1 |
2 |
2 |
3 |
5 |
4 |
14 |
5 |
42 |
6 |
132 |
7 |
429 |
8 |
1430 |
9 |
4862 |
- The number of orders for multiplying n matrices is small for
small n, but grows exponentially
- The number of orders is equal to the numbers in the middle of Pascal's
triangle (1, 2, 6, 20, 70,...)
divided by increasing natural numbers (1, 2, 3, 4, 5,...)
- These numbers are called Catalan numbers:
Cn =
(2n)!/(n!(n+1)!) =
Ω(4n/n3/2)
- Catalan numbers have many applications:
- Combinations of n pairs of properly nested parentheses
(n=3: ()()(), (())(), ()(()), ((())), (()()))
- Number of shapes of binary trees of size n
- Number of triangulations of a (convex) polygon with n
vertices
Optimal Order of Multiplications
- Checking all orders is very slow
(Ω(n4n/n3/2)
= Ω(4n/n1/2))
- Minimal evaluation cost (number of scalar multiplications):
- mincost(a, c): minimal cost for evaluating
aMc
- if a+1 ≧ c, mincost(a,
c) = 0
- if a+1 < c, mincost(a,
c) =
minc-1b=a+1
cost(a, b, c)
- split(a, c): optimal spliting point
- split(a, c) = arg
minb cost(a, b,
c)
- cost(a, b, c): cost for calculating
aMbMc
- i.e. cost for splitting the evaluation of
aMc at
b
- cost(a, b, c) =
mincost(a, b)+mincost(b,
c) +
rarbrc
- Simple implementation in Ruby:
MatrixSlow
in Cmatrix.rb
Inverting Optimization Order and Storing Intermediate Results
- The solution can be evaluated from split(0, n) top-down using
recursion
- The problem with top-down evaluation is that intermediate results
(mincost(x, y)) are calculated repeatedly
- Bottom-up calculation:
- Calculate the minimal costs and splitting points for chains of length
k, starting with k=2 and increasing to
k=n
- Store intermediate results for reuse
- Implementation in Ruby:
MatrixPlan
in Cmatrix.rb
Example Calculation
|
0M1M5:
274
0M2M5: 450
0M3M5: 470
0M4M5: 320 |
|
|
0M1M4:
260
0M2M4: 468
0M3M4: 400 |
1M2M5:
366
1M3M5: 330
1M4M5:
250 |
|
|
0M1M3:
200
0M2M3: 288 |
1M2M4:
360
1M3M4:
220 |
2M3M5:
330
2M4M5: 390 |
|
|
0M1M2:
48 |
1M2M3:
120 |
2M3M4:
300 |
3M4M5:
150 |
|
0M1: 0 |
1M2: 0 |
2M3: 0 |
3M4: 0 |
4M5: 0 |
r0 = 4 |
r1 = 2 |
r2 = 6 |
r3 = 10 |
r4 = 5 |
r5 = 3 |
Complexity of Optimizing Evaluation Order
- The calculation of mincost(a, c) is O(c-a)
- Evaluating all mincost(a, a+k) is O((n-k)·k)
- Total time complexity:
∑nk=1
O((n-k)·k) = O(n3)
The time complexity of dynamic programming depends on the structure of the
problem
O(n3),
O(n2), O(n),
O(nm),... are frequent time complexities
Overview of Dynamic Programming
- Investigate and clarify the structure of the (optimal) solution
- Recursive definition of (optimal) solution (e.g.
MatrixSlow
)
- Bottom-up calculation of (optimal) solution (e.g.
MatrixPlan
)
- Construction of (optimal) solution from calculation results
Conditions for Using Dynamic Programming
- Optimal substructure:
The global (optimal) solution can be constructed from the (optimal)
solutions of subproblems
(common with divide and conquer)
- Overlapping subproblems
(different from divide and conquer)
Memoization
- The key in dynamic programming is to reuse intermediate results
- Many functions can be changed so that they remember results
- This is called memoization:
- Add a data structure that stores results
(a dictionary with arguments as key and result as value)
- Check the dictionary
- If the result is stored, return it immediately
- If the result is not stored, calculate it, store it, and return
it
- Only possible for pure functions (no side effects)
Memoization in Ruby
- Use metaprogramming to modify a function so that:
- On first calculation, result is stored (e.g. in a
Hash
using function arguments as the key)
- Before each calculation, storage is checked, and stored result used
if available
- Metaprogramming changes the program while it runs
- Simple application example: Cfibonacci.rb
Summary
- Dynamic programming is an algorithm design strategy
- Dynamic programming is suited for problems where the overall (optimal)
solution can be obtained from solutions for subproblems, but the
subproblems overlap
- The time complexity of dynamic programming depends on the structure of
the actual problem
Homework
- Review this lecture (including the 'Example Calculation' and the
programs)
- Find three problems that can be solved using dynamic programming, and
investigate the algorithms used
Glossary
- dynamic programming
- 動的計画法
- algorithm design strategies
- アルゴリズムの設計方針
- optimal solution
- 最適解
- Catalan number
- カタラン数
- matrix chain multiplication
- 連鎖行列積、行列の連鎖乗算
- triangulations
- (多角形の) 三角分割
- (convex) polygon
- (凸) 多角形
- intermediate result
- 途中結果
- splitting point
- 分割点
- arg min (argument of the minimum)
- 最小値点
- top-down
- 下向き、トップダウン
- bottom-up
- 上向き、ボトムアップ
- optimal substructure
- 部分構造の最適性
- overlapping subproblems
- 部分問題の重複
- memoization (verb: memoize)
- 履歴管理
- metaprogramming
- メタプログラミング