-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy pathexample_017_DP_matrix_chain_multiplication.py
122 lines (83 loc) · 3.36 KB
/
example_017_DP_matrix_chain_multiplication.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# A top-down recursive implementation
import sys
def matrix_chain_recursive(p, i, j):
if (i == j):
return 0
# Set the maximum to be the largest possible number
# if we get something better than this, then we can swap it
min = sys.maxsize
# Start generating all possible combinations by brute forcing it and recursive call.
# This will generate a lots of different combinations that's why our runt time is bad.
for k in range(i, j):
count = (matrix_chain_recursive(p, i, k) +
matrix_chain_recursive(p, k + 1, j) + p[i-1] * p[k] * p[j])
if count < min:
min = count
# Return minimum count
return min
def matrix_chain_with_memoization(p, n):
'''
Calculates the best minimum operation number of matrix multiplications
O(n^3)
'''
i = 1
j = n - 1
# Create a Dynamic Programming Table to memoize
dp = [[-1 for i in range(100)] for j in range(100)]
# Function for matrix chain multiplication
def matrix_chain_memoization_helper(p, i, j):
if(i == j):
return 0
# if we have already computed it then get it from the memoization table.
if(dp[i][j] != -1):
return dp[i][j]
dp[i][j] = sys.maxsize
# Otherwise, we compute it using recursion
for k in range(i, j):
dp[i][j] = min(dp[i][j], matrix_chain_memoization_helper(p, i, k) +
matrix_chain_memoization_helper(p, k + 1, j) + p[i - 1] * p[k] * p[j])
return dp[i][j]
return matrix_chain_memoization_helper(p, i, j)
def matrix_chain_bottom_up_iterative(p, n):
'''This is a bottom up iterative solution with O(n^3) time complexity'''
dp = [[0 for x in range(n)] for x in range(n)]
# set the DP table cost for all zero
for i in range(1, n):
dp[i][i] = 0
# iterate over different chain length sizes by going from 2 to n
for chain_size in range(2, n):
for i in range(1, n - chain_size + 1):
j = i + chain_size - 1
dp[i][j] = sys.maxsize
for k in range(i, j):
q = dp[i][k] + dp[k + 1][j] + p[i-1]*p[k]*p[j]
if q < dp[i][j]:
dp[i][j] = q
return dp[1][n-1]
# Call the functions.
if __name__ == "__main__":
# A is a 4 × 1 matrix,
# B is a 1 × 4 matrix, and
# C is a 4 × 1 matrix.
# We have two options:
# 1. (AB) C = (4×1×4) + (4×4×1) = 16 + 16 = 32 operations
# 2. A (BC) = (1x4x1)+ (1 x 4 x 1) = 4 + 4 = 8 operations
# Naive Recusive solution Top-Down
p1 = [4, 1, 4, 1]
print("The Minimum number of multiplications is: ",
matrix_chain_recursive(p1, 1, len(p1)-1))
p2 = [1, 2, 3, 4]
print("The Minimum number of multiplications is: ",
matrix_chain_recursive(p2, 1, len(p2)-1))
# Recursive with Memoization Technique
print()
print("The Minimum number of multiplications is: ",
matrix_chain_with_memoization(p1, len(p1)))
print("The Minimum number of multiplications is: ",
matrix_chain_with_memoization(p2, len(p2)))
## Buttom Up with Iterations
print()
print("The Minimum number of multiplications is: ",
matrix_chain_bottom_up_iterative(p1, len(p1)))
print("The Minimum number of multiplications is: ",
matrix_chain_bottom_up_iterative(p2, len(p2)))