ViSP  2.8.0
vpMatrix_svd.cpp
1 /****************************************************************************
2  *
3  * $Id: vpMatrix_svd.cpp 4210 2013-04-16 08:57:46Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2013 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  delete[] w;
132  delete[] a;
133  delete[] v;
134  vpERROR_TRACE("\n\t\tSVDcmp: You must augment A with extra zero rows") ;
136  "\n\t\tSVDcmp: You must augment A with "
137  "extra zero rows")) ;
138  }
139  double* rv1=new double[n+1];
140 
141  for (i=1;i<=n;i++) {
142  l=i+1;
143  rv1[i]=scale*g;
144  g=s=scale=0.0;
145  if (i <= m) {
146  for (k=i;k<=m;k++) scale += fabs(a[k][i]);
147  //if ((scale != 0.0) || (fabs(scale) > EPS_SVD)) {
148  if ((std::fabs(scale) > epsilon)/* || (fabs(scale) > EPS_SVD)*/) {
149  for (k=i;k<=m;k++) {
150  a[k][i] /= scale;
151  s += a[k][i]*a[k][i];
152  }
153  f=a[i][i];
154  g = -SIGN(sqrt(s),f);
155  h=f*g-s;
156  a[i][i]=f-g;
157  if (i != n) {
158  for (j=l;j<=n;j++) {
159  for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
160  f=s/h;
161  for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
162  }
163  }
164  for (k=i;k<=m;k++) a[k][i] *= scale;
165  }
166  }
167  w[i]=scale*g;
168  g=s=scale=0.0;
169  if (i <= m && i != n) {
170  for (k=l;k<=n;k++) scale += fabs(a[i][k]);
171  //if ((scale != 0.0) || (fabs(scale) > EPS_SVD)) {
172  if ((std::fabs(scale) > epsilon) /*|| (fabs(scale) > EPS_SVD)*/) {
173  for (k=l;k<=n;k++) {
174  a[i][k] /= scale;
175  s += a[i][k]*a[i][k];
176  }
177  f=a[i][l];
178  g = -SIGN(sqrt(s),f);
179  h=f*g-s;
180  a[i][l]=f-g;
181  for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
182  if (i != m) {
183  for (j=l;j<=m;j++) {
184  for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
185  for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
186  }
187  }
188  for (k=l;k<=n;k++) a[i][k] *= scale;
189  }
190  }
191  anorm=vpMath::maximum(anorm,(fabs(w[i])+fabs(rv1[i])));
192  }
193  for (i=n;i>=1;i--) {
194  if (i < n) {
195  //if ((g) || (fabs(g) > EPS_SVD)) {
196  if ((std::fabs(g) > epsilon) /*|| (fabs(g) > EPS_SVD)*/) {
197  for (j=l;j<=n;j++)
198  v[j][i]=(a[i][j]/a[i][l])/g;
199  for (j=l;j<=n;j++) {
200  for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
201  for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
202  }
203  }
204  for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
205  }
206  v[i][i]=1.0;
207  g=rv1[i];
208  l=i;
209  }
210  for (i=n;i>=1;i--) {
211  l=i+1;
212  g=w[i];
213  if (i < n)
214  for (j=l;j<=n;j++) a[i][j]=0.0;
215  //if ((g != 0.0) || (fabs(g) > EPS_SVD)) {
216  if ((std::fabs(g) > epsilon) /*|| (fabs(g) > EPS_SVD)*/) {
217  g=1.0/g;
218  if (i != n) {
219  for (j=l;j<=n;j++) {
220  for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
221  f=(s/a[i][i])*g;
222  for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
223  }
224  }
225  for (j=i;j<=m;j++) a[j][i] *= g;
226  } else {
227  for (j=i;j<=m;j++) a[j][i]=0.0;
228  }
229  ++a[i][i];
230  }
231  for (k=n;k>=1;k--) {
232  for (its=1;its<=MAX_ITER_SVD;its++) {
233  flag=1;
234  for (l=k;l>=1;l--) {
235  nm=l-1;
236  //if ((fabs(rv1[l])+anorm == anorm) || (fabs(rv1[l]) <= EPS_SVD)) {
237  if ((std::fabs(rv1[l]) <= epsilon) /*|| (fabs(rv1[l]) <= EPS_SVD)*/) {
238  flag=0;
239  break;
240  }
241  //if ((fabs(w[nm])+anorm == anorm) || (fabs(w[nm]) <= EPS_SVD)) break;
242  if ((std::fabs(w[nm]) <= epsilon) /*|| (fabs(w[nm]) <= EPS_SVD)*/) break;
243  }
244  if (flag) {
245  c=0.0;
246  s=1.0;
247  for (i=l;i<=k;i++) {
248  f=s*rv1[i];
249  //if ((fabs(f)+anorm != anorm) || (fabs(f) <= EPS_SVD)) {
250  if ((std::fabs(f) > epsilon) /*|| (fabs(f) <= EPS_SVD)*/) {
251  g=w[i];
252  h=pythag(f,g);
253  w[i]=h;
254  h=1.0/h;
255  c=g*h;
256  s=(-f*h);
257  for (j=1;j<=m;j++) {
258  y=a[j][nm];
259  z=a[j][i];
260  a[j][nm]=y*c+z*s;
261  a[j][i]=z*c-y*s;
262  }
263  }
264  }
265  }
266  z=w[k];
267  if (l == k) {
268  if (z < 0.0) {
269  w[k] = -z;
270  for (j=1;j<=n;j++) v[j][k]=(-v[j][k]);
271  }
272  break;
273  }
274  if (its == MAX_ITER_SVD)
275  {
276  for (i=0;i<n;i++) W[i] = w[i+1];
277 
278  vpERROR_TRACE("\n\t\t No convergence in SVDcmp ") ;
279  std::cout << *this <<std::endl ;
280  // throw(vpMatrixException(vpMatrixException::matrixError,
281  // "\n\t\t No convergence in SVDcmp ")) ;
282  }
283  x=w[l];
284  nm=k-1;
285  y=w[nm];
286  g=rv1[nm];
287  h=rv1[k];
288  f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
289  g=pythag(f,1.0);
290  f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
291  c=s=1.0;
292  for (j=l;j<=nm;j++) {
293  i=j+1;
294  g=rv1[i];
295  y=w[i];
296  h=s*g;
297  g=c*g;
298  z=pythag(f,h);
299  rv1[j]=z;
300  c=f/z;
301  s=h/z;
302  f=x*c+g*s;
303  g=g*c-x*s;
304  h=y*s;
305  y=y*c;
306  for (jj=1;jj<=n;jj++) {
307  x=v[jj][j];
308  z=v[jj][i];
309  v[jj][j]=x*c+z*s;
310  v[jj][i]=z*c-x*s;
311  }
312  z=pythag(f,h);
313  w[j]=z;
314  //if ((z != 0.0) || (fabs(z) > EPS_SVD)) {
315  if ((std::fabs(z) > epsilon) /*|| (fabs(z) > EPS_SVD)*/) {
316  z=1.0/z;
317  c=f*z;
318  s=h*z;
319  }
320  f=(c*g)+(s*y);
321  x=(c*y)-(s*g);
322  for (jj=1;jj<=m;jj++) {
323  y=a[jj][j];
324  z=a[jj][i];
325  a[jj][j]=y*c+z*s;
326  a[jj][i]=z*c-y*s;
327  }
328  }
329  rv1[l]=0.0;
330  rv1[k]=f;
331  w[k]=x;
332  }
333  }
334  for (i=0;i<n;i++) W[i] = w[i+1];
335 
336 
337  delete[] w;
338  delete[] rv1;
339  delete[] a;
340  delete[] v;
341 
342 }
343 
344 #undef SIGN
345 #undef PYTHAG
346 
364 void vpMatrix::SVBksb( const vpColVector& w,
365  const vpMatrix& v,
366  const vpColVector& b, vpColVector& x)
367 {
368  unsigned int m = this->rowNum;
369  unsigned int n = this->colNum;
370  double** u = rowPtrs;
371 
372  unsigned int jj,j,i;
373  double s,*tmp;
374 
375  tmp=new double[n];
376  for (j=0;j<n;j++) {
377  s=0.0;
378  //if (w[j])
379  if (std::fabs(w[j]) > std::numeric_limits<double>::epsilon())
380  {
381  for (i=0;i<m;i++) s += u[i][j]*b[i];
382  s /= w[j];
383  }
384  tmp[j]=s;
385  }
386  for (j=0;j<n;j++) {
387  s=0.0;
388  for (jj=0;jj<n;jj++) s += v[j][jj]*tmp[jj];
389  x[j]=s;
390  }
391  delete [] tmp;
392 }
393 
394 #define TOL 1.0e-5
395 
415 #define TOLERANCE 1.0e-7
416 
417 static
418 void svd_internal_use(double *U, double *S, double *V,
419  unsigned int nRow, unsigned int nCol)
420 {
421  unsigned int i, j, k, EstColRank, RotCount, SweepCount, slimit;
422  double eps, e2, tol, vt, p, x0, y0, q, r, c0, s0, d1, d2;
423 
424  eps = TOLERANCE;
425  slimit = nCol / 4;
426  if (slimit < 6.0)
427  slimit = 6;
428  SweepCount = 0;
429  e2 = 10.0 * nRow * eps * eps;
430  tol = eps * .1;
431  EstColRank = nCol;
432  if(V)
433  for (i = 0; i < nCol; i++)
434  for (j = 0; j < nCol; j++) {
435  V[nCol * i + j] = 0.0;
436  V[nCol * i + i] = 1.0;
437  }
438  RotCount = EstColRank * (EstColRank - 1) / 2;
439  while (RotCount != 0 && SweepCount <= slimit) {
440  RotCount = EstColRank * (EstColRank - 1) / 2;
441  SweepCount++;
442  for (j = 0; j < EstColRank - 1; j++) {
443  for (k = j + 1; k < EstColRank; k++) {
444  p = q = r = 0.0;
445  for (i = 0; i < nRow; i++) {
446  x0 = U[nCol * i + j];
447  y0 = U[nCol * i + k];
448  p += x0 * y0;
449  q += x0 * x0;
450  r += y0 * y0;
451  }
452  S[j] = q;
453  S[k] = r;
454  if (q >= r) {
455  if (q <= e2 * S[0] || fabs(p) <= tol * q)
456  RotCount--;
457  else {
458  p /= q;
459  r = 1 - r / q;
460  vt = sqrt(4 * p * p + r * r);
461  c0 = sqrt(fabs(.5 * (1 + r / vt)));
462  s0 = p / (vt * c0);
463  for (i = 0; i < nRow; i++) {
464  d1 = U[nCol * i + j];
465  d2 = U[nCol * i + k];
466  U[nCol * i + j] = d1 * c0 + d2 * s0;
467  U[nCol * i + k] = -d1 * s0 + d2 * c0;
468  }
469  if(V)
470  for (i = 0; i < nCol; i++) {
471  d1 = V[nCol * i + j];
472  d2 = V[nCol * i + k];
473  V[nCol * i + j] = d1 * c0 + d2 * s0;
474  V[nCol * i + k] = -d1 * s0 + d2 * c0;
475  }
476  }
477  }
478  else {
479  p /= r;
480  q = q / r - 1;
481  vt = sqrt(4 * p * p + q * q);
482  s0 = sqrt(fabs(.5 * (1 - q / vt)));
483  if (p < 0)
484  s0 = -s0;
485  c0 = p / (vt * s0);
486  for (i = 0; i < nRow; i++) {
487  d1 = U[nCol * i + j];
488  d2 = U[nCol * i + k];
489  U[nCol * i + j] = d1 * c0 + d2 * s0;
490  U[nCol * i + k] = -d1 * s0 + d2 * c0;
491  }
492  if(V)
493  for (i = 0; i < nCol; i++) {
494  d1 = V[nCol * i + j];
495  d2 = V[nCol * i + k];
496  V[nCol * i + j] = d1 * c0 + d2 * s0;
497  V[nCol * i + k] = -d1 * s0 + d2 * c0;
498  }
499  }
500  }
501  }
502  while (EstColRank >= 3 && S[(EstColRank - 1)] <= S[0] * tol + tol * tol)
503  EstColRank--;
504  }
505  for(i = 0; i < nCol; i++)
506  S[i] = sqrt(S[i]);
507  for(i = 0; i < nCol; i++)
508  for(j = 0; j < nRow; j++)
509  U[nCol * j + i] = U[nCol * j + i] / S[i];
510 }
511 
537 void vpMatrix::svdFlake(vpColVector &W, vpMatrix &V)
538 {
539 
540 
541  svd_internal_use(data, W.data, V.data, getRows(), getCols());
542 }
543 
544 
545 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
546 # include <opencv2/core/core.hpp>
547 void vpMatrix::svdOpenCV(vpColVector& w, vpMatrix& v){
548  int rows = (int)this->getRows();
549  int cols = (int)this->getCols();
550  cv::Mat m(rows, cols, CV_64F, this->data);
551  cv::SVD opencvSVD(m);
552  cv::Mat opencvV = opencvSVD.vt;
553  cv::Mat opencvW = opencvSVD.w;
554  v.resize((unsigned int)opencvV.rows, (unsigned int)opencvV.cols);
555  w.resize((unsigned int)(opencvW.rows*opencvW.cols));
556 
557  memcpy(v.data, opencvV.data, (size_t)(8*opencvV.rows*opencvV.cols));
558  v=v.transpose();
559  memcpy(w.data, opencvW.data, (size_t)(8*opencvW.rows*opencvW.cols));
560  this->resize((unsigned int)opencvSVD.u.rows, (unsigned int)opencvSVD.u.cols);
561  memcpy(this->data,opencvSVD.u.data, (size_t)(8*opencvSVD.u.rows*opencvSVD.u.cols));
562 }
563 
564 #endif
565 
566 #ifdef VISP_HAVE_LAPACK
567 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);
568 #include <stdio.h>
569 #include <string.h>
570 
571 void vpMatrix::svdLapack(vpColVector& W, vpMatrix& V){
572  /* unsigned */ int m = static_cast<int>(this->getCols()), n = static_cast<int>(this->getRows()), lda = m, ldu = m, ldvt = std::min(m,n);
573  int info, lwork;
574 
575  double wkopt;
576  double* work;
577 
578  int* iwork = new int[8*static_cast<unsigned int>(std::min(n,m))];
579 
580  double *s = W.data;
581  double* a = new double[static_cast<unsigned int>(lda*n)];
582  memcpy(a,this->data,this->getRows()*this->getCols()*sizeof(double));
583  double* u = V.data;
584  double* vt = this->data;
585 
586 
587 
588  lwork = -1;
589  dgesdd_( (char*)"S", &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, &wkopt, &lwork, iwork, &info );
590  lwork = (int)wkopt;
591  work = new double[static_cast<unsigned int>(lwork)];
592 
593  dgesdd_( (char*)"S", &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info );
594 
595  if( info > 0 ) {
596  std::cout << "The algorithm computing SVD failed to converge." << std::endl;
597 
598  }
599 
600  V=V.transpose();
601  delete[] work;
602  delete[] iwork;
603  delete[] a;
604 }
605 #endif
606 
607 #ifdef VISP_HAVE_GSL
608 #include <gsl/gsl_linalg.h>
609 
610 void
611 vpMatrix::svdGsl(vpColVector& w, vpMatrix& v)
612 {
613 
614 #if 0
615  // premier test avec la gsl 1. on recopie...
616  int i,j ;
617 
618  int nc = getCols() ;
619  int nr = getRows() ;
620  gsl_matrix *A = gsl_matrix_alloc(nr, nc) ;
621 
622  int Atda = A->tda ;
623  for (i=0 ; i < nr ; i++)
624  {
625  int k = i*Atda ;
626  for (j=0 ; j < nc ; j++)
627  A->data[k+j] = (*this)[i][j] ;
628  }
629  // gsl_matrix_set(A,i,j,(*this)[i][j]) ;
630 
631  gsl_matrix *V = gsl_matrix_alloc(nc, nc) ;
632  gsl_vector *S = gsl_vector_alloc(nc) ;
633  gsl_vector *work = gsl_vector_alloc(nc) ;
634 
635  gsl_linalg_SV_decomp(A,V,S, work) ;
636 // gsl_linalg_SV_decomp_jacobi(A,V,S) ;
637 
638 
639  //l'acces par gsl_matrix_get est tres lourd, voir si on peut pas faire
640  // autremement (surement !)
641 
642  Atda = A->tda ;
643  for (i=0 ; i < nr ; i++)
644  for (j=0 ; j < nc ; j++)
645  (*this)[i][j] = gsl_matrix_get(A,i,j) ;
646 
647  int Vtda = V->tda ;
648  for (i=0 ; i < nc ; i++)
649  {
650  int k = i*Vtda ;
651  for (j=0 ; j < nc ; j++)
652  v[i][j] = V->data[k+j] ;
653  }
654 
655  for (j=0 ; j < nc ; j++)
656  w[j] = gsl_vector_get(S,j) ;
657 
658 
659  gsl_matrix_free(V) ;
660  gsl_matrix_free(A) ;
661  gsl_vector_free(S) ;
662  gsl_vector_free(work) ;
663 
664 #else //optimisation Anthony 20/03/2008
665 
666  unsigned int nc = getCols() ;
667  unsigned int nr = getRows() ;
668  gsl_vector *work = gsl_vector_alloc(nc) ;
669 
670 // gsl_linalg_SV_decomp_jacobi(A,V,S) ;
671 
672 
673  //l'acces par gsl_matrix_get est tres lourd, voir si on peut pas faire
674  // autremement (surement !)
675 
676  gsl_matrix A;
677  A.size1 = nr;
678  A.size2 = nc;
679  A.tda = A.size2;
680  A.data = this->data;
681  A.owner = 0;
682  A.block = 0;
683 
684  gsl_matrix V;
685  V.size1 = nc;
686  V.size2 = nc;
687  V.tda = V.size2;
688  V.data = v.data;
689  V.owner = 0;
690  V.block = 0;
691 
692  gsl_vector S;
693  S.size = nc;
694  S.stride = 1;
695  S.data = w.data;
696  S.owner = 0;
697  S.block = 0;
698 
699  gsl_linalg_SV_decomp(&A,&V,&S, work) ;
700 
701  gsl_vector_free(work) ;
702 
703 #endif
704 }
705 #endif // # #GSL
706 
707 
708 #undef TOL
709 #undef TOLERANCE
710 
711 #undef MAX_ITER_SVD
712 
713 #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:1206
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