Open-Source Internship opportunity by OpenGenus for programmers. Apply now.

In this article, we will understand how to perform Matrix Multiplication in Python programming language. We have covered two approaches: one using Numpy library and other is a naive approach using for loop.

**Table of contents**:

- Matrix Multiplication
- Matrix Multiplication in Python using Numpy
- Matrix Multiplication using nested for loops (without numpy)

## Matrix Multiplication

Matrix multiplication, also known as matrix dot product, is a binary operation that takes a pair of matrices and produces another matrix.

In Python, this operation can be performed using the *NumPy* library, which provides a function called *dot* for matrix multiplication.

The rule for matrix multiplication is that two matrices can only be multiplied if the number of columns in the first matrix is the same as the number of rows in the second matrix.

**Input:**

Two matrices A (size m x n) and B (size n x p)

**Output:**

A matrix C (size m x p) such that C = A x B

```
Example
A = [1 2 3]
[4 5 6]
B = [7 8]
[9 10]
[11 12]
C = A x B = [17+29+311 18+210+312]
[47+59+611 48+510+612]
C = [58 64]
[139 154]
```

In this example, the matrix A has 2 rows and 3 columns, and matrix B has 3 rows and 2 columns, so they can be multiplied. The output matrix C has 2 rows and 2 columns.

## Matrix Multiplication in Python using Numpy

The **numpy.mul()** function can be used to multiply two matrices.

you can also use the @ operator to perform matrix multiplication, for example **a @ b or a.mul(b)**

**Example of how to perform matrix multiplication in Python using NumPy:**

```
import numpy as np
a = np.array([[1,2], [3,4]])
b = np.array([[5,6], [7,8]])
c = np.mul(a, b)
print(c)
```

This will output the matrix:

[[19 22]

[43 50]]

## Matrix Multiplication using nested for loops (without numpy)

Matrix multiplication can be implemented in Python using nested for loops.

The outer loop iterates through the rows of the first matrix, and the inner loop iterates through the columns of the second matrix.

The result is computed by taking the dot product of the current row of the first matrix and the current column of the second matrix.

**Example :-**

```
def matrix_mult(A, B):
#get the number of rows and columns of the
result matrix
rows_A, cols_A = len(A), len(A[0])
rows_B, cols_B = len(B), len(B[0])
#check if the matrices can be multiplied
if cols_A != rows_B:
raise ValueError("Cannot multiply
matrices: incompatible dimensions.")
#create the result matrix
c =[[0 for _ in range(cols_B)] for _ in range(rows_A)]
for i in range(rows_A):
for j in range(cols_B):
for k in range(cols_A):
C[i][j] += A[i][k] * B[k][j]
return c
```

However, this implementation has a time complexity of O(n^3), and it can be improved by reordering the loops.

- One way to improve the performance is to use a technique called
**loop tiling**, which involves dividing the matrix into smaller blocks and computing the multiplication for each block. - Another way is to use the BLAS library (Basic Linear Algebra Subprograms) which are implemented in C and can be called from Python. This library can perform the matrix multiplication much faster than a pure Python implementation.

#### Sample input:

arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

* Sample output:*

1 2 3

4 5 6

7 8 9

In this example, the outer loop iterates through the rows of the 2D array (arr), and the inner loop iterates through the elements of each row. The **end=" "** parameter in the print() function is used to prevent a newline from being printed after each element, so that all elements in a row are printed on the same line. The final print() statement outside the inner loop is used to add a newline after each row is printed.

**Reordering the loops in a matrix multiplication implementation can improve performance, but the most efficient way to perform matrix multiplication in Python is to use an optimized library like numpy.**

## Nested loop approach

Here is an example of how you could call the method matrix_mult using nested loops to perform matrix multiplication:

```
class MatrixOperations:
def matrix_mult(self,matrix1, matrix2):
rowsA = len(matrix1)
colsA = len(matrix1[0])
rowsB = len(matrix2)
colsB = len(matrix2[0])
if colsA != rowsB:
return "Cannot Multiply!"
else:
result = [[0 for row in range(colsB)] for col in range(rowsA)]
for i in range(rowsA):
for j in range(colsB):
for k in range(colsA):
result[i][j] += matrix1[i][k] * matrix2[k][j]
return result
matrixA = [[1,2,3], [4,5,6], [7,8,9]]
matrixB = [[9,8,7], [6,5,4], [3,2,1]]
matrix_op = MatrixOperations()
result = matrix_op.matrix_mult(matrixA, matrixB)
print(result)
```

In this example, the matrix_mult method takes two matrices as arguments and performs matrix multiplication using nested loops. It first checks if the number of columns in the first matrix is equal to the number of rows in the second matrix, if not it returns "Cannot Multiply!" otherwise it proceeds with the multiplication.

It creates a new matrix "result" of the size of rows of matrix1 and columns of matrix2, and then multiplies each element of matrix1 with corresponding element of matrix2 and saves the result to result matrix.

With this article at OpenGenus, you must have the complete idea of Matrix Multiplication in Python.