文章目录
- Eigen Quick Reference
-
- Eigen array, matrix and vector types
- Which should I choose: matrix or array
- Initialization
-
- Repeating
- Miss those elements out
- Slicing
- Indexing and accessing elements
- Maximum and minimum
- Assignment
- Concatenation
- Reshape and flatten matrices
- Coefficient-wise math functions
-
- Basic operatoins
- Exponential and logarithm
- Round off
- Power functions
- Trigonometric functions
- Eigen exercise
Eigen Quick Reference
一个 Eigen 的参考手册,包含 Python(Numpy) 与 Eigen 的对应用法,以及一些练习题。持续更新中。
Eigen array, matrix and vector types
在 Eigen 中,Matrix 用来表示数学意义上的矩阵和向量,Array 用来表示 1D 和 2D 的数组,你可以这样定义它们:
typedef Matrix MyMatrixType;
typedef Array MyArrayType;
- Scalar 表示系数的类型(例如float, double, boll, int 等等)。
- RowsAtCompileTime 和 ColsAtCompileTime 表示矩阵行数和列数(必须在编译时期给定),或者使用 Dynamic 表示其行数或者列数在运行时期给定。
- Options 可以是 ColMajor 或者 RowMajor,它们表示存储数据的顺序,默认是 ColMajor。( 这里 有存储顺序的更多介绍)
你可以随意的组合上面的参数来创建 Matrix,例如
Matrix // 动态列数(堆分配)
Matrix // 动态行数(堆分配)
Matrix // 动态大小,RowMajor(堆大小)
Matrix // 固定大小(通常是栈大小)
你还可以使用更加简易形式来表示一些常用的 Matrix 或者 Array,例如
Matrices |
Arrays |
Matrix <=> MatrixXf |
Array <=> ArrayXXf |
Matrix <=> VectorXd |
Array <=> ArrayXd |
Matrix <=> RowVectorXi |
Array <=> RowArrayXi |
Matrix <=> Matrix3f |
Array <=> Array33f |
Matrix <=> Vector4f |
Array <=> Array4f |
Which should I choose: matrix or array
如果你也有类似的困惑,很大几率是因为你比较熟悉 Python(NumPy) 或者 MATLAB。
在 MATLAB 中所有变量都是多维数组,矩阵是指通常用来进行线性代数运算的二维数组(它还是个数组),MATALB 具有两种运算:数组运算和矩阵运算。所以 MATLAB 并不区分数组类型或者矩阵类型,它只区分数组操作或者矩阵操作。
在 Python(NumPy)中,你可以用 np.matrix
创建矩阵,np.array
创建数组,但是官方推荐用 np.array
,原因是:
Use arrays.
- They are the standard vector/matrix/tensor type of numpy. Many numpy functions return arrays, not matrices.
- There is a clear distinction between element-wise operations and linear algebra operations.
- You can have standard vectors or row/column vectors if you like.
Until Python 3.5 the only disadvantage of using the array type was that you had to use dot instead of * to multiply (reduce) two tensors (scalar product, matrix vector multiplication etc.). Since Python 3.5 you can use the matrix multiplication @ operator.
Given the above, we intend to deprecate matrix eventually.
由于 NumPy 的便利性,我们通常用 np.array
也能够完成线性代数相关的任务,进一步导致 np.matrix
存在感很弱。
但在 Eigen 中 matrix 与 array 是有明确区别的,总的来说,Eigen 中的 matrix 与线性代数息息相关,它设计的初衷就是为了解决线性代数问题,例如解线性方程组、求矩阵特征值、矩阵的秩、QR分解等等。而 array 则负责系数运算,例如所有系数加上一个常数或者两个 array 系数相乘。
因此,如果你需要线性代数的操作时,请使用 matrix;如果你需要系数操作时,请使用 array。但有时候事情不会那么简单,你可能需要同时使用 matrix 和 array,这种情况下,你需要对 matrix 和 array 进行相互转换。
一个 matrix 通过 .array()
来得到一个 array 表达式;相似的,一个 array 通过 .matrix()
来得到一个 matrix 表达式。.array()
和 .matrix()
不会有任何运行时开销,它们是在编译期完成的。
Matrix 和 Array 之间可以相互转换:
Array44f a1, a1;
Matrix4f m1, m2;
m1 = a1 * a2; // 系数相乘,隐式地从 Array 转到 Matrix
a1 = m1 * m2; // 矩阵相乘,隐式地从 Matrix 转到 Array
a2 = a1 + m1.array(); // Array 和 Matrix 混合使用是不被允许的,需要显式地转换
m2 = a1.matrix() + m1;
ArrayWrapper m1a(m1); // m1a 是 m1 的别名,它们共享同样的数据
MatrixWrapper a1m(a1);// a1m 是 a1 的别名,它们共享同样的数据
Initialization
int rows = 5;
int cols = 3;
int size = 3;
// fixed-size array
{
Array33f a1 = Array33f::Zero(); // np.zeros((3,3))
Array33f a2 = Array33f::Random(); // np.random.rand(3,3)
Array33f a3 = Array33f::Ones(); // np.ones((3,3))
Array3f a4 = Array3f::LinSpaced(3, 0, 2); // np.linspace(0,2,3)
Array33f a5 = Array33f::Constant(1.0); // np.full((3,3), 1.0)
}
// one-dimensional dynamic-size
{
ArrayXf a1 = ArrayXf::Zero(cols); // np.zeros(cols)
ArrayXf a2 = ArrayXf::Random(cols); // np.random.rand(cols)
ArrayXf a3 = ArrayXf::Ones(cols); // np.ones(cols)
ArrayXf a4 = ArrayXf::LinSpaced(size, 0, 2); // np.linspace(0,2,size)
ArrayXf a5 = ArrayXf::Constant(cols, 1.0); // np.full(cols, 1.0)
}
// two-dimensional dynamic-size
{
ArrayXXf a1 = ArrayXXf::Zero(rows,cols); // np.zeros((rows, cols)))
ArrayXXf a2 = ArrayXXf::Random(rows,cols); // np.random.rand(rows, cols)
ArrayXXf a3 = ArrayXXf::Ones(rows, cols); // np.ones((rows, cols))
ArrayXXf a4 = ArrayXXf::Constant(rows, cols, 1.0); // np.full((rows, cols), 1.0)
MatrixXf m1 = MatrixXf::Identity(rows, cols); // np.eye(rows, cols)
MatrixXf m2 = Vector3f{1,2,3}.asDiagonal(); // np.diag((1,2,3))
}
Repeating
ArrayXXf a(2,2);
a << 1,2,
3,4;
a.replicate(2, 1); // np.tile(a, (2,1)), repeat array by row
a.replicate(1, 2); // np.tile(a, (1,2)), repeat array by column
a.replicate(2, 3); // np.tile(a, (2,3))
Miss those elements out
ArrayXf a = ArrayXf::Random(10);
// NumPy
a.head(2); // a[:2], the first two element
a.tail(a.size() - 1); // a[1:], miss the first element
a.segment(1, 2); // a[1:3], middle element
a.tail(1); // a[-1], last element
a.tail(2); // a[-2:], last two element
ArrayXXf A = ArrayXXf::Random(10,10);
A.leftCols(2); // a[:, :2], the first two columns
A.topRows(2); // a[:2, :], the first two rows
A.bottomRows(A.rows() - 1); // a[1:, :], miss the first row
A.rightCols(A.cols() - 1); // a[:, 1:], miss the first column
A.middleCols(1, 2); // a[:, 1:3], middle columns
A.middleRows(1, 2); // a[1:3, :], middle rows
A.rightCols(1); // a[:, -1], last column
A.bottomRows(1); // a[-1, :], last row
A.rightCols(2); // a[:, -2:], last two column
A.bottomRows(2); // a[-2:, :], last two row
Slicing
ArrayXf a = ArrayXf::LinSpaced(20, 0, 19);
Map> v1(a.data(), a.size()/2); // a[::2]
Map> v2(a.middleRows(1, 6).data(), 3);// a[1:7:2]
ArrayXXf A = ArrayXXf::Random(8,10);// Column-major storage
Map> A1(A.data(), A.rows(), (A.cols() + 1)/2, OuterStride<>(A.outerStride()*2)); // A[:,::2]
typedef Array RowMajorArrayXXf;
RowMajorArrayXXf A2(A);
Map> A3(A2.data(), (A2.rows() + 1)/2, A2.cols(), OuterStride<>(A2.outerStride()*2)); // A[::2, :]
Indexing and accessing elements
更多关于索引和元素访问的细节请参看 block operations
ArrayXXf a = ArrayXXf::Random(3,4);
// NumPy
a(1,2); // a[1,2], element 1,2
a.row(0); // a[0,], first row
a.col(0); // a[:,0], first column
a.middleRows(1, 2); // a[1:3,], middle row
a.middleRows(1, a.rows()-1); // a[1:,], all, except first row
a.bottomRows(a.rows()-1);
a.bottomRows(2); // a[-2:,], last tow rows
Maximum and minimum
ArrayXXf a = ArrayXXf::Random(3,3);
ArrayXXf b = ArrayXXf::Random(3,3);
a.maxCoeff(); // np.max(a), max in array
a.colwise().maxCoeff(); // np.amax(a, axis=0), max in each column
a.rowwise().maxCoeff(); // np.amax(a, axis=1), max in each row
a.max(b); // np.maximum(a,b), pairwise max
Assignment
ArrayXXf a = ArrayXXf::Random(3,3);
// NumPy
a.col(0) = 99; // a[:,0] = 99;
a.col(0) = Array3f{99,98,97}; // a[:,0] = np.array([99, 98, 97])
(a > 90).select(a, 90); // (a>90).choose(a, 90)
Concatenation
// Concatenation(vectors)
Array3f a{1,1,1};
Array3f b{2,2,2};
ArrayXf c( a.size() + b.size() );
c << a, b; // np.concatenate((a,b))
// Concatenation(matrix)
int rows = 3;
int cols = 3;
ArrayXXf A = ArrayXXf::Constant(rows, cols, 1.0f);
ArrayXXf B = ArrayXXf::Constant(rows, cols, 2.0f);
ArrayXXf BindRows(A.rows() + B.rows(), cols);
BindRows << A,B; // np.concatenate((A,B), axis=0)
// or np.vstack((a,b))
ArrayXXf BindCols(rows, A.cols() + B.cols());
BindCols << A,B; // np.concatenate((A,B), axis=1)
// or np.hstack((a,b))
ArrayXf C(A.size() + B.size()); // np.concatenate((a,b), axis=None)
C << Map(A.data(), A.size()), // concatenate matrices into a 1d array
Map(B.data(), B.size());
Reshape and flatten matrices
ArrayXXf a = ArrayXXf::Random(3,4); // Column-major storage
// NumPy
Map b(a.data(), 2, 6); // np.reshape(a, (2,6))
Map v(a.data(), a.size()); // a.flatten("F"), flatten in column-major
Coefficient-wise math functions
下面列举一些常用的 coefficient-wise 数学运算函数,更多详细的内容请参看 Catalog of coefficient-wise math functions
Basic operatoins
Python |
Eigen |
Description |
abs(a) |
a.abs(); Eigen::abs(a); m.cwiseAbs() |
absolute value ( ∣ a i ∣ \vert a_i\vert ∣ai∣) |
reciprocal(a) |
a.inverse(); Eigen::inverse(a); m.cwiseInverse() |
inverse vaule( 1 / a i 1/a_i 1/ai) |
a.conj() |
a.conjugate(); Eigen::conj(a); m.conjugate(); |
complex conjugate( a i ˉ \bar{a_i} aiˉ) |
Exponential and logarithm
Python |
Eigen |
Description |
math.log(a) |
a.log(); log(a) |
logarithm, base e e e(natural) |
math.log10(a) |
a.log10(); log10(a) |
logarithm, base 10 |
math.exp(a) |
a.exp(); exp(a) |
exponential function |
math.log1p(a) |
a.log1p(); log1p(a) |
natural (base e e e) logarithm of 1 plus the given number ( ln ( 1 + a i ) \ln({1+a_i}) ln(1+ai)) |
Round off
Python |
Eigen |
Description |
around(a) or math.round(a) |
a.round() |
Round |
ceil(a) |
a.ceil() |
Round up |
floor(a) |
a.floor() |
Round down |
Power functions
Python |
Eigen |
Description |
power(a,b) |
a.pow(b) |
power, a i b i a_i ^ {b_i} aibi |
math.sqrt(a) |
a.sqrt(); Eigen::sqrt(a); m.cwiseSqrt() |
square root ( ( a i ) \sqrt(a_i) ( ai)) |
square(a) |
a.square(); Eigen::square(a) |
square power( a i 2 a_i^2 ai2) |
power(a,3) |
a.cube(); Eigen::cube(a) |
cubic power( a i 3 a_i^3 ai3) |
abs(a).square() |
a.abs2(); Eigen::abs2(a);m.cwiseAbs2() |
squared absolute value( ∣ a i ∣ 2 \vert a_i \vert^2 ∣ai∣2) |
Trigonometric functions
Python |
Eigen |
Description |
sin(a) |
a.sin(); Eigen::sin(a) |
computes sine |
cos(a) |
a.cos(); Eigen::cos(a) |
computes cosine |
tan(a) |
a.tan(); Eigen::tan(a) |
computes tangent |
arcsin(a) |
a.asin(); Eigen::asin(a) |
computes arc sine( sin − 1 a i \sin^{-1} a_i sin−1ai) |
arccos(a) |
a.acos(); Eigen::acos(a) |
computes arc cosine( cos − 1 a i \cos^{-1} a_i cos−1ai) |
arctan(a) |
a.atan(); Eigen::atan(a) |
computes arc tangent( tan − 1 a i \tan^{-1} a_i tan−1ai) |
Eigen exercise
/*
* Eigen exercise
*
* This is quick reference of Eigen.
*
* We use Eigen to implement 100 Numpy(some of them) (https://github.com/rougier/numpy-100)
*
* It is highly recommended to read Eigen document before starting if you never read it
*
*/
#include
#include
#include
#include
#include
#include