369 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			369 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
| /**
 | |
| * @file    Vector.cpp
 | |
| * @brief   typedef and functions to augment Boost's ublas::vector<double>
 | |
| * @author  Kai Ni
 | |
| * @author  Frank Dellaert
 | |
| */
 | |
| 
 | |
| #include <stdarg.h>
 | |
| #include <limits>
 | |
| #include <iostream>
 | |
| #include <sstream>
 | |
| #include <iomanip>
 | |
| #include <cmath>
 | |
| #include <boost/foreach.hpp>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #ifdef WIN32
 | |
| #include <Windows.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef GSL
 | |
| #include <gsl/gsl_blas.h> // needed for gsl blas
 | |
| #include <gsl/gsl_linalg.h>
 | |
| #endif
 | |
| 
 | |
| #include <boost/random/normal_distribution.hpp>
 | |
| #include <boost/random/variate_generator.hpp>
 | |
| 
 | |
| #include "Vector.h"
 | |
| 
 | |
| using namespace std;
 | |
| 
 | |
| namespace gtsam {
 | |
|   
 | |
|   void odprintf(const char *format, ...)
 | |
|   {
 | |
|     char    buf[4096], *p = buf;
 | |
|     int     n;
 | |
|     
 | |
|     va_list args;
 | |
|     va_start(args, format);
 | |
|     #ifdef WIN32
 | |
|     n = _vsnprintf(p, sizeof buf - 3, format, args); // buf-3 is room for CR/LF/NUL
 | |
|     #else
 | |
|     n = vsnprintf(p, sizeof buf - 3, format, args); // buf-3 is room for CR/LF/NUL
 | |
|     #endif
 | |
|     va_end(args);
 | |
|     
 | |
|     #ifdef WIN32
 | |
|     OutputDebugString(buf);
 | |
|     #else    
 | |
|     cout << buf;
 | |
|     #endif
 | |
|     
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   Vector Vector_( size_t m, const double* const data) {
 | |
|     Vector v(m);
 | |
|     copy(data, data+m, v.data().begin());
 | |
|     return v;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   Vector Vector_(size_t m, ...) {
 | |
|     Vector v(m);
 | |
|     va_list ap;
 | |
|     va_start(ap, m);
 | |
|     for( size_t i = 0 ; i < m ; i++) {
 | |
|       double value = va_arg(ap, double);
 | |
|       v(i) = value;
 | |
|     }
 | |
|     va_end(ap);
 | |
|     return v;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   bool zero(const Vector& v) {
 | |
|     bool result = true;
 | |
|     size_t n = v.size();
 | |
|     for( size_t j = 0 ; j < n ; j++)
 | |
|       result = result && (v(j) == 0.0);
 | |
|     return result;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   Vector repeat(size_t n, double value) {
 | |
|     Vector v(n, value);
 | |
|     return v;
 | |
|   }
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector delta(size_t n, size_t i, double value) {
 | |
| 	  Vector v = zero(n);
 | |
| 	  v(i) = value;
 | |
| 	  return v;
 | |
|   }
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   void print(const Vector& v, const string& s) {
 | |
|     size_t n = v.size();
 | |
|     odprintf("%s [", s.c_str());
 | |
|     for(size_t i=0; i<n; i++)
 | |
|       odprintf("%g%s", v[i], (i<n-1 ? "; " : ""));
 | |
|     odprintf("]\n");
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   bool operator==(const Vector& vec1,const Vector& vec2) {
 | |
|     Vector::const_iterator it1 = vec1.begin();
 | |
|     Vector::const_iterator it2 = vec2.begin();
 | |
|     size_t m = vec1.size();
 | |
|     for(size_t i=0; i<m; i++)
 | |
|       if(it1[i] != it2[i])
 | |
|       return false;
 | |
|     return true;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   bool greaterThanOrEqual(const Vector& vec1, const Vector& vec2) {
 | |
| 	  Vector::const_iterator it1 = vec1.begin();
 | |
| 	  Vector::const_iterator it2 = vec2.begin();
 | |
| 	  size_t m = vec1.size();
 | |
| 	  for(size_t i=0; i<m; i++)
 | |
| 		  if(!(it1[i] >= it2[i]))
 | |
| 			  return false;
 | |
| 	  return true;
 | |
|   }
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   bool equal_with_abs_tol(const Vector& vec1, const Vector& vec2, double tol) {
 | |
|     Vector::const_iterator it1 = vec1.begin();
 | |
|     Vector::const_iterator it2 = vec2.begin();
 | |
|     if (vec1.size()!=vec2.size()) return false;
 | |
|     for(size_t i=0; i<vec1.size(); i++) {
 | |
|     	if(isnan(it1[i]) xor isnan(it2[i]))
 | |
|     		return false;
 | |
|     	if(fabs(it1[i] - it2[i]) > tol)
 | |
|     		return false;
 | |
|     }
 | |
|     return true;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   bool assert_equal(const Vector& expected, const Vector& actual, double tol) {
 | |
|     if (equal_with_abs_tol(expected,actual,tol)) return true;
 | |
|     cout << "not equal:" << endl;
 | |
|     print(expected, "expected");
 | |
|     print(actual, "actual");
 | |
|     return false;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   Vector sub(const Vector &v, size_t i1, size_t i2) {
 | |
|     size_t n = i2-i1;
 | |
|     Vector v_return(n);
 | |
|     for( size_t i = 0; i < n; i++ )
 | |
|       v_return(i) = v(i1 + i);
 | |
|     return v_return;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   Vector emul(const Vector &a, const Vector &b) {
 | |
|   	size_t n = a.size();
 | |
| 		assert (b.size()==n);
 | |
| 		Vector c(n);
 | |
| 		for( size_t i = 0; i < n; i++ )
 | |
| 			c(i) = a(i)*b(i);
 | |
| 		return c;
 | |
| 		}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector ediv(const Vector &a, const Vector &b) {
 | |
|   	size_t n = a.size();
 | |
| 		assert (b.size()==n);
 | |
| 		Vector c(n);
 | |
| 		for( size_t i = 0; i < n; i++ )
 | |
| 			c(i) = a(i)/b(i);
 | |
| 		return c;
 | |
| 		}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector ediv_(const Vector &a, const Vector &b) {
 | |
|   	size_t n = a.size();
 | |
| 		assert (b.size()==n);
 | |
| 		Vector c(n);
 | |
| 		for( size_t i = 0; i < n; i++ ) {
 | |
| 			double ai = a(i), bi = b(i);
 | |
| 			c(i) = (bi==0.0 && ai==0.0) ? 0.0 : a(i)/b(i);
 | |
| 		}
 | |
| 		return c;
 | |
| 		}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   double sum(const Vector &a) {
 | |
|   	double result = 0.0;
 | |
|   	size_t n = a.size();
 | |
| 		for( size_t i = 0; i < n; i++ )
 | |
| 			result += a(i);
 | |
| 		return result;
 | |
| 		}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector reciprocal(const Vector &a) {
 | |
|   	size_t n = a.size();
 | |
|   	Vector b(n);
 | |
|   	for( size_t i = 0; i < n; i++ )
 | |
|   		b(i) = 1.0/a(i);
 | |
|   	return b;
 | |
|   	}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
| 	Vector esqrt(const Vector& v) {
 | |
| 		Vector s(v.size());
 | |
| 		transform(v.begin(), v.end(), s.begin(), ::sqrt);
 | |
| 		return s;
 | |
| 	}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
| 	Vector abs(const Vector& v) {
 | |
| 		Vector s(v.size());
 | |
| 		transform(v.begin(), v.end(), s.begin(), ::fabs);
 | |
| 		return s;
 | |
| 	}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   double max(const Vector &a) {
 | |
|   	return *(std::max_element(a.begin(), a.end()));
 | |
| 	}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector operator/(double s, const Vector& v) {
 | |
|     Vector result(v.size());
 | |
|     for(size_t i = 0; i < v.size(); i++)
 | |
|       result[i] = s / v[i];
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   pair<double, Vector > house(const Vector &x) {
 | |
| 	  const double x0 = x(0);
 | |
| 	  const double x02 = x0*x0;
 | |
| 
 | |
| 	  // old code - GSL verison was actually a bit slower
 | |
| 	  const double sigma = inner_prod(trans(x),x) - x02;
 | |
| 	  double beta = 0.0;
 | |
| 
 | |
| 	  Vector v(x); v(0) = 1.0;
 | |
| 
 | |
| 	  if( sigma == 0.0 )
 | |
| 		  beta = 0.0;
 | |
| 	  else {
 | |
| 		  double mu = sqrt(x02 + sigma);
 | |
| 		  if( x0 <= 0.0 )
 | |
| 			  v(0) = x0 - mu;
 | |
| 		  else
 | |
| 			  v(0) = -sigma / (x0 + mu);
 | |
| 
 | |
| 		  const double v02 = v(0)*v(0);
 | |
| 		  beta = 2.0 * v02 / (sigma + v02);
 | |
| 		  v = v / v(0);
 | |
| 	  }
 | |
| 	  return make_pair(beta, v);
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
| 	// Fast version *no error checking* !
 | |
| 	// Pass in initialized vector of size m or will crash !
 | |
| 	double weightedPseudoinverse(const Vector& a, const Vector& weights,
 | |
| 			Vector& pseudo) {
 | |
| 
 | |
| 		size_t m = weights.size();
 | |
| 		static const double inf = std::numeric_limits<double>::infinity();
 | |
| 
 | |
| 		// Check once for zero entries of a. TODO: really needed ?
 | |
| 		vector<bool> isZero;
 | |
| 		for (size_t i = 0; i < m; ++i) isZero.push_back(fabs(a[i]) < 1e-9);
 | |
| 
 | |
| 		// If there is a valid (a!=0) constraint (sigma==0) return the first one
 | |
| 		for (size_t i = 0; i < m; ++i)
 | |
| 			if (weights[i] == inf && !isZero[i]) {
 | |
| 				pseudo = delta(m, i, 1 / a[i]);
 | |
| 				return inf;
 | |
| 			}
 | |
| 
 | |
| 		// Form psuedo-inverse inv(a'inv(Sigma)a)a'inv(Sigma)
 | |
| 		// For diagonal Sigma, inv(Sigma) = diag(precisions)
 | |
| 		double precision = 0;
 | |
| 		for (size_t i = 0; i < m; i++) {
 | |
| 			double ai = a[i];
 | |
| 			if (!isZero[i]) // also catches remaining sigma==0 rows
 | |
| 				precision += weights[i] * (ai * ai);
 | |
| 		}
 | |
| 
 | |
| 		// precision = a'inv(Sigma)a
 | |
| 		if (precision < 1e-9)
 | |
| 			for (size_t i = 0; i < m; i++)
 | |
| 				pseudo[i] = 0;
 | |
| 		else {
 | |
| 			// emul(precisions,a)/precision
 | |
| 			double variance = 1.0 / precision;
 | |
| 			for (size_t i = 0; i < m; i++)
 | |
| 				pseudo[i] = isZero[i] ? 0 : variance * weights[i] * a[i];
 | |
| 		}
 | |
| 		return precision; // sum of weights
 | |
| 	}
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   // Slow version with error checking
 | |
|   pair<Vector, double>
 | |
|   weightedPseudoinverse(const Vector& a, const Vector& weights) {
 | |
| 	  size_t m = weights.size();
 | |
| 	  if (a.size() != m)
 | |
| 		  throw invalid_argument("a and weights have different sizes!");
 | |
| 	  Vector pseudo(m);
 | |
|   	double precision = weightedPseudoinverse(a, weights, pseudo);
 | |
| 	  return make_pair(pseudo, precision);
 | |
|   }
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector concatVectors(const std::list<Vector>& vs)
 | |
|   {
 | |
|     size_t dim = 0;
 | |
|     BOOST_FOREACH(Vector v, vs)
 | |
|       dim += v.size();
 | |
| 
 | |
|     Vector A(dim);
 | |
|     size_t index = 0;
 | |
|     BOOST_FOREACH(Vector v, vs) {
 | |
|       for(size_t d = 0; d < v.size(); d++)
 | |
|         A(d+index) = v(d);
 | |
|       index += v.size();
 | |
|     }
 | |
| 
 | |
|     return A;
 | |
|   }
 | |
| 
 | |
|   /* ************************************************************************* */
 | |
|   Vector concatVectors(size_t nrVectors, ...)
 | |
|   {
 | |
|     va_list ap;
 | |
|     list<Vector> vs;
 | |
|     va_start(ap, nrVectors);
 | |
|     for( size_t i = 0 ; i < nrVectors ; i++) {
 | |
|     	Vector* V = va_arg(ap, Vector*);
 | |
|       vs.push_back(*V);
 | |
|     }
 | |
|     va_end(ap);
 | |
|     return concatVectors(vs);
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   Vector rand_vector_norm(size_t dim, double mean, double sigma)
 | |
|   {
 | |
|     boost::normal_distribution<double> norm_dist(mean, sigma);
 | |
|     boost::variate_generator<boost::minstd_rand&, boost::normal_distribution<double> > norm(generator, norm_dist);
 | |
|     
 | |
|     Vector v(dim);
 | |
|     Vector::iterator it_v;
 | |
|     for(it_v=v.begin(); it_v!=v.end(); it_v++)
 | |
|       *it_v = norm();
 | |
|     
 | |
|     return v;
 | |
|   }
 | |
|   
 | |
|   /* ************************************************************************* */
 | |
|   
 | |
| } // namespace gtsam
 |