JAMA没有计算正确的特征向量

时间:2014-05-01 16:25:42

标签: java jama

我有以下矩阵,它是对称且真实的(它是一个汉密尔顿算子): (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

1 个答案:

答案 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;
}