前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Eigen 使用教程

Eigen 使用教程

作者头像
为为为什么
发布2023-02-21 13:13:05
2.7K0
发布2023-02-21 13:13:05
举报
文章被收录于专栏:又见苍岚又见苍岚

Eigen 是开源的C++线性代数库,常用在计算机图形学中,之前我们记录了安装使用方法,本文记录常用功能使用方法。

动态矩阵、静态矩阵

  • Eigen 在编译期间确定尺寸的矩阵为静态矩阵,运行期间确定尺寸的为动态矩阵(数据类型中带有X)
  • 选用原则:
    • 对于非常小尺寸的矩阵,尽可能使用固定尺寸,特别是小于(大约)16的尺寸,使用固定尺寸对性能非常有益,因为它允许 Eigen 避免动态内存分配和展开循环; 对于小尺寸在内部,一个固定大小的特征矩阵只是一个普通的数组。
    • 对于较大尺寸,或者在必须使用动态尺寸的地方,尽量使用动态尺寸。当矩阵尺寸大于(大约)32时,静态矩阵的性能收益变得可以忽略,而且对于动态矩阵,Eigen 更倾向于尝试使用 SIMD 指令集加速运算。

模板类

  • Eigen 中有几个基础数据结构模板类
Matrix类
  • 所有矩阵和向量都是Matrix模板类的对象,Matrix类有6个模板参数,主要使用前三个,剩下的使用默认值。
  • MaxRowsAtCompileTimeMaxColsAtCompileTime 在已知动态矩阵的尺寸上界时是可以提升工作效率的。
代码语言:javascript
复制
Matrix<typename Scalar,        int RowsAtCompileTime,        int ColsAtCompileTime,       int Options = 0,       int MaxRowsAtCompileTime = RowsAtCompileTime,       int MaxColsAtCompileTime = ColsAtCompileTime># Scalar 元素类型# RowsAtCompileTime 行# ColsAtCompileTime 列# 例 typedef Matrix<int, 3, 3> Matrix3i;# Options 比特标志位# MaxRowsAtCompileTime和MaxColsAtCompileTime表示在编译阶段矩阵的上限。# 列向量typedef Matrix<double, 3, 1> Vector3d;# 行向量typedef Matrix<float, 1, 3> RowVector3f;# 动态大小typedef Matrix<double, Dynamic, Dynamic> MatrixXd;typedef Matrix<float, Dynamic, 1> VectorXf;type

  • 默认构造时,指定大小的矩阵,只分配相应大小的空间,不进行初始化。动态大小的矩阵,则未分配空间。
  • []操作符可以用于向量元素的获取,但不能用于matrix
  • matrix的大小可以通过rows(), cols(), size()获取,resize()可以重新调整矩阵大小。
  • Matrix 定义的矩阵为静态矩阵,在编译时确定尺寸、分配内存,随机初始化:
代码语言:javascript
复制
Matrix<int, 3, 3> a;cout << a;-->1284850368      32759          1     32759         31          01284845929          0          0

MatrixX 开头的为动态矩阵,两个维度都可以变化,本质为 Matrix<Type, Dynamic, Dynamic> 定义的类型

例如: MatrixXd 为 double 类型的动态矩阵 1 2 3 4 5 6 7MatrixXd a(3, 3); cout << a; --> 0 0 0 0 0 0 0 0 0

静态矩阵运算很快,但是有 128k 的堆栈尺寸限制,常用的还是动态矩阵类型

仅变化一个维度的动态矩阵为动态向量 typedef Matrix<float, Dynamic, 1> VectorXf,使用方法类似

Array类
  • Array是类模板,前三个参数必须指定,后三个参数可选。
代码语言:javascript
复制
Array<typename Scalar,      int RowsAtCompileTime,      int ColsAtCompileTime># 常见类定义typedef Array<float, Dynamic, 1> ArrayXftypedef Array<float, 3, 1> Array3ftypedef Array<double, Dynamic, Dynamic> ArrayXXdtypedef Array<double, 3, 3> Array33dArrayXf a = ArrayXf::Random(5);a.abs();    # 绝对值a.sqrt();    # 平方根a.min(a.abs().sqrt());  # 两个array相应元素的最小值

类似于 Matrix 类,Array 默认仍会产生静态数组

代码语言:javascript
复制
Array<int, 3, 3> a;cout << a;-->-412990784      32758          1     32758         31          0-412995223          0          0

一维动态数组为 ArrayX 开头,二维动态数组为 ArrayXX 开头

代码语言:javascript
复制
ArrayXXi  a(3, 3);cout << a;-->6357107 7471220 45220447929971 6422621 60293717667805 7209066 7471185

