注:本文为 “Eigen 矩阵操作 ” 相关合辑。
略作重排,未整理去重。
如有内容异常,请看原文。
Eigen 库矩阵基本操作:转置矩阵、逆矩阵、伴随矩阵与特征值分析
齐天大圣~~ 于 2018-09-03 10:54:03 发布
一、代码实现
以下代码基于 Eigen 库,实现了 3 阶实矩阵的定义、初始化及核心运算,包括转置、伴随、求逆、行列式计算与特征值 / 特征向量求解。
#include <iostream>
#include "Eigen\Dense" // 包含 Eigen 库中稠密矩阵相关类与函数
using namespace Eigen; // 引入 Eigen 命名空间,简化代码调用
using namespace std; // 引入标准输入输出命名空间
int main()
{
// 定义并初始化 3×3 双精度实矩阵 Mat1
Matrix3d Mat1; // Matrix3d 表示 3 阶双精度(double)稠密矩阵
Mat1 << 1, 2, 3, // 按行赋值:第 1 行元素为 [1, 2, 3]
4, 6, 8, // 第 2 行元素为 [4, 6, 8]
7, 9, 9; // 第 3 行元素为 [7, 9, 9]
// 输出原始矩阵
cout << "Mat1 = \n" << Mat1 << endl;
// 计算并输出转置矩阵
cout << "Mat1 转置矩阵:\n" << Mat1.transpose() << endl;
// 计算并输出伴随矩阵
cout << "Mat1 伴随矩阵:\n" << Mat1.adjoint() << endl;
// 计算并输出逆矩阵
cout << "Mat1 逆矩阵:\n" << Mat1.inverse() << endl;
// 计算并输出行列式
cout << "Mat1 行列式:\n" << Mat1.determinant() << endl;
// 求解特征值与特征向量(针对自伴随矩阵)
SelfAdjointEigenSolver<Matrix3d> eigensolver(Mat1); // 定义特征值求解器
if (eigensolver.info() != Success) abort(); // 检查求解是否成功,失败则终止程序
// 输出特征值与特征向量
cout << "特征值:\n" << eigensolver.eigenvalues() << endl;
cout << "特征向量:\n" << eigensolver.eigenvectors() << endl;
return 0;
}
二、代码解析
(一)矩阵定义与初始化
- 类型说明:
Matrix3d是 Eigen 库预定义的类型,对应 3 阶双精度实矩阵(维度固定为 3×3,元素类型为double)。 - 赋值方式:通过流操作符
<<按“行优先”顺序赋值,即先输入第 1 行所有元素,再输入第 2 行,以此类推。
(二)矩阵转置(Transpose)
- 函数调用:
Mat1.transpose() - 数学定义:对于 m×n 矩阵 A = ( a i j ) \mathbf{A} = (a_{ij}) A=(aij),其转置矩阵 A T \mathbf{A}^\mathrm{T} AT 是 n×m 矩阵,满足 ( A T ) i j = a j i (\mathbf{A}^\mathrm{T})_{ij} = a_{ji} (AT)ij=aji(即第 i 行第 j 列元素等于原矩阵第 j 行第 i 列元素)。
- 示例:若 M a t 1 = ( 1 2 3 4 6 8 7 9 9 ) \mathbf{Mat1} = \begin{pmatrix} 1 & 2 & 3 \\ 4 & 6 & 8 \\ 7 & 9 & 9 \end{pmatrix} Mat1= 147269389 ,则其转置矩阵为 ( 1 4 7 2 6 9 3 8 9 ) \begin{pmatrix} 1 & 4 & 7 \\ 2 & 6 & 9 \\ 3 & 8 & 9 \end{pmatrix} 123468799 。
(三)矩阵伴随(Adjoint)
- 函数调用:
Mat1.adjoint() - 数学定义:
- 对于 复矩阵:伴随矩阵 = 共轭转置矩阵(先对每个元素取共轭,再做转置);
- 对于 实矩阵(如代码中的
Mat1):共轭操作不改变元素值,因此伴随矩阵 等价于转置矩阵。
- 适用场景:主要用于复矩阵运算(如量子力学、信号处理),实矩阵场景下可替代转置,但语义上更强调“伴随”的数学属性。
(四)矩阵求逆(Inverse)
- 函数调用:
Mat1.inverse() - 数学定义:对于 n 阶方阵 A \mathbf{A} A,若存在 n 阶方阵 A − 1 \mathbf{A}^{-1} A−1 满足 A A − 1 = I \mathbf{A}\mathbf{A}^{-1} = \mathbf{I} AA−1=I( I \mathbf{I} I 为 n 阶单位矩阵),则 A − 1 \mathbf{A}^{-1} A−1 称为 A \mathbf{A} A 的逆矩阵。
- 存在条件:矩阵可逆的充要条件是其行列式 det ( A ) ≠ 0 \det(\mathbf{A}) \neq 0 det(A)=0(即矩阵非奇异)。
- Eigen 特性:Eigen 会自动检查矩阵是否可逆,若不可逆(奇异矩阵),调用
inverse()会返回数值不稳定的结果,建议先通过determinant()验证行列式非零。
(五)行列式(Determinant)
- 函数调用:
Mat1.determinant() - 数学定义:n 阶方阵 A \mathbf{A} A 的行列式是一个标量,记为 det ( A ) \det(\mathbf{A}) det(A) 或 ∣ A ∣ |\mathbf{A}| ∣A∣,反映矩阵的“缩放能力”(如线性变换中面积 / 体积的缩放比例)。
- 3 阶矩阵行列式公式:对于
A
=
(
a
b
c
d
e
f
g
h
i
)
\mathbf{A} = \begin{pmatrix} a & b & c \\ d & e & f \\ g & h & i \end{pmatrix}
A=
adgbehcfi
,其行列式为:
det ( A ) = a ( e i − f h ) − b ( d i − f g ) + c ( d h − e g ) \det(\mathbf{A}) = a(ei - fh) - b(di - fg) + c(dh - eg) det(A)=a(ei−fh)−b(di−fg)+c(dh−eg) - 代码计算结果: det ( M a t 1 ) = 1 × ( 6 × 9 − 8 × 9 ) − 2 × ( 4 × 9 − 8 × 7 ) + 3 × ( 4 × 9 − 6 × 7 ) = 4 \det(\mathbf{Mat1}) = 1 × (6 × 9 - 8 × 9) - 2 × (4 × 9 - 8 × 7) + 3 × (4 × 9 - 6 × 7) = 4 det(Mat1)=1×(6×9−8×9)−2×(4×9−8×7)+3×(4×9−6×7)=4(非零,故矩阵可逆)。
(六)特征值与特征向量(Eigenvalue & Eigenvector)
- 求解类说明:
SelfAdjointEigenSolver<Matrix3d>是 Eigen 中用于求解 自伴随矩阵(实对称矩阵是自伴随矩阵的特例)特征值与特征向量的工具类,求解精度高且数值稳定。 - 数学定义:对于 n 阶方阵
A
\mathbf{A}
A,若存在标量
λ
\lambda
λ(特征值)和非零向量
v
\mathbf{v}
v(特征向量)满足:
A v = λ v \mathbf{A}\mathbf{v} = \lambda\mathbf{v} Av=λv
则称 λ \lambda λ 为 A \mathbf{A} A 的特征值, v \mathbf{v} v 为 λ \lambda λ 对应的特征向量。 - 求解结果说明:
eigensolver.eigenvalues():返回一个列向量,包含矩阵的所有特征值(自伴随矩阵的特征值均为实数);eigensolver.eigenvectors():返回一个矩阵,每一列对应一个特征值的单位特征向量(不同特征值的特征向量相互正交)。
- 合法性检查:
eigensolver.info() != Success用于判断特征值分解是否成功(如矩阵维度不匹配、数值奇异等会导致失败),失败时调用abort()终止程序,避免后续错误计算。
三、代码注意事项
- 头文件依赖:代码中
#include "Eigen\Dense"不可省略,该头文件包含了 Eigen 库中稠密矩阵的所有核心功能(如矩阵运算、特征值求解等)。 - 命名空间使用:
using namespace Eigen;和using namespace std;简化了代码调用(无需每次写Eigen::Matrix3d或std::cout),但在大型项目中建议减少全局命名空间的使用,避免命名冲突。 - 矩阵维度兼容性:Eigen 会在编译阶段检查矩阵运算的维度兼容性(如转置矩阵与原矩阵的乘法),若维度不匹配会报编译错误,需确保运算符合线性代数规则。
- 数值稳定性:对于非自伴随矩阵(非对称矩阵),应使用
EigenSolver<Matrix3d>类求解特征值与特征向量,而非SelfAdjointEigenSolver,否则会导致求解结果错误。
Eigen中transposeInPlace()和transpose()的使用详解和示例代码
点云SLAM于 2025-06-30 15:23:04 发布
在 Eigen 中,transpose() 和 transposeInPlace() 均用于矩阵转置,但其使用方式和应用场景存在差异。以下将详细阐释两者的区别、适用场景及示例代码。
一、函数区别总结
| 特性 | transpose() | transposeInPlace() |
|---|---|---|
| 类型 | 成员函数 | 成员函数 |
| 返回值 | 返回转置副本 | 无返回值 |
| 是否修改原矩阵 | ❌ 否(保留原矩阵) | ✅ 是(原地转置) |
| 适用于方阵 | ✅ | ✅ |
| 适用于非方阵 | ✅ | ❌ 仅适用于方阵 |
| 使用场景 | 保留原始数据,创建新矩阵 | 需要节省内存,原地修改矩阵 |
二、详细用法和示例
1. transpose() —— 返回一个转置后的新矩阵
示例:
#include <Eigen/Dense>
#include <iostream>
int main() {
Eigen::Matrix3f mat;
mat << 1, 2, 3,
4, 5, 6,
7, 8, 9;
Eigen::Matrix3f matT = mat.transpose(); // 返回新矩阵
std::cout << "Original:\n" << mat << "\n";
std::cout << "Transposed:\n" << matT << "\n";
return 0;
}
输出:
Original:
1 2 3
4 5 6
7 8 9
Transposed:
1 4 7
2 5 8
3 6 9
适合保留原始矩阵的应用场景,例如图像处理、缓存优化等。
2. transposeInPlace() —— 原地修改矩阵,仅限方阵
示例:
#include <Eigen/Dense>
#include <iostream>
int main() {
Eigen::Matrix3f mat;
mat << 1, 2, 3,
4, 5, 6,
7, 8, 9;
mat.transposeInPlace(); // 原地转置(只适用于方阵)
std::cout << "In-place Transposed:\n" << mat << "\n";
return 0;
}
输出:
In-place Transposed:
1 4 7
2 5 8
3 6 9
注意:非方阵(如
Matrix3x4f)调用transposeInPlace()会触发编译错误。
三、使用建议
| 使用目标 | 建议函数 |
|---|---|
| 不改变原始矩阵,需临时结果 | transpose() |
| 内存敏感,处理的是方阵 | transposeInPlace() |
| 处理非方阵 | 只能用 transpose() |
四、非方阵的 transpose 示例
Eigen::Matrix<float, 2, 3> mat;
mat << 1, 2, 3,
4, 5, 6;
Eigen::Matrix<float, 3, 2> matT = mat.transpose();
不能写成:
mat.transposeInPlace(); // ❌ 编译错误!
五、结合 memcpy 用法示例
Eigen::Matrix4f mat;
// ... fill mat
float* buffer = new float[16];
// 如果目标数组是 row-major,需转置
Eigen::Matrix4f temp = mat.transpose();
std::memcpy(buffer, temp.data(), sizeof(float) * 16);
总结
transpose()➜ 返回副本,不修改原矩阵,适用于所有维度。transposeInPlace()➜ 原地转置,仅限方阵,节省内存。- 非方阵请勿使用
transposeInPlace()。 - 可与
memcpy配合用于与 OpenGL / DirectX / 自定义矩阵格式对接。
Eigen 踩坑:Matrix 的 transpose(矩阵转置)计算之后不能赋值给自身
HW140701 于 2025-06-30 15:23:04 发布
在使用 Eigen 线性代数库进行矩阵操作时,发现一个关键差异:矩阵 Matrix 的 transpose()(转置)计算结果不能直接赋值给原矩阵自身,这与 C/C++ 中常规变量的赋值逻辑不同,核心原因在于 Eigen 对操作符重载的特殊设计,需重点注意以避免程序异常。
一、问题现象:直接赋值导致程序崩溃
1. 常规 C/C++ 赋值逻辑(可正常运行)
在 C/C++ 中,对普通变量执行“计算后赋值给自身”的操作是常规写法,例如:
int a = 10;
a = a / 10; // 结果为 a=1,无异常
2. Eigen 矩阵转置的错误写法(触发崩溃)
但在 Eigen 中,若将矩阵转置结果直接赋值给原矩阵,会导致程序崩溃,代码示例如下:
Eigen::MatrixXd A = B * C; // B、C 为已定义的 Eigen 矩阵
A = A.transpose(); // 错误:直接将转置结果赋值给原矩阵 A
3. 崩溃时的错误弹窗
程序崩溃时会弹出 Microsoft Visual C++ 运行时库的断言失败提示,核心错误信息如下(对应文档中插入的错误截图):
- 错误来源:
LocomotionController.dll中调用了 Eigen 的transpose.h文件 - 错误位置:
transpose.h第 378 行 - 核心断言:
(!check_transpose_aliasing_run_time_selector<...>::run(...)) && "aliasing detected during transposition..." - 错误原因:检测到“别名冲突(aliasing)”——即转置操作与原矩阵的内存访问存在冲突,导致未定义行为。

