For working professionals
For fresh graduates
More
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
Foreign Nationals
The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not .
1. Introduction
6. PyTorch
9. AI Tutorial
10. Airflow Tutorial
11. Android Studio
12. Android Tutorial
13. Animation CSS
16. Apex Tutorial
17. App Tutorial
18. Appium Tutorial
21. Armstrong Number
22. ASP Full Form
23. AutoCAD Tutorial
27. Belady's Anomaly
30. Bipartite Graph
35. Button CSS
39. Cobol Tutorial
46. CSS Border
47. CSS Colors
48. CSS Flexbox
49. CSS Float
51. CSS Full Form
52. CSS Gradient
53. CSS Margin
54. CSS nth Child
55. CSS Syntax
56. CSS Tables
57. CSS Tricks
58. CSS Variables
61. Dart Tutorial
63. DCL
65. DES Algorithm
83. Dot Net Tutorial
86. ES6 Tutorial
91. Flutter Basics
92. Flutter Tutorial
95. Golang Tutorial
96. Graphql Tutorial
100. Hive Tutorial
103. Install Bootstrap
107. Install SASS
109. IPv 4 address
110. JCL Programming
111. JQ Tutorial
112. JSON Tutorial
113. JSP Tutorial
114. Junit Tutorial
115. Kadanes Algorithm
116. Kafka Tutorial
117. Knapsack Problem
118. Kth Smallest Element
119. Laravel Tutorial
122. Linear Gradient CSS
129. Memory Hierarchy
133. Mockito tutorial
134. Modem vs Router
135. Mulesoft Tutorial
136. Network Devices
138. Next JS Tutorial
139. Nginx Tutorial
141. Octal to Decimal
142. OLAP Operations
143. Opacity CSS
144. OSI Model
145. CSS Overflow
146. Padding in CSS
148. Perl scripting
149. Phases of Compiler
150. Placeholder CSS
153. Powershell Tutorial
158. Pyspark Tutorial
161. Quality of Service
162. R Language Tutorial
164. RabbitMQ Tutorial
165. Redis Tutorial
166. Redux in React
167. Regex Tutorial
170. Routing Protocols
171. Ruby On Rails
172. Ruby tutorial
173. Scala Tutorial
175. Shadow CSS
178. Snowflake Tutorial
179. Socket Programming
180. Solidity Tutorial
181. SonarQube in Java
182. Spark Tutorial
189. TCP 3 Way Handshake
190. TensorFlow Tutorial
191. Threaded Binary Tree
196. Types of Queue
197. TypeScript Tutorial
198. UDP Protocol
202. Verilog Tutorial
204. Void Pointer
205. Vue JS Tutorial
206. Weak Entity Set
207. What is Bandwidth?
208. What is Big Data
209. Checksum
211. What is Ethernet
214. What is ROM?
216. WPF Tutorial
217. Wireshark Tutorial
218. XML Tutorial
Matrix Chain Multiplication is an important problem in computer science and mathematics. It focuses on finding the most efficient way to multiply a sequence of matrices. The goal is to minimize the total number of scalar multiplications needed, as different multiplication orders can lead to drastically different computation costs. This makes the problem significant in areas such as optimization, data processing, and scientific computing.
In this tutorial, we will explore the Matrix Chain Multiplication algorithm in detail. You will learn the problem statement, recursive solution, and dynamic programming approach. We will also cover implementations in C++ and Java, along with examples for better understanding. This structured guide will help you grasp both the logic and the application of the algorithm.
Want to strengthen your software development skills? Explore upGrad’s Online Software Engineering Courses. Build a strong foundation in JavaScript, Node.js, APIs, React, and more to accelerate your career in software engineering.
What Is Matrix Chain Multiplication?
Matrix Chain Multiplication is a problem in computer science that focuses on finding the most efficient way to multiply a sequence of matrices. Since matrix multiplication is associative, the order of multiplying does not affect the final result but can significantly change the total number of scalar operations required. The goal is to minimize these operations to improve performance.
Accelerate your tech career by mastering future-ready skills in Cloud, DevOps, AI, and Full Stack Development. Gain hands-on experience, learn from industry leaders, and develop the expertise that top employers demand.
The matrix chain multiplication algorithm helps determine the optimal parenthesizing of matrices, reducing computational cost. This is especially useful in applications like computer graphics, optimization, and scientific computing, where multiple matrix operations are common.
The problem statement for the Matrix Chain Multiplication problem is to determine the most efficient technique to multiply a given collection of matrices. The purpose is to determine the procedure in which the matrices should be multiplied to decrease the number of math steps required to compute the final result.
Here is an example to show the problem:
Suppose we have three matrices: A with dimensions 10×20, B with dimensions 20×30, and C with dimensions 30×40. There are various methods to parenthesize the product of these matrices. However, the number of operations necessary might vary depending on the multiplication sequence.
Option 1: (AB)C
The product of A and B is a matrix with a size of 10×30.
The product of the resultant matrix and C is a matrix with a size of 10×40.
Total amount of operations: (10×20×30) + (10×30×40) = 6000 + 12000 = 18000 operations.
Option 2: A(BC)
The product of B and C is a matrix with a size of 20×40.
The product of A and the resultant matrix is a matrix of size 10×40.
Total amount of operations: (20×30×40) + (10×20×40) = 24000 + 8000 = 32000 operations.
In this case, Option 1 involves fewer operations than Option 2. Hence it is the most efficient option to multiply the matrices.
The Matrix Chain Multiplication issue may be addressed using dynamic programming. By evaluating all conceivable methods to partition the series of matrices into subchains and computing the lowest number of operations for each subchain, we may build up a solution for the complete sequence.
Also Read: Laravel Tutorial for Beginners: Step-by-Step Guide to Build Web Apps
The recursive solution to the Matrix Chain Multiplication issue includes breaking down the problem into subproblems and solving them recursively. Here's an explanation of the recursive solution with an example:
Let's explore an example using a succession of matrices: A, B, C, D. The dimensions of the matrices are as follows:
A: 2x3
B: 3x4
C: 4x2
D: 2x5
To obtain the least number of scalar multiplications required to multiply these matrices, we may follow these steps:
Code:
#include <iostream>
#include <vector>
#include <climits>
// Function to calculate the minimum number of scalar multiplications
// needed to multiply a sequence of matrices
int matrixChainMultiplication(const std::vector<int>& dimensions) {
int n = dimensions.size() - 1;
std::vector<std::vector<int>> dp(n, std::vector<int>(n, 0));
// Initialize the diagonal elements with 0
for (int i = 0; i < n; ++i) {
dp[i][i] = 0;
}
// Loop to fill the remaining elements in the dp table
for (int len = 2; len <= n; ++len) {
for (int i = 0; i <= n - len + 1; ++i) {
int j = i + len - 1;
dp[i][j] = INT_MAX;
for (int k = i; k < j; ++k) {
int cost = dp[i][k] + dp[k + 1][j] + dimensions[i] * dimensions[k + 1] * dimensions[j + 1];
dp[i][j] = std::min(dp[i][j], cost);
}
}
}
return dp[0][n - 1];
}
int main() {
std::vector<int> dimensions = {10, 30, 5, 60};
int minScalarMultiplications = matrixChainMultiplication(dimensions);
std::cout << "Minimum scalar multiplications: " << minScalarMultiplications << std::endl;
return 0;
}
In the above example, we're given the dimensions of a sequence of matrices to be multiplied. The matrixChainMultiplication function calculates the minimum number of scalar multiplications needed to multiply the matrices in an optimal order. The dp table is used to store the optimal solutions for subproblems. The dynamic programming approach avoids redundant calculations and optimizes the matrix multiplication order.
Note that the dimensions vector should represent the dimensions of matrices in the sequence. For example, if you have matrices A with dimensions 10x30, B with dimensions 30x5, and C with dimensions 5x60, the dimensions vector would be {10, 30, 5, 60}. The output will provide the minimum number of scalar multiplications needed for optimal matrix chain multiplication.
Also Read: Understanding Half Adder and Full Adder in Digital Electronics
Dynamic Programming (DP) with memoization is a technique for increasing the performance of recursive algorithms by preserving and reusing the results of expensive function calls. This can significantly reduce the method's temporal complexity.
The algorithm for DP utilizing memoization may be stated as follows:
Here is the pseudocode for DP with memoization:
Memo = {} // Memoization table to store computed results
function dpMemoization(arguments):
if arguments are in Memo:
return Memo[arguments]
if base case:
result = compute base case value
else:
result = recursive call(s) with dpMemoization
Memo[arguments] = result
return result
Code:
#include <iostream>
#include <unordered_map>
std::unordered_map<int, int> memo; // Memoization table
int fibonacci(int n) {
if (memo.find(n) != memo.end()) {
return memo[n];
}
int result;
if (n <= 1) {
result = n;
} else {
result = fibonacci(n - 1) + fibonacci(n - 2);
}
memo[n] = result;
return result;
}
int main() {
int n = 10;
std::cout << "Fibonacci(" << n << ") = " << fibonacci(n) << std::endl;
return 0;
}
In this implementation, we calculate the nth Fibonacci number using dynamic programming with memoization. We use an unordered map memo to store precomputed results for different values of n. Before computing a Fibonacci value, we check if it exists in the memo map. If it does, we return the precomputed value. Otherwise, we calculate it recursively and store it in the memo map.
Code:
import java.util.HashMap;
import java.util.Map;
public class DPMemoization {
static Map<Integer, Integer> memo = new HashMap<>(); // Memoization table
static int fibonacci(int n) {
if (memo.containsKey(n)) {
return memo.get(n);
}
int result;
if (n <= 1) {
result = n;
} else {
result = fibonacci(n - 1) + fibonacci(n - 2);
}
memo.put(n, result);
return result;
}
public static void main(String[] args) {
int n = 10;
System.out.println("Fibonacci(" + n + ") = " + fibonacci(n));
}
}
This is the same implementation as the C++ version, but in Java. We use a HashMap memo to store precomputed results and avoid redundant calculations.
Must Read: Sum of N Natural Numbers
In the bottom-up DP approach, you start by solving the smallest subproblems and gradually build up to the desired solution by solving larger subproblems. You avoid the recursion and instead use iterative loops to fill up a table (often an array) that stores solutions to subproblems. This approach is often more intuitive for some people and can be more memory-efficient than memoization.
The algorithm for DP utilizing the bottom-up approach may be stated as follows:
Here is the pseudocode for DP with bottom-up approach:
function bottomUpDP(arguments):
table = createEmptyTable()
// Initialize base cases
table[0] = baseCaseValue0
table[1] = baseCaseValue1
// Fill the table iteratively
for i = 2 to n:
table[i] = computeSolutionFrom(table[i-1], table[i-2], ...)
return table[n]
Code:
#include <iostream>
#include <vector>
int bottomUpFibonacci(int n) {
if (n <= 1) {
return n;
}
std::vector<int> dp(n + 1);
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
int main() {
int n = 10;
std::cout << "Fibonacci(" << n << ") = " << bottomUpFibonacci(n) << std::endl;
return 0;
}
In this implementation, we calculate the nth Fibonacci number using a bottom-up dynamic programming approach. We use an array dp to store the solutions to subproblems, starting from the base cases (dp[0] = 0 and dp[1] = 1). We then iteratively fill the array using previously computed solutions.
Code:
public class BottomUpDP {
static int bottomUpFibonacci(int n) {
if (n <= 1) {
return n;
}
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
public static void main(String[] args) {
int n = 10;
System.out.println("Fibonacci(" + n + ") = " + bottomUpFibonacci(n));
}
}
This is the same implementation as the C++ version, but in Java. We use an array dp to store the solutions to subproblems and fill it using an iterative loop.
Matrix Chain Multiplication is a fundamental concept for optimizing matrix operations in computer science. By applying the matrix chain multiplication algorithm, we can determine the most efficient order of multiplication, minimizing scalar operations and reducing overall computational cost.
Dynamic programming techniques make this process more effective, especially for large matrix sequences. Mastering this concept is valuable for professionals in fields like computer graphics, scientific computing, and optimization, where efficient matrix calculations directly impact performance and scalability.
Matrix Chain Multiplication is an optimization problem in computer science. It focuses on finding the most efficient way to multiply a sequence of matrices. The cost is measured in terms of scalar multiplications. Since matrix multiplication is associative, the challenge is deciding the order of multiplication that minimizes operations. The problem is solved using the matrix chain multiplication algorithm, often implemented with dynamic programming.
Matrix Chain Multiplication is important because matrix operations are widely used in computer graphics, scientific computing, optimization, and AI. An inefficient multiplication order can drastically increase computation time. By applying the matrix chain multiplication algorithm, developers and researchers can reduce computational complexity, improve performance, and optimize algorithms that rely heavily on large-scale matrix calculations.
The problem statement is to determine the optimal order of multiplying a chain of matrices so that the total number of scalar multiplications is minimized. While the result of multiplication remains the same regardless of order, the computational cost varies significantly. The matrix chain multiplication algorithm provides a systematic way to solve this optimization problem.
Suppose matrices A(10×20), B(20×30), and C(30×40) are multiplied. Two possibilities exist:
The dynamic programming approach to matrix chain multiplication has a time complexity of O(n³), where n is the number of matrices. This is because the algorithm computes the cost of multiplying every possible subchain. While cubic complexity may seem high, it is significantly better than the exponential time of a naive recursive approach.
The recursive solution breaks the problem into subproblems by dividing the chain of matrices at different positions. For each division, it calculates the cost of multiplying the left and right subchains and adds the cost of multiplying the results. The solution explores all possible parenthesizations but suffers from overlapping subproblems, making it inefficient without memoization.
The dynamic programming solution uses a bottom-up approach to avoid redundant calculations. It fills a DP table where each entry represents the minimum scalar multiplications needed to multiply a subchain of matrices. By solving smaller subproblems first and building up, the matrix chain multiplication algorithm efficiently finds the optimal multiplication order.
Memoization improves the recursive matrix chain multiplication algorithm by storing results of already solved subproblems in a lookup table. When the same subproblem reoccurs, the result is retrieved instead of recalculated. This reduces the exponential time complexity of the naive recursive method to O(n³), making it as efficient as the bottom-up DP approach.
Optimal parenthesization refers to the best way of placing parentheses in a matrix chain expression to minimize scalar multiplications. For example, multiplying matrices as (AB)C instead of A(BC) can drastically change computation cost. The matrix chain multiplication algorithm helps in determining this optimal parenthesization systematically.
Yes, the recursive solution is essentially based on the divide and conquer strategy. The chain of matrices is divided at different points, subproblems are solved recursively, and results are combined. However, without memoization or dynamic programming, this approach leads to exponential time complexity due to overlapping subproblems.
Matrix Chain Multiplication is applied in computer graphics, 3D rendering, scientific simulations, neural networks, and operations research. In these domains, large matrix computations are common, and optimizing multiplication order reduces processing time and memory usage. Efficient use of the matrix chain multiplication algorithm directly improves algorithm performance.
In C, matrix chain multiplication can be implemented using a dynamic programming approach with a 2D array (DP table). The array stores the minimum cost of multiplying subchains of matrices. Nested loops are then used to fill the table iteratively, and the final result provides the minimum scalar multiplications required.
In C++, the implementation typically uses a 2D vector to store DP results. Iterative loops fill the DP table, and the solution is computed from smaller subchains to larger ones. With proper implementation, the C++ version of the matrix chain multiplication algorithm efficiently outputs the optimal cost and can also store the parenthesization.
In Java, matrix chain multiplication is implemented using 2D arrays or HashMaps for memoization. A bottom-up DP solution iteratively computes the minimum multiplication cost for all subchains. Java’s object-oriented features also make it easier to design reusable classes for representing matrices and storing optimal parenthesization sequences.
Yes, several online calculators allow users to input matrix dimensions and compute the optimal multiplication sequence. Tools like CalculatorSoup provide both the optimal parenthesization and the total number of scalar multiplications required. These calculators are useful for quickly understanding how the algorithm works.
The recursive solution explores all possible parenthesizations and recalculates many subproblems, leading to exponential time complexity. The dynamic programming solution, however, uses a DP table to store results of subproblems and builds the solution bottom-up. Both yield the correct result, but DP is significantly faster and more practical.
The dynamic programming implementation of matrix chain multiplication requires a 2D DP table of size O(n²), where n is the number of matrices. This space is used to store the minimum multiplication costs of all possible subchains. Some optimized implementations can reduce memory usage, but O(n²) is the standard.
Yes, the matrix chain multiplication algorithm can be adapted for sparse matrices, but additional optimizations are required. Sparse matrices have many zero elements, which can be exploited to reduce computation. Specialized libraries for sparse matrix operations integrate such optimizations beyond the standard algorithm.
Indirectly, yes. Many machine learning algorithms involve linear algebra operations, including matrix multiplications for training models, deep learning layers, and optimization routines. Efficiently multiplying matrices using the matrix chain multiplication algorithm reduces training time and computational overhead in large-scale ML applications.
The main limitation is its O(n³) time complexity, which becomes impractical for extremely large matrix chains. Additionally, the algorithm only optimizes multiplication order, not the multiplication process itself. In real-world scenarios with distributed systems or parallel processing, further optimizations are required beyond classical dynamic programming.
FREE COURSES
Start Learning For Free
Author|900 articles published
Recommended Programs