Matrices as Transformations and Matrix Multiplication as Composition
Last module you learned to read a vector as an arrow with a length and a direction, and to compare two arrows with the dot product. Now we stop looking at vectors one at a time and ask a bigger question: what happens to all of space when something pushes on it? That "something" is a matrix, and reading it as a moving grid is the single most useful habit in this module.
By the end of this lesson you can:
- Apply a matrix to a vector with
@in NumPy and predict the result by hand. - Say where the unit grid lands under a given 2x2 matrix.
- Explain why
A @ Bmeans "do B, then do A". - Show with a concrete example that order changes the answer.
A Matrix Is a Set of Landing Instructions
Picture the plane covered in graph paper. A matrix is a rule that grabs every point at once and slides it somewhere new, but with two constraints: straight lines stay straight, and the origin stays put. Transformations like that are called linear transformations.
Here is the trick that makes everything predictable. You only need to know where two arrows land: $\hat{e}_1 = (1,0)$ and $\hat{e}_2 = (0,1)$. Why? Because they are the columns of the matrix.
$$ M = \begin{bmatrix} 1 & 1 \ 0 & 1 \end{bmatrix} $$
Column 1 is $(1,0)$, so $\hat{e}_1$ stays exactly where it is. Column 2 is $(1,1)$, so $\hat{e}_2$ tilts to the right and up. Every other point follows along, because any vector is just a recipe of those two arrows: $v = x\hat{e}_1 + y\hat{e}_2$ lands at $x(\text{column 1}) + y(\text{column 2})$.
That is exactly what M @ v computes.
| Point before | Where it lands |
|---|---|
| (0, 0) | (0, 0) |
| (1, 0) | (1, 0) |
| (0, 1) | (1, 1) |
| (1, 1) | (2, 1) |
The unit square becomes a slanted parallelogram. Same area, same corners count, different shape. This particular matrix is called a shear.
Tip: To sketch any 2x2 transformation, transform the unit square and redraw the grid lines parallel to the new edges. The picture is fully determined by those two columns.
import numpy as np
M = np.array([[1, 1],
[0, 1]])
v = np.array([3, 2])
print(M @ v) # [5 2]
print(M @ np.eye(2)) # the two columns, back again
Try it now
- For $R = \begin{bmatrix} 0 & -1 \ 1 & 0 \end{bmatrix}$, where do $(1,0)$ and $(0,1)$ land? What motion is this?
- Compute
R @ np.array([3, 4])by hand, then check it in NumPy.
Click to reveal the answers
- $(1,0) \to (0,1)$ and $(0,1) \to (-1,0)$. This is a 90 degree counterclockwise rotation.
- $x(\text{column 1}) + y(\text{column 2}) = 3(0,1) + 4(-1,0) = (-4, 3)$.
Composition: Chaining Two Moves
Now suppose you shear the plane, and then rotate it. You could apply two matrices one after the other:
A = np.array([[0, -1], [1, 0]]) # rotate 90 degrees
B = np.array([[1, 1], [0, 1]]) # shear
v = np.array([1, 0])
print(A @ (B @ v)) # do B, then A -> [-2 1]
Two moves in a row is still a single linear transformation, so there must be one matrix that does both at once. That matrix is the product A @ B.
print((A @ B) @ v) # exactly the same answer
print(A @ B) # [[0 -1]
# [1 1]]
flowchart TD
V["📍<br/>v = (1, 0)"] --> B["B<br/>shear"] --> A["A<br/>rotate 90°"] --> R["✅<br/>(-2, 1)"]
In the product A @ B, the right-hand matrix B is the one that runs first. The notation feels backwards at first, but there is a clean reason: writing A @ B @ v should let you group it either way, and A @ (B @ v) reads left to right as "B acts on v, then A acts on the result". Matrix multiplication is defined precisely so that this grouping never changes the answer.
Two more facts fall out of this picture:
- Sizes must line up.
(2,2) @ (2,2)gives(2,2).(2,2) @ (2,)gives(2,). The inner dimensions must match, exactly like feeding a vector of the right length into the transformation. - The identity matrix does nothing.
np.eye(2) @ vreturnsvuntouched. It is the "take no step" transformation.
Try it now
- With
AandBabove, computeB @ A. Is it the same matrix? - Verify by hand that
(B @ A) @ np.array([1, 0])lands somewhere different from(A @ B) @ np.array([1, 0]).
Click to reveal the answers
B @ Ais[[-1, -1], [1, 0]], which is notA @ B. The two orders differ.A @ Bsends $(1,0)$ to $(-2,1)$.B @ Asends $(1,0)$ to $(-1,1)$. Same starting arrow, different destination, because the first move feeds a different input into the second.
Order Matters: A @ B Is Not B @ A
The exercise above is the whole point: matrix multiplication is not commutative. Rotating then shearing is a genuinely different deformation of the plane than shearing then rotating.
Think of it physically. Put on socks, then shoes. The reverse order gives a different result, and no amount of cleverness fixes it. Functions behave the same way: $\sin(2x)$ is not $2\sin(x)$.
A useful sanity check: any matrix times the identity in either order gives back that matrix. A @ np.eye(2) and np.eye(2) @ A both equal A. Pairs that commute are the exception, not the rule.
Rules of Thumb and Traps to Avoid
- Read a matrix by its columns, not its rows. Columns are landing spots for the basis vectors. Rows do something else (they compute dot products), and mixing them up is the most common beginner error.
- Always ask "which one runs first?" In
A @ B @ C, the order of execution is C, then B, then A. - Check shapes before you check values. NumPy will raise a clear error for mismatched shapes, so trust it and read the message.
- Do not assume
A @ B == B @ A. Test it once in code and the lesson sticks. - The origin never moves. If your sketch shows the origin drifting, you have drawn an affine transformation, not a linear one.
What to Take Away
- A matrix is a transformation of space, and its columns record where the basis vectors land.
- Applying a matrix is
M @ v; the grid you draw from the two columns tells you everything. - Matrix multiplication composes transformations:
A @ Bruns B first, then A. - Order matters, identity does nothing, and shapes must line up.
The next lesson, Inverse, Rank, and Span, asks what happens when a transformation can be undone, and what it means when a matrix squashes the whole plane onto a single line.
Front: What do the columns of a matrix tell you? Back: Where the basis vectors land after the transformation.
Front: What does M @ v compute? Back: The image of vector v under the transformation M.
Front: What does A @ B mean as a transformation? Back: Run B first, then run A on the result.
Front: In A @ B @ v, which transformation touches v first? Back: B, because the rightmost matrix acts first.
Front: Why is matrix multiplication defined in that backwards-looking order? Back: So that A @ (B @ v) and (A @ B) @ v always agree.
Front: What does the identity matrix do? Back: Nothing: it leaves every vector exactly where it was.
Front: Is A @ B equal to B @ A in general? Back: No, matrix multiplication is not commutative.
Front: What shape does (2,2) @ (2,) produce in NumPy? Back: A vector of shape (2,).
Front: Which NumPy operator applies a matrix to a vector? Back: The @ operator, as in M @ v.
Front: What is the fastest way to sketch where a 2x2 matrix sends the plane? Back: Transform the unit square corners and redraw the grid along the new edges.
Front: What shape does a linear transformation make of the unit square? Back: A parallelogram, possibly flattened to a segment or a point.
Front: What does [[2,0],[0,1]] do to the plane? Back: Stretches the x direction by 2 and leaves y unchanged.
Front: What does [[0,-1],[1,0]] do to the plane? Back: Rotates every vector 90 degrees counterclockwise.
The columns of a matrix are the landing spots of the _____. In the product A @ B, the transformation _____ runs first. The matrix that changes nothing is the _____. Because matrix multiplication is not _____, A @ B usually differs from B @ A. In NumPy the _____ operator applies a matrix to a vector.