BRAGA

02 Writing02-02 Notes02-02-165

Trace Identity (eigenvalues)

Published 16 Apr 20268 min read
Contents
  1. 01Deep Breakdown
  2. 02Flowchart
  3. 03Real-world use
  4. 04The formula, piece by piece
  5. 05The formula in words
  6. 06Critical Concepts
  7. 07Step-by-step calculation (tiny example)
  8. 08Code examples
tr(A)=∑iλi\text{tr}(A) = \sum_{i} \lambda_i
(1)

Deep Breakdown

What it tells me (Situation Awareness): The trace of a square matrix equals the sum of its eigenvalues: tr(A)=∑iλi\text{tr}(A) = \sum_i \lambda_i. This connects two different representations of the same matrix: the trace (computable in O(n)O(n) from the diagonal) and the eigenvalues (requiring O(n3)O(n^3) eigendecomposition). The identity provides a fast sanity check after eigendecomposition and, more importantly, a direct interpretation of the trace in terms of the spectrum. In DA/DS and ML, this identity is used constantly in PCA: the trace of a covariance matrix Σ\Sigma equals the total variance in the data, and since tr(Σ)=∑iλi\text{tr}(\Sigma) = \sum_i \lambda_i, the fraction of variance explained by the top kk principal components is ∑i=1kλitr(Σ)\frac{\sum_{i=1}^k \lambda_i}{\text{tr}(\Sigma)}. It also appears in regularization theory, spectral graph analysis, and the Stein's lemma for risk estimation.

Flowchart

PCA varianceSanity checkNuclear norm boundRegularizationInput: squarematrix A (n x n)Path 1: computetrace directlyfrom diagonalPath 2: computeeigenvalues,then sum themtr(A) = a_11 +a_22 + ... +a_nn (O(n) cost)eigenvalues =eig(A) (O(n^3)cost)sum(eigenvalues)Both paths givethe same scalarDA/DS use caseexplained_ratio_k = sum(top keigenvalues) /tr(Sigma)After eigdecomp:sum(lambdas)== tr(A)?tr(A) =sum(lambdas)bounds matrixenergyRidge penalty:lambda * tr(I) =lambda * n

Real-world use

Where it is used

Used in PCA to compute the explained variance ratio for each component, in spectral graph theory where tr(Ak)\text{tr}(A^k) counts closed walks of length kk, as a fast sanity check after eigendecomposition, in covariance matrix analysis to interpret total data spread, and in trace-norm regularization for matrix completion (collaborative filtering, recommender systems).

Problem it solves

Computing eigenvalues is expensive (O(n3)O(n^3)). When you only need the sum of eigenvalues (e.g., to get total variance), you get it for free from the trace in O(n)O(n). Conversely, when you already have the eigenvalues from a PCA, you can verify your computation by checking ∑iλi=tr(Σ)\sum_i \lambda_i = \text{tr}(\Sigma) without recomputing the trace from scratch.

How it solves the problem

The identity follows from the characteristic polynomial: tr(A)\text{tr}(A) equals the negative of the coefficient of λn−1\lambda^{n-1} in det⁡(λI−A)\det(\lambda I - A), which also equals ∑iλi\sum_i \lambda_i. More intuitively, in the eigenbasis A=QΛQ−1A = Q\Lambda Q^{-1}, so tr(A)=tr(QΛQ−1)=tr(ΛQ−1Q)=tr(Λ)=∑iλi\text{tr}(A) = \text{tr}(Q\Lambda Q^{-1}) = \text{tr}(\Lambda Q^{-1}Q) = \text{tr}(\Lambda) = \sum_i \lambda_i (using the cyclic property of trace).

Example in a business

A data scientist runs PCA on a customer behaviour dataset with p=20p = 20 features. The covariance matrix eigenvalues are λ1,…,λ20\lambda_1, \dots, \lambda_{20}. They compute the number of components needed to explain 90% of variance: the threshold is ∑i=1kλi≥0.90⋅tr(Σ)\sum_{i=1}^k \lambda_i \geq 0.90 \cdot \text{tr}(\Sigma). Using np.trace(cov_matrix) (fast) for the denominator and the sorted eigenvalues for the numerator, they find k=6k = 6 components explain 91% of variance, reducing 20 dimensions to 6.

The formula, piece by piece

  • tr(A)\text{tr}(A): the trace of matrix AA; the sum of all diagonal entries a11+a22+⋯+anna_{11} + a_{22} + \cdots + a_{nn}; computed in O(n)O(n)
  • ∑i\sum_i: sum over all nn eigenvalues, each counted with its algebraic multiplicity
  • λi\lambda_i: the ii-th eigenvalue of AA; possibly complex for non-symmetric AA; always real for symmetric positive semi-definite matrices (like covariance matrices)
  • The equality: invariant to basis change; both the trace and the eigenvalue sum are spectrum invariants Full formula: tr(A)=∑i=1nλi\text{tr}(A) = \sum_{i=1}^n \lambda_i

