3

我正在使用jama来计算 SVD。它工作得很好。如果我通过方阵。例如 2x2 或 3x3 等矩阵。但是当我通过像这样的 2x3 或 4x8 的东西时,它会给出错误。我用了他们所有的例子。他们有不同的构造函数来执行这项工作。另外我的第二个问题是,我使用了 3x3 矩阵,它给出了

double[][] vals = {{1.,1.,0},{1.,0.,1.},{1.,3.,4.},{6.,4.,8.}};
  Matrix A = new Matrix(vals);

它产生了以下错误:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3

之后,我想使用另一个构造函数,如下所示

double[][] vals = {{1.,1.,0,4},{1.,0.,1.,2},{1.,3.,4.,8},{1.,3.,4.,8}};
  Matrix A = new Matrix(vals,4,3);

它产生以下输出:

A = 
 1.0 1.0 0.0
 1.0 0.0 1.0
 1.0 3.0 4.0
 6.0 4.0 8.0

A = U S V^T

U = 
 0.078 -0.115 -0.963
 0.107 -0.281 0.260
 0.402 0.886 -0.018
 0.906 -0.351 0.060

Sigma = 
 11.861881 0.000000 0.000000
 0.000000 2.028349 0.000000
 0.000000 0.000000 1.087006

V = 
 0.507705 -0.795196 -0.331510
 0.413798 0.562579 -0.715735
 0.755650 0.226204 0.614675

rank = 3
condition number = 10.912437186202627
2-norm = 11.86188091889931
singular values = 
 11.861881 2.028349 1.087006

它适用于非方阵。但它为 svd 产生了错误的结果,因为 V 和 S 没有相同的 rows=4 (如果我无法正确分析结果,我很抱歉,因为我是 SVD 的新手)。任何的想法?我该怎么办?

4

4 回答 4

4

请注意,JAMA 主要支持满秩矩阵的 SVD,如果您阅读“自述文件”,您会注意到该行为对于秩不足 (m < n) 矩阵不一定正确。

本质上,导致 ArrayIndexOutOfBounds 异常的原因是第 486 行SingularValueDecomposition

return new Matrix(U,m,Math.min(m+1,n));

将其更改为:

return new Matrix(U);

将解决问题。最终在幕后发生的事情(至少对于vicatcu的例子)是你用m=4and注入一个矩阵n=5,但是在实际输出中注意U有尺寸m=4and n=4。如果您阅读课程的顶部,SingularValueDecomposition它会指出:

对于 m >= n 的 m×n 矩阵 A,奇异值分解为 m×n 正交矩阵 U、n×n 对角矩阵 S 和 n×n 正交矩阵 V使得 A = U S V'。

但这在这种情况下并不成立,因为m=4n=5意味着m<n。所以现在因为你传递一个秩亏矩阵 U 具有与SVD 类的正常调用情况不同的维度,因此声明:

new Matrix(U, m, Math.min(m+1,n))

将创建一个矩阵,假设行为m,此处为 4(正确),假设列为n,此处Math.min(4+1,5)=5(不正确)。所以:当您打印矩阵并且打印例程调用getColumnDimension时,U 矩阵返回5,它大于实际的后备数组维度。

简而言之,切换到我上面粘贴的行将检测 U 的尺寸,因此无论排名如何都会返回有效结果。

于 2010-01-18T19:53:27.543 回答
1

阅读关于 SVD 的 wiki 文章。以下代码代表第 2 节中的示例。

import Jama.Matrix; 
import Jama.SingularValueDecomposition; 

public class JAMATest { 

    static public void printMatrix(Matrix m){
        double[][] d = m.getArray();

        for(int row = 0; row < d.length; row++){
            for(int col = 0; col < d[row].length; col++){
                System.out.printf("%6.4f\t", m.get(row, col));
            }
            System.out.println();
        }
        System.out.println();
    }

    public static void main(String[] args) { 
        double[][] vals = { {1., 0., 0., 0., 2.}, 
                            {0., 0., 3., 0., 0.}, 
                            {0., 0., 0., 0., 0.}, 
                            {0., 4., 0., 0., 0.} 
                          };  
        Matrix A = new Matrix(vals);         
        SingularValueDecomposition svd = new SingularValueDecomposition(A); 

        System.out.println("A = ");
        printMatrix(A);

        System.out.println("U = ");
        printMatrix(svd.getU());

        System.out.println("Sigma = ");
        printMatrix(svd.getS());

        System.out.println("V = ");
        printMatrix(svd.getV());
    } 
} 

并产生输出L:

A = 
1.0000  0.0000  0.0000  0.0000  2.0000  
0.0000  0.0000  3.0000  0.0000  0.0000  
0.0000  0.0000  0.0000  0.0000  0.0000  
0.0000  4.0000  0.0000  0.0000  0.0000  

U = 
0.0000  0.0000  -1.0000 0.0000  
0.0000  1.0000  -0.0000 0.0000  
0.0000  0.0000  -0.0000 1.0000  
1.0000  0.0000  -0.0000 0.0000  

Sigma = 
4.0000  0.0000  0.0000  0.0000  0.0000  
0.0000  3.0000  0.0000  0.0000  0.0000  
0.0000  0.0000  2.2361  0.0000  0.0000  
0.0000  0.0000  0.0000  0.0000  0.0000  
0.0000  0.0000  0.0000  0.0000  0.0000  

V = 
0.0000  -0.0000 -0.4472 -0.8944 -0.0000 
0.0000  -0.0000 -0.0000 -0.0000 -0.0000 
0.0000  1.0000  -0.0000 -0.0000 -0.0000 
0.0000  -0.0000 -0.0000 -0.0000 1.0000  
1.0000  -0.0000 -0.8944 0.4472  -0.0000 

希望这可以帮助。此外,这里的 FWIW 是 Matlab 对同一问题的输出:

>> A = [1.0000,  0.0000,  0.0000,  0.0000,  2.0000; 0, 0, 3, 0, 0; 0, 0, 0, 0, 0; 0, 4, 0, 0, 0];
>> A

A =

     1     0     0     0     2
     0     0     3     0     0
     0     0     0     0     0
     0     4     0     0     0

>> [U, S, V] = svd(A);
>> U

U =

     0     0     1     0
     0     1     0     0
     0     0     0    -1
     1     0     0     0

>> S

S =

    4.0000         0         0         0         0
         0    3.0000         0         0         0
         0         0    2.2361         0         0
         0         0         0         0         0

>> V

V =

         0         0    0.4472         0   -0.8944
    1.0000         0         0         0         0
         0    1.0000         0         0         0
         0         0         0    1.0000         0
         0         0    0.8944         0    0.4472

关于您的第一个问题,以下代码不会产生错误:

import Jama.Matrix;

public class JAMATest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        double[][] vals = {{1.,1.,0},{1.,0.,1.},{1.,3.,4.},{6.,4.,8.}}; 
        Matrix A = new Matrix(vals); 

    }
}

因此,您正在做的其他事情一定会导致它出现异常。尝试使用我的 printMatrix 方法代替您正在使用的任何方法,看看它是否有帮助。

于 2010-01-18T17:55:09.360 回答
0

U、S 和 V 的维度不必与 A 的维度相同。U 将具有相同的行数,V^T 将具有相同的列数。这足以通过矩阵乘法规则重新创建 A。

另一个维度(U 的列、V^T 的行和 S 的行/列)将是 A 的“等级”(在您的示例 3 中)。粗略地说,这就是数据的维数……需要多少个轴才能唯一地表示 A 中的列或行。它最多min(rows, cols)但通常可以少得多。那没问题。

于 2010-01-18T19:16:16.593 回答
0

Jama 不支持完整的 SVD,但只支持减少的 SVD。它等效于 Matlab svd(B,0) 或 svd(B,'econ')。再见

于 2013-10-23T12:35:08.530 回答