Skip to content

Inner Products

The previous page measured one vector at a time. Everything else in this chapter needs a function of two vectors — a way of asking how much they have in common — and once you have one, length, distance, angle and orthogonality all follow without further assumptions.

You already know one such function: the dot product xy\mathbf{x}^\top\mathbf{y}. This page shows what the dot product is an instance of, and why the general version is not an abstraction for its own sake — a covariance matrix, a kernel, and a Mahalanobis distance are all inner products that are not the dot product.

  • What a bilinear mapping is, and why bilinearity is the condition that makes matrix notation possible.
  • The two extra conditions — symmetry and positive definiteness — and what each one buys.
  • Why every inner product on Rn\mathbb{R}^n can be written xAy\mathbf{x}^\top\mathbf{A}\mathbf{y} for a symmetric positive definite matrix A\mathbf{A}, and vice versa.
  • How to test a candidate matrix, and why Cholesky is the test to reach for rather than eigenvalues.
  • The book’s Example 3.4, where changing one entry from 5 to 3 destroys the whole structure — and the exact value of that entry at which it breaks.

Think of an inner product as a scoring rule that takes two vectors and returns how much they agree. The dot product’s version of “agree” is a specific one: multiply matching coordinates, add up. That treats every coordinate as equally important and as entirely independent of the others.

Often neither is true. If your two coordinates are height in metres and height in centimetres, the dot product double-counts what is really one measurement. If one coordinate is measured carefully and the other is noise, the dot product weighs them the same. The general inner product is what lets you say which coordinates matter and how they interact — and it does so with one matrix:

x,y=xAy\langle \mathbf{x}, \mathbf{y} \rangle = \mathbf{x}^\top \mathbf{A}\, \mathbf{y}

The diagonal of A\mathbf{A} sets how much each coordinate counts; the off-diagonal entries say how much a unit of one coordinate is worth in the direction of another.

diagram Diagram mermaid

The rightmost node is the reason positive definiteness is not optional decoration. Length is going to be defined as x,x\sqrt{\langle \mathbf{x},\mathbf{x}\rangle}; if the inner product of a vector with itself could be negative, that square root would be imaginary and there would be no geometry to do.

“Linear in each argument separately” is worth reading carefully. The map is not linear in the pair — doubling both arguments quadruples the output, not doubles it. It is linear if you freeze one argument and vary the other.

Bilinearity is what makes the matrix form possible. Fix an ordered basis B=(b1,,bn)B = (\mathbf{b}_1, \dots, \mathbf{b}_n) and expand x=iψibi\mathbf{x} = \sum_i \psi_i \mathbf{b}_i, y=jλjbj\mathbf{y} = \sum_j \lambda_j \mathbf{b}_j. Bilinearity lets you pull both sums out:

x,y=i=1nψibi, j=1nλjbj=i=1nj=1nψibi,bjλj=x^Ay^\langle \mathbf{x}, \mathbf{y} \rangle = \left\langle \sum_{i=1}^{n}\psi_i \mathbf{b}_i,\ \sum_{j=1}^{n}\lambda_j \mathbf{b}_j \right\rangle = \sum_{i=1}^{n}\sum_{j=1}^{n} \psi_i \langle \mathbf{b}_i, \mathbf{b}_j\rangle \lambda_j = \hat{\mathbf{x}}^\top \mathbf{A}\, \hat{\mathbf{y}}

with Aij=bi,bjA_{ij} = \langle \mathbf{b}_i, \mathbf{b}_j \rangle and x^,y^\hat{\mathbf{x}}, \hat{\mathbf{y}} the coordinate vectors with respect to BB. The inner product is determined entirely by its values on pairs of basis vectorsn2n^2 numbers, and nothing else is needed.

That “if and only if” is the practical content of the section. It means:

  • Every inner product you will ever meet on Rn\mathbb{R}^n is a matrix. There is no exotic case hiding.
  • Testing whether a candidate is an inner product reduces to testing whether one matrix is SPD.
  • The dot product is the case A=I\mathbf{A} = \mathbf{I}, which is why it treats coordinates as independent and equally weighted.

