PHYS-234 · Lesson 9 of 12 · 26 min

Linear algebra in physics: eigenvalue problems and normal modes

Linear algebra is the hidden engine of computational physics. A circuit of resistors gives a linear system for the node voltages. A finite-difference discretization of a boundary value problem gives a linear system for the grid values. A collection of masses and springs gives an eigenvalue problem whose eigenvalues are the squared frequencies of its normal modes, and a discretized Schrödinger equation gives an eigenvalue problem whose eigenvalues are energy levels. This lesson builds the two central algorithms, Gaussian elimination for linear systems and iterative methods for eigenvalues, and applies them to oscillations of molecules and chains of atoms.

Linear systems and Gaussian elimination

A system \(A\mathbf{x} = \mathbf{b}\) of \(N\) equations in \(N\) unknowns is solved by elimination. For each column in turn, subtract multiples of the pivot row from the rows below to create zeros under the diagonal; then solve the resulting upper triangular system from the bottom up by back substitution. Elimination takes about \(\frac23 N^3\) arithmetic operations and back substitution about \(N^2\). The method appears in the Chinese text The Nine Chapters on the Mathematical Art from around the first century, and is named after Gauss, who used it systematically for least-squares problems in astronomy and geodesy around 1810.

Plain elimination fails if a pivot is zero and is inaccurate if a pivot is small, because dividing by it magnifies rounding errors. Partial pivoting fixes this by swapping rows so that the pivot is the largest available entry in its column. With partial pivoting, Gaussian elimination is backward stable in practice, in the sense of lesson 2: the computed solution is the exact solution of a nearby system. Whether that nearby solution is close to the true one depends on the condition number of the matrix, \(\kappa(A) = \|A\|\,\|A^{-1}\|\), which bounds how much relative errors in \(\mathbf{b}\) or \(A\) can be magnified. With \(\kappa = 10^{k}\), expect to lose about \(k\) of the 16 digits.

Physics often produces matrices with special structure, and exploiting it pays. The tridiagonal matrices of lesson 8 are solved in \(O(N)\) operations by the Thomas algorithm. Symmetric positive definite matrices, such as stiffness matrices of structures and the discrete Laplacian, can be factored as \(A = LL^T\) by Cholesky's method at half the cost of general elimination and with no pivoting. Large sparse systems from three-dimensional grids are solved iteratively, by the relaxation methods of lesson 8 or by the conjugate gradient method of Magnus Hestenes and Eduard Stiefel from 1952.

A resistor bridge solved by elimination with pivoting, and the ill-conditioned Hilbert matrix
from fractions import Fraction

def solve(A, b):
    """Gaussian elimination with partial pivoting; A and b are copied."""
    n = len(b)
    M = [row[:] + [b[i]] for i, row in enumerate(A)]
    for k in range(n):
        p = max(range(k, n), key=lambda i: abs(M[i][k]))
        M[k], M[p] = M[p], M[k]
        for i in range(k + 1, n):
            m = M[i][k] / M[k][k]
            for j in range(k, n + 1):
                M[i][j] -= m * M[k][j]
    x = [0] * n
    for i in range(n - 1, -1, -1):
        x[i] = (M[i][n] - sum(M[i][j] * x[j] for j in range(i + 1, n))) / M[i][i]
    return x

# Wheatstone bridge: 10 V source between node 1 and ground; unknown voltages at nodes 1, 2, 3.
# R12 = 100, R13 = 200, R2g = 300, R3g = 400, bridge R23 = 50 ohms, source resistance 1 ohm.
G = lambda r: 1.0 / r
A = [[G(1) + G(100) + G(200), -G(100), -G(200)],
     [-G(100), G(100) + G(300) + G(50), -G(50)],
     [-G(200), -G(50), G(200) + G(400) + G(50)]]
b = [10 * G(1), 0.0, 0.0]
V = solve(A, b)
print("node voltages (V):", " ".join(f"{v:.6f}" for v in V))
print(f"current through the bridge resistor: {(V[1] - V[2]) / 50 * 1000:.4f} mA")

# Ill conditioning: the Hilbert matrix H[i][j] = 1/(i+j+1), with exact solution all ones
print("\n n   max error in float solution   (exact rational arithmetic gives zero error)")
for n in (4, 6, 8, 10, 12):
    H = [[1.0 / (i + j + 1) for j in range(n)] for i in range(n)]
    bh = [sum(row) for row in H]
    x = solve(H, bh)
    Hq = [[Fraction(1, i + j + 1) for j in range(n)] for i in range(n)]
    xq = solve(Hq, [sum(row) for row in Hq])
    print(f"{n:2d}   {max(abs(xi - 1) for xi in x):.2e}                     exact: {all(v == 1 for v in xq)}")
