480 lines
14 KiB
C++
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 "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
|