The formula in words

"The sum of the diagonal entries of a matrix equals the sum of its eigenvalues. You don't need to compute eigenvalues to get their sum — the diagonal already encodes it. Conversely, after an eigendecomposition, the eigenvalue sum gives you a free sanity check." Tiny numeric example: A=[5223]A = \begin{bmatrix}5 & 2 \\ 2 & 3\end{bmatrix}. tr(A)=5+3=8\text{tr}(A) = 5 + 3 = 8. Eigenvalues: λ2−8λ+(15−4)=0  ⟹  λ2−8λ+11=0  ⟹  λ=4±5\lambda^2 - 8\lambda + (15-4) = 0 \implies \lambda^2 - 8\lambda + 11 = 0 \implies \lambda = 4 \pm \sqrt{5}. λ1+λ2=(4+5)+(4−5)=8=tr(A)\lambda_1 + \lambda_2 = (4+\sqrt{5}) + (4-\sqrt{5}) = 8 = \text{tr}(A).

Critical Concepts

  • Trace is basis-independent: tr(A)=tr(P−1AP)\text{tr}(A) = \text{tr}(P^{-1}AP) for any invertible PP. Changing the coordinate system doesn't change the sum of diagonal entries. This is why it equals the eigenvalue sum (spectrum = invariant).
  • Complex eigenvalues come in conjugate pairs for real matrices: tr\text{tr} is real, so the imaginary parts cancel. The sum of eigenvalues is always real for real AA.
  • Repeated eigenvalues: if λ\lambda has algebraic multiplicity mm, it contributes mλm\lambda to the sum, not just λ\lambda.
  • PCA connection: for a covariance matrix Σ\Sigma, all eigenvalues are non-negative, so tr(Σ)=∑λi\text{tr}(\Sigma) = \sum \lambda_i is the total variance. Explained variance ratio: rk=∑i=1kλi/tr(Σ)r_k = \sum_{i=1}^k \lambda_i / \text{tr}(\Sigma).
  • Relation to Frobenius norm: ∥A∥F2=tr(ATA)=∑iσi2\|A\|_F^2 = \text{tr}(A^T A) = \sum_i \sigma_i^2 (singular values squared), not eigenvalues. Don't confuse eigenvalues with singular values.
  • Trace of matrix power: tr(Ak)=∑iλik\text{tr}(A^k) = \sum_i \lambda_i^k.

In graph theory, tr(A3)/6\text{tr}(A^3)/6 counts triangles in the adjacency matrix.

Step-by-step calculation (tiny example)

Step 1: Compute the trace directly from the diagonal A=[4132]A = \begin{bmatrix}4 & 1 \\ 3 & 2\end{bmatrix}. tr(A)=a11+a22=4+2=6\text{tr}(A) = a_{11} + a_{22} = 4 + 2 = 6.

Step 2: Find the eigenvalues via the characteristic polynomial det⁡(λI−A)=(λ−4)(λ−2)−1⋅3=λ2−6λ+5=0\det(\lambda I - A) = (\lambda - 4)(\lambda - 2) - 1 \cdot 3 = \lambda^2 - 6\lambda + 5 = 0. (λ−1)(λ−5)=0  ⟹  λ1=1,λ2=5(\lambda - 1)(\lambda - 5) = 0 \implies \lambda_1 = 1, \lambda_2 = 5.

Step 3: Verify the trace identity λ1+λ2=1+5=6=tr(A)\lambda_1 + \lambda_2 = 1 + 5 = 6 = \text{tr}(A). Note: λ1⋅λ2=5=det⁡(A)=8−3=5\lambda_1 \cdot \lambda_2 = 5 = \det(A) = 8 - 3 = 5 (trace = eigenvalue sum, det = eigenvalue product).

Code examples

Beginner example (Python)

python
import numpy as np

# -- tr(A) = sum of eigenvalues: verification and PCA variance check ---
A = np.array([[4.0, 1.0], [3.0, 2.0]])
trace_direct = float(np.trace(A))
eigenvalues, _ = np.linalg.eig(A)
trace_from_eigs = float(np.sum(eigenvalues.real))   # real part (imag ~ 0 for real symm)
print(f"Matrix A:\n{A}")
print(f"\nTrace (diagonal sum): {trace_direct:.6f}")
print(f"Sum of eigenvalues: {trace_from_eigs:.6f}")
print(f"Identity holds: {np.isclose(trace_direct, trace_from_eigs)}")

# Symmetric PSD example: covariance matrix
np.random.seed(42)
cov = np.cov(np.random.randn(5, 50))   # 5x5 sample covariance
eigvals_cov = np.linalg.eigvalsh(cov)   # eigvalsh for symmetric: real eigenvalues
print(f"\nCovariance matrix trace: {float(np.trace(cov)):.6f}")
print(f"Sum of eigenvalues: {float(np.sum(eigvals_cov)):.6f}")
print(f"Explained variance ratio per component: {eigvals_cov[::-1] / np.trace(cov)}")

Beginner example (R)

r
# -- tr(A) = sum of eigenvalues: verification and PCA variance check ---
A <- matrix(c(4, 1, 3, 2), nrow = 2, byrow = TRUE)
trace_direct <- sum(diag(A))  # R has no built-in trace(); use sum(diag())
eig_result <- eigen(A)
trace_eigsum <- sum(Re(eig_result$values))
cat(sprintf("Trace (diagonal sum): %.6f\n", trace_direct))
cat(sprintf("Sum of eigenvalues: %.6f\n", trace_eigsum))
cat(sprintf("Identity holds: %s\n", isTRUE(all.equal(trace_direct, trace_eigsum))))

# PCA variance
set.seed(42)
X_data <- matrix(rnorm(50 * 5), nrow = 50, ncol = 5)
cov_mat <- cov(X_data)
eigvals <- eigen(cov_mat, symmetric = TRUE)$values  # sorted descending
cat(sprintf("\nCovariance matrix trace: %.6f\n", sum(diag(cov_mat))))
cat(sprintf("Sum of eigenvalues: %.6f\n", sum(eigvals)))
cat(sprintf("Explained variance ratio: %s\n", paste(round(eigvals / sum(diag(cov_mat)), 4), collapse = ", ")))

Professional example (Python)

python
import numpy as np
import pandas as pd
np.random.seed(42)

# -- Business scenario: PCA component selection using trace identity
# Customer behaviour dataset: 20 features.
# Use tr(Sigma) as the total-variance denominator (O(n) cost, no eigendecomp needed).
# Then determine how many PCA components explain >= 90% of variance.
N_OBS = 500
N_FEATURES = 20
VARIANCE_THRESHOLD = 0.90
FEATURE_NAMES = [f"behaviour_{i:02d}" for i in range(1, N_FEATURES + 1)]

# Simulate data with latent structure: first 5 factors drive most variance
latent_factors = np.random.randn(N_OBS, 5)
factor_scales = np.array([2.0, 1.5, 1.2, 0.8, 0.5])
loadings = np.random.randn(5, N_FEATURES) * factor_scales[:, None]   # scale each factor's row
noise = np.random.randn(N_OBS, N_FEATURES) * 0.3
X = latent_factors @ loadings + noise

# Center and compute covariance matrix
X_centered = X - X.mean(axis=0)
cov_matrix = np.cov(X_centered.T)   # (20 x 20)

# Total variance via trace (O(n), no eigendecomp required)
total_variance = float(np.trace(cov_matrix))

# Eigendecomposition for component analysis
eigenvalues = np.linalg.eigvalsh(cov_matrix)[::-1]   # sorted descending

# Verify trace identity
trace_vs_eigsum_match = np.isclose(total_variance, float(np.sum(eigenvalues)))

# Find k components to exceed the variance threshold
cumulative_ratio = np.cumsum(eigenvalues) / total_variance
k_components = int(np.searchsorted(cumulative_ratio, VARIANCE_THRESHOLD)) + 1

# Summary table
component_df = pd.DataFrame({
    "component": range(1, N_FEATURES + 1),
    "eigenvalue": eigenvalues.round(4),
    "explained_pct": (eigenvalues / total_variance * 100).round(2),
    "cumulative_pct": (cumulative_ratio * 100).round(2),
})
print(f"Total variance tr(Sigma) = {total_variance:.4f}")
print(f"Sum of eigenvalues = {float(np.sum(eigenvalues)):.4f}")
print(f"Trace identity holds : {trace_vs_eigsum_match}")
print(f"\nComponents needed for {VARIANCE_THRESHOLD*100:.0f}% variance: {k_components}")
print(f"\nPer-component breakdown (top 10):")
print(component_df.head(10).to_string(index=False))
print(f"\nInterpretation: tr(Sigma) = sum(lambda_i) gives the total variance in O(n) without eigendecomposition. Dividing each lambda_i by tr(Sigma) gives the PCA explained variance ratio, enabling component count selection.")

Source: MYLA p. 6

#linear-algebra#matrices-and-determinants#determinants-and-inverses

Keyboard shortcuts

Single keys, ignored while typing in a field or with Cmd, Ctrl or Alt held.

0
Home
1 2 3 4
Work, Writing, Tools, About
j / k
Next / previous section on this page
n / p
Next / previous project or essay
u
Up one level
l
Deutsch
t
Light or dark theme
?
This list
Esc
Close