第五章:特征值和特征向量

类层次结构

本章介绍特征值计算相关的类。相关内容请参见:

classDiagram
    class EigenSolverBase~Derived~ {
        <<interface>>
        +compute(Matrix) bool
        +eigenvalues() Vector
        +eigenvectors() Matrix
        +info() ComputationInfo
    }
    
    class EigenSolver~MatrixType~ {
        -m_eigenvalues Vector
        -m_eigenvectors Matrix
        +compute(Matrix) bool
        +eigenvalues() Vector
        +eigenvectors() Matrix
    }
    
    class SelfAdjointEigenSolver~MatrixType~ {
        -m_eigenvalues RealVector
        -m_eigenvectors Matrix
        +compute(Matrix) bool
        +eigenvalues() RealVector
        +eigenvectors() Matrix
    }
    
    class ComplexEigenSolver~MatrixType~ {
        -m_eigenvalues ComplexVector
        -m_eigenvectors ComplexMatrix
        +compute(Matrix) bool
        +eigenvalues() ComplexVector
        +eigenvectors() ComplexMatrix
    }
    
    class GeneralizedEigenSolver~MatrixType~ {
        -m_alpha ComplexVector
        -m_beta Vector
        +compute(MatrixA, MatrixB) bool
        +eigenvalues() ComplexVector
        +eigenvectors() ComplexMatrix
    }
    
    EigenSolverBase <|-- EigenSolver
    EigenSolverBase <|-- SelfAdjointEigenSolver
    EigenSolverBase <|-- ComplexEigenSolver
    EigenSolverBase <|-- GeneralizedEigenSolver

类说明

  1. EigenSolver:通用特征值求解器
    • 适用于一般方阵
    • 返回实数或复数特征值
    • 计算复杂度 O(n³)
  2. SelfAdjointEigenSolver:对称矩阵专用
    • 仅适用于对称/厄米特矩阵
    • 保证返回实数特征值
    • 性能优于通用求解器
  3. ComplexEigenSolver:复数矩阵专用
    • 处理复数矩阵
    • 返回复数特征值和特征向量
    • 支持一般复数矩阵

5.1 基本概念

对于一个矩阵而言,特征值和特征向量是矩阵的最重要的性质之一。数学概念如下:

在实际矩阵分析中,特征值和特征向量可以帮助我们理解矩阵的性质,比如矩阵的稳定性、振动特性、对角化等。这在实际的工程应用中非常重要。例如,在机械振动分析中,特征值和特征向量可以帮助我们理解机械系统的振动特性,从而进行结构优化和故障诊断。

5.1.1 特征值问题

5.1.2 特征值类型

5.2 特征值计算

5.2.1 计算方法

5.2.2 数值稳定性

5.2.2 基本算法实现

一般矩阵

Matrix3d A;
// ... 初始化矩阵 A ...
EigenSolver<Matrix3d> solver(A);
Vector3cd eigenvalues = solver.eigenvalues();
Matrix3cd eigenvectors = solver.eigenvectors();

实对称矩阵

// 对于实对称矩阵,特征值和特征向量都是实数
SelfAdjointEigenSolver<Matrix3d> solver(A);
Vector3d eigenvalues = solver.eigenvalues();
Matrix3d eigenvectors = solver.eigenvectors();

5.2.3 性能优化

计算优化

内存优化

5.3 高级特征值计算

5.3.1 广义特征值问题

// 求解 Ax = λBx
GeneralizedEigenSolver<Matrix3d> solver(A, B);
Vector3cd eigenvalues = solver.eigenvalues();

5.3.2 实对称广义特征值问题

// 当A和B都是实对称矩阵时
GeneralizedSelfAdjointEigenSolver<Matrix3d> solver(A, B);
Vector3d eigenvalues = solver.eigenvalues();

5.4 应用实例

5.4.1 主成分分析(PCA)

// 计算协方差矩阵
MatrixXd centered = data.rowwise() - data.colwise().mean();
MatrixXd cov = (centered.adjoint() * centered) / double(data.rows() - 1);

// 计算特征值和特征向量
SelfAdjointEigenSolver<MatrixXd> solver(cov);
VectorXd principal_values = solver.eigenvalues();
MatrixXd principal_vectors = solver.eigenvectors();

5.4.2 模态分析