二、问题根源:Eigen 的“表达式模板”设计
崩溃的核心原因是 Eigen 采用了表达式模板(Expression Templates) 优化机制:
- Eigen 的
transpose()方法不直接返回新的矩阵对象,而是返回一个“转置表达式对象”(仅记录转置操作的逻辑,不立即执行计算、不分配新内存)。 - 当执行
A = A.transpose()时,Eigen 会尝试直接在原矩阵A的内存空间上进行转置操作,但转置过程中需要读取原矩阵的元素,而赋值操作又会覆盖原内存——这种“边读边写”的冲突触发了别名检测断言,最终导致程序崩溃。
三、解决方案:两种正确的实现方式
1. 方案一:通过临时矩阵中转(间接赋值)
先将原矩阵的副本进行转置,再将结果赋值给目标矩阵(避免原内存冲突),代码示例:
Eigen::MatrixXd A;
Eigen::MatrixXd Acopy = B * C; // 第一步:先创建原矩阵(B*C)的副本 Acopy
A = Acopy.transpose(); // 第二步:将副本的转置结果赋值给 A,无冲突
2. 方案二:使用 Eigen 内置的 transposeInPlace() 方法(推荐)
Eigen 官方提供了专门用于“原地转置”的方法 transposeInPlace(),该方法会安全地在原矩阵内存中执行转置操作,无需额外创建临时矩阵,代码示例:
Eigen::MatrixXd A = B * C;
A.transposeInPlace(); // 正确:原地执行转置,直接修改 A 的值,无内存冲突
注:查阅 Eigen 官方文档可知,
transposeInPlace()是为“矩阵自身转置”场景设计的安全接口,已内部处理了内存访问冲突问题。
四、注意事项
- 避免“自身转置后赋值”:永远不要写
A = A.transpose(),需改用A.transposeInPlace()。 - 理解表达式模板特性:Eigen 中类似
transpose()的操作(如inverse()、dot()等)多返回表达式对象,而非直接返回计算结果,需注意赋值目标是否与原矩阵冲突。 - 优先使用官方接口:对于“原地修改矩阵”的需求,优先选择 Eigen 提供的
InPlace后缀方法(如transposeInPlace()、inverseInPlace()),确保操作安全。
记录此问题及解决方案,以防后续开发中再次因 Eigen 的特殊设计导致类似崩溃。
via:
-
Eigen 库 矩阵基本操作:转置矩阵,逆矩阵,伴随矩阵,特征值_eigen matrix inverse-优快云博客
https://blog.youkuaiyun.com/hankerbit/article/details/82345603 -
Eigen 中 transposeInPlace () 和 transpose () 的使用详解和示例代码_转置矩阵 eigen-优快云 博客
https://blog.youkuaiyun.com/qq_36812406/article/details/149024355 -
Eigen 踩坑:Matrix 的 transpose(矩阵转置)计算之后不能赋值给自身_eigen transpose-优快云 博客
https://blog.youkuaiyun.com/HW140701/article/details/93592741 -
Eigen 库学习教程(全)-优快云博客
https://blog.youkuaiyun.com/hongge_smile/article/details/107296658 -
Eigen 线性代数库学习大全_eigen学习-优快云博客
https://deepthink.blog.youkuaiyun.com/article/details/127583402
1759

被折叠的 条评论
为什么被折叠?



