1、Dense简介
1️.Dense 模块概述
Eigen::Dense
模块是 Eigen 的核心模块之一,主要用于处理 密集矩阵(Dense Matrix)和向量(Dense Vector) 。它与 Eigen 的稀疏矩阵模块(Eigen::Sparse
)互补。
特点:
-
支持固定和动态大小
- 固定大小:如
Matrix3d
、Vector4f
- 动态大小:如
MatrixXd
、VectorXd
- 优势:固定大小矩阵在编译期优化,速度快;动态大小矩阵灵活性高。
- 固定大小:如
-
面向表达式模板(Expression Templates)
- Eigen 的运算不是立即计算,而是构建表达式树
- 优点:减少临时变量、延迟计算、优化性能
-
高性能
- 内存连续(RowMajor 或 ColumnMajor,可选)
- 支持 SIMD 向量化(如 SSE、AVX)
- 适合线性代数、最小二乘、矩阵分解、几何变换等场景
-
丰富的线性代数支持
- 基本运算:加减、乘除、转置
- 矩阵分解:LU、QR、SVD、Cholesky、EigenSolver
- 特殊矩阵生成:零矩阵、单位矩阵、全1矩阵
- 块操作:
block()
、row()
、col()
、segment()
-
模板化设计
- 数据类型可选:
float
、double
、int
等 - 支持矩阵和向量混合运算
- 数据类型可选:
2️.Dense 模块核心类型
类型 | 描述 | 备注 |
---|---|---|
Matrix<T, Rows, Cols> |
通用矩阵 | Rows 和 Cols 可固定或动态(用 Dynamic ) |
Vector<T, Size> |
列向量 | 等价于 Matrix<T, Size, 1> |
RowVector<T, Size> |
行向量 | 等价于 Matrix<T, 1, Size> |
Array<T, Rows, Cols> |
元素逐一运算 | 用于逐元素加减乘除等 |
DiagonalMatrix<T, Size> |
对角矩阵 | 可与矩阵相乘或求逆 |
Quaternion<T> |
四元数 | 用于旋转表示 |
AngleAxis<T> |
旋转轴角表示 | 可转换为旋转矩阵 |
3.Dense 模块内部机制
-
内存布局
- 默认按列主序(ColumnMajor)
- 可改为行主序(
Matrix<T, Rows, Cols, RowMajor>
)
-
表达式模板
- 避免临时矩阵
- 支持链式运算
A + B + C
高效执行
-
固定 vs 动态大小
- 固定大小在编译期优化,适合小矩阵(如 2x2, 3x3)
- 动态大小适合大矩阵(如点云处理、最小二乘)
-
SIMD 向量化
- 自动利用 CPU SIMD 指令(SSE/AVX)
- 速度可接近手写优化代码
2、Eigen/Dense 基础
2.1 引入头文件
cpp
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
using namespace std;
Eigen/Dense
会自动包含 Eigen 所有核心模块,适合大部分线性代数操作。- 使用
using namespace Eigen
简化类型书写。
2.2 向量类型
Eigen 中向量是矩阵的特殊情况,行向量或列向量。
cpp
Vector3d v1(1.0, 2.0, 3.0); // 列向量 3x1, double 类型
Vector3f v2(1.0f, 2.0f, 3.0f); // float 类型
VectorXd vDynamic(5); // 动态大小向量
vDynamic << 1, 2, 3, 4, 5;
Vector3d
→ 3维 double 列向量VectorXd
→ 动态维度列向量<<
可快速赋值
2.3 矩阵类型
cpp
Matrix3d A; // 3x3 double 矩阵
MatrixXd B(2, 3); // 2x3 动态矩阵
A << 1, 2, 3,
4, 5, 6,
7, 8, 9;
B << 1, 2, 3,
4, 5, 6;
Matrix3d
→ 3x3 固定大小矩阵MatrixXd
→ 动态大小矩阵<<
支持逐行填充
2.4 矩阵操作
cpp
Matrix3d M;
M << 1, 2, 3,
0, 1, 4,
5, 6, 0;
// 转置
Matrix3d Mt = M.transpose();
// 逆矩阵
Matrix3d Minv = M.inverse();
// 矩阵乘法
Matrix3d R = M * Mt;
// 元素逐一操作
Matrix3d N = M.array() + 1.0; // 每个元素加1
Matrix3d P = M.array() * 2; // 每个元素乘2
matrix.array()
→ 逐元素操作matrix * matrix2
→ 矩阵乘法matrix.inverse()
→ 求逆(仅对方阵有效)
2.5 特殊矩阵生成
cpp
Matrix3d I = Matrix3d::Identity(); // 单位矩阵
MatrixXd Z = MatrixXd::Zero(2, 3); // 零矩阵
MatrixXd O = MatrixXd::Ones(2, 3); // 全1矩阵
2.6 矩阵块操作
cpp
Matrix3d M;
M << 1,2,3,
4,5,6,
7,8,9;
// 提取子矩阵
Matrix2d sub = M.block<2,2>(0,0); // 左上角2x2块
// 改变子矩阵
M.block<2,2>(1,1) = Matrix2d::Identity();
block<rows,cols>(i,j)
→ 固定大小块block(i,j,rows,cols)
→ 动态块
2.7 特征值与奇异值分解
cpp
Matrix3d A;
A << 1, 2, 3,
0, 1, 4,
5, 6, 0;
// Eigen值分解(仅对方阵)
EigenSolver<Matrix3d> es(A);
cout << "Eigenvalues:\n" << es.eigenvalues() << endl;
cout << "Eigenvectors:\n" << es.eigenvectors() << endl;
// 奇异值分解
JacobiSVD<MatrixXd> svd(A, ComputeFullU | ComputeFullV);
cout << "U:\n" << svd.matrixU() << endl;
cout << "S:\n" << svd.singularValues() << endl;
cout << "V:\n" << svd.matrixV() << endl;
EigenSolver
→ 特征值与特征向量JacobiSVD
→ 奇异值分解,用于非方阵或最小二乘
3、Eigen 实战示例
示例1:最小二乘拟合直线
cpp
int n = 5;
VectorXd x(n), y(n);
x << 0, 1, 2, 3, 4;
y << 1, 3, 7, 13, 21;
// 构造 A*x = b
MatrixXd A(n,2);
A.col(0) = VectorXd::Ones(n);
A.col(1) = x;
VectorXd coeff = A.colPivHouseholderQr().solve(y);
cout << "y = " << coeff(1) << " * x + " << coeff(0) << endl;
- 用
colPivHouseholderQr()
进行最小二乘求解 - 输出拟合直线参数
示例2:旋转矩阵 + 向量变换(机器人/SLAM常用)
cpp
Matrix3d R;
R = AngleAxisd(M_PI/4, Vector3d::UnitZ()).toRotationMatrix();
Vector3d t(1, 2, 3);
Vector3d p(1, 0, 0);
// 变换
Vector3d p_trans = R * p + t;
cout << "Transformed point: " << p_trans.transpose() << endl;
AngleAxisd
→ 构造绕某轴旋转的旋转矩阵R*p + t
→ 坐标变换
示例3:点云质心和协方差矩阵
cpp
MatrixXd points(3,5);
points << 1,2,3,4,5,
0,1,0,1,0,
2,3,4,5,6;
// 计算质心
Vector3d centroid = points.rowwise().mean();
// 去质心
MatrixXd centered = points.colwise() - centroid;
// 协方差矩阵
Matrix3d cov = (centered * centered.transpose()) / (points.cols() - 1);
cout << "Covariance matrix:\n" << cov << endl;
- 常用于 PCA、点云处理、SLAM
示例4:动态稀疏求解(大规模线性系统)
cpp
MatrixXd A = MatrixXd::Random(1000, 500);
VectorXd b = VectorXd::Random(1000);
// 最小二乘解
VectorXd x = A.colPivHouseholderQr().solve(b);
cout << "Residual norm: " << (A*x - b).norm() << endl;
- 大规模系统可直接用 Eigen 的
QR
或SVD
求解 - 高性能场景可使用稀疏模块(
Eigen/Sparse
)
4、️总结与应用场景
Dense 模块特点
- 面向密集矩阵、向量运算
- 支持固定和动态维度
- 支持矩阵运算、分解、块操作
- 高度模板化,性能优秀
实战应用
- 机器人/SLAM:位姿变换、最小二乘优化、点云协方差计算
- 计算机视觉:PCA、SVD、特征提取
- 数值计算:大规模线性方程求解、矩阵分解、特征值问题