The Matrix Transformer
Linear Algebra in Code — Dot Products, Transforms, and the Shape of Space
Course: AI Models From Scratch — Beginner Edition
Part: Course 1 of 3 | Difficulty: Beginner
Estimated Time: 90 minutes
The numpy.linalg Trap
Here is how most tutorials teach matrix transformation:
That works. It is correct. And it teaches you almost nothing.
What it hides: why @ produces that result, what happens when you applyM to 2,500 grid points simultaneously, what the number np.linalg.det(M)
is actually measuring, and — critically — what breaks when the matrix is
singular. The one-liner abstracts away the entire lesson. sklearn'sLinearRegression().fit() does the same thing to least-squares. Keras'sDense(64) does it to weight initialization and matrix multiplication.
This lesson tears the abstraction open. You will implement the
transformation pipeline from scratch, apply it to a live point cloud, and
watch the grid of 2D space physically bend and stretch as you type matrix
entries into the app. By the end, M @ v will not be magic syntax — it
will be a computation you can expand, debug, and modify by hand.
The Failure Mode: Shape Mismatch in Matrix Multiply
Say you have 2,500 grid points you want to transform. The natural instinct:
The rule of matrix multiplication: (m, k) @ (k, n) → (m, n). Your matrixM is (2, 2). Your points array is (2500, 2). The inner dimensions are2 and 2500 — they do not match. NumPy refuses.
The fix requires understanding why the shapes have to align. A 2×2
transformation matrix maps 2D vectors to 2D vectors: it expects its input
as a column vector of shape (2,), or as a batch of column vectors packed
into shape (2, N) — two rows, N columns. Your points array is the
transpose of that. So the correct call is:
Or equivalently:
Both are correct. They express different mental models: the first says
"transform each column vector"; the second says "transform each row vector
using the transposed matrix." Understanding both is what separates someone
who can use NumPy from someone who can reason about it.
There is a second, more insidious failure. What if your matrix is singular?
A singular matrix has determinant zero. It collapses 2D space into a line
or a point — it destroys information, so it cannot be inverted. The app's
"Simulate Error" button loads exactly this matrix. Watch the entire grid
collapse onto a single line. That visual is the definition of determinant = 0.
The ScratchAI Architecture
This lesson has no training loop and no loss function. Instead it has a
transformation pipeline: a pure function that maps a set of 2D points
through a matrix and returns the transformed coordinates. The computation
graph is:
Supporting that core are four derived quantities, each computed directly
from M:
Every function in model.py is pure: it takes arrays in and returns arrays
out, with no hidden state and no side effects. This is not a stylistic
choice — it is the foundation of every well-engineered ML system. The
Streamlit app calls these functions on each widget interaction and re-renders
the Plotly figure. That is the entire architecture.