Output
node voltages (V): 9.958240 7.227755 7.067138
current through the bridge resistor: 3.2123 mA

 n   max error in float solution   (exact rational arithmetic gives zero error)
 4   4.56e-13                     exact: True
 6   5.27e-11                     exact: True
 8   1.37e-07                     exact: True
10   7.18e-04                     exact: True
12   5.95e-03                     exact: True

The bridge solution is ordinary and accurate. The Hilbert matrix is the classic ill-conditioned example: its condition number grows roughly like \(e^{3.5N}\), reaching about \(10^{16}\) at \(N = 12\), so the floating-point solution of a system whose exact answer is all ones loses more digits with every increase in \(N\): errors of \(10^{-13}\) at \(N = 4\) grow to nearly \(10^{-2}\) at \(N = 12\), and a few sizes larger the answer has no correct digits at all. The same algorithm in exact rational arithmetic, using Python's Fraction type, returns exactly the right answer, which shows that the trouble is conditioning and rounding, not the algorithm. Hilbert matrices arise in least-squares fitting with the monomials \(1, x, x^2, \ldots\) on \([0, 1]\), which is why lesson 11 fits with better-behaved functions.

Normal modes

Consider masses connected by springs, displaced slightly from equilibrium. Newton's second law for small displacements \(\mathbf{x}\) takes the form

\[M\ddot{\mathbf{x}} = -K\mathbf{x},\]

where \(M\) is a diagonal matrix of masses and \(K\) a symmetric stiffness matrix. Looking for solutions in which every mass oscillates at the same frequency, \(\mathbf{x} = \mathbf{v}\cos\omega t\), gives the generalized eigenvalue problem

\[K\mathbf{v} = \omega^2 M\mathbf{v}.\]

Each eigenvalue \(\omega^2\) is the square of a normal-mode frequency and each eigenvector \(\mathbf{v}\) the pattern of motion. Because \(K\) and \(M\) are symmetric and \(M\) is positive definite, the eigenvalues are real and the modes are orthogonal with respect to \(M\). Any small motion is a superposition of normal modes, each oscillating independently at its own frequency. Substituting \(\mathbf{v} = M^{-1/2}\mathbf{w}\) converts the problem to the ordinary symmetric eigenvalue problem \(M^{-1/2}KM^{-1/2}\mathbf{w} = \omega^2\mathbf{w}\).

For a chain of \(N\) equal masses \(m\) joined by \(N + 1\) equal springs \(k\) between fixed walls, \(K\) is \(k\) times the tridiagonal matrix with 2 on the diagonal and \(-1\) beside it, the same matrix as the discrete second derivative. Its eigenvalues are known exactly:

\[\omega_n = 2\sqrt{\frac{k}{m}}\,\sin\frac{n\pi}{2(N+1)}, \qquad v_{n,j} = \sin\frac{nj\pi}{N+1}, \qquad n = 1, \ldots, N .\]

For long wavelengths, small \(n\), the frequency is proportional to \(n\), as for a continuous string. For short wavelengths it bends over and reaches a maximum of \(2\sqrt{k/m}\): a discrete chain cannot vibrate faster than this, a fact behind the Debye cutoff of lesson 4 and the phonon spectra of crystals.

Five rows, one for each normal mode of a chain of five masses between two walls. Each row shows the displacement of the five masses as dots joined by lines, following a sine shape with one, two, three, four and five half waves. The frequency of each mode is written beside it, rising from 0.52 to 1.93 in units of the square root of k over m.
The five normal modes of a chain of five equal masses between fixed walls. The patterns are sampled sine waves, and the frequencies follow \(2\sin(n\pi/12)\)

Computing eigenvalues

For small matrices the characteristic polynomial \(\det(A - \lambda I)\) can be written down, but its roots are a terrible way to compute eigenvalues: the polynomial's coefficients are extremely sensitive, as James Wilkinson showed with a famous degree-20 example. Practical methods work directly with the matrix.

