本文共 8198 字,大约阅读时间需要 27 分钟。
在上一篇博文中,博主记录了如何使用Eigen进行矩阵、向量的基础运算。本篇博文将在此基础上进一步记录数组类型和块操作。
与用于线性代数的Matrix类不同,Array类提供了一种通用数组。此类数组不具备线性代数的含义但提供了部分更为便捷的运算方式。
同定义Matrix类一样,Array类提供了一个六个参数的类模板,其中前三个参数是必须填写的。
// 数据类型 行数 列数Array
例如,定义一个3行1列的float类型的Array数组。
Arrayarray_31f
同Matrix一样,Array类也存在大量好用的TypeDef用于快速定义数组。
不同的是在Matrix模板类中,一维的矩阵称为列向量(Vector)或行向量(RowVector),二维的矩阵则被定义为矩阵(Matrix)。而在Array中则不存在此类规定,故而采用如下方式进行定义:Type | Typedef |
---|---|
Array<float,Dynamic,1> | ArrayXf |
Array<float,3,1> | Array3f |
Array<float,Dynamic,Dynamic> | ArrayXXf |
Array<float,2,3> | Array23f |
同Matrix类相同,不展开说明。
#include#include using namespace Eigen;using namespace std; int main(){ // 定义数组 ArrayXXf m(2,2); // 逐个赋予元素 m(0,0) = 1.0; m(0,1) = 2.0; m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0); // 输出数组元素 cout << m << endl ; // 输入数组 m << 1.0,2.0, 3.0,4.0; // 输出 cout << m << endl;}
和Matrix不同,数组的加法支持将标量添加到数组中的每个元素。如若将矩阵与标量相加则会产生报错。
#include#include using namespace Eigen;using namespace std; int main(){ 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; // 数组间相加减 cout << "a + b = \n" << endl << a + b << endl << endl; /*输出如下: * a + b = * 2 4 6 * 5 7 9 * 8 10 12 */ // 数组与标量间相加减 cout << "a - 2 = \n" << endl << a - 2 << endl; /*输出如下: * a - 2 = * -1 0 1 * 2 3 4 * 5 6 7 */}
在Matrix中,乘法被定义为矩阵间乘法;而在数组中则将乘法定义为对应元素(索引相同)相乘。在数组中两个相乘的数组必须满足**大小(size)**相同。
#include#include using namespace Eigen;using namespace std; int main(){ ArrayXXf a(2,2); ArrayXXf b(2,2); a << 1,2, 3,4; b << 5,6, 7,8; cout << "a * b = " << endl << a * b << endl; /*输出如下: * a * b = * 5 12 * 21 32 */}
在数组中支持大量的数学运算API,在使用时只需调用规定的API即可实现所需功能。
// API 数学含义array1.abs2() abs(array1)^2array1.abs() abs(array1)array1.sqrt() sqrt(array1)array1.log() log(array1)array1.log10() log10(array1)array1.exp() exp(array1)array1.pow(array2) pow(array1,array2)array1.pow(scalar) pow(array1,scalar) pow(scalar,array2)array1.square()array1.cube()array1.inverse() array1.sin() sin(array1)array1.cos() cos(array1)array1.tan() tan(array1)array1.asin() asin(array1)array1.acos() acos(array1)array1.atan() atan(array1)array1.sinh() sinh(array1)array1.cosh() cosh(array1)array1.tanh() tanh(array1)array1.arg() arg(array1) array1.floor() floor(array1)array1.ceil() ceil(array1)array1.round() round(aray1) array1.isFinite() isfinite(array1)array1.isInf() isinf(array1)array1.isNaN() isnan(array1)
在Eigen中,当需要进行线性代数运算应使用矩阵;当需要进行元素运算应使用数组。如需要同时使用Matrix和Array操作,需要将数组与矩阵进行相互转换。这样,无论选择将对象声明为数组还是矩阵,都可以访问所有操作。
对于Matrix类型数据,使用其 .array()方法 可转换为Array类型数据,同样对于 Array类型数据具有 .matrix()方法。 .array()和.matrix()可被用作右值或左值。
Eigen禁止在表达式中混用矩阵和数组。例如,不能直接将矩阵和数组进行相加,必须将其转换为同一类型后再进行计算。但同时,Eigen库允许将Matrix数据类型赋值给Array或相反。
#include#include using namespace Eigen;using namespace std; int main(){ MatrixXf m(2,2); MatrixXf n(2,2); MatrixXf result(2,2); m << 1,2, 3,4; n << 5,6, 7,8; // 矩阵乘法 result = m * n; cout << "-- Matrix m*n: --" << endl << result << endl << endl; /* * 输出结果如下: * -- Matrix m*n: -- * 19 22 * 43 50 */ // 数组乘法 result = m.array() * n.array(); cout << "-- Array m*n: --" << endl << result << endl << endl; /* * 输出结果如下: * --- Array m*n: -- * 5 12 * 21 32 */ // cwiseProduct方法实现数组乘法 result = m.cwiseProduct(n); cout << "-- With cwiseProduct: --" << endl << result << endl << endl; /* * 输出结果如下: * --- With cwiseProduct: -- * 5 12 * 21 32 */ // 数组加法 result = m.array() + 4; cout << "-- Array m + 4: --" << endl << result << endl << endl; /* * 输出结果如下: * -- Array m + 4: -- * 5 6 * 7 8 */ // 复合运算1 result = (m.array() + 4).matrix() * m; cout << "-- Combination 1: --" << endl << result << endl << endl; /* * 输出结果如下: * -- Combination 1: -- * 23 34 * 31 46 */ // 复合运算2 result = (m.array() * n.array()).matrix() * m; cout << "-- Combination 2: --" << endl << result << endl << endl; /* * 输出结果如下: * -- Combination 2: -- * 41 58 * 117 170 */}
块是矩阵或阵列的矩形部分。块表达式既可以用作右值,也可以用作左值。
构造一个块需要使用 .block()方法 ,其用法如下:
// 固定大小的块matrix.block (i,j)// 动态大小的块matrix.block(i,j,p,q)
其中参数具体含义如下:
即从原有矩阵的第i行第j列的元素开始起,构建一个p行q列的块。需要注意,在Eigen库中,索引从0开始。
#include#include using namespace std; int main(){ // 定义一个4*4的矩阵 Eigen::MatrixXf m(4,4); m << 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12, 13,14,15,16; //新建一个块 cout << "Block in the middle" << endl; cout << m.block<2,2>(1,1) << endl << endl; /* * 输出结果如下: * Block in the middle * 6 7 * 10 11 */ for (int i = 1; i <= 3; ++i) { cout << "Block of size " << i << "x" << i << endl; cout << m.block(0,0,i,i) << endl << endl; } /* * 输出结果如下: * Block of size 1x1 * 1 * Block of size 2x2 * 1 2 * 5 6 * Block of size 3x3 * 1 2 3 * 5 6 7 * 9 10 11 */}
同样,块操作可以运用在Array类型上:
#include#include using namespace std;using namespace Eigen; int main(){ // 定义一个数组 Array22f m; m << 1,2, 3,4; // 定义一个数组并初始化其值为0.6 Array44f a = Array44f::Constant(0.6); cout << "Here is the array a:" << endl << a << endl << endl; /* * 输出结果如下: * Here is the array a: * 0.6 0.6 0.6 0.6 * 0.6 0.6 0.6 0.6 * 0.6 0.6 0.6 0.6 * 0.6 0.6 0.6 0.6 */ // 将a中指定块的内容重新赋值 a.block<2,2>(1,1) = m; cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl; /* * 输出结果如下: * Here is now a with m copied into its central 2x2 block: * 0.6 0.6 0.6 0.6 * 0.6 1 2 0.6 * 0.6 3 4 0.6 * 0.6 0.6 0.6 0.6 */ // 将a中指定块的内容赋值为另一块的内容 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 2x3 block:" << endl << a << endl << endl; /* * 输出结果如下: * Here is now a with bottom-right 2x3 block copied into top-left 2x3 block: * 3 4 0.6 0.6 * 0.6 0.6 0.6 0.6 * 0.6 3 4 0.6 * 0.6 0.6 0.6 0.6 */ }
虽然使用块进行操作已经十分方便,但是为了获取到更好的性能,对于特殊的情况最好使用特定的API进行操作。例如在获取一个矩阵或数组的单列或单行时,可以使用方法 .col() 和 .row()。
#include#include using namespace std; int main(){ Eigen::MatrixXf m(3,3); m << 1,2,3, 4,5,6, 7,8,9; // 输出矩阵 cout << "Here is the matrix m:" << endl << m << endl; /* * 输出结果如下: * Here is the matrix m: * 1 2 3 * 4 5 6 * 7 8 9 */ // 获取第二行 cout << "2nd Row: " << m.row(1) << endl; /* * 输出结果如下: * 2nd Row: 4 5 6 */ // 第三行修改为第一行的三倍 m.col(2) += 3 * m.col(0); cout << "After adding 3 times the first column into the third column, the matrix m is:\n"; cout << m << endl; /* * 输出结果如下: * After adding 3 times the first column into the third column, the matrix m is: * 1 2 6 * 4 5 18 * 7 8 30 */}
在Eigen中针对向量和一维数组设计了一些便捷的API用于块操作。
#include#include 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 */}
转载地址:http://opnv.baihongyu.com/