Eigen 是开源的C++线性代数库,常用在计算机图形学中,之前我们记录了安装使用方法,本文记录常用功能使用方法。
Matrix
模板类的对象,Matrix
类有6个模板参数,主要使用前三个,剩下的使用默认值。MaxRowsAtCompileTime
和MaxColsAtCompileTime
在已知动态矩阵的尺寸上界时是可以提升工作效率的。Matrix<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime, int Options = 0, int MaxRowsAtCompileTime = RowsAtCompileTime, int MaxColsAtCompileTime = ColsAtCompileTime># Scalar 元素类型# RowsAtCompileTime 行# ColsAtCompileTime 列# 例 typedef Matrix<int, 3, 3> Matrix3i;# Options 比特标志位# MaxRowsAtCompileTime和MaxColsAtCompileTime表示在编译阶段矩阵的上限。# 列向量typedef Matrix<double, 3, 1> Vector3d;# 行向量typedef Matrix<float, 1, 3> RowVector3f;# 动态大小typedef Matrix<double, Dynamic, Dynamic> MatrixXd;typedef Matrix<float, Dynamic, 1> VectorXf;type
[]
操作符可以用于向量元素的获取,但不能用于matrix
。
matrix
的大小可以通过rows()
, cols()
, size()
获取,resize()
可以重新调整矩阵大小。
Matrix
定义的矩阵为静态矩阵,在编译时确定尺寸、分配内存,随机初始化:
Matrix<int, 3, 3> a;cout << a;-->1284850368 32759 1 32759 31 01284845929 0 0
MatrixX
开头的为动态矩阵,两个维度都可以变化,本质为 Matrix<Type, Dynamic, Dynamic>
定义的类型
例如:
MatrixXd
为 double 类型的动态矩阵 1 2 3 4 5 6 7MatrixXd a(3, 3); cout << a; --> 0 0 0 0 0 0 0 0 0
静态矩阵运算很快,但是有 128k 的堆栈尺寸限制,常用的还是动态矩阵类型
仅变化一个维度的动态矩阵为动态向量 typedef Matrix<float, Dynamic, 1> VectorXf
,使用方法类似
Array
是类模板,前三个参数必须指定,后三个参数可选。Array<typename Scalar, int RowsAtCompileTime, int ColsAtCompileTime># 常见类定义typedef Array<float, Dynamic, 1> ArrayXftypedef Array<float, 3, 1> Array3ftypedef Array<double, Dynamic, Dynamic> ArrayXXdtypedef Array<double, 3, 3> Array33dArrayXf a = ArrayXf::Random(5);a.abs(); # 绝对值a.sqrt(); # 平方根a.min(a.abs().sqrt()); # 两个array相应元素的最小值
类似于 Matrix
类,Array
默认仍会产生静态数组
Array<int, 3, 3> a;cout << a;-->-412990784 32758 1 32758 31 0-412995223 0 0
一维动态数组为 ArrayX
开头,二维动态数组为 ArrayXX
开头
ArrayXXi a(3, 3);cout << a;-->6357107 7471220 45220447929971 6422621 60293717667805 7209066 7471185
Matrix
对象——>Array
对象:.array()
函数Array
对象——>Matrix
对象:.matrix()
函数建议矩阵数据都要初始化,不然是十分危险的。
ArrayXXi a(2, 4);cout << a;-->7602273 7209025 7209071 30147076029409 6488161 6357092 3014712
赋值初始化
Matrix<int, 5, 1> b {1, 2, 3, 4, 5};Matrix<double, 2, 3> b { {2, 3, 4}, {5, 6, 7},};VectorXd a {{1.5, 2.5, 3.5}};RowVectorXd b {{1.0, 2.0, 3.0, 4.0}};
可以用其他对象初始化新的相同内容对象
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;MatrixXf n(m);m.block(0, 0, 2, 2).swap(n.block(2, 2, 2, 2));cout << m;--> 11 12 3 415 16 7 8 9 10 11 1213 14 15 16
ArrayXXi a(2, 3);a << 1, 2, 3, 4, 5, 6;cout << a << endl << endl;ArrayXXi b(2, 2);b << 7, 8, 9, 10;cout << b << endl << endl;ArrayXXi c(4, 7);c << b, a, b, a, b, b;cout << c << endl << endl;-->1 2 34 5 6 7 8 9 10 7 8 1 2 3 7 8 9 10 4 5 6 9 10 1 2 3 7 8 7 8 4 5 6 9 10 9 10
一下几个函数均为静态矩阵调用的初始化函数,动态矩阵调用会报错: 1YOU CALLED A_FIXED SIZE METHOD ON A DYNAMIC SIZE MATRIX OR VECTOR
Zero()
Constant(rows, cols, value)
Random()
Identity()
Matrix<int, 3, 3> a;cout << a << endl << endl;a = a.Zero();cout << a << endl << endl;a = a.Constant(3, 3, 7);cout << a << endl << endl;a = a.Random();cout << a << endl << endl;a = a.Identity();cout << a << endl << endl;-->1028866792 32759 1 32759 31 01028862809 0 00 0 00 0 00 0 07 7 77 7 77 7 7-16343 10116 -4906 2083 2785 12974-10050 -660 105781 0 00 1 00 0 1
函数 | 含义 |
---|---|
setZero() | 矩阵归零 |
setConstant() | 矩阵归常数 |
setIdentity() | 矩阵归单位阵 |
setOnes() | 矩阵归一 |
setRandom() | 矩阵随机数 |
MatrixXi a(3, 3);cout << a << endl << endl;a.setZero();cout << a << endl << endl;a.setConstant(2);cout << a << endl << endl;a.setIdentity();cout << a << endl << endl;a.setOnes();cout << a << endl << endl;a.setRandom();cout << a << endl << endl;-->5701724 7536759 66192527209065 5439580 33424457274596 7536761 60293620 0 00 0 00 0 02 2 22 2 22 2 21 0 00 1 00 0 11 1 11 1 11 1 1-16343 10116 -4906 2083 2785 12974-10050 -660 10578
函数 | 含义 |
---|---|
setLinSpaced() | 填充线性间隔的数据 |
setUnit() | 指定向量位置数据置1,其余为0 |
RowVectorXf b(8);cout << b << endl << endl;b.setLinSpaced(0, 14);cout << b << endl << endl;b.setUnit(3);cout << b << endl << endl;b.setOnes();cout << b << endl << endl;b.setConstant(2);cout << b << endl << endl;-->9.91839e-39 9.64288e-39 8.44903e-39 7.80611e-39 5.9694e-39 1.08367e-38 4.50001e-39 4.5e-390 2 4 6 8 10 12 140 0 0 1 0 0 0 01 1 1 1 1 1 1 12 2 2 2 2 2 2 2
主要数据的存取和修改都是通过重载的括号运算符完成的
对于二维矩阵,下标顺序为 row col
对于向量,则只有向量下标需要传入
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);cout << m;--> 3 -12.5 1.5
块 | 动态矩阵 | 静态矩阵 |
---|---|---|
尺寸 (p, q) 左上角坐标 (i, j) | matrix.block(i,j,p,q); | matrix.block<p,q>(i,j); |
示例:
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;m.block<2, 2>(0, 0) = m.block<2, 2>(0, 0) * 3;m.block<2, 2>(2, 2).setConstant(0);cout << m << endl << endl;-->18 21 3 430 33 7 8 9 10 0 013 14 0 0
操作 | 方法 |
---|---|
第 i 行 | matrix.row(i); |
第 i 列 | matrix.col(j); |
示例:
Eigen::MatrixXf m(3, 3);m << 1, 2, 3,4, 5, 6,7, 8, 9;cout << "Here is the matrix m:" << endl << m << endl;cout << "2nd Row: " << m.row(1) << endl;m.col(2) += 3 * m.col(0);cout << "After adding 3 times the first column into the third column, the matrix m is:\n";cout << m << endl;-->Here is the matrix m:1 2 34 5 67 8 92nd Row: 4 5 6After adding 3 times the first column into the third column, the matrix m is: 1 2 6 4 5 18 7 8 30
块操作 | 动态矩阵语法 | 静态矩阵语法 |
---|---|---|
左上角 p 行 q 列 | matrix.topLeftCorner(p,q); | matrix.topLeftCorner<p,q>(); |
左下角 p 行 q 列 | matrix.bottomLeftCorner(p,q); | matrix.bottomLeftCorner<p,q>(); |
右上角 p 行 q 列 | matrix.topRightCorner(p,q); | matrix.topRightCorner<p,q>(); |
右下角 p 行 q 列 | matrix.bottomRightCorner(p,q); | matrix.bottomRightCorner<p,q>(); |
前 q 行 | matrix.topRows(q); | matrix.topRows<q>(); |
后 q 行 | matrix.bottomRows(q); | matrix.bottomRows<q>(); |
前 p 列 | matrix.leftCols(p); | matrix.leftCols<p>(); |
后 p 列 | matrix.rightCols(q); | matrix.rightCols<q>(); |
第 i 列开始取 q 列 | matrix.middleCols(i,q); | matrix.middleCols<q>(i); |
第 i 行开始取 q 行 | matrix.middleRows(i,q); | matrix.middleRows<q>(i); |
示例:
Eigen::Matrix4f m;m << 1, 2, 3, 4,5, 6, 7, 8,9, 10,11,12,13,14,15,16;cout << "m.leftCols(2) =" << endl << m.leftCols(2) << endl << endl;cout << "m.bottomRows<2>() =" << endl << m.bottomRows<2>() << endl << endl;m.topLeftCorner(1,3) = m.bottomRightCorner(3,1).transpose();cout << "After assignment, m = " << endl << m << endl;-->m.leftCols(2) = 1 2 5 6 9 1013 14m.bottomRows<2>() = 9 10 11 1213 14 15 16After assignment, m = 8 12 16 4 5 6 7 8 9 10 11 1213 14 15 16
块操作 | 动态矩阵语法 | 静态矩阵语法 |
---|---|---|
向量前 n 个数据 | vector.head(n); | vector.head<n>(); |
向量后 n 个数据 | vector.tail(n); | vector.tail<n>(); |
向量从下标 i 开始的 n 个数据 | vector.segment(i,n); | vector.segment<n>(i); |
操作 | 语法 | 示例 |
---|---|---|
转置 | .transpose() | v.transpose() |
所有元素为 true(非0),返回 bool 值 | all() | m.all() |
存在元素为 true(非0),返回 bool 值 | any() | m.any() |
统计 true(非0) 的个数 | count() | m.count() |
操作 | 语法 | 示例 |
---|---|---|
数据类型转换为 double | .cast<double>() | A.cast<double>() |
数据类型转换为 float | .cast<float>() | A.cast<float>() |
数据类型转换为 int | .cast<int>() | A.cast<int>() |
数据类型转换为实部 | .real() | A.real() |
数据类型转换为虚部 | .imag() | A.imag() |
内存数据转 Eigen | Map<>() | Map<Matrix3i>(array) |
内存数据转 Eigen:
int array[9];for (int i = 0; i < 9; ++i) {array[i] = i;}cout << Map<Matrix3i>(array).transpose() << endl;-->0 1 23 4 56 7 8
操作 | 语法 | 示例 |
---|---|---|
点乘 | dot() | v.dot(w) |
叉乘 | .cross() | v.cross(w) |
元素个数 | .size() | v.size() |
生成对角阵 | .asDiagonal() | v.asDiagonal() |
向量平方和 | .squaredNorm() | v.squaredNorm() |
向量模长 | .norm() | v.norm() |
操作 | 语法 | 示例 |
---|---|---|
转置 | .transpose() | v.transpose() |
共轭 | .conjugate() | a.conjugate() |
共轭转置 | .adjoint() | a.adjoint() |
元素个数 | .size() | a.size() |
行数 | .rows() | a.rows() |
列数 | .rols() | a.rols() |
填充 | .fill() | a.fill(6) |
交换行/列 | .swap() | m.block(0, 0, 2, 2).swap(n.block(2, 2, 2, 2)); |
获取对角线 | .diagonal() | a.diagonal() |
列向操作 | .colwise() | m.colwise().sum() |
元素颠倒 | .reverse() | m.reverse() |
赋值经过优化:
行可以给列赋值,这个其实还是挺可怕的,需要格外小心。
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;m.row(0) = m.col(3);cout << m;--> 4 8 12 16 5 6 7 8 9 10 11 1213 14 15 16
列向操作相当于 numpy 中的 axis=1
,只对列方向做某种操作:
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;cout << "Here is the matrix m:" << endl << m << endl;cout << "Here is the sum of each column:" << endl << m.colwise().sum() << endl;cout << "Here is the maximum absolute value of each column:"<< endl << m.cwiseAbs().colwise().maxCoeff() << endl;-->Here is the matrix m: 1 2 3 4 5 6 7 8 9 10 11 1213 14 15 16Here is the sum of each column:28 32 36 40Here is the maximum absolute value of each column:13 14 15 16
操作 | 语法 | 示例 |
---|---|---|
矩阵相加 | + | a + b |
矩阵相减 | - | a - b |
负号 | - | - a |
复合算子加 | += | a += b |
复合算子减 | -= | a -= b |
标量乘法 | * | matrix*scalar / scalar*matrix |
标量除法 | / | matrix/scalar |
复合算子乘 | *= | matrix*=scalar |
复合算子除 | /= | matrix/=scalar |
矩阵\向量乘法 | * | matrix*matrix, matrix*vector |
矩阵求和 | .sum() | mat.sum() |
所有元素乘积 | .prod() | mat.prod() |
矩阵均值 | .mean() | mat.mean() |
矩阵最小值 | .minCoeff() | mat.minCoeff() |
矩阵最大值 | .maxCoeff() | mat.maxCoeff() |
矩阵最小值,带位置 | .minCoeff(&r, &c) | mat.minCoeff(&r, &c) |
矩阵最大值,带位置 | .maxCoeff(&r, &c) | mat.maxCoeff(&r, &c) |
迹 | .trace() | mat.trace() |
逐元素绝对值 | .cwiseAbs() | mat.cwiseAbs() |
逐元素相乘 | .cwiseProduct() | mat = mat.cwiseProduct(mat) |
逐元素相除 | .cwiseQuotient() | mat = mat.cwiseQuotient(mat) |
逐元素取倒数 | .cwiseInverse() | mat.cwiseInverse() |
逐元素开根号 | .cwiseSqrt() | mat.cwiseSqrt() |
逐元素最大值 | .cwiseMax(m) | mat.cwiseMax(mat2) |
逐元素最小值 | .cwiseMin(m) | mat.cwiseMin(mat2) |
元素平方和 | .squaredNorm() | mat.squaredNorm() |
矩阵二阶范数 | .norm() | mat.norm() |
p 阶范数 | .lpNorm<p>() | mat.lpNorm<3>() |
最大值、最小值
返回最大、最小值,同时定位位置
Matrix3f m = Matrix3f::Random();std::ptrdiff_t i, j;float minOfM = m.minCoeff(&i,&j);cout << "Here is the matrix m:\n" << m << endl;cout << "Its minimum coefficient (" << minOfM << ") is at position (" << i << "," << j << ")\n\n";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;-->Here is the matrix m: -0.997497 0.617481 -0.299417 0.127171 0.170019 0.791925 -0.613392 -0.0402539 0.64568Its minimum coefficient (-0.997497) is at position (0,0)Here is the vector v: 8080 -10679 11761 6897Its maximum coefficient (11761) is at position 2
操作 | 语法 | 示例 |
---|---|---|
逐元素相乘 | * | a * b |
逐元素相除 | / | a * b |
矩阵相加 | + | a + b |
矩阵相减 | - | a - b |
负号 | - | - a |
复合算子加 | += | a += b |
复合算子减 | -= | a -= b |
逐元素比较 | <, >, >=, <=, == | a < b |
逐元素标量计算 | +, -, *, / | a + 3 |
逐元素标量复合计算 | +=, -=, *=, /= | a /= 3 |
逐元素取倒数 | .inverse() | a.inverse() |
逐元素 sin | .sin() | a.sin() |
逐元素 cos | .cos() | a.cos() |
逐元素乘方 | .pow(s) | a.pow(3) |
逐元素平方 | .square() | a.square() |
逐元素立方 | .cube() | a.cube() |
逐元素开根号 | .sqrt() | a.sqrt() |
逐元素计算自然指数 | .exp() | a.exp() |
逐元素计算自然对数 | .log() | a.log() |
逐元素最小值 | .min() | a.min(b) |
逐元素最大值 | .max() | a.max(b) |
逐元素绝对值 | .abs() | a.abs() |
逐元素选择 | .select() | (R.array() < s).select(P,Q) |
逐元素比较:
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;cout << (m.array() > m.reverse().array());-->0 0 0 00 0 0 01 1 1 11 1 1 1
逐元素选择:
Eigen::MatrixXf m(4, 4);m << 1, 2, 3, 4,5, 6, 7, 8,9, 10, 11, 12,13, 14, 15, 16;MatrixXf n(4, 4), p(4, 4);n.setZero();p = (m.array() < 10).select(m, n);cout << p;-->1 2 3 45 6 7 89 0 0 00 0 0 0
分解方法 | 语法 | 输出 |
---|---|---|
柯列斯基分解 | .ldlt() | .matrixL() and .matrixD() |
LLT 分解 | .llt() | .matrixL() |
部分旋转的 LU分解 | .lu() | .matrixL() and .matrixU() |
QR 分解 | .qr() | .matrixQ() and .matrixR() |
SVD 分解 | .svd() | .matrixU(), .singularValues(), and .matrixV() |
语法 | 描述 |
---|---|
x = A.ldlt().solve(b)); | A sym. p.s.d. #include <Eigen/Cholesky> |
x = A.llt() .solve(b)); | A sym. p.d. #include <Eigen/Cholesky> |
x = A.lu() .solve(b)); | Stable and fast. #include <Eigen/LU> |
x = A.qr() .solve(b)); | No pivoting. #include <Eigen/QR> |
x = A.svd() .solve(b)); | Stable, slowest. #include <Eigen/SVD> |
特征值:
A.eigenvalues();
特征向量:
eig.eigenvectors();
eval()
函数解决把右值赋值为一个临时矩阵,再赋给左值时可能有造成的混淆。如:MatrixXi mat(3,3);mat << 1,2,3, 4,5,6, 7,8,9;mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2).eval();
普通函数 | inplace函数 |
---|---|
MatrixBase::adjoint() | MatrixBase::adjointInPlace() |
DenseBase::reverse() | DenseBase::reverseInPlace() |
LDLT::solve() | LDLT::solveInPlace() |
LLT::solve() | LLT::solveInPlace() |
TriangularView::solve() | TriangularView::solveInPlace() |
DenseBase::transpose() | DenseBase::transposeInPlace() |
noalias()
eval()
和xxxInPlace()
函数解决