How to Compute the Dot Product of Arrays Using Linalg.multi_dot?

Compute The Dot Product Of Two Or More Arrays

The dot product of the arrays can be calculated by the function called linalg.multi_dot of the NumPy library, which is easier to compute and takes less computational time than its predecessor, np.dot.

We are also going to see the comparison of np.dot and multi_dot in this post.

Find everything you need to know about how to compute the dot product of arrays as well as vectors using np dot() in this article.

What Is the Dot Product?

The dot product is a mathematical operation between two arrays of the same length that returns a scalar value. It is calculated as the sum of the element-wise products of the two arrays. It is given as : dot(a, b)[i,j,k,m] = sum(a [i,j,:] * b[k,:,m])


Everything You Need to Know About linalg.multi_dot

This function of the NumPy library is convenient as it can compute the dot product of two or more arrays in a single function call.

By single function call, we mean that while computing the dot product of two or more arrays, there is no necessity to compute the dot product of arrays separately in different function calls and then combine the result into another function call. We can compute the dot product of as many arrays in just one call of the function.

The multi_dot can be thought of as :

def mulit_dot(arrays): return functools.reduce(np.dot, arrays)

Syntax:

linalg.multi_dot(arrays*out=None)

ArgumentsDescriptionDefault valueRequired/Optional
arraysIf the first argument is 1-D it is treated as a row vector. If the last argument is 1-D it is treated as a column vector
The resultant array has the same number of rows as the first argument and the same number of columns as the second argument
sequence of array_likeRequired
outOutput argument. It is not usually specified in the syntax, but when it is specified, the output of the computation should be the same type and memory layout as specified in this field
The purpose of this parameter is to reuse an existing NumPy array as the output argument, which can lead to performance improvements
If the specified condition for the out the argument is not met, the function will raise an exception
ndarrayOptional
Arguments of multi_dot

Returns: This function returns the dot product of the given arrays as input. The output is a NumPy array.

Dot Product of Two Simple Arrays

Let us compute the dot product of two simple 2D matrices.

The code is given below.

import numpy as np
#creating two arrays
a=np.array([[1,2],[3,4]])
b=np.array([[5,6],[7,8]]) 
#computing the dot product
comp=np.linalg.multi_dot([a, b])
print(comp)

import numpy as np: We are importing the NumPy library with an alias name- np.

In the third and fourth lines, two arrays are created using np.array function and are stored in two different variables a and b.

The dot product of a and b is computed with the help of np.linalg.multi_dot and is stored in a variable called comp in the sixth line.

In the next line, we are printing the result of the dot product.

The dot product of the a and b is shown below./

Dotproduct1
Dotproduct1

Let us check the time taken to execute.

#checking the execution time
%timeit np.linalg.multi_dot([a, b])

The %timeit function is used to calculate the time taken to perform this operation.

Timeit1
Timeit1

Now that we have understood the basic functionality let us see a more complex example.


Dot Product of Two Arrays When One of Them Has Infinity Values

Let us first consider one array with a positive infinity value.

While we are dealing with the elimination of infinite values , here is an article that shows how to create infinity in python.

The code is given below.

import numpy as np
#creating arrays
a=np.array([[3,np.inf],[4,5]])
b=np.array([[5,6],[7,8]])
print("The first array is:\n",a)
print("-"*15)
print("The second array is :\n",b)
print("-"*15)
#converting the infintiy values to some number 
a1=np.nan_to_num(a,posinf=12)
print("Modified array :\n",a1)
print("*"*15)
comp1=np.linalg.multi_dot([a1, b])
print("The dot product of two arrays is:\n",comp1)

import numpy as np : We are importing the NumPy library with an alias name- np.

In the third line, we are creating a two-dimensional array that has one positive infinite value in it. The keyword np.inf is used to create a positive infinity value. This array is stored in a variable called a.

In the fourth line, we are creating a two-dimensional array that is stored in a new variable called b.

In the next line, we are printing the first array to the screen.

print("-"*15) is used as a separator. It prints 15 hyphens(-) on the screen.

In line 7, we are printing the second array to the screen.

print("-"*15) is used as a separator. It prints 15 hyphens(-) on the screen.

We now have two arrays a and b. But we need to replace the positive infinity value with some number. It can be done using np.nan_to_num method by passing the array we need to modify (a) and the number we wish to replace the infinity with(in this case, 12). posinf is used to specify that the number we are giving is a positive number.

This modified array is stored in a1 and is passed as an argument to the multi_dot function.

The result of the dot product is stored in comp1 and is printed in line 14.

And the output is:

Dotproduct2
Dotproduct2

Let us see if the dot product works with negative values.

The code is shown below.

import numpy as np
#creating arrays
a=np.array([[3,6],[4,5]])
b=np.array([[5,-np.inf],[7,8]])
print("The first array is:\n",a)
print("-"*15)
print("The second array is :\n",b)
print("-"*15)
#converting the infintiy values to some number 
b1=np.nan_to_num(b,neginf=-13)
print("Modified array :\n",b1)
print("*"*15)
comp2=np.linalg.multi_dot([a,  b1])
print("The dot product of two arrays is:\n",comp2)

