C++线性代数库Eigen简明教程

线性代数在3D游戏建模、深度学习、机器人工程、视频图像处理、航空航天等领域都有着举足轻重的位置。在使用C++编程时,如果从零编写矩阵的乘法、求逆、求特征值等运算,将会是件很麻烦的事情。而且,不管是从计算正确性,还是从效率方面都很难得到保障。因此,成熟稳定的线性代数库显得尤为重要。

Eigen是线性代数的C++模板库,它包含矩阵、向量、四元数、数值求解器和相关算法,其拥有良好的稳定性和计算效率,是我们搭建C++工程研究算法的必备利器。

目录

一、向量

1.1初始化

1.2二范数

1.3点积

1.4叉积

二、矩阵

2.1单位矩阵

2.2矩阵的迹

2.3转置

2.4块操作

2.5乘法

2.6求逆

2.7特征值

2.8特征向量

三、四元数 

3.1初始化

3.2旋转矩阵

四、调试技巧 

4.1向量的调试

4.2矩阵的调试

五、整体代码 


 

通过官网下载,然后解压到自己指定的目录即可。在进行VS工程配置时,只需要如下图那样包含Eigen库所在目录即可。

右击工程名——》属性——》VC++目录——》常规——》包含目录

一、向量

常用的向量类型有 Vector3d Vector4d VectorXd VectorXcd等。其中VectorXd 表示实数向量,VectorXcd 表示复数向量,前者应用在许多科学计算和工程中,如物理模拟、信号处理等,后者在需要处理复数时应用,如电磁学、量子物理等。

1.1初始化

Vector3d v3d_a = { 1,2,3 };
cout << "Vector3d构造一:\n" << v3d_a << endl;
Vector3d v3d_b;
v3d_b << 4, 5, 6;
cout << "Vector3d构造二:\n" << v3d_b << endl;

Vector4d v4d = { 1.1,2.2,3.3,4.4 };
cout << "Vector4d:\n" << v4d << endl;
VectorXd vxd(8); //这里一定要指定向量长度,否则报错!
vxd << 3, 1, 4, 1, 5, 9, 2, 6;
cout << "VectorXd:\n" << vxd << endl;

VectorXcd xcd(3, 1);
xcd.setZero();
xcd[0]._Val[0] = 1.2;
xcd[2]._Val[1] = 1.3;
cout << "VectorXcd:\n" << xcd << endl;
cout << "VectorXcd real:\n" << xcd.real() << endl;

1.2二范数

Vector3d v3d_a = { 1,2,3 };
cout << "二范数:\n" << v3d_a.norm() << endl;

1.3点积

Vector3d v3d_a = { 1,2,3 };
Vector3d v3d_b;
v3d_b << 4, 5, 6;
cout << "点积:\n" << v3d_a.dot(v3d_b) << endl;

1.4叉积

Vector3d v3d_a = { 1,2,3 };
Vector3d v3d_b;
v3d_b << 4, 5, 6;
cout << "叉积:\n" << v3d_a.cross(v3d_b) << endl;

二、矩阵

2.1单位矩阵

MatrixXd I = MatrixXd::Identity(4, 4);
cout << "单位矩阵:\n" << I << endl;

2.2矩阵的迹

MatrixXd MatA(3, 3);
MatA << 1, 2, 3,
        4, 5, 6,
        7, 8, 9;
cout << "矩阵的迹:\n" << MatA.trace() << endl;

2.3转置

cout << "矩阵的转置:\n" << MatA.transpose() << endl;

2.4块操作

大小为 (p,q), 起始于 (i,j)的块

动态大小的块表达式 matrix.block(i,j,p,q);

固定大小的块表达式matrix.block<p,q>(i,j);

二者区别是,固定大小的版本会在块比较小的时候快一点,但要求块大小在编译的时候就知道。

MatrixXd MatB(3, 3);
Vector3d va = { 0.1,0.4,0.7 };
Vector3d vb = { 0.2,0.5,0.8 };
Vector3d vc = { 0.3,0.6,0.9 };
MatB.block<3, 1>(0, 0) = va; //固定 从0编码,以0,0为起点,存入3行1列的向量
MatB.block(0, 1, 3, 1) = vb; //动态 从0编码,以0,1为起点,存入3行1列的向量
MatB.block<3, 1>(0, 2) = vc;
cout << "块操作:\n" << MatB << endl;

2.5乘法

cout << "矩阵乘法:\n" << MatA * MatB << endl;

2.6求逆

MatrixXd MatC(3, 3);
MatC << 1, 2, 3,
2, 5, 6,
3, 4, 8;
cout << "矩阵求逆:\n" << MatC.inverse() << endl;

2.7特征值

MatrixXd K(4, 4);
K << -0.504129, 0.0190935, -0.836998, -0.137961,
0.0190935, -0.534845, 0.114843, -0.813407,
-0.836998, 0.114843, 0.526649, -0.0167767,
-0.137961, -0.813407, -0.0167767, 0.512325;
VectorXd eigVals = K.eigenvalues().real();
cout << "特征值:\n" << eigVals << endl;

2.8特征向量

// 求解矩阵的最大特征值和对应特征向量
EigenSolver<MatrixXd> es(K);
MatrixXcd eigenvectors = es.eigenvectors();
int index_of_max = MaxElementIndex(eigVals); // 找到最大特征值对应的下标
VectorXcd max_eigenvector = eigenvectors.col(index_of_max);
Vector4d vec4 = max_eigenvector.real();
cout << "最大特征值对应的特征向量:\n" << vec4 << endl;

