C++相关|Eigen:常用功能速查

引:

  • 本文参考https://zhuanlan.zhihu.com/p/362461462而来,并对其中中文部分进行了解释和补充,此外记录了笔者在学习这些内容时一些疑问点的验证。
  • 详细的说明可参照eigen官方文档:链接
一、疑问点验证 1、Matrix矩阵默认是按列优先存储(若要按行存储要指定 如Matrix ),那为什么执行如下命令得到的还是按行存储的呢?
Matrix Acolmajor; Acolmajor << 8, 2, 2, 9, 9, 1, 4, 4, 3, 5, 4, 5; cout << Acolmajor << endl << endl; 结果为: 8 2 2 9 9 1 4 4 3 5 4 5 而不是: 8 9 4 5 2 9 4 4 2 1 3 5

原因:列优先存储还是行优先存储指的是在线性内存地址中元素的存储方式,这与每个元素呈现在矩阵中的位置是无关的,也就是我们正常按照矩阵字面排布赋值即可,行优先和列有限是底层数据存储的问题,这一点在使用数组对Matrix进行初始化时极为重要。继续验证如下:
cout << "In memory (column-major):" << endl; for (int i = 0; i < Acolmajor.size(); i++) cout << *(Acolmajor.data() + i) << ""; cout << endl << endl; Matrix Arowmajor = Acolmajor; cout << "In memory (row-major):" << endl; for (int i = 0; i < Arowmajor.size(); i++) cout << *(Arowmajor.data() + i) << ""; cout << endl; 输出: In memory (column-major): 893215244945In memory (row-major): 822991443545

2、x.asDiagonal() 功能:通过x中元素作为对角元素(构建对角阵)这里x必须为VectorXX类型不能为矩阵
Eigen::Vector4i M; M<<1, 1, 3, 4; Eigen::MatrixXi V(M.asDiagonal()); std::cout<

3、R.transpose().colwise().reverse(); // rot90?所有元素逆时针转了90度(注意这里的colwise().reverse()应理解为每一列中逐元素反转,本质上是行交换)
//逆时针旋转90度 Eigen::Matrix2i N; N<<5, 6, 7, 8; std::cout<

二、速查笔记 【C++相关|Eigen:常用功能速查】注:以下包含了matlab的对应方法,Matlab下标是从1开始的,Eigen 中Matrix等下标是从0开始的。
  • 基础定义:
#include // 基本函数只需要包含这个头文件 Matrix A; // 固定了行数和列数的矩阵和Matrix3d一致. Matrix B; // 固定行数. Matrix C; // 和MatrixXd一致. Matrix E; // 按行存储; 默认按列(列优先)存储. Matrix3f P, Q, R; // 3x3 float 矩阵. Vector3f x, y, z; // 3x1 float 列向量. RowVector3f a, b, c; // 1x3 float 行向量. VectorXd v; // 动态长度double型列向量 // Eigen// Matlab// comments x.size()// length(x)// 向量长度 C.rows()// size(C,1)// 矩阵行数 C.cols()// size(C,2)// 矩阵列数 x(i)// x(i+1)// 下标0开始 C(i,j)// C(i+1,j+1)//123456789101112131415

  • Eigen 中矩阵的基本使用方法
A.resize(4, 4); // 如果越界触发运行时错误. B.resize(4, 9); // 如果越界触发运行时错误. A.resize(3, 3); // Ok; 没有越界. B.resize(3, 9); // Ok; 没有越界. A << 1, 2, 3,// Initialize A. The elements can also be 4, 5, 6,// matrices, which are stacked along cols 7, 8, 9; // and then the rows are stacked. B << A, A, A; // B is three horizontally stacked A's.三行A A.fill(10); // Fill A with all 10's.全10

  • 生成特殊矩阵
// Eigen// Matlab MatrixXd::Identity(rows,cols)// eye(rows,cols) 单位矩阵 C.setIdentity(rows,cols)// C = eye(rows,cols) 单位矩阵 MatrixXd::Zero(rows,cols)// zeros(rows,cols) 零矩阵 C.setZero(rows,cols)// C = ones(rows,cols) 零矩阵 MatrixXd::Ones(rows,cols)// ones(rows,cols)全一矩阵 C.setOnes(rows,cols)// C = ones(rows,cols)全一矩阵 MatrixXd::Random(rows,cols)// rand(rows,cols)*2-1// 元素随机在-1->1 C.setRandom(rows,cols)// C = rand(rows,cols)*2-1 同上 VectorXd::LinSpaced(size,low,high)// linspace(low,high,size)'线性分布的数组(size表示元素个数) v.setLinSpaced(size,low,high)// v = linspace(low,high,size)'线性分布的数组

  • Eigen 矩阵分块
