我试图确定Eigen中稀疏数组的特征值和特征向量。由于我需要计算所有特征向量和特征值,并且我无法使用不支持的ArpackSupport模块工作完成,我选择将系统转换为密集矩阵并使用SelfAdjointEigenSolver计算特征系统(我知道我的矩阵是真实的并具有真实的特征值)。这种方法很有效,直到我有1024 * 1024的矩阵,但后来我开始偏离预期的结果。
在我所理解的模块(https://eigen.tuxfamily.org/dox/classEigen_1_1SelfAdjointEigenSolver.html)的文档中,可以更改最大迭代次数:
const int m_maxIterations 静态的 最大迭代次数。
如果算法不在m_maxIterations * n次迭代中收敛,则算法终止,其中n表示矩阵的大小。此值当前设置为30(从LAPACK复制)。
但是,我不明白你是如何使用他们的例子来实现的:
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
如何修改它以更改最大迭代次数?
另外,这会解决我的问题,还是应该尝试寻找替代函数或算法来解决本征系统?
我提前感谢。
答案 0 :(得分:2)
增加迭代次数不太可能有所帮助。另一方面,从float
移动到double
会有很大帮助!
如果这没有帮助,请更具体地说明与预期结果的偏差&#34;。
答案 1 :(得分:1)
m_maxIterations
是static const int
变量,因此可以将其视为该类型的固有属性。通常通过特定的模板参数来改变这种类型属性。但是,在这种情况下,它被设置为常数30
,因此无法实现。
因此,您唯一的选择是更改头文件中的值并重新编译您的程序。
然而,在此之前,我会尝试Singular Value Decomposition。根据主页,它的准确性是&#34;优秀的证明&#34;。此外,它可以克服由于数值上不完全对称的矩阵引起的问题。
答案 2 :(得分:1)
我通过编写改编自Book Numerical Recipes的Jacobi算法解决了这个问题:
void ROTATy(MatrixXd &a, int i, int j, int k, int l, double s, double tau)
{
double g,h;
g=a(i,j);
h=a(k,l);
a(i,j)=g-s*(h+g*tau);
a(k,l)=h+s*(g-h*tau);
}
void jacoby(int n, MatrixXd &a, MatrixXd &v, VectorXd &d )
{
int j,iq,ip,i;
double tresh,theta,tau,t,sm,s,h,g,c;
VectorXd b(n);
VectorXd z(n);
v.setIdentity();
z.setZero();
for (ip=0;ip<n;ip++)
{
d(ip)=a(ip,ip);
b(ip)=d(ip);
}
for (i=0;i<50;i++)
{
sm=0.0;
for (ip=0;ip<n-1;ip++)
{
for (iq=ip+1;iq<n;iq++)
sm += fabs(a(ip,iq));
}
if (sm == 0.0) {
break;
}
if (i < 3)
tresh=0.2*sm/(n*n);
else
tresh=0.0;
for (ip=0;ip<n-1;ip++)
{
for (iq=ip+1;iq<n;iq++)
{
g=100.0*fabs(a(ip,iq));
if (i > 3 && (fabs(d(ip))+g) == fabs(d[ip]) && (fabs(d[iq])+g) == fabs(d[iq]))
a(ip,iq)=0.0;
else if (fabs(a(ip,iq)) > tresh)
{
h=d(iq)-d(ip);
if ((fabs(h)+g) == fabs(h))
{
t=(a(ip,iq))/h;
}
else
{
theta=0.5*h/(a(ip,iq));
t=1.0/(fabs(theta)+sqrt(1.0+theta*theta));
if (theta < 0.0)
{
t = -t;
}
c=1.0/sqrt(1+t*t);
s=t*c;
tau=s/(1.0+c);
h=t*a(ip,iq);
z(ip)=z(ip)-h;
z(iq)=z(iq)+h;
d(ip)=d(ip)- h;
d(iq)=d(iq) + h;
a(ip,iq)=0.0;
for (j=0;j<ip;j++)
ROTATy(a,j,ip,j,iq,s,tau);
for (j=ip+1;j<iq;j++)
ROTATy(a,ip,j,j,iq,s,tau);
for (j=iq+1;j<n;j++)
ROTATy(a,ip,j,iq,j,s,tau);
for (j=0;j<n;j++)
ROTATy(v,j,ip,j,iq,s,tau);
}
}
}
}
}
}
函数jacoby接收方形矩阵n的大小,我们想要计算的矩阵(a)和将在每列中接收特征向量的矩阵以及将要接收的特征向量的向量特征值。它有点慢,所以我尝试将它与OpenMp并行化(参见:Parallelization of Jacobi algorithm using eigen c++ using openmp),但是对于4096x4096大小的矩阵,我并不意味着计算时间有所改善。