三、四元数 

3.1初始化

Quaterniond q(4, 1, 2, 3);//要注意Eigen中四元数赋值的顺序,实数w在首;
cout << "四元数:\n" << q << endl; //但是实际上它的内部存储顺序是[x y z w]
cout << q.w() << " " << q.x() << " " << q.y() << " " << q.z() << endl; //单个取值

3.2旋转矩阵

q = vec4;
cout << "旋转矩阵:\n" << q.toRotationMatrix() << endl; //将四元数转换为旋转矩阵

四、调试技巧 

在用VS断点调试一般变量时,只需要鼠标悬停在变量上即可看见变量值,但由于矩阵和向量都是一个抽象对象,若要观察其具体变量就需要使用“快速监视“窗口,并且编辑表达式,使数据内容完全展开。

4.1向量的调试

双击选中变量

Shift+F9

一直展开到array,就可以看见向量全部内容

4.2矩阵的调试

同理,选中变量,Shift+F9,打开快速监视

此时展开到m_data变量,发现只能看到一个数值,这是因为该变量是个double指针类型

为了观察整个矩阵,在表达式栏,输入”,16”,表示展开指针后面16个数值,如下

敲击两次回车

认真比对存储顺序发现——矩阵元素存储按列依次排列,而非按行依次排列!

五、整体代码 

#include <iostream>
#include <Eigen/Core>
#include <Eigen/Geometry>
#include <Eigen/Eigenvalues>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

int MaxElementIndex(VectorXd v)
{
	int index = 0;
	for (int i = 1; i < v.size(); i++)
	{
		if (v(index) < v(i))
		{
			index = i;
		}
	}
	return index;
}

int main()
{
	Vector3d v3d_a = { 1,2,3 };
	cout << "Vector3d构造一:\n" << v3d_a << endl;
	Vector3d v3d_b;
	v3d_b << 4, 5, 6;
	cout << "Vector3d构造二:\n" << v3d_b << endl;

	cout << "二范数:\n" << v3d_a.norm() << endl;
	cout << "点积:\n" << v3d_a.dot(v3d_b) << endl;
	cout << "叉积:\n" << v3d_a.cross(v3d_b) << endl;

	Vector4d v4d = { 1.1,2.2,3.3,4.4 };
	cout << "Vector4d:\n" << v4d << endl;

	VectorXd vxd(8); //这里一定要指定向量长度,否则报错!
	vxd << 3, 1, 4, 1, 5, 9, 2, 6;
	cout << "VectorXd:\n" << vxd << endl;

	VectorXcd xcd(3, 1);
	xcd.setZero();
	xcd[0]._Val[0] = 1.2;
	xcd[2]._Val[1] = 1.3;
	cout << "VectorXcd:\n" << xcd << endl;
	cout << "VectorXcd real:\n" << xcd.real() << endl;

	MatrixXd I = MatrixXd::Identity(4, 4);
	cout << "单位矩阵:\n" << I << endl;
	MatrixXd MatA(3, 3);
	MatA << 1, 2, 3,
		4, 5, 6,
		7, 8, 9;
	cout << "矩阵的迹:\n" << MatA.trace() << endl;
	cout << "矩阵的转置:\n" << MatA.transpose() << endl;

	MatrixXd MatB(3, 3);
	Vector3d va = { 0.1,0.4,0.7 };
	Vector3d vb = { 0.2,0.5,0.8 };
	Vector3d vc = { 0.3,0.6,0.9 };
	MatB.block<3, 1>(0, 0) = va; //固定 从0编码,以0,0为起点,存入3行1列的向量
	MatB.block(0, 1, 3, 1) = vb; //动态 从0编码,以0,1为起点,存入3行1列的向量
	MatB.block<3, 1>(0, 2) = vc;
	cout << "块操作:\n" << MatB << endl;
	cout << "矩阵乘法:\n" << MatA * MatB << endl;

	MatrixXd MatC(3, 3);
	MatC << 1, 2, 3,
		2, 5, 6,
		3, 4, 8;
	cout << "矩阵求逆:\n" << MatC.inverse() << endl;

	MatrixXd K(4, 4);
	K << -0.504129, 0.0190935, -0.836998, -0.137961,
		0.0190935, -0.534845, 0.114843, -0.813407,
		-0.836998, 0.114843, 0.526649, -0.0167767,
		-0.137961, -0.813407, -0.0167767, 0.512325;
	VectorXd eigVals = K.eigenvalues().real();
	cout << "特征值:\n" << eigVals << endl;

	// 求解矩阵的最大特征值和对应特征向量
	EigenSolver<MatrixXd> es(K);
	MatrixXcd eigenvectors = es.eigenvectors();
	int index_of_max = MaxElementIndex(eigVals); // 找到最大特征值对应的下标
	VectorXcd max_eigenvector = eigenvectors.col(index_of_max);
	Vector4d vec4 = max_eigenvector.real();
	cout << "最大特征值对应的特征向量:\n" << vec4 << endl;

	Quaterniond q(4, 1, 2, 3);//要注意Eigen中四元数赋值的顺序,实数w在首;
	cout << "四元数:\n" << q << endl; //但是实际上它的内部存储顺序是[x y z w]
	cout << q.w() << " " << q.x() << " " << q.y() << " " << q.z() << endl; //单个取值
	q = vec4;
	cout << "旋转矩阵:\n" << q.toRotationMatrix() << endl; //将四元数转换为旋转矩阵
}

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值