ViSP  2.6.2
vpMatrix_svd.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMatrix_svd.cpp 3805 2012-06-23 20:56:16Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2012 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.txt at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Matrix SVD decomposition.
36  *
37  * Authors:
38  * Eric Marchand
39  *
40  *****************************************************************************/
41 
42 #include <visp/vpConfig.h>
43 
44 #ifndef DOXYGEN_SHOULD_SKIP_THIS
45 
46 #include <visp/vpMatrix.h>
47 #include <visp/vpMath.h>
48 #include <visp/vpColVector.h>
49 #include <visp/vpException.h>
50 #include <visp/vpMatrixException.h>
51 #include <visp/vpDebug.h>
52 
53 
54 #include <cmath> // std::fabs
55 #include <limits> // numeric_limits
56 #include <iostream>
57 
58 /*---------------------------------------------------------------------
59 
60 SVD related functions
61 
62 ---------------------------------------------------------------------*/
63 
64 
65 static double pythag(double a, double b)
66 {
67  double absa, absb;
68  absa = fabs(a);
69  absb = fabs(b);
70  if (absa > absb) return absa*sqrt(1.0+vpMath::sqr(absb/absa));
71  //else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+vpMath::sqr(absa/absb)));
72  else return (std::fabs(absb) <= std::numeric_limits<double>::epsilon() ? 0.0 : absb*sqrt(1.0+vpMath::sqr(absa/absb)));
73 }
74 
75 #ifdef SIGN
76 #undef SIGN
77 #endif
78 #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
79 
100 #define MAX_ITER_SVD 50
101 void vpMatrix::svdNr(vpColVector& W, vpMatrix& V)
102 {
103 
104  unsigned int m = rowNum;
105  unsigned int n = colNum;
106  double epsilon = 10*std::numeric_limits<double>::epsilon();
107 
108  unsigned int flag,i,its,j,jj,k,l=0,nm=0;
109  double c,f,h,s,x,y,z;
110  double anorm=0.0,g=0.0,scale=0.0;
111 
112  // So that the original NRC code (using 1..n indexing) can be used
113  // This should be considered as a temporary fix.
114  double **a = new double*[m+1];
115  double **v = new double*[n+1];
116  // double **w = W.rowPtrs;
117  // w--;
118 
119  double *w = new double[n+1];
120  for (i=0;i<n;i++) w[i+1] = 0.0;
121 
122  for (i=1;i<=m;i++) {
123  a[i] = this->rowPtrs[i-1]-1;
124  }
125  for (i=1;i<=n;i++) {
126  v[i] = V.rowPtrs[i-1]-1;
127  }
128 
129  if (m < n)
130  {
131  vpERROR_TRACE("\n\t\tSVDcmp: You must augment A with extra zero rows") ;
133  "\n\t\tSVDcmp: You must augment A with "
134  "extra zero rows")) ;
135  }
136  double* rv1=new double[n+1];
137 
138  for (i=1;i<=n;i++) {
139  l=i+1;
140  rv1[i]=scale*g;
141  g=s=scale=0.0;
142  if (i <= m) {
143  for (k=i;k<=m;k++) scale += fabs(a[k][i]);
144  //if ((scale != 0.0) || (fabs(scale) > EPS_SVD)) {
145  if ((std::fabs(scale) > epsilon)/* || (fabs(scale) > EPS_SVD)*/) {
146  for (k=i;k<=m;k++) {
147  a[k][i] /= scale;
148  s += a[k][i]*a[k][i];
149  }
150  f=a[i][i];
151  g = -SIGN(sqrt(s),f);
152  h=f*g-s;
153  a[i][i]=f-g;
154  if (i != n) {
155  for (j=l;j<=n;j++) {
156  for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
157  f=s/h;
158  for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
159  }
160  }
161  for (k=i;k<=m;k++) a[k][i] *= scale;
162  }
163  }
164  w[i]=scale*g;
165  g=s=scale=0.0;
166  if (i <= m && i != n) {
167  for (k=l;k<=n;k++) scale += fabs(a[i][k]);
168  //if ((scale != 0.0) || (fabs(scale) > EPS_SVD)) {
169  if ((std::fabs(scale) > epsilon) /*|| (fabs(scale) > EPS_SVD)*/) {
170  for (k=l;k<=n;k++) {
171  a[i][k] /= scale;
172  s += a[i][k]*a[i][k];
173  }
174  f=a[i][l];
175  g = -SIGN(sqrt(s),f);
176  h=f*g-s;
177  a[i][l]=f-g;
178  for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
179  if (i != m) {
180  for (j=l;j<=m;j++) {
181  for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
182  for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
183  }
184  }
185  for (k=l;k<=n;k++) a[i][k] *= scale;
186  }
187  }
188  anorm=vpMath::maximum(anorm,(fabs(w[i])+fabs(rv1[i])));
189  }
190  for (i=n;i>=1;i--) {
191  if (i < n) {
192  //if ((g) || (fabs(g) > EPS_SVD)) {
193  if ((std::fabs(g) > epsilon) /*|| (fabs(g) > EPS_SVD)*/) {
194  for (j=l;j<=n;j++)
195  v[j][i]=(a[i][j]/a[i][l])/g;
196  for (j=l;j<=n;j++) {
197  for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
198  for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
199  }
200  }
201  for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
202  }
203  v[i][i]=1.0;
204  g=rv1[i];
205  l=i;
206  }
207  for (i=n;i>=1;i--) {
208  l=i+1;
209  g=w[i];
210  if (i < n)
211  for (j=l;j<=n;j++) a[i][j]=0.0;
212  //if ((g != 0.0) || (fabs(g) > EPS_SVD)) {
213  if ((std::fabs(g) > epsilon) /*|| (fabs(g) > EPS_SVD)*/) {
214  g=1.0/g;
215  if (i != n) {
216  for (j=l;j<=n;j++) {
217  for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
218  f=(s/a[i][i])*g;
219  for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
220  }
221  }
222  for (j=i;j<=m;j++) a[j][i] *= g;
223  } else {
224  for (j=i;j<=m;j++) a[j][i]=0.0;
225  }
226  ++a[i][i];
227  }
228  for (k=n;k>=1;k--) {
229  for (its=1;its<=MAX_ITER_SVD;its++) {
230  flag=1;
231  for (l=k;l>=1;l--) {
232  nm=l-1;
233  //if ((fabs(rv1[l])+anorm == anorm) || (fabs(rv1[l]) <= EPS_SVD)) {
234  if ((std::fabs(rv1[l]) <= epsilon) /*|| (fabs(rv1[l]) <= EPS_SVD)*/) {
235  flag=0;
236  break;
237  }
238  //if ((fabs(w[nm])+anorm == anorm) || (fabs(w[nm]) <= EPS_SVD)) break;
239  if ((std::fabs(w[nm]) <= epsilon) /*|| (fabs(w[nm]) <= EPS_SVD)*/) break;
240  }
241  if (flag) {
242  c=0.0;
243  s=1.0;
244  for (i=l;i<=k;i++) {
245  f=s*rv1[i];
246  //if ((fabs(f)+anorm != anorm) || (fabs(f) <= EPS_SVD)) {
247  if ((std::fabs(f) > epsilon) /*|| (fabs(f) <= EPS_SVD)*/) {
248  g=w[i];
249  h=pythag(f,g);
250  w[i]=h;
251  h=1.0/h;
252  c=g*h;
253  s=(-f*h);
254  for (j=1;j<=m;j++) {
255  y=a[j][nm];
256  z=a[j][i];
257  a[j][nm]=y*c+z*s;
258  a[j][i]=z*c-y*s;
259  }
260  }
261  }
262  }
263  z=w[k];
264  if (l == k) {
265  if (z < 0.0) {
266  w[k] = -z;
267  for (j=1;j<=n;j++) v[j][k]=(-v[j][k]);
268  }
269  break;
270  }
271  if (its == MAX_ITER_SVD)
272  {
273  for (i=0;i<n;i++) W[i] = w[i+1];
274 
275  vpERROR_TRACE("\n\t\t No convergence in SVDcmp ") ;
276  std::cout << *this <<std::endl ;
277  // throw(vpMatrixException(vpMatrixException::matrixError,
278  // "\n\t\t No convergence in SVDcmp ")) ;
279  }
280  x=w[l];
281  nm=k-1;
282  y=w[nm];
283  g=rv1[nm];
284  h=rv1[k];
285  f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
286  g=pythag(f,1.0);
287  f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
288  c=s=1.0;
289  for (j=l;j<=nm;j++) {
290  i=j+1;
291  g=rv1[i];
292  y=w[i];
293  h=s*g;
294  g=c*g;
295  z=pythag(f,h);
296  rv1[j]=z;
297  c=f/z;
298  s=h/z;
299  f=x*c+g*s;
300  g=g*c-x*s;
301  h=y*s;
302  y=y*c;
303  for (jj=1;jj<=n;jj++) {
304  x=v[jj][j];
305  z=v[jj][i];
306  v[jj][j]=x*c+z*s;
307  v[jj][i]=z*c-x*s;
308  }
309  z=pythag(f,h);
310  w[j]=z;
311  //if ((z != 0.0) || (fabs(z) > EPS_SVD)) {
312  if ((std::fabs(z) > epsilon) /*|| (fabs(z) > EPS_SVD)*/) {
313  z=1.0/z;
314  c=f*z;
315  s=h*z;
316  }
317  f=(c*g)+(s*y);
318  x=(c*y)-(s*g);
319  for (jj=1;jj<=m;jj++) {
320  y=a[jj][j];
321  z=a[jj][i];
322  a[jj][j]=y*c+z*s;
323  a[jj][i]=z*c-y*s;
324  }
325  }
326  rv1[l]=0.0;
327  rv1[k]=f;
328  w[k]=x;
329  }
330  }
331  for (i=0;i<n;i++) W[i] = w[i+1];
332 
333 
334  delete[] w;
335  delete[] rv1;
336  delete[] a;
337  delete[] v;
338 
339 }
340 
341 #undef SIGN
342 #undef PYTHAG
343 
361 void vpMatrix::SVBksb( const vpColVector& w,
362  const vpMatrix& v,
363  const vpColVector& b, vpColVector& x)
364 {
365  unsigned int m = this->rowNum;
366  unsigned int n = this->colNum;
367  double** u = rowPtrs;
368 
369  unsigned int jj,j,i;
370  double s,*tmp;
371 
372  tmp=new double[n];
373  for (j=0;j<n;j++) {
374  s=0.0;
375  //if (w[j])
376  if (std::fabs(w[j]) > std::numeric_limits<double>::epsilon())
377  {
378  for (i=0;i<m;i++) s += u[i][j]*b[i];
379  s /= w[j];
380  }
381  tmp[j]=s;
382  }
383  for (j=0;j<n;j++) {
384  s=0.0;
385  for (jj=0;jj<n;jj++) s += v[j][jj]*tmp[jj];
386  x[j]=s;
387  }
388  delete [] tmp;
389 }
390 
391 #define TOL 1.0e-5
392 
412 #define TOLERANCE 1.0e-7
413 
414 static
415 void svd_internal_use(double *U, double *S, double *V,
416  unsigned int nRow, unsigned int nCol)
417 {
418  unsigned int i, j, k, EstColRank, RotCount, SweepCount, slimit;
419  double eps, e2, tol, vt, p, x0, y0, q, r, c0, s0, d1, d2;
420 
421  eps = TOLERANCE;
422  slimit = nCol / 4;
423  if (slimit < 6.0)
424  slimit = 6;
425  SweepCount = 0;
426  e2 = 10.0 * nRow * eps * eps;
427  tol = eps * .1;
428  EstColRank = nCol;
429  if(V)
430  for (i = 0; i < nCol; i++)
431  for (j = 0; j < nCol; j++) {
432  V[nCol * i + j] = 0.0;
433  V[nCol * i + i] = 1.0;
434  }
435  RotCount = EstColRank * (EstColRank - 1) / 2;
436  while (RotCount != 0 && SweepCount <= slimit) {
437  RotCount = EstColRank * (EstColRank - 1) / 2;
438  SweepCount++;
439  for (j = 0; j < EstColRank - 1; j++) {
440  for (k = j + 1; k < EstColRank; k++) {
441  p = q = r = 0.0;
442  for (i = 0; i < nRow; i++) {
443  x0 = U[nCol * i + j];
444  y0 = U[nCol * i + k];
445  p += x0 * y0;
446  q += x0 * x0;
447  r += y0 * y0;
448  }
449  S[j] = q;
450  S[k] = r;
451  if (q >= r) {
452  if (q <= e2 * S[0] || fabs(p) <= tol * q)
453  RotCount--;
454  else {
455  p /= q;
456  r = 1 - r / q;
457  vt = sqrt(4 * p * p + r * r);
458  c0 = sqrt(fabs(.5 * (1 + r / vt)));
459  s0 = p / (vt * c0);
460  for (i = 0; i < nRow; i++) {
461  d1 = U[nCol * i + j];
462  d2 = U[nCol * i + k];
463  U[nCol * i + j] = d1 * c0 + d2 * s0;
464  U[nCol * i + k] = -d1 * s0 + d2 * c0;
465  }
466  if(V)
467  for (i = 0; i < nCol; i++) {
468  d1 = V[nCol * i + j];
469  d2 = V[nCol * i + k];
470  V[nCol * i + j] = d1 * c0 + d2 * s0;
471  V[nCol * i + k] = -d1 * s0 + d2 * c0;
472  }
473  }
474  }
475  else {
476  p /= r;
477  q = q / r - 1;
478  vt = sqrt(4 * p * p + q * q);
479  s0 = sqrt(fabs(.5 * (1 - q / vt)));
480  if (p < 0)
481  s0 = -s0;
482  c0 = p / (vt * s0);
483  for (i = 0; i < nRow; i++) {
484  d1 = U[nCol * i + j];
485  d2 = U[nCol * i + k];
486  U[nCol * i + j] = d1 * c0 + d2 * s0;
487  U[nCol * i + k] = -d1 * s0 + d2 * c0;
488  }
489  if(V)
490  for (i = 0; i < nCol; i++) {
491  d1 = V[nCol * i + j];
492  d2 = V[nCol * i + k];
493  V[nCol * i + j] = d1 * c0 + d2 * s0;
494  V[nCol * i + k] = -d1 * s0 + d2 * c0;
495  }
496  }
497  }
498  }
499  while (EstColRank >= 3 && S[(EstColRank - 1)] <= S[0] * tol + tol * tol)
500  EstColRank--;
501  }
502  for(i = 0; i < nCol; i++)
503  S[i] = sqrt(S[i]);
504  for(i = 0; i < nCol; i++)
505  for(j = 0; j < nRow; j++)
506  U[nCol * j + i] = U[nCol * j + i] / S[i];
507 }
508 
534 void vpMatrix::svdFlake(vpColVector &W, vpMatrix &V)
535 {
536 
537 
538  svd_internal_use(data, W.data, V.data, getRows(), getCols());
539 }
540 
541 
542 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
543 # include <opencv2/core/core.hpp>
544 void vpMatrix::svdOpenCV(vpColVector& w, vpMatrix& v){
545  int rows = (int)this->getRows();
546  int cols = (int)this->getCols();
547  cv::Mat m(rows, cols, CV_64F, this->data);
548  cv::SVD opencvSVD(m);
549  cv::Mat opencvV = opencvSVD.vt;
550  cv::Mat opencvW = opencvSVD.w;
551  v.resize((unsigned int)opencvV.rows, (unsigned int)opencvV.cols);
552  w.resize((unsigned int)(opencvW.rows*opencvW.cols));
553 
554  memcpy(v.data, opencvV.data, (size_t)(8*opencvV.rows*opencvV.cols));
555  v=v.transpose();
556  memcpy(w.data, opencvW.data, (size_t)(8*opencvW.rows*opencvW.cols));
557  this->resize((unsigned int)opencvSVD.u.rows, (unsigned int)opencvSVD.u.cols);
558  memcpy(this->data,opencvSVD.u.data, (size_t)(8*opencvSVD.u.rows*opencvSVD.u.cols));
559 }
560 
561 #endif
562 
563 #ifdef VISP_HAVE_LAPACK
564 extern "C" int dgesdd_(char *jobz, int *m, int *n, double *a, int *lda, double *s, double *u, int *ldu, double *vt, int *ldvt, double *work, int *lwork, int *iwork, int *info);
565 #include <stdio.h>
566 #include <string.h>
567 
568 void vpMatrix::svdLapack(vpColVector& W, vpMatrix& V){
569  /* unsigned */ int m = static_cast<int>(this->getCols()), n = static_cast<int>(this->getRows()), lda = m, ldu = m, ldvt = std::min(m,n);
570  int info, lwork;
571 
572  double wkopt;
573  double* work;
574 
575  int* iwork = new int[8*static_cast<unsigned int>(std::min(n,m))];
576 
577  double *s = W.data;
578  double* a = new double[static_cast<unsigned int>(lda*n)];
579  memcpy(a,this->data,this->getRows()*this->getCols()*sizeof(double));
580  double* u = V.data;
581  double* vt = this->data;
582 
583 
584 
585  lwork = -1;
586  dgesdd_( (char*)"S", &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, &wkopt, &lwork, iwork, &info );
587  lwork = (int)wkopt;
588  work = new double[static_cast<unsigned int>(lwork)];
589 
590  dgesdd_( (char*)"S", &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info );
591 
592  if( info > 0 ) {
593  std::cout << "The algorithm computing SVD failed to converge." << std::endl;
594 
595  }
596 
597  V=V.transpose();
598  delete[] work;
599  delete[] iwork;
600  delete[] a;
601 }
602 #endif
603 
604 #ifdef VISP_HAVE_GSL
605 #include <gsl/gsl_linalg.h>
606 
607 void
608 vpMatrix::svdGsl(vpColVector& w, vpMatrix& v)
609 {
610 
611 #if 0
612  // premier test avec la gsl 1. on recopie...
613  int i,j ;
614 
615  int nc = getCols() ;
616  int nr = getRows() ;
617  gsl_matrix *A = gsl_matrix_alloc(nr, nc) ;
618 
619  int Atda = A->tda ;
620  for (i=0 ; i < nr ; i++)
621  {
622  int k = i*Atda ;
623  for (j=0 ; j < nc ; j++)
624  A->data[k+j] = (*this)[i][j] ;
625  }
626  // gsl_matrix_set(A,i,j,(*this)[i][j]) ;
627 
628  gsl_matrix *V = gsl_matrix_alloc(nc, nc) ;
629  gsl_vector *S = gsl_vector_alloc(nc) ;
630  gsl_vector *work = gsl_vector_alloc(nc) ;
631 
632  gsl_linalg_SV_decomp(A,V,S, work) ;
633 // gsl_linalg_SV_decomp_jacobi(A,V,S) ;
634 
635 
636  //l'acces par gsl_matrix_get est tres lourd, voir si on peut pas faire
637  // autremement (surement !)
638 
639  Atda = A->tda ;
640  for (i=0 ; i < nr ; i++)
641  for (j=0 ; j < nc ; j++)
642  (*this)[i][j] = gsl_matrix_get(A,i,j) ;
643 
644  int Vtda = V->tda ;
645  for (i=0 ; i < nc ; i++)
646  {
647  int k = i*Vtda ;
648  for (j=0 ; j < nc ; j++)
649  v[i][j] = V->data[k+j] ;
650  }
651 
652  for (j=0 ; j < nc ; j++)
653  w[j] = gsl_vector_get(S,j) ;
654 
655 
656  gsl_matrix_free(V) ;
657  gsl_matrix_free(A) ;
658  gsl_vector_free(S) ;
659  gsl_vector_free(work) ;
660 
661 #else //optimisation Anthony 20/03/2008
662 
663  unsigned int nc = getCols() ;
664  unsigned int nr = getRows() ;
665  gsl_vector *work = gsl_vector_alloc(nc) ;
666 
667 // gsl_linalg_SV_decomp_jacobi(A,V,S) ;
668 
669 
670  //l'acces par gsl_matrix_get est tres lourd, voir si on peut pas faire
671  // autremement (surement !)
672 
673  gsl_matrix A;
674  A.size1 = nr;
675  A.size2 = nc;
676  A.tda = A.size2;
677  A.data = this->data;
678  A.owner = 0;
679  A.block = 0;
680 
681  gsl_matrix V;
682  V.size1 = nc;
683  V.size2 = nc;
684  V.tda = V.size2;
685  V.data = v.data;
686  V.owner = 0;
687  V.block = 0;
688 
689  gsl_vector S;
690  S.size = nc;
691  S.stride = 1;
692  S.data = w.data;
693  S.owner = 0;
694  S.block = 0;
695 
696  gsl_linalg_SV_decomp(&A,&V,&S, work) ;
697 
698  gsl_vector_free(work) ;
699 
700 #endif
701 }
702 #endif // # #GSL
703 
704 
705 #undef TOL
706 #undef TOLERANCE
707 
708 #undef MAX_ITER_SVD
709 
710 #endif // doxygen should skip this
Definition of the vpMatrix class.
Definition: vpMatrix.h:96
void resize(const unsigned int nrows, const unsigned int ncols, const bool nullify=true)
Definition: vpMatrix.cpp:174
#define vpERROR_TRACE
Definition: vpDebug.h:379
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:137
double * data
address of the first element of the data array
Definition: vpMatrix.h:116
double ** rowPtrs
address of the first element of each rows
Definition: vpMatrix.h:119
static double sqr(double x)
Definition: vpMath.h:106
vpMatrix transpose() const
Definition: vpMatrix.cpp:1204
unsigned int rowNum
number of rows
Definition: vpMatrix.h:110
Class that provides a data structure for the column vectors as well as a set of operations on these v...
Definition: vpColVector.h:72
unsigned int getCols() const
Return the number of columns of the matrix.
Definition: vpMatrix.h:159
error that can be emited by the vpMatrix class and its derivates
unsigned int colNum
number of columns
Definition: vpMatrix.h:112
unsigned int getRows() const
Return the number of rows of the matrix.
Definition: vpMatrix.h:157
void resize(const unsigned int i, const bool flagNullify=true)
Definition: vpColVector.h:94