public inbox for gsl-discuss@sourceware.org
 help / color / mirror / Atom feed
* Re: Problem with Singular Value Decomposition Algorithm
@ 2001-12-19 13:20 Jim Love
  2001-12-19 13:20 ` Brian Gough
  0 siblings, 1 reply; 15+ messages in thread
From: Jim Love @ 2001-12-19 13:20 UTC (permalink / raw)
  To: jt; +Cc: gsl-discuss

In every text that I have read dealing with the process of SVD, they have always placed the eigenvalues in a decreasing order.  The stated reason is to provide a standard solution and methodology.  Why would anybody build an API that does something different??  If you are using the SVD to find the least squares fit of a plane or a cylinder for example, order matters (if you want the right answer hehehe).  Yes I can add to my code to re-order the output, but so will most everybody else that uses this function.  So it should be done in the API.  Just a suggestion.

James A. Love
X4477
Pager 1-800-286-1188 Pin# 400659

>>> James Theiler <jt@lanl.gov> 09/12/01 10:51AM >>>
On Wed, 12 Sep 2001, Jim Love wrote:

] I have downloaded the latest beta release and the SVD algorithm
] produces the wrong answers.  It appears that columns are swapped
] in the output and possibly a sign problem.
]
] Here was my test array:
]
] 1 1 0.975
] 1 -1 0.975
] -1 -1 -0.925
] -1 1 -1.025
]
] The correct answer for the S vector is:  2.7940 2.0000 0.0358
] The gls output was: 2.0000 2.7940 0.0358
]
] The Correct Q matrix is:
]
] -0.7155    0.0256   -0.6981
]     0.0183    0.9997    0.0179
]    -0.6983   -0.0000    0.7158
]
] The gls output was:
]
] -0.025633 -0.715538 -0.698103
] -0.999671 0.018347 0.017900
] -0.000000 -0.698332 0.715774
]
] A similar problem was seen in the U matrix.
]
] Any ideas?  Is this caused by my implementation or is it a real bug?

I don't believe this is a bug at all.
Both answers are correct.  For SVD, the algorithm is
asked to find matrices U,S,Q such that U.S.Q' equals
the original matrix.  If you swap the columns of Q
and swap the equivalent rows of U, and also swap the
corresponding elements of S, you have another solution.

Also if you multiply one of the columns of Q by -1,
and multiply the corresponding row of U by -1, you
will get another equivalent solution.

Sometimes you want the solution with the eigenvalues (the
diagonal elements of the S matrix -- represented as a vector)
sorted numerically, as the one you cite as "correct" but
that is a convenience that can be performed after the fact.
And in fact, I notice that the documentation says that
eigenvalues are "generally chosen" to form a non-decreasing
sequence.  Maybe worth a sentence to say that these algorithms
do not always do that, or else add a utility that does this
postprocessing step.

jt

---------------------------------------------
James Theiler                     jt@lanl.gov 
MS-D436, NIS-2, LANL        tel: 505/665-5682
Los Alamos, NM 87545        fax: 505/665-4414
----- Space and Remote Sensing Sciences -----




^ permalink raw reply	[flat|nested] 15+ messages in thread
* Re: Problem with Singular Value Decomposition Algorithm
@ 2001-12-19 13:20 Jim Love
  2001-12-19 13:20 ` James Theiler
  0 siblings, 1 reply; 15+ messages in thread
From: Jim Love @ 2001-12-19 13:20 UTC (permalink / raw)
  To: bjg; +Cc: <

I guess the best way to explain this is via a physical example.  If I have a plane that is tilted some angle about the Y-axis and I make 4 measurements of the distance from the xy plane to the surface at 4 points.  

1,1 I get 1
1,-1 I get 1
-1, -1 I get -0.9
-1, 1 I get -1

You can then process the data to set up the least square fit to find the "best fit" plane by making a matrix:

x1-mean(x) y1-mean(y) z1-mean(z)
x2-mean(x) y2-mean(y) z2-mean(z)
x3-mean(x) y3-mean(y) z3-mean(z)
x4-mean(x) y4-mean(y) z4-mean(z)

so in this example you would have

1.000000 1.000000 0.975000
1.000000 -1.000000 0.975000
-1.000000 -1.000000 -0.925000
-1.000000 1.000000 -1.025000

find the svd of this matrix.

The solution of the problem is the vector from v the corresponds to the smallest eigenvalue

in our case:

min eigenvalue =  0.035791

the vector from v is -0.698332 -0.000000 0.715774

the equation of a plane is 

a(x-xo) + b(y-yo) + c(z-zo) = 0

in this case:

a = -0.698332
b = -0.000000
c = 0.715774

therefore

-0.698332*x + -0.000000*y + 0.715774*z = 0

substituting back our initial points we get:

1,1 = 1.000633
1,-1 = 1.000633
-1, -1 = -0.950633
1,-1 = -0.950633

You can see by inspection that this is correct.

Now the solution that you API provides is:

a = -0.698332
b = -0.000000
c = -0.715774

-0.698332*x + -0.000000*y + -0.715774*z = 0

1,1 = -0.950633
1,-1 = -0.950633
-1,-1 = 1.000633
1,-1 = 1.000633

This is clearly not the "best fit" plane to the data and is clearly wrong.  

The sign is not arbitrary for this case or any use of SVD.


James A. Love
X4477
Pager 1-800-286-1188 Pin# 400659

>>> Brian Gough <bjg@network-theory.co.uk> 09/13/01 12:21PM >>>
Columns 2 and 3 have the opposite sign, but this is the arbitrary
minus-sign factor referred to earlier.  The results satisfy m =
u*diag(s)*v' and u'*u = I, v'*v = I numerically --- so the
decomposition looks ok.  Let me know if there's something I missing
here.

regards
Brian Gough

Jim Love writes:
 > This code fixes the order problem of the S vector and the other matrix, but their is still a sign problem. Using this matrix for A:
 > 
 > 1.000000 1.000000 0.975000
 > 1.000000 -1.000000 0.975000
 > -1.000000 -1.000000 -0.925000
 > -1.000000 1.000000 -1.025000
 > 
 > The modified code produces:
 > 
 > s:
 > 2.793961 2.000000 0.035791
 > 
 > This is correct!
 > 
 > For V:
 > 
 > -0.715538 -0.025633 0.698103
 > 0.018347 -0.999671 -0.017900
 > -0.698332 -0.000000 -0.715774
 > 
 > This is NOT correct! 
 > 
 > The correct answer for V is:
 > 
 > -0.7155    0.0256   -0.6981
 >     0.0183    0.9997    0.0179
 >    -0.6983   -0.0000    0.7158
 > 
 > U is also wrong:  the program outputs:
 > 
 > -0.493230 -0.512652 -0.493875
 > -0.506363 0.487019 0.506368
 > 0.480733 0.512652 -0.506047
 > 0.518861 -0.487019 0.493554
 > 
 > The correct U is:
 > 
 > -0.4932    0.5127    0.4939    
 >    -0.5064   -0.4870   -0.5064   
 >     0.4807   -0.5127    0.5060   
 >     0.5189    0.4870   -0.4936   
 > 
 > Note last column missing for both solutions  for U.
 > 

^ permalink raw reply	[flat|nested] 15+ messages in thread
* Re: Problem with Singular Value Decomposition Algorithm
@ 2001-12-19 13:20 Jim Love
  0 siblings, 0 replies; 15+ messages in thread
From: Jim Love @ 2001-12-19 13:20 UTC (permalink / raw)
  To: jt; +Cc: <Brian Gough, <

You have made a mistake,  the equation for a z at point x,y of the "best fit" plane is:

z = (a(x-mean(x))+b(y-mean(y))-c(mean(z)))/-c

so using your values of a,b,c i get

1,1 = -0.975
1,-1 = -1.025

no need to go and calc the others - this is clearly wrong.

James A. Love
X4477
Pager 1-800-286-1188 Pin# 400659

>>> James Theiler <jt@lanl.gov> 09/13/01 03:28PM >>>
i think there may be some confusion about transposes; see below.

jt

On Thu, 13 Sep 2001, Jim Love wrote:

] I guess the best way to explain this is via a physical example.
] If I have a plane that is tilted some angle about the Y-axis and I
] make 4 measurements of the distance from the xy plane to the
] surface at 4 points.
]
] 1,1 I get 1
] 1,-1 I get 1
] -1, -1 I get -0.9
] -1, 1 I get -1
]
] You can then process the data to set up the least square fit to
] find the "best fit" plane by making a matrix:
]
] x1-mean(x) y1-mean(y) z1-mean(z)
] x2-mean(x) y2-mean(y) z2-mean(z)
] x3-mean(x) y3-mean(y) z3-mean(z)
] x4-mean(x) y4-mean(y) z4-mean(z)
]
] so in this example you would have
]
] 1.000000 1.000000 0.975000
] 1.000000 -1.000000 0.975000
] -1.000000 -1.000000 -0.925000
] -1.000000 1.000000 -1.025000
]
] find the svd of this matrix.
]
] The solution of the problem is the vector from v the corresponds
] to the smallest eigenvalue
]
] in our case:
]
] min eigenvalue =  0.035791
]
] the vector from v is -0.698332 -0.000000 0.715774

isn't it 0.698103, -0.017900, -0.715774
ie, the third column and not the third row?

note also, if you use the columns of V
and not the rows, then the sign ambiguity
doesn't matter.

]
] the equation of a plane is
]
] a(x-xo) + b(y-yo) + c(z-zo) = 0
]
] in this case:
]
] a = -0.698332
] b = -0.000000
] c = 0.715774
]
] therefore
]
] -0.698332*x + -0.000000*y + 0.715774*z = 0
]
] substituting back our initial points we get:
]
] 1,1 = 1.000633
] 1,-1 = 1.000633
] -1, -1 = -0.950633
] 1,-1 = -0.950633   <== you mean -1,1 ??

let's see z = zo - [a(x-xo)+b(y-yo)]/c
if i use

a = 0.698103
b = -0.017900
c = -0.715774

then i get

 1  1    0.97530415
 1 -1    1.0253199
-1 -1   -0.92530415
-1  1   -0.97531993

which also seems reasonable to me.



]
] You can see by inspection that this is correct.
]
] Now the solution that you API provides is:
]
] a = -0.698332
] b = -0.000000
] c = -0.715774
]
] -0.698332*x + -0.000000*y + -0.715774*z = 0
]
] 1,1 = -0.950633
] 1,-1 = -0.950633
] -1,-1 = 1.000633
] 1,-1 = 1.000633
]
] This is clearly not the "best fit" plane to the data and is clearly wrong.
]
] The sign is not arbitrary for this case or any use of SVD.
]
]
] James A. Love
] X4477
] Pager 1-800-286-1188 Pin# 400659
]
] >>> Brian Gough <bjg@network-theory.co.uk> 09/13/01 12:21PM >>>
] Columns 2 and 3 have the opposite sign, but this is the arbitrary
] minus-sign factor referred to earlier.  The results satisfy m =
] u*diag(s)*v' and u'*u = I, v'*v = I numerically --- so the
] decomposition looks ok.  Let me know if there's something I missing
] here.
]
] regards
] Brian Gough
]
] Jim Love writes:
]  > This code fixes the order problem of the S vector and the other matrix, but their is still a sign problem. Using this matrix for A:
]  >
]  > 1.000000 1.000000 0.975000
]  > 1.000000 -1.000000 0.975000
]  > -1.000000 -1.000000 -0.925000
]  > -1.000000 1.000000 -1.025000
]  >
]  > The modified code produces:
]  >
]  > s:
]  > 2.793961 2.000000 0.035791
]  >
]  > This is correct!
]  >
]  > For V:
]  >
]  > -0.715538 -0.025633 0.698103
]  > 0.018347 -0.999671 -0.017900
]  > -0.698332 -0.000000 -0.715774
]  >
]  > This is NOT correct!
]  >
]  > The correct answer for V is:
]  >
]  > -0.7155    0.0256   -0.6981
]  >     0.0183    0.9997    0.0179
]  >    -0.6983   -0.0000    0.7158
]  >
]  > U is also wrong:  the program outputs:
]  >
]  > -0.493230 -0.512652 -0.493875
]  > -0.506363 0.487019 0.506368
]  > 0.480733 0.512652 -0.506047
]  > 0.518861 -0.487019 0.493554
]  >
]  > The correct U is:
]  >
]  > -0.4932    0.5127    0.4939
]  >    -0.5064   -0.4870   -0.5064
]  >     0.4807   -0.5127    0.5060
]  >     0.5189    0.4870   -0.4936
]  >
]  > Note last column missing for both solutions  for U.
]  >
]

