Mathematical foundations
Matrices and Linear Transformations
Understand how matrices organize datasets, transform coordinates, mix features, and compose the operations inside ML models.
By the end you can
- Interpret a matrix as a dataset, a collection of vectors, and a linear transformation
- Reason about matrix multiplication through shapes, composition, and weighted combinations
- Explain transpose, inverse, and orthogonal transformations without relying on memorized rules
- Diagnose common shape and interpretation errors in ML pipelines
Visual
What a linear transformation can do
Linear transformations rotate, reflect, scale, shear, project, or combine these effects. Whatever geometric word fits the picture, the arithmetic underneath is always the same one. Each output coordinate is a weighted sum of the input coordinates, and the weights are the entries of the matrix. The geometry is a consequence of the weights, not a separate mechanism.
- 1
Input coordinates
A vector describes an object in the source space.
- 2
Weighted mixing
Each output coordinate is a weighted sum of input coordinates.
- 3
Geometric action
The transformation changes lengths, angles, orientation, or dimension according to its structure.
- 4
Output coordinates
The result lives in the target space defined by the matrix rows.
Matrix multiplication is a controlled mixing of coordinates.
Matrices have two lives in machine learning
A matrix may store data, with rows as examples and columns as features. The same mathematical object may also act as a transformation that maps one vector space into another. These two roles meet in expressions such as Xw. The data matrix X collects examples. The vector w defines a linear rule. The product returns one score for each row. Matrix fluency comes from reading shapes and actions together: an expression should tell you what enters, what leaves, and which dimensions are being combined.
The word came before the algebra. In 1850 Sylvester coined “matrix” for an oblong arrangement of terms that gives rise to determinants. The operations arrived eight years later, in a memoir read to the Royal Society in January 1858. MacTutor's history of matrices records what that memoir did: “Cayley in 1858 published Memoir on the theory of matrices which is remarkable for containing the first abstract definition of a matrix”. The same entry lists what was in it — “Cayley gave a matrix algebra defining addition, multiplication, scalar multiplication and inverses”.
The founding paper does not begin from a grid either. Cayley starts from a set of linear equations, X = ax + by + cz, …, and treats the array of coefficients as an object in its own right. The double life this lesson is about — an array of numbers that is also an action — is the move that paper makes on its first page.
A matrix expression is easier to understand when every dimension has a name.
Matrix multiplication means composition
If B maps inputs to an intermediate representation and A maps that representation to outputs, then AB applies B first and A second. Order matters, because the spaces have to line up. Rotating and then stretching can produce a different result from stretching and then rotating.
That non-commutativity is not a caution teachers added later. It is in the founding document, flagged there as the surprise. Writing about the multiplication of matrices in his opening paragraph, Cayley notes that “there is the peculiarity that matrices are not in general convertible”. The first abstract definition of a matrix and the warning that AB need not equal BA sit on the same page of the same paper, read in January 1858.
Shape checking makes the composition visible. For A with shape m×n and B with shape n×p, the shared n is summed out, leaving an m×p transformation.
Case
Seven products instead of eight, and n³ stopped being necessary
The obvious cost of composition is not the true cost. The paper that proved it is three pages long, and its title states the finding flatly: Gaussian elimination is not optimal. Strassen published it in 1969, and its claim is a count. Two n×n matrices can be multiplied in fewer than 4.7·n^log₂7 arithmetic operations, where the usual method needs about 2n³.
The mechanism is one multiplication removed. The recursive block scheme uses 7 sub-block products where the naive one uses 8. That per-level count sets the exponent, so the cost is n^log₂7, with log₂7 ≈ 2.807 instead of 3.
A different research group restated the same count 53 years later, in the sentence in which they beat it: “AlphaTensor finds an algorithm for multiplying 4 × 4 matrices using 47 multiplications in ℤ2, thereby outperforming Strassen's two-level algorithm, which involves 7² = 49 multiplications.” That is AlphaTensor, in Nature, on 5 October 2022. Applied recursively their scheme gives O(N^2.778) in ℤ₂, below Strassen's 2.807.
The number is still moving. Three days after that publication, Kauers and Moosbauer posted a reply whose abstract begins: “In response to a recent Nature article which announced an algorithm for multiplying $5\times5$-matrices over $\mathbb{Z}_2$ with only 96 multiplications, two fewer than the previous record, we present an algorithm that does the job with only 95 multiplications.” The 5×5 record over ℤ₂ fell twice inside a single week. First to 96, then to 95.
Figure
Example
A dense layer as a matrix transformation
Consider y = Wx + b with x in ℝ³ and y in ℝ². The conventions below are not this lesson's house style. They are what the two dominant frameworks document. The PyTorch 2.9 documentation describes its dense layer this way: “Applies an affine linear transformation to the incoming data: y = xA^T + b”. Affine, not linear, in the library's own text. It stores the weight with shape (out_features, in_features) and the bias with shape (out_features). Keras documents the same layer as “output = activation(dot(input, kernel) + bias)”, taking input shape (batch_size, input_dim) to output shape (batch_size, units). A different organisation, the same batch × features convention, with the transpose absorbed into the kernel orientation.
- Shape: W must have shape 2×3, because it maps three input coordinates to two outputs. That is exactly PyTorch's (out_features, in_features) storage order — outputs first.
- Rows: Each row of W holds the weights used to compute one output coordinate. The bias carries one entry per row, its shape being (out_features).
- Columns: Each column shows how one input coordinate contributes across both outputs. In the Keras phrasing, it is the column of the kernel that dot(input, kernel) consumes.
- Bias: b translates the result, so the full affine map is not linear in the strict mathematical sense. That is why PyTorch's own sentence says “affine linear transformation” rather than linear.
- Batch form: A batch X with shape batch×3 is commonly multiplied by Wᵀ to produce batch×2 outputs. PyTorch's worked example prints it: nn.Linear(20, 30) applied to an input of shape (128, 20) returns torch.Size([128, 30]). Keras states the same rule as (batch_size, input_dim) → (batch_size, units).
Key idea
Do not compute an inverse merely because the notation contains one
Formulas often write A⁻¹b. The vendor's own reference page tells you not to read that as an instruction. Under Tips, the MATLAB documentation for inv says: “It is seldom necessary to form the explicit inverse of a matrix.”
The same page measures what the habit costs. Take a 500-by-500 badly conditioned matrix, condition number 1e10. There, x = inv(A)*b leaves a residual error of 5.1611e-07, while x = A\b leaves 3.9285e-15. Same matrix, same right-hand side, roughly eight orders of magnitude between the two answers.
Inverting a matrix is also the first of the “Seven Sins of Numerical Linear Algebra”, a list Nicholas J. Higham published in 2022. Solving a linear system by LU factorization with partial pivoting is faster and more accurate than inverting A — which itself has to be done by LU factorization. He also names the rare cases where A⁻¹ is genuinely the thing you want: the diagonal of an inverse covariance matrix, some matrix-function algorithms. That is what makes this a rule rather than a prohibition.
An inverse can exist mathematically while being unreliable numerically. If small input changes create large solution changes, the system is ill-conditioned. Treat inverse notation as a statement about the solution, not as an order to compute one.
Solve systems; do not reflexively materialize inverses.
Comparison
Transpose, inverse, and pseudoinverse answer different questions
These operations are often grouped together, but they answer different questions and carry different requirements. The pseudoinverse even carries two dates, because being defined and being computable were separate achievements ten years apart.
The transpose Aᵀ is always defined. It turns m×n into n×m, swaps rows and columns, reverses the direction of an inner-product map, and shows up in gradients and normal equations. It is not an inverse in general. The ordinary inverse A⁻¹ exists only under specific conditions — a square matrix of full rank — and stays numerically fragile when A is ill-conditioned.
The pseudoinverse A⁺ is the generalization, and its reach is the point of the paper that defined it. Penrose set it out in 1955 as the unique solution of a set of equations, and the abstract states the scope: “This generalized inverse exists for any (possibly rectangular) matrix whatsoever with complex elements.”
Existence is not an algorithm. Ten years later, in 1965, Golub and Kahan gave the numerically stable route: bidiagonalize, diagonalize, then form A⁺ = VΣ⁺U* by replacing each positive singular value with its reciprocal. Their abstract offers “the use of the pseudo-inverse … to solve least squares problems in a way which dampens spurious oscillation and cancellation”. That reciprocal is also where the fragility lives, because a positive singular value close to zero becomes a very large reciprocal. So A⁺ produces least-squares or minimum-norm solutions, is sensitive to small singular values, and still makes no lost information recoverable.
Transpose Aᵀ
Swaps rows and columns and reverses the direction of an inner-product map.
- Always defined
- Turns m×n into n×m
- Appears in gradients and normal equations
- Not an inverse in general
Inverse A⁻¹
Undoing map for a square, nonsingular transformation.
- Exists only under specific conditions
- Requires full rank in a square matrix
- Numerically fragile when A is ill-conditioned
- Usually avoided as an explicit computation
Pseudoinverse A⁺
Generalized solution operator for rectangular or rank-deficient systems.
- Defined through the SVD
- Produces least-squares or minimum-norm solutions
- Does not make lost information recoverable
- Sensitive to small singular values
Analogy
A mixing desk sets how much of each input reaches each output
At a mixing desk, a sound engineer receives several input microphones and controls how much of each microphone enters each output channel. The fader settings form a matrix. Every output is a weighted mixture of inputs. Connecting one desk to another corresponds to multiplying their matrices, because the second desk acts on the first desk's outputs. The order of the two desks matters, for the same reason Cayley called non-commutativity the peculiarity of the subject.
The desk has no fader for a nonlinear activation. A sequence of purely linear layers collapses into one matrix. Nonlinearities create genuinely new behavior.
A matrix specifies how every output channel mixes the available input directions.
Key idea
Treat dimensions as a type checker
If A has shape m×n and x has shape n, then Ax has shape m. The inner dimensions must match, because the columns of A describe the coordinates consumed from x. A product that happens to run after broadcasting or reshaping can still violate that semantic contract. Write the dimensions beside every factor before simplifying a matrix expression.
The failure this prevents has a name in the research literature and a measured frequency. A 2018 empirical study of TensorFlow program bugs defines it: “A bug spotted in computation graph construction phase when the shape of the input tensor does not match what it is expected is called an unaligned tensor bug.” Its five authors classified 175 real TensorFlow bugs — 87 from Stack Overflow and 88 from GitHub — and attributed 24 of them to that single cause. That is 15 from Stack Overflow plus 9 from GitHub, or 13.7% of the corpus.
Another group reached the same conclusion independently in 2019, on a larger corpus: 2,716 Stack Overflow posts and 500 GitHub bug-fix commits across five libraries. In their Stack Overflow data, unaligned tensor is the root cause of 16% of TensorFlow bugs, 12% of Keras, 28% of Torch, 7% of Theano and 3% of Caffe. In their GitHub bug-fix commits the same root cause accounts for 0% (TensorFlow), 5% (Keras), 20% (Torch), 34% (Theano) and 19% (Caffe). Two corpora, two research groups, one failure mode. A written-out dimension catches it before any numerical value can hide it.
Matrix dimensions are part of the meaning, not merely an implementation detail.
Steps
How to read a matrix expression
This routine prevents most dimension errors and many conceptual ones. Label every axis with what it represents. State the source space and the target space of each matrix. Read the multiplication right to left, so you know which transformation acts first and which dimension is summed. Ask what the map preserves — lengths, angles, rank, information. Only then choose the numerical operation that matches the mathematical goal: multiplication, factorization, or a solver.
1. Label every axis
Write what each dimension represents: examples, features, classes, tokens, or hidden units.
2. Check the map
State the source space and target space of each matrix.
3. Read multiplication right to left
Describe which transformation acts first and which dimensions are summed.
4. Track preserved structure
Ask whether lengths, angles, rank, or information are changed.
5. Choose the numerical operation
Use multiplication, factorization, or a solver that matches the mathematical goal.
Key takeaways
- Matrices serve both as data containers and as transformations between vector spaces — the double life Cayley's 1858 memoir set up when it read a linear system as an array of coefficients.
- Matrix multiplication composes transformations, so order and shape carry mathematical meaning. The opening paragraph of that memoir already calls non-commutativity “the peculiarity” of the subject.
- Rows describe output rules, while columns describe how input directions contribute to outputs — the storage order PyTorch documents as (out_features, in_features).
- Transpose, inverse, and pseudoinverse are distinct operations with different conditions and uses. Penrose defined the pseudoinverse in 1955; Golub and Kahan made it computable in 1965.
- Affine maps add a translation to a linear transformation and therefore need not preserve the origin, which is why PyTorch calls its dense layer affine rather than linear.
- Numerical implementations should solve systems or use factorizations rather than form explicit inverses by habit: 5.1611e-07 against 3.9285e-15 on the same 500-by-500 system.