// Eigen// Matlab x.head(n)// x(1:n)用于数组提取前n个[vector] x.head()// x(1:n)同理 x.tail(n)// x(end - n + 1: end)同理 x.tail()// x(end - n + 1: end)同理 x.segment(i, n)// x(i+1 : i+n)同理/第i个元素开始取n个 x.segment(i)// x(i+1 : i+n)同理 P.block(i, j, rows, cols)// P(i+1 : i+rows, j+1 : j+cols)i,j开始,rows行cols列 P.block(i, j)// P(i+1 : i+rows, j+1 : j+cols)i,j开始,rows行cols列 P.row(i)// P(i+1, :)i行 P.col(j)// P(:, j+1)j列 P.leftCols()// P(:, 1:cols)左边cols列 P.leftCols(cols)// P(:, 1:cols)左边cols列 P.middleCols(j)// P(:, j+1:j+cols)中间从j数cols列 P.middleCols(j, cols)// P(:, j+1:j+cols)中间从j数cols列 P.rightCols()// P(:, end-cols+1:end)右边cols列 P.rightCols(cols)// P(:, end-cols+1:end)右边cols列 P.topRows()// P(1:rows, :)同列 P.topRows(rows)// P(1:rows, :)同列 P.middleRows(i)// P(i+1:i+rows, :)同列 P.middleRows(i, rows)// P(i+1:i+rows, :)同列 P.bottomRows()// P(end-rows+1:end, :)同列 P.bottomRows(rows)// P(end-rows+1:end, :)同列 P.topLeftCorner(rows, cols)// P(1:rows, 1:cols)上左角rows行,cols列 P.topRightCorner(rows, cols)// P(1:rows, end-cols+1:end)上右角rows行,cols列 P.bottomLeftCorner(rows, cols)// P(end-rows+1:end, 1:cols)下左角rows行,cols列 P.bottomRightCorner(rows, cols)// P(end-rows+1:end, end-cols+1:end)下右角rows行,cols列 P.topLeftCorner()// P(1:rows, 1:cols)同上 P.topRightCorner()// P(1:rows, end-cols+1:end)同上 P.bottomLeftCorner()// P(end-rows+1:end, 1:cols)同上 P.bottomRightCorner()// P(end-rows+1:end, end-cols+1:end)同上

  • Eigen 矩阵元素交换
// Eigen// Matlab R.row(i) = P.col(j); // R(i, :) = P(:, i)交换列为行 R.col(j1).swap(R.col(j2)); // R(:, [j1 j2]) = R(:, [j2, j1]) 交换列(笔者验证过)

  • 矩阵转置
// Views, transpose, etc; all read-write except for .adjoint(). // Eigen// Matlab R.adjoint()// R' 伴随矩阵 R.transpose()// R.' or conj(R')转置 R.diagonal()// diag(R)对角(求主对角元素) x.asDiagonal()// diag(x)对角阵(通过x中元素作为对角元素(构建对角矩阵)这里x必须为VectorXX类型不能为矩阵) R.transpose().colwise().reverse(); // rot90(R)所有元素逆时针转了90度(注意这里的colwise().reverse()应理解为每一列中逐元素反转,本质上是行互换) R.conjugate()// conj(R)共轭矩阵12345678

  • 矩阵乘积
// 与Matlab一致, 但是matlab不支持*=等形式的运算. // Matrix-vector.Matrix-matrix.Matrix-scalar. y= M*x; R= P*Q; R= P*s; a= b*M; R= P - Q; R= s*P; a *= M; R= P + Q; R= P/s; R *= Q; R= s*P; R += Q; R *= s; R -= Q; R /= s;

  • 矩阵单个元素操作