---------------------------------------------
James Theiler                     jt@lanl.gov 
MS-D436, NIS-2, LANL        tel: 505/665-5682
Los Alamos, NM 87545        fax: 505/665-4414
----- Space and Remote Sensing Sciences -----



^ permalink raw reply	[flat|nested] 15+ messages in thread
* Problem with Singular Value Decomposition Algorithm
@ 2001-12-19 13:20 Jim Love
  2001-12-19 13:20 ` James Theiler
  0 siblings, 1 reply; 15+ messages in thread
From: Jim Love @ 2001-12-19 13:20 UTC (permalink / raw)
  To: gsl-discuss

I have downloaded the latest beta release and the SVD algorithm produces the wrong answers.  It appears that columns are swapped in the output and possibly a sign problem.

Here was my test array:

1 1 0.975
1 -1 0.975
-1 -1 -0.925
-1 1 -1.025

The correct answer for the S vector is:  2.7940 2.0000 0.0358
The gls output was: 2.0000 2.7940 0.0358

The Correct Q matrix is:

-0.7155    0.0256   -0.6981
    0.0183    0.9997    0.0179
   -0.6983   -0.0000    0.7158

The gls output was:

-0.025633 -0.715538 -0.698103
-0.999671 0.018347 0.017900
-0.000000 -0.698332 0.715774

A similar problem was seen in the U matrix.  

Any ideas?  Is this caused by my implementation or is it a real bug?

Here is the source code to the program I made to test the LIB:

#include "stdafx.h"
#include <math.h>
#include <stdio.h>
#include <C:\Program Files\gsl-0-9-2\gsl\gsl_matrix.h>
#include <C:\Program Files\gsl-0-9-2\gsl\gsl_blas.h>
#include <C:\Program Files\gsl-0-9-2\gsl\gsl_linalg.h>


int main(void)
{

  gsl_matrix *a = gsl_matrix_alloc (4, 3);
  gsl_matrix *u = gsl_matrix_alloc (4, 4);
  gsl_matrix *v = gsl_matrix_alloc (3, 3);
  gsl_vector *s = gsl_vector_alloc (3);
  gsl_vector *work = gsl_vector_alloc (3);

  gsl_matrix_set_zero(a);

  gsl_matrix_set (a, 0, 0, 1);
  gsl_matrix_set (a, 0, 1, 1);
  gsl_matrix_set (a, 0, 2, 0.975);
  gsl_matrix_set (a, 1, 0, 1);
  gsl_matrix_set (a, 1, 1, -1);
  gsl_matrix_set (a, 1, 2, 0.975);
  gsl_matrix_set (a, 2, 0, -1);
  gsl_matrix_set (a, 2, 1, -1);
  gsl_matrix_set (a, 2, 2, -0.925);
  gsl_matrix_set (a, 3, 0, -1);
  gsl_matrix_set (a, 3, 1, 1);
  gsl_matrix_set (a, 3, 2, -1.025);


  printf ("%f %f %f \n",gsl_matrix_get (a, 0, 0), gsl_matrix_get (a, 0, 1), gsl_matrix_get (a, 0, 2));
  printf ("%f %f %f \n",gsl_matrix_get (a, 1, 0), gsl_matrix_get (a, 1, 1), gsl_matrix_get (a, 1, 2));
  printf ("%f %f %f \n",gsl_matrix_get (a, 2, 0), gsl_matrix_get (a, 2, 1), gsl_matrix_get (a, 2, 2));
  printf ("%f %f %f \n",gsl_matrix_get (a, 3, 0), gsl_matrix_get (a, 3, 1), gsl_matrix_get (a, 3, 2));

  gsl_linalg_SV_decomp (a, v, s, work);

  printf ("\n");
  printf ("%f %f %f \n",gsl_matrix_get (a, 0, 0), gsl_matrix_get (a, 0, 1), gsl_matrix_get (a, 0, 2));
  printf ("%f %f %f \n",gsl_matrix_get (a, 1, 0), gsl_matrix_get (a, 1, 1), gsl_matrix_get (a, 1, 2));
  printf ("%f %f %f \n",gsl_matrix_get (a, 2, 0), gsl_matrix_get (a, 2, 1), gsl_matrix_get (a, 2, 2));
  printf ("%f %f %f \n",gsl_matrix_get (a, 3, 0), gsl_matrix_get (a, 3, 1), gsl_matrix_get (a, 3, 2));
  

  printf ("\n");
  printf ("%f %f %f \n",gsl_vector_get (s, 0), gsl_vector_get (s, 1), gsl_vector_get (s, 2));

  printf ("\n");
  printf ("%f %f %f \n",gsl_matrix_get (v, 0, 0), gsl_matrix_get (v, 0, 1), gsl_matrix_get (v, 0, 2));
  printf ("%f %f %f \n",gsl_matrix_get (v, 1, 0), gsl_matrix_get (v, 1, 1), gsl_matrix_get (v, 1, 2));
  printf ("%f %f %f \n",gsl_matrix_get (v, 2, 0), gsl_matrix_get (v, 2, 1), gsl_matrix_get (v, 2, 2));
gsl_matrix_free (a);
  gsl_matrix_free (u);
  gsl_matrix_free (v);
  gsl_vector_free (work);
  gsl_vector_free (s);

	return 0;
}

James A. Love
X4477
Pager 1-800-286-1188 Pin# 400659

^ permalink raw reply	[flat|nested] 15+ messages in thread
* Re: Problem with Singular Value Decomposition Algorithm
@ 2001-12-19 13:20 Jim Love
  2001-12-19 13:20 ` Brian Gough
  0 siblings, 1 reply; 15+ messages in thread
From: Jim Love @ 2001-12-19 13:20 UTC (permalink / raw)
  To: bjg; +Cc: gsl-discuss

I still think their is a problem with your API.  I have done this problem using a pencil and paper, using Matlab, using Mathematica, and using the LAPACK DGESVD routine.  These 4 implementations all produce the same exact solution for the U S and Q matrix - only yours is different.  How do you explain this?

James A. Love
X4477
Pager 1-800-286-1188 Pin# 400659

^ permalink raw reply	[flat|nested] 15+ messages in thread
[parent not found: <sba09ba1.005@wiltonhub.svg.com>]
* Re: Problem with Singular Value Decomposition Algorithm
@ 2001-12-19 13:20 Jim Love
  0 siblings, 0 replies; 15+ messages in thread
From: Jim Love @ 2001-12-19 13:20 UTC (permalink / raw)
  To: bjg, gsl-discuss

This code fixes the order problem of the S vector and the other matrix, but their is still a sign problem. Using this matrix for A:

1.000000 1.000000 0.975000
1.000000 -1.000000 0.975000
-1.000000 -1.000000 -0.925000
-1.000000 1.000000 -1.025000

The modified code produces:

s:
2.793961 2.000000 0.035791

This is correct!

For V:

-0.715538 -0.025633 0.698103
0.018347 -0.999671 -0.017900
-0.698332 -0.000000 -0.715774

This is NOT correct! 

The correct answer for V is:

-0.7155    0.0256   -0.6981
    0.0183    0.9997    0.0179
   -0.6983   -0.0000    0.7158

U is also wrong:  the program outputs:

-0.493230 -0.512652 -0.493875
-0.506363 0.487019 0.506368
0.480733 0.512652 -0.506047
0.518861 -0.487019 0.493554

The correct U is:

-0.4932    0.5127    0.4939    
   -0.5064   -0.4870   -0.5064   
    0.4807   -0.5127    0.5060   
    0.5189    0.4870   -0.4936   

Note last column missing for both solutions  for U.



James A. Love
X4477
Pager 1-800-286-1188 Pin# 400659

>>> Brian Gough <bjg@network-theory.co.uk> 09/12/01 06:35PM >>>
Patch below fixes the problem, I'll do more testing on that routine
tomorrow.


Index: svdstep.c
===================================================================
RCS file: /cvs/gsl/gsl/linalg/svdstep.c,v
retrieving revision 1.3
diff -u -r1.3 svdstep.c
--- svdstep.c	2001/08/29 15:37:21	1.3
+++ svdstep.c	2001/09/12 22:33:01
@@ -126,14 +126,14 @@
 
   if (d0 == 0.0)
     {
-      /* Eliminate off-diagonal element in [0,f1;0,d1] */
+      /* Eliminate off-diagonal element in [0,f1;0,d1] to make [d,0;0,0] */
 
       create_givens (f0, d1, &c, &s);
 
-      /* compute B <= G^T B */
+      /* compute B <= G^T B X,  where X = [0,1;1,0] */
 
-      gsl_vector_set (f, 0, c * f0 - s * d1);
-      gsl_vector_set (d, 1, s * f0 + c * d1);
+      gsl_vector_set (d, 0, c * f0 - s * d1);
+      gsl_vector_set (f, 1, s * f0 + c * d1);
       
       /* Compute U <= U G */
 
@@ -145,6 +145,10 @@
 	  gsl_matrix_set (U, i, 1, s * Uip + c * Uiq);
 	}
 
+      /* Compute V <= V X */
+
+      gsl_matrix_swap_columns (V, 0, 1);
+
       return;
     }
   else if (d1 == 0.0)
@@ -194,17 +198,24 @@
           gsl_matrix_set (V, i, 1, s * Vip + c * Viq);
         }
       
-      /* Eliminate off-diagonal elements, work with the column that
-         has the largest norm */
+      /* Eliminate off-diagonal elements, bring column with largest
+         norm to first column */
       
-      if (fabs(a11) + fabs(a21) > fabs(a12) + fabs(a22))
+      if (hypot(a11, a21) < hypot(a12,a22))
         {
-          create_givens (a11, a21, &c, &s);
+          double t1, t2;
+
+          /* B <= B X */
+
+          t1 = a11; a11 = a12; a12 = t1;
+          t2 = a21; a21 = a22; a22 = t2;
+
+          /* V <= V X */
+
+          gsl_matrix_swap_columns(V, 0, 1);
         } 
-      else
-        {
-          create_givens (a22, -a12, &c, &s);
-        }
+
+      create_givens (a11, a21, &c, &s);
       
       /* compute B <= G^T B */
       

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2001-12-19 13:20 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-12-19 13:20 Problem with Singular Value Decomposition Algorithm Jim Love
2001-12-19 13:20 ` Brian Gough
2001-12-19 13:20   ` Brian Gough
  -- strict thread matches above, loose matches on Subject: below --
2001-12-19 13:20 Jim Love
2001-12-19 13:20 ` James Theiler
2001-12-19 13:20   ` Brian Gough
2001-12-19 13:20     ` Peter Schmitteckert
2001-12-19 13:20       ` Brian Gough
2001-12-19 13:20 Jim Love
2001-12-19 13:20 Jim Love
2001-12-19 13:20 ` James Theiler
2001-12-19 13:20 Jim Love
2001-12-19 13:20 ` Brian Gough
     [not found] <sba09ba1.005@wiltonhub.svg.com>
2001-12-19 13:20 ` Brian Gough
2001-12-19 13:20 Jim Love

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).