Chapter 11: Eigenvalues and Eigenvectors

Introduction

Some vectors are special - they don’t rotate under a transformation, they just get scaled!

The Big Question

For a transformation represented by matrix A, which vectors v satisfy:

\[ A\vec{v} = \lambda \vec{v} \]

Where λ is just a scalar?

Translation: Find vectors that only get stretched or squished, never rotated!

These special vectors are called eigenvectors, and λ is the corresponding eigenvalue.

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_style('whitegrid')
plt.rcParams['figure.figsize'] = (12, 10)
np.set_printoptions(precision=3, suppress=True)

1. The Eigenvector Concept

Eigenvector: A vector that stays on its own span during the transformation
Eigenvalue: The factor by which it gets scaled

Geometric Picture

When you apply transformation A to eigenvector v:

  • Direction: Stays the same (or exactly opposite)

  • Magnitude: Multiplied by λ

\[ A\vec{v} = \lambda \vec{v} \]

Example: For a horizontal shear, vertical vectors are eigenvectors with λ = 1

def visualize_eigenvectors_concept():
    """Show eigenvectors staying on their span."""
    # Horizontal shear matrix
    A = np.array([[1, 1], [0, 1]])
    
    # Eigenvector: vertical direction [0, 1]
    v_eigen = np.array([0, 1])
    Av_eigen = A @ v_eigen
    
    # Non-eigenvector
    v_other = np.array([1, 1])
    Av_other = A @ v_other
    
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
    
    # Eigenvector
    ax1.quiver(0, 0, v_eigen[0], v_eigen[1], angles='xy', scale_units='xy', scale=1,
               color='green', width=0.01, label='Original eigenvector')
    ax1.quiver(0, 0, Av_eigen[0], Av_eigen[1], angles='xy', scale_units='xy', scale=1,
               color='darkgreen', width=0.008, linestyle='--', label='After transformation (still on span!)')
    
    ax1.axline((0, 0), slope=float('inf'), color='lightgreen', linestyle=':', linewidth=2, alpha=0.5,
               label='Eigenvector span')
    ax1.set_xlim(-1, 3)
    ax1.set_ylim(-0.5, 2)
    ax1.set_aspect('equal')
    ax1.grid(True, alpha=0.3)
    ax1.set_title('Eigenvector: Stays on Span', fontsize=13, fontweight='bold')
    ax1.legend()
    
    # Non-eigenvector
    ax2.quiver(0, 0, v_other[0], v_other[1], angles='xy', scale_units='xy', scale=1,
               color='blue', width=0.01, label='Original vector')
    ax2.quiver(0, 0, Av_other[0], Av_other[1], angles='xy', scale_units='xy', scale=1,
               color='red', width=0.008, label='After transformation (rotated off!)')
    
    ax2.axline((0, 0), (v_other[0], v_other[1]), color='lightblue', linestyle=':', 
               linewidth=2, alpha=0.5, label='Original span')
    ax2.set_xlim(-1, 3)
    ax2.set_ylim(-0.5, 2)
    ax2.set_aspect('equal')
    ax2.grid(True, alpha=0.3)
    ax2.set_title('Non-Eigenvector: Rotates Off Span', fontsize=13, fontweight='bold')
    ax2.legend()
    
    plt.tight_layout()
    plt.show()
    
    print(f"Shear matrix A =\n{A}\n")
    print(f"Eigenvector v = {v_eigen}")
    print(f"A × v = {Av_eigen}")
    print(f"Eigenvalue λ = 1 (no scaling!)\n")
    print(f"Non-eigenvector w = {v_other}")
    print(f"A × w = {Av_other} (rotated away from original direction)")

visualize_eigenvectors_concept()

2. Finding Eigenvalues: The Characteristic Equation

To find eigenvalues, we solve:

\[ A\vec{v} = \lambda \vec{v} \]

Rearrange:

\[ A\vec{v} - \lambda \vec{v} = \vec{0} \]
\[ (A - \lambda I)\vec{v} = \vec{0} \]

Key insight: For non-zero v to exist, (A - λI) must be non-invertible!

This means:

\[ \boxed{\det(A - \lambda I) = 0} \]

This is the characteristic equation!

def demonstrate_characteristic_equation():
    """Show how to find eigenvalues."""
    A = np.array([[3, 1], [0, 2]])
    
    print("Finding Eigenvalues\n")
    print(f"Matrix A =\n{A}\n")
    print("Step 1: Form (A - λI)")
    print("       [3-λ   1  ]")
    print("       [ 0   2-λ ]\n")
    
    print("Step 2: Compute determinant")
    print("       det(A - λI) = (3-λ)(2-λ) - (1)(0)")
    print("                   = 6 - 3λ - 2λ + λ²")
    print("                   = λ² - 5λ + 6\n")
    
    print("Step 3: Solve det(A - λI) = 0")
    print("       λ² - 5λ + 6 = 0")
    print("       (λ - 2)(λ - 3) = 0")
    print("       λ = 2 or λ = 3\n")
    
    # Verify with NumPy
    eigenvalues, eigenvectors = np.linalg.eig(A)
    print(f"NumPy verification: λ = {eigenvalues}")
    
    return eigenvalues, eigenvectors

eigenvalues, eigenvectors = demonstrate_characteristic_equation()

3. Finding Eigenvectors

Once we have eigenvalues, find eigenvectors by solving:

\[ (A - \lambda I)\vec{v} = \vec{0} \]

Process:

  1. Find eigenvalues from det(A - λI) = 0

  2. For each λ, solve (A - λI)v = 0

  3. The solutions are the eigenvectors!

Note: There are infinitely many eigenvectors for each eigenvalue (any scalar multiple works!)

def find_eigenvectors_manually():
    """Find eigenvectors step by step."""
    A = np.array([[3, 1], [0, 2]])
    
    print("Finding Eigenvectors\n")
    print(f"Matrix A = \n{A}\n")
    print("Eigenvalues: λ₁ = 3, λ₂ = 2\n")
    
    # For λ₁ = 3
    lambda1 = 3
    A_minus_lambda1_I = A - lambda1 * np.eye(2)
    print(f"For λ₁ = {lambda1}:")
    print(f"(A - {lambda1}I) = \n{A_minus_lambda1_I}\n")
    print("Solving (A - 3I)v = 0:")
    print("[0  1][x] = [0]")
    print("[0 -1][y]   [0]\n")
    print("This gives: y = 0, x is free")
    print("Eigenvector: v₁ = [1, 0]\n")
    
    # For λ₂ = 2
    lambda2 = 2
    A_minus_lambda2_I = A - lambda2 * np.eye(2)
    print(f"For λ₂ = {lambda2}:")
    print(f"(A - {lambda2}I) = \n{A_minus_lambda2_I}\n")
    print("Solving (A - 2I)v = 0:")
    print("[1  1][x] = [0]")
    print("[0  0][y]   [0]\n")
    print("This gives: x + y = 0, so y = -x")
    print("Eigenvector: v₂ = [1, -1] (or any multiple)\n")
    
    # Verify
    v1 = np.array([1, 0])
    v2 = np.array([1, -1])
    
    print("Verification:")
    print(f"A × v₁ = {A @ v1} = {lambda1} × {v1} ✓")
    print(f"A × v₂ = {A @ v2} = {lambda2} × {v2} ✓")

find_eigenvectors_manually()

4. Eigenvalue Properties

Beautiful connections between eigenvalues and matrix properties!

Sum of Eigenvalues = Trace

\[ \lambda_1 + \lambda_2 + \cdots + \lambda_n = \text{tr}(A) \]

Product of Eigenvalues = Determinant

\[ \lambda_1 \cdot \lambda_2 \cdot \cdots \cdot \lambda_n = \det(A) \]

Why this makes sense:

  • det(A) measures volume scaling

  • Each eigenvalue scales its eigendirection

  • Total volume scaling = product of individual scalings!

def verify_eigenvalue_properties():
    """Verify trace and determinant properties."""
    matrices = [
        ("Example 1", np.array([[4, 2], [1, 3]])),
        ("Example 2", np.array([[5, -2], [3, 1]])),
        ("Example 3", np.array([[2, 1, 0], [0, 3, 1], [0, 0, 4]]))
    ]
    
    for name, A in matrices:
        eigenvalues = np.linalg.eigvals(A)
        trace = np.trace(A)
        det = np.linalg.det(A)
        
        sum_eig = np.sum(eigenvalues)
        prod_eig = np.prod(eigenvalues)
        
        print(f"\n{'='*60}")
        print(f"{name}")
        print(f"{'='*60}")
        print(f"Matrix:\n{A}\n")
        print(f"Eigenvalues: {eigenvalues}\n")
        print(f"Sum of eigenvalues:     {sum_eig:.6f}")
        print(f"Trace of matrix:        {trace:.6f}")
        print(f"Match: {np.isclose(sum_eig, trace)}\n")
        print(f"Product of eigenvalues: {prod_eig:.6f}")
        print(f"Determinant of matrix:  {det:.6f}")
        print(f"Match: {np.isclose(prod_eig, det)} ✓")

verify_eigenvalue_properties()

Summary

Key Concepts

  1. Eigenvectors: Vectors that stay on their span

  2. Eigenvalues: Scaling factors

  3. Characteristic equation: det(A - λI) = 0

  4. Beautiful properties: Σλ = tr(A), ∏λ = det(A)

Applications

  • Stability analysis: Is |λ| < 1 or > 1?

  • Principal components: Directions of maximum variance

  • Google PageRank: Largest eigenvector

  • Quantum mechanics: Energy eigenstates

Next: Abstract vector spaces!