255 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C++
		
	
	
/**
 | 
						|
 * @file    svdcmp.cpp
 | 
						|
 * @brief   SVD decomposition adapted from NRC
 | 
						|
 * @author  Alireza Fathi
 | 
						|
 * @author  Frank Dellaert
 | 
						|
 */
 | 
						|
#include <stdexcept>
 | 
						|
#include <math.h>    /* for 'fabs' */
 | 
						|
#include <iostream>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
using namespace std;
 | 
						|
 | 
						|
 | 
						|
#define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
 | 
						|
static double sqrarg;
 | 
						|
#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
 | 
						|
static double maxarg1,maxarg2;
 | 
						|
#define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ?\
 | 
						|
        (maxarg1) : (maxarg2))
 | 
						|
static int iminarg1,iminarg2;
 | 
						|
#define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ?\
 | 
						|
        (iminarg1) : (iminarg2))
 | 
						|
 | 
						|
 | 
						|
/* ************************************************************************* */
 | 
						|
/*
 | 
						|
double pythag(double a, double b)
 | 
						|
{
 | 
						|
  double absa = 0.0, absb = 0.0;
 | 
						|
  absa=fabs(a);
 | 
						|
  absb=fabs(b);
 | 
						|
  if (absa > absb) return absa*sqrt(1.0+SQR(absb/absa));
 | 
						|
  else return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+SQR(absa/absb)));
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
/* ************************************************************************* */
 | 
						|
double pythag(double a, double b)
 | 
						|
{
 | 
						|
  double absa = 0.0, absb = 0.0;
 | 
						|
  absa=fabs(a);
 | 
						|
  absb=fabs(b);
 | 
						|
  if (absa > absb) return absa*sqrt(1.0+SQR(absb/absa));
 | 
						|
  else {
 | 
						|
    if(absb == 0.0)
 | 
						|
      return 0.0;
 | 
						|
    else
 | 
						|
     return (absb * sqrt(1.0 + SQR(absa/absb))); 
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* ************************************************************************* */
 | 
						|
void svdcmp(double **a, int m, int n, double w[], double **v)
 | 
						|
{
 | 
						|
  int flag,i,its,j,jj,k,l,nm;
 | 
						|
  double anorm,c,f,g,h,s,scale,x,y,z;
 | 
						|
 | 
						|
  //vector sizes:
 | 
						|
  // w[n] - q-1 passed in
 | 
						|
  // a[m] - u-1 passed in 
 | 
						|
  // v[n] - v-1 passed in
 | 
						|
 | 
						|
  //Current progress on verifying array bounds:
 | 
						|
  // rv1 references have been fixed
 | 
						|
 | 
						|
  double *rv1 = new double[n];
 | 
						|
 | 
						|
  g= 0.0;
 | 
						|
  scale= 0.0;
 | 
						|
  anorm= 0.0;
 | 
						|
  for (i=1;i<=n;i++) {
 | 
						|
    l=i+1;
 | 
						|
    rv1[i-1]=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(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) {
 | 
						|
      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(sqrt(s),f);
 | 
						|
	h=f*g-s;
 | 
						|
	a[i][l]=f-g;
 | 
						|
	for (k=l;k<=n;k++) 
 | 
						|
	  {
 | 
						|
	    rv1[k-1]=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-1];
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	for (k=l;k<=n;k++) a[i][k] *= scale;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    anorm=FMAX(anorm,(fabs(w[i])+fabs(rv1[i-1]))); 
 | 
						|
 | 
						|
  }
 | 
						|
  for (i=n;i>=1;i--) {
 | 
						|
    if (i < n) {
 | 
						|
      if (g) {
 | 
						|
	for (j=l;j<=n;j++)
 | 
						|
	  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-1];
 | 
						|
    l=i;
 | 
						|
  }
 | 
						|
  for (i=IMIN(m,n);i>=1;i--) {
 | 
						|
    l=i+1;
 | 
						|
    g=w[i];
 | 
						|
    for (j=l;j<=n;j++) a[i][j]=0.0;
 | 
						|
    if (g) {
 | 
						|
      g=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];
 | 
						|
  }
 | 
						|
  for (k=n;k>=1;k--) {
 | 
						|
    for (its=1;its<=30;its++) {
 | 
						|
      flag=1;
 | 
						|
      for (l=k;l>=1;l--) {
 | 
						|
	nm=l-1;
 | 
						|
	if ((double)(fabs(rv1[l-1])+anorm) == anorm) {
 | 
						|
	  flag=0;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
	if ((double)(fabs(w[nm])+anorm) == anorm) break; 
 | 
						|
      }
 | 
						|
      if (flag) {
 | 
						|
	c=0.0;
 | 
						|
	s=1.0;
 | 
						|
	for (i=l;i<=k;i++) {
 | 
						|
	  f=s*rv1[i-1];
 | 
						|
	  rv1[i-1]=c*rv1[i-1];
 | 
						|
	  if ((double)(fabs(f)+anorm) == anorm) break;
 | 
						|
	  g=w[i];  
 | 
						|
	  h=pythag(f,g);
 | 
						|
	  w[i]=h;
 | 
						|
	  h=1.0/h;
 | 
						|
	  c=g*h;
 | 
						|
	  s = -f*h;
 | 
						|
	  for (j=1;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) {
 | 
						|
	if (z < 0.0) {
 | 
						|
	  w[k] = -z;  
 | 
						|
	  for (j=1;j<=n;j++) v[j][k] = -v[j][k];
 | 
						|
	}
 | 
						|
	break;
 | 
						|
      }
 | 
						|
      if (its == 30) throw(std::domain_error("no convergence in 30 svdcmp iterations"));
 | 
						|
      x=w[l];  
 | 
						|
      nm=k-1;
 | 
						|
      y=w[nm];  
 | 
						|
      g=rv1[nm-1] ;
 | 
						|
      h=rv1[k-1];
 | 
						|
      f=((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y);
 | 
						|
      g=pythag(f,1.0);
 | 
						|
      f=((x-z)*(x+z)+h*((y/(f+SIGN(g,f)))-h))/x;
 | 
						|
      c=s=1.0;
 | 
						|
      for (j=l;j<=nm;j++) {
 | 
						|
	i=j+1;
 | 
						|
	g=rv1[i-1];
 | 
						|
	y=w[i]; 
 | 
						|
	h=s*g;
 | 
						|
	g=c*g;
 | 
						|
	z=pythag(f,h);
 | 
						|
	rv1[j-1]=z;
 | 
						|
	c=f/z;
 | 
						|
	s=h/z;
 | 
						|
	f=x*c+g*s;
 | 
						|
	g = g*c-x*s;
 | 
						|
	h=y*s;
 | 
						|
	y *= c;
 | 
						|
	for (jj=1;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=pythag(f,h);
 | 
						|
	w[j]=z; 
 | 
						|
	if (z) {
 | 
						|
	  z=1.0/z;
 | 
						|
	  c=f*z;
 | 
						|
	  s=h*z;
 | 
						|
	}
 | 
						|
	f=c*g+s*y;
 | 
						|
	x=c*y-s*g;
 | 
						|
	for (jj=1;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-1]=0.0;
 | 
						|
      rv1[k-1]=f;
 | 
						|
      w[k]=x; 
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  delete[] rv1;
 | 
						|
  
 | 
						|
}
 | 
						|
 | 
						|
/* ************************************************************************* */
 |