Eigen 通过重载C++的算数运算符或特殊方法来进行矩阵的算数运算
参与加减的矩阵要满足行列情况,并且元素数据类型也要相同,Eigen 不会自己进行数据类型转换。
//这里简单给出加减法运算,注意数据矩阵的数据类型
Matrix2d a;
a << 1, 2,
3, 4;
MatrixXd b(2,2);
b << 2, 3,
1, 4;
//双目加法:a+b
//双目减法:a-b
//单目减法:-a
//复合加法:a+=b //a = a + b;
//复合减法:a-=b //a = a - b;
Matrix2d a;
a << 1, 2,
3, 4;
//双目乘法:a*2.5
//双目乘法:2.5*a
//双目除法:a/2.5
//复合乘法:a*=2.5
//复合除法:a/=2.5
在Eigen 中,算术运算符本身是不执行任何计算,他只返回一个描述要执行的“表达式对象”,实际的计算是编译器进行优化后进行的。
说白了,不要去想象矩阵运算是怎么进行的,是按照数学上直接相加还是怎么样,不关心也没必要去知道。
注意:
transpose()
并adjoint()
简单地返回一个代理对象没有做实际的换位。a = a.transpose()
这样的操作,这种操作a 将不会发生变化,这种现象称为aliasing issue。Matrix2d a;
a << 1, 2,
3, 4;
Matrix2d b;
a << 5, 2,
7, 5;
a.transpose(); //转置,a取转置,但a本身不变化
a.conjugate(); //共轭
a.adjoint(); //伴随
a.transposeInPlace(); //对a 进行立即取转置,a 直接产生变化
b = a.transpose(); //结果在写入的时候同时产生转置,之前的a.transpose()只是简单的返回代理对象,并没有进行转换
a = a.transpose(); //不允许这样做,a的值将不变化。在写入a的同时还要对a进行转置,这不难为人么
注意:
Matrix2d a;
a << 1, 2,
3, 4;
Matrix2d b;
b << 2, 3,
4, 5;
//双目乘法:a*b
//复合乘法:a*=b //等价于a = a*b,注意a,b位置
//允许:a = a*a //可以这样写,不会产aliasing issue
注意:
Vector3d v(1,2,3);
Vector3d w(0,1,2);
\\点积:v.dot(w);
\\叉积:v.cross(w):
Array 类与Matrix 类很相似,但是我认为:
Array //与Matrix一样
自带定义
Array typedef ArrayXf
Array typedef Array3f
Array typedef ArrayXXd
Array typedef Array33d
索引
ArrayXXf m(2,2);
m(0,0) = 1.0; //索引,与Matrix一样
加减法
ArrayXXf a(3,3);
ArrayXXf b(3,3);
a << 1,2,3,
4,5,6,
7,8,9;
b << 1,2,3,
1,2,3,
1,2,3;
//a + b 的结果是:2,4,6;5,7,8;8,10,12;对应元素进行操作!!!!
//a + 2 :Array类可以与标量进行运算
乘法
ArrayXXf a(2,2);
ArrayXXf b(2,2);
a << 1,2,
3,4;
b << 5,6,
7,8;
//a * b 的结果是:5,12;21,32;对应元素进行乘法!!!!
其他运算
a.abs() //对每个元素取绝对值
a.sqrt() //对每个元素取算术平方根
MatrixXf m(2,2);
ArrayXXf n(2,2);
m.array(); //Matrix转Array
m.matrix(); //Array转Matrix
就是取Matrix或者Array的一个子块:
matrix.block(i,j,p,q);
matrix.block(i,j);
array.block(i,j,p,q);
array.block
(i,j);
//i,j为起始行列;
//p,q块的大小;!!!!
matrix.row(i); //取低i行
matrix.col(j); //取低j列
//取左上角p行q列的矩阵
matrix.topLeftCorner(p,q);
matrix.topLeftCorner();
//取左下角p行q列的矩阵
matrix.bottomLeftCorner(p,q);
matrix.bottomLeftCorner
();
//取右上角p行q列的矩阵
matrix.topRightCorner(p,q);
matrix.topRightCorner
();
//取右下角p行q列的矩阵
matrix.bottomRightCorner(p,q);
matrix.bottomRightCorner
();
//取从顶部开始的q行
matrix.topRows(q);
matrix.topRows();
//取从底部开始的q行
matrix.bottomRows(q);
matrix.bottomRows();
//取从左部开始的p列
matrix.leftCols(p);
matrix.leftCols();
//取从右部开始的p列
matrix.rightCols(q);
matrix.rightCols();
//取从i行开始的q行
matrix.middleCols(i,q);
matrix.middleCols(i);
//取从i列开始的q列
matrix.middleRows(i,q);
matrix.middleRows(i);
//取向量前n个元素
vector.head(n);
vector.head();
//取向量后n个元素
vector.tail(n);
vector.tail();
//取从i开始的n个元素
vector.segment(i,n);
vector.segment(i);
对于Matrix 和Array 的索引不单单局限于之前提到的角标或者块的方式,Eigen 中支持利用**“切片进行索引”,可以在操作符”()“**,中添加切片完成对Matrix 或者Array 子集索引。很像matlab中的索引方式
这种利用**”操作符()“**进行的索引可以如下表示:
DenseBase::operator()(const RowIndices&, const ColIndices&) //官方文档的表示,只要是“()”操作,则都可以用切片索引
其中两个参数可以是如下的任何一种形式:
Eigen::all
,Eigen::last
等表示的集合Eigen::seq,Eigen::seqN,Eigen::lastN
构造的集合seq (firstIdx,lastIdx); //从firstIdx开始,每次递增1,到lastIdx结束
seq (firstIdx,lastIdx,incr); //从firstIdx开始,每次递增incr,到lastIdx结束
seqN (firstIdx,size); //从firstIdx开始,每次递增1,递增size个
seqN (firstIdx,size,incr); //从firstIdx开始,每次递增incr,递增size个
Eigen::all; //从0开始每次递增1,直到结束
Eigen::last; //表示结尾,不是集合
注:后面有些内容看不懂,是关于自定义切片类型的部分,感觉用不到,就不写了
逗号初始化是:从左到右,从上到下,一行一行进行填充。
//用逗号直接构造一个矩阵
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
//逗号还可以用小矩阵来构建大矩阵
RowVectorXd vec1(3); //小向量
vec1 << 1, 2, 3;
RowVectorXd vec2(4); //小向量
vec2 << 1, 4, 9, 16;
RowVectorXd joined(7); //大向量
joined << vec1, vec2; //逗号构造!!!!
MatrixXf matA(2, 2); //小矩阵
matA << 1, 2, 3, 4;
MatrixXf matB(4, 4); //大矩阵
matB << matA, matA/10, matA/10, matA; //逗号构造!!!
//逗号构建矩阵的子集
Matrix3f m;
m.row(0) << 1, 2, 3;
m.block(1,0,2,2) << 4, 5, 7, 8;
m.col(2).tail(2) << 6, 9;
此外:
//m数据结构:Matrix或者Array,一下是常量矩阵和向量,动态矩阵和向量需要指定行和列
m::Zero(); //零矩阵
m::Ones(); //全1矩阵
m::Constant(value); //常量矩阵
m::Random(); //随机矩阵
m::LinSpaced(size, low, high); //生成size大小,从low到high的向量,只能是向量!!!!
m::Identity();
//x是对象,Matrix或者Array对象
x.setZero();
x.setOnes();
x.setConstant(value);
x.setRandom();
x.setLinSpaced(size, low, high);
//利用表达式进行构造
MatrixXd m = MatrixXd::Random (3,3);
m = (m + MatrixXd::Constant (3,3,1.2)) * 50 //用函数生成的常量矩阵来构造m,减小开销。
就是:根据矩阵元素计算一个标量,比如矩阵的迹等等
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
mat.sum(); //矩阵元素求和
mat.prod(); //矩阵元素求积
mat.mean(); //矩阵元素就平均值
mat.minCoeff(); //最小元素
mat.maxCoeff(); //最大元素
mat.trace(); //矩阵的迹
MatrixXf m(2,2);
m << 1,-2,
-3,4;
m.squaredNorm(); //二范数
m.norm(); //二范数的平方根
m.lpNorm<1>(); //p范数,<1>表示一范数
m.lpNorm(); //无穷范数
注:通常与Array的比较运算符联合使用,并且C++中非零都算是真哦
ArrayXXf a(2,2);
a << 1,2,
3,4;
(a > 0).all(); //元素是否都为真
(a > 0).any(); //元素是否有至少一个真
(a > 0).count(); //返回真的个数
a.all(); //也可以,非零都算是真
有时需要获取元素的位置信息,常用比如获取最大最小元素的位置和值,用到.maxCoeff
和.minCoeff
函数。
Eigen::MatrixXf m(2,2);
m << 1, 2,
3, 4;
MatrixXf::Index maxRow, maxCol; //Index类型,查找后是std::ptrdiff_t
float max = m.maxCoeff(&maxRow, &maxCol); //max,maxRow,maxCol均是输入
MatrixXf::Index minRow, minCol;
float min = m.minCoeff(&minRow, &minCol);
可以对矩阵的部分元素执行计算。
mat.colwise().maxCoeff(); //mat.colwize()本身返回的是VectorwiseOp类对象,maxCoeff()是这个类的函数
mat.rowwise().maxCoeff(); //直观理解就是将矩阵按每行或每列切片,个人理解啊!!
//官方给的一个复杂的应用
MatrixXf::Index maxIndex;
float maxNorm = mat.colwise().sum().maxCoeff(&maxIndex);
//先把矩阵按每列切片,然后按行求和,此时得到的是一个向量了
//然后找向量中最大元素
类似于Partial reductions,但是进行表达式的算术运算。
m << 1, 23, 6, 9,
3, 11, 7, 2;
v << 2,
3;
MatrixXf::Index index;
(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);
//!!!!! m.colwise() 返回的是类
//!!!!! m.colwise()-v 返回的是矩阵。。很有意思吧
注:这里是我根据源文件查看的信息,自己的理解,我尝试取直接输出 m.colwise()和 m.colwise()-v,前者会编译错误,后者输出矩阵。