Array 和 Martix 的区别
  • Martix 表示的是矩阵,运算为矩阵运算,运算时尺寸需要遵循矩阵运算规则
  • Array 和 Matrix 数据组成相同,但运算规则为逐元素运算,需要相同尺寸数据进行运算
Array 和 Martix 的转换
  • Matrix对象——>Array对象:.array()函数
  • Array对象——>Matrix对象:.matrix()函数

初始化

建议矩阵数据都要初始化,不然是十分危险的。

默认初始化
  • 默认初始化为随机数:
代码语言:javascript
复制
ArrayXXi  a(2, 4);cout << a;-->7602273 7209025 7209071 30147076029409 6488161 6357092 3014712

赋值初始化

赋值初始化

代码语言:javascript
复制
Matrix<int, 5, 1> b {1, 2, 3, 4, 5};Matrix<double, 2, 3> b {      {2, 3, 4},      {5, 6, 7},};VectorXd a {{1.5, 2.5, 3.5}};RowVectorXd b {{1.0, 2.0, 3.0, 4.0}};

对象初始化

可以用其他对象初始化新的相同内容对象

代码语言:javascript
复制
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;MatrixXf n(m);m.block(0, 0, 2, 2).swap(n.block(2, 2, 2, 2));cout << m;-->    11 12  3  415 16  7  8 9 10 11 1213 14 15 16

逗号初始化
  • 为矩阵元素赋值,顺序是从左到右,从上到下,数目必须匹配。
代码语言:javascript
复制
ArrayXXi  a(2, 3);a << 1, 2, 3, 4, 5, 6;cout << a << endl << endl;ArrayXXi  b(2, 2);b << 7, 8, 9, 10;cout << b << endl << endl;ArrayXXi  c(4, 7);c << b, a, b, a, b, b;cout << c << endl << endl;-->1 2 34 5 6 7  8 9 10 7  8  1  2  3  7  8 9 10  4  5  6  9 10 1  2  3  7  8  7  8 4  5  6  9 10  9 10

特殊矩阵初始化
静态矩阵

一下几个函数均为静态矩阵调用的初始化函数,动态矩阵调用会报错: 1YOU CALLED A_FIXED SIZE METHOD ON A DYNAMIC SIZE MATRIX OR VECTOR

  • 零阵:类静态成员函数Zero()
  • 常量矩阵:Constant(rows, cols, value)
  • 随机矩阵:Random()
  • 单位矩阵:Identity()
代码语言:javascript
复制
Matrix<int, 3, 3> a;cout << a << endl << endl;a = a.Zero();cout << a << endl << endl;a = a.Constant(3, 3, 7);cout << a << endl << endl;a = a.Random();cout << a << endl << endl;a = a.Identity();cout << a << endl << endl;-->1028866792      32759          1     32759         31          01028862809          0          00 0 00 0 00 0 07 7 77 7 77 7 7-16343  10116  -4906  2083   2785  12974-10050   -660  105781 0 00 1 00 0 1

动态矩阵

函数

含义

setZero()

矩阵归零

setConstant()

矩阵归常数

setIdentity()

矩阵归单位阵

setOnes()

矩阵归一

setRandom()

矩阵随机数

代码语言:javascript
复制
MatrixXi a(3, 3);cout << a << endl << endl;a.setZero();cout << a << endl << endl;a.setConstant(2);cout << a << endl << endl;a.setIdentity();cout << a << endl << endl;a.setOnes();cout << a << endl << endl;a.setRandom();cout << a << endl << endl;-->5701724 7536759 66192527209065 5439580 33424457274596 7536761 60293620 0 00 0 00 0 02 2 22 2 22 2 21 0 00 1 00 0 11 1 11 1 11 1 1-16343  10116  -4906  2083   2785  12974-10050   -660  10578

动态向量函数
  • 仅能在向量类型数据中使用

函数

含义

setLinSpaced()

填充线性间隔的数据

setUnit()

指定向量位置数据置1,其余为0

代码语言:javascript
复制
RowVectorXf b(8);cout << b << endl << endl;b.setLinSpaced(0, 14);cout << b << endl << endl;b.setUnit(3);cout << b << endl << endl;b.setOnes();cout << b << endl << endl;b.setConstant(2);cout << b << endl << endl;-->9.91839e-39 9.64288e-39 8.44903e-39 7.80611e-39  5.9694e-39 1.08367e-38 4.50001e-39     4.5e-390  2  4  6  8 10 12 140 0 0 1 0 0 0 01 1 1 1 1 1 1 12 2 2 2 2 2 2 2

