![]()
1 Matrix类
1.1 介绍
Eigen中所有的矩阵或者向量都用
Matrix表示,向量就是行为1或者列为1的矩阵
// Matrix 是个模板类 模板有六个参数 后三个都有默认值 一般只需要前三个就可以使用
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
class Matrix public ... {
...
};_Scalar矩阵类型(dtype) 可选 double, float, int …_Rowsand_Cols行和列 可以指定为已知值, 可以指定动态类型Dynamic(const int Dynamic = -1), 表示编译时候大小未知,动态指定_Options指定主存储顺序, 默认为0, 表示列优先(row-major)存储, 可选RowMajor|ColMajor_MaxRows指定行上限 默认为RowsAtCompileTime_MaxCols指定列上限 默认为ColsAtCompileTime
当然,在Eigen 定义了许多便利类使用,类似于:
typedef Matrix<double, Dynamic, Dynamic> MatrixXd; 行列为动态类型 类型为double的矩阵
typedef Matrix<double, 3, 3> Matrix3d; 3*3 double 类型矩阵
typedef Matrix<float, 4, 4> Matrix4f; 4*4 float 类型矩阵
typedef Matrix<float, 3, 1> Vector3f; 3个元素的列向量
typedef Matrix<int, 1, 2> RowVector2i; 行向量
1.2 构造函数(Constructors)
// 默认构造
Matrix3f a; // 3*3 float 大小为3*3 已分配内存 未初始化系数
MatrixXf b; // Dynamic * Dynamic double 大小为0*0 内存未分配 未初始化系数
// 指定行列 会分配内存 但不会初始化系数
MatrixXf a(10, 15) // 10*15 float
VectorXf b(30); // 10 * 1
Matrix3f a(3,3); // 合法 但是参数没啥用 已经指定好大小了1.3 初始化
// ★★★ 向量的初始化 最多不超过四个
Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);
// c++11初始化列表初始化
Vector2i a(1, 2);
Matrix<int, 5, 1> b {1, 2, 3, 4, 5};
Matrix<int, 1, 5> c = {1, 2, 3, 4, 5};
// 2*2 int
MatrixXi a {
{1, 2},
{3, 4}
};
2*3 double
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}}; // 行向量也可以通过逗号初始化矩阵
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << m;1.4 访问矩阵元素
一般通过 重载的 operator() 访问, 先传递行索引, 然后传递列索引, 获得对应位置的值的引用
Eigen::MatrixXd m(2,2); // 2*2 double
m(0,0) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);向量不可以通过重载 operator[] 访问, 直接传递下标访问
矩阵默认存储为列顺序存储, 如果要通过 operator 访问矩阵, 则关注一下存储顺序
1.5 调整大小(Resizing)
rows()获取行数cols()获取列数size()获取元素总数 size() = rows() * cols()resize()调整大小 会给便行列 保证resize()前后 size()不变
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::MatrixXd m(2,5);
m.resize(4,3);
std::cout << "The matrix m is of size "
<< m.rows() << "x" << m.cols() << std::endl;
std::cout << "It has " << m.size() << " coefficients" << std::endl;
Eigen::VectorXd v(2);
v.resize(5);
std::cout << "The vector v is of size " << v.size() << std::endl;
std::cout << "As a matrix, v is of size "
<< v.rows() << "x" << v.cols() << std::endl;
}output
The matrix m is of size 4x3
It has 12 coefficients
The vector v is of size 5
As a matrix, v is of size 5x11.6 矩阵赋值(Assignment)
使用操作符 = 将一个矩阵复制到另一个矩阵的操作, Eigen会自动调整左边矩阵的大小去适应右边矩阵大小
MatrixXf a(2,2);
std::cout << "a is of size " << a.rows() << "x" << a.cols() << std::endl;
MatrixXf b(3,3);
a = b;
std::cout << "a is now of size " << a.rows() << "x" << a.cols() << std::endl;outout
a is of size 2x2
a is now of size 3x31.7 固定大小和动态大小
对于较小的大小,特别是小于(大约)16,使用固定大小对性能非常有益 大于(大约)32的大小,使用固定大小的性能优势变得可以忽略不计 固定大小矩阵的数组直接指定大小 动态大小矩阵的数组总是在堆上分配
2 Tensor arithmetic
Eigen 通过重载c++算数运算符或特殊方法提供了矩阵/向量算数运算, ==操作符只被用作支持线性代数操作==
2.1 加法和减法运算(Addition and subtraction)
计算左边和右边必须有相同的行和列 必须有相同的Scalar类型, Eigen无法自动提升类型
- 加法
a + b或者a += b==对应位置元素相加== - 减法
a - b或者a -= b==对应位置元素相减==
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Matrix2d a;
a << 1, 2,
3, 4;
Eigen::MatrixXd b(2,2);
b << 2, 3,
1, 4;
std::cout << "a + b =\n" << a + b << std::endl;
std::cout << "a - b =\n" << a - b << std::endl;
std::cout << "Doing a += b;" << std::endl;
a += b;
std::cout << "Now a =\n" << a << std::endl;
Eigen::Vector3d v(1,2,3);
Eigen::Vector3d w(1,0,0);
std::cout << "-v + w - v =\n" << -v + w - v << std::endl;output
a * 2.5 =
2.5 5
7.5 10
0.1 * v =
0.1
0.2
0.3
Doing v *= 2;
Now v =
2
4
62.2 标量和矩阵的乘法和除法运算(Scalar multiplication and division)
- 乘法
matrix*scalar或者scalar*matrix或者matrix*=scalar==标量和矩阵每个元素相乘== - 除法
matrix/scalar或者matrix/=scalar==标量和矩阵每个元素相除== 注意: 标量不能除矩阵
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Matrix2d a;
a << 1, 2,
3, 4;
Eigen::Vector3d v(1,2,3);
std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl;
std::cout << "0.1 * v =\n" << 0.1 * v << std::endl;
std::cout << "Doing v *= 2;" << std::endl;
v *= 2;
std::cout << "Now v =\n" << v << std::endl;
}output
a * 2.5 =
2.5 5
7.5 10
0.1 * v =
0.1
0.2
0.3
Doing v *= 2;
Now v =
2
4
62.3 转置和共轭(Transposition and conjugation)
transpose()转置($a^T$)** 调用该方法需要赋值时才计算 ==如果要原地转置则用其他方法==**conjugate()共轭($\bar{a}$) (虚数才有)adjoint()共轭转置($a^*$) (实数的共轭转置相当于转置)transposeInPlace()原地转置 直接在
MatrixXcf a = MatrixXcf::Random(2,2);
cout << "Here is the matrix a\n" << a << endl;
cout << "Here is the matrix a^T\n" << a.transpose() << endl;
cout << "Here is the conjugate of a\n" << a.conjugate() << endl;
cout << "Here is the matrix a^*\n" << a.adjoint() << endl;output
Here is the matrix a
(-0.211,0.68) (-0.605,0.823)
(0.597,0.566) (0.536,-0.33)
Here is the matrix a^T
(-0.211,0.68) (0.597,0.566)
(-0.605,0.823) (0.536,-0.33)
Here is the conjugate of a
(-0.211,-0.68) (-0.605,-0.823)
(0.597,-0.566) (0.536,0.33)
Here is the matrix a^*
(-0.211,-0.68) (0.597,-0.566)
(-0.605,-0.823) (0.536,0.33)2.4 矩阵-矩阵和矩阵-向量乘法(Matrix-matrix and matrix-vector multiplication)
矩阵和矩阵的乘法也是运算符*完成, 矩阵-向量乘法是矩阵-矩阵的特殊情况 向量-向量的外积(区别于实际中向量的外积(叉积,矢量积))也是特殊情况 都按照矩阵乘法来计算
矩阵相乘的条件是==左矩阵的列和右矩阵的行相同==
a * ba *= b
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
Eigen::Vector2d u(-1,1), v(2,0);
std::cout << "Here is mat*mat:\n" << mat*mat << std::endl; // temp = m * m; m = temp;
std::cout << "Here is mat*u:\n" << mat*u << std::endl;
std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl;
std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl;
std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl;
std::cout << "Let's multiply mat by itself" << std::endl;
mat = mat*mat;
std::cout << "Now mat is mat:\n" << mat << std::endl;
}output
Here is mat*mat:
7 10
15 22
Here is mat*u:
1
1
Here is u^T*mat:
2 2
Here is u^T*v:
-2
Here is u*v^T:
-2 -0
2 0
Let's multiply mat by itself
Now mat is mat:
7 10
15 22如果知道矩阵计算可以安全计算而没有叠加问题 可以使用 noalias()
c.noalias() += a * b;
2.5 点乘(点积)和叉乘(叉积)(Dot product and cross product)
dot()点乘cross()叉乘
#include <iostream>
#include <Eigen/Dense>
int main()
{
Eigen::Vector3d v(1,2,3);
Eigen::Vector3d w(0,1,2);
std::cout << "Dot product: " << v.dot(w) << std::endl;
double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
std::cout << "Dot product via a matrix product: " << dp << std::endl;
std::cout << "Cross product:\n" << v.cross(w) << std::endl;
}output
Dot product: 8
Dot product via a matrix product: 8
Cross product:
1
-2
1外积(cross product)适用大小小于3的向量, 而内积(dot product)适用于任意大小的向量
2.6 基本的算术约简操作(Basic arithmetic reduction operations)
约简操作值得是用于汇总或者聚合数据的操作,以便得到某种总结或同级的结果
sum()求和(Summation)prod()求积(Product)mean()平均值(Mean)maxCoeff()最大值(Maximum)minCoeff()最小值(Minimum)trace()迹(对角系数的和) ==a.diagonal().sum()
maxCoeff() 和 minCoeff() 也可以传入参数, 可以获取最大值或最小值的下标
#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;
}output
Here is mat.sum(): 10
Here is mat.prod(): 24
Here is mat.mean(): 2.5
Here is mat.minCoeff(): 1
Here is mat.maxCoeff(): 4
Here is mat.trace(): 5