Eigen库:数据运算、块与广播

数据运算

基础运算

在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
    */
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值