数据运算
基础运算
在Eigen库中,对运算符(+、-、*、/)重载实现了矩阵、数组间的运算。两类数据的基础运算方式相同。
加减运算
矩阵和数组的加减运算相同,也即对应位置的元素间进行加减运算(矩阵加减法):
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Matrix3d a = Matrix3d::Identity();
Matrix3d b = Matrix3d::Ones();
// 加减运算
cout << "a+b=\n"<<a+b << endl;
cout << "a-b=\n"<<a-b << endl;
// 复合运算
a+=b;
cout << "a=a+b\n" << a << endl;
return 0;
}
输出如下:
a+b=
2 1 1
1 2 1
1 1 2
a-b=
0 -1 -1
-1 0 -1
-1 -1 0
a=a+b
2 1 1
1 2 1
1 1 2
取反、数乘、数除运算
数据的取反运算为对每个元素进行取反;数据同常数间的乘法、除法满足矩阵与常数间的乘法、除法:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Matrix3d a = Matrix3d::Identity();
// 取反运算
cout << "-a\n" << -a << endl;
// 常数乘法、除法运算
cout << "a*3=\n"<<a*3 << endl;
cout << "a/b=\n"<<a/3 << endl;
return 0;
}
输出如下:
-a
-1 -0 -0
-0 -1 -0
-0 -0 -1
a*3=
3 0 0
0 3 0
0 0 3
a/b=
0.333333 0 0
0 0.333333 0
0 0 0.333333
矩阵计算
矩阵乘法
Matrix
数据的乘法,满足矩阵乘法法则:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Matrix3d a = Matrix3d::Identity();
Matrix3d b = Matrix3d::Ones();
// 矩阵乘法
cout << a*b << endl;
return 0;
}
输出如下:
1 1 1
1 1 1
1 1 1
矩阵API
矩阵转置、逆、共轭、迹等,Eigen提供了对应API:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Matrix3d a = Matrix3d::Identity();
// 转置矩阵
a.transpose();
// 逆
a.inverse();
// 共轭矩阵
a.conjugate();
// 伴随矩阵
a.adjoint();
// 迹
a.trace();
// 行列式
a.determinant();
return 0;
}
同时,对于特殊的矩阵,向量,提供了实现其内外积的API:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main(){
Vector3d v(1,2,3);
Vector3d w(0,1,2);
cout << "向量内积 " << v.dot(w) << endl;
cout << "向量外积\n" << v.cross(w) << endl;
特征值、特征向量
Eigen中使用如下方式计算矩阵的特征值、特征向量:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Matrix3d mat=Matrix3d::Identity();
// 求解特征向量、特征值
SelfAdjointEigenSolver<Matrix3d> eigenSolver(mat.transpose()*mat);
// 特征向量
cout << eigenSolver.eigenvectors() << endl;
// 特征值
cout << eigenSolver.eigenvalues();
return 0;
}
数组计算
数组乘法
Array
数组类数据的乘法满足如下规则:对应位置的两个元素相乘。
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Array33d a = Array33d::Ones()*2;
Array33d b = Array33d::Ones();
// 数组乘法
cout << a*b << endl;
return 0;
}
输出结果如下:
2 2 2
2 2 2
2 2 2
数组API
对于数组数据,Eigen提供了大量API用于计算:
绝对值
array.abs2()
array.abs()
用于计算绝对值平方和绝对值。
开方
array.sqrt()
对数、指数
array.log()
array.log10()
用于计算数组元素的自然对数和10对数。
array.exp()
以自然对数为底,计算数组元素的指数。
array.pow(array2)
array.pow(scalar)
计算数组元素的指数,前者以array
为底,array2
中对应的元素为指数;
后者,统一以常数scalar
为指数。
三角函数、双曲函数
array.sin()
array.cos()
array.tan()
array.asin()
array.acos()
array.atan()
array.sinh()
array.cosh()
array.tanh()
取整函数
array.floor()
array.ceil()
array.round()
ceil
为上取整函数;floor
为下取整函数;round
为四舍五入函数。
元素检测函数
array.isInf()
array.isNaN()
用于逐一检测数据中元素是否存在INF、NAN
统计运算
Eigen库自带了用于统计运算的函数,如求和、积、最大值、最小值等。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main(){
Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "矩阵元素求和:" << mat.sum() << endl;
cout << "矩阵元素求积:" << mat.prod() << endl;
cout << "矩阵元素取中位数:" << mat.mean() << endl;
cout << "矩阵元素取最小值:" << mat.minCoeff() << endl;
cout << "矩阵元素取最大值:" << mat.maxCoeff() << endl;
}
数据广播
数据的广播能够使得向量(列或行)在一个方向上进行复制,从而形成矩阵。(数组原理相同)
实现广播需要使用方法**.colwise()** 和 .rowwise(),如下用数组数据进行演示:
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义数据
Array<double, 2, 4> arr = Array<double, 2, 4>::Zero();
Array<double,1,4> vec_row;
Array2d vec_col;
// 赋值
arr << 1, 2, 6, 9,
3, 1, 7, 2;
vec_row << 0, 1, 0, 1;
vec_col << 0,
1;
// 行广播
arr.rowwise()+=vec_row;
cout << "arr:\n" << arr << endl;
// 列广播
arr.colwise()+=vec_col;
cout << "arr:\n" << arr << endl;
return 0;
}
输出结果如下:
arr:
1 3 6 10
3 2 7 3
arr:
1 3 6 10
4 3 8 4
块操作
块操作可以择取数据中的一部分进行操作,而不改变其他数据。块可用作右值,也可用作左值。
构建块
首先,使用block
进行构建快区域 :
// 构建块
matrix.block<p,q>(i,j)
matrix.block(i,j,p,q)
以上两种形式都可用于构建块区域,其中参数含义如下:
- 块大小(行):p
- 块大小(列):q
- 起始索引位置(行):i
- 起始索引位置(列):j
即从原有数据第i行第j列的元素开始,构建一个p行q列的块。
如下,为块区域的构建效果
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义矩阵
Matrix4d mat;
Matrix2d m;
mat << 1, 2, 3, 4,
5, 6, 7, 8,
9,10,11,12,
13,14,15,16;
m << 2, 2,
2, 2;
// 构建块区域并修改区域内参数
mat.block<2,2>(1,1)=m;
cout << mat << endl;
return 0;
}
输出如下:
1 2 3 4
5 2 2 8
9 2 2 12
13 14 15 16
获取行或列
虽然使用块进行操作已经十分方便,但是为了获取到更好的性能,对于特殊的情况最好使用特定的API进行操作。例如在获取一个矩阵或数组的单列或单行时,可以使用方法 .col() 和 .row()。
#include <iostream>
#include <Eigen/Core>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
int main() {
// 定义矩阵
Matrix4d mat;
mat << 1, 2, 3, 4,
5, 6, 7, 8,
9,10,11,12,
13,14,15,16;
// 获取第二行
cout << "row 2:\n" << mat.row(1) << endl;
//获取第二列
cout << "col 2:\n" << mat.col(1) << endl;
return 0;
}
输出如下:
row 2:
5 6 7 8
col 2:
2
6
10
14
3.向量的块操作
在Eigen中针对向量、一维数组设计了一些API用于块操作:
#include <Eigen/Dense>
#include <iostream>
using namespace std;
int main()
{
Eigen::ArrayXf v(6);
v << 1, 2, 3, 4, 5, 6;
//输出向量的前三个元素
cout << v.head(3) << endl;
/*
* 输出结果如下:
* 1
* 2
* 3
*/
// 输出向量的后三个元素
cout << v.tail(3) << endl ;
/*
* 输出结果如下:
* 4
* 5
* 6
*/
v.segment(1,4) *= 2;
// 将向量从第二元素起后四个(包含第二元素)扩大至两倍
cout << "after 'v.segment(1,4) *= 2', v = \n" << v << endl;
/*
* 输出结果如下:
* 1
* 4
* 6
* 8
* 10
* 6
*/
}