我有以下矩阵,它是对称且真实的(它是一个汉密尔顿算子): (Matlab友好)
[63.000000,-1.732051,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000; -1.732051,61.000000,-2.000000,0.000000,-1.000000,0.000000,0.000000,0.000000,0.000000,0.000000; 0.000000,-2.000000,61.000000,-1.732051,0.000000,-1.414214,0.000000,0.000000,0.000000,0.000000; 0.000000,0.000000,-1.732051,63.000000,0.000000,0.000000,-1.732051,0.000000,0.000000,0.000000; 0.000000,-1.000000,0.000000,0.000000,6.00.000000,-1.414214,0.000000,0.000000,0.000000,0.000000; 0.000000,0.000000,-1.414214,0.000000,-1.414214,60.000000,-1.414214,-1.414214,0.000000,0.000000; 0.000000,0.000000,0.000000,-1.732051,0.000000,-1.414214,61.000000,0.000000,-2.000000,0.000000; 0.000000,0.000000,0.000000,0.000000,0.000000,-1.414214,0.000000,6.00.000000,-1.000000,0.000000; 0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,-2.000000,-1.000000,61.000000,-1.732051; 0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000,0.000000, -1.732051,63.000000]
如果我用这些值制作JAMA矩阵,并执行特征值分解,则V * D *转置(V)不等于汉密尔顿。你们中的任何人都知道出了什么问题吗?特征值与MATLAB一致,但特征向量不是。
这是一个测试它的类
public class TestJama {
public static void main(String[] args) {
double[][] m = new double[][] {
{63.000000, -1.732051, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000},
{ -1.732051, 61.000000, -2.000000, 0.000000, -1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000},
{ 0.000000, -2.000000, 61.000000, -1.732051, 0.000000, -1.414214, 0.000000, 0.000000, 0.000000, 0.000000},
{ 0.000000, 0.000000, -1.732051, 63.000000, 0.000000, 0.000000, -1.732051, 0.000000, 0.000000, 0.000000},
{ 0.000000, -1.000000, 0.000000, 0.000000, 61.000000, -1.414214, 0.000000, 0.000000, 0.000000, 0.000000},
{ 0.000000, 0.000000, -1.414214, 0.000000, -1.414214, 60.000000, -1.414214, -1.414214, 0.000000, 0.000000},
{ 0.000000, 0.000000, 0.000000, -1.732051, 0.000000, -1.414214, 61.000000, 0.000000, -2.000000, 0.000000},
{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -1.414214, 0.000000, 61.000000, -1.000000, 0.000000},
{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -2.000000, -1.000000, 61.000000, -1.732051},
{ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -1.732051, 63.000000}
};
Matrix hamilton = new Matrix(m);
System.out.println(jamaToString(hamilton));
EigenvalueDecomposition e = hamilton.eig();
System.out.println(jamaToString(e.getD()));
System.out.println(jamaToString(e.getV()));
Matrix recomb = e.getV().times(e.getD()).times(e.getV().transpose());
System.out.println(jamaToString(recomb));
System.out.println(hamilton.equals(recomb));
}
private static String jamaToString(Matrix m) {
StringBuilder b = new StringBuilder();
b.append("[");
for(int i=0; i<m.getRowDimension(); i++) {
for(int j=0; j<m.getColumnDimension(); j++) {
b.append(m.get(i, j));
if(j<m.getColumnDimension() - 1) b.append(",");
}
if(i<m.getRowDimension() - 1) b.append(";");
}
b.append("]");
return b.toString();
}
}
编辑: 结果(V * D *转置(V))产生
63.1093 -0.6379 0.3400 -0.6576 0.0938 -0.0437 -0.6056 -0.5066 0.3463 0.5039 -0.6379 61.3082 -0.2368 -1.7813 -0.0851 0.7949 -0.1337 0.7668 -0.0422 -2.4329 0.3400 -0.2368 60.1481 1.3323 -0.4099 -1.8834 -0.5780 0.7516 0.0946 0.1705 -0.6576 -1.7813 1.3323 61.2455 0.0972 -0.8075 -0.9004 0.0242 0.3963 -1.2527 0.0938 -0.0851 -0.4099 0.0972 60.3086 -0.1899 0.0394 0.1987 -0.0484 -0.1495 -0.0437 0.7949 -1.8834 -0.8075 -0.1899 61.7941 0.3741 0.8237 0.7772 0.7557 -0.6056 -0.1337 -0.5780 -0.9004 0.0394 0.3741 60.6415 0.6351 0.7099 0.3349 -0.5066 0.7668 0.7516 0.0242 0.1987 0.8237 0.6351 62.8108 1.3507 1.3002 0.3463 -0.0422 0.0946 0.3963 -0.0484 0.7772 0.7099 1.3507 63.3270 0.1244 0.5039 -2.4329 0.1705 -1.2527 -0.1495 0.7557 0.3349 1.3002 0.1244 60.3069
答案 0 :(得分:0)
如果它只是矩阵的值:它是正确的。
编辑:上面的陈述是在之前写的,结果矩阵被插入到原始问题中。当然,这个矩阵不正确。根据评论,似乎这个错误的矩阵是由旧的JAMA版本中的一些错误引起的。有了JAMA 1.0.3,它就可以了。尽管如此,这个答案的其余部分仍然有效且与问题相关:
这里有两个问题。首先,不会覆盖JAMA equals
类的Matrix
方法来比较矩阵的内容。 equals
的默认实现比较了引用对象的身份。所以即使是像这样的微不足道的比较
Matrix A = new Matrix(new double[][]{{1.0}});
Matrix B = new Matrix(new double[][]{{1.0}});
System.out.println(A.equals(B));
会打印false
。
第二个问题相当简单(并且很常见):具有double
值的计算不是无限精确的。您可以在StackOverflow上找到许多有关此问题的问题,但可能需要查看Wikipedia about Floating Point Accuracy Problems。 (有些人会推荐关于What Every Computer Scientist Should Know About Floating-Point Arithmetic的文章,但它涉及到......)。
使用这个小例子可以轻松复制基本问题:
double x = 0.1;
double y = 0;
for (int i=0; i<10; i++)
{
y += x;
}
System.out.println(y+" == 1.0: "+(y==1.0));
此计算的结果是不 y==1.0
,而是y==0.99999999999999...
。
所以即使如果覆盖了equals
方法来执行逐元素比较,由于浮点错误,比较仍会产生false
。
缓解这个问题的一种方法是检查某些值是否等于小ε&#34;。这可能仍然很棘手,因为要比较的值的大小在这里会有所不同,但一种解决方案可能是使用以下方法来比较epsilon-equality的矩阵:
private static boolean epsilonEqual(Matrix a, Matrix b)
{
int ra = a.getRowDimension();
int rb = b.getRowDimension();
if (ra != rb)
{
return false;
}
int ca = a.getColumnDimension();
int cb = b.getColumnDimension();
if (ca != cb)
{
return false;
}
for (int c=0; c<ca; c++)
{
for (int r=0; r<ra; r++)
{
double ea = a.get(r, c);
double eb = b.get(r, c);
if (!epsilonEqual(ea, eb))
{
return false;
}
}
}
return true;
}
private static boolean epsilonEqual(double x, double y)
{
final double epsilon = 1e-8;
return Math.abs(x - y) <= epsilon;
}