From 7767e4a63bd258b5853c7827d42a2c95fac836da Mon Sep 17 00:00:00 2001 From: cnr-isti-vclab Date: Mon, 18 Oct 2004 08:25:28 +0000 Subject: [PATCH] Added SingularValueDecomposition method --- vcg/math/lin_algebra.h | 263 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 3 deletions(-) diff --git a/vcg/math/lin_algebra.h b/vcg/math/lin_algebra.h index bd301f7b..90e50a6f 100644 --- a/vcg/math/lin_algebra.h +++ b/vcg/math/lin_algebra.h @@ -13,7 +13,7 @@ namespace vcg * \param nrot returns the number of Jacobi rotations that were required. */ template - static void Jacobi(Matrix44 &w, Point4 &d, Matrix44 &v, int &nrot) + static void Jacobi(Matrix44 &w, Point4 &d, Matrix44 &v, int &nrot) { int j,iq,ip,i; //assert(w.IsSymmetric()); @@ -112,15 +112,259 @@ namespace vcg /*! * Given a matrix Am×n, this routine computes its singular value decomposition, * i.e. A=U·W·VT. The matrix A will be destroyed! - * \param A ... + * (This is the implementation described in Numerical Recipies). + * \param A the matrix to be decomposed * \param W the diagonal matrix of singular values W, stored as a vector W[1...N] * \param V the matrix V (not the transpose VT) + * \param max_iters max iteration number (default = 30). + * \return */ template - static void SingularValueDecomposition(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType *W, MATRIX_TYPE &V) + static bool SingularValueDecomposition(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType *W, MATRIX_TYPE &V, const int max_iters = 30) { typedef typename MATRIX_TYPE::ScalarType ScalarType; + int m = (int) A.RowsNumber(); + int n = (int) A.ColumnsNumber(); + int flag,i,its,j,jj,k,l,nm; + double anorm, c, f, g, h, s, scale, x, y, z, *rv1; + bool convergence = true; + rv1 = new double[n]; + g = scale = anorm = 0; + // Householder reduction to bidiagonal form. + for (i=0; i( sqrt(s), f ); + h = f*g - s; + A[i][i]=f-g; + for (j=l; j(sqrt(s),f); + h = f*g - s; + A[i][l] = f-g; + for (k=l; k=0; i--) + { + //Accumulation of right-hand transformations. + if (i < (n-1)) + { + if (g) + { + for (j=l; j=0; i--) + { + l = i+1; + g = W[i]; + for (j=l; j=0; k--) + { + for (its=1; its<=max_iters; its++) + { + flag=1; + for (l=k; l>=0; l--) + { + // Test for splitting. + nm=l-1; + // Note that rv1[1] is always zero. + if ((double)(fabs(rv1[l])+anorm) == anorm) + { + flag=0; + break; + } + if ((double)(fabs(W[nm])+anorm) == anorm) + break; + } + if (flag) + { + c=0.0; //Cancellation of rv1[l], if l > 1. + s=1.0; + for (i=l ;i<=k; i++) + { + f = s*rv1[i]; + rv1[i] = c*rv1[i]; + if ((double)(fabs(f)+anorm) == anorm) + break; + g = W[i]; + h = pythagora< double >(f,g); + W[i] = h; + h = 1.0/h; + c = g*h; + s = -f*h; + for (j=0; j(f,1.0); + f=((x-z)*(x+z) + h*((y/(f+sign(g,f)))-h))/x; + c=s=1.0; + //Next QR transformation: + for (j=l; j<= nm;j++) + { + i = j+1; + g = rv1[i]; + y = W[i]; + h = s*g; + g = c*g; + z = pythagora(f,h); + rv1[j] = z; + c = f/z; + s = h/z; + f = x*c + g*s; + g = g*c - x*s; + h = y*s; + y *= c; + for (jj=0; jj(f,h); + W[j] = z; + // Rotation can be arbitrary if z = 0. + if (z) + { + z = 1.0/z; + c = f*z; + s = h*z; + } + f = c*g + s*y; + x = c*y - s*g; + for (jj=0; jj + inline TYPE sign(TYPE a, TYPE b) + { + return (b >= 0.0 ? fabs(a) : -fabs(a)); + }; + + template + inline TYPE sqr(TYPE a) + { + TYPE sqr_arg = a; + return (sqr_arg == 0 ? 0 : sqr_arg*sqr_arg); + } + /*! @} */ }; // end of namespace \ No newline at end of file