Rank, Nullity & Solution Sets
Stack a clutch of arrows as a matrix's columns and the count of independent directions has a name — rank. Its partner nullity counts the free directions, and the one identity rank + nullity = columns settles, at a glance, whether Ax = b has one solution, infinitely many, or none.
What you'll learn
- Rank = number of independent rows/columns = number of pivots
- Nullity = dimension of the null space (solutions of Ax = 0) = free variables
- The rank-nullity theorem: rank + nullity = number of columns (n)
- Classifying Ax = b as unique, infinitely many, or none via rank
Before you start
The last lesson asked how many independent directions a clutch of arrows holds. Stack
those arrows as the columns of a matrix, and that same count earns a name. It turns out
to answer, at a single glance, the question we ground through elimination two lessons
ago: does Ax = b have one solution, infinitely many, or none? The shortcut is to
count.
Two counts: rank and nullity
The rank of a matrix is the number of genuinely independent rows it holds — equally, the number of pivots elimination eventually produces. A row that is a combination of the others is redundant and adds nothing to the count.
A fact is being smuggled into that sentence, and it deserves a stop because nothing about
it is obvious: the count of independent rows and the count of independent columns are
always the same number. A 3 × 5 matrix has five columns living in 3-D space and three
rows living in 5-D space — different worlds entirely. Yet the two tallies never disagree.
That shared value is the rank, which is why you may compute it whichever way is easier,
and why it can never exceed either dimension: rank ≤ min(m, n).
Its partner is the nullity — the number of free directions, the dimension of the
null space (the set of x solving Ax = 0). If only x = 0 works, the nullity is
0; each independent direction you can slide along and stay at zero adds one. Put
plainly, nullity is just how many free variables the system has.
The rank-nullity theorem
For any m × n matrix A — that is, n columns — the two counts always add up to the
number of columns:
The reason it is exact: each of the n columns is either a pivot column (counted by
rank) or a free column (counted by nullity) — there is no third kind. And that one
equation classifies Ax = b. Write r for the rank of A and assume the system is
consistent (b is actually reachable, so [A | b] has the same rank as A — no
0 = nonzero row):
- One solution when
r = n(full column rank): no free variables, so a single point. - Infinitely many when consistent with
r < n: there aren − rfree variables, a whole family. - No solution when inconsistent:
rank[A | b] > rank A, a contradiction row.
The third branch is the one that stays abstract until you meet it, so meet it now.
Take x + y = 2 alongside 2x + 2y = 5. Here rank A = 1 (the second row is twice
the first). Subtracting 2 × R1 from R2 in the augmented matrix leaves the row
0 = 1, so rank[A | b] = 2 > 1 and there is no solution.
Change that 5 to a 4 and the same subtraction leaves 0 = 0. Now the system is
consistent with r = 1 < n = 2, one free variable, and infinitely many solutions.
Same matrix A, different b, two of the three branches.
A consequence drops straight out. A wide matrix (more columns than rows, m < n)
can have rank at most m, so r ≤ m < n, forcing nullity = n − r > 0. More unknowns
than equations can never pin down a single point.
A worked example, traced
Watch dependent rows collapse. In A, every row is a multiple of [1 2 3]:
A = [ 1 2 3 ] R2 → R2 − 2R1, R3 → R3 − 3R1 [ 1 2 3 ]
[ 2 4 6 ] ──────────────────────────────► [ 0 0 0 ]
[ 3 6 9 ] [ 0 0 0 ]
One pivot survives, so rank A = 1 — the three rows held only one independent
direction.
Now a matrix with a genuine second direction:
B = [ 1 2 3 ] echelon [ 1 2 3 ]
[ 0 1 4 ] ──────────────────────────────► [ 0 1 4 ]
[ 2 5 10] [ 0 0 0 ]
Two pivots, so rank B = 2. With n = 3 columns the theorem hands you the nullity with
no extra work:
nullity = n − rank = 3 − 2 = 1
So Bx = 0 has a one-parameter family of solutions — set the single free variable to
t and every solution is a multiple of one direction.
And a 2-equation, 3-unknown system has a 2 × 3 matrix, so rank ≤ 2 < 3: its
nullity is at least 1. It can never have a unique answer — only infinitely many (if
consistent) or none.
A question to carry forward
For a square matrix, “full rank” is the line between a unique solution and trouble.
It would be handy to test that with a single number, computed once, rather than reducing
the whole matrix every time. Here is the thread onward: is there one number attached to a
square matrix that is non-zero exactly when its rank is full — when its columns are
independent and Ax = b has a unique answer?
In one breath
- Rank = independent rows/columns = number of pivots; nullity = dimension of the null space (
Ax=0) = number of free variables. - Rank-nullity theorem:
rank + nullity = n, wherenis the number of COLUMNS (every column is a pivot or a free column). - Classify
Ax=b(consistent):r = n→ unique;r < n→ infinitely many (n−rfree vars); inconsistent (rank[A|b] > rank A) → none. - A wide matrix (
m < n) has nullity> 0, soAx = 0always has non-zero solutions — more unknowns than equations never gives a unique point. - Nullity is almost always
n − rankstraight from the theorem.
Practice
Quick check
Practice this in an interview
All questionsUnder full column rank, OLS sets the gradient of the squared-error objective to zero, giving the normal equations and the unique coefficient vector β = (XᵀX)⁻¹Xᵀy. In rank-deficient or numerical settings, use the pseudoinverse or a least-squares solver rather than explicitly forming the inverse.
ROWNUMBER assigns a unique sequential integer to every row regardless of ties. RANK assigns the same number to tied rows but skips subsequent positions. DENSERANK also assigns the same number to ties but never skips positions.
Sort the array, then fix one element at a time and run a two-pointer search on the remaining right portion to find pairs that sum to its negation. Careful duplicate-skipping at both the outer loop and the inner pointers is what makes the result unique. Overall complexity is O(n²).
SQL uses three-valued logic: comparing any value to NULL yields UNKNOWN, not FALSE. NOT IN evaluates as NOT (a = v1 OR a = v2 OR ...), so a single NULL in the list makes the entire predicate UNKNOWN for every row, suppressing all results. Use NOT EXISTS or a LEFT JOIN anti-pattern instead.