c++ 的 eigen 类似于 python 的 numpy, 还有一个类似的库是 Armadillo, 当然还有 opencv.
Armadillo 与 matlab 在函数名称上更接近, 但是 TensorFlow 和 Ceres 使用了 eigen.
这里不讲究谁优谁劣, 入门阶段迅速掌握一个, 用起来就够了.
1. The Matrix Class
1) The first three template parameters of Matrix
Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime> typedef Matrix<float, 4, 4> Matrix4f;
2) Vectors
In Eigen, vectors are just a special case of matrices.
typedef Matrix<float, 3, 1> Vector3f; typedef Matrix<int, 1, 2> RowVector2i;
3) The special value dynamic
Matrices dimensions can be unknown at compile time in Eigen.
typedef Matrix<double, Dynamic, Dynamic> MatrixXd; typedef Matrix<int, Dynamic, 1> VectorXi; Matrix<float, 3, Dynamic>;
4) Constructors
Matrix3f a; MatrixXf b; MatrixXf a(10, 15); MatrixXf b(30); Matrix3f a(3, 3); Vector2d a(5.0, 6.0); Vector3d b(5.0, 6.0, 7.0);
Matrix3f 声明的矩阵, 大小是固定的, 不能修改. 4维之下的矩阵可以使用形如 Matrix4f 的形式, 稍微增加编译时间, 但是执行更快.
5) Coefficient accessors
int main() { MatrixXd m(2,2); m(0,0) = 3; m(1,0) = 2.5; m(0,1) = -1; m(1,1) = m(1,0) + m(0,1); std::cout << "Here is the matrix m: " << m << std::endl; VectorXd v(2); v(0) = 4; v(1) = v(0) - 1; std::cout << "Here is the vector v: " << v << std::endl; }
m(index) 除了可以访问 vector, 还可以访问 matrix, matrix 在 Eigen 中默认按列存储. 在上例中, m(2) == -1.
[] 也被重载了, 类似 () 的功能, 但是只能有一个 index, 因为 c++ 的特性, matrix[i, j] == matrix[j].
推测, 访问单独或批量的列或行, 应该有专有的函数, 用 () 和 [] 只能访问单个值.
6) Comma-initialization
Matrix3f m; m << 1, 2, 3, 4, 5, 6, 7, 8, 9; cout << m;
7) Resizing
int main() { MatrixXd m(2,5); m.resize(4,3); std::cout << "The matrix m is of size " << m.rows() << "x" << m.cols() << std::endl; std::cout << "It has " << m.size() << " coefficients" << std::endl; VectorXd v(2); v.resize(5); std::cout << "The vector v is of size " << v.size() << std::endl; std::cout << "As a matrix, v is of size " << v.rows() << "x" << v.cols() << std::endl; }
resize() 会覆盖之前矩阵的值, 如果要保留原有未知的值, 可以使用 conservativeResize().
再次强调, 形如 Matrix4d 声明的矩阵大小不可更改.
8) Assignment and resizing
MatrixXf a(2,2); std::cout << "a is of size " << a.rows() << "x" << a.cols() << std::endl; MatrixXf b(3,3); a = b; std::cout << "a is now of size " << a.rows() << "x" << a.cols() << std::endl;
如果等号左侧是 fixed size, 则 resizing 不被允许.
9) Convenience typedefs
MatrixNt for Matrix<type, N, N>
VectorNt for Matrix<type, N, 1>
RowVectorNt for Matrix<type, 1, N>
N can be 2, 3,... or X (Dynamic)
t can be i (int), f (float), d (double), cf (complex<float>), cd (complex<double>)
2. Matrix and vector arithmetic
1) Introduction
Eigen 重载了 matrix 之间的运算符号, 但是 matrix 和 scalar 之间的运算符号未重载.
2) Addition and subtraction
Eigen 不会对 scalar 进行自动类型转换.
a + b, a - b, -a, a += b, a -= b
int main() { Matrix2d a; a << 1, 2, 3, 4; MatrixXd b(2,2); b << 2, 3, 1, 4; std::cout << "a + b = " << a + b << std::endl; std::cout << "a - b = " << a - b << std::endl; std::cout << "Doing a += b;" << std::endl; a += b; std::cout << "Now a = " << a << std::endl; Vector3d v(1,2,3); Vector3d w(1,0,0); std::cout << "-v + w - v = " << -v + w - v << std::endl; }
3) Scalar multiplication and division
matrix * scalar, scalar * matrix, matrix / scalar, matrix *= scalar, matrix /= scalar
int main() { Matrix2d a; a << 1, 2, 3, 4; Vector3d v(1,2,3); std::cout << "a * 2.5 = " << a * 2.5 << std::endl; std::cout << "0.1 * v = " << 0.1 * v << std::endl; std::cout << "Doing v *= 2;" << std::endl; v *= 2; std::cout << "Now v = " << v << std::endl; }
4) A note about expression templates
简单说就是 Eigen 对 arithmetic expression 有进行优化, 但这是它应该做的.
5) Transposition and conjugation
transpose() 转置
MatrixXcf a = MatrixXd::Random(2,2); cout << "Here is the matrix a " << a << endl; cout << "Here is the matrix a^T " << a.transpose() << endl;
不能使用 a = a.transpose(), a 的值会发生错乱, 要使用 a = a.transposeInPlace().
Matrix2i a; a << 1, 2, 3, 4; cout << "Here is the matrix a: " << a << endl; a = a.transpose(); // !!! do NOT do this !!! cout << "and the result of the aliasing effect: " << a << endl; a.transposeInPlace(); cout << "and after being transposed: " << a << endl;
6) Matrix-matrix and matrix-vector multiplication
a * b, a *= b
对于 a *= b, 如果 size 会发生变化, 则 a 不能是 fixed size
int main() { Matrix2d mat; mat << 1, 2, 3, 4; Vector2d u(-1,1), v(2,0); std::cout << "Here is mat*mat: " << mat*mat << std::endl; std::cout << "Here is mat*u: " << mat*u << std::endl; std::cout << "Here is u^T*mat: " << u.transpose()*mat << std::endl; std::cout << "Here is u^T*v: " << u.transpose()*v << std::endl; std::cout << "Here is u*v^T: " << u*v.transpose() << std::endl; std::cout << "Let's multiply mat by itself" << std::endl; mat = mat*mat; std::cout << "Now mat is mat: " << mat << std::endl; }
7) Dot product and cross product
dot() 点积
cross() 叉积
int main() { Vector3d v(1,2,3); Vector3d w(0,1,2); cout << "Dot product: " << v.dot(w) << endl; double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar cout << "Dot product via a matrix product: " << dp << endl; cout << "Cross product: " << v.cross(w) << endl; }
8) Basic arithmetic reduction operations
sum(), prod(), mean(), minCoeff(), maxCoeff(), trace()
int main() { Eigen::Matrix2d mat; mat << 1, 2, 3, 4; cout << "Here is mat.sum(): " << mat.sum() << endl; cout << "Here is mat.prod(): " << mat.prod() << endl; cout << "Here is mat.mean(): " << mat.mean() << endl; cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl; cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl; cout << "Here is mat.trace(): " << mat.trace() << endl; }
a.trace() == a.diagonal().sum()
minCoeff() 和 maxCoeff() 除了返回最小最大值, 还可以获取该值的索引
Matrix3f m = Matrix3f::Random(); std::ptrdiff_t i, j; float minOfM = m.minCoeff(&i,&j); cout << "Here is the matrix m: " << m << endl; cout << "Its minimum coefficient (" << minOfM << ") is at position (" << i << "," << j << ") "; RowVector4i v = RowVector4i::Random(); int maxOfV = v.maxCoeff(&i); cout << "Here is the vector v: " << v << endl; cout << "Its maximum coefficient (" << maxOfV << ") is at position " << i << endl;
9) Validity of operations
编译时和运行时都会检查运算的合法性
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
1) Array types
Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime>
可以有多维数组
Array<float, Dynamic, 1> ArrayXf
Array<float, 3, 1> Array3f
Array<double, Dynamic, Dynamic> ArrayXXd
Array<double, 3, 3> Array33d
2) Accessing values inside an Array
int main() { ArrayXXf m(2,2); // assign some values coefficient by coefficient m(0,0) = 1.0; m(0,1) = 2.0; m(1,0) = 3.0; m(1,1) = m(0,1) + m(1,0); // print values to standard output cout << m << endl << endl; // using the comma-initializer is also allowed m << 1.0,2.0, 3.0,4.0; // print values to standard output cout << m << endl; }
3) Addition and subtraction
array + array, array - scalar
int main() { ArrayXXf a(3,3); ArrayXXf b(3,3); a << 1,2,3, 4,5,6, 7,8,9; b << 1,2,3, 1,2,3, 1,2,3; // Adding two arrays cout << "a + b = " << endl << a + b << endl << endl; // Subtracting a scalar from an array cout << "a - 2 = " << endl << a - 2 << endl; }
4) Array multiplicaiton
区分于矩阵乘法, 对应位置参数相乘.
int main() { ArrayXXf a(2,2); ArrayXXf b(2,2); a << 1,2, 3,4; b << 5,6, 7,8; cout << "a * b = " << endl << a * b << endl; }
5) Other coefficient-wise operations
abs(), sqrt(), min() 两个 array 对应位置取最小
int main() { ArrayXf a = ArrayXf::Random(5); a *= 2; cout << "a =" << endl << a << endl; cout << "a.abs() =" << endl << a.abs() << endl; cout << "a.abs().sqrt() =" << endl << a.abs().sqrt() << endl; cout << "a.min(a.abs().sqrt()) =" << endl << a.min(a.abs().sqrt()) << endl; }
6) Converting between array and matrix expressions
matrix 有一个 array() 方法, array 有一个 matrix 方法, .array() 和 .matrix() 的返回值可以用作左值或右值.
matrix 有一个 cwiseProduct() 方法, 用于两个 matrix 对应参数相乘.
Eigen 允许将 array expression 赋值给 matrix 变量.
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; }
稍微复杂点的栗子
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.array() + 4).matrix() * m; cout << "-- Combination 1: --" << endl << result << endl << endl; result = (m.array() * n.array()).matrix() * m; cout << "-- Combination 2: --" << endl << result << endl << endl; }