Affine Spaces
Everything so far insisted on passing through the origin. Subspaces must contain ; linear mappings must send to . That insistence bought a great deal of structure, and it also excluded most of the objects you actually care about: a regression line with a nonzero intercept, a decision boundary that is not through the origin, a neural network layer with a bias.
This section relaxes it, in the smallest possible way: take a subspace and slide it.
What you’ll learn
Section titled “What you’ll learn”- What an affine subspace is — support point plus direction space — and why it is not a subspace.
- The parametric equation, and why the representation is unique once you fix an ordered basis.
- Lines, planes and hyperplanes, and the dimension counting behind each.
- Why the solution set of an inhomogeneous system is exactly an affine subspace.
- Affine mappings, and the fact that every one is a linear mapping followed by a translation.
Intuition: a regression line
Section titled “Intuition: a regression line”Fit a straight line to data and you get . If the line does not pass through the origin, so the set of points on it is not a subspace. It fails the very first test: the origin is not on it.
But it is only barely not a subspace. Take the line through the origin — that is a subspace, a one-dimensional one — and slide it up by . Same direction, shifted position. That is the entire construction, and the terminology follows it:
- the direction space is the subspace you started with,
- the support point is how far you slid it.
flowchart TD S["a subspace U
contains 0, closed"] --> T["slide it by x0"] T --> L["AFFINE SUBSPACE
L = x0 + U"] L --> N1["contains 0 only if x0 is in U
-> otherwise NOT a subspace"] L --> N2["not closed under addition or scaling"] L --> P["parametric equation
x = x0 + lambda1 b1 + ... + lambdak bk"] P --> D1["k = 1: a LINE"] P --> D2["k = 2: a PLANE"] P --> D3["k = n-1: a HYPERPLANE"] L --> SOL["the solution set of Ax = b
is exactly one of these"]
The math
Section titled “The math”Affine subspace
Section titled “Affine subspace”Let be a vector space, , and a subspace. The subset
is an affine subspace of , also called a linear manifold. is the direction or direction space, and is the support point.
The definition excludes whenever . So an affine subspace is not a linear subspace in that case — the book says so explicitly, and it is the whole distinction.
The parametric equation
Section titled “The parametric equation”If is -dimensional and is an ordered basis of , then every can be uniquely described as
with . This is the parametric equation of with directional vectors and parameters .
Uniqueness here is §2.6’s uniqueness-of-coordinates, inherited: once and the ordered basis are fixed, the parameters are determined. Change the support point and every shifts, but for a given choice there is exactly one answer.
Lines, planes, hyperplanes
Section titled “Lines, planes, hyperplanes”| name | parametric equation | in | |
|---|---|---|---|
| 1 | line | needs a support point and 1 direction | |
| 2 | plane | 2 linearly independent directions | |
| hyperplane | independent directions |
The hyperplane row is the one worth internalising, because “hyperplane” is used constantly in machine learning and its dimension is relative:
- In , a hyperplane is a line.
- In , a hyperplane is a plane.
- In , a hyperplane is a 999-dimensional object nobody can picture.
A hyperplane is always one dimension short of the ambient space, which is exactly why it divides it into two halves. That is what makes it a decision boundary, and Chapter 12 builds support vector machines on precisely this — the book even notes in this section that Chapter 12 will refer to such a subspace as a hyperplane.
Inhomogeneous systems are affine subspaces
Section titled “Inhomogeneous systems are affine subspaces”The connection that makes this section retroactively explain §2.3. For and , the solution set of is either empty or an affine subspace of of dimension .
That is §2.3’s particular-plus-general decomposition, renamed:
And the converse holds too: in , every -dimensional affine subspace is the solution of an inhomogeneous system with . Affine subspaces and inhomogeneous systems are two descriptions of one thing, exactly as subspaces and homogeneous systems were in §2.4.
Two special cases worth naming:
- The solution of a single equation with not all zero is a hyperplane in . One equation removes one dimension.
- A homogeneous system’s solution set is a subspace, which the book notes can be thought of as “a special affine space with support point ”.
So subspaces are affine subspaces that happen to be centred. The general notion is the affine one.
Affine mappings
Section titled “Affine mappings”For vector spaces , a linear mapping and a vector , the mapping
is an affine mapping from to , and is the translation vector.
Three properties:
- Every affine mapping is the composition of a linear mapping and a translation: , and the two are uniquely determined.
- The composition of affine mappings is affine.
- Affine mappings keep the geometric structure invariant, and preserve dimension and parallelism.
Worked example by hand
Section titled “Worked example by hand”A line in . Take and direction . The parametric equation is , so
| — the support point | |
Is on this line? We would need with and , giving and respectively. Different values, so no. The line misses the origin and is therefore not a subspace.
Closure fails, concretely. Take the two points at and : and . Their sum is . Is that on the line? Solve , giving ; then the second coordinate would be . Not on the line. Affine subspaces are not closed under addition, which is the second reason they are not subspaces.
An inhomogeneous system, as an affine subspace. Solve in . One particular solution is . The direction space is the null space of , which is two-dimensional, spanned by and . So
Dimension : a plane in , which is also a hyperplane because . Checking : the point is , and ✓.
And the affine-to-linear trick. The affine map on becomes the linear map
on . Check the zero test in the new space: the input is not the zero vector of , so nothing is violated — the trick works precisely because the augmented input never is zero.
See it move
Section titled “See it move”The violet arrow is the support point; the amber arrow is the direction. The white point slides along the affine line as changes. The dashed grey line is the direction space itself — parallel, and passing through the origin.
The two lines are parallel and never meet. The grey one is a subspace — the origin sits on it. The green one is its translate, and no value of ever brings the white point to the origin. That gap is the support point, and it is the whole difference between the two objects.
From scratch
Section titled “From scratch”import numpy as np
# ---- a line as support point plus direction --------------------------
x0 = np.array([-1.5, 1.4])
u = np.array([ 1.6, 0.7])
def on_line(y, tol=1e-9):
"""Is y on the affine line x0 + lambda*u? Solve both coordinates and compare."""
lams = (y - x0) / u
return np.allclose(lams, lams[0], atol=tol), lams
for lam in (-2.0, -1.0, 0.0, 1.0, 2.0):
print(f"lambda={lam:5} y = {x0 + lam * u}")
print("\nis the origin on the line?", on_line(np.zeros(2))[0],
" -> the two lambdas disagree:", np.round(on_line(np.zeros(2))[1], 4))
# ---- affine subspaces are not closed --------------------------------
p, q = x0 + 0.0 * u, x0 + 1.0 * u
print("\ntwo points on the line:", p, q)
print("their sum:", p + q, " on the line?", on_line(p + q)[0])
print("2*p :", 2 * p, " on the line?", on_line(2 * p)[0])
print("-> not closed under addition OR scaling, so not a subspace")
# ---- but the DIRECTION space is a subspace --------------------------
d1, d2 = 1.3 * u, -0.4 * u
print("\ndirections", np.round(d1, 3), "and", np.round(d2, 3))
print("their sum is still a multiple of u:",
np.allclose(np.cross(np.append(d1 + d2, 0), np.append(u, 0)), 0))
# ---- an inhomogeneous system IS an affine subspace -----------------
A = np.array([[1.0, 1.0, 1.0]])
b = np.array([3.0])
xp = np.array([3.0, 0.0, 0.0]) # a particular solution
n1 = np.array([1.0, -1.0, 0.0]) # null-space basis
n2 = np.array([1.0, 0.0, -1.0])
n, r = A.shape[1], np.linalg.matrix_rank(A)
print("\nsolution set of x1+x2+x3 = 3")
print(" particular solution works:", np.allclose(A @ xp, b))
print(" n1, n2 in the null space :", np.allclose(A @ n1, 0), np.allclose(A @ n2, 0))
print(" dimension n - rank :", n - r, "-> a plane in R^3")
print(" which is a hyperplane :", (n - r) == n - 1)
pt = xp + 2 * n1 - 1 * n2
print(" a sample point :", pt, " satisfies the equation:", np.allclose(A @ pt, b))
print(" contains the origin? :", np.allclose(A @ np.zeros(3), b))
# ---- the containment test needs BOTH conditions -------------------
# L = x0 + span(u) inside Ltilde = 0 + span(u)? Directions nest, offset does not.
offset_in_direction = np.allclose(np.cross(np.append(x0 - np.zeros(2), 0),
np.append(u, 0)), 0)
print("\ndirections nest:", True, " offset is a direction:", offset_in_direction)
print("so L is a subset of the direction space?", offset_in_direction)
# ---- affine mapping = linear mapping + translation ----------------
W = np.array([[2.0, -1.0], [0.0, 3.0]])
a = np.array([5.0, -2.0])
phi = lambda v: a + W @ v
print("\nphi(0) =", phi(np.zeros(2)), " == the translation vector:", np.allclose(phi(np.zeros(2)), a))
x, y = np.array([1.0, 2.0]), np.array([-3.0, 0.5])
print("phi(x+y) == phi(x) + phi(y)?", np.allclose(phi(x + y), phi(x) + phi(y)),
" <- fails, so not linear")
print("but phi(x+y) - a == (phi(x)-a) + (phi(y)-a)?",
np.allclose(phi(x + y) - a, (phi(x) - a) + (phi(y) - a)),
" <- the linear part IS linear")
# ---- the augmentation trick: affine in R^n = linear in R^(n+1) ---
W_aug = np.c_[W, a] # absorb the translation
for v in (x, y, np.zeros(2)):
v_aug = np.append(v, 1.0)
print(f" phi({v}) = {phi(v)} augmented: {W_aug @ v_aug}")
print("identical:", all(np.allclose(phi(v), W_aug @ np.append(v, 1.0))
for v in (x, y, np.zeros(2))))
# ---- affine mappings preserve parallelism ------------------------
line_a = [x0 + t * u for t in (-1.0, 0.0, 1.0, 2.0)]
line_b = [x0 + np.array([0.0, 2.0]) + t * u for t in (-1.0, 0.0, 1.0, 2.0)]
img_a = np.array([phi(v) for v in line_a])
img_b = np.array([phi(v) for v in line_b])
dir_a = img_a[1] - img_a[0]
dir_b = img_b[1] - img_b[0]
print("\ntwo parallel lines stay parallel:",
np.allclose(np.cross(np.append(dir_a, 0), np.append(dir_b, 0)), 0))lambda= -2.0 y = [-4.7 0. ]
lambda= -1.0 y = [-3.1 0.7]
lambda= 0.0 y = [-1.5 1.4]
lambda= 1.0 y = [0.1 2.1]
lambda= 2.0 y = [1.7 2.8]
is the origin on the line? False -> the two lambdas disagree: [ 0.9375 -2. ]
two points on the line: [-1.5 1.4] [0.1 2.1]
their sum: [-1.4 3.5] on the line? False
2*p : [-3. 2.8] on the line? False
-> not closed under addition OR scaling, so not a subspace
directions [2.08 0.91] and [-0.64 -0.28]
their sum is still a multiple of u: True
solution set of x1+x2+x3 = 3
particular solution works: True
n1, n2 in the null space : True True
dimension n - rank : 2 -> a plane in R^3
which is a hyperplane : True
a sample point : [ 4. -2. 1.] satisfies the equation: True
contains the origin? : False
directions nest: True offset is a direction: False
so L is a subset of the direction space? False
phi(0) = [ 5. -2.] == the translation vector: True
phi(x+y) == phi(x) + phi(y)? False <- fails, so not linear
but phi(x+y) - a == (phi(x)-a) + (phi(y)-a)? True <- the linear part IS linear
phi([1. 2.]) = [5. 4.] augmented: [5. 4.]
phi([-3. 0.5]) = [-1.5 -0.5] augmented: [-1.5 -0.5]
phi([0. 0.]) = [ 5. -2.] augmented: [ 5. -2.]
identical: True
two parallel lines stay parallel: TrueFour readings.
The origin test gives two different s — and — which is exactly what “not on the line” looks like when you compute it. One coordinate can always be matched; both is the question.
Closure fails on both operations. The sum of two points on the line is off it, and so is twice a point. Two independent reasons this is not a subspace.
The inhomogeneous solution set is a hyperplane, dimension , containing and not containing the origin. §2.3’s general solution, renamed.
The augmentation trick is exact, including at where the affine map returns the translation vector and the augmented linear map returns the same thing — because the augmented input is not the zero vector of .
On real data
Section titled “On real data”Reading the plot
Section titled “Reading the plot”The second figure is why this section exists at all in a machine learning book.
A hyperplane in is defined by one linear equation, and one equation removes exactly one dimension — hence . That deficiency is not a technicality: it is precisely what allows the object to have two sides. Evaluate at a point and the sign tells you which half-space you are in. A lower-dimensional object, like a line in , does not separate anything — you can walk around it.
So classification by a linear model is: place a hyperplane, and read off signs. The offset is what lets the hyperplane sit anywhere rather than being forced through the origin — and forcing it through the origin would make a whole class of problems unsolvable, which is the practical reason the bias term exists.
Chapter 12 then asks the natural follow-up: of all the hyperplanes that separate the data, which is best? Its answer is the one furthest from the nearest points, and §3.8’s projections supply the distance.
Pitfalls
Section titled “Pitfalls”Compare
Section titled “Compare”| subspace | affine subspace | |
|---|---|---|
| contains | yes, required | only if |
| closed under addition | yes | no |
| closed under scaling | yes | no |
| description | ||
| as a solution set | homogeneous | inhomogeneous |
| the associated mapping | linear, | affine, |
| in deep learning | — what layers actually compute |
-
An affine subspace with support point outside its direction space fails how many of the three subspace conditions?
All three. The numerical check on this page shows the sum of two points on the line is off it, and twice a point is off it, in addition to the origin not being on it.
pch.quizShowAnswer
B — All three — no zero vector, and closed under neither addition nor scaling — All three. The numerical check on this page shows the sum of two points on the line is off it, and twice a point is off it, in addition to the origin not being on it.
-
What is a hyperplane in R to the 1000?
Hyperplane means codimension one. One linear equation removes exactly one dimension, and that deficiency is what gives the object two sides — which is what makes it a decision boundary.
pch.quizShowAnswer
B — A 999-dimensional affine subspace — always one dimension less than the ambient space — Hyperplane means codimension one. One linear equation removes exactly one dimension, and that deficiency is what gives the object two sides — which is what makes it a decision boundary.
-
A neural network layer computes W x plus b. Is it linear?
The bias is a translation vector, so the map is affine. The book explicitly notes the literature blurs this. It matters because a stack of affine maps with nothing between them collapses to one affine map.
pch.quizShowAnswer
B — No — it is affine, because it sends the zero vector to b rather than to zero — The bias is a translation vector, so the map is affine. The book explicitly notes the literature blurs this. It matters because a stack of affine maps with nothing between them collapses to one affine map.
-
Why does appending a constant one to the input turn an affine map into a linear one?
The bias becomes an extra matrix column acting on the constant one. The augmented map is genuinely linear in the larger space, and the reason no contradiction arises is that the augmented input can never be zero. This is why design matrices carry a column of ones.
pch.quizShowAnswer
B — Because the translation can be absorbed as an extra column, and the augmented input is never the zero vector so the zero test is not violated — The bias becomes an extra matrix column acting on the constant one. The augmented map is genuinely linear in the larger space, and the reason no contradiction arises is that the augmented input can never be zero. This is why design matrices carry a column of ones.
🧪 Try It Yourself
Section titled “🧪 Try It Yourself”Exercise 1 – Is the origin on the line?
Section titled “Exercise 1 – Is the origin on the line?”Exercise 2 – Closure fails
Section titled “Exercise 2 – Closure fails”Exercise 3 – An inhomogeneous system is a hyperplane
Section titled “Exercise 3 – An inhomogeneous system is a hyperplane”Exercise 4 – An affine map is not linear
Section titled “Exercise 4 – An affine map is not linear”Exercise 5 – The augmentation trick
Section titled “Exercise 5 – The augmentation trick”Recall card
Section titled “Recall card”- An affine subspace is a subspace slid off the origin — support point plus direction space — and it is not a subspace whenever the support point lies outside the direction space.
- It fails all three subspace conditions: no zero vector, and closure under neither addition nor scaling.
- The support point is not canonical. Any point of the set works, so two different descriptions can name the same set.
- The containment test needs two conditions — the direction spaces nest, and the offset between support points is itself a direction.
- The parametric equation gives a unique representation once the support point and an ordered basis of the direction space are fixed.
- A hyperplane is always one dimension short of the ambient space — a line in the plane, a plane in three dimensions — and that codimension of one is what gives it two sides.
- The solution set of an inhomogeneous system is exactly an affine subspace of dimension minus the rank, and conversely every affine subspace is such a solution set.
- A single linear equation defines a hyperplane, because one equation removes one dimension.
- A subspace is an affine subspace with support point at the origin — the affine notion is the more general one.
- Every affine mapping is a linear mapping followed by a translation, uniquely determined, and affine mappings preserve dimension and parallelism.
- A “linear layer” computing Wx + b is affine, not linear — the bias is the translation vector, and the book notes the literature blurs this.
- Appending a constant one absorbs the translation into the matrix, turning an affine map in dimensions into a linear map in . That is why design matrices have a column of ones.
Next: Chapter 2 gave you vectors, matrices and the maps between them, all without a notion of length or angle. Chapter 3 adds the geometry — Analytic Geometry.
pch.coffeeTagline
pch.coffeeCtapch.feedbackHeading
pch.feedbackSubheading