Visual Servoing Platform  version 3.0.0
vpMatrix_svd.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See http://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Matrix SVD decomposition.
32  *
33  * Authors:
34  * Eric Marchand
35  *
36  *****************************************************************************/
37 
38 #include <visp3/core/vpConfig.h>
39 
40 #ifndef DOXYGEN_SHOULD_SKIP_THIS
41 
42 #include <visp3/core/vpMatrix.h>
43 #include <visp3/core/vpMath.h>
44 #include <visp3/core/vpColVector.h>
45 #include <visp3/core/vpException.h>
46 #include <visp3/core/vpMatrixException.h>
47 #include <visp3/core/vpDebug.h>
48 
49 
50 #include <cmath> // std::fabs
51 #include <limits> // numeric_limits
52 #include <iostream>
53 
54 /*---------------------------------------------------------------------
55 
56 SVD related functions
57 
58 ---------------------------------------------------------------------*/
59 
60 
61 static double pythag(double a, double b)
62 {
63  double absa, absb;
64  absa = fabs(a);
65  absb = fabs(b);
66  if (absa > absb) return absa*sqrt(1.0+vpMath::sqr(absb/absa));
67  //else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+vpMath::sqr(absa/absb)));
68  else return (std::fabs(absb) <= std::numeric_limits<double>::epsilon() ? 0.0 : absb*sqrt(1.0+vpMath::sqr(absa/absb)));
69 }
70 
71 #ifdef SIGN
72 #undef SIGN
73 #endif
74 #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
75 
96 #define MAX_ITER_SVD 50
97 void vpMatrix::svdNr(vpColVector& W, vpMatrix& V)
98 {
99 
100  unsigned int m = rowNum;
101  unsigned int n = colNum;
102  double epsilon = 10*std::numeric_limits<double>::epsilon();
103 
104  unsigned int flag,i,its,j,jj,k,l=0,nm=0;
105  double c,f,h,s,x,y,z;
106  double anorm=0.0,g=0.0,scale=0.0;
107 
108  // So that the original NRC code (using 1..n indexing) can be used
109  // This should be considered as a temporary fix.
110  double **a = new double*[m+1];
111  double **v = new double*[n+1];
112  // double **w = W.rowPtrs;
113  // w--;
114 
115  double *w = new double[n+1];
116  for (i=0;i<n;i++) w[i+1] = 0.0;
117 
118  for (i=1;i<=m;i++) {
119  a[i] = this->rowPtrs[i-1]-1;
120  }
121  for (i=1;i<=n;i++) {
122  v[i] = V.rowPtrs[i-1]-1;
123  }
124 
125  if (m < n)
126  {
127  delete[] w;
128  delete[] a;
129  delete[] v;
130  vpERROR_TRACE("\n\t\tSVDcmp: You must augment A with extra zero rows") ;
132  "\n\t\tSVDcmp: You must augment A with "
133  "extra zero rows")) ;
134  }
135  double* rv1=new double[n+1];
136 
137  for (i=1;i<=n;i++) {
138  l=i+1;
139  rv1[i]=scale*g;
140  g=s=scale=0.0;
141  if (i <= m) {
142  for (k=i;k<=m;k++) scale += fabs(a[k][i]);
143  //if ((scale != 0.0) || (fabs(scale) > EPS_SVD)) {
144  if ((std::fabs(scale) > epsilon)/* || (fabs(scale) > EPS_SVD)*/) {
145  for (k=i;k<=m;k++) {
146  a[k][i] /= scale;
147  s += a[k][i]*a[k][i];
148  }
149  f=a[i][i];
150  g = -SIGN(sqrt(s),f);
151  h=f*g-s;
152  a[i][i]=f-g;
153  if (i != n) {
154  for (j=l;j<=n;j++) {
155  for (s=0.0,k=i;k<=m;k++) s += a[k][i]*a[k][j];
156  f=s/h;
157  for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
158  }
159  }
160  for (k=i;k<=m;k++) a[k][i] *= scale;
161  }
162  }
163  w[i]=scale*g;
164  g=s=scale=0.0;
165  if (i <= m && i != n) {
166  for (k=l;k<=n;k++) scale += fabs(a[i][k]);
167  //if ((scale != 0.0) || (fabs(scale) > EPS_SVD)) {
168  if ((std::fabs(scale) > epsilon) /*|| (fabs(scale) > EPS_SVD)*/) {
169  for (k=l;k<=n;k++) {
170  a[i][k] /= scale;
171  s += a[i][k]*a[i][k];
172  }
173  f=a[i][l];
174  g = -SIGN(sqrt(s),f);
175  h=f*g-s;
176  a[i][l]=f-g;
177  for (k=l;k<=n;k++) rv1[k]=a[i][k]/h;
178  if (i != m) {
179  for (j=l;j<=m;j++) {
180  for (s=0.0,k=l;k<=n;k++) s += a[j][k]*a[i][k];
181  for (k=l;k<=n;k++) a[j][k] += s*rv1[k];
182  }
183  }
184  for (k=l;k<=n;k++) a[i][k] *= scale;
185  }
186  }
187  anorm=vpMath::maximum(anorm,(fabs(w[i])+fabs(rv1[i])));
188  }
189  for (i=n;i>=1;i--) {
190  if (i < n) {
191  //if ((g) || (fabs(g) > EPS_SVD)) {
192  if ((std::fabs(g) > epsilon) /*|| (fabs(g) > EPS_SVD)*/) {
193  for (j=l;j<=n;j++)
194  v[j][i]=(a[i][j]/a[i][l])/g;
195  for (j=l;j<=n;j++) {
196  for (s=0.0,k=l;k<=n;k++) s += a[i][k]*v[k][j];
197  for (k=l;k<=n;k++) v[k][j] += s*v[k][i];
198  }
199  }
200  for (j=l;j<=n;j++) v[i][j]=v[j][i]=0.0;
201  }
202  v[i][i]=1.0;
203  g=rv1[i];
204  l=i;
205  }
206  for (i=n;i>=1;i--) {
207  l=i+1;
208  g=w[i];
209  if (i < n)
210  for (j=l;j<=n;j++) a[i][j]=0.0;
211  //if ((g != 0.0) || (fabs(g) > EPS_SVD)) {
212  if ((std::fabs(g) > epsilon) /*|| (fabs(g) > EPS_SVD)*/) {
213  g=1.0/g;
214  if (i != n) {
215  for (j=l;j<=n;j++) {
216  for (s=0.0,k=l;k<=m;k++) s += a[k][i]*a[k][j];
217  f=(s/a[i][i])*g;
218  for (k=i;k<=m;k++) a[k][j] += f*a[k][i];
219  }
220  }
221  for (j=i;j<=m;j++) a[j][i] *= g;
222  } else {
223  for (j=i;j<=m;j++) a[j][i]=0.0;
224  }
225  ++a[i][i];
226  }
227  for (k=n;k>=1;k--) {
228  for (its=1;its<=MAX_ITER_SVD;its++) {
229  flag=1;
230  for (l=k;l>=1;l--) {
231  nm=l-1;
232  //if ((fabs(rv1[l])+anorm == anorm) || (fabs(rv1[l]) <= EPS_SVD)) {
233  if ((std::fabs(rv1[l]) <= epsilon) /*|| (fabs(rv1[l]) <= EPS_SVD)*/) {
234  flag=0;
235  break;
236  }
237  //if ((fabs(w[nm])+anorm == anorm) || (fabs(w[nm]) <= EPS_SVD)) break;
238  if ((std::fabs(w[nm]) <= epsilon) /*|| (fabs(w[nm]) <= EPS_SVD)*/) break;
239  }
240  if (flag) {
241  c=0.0;
242  s=1.0;
243  for (i=l;i<=k;i++) {
244  f=s*rv1[i];
245  //if ((fabs(f)+anorm != anorm) || (fabs(f) <= EPS_SVD)) {
246  if ((std::fabs(f) > epsilon) /*|| (fabs(f) <= EPS_SVD)*/) {
247  g=w[i];
248  h=pythag(f,g);
249  w[i]=h;
250  h=1.0/h;
251  c=g*h;
252  s=(-f*h);
253  for (j=1;j<=m;j++) {
254  y=a[j][nm];
255  z=a[j][i];
256  a[j][nm]=y*c+z*s;
257  a[j][i]=z*c-y*s;
258  }
259  }
260  }
261  }
262  z=w[k];
263  if (l == k) {
264  if (z < 0.0) {
265  w[k] = -z;
266  for (j=1;j<=n;j++) v[j][k]=(-v[j][k]);
267  }
268  break;
269  }
270  if (its == MAX_ITER_SVD)
271  {
272  for (i=0;i<n;i++) W[i] = w[i+1];
273 
274  vpERROR_TRACE("\n\t\t No convergence in SVDcmp ") ;
275  std::cout << *this <<std::endl ;
276  // throw(vpMatrixException(vpMatrixException::matrixError,
277  // "\n\t\t No convergence in SVDcmp ")) ;
278  }
279  x=w[l];
280  nm=k-1;
281  y=w[nm];
282  g=rv1[nm];
283  h=rv1[k];
284  f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
285  g=pythag(f,1.0);
286  f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
287  c=s=1.0;
288  for (j=l;j<=nm;j++) {
289  i=j+1;
290  g=rv1[i];
291  y=w[i];
292  h=s*g;
293  g=c*g;
294  z=pythag(f,h);
295  rv1[j]=z;
296  if ((std::fabs(z) > epsilon) /*|| (fabs(z) > EPS_SVD)*/) {
297  c=f/z;
298  s=h/z;
299  }
300  f=x*c+g*s;
301  g=g*c-x*s;
302  h=y*s;
303  y=y*c;
304  for (jj=1;jj<=n;jj++) {
305  x=v[jj][j];
306  z=v[jj][i];
307  v[jj][j]=x*c+z*s;
308  v[jj][i]=z*c-x*s;
309  }
310  z=pythag(f,h);
311  w[j]=z;
312  //if ((z != 0.0) || (fabs(z) > EPS_SVD)) {
313  if ((std::fabs(z) > epsilon) /*|| (fabs(z) > EPS_SVD)*/) {
314  z=1.0/z;
315  c=f*z;
316  s=h*z;
317  }
318  f=(c*g)+(s*y);
319  x=(c*y)-(s*g);
320  for (jj=1;jj<=m;jj++) {
321  y=a[jj][j];
322  z=a[jj][i];
323  a[jj][j]=y*c+z*s;
324  a[jj][i]=z*c-y*s;
325  }
326  }
327  rv1[l]=0.0;
328  rv1[k]=f;
329  w[k]=x;
330  }
331  }
332  for (i=0;i<n;i++) W[i] = w[i+1];
333 
334 
335  delete[] w;
336  delete[] rv1;
337  delete[] a;
338  delete[] v;
339 
340 }
341 
342 #undef SIGN
343 #undef PYTHAG
344 
362 void vpMatrix::SVBksb( const vpColVector& w,
363  const vpMatrix& v,
364  const vpColVector& b, vpColVector& x)
365 {
366  unsigned int m = this->rowNum;
367  unsigned int n = this->colNum;
368  double** u = rowPtrs;
369 
370  unsigned int jj,j,i;
371  double s,*tmp;
372 
373  tmp=new double[n];
374  for (j=0;j<n;j++) {
375  s=0.0;
376  //if (w[j])
377  if (std::fabs(w[j]) > std::numeric_limits<double>::epsilon())
378  {
379  for (i=0;i<m;i++) s += u[i][j]*b[i];
380  s /= w[j];
381  }
382  tmp[j]=s;
383  }
384  for (j=0;j<n;j++) {
385  s=0.0;
386  for (jj=0;jj<n;jj++) s += v[j][jj]*tmp[jj];
387  x[j]=s;
388  }
389  delete [] tmp;
390 }
391 
392 #define TOL 1.0e-5
393 
413 #define TOLERANCE 1.0e-7
414 
415 static
416 void svd_internal_use(double *U, double *S, double *V,
417  unsigned int nRow, unsigned int nCol)
418 {
419  unsigned int i, j, k, EstColRank, RotCount, SweepCount, slimit;
420  double eps, e2, tol, vt, p, x0, y0, q, r, c0, s0, d1, d2;
421 
422  eps = TOLERANCE;
423  slimit = nCol / 4;
424  if (slimit < 6.0)
425  slimit = 6;
426  SweepCount = 0;
427  e2 = 10.0 * nRow * eps * eps;
428  tol = eps * .1;
429  EstColRank = nCol;
430  if(V)
431  for (i = 0; i < nCol; i++)
432  for (j = 0; j < nCol; j++) {
433  V[nCol * i + j] = 0.0;
434  V[nCol * i + i] = 1.0;
435  }
436  RotCount = EstColRank * (EstColRank - 1) / 2;
437  while (RotCount != 0 && SweepCount <= slimit) {
438  RotCount = EstColRank * (EstColRank - 1) / 2;
439  SweepCount++;
440  for (j = 0; j < EstColRank - 1; j++) {
441  for (k = j + 1; k < EstColRank; k++) {
442  p = q = r = 0.0;
443  for (i = 0; i < nRow; i++) {
444  x0 = U[nCol * i + j];
445  y0 = U[nCol * i + k];
446  p += x0 * y0;
447  q += x0 * x0;
448  r += y0 * y0;
449  }
450  S[j] = q;
451  S[k] = r;
452  if (q >= r) {
453  if (q <= e2 * S[0] || fabs(p) <= tol * q)
454  RotCount--;
455  else {
456  p /= q;
457  r = 1 - r / q;
458  vt = sqrt(4 * p * p + r * r);
459  c0 = sqrt(fabs(.5 * (1 + r / vt)));
460  s0 = p / (vt * c0);
461  for (i = 0; i < nRow; i++) {
462  d1 = U[nCol * i + j];
463  d2 = U[nCol * i + k];
464  U[nCol * i + j] = d1 * c0 + d2 * s0;
465  U[nCol * i + k] = -d1 * s0 + d2 * c0;
466  }
467  if(V)
468  for (i = 0; i < nCol; i++) {
469  d1 = V[nCol * i + j];
470  d2 = V[nCol * i + k];
471  V[nCol * i + j] = d1 * c0 + d2 * s0;
472  V[nCol * i + k] = -d1 * s0 + d2 * c0;
473  }
474  }
475  }
476  else {
477  p /= r;
478  q = q / r - 1;
479  vt = sqrt(4 * p * p + q * q);
480  s0 = sqrt(fabs(.5 * (1 - q / vt)));
481  if (p < 0)
482  s0 = -s0;
483  c0 = p / (vt * s0);
484  for (i = 0; i < nRow; i++) {
485  d1 = U[nCol * i + j];
486  d2 = U[nCol * i + k];
487  U[nCol * i + j] = d1 * c0 + d2 * s0;
488  U[nCol * i + k] = -d1 * s0 + d2 * c0;
489  }
490  if(V)
491  for (i = 0; i < nCol; i++) {
492  d1 = V[nCol * i + j];
493  d2 = V[nCol * i + k];
494  V[nCol * i + j] = d1 * c0 + d2 * s0;
495  V[nCol * i + k] = -d1 * s0 + d2 * c0;
496  }
497  }
498  }
499  }
500  while (EstColRank >= 3 && S[(EstColRank - 1)] <= S[0] * tol + tol * tol)
501  EstColRank--;
502  }
503  for(i = 0; i < nCol; i++)
504  S[i] = sqrt(S[i]);
505  for(i = 0; i < nCol; i++)
506  for(j = 0; j < nRow; j++)
507  U[nCol * j + i] = U[nCol * j + i] / S[i];
508 }
509 
535 void vpMatrix::svdFlake(vpColVector &W, vpMatrix &V)
536 {
537 
538 
539  svd_internal_use(data, W.data, V.data, getRows(), getCols());
540 }
541 
542 
543 #if (VISP_HAVE_OPENCV_VERSION >= 0x020101) // Require opencv >= 2.1.1
544 # include <opencv2/core/core.hpp>
545 void vpMatrix::svdOpenCV(vpColVector& w, vpMatrix& v){
546  int rows = (int)this->getRows();
547  int cols = (int)this->getCols();
548  cv::Mat m(rows, cols, CV_64F, this->data);
549  cv::SVD opencvSVD(m);
550  cv::Mat opencvV = opencvSVD.vt;
551  cv::Mat opencvW = opencvSVD.w;
552  v.resize((unsigned int)opencvV.rows, (unsigned int)opencvV.cols);
553  w.resize((unsigned int)(opencvW.rows*opencvW.cols));
554 
555  memcpy(v.data, opencvV.data, (size_t)(8*opencvV.rows*opencvV.cols));
556  v=v.transpose();
557  memcpy(w.data, opencvW.data, (size_t)(8*opencvW.rows*opencvW.cols));
558  this->resize((unsigned int)opencvSVD.u.rows, (unsigned int)opencvSVD.u.cols);
559  memcpy(this->data,opencvSVD.u.data, (size_t)(8*opencvSVD.u.rows*opencvSVD.u.cols));
560 }
561 
562 #endif
563 
564 #ifdef VISP_HAVE_LAPACK_C
565 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);
566 #include <stdio.h>
567 #include <string.h>
568 
569 void vpMatrix::svdLapack(vpColVector& W, vpMatrix& V){
570  /* unsigned */ int m = static_cast<int>(this->getCols()), n = static_cast<int>(this->getRows()), lda = m, ldu = m, ldvt = std::min(m,n);
571  int info, lwork;
572 
573  double wkopt;
574  double* work;
575 
576  int* iwork = new int[8*static_cast<unsigned int>(std::min(n,m))];
577 
578  double *s = W.data;
579  double* a = new double[static_cast<unsigned int>(lda*n)];
580  memcpy(a,this->data,this->getRows()*this->getCols()*sizeof(double));
581  double* u = V.data;
582  double* vt = this->data;
583 
584 
585 
586  lwork = -1;
587  dgesdd_( (char*)"S", &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, &wkopt, &lwork, iwork, &info );
588  lwork = (int)wkopt;
589  work = new double[static_cast<unsigned int>(lwork)];
590 
591  dgesdd_( (char*)"S", &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info );
592 
593  if( info > 0 ) {
594  vpTRACE("The algorithm computing SVD failed to converge.");
596  "The algorithm computing SVD failed to converge.")) ;
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
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:92
void resize(const unsigned int nrows, const unsigned int ncols, const bool flagNullify=true)
Definition: vpArray2D.h:167
#define vpERROR_TRACE
Definition: vpDebug.h:391
double * data
Address of the first element of the data array.
Definition: vpArray2D.h:84
unsigned int getCols() const
Return the number of columns of the 2D array.
Definition: vpArray2D.h:154
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:141
unsigned int rowNum
Number of rows in the array.
Definition: vpArray2D.h:74
#define vpTRACE
Definition: vpDebug.h:414
static double sqr(double x)
Definition: vpMath.h:110
vpMatrix transpose() const
Definition: vpMatrix.cpp:247
unsigned int getRows() const
Return the number of rows of the 2D array.
Definition: vpArray2D.h:152
unsigned int colNum
Number of columns in the array.
Definition: vpArray2D.h:76
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
error that can be emited by the vpMatrix class and its derivates
double ** rowPtrs
Address of the first element of each rows.
Definition: vpArray2D.h:78
void resize(const unsigned int i, const bool flagNullify=true)
Definition: vpColVector.h:217