Vector spaces & subspaces
Define a vector space from its axioms, see that the only property we ever actually use is closure under linear combination, and learn the one-line test that decides whether a subset is a subspace.
Everything in this course, a dataset, a layer of a network, a gradient, lives in a vector space. Before using that word freely we should pin down exactly what it means, and notice that out of the long list of axioms, almost all of our work leans on a single consequence: you can take linear combinations and stay inside the space.
What problem are we solving?
We want a setting where "add two things" and "scale a thing by a number" both make sense and behave the way arrows in the plane behave. Points in work; so do polynomials, and so do functions. Rather than re-derive facts for each case, we name the shared structure once and prove things there.
The definition
A vector space over the real numbers is a set together with two operations, addition and scalar multiplication (with ), such that the following hold for all and all [1, 2]:
The list looks long, but read it once and move on. Its only purpose is to guarantee that the next definition behaves sensibly.
The one move: linear combinations
A linear combination of vectors is any expression
Axioms (1) through (8) are exactly what we need to know that this expression is again a well-defined element of , no matter how we group or reorder the terms. This is the property the rest of the course actually uses. When we later write a model output as a weighted sum of features, or a gradient as a combination of per-example gradients, we are relying on nothing more than closure under linear combination.
Subspaces
Often we care about a smaller set sitting inside that is itself a vector space under the same operations. Call a subspace if it is a vector space in its own right. Checking all eight axioms again would be tedious, so we prove a shortcut.
Subspace test. A nonempty subset is a subspace if and only if it is closed under addition and scalar multiplication[3]:
Proof. () If is a subspace it is closed under its own operations by definition, so both conditions hold.
() Suppose the two closure conditions hold and is nonempty; we must recover the axioms. Take any (one exists since ).
- Zero vector. Scalar-multiply by : closure under scalar multiplication gives . And (a one-line consequence of axiom (8): , then subtract ). So .
- Additive inverses. Scalar-multiply by : , and (again from the axioms). So every element of has its inverse in .
- Remaining axioms. Commutativity, associativity, and the scalar laws hold for all elements of , so in particular they hold for the elements of .
So , being closed and containing and inverses while inheriting the rest, is a vector space.
The test collapses eight checks into two. A quick consequence, proved the same way: the intersection of two subspaces is a subspace (if lie in both, so does and , since each subspace is closed).
Examples and one non-example
- The line is a subspace: adding two such points or scaling one keeps the relation.
- The set of degree- polynomials is a subspace of all polynomials.
- The line is not a subspace: it misses the origin (), so it fails the test immediately. Any set not containing is disqualified.
Check it on arrays
The subspace test is something you can probe numerically: take the plane spanned by two vectors in , form a random linear combination of points already in it, and confirm the result still satisfies the plane's defining equation (its normal vector stays orthogonal to it).
import numpy as np
# A plane through the origin in R^3: span of b1, b2. Its normal is b1 x b2.
b1 = np.array([1.0, 0.0, 2.0])
b2 = np.array([0.0, 1.0, -1.0])
normal = np.cross(b1, b2)
# Two points already in the subspace (linear combinations of b1, b2):
u = 3.0 * b1 - 2.0 * b2
v = -1.0 * b1 + 4.0 * b2
# A further linear combination of them:
w = 0.7 * u + 5.0 * v
# Closure check: w still lies in the plane <=> normal . w == 0
for name, vec in [("u", u), ("v", v), ("w", w)]:
print(f"normal . {name} = {np.dot(normal, vec):.12f}") # all ~0Every point built as a linear combination of stays on the plane. That is the subspace test confirmed: closed under addition and scaling. A point off the plane (say ) would give a nonzero dot product, landing outside .
Exercises
Exercise 1. Decide whether is a subspace of , using only the two-condition subspace test.
Solution
Step 1. Check nonempty: satisfies , so and is nonempty.
Step 2. Closure under addition. Take and in , so and . Their sum has coordinate total , so .
Step 3. Closure under scalar multiplication. For and , the total is , so .
Both conditions hold on a nonempty set, so is a subspace. It is the plane through the origin with normal .
Exercise 2. Give a subset of that is closed under scalar multiplication but not under addition, proving it fails exactly one condition.
Solution
Step 1. Take , the union of the two coordinate axes.
Step 2. Closure under scalar multiplication holds: if then , so for every scalar .
Step 3. Closure under addition fails. The point lies on the -axis and lies on the -axis, so both are in . Their sum has product , so .
A single counterexample to addition is enough; is not a subspace even though it passes the scalar-multiplication condition and contains .
Exercise 3 (code). The subspace test predicts that any linear combination of points in (the solution set of a homogeneous system) is again in . Verify this numerically for a random matrix : build two solutions, take a random linear combination, and assert it still solves .
Solution
The null space of is a subspace, so closure must hold to machine precision. Two null-space vectors come from the right singular vectors of the smallest singular values (here the last two columns of , since a matrix has nullity at least ).
import numpy as np
rng = np.random.default_rng(0)
A = rng.normal(size=(3, 5))
# Right singular vectors for the (near-)zero singular values span the null space.
_, _, Vt = np.linalg.svd(A)
x1 = Vt[-1] # A @ x1 ~ 0
x2 = Vt[-2] # A @ x2 ~ 0
# A random linear combination of two null-space vectors:
a, b = rng.normal(size=2)
w = a * x1 + b * x2
assert np.allclose(A @ x1, 0, atol=1e-12)
assert np.allclose(A @ x2, 0, atol=1e-12)
assert np.allclose(A @ w, 0, atol=1e-12) # closure under linear combination
print("max |A @ w| =", np.max(np.abs(A @ w)))The combination satisfies by linearity of , which is the subspace test at work: the solution set of a homogeneous system is closed under linear combination.
With the container defined, the next lesson asks the sharper question: how many vectors do we actually need to generate a space, and when is a set of them non-redundant. That is span, independence, basis, and dimension.
References
- [1]Axler, S. (2015). Linear Algebra Done Right (3rd ed.), ch. 1. Springer. The axiomatic, basis-free development of vector spaces (doi:10.1007/978-3-319-11080-6).↩
- [2]Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep Learning, ch. 2 (Linear Algebra). MIT Press. The machine-learning reader's review of the same objects.↩
- [3]Strang, G. (2016). Introduction to Linear Algebra (5th ed.). Wellesley-Cambridge Press. Subspaces and the closure conditions.↩