import numpy as np
A = np.array([
[1, 2],
[3, 4]
], dtype=float)
B = np.array([
[2, 1],
[0, -1]
], dtype=float)
A @ Barray([[ 2., -1.],
[ 6., -1.]])
In the first three chapters, matrices appeared as containers for linear systems. But matrices are much more than storage devices.
A matrix can also represent a process:
\[ x \longmapsto Ax. \]
If one matrix represents one process and another matrix represents another process, then matrix multiplication represents doing one process after another.
This chapter develops the algebra of matrices:
The key idea is:
Matrix multiplication is the algebra of composition.
After studying this chapter, you should be able to:
Let
\[ A= \begin{bmatrix} a_{11}&a_{12}&\cdots&a_{1n}\\ a_{21}&a_{22}&\cdots&a_{2n}\\ \vdots&\vdots&\ddots&\vdots\\ a_{m1}&a_{m2}&\cdots&a_{mn} \end{bmatrix} \]
and
\[ x= \begin{bmatrix} x_1\\ x_2\\ \vdots\\ x_n \end{bmatrix}. \]
Then
\[ Ax= \begin{bmatrix} a_{11}x_1+a_{12}x_2+\cdots+a_{1n}x_n\\ a_{21}x_1+a_{22}x_2+\cdots+a_{2n}x_n\\ \vdots\\ a_{m1}x_1+a_{m2}x_2+\cdots+a_{mn}x_n \end{bmatrix}. \]
If \(A\) is \(m\times n\) and \(x\) is \(n\times 1\), then
\[ Ax \]
is an \(m\times 1\) vector.
In dimensions,
\[ \underbrace{A}_{m\times n} \underbrace{x}_{n\times 1} = \underbrace{Ax}_{m\times 1}. \]
Suppose \(B\) has columns
\[ B= \begin{bmatrix} |&|&&|\\ b_1&b_2&\cdots&b_p\\ |&|&&| \end{bmatrix}. \]
Then the product \(AB\) is defined by multiplying \(A\) by each column of \(B\):
\[ AB= \begin{bmatrix} |&|&&|\\ Ab_1&Ab_2&\cdots&Ab_p\\ |&|&&| \end{bmatrix}. \]
This is often the cleanest way to understand matrix multiplication.
If \(A\) is \(m\times n\) and \(B\) is \(n\times p\), then every column \(b_j\) of \(B\) is in \(\mathbb{R}^n\), so \(Ab_j\) is in \(\mathbb{R}^m\). Therefore \(AB\) is \(m\times p\).
In dimensions,
\[ \underbrace{A}_{m\times n} \underbrace{B}_{n\times p} = \underbrace{AB}_{m\times p}. \]
The product \(AB\) is defined exactly when the number of columns of \(A\) equals the number of rows of \(B\).
The entry in row \(i\), column \(j\) of \(AB\) is the dot product of row \(i\) of \(A\) with column \(j\) of \(B\).
If
\[ C=AB, \]
then
\[ c_{ij}=a_{i1}b_{1j}+a_{i2}b_{2j}+\cdots+a_{in}b_{nj}. \]
Equivalently,
\[ c_{ij}=\sum_{k=1}^n a_{ik}b_{kj}. \]
This formula is important, but do not memorize it without meaning. It says:
row of \(A\) times column of \(B\) gives one entry of \(AB\).
Let
\[ A= \begin{bmatrix} 1&2\\ 3&4 \end{bmatrix}, \qquad B= \begin{bmatrix} 2&1\\ 0&-1 \end{bmatrix}. \]
Then
\[ AB= \begin{bmatrix} 1(2)+2(0)&1(1)+2(-1)\\ 3(2)+4(0)&3(1)+4(-1) \end{bmatrix} = \begin{bmatrix} 2&-1\\ 6&-1 \end{bmatrix}. \]
Now compute \(BA\):
\[ BA= \begin{bmatrix} 2&1\\ 0&-1 \end{bmatrix} \begin{bmatrix} 1&2\\ 3&4 \end{bmatrix} = \begin{bmatrix} 2(1)+1(3)&2(2)+1(4)\\ 0(1)+(-1)(3)&0(2)+(-1)(4) \end{bmatrix} = \begin{bmatrix} 5&8\\ -3&-4 \end{bmatrix}. \]
So
\[ AB\ne BA. \]
This is one of the most important differences between matrix algebra and ordinary number algebra.
For real numbers,
\[ ab=ba. \]
For matrices, usually
\[ AB\ne BA. \]
Sometimes \(AB\) and \(BA\) are both defined but unequal.
Sometimes \(AB\) is defined but \(BA\) is not.
Let
\[ A= \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix} \]
and
\[ B= \begin{bmatrix} 1\\ 0\\ -1 \end{bmatrix}. \]
Then \(A\) is \(2\times 3\) and \(B\) is \(3\times 1\), so
\[ AB \]
is defined and has size \(2\times 1\).
But
\[ BA \]
would require multiplying a \(3\times 1\) matrix by a \(2\times 3\) matrix. The inner dimensions \(1\) and \(2\) do not match, so \(BA\) is not defined.
Do not write \(AB=BA\) unless you have checked it. Matrix multiplication is not usually commutative.
The identity matrix acts like the number \(1\).
If \(A\) is \(m\times n\), then
\[ I_mA=A \]
and
\[ AI_n=A. \]
The sizes matter:
Example:
\[ I_2 \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix} = \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix}, \]
and
\[ \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix} I_3 = \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix}. \]
If sizes are compatible, multiplying by a zero matrix gives a zero matrix:
\[ A0=0, \]
\[ 0A=0. \]
Again, the sizes must match.
For example, if \(A\) is \(2\times 3\), then
\[ A0_{3\times 4}=0_{2\times 4}. \]
The output size is determined by the outside dimensions.
When the dimensions are compatible, matrix multiplication satisfies:
\[ (AB)C=A(BC). \]
This is very important. It means we may write
\[ ABC \]
without ambiguity.
\[ A(B+C)=AB+AC, \]
and
\[ (A+B)C=AC+BC. \]
For a scalar \(c\),
\[ c(AB)=(cA)B=A(cB). \]
Usually,
\[ AB\ne BA. \]
If \(A\) is square, then powers of \(A\) are defined:
\[ A^2=AA, \]
\[ A^3=AAA, \]
and in general,
\[ A^k=\underbrace{AA\cdots A}_{k\text{ times}}. \]
Matrix powers represent repeated application of the same linear process.
For example, if
\[ x_{t+1}=Ax_t, \]
then
\[ x_1=Ax_0, \]
\[ x_2=Ax_1=A^2x_0, \]
and
\[ x_k=A^kx_0. \]
This idea will return in the chapters on eigenvalues, diagonalization, Markov chains, and dynamical systems.
Let
\[ D= \begin{bmatrix} 2&0\\ 0&3 \end{bmatrix}. \]
Then
\[ D^2= \begin{bmatrix} 4&0\\ 0&9 \end{bmatrix}, \]
and
\[ D^3= \begin{bmatrix} 8&0\\ 0&27 \end{bmatrix}. \]
In general,
\[ D^k= \begin{bmatrix} 2^k&0\\ 0&3^k \end{bmatrix}. \]
Diagonal matrices are easy to power because each coordinate is scaled independently.
A diagonal matrix has the form
\[ D= \begin{bmatrix} d_1&0&\cdots&0\\ 0&d_2&\cdots&0\\ \vdots&\vdots&\ddots&\vdots\\ 0&0&\cdots&d_n \end{bmatrix}. \]
Multiplying by \(D\) scales the coordinates:
\[ D \begin{bmatrix} x_1\\ x_2\\ \vdots\\ x_n \end{bmatrix} = \begin{bmatrix} d_1x_1\\ d_2x_2\\ \vdots\\ d_nx_n \end{bmatrix}. \]
Thus diagonal matrices are computationally simple and geometrically meaningful.
They stretch or shrink along coordinate axes.
An \(n\times n\) matrix is upper triangular if all entries below the main diagonal are zero.
Example:
\[ U= \begin{bmatrix} 2&1&4\\ 0&3&-1\\ 0&0&5 \end{bmatrix}. \]
An \(n\times n\) matrix is lower triangular if all entries above the main diagonal are zero.
Example:
\[ L= \begin{bmatrix} 2&0&0\\ 1&3&0\\ 4&-1&5 \end{bmatrix}. \]
Triangular matrices are important because triangular systems are easy to solve.
For an upper triangular system, we use back substitution.
For a lower triangular system, we use forward substitution.
Solve
\[ \begin{cases} x_1+2x_2-x_3=4,\\ x_2+3x_3=5,\\ x_3=1. \end{cases} \]
Start from the bottom:
\[ x_3=1. \]
Then
\[ x_2+3(1)=5, \]
so
\[ x_2=2. \]
Finally,
\[ x_1+2(2)-1=4, \]
so
\[ x_1=1. \]
Thus
\[ (x_1,x_2,x_3)=(1,2,1). \]
Triangular structure makes the solution straightforward.
Suppose
\[ T(x)=Bx \]
and
\[ S(y)=Ay. \]
If we first apply \(T\) and then apply \(S\), we get
\[ S(T(x))=A(Bx). \]
By associativity,
\[ A(Bx)=(AB)x. \]
Therefore the matrix of the combined transformation is
\[ AB. \]
This explains the order of multiplication:
\(AB\) means first apply \(B\), then apply \(A\).
In the product \(ABx\), the vector \(x\) is first multiplied by \(B\), then the result is multiplied by \(A\).
Let
\[ P= \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} \]
be projection onto the \(x\)-axis, and let
\[ R= \begin{bmatrix} 1&0\\ 0&-1 \end{bmatrix} \]
be reflection across the \(x\)-axis.
Then
\[ PR= \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} \begin{bmatrix} 1&0\\ 0&-1 \end{bmatrix} = \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} =P. \]
Also,
\[ RP= \begin{bmatrix} 1&0\\ 0&-1 \end{bmatrix} \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} = \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} =P. \]
In this special case,
\[ PR=RP. \]
Why? Projecting onto the \(x\)-axis removes the \(y\)-component, and reflecting across the \(x\)-axis only changes the \(y\)-component. Once the \(y\)-component is gone, reflection has no visible effect.
Not all geometric transformations commute.
Let
\[ P= \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} \]
be projection onto the \(x\)-axis, and let
\[ Q= \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix} \]
be counterclockwise rotation by \(90^\circ\).
Compute
\[ PQ= \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix} = \begin{bmatrix} 0&-1\\ 0&0 \end{bmatrix}. \]
But
\[ QP= \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix} \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} = \begin{bmatrix} 0&0\\ 1&0 \end{bmatrix}. \]
Thus
\[ PQ\ne QP. \]
The order of operations matters:
These produce different results.
Sometimes a large matrix can be divided into smaller blocks.
For example,
\[ A= \begin{bmatrix} A_{11}&A_{12}\\ A_{21}&A_{22} \end{bmatrix}, \qquad B= \begin{bmatrix} B_{11}&B_{12}\\ B_{21}&B_{22} \end{bmatrix}. \]
If the block sizes are compatible, then
\[ AB= \begin{bmatrix} A_{11}B_{11}+A_{12}B_{21}&A_{11}B_{12}+A_{12}B_{22}\\ A_{21}B_{11}+A_{22}B_{21}&A_{21}B_{12}+A_{22}B_{22} \end{bmatrix}. \]
This looks like ordinary \(2\times 2\) multiplication, but each entry is a block.
Block multiplication is useful in computation because large matrices are often processed in pieces.
If \(A\) is \(m\times n\) and \(B\) is \(n\times p\), then computing \(AB\) directly requires many multiplications and additions.
There are \(mp\) entries in \(AB\). Each entry requires about \(n\) multiplications and additions.
So the direct cost is approximately proportional to
\[ mnp. \]
For large matrices, matrix multiplication can be expensive. Modern numerical linear algebra studies how to perform these computations accurately and efficiently.
In AI and data science, large matrix multiplications are everywhere. They are the basic computational operation behind neural network layers, linear regression, PCA, attention mechanisms, and many optimization algorithms.
import numpy as np
A = np.array([
[1, 2],
[3, 4]
], dtype=float)
B = np.array([
[2, 1],
[0, -1]
], dtype=float)
A @ Barray([[ 2., -1.],
[ 6., -1.]])
The symbol @ is Python’s matrix multiplication operator.
Now compare with \(BA\):
B @ Aarray([[ 5., 8.],
[-3., -4.]])
Usually the results are different.
A = np.array([
[1, 2, 3],
[4, 5, 6]
], dtype=float)
x = np.array([1, 0, -1], dtype=float)
A @ xarray([-2., -2.])
This works because \(A\) is \(2\times 3\) and \(x\) has \(3\) entries.
Now try a vector with the wrong size:
y = np.array([1, 0], dtype=float)
# Uncomment the next line to see the dimension mismatch error.
# A @ yThe product is not defined because the inner dimensions do not match.
A = np.array([
[1, 1],
[1, 0]
], dtype=float)
A2 = A @ A
A3 = A @ A @ A
A2, A3(array([[2., 1.],
[1., 1.]]),
array([[3., 2.],
[2., 1.]]))
For repeated powers, NumPy provides:
np.linalg.matrix_power(A, 5)array([[8., 5.],
[5., 3.]])
This is useful for repeated processes.
Consider the recurrence
\[ x_{t+1}=Ax_t, \]
where
\[ A= \begin{bmatrix} 0.8&0.3\\ 0.2&0.7 \end{bmatrix}. \]
Start with
\[ x_0= \begin{bmatrix} 100\\ 0 \end{bmatrix}. \]
A = np.array([
[0.8, 0.3],
[0.2, 0.7]
], dtype=float)
x = np.array([100, 0], dtype=float)
history = [x]
for k in range(10):
x = A @ x
history.append(x)
np.array(history)array([[100. , 0. ],
[ 80. , 20. ],
[ 70. , 30. ],
[ 65. , 35. ],
[ 62.5 , 37.5 ],
[ 61.25 , 38.75 ],
[ 60.625 , 39.375 ],
[ 60.3125 , 39.6875 ],
[ 60.15625 , 39.84375 ],
[ 60.078125 , 39.921875 ],
[ 60.0390625, 39.9609375]])
This kind of model appears in population movement, Markov chains, ranking algorithms, and dynamical systems. We will return to it later with eigenvalues.
Matrix multiplication is not entrywise multiplication.
In general,
\[ AB \]
is not obtained by multiplying corresponding entries.
Always check the inner dimensions:
\[ (m\times n)(n\times p)=(m\times p). \]
Matrix multiplication is usually not commutative.
The product \(ABx\) means \(B\) acts first, then \(A\) acts.
The power \(A^2\) is defined only when \(A\) is square.
If \(A\) is \(m\times n\), then
\[ I_mA=A \]
and
\[ AI_n=A. \]
The identity sizes are different unless \(m=n\).
Matrix multiplication is defined when inner dimensions match:
\[ (m\times n)(n\times p)=(m\times p). \]
The entry formula is
\[ (AB)_{ij}=\sum_{k=1}^n a_{ik}b_{kj}. \]
The column interpretation is
\[ AB= \begin{bmatrix} Ab_1&Ab_2&\cdots&Ab_p \end{bmatrix}. \]
Matrix multiplication is associative and distributive, but not usually commutative.
The identity matrix acts like \(1\):
\[ I_mA=A,\qquad AI_n=A. \]
Matrix powers represent repeated application of a square matrix.
Matrix multiplication represents composition:
\[ A(Bx)=(AB)x. \]
The order matters: in \(ABx\), \(B\) acts first and \(A\) acts second.
For each product, determine whether it is defined. If it is defined, give the size of the result.
Compute each product if it is defined.
\[ \begin{bmatrix} 1&2\\ 3&4 \end{bmatrix} \begin{bmatrix} 2&1\\ 0&-1 \end{bmatrix} \]
\[ \begin{bmatrix} 2&1\\ 0&-1 \end{bmatrix} \begin{bmatrix} 1&2\\ 3&4 \end{bmatrix} \]
\[ \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix} \begin{bmatrix} 1\\ 0\\ -1 \end{bmatrix} \]
\[ \begin{bmatrix} 1&2\\ 3&4 \end{bmatrix} \begin{bmatrix} 1&0&2\\ 0&1&3 \end{bmatrix} \]
Find \(AB\) and \(BA\).
\[ A= \begin{bmatrix} 1&1\\ 0&1 \end{bmatrix}, \qquad B= \begin{bmatrix} 1&0\\ 1&1 \end{bmatrix}. \]
\[ A= \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix}, \qquad B= \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix}. \]
Let
\[ A= \begin{bmatrix} 1&2&3\\ 4&5&6 \end{bmatrix}. \]
Compute:
Compute \(A^2\) and \(A^3\).
\[ A= \begin{bmatrix} 2&0\\ 0&3 \end{bmatrix} \]
\[ A= \begin{bmatrix} 1&1\\ 0&1 \end{bmatrix} \]
\[ A= \begin{bmatrix} 0&1\\ 1&0 \end{bmatrix} \]
Solve by substitution.
\[ \begin{cases} x_1+2x_2-x_3=4,\\ x_2+3x_3=5,\\ x_3=1. \end{cases} \]
\[ \begin{cases} 2x_1=6,\\ x_1+3x_2=8,\\ 4x_1-x_2+x_3=10. \end{cases} \]
Let
\[ P= \begin{bmatrix} 1&0\\ 0&0 \end{bmatrix} \]
and
\[ Q= \begin{bmatrix} 0&-1\\ 1&0 \end{bmatrix}. \]
\[ x= \begin{bmatrix} 1\\ 2 \end{bmatrix}. \]
Create two \(2\times 2\) matrices \(A\) and \(B\) in NumPy. Compute \(AB\) and \(BA\).
Find an example where \(AB=BA\).
Find an example where \(AB\) is defined but \(BA\) is not defined.
Use np.linalg.matrix_power to compute \(A^{10}\) for
\[ A= \begin{bmatrix} 1&1\\ 1&0 \end{bmatrix}. \]
\[ A= \begin{bmatrix} 0.8&0.3\\ 0.2&0.7 \end{bmatrix} \]
and several different initial vectors \(x_0\).
Matrix multiplication is one of the central operations of modern computation. A neural network layer multiplies an input vector by a weight matrix. A data transformation multiplies a data matrix by another matrix. A recommendation system, a graph algorithm, or a dimensionality reduction method may require many large matrix products. Understanding matrix multiplication as both computation and composition is essential for understanding linear algebra in the age of AI.