Two further properties of an SPD matrix, both stated in the book:

  • Its null space is trivialAx=0\mathbf{A}\mathbf{x} = \mathbf{0} only for x=0\mathbf{x} = \mathbf{0}, since otherwise xAx=0\mathbf{x}^\top\mathbf{A}\mathbf{x} = 0 for a nonzero x\mathbf{x}.
  • Its diagonal entries are positive, because eiAei=Aii>0\mathbf{e}_i^\top \mathbf{A} \mathbf{e}_i = A_{ii} > 0.

Neither is sufficient. A matrix can have a positive diagonal and a trivial null space and still fail — which is exactly what the next section demonstrates.

The book’s Example 3.4. Two matrices, identical except for a single entry:

A1=[9665],A2=[9663]\mathbf{A}_1 = \begin{bmatrix} 9 & 6 \\ 6 & 5 \end{bmatrix}, \qquad \mathbf{A}_2 = \begin{bmatrix} 9 & 6 \\ 6 & 3 \end{bmatrix}

Both are symmetric. Both have positive diagonals. One is an inner product and one is not.

Completing the square is the honest way to see it. For A1\mathbf{A}_1:

xA1x=9x12+12x1x2+5x22=(3x1+2x2)2+x22\mathbf{x}^\top\mathbf{A}_1\mathbf{x} = 9x_1^2 + 12x_1x_2 + 5x_2^2 = (3x_1 + 2x_2)^2 + x_2^2

Check the expansion: (3x1+2x2)2=9x12+12x1x2+4x22(3x_1+2x_2)^2 = 9x_1^2 + 12x_1x_2 + 4x_2^2, and adding x22x_2^2 gives 5x225x_2^2 in the last term. Both summands are squares, so the total is 0\geq 0, and it is 00 only when x2=0x_2 = 0 and 3x1=03x_1 = 0 — that is, only at the origin. Positive definite.

For A2\mathbf{A}_2:

xA2x=9x12+12x1x2+3x22=(3x1+2x2)2x22\mathbf{x}^\top\mathbf{A}_2\mathbf{x} = 9x_1^2 + 12x_1x_2 + 3x_2^2 = (3x_1 + 2x_2)^2 - x_2^2

Now the second term is subtracted, and there is nothing stopping it from winning. The book’s witness is x=(2,3)\mathbf{x} = (2, -3)^\top:

(32+2(3))2(3)2=(66)29=09=9<0(3\cdot 2 + 2\cdot(-3))^2 - (-3)^2 = (6-6)^2 - 9 = 0 - 9 = -9 < 0

Not positive definite, and therefore not an inner product. Under A2\mathbf{A}_2 the vector (2,3)(2,-3) would have squared length 9-9, so its “length” would be 3i3i.

Vary the lower-right entry aa and keep the rest: A(a)=[966a]\mathbf{A}(a) = \begin{bmatrix} 9 & 6 \\ 6 & a \end{bmatrix}. Completing the square gives (3x1+2x2)2+(a4)x22(3x_1 + 2x_2)^2 + (a-4)x_2^2, so positive definiteness needs a>4a > 4 — and the determinant 9a369a - 36 agrees, changing sign at exactly a=4a = 4.

aadetA(a)\det \mathbf{A}(a)smallest eigenvalueverdict
5.0+9.0000+9.0000+0.675445+0.675445SPD — the book’s A1\mathbf{A}_1
4.5+4.5000+4.5000+0.341997+0.341997SPD
4.00.00000.00000.0000000.000000the boundary — positive semidefinite, not definite
3.54.5000-4.50000.350189-0.350189indefinite
3.09.0000-9.00000.708204-0.708204indefinite — the book’s A2\mathbf{A}_2

At a=4a = 4 the matrix is only semidefinite: xAx=0\mathbf{x}^\top\mathbf{A}\mathbf{x} = 0 for x=(2,3)\mathbf{x} = (2,-3) without x\mathbf{x} being zero. That fails Definition 3.2, and it fails in a way that matters downstream — a nonzero vector of length zero breaks the positive-definiteness of the induced norm too.

