In [1]:
import numpy as np

Matrix multiplication: The rules for validity

$\left[ \begin{matrix} \quad \quad \quad\\ \\ \\ \end{matrix} \right] \left[ \begin{matrix} \quad \\ \\ \\ \\ \end{matrix} \right] = \left[ \begin{matrix} \quad \\ \\ \\ \end{matrix} \right]$

$\: M \times N \quad N \times K = M \times K$

Valid

$\quad AB$$\quad 5 \times 2 \quad 2 \times 7$

Invalid

$\quad BA$$\quad 2 \times 7 \quad 5 \times 2$

$\quad CA$$\quad 5 \times 7 \quad 5 \times 2$

In [2]:
A = np.random.randn(14,10)
B = np.random.randn(14,10)
C = np.random.randn(10,14)

# invalid
# np.shape(A@B)

# valid
print(np.shape(C@B))
print(np.shape(B@C))
(10, 10)
(14, 14)

Mechanics of matrix multiplication

$\left[ \begin{matrix} 0 \: 1\\ 2 \: 3 \end{matrix} \right] \left[ \begin{matrix} a \: b\\ c \: d \end{matrix} \right] = \left[ \begin{matrix} 0a+1c \quad 0b+1d\\ 2a+3c \quad 2b+3d \end{matrix} \right]$

np.dot(A[i, :],B[:, j])

In [3]:
def matrixMultiplication(A,B):
    # get matrix sizes
    szA = np.shape(A)
    szB = np.shape(B)
    
    # check sizes and give error if multiplication is not valid
    if szA[1]!=szB[0]:
        raise ValueError('"Inner"dimensions don\'t match')
        
    # initialize
    C = np.zeros((szA[0],szB[1]))
    print(szA[0])
    print(szB[1])
    
    # compute
    for i in range(szA[0]):
        for j in range(szB[1]):
            C[i,j] = np.dot(A[i,:],B[:,j])
#             print(i)
#             print(A[i,:])
#             print(B[:,j])
#             print(np.dot(A[i,:],B[:,j]))
            
    return C
In [4]:
A = np.random.randn(6,2)
B = np.random.randn(2,6)

C1 = matrixMultiplication(A,B)
C2 = A@B

print(C1-C2)
6
6
[[0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0.]]