2017-03-27 17:23:15 +08:00
{
" cells " : [
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" This notebook was prepared by [Donne Martin](https://github.com/donnemartin). Source and license info is on [GitHub](https://github.com/donnemartin/interactive-coding-challenges). "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" # Solution Notebook "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ## Problem: Given a list of 2x2 matrices, minimize the cost of matrix multiplication. \n " ,
" \n " ,
" * [Constraints](#Constraints) \n " ,
" * [Test Cases](#Test-Cases) \n " ,
" * [Algorithm](#Algorithm) \n " ,
" * [Code](#Code) \n " ,
" * [Unit Test](#Unit-Test) "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ## Constraints \n " ,
" \n " ,
" * Do we just want to calculate the cost and not list the actual order of operations? \n " ,
" * Yes \n " ,
" * Can we assume the inputs are valid? \n " ,
" * No \n " ,
" * Can we assume this fits memory? \n " ,
" * Yes "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ## Test Cases \n " ,
" \n " ,
" * None -> Exception \n " ,
" * [] -> 0 \n " ,
" * [Matrix(2, 3), Matrix(3, 6), Matrix(6, 4), Matrix(4, 5)] -> 124 "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ## Algorithm \n " ,
" \n " ,
" We ' ll use bottom up dynamic programming to build a table. \n " ,
" \n " ,
" <pre> \n " ,
" \n " ,
" 0 1 2 3 \n " ,
" [2,3][3,6][6,4][4,5] \n " ,
" \n " ,
" Case: 0 * 1 \n " ,
" 2 * 3 * 6 = 36 \n " ,
" \n " ,
" Case: 1 * 2 \n " ,
" 3 * 6 * 4 = 72 \n " ,
" \n " ,
" Case: 2 * 3 \n " ,
" 6 * 4 * 5 = 120 \n " ,
" \n " ,
" Case: 0 * 1 * 2 \n " ,
" 0 * (1 * 2) = 2 * 3 * 4 + 72 = 96 \n " ,
" (0 * 1) * 2 = 36 + 2 * 6 * 4 = 84 \n " ,
" min: 84 \n " ,
" \n " ,
" Case: 1 * 2 * 3 \n " ,
" 1 * (2 * 3) = 3 * 6 * 5 + 120 = 210 \n " ,
" (1 * 2) * 3 = 72 + 3 * 4 * 5 = 132 \n " ,
" min: 132 \n " ,
" \n " ,
" Case: 0 * 1 * 2 * 3 \n " ,
" 0 * (1 * 2 * 3) = 2 * 3 * 5 + 132 = 162 \n " ,
" (0 * 1) * (2 * 3) = 36 + 120 + 2 * 6 * 5 = 216 \n " ,
" (0 * 1 * 2) * 3 = 84 + 2 * 4 * 5 = 124 \n " ,
" min: 124 \n " ,
" \n " ,
" --------------------- \n " ,
" | 0 | 1 | 2 | 3 | \n " ,
" --------------------- \n " ,
" 0 | 0 | 36 | 84 | 124 | \n " ,
" 1 | x | 0 | 72 | 132 | \n " ,
" 2 | x | x | 0 | 120 | \n " ,
" 3 | x | x | x | 0 | \n " ,
" --------------------- \n " ,
" \n " ,
" min cost = T[0][cols-1] = 124 \n " ,
" \n " ,
" for k in range(i, j): \n " ,
" T[i][j] = minimum of (T[i][k] + T[k+1][j] + \n " ,
" m[i].first * m[k].second * m[j].second) for all k \n " ,
" </pre> "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ### Explanation of k "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" <pre> \n " ,
" 0 1 2 3 \n " ,
" [2,3][3,6][6,4][4,5] \n " ,
" \n " ,
" Fill in the missing cell, where i = 0, j = 3 \n " ,
" \n " ,
" --------------------- \n " ,
" | 0 | 1 | 2 | 3 | \n " ,
" --------------------- \n " ,
" 0 | 0 | 36 | 84 | ??? | \n " ,
" 1 | x | 0 | 72 | 132 | \n " ,
" 2 | x | x | 0 | 120 | \n " ,
" 3 | x | x | x | 0 | \n " ,
" --------------------- \n " ,
" \n " ,
" Case: 0 * (1 * 2 * 3), k = 0 \n " ,
" i = 0, j = 3 \n " ,
" \n " ,
" 0 * (1 * 2 * 3) = 2 * 3 * 5 + 132 = 162 \n " ,
" T[i][k] + T[k+1][j] + m[i].first * m[k].second * m[j].second \n " ,
" T[0][0] + T[1][3] + 2 * 3 * 5 \n " ,
" 0 + 132 + 30 = 162 \n " ,
" \n " ,
" Case: (0 * 1) * (2 * 3), k = 1 \n " ,
" i = 0, j = 3 \n " ,
" \n " ,
" (0 * 1) * (2 * 3) = 36 + 120 + 2 * 6 * 5 = 216 \n " ,
" T[i][k] + T[k+1][j] + m[i].first * m[k].second * m[j].second \n " ,
" T[0][1] + T[2][3] + 2 * 6 * 5 \n " ,
" 36 + 120 + 60 = 216 \n " ,
" \n " ,
" Case: (0 * 1 * 2) * 3, k = 2 \n " ,
" i = 0, j = 3 \n " ,
" \n " ,
" (0 * 1 * 2) * 3 = 84 + 2 * 4 * 5 = 124 \n " ,
" T[i][k] + T[k+1][j] + m[i].first * m[k].second * m[j].second \n " ,
" T[0][2] + T[3][3] + 2 * 4 * 5 \n " ,
" 84 + 0 + 40 = 124 \n " ,
" \n " ,
" </pre> \n " ,
" \n " ,
" Complexity: \n " ,
" * Time: O(n^3) \n " ,
" * Space: O(n^2) "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ## Code "
]
} ,
{
" cell_type " : " code " ,
" execution_count " : 1 ,
2020-07-14 09:26:50 +08:00
" metadata " : { } ,
2017-03-27 17:23:15 +08:00
" outputs " : [ ] ,
" source " : [
" class Matrix(object): \n " ,
" \n " ,
" def __init__(self, first, second): \n " ,
" self.first = first \n " ,
" self.second = second "
]
} ,
{
" cell_type " : " code " ,
" execution_count " : 2 ,
2020-07-14 09:26:50 +08:00
" metadata " : { } ,
2017-03-27 17:23:15 +08:00
" outputs " : [ ] ,
" source " : [
" import sys \n " ,
" \n " ,
" \n " ,
" class MatrixMultiplicationCost(object): \n " ,
" \n " ,
" def find_min_cost(self, matrices): \n " ,
" if matrices is None: \n " ,
" raise TypeError( ' matrices cannot be None ' ) \n " ,
" if not matrices: \n " ,
" return 0 \n " ,
" size = len(matrices) \n " ,
" T = [[0] * size for _ in range(size)] \n " ,
" for offset in range(1, size): \n " ,
" for i in range(size-offset): \n " ,
" j = i + offset \n " ,
" min_cost = sys.maxsize \n " ,
" for k in range(i, j): \n " ,
" cost = (T[i][k] + T[k+1][j] + \n " ,
" matrices[i].first * \n " ,
" matrices[k].second * \n " ,
" matrices[j].second) \n " ,
" if cost < min_cost: \n " ,
" min_cost = cost \n " ,
" T[i][j] = min_cost \n " ,
" return T[0][size-1] "
]
} ,
{
" cell_type " : " markdown " ,
" metadata " : { } ,
" source " : [
" ## Unit Test "
]
} ,
{
" cell_type " : " code " ,
" execution_count " : 3 ,
2020-07-14 09:26:50 +08:00
" metadata " : { } ,
2017-03-27 17:23:15 +08:00
" outputs " : [
{
" name " : " stdout " ,
" output_type " : " stream " ,
" text " : [
" Overwriting test_find_min_cost.py \n "
]
}
] ,
" source " : [
" %% writefile test_find_min_cost.py \n " ,
2020-07-14 09:26:50 +08:00
" import unittest \n " ,
2017-03-27 17:23:15 +08:00
" \n " ,
" \n " ,
2020-07-14 09:26:50 +08:00
" class TestMatrixMultiplicationCost(unittest.TestCase): \n " ,
2017-03-27 17:23:15 +08:00
" \n " ,
" def test_find_min_cost(self): \n " ,
" matrix_mult_cost = MatrixMultiplicationCost() \n " ,
2020-07-14 09:26:50 +08:00
" self.assertRaises(TypeError, matrix_mult_cost.find_min_cost, None) \n " ,
" self.assertEqual(matrix_mult_cost.find_min_cost([]), 0) \n " ,
2017-03-27 17:23:15 +08:00
" matrices = [Matrix(2, 3), \n " ,
" Matrix(3, 6), \n " ,
" Matrix(6, 4), \n " ,
" Matrix(4, 5)] \n " ,
" expected_cost = 124 \n " ,
2020-07-14 09:26:50 +08:00
" self.assertEqual(matrix_mult_cost.find_min_cost(matrices), expected_cost) \n " ,
2017-03-27 17:23:15 +08:00
" print( ' Success: test_find_min_cost ' ) \n " ,
" \n " ,
" \n " ,
" def main(): \n " ,
" test = TestMatrixMultiplicationCost() \n " ,
" test.test_find_min_cost() \n " ,
" \n " ,
" \n " ,
" if __name__ == ' __main__ ' : \n " ,
" main() "
]
} ,
{
" cell_type " : " code " ,
" execution_count " : 4 ,
2020-07-14 09:26:50 +08:00
" metadata " : { } ,
2017-03-27 17:23:15 +08:00
" outputs " : [
{
" name " : " stdout " ,
" output_type " : " stream " ,
" text " : [
" Success: test_find_min_cost \n "
]
}
] ,
" source " : [
" %r un -i test_find_min_cost.py "
]
}
] ,
" 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 " ,
2020-07-14 09:26:50 +08:00
" version " : " 3.7.2 "
2017-03-27 17:23:15 +08:00
}
} ,
" nbformat " : 4 ,
2020-07-14 09:26:50 +08:00
" nbformat_minor " : 1
2017-03-27 17:23:15 +08:00
}