Power iteration is the simplest. Repeatedly multiply a vector by \(A\) and normalize. Writing the starting vector as a combination of eigenvectors, \(\mathbf{u}_0 = \sum c_i\mathbf{v}_i\), we get \(A^k\mathbf{u}_0 = \sum c_i\lambda_i^k\mathbf{v}_i\), which is dominated by the eigenvector with the largest \(|\lambda|\). The Rayleigh quotient \(\mathbf{u}^T A\mathbf{u}/\mathbf{u}^T\mathbf{u}\) estimates the eigenvalue, with error shrinking like \((\lambda_2/\lambda_1)^{2k}\) for a symmetric matrix. Power iteration with \(A^{-1}\), called inverse iteration, finds the smallest eigenvalue, and with \((A - \sigma I)^{-1}\) the eigenvalue nearest any chosen shift \(\sigma\). Inverse iteration needs a linear solve per step, but it converges quickly when \(\sigma\) is close to an eigenvalue.

To find all eigenvalues of a symmetric matrix, Carl Jacobi's method of 1846 applies a sequence of plane rotations, each chosen to zero one off-diagonal pair. Every rotation reduces the sum of squares of the off-diagonal entries, so the matrix converges to diagonal form; the diagonal holds the eigenvalues and the product of the rotations holds the eigenvectors. Jacobi's method is simple, extremely accurate and easy to program, which suits it to the small matrices of molecular vibrations and coupled oscillators. For large matrices the QR algorithm, discovered independently by John Francis and Vera Kublanovskaya around 1961, is faster and is what libraries use; it was later named one of the top ten algorithms of the twentieth century.

Normal modes of a five-mass chain by Jacobi rotations and power iteration, and the stretching modes of a linear triatomic molecule
import math

def jacobi_eigen(A, tol=1e-14):
    """All eigenvalues and eigenvectors of a symmetric matrix by Jacobi rotations."""
    n = len(A); A = [row[:] for row in A]
    V = [[float(i == j) for j in range(n)] for i in range(n)]
    for sweep in range(100):
        off = sum(A[i][j]**2 for i in range(n) for j in range(n) if i != j)
        if off < tol: break
        for p in range(n):
            for q in range(p + 1, n):
                if abs(A[p][q]) < 1e-300: continue
                theta = (A[q][q] - A[p][p]) / (2 * A[p][q])
                t = math.copysign(1.0, theta) / (abs(theta) + math.sqrt(theta * theta + 1))
                c = 1 / math.sqrt(t * t + 1); s = t * c
                for k in range(n):                 # rotate columns p and q
                    akp, akq = A[k][p], A[k][q]
                    A[k][p], A[k][q] = c * akp - s * akq, s * akp + c * akq
                for k in range(n):                 # rotate rows p and q
                    apk, aqk = A[p][k], A[q][k]
                    A[p][k], A[q][k] = c * apk - s * aqk, s * apk + c * aqk
                for k in range(n):
                    vkp, vkq = V[k][p], V[k][q]
                    V[k][p], V[k][q] = c * vkp - s * vkq, s * vkp + c * vkq
    vals = [A[i][i] for i in range(n)]
    order = sorted(range(n), key=lambda i: vals[i])
    return [vals[i] for i in order], [[V[k][i] for k in range(n)] for i in order], sweep

def power_iteration(A, iters=200):
    n = len(A); u = [1.0 + 0.1 * i for i in range(n)]
    for _ in range(iters):
        w = [sum(A[i][j] * u[j] for j in range(n)) for i in range(n)]
        norm = math.sqrt(sum(x * x for x in w)); u = [x / norm for x in w]
    Au = [sum(A[i][j] * u[j] for j in range(n)) for i in range(n)]
    return sum(u[i] * Au[i] for i in range(n))

N = 5                                           # chain of five masses, k = m = 1
K = [[2.0 if i == j else (-1.0 if abs(i - j) == 1 else 0.0) for j in range(N)] for i in range(N)]
vals, vecs, sweeps = jacobi_eigen(K)
print(f"chain of {N} masses: Jacobi converged in {sweeps} sweeps")
for n, (lam, v) in enumerate(zip(vals, vecs), start=1):
    exact = 2 * math.sin(n * math.pi / (2 * (N + 1)))
    if v[0] < 0: v = [-x for x in v]
    print(f"  mode {n}: omega = {math.sqrt(lam):.12f}   exact {exact:.12f}   shape " +
          " ".join(f"{x:+.3f}" for x in v))
print(f"power iteration, largest omega^2 = {power_iteration(K):.12f}"
      f" (exact {4 * math.sin(5 * math.pi / 12)**2:.12f})")

