gtsam/base/Vector.cpp

480 lines
14 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 <fstream>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <stdio.h>
#ifdef WIN32
#include <Windows.h>
#endif
#include <boost/numeric/ublas/io.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/random/normal_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <gtsam/base/Vector.h>
using namespace std;
namespace ublas = boost::numeric::ublas;
namespace gtsam {
/* ************************************************************************* */
void odprintf_(const char *format, ostream& stream, ...) {
char buf[4096], *p = buf;
int n;
va_list args;
va_start(args, stream);
#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
stream << buf;
#endif
}
/* ************************************************************************* */
// copy and paste from above, as two functions can not be easily merged
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, ostream& stream) {
size_t n = v.size();
odprintf_("%s [", stream, s.c_str());
for(size_t i=0; i<n; i++)
odprintf_("%g%s", stream, v[i], (i<n-1 ? "; " : ""));
odprintf_("];\n", stream);
}
/* ************************************************************************* */
void save(const Vector& v, const string &s, const string& filename) {
fstream stream(filename.c_str(), fstream::out | fstream::app);
print(v, s + "=", stream);
stream.close();
}
/* ************************************************************************* */
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;
}
/* ************************************************************************* */
bool assert_equal(SubVector expected, SubVector 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;
}
/* ************************************************************************* */
bool assert_equal(ConstSubVector expected, ConstSubVector 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;
}
/* ************************************************************************* */
bool linear_dependent(const Vector& vec1, const Vector& vec2, double tol) {
if (vec1.size()!=vec2.size()) return false;
Vector::const_iterator it1 = vec1.begin();
Vector::const_iterator it2 = vec2.begin();
boost::optional<double> scale;
for(size_t i=0; i<vec1.size(); i++) {
if((fabs(it1[i])>tol&&fabs(it2[i])<tol) || (fabs(it1[i])<tol&&fabs(it2[i])>tol))
return false;
if(it1[i] == 0 && it2[i] == 0)
continue;
if (!scale)
scale = it1[i] / it2[i];
else if (fabs(it1[i] - it2[i] * (*scale)) > tol)
return false;
}
return scale.is_initialized();
}
/* ************************************************************************* */
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;
}
/* ************************************************************************* */
void subInsert(Vector& big, const Vector& small, size_t i) {
ublas::vector_range<Vector> colsubproxy(big, ublas::range (i, i+small.size()));
colsubproxy = small;
}
/* ************************************************************************* */
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()));
}
/* ************************************************************************* */
double dot(const Vector& a, const Vector& b) {
size_t n = a.size();
assert (b.size()==n);
double result = 0.0;
for (size_t i = 0; i < n; i++)
result += a[i] * b[i];
return result;
}
/* ************************************************************************* */
void scal(double alpha, Vector& x) {
size_t n = x.size();
for (size_t i = 0; i < n; i++)
x[i] *= alpha;
}
/* ************************************************************************* */
void axpy(double alpha, const Vector& x, Vector& y) {
size_t n = x.size();
assert (y.size()==n);
for (size_t i = 0; i < n; i++)
y[i] += alpha * x[i];
}
/* ************************************************************************* */
void axpy(double alpha, const Vector& x, SubVector y) {
size_t n = x.size();
assert (y.size()==n);
for (size_t i = 0; i < n; i++)
y[i] += alpha * x[i];
}
/* ************************************************************************* */
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;
}
/* ************************************************************************* */
// imperative version, pass in x
double houseInPlace(Vector &v) {
const double x0 = v(0);
const double x02 = x0*x0;
// old code - GSL verison was actually a bit slower
const double sigma = inner_prod(v,v) - x02;
v(0) = 1.0;
if( sigma == 0.0 )
return 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);
v = v / v(0);
return 2.0 * v02 / (sigma + v02);
}
}
/* ************************************************************************* */
pair<double, Vector > house(const Vector &x) {
Vector v(x);
double beta = houseInPlace(v);
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