簡體   English   中英

JAMA沒有計算正確的特征向量

[英]JAMA is not calculating the right eigen vectors

我有以下對稱且實的矩陣(它是漢密爾頓運算符):(適用於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、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]

如果我使用這些值制作一個JAMA矩陣,然后執行特征值分解,則V * D * transpose(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 * transpose(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

如果僅關於矩陣的值:是正確的。

編輯:以上語句是將結果矩陣插入到原始問題之前編寫的。 當然,這個矩陣是正確的。 根據評論,似乎此錯誤矩陣是由較舊的JAMA版本中的某些錯誤引起的。 使用JAMA 1.0.3可以正常工作。 但是,此答案的其余部分仍然有效,並且與該問題相關:

這里有兩個問題。 首先,不會重寫JAMA Matrix類的equals方法來比較矩陣的內容 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 (有些人會推薦有關每位計算機科學家應該了解的有關浮點算法的文章 ,但這確實涉及其中……)。

這個小例子可以很容易地重現基本問題:

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由於浮點錯誤。

緩解此問題的一種方法是檢查某些值是否“等於小ε”。 這可能仍然很棘手,因為要比較的值的大小會在這里有所不同,但是一種解決方案可能是使用以下方法比較矩陣以求出ε等式:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM