Dense matrix and array manipulation
1.The Matrix class
Matrix类具有六个模板参数,但到目前为止,足以了解前三个第一个参数。剩下的三个参数具有默认值,现在我们将保持不变,下面将进行讨论。
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
1.1 vectors
在Eigen中,向量只是具有1行或1列的矩阵的一种特殊情况。 他们只有1列的情况最为常见; 这样的向量称为列向量,通常缩写为向量。 在另一行有1行的情况下,它们称为行向量
行,列表示:
typedef Matrix<float, 3, 1> Vector3f;
typedef Matrix<int, 1, 2> RowVector2i;
1.1.1 segment
获取从向量的第i个元素开始的n个元素:vector.segment(i,n)
1.2 The special value Dynamic
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
typedef Matrix<int, Dynamic, 1> VectorXi;
1.3 Constructors
1.3.1 默认
Matrix3f a;
MatrixXf b;
a是一个3×3矩阵,带有未初始化系数的普通float [9]数组,
b是一个动态大小的矩阵,其大小当前为0×0,并且其系数数组尚未分配。
1.3.2 固定大小构造
MatrixXf a(10,15);
VectorXf b(30);
为了在固定大小和动态大小的矩阵上提供统一的API,合法的是在固定大小的矩阵上使用这些构造函数,即使在这种情况下传递大小都没有用。所以这是合法的:
Matrix3f a(3,3);
1.3.3 构造函数来初始化
Vector2d a(5.0, 6.0);
Vector3d b(5.0, 6.0, 7.0);
Vector4d c(5.0, 6.0, 7.0, 8.0);
1.4 Coefficient accessors
- 本征中的主要系数访问器和变异器是重载的括号运算符。
- 对于矩阵,总是先传递行索引。
- 对于向量,只需传递一个索引。
- 编号从0开始。
-
请注意,语法m(index)不仅限于向量,它也可用于一般矩阵,这意味着在系数数组中基于索引的访问。 但是,这取决于矩阵的存储顺序。 所有本征矩阵默认为列主存储顺序,但是可以将其更改为行主存储顺序,请参阅存储顺序。
-
向量中基于索引的访问也要重载operator [],但是请记住,C ++不允许operator []接受多个参数。 我们将operator []限制为向量,因为C ++语言中的笨拙会导致matrix [i,j]编译为与matrix [j]相同的东西!
1.5 Comma-initialization
矩阵和矢量系数可以使用所谓的逗号初始化语法方便地设置。现在,只需要知道以下示例即可:
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
std::cout << m; //打印
1.6 Resizing
- 矩阵的当前大小可以通过rows(),cols()和size()检索。这些方法分别返回行数,列数和系数数。调整动态大小矩阵的大小是通过resize()方法完成的。
- 如果实际矩阵大小不变,则resize()方法为空操作。 否则具有破坏性:系数的值可能会更改。 如果您希望保守的resize()变体不改变系数,请使用relativeResize(),有关更多详细信息,请参见此页面。
- 为了实现API统一性,所有这些方法仍可用于固定大小的矩阵。 当然,您实际上不能调整固定大小的矩阵的大小。 尝试将固定大小更改为实际不同的值将触发断言失败。 但是以下代码是合法的:
Matrix4d m;
m.resize(4,4); // no operation
1.7 Assignment and resizing
赋值是使用operator =将矩阵复制到另一个矩阵中的动作。 Eigen自动调整左侧矩阵的大小,使其与右侧大小的矩阵大小匹配。例如:
MatrixXf a(2,2);
MatrixXf b(3,3);
a = b;
当然,如果左侧尺寸固定,则不允许调整尺寸。
如果您不希望这种自动调整大小(例如出于调试目的),可以将其禁用,请参阅此页面。
1.8 Fixed vs. Dynamic size
在可能的地方使用固定尺寸来显示非常小的尺寸,在需要的地方使用动态尺寸来显示较大的尺寸。 对于小尺寸,尤其是对于小于(大约)16的尺寸,使用固定尺寸对性能有极大的好处,因为它使Eigen避免了动态内存分配并展开了循环。 在内部,固定大小的本征矩阵只是一个简单的数组,即:
Matrix4f mymatrix;
//really amounts to just doing
float mymatrix[16];
因此这确实具有零运行时间成本。相比之下,动态大小矩阵的数组始终分配在堆上,因此
MatrixXf mymatrix(rows,columns);
//amounts to doing
float *mymatrix = new float[rows*columns];
除此之外,MatrixXf对象还将其行数和列数存储为成员变量。
当然,使用固定大小的限制是,只有当您在编译时知道大小时,才有可能这样做。 同样,对于足够大的尺寸(例如,对于大于(大约)32的尺寸),使用固定尺寸的性能优势变得可以忽略不计。 更糟糕的是,尝试使用函数内部的固定大小创建非常大的矩阵可能会导致堆栈溢出,因为Eigen会尝试将数组自动分配为局部变量,而这通常是在堆栈上完成的。 最后,视情况而定,当使用动态尺寸时,Eigen还可以尝试进行矢量化(使用SIMD指令),请参见“矢量化”。
1.9 Optional template parameters
我们在页面开始时提到Matrix类采用六个模板参数,但到目前为止,我们仅讨论了前三个。其余三个参数是可选的。这是模板参数的完整列表:
Matrix<typename Scalar,
int RowsAtCompileTime,
int ColsAtCompileTime,
int Options = 0,
int MaxRowsAtCompileTime = RowsAtCompileTime,
int MaxColsAtCompileTime = ColsAtCompileTime>
- 选项是一个位字段。 在这里,我们只讨论一点:RowMajor。 它指定这种类型的矩阵使用行优先存储顺序。 默认情况下,存储顺序为“大列”。 请参阅有关存储订单的页面。 例如,此类型表示行优先的3x3矩阵:
Matrix<float, 3, 3, RowMajor>
- 当您希望指定MaxRowsAtCompileTime和MaxColsAtCompileTime时,即使在编译时不知道矩阵的确切大小,在编译时也知道固定的上限,该功能非常有用。 您可能要这样做的最大原因是避免动态内存分配。 例如,以下矩阵类型使用12个浮点数的普通数组,而不分配动态内存:
Matrix<float, Dynamic, Dynamic, 0, 3, 4>
1.10 Convenience typedefs
- MatrixNt for Matrix<type, N, N>. For example, MatrixXi for Matrix<int, Dynamic, Dynamic>.
- VectorNt for Matrix<type, N, 1>. For example, Vector2f for Matrix<float, 2, 1>.
- RowVectorNt for Matrix<type, 1, N>. For example, RowVector3d for Matrix<double, 1, 3>.
2. Matrix and vector arithmetic
该页面旨在概述和详细介绍如何使用Eigen在矩阵,向量和标量之间执行算术运算。
2.1 Addition and subtraction
左侧和右侧必须具有相同数量的行和列。它们也必须具有相同的Scalar类型,因为Eigen不会自动进行类型升级。这里的操作员是:
- binary operator + as in a+b
- binary operator - as in a-b
- unary operator - as in -a
- compound operator += as in a+=b
- compound operator -= as in a-=b
2.2 Scalar multiplication and division
标量的乘法和除法也非常简单。这里的操作员是:
- binary operator * as in matrix*scalar
- binary operator * as in scalar*matrix
- binary operator / as in matrix/scalar
- compound operator = as in matrix=scalar
- compound operator /= as in matrix/=scalar
2.3 A note about expression templates
在Eigen中,算术运算符(例如operator +)本身不会执行任何计算,它们仅返回描述要执行的计算的“表达式对象”。 当计算整个表达式时,实际的计算将在稍后进行,通常是在operator =中。
VectorXf a(50), b(50), c(50), d(50);
...
a = 3*b + 4*c + 5*d;
Eigen将其编译为一个for循环,因此数组仅被遍历一次。简化(例如忽略SIMD优化),此循环如下所示:
for(int i = 0; i < 50; ++i)
a[i] = 3*b[i] + 4*c[i] + 5*d[i];
因此,您不必担心Eigen会使用相对较大的算术表达式:它只会为Eigen提供更多优化机会。
2.3 Transposition and conjugation
转置和共轭
矩阵或向量的转置,共轭和伴随(即共轭转置)分别通过成员函数transpose(),conjugate()和adjoint()获得。
MatrixXcf a = MatrixXcf::Random(2,2);
cout << "Here is the matrix a\n" << a << endl;
cout << "Here is the matrix a^T\n" << a.transpose() << endl;
cout << "Here is the conjugate of a\n" << a.conjugate() << endl;
cout << "Here is the matrix a^*\n" << a.adjoint() << endl;
对于实数矩阵,conjugate()是无操作的,因此adjoint()等效于transpose()。
A
=
[
3
+
i
5
2
−
2
i
i
]
,
A
ˉ
=
[
3
−
i
5
2
+
2
i
−
i
]
{A= \left [ { \begin{matrix} 3+i& 5\\ 2-2i& i \end{matrix} } \right ], \bar A= \left [ { \begin{matrix} 3-i& 5\\ 2+2i& -i \end{matrix} } \right ]}
A=[3+i2−2i5i],Aˉ=[3−i2+2i5−i]
2.4 Matrix-matrix and matrix-vector multiplication
矩阵矩阵乘法再次使用运算符*完成。 由于向量是矩阵的一种特殊情况,因此它们也在其中隐式处理,因此矩阵向量乘积实际上只是矩阵-矩阵乘积的一种特殊情况,向量-向量外积也是如此。 因此,所有这些情况仅由两个运算符处理:
- binary operator * as in a*b
- compound operator = as in a=b (this multiplies on the right: a*=b is equivalent to a = a*b)
注意:如果您在表达式模板上阅读了以上段落,并担心执行m = m * m可能会引起混叠问题,请立即放心:Eigen将矩阵乘法视为一种特殊情况,并在此处考虑引入一个临时变量,因此 将m = m * m编译为:
tmp = m*m;
m = tmp;
如果您知道您的矩阵产品可以安全地评估到目标矩阵中而不会出现混叠问题,则可以使用noalias()函数来避免出现临时情况,例如:
c.noalias() += a * b;
有关此主题的更多详细信息,请参见别名页面。
2.5 Dot product and cross product
对于点积和叉积,您需要dot()和cross()方法。当然,点积也可以作为u.adjoint()* v的1x1矩阵获得。
Vector3d v(1,2,3);
Vector3d w(0,1,2);
double dp = v.adjoint()*w;
// automatic conversion of the inner product to a scalar
请记住,叉积仅适用于大小为3的向量。点积适用于任何大小的向量。当使用复数时,本征点积在第一个变量中是共轭线性的,而在第二个变量中是线性的。
2.6 Basic arithmetic reduction operations
Eigen还提供了一些归约运算,以将给定的矩阵或向量归约为单个值,例如总和(由sum()计算),乘积(prod())或最大值(maxCoeff())和最小值(minCoeff() )的所有系数。
函数trace()返回的矩阵轨迹是对角系数的总和,并且也可以使用a.diagonal()
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl; //10
cout << "Here is mat.prod(): " << mat.prod() << endl; //24
cout << "Here is mat.mean(): " << mat.mean() << endl; //2.5
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl; //1
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl; //4
cout << "Here is mat.trace(): " << mat.trace() << endl; //5
2.7 Validity of operations
本征检查您执行的操作的有效性。 如果可能,它将在编译时检查它们,从而产生编译错误。 这些错误消息可能很长很丑,但是Eigen将重要消息写在UPPERCASE_LETTERS_SO_IT_STANDS_OUT中。 例如:
Matrix3f m;
Vector4f v;
v = m*v; // Compile-time error: YOU_MIXED_MATRICES_OF_DIFFERENT_SIZES
当然,在许多情况下,例如在检查动态大小时,无法在编译时执行检查。 然后,本征使用运行时断言。 这意味着,如果程序在“调试模式”下运行,则在执行非法操作时该程序将中止并显示一条错误消息,并且如果断言被关闭,它可能会崩溃。
MatrixXf m(3,3);
VectorXf v(4);
v = m * v; // Run-time assertion failure here: "invalid matrix product"
3.The Array class and coefficient-wise operations
与用于线性代数的Matrix类相反,Array类提供了通用数组。 此外,Array类提供了一种执行逐系数运算的简便方法,该运算可能没有线性代数含义,例如将常数添加到数组中的每个系数或按系数乘两个数组。
3.1 Array types
Array是具有与Matrix相同的模板参数的类模板。与Matrix一样,前三个模板参数是必需的:
Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
- 最后三个模板参数是可选的。由于这与Matrix完全相同,因此我们在这里不再赘述,而仅引用Matrix类.
Eigen还为某些常见情况提供了typedef,其方式类似于Matrix typedef,但有一些细微的差异,因为单词“ array”既用于一维数组又用于二维数组。 我们采用以下约定:ArrayNt形式的typedef代表一维数组,其中N和t是大小和标量类型,如本页上解释的Matrix typedef所示。 对于二维数组,我们使用ArrayNNt形式的typedef。 下表显示了一些示例:
- Array<float,Dynamic,1> ArrayXf
- Array<float,3,1> Array3f
- Array<double,Dynamic,Dynamic> ArrayXXd
- Array<double,3,3> Array33d
3.2 Accessing values inside an Array
括号运算符被重载以提供对数组系数的写和读访问,就像矩阵一样。此外,<<操作符可用于初始化数组(通过逗号初始化程序)或打印它们
有关逗号初始化程序的更多信息,请参见高级初始化。
3.3 Addition and subtraction
两个数组的加减法与矩阵相同。如果两个数组的大小相同,并且该加法或减法是按系数进行的,则此操作有效。
数组还支持数组+标量形式的表达式,该表达式将标量添加到数组中的每个系数。 这提供了不能直接用于Matrix对象的功能。
3.4 Array multiplication
首先,当然,您可以将一个数组乘以标量,这与矩阵的工作方式相同。数组与矩阵根本不同的地方是将两个矩阵相乘。 矩阵将乘法解释为矩阵乘积,而数组将乘法解释为按系数乘积。因此,当且仅当两个数组具有相同的维数时,它们才能相乘。
3.5 Other coefficient-wise operations
除了上述加法,减法和乘法运算符外,Array类还定义了其他按系数的运算。
- .abs(方法获取每个系数的绝对值,
- .sqrt()计算系数的平方根。
- 如果您有两个大小相同的数组,则可以调用.min(),来构造其系数是两个给定数组中对应系数的最小值的数组。
3.6 Converting between array and matrix expressions
-
什么时候应该使用Matrix类的对象,什么时候应该使用Array类的对象?您不能对数组应用矩阵运算,也不能对矩阵应用数组运算。
-
因此,如果您需要进行线性代数运算(例如矩阵乘法),则应使用矩阵。**如果需要进行系数运算,则应使用数组。**但是,有时并不是那么简单,但是您需要同时使用Matrix和Array操作。在这种情况下,您需要将矩阵转换为数组或反向转换。无论选择将对象声明为数组还是矩阵,都可以访问所有操作。
-
矩阵表达式具有.array()方法,可以将它们“转换”为数组表达式,因此可以轻松地应用按系数进行运算。相反**,数组表达式具有.matrix()方法**。与所有Eigen表达式抽象一样,这没有任何运行时开销(只要您让编译器进行优化)。 .array()和.matrix()都可以用作右值和左值。
-
Eigen禁止在表达式中混合矩阵和数组。例如,您不能直接添加矩阵和数组。 +运算符的操作数要么都是矩阵,要么都是数组。但是,使用.array()和.matrix()可以轻松地将其转换为另一种。此规则的例外是赋值运算符:允许将矩阵表达式分配给数组变量,或将数组表达式分配给矩阵变量。
下面的示例演示如何通过使用.array()方法对Matrix对象使用数组操作。例如,语句result = m.array()* n.array()接受两个矩阵m和n,将它们都转换为数组,使用将它们按系数相乘并将结果分配给矩阵变量result(是合法的,因为Eigen允许将数组表达式分配给矩阵变量。
#include <Eigen/Dense>
#include <iostream>
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;
result = m.array() * n.array();
cout << "-- Array m*n: --" << endl << result << endl << endl;
result = m.cwiseProduct(n);
cout << "-- With cwiseProduct: --" << endl << result << endl << endl;
result = m.array() + 4;
cout << "-- Array m + 4: --" << endl << result << endl << endl;
}
同样,如果array1和array2是数组,则表达式array1.matrix()* array2.matrix()计算其矩阵乘积。
4. Block operations
本页说明了块操作的要点。 块是矩阵或阵列的矩形部分。 块表达式既可以用作右值,也可以用作左值。 与本征表达式一样,只要让编译器进行优化,此抽象的运行时成本为零。
4.1 Using block operations
- 本征中最通用的块操作称为.block()。有两个版本,其语法如下:
Block operation | Version constructing a dynamic-size block expressio | Version constructing a fixed-size block expression |
---|---|---|
Block of size (p,q), starting at (i,j) | matrix.block(i,j,p,q); | matrix.block<p,q>(i,j); |
- 与Eigen一样,索引从0开始。
- .block()函数用作右值,即仅从中读取。但是,块也可以用作左值,这意味着您可以分配给块。
- 尽管.block()方法可用于任何块操作,但对于特殊情况,还有其他方法可提供更专业的API和/或更好的性能。 关于性能,最重要的是在编译时为Eigen提供尽可能多的信息。 例如,如果您的块是矩阵中的单个整列,则使用下面描述的专用.col()函数让Eigen知道这一点,这可以为其提供优化机会。
4.2 Columns and rows
单独的列和行是块的特殊情况。 Eigen提供了可轻松解决它们的方法:.col()和.row()。
Block operator | Method |
---|---|
i t h {i^{th}} ith row* | matrix.row(i); |
.rowwise() | 逐行 |
j t h {j^{th}} jth column* | matrix.column(j); |
col()和row()的参数是要访问的列或行的索引。与Eigen一样,索引从0开始。
4.3 Corner-related operations
- Eigen还为针对矩阵或数组的角或侧面之一齐平的块提供了特殊的方法。例如,.topLeftCorner()可用于引用矩阵左上角的块。
下表总结了各种可能性:
Block operation | Version constructing a dynamic-size block expression | Version constructing afixed-size block expression |
---|---|---|
Top-left p by q block * | matrix.topLeftCorner(p,q); | matrix.topLeftCorner<p,q>(); |
Bottom-left p by q block * | matrix.bottomLeftCorner(p,q); | matrix.bottomLeftCorner<p,q>(); |
Top-right p by q block * | matrix.topRightCorner(p,q); | matrix.topRightCorner<p,q>(); |
Bottom-right p by q block * | matrix.bottomRightCorner(p,q); | matrix.bottomRightCorner<p,q>(); |
Block containing the first q rows * | matrix.topRows(q); | matrix.topRows(); |
Block containing the last q rows * | matrix.bottomRows(q); | matrix.bottomRows(); |
Block containing the first p columns * | matrix.leftCols§; | matrix.leftCols (); |
Block containing the last q columns * | matrix.rightCols(q); | matrix.rightCols(); |
4.4 Block operations for vectors
Eigen还提供了一组专门针对矢量和一维数组的特殊情况设计的块操作:
Block operation | Version constructing a dynamic-size block expression | Version constructing a fixed-size block expression |
---|---|---|
Block containing the first n elements * | vector.head(n); | vector.head(); |
Block containing the last n elements * | vector.tail(n); | vector.tail(); |
Block containing n elements, starting at position i * | vector.segment(i,n); | vector.segment(i); |
5. Advanced initialization
本页讨论了几种初始化矩阵的高级方法。它提供了有关之前介绍的逗号初始化程序的更多详细信息。它还说明了如何获得特殊矩阵,例如单位矩阵和零矩阵。
5.1 The comma initializer
- Eigen提供了一种逗号初始化器语法,该语法使用户可以轻松设置矩阵,向量或数组的所有系数。 只需列出系数,从左上角开始,从左到右,从上到下移动。 需要预先指定对象的大小。 如果列出的系数太少或太多,Eigen 就会抱怨。
Matrix3f m;
m << 1, 2, 3,
4, 5, 6,
7, 8, 9;
- 此外,初始化列表的元素本身可以是向量或矩阵。 通常的用途是将向量或矩阵连接在一起。 例如,这是将两个行向量连接在一起的方法。 请记住,必须先设置大小,然后才能使用逗号初始化程序。
RowVectorXd vec1(3);
vec1 << 1, 2, 3;
RowVectorXd vec2(4);
vec2 << 1, 4, 9, 16;
RowVectorXd joined(7);
joined << vec1, vec2;
- 我们可以使用相同的技术来初始化具有块结构的矩阵。
MatrixXf matA(2, 2);
matA << 1, 2, 3, 4;
MatrixXf matB(4, 4);
matB << matA, matA/10, matA/10, matA;
逗号初始值设定项还可以用于填充块表达式,例如m.row(i)。与上面的第一个示例相比,这是一种更复杂的方法来获得相同的结果:
Matrix3f m;
m.row(0) << 1, 2, 3;
m.block(1,0,2,2) << 4, 5, 7, 8;
m.col(2).tail(2) << 6, 9;
std::cout << m;
5.2 Special matrices and arrays
- Matrix和Array类具有Zero()之类的静态方法,可用于将所有系数初始化为零。 有三种变体。 第一个变体不带参数,只能用于固定大小的对象。 如果要将动态尺寸对象初始化为零,则需要指定尺寸。 因此,第二个变体需要一个参数,并且可以用于一维动态大小的对象,而第三个变体需要两个参数,并且可以用于二维对象。 以下示例说明了这三种变体:
std::cout << "A fixed-size array:\n";
Array33f a1 = Array33f::Zero();
std::cout << a1 << "\n\n";
std::cout << "A one-dimensional dynamic-size array:\n";
ArrayXf a2 = ArrayXf::Zero(3);
std::cout << a2 << "\n\n";
std::cout << "A two-dimensional dynamic-size array:\n";
ArrayXXf a3 = ArrayXXf::Zero(3, 4);
- 同样,静态方法Constant(value)将所有系数设置为value。 如果需要指定对象的大小,则其他参数放在value参数之前,如MatrixXd :: Constant(rows,cols,value) 一样。 方法Random()用随机系数填充矩阵或数组。 可以通过调用Identity()获得单位矩阵; 此方法仅适用于Matrix,不适用于Array,因为“恒等矩阵”是线性代数概念。LinSpaced(size,low,high) 方法仅适用于向量和一维数组; 它产生指定大小的向量,其系数在高低之间均等间隔。 下面的示例说明了方法LinSpaced(),该方法打印一张表格,其中包含以度为单位的角度,以弧度为单位的相应角度以及它们的正弦和余弦值。
- 可以将诸如LinSpaced()返回的对象的对象分配给变量(和表达式)。 Eigen定义了诸如setZero(),MatrixBase :: setIdentity()和DenseBase :: setLinSpaced() 之类的实用程序函数来方便地执行此操作。
- 快速参考指南中提供了所有预定义的矩阵,向量和数组对象的摘要。
5.3 Usage as temporary objects
可以在声明时或在赋值运算符的右侧使用静态方法Zero()和Constant()来初始化变量。 您可以将这些方法视为返回矩阵或数组。 实际上,它们返回所谓的表达式对象,这些表达式对象在需要时求值到矩阵或数组,因此该语法不会产生任何开销。
6. Reductions, visitors and broadcasting
本页说明了Eigen的归约,访问者和广播,以及它们如何与矩阵和数组一起使用。
6.1 Reductions
在Eigen中,Reduction 一个采用矩阵或数组并返回单个标量值的函数。最常用的归约方法之一是.sum(),它返回给定矩阵或数组内所有系数的总和。
#include <iostream>
#include <Eigen/Dense>
using namespace std;
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2,
3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl; 10
cout << "Here is mat.prod(): " << mat.prod() << endl; 24
cout << "Here is mat.mean(): " << mat.mean() << endl; 2.5
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl; 1
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl; 4
cout << "Here is mat.trace(): " << mat.trace() << endl; 5
}
由函数trace()返回的矩阵的轨迹是对角线系数的总和,可以等效地计算a.diagonal()。sum()。
6.1.1 Norm computations
- 向量的(Euclidean a.k.a.)平方范数可以通过squaredNorm()获得。它本身等于矢量的点积,并且等效于其系数的平方绝对值的总和
- Eigen还提供了norm()方法,该方法返回squaredNorm()的平方根。
- 如果需要其他按系数的 l p {l^ p } lp范数,请使用 lpNorm<p>() 方法。 如果想要 l ∞ l ^ \infty l∞范数,则lpNorm<Infinity>(),这是系数绝对值的最大值。
VectorXf v(2);
MatrixXf m(2,2), n(2,2);
v << -1,
2;
m << 1,-2,
-3,4;
cout << "v.squaredNorm() = " << v.squaredNorm() << endl; 5
cout << "v.norm() = " << v.norm() << endl; 2.23
cout << "v.lpNorm<1>() = " << v.lpNorm<1>() << endl; 3
cout << "v.lpNorm<Infinity>() = " << v.lpNorm<Infinity>() << endl; 2
cout << endl;
cout << "m.squaredNorm() = " << m.squaredNorm() << endl; 30
cout << "m.norm() = " << m.norm() << endl; 5.477
cout << "m.lpNorm<1>() = " << m.lpNorm<1>() << endl; 10
cout << "m.lpNorm<Infinity>() = " << m.lpNorm<Infinity>() << endl 4
6.1.2 Boolean reductions
- all() returns true if all of the coefficients in a given Matrix or Array evaluate to true .
- any() returns true if at least one of the coefficients in a given Matrix or Array evaluates to true
- count() returns the number of coefficients in a given Matrix or Array that evaluate to true.
ArrayXXf a(2,2);
a << 1,2, 3,4;
cout << "(a > 0).all() = " << (a > 0).all() << endl; //1
cout << "(a > 0).any() = " << (a > 0).any() << endl; //1
cout << "(a > 0).count() = " << (a > 0).count() << endl; //4
cout << endl;
cout << "(a > 2).all() = " << (a > 2).all() << endl; //0
cout << "(a > 2).any() = " << (a > 2).any() << endl; //1
cout << "(a > 2).count() = " << (a > 2).count() << endl; //2
6.2 Visitors
- 当人们想要获取矩阵或数组内系数的位置时,访问者很有用。 最简单的示例是maxCoeff(&x,&y)和minCoeff(&x,&y),可用于查找矩阵或数组中最大或最小系数的位置。
- 传递给访问者的参数是指向要存储行和列位置的变量的指针。这些变量应为Index类型,如下所示:
Eigen::MatrixXf m(2,2);
m << 1, 2,
3, 4;
//get location of maximum
MatrixXf::Index maxRow, maxCol;
float max = m.maxCoeff(&maxRow, &maxCol); //4 1,1
//get location of minimum
MatrixXf::Index minRow, minCol;
float min = m.minCoeff(&minRow, &minCol); //1 0,0
cout << "Max: " << max << ", at: " <<
maxRow << "," << maxCol << endl;
cout << "Min: " << min << ", at: " <<
minRow << "," << minCol << endl;
两个函数还返回最小或最大系数的值。
6.3 Partial reductions
- 部分 reductions 是可以对矩阵或数组按列或按行进行操作的归约,对每个列或行应用归约运算并返回具有相应值的列或行向量。 部分缩减适用于colwise()或rowwise()。
一个简单的示例是获取给定矩阵中每一列中元素的最大值,并将结果存储在行向量中:
Eigen::MatrixXf mat(2,4);
mat << 1, 2, 6, 9,
3, 1, 7, 2;
// 3 2 7 9
std::cout << "Column's maximum: " << std::endl
<< mat.colwise().maxCoeff() << std::endl;
// 9 7
std::cout << "Row's maximum: " << std::endl
<< mat.rowwise().maxCoeff() << std::endl;
请注意,按列操作返回行向量,而按行操作返回列向量。
6.4 Broadcasting
- 广播背后的概念类似于部分归约,区别在于广播构造了一个表达式,其中向量(列或行)通过在一个方向上复制而被解释为矩阵。
一个简单的示例是将某个列向量添加到矩阵中的每一列。这可以通过以下方式完成:
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;
// 1 2 6 9
// 4 2 8 3
std::cout << "Broadcasting result: " << std::endl;
std::cout << mat << std::endl;
7.Interfacing with raw buffers: the Map class
- 本页说明了如何使用“原始” C / C ++数组。这在各种情况下都可能有用,特别是在将其他库中的向量和矩阵“导入” Eigen 时。
- 有时您可能要在Eigen中使用预定义的数字数组作为矢量或矩阵。 一种选择是复制数据,但最常见的情况是您可能希望将此内存作为Eigen类型重复使用。 幸运的是,使用Map类非常容易。
7.1 Map types and declaring Map variables
Map<Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> >
- 请注意,在这种默认情况下,地图仅需要一个模板参数。
- 要构造Map变量,您还需要其他两条信息:指向定义系数数组的内存区域的指针,以及所需的矩阵或矢量形状。
例如,要定义一个在编译时确定大小的float矩阵,可以执行以下操作:
Map<MatrixXf> mf(pf,rows,columns);
其中pf是一个 float *,指向内存数组。固定大小的整数只读向量可能会声明为
Map<const Vector4i> mi(pi);
pi是int *。在这种情况下,不必将大小传递给构造函数,因为它已经由Matrix / Array类型指定。
请注意,Map没有默认的构造函数。您必须传递一个指针来初始化对象。但是,您可以解决此要求(请参阅更改映射数组)。
int data[] = {1,2,3,4,5,6,7,8,9};
Map<RowVectorXi> v(data,4);
cout << "The mapped vector v is: " << v << "\n";
new (&v) Map<RowVectorXi>(data+4,5);
cout << "Now v is: " << v << "\n";
//out
The mapped vector v is: 1 2 3 4
Now v is: 5 6 7 8 9
7.2 Reshape and Slicing
- Eigen还没有提供方便的方法来切片或重塑矩阵。但是,可以使用Map类轻松模拟这些功能。
7.2.1 Reshape
整形操作在于修改矩阵的大小,同时保持相同的系数。 除了修改输入矩阵本身(这对于编译时大小而言是不可能的)之外,该方法还包括使用类Map在存储上创建不同的视图。 这是创建矩阵的一维线性视图的典型示例:
MatrixXf M1(3,3); // Column-major storage
M1 << 1, 2, 3,
4, 5, 6,
7, 8, 9;
Map<RowVectorXf> v1(M1.data(), M1.size());
cout << "v1:" << endl << v1 << endl;
Matrix<float,Dynamic,Dynamic,RowMajor> M2(M1);
Map<RowVectorXf> v2(M2.data(), M2.size());
cout << "v2:" << endl << v2 << endl;
//output
v1:
1 4 7 2 5 8 3 6 9
v2:
1 2 3 4 5 6 7 8 9
MatrixXf M1(2,6); // Column-major storage
M1 << 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12;
Map<MatrixXf> M2(M1.data(), 6,2);
cout << "M2:" << endl << M2 << endl;
//output :
M2:
1 4
7 10
2 5
8 11
3 6
9 12
7.2.2 Slicing
切片包括获取一组在矩阵内均匀间隔的行,列或元素。再次,Map类可以轻松模仿此功能。
例如,可以跳过向量中的每个P元素:
RowVectorXf v = RowVectorXf::LinSpaced(20,0,19);
cout << "Input:" << endl << v << endl;
Map<RowVectorXf,0,InnerStride<2> > v2(v.data(), v.size()/2);
cout << "Even:" << v2 << endl;
//output
Input:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Even: 0 2 4 6 8 10 12 14 16 18