Example 3.3 defines, on R2\mathbb{R}^2,

x,y:=x1y1(x1y2+x2y1)+2x2y2\langle \mathbf{x}, \mathbf{y}\rangle := x_1y_1 - (x_1y_2 + x_2y_1) + 2x_2y_2

which in matrix form is A=[1112]\mathbf{A} = \begin{bmatrix} 1 & -1 \\ -1 & 2\end{bmatrix}, with eigenvalues 0.3819660.381966 and 2.6180342.618034 — both positive, so this really is an inner product. And it disagrees with the dot product about more than magnitude. Take x=(1,2)\mathbf{x} = (1,2) and y=(3,1)\mathbf{y} = (3,-1):

xy=32=+1,x,y=3(1+6)+2(2)=354=6\mathbf{x}^\top\mathbf{y} = 3 - 2 = +1, \qquad \langle \mathbf{x}, \mathbf{y}\rangle = 3 - (-1 + 6) + 2(-2) = 3 - 5 - 4 = -6

Different sign. Under the dot product these two vectors are (weakly) pointing the same way; under Example 3.3’s inner product they are pointing away from each other. Whatever “similar” means, it means something relative to a choice.

example_34_and_33.py
import numpy as np
 
A1 = np.array([[9.0, 6.0], [6.0, 5.0]])
A2 = np.array([[9.0, 6.0], [6.0, 3.0]])
A3 = np.array([[1.0, -1.0], [-1.0, 2.0]])   # Example 3.3
 
for name, A in (("A1", A1), ("A2", A2), ("Ex3.3", A3)):
    ev = np.linalg.eigvalsh(A)
    try:
        np.linalg.cholesky(A)
        chol = "succeeds"
    except np.linalg.LinAlgError:
        chol = "fails"
    print(f"{name:6} eig {np.round(ev, 6)}  det {np.linalg.det(A):+.4f}  "
          f"cholesky {chol}  spd {bool(np.all(ev > 0))}")
 
w = np.array([2.0, -3.0])
print("witness (2,-3):  A1 gives", float(w @ A1 @ w), " A2 gives", float(w @ A2 @ w))
 
x, y = np.array([1.0, 2.0]), np.array([3.0, -1.0])
print("dot product:", float(x @ y), "  Example 3.3:", float(x @ A3 @ y))
output
A1     eig [ 0.675445 13.324555]  det +9.0000  cholesky succeeds  spd True
A2     eig [-0.708204 12.708204]  det -9.0000  cholesky fails  spd False
Ex3.3  eig [0.381966 2.618034]  det +1.0000  cholesky succeeds  spd True
witness (2,-3):  A1 gives 9.0  A2 gives -9.0
dot product: 1.0   Example 3.3: -6.0

The first sketch is Example 3.4 with the broken entry on a knob. The background is the quadratic form xAx\mathbf{x}^\top\mathbf{A}\mathbf{x} — green where it is positive, red where it is negative — and the white curve is where it equals zero. Slide aa down through 44 and watch the red wedge open.

sketch One entry, and the whole structure collapses p5.js
The field shows x-transpose A x for A = [[9, 6], [6, a]]. Green is positive, red is negative, and the white curve is the zero set. Above a = 4 the whole plane except the origin is green and A is an inner product. At exactly a = 4 the zero set becomes a line through the origin. Below it a negative wedge opens and A is no longer an inner product.

The second sketch is the payoff: the same two vectors, and an inner product you control. Drag the matrix entries and watch the inner product’s sign flip while the arrows do not move at all.

sketch The same two arrows, an inner product you control p5.js
Drag x and y, and drag the three entries of the symmetric matrix A. The readout gives x-transpose A y and the two induced lengths. The dashed grey curve is the set of vectors A calls unit length. Nothing about the arrows changes when you move A, and yet the number and even its sign do.

