Eigen 学习笔记
文章目录
一、Eigen 使用基础
1矩阵初始化以及基本使用
#include <iostream>
#include<Eigen/Dense>//Eigen 头文件 <Eigen/Dense>包含Eigen 里面所有的函数和类
using namespace std;
int main() {
Eigen::MatrixXd m(2, 2);// MatrixXd 是动态数组,初始化的时候指定数组的行数和列数
m(0, 0) = 3;//m(i,j)表示第i行和第j列的值,这里对数组进行初始化
m(1, 0) = 2.5;
m(0, 1) = -1;
m(1, 1) = m(1, 0) + m(0, 1);
cout << m << endl;//eigen 重载<< 运算符 可以直接输出eigen 矩阵
}
2 矩阵和向量
// 矩阵和向量
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
MatrixXd m = MatrixXd::Random(3, 3);//初始化动态矩阵m,使用random 函数,初始化的值在[-1,1]区间
m = (m + MatrixXd::Constant(3, 3, 1.2)) * 50;//MatrixXd::Constant(3, 3, 1.2)初始化3*3的矩阵 元素全部为1.2
cout << "m=" << endl << m << endl;
VectorXd v(3);
v << 1, 2, 3;// 逗号初始化 comma initializer ,Eigen未提供c++ 的{}初始化方式
cout << "v=" << endl << v << endl;
cout << "v*m=" << endl << m * v << endl;//
}
3逗号初始化
// 逗号初始化
// Eigen提供了一种逗号初始化器语法,该语法使用户可以轻松设置矩阵,
// 向量或数组的所有系数。只需列出系数,从左上角开始,从左到右,从上到下移动。
// 需要预先指定对象的大小。如果列出的系数太少或太多,编译器就会报错。
//此外,初始化列表的元素本身可以是向量或矩阵。通常的用途是将向量或矩阵连接在一起。
//例如,这是如何将两个行向量连接在一起。请记住,必须先设置大小,然后才能使用逗号初始化程序。
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
RowVectorXd cevl(2);
cevl << 1, 2;
cout << cevl << endl;
cout << "----------" << endl;
RowVectorXd cevl2(3);
cevl2 << 3, 4, 5;
RowVectorXd cevl3(5);
cevl3 << cevl2, cevl;
cout << cevl3 << endl;
cout << "----------" << endl;
MatrixXd m(2, 2);
m << 1, 2, 3, 4;
cout << m << endl;
}
4 一些常用的初始化方法
// 一些常用的初始化方法
#include<iostream>
#include<Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
MatrixXd m0 = MatrixXd::Random(3, 3);// 随机初始化的值在[-1,1]区间内 矩阵大小为3*3
MatrixXd m1 = MatrixXd::Constant(3, 3, 2.4);//常量值初始化,矩阵的值全部为2.4,3个参数分别代表行数、列数、常量值
MatrixXd m2 = MatrixXd::Zero(2, 2);// 0矩阵初始化 矩阵的值全部为0
Matrix4d m3 = Matrix4d::Identity();//初始化单位矩阵
cout << "m3=" << endl << m3 << endl;
MatrixXf mat = MatrixXf::Ones(2, 3);
cout << "before" << endl << mat << endl;
mat = (MatrixXf(2, 2) << 0, 1, 2, 0).finished() * mat;//此处使用了临时变量,然后使用逗号初始化 在此必须使用finish()方法来获取实际的矩阵对象
cout << "after" << endl << mat << endl;
}
说明: MatrixXd 是初始化动态矩阵 后面必须说明数组的行数和列数
Matrix2d Matrix3d 是显式说明矩阵的维数 不需要进行尺寸说明
5调整当前矩阵大小
// 调整矩阵大小
// 当前矩阵的大小可以通过rows colds size 检索 分别返回行数、列数、系数 动态调整大小是通过resize()方法完成的
// 动态矩阵可以调整大小 固定尺寸的矩阵无法调整大小
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
MatrixXd m = MatrixXd(2, 5);
m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
cout << m << endl;
m.resize(3, 2);// 如果不想改变元素 使用conservativeResize()
cout << "m 的 行数" << m.rows() << "m 的列数" << m.cols() << endl;
cout << "---------" << endl << m << endl;
VectorXd V(2);
V.resize(5);
cout << V.size() << endl;
cout << V.rows() << V.cols() << endl;
}
6 固定尺寸与动态尺寸的选择
在可能的地方使用固定尺寸来显示非常小的尺寸,在需要的地方使用动态尺寸来显示较大的尺寸。对于小尺寸,尤其是对于小于(大约)16的尺寸,使用固定尺寸对性能有极大的好处,因为它使Eigen避免了动态内存分配并展开了循环
二、矩阵类
- 在Eigen中,所有matrices和vectors都是Matrix模板类的对象。vectors只是matrices的一种特殊情况,具有1行或1列。
1 Matrix 的前三个模板参数
- Eigen里面用到了很多的typedef简化名称长度,例如下面:
typedef Matrix<float, 3, 1> Vector3f;
typedef Matrix<int, 1, 2> RowVector2i;
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
typedef Array<float,Dynamic,Dynamic> ArrayXXf
typedef Array<double,Dynamic,1> ArrayXd
typedef Array<int,1,Dynamic> RowArrayXi
typedef Array<float,3,3> Array33f
typedef Array<float,4,1> Array4f
......
2 vectors
在Eigen中,vectors只是Matrix的一种特殊情况,具有1行或1列。他们只有1列的情况最为常见;这样的向量称为列向量,通常缩写为向量。在另一行有1行的情况下,它们称为行向量。
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
Vector3f m = Vector3f::Random(3);//
RowVector2d mo = RowVector2d::Random(2);
cout << mo << endl;
}
3 动态矩阵
- 动态矩阵在编译的时候不知道其大小,需要在运行的时候才能确定其大小
三、Array类的介绍
Eigen 不仅提供了Matrix和Vector结构,还提供了Array结构。区别如下,Matrix和Vector就是线性代数中定义的矩阵和向量,所有的数学运算都和数学上一致。但是存在一个问题是数学上的定义并不一定能完全满足现实需求。比如,数学上并没有定义一个矩阵和一个标量的加法运算。但是如果我们想给一个矩阵的每个元素都加上同一个数,那么这个操作就需要我们自己去实现,这显然并不方便。
Array 提供了一个Array类,为我们提供了大量的矩阵未定义的操作,且Array和Matrix之间很容易相互转换 ,所以相当于给矩阵提供更多的方法。也为使用者的不同需求提供了更多的选择。
1 Array 初始化操作 加减乘除操作
- Eigen::Array类重载了+ , - ,* ,/ 运算符,可以直接用这些运算符对Array对象进行操作。相乘操作是对应的数字相乘,相除是对应的元素相除。
// Array初始化操作
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
ArrayXXf a(3, 3);
ArrayXXf b(3, 3);
a << 1, 1, 1, 1, 1, 1, 1, 1, 1;
b << 2, 2, 2, 2, 2, 2, 2, 2, 2;
cout << a + b << endl;
cout << a - b << endl;
cout << a * b << endl;
cout << a / b << endl;
}
2 Arrays类的其他操作
- Array 还定义了 绝对值 abs() ,开平方根sqrt() , 以及找对应元素最小值操作 min() ;
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
ArrayXXf a = ArrayXXf::Random(2, 2);// 初始化2x2 数组
a *= 2;
cout << a << endl;
cout << "------------" << endl;
cout << a.abs() << endl;
cout << "------------" << endl;
cout << a.abs().sqrt() << endl;
cout << "------------" << endl;
cout << a.min(a.abs().sqrt()) << endl;
}
六 Matrix和Array之间的相互转换
- Matrix类和Array类之间可以相互转换,必须显式转换,才能对他们进行加减乘除运算
// Array初始化操作
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
Array44f a1, a2;
Matrix4f m1, m2;
m1 = a1 * a2;//coffwise乘积 从数组到矩阵的隐式转换
a1 = m1 * m2;// 矩阵乘积 从矩阵到数组的隐式转换
a2 = a1 + m1.array();// 禁止混合数组矩阵,必须显式转换以后才可以相加
m2 = a1.matrix() + m1;// 需要显式转换
ArrayWrapper<Matrix4f> m1a(m1);// m1a 是m1.array()的别名 他们共享相同的系数
MatrixWrapper<Array44f> a1m(a1);
std::cout << "a1: " << std::endl << a1 << std::endl;
std::cout << "a2: " << std::endl << a2 << std::endl;
std::cout << "m1: " << std::endl << m1 << std::endl;
std::cout << "m2: " << std::endl << m2 << std::endl;
}
七 矩阵转置,共轭,共轭转置
1 转置和共轭
- 对于矩阵的转置、共轭和共轭转置由成员函数transpose(),conjugate(),adjoint()实现
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
MatrixXd m = MatrixXd::Random(2, 2);
cout << "原型" << endl << m << endl;
cout << "转置" << endl << m.transpose() << endl;
cout << "共轭" << endl << m.conjugate() << endl;
cout << "共轭转置" << endl << m.adjoint() << endl;
}
2 转置需要注意的事项
a = a.transpose();
无法运行,这称为别名问题,在debug模式下当assertions没有禁止时,这种问题会被自动检测到。要避免错误,可以使用in-place转置。类似的还有adjointInPlace()
// Array初始化操作
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
MatrixXd m = MatrixXd::Random(2, 2);
//m = m.transpose(); 报错
cout << "原型" << endl << m << endl;
m.transposeInPlace();
cout << "转置" << endl << m.transpose() << endl;
}
八 点积和叉积
- 对于点积和叉积,直接使用dot()和cross()方法
// Array初始化操作
#include<iostream>
#include<Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
Vector3d m = Vector3d::Random(3);
Vector3d m0 = Vector3d::Random(3);
cout << "点积1" << endl << m.transpose().dot(m0) << endl;
cout << "叉积" << endl << m.cross(m0) << endl;
}
注意:记住叉积仅仅用于尺寸为3的向量!点积可以用于任意尺寸的向量,当使用复数时,Eigen的点积操作是第一个变量为共轭线性的,第二个为线性的。
九 矩阵的基础算术(求和、平均值)
#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl;//矩阵求和-所有元素相加
cout << "Here is mat.prod(): " << mat.prod() << endl;//矩阵的所有元素相乘
cout << "Here is mat.mean(): " << mat.mean() << endl;//矩阵所有元素相加求平均值
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;//求矩阵的最小值
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;//求矩阵的最大值
cout << "Here is mat.trace(): " << mat.trace() << endl;//求矩阵的迹 对角线相加
}
十 矩阵的块操作
1 块基本操作
- 索引从0开始。两个版本都可用于固定尺寸或者动态尺寸的矩阵和数组。这两个表达式语义上相同,唯一的区别是如果块的尺寸比较小的话固定尺寸版本的块操作运行更快,但是需要在编译阶段知道大小。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main()
{
MatrixXd m(4, 4);
// 初始化矩阵
for (size_t i = 0; i < 4; i++)
{
for (size_t j = 0; j < 4; j++)
{
m(i, j) = j + 1 + i * 4;
}
}
cout << "m" << endl << m << endl;
cout << m.block<2, 2>(1, 1) << endl << endl; // m.block<i,j> (a,b) 表示从第(a+1)行(b+1)列开始,截图i行,j列
for (size_t i = 0; i < 4; i++)
{
cout << "Block of size " << i << "x" << i << endl;
cout << m.block(0, 0, i, i) << endl << endl; //m.block(a,b,i,j) 表示从第(a+1)行(b+1)列开始,截图i行,j列
}
}
注意:m.block<i,j> (a,b) 表示从第(a+1)行(b+1)列开始,截图i行,j列
m.block(a,b,i,j) 表示从第(a+1)行(b+1)列开始,截图i行,j列
//
// Created by fuhong on 20-7-14.
//
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main() {
Array22f m;
m << 1, 2,
3, 4;
Array44f a = Array44f::Constant(0.6);
cout << "Here is the array a:" << endl << a << endl << endl;
a.block<2, 2>(1, 1) = m;
cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl;
a.block(0, 0, 2, 3) = a.block(2, 1, 2, 3);
cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x2 block:" << endl << a << endl << endl;
}
2 行和列操作
//
// Created by fuhong on 20-7-14.
//
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main() {
Array44f a = Array44f::Constant(0.6);
cout << a << endl << "-------------" << endl << a.row(0) << endl << endl;
cout << "---------" << endl << a.col(1) << endl;//取出第一列
cout << "---------" << endl << a.cols() << endl;//计算列数
}
3 边角相关操作
#include <Eigen/Dense>
#include <iostream>
using namespace std;
int main() {
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;
}
4 向量的块操作
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main() {
Eigen::VectorXd m(8);
m << 1, 2, 3, 4,
5, 6, 7, 8;
cout << "m = " << endl << m.head(3) << endl;
}
十一范数计算
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main() {
Eigen::VectorXd m(2);
m << 0, 2;
cout << "m = " << endl << m.norm() << endl;
}
十二布尔规约
all()返回真,如果矩阵或数组的所有元素为真
any()返回真,如果矩阵或数组至少有一个元素为真
count()返回元素为真的个数
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main()
{
ArrayXXf a(2, 2);
a << 1, 2,
3, 4;
cout << "(a > 0).all() = " << (a > 0).all() << endl;
cout << "(a > 0).any() = " << (a > 0).any() << endl;
cout << "(a > 0).count() = " << (a > 0).count() << endl;
cout << endl;
cout << "(a > 2).all() = " << (a > 2).all() << endl;
cout << "(a > 2).any() = " << (a > 2).any() << endl;
cout << "(a > 2).count() = " << (a > 2).count() << endl;
}
十三迭代
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main()
{
ArrayXXf a(2, 2);
a << 1, 2,
3, 4;
ArrayXXf::Index max, min;
cout << "max = " << a.maxCoeff(&max, &min) << endl;
cout << "max = " << a.minCoeff(&max, &min) << endl;
}
十四部分规约
- 部分规约指的是对矩阵或数组按行或列进行的操作,对每一列或者行进行规约操作时得到的是一个列或者行向量。如下例子得到矩阵每一列的最大值并存入一个行向量中
#include <Eigen/Dense>
#include <iostream>
using namespace std;
using namespace Eigen;
int main()
{
ArrayXXf a(2, 2);
a << 1, 2,
3, 4;
cout << "max = " << a.colwise().minCoeff() << endl;
}
部分规约和其他操作的结合
使用部分规约操作得到的结果去做其他的操作也是可以的,如下例子用于得到矩阵中元素和最大的一列
十五广播机制
- 广播的概念类似于部分规约,不同之处在于广播通过对向量在一个方向上的复制,将向量解释成矩阵。如下例子将一个列向量加到矩阵的每一列中
#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
Eigen::MatrixXf mat(2,4);
Eigen::VectorXf v(2);
mat << 1, 2, 6, 9,
3, 1, 7, 2;
v << 0,
1;
//add v to each column of m
mat.colwise() += v;
std::cout << "Broadcasting result: " << std::endl;
std::cout << mat << std::endl;
}
广播也可以和其他操作结合
参考链接 https://blog.csdn.net/hongge_smile/article/details/107296658 侵删