索引数据

单个数据

主要数据的存取和修改都是通过重载的括号运算符完成的

对于二维矩阵,下标顺序为 row col

对于向量,则只有向量下标需要传入

代码语言:javascript
复制
MatrixXd m(2,2);m(0,0) = 3;m(1,0) = 2.5;m(0,1) = -1;m(1,1) = m(1,0) + m(0,1);cout << m;-->  3  -12.5 1.5

块操作
  • 语法:

动态矩阵

静态矩阵

尺寸 (p, q) 左上角坐标 (i, j)

matrix.block(i,j,p,q);

matrix.block<p,q>(i,j);

示例:

代码语言:javascript
复制
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;m.block<2, 2>(0, 0) = m.block<2, 2>(0, 0) * 3;m.block<2, 2>(2, 2).setConstant(0);cout << m << endl << endl;-->18 21  3  430 33  7  8 9 10  0  013 14  0  0

行列操作
  • 语法:

操作

方法

第 i 行

matrix.row(i);

第 i 列

matrix.col(j);

示例:

代码语言:javascript
复制
Eigen::MatrixXf m(3, 3);m << 1, 2, 3,4, 5, 6,7, 8, 9;cout << "Here is the matrix m:" << endl << m << endl;cout << "2nd Row: " << m.row(1) << endl;m.col(2) += 3 * m.col(0);cout << "After adding 3 times the first column into the third column, the matrix m is:\n";cout << m << endl;-->Here is the matrix m:1 2 34 5 67 8 92nd Row: 4 5 6After adding 3 times the first column into the third column, the matrix m is: 1  2  6 4  5 18 7  8 30

角操作
  • 语法:

块操作

动态矩阵语法

静态矩阵语法

左上角 p 行 q 列

matrix.topLeftCorner(p,q);

matrix.topLeftCorner<p,q>();

左下角 p 行 q 列

matrix.bottomLeftCorner(p,q);

matrix.bottomLeftCorner<p,q>();

右上角 p 行 q 列

matrix.topRightCorner(p,q);

matrix.topRightCorner<p,q>();

右下角 p 行 q 列

matrix.bottomRightCorner(p,q);

matrix.bottomRightCorner<p,q>();

前 q 行

matrix.topRows(q);

matrix.topRows<q>();

后 q 行

matrix.bottomRows(q);

matrix.bottomRows<q>();

前 p 列

matrix.leftCols(p);

matrix.leftCols<p>();

后 p 列

matrix.rightCols(q);

matrix.rightCols<q>();

第 i 列开始取 q 列

matrix.middleCols(i,q);

matrix.middleCols<q>(i);

第 i 行开始取 q 行

matrix.middleRows(i,q);

matrix.middleRows<q>(i);

示例:

代码语言:javascript
复制
Eigen::Matrix4f m;m << 1, 2, 3, 4,5, 6, 7, 8,9, 10,11,12,13,14,15,16;cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl;cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl;m.topLeftCorner(1,3) = m.bottomRightCorner(3,1).transpose();cout << "After assignment, m = " << endl << m << endl;-->m.leftCols(2) = 1  2 5  6 9 1013 14m.bottomRows<2>() = 9 10 11 1213 14 15 16After assignment, m = 8 12 16  4 5  6  7  8 9 10 11 1213 14 15 16

向量块操作

块操作

动态矩阵语法

静态矩阵语法

向量前 n 个数据

vector.head(n);

vector.head<n>();

向量后 n 个数据

vector.tail(n);

vector.tail<n>();

向量从下标 i 开始的 n 个数据

vector.segment(i,n);

vector.segment<n>(i);

常用操作

  • 大多数情况下,Eigen 要求操作的数据类型一致
布尔归约

操作

语法

示例

转置

.transpose()

v.transpose()

所有元素为 true(非0),返回 bool 值

all()

m.all()

存在元素为 true(非0),返回 bool 值

any()

m.any()

统计 true(非0) 的个数

count()

m.count()

数据类型转换

操作

语法

示例

数据类型转换为 double

.cast<double>()

A.cast<double>()

数据类型转换为 float

.cast<float>()

A.cast<float>()

数据类型转换为 int

.cast<int>()

A.cast<int>()

数据类型转换为实部

.real()

A.real()

数据类型转换为虚部

.imag()

A.imag()

内存数据转 Eigen

Map<>()

Map<Matrix3i>(array)

内存数据转 Eigen:

代码语言:javascript
复制
int array[9];for (int i = 0; i < 9; ++i) {array[i] = i;}cout << Map<Matrix3i>(array).transpose() << endl;-->0 1 23 4 56 7 8

Vector 向量操作

操作

语法

示例

点乘

dot()

v.dot(w)

叉乘

.cross()

v.cross(w)

元素个数

.size()

v.size()

生成对角阵

.asDiagonal()

v.asDiagonal()

向量平方和

.squaredNorm()

v.squaredNorm()

向量模长

.norm()

v.norm()

Matrix 矩阵操作

操作

语法

示例

转置

.transpose()

v.transpose()

共轭

.conjugate()

a.conjugate()

共轭转置

.adjoint()

a.adjoint()

元素个数

.size()

a.size()

行数

.rows()

a.rows()

列数

.rols()

a.rols()

填充

.fill()

a.fill(6)

交换行/列

.swap()

m.block(0, 0, 2, 2).swap(n.block(2, 2, 2, 2));

获取对角线

.diagonal()

a.diagonal()

列向操作

.colwise()

m.colwise().sum()

元素颠倒

.reverse()

m.reverse()

赋值经过优化:

行可以给列赋值,这个其实还是挺可怕的,需要格外小心。

代码语言:javascript
复制
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;m.row(0) = m.col(3);cout << m;--> 4  8 12 16 5  6  7  8 9 10 11 1213 14 15 16

列向操作相当于 numpy 中的 axis=1,只对列方向做某种操作:

代码语言:javascript
复制
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;cout << "Here is the matrix m:" << endl << m << endl;cout << "Here is the sum of each column:" << endl << m.colwise().sum() << endl;cout << "Here is the maximum absolute value of each column:"<< endl << m.cwiseAbs().colwise().maxCoeff() << endl;-->Here is the matrix m: 1  2  3  4 5  6  7  8 9 10 11 1213 14 15 16Here is the sum of each column:28 32 36 40Here is the maximum absolute value of each column:13 14 15 16

Matrix 矩阵运算

操作

语法

示例

矩阵相加

+

a + b

矩阵相减

-

a - b

负号

-

- a

复合算子加

+=

a += b

复合算子减

-=

a -= b

标量乘法

*

matrix*scalar / scalar*matrix

标量除法

/

matrix/scalar

复合算子乘

*=

matrix*=scalar

复合算子除

/=

matrix/=scalar

矩阵\向量乘法

*

matrix*matrix, matrix*vector

矩阵求和

.sum()

mat.sum()

所有元素乘积

.prod()

mat.prod()

矩阵均值

.mean()

mat.mean()

矩阵最小值

.minCoeff()

mat.minCoeff()

矩阵最大值

.maxCoeff()

mat.maxCoeff()

矩阵最小值,带位置

.minCoeff(&r, &c)

mat.minCoeff(&r, &c)

矩阵最大值,带位置

.maxCoeff(&r, &c)

mat.maxCoeff(&r, &c)

.trace()

mat.trace()

逐元素绝对值

.cwiseAbs()

mat.cwiseAbs()

逐元素相乘

.cwiseProduct()

mat = mat.cwiseProduct(mat)

逐元素相除

.cwiseQuotient()

mat = mat.cwiseQuotient(mat)

逐元素取倒数

.cwiseInverse()

mat.cwiseInverse()

逐元素开根号

.cwiseSqrt()

mat.cwiseSqrt()

逐元素最大值

.cwiseMax(m)

mat.cwiseMax(mat2)

逐元素最小值

.cwiseMin(m)

mat.cwiseMin(mat2)

元素平方和

.squaredNorm()

mat.squaredNorm()

矩阵二阶范数

.norm()

mat.norm()

p 阶范数

.lpNorm<p>()

mat.lpNorm<3>()

最大值、最小值

返回最大、最小值,同时定位位置

代码语言:javascript
复制
Matrix3f m = Matrix3f::Random();std::ptrdiff_t i, j;float minOfM = m.minCoeff(&i,&j);cout << "Here is the matrix m:\n" << m << endl;cout << "Its minimum coefficient (" << minOfM << ") is at position (" << i << "," << j << ")\n\n";RowVector4i v = RowVector4i::Random();int maxOfV = v.maxCoeff(&i);cout << "Here is the vector v: " << v << endl;cout << "Its maximum coefficient (" << maxOfV << ") is at position " << i << endl;-->Here is the matrix m: -0.997497   0.617481  -0.299417  0.127171   0.170019   0.791925 -0.613392 -0.0402539    0.64568Its minimum coefficient (-0.997497) is at position (0,0)Here is the vector v:   8080 -10679  11761   6897Its maximum coefficient (11761) is at position 2

Array 数组运算