# Linear triatomic molecule O=C=O along a line: masses 16, 12, 16; one bond constant k = 1
mO, mC = 16.0, 12.0
Kt = [[1, -1, 0], [-1, 2, -1], [0, -1, 1]]
Mi = [1 / math.sqrt(mO), 1 / math.sqrt(mC), 1 / math.sqrt(mO)]
D = [[Mi[i] * Kt[i][j] * Mi[j] for j in range(3)] for i in range(3)]
vals, vecs, _ = jacobi_eigen(D)
w = [math.sqrt(max(v, 0.0)) for v in vals]
print("\nlinear triatomic O-C-O: omega =", " ".join(f"{x:.5f}" for x in w))
print(f"ratio asymmetric/symmetric stretch = {w[2] / w[1]:.4f};"
      f" formula sqrt(1 + 2 mO/mC) = {math.sqrt(1 + 2 * mO / mC):.4f}")
Output
chain of 5 masses: Jacobi converged in 4 sweeps
  mode 1: omega = 0.517638090205   exact 0.517638090205   shape +0.289 +0.500 +0.577 +0.500 +0.289
  mode 2: omega = 1.000000000000   exact 1.000000000000   shape +0.500 +0.500 +0.000 -0.500 -0.500
  mode 3: omega = 1.414213562373   exact 1.414213562373   shape +0.577 +0.000 -0.577 -0.000 +0.577
  mode 4: omega = 1.732050807569   exact 1.732050807569   shape +0.500 -0.500 +0.000 +0.500 -0.500
  mode 5: omega = 1.931851652578   exact 1.931851652578   shape +0.289 -0.500 +0.577 -0.500 +0.289
power iteration, largest omega^2 = 3.732050807569 (exact 3.732050807569)

linear triatomic O-C-O: omega = 0.00000 0.25000 0.47871
ratio asymmetric/symmetric stretch = 1.9149; formula sqrt(1 + 2 mO/mC) = 1.9149

Jacobi's method reproduces the analytic frequencies to twelve digits in a handful of sweeps, and the eigenvectors are the sampled sine patterns of the figure, normalized. Power iteration also finds the largest eigenvalue to full precision, but it needs a couple of hundred iterations, because the two largest eigenvalues of the chain are close together: the error of the Rayleigh quotient shrinks only by \((\lambda_4/\lambda_5)^2 \approx 0.64\) per iteration.

The triatomic model treats carbon dioxide as three masses on a line joined by two identical springs. It has three eigenvalues: zero, for the uniform translation of the whole molecule, which costs no spring energy; the symmetric stretch, in which the oxygens move outward together while the carbon stays still, at \(\omega_s = \sqrt{k/m_O}\); and the asymmetric stretch, in which the carbon moves against both oxygens, at \(\omega_a = \omega_s\sqrt{1 + 2m_O/m_C}\). The model predicts a frequency ratio of 1.915. The measured infrared and Raman frequencies of carbon dioxide, about 1388 and 2349 per centimeter, give a ratio of 1.69. The difference is modeling error in the sense of lesson 1: real bonds interact, and the symmetric stretch is shifted by a resonance with an overtone of the bending mode, which this one-dimensional model leaves out entirely. The asymmetric stretch is the mode that absorbs infrared radiation near 4.3 micrometers, one of the reasons carbon dioxide is a greenhouse gas.

Eigenvalues of a quantum Hamiltonian

Discretizing the Schrödinger equation \(-\psi'' + V\psi = E\psi\) on a grid with spacing \(h\) and \(\psi = 0\) at both ends turns it into the matrix eigenvalue problem \(H\boldsymbol{\psi} = E\boldsymbol{\psi}\), where \(H\) has \(2/h^2 + V_j\) on the diagonal and \(-1/h^2\) beside it. For the infinite well this is exactly the chain matrix divided by \(h^2\), so its eigenvalues are \(E_n = (4/h^2)\sin^2(n\pi h/2)\), which approach the exact \(n^2\pi^2\) with error \(O(h^2)\) for the low states but are badly wrong for states whose wavelength is comparable with the grid spacing. This is a general lesson: a grid of \(N\) points represents \(N\) states, but only the lower part of its spectrum is physically meaningful. Inverse iteration with a shift near a desired energy, using the Thomas algorithm for each solve, extracts any single level of a large tridiagonal Hamiltonian in \(O(N)\) operations per iteration, a matrix alternative to the shooting of lesson 7.

Worked problem

A two-mass chain by hand

Two masses \(m\) are connected to each other and to two walls by three springs of constant \(k\). Find the normal modes.

Show solution
  1. \(K = k\begin{pmatrix} 2 & -1 \\ -1 & 2 \end{pmatrix}\) and \(M = mI\).
  2. \(\det(K - \omega^2 m I) = (2k - m\omega^2)^2 - k^2 = 0\) gives \(m\omega^2 = k\) or \(3k\).
  3. For \(\omega = \sqrt{k/m}\) the eigenvector is \((1, 1)\): the masses move together and the middle spring is never stretched.
  4. For \(\omega = \sqrt{3k/m}\) the eigenvector is \((1, -1)\): the masses move in opposition. The formula \(2\sin(n\pi/6)\) gives 1 and \(\sqrt3\), in agreement.

