├── README.md ├── chapter 1 ├── The matrix class.assets │ └── 318FCA1.PNG ├── Matrix and vector arithmetic.assets │ └── C019FC1.PNG ├── Interfacing with raw buffers the Map class.md ├── Reductions, visitors and broadcasting.assets │ ├── image-20220805190847053.png │ └── image-20220805192843403.png ├── Iterating over 1D arrays and vectors.md ├── Reshape.md ├── Eigen Advanced initialization.md ├── The Array class and coefficient-wise operations.md ├── The matrix class.md ├── Matrix and vector arithmetic.md ├── Eigen Block operations.md ├── Slicing and Indexing.md └── Reductions, visitors and broadcasting.md ├── 概述.md ├── 快速开始.md └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # Eigen-Chinese-Document 2 | 这是Eigen 3.4.90官方文档的翻译 3 | 4 | 由于个人水平有限,翻译不好的地方还请见谅。 5 | 6 | 欢迎对其中错误的地方进行指正和修改。 7 | 8 | jakeonef@gmail.com 9 | -------------------------------------------------------------------------------- /chapter 1/The matrix class.assets/318FCA1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jake-robot/Eigen-Chinese-Document/HEAD/chapter 1/The matrix class.assets/318FCA1.PNG -------------------------------------------------------------------------------- /chapter 1/Matrix and vector arithmetic.assets/C019FC1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jake-robot/Eigen-Chinese-Document/HEAD/chapter 1/Matrix and vector arithmetic.assets/C019FC1.PNG -------------------------------------------------------------------------------- /chapter 1/Interfacing with raw buffers the Map class.md: -------------------------------------------------------------------------------- 1 | [Eigen: Interfacing with raw buffers: the Map class](http://eigen.tuxfamily.org/dox/group__TutorialMapClass.html) 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /chapter 1/Reductions, visitors and broadcasting.assets/image-20220805190847053.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jake-robot/Eigen-Chinese-Document/HEAD/chapter 1/Reductions, visitors and broadcasting.assets/image-20220805190847053.png -------------------------------------------------------------------------------- /chapter 1/Reductions, visitors and broadcasting.assets/image-20220805192843403.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jake-robot/Eigen-Chinese-Document/HEAD/chapter 1/Reductions, visitors and broadcasting.assets/image-20220805192843403.png -------------------------------------------------------------------------------- /概述.md: -------------------------------------------------------------------------------- 1 | # 概述 2 | 3 | 这是Eigen3的API文档,你可以[下载](http://eigen.tuxfamily.org/dox/eigen-doc.tgz)它以便于离线阅读。 4 | 5 | 对于第一次接触Eigen,学习Eigen最好的方法就是阅读[开始页](http://eigen.tuxfamily.org/dox/GettingStarted.html),这可以让你学会如何使用Eigen编写你的代码。 6 | 7 | 然后,快速参考页面以非常简洁的格式提供了API的相当完整的描述,这对于回忆特定特性的语法或快速浏览API非常有用。它们目前涵盖了以下两个特性集,将来还会有更多。 8 | 9 | - 稠密矩阵和数组操作 10 | - 稀疏线性代数 11 | 12 | 如果你会使用MATLAB,那么[这里](http://eigen.tuxfamily.org/dox/AsciiQuickReference.txt)有一个Eigen与MATLAB操作对照文档。 13 | 14 | 文档的章节是按照不同特性领域来划分的,他们由两个部分组成:用户手册页面、参考页面,前者综合性的描述了不同的特性,后者让你接触到实际使用的API。 15 | 16 | 在[Extending/Customizing Eigen](http://eigen.tuxfamily.org/dox/UserManual_CustomizingEigen.html) 部分,你可以找到讨论和Eigen额外特性的例子与支持自定义标量类型。 17 | 18 | 在[General topics](http://eigen.tuxfamily.org/dox/UserManual_Generalities.html)部分,你可以看到诸如预处理指令、控制断言、多线程、MKL使用和Eigen的内部见解等等。 19 | 20 | 最后,使用搜索引擎可以让你快速的找到相关的类或者函数。 21 | 22 | -------------------------------------------------------------------------------- /chapter 1/Iterating over 1D arrays and vectors.md: -------------------------------------------------------------------------------- 1 | [Eigen: STL iterators and algorithms](http://eigen.tuxfamily.org/dox/group__TutorialSTL.html) 2 | 3 | 自从3\.4版本后,Eigen的稠密矩阵和阵列提供了与STL兼容的迭代器。如下所示,这让他们很自然的兼容范围的for循环和STL算法库。 4 | 5 | # 对一维阵列和向量进行迭代 6 | 7 | 任何有`begin()`和`end()`方法的一维表达式都可以进行迭代。 8 | 9 | 这直接的让C++11的range循环可以使用: 10 | 11 | ```c++ 12 | VectorXi v = VectorXi::Random(4); 13 | cout << "Here is the vector v:\n"; 14 | for(auto x : v) cout << x << " "; 15 | cout << "\n"; 16 | Output: 17 | Here is the vector v: 18 | 7 -2 6 6 19 | ``` 20 | 21 | 一维表达式同样可以很容易的传递给STL算法: 22 | 23 | ```c++ 24 | Array4i v = Array4i::Random().abs(); 25 | cout << "Here is the initial vector v:\n" << v.transpose() << "\n"; 26 | std::sort(v.begin(), v.end()); 27 | cout << "Here is the sorted vector v:\n" << v.transpose() << "\n"; 28 | Output: 29 | Here is the initial vector v: 30 | 7 2 6 6 31 | Here is the sorted vector v: 32 | 2 6 6 7 33 | ``` 34 | 35 | 类似于`std::vector`,一维表达式同样有`cbegin()/cend()`方法去方便的在non-const对象上获得const类型的迭代器。 36 | 37 | # 在二维阵列和矩阵上迭代 38 | 39 | STL迭代器本质上设计来迭代一维数据结构的。这就是为什么`begin()/end()`方法不可以在二维表达式上使用。迭代二维表达式可以通过reshaped()方法创建一维线性表达式来轻松完成。 40 | 41 | ```c++ 42 | Matrix2i A = Matrix2i::Random(); 43 | cout << "Here are the coeffs of the 2x2 matrix A:\n"; 44 | for(auto x : A.reshaped()) 45 | cout << x << " "; 46 | cout << "\n"; 47 | Output: 48 | Here are the coeffs of the 2x2 matrix A: 49 | 7 -2 6 6 50 | ``` 51 | 52 | 对二维矩阵或阵列的行或者列迭代 53 | 54 | 对二维表达式的行或列迭代也是可能的。这可以通过`rowwise()`和`colwise()`来完成,下面是一个对没列和行排序的例子: 55 | 56 | ```c++ 57 | ArrayXXi A = ArrayXXi::Random(4,4).abs(); 58 | cout << "Here is the initial matrix A:\n" << A << "\n"; 59 | for(auto row : A.rowwise()) 60 | std::sort(row.begin(), row.end()); 61 | cout << "Here is the sorted matrix A:\n" << A << "\n"; 62 | Output: 63 | 64 | Here is the initial matrix A: 65 | 7 9 5 3 66 | 2 6 1 0 67 | 6 3 0 9 68 | 6 6 3 9 69 | Here is the sorted matrix A: 70 | 3 5 7 9 71 | 0 1 2 6 72 | 0 3 6 9 73 | 3 6 6 9 74 | ``` 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /chapter 1/Reshape.md: -------------------------------------------------------------------------------- 1 | [Eigen: Reshape](http://eigen.tuxfamily.org/dox/group__TutorialReshape.html) 2 | 3 | 自从3.4版本以后,Eigen提供了可以对矩阵或向量重新塑形更方便的方法,所有的操作可以通过`DenseBase::reshaped(NRowsType,NColsType)`和`DenseBase::reshaped()`两个函数完成。该类函数并不改变原有的变量,而是返回一个重新塑形后的版本。 4 | 5 | # 二维度reshape 6 | 7 | 通常的reshape操作是通过`reshaped(nrows,ncols)`来完成,下面是一个例子把4\*4的矩阵变成2\*8的矩阵。 8 | 9 | ```c++ 10 | Matrix4i m = Matrix4i::Random(); 11 | cout << "Here is the matrix m:" << endl << m << endl; 12 | cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; 13 | 14 | Output: 15 | 16 | Here is the matrix m: 17 | 7 9 -5 -3 18 | -2 -6 1 0 19 | 6 -3 0 9 20 | 6 6 3 9 21 | Here is m.reshaped(2, 8): 22 | 7 6 9 -3 -5 0 -3 9 23 | -2 6 -6 6 1 3 0 9 24 | ``` 25 | 26 | 不管输入表达式的存储顺序,默认情况下,所有的系数都按照列来排序。想要控制顺序、编译时的大小和自动约简,可以参考`DenseBase::reshaped(NRowsType,NColsType)`的文档,文档中有很多细节。 27 | 28 | # 一维reshape 29 | 30 | 一个常见的用法即把二维的矩阵或者表达式变成一维的形式。这种情况下,维度可以计算出来,所以就不用传入相关参数了,如下: 31 | 32 | ```c++ 33 | Matrix4i m = Matrix4i::Random(); 34 | cout << "Here is the matrix m:" << endl << m << endl; 35 | cout << "Here is m.reshaped().transpose():" << endl << m.reshaped().transpose() << endl; 36 | cout << "Here is m.reshaped().transpose(): " << endl << m.reshaped().transpose() << endl; 37 | Output: 38 | Here is the matrix m: 39 | 7 9 -5 -3 40 | -2 -6 1 0 41 | 6 -3 0 9 42 | 6 6 3 9 43 | Here is m.reshaped().transpose(): 44 | 7 -2 6 6 9 -6 -3 6 -5 1 0 3 -3 0 9 9 45 | Here is m.reshaped().transpose(): 46 | 7 9 -5 -3 -2 -6 1 0 6 -3 0 9 6 6 3 9 47 | ``` 48 | 49 | 该方法返回列向量,并且,默认情况下输入系数总是按列排序。如果想要改变可以参考` DenseBase::reshaped() `相关文档。 50 | 51 | # 原地reshape 52 | 53 | 上述的例子都是返回另一个表达式,而不是原地修改变量,那么如何原地修改变量的大小呢?当然,这只对具有动态大小的矩阵或者阵列有用。大多数情况下,可以使用[PlainObjectBase::resize(Index,Index)](http://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#a9fd0703bd7bfe89d6dc80e2ce87c312a) 54 | 55 | ```c++ 56 | MatrixXi m = Matrix4i::Random(); 57 | cout << "Here is the matrix m:" << endl << m << endl; 58 | cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; 59 | m.resize(2,8); 60 | cout << "Here is the matrix m after m.resize(2,8):" << endl << m << endl; 61 | Output: 62 | Here is the matrix m: 63 | 7 9 -5 -3 64 | -2 -6 1 0 65 | 6 -3 0 9 66 | 6 6 3 9 67 | Here is m.reshaped(2, 8): 68 | 7 6 9 -3 -5 0 -3 9 69 | -2 6 -6 6 1 3 0 9 70 | Here is the matrix m after m.resize(2,8): 71 | 7 6 9 -3 -5 0 -3 9 72 | -2 6 -6 6 1 3 0 9 73 | ``` 74 | 75 | 但是,需要注意的是不像reshape,resize的顺序取决与输入的存储顺序,因此和`reshaped`表现类似。 76 | 77 | ```c++ 78 | Matrix m = Matrix4i::Random(); 79 | cout << "Here is the matrix m:" << endl << m << endl; 80 | cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; 81 | cout << "Here is m.reshaped(2, 8):" << endl << m.reshaped(2, 8) << endl; 82 | m.resize(2,8); 83 | cout << "Here is the matrix m after m.resize(2,8):" << endl << m << endl; 84 | Output: 85 | Here is the matrix m: 86 | 7 -2 6 6 87 | 9 -6 -3 6 88 | -5 1 0 3 89 | -3 0 9 9 90 | Here is m.reshaped(2, 8): 91 | 7 -5 -2 1 6 0 6 3 92 | 9 -3 -6 0 -3 9 6 9 93 | Here is m.reshaped(2, 8): 94 | 7 -2 6 6 9 -6 -3 6 95 | -5 1 0 3 -3 0 9 9 96 | Here is the matrix m after m.resize(2,8): 97 | 7 -2 6 6 9 -6 -3 6 98 | -5 1 0 3 -3 0 9 9 99 | ``` 100 | 101 | 最后,给自身赋一个reshape的值是禁止的,这是因为这样会由于混淆而导致未定义行为。`A = A.reshaped(2,8)`是禁止的,而`A = A.reshaped(2,8).eval(); `是可以的。 102 | -------------------------------------------------------------------------------- /快速开始.md: -------------------------------------------------------------------------------- 1 | [Eigen: Getting started](http://eigen.tuxfamily.org/dox/GettingStarted.html) 2 | 3 | 这是一个非常简短的让您能过快速上手Eigen的文章。这又两层目的。第一让你快速上手。你可以把该文章作为教程的第一部分,这更加详细的解释了Eigen库;看完这个教程后可以继续阅读 [The Matrix class](http://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html)教程。 4 | 5 | # 如何安装Eigen 6 | 7 | 为了使用Eigen,你仅仅需要下载和解压[Eigen](http://eigen.tuxfamily.org/dox/namespaceEigen.html)的源码。事实上,在Eigen的子目录中有头文件,这是你唯一需要的文件。这些文件在所有平台下都是通用的。它不需要使用Cmake或者安装什么。 8 | 9 | # 第一个简单的程序 10 | 11 | 这是一个非常简单的程序 12 | 13 | ```c++ 14 | #include 15 | #include 16 | 17 | using Eigen::MatrixXd; 18 | 19 | int main() 20 | { 21 | MatrixXd m(2,2); 22 | m(0,0) = 3; 23 | m(1,0) = 2.5; 24 | m(0,1) = -1; 25 | m(1,1) = m(1,0) + m(0,1); 26 | std::cout << m << std::endl; 27 | } 28 | ``` 29 | 30 | 在告诉你如何编译后再像您解释具体的代码。 31 | 32 | # 编译和运行您的第一个程序 33 | 34 | 没有任何库需要链接。脑袋中只要记住一件事情,需要让编译器能够找到Eigen的头文件即可。您放置的Eigen的源代码必须再include的路径追踪。使用GCC编译器时,需要用```-I```选项去完成这一目标,所以你需要通过下列命令来编译程序。 35 | 36 | ```g++ -I /path/to/eigen/ my_program.cpp -o my_program ``` 37 | 38 | 在linux或者Mac OS X,您也可以使用符号链接或者复制Eigen文件夹到```/usr/local/include/```.这样,你就可以使用下列命令来编译程序 39 | 40 | ```g++ my_program.cpp -o my_program``` 41 | 42 | 当年运行这个程序时,它将产生下列输出 43 | 44 | ``` 45 | 3 -1 46 | 2.5 1.5 47 | ``` 48 | 49 | # 解释第一个程序 50 | 51 | Eigen头文件定义了很多类型,但是简单的应用可能仅仅使用MatrixXd类型就足够了。这代表任意大小的矩阵,名字后面的X代表任意大小,d代表元素的类型是double。您可以[在此 ](http://eigen.tuxfamily.org/dox/group__QuickRefPage.html#QuickRef_Types)浏览各个类型可以表示的矩阵。 52 | 53 | Eigen/Dense头文件定义了所有的关于MatrixXd和 [相关类型](http://eigen.tuxfamily.org/dox/group__QuickRefPage.html#QuickRef_Headers)的成员函数。在头文件中定义所有的类和函数都有一个共同的命名空间Eigen。 54 | 55 | 上述main函数的第一行声明了一个MatrixXd类型的变量,然后指定了该变量的大小为2*2,但请注意这并没有初始化。m(0,0) = 3,代表对应的位置设置大小为3。你需要通过圆括号去访问矩阵中对应的元素。在计算机科学中,索引通常从零开始,Eigen也是一样。 56 | 57 | 下面的三行代码设置其它三个元素。最后一行代码把矩阵m输送给标准的输出流。 58 | 59 | # 示例2:矩阵和向量 60 | 61 | 这是结合了矩阵和向量的例子。 62 | 63 | ```c++ 64 | #include 65 | #include 66 | 67 | using Eigen::MatrixXd; 68 | using Eigen::VectorXd; 69 | 70 | int main() 71 | { 72 | MatrixXd m = MatrixXd::Random(3,3); 73 | m = (m + MatrixXd::Constant(3,3,1.2)) * 50; 74 | std::cout << "m =" << std::endl << m << std::endl; 75 | VectorXd v(3); 76 | v << 1, 2, 3; 77 | std::cout << "m * v =" << std::endl << m * v << std::endl; 78 | } 79 | ``` 80 | 81 | 输出 82 | 83 | ```c++ 84 | m = 85 | 94 89.8 43.5 86 | 49.4 101 86.8 87 | 88.3 29.8 37.8 88 | m * v = 89 | 404 90 | 512 91 | 261 92 | ``` 93 | 94 | # 解释第二个例子 95 | 96 | 第二个例子使用random()函数初始化了一个3*3的矩阵,其中每一个元素的值都在-1~1之间。下面的一行使用了一个线性变换,这让所有的值都在10~110之间。该函数调用MatrixXd::Constant(3,3,1.2),这返回了一个所有元素值都是1.2的3**3矩阵。剩下的部分是标准的计算。 97 | 98 | main函数的下一行介绍了一个新的类型VectorXd。这代表了一个任意大小的列向量。因此v包含3个未初始化的系数。倒数第二行使用了一个叫做逗号初始化的方法,您可以在[此](http://eigen.tuxfamily.org/dox/group__TutorialAdvancedInitialization.html)看到,这让v初始化为v = [1,2,3]**'** 。 99 | 100 | 最后一行让矩阵m和向量v相乘然后输出结果。 101 | 102 | 现在来解释下面的例子: 103 | 104 | ```C++ 105 | #include 106 | #include 107 | 108 | using Eigen::Matrix3d; 109 | using Eigen::Vector3d; 110 | 111 | int main() 112 | { 113 | Matrix3d m = Matrix3d::Random(); 114 | m = (m + Matrix3d::Constant(1.2)) * 50; 115 | std::cout << "m =" << std::endl << m << std::endl; 116 | Vector3d v(1,2,3); 117 | 118 | std::cout << "m * v =" << std::endl << m * v << std::endl; 119 | } 120 | ``` 121 | 122 | 与上面不同的是我们使用了Matrix3d而不是MatrixXd,这表示了一个固定的大小3*3。类似的,VectorXd代表任意大小,Vector3d代表固定的大小。注意现在向量v的大小直接在构造函数中创建了。 123 | 124 | 固定大小的矩阵和向量有两个好处。编译器会产生更好的代码,因为它知道矩阵和向量的大小。在类型中指定大小会在编译期间进行严格的检查。例如,编译器将会在一个4 * 4矩阵与3 * 1矩阵相乘时提示错误。但是使用太多类型会增加编译时间和可执行文件的大小。在编译时也可能不知道矩阵的大小。一个使用经验,在4*4或者更小的矩阵上使用固定大小的类型。 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /chapter 1/Eigen Advanced initialization.md: -------------------------------------------------------------------------------- 1 | [Eigen: Advanced initialization](http://eigen.tuxfamily.org/dox/group__TutorialAdvancedInitialization.html) 2 | 3 | 本文讨论几个高级的初始化方法,进一步的讨论之前的逗号初始化。同时解释了如何获取特殊的矩阵如单位矩阵和零矩阵。 4 | 5 | # 逗号初始化 6 | 7 | Eigen提供一个逗号初始化语法,这让用户可以很容易的设置矩阵、向量、阵列的系数。仅仅需要简单的列出系数,从左上角开始,从左向右,从上向下一次列出系数。初始化对象的大小需要提前指定。如果给的系数多了或少了,Eigen会报错。 8 | 9 | ```c++ 10 | Matrix3f m; 11 | m << 1, 2, 3, 12 | 4, 5, 6, 13 | 7, 8, 9; 14 | std::cout << m; 15 | Output: 16 | 1 2 3 17 | 4 5 6 18 | 7 8 9 19 | ``` 20 | 21 | 初始化列表它们自身可能是向量或者矩阵。逗号的使用就是把向量和矩阵连接起来。例如,下面是在指定向量大小后,连接两行向量。 22 | 23 | ```c++ 24 | RowVectorXd vec1(3); 25 | vec1 << 1, 2, 3; 26 | std::cout << "vec1 = " << vec1 << std::endl; 27 | 28 | RowVectorXd vec2(4); 29 | vec2 << 1, 4, 9, 16; 30 | std::cout << "vec2 = " << vec2 << std::endl; 31 | 32 | RowVectorXd joined(7); 33 | joined << vec1, vec2; 34 | std::cout << "joined = " << joined << std::endl; 35 | Output: 36 | vec1 = 1 2 3 37 | vec2 = 1 4 9 16 38 | joined = 1 2 3 1 4 9 16 39 | ``` 40 | 41 | 同样,我们也可以使用同样的技术去以一个块去初始化矩阵。 42 | 43 | ```c++ 44 | MatrixXf matA(2, 2); 45 | matA << 1, 2, 3, 4; 46 | MatrixXf matB(4, 4); 47 | matB << matA, matA/10, matA/10, matA; 48 | std::cout << matB << std::endl; 49 | Output: 50 | 1 2 0.1 0.2 51 | 3 4 0.3 0.4 52 | 0.1 0.2 1 2 53 | 0.3 0.4 3 4 54 | ``` 55 | 56 | 逗号初始化同样也可以填充块表达式如`m.row(i)`,下面是一个更加复杂的方式去实现第一个例子。 57 | 58 | ```c++ 59 | Matrix3f m; 60 | m.row(0) << 1, 2, 3; 61 | m.block(1,0,2,2) << 4, 5, 7, 8; 62 | m.col(2).tail(2) << 6, 9; 63 | std::cout << m; 64 | 65 | Output: 66 | 1 2 3 67 | 4 5 6 68 | 7 8 9 69 | ``` 70 | 71 | # 特殊的矩阵和阵列 72 | 73 | matrix和array类有静态方法如`Zero()`,这可以初始化所有系数为零。其中有三个变体。第一个变体不需要任何参数,仅仅可以用在固定大小的对象。如果你想要一个动态大小的对象,你需要指定大小。因此,第二个变体需要一个参数用来初始化一维动态对象。第三个变体,需要两个参数用来初始化二维对象的大小。所有的变体解释如下: 74 | 75 | ```c++ 76 | std::cout << "A fixed-size array:\n"; 77 | Array33f a1 = Array33f::Zero(); 78 | std::cout << a1 << "\n\n"; 79 | 80 | 81 | std::cout << "A one-dimensional dynamic-size array:\n"; 82 | ArrayXf a2 = ArrayXf::Zero(3); 83 | std::cout << a2 << "\n\n"; 84 | 85 | 86 | std::cout << "A two-dimensional dynamic-size array:\n"; 87 | ArrayXXf a3 = ArrayXXf::Zero(3, 4); 88 | std::cout << a3 << "\n"; 89 | 90 | Output: 91 | A fixed-size array: 92 | 0 0 0 93 | 0 0 0 94 | 0 0 0 95 | 96 | A one-dimensional dynamic-size array: 97 | 0 98 | 0 99 | 0 100 | 101 | A two-dimensional dynamic-size array: 102 | 0 0 0 0 103 | 0 0 0 0 104 | 0 0 0 0 105 | ``` 106 | 107 | 类似的,静态方法`Constant(value)`把所有系数都设置为value。如果对象的大小需要指定,除了value参数还需要额外的参数,如 `MatrixXd::Constant(rows, cols, value)`。方法`Random()`用随机的数字填充矩阵或阵列。使用`Identity()`获取单位矩阵,这只能用于matrix而不能用于vector,因为单位矩阵的概念是线性代数中的。方法`LinSpaced(size,low,high)`只对向量和一维阵列有效,它产生一个指定大小的向量,在low和high的等差数列。下面的例子解释`LinSpaced()`,其打印一个表格,表格中是角度和弧度的对应值,还有他们的sin和cos值。 108 | 109 | ```c++ 110 | ArrayXXf table(10, 4); 111 | table.col(0) = ArrayXf::LinSpaced(10, 0, 90); 112 | table.col(1) = M_PI / 180 * table.col(0); 113 | table.col(2) = table.col(1).sin(); 114 | table.col(3) = table.col(1).cos(); 115 | std::cout << " Degrees Radians Sine Cosine\n"; 116 | std::cout << table << std::endl; 117 | Output: 118 | Degrees Radians Sine Cosine 119 | 0 0 0 1 120 | 10 0.175 0.174 0.985 121 | 20 0.349 0.342 0.94 122 | 30 0.524 0.5 0.866 123 | 40 0.698 0.643 0.766 124 | 50 0.873 0.766 0.643 125 | 60 1.05 0.866 0.5 126 | 70 1.22 0.94 0.342 127 | 80 1.4 0.985 0.174 128 | 90 1.57 1 -4.37e-08 129 | ``` 130 | 131 | # 用作临时对象 132 | 133 | 如上所示,静态方法`Zero()`和`Constant()` 可以在声明时进行初始化或者在赋值操作符右侧进行初始化。你可以认为这些方法返回一个矩阵或者阵列,实际上,它们返回所谓的表达式对象,该对象当在需要的时候才被计算,所以这样的语法不会带来任何开销。 134 | 135 | 这些表达式也可以用作临时对象。如下为[Getting started](http://eigen.tuxfamily.org/dox/GettingStarted.html)的第二个例子,其说明了这个特性: 136 | 137 | ```c++ 138 | #include 139 | #include 140 | 141 | using Eigen::MatrixXd; 142 | using Eigen::VectorXd; 143 | 144 | int main() 145 | { 146 | MatrixXd m = MatrixXd::Random(3,3); 147 | m = (m + MatrixXd::Constant(3,3,1.2)) * 50; 148 | std::cout << "m =" << std::endl << m << std::endl; 149 | VectorXd v(3); 150 | v << 1, 2, 3; 151 | std::cout << "m * v =" << std::endl << m * v << std::endl; 152 | } 153 | 154 | Output: 155 | 156 | m = 157 | 94 89.8 43.5 158 | 49.4 101 86.8 159 | 88.3 29.8 37.8 160 | m * v = 161 | 404 162 | 512 163 | 261 164 | ``` 165 | 166 | 表达式 `m + MatrixXf::Constant(3,3,1.2)` 构造了一个3*3元素全为1.2的矩阵然后与对应的m元素相加。 167 | 168 | 逗号初始化也可以构造临时对象,下面的例子构造了一个2*3的随机矩阵,然后与矩阵[0,1;1,0]相乘。 169 | 170 | ```c++ 171 | MatrixXf mat = MatrixXf::Random(2, 3); 172 | std::cout << mat << std::endl << std::endl; 173 | mat = (MatrixXf(2,2) << 0, 1, 1, 0).finished() * mat; 174 | std::cout << mat << std::endl; 175 | Output: 176 | 0.68 0.566 0.823 177 | -0.211 0.597 -0.605 178 | 179 | -0.211 0.597 -0.605 180 | 0.68 0.566 0.823 181 | ``` 182 | 183 | 在完成临时子矩阵的逗号初始化之后,这里需要使用finished()方法来获得实际的矩阵对象。 184 | -------------------------------------------------------------------------------- /chapter 1/The Array class and coefficient-wise operations.md: -------------------------------------------------------------------------------- 1 | [Eigen: The Array class and coefficient-wise operations](http://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html) 2 | 3 | 该文章主要是介绍Eigen的数组类 4 | 5 | # 什么是数组类? 6 | 7 | 与Matrix类用于线性代数计算不同的是,Array类提供了通用目的数组。更进一步的说,Array类提供了更简单的方式去操作按照系数,这可能没有线性代数的意义,例如对每一个元素都相加一个常数或者对应元素相乘 8 | 9 | # 数组类型 10 | 11 | Array和Matrix类都是类模板。与Matrix一样,Array的前三个参数是强制性的: 12 | 13 | ```c++ 14 | Array 15 | ``` 16 | 17 | 后三个参数是可选择的。因为都是一样的,所以,再次我们不解释了。 18 | 19 | 对于一些常见的情况,Eigen同时也提供了已经定义好的类型,这与Matrix类相同,但是还有有一点区别的。array用在一维和二维数组上。我们使用ArrayNt代表一维N个大小的标量;使用ArrayNNt代表二维,解释如下: 20 | 21 | | Type | Typedef | 22 | | :---------------------------- | :------- | 23 | | Array | ArrayXf | 24 | | Array | Array3f | 25 | | Array | ArrayXXd | 26 | | Array | Array33d | 27 | 28 | # 访问数组内部的值 29 | 30 | 与Matrices相同,重载了括号运算符来读写数组元素的系数,使用`<<`来初始化数组或者打印数据。 31 | 32 | ```c++ 33 | #include 34 | #include 35 | 36 | int main() 37 | { 38 | Eigen::ArrayXXf m(2,2); 39 | 40 | // assign some values coefficient by coefficient 41 | m(0,0) = 1.0; m(0,1) = 2.0; 42 | m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0); 43 | 44 | // print values to standard output 45 | std::cout << m << std::endl << std::endl; 46 | 47 | // using the comma-initializer is also allowed 48 | m << 1.0,2.0, 49 | 3.0,4.0; 50 | 51 | // print values to standard output 52 | std::cout << m << std::endl; 53 | } 54 | Output: 55 | 1 2 56 | 3 5 57 | 58 | 1 2 59 | 3 4 60 | ``` 61 | 62 | # 加法和减法 63 | 64 | 加法和减法与matrices相同,只有数组的大小相同才可以,它们是对应元素相加或者相减。 65 | 66 | 数组同时支持`array + scalar`的表达形式,这对数组的每一个系数都相加一个常数。这是在Matrix类中所不可以实现的。 67 | 68 | ```c++ 69 | #include 70 | #include 71 | 72 | int main() 73 | { 74 | Eigen::ArrayXXf a(3,3); 75 | Eigen::ArrayXXf b(3,3); 76 | a << 1,2,3, 77 | 4,5,6, 78 | 7,8,9; 79 | b << 1,2,3, 80 | 1,2,3, 81 | 1,2,3; 82 | 83 | // Adding two arrays 84 | std::cout << "a + b = " << std::endl << a + b << std::endl << std::endl; 85 | 86 | // Subtracting a scalar from an array 87 | std::cout << "a - 2 = " << std::endl << a - 2 << std::endl; 88 | } 89 | Output: 90 | a + b = 91 | 2 4 6 92 | 5 7 9 93 | 8 10 12 94 | 95 | a - 2 = 96 | -1 0 1 97 | 2 3 4 98 | 5 6 7 99 | ``` 100 | 101 | # 数组乘法 102 | 103 | 首先,你可以使用一个数组乘以一个标量来完成,这和matrices一样,但是当你把两个Array相乘的时候,Array会对应元素相乘,但是matrices确是矩阵的乘法。所以Array相乘的时候,其大小必须是一样的。 104 | 105 | ```c++ 106 | #include 107 | #include 108 | 109 | int main() 110 | { 111 | Eigen::ArrayXXf a(2,2); 112 | Eigen::ArrayXXf b(2,2); 113 | a << 1,2, 114 | 3,4; 115 | b << 5,6, 116 | 7,8; 117 | std::cout << "a * b = " << std::endl << a * b << std::endl; 118 | } 119 | Output: 120 | a * b = 121 | 5 12 122 | 21 32 123 | ``` 124 | 125 | # 其他按系数操作 126 | 127 | 除了加减乘除,Array还定义了其他按系数操作的运算,例如`.abs()`对每一个元素求绝对值`.sqrt()` 计算每个元素的平方根。如果你有两个同样大小的array,你可以通过`.min(.)`来构造一个array,其每个元素的值是两个array中的较小的一个。示例如下: 128 | 129 | ```c++ 130 | #include 131 | #include 132 | 133 | int main() 134 | { 135 | Eigen::ArrayXf a = Eigen::ArrayXf::Random(5); 136 | a *= 2; 137 | std::cout << "a =" << std::endl 138 | << a << std::endl; 139 | std::cout << "a.abs() =" << std::endl 140 | << a.abs() << std::endl; 141 | std::cout << "a.abs().sqrt() =" << std::endl 142 | << a.abs().sqrt() << std::endl; 143 | std::cout << "a.min(a.abs().sqrt()) =" << std::endl 144 | << a.min(a.abs().sqrt()) << std::endl; 145 | } 146 | Output: 147 | a = 148 | 1.36 149 | -0.422 150 | 1.13 151 | 1.19 152 | 1.65 153 | a.abs() = 154 | 1.36 155 | 0.422 156 | 1.13 157 | 1.19 158 | 1.65 159 | a.abs().sqrt() = 160 | 1.17 161 | 0.65 162 | 1.06 163 | 1.09 164 | 1.28 165 | a.min(a.abs().sqrt()) = 166 | 1.17 167 | -0.422 168 | 1.06 169 | 1.09 170 | 1.28 171 | ``` 172 | 173 | # Array和Matrix表达式之间的转换 174 | 175 | 如何选择是使用array还是matrix呢?它们之间的运算是不相同的,不能混合使用。因此,当需要线性代数运算时使用matrix,当需要按元素操作时使用array。但是,当你同时需要两个操作的时候这不是很方便,所以你需要两个之间的转换,这就可以同时获得两个所有的运算能力。 176 | 177 | Matrix表达式有`.array()`方法可以把matrix转换为array表达式;array()有`.matrix()`方法转换回去。由于Eigen表达式的抽象,这些转换发生在编译的时候,所以不需要任何运行时间成本。`.array()`和`.matrix()`既可以作为左值,也可以作为右值。 178 | 179 | 但是在Eigen的表达式中混合使用array和matrices是不可取的的。例如,你不可以把一个matrix和array直接相加。但是,你可以转换过后再相加,有一个是例外的,赋值运算符是可以的,可以使用array赋值给matrices,反之亦然。 180 | 181 | 下面的例子,展示了如何再matrix上使用array的方法。例如,`result = m.array()*m.array()`把两个matrices转换为array,然后使用按元素相乘的方法把结果放在result中。 182 | 183 | 事实上,在Eigen中这样的用法很常见,所以提供了`const.cwiseProduct(.)`方法来满足matrices的按元素相乘的需要,下面是一个例子: 184 | 185 | ```c++ 186 | #include 187 | #include 188 | 189 | using Eigen::MatrixXf; 190 | 191 | int main() 192 | { 193 | MatrixXf m(2,2); 194 | MatrixXf n(2,2); 195 | MatrixXf result(2,2); 196 | 197 | m << 1,2, 198 | 3,4; 199 | n << 5,6, 200 | 7,8; 201 | 202 | result = m * n; 203 | std::cout << "-- Matrix m*n: --\n" << result << "\n\n"; 204 | result = m.array() * n.array(); 205 | std::cout << "-- Array m*n: --\n" << result << "\n\n"; 206 | result = m.cwiseProduct(n); 207 | std::cout << "-- With cwiseProduct: --\n" << result << "\n\n"; 208 | result = m.array() + 4; 209 | std::cout << "-- Array m + 4: --\n" << result << "\n\n"; 210 | } 211 | Output: 212 | #include 213 | #include 214 | 215 | using Eigen::MatrixXf; 216 | 217 | int main() 218 | { 219 | MatrixXf m(2,2); 220 | MatrixXf n(2,2); 221 | MatrixXf result(2,2); 222 | 223 | m << 1,2, 224 | 3,4; 225 | n << 5,6, 226 | 7,8; 227 | 228 | result = m * n; 229 | std::cout << "-- Matrix m*n: --\n" << result << "\n\n"; 230 | result = m.array() * n.array(); 231 | std::cout << "-- Array m*n: --\n" << result << "\n\n"; 232 | result = m.cwiseProduct(n); 233 | std::cout << "-- With cwiseProduct: --\n" << result << "\n\n"; 234 | result = m.array() + 4; 235 | std::cout << "-- Array m + 4: --\n" << result << "\n\n"; 236 | } 237 | ``` 238 | 239 | 类似的,如果array1和array2是数组,`array1.matrix() * array2.matrix()`计算他们的矩阵乘积。 240 | 241 | 下面是一个更复杂点的例子,表达式`(m.array() + 4).matrix() * m`对每一个元素都相加了4,然后计算m和其结果的矩阵乘积。类似的,表达式`(m.array() * n.array()).matrix() * m`按元素计算矩阵m和n的乘积,然后计算其结果与m的矩阵乘法。 242 | 243 | ```c++ 244 | #include 245 | #include 246 | 247 | using Eigen::MatrixXf; 248 | 249 | int main() 250 | { 251 | MatrixXf m(2,2); 252 | MatrixXf n(2,2); 253 | MatrixXf result(2,2); 254 | 255 | m << 1,2, 256 | 3,4; 257 | n << 5,6, 258 | 7,8; 259 | 260 | result = (m.array() + 4).matrix() * m; 261 | std::cout << "-- Combination 1: --\n" << result << "\n\n"; 262 | result = (m.array() * n.array()).matrix() * m; 263 | std::cout << "-- Combination 2: --\n" << result << "\n\n"; 264 | } 265 | 266 | Output: 267 | -- Combination 1: -- 268 | 23 34 269 | 31 46 270 | 271 | -- Combination 2: -- 272 | 41 58 273 | 117 170 274 | ``` 275 | 276 | -------------------------------------------------------------------------------- /chapter 1/The matrix class.md: -------------------------------------------------------------------------------- 1 | [Eigen: The Matrix class](http://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html) 2 | 3 | 4 | 5 | 在Eigen中,所有的矩阵和向量都是Matrix类模板的对象。向量只是行数或者列数为一的特殊矩阵。 6 | 7 | # Matrix前三个模板参数 8 | 9 | Matrix类有六个模板参数,但是目前为止学习前三个参数即可,剩下的三个都有默认的参数值,我们以后再讨论后面的三个。 10 | 11 | Matrix类三个强制性的模板参数是: 12 | 13 | ```C++ 14 | Matrix 15 | ``` 16 | 17 | - Scalar是标量的类型,例如系数的类型。如果你想要一个float类型的矩阵,那么你可以再次填写float。点击[Scalar types](http://eigen.tuxfamily.org/dox/TopicScalarTypes.html)查看标量的类型和如何添加新的类型。 18 | - RowsAtCompileTime和ColsAtCompileTime是矩阵的行和列数,这是在编译期间就知道的。点击[below](http://eigen.tuxfamily.org/dox/group__TutorialMatrixClass.html#TutorialMatrixDynamic)查看,如果不知道矩阵的大小该如何做。 19 | 20 | 我们提供了很多通常使用的类型。例如,Matrix4f是4*4的float矩阵,这在Eigen中定义为: 21 | 22 | ```C++ 23 | typedef Matrix Matrix4f; 24 | ``` 25 | 26 | # 向量 27 | 28 | 如上面所提到的,在Eigen中,向量仅仅是一种特殊的矩阵,把只有一列的矩阵叫做列向量,经常把列向量称为向量。行数为一的叫做行向量。 29 | 30 | 例如,Vector3f是3个float的列向量。这在Eigen中这样定义: 31 | 32 | ```c++ 33 | typedef Matrix RowVector2i; 34 | ``` 35 | 36 | # 动态的特殊值 37 | 38 | 当然,Eigen不限于指定大小的矩阵,RowsAtCompileTime和ColsAtCompileTime模板参数可以是一个动态值,这表明在编译阶段这个大小是不知道的,因为必须当作运行时的变量进行处理。在Eigen的俗术语中,这叫做动态大小;如果在编译期间就知道大小的叫做固定大小。例如,MatrixXd是double类型的动态大小: 39 | 40 | ```C++ 41 | typedef Matrix MatrixXd; 42 | ``` 43 | 44 | 类似的,我们定义VectorXi: 45 | 46 | ```c++ 47 | typedef Matrix VectorXi; 48 | ``` 49 | 50 | 您可以使用一个固定的行数和一个动态的列数 51 | 52 | ```c++ 53 | Matrix 54 | ``` 55 | 56 | # 构造函数 57 | 58 | 默认的构造函数总是可以使用的,它从来不执行任何动态内存分配,也从来不初始化矩阵元素。你可以这么做: 59 | 60 | ```c++ 61 | Matrix3f a; 62 | MatrixXf b; 63 | ``` 64 | 65 | - a是一个3*3的矩阵,他是一个9个大小的数组,而且没有任何初始化。 66 | - b是一个动态大小的矩阵,它的大小目前是0*0,它的内存也没有开辟 67 | 68 | 也有指定大小的构造函数。对于矩阵来说,第一个参数总是行,对于向量来说,只需要传入向量的大小即可。构造函数按照给定的大小开辟内存,但是并没有初始化内存。 69 | 70 | ```C++ 71 | MatrixXf a(10,15); 72 | VectorXf b(30); 73 | ``` 74 | 75 | - a是一个10*15的动态大小的矩阵,开辟了内存但是没有初始化 76 | - b是一个动态大小为30的向量,同样开辟了内存但是没有初始化 77 | 78 | 为了提供动态大小和固定大小矩阵统一的API,您可以向固定大小矩阵的构造函数传递大小,尽管这是没有用的,但是是合法的: 79 | 80 | ```C++ 81 | Matrix3f a(3,3); 82 | ``` 83 | 84 | 这并没有任何操作。 85 | 86 | 矩阵和向量也可以从一个列表及进行初始化。在C++11之前,这个功能这个只能用在固定大小的列或者向量并且其大小要小于4。 87 | 88 | ```C++ 89 | Vector2d a(5.0, 6.0); 90 | Vector3d b(5.0, 6.0, 7.0); 91 | Vector4d c(5.0, 6.0, 7.0, 8.0); 92 | ``` 93 | 94 | 如果使用C++11编译,任意固定大小的行或者列向量都可以使用这种方式传递向量。 95 | 96 | ```C++ 97 | Vector2i a(1, 2); // A column vector containing the elements {1, 2} 98 | Matrix b {1, 2, 3, 4, 5}; // A row-vector containing the elements {1, 2, 3, 4, 5} 99 | Matrix c = {1, 2, 3, 4, 5}; // A column vector containing the elements {1, 2, 3, 4, 5} 100 | ``` 101 | 102 | 通常,固定大小或者运行时大小固定的矩阵和向量,元素的系数是按照行进行分组的,然后使用该行去初始化矩阵的一行。 103 | 104 | ```C++ 105 | MatrixXi a { // construct a 2x2 matrix 106 | {1, 2}, // first row 107 | {3, 4} // second row 108 | }; 109 | Matrix b { 110 | {2, 3, 4}, 111 | {5, 6, 7}, 112 | }; 113 | ``` 114 | 115 | 对于列或者行向量,隐士的转置是被允许的。这意味着一个列向量可以被一个行进行初始化。 116 | 117 | ```C++ 118 | VectorXd a {{1.5, 2.5, 3.5}}; // A column-vector with 3 coefficients,隐式转换了 119 | RowVectorXd b {{1.0, 2.0, 3.0, 4.0}}; // A row-vector with 4 coefficients 120 | ``` 121 | 122 | # 访问系数 123 | 124 | 在Eigen中主要的系数访问方法是重载括号运算符。对于矩阵,行索引总是优先传递的。对于向量,只需要传递一个索引。索引从0开始。下面例子很清楚的解释了这一点。 125 | 126 | ```C++ 127 | #include 128 | #include 129 | 130 | int main() 131 | { 132 | Eigen::MatrixXd m(2,2); 133 | m(0,0) = 3; 134 | m(1,0) = 2.5; 135 | m(0,1) = -1; 136 | m(1,1) = m(1,0) + m(0,1); 137 | std::cout << "Here is the matrix m:\n" << m << std::endl; 138 | Eigen::VectorXd v(2); 139 | v(0) = 4; 140 | v(1) = v(0) - 1; 141 | std::cout << "Here is the vector v:\n" << v << std::endl; 142 | } 143 | 144 | Here is the matrix m: 145 | 3 -1 146 | 2.5 1.5 147 | Here is the vector v: 148 | 4 149 | 3 150 | ``` 151 | 152 | 请注意m(index)不只是只能用在向量,对普通的矩阵同样可以使用,在系数行列式中点访问是基于索引的。但是,索引取决于矩阵的存储顺序。在Eigen中,矩阵默认是列优先进行存储,但是这也可以改变,详情请查阅 [Storage orders](http://eigen.tuxfamily.org/dox/group__TopicStorageOrders.html)。 153 | 154 | 运算符**[ ]**同样也被重载用于基于索引的向量访问,但是请记住,C++只允许远算符**[ ]**最多传入1个参数。我们限制了运算符**[ ]**只能在vector上的使用,因为C++语言的笨拙,会把matrix[i,j]编译成matrix[j]。 155 | 156 | # 逗号初始化 157 | 158 | 矩阵和向量系数可以使用逗号进行初始化。如下: 159 | 160 | ```C++ 161 | Matrix3f m; 162 | m << 1, 2, 3, 163 | 4, 5, 6, 164 | 7, 8, 9; 165 | std::cout << m; 166 | 167 | Output: 168 | 1 2 3 169 | 4 5 6 170 | 7 8 9 171 | ``` 172 | 173 | # 重置大小 174 | 175 | 矩阵当前的大小可以通过函数rows(),cols(),size()来返回。这些方法分别返回函数、列数、系数的数量。对于动态大小的矩阵,可以使用函数resize()来重新调整大小。 176 | 177 | ```C++ 178 | #include 179 | #include 180 | 181 | int main() 182 | { 183 | Eigen::MatrixXd m(2,5); 184 | m.resize(4,3); 185 | std::cout << "The matrix m is of size " 186 | << m.rows() << "x" << m.cols() << std::endl; 187 | std::cout << "It has " << m.size() << " coefficients" << std::endl; 188 | Eigen::VectorXd v(2); 189 | v.resize(5); 190 | std::cout << "The vector v is of size " << v.size() << std::endl; 191 | std::cout << "As a matrix, v is of size " 192 | << v.rows() << "x" << v.cols() << std::endl; 193 | } 194 | 195 | Output: 196 | The matrix m is of size 4x3 197 | It has 12 coefficients 198 | The vector v is of size 5 199 | As a matrix, v is of size 5x1 200 | ``` 201 | 202 | 如果矩阵的大小没有改变,那么resize()方法不做任何操作。否则,该返回会破坏当前的矩阵,矩阵的系数可能会改变。如果你不想改变矩阵的系数,可以使用resize()的变体[conservativeResize()](http://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html#a712c25be1652e5a64a00f28c8ed11462)。 203 | 204 | 所有的这些方法都可以对固定大小的矩阵使用。当然,你不能对一个固定大小的矩阵使用resize。试图对一个固定大小的矩阵进行改变大小会触发断言。但是下列的代码是合法的。 205 | 206 | ```C++ 207 | #include 208 | #include 209 | 210 | int main() 211 | { 212 | Eigen::Matrix4d m; 213 | m.resize(4,4); // no operation 214 | std::cout << "The matrix m is of size " 215 | << m.rows() << "x" << m.cols() << std::endl; 216 | } 217 | Output: 218 | The matrix m is of size 4x4 219 | ``` 220 | 221 | # 赋值和重置大小 222 | 223 | 赋值是使用操作符=来完成复制的操作。Eigen将会自动调整等式左边的大小以便与和等式右边的大小做一个匹配,例如: 224 | 225 | ```C++ 226 | MatrixXf a(2,2); 227 | std::cout << "a is of size " << a.rows() << "x" << a.cols() << std::endl; 228 | MatrixXf b(3,3); 229 | a = b; 230 | std::cout << "a is now of size " << a.rows() << "x" << a.cols() << std::endl; 231 | Output: 232 | a is of size 2x2 233 | a is now of size 3x3 234 | ``` 235 | 236 | 当然如果,等式左边的大小是固定大小,重置大小是不被允许的。 237 | 238 | 如果你不想自动重置大小的操作发生,你可以关闭它,详情请参考[this page](http://eigen.tuxfamily.org/dox/TopicResizing.html)。 239 | 240 | # 固定和动态大小的比较 241 | 242 | 如何选择使用固定大小还是动态大小呢?对于非常小的矩阵应该选择固定大小,当面对大矩阵的时候应该使用动态大小。对于小的大小,特别是对于大小小于16时,使用固定大小效率更高,因为它允许Eigen避免动态分配内存和展开循环。一个固定大小Eigen矩阵仅仅是一个纯数组。例如,`Matrix4f mymatrix`等同于`float mymatrix[16]`,所以这没有没有运行的成本。而动态矩阵需要在堆中分配空间,例如:`MatrixXf mymatrix(rows,columns)`等价于`float *mymatrix = new float[rows*columns]`,除此之外,MatrixXf对象还存储了其行数和列数。 243 | 244 | 使用固定大小的限制就是在要求你在编译的时候就知道大小,而且对于大的矩阵,例如大于32的矩阵,使用固定大小的矩阵带来的优势可以忽略不计。更糟糕的是,试图使用固定大小的矩阵创建一个非常大的矩阵可能会导致栈溢出,因为Eigen使用分配一个很大的栈空间来存储这个局部变量。最后,看情况,如果使用动态大小,Eigen可以更加积极的去向量化操作,具体请查看 [Vectorization](http://eigen.tuxfamily.org/dox/TopicVectorization.html)。 245 | 246 | # 可选择的其他模板参数 247 | 248 | 在开始的时候,我们提及Matrix类有6个模板参数,但是,目前我们只讨论了前三个,剩下的三个参数是可供选择的。下面是完整的模板参数: 249 | 250 | ```C++ 251 | Matrix 257 | ``` 258 | 259 | - Options 是一个位域。这里,我们只讨论一个位RowMajor。它指定了矩阵是按照行优先进行存储的。默认情况下,存储顺序是按照列存储的。例如```Matrix```是指一个行优先3*3矩阵。 260 | - MaxRowsAtCompileTime 和 MaxColsAtCompileTime 是矩阵大小的上界,这让在编译前不知道矩阵的具体大小,就可以分配最大多少的内存,例如,```Matrix``` 会在编译的时候就使用一个大小为12个float的纯数组,而不需要动态分配内存。 261 | 262 | # 常用的类型 263 | 264 | - MatrixNt **<=>** Matrix. **例如** Matrix. 265 | - MatrixXNt **<=>** Matrix.**例如**Matrix. 266 | - MatrixNXt **<=>** Matrix. **例如** Matrix. 267 | - VectorNt **<=>** Matrix. **例如** Vector2f for Matrix. 268 | - RowVectorNt **<=>** Matrix. **例如** Matrix. 269 | 270 | 上述: 271 | 272 | - **N**代表2、3、4或者X 273 | - **t**代表任何一个i(int)、f(float)、d(double)、cf(complex)、cd(complex)。事实上,typedefs只定义了5种类型,但是这并不意味着,他们仅仅支持标量。例如,标准整形是支持的。 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | -------------------------------------------------------------------------------- /chapter 1/Matrix and vector arithmetic.md: -------------------------------------------------------------------------------- 1 | [Eigen: Matrix and vector arithmetic](http://eigen.tuxfamily.org/dox/group__TutorialMatrixArithmetic.html) 2 | 3 | 该文章主要大体的展示了如何使用Eigen在矩阵、向量、标量之间进行运算。 4 | 5 | # 介绍 6 | 7 | Eigen通过重载C++运算符号如+、-、*或者一些特殊的方法dot()、cross()等来完成计算操作。对于matrix类(矩阵和向量),相关的操作只支持线性代数的运算。例如,matrix1 * matrix2代表着矩阵的乘法;vector+scalar是不被允许的。如果你想执行各种各样的数组操作,而不是线性代数运算,请查阅[next page](http://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html)。 8 | 9 | # 加法和减法 10 | 11 | 在操作符左右两侧必须有同样的行数和同样的列数。它们的元素必须是同种类型。因为Eigen不支持自动类型转换。 12 | 13 | - binary operator + as in `a+b` 14 | - binary operator - as in `a-b` 15 | - unary operator - as in `-a` 16 | - compound operator += as in `a+=b` 17 | - compound operator -= as in `a-=b` 18 | 19 | ```C++ 20 | #include 21 | #include 22 | 23 | int main() 24 | { 25 | Eigen::Matrix2d a; 26 | a << 1, 2, 27 | 3, 4; 28 | Eigen::MatrixXd b(2,2); 29 | b << 2, 3, 30 | 1, 4; 31 | std::cout << "a + b =\n" << a + b << std::endl; 32 | std::cout << "a - b =\n" << a - b << std::endl; 33 | std::cout << "Doing a += b;" << std::endl; 34 | a += b; 35 | std::cout << "Now a =\n" << a << std::endl; 36 | Eigen::Vector3d v(1,2,3); 37 | Eigen::Vector3d w(1,0,0); 38 | std::cout << "-v + w - v =\n" << -v + w - v << std::endl; 39 | } 40 | Output: 41 | 42 | a + b = 43 | 3 5 44 | 4 8 45 | a - b = 46 | -1 -1 47 | 2 0 48 | Doing a += b; 49 | Now a = 50 | 3 5 51 | 4 8 52 | -v + w - v = 53 | -1 54 | -4 55 | -6 56 | ``` 57 | 58 | # 标量的乘除 59 | 60 | 乘法和除法是非常简单的 61 | 62 | - binary operator * as in `matrix*scalar` 63 | - binary operator * as in `scalar*matrix` 64 | - binary operator / as in `matrix/scalar` 65 | - compound operator *= as in `matrix*=scalar` 66 | - compound operator /= as in `matrix/=scalar` 67 | 68 | ```C++ 69 | #include 70 | #include 71 | 72 | int main() 73 | { 74 | Eigen::Matrix2d a; 75 | a << 1, 2, 76 | 3, 4; 77 | Eigen::Vector3d v(1,2,3); 78 | std::cout << "a * 2.5 =\n" << a * 2.5 << std::endl; 79 | std::cout << "0.1 * v =\n" << 0.1 * v << std::endl; 80 | std::cout << "Doing v *= 2;" << std::endl; 81 | v *= 2; 82 | std::cout << "Now v =\n" << v << std::endl; 83 | } 84 | Output: 85 | a * 2.5 = 86 | 2.5 5 87 | 7.5 10 88 | 0.1 * v = 89 | 0.1 90 | 0.2 91 | 0.3 92 | Doing v *= 2; 93 | Now v = 94 | 2 95 | 4 96 | 6 97 | ``` 98 | 99 | # 表达式模板的注解 100 | 101 | 这是一个比较高级的主题在这篇文章中,但是,现在提出是比较有用的。在Eigen,算数操作,例如+,他们自己不执行任何操作,他们只是返回一个表达式对象,该对象描述了将要执行的计算。实际的计算发生在后面,当整个表达式被求值时,通常是使用=。虽然这听起来很繁重,但任何现代优化编译器都能够优化掉这种抽象,从而得到完美优化的代码。例如,当你这样做时: 102 | 103 | ```c++ 104 | VectorXf a(50), b(50), c(50), d(50); 105 | ... 106 | a = 3*b + 4*c + 5*d; 107 | ``` 108 | 109 | Eigen会把上述代表编译成一个循环,这个数组只遍历一次。这个数组循环看起来像这样: 110 | 111 | ```C++ 112 | for(int i = 0; i < 50; ++i) 113 | a[i] = 3*b[i] + 4*c[i] + 5*d[i]; 114 | ``` 115 | 116 | 因此,你不要害怕使用相对较大的运算表达式,这只会给Eigen更多机会进行优化。 117 | 118 | # 转置和共轭 119 | 120 | a的转置、共轭和伴随(如共轭转置)是可以通过函数transpose(), conjugate(),adjoint()分别得到。 121 | 122 | 例如: 123 | 124 | ```c++ 125 | MatrixXcf a = MatrixXcf::Random(2,2); 126 | cout << "Here is the matrix a\n" << a << endl; 127 | 128 | cout << "Here is the matrix a^T\n" << a.transpose() << endl; 129 | 130 | 131 | cout << "Here is the conjugate of a\n" << a.conjugate() << endl; 132 | 133 | 134 | cout << "Here is the matrix a^*\n" << a.adjoint() << endl; 135 | 136 | OUTPUT: 137 | Here is the matrix a 138 | (-0.211,0.68) (-0.605,0.823) 139 | (0.597,0.566) (0.536,-0.33) 140 | Here is the matrix a^T 141 | (-0.211,0.68) (0.597,0.566) 142 | (-0.605,0.823) (0.536,-0.33) 143 | Here is the conjugate of a 144 | (-0.211,-0.68) (-0.605,-0.823) 145 | (0.597,-0.566) (0.536,0.33) 146 | Here is the matrix a^* 147 | (-0.211,-0.68) (0.597,-0.566) 148 | (-0.605,-0.823) (0.536,0.33) 149 | ``` 150 | 151 | 对于一个实数矩阵,共轭conjugate()函数没有任何操作,共轭转置adjoint()函数相当于transpose()函数。 152 | 153 | 作为基本的操作符,transpose和adjoint函数仅仅返回一个代理对象而没有做任何操作。如果你执行`b = a.transpose()`,真正的转置计算是在写入b的时候发生的。但是,这有一个复杂的问题,如果你执行`a = a.transpose()`,Eigen在转置计算完全完成之前就开始写入a,因此,所以指令`a = a.transpose()`不会改变a的任何元素。 154 | 155 | ```c++ 156 | Matrix2i a; a << 1, 2, 3, 4; 157 | cout << "Here is the matrix a:\n" << a << endl; 158 | 159 | a = a.transpose(); // !!! do NOT do this !!! 160 | cout << "and the result of the aliasing effect:\n" << a << endl; 161 | 162 | OUTPUT: 163 | Here is the matrix a: 164 | 1 2 165 | 3 4 166 | and the result of the aliasing effect: 167 | 1 2 168 | 2 4 169 | ``` 170 | 171 | 上述的问题就是所谓的混淆问题,在debug模式下,当assertion打开,这个问题可以自动检测到。 172 | 173 | 解决上述问题的方式可以使用transposeInPlace()函数: 174 | 175 | ```c++ 176 | MatrixXf a(2,3); a << 1, 2, 3, 4, 5, 6; 177 | cout << "Here is the initial matrix a:\n" << a << endl; 178 | 179 | 180 | a.transposeInPlace(); 181 | cout << "and after being transposed:\n" << a << endl; 182 | 183 | Output: 184 | Here is the initial matrix a: 185 | 1 2 3 186 | 4 5 6 187 | and after being transposed: 188 | 1 4 189 | 2 5 190 | 3 6 191 | ``` 192 | 193 | 同样,对于复数的共轭也有adjointInPlace()函数。 194 | 195 | # 矩阵之间和矩阵向量之间的乘法 196 | 197 | 矩阵和矩阵间的乘法是通过运算符`*`来完成的。由于向量是特殊的矩阵,所以向量和矩阵的乘法是一样的。所有的情况都会被处理成两类 198 | 199 | - 二位操作运算`*` ,如a`*`b 200 | - 混合运算符 `*=` ,如`a*=b` 即a = a`*` b 201 | 202 | ```c++ 203 | #include 204 | #include 205 | 206 | int main() 207 | { 208 | Eigen::Matrix2d mat; 209 | mat << 1, 2, 210 | 3, 4; 211 | Eigen::Vector2d u(-1,1), v(2,0); 212 | std::cout << "Here is mat*mat:\n" << mat*mat << std::endl; 213 | std::cout << "Here is mat*u:\n" << mat*u << std::endl; 214 | std::cout << "Here is u^T*mat:\n" << u.transpose()*mat << std::endl; 215 | std::cout << "Here is u^T*v:\n" << u.transpose()*v << std::endl; 216 | std::cout << "Here is u*v^T:\n" << u*v.transpose() << std::endl; 217 | std::cout << "Let's multiply mat by itself" << std::endl; 218 | mat = mat*mat; 219 | std::cout << "Now mat is mat:\n" << mat << std::endl; 220 | } 221 | 222 | Output: 223 | Here is mat*mat: 224 | 7 10 225 | 15 22 226 | Here is mat*u: 227 | 1 228 | 1 229 | Here is u^T*mat: 230 | 2 2 231 | Here is u^T*v: 232 | -2 233 | Here is u*v^T: 234 | -2 -0 235 | 2 0 236 | Let's multiply mat by itself 237 | Now mat is mat: 238 | 7 10 239 | 15 22 240 | ``` 241 | 242 | 注意:如果你阅读过上面的关于表达式模板的段落,有可能会担心m = m`* `m会引发混淆,先在你应该放心,Eigen把矩阵乘法作为一个特殊的例子,并且在此引入了一个临时变量,所以它会编译为: 243 | 244 | ```c++ 245 | tmp = m*m; 246 | m = tmp; 247 | ``` 248 | 249 | 如果你知道你的矩阵乘积可以安全的计算并且没有混淆问题,那么你可以使用noalias()函数来避免编译临时变量,例如: 250 | 251 | ```C++ 252 | c.noalias() += a * b; 253 | ``` 254 | 255 | 更多细节请点击[aliasing](http://eigen.tuxfamily.org/dox/group__TopicAliasing.html) 256 | 257 | 注意:对于BLAS用户但是性能的问题,表达式如:`c.noalias() -= 2 * a.adjoint() * b;`可以完全的优化并触发一个类似矩阵乘法的函数。 258 | 259 | # 基本的算法简化运算 260 | 261 | Eigen也提供了一些简化的把一个给定矩阵和向量变成标量的运算,如求和、求积、最大元素、最小元素。 262 | 263 | ```c++ 264 | #include 265 | #include 266 | 267 | using namespace std; 268 | int main() 269 | { 270 | Eigen::Matrix2d mat; 271 | mat << 1, 2, 272 | 3, 4; 273 | cout << "Here is mat.sum(): " << mat.sum() << endl; 274 | cout << "Here is mat.prod(): " << mat.prod() << endl; 275 | cout << "Here is mat.mean(): " << mat.mean() << endl; 276 | cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl; 277 | cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl; 278 | cout << "Here is mat.trace(): " << mat.trace() << endl; 279 | } 280 | Output: 281 | 282 | Here is mat.sum(): 10 283 | Here is mat.prod(): 24 284 | Here is mat.mean(): 2.5 285 | Here is mat.minCoeff(): 1 286 | Here is mat.maxCoeff(): 4 287 | Here is mat.trace(): 5 288 | ``` 289 | 290 | 矩阵的迹运算可以使用`trace()`或者 `a.diagonal().sum()` 291 | 292 | 同时存在`minCoeff` 和 `maxCoeff` 的变体,同时可以返回对应元素的坐标,如下所示: 293 | 294 | ```c++ 295 | Matrix3f m = Matrix3f::Random(); 296 | std::ptrdiff_t i, j; 297 | float minOfM = m.minCoeff(&i,&j); 298 | cout << "Here is the matrix m:\n" << m << endl; 299 | cout << "Its minimum coefficient (" << minOfM 300 | << ") is at position (" << i << "," << j << ")\n\n"; 301 | 302 | RowVector4i v = RowVector4i::Random(); 303 | int maxOfV = v.maxCoeff(&i); 304 | cout << "Here is the vector v: " << v << endl; 305 | cout << "Its maximum coefficient (" << maxOfV 306 | << ") is at position " << i << endl; 307 | Output: 308 | Here is the matrix m: 309 | 0.68 0.597 -0.33 310 | -0.211 0.823 0.536 311 | 0.566 -0.605 -0.444 312 | Its minimum coefficient (-0.605) is at position (2,1) 313 | 314 | Here is the vector v: 1 0 3 -3 315 | Its maximum coefficient (3) is at position 2 316 | ``` 317 | 318 | 319 | 320 | # 操作的有效性 321 | 322 | Eigen会检查你操作的有效性,如果有错误,它会在编译的时候产生提示。错误提示可能非常长而且难看,但是Eigen会把重要的信息写成大写,以使其更加显眼,如: 323 | 324 | ```c++ 325 | Matrix3f m; 326 | Vector4f v; 327 | v = m*v; // Compile-time error: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES 328 | ``` 329 | 330 | 当然,在很多情况下,如检查动态矩阵的大小,这是不能在编译的时候就知道的,Eigen会使用运行时的断言来判断。如果在debug模式下运行,遇到非法操作会终止运行并且会打印出错误消息。如果断言关闭了,程序可能会跑飞。 331 | 332 | ```c++ 333 | MatrixXf m(3,3); 334 | VectorXf v(4); 335 | v = m * v; // Run-time assertion failure here: "invalid matrix product" 336 | ``` 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | -------------------------------------------------------------------------------- /chapter 1/Eigen Block operations.md: -------------------------------------------------------------------------------- 1 | [Eigen: Block operations](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) 2 | 3 | 本文为块操作的概要。块是matrix或array的矩形的一部分,它可以是左值也可以是右值。与Eigen表达式一样,如果让编译器优化,块操作没有运行时间成本。 4 | 5 | # 使用块操作 6 | 7 | 在Eigen中最常见的块操作时`.block()` ,这右两个版本,语法如下: 8 | 9 | | **Block** **operation** | Version constructing a dynamic-size block expression | Version constructing a fixed-size block expression | 10 | | :----------------------------------------- | :--------------------------------------------------- | :------------------------------------------------- | 11 | | Block of size `(p,q)`, starting at `(i,j)` | matrix.block(i,j,p,q); | matrix.block(i,j); | 12 | 13 | Eigen的索引是以0开始的。 14 | 15 | 两个版本都可以用在固定大小和动态大小的matrices和array上。两种表达式语义上是一致的,只有一点差别即固定的版本会在块比较小的时候快一点,但是要求块大小在编译的时候就知道。 16 | 17 | 下面的程序使用动态和固定版本去打印matrix中的几个块: 18 | 19 | ```c++ 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | 25 | int main() 26 | { 27 | Eigen::MatrixXf m(4,4); 28 | m << 1, 2, 3, 4, 29 | 5, 6, 7, 8, 30 | 9,10,11,12, 31 | 13,14,15,16; 32 | cout << "Block in the middle" << endl; 33 | cout << m.block<2,2>(1,1) << endl << endl; 34 | for (int i = 1; i <= 3; ++i) 35 | { 36 | cout << "Block of size " << i << "x" << i << endl; 37 | cout << m.block(0,0,i,i) << endl << endl; 38 | } 39 | } 40 | Output: 41 | 42 | Block in the middle 43 | 6 7 44 | 10 11 45 | 46 | Block of size 1x1 47 | 1 48 | 49 | Block of size 2x2 50 | 1 2 51 | 5 6 52 | 53 | Block of size 3x3 54 | 1 2 3 55 | 5 6 7 56 | 9 10 11 57 | ``` 58 | 59 | 在上述的例子中`.block()`函数当作一个右值,但是块也可以当作左值。 60 | 61 | 下面给出在array中使用块: 62 | 63 | ```c++ 64 | #include 65 | #include 66 | 67 | int main() 68 | { 69 | Eigen::Array22f m; 70 | m << 1,2, 71 | 3,4; 72 | Eigen::Array44f a = Eigen::Array44f::Constant(0.6); 73 | std::cout << "Here is the array a:\n" << a << "\n\n"; 74 | a.block<2,2>(1,1) = m; 75 | std::cout << "Here is now a with m copied into its central 2x2 block:\n" << a << "\n\n"; 76 | a.block(0,0,2,3) = a.block(2,1,2,3); 77 | std::cout << "Here is now a with bottom-right 2x3 block copied into top-left 2x3 block:\n" << a << "\n\n"; 78 | } 79 | Output: 80 | 81 | Here is the array a: 82 | 0.6 0.6 0.6 0.6 83 | 0.6 0.6 0.6 0.6 84 | 0.6 0.6 0.6 0.6 85 | 0.6 0.6 0.6 0.6 86 | 87 | Here is now a with m copied into its central 2x2 block: 88 | 0.6 0.6 0.6 0.6 89 | 0.6 1 2 0.6 90 | 0.6 3 4 0.6 91 | 0.6 0.6 0.6 0.6 92 | 93 | Here is now a with bottom-right 2x3 block copied into top-left 2x3 block: 94 | 3 4 0.6 0.6 95 | 0.6 0.6 0.6 0.6 96 | 0.6 3 4 0.6 97 | 0.6 0.6 0.6 0.6 98 | ``` 99 | 100 | 尽管`.block()`可以用在任何块操作,但仍然右一些API用于特殊情况,可以提供更好的性能。在性能表现上,最重要的是能在编译的前提供给Eigen尽可能多的信息。例如,所使用的块是一列,那么使用`.col()`函数可以让Eigen知道这只是一列,从而给更多的机会去优化。 101 | 102 | 下文是描述一些特殊情况。 103 | 104 | # 列和行 105 | 106 | 单独的列和行是特殊的块,Eigen提供更容易的方法`.col()`和`.row()`去处理这些块。 107 | 108 | | Block operation | Method | 109 | | :----------------------------------------------------------- | :------------- | 110 | | ith row [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.row(i); | 111 | | jth column [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.col(j); | 112 | 113 | `row()`和`col()`的参数是需要访问的行数和列数,在Eigen中是从0开始的。 114 | 115 | ```c++ 116 | #include 117 | #include 118 | 119 | using namespace std; 120 | 121 | int main() 122 | { 123 | Eigen::MatrixXf m(3,3); 124 | m << 1,2,3, 125 | 4,5,6, 126 | 7,8,9; 127 | cout << "Here is the matrix m:" << endl << m << endl; 128 | cout << "2nd Row: " << m.row(1) << endl; 129 | m.col(2) += 3 * m.col(0); 130 | cout << "After adding 3 times the first column into the third column, the matrix m is:\n"; 131 | cout << m << endl; 132 | } 133 | Output: 134 | Here is the matrix m: 135 | 1 2 3 136 | 4 5 6 137 | 7 8 9 138 | 2nd Row: 4 5 6 139 | After adding 3 times the first column into the third column, the matrix m is: 140 | 1 2 6 141 | 4 5 18 142 | 7 8 30 143 | ``` 144 | 145 | 示例还演示了块表达式可以像其它算术表达式一样使用。 146 | 147 | # 关于拐角的操作 148 | 149 | Eigen还对矩阵或数组的角或边的块提供了特殊的方法,例如:`.topLeftCorner()` 可以用作一个矩阵左上角的块。 150 | 151 | 下表总结了各种各样的可能: 152 | 153 | | Block **operation** | Version constructing a dynamic-size block expression | Version constructing a fixed-size block expression | 154 | | :----------------------------------------------------------- | :--------------------------------------------------- | :------------------------------------------------- | 155 | | Top-left p by q block [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.topLeftCorner(p,q); | matrix.topLeftCorner(); | 156 | | Bottom-left p by q block [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.bottomLeftCorner(p,q); | matrix.bottomLeftCorner(); | 157 | | Top-right p by q block [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.topRightCorner(p,q); | matrix.topRightCorner(); | 158 | | Bottom-right p by q block [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.bottomRightCorner(p,q); | matrix.bottomRightCorner(); | 159 | | Block containing the first q rows [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.topRows(q); | matrix.topRows(); | 160 | | Block containing the last q rows [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.bottomRows(q); | matrix.bottomRows(); | 161 | | Block containing the first p columns [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.leftCols(p); | matrix.leftCols

(); | 162 | | Block containing the last q columns [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.rightCols(q); | matrix.rightCols(); | 163 | | Block containing the q columns starting from i [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.middleCols(i,q); | matrix.middleCols(i); | 164 | | Block containing the q rows starting from i [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | matrix.middleRows(i,q); | matrix.middleRows(i); | 165 | 166 | 下面是一个简单的例子来解释上述的函数: 167 | 168 | ```c++ 169 | #include 170 | #include 171 | 172 | using namespace std; 173 | 174 | int main() 175 | { 176 | Eigen::Matrix4f m; 177 | m << 1, 2, 3, 4, 178 | 5, 6, 7, 8, 179 | 9, 10,11,12, 180 | 13,14,15,16; 181 | cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl; 182 | cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl; 183 | m.topLeftCorner(1,3) = m.bottomRightCorner(3,1).transpose(); 184 | cout << "After assignment, m = " << endl << m << endl; 185 | } 186 | Output: 187 | m.leftCols(2) = 188 | 1 2 189 | 5 6 190 | 9 10 191 | 13 14 192 | 193 | m.bottomRows<2>() = 194 | 9 10 11 12 195 | 13 14 15 16 196 | 197 | After assignment, m = 198 | 8 12 16 4 199 | 5 6 7 8 200 | 9 10 11 12 201 | 13 14 15 16 202 | ``` 203 | 204 | # 对向量使用块操作 205 | 206 | Eigen同样针对一些特殊情况的向量和一维数组提供一些特殊的函数,如下: 207 | 208 | | Block operation | Version constructing a dynamic-size block expression | Version constructing a fixed-size block expression | 209 | | :----------------------------------------------------------- | :--------------------------------------------------- | :------------------------------------------------- | 210 | | Block containing the first `n` elements [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | vector.head(n); | vector.head(); | 211 | | Block containing the last `n` elements [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | vector.tail(n); | vector.tail(); | 212 | | Block containing `n` elements, starting at position `i` [*](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html) | vector.segment(i,n); | vector.segment(i); | 213 | 214 | 示例如下: 215 | 216 | ```c++ 217 | #include 218 | #include 219 | 220 | using namespace std; 221 | 222 | int main() 223 | { 224 | Eigen::ArrayXf v(6); 225 | v << 1, 2, 3, 4, 5, 6; 226 | cout << "v.head(3) =" << endl << v.head(3) << endl << endl; 227 | cout << "v.tail<3>() = " << endl << v.tail<3>() << endl << endl; 228 | v.segment(1,4) *= 2; 229 | cout << "after 'v.segment(1,4) *= 2', v =" << endl << v << endl; 230 | } 231 | Output: 232 | v.head(3) = 233 | 1 234 | 2 235 | 3 236 | 237 | v.tail<3>() = 238 | 4 239 | 5 240 | 6 241 | 242 | after 'v.segment(1,4) *= 2', v = 243 | 1 244 | 4 245 | 6 246 | 8 247 | 10 248 | 6 249 | ``` 250 | 251 | -------------------------------------------------------------------------------- /chapter 1/Slicing and Indexing.md: -------------------------------------------------------------------------------- 1 | [Eigen: Slicing and Indexing](http://eigen.tuxfamily.org/dox/group__TutorialSlicingIndexing.html) 2 | 3 | 4 | 5 | 本文展示如果使用操作运算符`operator()` 来索引行和列的子集。这个API是在Eigen 3.4中完成的。它拥有 [block API](http://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html)提供的所有功能,甚至更多。特别的,它支持包含提取一行、一列、单个元素的操作以及等间隔的从矩阵或者数组中提取元素。 6 | 7 | # 概述 8 | 9 | 上述所以提到的操作都是用`DenseBase::operator()(const RowIndices&, const ColIndices&)`来完成的,每一个参数可以是: 10 | 11 | - 索引单行或列的整数,包括符号索引 12 | - 符号Eigen::all表示按递增顺序排列的所有行或列 13 | - 由 `Eigen::seq`,` Eigen::seqN`或者` Eigen::placeholders::lastN` 函数构造的[ArithmeticSequence](http://eigen.tuxfamily.org/dox/classEigen_1_1ArithmeticSequence.html) 14 | - 任意一维整数向量、阵列,形式如Eigen数组、阵列、表达式,`std::vector` , C的数组`int[N]` 15 | 16 | 更一般的,该函数可以接受任何有下列两个成员函数接口的对象 17 | 18 | ```c++ 19 | operator[]() const; 20 | 21 | size() const; 22 | ``` 23 | 24 | 其中`` 代表任何可以与`Eigen::index`兼容的整数,如`std::ptrdiff_t` 25 | 26 | # 基本的切片 27 | 28 | 通过`Eigen::seq`或`Eigen::seqN`函数,取矩阵或向量中均匀间隔的一组行、列或元素,其中seq代表等差数列。他们的用法如下: 29 | 30 | | function | description | example | 31 | | :----------------------------------------------------------- | :-------------------------------------------- | :----------------------------------------------------------- | 32 | | [seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(firstIdx,lastIdx) | 返回从`firstIdx` 到 `lastIdx`的整数 | [seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(2,5) <=> {2,3,4,5} | 33 | | [seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(firstIdx,lastIdx,incr) | 与上面相同,但是索引每次增加incr | [seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(2,8,2) <=> {2,4,6,8} | 34 | | [seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(firstIdx,size) | 从`firstIdx`开始,索引每次加1,总的个数为size | [seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(2,5) <=> {2,3,4,5,6} | 35 | | [seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(firstIdx,size,incr) | 与上述相同,索引每次增加incr | [seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(2,3,3) <=> {2,5,8} | 36 | 37 | 一旦等差序列通过operator()传递给它,`firststidx`和`lasttidx`参数也可以用`Eigen::last`符号来定义,该符号表示矩阵/向量的最后一行、最后一列或元素的索引,使用如下: 38 | 39 | | Intent | Code | Block-API equivalence | 40 | | :------------------------------------------------------- | :----------------------------------------------------------- | :------------------------------- | 41 | | Bottom-left corner starting at row `i` with `n` columns | A([seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(i,[last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d)), [seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(0,n)) | A.bottomLeftCorner(A.rows()-i,n) | 42 | | Block starting at `i`,j having `m` rows, and `n` columns | A([seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(i,m), [seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(i,n)) | A.block(i,j,m,n) | 43 | | Block starting at `i0`,j0 and ending at `i1`,j1 | A([seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(i0,i1), [seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(j0,j1) | A.block(i0,j0,i1-i0+1,j1-j0+1) | 44 | | Even columns of A | A([all](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga4abe6022fbef6cda264ef2947a2be1a9), [seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(0,[last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d),2)) | | 45 | | First `n` odd rows A | A([seqN](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a3a3c346d2a61d1e8e86e6fb4cf57fbda)(1,n,2), [all](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga4abe6022fbef6cda264ef2947a2be1a9)) | | 46 | | The last past one column | A([all](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga4abe6022fbef6cda264ef2947a2be1a9), [last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d)-1) | A.col(A.cols()-2) | 47 | | The middle row | A([last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d)/2,[all](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga4abe6022fbef6cda264ef2947a2be1a9)) | A.row((A.rows()-1)/2) | 48 | | Last elements of v starting at i | v([seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)(i,[last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d))) | v.tail(v.size()-i) | 49 | | Last `n` elements of v | v([seq](http://eigen.tuxfamily.org/dox/namespaceEigen.html#a0c04400203ca9b414e13c9c721399969)([last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d)+1-n,[last](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga66661a473fe06e47e3fd5c591b6ffe8d))) | v.tail(n) | 50 | 51 | 正如在上一个示例中看到的,引用最后n个元素(或行/列)编写起来有点麻烦。使用非默认增量时,这将变得更加棘手和容易出错。因此,Eigen提供了[Eigen::placeholders::lastN(size)](http://eigen.tuxfamily.org/dox/group__TutorialSlicingIndexing.html)和[Eigen::placeholders::lastN(size,incr) ](http://eigen.tuxfamily.org/dox/group__TutorialSlicingIndexing.html)函数来完成最后几个元素的提取,用法如下: 52 | 53 | | | | | 54 | | :--------------------------------------------- | :----------------------------------------------------------- | :----------------------- | 55 | | Intent | Code | Block-API equivalence | 56 | | Last `n` elements of v | v(lastN(n)) | v.tail(n) | 57 | | Bottom-right corner of A of size `m` times `n` | v(lastN(m), lastN(n)) | A.bottomRightCorner(m,n) | 58 | | Bottom-right corner of A of size `m` times `n` | v(lastN(m), lastN(n)) | A.bottomRightCorner(m,n) | 59 | | Last `n` columns taking 1 column over 3 | A([all](http://eigen.tuxfamily.org/dox/group__Core__Module.html#ga4abe6022fbef6cda264ef2947a2be1a9), lastN(n,3)) | | 60 | 61 | # 编译时的大小和增量 62 | 63 | 在性能方面,Eigen和编译器可以利用编译时的大小和增量。为了这个目的,你可以使用`Eigen::fix`在编译时刻强制指定大小。而且,它可以和`Eigen::last`符号一起使用: 64 | 65 | ```c++ 66 | v(seq(last-fix<7>, last-fix<2>)) 67 | ``` 68 | 69 | 在这个例子中,Eigen在编译时就知道返回的表达式有6个元素。它等价于: 70 | 71 | ```c++ 72 | v(seqN(last-7, fix<6>)) 73 | ``` 74 | 75 | 我们可以查看A的偶数列,如: 76 | 77 | ```c++ 78 | A(all, seq(0,last,fix<2>)) 79 | ``` 80 | 81 | # 倒序 82 | 83 | 我们可以把增量设置为负数,如该例子实现A的20到10列中取一半: 84 | 85 | ```c++ 86 | A(all, seq(20, 10, fix<-2>)) 87 | ``` 88 | 89 | 从最后一个开始,取n个数: 90 | 91 | ```c++ 92 | A(seqN(last, n, fix<-1>), all) 93 | ``` 94 | 95 | 也可以使用函数`ArithmeticSequence::reverse() `方法来反转序列,之前的例子也可以写作: 96 | 97 | ```c++ 98 | A(lastN(n).reverse(), all) 99 | ``` 100 | 101 | # 数组的索引 102 | 103 | `operator()`输入的也可以是`ArrayXi`, `std::vector`, `std::array`,如: 104 | 105 | ```c++ 106 | Example: 107 | std::vector ind{4,2,5,5,3}; 108 | MatrixXi A = MatrixXi::Random(4,6); 109 | cout << "Initial matrix A:\n" << A << "\n\n"; 110 | cout << "A(all,ind):\n" << A(Eigen::placeholders::all,ind) << "\n\n"; 111 | Output: 112 | Initial matrix A: 113 | 7 9 -5 -3 3 -10 114 | -2 -6 1 0 5 -5 115 | 6 -3 0 9 -8 -8 116 | 6 6 3 9 2 6 117 | 118 | A(all,ind): 119 | 3 -5 -10 -10 -3 120 | 5 1 -5 -5 0 121 | -8 0 -8 -8 9 122 | 2 3 6 6 9 123 | 124 | 125 | ``` 126 | 127 | ```c++ 128 | MatrixXi A = MatrixXi::Random(4,6); 129 | cout << "Initial matrix A:\n" << A << "\n\n"; 130 | cout << "A(all,{4,2,5,5,3}):\n" << A(Eigen::placeholders::all,{4,2,5,5,3}) << "\n\n"; 131 | Output: 132 | Initial matrix A: 133 | 7 9 -5 -3 3 -10 134 | -2 -6 1 0 5 -5 135 | 6 -3 0 9 -8 -8 136 | 6 6 3 9 2 6 137 | 138 | A(all,{4,2,5,5,3}): 139 | 3 -5 -10 -10 -3 140 | 5 1 -5 -5 0 141 | -8 0 -8 -8 9 142 | 2 3 6 6 9 143 | ``` 144 | 145 | ```c++ 146 | ArrayXi ind(5); ind<<4,2,5,5,3; 147 | MatrixXi A = MatrixXi::Random(4,6); 148 | cout << "Initial matrix A:\n" << A << "\n\n"; 149 | cout << "A(all,ind-1):\n" << A(Eigen::placeholders::all,ind-1) << "\n\n"; 150 | Output: 151 | Initial matrix A: 152 | 7 9 -5 -3 3 -10 153 | -2 -6 1 0 5 -5 154 | 6 -3 0 9 -8 -8 155 | 6 6 3 9 2 6 156 | 157 | A(all,ind-1): 158 | -3 9 3 3 -5 159 | 0 -6 5 5 1 160 | 9 -3 -8 -8 0 161 | 9 6 2 2 3 162 | ``` 163 | 164 | 当传递一个具有编译时大小的对象(如`Array4i`、`std::array`或静态数组)时,返回的表达式也会显示编译时维度。 165 | 166 | # 自定义索引列表 167 | 168 | 更一般的,`operator()`可以接受任何与下列兼容的T类型的对象ind: 169 | 170 | ```c++ 171 | Index s = ind.size(); or Index s = size(ind); 172 | Index i; 173 | i = ind[i]; 174 | ``` 175 | 176 | 这意味着您可以轻松地构建自己的序列生成器并将其传递给operator()。下面是一个例子,扩大一个给定的矩阵,同时通过重复填充额外的第一行和列: 177 | 178 | ```c++ 179 | struct pad { 180 | Index size() const { return out_size; } 181 | Index operator[] (Index i) const { return std::max(0,i-(out_size-in_size)); } 182 | Index in_size, out_size; 183 | }; 184 | 185 | Matrix3i A; 186 | A.reshaped() = VectorXi::LinSpaced(9,1,9); 187 | cout << "Initial matrix A:\n" << A << "\n\n"; 188 | MatrixXi B(5,5); 189 | B = A(pad{3,5}, pad{3,5}); 190 | cout << "A(pad{3,N}, pad{3,N}):\n" << B << "\n\n"; 191 | 192 | Output: 193 | Initial matrix A: 194 | 1 4 7 195 | 2 5 8 196 | 3 6 9 197 | 198 | A(pad{3,N}, pad{3,N}): 199 | 1 1 1 4 7 200 | 1 1 1 4 7 201 | 1 1 1 4 7 202 | 2 2 2 5 8 203 | 3 3 3 6 9 204 | ``` 205 | 206 | -------------------------------------------------------------------------------- /chapter 1/Reductions, visitors and broadcasting.md: -------------------------------------------------------------------------------- 1 | [Eigen: Reductions, visitors and broadcasting](http://eigen.tuxfamily.org/dox/group__TutorialReductionsVisitorsBroadcasting.html) 2 | 3 | 本文解释Eigen的约简、访客和广播以及它们如何用于矩阵和数组。 4 | 5 | # 约简 6 | 7 | 在Eigen,约简单是把一个矩阵和数组变成一个标量。一个经常用到的约简是`sum()`,它返回所有矩阵和阵列元素的和。 8 | 9 | ```c++ 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | int main() 15 | { 16 | Eigen::Matrix2d mat; 17 | mat << 1, 2, 18 | 3, 4; 19 | cout << "Here is mat.sum(): " << mat.sum() << endl; 20 | cout << "Here is mat.prod(): " << mat.prod() << endl; 21 | cout << "Here is mat.mean(): " << mat.mean() << endl; 22 | cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl; 23 | cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl; 24 | cout << "Here is mat.trace(): " << mat.trace() << endl; 25 | } 26 | 27 | Output: 28 | Here is mat.sum(): 10 29 | Here is mat.prod(): 24 30 | Here is mat.mean(): 2.5 31 | Here is mat.minCoeff(): 1 32 | Here is mat.maxCoeff(): 4 33 | Here is mat.trace(): 5 34 | ``` 35 | 36 | 矩阵的迹可以通过`trace()`来得到,也可以通过`a.diagonal().sum()`得到。 37 | 38 | # 模的计算 39 | 40 | 向量的二范数可以通过[squaredNorm()](http://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#ac8da566526419f9742a6c471bbd87e0a)来计算,这等价于自己和自己点乘,也等于它系数绝对值的平方和。 41 | 42 | Eigen同时提供`norm()`方法,他返回 [squaredNorm()](http://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#ac8da566526419f9742a6c471bbd87e0a)的平方根。 43 | 44 | 这些操作同时可以在矩阵上进行操作,在这样的情况下,一个n*p的矩阵被认为是(n\*p)大小的向量,所以对于`norm()`方法,其返回“Frobenius" or "Hilbert-Schmidt" 范数。我们避免谈论矩阵的ℓ2范数,因为那可能意味着不同的事情。 45 | 46 | 如果你想其它按照系数的范数,可以使用[lpNorm

()](http://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#a72586ab059e889e7d2894ff227747e35)方法,参数p可以使用特殊值如果你想计算无穷范数,其返回矩阵元素的最大值。 47 | 48 | ```c++ 49 | #include 50 | #include 51 | 52 | int main() 53 | { 54 | Eigen::VectorXf v(2); 55 | Eigen::MatrixXf m(2,2), n(2,2); 56 | 57 | v << -1, 58 | 2; 59 | 60 | m << 1,-2, 61 | -3,4; 62 | 63 | std::cout << "v.squaredNorm() = " << v.squaredNorm() << std::endl; 64 | std::cout << "v.norm() = " << v.norm() << std::endl; 65 | std::cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << std::endl; 66 | std::cout << "v.lpNorm() = " << v.lpNorm() << std::endl; 67 | 68 | std::cout << std::endl; 69 | std::cout << "m.squaredNorm() = " << m.squaredNorm() << std::endl; 70 | std::cout << "m.norm() = " << m.norm() << std::endl; 71 | std::cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << std::endl; 72 | std::cout << "m.lpNorm() = " << m.lpNorm() << std::endl; 73 | } 74 | Output: 75 | v.squaredNorm() = 5 76 | v.norm() = 2.23607 77 | v.lpNorm<1>() = 3 78 | v.lpNorm() = 2 79 | 80 | m.squaredNorm() = 30 81 | m.norm() = 5.47723 82 | m.lpNorm<1>() = 10 83 | m.lpNorm() = 4 84 | ``` 85 | 86 | 算子范数:一范数和无穷范数可以很容易的计算,如下: 87 | 88 | ```c++ 89 | #include 90 | #include 91 | 92 | int main() 93 | { 94 | Eigen::MatrixXf m(2,2); 95 | m << 1,-2, 96 | -3,4; 97 | 98 | std::cout << "1-norm(m) = " << m.cwiseAbs().colwise().sum().maxCoeff() 99 | << " == " << m.colwise().lpNorm<1>().maxCoeff() << std::endl; 100 | 101 | std::cout << "infty-norm(m) = " << m.cwiseAbs().rowwise().sum().maxCoeff() 102 | << " == " << m.rowwise().lpNorm<1>().maxCoeff() << std::endl; 103 | } 104 | Output: 105 | 1-norm(m) = 6 == 6 106 | infty-norm(m) = 7 == 7 107 | ``` 108 | 109 | 关于这些表达式的语法具体解释如下。 110 | 111 | # 布尔约简 112 | 113 | 下列是关于布尔值的简约操作: 114 | 115 | - all() 当Matrix或者Array所有的系数都为true时,该函数返回true 116 | - any() 当Matrix或者Array至少有一个是true,函数返回true 117 | - count() 返回Matrix或者Array中true的个数 118 | 119 | 这些操作通常与Array提供的按系数比较和相等操作符一起使用。例如,array>0是一个与array大小相同的array,结果的对应位置为true,如果array对应部分是大于零的。因此,`(array>0).all()` 测试是否array所有的系数都是正的。可以参考下面的例子: 120 | 121 | ```c++ 122 | #include 123 | #include 124 | 125 | int main() 126 | { 127 | Eigen::ArrayXXf a(2,2); 128 | 129 | a << 1,2, 130 | 3,4; 131 | 132 | std::cout << "(a > 0).all() = " << (a > 0).all() << std::endl; 133 | std::cout << "(a > 0).any() = " << (a > 0).any() << std::endl; 134 | std::cout << "(a > 0).count() = " << (a > 0).count() << std::endl; 135 | std::cout << std::endl; 136 | std::cout << "(a > 2).all() = " << (a > 2).all() << std::endl; 137 | std::cout << "(a > 2).any() = " << (a > 2).any() << std::endl; 138 | std::cout << "(a > 2).count() = " << (a > 2).count() << std::endl; 139 | } 140 | 141 | Output: 142 | (a > 0).all() = 1 143 | (a > 0).any() = 1 144 | (a > 0).count() = 4 145 | 146 | (a > 2).all() = 0 147 | (a > 2).any() = 1 148 | (a > 2).count() = 2 149 | ``` 150 | 151 | # 用户定义的约简 152 | 153 | 待做: 154 | 155 | 在此期间你可以看一下`DenseBase::redux()` 相关的函数 156 | 157 | # 访客 158 | 159 | 在获取matrix或者array一个系数的位置时,访客是非常有用的。 最简单的例子是`maxCoeff(&x,&y)`和`minCoeff(&x,&y)`,这两个函数可以获取Matrix和Array最大或者最小系数的位置。 160 | 161 | 传递给访客的两个参数是将要储存行和列的指针,传入的参数应该是Index类型,如下: 162 | 163 | ```c++ 164 | #include 165 | #include 166 | 167 | int main() 168 | { 169 | Eigen::MatrixXf m(2,2); 170 | 171 | m << 1, 2, 172 | 3, 4; 173 | 174 | //get location of maximum 175 | Eigen::Index maxRow, maxCol; 176 | float max = m.maxCoeff(&maxRow, &maxCol); 177 | 178 | //get location of minimum 179 | Eigen::Index minRow, minCol; 180 | float min = m.minCoeff(&minRow, &minCol); 181 | 182 | std::cout << "Max: " << max << ", at: " << 183 | maxRow << "," << maxCol << std::endl; 184 | std:: cout << "Min: " << min << ", at: " << 185 | minRow << "," << minCol << std::endl; 186 | } 187 | 188 | Output: 189 | Max: 4, at: 1,1 190 | Min: 1, at: 0,0 191 | 192 | ``` 193 | 194 | # 部分约简 195 | 196 | 部分约简是可以按行或列操作的约简,对每一列或者行进行约简操作并返回一列或者一行。部分约简使用函数`colwise()`和`rowwise()` 。 197 | 198 | 一个简单的例子是获取每一行或者每一列的最大值,并把结果储存为行向量。 199 | 200 | ```c++ 201 | #include 202 | #include 203 | 204 | using namespace std; 205 | int main() 206 | { 207 | Eigen::MatrixXf mat(2,4); 208 | mat << 1, 2, 6, 9, 209 | 3, 1, 7, 2; 210 | 211 | std::cout << "Column's maximum: " << std::endl 212 | << mat.colwise().maxCoeff() << std::endl; 213 | } 214 | 215 | Output: 216 | Column's maximum: 217 | 3 2 7 9 218 | ``` 219 | 220 | 也可以按行进行操作: 221 | 222 | ```c++ 223 | #include 224 | #include 225 | 226 | using namespace std; 227 | int main() 228 | { 229 | Eigen::MatrixXf mat(2,4); 230 | mat << 1, 2, 6, 9, 231 | 3, 1, 7, 2; 232 | 233 | std::cout << "Row's maximum: " << std::endl 234 | << mat.rowwise().maxCoeff() << std::endl; 235 | } 236 | Output: 237 | Row's maximum: 238 | 9 239 | 7 240 | ``` 241 | 242 | 按列操作返回行向量,按行操作返回列向量。 243 | 244 | # 把部分约简和其他操作结合起来 245 | 246 | 我们可以使用部分约简操作的结果去做进一步的处理。这里是另一个例子,该例子展示了一个matrix中哪一列的元素和最大。可以编写如下部分约简代码: 247 | 248 | ```c++ 249 | #include 250 | #include 251 | 252 | int main() 253 | { 254 | Eigen::MatrixXf mat(2,4); 255 | mat << 1, 2, 6, 9, 256 | 3, 1, 7, 2; 257 | 258 | Eigen::Index maxIndex; 259 | float maxNorm = mat.colwise().sum().maxCoeff(&maxIndex); 260 | 261 | std::cout << "Maximum sum at position " << maxIndex << std::endl; 262 | 263 | std::cout << "The corresponding vector is: " << std::endl; 264 | std::cout << mat.col( maxIndex ) << std::endl; 265 | std::cout << "And its sum is is: " << maxNorm << std::endl; 266 | } 267 | Output: 268 | Maximum sum at position 2 269 | The corresponding vector is: 270 | 6 271 | 7 272 | And its sum is is: 13 273 | ``` 274 | 275 | 之前的例子通过`colwise()`访客在每一列上使用`sum()`约简,获取了一个大小为1*4的新矩阵。 276 | 277 | 因此,如果:m=[1 2 5 9;3 1 7 2],随后,`m.colwise().sum() = [4 3 13 11]` 278 | 279 | 函数`maxCoeff()`约简最后使用去获取最大和的列索引即为2。 280 | 281 | # 广播 282 | 283 | 广播背后的概念有点类似于部分约简,不同点在于广播构建了一个向量表达式,该表达式被解释为按照一个方向复制的矩阵。 284 | 285 | 一个简单的例子是把一个列向量相加在一个矩阵的每一列上。可以通过如下代码完成: 286 | 287 | ```c++ 288 | #include 289 | #include 290 | 291 | using namespace std; 292 | int main() 293 | { 294 | Eigen::MatrixXf mat(2,4); 295 | Eigen::VectorXf v(2); 296 | 297 | mat << 1, 2, 6, 9, 298 | 3, 1, 7, 2; 299 | 300 | v << 0, 301 | 1; 302 | 303 | //add v to each column of m 304 | mat.colwise() += v; 305 | 306 | std::cout << "Broadcasting result: " << std::endl; 307 | std::cout << mat << std::endl; 308 | } 309 | Output: 310 | Broadcasting result: 311 | 1 2 6 9 312 | 4 2 8 3 313 | ``` 314 | 315 | 我们可以按照两步来解释`mat.colwise()+=v`。它给矩阵的每一列都加上了向量v。或者,它可以解释为重复向量v四次去构成一个4*4的矩阵,然后再把两者进行相加: 316 | 317 | ![image-20220805190847053](Reductions, visitors and broadcasting.assets/image-20220805190847053.png) 318 | 319 | 运算符-=,+和-同样可以用在按行或者按列操作。在array,我们同样也可以使用\*=,/=,\*和/是用在按列或者按行的对应元素相乘和相除。这些操作在矩阵上也没有办法操作的,因为,当使用的时候会产生歧义。如果你想把矩阵的第0列和v(0)相乘,第一列与v(1)相乘,以此类推,你可以使用`mat = mat*v.asDiagonal()`。 320 | 321 | 重要的一点是想要按行或者按列相加在矩阵上的向量必须是vector类型,而不能是matrix类型。如果不满足会在编译的时候出现错误。array类型也是一样,其中VectorXf和ArrayXf是等价的。通常,你不应该把array和matric在一个表达式中混合使用。 322 | 323 | 按列做同样的操作: 324 | 325 | ```c++ 326 | #include 327 | #include 328 | 329 | using namespace std; 330 | int main() 331 | { 332 | Eigen::MatrixXf mat(2,4); 333 | Eigen::VectorXf v(4); 334 | 335 | mat << 1, 2, 6, 9, 336 | 3, 1, 7, 2; 337 | 338 | v << 0,1,2,3; 339 | 340 | //add v to each row of m 341 | mat.rowwise() += v.transpose(); 342 | 343 | std::cout << "Broadcasting result: " << std::endl; 344 | std::cout << mat << std::endl; 345 | } 346 | Output: 347 | Broadcasting result: 348 | 1 3 8 12 349 | 3 2 9 5 350 | 351 | ``` 352 | 353 | # 把广播和其他操作结合在一起 354 | 355 | 广播可以和其他操作结合在一起使用,例如matrix和array的运算、约简和部分约简。 356 | 357 | 广播、约简、部分约简已经介绍过了。我们可以进入到一个更复杂的例子,该例子在矩阵m的列向量中去寻找一个最近的邻居向量v。欧式距离将在这个例子中使用,使用部分约简操作`squaredNorm()`去计算欧式距离的平方。 358 | 359 | ```c++ 360 | #include 361 | #include 362 | 363 | int main() 364 | { 365 | Eigen::MatrixXf m(2,4); 366 | Eigen::VectorXf v(2); 367 | 368 | m << 1, 23, 6, 9, 369 | 3, 11, 7, 2; 370 | 371 | v << 2, 372 | 3; 373 | 374 | Eigen::Index index; 375 | // find nearest neighbour 376 | (m.colwise() - v).colwise().squaredNorm().minCoeff(&index); 377 | 378 | std::cout << "Nearest neighbour is column " << index << ":" << std::endl; 379 | std::cout << m.col(index) << std::endl; 380 | } 381 | 382 | Output: 383 | Nearest neighbour is column 0: 384 | 1 385 | 3 386 | ``` 387 | 388 | 真正起作用的是:`(m.colwise() - v).colwise().squaredNorm().minCoeff(&index);` 我们来一步一步的理解这行代码起的作用。 389 | 390 | - m.colwise() -v 是一个广播操作,m的每一列都减去v。得到一个与m同样大小的矩阵![image-20220805192843403](Reductions, visitors and broadcasting.assets/image-20220805192843403.png) 391 | - `(m.colwise() - v).colwise().squaredNorm() ` 是一个部分约简操作,按列计算2范数。这个操作的结果是一个行向量,行向量的每一个元素是矩阵m的每一行与v的平方欧式距离。`(m.colwise() - v).colwise().squaredNorm()=[1 505 32 50]` 392 | - 最后,`minCoeff(&index)`获取m中距离v最小欧式距离的列索引 393 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------