操作

语法

示例

逐元素相乘

*

a * b

逐元素相除

/

a * b

矩阵相加

+

a + b

矩阵相减

-

a - b

负号

-

- a

复合算子加

+=

a += b

复合算子减

-=

a -= b

逐元素比较

<, >, >=, <=, ==

a < b

逐元素标量计算

+, -, *, /

a + 3

逐元素标量复合计算

+=, -=, *=, /=

a /= 3

逐元素取倒数

.inverse()

a.inverse()

逐元素 sin

.sin()

a.sin()

逐元素 cos

.cos()

a.cos()

逐元素乘方

.pow(s)

a.pow(3)

逐元素平方

.square()

a.square()

逐元素立方

.cube()

a.cube()

逐元素开根号

.sqrt()

a.sqrt()

逐元素计算自然指数

.exp()

a.exp()

逐元素计算自然对数

.log()

a.log()

逐元素最小值

.min()

a.min(b)

逐元素最大值

.max()

a.max(b)

逐元素绝对值

.abs()

a.abs()

逐元素选择

.select()

(R.array() < s).select(P,Q)

逐元素比较:

代码语言:javascript
复制
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;cout << (m.array() > m.reverse().array());-->0 0 0 00 0 0 01 1 1 11 1 1 1

逐元素选择:

代码语言:javascript
复制
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;MatrixXf n(4, 4), p(4, 4);n.setZero();p = (m.array() < 10).select(m, n);cout << p;-->1 2 3 45 6 7 89 0 0 00 0 0 0

矩阵分解与解线性方程组

矩阵分解

分解方法

语法

输出

柯列斯基分解

.ldlt()

.matrixL() and .matrixD()

LLT 分解

.llt()

.matrixL()

部分旋转的 LU分解

.lu()

.matrixL() and .matrixU()

QR 分解

.qr()

.matrixQ() and .matrixR()

SVD 分解

.svd()

.matrixU(), .singularValues(), and .matrixV()

求解线性方程组
  • 对应不同矩阵分解方式,有不同的解方程组的方法

语法

描述

x = A.ldlt().solve(b));

A sym. p.s.d. #include <Eigen/Cholesky>

x = A.llt() .solve(b));

A sym. p.d. #include <Eigen/Cholesky>

x = A.lu() .solve(b));

Stable and fast. #include <Eigen/LU>

x = A.qr() .solve(b));

No pivoting. #include <Eigen/QR>

x = A.svd() .solve(b));

Stable, slowest. #include <Eigen/SVD>

特征值特征向量

特征值:

代码语言:javascript
复制
A.eigenvalues();

特征向量:

代码语言:javascript
复制
eig.eigenvectors();

混淆问题

  • 使用eval()函数解决把右值赋值为一个临时矩阵,再赋给左值时可能有造成的混淆。如:
代码语言:javascript
复制
MatrixXi mat(3,3);mat << 1,2,3, 4,5,6, 7,8,9;mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2).eval();

  • 原地操作的一类函数:

普通函数

inplace函数

MatrixBase::adjoint()

MatrixBase::adjointInPlace()

DenseBase::reverse()

DenseBase::reverseInPlace()

LDLT::solve()

LDLT::solveInPlace()

LLT::solve()

LLT::solveInPlace()

TriangularView::solve()

TriangularView::solveInPlace()

DenseBase::transpose()

DenseBase::transposeInPlace()

  1. 当相同的矩阵或array出现在等式左右时,容易出现混淆
  2. 当确定不会出现混淆时,可以使用noalias()
  3. 混淆出现时,可以使用eval()xxxInPlace()函数解决

参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023年1月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态矩阵、静态矩阵
  • 模板类
    • Matrix类
      • Array类
        • Array 和 Martix 的区别
          • Array 和 Martix 的转换
          • 初始化
            • 默认初始化
              • 赋值初始化
                • 对象初始化
                  • 逗号初始化
                    • 特殊矩阵初始化
                      • 静态矩阵
                      • 动态矩阵
                      • 动态向量函数
                  • 索引数据
                    • 单个数据
                      • 块操作
                        • 行列操作
                          • 角操作
                            • 向量块操作
                            • 常用操作
                              • 布尔归约
                                • 数据类型转换
                                  • Vector 向量操作
                                    • Matrix 矩阵操作
                                      • Matrix 矩阵运算
                                        • Array 数组运算
                                        • 矩阵分解与解线性方程组
                                          • 矩阵分解
                                            • 求解线性方程组
                                            • 特征值特征向量
                                            • 混淆问题
                                            • 参考资料
                                            领券
                                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档