Answer: \(\omega_1 = \sqrt{k/m}\) with the masses in phase and \(\omega_2 = \sqrt{3k/m}\) with them out of phase.

Common mistakes

  • MistakeSolving a linear system without pivoting.

    InsteadA small pivot magnifies rounding errors; always use partial pivoting for general matrices.

  • MistakeInverting a matrix to solve a single system.

    InsteadComputing \(A^{-1}\) costs about three times as much as elimination and is less accurate; solve \(A\mathbf{x} = \mathbf{b}\) directly.

  • MistakeFinding eigenvalues as roots of the characteristic polynomial.

    InsteadThe polynomial's roots are extremely sensitive to its coefficients; use Jacobi, QR or power-type iterations on the matrix itself.

  • MistakeTreating every eigenvalue of a discretized operator as physical.

    InsteadOnly states with wavelengths much longer than the grid spacing are represented accurately.

  • MistakeIgnoring the mass matrix in a normal-mode calculation with unequal masses.

    InsteadSolve \(K\mathbf{v} = \omega^2 M\mathbf{v}\), for instance by transforming with \(M^{-1/2}\).

Summary and key terms

  • Gaussian elimination with partial pivoting solves dense linear systems in about \(\frac23N^3\) operations and is backward stable.
  • The condition number bounds how much the solution can magnify input errors; ill-conditioned systems such as Hilbert matrices lose many digits.
  • Small oscillations of coupled masses obey \(K\mathbf{v} = \omega^2M\mathbf{v}\); eigenvalues are squared normal-mode frequencies.
  • A uniform chain has frequencies \(2\sqrt{k/m}\sin(n\pi/(2(N+1)))\) and sine-shaped modes.
  • Power iteration finds the dominant eigenvalue, inverse iteration the one nearest a shift, and Jacobi rotations all eigenvalues of a symmetric matrix.
  • A discretized Hamiltonian is a matrix whose low eigenvalues approximate the energy levels.
partial pivoting
Swapping rows during elimination so that each pivot is the largest available in its column.
condition number of a matrix
The product of the norms of a matrix and its inverse; it bounds error magnification.
normal mode
A pattern of motion in which all parts oscillate at one frequency.
Rayleigh quotient
u·Au divided by u·u, an estimate of an eigenvalue from an approximate eigenvector.
inverse iteration
Power iteration with the inverse of a shifted matrix, converging to the eigenvalue nearest the shift.
Jacobi eigenvalue method
Diagonalizing a symmetric matrix by a sequence of plane rotations.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. Solve by elimination with partial pivoting: \(0.001x + y = 1\), \(x + y = 2\).

    Show answer

    Pivoting swaps the rows. Subtracting 0.001 times the new first row gives \(0.999y = 0.998\), so \(y = 0.998999\) and \(x = 1.001001\). Without pivoting, the multiplier 1000 would magnify rounding errors.

  2. Find the frequencies of a chain of three equal masses between walls in units of \(\sqrt{k/m}\).

    Show answer

    \(2\sin(\pi/8) = 0.765\), \(2\sin(\pi/4) = 1.414\) and \(2\sin(3\pi/8) = 1.848\).

  3. A symmetric matrix has eigenvalues 10, 9 and 1. By what factor per iteration does the Rayleigh-quotient error of power iteration shrink?

    Show answer

    By \((9/10)^2 = 0.81\), slow because the top two eigenvalues are close.

  4. Why does the zero eigenvalue appear in the free triatomic molecule but not in the chain between walls?

    Show answer

    Without walls the whole molecule can translate with no spring stretched, a zero-frequency mode; walls remove that freedom.

  5. Using \(E_n = (4/h^2)\sin^2(n\pi h/2)\) with \(h = 0.01\), find the relative error of the ground state of the unit infinite well.

    Show answer

    \(\sin^2\) expands as \((n\pi h/2)^2(1 - (n\pi h)^2/12)\), so the relative error is about \(\pi^2 h^2/12 = 8.2 \times 10^{-5}\).

  6. Estimate the time to solve a dense system with \(N = 10\,000\) at \(10^{10}\) operations per second.

    Show answer

    \(\frac23 N^3 \approx 6.7 \times 10^{11}\) operations, about 67 s.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz