Basic matrix operations

24. Basic matrix operations#

There are many matrix operations in Python (NumPy) that make finding solutions to systems equations much easier than doing so by hand. In order to use these operations, the matrices and vectors must first be stored in memory. NumPy can be used to create matrices, or 2D arrays, starting from a list of lists, as we’ll see below.

Consider the following matrices and vectors:

\[\begin{split} A = \begin{bmatrix} 3 & 5 & 2 \\ 0 & 1 & 2 \\ 3 & 6 & 1 \end{bmatrix}, \qquad B = \begin{bmatrix} 2 & 5 & 4 \\ 4 & 6 & 3 \\ 4 & 10 & 8 \end{bmatrix}, \qquad C = \begin{bmatrix} 1 & 3 \\ 3 & 2 \\ 4 & 5 \end{bmatrix}, \qquad \vec{x} = \begin{bmatrix} 3 \\ 2 \\ 1 \end{bmatrix} \end{split}\]

Enter the matrices into Python and perform the following operations:
(a) \(AB\)
(b) \(AC\)
(c) \(CA\)
(d) \(B\vec{x}\)
(e) \(B\vec{x}^T\)

# import packages
import numpy as np

# define matrices and vectors
A = np.array([ [3, 5, 2], [0, 1, 2], [3, 6, 1] ])   # each inner list is a row of the matrix
B = np.array([ [2, 5, 4], [4, 6, 3], [4, 10, 8] ])
C = np.array([ [1, 3], [3, 2], [4, 5] ])
x = np.array([ [3], [2], [1] ])

We can print out these variables to see if we did it correctly.

print(A)
print()
print(x, x.shape)
[[3 5 2]
 [0 1 2]
 [3 6 1]]

[[3]
 [2]
 [1]] (3, 1)

You may recall from back in Vector operations I we talked about the shapes of 1D arrays. Here, based on the way we constructed x, both dimensions are present! (so it is more like a true column vector)

If it all looks good, we can proceed with the computation. In NumPy, matrix multiplication (successive row-column products) is performed with the @ operator. If you use the * operator, it might still work, but it will likely be wrong, as this will perform element-wise multiplication.

# part a: AB
print("AB:")
print(A @ B)

# part b: AC
print("\nAC:")
print(A @ C)

# part c: CA
print("\nCA:")
print(C @ A)
AB:
[[34 65 43]
 [12 26 19]
 [34 61 38]]

AC:
[[26 29]
 [11 12]
 [25 26]]

CA:
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[3], line 11
      9 # part c: CA
     10 print("\nCA:")
---> 11 print(C @ A)

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 3 is different from 2)

As expected, \(CA\) gave an error because the inner dimensions do not match. In this next cell, notice how we take the transpose of \(\vec{x}\) by appending a .T to the array.

# part d: Bx
print("\nBx:")
print(B @ x)

# part e: Bx^T
print("\nBx^T:")
print(B @ x.T)
Bx:
[[20]
 [27]
 [40]]

Bx^T:
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[4], line 7
      5 # part e: Bx^T
      6 print("\nBx^T:")
----> 7 print(B @ x.T)

ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 1 is different from 3)

Reduced row echelon form#

Next we will reduce \(A\) to reduced row echelon form using the rref() method from the SymPy library. Unfortunately there’s no built-in method in NumPy, but the SymPy library has its own advantages (look at that \(\LaTeX\)-ified output!).

from sympy import Matrix

A2 = Matrix(A)
display(A2)

A2.rref()[0]
\[\begin{split}\displaystyle \left[\begin{matrix}3 & 5 & 2\\0 & 1 & 2\\3 & 6 & 1\end{matrix}\right]\end{split}\]
\[\begin{split}\displaystyle \left[\begin{matrix}1 & 0 & 0\\0 & 1 & 0\\0 & 0 & 1\end{matrix}\right]\end{split}\]

Note

Depending on your Python environment, you may have to install SymPy before you can import it, i.e., pip install sympy. Luckily, Colab comes with it pre-installed!

We will also reduce the augmented matrix \([A\ |\ \vec{x}]\). To create this, we will use the np.concatenate(list_of_arr, axis) function from NumPy, where the first argument is the list of matrices/vectors we want to augment, and the axis parameter is the dimension to concatenate along (0 refers to rows = vertical stacking, 1 refers to columns = horizontal stacking).

Ax = Matrix(np.concatenate([A, x], axis=1))
display(Ax)

Ax.rref()[0]
\[\begin{split}\displaystyle \left[\begin{matrix}3 & 5 & 2 & 3\\0 & 1 & 2 & 2\\3 & 6 & 1 & 1\end{matrix}\right]\end{split}\]
\[\begin{split}\displaystyle \left[\begin{matrix}1 & 0 & 0 & \frac{11}{9}\\0 & 1 & 0 & - \frac{2}{3}\\0 & 0 & 1 & \frac{4}{3}\end{matrix}\right]\end{split}\]