An inner product is a linear map’s worth of information, so the matrix stepper from Chapter 2 applies directly. Here it is on Example 3.3’s matrix — note the eigenvalues it reports, which are the definiteness test:

matrixExample 3.3's matrix, and why it qualifieslinear map on R^2
-505-505x1x2
1-1-12
columns of A = images of e1, e2
det A 1area factor 1orientation preserved
det A1A e1(1, -1)A e2(-1, 2)
basisThe plane before anything happens, with the standard basis e1 = (1, 0) and e2 = (0, 1) and the unit square they span.
1/8

Both eigenvalues are positive, so no direction gets flipped or flattened — which is exactly what positive definiteness means geometrically.

Testing a candidate has three parts, and the third one has a good implementation and a bad one:

is_inner_product.py
import numpy as np
 
def is_inner_product(A, tol=1e-12):
    """Test the conditions of Definition 3.2 on a candidate matrix A."""
    A = np.asarray(A, dtype=float)
    checks = {}
 
    # 1. Bilinearity is automatic for x^T A y. Any matrix gives a bilinear form;
    #    that is what the matrix form of Equation 3.10 means. Nothing to test.
    checks["bilinear"] = True
 
    # 2. Symmetry.
    checks["symmetric"] = bool(np.allclose(A, A.T, atol=tol))
 
    # 3. Positive definiteness. Cholesky is the right test: it succeeds exactly
    #    when the matrix is positive definite, so there is no tolerance to pick.
    #    Comparing eigenvalues to zero needs one, and the choice is where the
    #    semidefinite boundary case slips through.
    if not checks["symmetric"]:
        checks["positive definite"] = False
    else:
        try:
            np.linalg.cholesky(A)
            checks["positive definite"] = True
        except np.linalg.LinAlgError:
            checks["positive definite"] = False
 
    return all(checks.values()), checks
 
candidates = {
    "identity (the dot product)": np.eye(3),
    "A1 from Example 3.4": [[9, 6], [6, 5]],
    "A2 from Example 3.4": [[9, 6], [6, 3]],
    "the a = 4 boundary": [[9, 6], [6, 4]],
    "non-symmetric": [[2, 0], [1, 2]],
    "Example 3.3": [[1, -1], [-1, 2]],
}
 
for name, A in candidates.items():
    ok, detail = is_inner_product(A)
    print(f"{'YES' if ok else 'no':4} {name:28} "
          f"symmetric={detail['symmetric']}  definite={detail['positive definite']}")
output
YES  identity (the dot product)   symmetric=True  definite=True
YES  A1 from Example 3.4          symmetric=True  definite=True
no   A2 from Example 3.4          symmetric=True  definite=False
no   the a = 4 boundary           symmetric=True  definite=False
no   non-symmetric                symmetric=False  definite=False
YES  Example 3.3                  symmetric=True  definite=True

Six candidates, three accepted. The instructive rejection is the fourth, and it is worth checking why the naive test disagrees:

why_cholesky.py
import numpy as np
 
boundary = np.array([[9.0, 6.0], [6.0, 4.0]])
print("eigenvalues:", np.round(np.linalg.eigvalsh(boundary), 12))
print("a >= 0 test would accept it:", bool(np.all(np.linalg.eigvalsh(boundary) >= 0)))
print("cholesky accepts it:", end=" ")
try:
    np.linalg.cholesky(boundary)
    print(True)
except np.linalg.LinAlgError:
    print(False)
 
w = np.array([2.0, -3.0])
print("but (2,-3) has squared length", float(w @ boundary @ w), "while being nonzero")
output
eigenvalues: [ 0. 13.]
a >= 0 test would accept it: True
cholesky accepts it: False
but (2,-3) has squared length 0.0 while being nonzero

The eigenvalues at the boundary are exactly 00 and 1313, so np.all(eigvalsh(A) >= 0) returns True and a nonzero vector nevertheless has length zero. That is positive semidefiniteness, and Definition 3.2 asks for the strict version. Cholesky tests the strict version by construction — it is the test to reach for, and it happens to be about twice as fast as an eigendecomposition as well.

