matrix chain order Algorithm

Matrix Chain Order Algorithm is a dynamic programming technique used to find the most efficient way to multiply a given sequence of matrices. The algorithm aims to minimize the number of scalar multiplications required to compute the product of the matrices, which can be quite computationally expensive for large matrices. The problem can be stated as follows: given a sequence of matrices A1, A2, ..., An, and the dimensions of these matrices, find the optimal parenthesization order to minimize the total number of scalar multiplications required to compute their product. The main idea behind the algorithm is to break down the problem into smaller subproblems and use the results of these subproblems to construct the optimal solution for the original problem. The Matrix Chain Order Algorithm employs a bottom-up approach, where it computes the optimal parenthesization for all possible subproblems of smaller sizes and stores the results in a table. This table is used to look up the solutions for larger subproblems and avoid redundant computations. The algorithm initializes a cost matrix, where the entry at the ith row and jth column represents the minimum number of scalar multiplications required to compute the product of matrices from Ai to Aj. It then iteratively computes the cost matrix entries for increasing chain lengths, starting from the diagonal elements (chain length of 1) and moving towards the top-right corner of the matrix (chain length of n). To compute the cost of multiplying a chain of matrices, the algorithm considers all possible ways to split the chain into two smaller chains and chooses the one that results in the least number of scalar multiplications. Once the cost matrix is filled, the optimal parenthesization order can be obtained by backtracking through the matrix and determining the optimal split points.
import sys

"""
Dynamic Programming
Implementation of Matrix Chain Multiplication
Time Complexity: O(n^3)
Space Complexity: O(n^2)
"""


def MatrixChainOrder(array):
    N = len(array)
    Matrix = [[0 for x in range(N)] for x in range(N)]
    Sol = [[0 for x in range(N)] for x in range(N)]

    for ChainLength in range(2, N):
        for a in range(1, N - ChainLength + 1):
            b = a + ChainLength - 1

            Matrix[a][b] = sys.maxsize
            for c in range(a, b):
                cost = (
                    Matrix[a][c] + Matrix[c + 1][b] + array[a - 1] * array[c] * array[b]
                )
                if cost < Matrix[a][b]:
                    Matrix[a][b] = cost
                    Sol[a][b] = c
    return Matrix, Sol


# Print order of matrix with Ai as Matrix
def PrintOptimalSolution(OptimalSolution, i, j):
    if i == j:
        print("A" + str(i), end=" ")
    else:
        print("(", end=" ")
        PrintOptimalSolution(OptimalSolution, i, OptimalSolution[i][j])
        PrintOptimalSolution(OptimalSolution, OptimalSolution[i][j] + 1, j)
        print(")", end=" ")


def main():
    array = [30, 35, 15, 5, 10, 20, 25]
    n = len(array)
    # Size of matrix created from above array will be
    # 30*35 35*15 15*5 5*10 10*20 20*25
    Matrix, OptimalSolution = MatrixChainOrder(array)

    print("No. of Operation required: " + str(Matrix[1][n - 1]))
    PrintOptimalSolution(OptimalSolution, 1, n - 1)


if __name__ == "__main__":
    main()

LANGUAGE:

DARK MODE: