Search code examples
javamathmatrixjama

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?


Solution

  • 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 = USV'.

    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.