One more thing the run shows: the shear is rejected on symmetry, before definiteness is ever examined. It is worth knowing that its symmetric part 12(A+A)=[20.50.52]\tfrac{1}{2}(\mathbf{A}+\mathbf{A}^\top) = \begin{bmatrix}2 & 0.5 \\ 0.5 & 2\end{bmatrix} is positive definite, so the shear gives a perfectly positive quadratic form xAx\mathbf{x}^\top\mathbf{A}\mathbf{x} while still failing to be an inner product. Definiteness of the form is not enough; the matrix itself has to be symmetric, or the two arguments are not interchangeable.

figure Example 3.4, as a surface matplotlib
Two filled-contour panels of the quadratic form for the two matrices of Example 3.4, drawn on a red-blue diverging scale with the zero contour marked. The left panel is entirely one sign; the right has a wedge of the opposite sign containing a marked point at (2, -3). Two filled-contour panels of the quadratic form for the two matrices of Example 3.4, drawn on a red-blue diverging scale with the zero contour marked. The left panel is entirely one sign; the right has a wedge of the opposite sign containing a marked point at (2, -3).
A1 has eigenvalues 0.675 and 13.325 and never goes negative. A2 has eigenvalues -0.708 and 12.708, and the shaded wedge is where a vector would have negative squared length. The marked point is the book's witness, at which the form equals exactly -9.
figure Three inner products, three meanings of length one matplotlib
Three closed curves on one pair of axes — a circle, a tilted ellipse and an axis-aligned ellipse — with an arrow to the point (1, 1) and a table of its three measured lengths. Three closed curves on one pair of axes — a circle, a tilted ellipse and an axis-aligned ellipse — with an arrow to the point (1, 1) and a table of its three measured lengths.
The point (1, 1) has length 1.4142 under the dot product, exactly 1.0000 under the book's Equation 3.19, and 1.7321 under diag(2, 1). It lies exactly on the amber curve, which is what makes it a unit vector under that inner product and not under the others.

From the surface plot. The interesting feature of A2\mathbf{A}_2‘s panel is not that a negative region exists but that it is a wedge through the origin, not a bounded blob. Positive definiteness is a statement about directions rather than about magnitudes: the form is homogeneous of degree two, so if it is negative at x\mathbf{x} it is negative along the whole line through x\mathbf{x}, scaled by λ2\lambda^2. The negative eigenvalue 0.708204-0.708204 is the value of the form at its own eigenvector, and that is the most negative value any unit vector can produce. The book’s witness (2,3)(2,-3) is a different direction in the same wedge — normalised, it scores 0.692308-0.692308, which is close to the extreme without being it.

Note also that A2\mathbf{A}_2‘s largest eigenvalue is 12.70812.708 — comfortably positive. A single negative eigenvalue among positives is enough. There is no “mostly positive definite”.

From the unit sets. The three curves have the same centre and enclose the point (1,1)(1,1) to different depths, which is the visual form of the statement that the same vector has three lengths. More usefully: the shape tells you what the inner product cares about. The axis-aligned ellipse of diag(2,1)\mathrm{diag}(2,1) is narrow in x1x_1, meaning x1x_1 is expensive — a small step in x1x_1 counts as much length as a bigger step in x2x_2. The tilted ellipse of Equation 3.19 is stretched along the diagonal x1=x2x_1 = x_2, meaning that agreement between the coordinates is cheap: moving both together costs less length than moving one alone. That is what a negative off-diagonal entry does, and it is exactly the structure a covariance matrix has when two features are positively correlated.