// Vectorized operations on each element independently // Eigen// Matlab R = P.cwiseProduct(Q); // R = P .* Q 对应点相乘 R = P.array() * s.array(); // R = P .* s 对应点相乘 R = P.cwiseQuotient(Q); // R = P ./ Q 对应点相除 R = P.array() / Q.array(); // R = P ./ Q对应点相除 R = P.array() + s.array(); // R = P + s对应点相加 R = P.array() - s.array(); // R = P - s对应点相减 R.array() += s; // R = R + s全加s R.array() -= s; // R = R - s全减s R.array() < Q.array(); // R < Q 以下的都是针对矩阵的单个元素的操作 R.array() <= Q.array(); // R <= Q矩阵元素比较,会在相应位置置0或1 R.cwiseInverse(); // 1 ./ P R.array().inverse(); // 1 ./ P R.array().sin()// sin(P) R.array().cos()// cos(P) R.array().pow(s)// P .^ s R.array().square()// P .^ 2 R.array().cube()// P .^ 3 R.cwiseSqrt()// sqrt(P) R.array().sqrt()// sqrt(P) R.array().exp()// exp(P) R.array().log()// log(P) R.cwiseMax(P)// max(R, P) 对应取大 R.array().max(P.array())// max(R, P) 对应取大 R.cwiseMin(P)// min(R, P) 对应取小 R.array().min(P.array())// min(R, P) 对应取小 R.cwiseAbs()// abs(P) 绝对值 R.array().abs()// abs(P) 绝对值 R.cwiseAbs2()// abs(P.^2) 绝对值平方 R.array().abs2()// abs(P.^2) 绝对值平方 (R.array() < s).select(P,Q); // (R < s ? P : Q)这个也是单个元素的操作

  • 矩阵化简
// Reductions. int r, c; // Eigen// Matlab R.minCoeff()// min(R(:))最小值 R.maxCoeff()// max(R(:))最大值 s = R.minCoeff(&r, &c)// [s, i] = min(R(:)); [r, c] = ind2sub(size(R), i); 求出最小值,并获取最小值的索引 s = R.maxCoeff(&r, &c)// [s, i] = max(R(:)); [r, c] = ind2sub(size(R), i); 求出最大值,并获取最大值的索引 R.sum()// sum(R(:))求和 R.colwise().sum()// sum(R)列求和1×N()按列求和 R.rowwise().sum()// sum(R, 2) or sum(R')'行求和N×1 R.prod()// prod(R(:))所有乘积 R.colwise().prod()// prod(R)列乘积 R.rowwise().prod()// prod(R, 2) or prod(R')'行乘积 R.trace()// trace(R)迹 R.all()// all(R(:))且运算 R.colwise().all()// all(R) 且运算 R.rowwise().all()// all(R, 2) 且运算 R.any()// any(R(:)) 或运算 R.colwise().any()// any(R) 或运算 R.rowwise().any()// any(R, 2) 或运算

  • 矩阵点乘
// Dot products, norms, etc. // Eigen// Matlab x.norm()// norm(x).模 /单纯的平方和开根号,注意与行列式区分开(determinant()) x.squaredNorm()// dot(x, x)平方和 x.dot(y)// dot(x, y)点乘 x.cross(y)// cross(x, y) Requires #include 这是向量叉乘(结果还是向量)

  • 矩阵类型转换
// Eigen// Matlab A.cast(); // double(A) A.cast(); // single(A) A.cast(); // int32(A) 向下取整 A.real(); // real(A) //实部 A.imag(); // imag(A)。//虚部 // if the original type equals destination type, no work is done

  • 求解线性方程组 Ax = b
// Solve Ax = b. Result stored in x. Matlab: x = A \ b.不同算法求法(精度和速度不同,可查资料) x = A.ldlt().solve(b)); // #include LDLT分解法实际上是Cholesky分解法的改进 x = A.llt() .solve(b)); // A sym. p.d.#include x = A.lu().solve(b)); // Stable and fast. #include x = A.qr().solve(b)); // No pivoting.#include x = A.svd() .solve(b)); // Stable, slowest. #include // .ldlt() -> .matrixL() and .matrixD() // .llt()-> .matrixL() // .lu()-> .matrixL() and .matrixU() // .qr()-> .matrixQ() and .matrixR() // .svd()-> .matrixU(), .singularValues(), and .matrixV()1234567891011

  • 矩阵特征值
// Eigen// Matlab A.eigenvalues(); // eig(A); 特征值 EigenSolver eig(A); // [vec val] = eig(A) eig.eigenvalues(); // diag(val)与前边的是一样的结果 eig.eigenvectors(); // vec 特征值对应的特征向量

    推荐阅读