赞
踩
本文参考于 https://eigen.tuxfamily.org/dox/group__TopicLinearAlgebraDecompositions.html
很多场合我们需要去计算矩阵的特征值与特征向量,但是Eigen中有好几个计算特征值与特征向量的方法,这些方法到底该选哪个呢?这篇文章就带着大家来分析一下。
功能为:Bidiagonal Divide and Conquer SVD,双对角线分治SVD
类的原型为
template<typename MatrixType_, int Options_>
class Eigen::BDCSVD< MatrixType_, Options_ >
模板参数 MatrixType_: 我们正在计算 SVD 分解的矩阵的类型
模板参数 Options_ : 此可选参数允许指定计算U和V的选项. 可选参数为ComputeThinU,ComputeThinV,ComputeFullU,ComputeFullV。无法同时请求 U 或 V 的精简版和完整版。默认情况下,不计算酉。
此类首先使用类上双对角化将输入矩阵简化为双对角线形式,然后执行分而治之对角化。小块使用类 JacobiSVD 对角化。您可以使用 setSwitchSize() 方法控制切换大小,默认值为 16。因此,对于小矩阵(<16),最好直接使用JacobiSVD。对于较大的,强烈建议使用BDCSVD,并且可以快几个数量级。
画重点,16维以下的矩阵,进行SVD分解,直接使用JacobiSVD,大于等于16维的矩阵,强烈建议使用BDCSVD。
功能为:Two-sided Jacobi SVD decomposition of a rectangular matrix, 长方形矩阵的双侧 Jacobi SVD 分解。
模板参数 MatrixType_:我们正在计算 SVD 分解的矩阵的类型
模板参数 Options_ :此可选参数允许指定将在内部用于非平方矩阵的 R-SVD 步骤的 QR 分解类型。此外,它还允许人们指定是计算薄酉还是全酉U和V。请参阅下面对可能值的讨论
SVD 分解包括将任何 n×p 矩阵 A 分解为乘积 A=USV∗
其中 U 是 n×n ,V 是 p×p ,S 是 n×p 实正矩阵,在其主对角线之外为零;
S 的对角线条目称为 A 的奇异值,U 和 V 的列分别称为 A 的左奇异向量和右奇异向量。
奇异值始终按降序排序。
默认情况下,此 JacobiSVD 分解仅计算奇异值。如果你想要U或V,你需要明确地要求它们。
您可以要求仅计算薄 U 或 V,这意味着以下内容。在矩形 n×p 矩阵的情况下,让 m 是 n 和 p 中的较小值,只有 m 个奇异向量;U 和 V 的其余列与实际的奇异向量不对应。要求细 U 或 V 意味着只要求形成它们的 m 第一列。所以 U 是一个 n×m 矩阵,V 是一个 p×m 矩阵。请注意,瘦 U 和 V 是求解(最小二乘法)所需要的全部内容。
这个 JacobiSVD 类是双侧 JacobiR-SVD 分解,确保了最佳的可靠性和准确性。缺点是对于大的方阵,它比双对角化 SVD 算法慢; 但是它的复杂度仍然是 O (n^2 * p) ,其中 n 是较小的维数,p 是较大的维数,这意味着它的复杂度仍然与更快的双对角化 R-SVD 算法相同。特别地,像任何 R-SVD 一样,它利用了非平方性,因为它的复杂性只在更大的维数上是线性的。如果输入矩阵有 inf 或 nan 系数,计算结果是未定义的,但计算保证在有限(合理)时间内终止。
画重点,16维以下的矩阵,进行SVD分解,直接使用JacobiSVD。
MatrixXf m = MatrixXf::Random(3,2); cout << "Here is the matrix m:" << endl << m << endl; JacobiSVD<MatrixXf, ComputeThinU | ComputeThinV> svd(m); cout << "Its singular values are:" << endl << svd.singularValues() << endl; cout << "Its left singular vectors are the columns of the thin U matrix:" << endl << svd.matrixU() << endl; cout << "Its right singular vectors are the columns of the thin V matrix:" << endl << svd.matrixV() << endl; Vector3f rhs(1, 0, 0); cout << "Now consider this rhs vector:" << endl << rhs << endl; cout << "A least-squares solution of m*x = rhs is:" << endl << svd.solve(rhs) << endl; --- Here is the matrix m: 0.68 0.597 -0.211 0.823 0.566 -0.605 Its singular values are: 1.19 0.899 Its left singular vectors are the columns of the thin U matrix: 0.388 0.866 0.712 -0.0634 -0.586 0.496 Its right singular vectors are the columns of the thin V matrix: -0.183 0.983 0.983 0.183 Now consider this rhs vector: 1 0 0 A least-squares solution of m*x = rhs is: 0.888 0.496
功能为:Computes eigenvalues and eigenvectors of selfadjoint matrices. 计算自伴矩阵的特征值与特征矢量。
这是在特征值模块中定义的。
#include <Eigen/Eigenvalues>
首先要考虑一下什么是自伴矩阵。
对于实矩阵,自伴矩阵就是对称矩阵。 对于复数矩阵,自伴是厄米特矩阵的同义词。
更一般地说,矩阵 A 是自伴的,当且仅当它等于它的伴随 A * 。
这个类计算自伴矩阵的特征值与特征矢量。这些是标量 λ 和向量 v,使得 Av = λv。自伴矩阵的特征值总是实的。如果 D 是特征值在对角线上的对角矩阵,V 是以特征向量为列的矩阵,则 A = VDV-1。这就是所谓的特征分解。
对于自伴矩阵,V 是酉矩阵,意味着它的逆等于它的伴随矩阵,V-1 = V*。如果 A 是实的,那么 V 也是实的,因此是正交的,这意味着它的逆等于它的转置,V-1 = VT。算法利用了矩阵是自伴的这一事实,使它比在 EigenSolver 和 ComplexEigenSolver 中实现的通用特征值算法更快、更准确。
调用 computer ()函数来计算给定矩阵的特征矢量。或者,你可以使用 selfAdjointeigenSolver (const matrixType & ,int)构造函数在构造时计算特征矢量。一旦特征值和特征向量被计算出来,它们就可以用 eigenvalues() eigenvectors()函数来检索。
画重点,SelfAdjointEigenSolver是计算实对称矩阵的特征值与特征向量的
SelfAdjointEigenSolver<Matrix4f> es;
Matrix4f X = Matrix4f::Random(4,4);
Matrix4f A = X + X.transpose();
es.compute(A);
cout << "The eigenvalues of A are: " << es.eigenvalues().transpose() << endl;
es.compute(A + Matrix4f::Identity(4,4)); // re-use es to compute eigenvalues of A+I
cout << "The eigenvalues of A+I are: " << es.eigenvalues().transpose() << endl;
The eigenvalues of A are: -1.58 -0.473 1.32 2.46
The eigenvalues of A+I are: -0.581 0.527 2.32 3.46
MatrixXd X = MatrixXd::Random(5,5); MatrixXd A = X + X.transpose(); cout << "Here is a random symmetric 5x5 matrix, A:" << endl << A << endl << endl; SelfAdjointEigenSolver<MatrixXd> es(A); cout << "The eigenvalues of A are:" << endl << es.eigenvalues() << endl; cout << "The matrix of eigenvectors, V, is:" << endl << es.eigenvectors() << endl << endl; double lambda = es.eigenvalues()[0]; cout << "Consider the first eigenvalue, lambda = " << lambda << endl; VectorXd v = es.eigenvectors().col(0); cout << "If v is the corresponding eigenvector, then lambda * v = " << endl << lambda * v << endl; cout << "... and A * v = " << endl << A * v << endl << endl; MatrixXd D = es.eigenvalues().asDiagonal(); MatrixXd V = es.eigenvectors(); cout << "Finally, V * D * V^(-1) = " << endl << V * D * V.inverse() << endl; --- Here is a random symmetric 5x5 matrix, A: 1.36 -0.816 0.521 1.43 -0.144 -0.816 -0.659 0.794 -0.173 -0.406 0.521 0.794 -0.541 0.461 0.179 1.43 -0.173 0.461 -1.43 0.822 -0.144 -0.406 0.179 0.822 -1.37 The eigenvalues of A are: -2.65 -1.77 -0.745 0.227 2.29 The matrix of eigenvectors, V, is: -0.326 -0.0984 0.347 -0.0109 0.874 -0.207 -0.642 0.228 0.662 -0.232 0.0495 0.629 -0.164 0.74 0.164 0.721 -0.397 -0.402 0.115 0.385 -0.573 -0.156 -0.799 -0.0256 0.0858 Consider the first eigenvalue, lambda = -2.65 If v is the corresponding eigenvector, then lambda * v = 0.865 0.55 -0.131 -1.91 1.52 ... and A * v = 0.865 0.55 -0.131 -1.91 1.52 Finally, V * D * V^(-1) = 1.36 -0.816 0.521 1.43 -0.144 -0.816 -0.659 0.794 -0.173 -0.406 0.521 0.794 -0.541 0.461 0.179 1.43 -0.173 0.461 -1.43 0.822 -0.144 -0.406 0.179 0.822 -1.37
功能为:Computes eigenvalues and eigenvectors of general complex matrices. 计算一般复数矩阵的特征值与特征向量,这在特征值模块中定义。
#include <Eigen/Eigenvalues>
画重点,ComplexEigenSolver是计算复数矩阵的特征值与特征向量
MatrixXcf A = MatrixXcf::Random(4,4); cout << "Here is a random 4x4 matrix, A:" << endl << A << endl << endl; ComplexEigenSolver<MatrixXcf> ces; ces.compute(A); cout << "The eigenvalues of A are:" << endl << ces.eigenvalues() << endl; cout << "The matrix of eigenvectors, V, is:" << endl << ces.eigenvectors() << endl << endl; complex<float> lambda = ces.eigenvalues()[0]; cout << "Consider the first eigenvalue, lambda = " << lambda << endl; VectorXcf v = ces.eigenvectors().col(0); cout << "If v is the corresponding eigenvector, then lambda * v = " << endl << lambda * v << endl; cout << "... and A * v = " << endl << A * v << endl << endl; cout << "Finally, V * D * V^(-1) = " << endl << ces.eigenvectors() * ces.eigenvalues().asDiagonal() * ces.eigenvectors().inverse() << endl; Here is a random 4x4 matrix, A: (-0.211,0.68) (0.108,-0.444) (0.435,0.271) (-0.198,-0.687) (0.597,0.566) (0.258,-0.0452) (0.214,-0.717) (-0.782,-0.74) (-0.605,0.823) (0.0268,-0.27) (-0.514,-0.967) (-0.563,0.998) (0.536,-0.33) (0.832,0.904) (0.608,-0.726) (0.678,0.0259) The eigenvalues of A are: (0.137,0.505) (-0.758,1.22) (1.52,-0.402) (-0.691,-1.63) The matrix of eigenvectors, V, is: (-0.246,-0.106) (0.418,0.263) (0.0417,-0.296) (-0.122,0.271) (-0.205,-0.629) (0.466,-0.457) (0.244,-0.456) (0.247,0.23) (-0.432,-0.0359) (-0.0651,-0.0146) (-0.191,0.334) (0.859,-0.0877) (-0.301,0.46) (-0.41,-0.397) (0.623,0.328) (-0.116,0.195) Consider the first eigenvalue, lambda = (0.137,0.505) If v is the corresponding eigenvector, then lambda * v = (0.0197,-0.139) (0.29,-0.19) (-0.0412,-0.223) (-0.274,-0.0891) ... and A * v = (0.0197,-0.139) (0.29,-0.19) (-0.0412,-0.223) (-0.274,-0.0891) Finally, V * D * V^(-1) = (-0.211,0.68) (0.108,-0.444) (0.435,0.271) (-0.198,-0.687) (0.597,0.566) (0.258,-0.0452) (0.214,-0.717) (-0.782,-0.74) (-0.605,0.823) (0.0268,-0.27) (-0.514,-0.967) (-0.563,0.998) (0.536,-0.33) (0.832,0.904) (0.608,-0.726) (0.678,0.0259)
功能为:Computes eigenvalues and eigenvectors of general matrices. 计算一般矩阵的特征值与特征向量,这在特征值模块中定义。
#include <Eigen/Eigenvalues>
矩阵 a 的特征矢量是标量 λ 和向量 v,使得 Av = λv。
如果 D 是特征值在对角线上的对角矩阵,V 是以特征向量为列的矩阵,则 AV = VD。矩阵 V 几乎总是可逆的,在这种情况下,我们有 A = VDV-1。这就是所谓的特征分解。
矩阵的特征矢量可能很复杂,即使矩阵是真实的。然而,我们可以选择实矩阵 V 和 D 满足 AV = VD,就像特征分解一样,如果矩阵 D 不需要是对角线,但是如果它允许在对角线上有块[ u-vvu ](其中 u 和 v 是实数)。这些块对应于复特征值对 u ± iv。我们称这种特征分解的变体为伪特征分解。
调用 computer ()函数来计算给定矩阵的特征矢量。或者,你也可以使用 eigenSolver (const Matrix Type & ,bool)构造函数来计算构造时的特征矢量。一旦特征值和特征向量被计算出来,它们就可以用eigenvalues() 和 eigenvectors()函数来获取。pseudoEigenvalueMatrix() and pseudoEigenvectors() 方法允许构造伪特征分解。
画重点,EigenSolver是一般矩阵(非对称矩阵,复数矩阵)的特征值与特征向量
MatrixXd A = MatrixXd::Random(6,6); cout << "Here is a random 6x6 matrix, A:" << endl << A << endl << endl; EigenSolver<MatrixXd> es(A); cout << "The eigenvalues of A are:" << endl << es.eigenvalues() << endl; cout << "The matrix of eigenvectors, V, is:" << endl << es.eigenvectors() << endl << endl; complex<double> lambda = es.eigenvalues()[0]; cout << "Consider the first eigenvalue, lambda = " << lambda << endl; VectorXcd v = es.eigenvectors().col(0); cout << "If v is the corresponding eigenvector, then lambda * v = " << endl << lambda * v << endl; cout << "... and A * v = " << endl << A.cast<complex<double> >() * v << endl << endl; MatrixXcd D = es.eigenvalues().asDiagonal(); MatrixXcd V = es.eigenvectors(); cout << "Finally, V * D * V^(-1) = " << endl << V * D * V.inverse() << endl; Here is a random 6x6 matrix, A: 0.68 -0.33 -0.27 -0.717 -0.687 0.0259 -0.211 0.536 0.0268 0.214 -0.198 0.678 0.566 -0.444 0.904 -0.967 -0.74 0.225 0.597 0.108 0.832 -0.514 -0.782 -0.408 0.823 -0.0452 0.271 -0.726 0.998 0.275 -0.605 0.258 0.435 0.608 -0.563 0.0486 The eigenvalues of A are: (0.049,1.06) (0.049,-1.06) (0.967,0) (0.353,0) (0.618,0.129) (0.618,-0.129) The matrix of eigenvectors, V, is: (-0.292,-0.454) (-0.292,0.454) (-0.0607,0) (-0.733,0) (0.59,-0.121) (0.59,0.121) (0.134,-0.104) (0.134,0.104) (-0.799,0) (0.136,0) (0.334,0.368) (0.334,-0.368) (-0.422,-0.18) (-0.422,0.18) (0.192,0) (0.0563,0) (-0.335,-0.143) (-0.335,0.143) (-0.589,0.0274) (-0.589,-0.0274) (-0.0788,0) (-0.627,0) (0.322,-0.155) (0.322,0.155) (-0.248,0.132) (-0.248,-0.132) (0.401,0) (0.218,0) (-0.335,-0.0761) (-0.335,0.0761) (0.105,0.18) (0.105,-0.18) (-0.392,0) (-0.00564,0) (-0.0324,0.103) (-0.0324,-0.103) Consider the first eigenvalue, lambda = (0.049,1.06) If v is the corresponding eigenvector, then lambda * v = (0.466,-0.331) (0.117,0.137) (0.17,-0.456) (-0.0578,-0.622) (-0.152,-0.256) (-0.186,0.12) ... and A * v = (0.466,-0.331) (0.117,0.137) (0.17,-0.456) (-0.0578,-0.622) (-0.152,-0.256) (-0.186,0.12) Finally, V * D * V^(-1) = (0.68,0) (-0.33,-5.55e-17) (-0.27,6.66e-16) (-0.717,0) (-0.687,-8.88e-16) (0.0259,-4.44e-16) (-0.211,2.22e-16) (0.536,3.21e-17) (0.0268,0) (0.214,0) (-0.198,0) (0.678,-4.44e-16) (0.566,4.44e-16) (-0.444,5.55e-17) (0.904,1.11e-16) (-0.967,-3.33e-16) (-0.74,4.44e-16) (0.225,2e-15) (0.597,-4.44e-16) (0.108,-2.78e-17) (0.832,3.33e-16) (-0.514,-1.11e-16) (-0.782,-1.33e-15) (-0.408,1.33e-15) (0.823,8.88e-16) (-0.0452,4.16e-17) (0.271,-3.89e-16) (-0.726,-6.66e-16) (0.998,1.33e-15) (0.275,2.22e-15) (-0.605,-9.71e-17) (0.258,4.16e-17) (0.435,-8.33e-17) (0.608,1.18e-16) (-0.563,-2.78e-16) (0.0486,-2.95e-16)
功能为:Computes eigenvalues and eigenvectors of the generalized selfadjoint eigen problem. 计算广义自伴特征问题的特征值与特征向量。,这在特征值模块中定义。
#include <Eigen/Eigenvalues>
该类解决了广义特征值问题 Av = λBv。在这种情况下,矩阵 A 应该是自伴的,矩阵 B 应该是正定的。
需要输入2个矩阵,A是自伴矩阵,B是正定矩阵,然后计算出特征值λ和特征向量v.
画重点,GeneralizedSelfAdjointEigenSolver 是计算 Av = λBv用的
MatrixXd X = MatrixXd::Random(5,5); MatrixXd A = X + X.transpose(); cout << "Here is a random symmetric matrix, A:" << endl << A << endl; X = MatrixXd::Random(5,5); MatrixXd B = X * X.transpose(); cout << "and a random positive-definite matrix, B:" << endl << B << endl << endl; GeneralizedSelfAdjointEigenSolver<MatrixXd> es(A,B); cout << "The eigenvalues of the pencil (A,B) are:" << endl << es.eigenvalues() << endl; cout << "The matrix of eigenvectors, V, is:" << endl << es.eigenvectors() << endl << endl; double lambda = es.eigenvalues()[0]; cout << "Consider the first eigenvalue, lambda = " << lambda << endl; VectorXd v = es.eigenvectors().col(0); cout << "If v is the corresponding eigenvector, then A * v = " << endl << A * v << endl; cout << "... and lambda * B * v = " << endl << lambda * B * v << endl << endl; Here is a random symmetric matrix, A: 1.36 -0.816 0.521 1.43 -0.144 -0.816 -0.659 0.794 -0.173 -0.406 0.521 0.794 -0.541 0.461 0.179 1.43 -0.173 0.461 -1.43 0.822 -0.144 -0.406 0.179 0.822 -1.37 and a random positive-definite matrix, B: 0.132 0.0109 -0.0512 0.0674 -0.143 0.0109 1.68 1.13 -1.12 0.916 -0.0512 1.13 2.3 -2.14 1.86 0.0674 -1.12 -2.14 2.69 -2.01 -0.143 0.916 1.86 -2.01 1.68 The eigenvalues of the pencil (A,B) are: -227 -3.9 -0.837 0.101 54.2 The matrix of eigenvectors, V, is: 14.2 -1.03 0.0766 -0.0273 -8.36 0.0546 -0.115 0.729 0.478 0.374 -9.23 0.624 -0.0165 0.499 3.01 7.88 1.3 0.225 0.109 -3.85 20.8 0.805 -0.567 -0.0828 -8.73 Consider the first eigenvalue, lambda = -227 If v is the corresponding eigenvector, then A * v = 22.8 -28.8 19.8 21.9 -25.9 ... and lambda * B * v = 22.8 -28.8 19.8 21.9 -25.9
官方文档里有这几个函数的对比
第二列是这些方法对矩阵的要求,第三列是计算的速度,第四列是算法的可靠性与准确性。
BDCSVD和JacobiSVD是计算奇异值的,如果维度小于16, 可以直接用JacobiSVD。
SelfAdjointEigenSolver是计算实对称矩阵或者复数下的自伴矩阵的特征值与特征向量的。
ComplexEigenSolver是计算复数矩阵的特征值与特征向量的。
EigenSolver是一般矩阵(非对称矩阵,复数矩阵)的特征值与特征向量。
GeneralizedSelfAdjointEigenSolver 是计算 Av = λBv用的,需要输入2个矩阵,A是自伴矩阵,B是正定矩阵,然后计算出特征值λ和特征向量v。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。