import numpy as np : We are importing the NumPy library with an alias name- np.

In the third line, we are creating a two -dimensional array which is stored in a new variable called a.

In the fourth line, we are creating a two-dimensional array that has one negative infinite value in it. The keyword –np.inf is used to create a negative infinity value. This array is stored in a variable called b.

In the next line, we are printing the first array to the screen.

print("-"*15) is used as a separator. It prints 15 hyphens(-) on the screen.

In line 7, we are printing the second array to the screen.

print("-"*15) is used as a separator. It prints 15 hyphens(-) on the screen.

We need to replace the negative infinity value with some number. It can be done using np.nan_to_num method by passing the array we need to modify (b) and the number we wish to replace the infinity with(in this case, -13). neginf is used to specify that the number we are giving is a negative number.

This modified array is stored in b1 and is passed as an argument to the multi_dot function.

The result of the dot product is stored in comp1 and is printed in line 14.

The computed dot product is as follows:

Dotproduct3
Dotproduct3

Dot Product of Three Arrays of Three Dimension

Let us consider three matrices of 3×3 dimensions.

Here is the code.

import numpy as np
#creating three matrices 
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("First 3x3 matrix:\n",a)
print("-"*15)
b = np.array([[9, 0,1], [1, 5, 4], [8,1,0]])
print("Second 3x3 matrix:\n",b)
print("-"*15)
c = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
print("Third 3x3 matrix:\n",c)
print("*"*15)
#calculating the dot product
comp3 = np.linalg.multi_dot([a,b,c])
print("The dot product is:")
print(comp3)

In the first line, we are bringing the NumPy library to the environment.

Three-dimensional arrays can be thought of as three lists combined together into one single matrix.

In the third line, we are creating the first array and storing it in a variable a.

In the next line, we print the array on the screen. The \n is a newline character. All the arguments after \n are printed in a new line.

print("-"*15): This line is used to create a separator and outputs 15 hyphens(-) on the screen.

The following line is used to create the second matrix stored in b.

We are printing the new array on the screen.

We are creating the third array and storing it in a variable called c in the ninth line,

The dot product of the three arrays(a, b, and c) is computed in line 13 and is stored in a variable called comp3.

Finally, we are printing the result in line 14.

The output is given below.

Dotproduct4
Dotproduct4

Execution Time Taken by np.dot and multi_dot

Let us compare the execution time of the two methods: np.dot and multi_dot.

Here is the code for np.dot

#using np.dot
import numpy as np
#Creating arrays
a = np.array([[1, 3], [4, 6]])
b = np.array([[5, 6], [7, 9]])
c = np.array([[6, 1], [3, 4]])
#computing the dot product
comp1 = np.dot(a, b)
res=np.dot(comp1,c)
print("Dot products of these 3 arrays is:")
print(res)
%timeit np.dot(a,b,c)

We are creating three arrays a,b, and c in lines 4,5, and 6, respectively.

Since we are using np.dot, we cannot pass all three arrays as arguments to the function at once. So, we are computing the dot product of the first two arrays (a and b), storing the result in a variable called comp1.

Now, comp1 and the array c are passed as arguments to the np.dot , and the dot product of the three matrices is stored in res.

In line 11, we are printing the result.

In line 12, we are calculating the execution time of np.dot using the magic command %timeit.

The output is given below.

Timeit of np.dot
Timeit of np.dot

As you can see, the time taken by np.dot is less than 3 microseconds.

Let us see the code for multi_dot.

#using multi_dot
import numpy as np
#Creating arrays
a = np.array([[1, 3], [4, 6]])
b = np.array([[5, 6], [7, 9]])
c = np.array([[6, 1], [3, 4]])
#computing the dot product
comp2 = np.linalg.multi_dot([a, b, c])
print("Dot products of these 3 arrays is:")
print(comp2)
%timeit np.linalg.multi_dot([a, b, c])

We are creating three arrays a,b, and c in lines 4,5, and 6, respectively.

Since we are using multi_dot, we don’t need to compute the dot product multiple times. We can pass all three arrays to the function and obtain the dot product in a single function call.

The result is stored in a variable called comp2.

In the last line, we are checking the execution time of the multi_dot using %timeit.

Timeit of multi_dot
Timeit of multi_dot

As observed from both outputs, the multi_dot takes almost 2x time than np.dot.


Conclusion

We have seen what is a dot product and how multi_dot function enables us to compute the dot product of two or more arrays in just a single function call. We have also seen the syntax of multi_dot().

In the first example, we have calculated the dot product of two simple matrices of 2d size.

Next, we have seen how to compute the dot product when one array has infinite values(both positive and negative).

We have also seen the calculation of the dot product for three-dimensional arrays.

Lastly, we have compared np.dot and multi_dot. Though multi_dot helps us to compute the dot product of two or more arrays in a single call, np.dot takes much less time to execute.

Hence, it is safe to say the choice between np.dot and multi-dot depends on the use case and the size of the arrays.

If the arrays are simple and of less dimension, np.dot they can be used. But if the arrays are of higher dimension (like 4d), we need to go for multi_dot.

References

Official NumPy manual for linalg.multi_dot.

Stack overflow question on the usage of timeit module.