// 求解结构动力学特征值问题 Kx = λMx
GeneralizedSelfAdjointEigenSolver<MatrixXd> solver(K, M);
VectorXd frequencies = solver.eigenvalues().cwiseSqrt() / (2 * M_PI);
MatrixXd modes = solver.eigenvectors();

5.5 代码示例说明

5.5.1 eigenvalues.cpp 详解

这个示例展示了如何计算矩阵的特征值和特征向量,并验证计算结果。让我们逐行分析代码:

Matrix3d A;
A << 1, 2, 3,
    2, 4, 5,
    3, 5, 6;
EigenSolver<Matrix3d> solver(A);

一般特征值求解器:

SelfAdjointEigenSolver<Matrix3d> symm_solver(A);

对称矩阵特征值求解器:

Vector3cd eigenval = solver.eigenvalues();
Matrix3cd eigenvec = solver.eigenvectors();

获取特征值和特征向量:

for (int i = 0; i < 3; ++i) {
    cout << "λv =\n" << eigenval(i) * eigenvec.col(i) << "\n";
    cout << "Av =\n" << A * eigenvec.col(i) << "\n\n";
}

验证计算结果:

重要概念说明

  1. 特征值求解器类型
    • EigenSolver: 一般矩阵
    • SelfAdjointEigenSolver: 实对称矩阵
    • ComplexEigenSolver: 复数矩阵
  2. 数据类型
    • Matrix3d: 3×3实数矩阵
    • Vector3cd: 3维复数向量
    • Matrix3cd: 3×3复数矩阵
  3. 特征值排序
    • SelfAdjointEigenSolver 默认按降序排列特征值
    • EigenSolver 的特征值排序可能不确定
  4. 验证方法
    • 检查 (Av = \lambda v)
    • 数值计算可能有小的误差
    • 特征向量的模长默认归一化

注意事项

  1. 对于实对称矩阵,优先使用 SelfAdjointEigenSolver
  2. 验证结果时要考虑数值误差
  3. 特征向量的方向可能与预期相反(因为 (v) 和 (-v) 都是特征向量)
  4. 对于重特征值,对应的特征向量可能不唯一

5.5.2 pca_example.cpp 详解

这个示例展示了如何使用 Eigen 实现主成分分析(PCA)。让我们逐行分析代码:

#include <Eigen/Dense>

引入 Eigen 的密集矩阵运算模块,包含了我们需要的所有矩阵操作。

MatrixXd data(100, 3);
for (int i = 0; i < 100; ++i) {
    data.row(i) = Vector3d::Random();
}
MatrixXd centered = data.rowwise() - data.colwise().mean();

数据中心化处理:

MatrixXd cov = (centered.adjoint() * centered) / double(data.rows() - 1);

计算协方差矩阵:

SelfAdjointEigenSolver<MatrixXd> solver(cov);

创建特征值求解器:

solver.eigenvalues()    // 获取特征值
solver.eigenvectors()   // 获取特征向量
MatrixXd pc = centered * solver.eigenvectors();

数据投影:

重要对象和方法说明

  1. MatrixXd
    • X 表示大小可变
    • d 表示元素类型为 double
    • 常用操作:
      • .rows(): 获取行数
      • .cols(): 获取列数
      • .row(i): 访问第i行
      • .col(i): 访问第i列
  2. Vector3d
    • 3维向量(固定大小)
    • 静态方法:
      • ::Random(): 生成随机向量
      • ::Zero(): 生成零向量
      • ::Ones(): 生成全1向量
  3. 矩阵运算
    • .adjoint(): 共轭转置
    • .transpose(): 转置
    • .colwise(): 按列操作
    • .rowwise(): 按行操作
  4. SelfAdjointEigenSolver
    • 专门用于对称矩阵的特征值分解
    • 主要方法:
      • eigenvalues(): 获取特征值
      • eigenvectors(): 获取特征向量
      • compute(): 重新计算新矩阵的特征值

5.6 注意事项

  1. 数值稳定性
    • 对于病态矩阵,结果可能不准确
    • 考虑使用预处理或平衡技术
  2. 计算效率
    • 利用矩阵的特殊结构(对称、正定等)
    • 只计算需要的特征值/特征向量
  3. 特征向量的归一化
    • 默认返回的特征向量是归一化的
    • 可以使用 .normalized() 重新归一化