/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004-2016 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_LINALGEBRA_H #define __VCGLIB_LINALGEBRA_H #include <vcg/math/base.h> #include <vcg/math/matrix44.h> #include <algorithm> #ifndef _YES_I_WANT_TO_USE_DANGEROUS_STUFF #error "Please do not never user this file. Use EIGEN!!!!" #endif namespace vcg { /** \addtogroup math */ /* @{ */ /*! * */ template< typename MATRIX_TYPE > static void JacobiRotate(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType s, typename MATRIX_TYPE::ScalarType tau, int i,int j,int k,int l) { typename MATRIX_TYPE::ScalarType g=A[i][j]; typename MATRIX_TYPE::ScalarType h=A[k][l]; A[i][j]=g-s*(h+g*tau); A[k][l]=h+s*(g-h*tau); }; /*! * Computes all eigenvalues and eigenvectors of a real symmetric matrix . * On output, elements of the input matrix above the diagonal are destroyed. * \param d returns the eigenvalues of a. * \param v is a matrix whose columns contain, the normalized eigenvectors * \param nrot returns the number of Jacobi rotations that were required. */ template <typename MATRIX_TYPE, typename POINT_TYPE> static void Jacobi(MATRIX_TYPE &w, POINT_TYPE &d, MATRIX_TYPE &v, int &nrot) { typedef typename MATRIX_TYPE::ScalarType ScalarType; assert(w.RowsNumber()==w.ColumnsNumber()); int dimension = w.RowsNumber(); int j,iq,ip,i; //assert(w.IsSymmetric()); typename MATRIX_TYPE::ScalarType tresh, theta, tau, t, sm, s, h, g, c; POINT_TYPE b, z; v.SetIdentity(); for (ip=0;ip<dimension;++ip) //Initialize b and d to the diagonal of a. { b[ip]=d[ip]=w[ip][ip]; z[ip]=ScalarType(0.0); //This vector will accumulate terms of the form tapq as in equation (11.1.14). } nrot=0; for (i=0;i<50;i++) { sm=ScalarType(0.0); for (ip=0;ip<dimension-1;++ip) // Sum off diagonal elements { for (iq=ip+1;iq<dimension;++iq) sm += math::Abs(w[ip][iq]); } if (sm == ScalarType(0.0)) //The normal return, which relies on quadratic convergence to machine underflow. { return; } if (i < 4) tresh=ScalarType(0.2)*sm/(dimension*dimension); //...on the first three sweeps. else tresh=ScalarType(0.0); //...thereafter. for (ip=0;ip<dimension-1;++ip) { for (iq=ip+1;iq<dimension;iq++) { g=ScalarType(100.0)*fabs(w[ip][iq]); //After four sweeps, skip the rotation if the off-diagonal element is small. if(i>4 && (float)(fabs(d[ip])+g) == (float)fabs(d[ip]) && (float)(fabs(d[iq])+g) == (float)fabs(d[iq])) w[ip][iq]=ScalarType(0.0); else if (fabs(w[ip][iq]) > tresh) { h=d[iq]-d[ip]; if ((float)(fabs(h)+g) == (float)fabs(h)) t=(w[ip][iq])/h; //t =1/(2#) else { theta=ScalarType(0.5)*h/(w[ip][iq]); //Equation (11.1.10). t=ScalarType(1.0)/(fabs(theta)+sqrt(ScalarType(1.0)+theta*theta)); if (theta < ScalarType(0.0)) t = -t; } c=ScalarType(1.0)/sqrt(ScalarType(1.0)+t*t); s=t*c; tau=s/(ScalarType(1.0)+c); h=t*w[ip][iq]; z[ip] -= h; z[iq] += h; d[ip] -= h; d[iq] += h; w[ip][iq]=ScalarType(0.0); for (j=0;j<=ip-1;j++) { //Case of rotations 1 <= j < p. JacobiRotate<MATRIX_TYPE>(w,s,tau,j,ip,j,iq) ; } for (j=ip+1;j<=iq-1;j++) { //Case of rotations p < j < q. JacobiRotate<MATRIX_TYPE>(w,s,tau,ip,j,j,iq); } for (j=iq+1;j<dimension;j++) { //Case of rotations q< j <= n. JacobiRotate<MATRIX_TYPE>(w,s,tau,ip,j,iq,j); } for (j=0;j<dimension;j++) { JacobiRotate<MATRIX_TYPE>(v,s,tau,j,ip,j,iq); } ++nrot; } } } for (ip=0;ip<dimension;ip++) { b[ip] += z[ip]; d[ip]=b[ip]; //Update d with the sum of ta_pq , z[ip]=0.0; //and reinitialize z. } } }; /*! * Given the eigenvectors and the eigenvalues as output from JacobiRotate, sorts the eigenvalues * into descending order, and rearranges the columns of v correspondinlgy. * \param eigenvalues * \param eigenvector (in columns) * \param absComparison sort according to the absolute values of the eigenvalues. */ template < typename MATRIX_TYPE, typename POINT_TYPE > void SortEigenvaluesAndEigenvectors(POINT_TYPE &eigenvalues, MATRIX_TYPE &eigenvectors, bool absComparison = false) { assert(eigenvectors.ColumnsNumber()==eigenvectors.RowsNumber()); int dimension = eigenvectors.ColumnsNumber(); int i, j, k; float p,q; for (i=0; i<dimension-1; i++) { if (absComparison) { p = fabs(eigenvalues[k=i]); for (j=i+1; j<dimension; j++) if ((q=fabs(eigenvalues[j])) >= p) { p = q; k = j; } p = eigenvalues[k]; } else { p = eigenvalues[ k=i ]; for (j=i+1; j<dimension; j++) if (eigenvalues[j] >= p) p = eigenvalues[ k=j ]; } if (k != i) { eigenvalues[k] = eigenvalues[i]; // i.e. eigenvalues[i] = p; // swaps the value of the elements i-th and k-th for (j=0; j<dimension; j++) { p = eigenvectors[j][i]; // i.e. eigenvectors[j][i] = eigenvectors[j][k]; // swaps the eigenvectors stored in the eigenvectors[j][k] = p; // i-th and the k-th column } } } }; template <typename TYPE> inline static TYPE sqr(TYPE a) { TYPE sqr_arg = a; return (sqr_arg == 0 ? 0 : sqr_arg*sqr_arg); } // Computes (a^2 + b^2)^(1/2) without destructive underflow or overflow. template <typename TYPE> inline static TYPE pythagora(TYPE a, TYPE b) { TYPE abs_a = fabs(a); TYPE abs_b = fabs(b); if (abs_a > abs_b) return abs_a*sqrt((TYPE)1.0+sqr(abs_b/abs_a)); else return (abs_b == (TYPE)0.0 ? (TYPE)0.0 : abs_b*sqrt((TYPE)1.0+sqr(abs_a/abs_b))); } template <typename TYPE> inline static TYPE sign(TYPE a, TYPE b) { return (b >= 0.0 ? fabs(a) : -fabs(a)); } /*! * */ enum SortingStrategy {LeaveUnsorted=0, SortAscending=1, SortDescending=2}; template< typename MATRIX_TYPE > void Sort(MATRIX_TYPE &U, typename MATRIX_TYPE::ScalarType W[], MATRIX_TYPE &V, const SortingStrategy sorting) ; /*! * Given a matrix <I>A<SUB>mxn</SUB></I>, this routine computes its singular value decomposition, * i.e. <I>A=UxWxV<SUP>T</SUP></I>. The matrix <I>A</I> will be destroyed! * (This is the implementation described in <I>Numerical Recipies</I>). * \param A the matrix to be decomposed * \param W the diagonal matrix of singular values <I>W</I>, stored as a vector <I>W[1...N]</I> * \param V the matrix <I>V</I> (not the transpose <I>V<SUP>T</SUP></I>) * \param max_iters max iteration number (default = 30). * \return */ template <typename MATRIX_TYPE> static bool SingularValueDecomposition(MATRIX_TYPE &A, typename MATRIX_TYPE::ScalarType *W, MATRIX_TYPE &V, const SortingStrategy sorting=LeaveUnsorted, 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; ScalarType anorm, c, f, g, h, s, scale, x, y, z, *rv1; bool convergence = true; rv1 = new ScalarType[n]; g = scale = anorm = 0; // Householder reduction to bidiagonal form. for (i=0; i<n; i++) { l = i+1; rv1[i] = scale*g; g = s = scale = 0.0; if (i < m) { for (k = i; k<m; k++) scale += fabs(A[k][i]); if (scale) { for (k=i; k<m; k++) { A[k][i] /= scale; s += A[k][i]*A[k][i]; } f=A[i][i]; g = -sign<ScalarType>( sqrt(s), f ); h = f*g - s; A[i][i]=f-g; for (j=l; j<n; j++) { for (s=0.0, k=i; k<m; k++) s += A[k][i]*A[k][j]; f = s/h; for (k=i; k<m; k++) A[k][j] += f*A[k][i]; } for (k=i; k<m; k++) A[k][i] *= scale; } } W[i] = scale *g; g = s = scale = 0.0; if (i < m && i != (n-1)) { for (k=l; k<n; k++) scale += fabs(A[i][k]); if (scale) { for (k=l; k<n; k++) { A[i][k] /= scale; s += A[i][k]*A[i][k]; } f = A[i][l]; g = -sign<ScalarType>(sqrt(s),f); h = f*g - s; A[i][l] = f-g; for (k=l; k<n; k++) rv1[k] = A[i][k]/h; for (j=l; j<m; j++) { for (s=0.0, k=l; k<n; k++) s += A[j][k]*A[i][k]; for (k=l; k<n; k++) A[j][k] += s*rv1[k]; } for (k=l; k<n; k++) A[i][k] *= scale; } } anorm=std::max( anorm, (math::Abs(W[i])+math::Abs(rv1[i])) ); } // Accumulation of right-hand transformations. for (i=(n-1); i>=0; i--) { //Accumulation of right-hand transformations. if (i < (n-1)) { if (g) { for (j=l; j<n;j++) //Double division to avoid possible underflow. V[j][i]=(A[i][j]/A[i][l])/g; for (j=l; j<n; j++) { for (s=0.0, k=l; k<n; k++) s += A[i][k] * V[k][j]; for (k=l; k<n; k++) V[k][j] += s*V[k][i]; } } for (j=l; j<n; j++) V[i][j] = V[j][i] = 0.0; } V[i][i] = 1.0; g = rv1[i]; l = i; } // Accumulation of left-hand transformations. for (i=std::min(m,n)-1; i>=0; i--) { l = i+1; g = W[i]; for (j=l; j<n; j++) A[i][j]=0.0; if (g) { g = (ScalarType)1.0/g; for (j=l; j<n; j++) { for (s=0.0, k=l; k<m; k++) s += A[k][i]*A[k][j]; f = (s/A[i][i])*g; for (k=i; k<m; k++) A[k][j] += f*A[k][i]; } for (j=i; j<m; j++) A[j][i] *= g; } else for (j=i; j<m; j++) A[j][i] = 0.0; ++A[i][i]; } // Diagonalization of the bidiagonal form: Loop over // singular values, and over allowed iterations. for (k=(n-1); k>=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<ScalarType>(f,g); W[i] = h; h = (ScalarType)1.0/h; c = g*h; s = -f*h; for (j=0; j<m; j++) { y = A[j][nm]; z = A[j][i]; A[j][nm] = y*c + z*s; A[j][i] = z*c - y*s; } } } z = W[k]; if (l == k) //Convergence. { if (z < 0.0) { // Singular value is made nonnegative. W[k] = -z; for (j=0; j<n; j++) V[j][k] = -V[j][k]; } break; } if (its == max_iters) { convergence = false; } x = W[l]; // Shift from bottom 2-by-2 minor. nm = k-1; y = W[nm]; g = rv1[nm]; h = rv1[k]; f = ((y-z)*(y+z) + (g-h)*(g+h))/((ScalarType)2.0*h*y); g = pythagora<ScalarType>(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<ScalarType>(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<n; jj++) { x = V[jj][j]; z = V[jj][i]; V[jj][j] = x*c + z*s; V[jj][i] = z*c - x*s; } z = pythagora<ScalarType>(f,h); W[j] = z; // Rotation can be arbitrary if z = 0. if (z) { z = (ScalarType)1.0/z; c = f*z; s = h*z; } f = c*g + s*y; x = c*y - s*g; for (jj=0; jj<m; jj++) { y = A[jj][j]; z = A[jj][i]; A[jj][j] = y*c + z*s; A[jj][i] = z*c - y*s; } } rv1[l] = 0.0; rv1[k] = f; W[k] = x; } } delete []rv1; if (sorting!=LeaveUnsorted) Sort<MATRIX_TYPE>(A, W, V, sorting); return convergence; }; /*! * Sort the singular values computed by the <CODE>SingularValueDecomposition</CODE> procedure and * modify the matrices <I>U</I> and <I>V</I> accordingly. */ // TODO modify the last parameter type template< typename MATRIX_TYPE > void Sort(MATRIX_TYPE &U, typename MATRIX_TYPE::ScalarType W[], MATRIX_TYPE &V, const SortingStrategy sorting) { typedef typename MATRIX_TYPE::ScalarType ScalarType; assert(U.ColumnsNumber()==V.ColumnsNumber()); int mu = U.RowsNumber(); int mv = V.RowsNumber(); int n = U.ColumnsNumber(); //ScalarType* u = &U[0][0]; //ScalarType* v = &V[0][0]; for (int i=0; i<n; i++) { int k = i; ScalarType p = W[i]; switch (sorting) { case SortAscending: { for (int j=i+1; j<n; j++) { if (W[j] < p) { k = j; p = W[j]; } } break; } case SortDescending: { for (int j=i+1; j<n; j++) { if (W[j] > p) { k = j; p = W[j]; } } break; } case LeaveUnsorted: break; // nothing to do. } if (k != i) { W[k] = W[i]; // i.e. W[i] = p; // swaps the i-th and the k-th elements int j = mu; //ScalarType* uji = u + i; // uji = &U[0][i] //ScalarType* ujk = u + k; // ujk = &U[0][k] //ScalarType* vji = v + i; // vji = &V[0][i] //ScalarType* vjk = v + k; // vjk = &V[0][k] //if (j) //{ // for(;;) for( ; j!=0; --j, uji+=n, ujk+=n) // { { // p = *uji; p = *uji; // i.e. // *uji = *ujk; *uji = *ujk; // swap( U[s][i], U[s][k] ) // *ujk = p; *ujk = p; // // if (!(--j)) } // break; // uji += n; // ujk += n; // } //} for(int s=0; j!=0; ++s, --j) std::swap(U[s][i], U[s][k]); j = mv; //if (j!=0) //{ // for(;;) for ( ; j!=0; --j, vji+=n, ujk+=n) // { { // p = *vji; p = *vji; // i.e. // *vji = *vjk; *vji = *vjk; // swap( V[s][i], V[s][k] ) // *vjk = p; *vjk = p; // // if (!(--j)) } // break; // vji += n; // vjk += n; // } //} for (int s=0; j!=0; ++s, --j) std::swap(V[s][i], V[s][k]); } } } /*! * Solves AxX = B for a vector X, where A is specified by the matrices <I>U<SUB>mxn</SUB></I>, * <I>W<SUB>nx1</SUB></I> and <I>V<SUB>nxn</SUB></I> as returned by <CODE>SingularValueDecomposition</CODE>. * No input quantities are destroyed, so the routine may be called sequentially with different bxs. * \param x is the output solution vector (<I>x<SUB>nx1</SUB></I>) * \param b is the input right-hand side (<I>b<SUB>nx1</SUB></I>) */ template <typename MATRIX_TYPE> static void SingularValueBacksubstitution(const MATRIX_TYPE &U, const typename MATRIX_TYPE::ScalarType *W, const MATRIX_TYPE &V, typename MATRIX_TYPE::ScalarType *x, const typename MATRIX_TYPE::ScalarType *b) { typedef typename MATRIX_TYPE::ScalarType ScalarType; unsigned int jj, j, i; unsigned int columns_number = U.ColumnsNumber(); unsigned int rows_number = U.RowsNumber(); ScalarType s; ScalarType *tmp = new ScalarType[columns_number]; for (j=0; j<columns_number; j++) //Calculate U^T * B. { s = 0; if (W[j]!=0) //Nonzero result only if wj is nonzero. { for (i=0; i<rows_number; i++) s += U[i][j]*b[i]; s /= W[j]; //This is the divide by wj . } tmp[j]=s; } for (j=0;j<columns_number;j++) //Matrix multiply by V to get answer. { s = 0; for (jj=0; jj<columns_number; jj++) s += V[j][jj]*tmp[jj]; x[j]=s; } delete []tmp; }; /*! @} */ }; // end of namespace #endif