Generalized Eigenvalues¶
Generalized eigenvalue problems solve \(Av = \lambda Bv\).
Mental Model
The standard eigenvalue problem asks "which vectors does \(A\) merely scale?" The generalized problem asks "which vectors does \(A\) scale relative to \(B\)?" This arises naturally in physics and engineering when the mass matrix \(B\) and stiffness matrix \(A\) define vibration modes, and in statistics where it underpins Fisher's discriminant analysis.
linalg.eig with Two Matrices¶
1. Basic Usage¶
```python import numpy as np from scipy import linalg
def main(): A = np.array([[1, 2], [3, 4]]) B = np.array([[5, 6], [7, 8]])
# Solve A @ v = λ @ B @ v
eigenvalues, eigenvectors = linalg.eig(A, B)
print("Generalized eigenvalues:")
print(eigenvalues)
print()
print("Generalized eigenvectors:")
print(eigenvectors)
if name == "main": main() ```
2. Verify Solution¶
```python import numpy as np from scipy import linalg
def main(): A = np.array([[4, 2], [2, 3]]) B = np.array([[2, 0], [0, 1]])
eigenvalues, eigenvectors = linalg.eig(A, B)
for i in range(len(eigenvalues)):
lam = eigenvalues[i]
v = eigenvectors[:, i]
Av = A @ v
lam_Bv = lam * B @ v
print(f"Eigenvalue {i}: λ = {lam:.4f}")
print(f" Match: {np.allclose(Av, lam_Bv)}")
if name == "main": main() ```
Symmetric Generalized Problem¶
1. linalg.eigh with B¶
```python import numpy as np from scipy import linalg
def main(): # Both A and B symmetric, B positive definite A = np.array([[4, 2], [2, 3]]) B = np.array([[2, 0.5], [0.5, 1]])
eigenvalues, eigenvectors = linalg.eigh(A, B)
print("Eigenvalues (real, sorted):")
print(eigenvalues)
if name == "main": main() ```
2. B-Orthogonality¶
```python import numpy as np from scipy import linalg
def main(): A = np.array([[4, 2], [2, 3]]) B = np.array([[2, 0], [0, 1]])
eigenvalues, V = linalg.eigh(A, B)
# Eigenvectors are B-orthonormal: V.T @ B @ V = I
print("V.T @ B @ V:")
print((V.T @ B @ V).round(10))
if name == "main": main() ```
Applications¶
1. Vibration Analysis¶
```python import numpy as np from scipy import linalg
def main(): # Mass-spring system: K @ x = ω² @ M @ x K = np.array([[3, -1, 0], [-1, 2, -1], [0, -1, 1]]) M = np.array([[2, 0, 0], [0, 1, 0], [0, 0, 1]])
eigenvalues, modes = linalg.eigh(K, M)
print("Natural frequencies (ω):")
print(np.sqrt(eigenvalues))
if name == "main": main() ```
2. Fisher's Linear Discriminant¶
```python import numpy as np from scipy import linalg
def main(): np.random.seed(42)
class1 = np.random.randn(50, 3) + [0, 0, 0]
class2 = np.random.randn(50, 3) + [2, 1, 1]
S_W = np.cov(class1.T) + np.cov(class2.T)
m1, m2 = class1.mean(axis=0), class2.mean(axis=0)
diff = (m1 - m2).reshape(-1, 1)
S_B = diff @ diff.T
eigenvalues, eigenvectors = linalg.eig(S_B, S_W)
idx = np.argmax(eigenvalues.real)
w = eigenvectors[:, idx].real
print("Optimal projection:")
print(w / np.linalg.norm(w))
if name == "main": main() ```
Summary¶
| Function | Description |
|---|---|
linalg.eig(A, B) |
General Av = λBv |
linalg.eigh(A, B) |
Symmetric A, SPD B |
linalg.qz(A, B) |
QZ decomposition |
Exercises¶
Exercise 1.
Solve the generalized eigenvalue problem \(Av = \lambda Bv\) for \(A = \begin{pmatrix} 6 & 2 \\ 2 & 4 \end{pmatrix}\) and \(B = \begin{pmatrix} 2 & 0 \\ 0 & 1 \end{pmatrix}\) using linalg.eigh(A, B). Verify that \(V^T B V = I\) (B-orthogonality) and that \(Av_i = \lambda_i B v_i\) for each eigenpair.
Solution to Exercise 1
import numpy as np
from scipy import linalg
A = np.array([[6, 2],
[2, 4]])
B = np.array([[2, 0],
[0, 1]])
eigenvalues, V = linalg.eigh(A, B)
# B-orthogonality
b_orth = V.T @ B @ V
print(f"V^T B V:\n{b_orth.round(10)}")
print(f"B-orthogonal: {np.allclose(b_orth, np.eye(2))}")
# Verify Av = lambda Bv
for i in range(len(eigenvalues)):
lam = eigenvalues[i]
v = V[:, i]
print(f"lambda={lam:.4f}, Av=lBv: {np.allclose(A @ v, lam * B @ v)}")
Exercise 2. Model a 3-mass spring system with stiffness matrix \(K = \begin{pmatrix} 5 & -2 & 0 \\ -2 & 4 & -2 \\ 0 & -2 & 3 \end{pmatrix}\) and mass matrix \(M = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 2 & 0 \\ 0 & 0 & 1 \end{pmatrix}\). Find the natural frequencies \(\omega_i = \sqrt{\lambda_i}\) by solving the generalized eigenvalue problem \(Kx = \lambda M x\).
Solution to Exercise 2
import numpy as np
from scipy import linalg
K = np.array([[5, -2, 0],
[-2, 4, -2],
[0, -2, 3]])
M = np.array([[1, 0, 0],
[0, 2, 0],
[0, 0, 1]])
eigenvalues, modes = linalg.eigh(K, M)
frequencies = np.sqrt(eigenvalues)
print("Eigenvalues (omega^2):", eigenvalues)
print("Natural frequencies (omega):", frequencies)
Exercise 3.
Generate two random \(4 \times 4\) matrices with np.random.seed(42). Make \(A\) symmetric (\(A = B_1 + B_1^T\)) and \(B\) symmetric positive definite (\(B = B_2^T B_2 + 4I\)). Solve the generalized problem with linalg.eigh(A, B) and verify the result by checking \(\|A V - B V \Lambda\|_F < 10^{-10}\) where \(\Lambda = \text{diag}(\lambda)\).
Solution to Exercise 3
import numpy as np
from scipy import linalg
np.random.seed(42)
B1 = np.random.randn(4, 4)
B2 = np.random.randn(4, 4)
A = B1 + B1.T
B = B2.T @ B2 + 4 * np.eye(4)
eigenvalues, V = linalg.eigh(A, B)
Lambda = np.diag(eigenvalues)
error = np.linalg.norm(A @ V - B @ V @ Lambda)
print(f"Eigenvalues: {eigenvalues}")
print(f"Verification error: {error:.2e}")
assert error < 1e-10