The previous lessons operated on vectors and matrices taking for granted what they are. This module establishes the definition. It is not a dispensable formality: it is what explains why the same techniques apply to lists of numbers, to polynomials and to the internal representations of a language model.
The definition
A vector space over is a set with two operations, an addition and a scalar multiplication , satisfying eight conditions. For all and :
The elements of are called vectors, whatever their nature. The definition mentions neither arrows, nor lists, nor coordinates.
In , realised in NumPy as a one-dimensional ndarray, all eight are inherited from the properties of the real numbers and can be checked directly:
import numpy as np
u = np.array([1., 2., 3.])
v = np.array([4., 5., 6.])
np.allclose(u + v, v + u) # commutativity
np.allclose(3 * (u + v), 3 * u + 3 * v) # distributivity
np.allclose(u + np.zeros(3), u) # identity element
Closure and vectorisation
The first two conditions of the definition, preceding the axioms, are that addition and scalar multiplication return elements of . That property is called closure, and in NumPy it shows up in the shape of the result:
(u + v).shape == (3 * u).shape == u.shape # True
The consequence is one of implementation, not merely of notation. Because the result belongs to the same space and has the same type and shape, the operation can be compiled into a single typed loop over a contiguous block of memory, with nothing to decide per element. That is what vectorisation means, and it is why u + v runs one to two orders of magnitude faster than the equivalent Python loop.
Algebraic closure and library efficiency are not independent facts: the second is possible because the first holds.
Linear combinations and the span
The central operation of linear algebra combines both: scaling several vectors and adding them.
Arranging the vectors as the columns of a matrix, the combination is a matrix-vector product:
V = np.column_stack([u, v]) # (3, 2)
c = np.array([2., -1.])
V @ c # array([-2., -1., 0.]) = 2u − v
The identification is worth stating plainly: the product is the linear combination of the columns of with coefficients . It is the reading that turns into the question of which combination of the columns of produces .
The set of all possible linear combinations is called the span:
Applied to the columns of a matrix, it is called the column space, and it is exactly the set of vectors for which has a solution.
Subspaces
A subset is a subspace if it is itself a vector space under the same operations. There is no need to verify the eight axioms: they are inherited from . Three conditions suffice:
The figure applies the test to several subsets of :
- contains 0
- closed under addition
- closed under scalar multiplication
is a subspace
Each failure illustrates a different condition. The shifted line does not contain the origin. The first quadrant does contain it and is closed under addition, but multiplying by leaves it. The parabola contains the origin and fails the other two: and belong to it and their sum does not, and doubling gives , which does not either.
The subspaces of are therefore only , the lines through the origin, and itself. A subspace always contains the origin, and that is the difference from the solution set of described in the lesson on particular and general solutions, which is affine unless .
The subspaces already met in the course are instances of this definition: the null space of a matrix, its column space and its row space.
The three orientations of an array
In NumPy, a one-dimensional vector of shape (n,) has no orientation: it is neither a row nor a column. For matrix algebra it is given one explicitly:
u.shape # (3,) no orientation
u.reshape(-1, 1).shape # (3, 1) column
u.reshape(1, -1).shape # (1, 3) row
The distinction is not cosmetic. Under the broadcasting rules described in the lesson on matrices, combining two different orientations produces a matrix rather than a vector:
v + v
result (3) · element by element
Adding a column (3, 1) to a row (1, 3) aligns the shapes from the right, finds a in each position and stretches both: the result has shape (3, 3) and holds every cross sum. The operation is legal and raises no warning, so the error surfaces later, in a dimension that does not fit or in a loss quietly computed wrong.
Checking .shape before operating is the habit that prevents it.
Spaces that are not ℝⁿ
The generality of the definition is not a technicality. Any set whose operations satisfy the eight axioms inherits the whole of the theory that follows: linear independence, basis, dimension, linear transformations.
| Space | Elements | Dimension |
|---|---|---|
| real matrices | ||
| polynomials of degree | ||
| continuous functions on | infinite | |
| the null space of |
In machine learning the relevant space is almost always , but the choice of and of the map that carries the data there is where the design work sits. A text is represented as a point of , an image as one of after flattening its pixels, a user as a vector of latent factors.
That these representations live in a vector space is what licenses the usual operations on them. Averaging embeddings to represent a document makes sense because addition and scalar multiplication are defined and the result still belongs to the space. The lesson on multiplication by a scalar showed the other side: the metric used on that space decides what it means for two representations to be close.
Exercise. Determine which of the following subsets of are subspaces by applying the three conditions: the vectors with ; the vectors with ; the vectors with . Then verify the first answer by checking that null_space(np.ones((1, 3))) has the expected dimension.