candidatematrixinner product?why
dot productI\mathbf{I}yessymmetric, all eigenvalues 11
weighted dotdiag(w1,,wn)\mathrm{diag}(w_1,\dots,w_n), wi>0w_i > 0yessymmetric, eigenvalues are the weights
Example 3.3[1112]\begin{bmatrix}1&-1\\-1&2\end{bmatrix}yeseigenvalues 0.3820.382, 2.6182.618
MahalanobisΣ1\Sigma^{-1} for invertible Σ\Sigmayesa covariance matrix of full rank is SPD, and so is its inverse
A1\mathbf{A}_1[9665]\begin{bmatrix}9&6\\6&5\end{bmatrix}yescompleting the square gives a sum of two squares
the a=4a=4 boundary[9664]\begin{bmatrix}9&6\\6&4\end{bmatrix}nosemidefinite: (2,3)(2,-3) has squared length 00
A2\mathbf{A}_2[9663]\begin{bmatrix}9&6\\6&3\end{bmatrix}no(2,3)(2,-3) has squared length 9-9
a shear[2012]\begin{bmatrix}2&0\\1&2\end{bmatrix}nonot symmetric
pch.quizTag Check your understanding
  1. Theorem 3.5 says something stronger than 'matrices give inner products'. What is the extra content?

    pch.quizShowAnswer

    B — That the correspondence runs both ways: every inner product on a finite-dimensional real vector space with a fixed basis IS x-transpose A y for some symmetric positive definite A, so there are no other kinds — The 'if and only if' is what makes the test practical: checking a candidate reduces to checking whether one matrix is SPD, with no exotic cases to worry about. Note that plain symmetry is not enough — A2 of Example 3.4 is symmetric and fails.

  2. A2 = [[9, 6], [6, 3]] has positive diagonal entries and a trivial-looking structure. Why is it not an inner product?

    pch.quizShowAnswer

    B — Because completing the square gives (3x1 + 2x2)^2 minus x2^2, and the witness (2, -3) makes that minus 9 — a nonzero vector with negative squared length — The determinant is -9 and the eigenvalues are -0.708 and 12.708. One negative eigenvalue among positive ones is enough; there is no partial credit for definiteness.

  3. Why does the from-scratch code use Cholesky rather than comparing eigenvalues to zero?

    pch.quizShowAnswer

    B — Because Cholesky tests definiteness exactly, whereas an eigenvalue comparison needs a tolerance — and at the a = 4 boundary the eigenvalues are 0 and 13, so a >= 0 test wrongly accepts a matrix that Definition 3.2 rejects — It is also about twice as fast, but the correctness argument is the one that matters. Semidefinite is not definite, and the a = 4 case is exactly where the two tests disagree.

  4. Under the dot product, x = (1, 2) and y = (3, -1) have inner product +1. Under Example 3.3's inner product the value is -6. What should you conclude?

    pch.quizShowAnswer

    B — Nothing follows — the two numbers measure different things, and whether two vectors 'agree' is a statement relative to a chosen inner product, including its sign — Example 3.3's matrix has eigenvalues 0.382 and 2.618, so it is a perfectly valid inner product. The sign flip is the point: cosine similarity, orthogonality and angle all inherit this relativity, which is what the next two pages develop.

Exercise 2 – The worst direction, and the book’s witness

Section titled “Exercise 2 – The worst direction, and the book’s witness”

Exercise 3 – Bilinearity, symmetry, definiteness, all measured

Section titled “Exercise 3 – Bilinearity, symmetry, definiteness, all measured”
  • An inner product is a bilinear, symmetric, positive definite function of two vectors, and those three words are the entire definition.
  • Bilinear means linear in each argument separately — scaling both arguments scales the result by the square, so an inner product is not a linear map.
  • Theorem 3.5 is an if and only if: every inner product on a finite-dimensional real space is x-transpose A y for a symmetric positive definite A, and every such A gives one.
  • Positive definiteness is what makes the induced norm real, since length is the square root of the inner product of a vector with itself.
  • A positive diagonal is necessary but not sufficient — the book’s second matrix of Example 3.4 has both diagonal entries positive and a witness of squared length minus nine.
  • Semidefinite is not definite: at the boundary value the eigenvalues are zero and thirteen, and a nonzero vector has length zero. Test with Cholesky, not with eigenvalues compared to zero.
  • The dot product is the case where the matrix is the identity, which is why it treats coordinates as independent and equally weighted.

Next: Lengths and Distances — the first two things the inner product hands you for free.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading