2.1 Hello World
#include#include // Eigen头文件,包含Eigen库里面所有的函数和类 int main() { Eigen::MatrixXd m(2,3); // MatrixXd:动态数组,初始化时指定数组的行列 m(0,0) = 3; m(1,0) = 2.5; ...; std::cout << m << std::endl; // Eigen重载了<<运算符,可以直接输出Eigen矩阵的值 }
2.2 Matrices and Vectors
#include#include using namespace std; using namespace Eigen; int main() { MatrixXd m = MatrixXd::Random(3,3); // 初始化动态数组 m = (m + MtrixXd::Constant(3,3,1.2)) * 50; cout<<"m = "< 6. Matrix和Array之间的相互转换
Matrix类和Array类之间可以相互转换,必须显示转换,才能对他们进行加减乘除运算。
Array44f a1,a2; Matrix4f m1,m2; m1 = a1 * a2; a1 = m1 * m2; a2 = a1 + m1.array(); m2 = a1.matrix() + m1; ArrayWrapperm1a(m1);// m1a是m1.array()的别名,他们共享相同的系数 MatrixWrapper a1m(a1); 7. 矩阵转置、共轭、共轭转置
下面介绍矩阵的一些操作。
7.1 转置与共轭
对矩阵的转置、共轭和共轭转置由成员函数transpose()/conjugate()/adjoint()实现。
MatrixXcf a = MatrixXcf::Random(2,2); cout<<"a = "<7.2 转置需要注意的事项
a = a.tanspose(); 无法运行,这称为别名问题。在Debug模式下当assertions没有禁止时,这种问题会被自动检测到。要避免错误,可以使用in-place转置。
Matrix2i a; a<<1,2,3,4; cout<<" a = \n"<8. 点积和叉积
对于点积和叉积,直接使用dot()和cross()方法。
Vector3d v(1,2,3); Vector3d w(0,1,2); cout<<"Dot product: "<注意:叉积仅仅用于尺寸为3的向量!点积可以用于任意尺寸的向量,当时用复数时,Eigen的点积作为第一个变量为共轭线性的,第二个为线性的。
9. 矩阵的基础的算术(求和、平均值等)
Eigen提供了一些对于矩阵或向量的规约操作,如sum()、prod()、maxCoeff()、minCoeff()
Eigen::Matrix2d mat; mat<<1,2,3,4; cout<<"mat.sum: "<10. Eigen块操作
10.1 块基本操作
块指的是矩阵或者数组中的一个矩形区域,块表达式可以用于左值或者右值,同样不会耗费运行时间,由编译器优化。 Eigen中最常用的快操作是block()方法,共有两个版本
索引从0开始,两个版本都可用于固定尺寸或者动态尺寸的矩阵和数组。这两个表达式语义上相同,唯一的区别是如果块的尺寸比较小的话固定尺寸版本的块操作运行更快,但是需要在便器阶段知道大小。
#include#include using namespace std; int main() { Eigen::MatrixXf m(4, 4); // 初始化m矩阵 for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { m(i, j) = j + 1 + i * 4; } } cout << "m: " << endl << m << endl; cout << "Block in the middle" << endl; cout << m.block<2, 2>(1, 1) << endl << endl;// m.block (a,b) 表示从第(a+1)行(b+1)列开始,截图i行,j列 for (int i = 1; i <= 3; ++i) { cout << "Block of size " << i << "x" << i << endl; cout << m.block(0, 0, i, i) << endl << endl;// m.block(a,b,i,j) 表示从第(a+1)行(b+1)列开始,截图i行,j列 } } 注意:m.block(a,b)表示从第(a+1)行(b+1)列开始,截i行j列。 上述例子中的块操作方法作为表达式的右值,意味着是只读形式的,然而,快操作也可以作为左值使用,意味着可以给其幅值,下面的例子说明了这一点,当然对于矩阵的操作是一样的。
#include#include using namespace std; using namespace Eigen; int main() { Array22f m; m << 1, 2, 3, 4; Array44f a = Array44f::Constant(0.6); cout << "Here is the array a:" << endl << a << endl << endl; a.block<2, 2>(1, 1) = m; cout << "Here is now a with m copied into its central 2x2 block:" << endl << a << endl << endl; 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 2x2 block:" << endl << a << endl << endl; } 尽管block()方法可用于任何形式的块操作,还是有特殊的方法用于特殊情况的,主要是为了更好的性能。说到性能,最重要的是在编译阶段给EIgen尽可能多的信息。比如,如果你的块是一个矩阵中的一列,那么使用col()方法会更好。
10.2 行和列
行和列是一种特殊的块,Eigen提供了特殊的方法:col()和row()。
#include#include using namespace std; int main() { Eigen::MatrixXf m(4, 4); // 数组初始化 for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { m(i, j) = j + 1 + i * 4; } } cout << "Here is the matrix m:" << endl << m << endl; cout << "2nd Row: " << m.row(1) << endl; 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; } 10.3 边角相关的操作
Eigen同样提供了对于挨着矩阵或数组的边、角的特殊操作方法,比如topLeftCorner()方法可用于操作矩阵左上角的区域。总结如下:
Eigen::Matrix4f m; m << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16; cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl; cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl; m.topLeftCorner(1, 3) = m.bottomRightCorner(3, 1).transpose(); cout << "After assignment, m = " << endl << m << endl;10.4 对于向量的块操作
Eigen也提供了一些针对向量和一维数组的块操作方法:
Eigen::ArrayXf v(6); v << 1, 2, 3, 4, 5, 6; cout << "v.head(3) =" << endl << v.head(3) << endl << endl; cout << "v.tail<3>() = " << endl << v.tail<3>() << endl << endl; v.segment(1,4) *= 2; cout << "after 'v.segment(1,4) *= 2', v =" << endl << v << endl;11 范数计算
向量的平方范数由squaredNorm()获得,等价于向量对自身做点积,也等同于所有元素额平方和。Eigen也提供了norm()范数,返回的是squaredNorm()的根。这些操作也适用于矩阵。如果想使用其他元素级的范数,使用lpNorm()方法,当求无穷范数时,模板参数p可以取特殊值Infinity,得到的是所有元素的最大绝对值。
#include#include using namespace std; using namespace Eigen; int main() { VectorXf v(2); MatrixXf m(2, 2), n(2, 2); v << -1, 2; m << 1, -2, -3, 4; cout << "v.squaredNorm() = " << v.squaredNorm() << endl; cout << "v.norm() = " << v.norm() << endl; cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << endl; cout << "v.lpNorm () = " << v.lpNorm () << endl; cout << endl; cout << "m.squaredNorm() = " << m.squaredNorm() << endl; cout << "m.norm() = " << m.norm() << endl; cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << endl; cout << "m.lpNorm () = " << m.lpNorm () << endl; } 矩阵的1范数和无穷范数也可以用下面的方法计算:
#include#include using namespace Eigen; using namespace std; int main() { MatrixXf m(2,2); m << 1,-2, -3,4; cout << "1-norm(m) = " << m.cwiseAbs().colwise().sum().maxCoeff() << " == " << m.colwise().lpNorm<1>().maxCoeff() << endl; cout << "infty-norm(m) = " << m.cwiseAbs().rowwise().sum().maxCoeff() << " == " << m.rowwise().lpNorm<1>().maxCoeff() << endl; } 12 布尔规约
如下的操作得到的是布尔值 all()返回真,如果矩阵或数组的所有元素为真 any()返回真,如果矩阵或数组至少有一个元素为真 count()返回元素为真的个数
#include#include using namespace std; using namespace Eigen; int main() { ArrayXXf a(2,2); a << 1,2,3,4; cout << "(a > 0).all() = " << (a > 0).all() << endl; cout << "(a > 0).any() = " << (a > 0).any() << endl; cout << "(a > 0).count() = " << (a > 0).count() << endl; cout << endl; cout << "(a > 2).all() = " << (a > 2).all() << endl; cout << "(a > 2).any() = " << (a > 2).any() << endl; cout << "(a > 2).count() = " << (a > 2).count() << endl; } 13迭代
当需要获得元素在矩阵或数组中的位置时使用迭代。
#include#include using namespace std; using namespace Eigen; int main() { Eigen::MatrixXf m(2,2); m << 1, 2,3, 4; //get location of maximum MatrixXf::Index maxRow, maxCol; float max = m.maxCoeff(&maxRow, &maxCol); //get location of minimum MatrixXf::Index minRow, minCol; float min = m.minCoeff(&minRow, &minCol); cout << "Max: " << max << ", at: " << maxRow << "," << maxCol << endl; cout << "Min: " << min << ", at: " << minRow << "," << minCol << endl; } 14 部分规约
部分规约指的是对矩阵或数组按行或列进行的操作,对每一列或者行进行规约操作时得到的是一个列或者行向量。如下例子得到矩阵每一列的最大值并存入一个行向量中。
#include#include using namespace std; int main() { Eigen::MatrixXf mat(2,4); mat << 1, 2, 6, 9, 3, 1, 7, 2; std::cout << "Column's maximum: \n" < 同样也可以得到每一行的最大值,返回一个列向量。
#include#include using namespace std; int main() { Eigen::MatrixXf mat(2,4); mat << 1, 2, 6, 9, 3, 1, 7, 2; std::cout << "Row's maximum: " << std::endl << mat.rowwise().maxCoeff() << std::endl; } 15 广播机制
广播的概念类似于部分规约,不同之处在于广播通过对向量在一个方向上的复制,将向量解释成矩阵。如下例子将一个列向量加到矩阵的每一列中。
#include#include using namespace std; int main() { Eigen::MatrixXf mat(2,4); Eigen::VectorXf v(2); mat << 1, 2, 6, 9, 3, 1, 7, 2; v << 0, 1; // add v to each column of m mat.colwise() += v; std::cout << "Broadcasting result: " << std::endl; std::cout << mat << std::endl; } 可以将mat.colwise()+=v理解成两种等价的方式,它将列向量加到矩阵的每一列中;或者将列向量复制4次的得到一个2x4的矩阵,之后进行矩阵的相加运算:
+=、+和-运算符也可以按列或行操作。在数组中也可以用=、/=、和/运算符执行元素级的按行或列乘除运算。但不能用在矩阵上,如果想用v(0)乘以矩阵的第0列,v(1)乘以矩阵的第1列…使用mat = matv.asDiagonal()。
结合广播和其他操作
广播也可以和其他操作结合,比如矩阵或数组的运算、规约和部分规约操作。下面介绍一个更加复杂的例子,演示了在矩阵中找到和给定向量最接近的一列,使用到了欧氏距离。
#include#include using namespace std; using namespace Eigen; int main() { Eigen::MatrixXf m(2,4); Eigen::VectorXf v(2); m << 1, 23, 6, 9, 3, 11, 7, 2; v << 2, 3; MatrixXf::Index index; // find nearest neighbour (m.colwise() - v).colwise().squaredNorm().minCoeff(&index); cout << "Nearest neighbour is column " << index << ":" << endl; cout << m.col(index) << endl; }