简体   繁体   中英

java jama matrix problem

I am using jama to calculate SVD. It work very good. If i pass square matrix. For example 2x2 or 3x3 etc. matrix. But when I pass some thing like this 2x3 or 4x8 it give error . I used all of their example. They have different constructor to perform the job. Also my second question is, I am usded 3x3 matrix and it gave

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

It produced following error:

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

After that I thaught to use another constructor that is as follow

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

It produced following output:

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

It worked for non square matrix. But it produced wrong results for svd because V and S doesn't have same rows=4 ( I am sorry if i couldn't analyze result properly as i am new for SVD) . Any idea? What should I do?

Be careful here, JAMA supports SVD primarily for full rank matrices, and if you read the "readme" you'll notice that the behavior is not necessarily correct for rank deficient (m < n) matrices.

In essence, what causes your ArrayIndexOutOfBounds exception is line 486 in SingularValueDecomposition :

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

Changing this to:

return new Matrix(U);

will solve the problem. Ultimate what happens under the covers (at least for vicatcu's example) is that you inject a matrix with m=4 and n=5 , but notice in the actual output U has dimensions m=4 and n=4 . If you read the top of the SingularValueDecomposition class it states:

For an m-by-n matrix A with m >= n, the singular value decomposition is an m-by-n orthogonal matrix U, an n-by-n diagonal matrix S, and an n-by-n orthogonal matrix V so that A = U S V'.

But this doesn't hold in this case, because m=4 and n=5 means m<n . So now since you're passing a rank deficient matrix U has different dimensions than the normal calling case of the SVD class, and as such the statement:

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

will create a matrix with assumed rows of m , here 4 (which is correct) and assumed columns n , here Math.min(4+1,5)=5 (which is incorrect). So: when you go print the matrix and the print routine calls getColumnDimension , the U matrix returns 5 , which is greater than the actual backing array dimension.

In short, switching to the line I pasted above will detect the dimensions of U, and as such return a valid result regardless of the rank.

Read the wiki article on SVD . The following code is representative of the example in Section 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());
    } 
} 

and yields the outputL:

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 

Hope this helps. Also, FWIW here is Matlab's output on the same problem:

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

With regards to your first question, the following code produces no error:

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

    }
}

So something else you're doing must be causing it to have an exception. Try using my printMatrix method in place of whatever you are using and see if it helps.

Jama don't support full SVD but only reduced SVD. It's equivalent Matlab svd(B,0) or svd(B,'econ'). Bye

The dimensions of U, S and V do not need to be the same dimensions as A. U will have the same number of rows and V^T will have the same number of columns. That is sufficient to recreate A by the rules of matrix multiplication.

The other dimension (columns of U, rows of V^T and rows/columns of S) will be the "rank" of A (in your example 3). This is, roughly speaking, the dimensionality of your data...how many axes are needed to uniquely represent a column or row in A. It will be at most min(rows, cols) but can often be much less. That is ok.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM