# Siv Scripts

Solving Problems Using Code

Fri 05 January 2018

# @ Python's Matrix Multiplication Operator

Posted by Aly Sivji in Quick Hits

2017 will forever be etched in our memories as the year Python overtook R to become the leading language for Data Science. There are many factors that play into this: Python's simple syntax, the fantastic PyData ecosystem, and of course buy-in from Python's BDFL.

PEP 465 introduced the @ infix operator that is designated to be used for matrix multiplication. The acceptance and implementation of this proposal in Python 3.5 was a signal to the scientific community that Python is taking its role as a numerical computation language very seriously.

I was a Computational Mathematics major in college so matrices are very near and dear to my heart. Shoutout to Professor Jeff Orchard for having us implement matrix algorithms in C++. His Numerical Linear Algebra course was the best class I've ever taken.

In this post, we will explore the @ operator.

In [1]:
import numpy as np

In [2]:
A = np.matrix('3 1; 8 2')
A

Out[2]:
matrix([[3, 1],
[8, 2]])
In [3]:
B = np.matrix('6 1; 7 9')
B

Out[3]:
matrix([[6, 1],
[7, 9]])
In [4]:
A @ B

Out[4]:
matrix([[25, 12],
[62, 26]])

Let's confirm this works

In [5]:
# element at the top left. i.e. (1, 1) aka (0, 0) in python
A[0, 0] * B[0, 0] + A[0, 1] * B[1, 0]

Out[5]:
25
In [6]:
# element at the top right. i.e. (1, 2) aka (0, 1) in python
A[0, 0] * B[0, 1] + A[0, 1] * B[1, 1]

Out[6]:
12
In [7]:
# element at the bottom left. i.e. (2, 1) aka (1, 0) in python
A[1, 0] * B[0, 0] + A[1, 1] * B[1, 0]

Out[7]:
62
In [8]:
# element at the top right. i.e. (2, 2) aka (1, 1) in python
A[1, 0] * B[0, 1] + A[1, 1] * B[1, 1]

Out[8]:
26
In [9]:
# let's put it in matrix form
result = np.matrix([[A[0, 0] * B[0, 0] + A[0, 1] * B[1, 0], A[0, 0] * B[0, 1] + A[0, 1] * B[1, 1]],
[A[1, 0] * B[0, 0] + A[1, 1] * B[1, 0], A[1, 0] * B[0, 1] + A[1, 1] * B[1, 1]]])
result

Out[9]:
matrix([[25, 12],
[62, 26]])
In [10]:
A @ B == result

Out[10]:
matrix([[ True,  True],
[ True,  True]], dtype=bool)

Looks good!

The Python Data Model specifies that the @ operator invokes __matmul__ and __rmatmul__.

We can overload @ by defining custom behavior for each of the special methods above, but this would result in our API not being Pythonic.

To build Pythonic objects, observe how real Python objects behave.