//-*-c++-*- #ifndef VEC_H #define VEC_H /** * @file vec.h * @brief Basic static vector type, templated in type and size * @author James R. Diebel, Stanford University * * - History: * - 31 July 2005 - Started (JD) * - 30 Aug 2005 - Commented and tested (KH) * - 30 Aug 2005 - forked off from matmath.h */ #include #include #include #include #include #include #undef min #undef max /** * @namespace sla * @brief Simple Linear Algebra - library of matrix and vector classes */ namespace sla { ///////////////////////////////////////////////////////////////////////////// // DECLARATIONS ///////////////////////////////////////////////////////////////////////////// // Forward declarations template class Vec; // M-d vector template class Mat; // MxN Matrix template class SMat; // MxM Square Matrix //////////////////// Vec //////////////////// /** * An M-Dimensional statically allocated vector. * Represents an M dimensional vector of type T */ template class Vec { public: // Data T x[M]; ///< storage array // Constructors Vec(); Vec(const T* d); Vec(const T a); Vec(const Vec& v); // Cast Operation template Vec(const Vec& v); // Mutators void set(const T* d, const int len = M); void set(const T a, const int len = M); void set(const Vec& v, const int len = M); Vec& operator = (const T a); Vec& operator = (const T* d); Vec& operator = (const Vec& v); template void setSubVec(const int i, const Vec& v); template void addToSubVec(const int i, const Vec& v); // Casting Mutators template void set(const Vec& v); template Vec& operator = (const Vec& v); // Accessors const T& operator () (const int i) const; T& operator () (const int i); const T& end(const int i = 0) const; T& end(const int i = 0); template Vec getSubVec(const int i) const; // Norms and Normalize T norm() const; T normSqr() const; T pnorm(float p) const; T normalize(); Vec normalized() const; // Reductions: Max/Min, Sum/Product T max() const; T min() const; T sum() const; T prod() const; int argmax(int active_m = M) const; // Elementwise operations void perform(T (*mathFun)(T)); void perform(T (*mathFun)(T,T), const T arg2); void perform(T (*mathFun)(T,T), const Vec& v); Vec performed(T (*mathFun)(T)); Vec performed(T (*mathFun)(T,T), const T arg2); Vec performed(T (*mathFun)(T,T), const Vec& v); // Dot and Outer Products T dot(const Vec& v) const; SMat outer(const Vec& v) const; SMat outer() const; // Random vectors and sorting etc static Vec uniformRand(const T a = T(0), const T b = T(1)); static Vec normalRand(const T mean = T(0), const T stdev = T(1)); void sort(bool ascending = true); Vec sorted(bool ascending = true); int find(const T element, const int active_m = M) const; bool contains(const T element, const int active_m = M) const; bool containsAll(const Vec& v, const int active_m = M) const; void shiftBack(const T element); // Addition and subtraction Vec operator + (const Vec& v) const; void operator += (const Vec& v); Vec operator - (const Vec& v) const; void operator -= (const Vec& v); Vec operator - () const; Vec operator + (const T a) const; void operator += (const T a); Vec operator - (const T a) const; void operator -= (const T a); // Multiplication and division Vec operator * (const T a) const; Vec operator / (const T a) const; void operator *= (const T a); void operator /= (const T a); // Equality and inequality tests Vec operator == (const Vec& v) const; Vec operator != (const Vec& v) const; Vec operator >= (const Vec& v) const; Vec operator <= (const Vec& v) const; Vec operator > (const Vec& v) const; Vec operator < (const Vec& v) const; int compareTo(const Vec& v) const; bool equalTo(const Vec& v, const int active_m = M) const; bool nearTo(const Vec& v, const T tol = T(0), const int active_m = M) const; // Element-wise operations Vec operator * (const Vec& v) const; Vec operator / (const Vec& v) const; void operator *= (const Vec& v); void operator /= (const Vec& v); // Serialization void writeTo(std::ostream& os) const; void readFrom(std::istream& is); void print(std::ostream& os = std::cout, const int active_m = M) const; void matlab_print(const std::string name, std::ostream& os = std::cout, const int active_m = M) const; }; // Global operators for cases where Vec // is the second argument in a binary operator template Vec operator + (const T a, const Vec& v); template Vec operator - (const T a, const Vec& v); template Vec operator * (const T a, const Vec& v); // Qsort-style comparison function template int compareVecAscending(const void* a, const void* b); template int compareVecDescending(const void* a, const void* b); template int compareVecElementAscending(const void* a, const void* b); template int compareVecElementDescending(const void* a, const void* b); // ASCII stream IO template std::ostream& operator<<(std::ostream& os, const Vec& vec); // Declare a few common typdefs typedef Vec Vec5b; typedef Vec Vec5c; typedef Vec Vec5uc; typedef Vec Vec5i; typedef Vec Vec5f; typedef Vec Vec5d; typedef Vec Vec6b; typedef Vec Vec6c; typedef Vec Vec6uc; typedef Vec Vec6i; typedef Vec Vec6f; typedef Vec Vec6d; typedef Vec Vec8b; typedef Vec Vec8c; typedef Vec Vec8uc; typedef Vec Vec8i; typedef Vec Vec8f; typedef Vec Vec8d; //////////////////////////////////////////////////////////////////////////// // DEFINITIONS //////////////////////////////////////////////////////////////////////////// //////////////////// Vec //////////////////// // Constructors /** Ctor that does no initalization. */ template inline Vec::Vec() {} /** Ctor that initializes elements from an array. * @param d pointer to the initalization array */ template inline Vec::Vec(const T* d) { set(d); } /** Ctor that initializes all elements from a scalar. * @param a the value to assign to all elements */ template inline Vec::Vec(const T a) { set(a); } /** Ctor that initialized from vector of different type * @param a the value to assign to all elements */ template inline Vec::Vec(const Vec& v) { set(v); } // Casting Operation /** Casting Ctor that initializes from passed vector. * @param a the value to assign to all elements */ template template inline Vec::Vec(const Vec& v) { set(v); } // Mutators /** Set all elements equal to a scalar. * @param a the value to assign to all elements */ template inline void Vec::set(const T a, const int len) { for (int i=0;i inline void Vec::set(const T* d, const int len) { for (int i=0;i inline void Vec::set(const Vec& v, const int len) { for (int i=0;i inline Vec& Vec::operator = (const T a) { set(a); return *this; } /** Set all elements from an array. * @param d pointer to the initalization array */ template inline Vec& Vec::operator = (const T* d) { set(d); return *this; } /** Set this vector equal to passed vector * @param v the vector to replicate */ template inline Vec& Vec::operator = (const Vec& v) { set(v); return *this; } /** Set a subvector by replacing elements from i onward with the * elements from v. * Replaces elements till the end of either vector is reached. * @param v the vector from which to copy values * @param i the (zero based) index of the start of the subvector */ template template inline void Vec::setSubVec(const int i, const Vec& v) { for (int j=i,k=0;j template inline void Vec::addToSubVec(const int i, const Vec& v) { for (int j=i,k=0;j template inline void Vec::set(const Vec& v) { for (int i=0;i template inline Vec& Vec::operator = (const Vec& v) { set(v); return *this; } // Accessors /** Get an element of the vector (by value). * Does bounds checking if MATMATH_CHECK_BOUNDS is set * @param i the (zero based) index into the vector */ template inline const T& Vec::operator () (const int i) const { #if MATMATH_CHECK_BOUNDS if (i < 0 || i >= M) { std::cerr << "Vec<" << M << ">::(" << i << "): index out of range\n"; std::cerr << std::flush; assert(0); exit(1); } #endif return x[i]; } /** Get an element of the vector (by reference). * Does bounds checking if MATMATH_CHECK_BOUNDS is set * @param i the (zero based) index into the vector */ template inline T& Vec::operator () (const int i) { #if MATMATH_CHECK_BOUNDS if (i < 0 || i >= M) { std::cerr << "&Vec<" << M << ">::(" << i << "): index out of range\n"; std::cerr << std::flush; assert(0); exit(1); } #endif return x[i]; } /** Get an element of the vector (by reference), starting from the end of the vector. * Indices need to be negative, positive indices lead to out-of-bounds accessing. * Does bounds checking if MATMATH_CHECK_BOUNDS is set * @param i the (zero based) index into the vector */ template inline const T& Vec::end(const int i) const { return operator()(M-1+i); } /** Get an element of the vector (by reference), starting from the end of the vector. * Indices need to be negative, positive indices lead to out-of-bounds accessing. * Does bounds checking if MATMATH_CHECK_BOUNDS is set * @param i the (zero based) index into the vector */ template inline T& Vec::end(const int i) { return operator()(M-1+i); } /** Get the subvector of length N starting at element i * @param i the (zero based) index of the first element of subvector */ template template inline Vec Vec::getSubVec(const int i) const { Vec v(T(0)); for (int j=i,k=0;j inline T Vec::norm() const { return T(sqrt(double(normSqr()))); } /** Calculate the square of the euclidan norm (2-norm). * @return the sum of squares of the elements */ template inline T Vec::normSqr() const { T sum = T(0); for (int i=0;i inline T Vec::pnorm(float p) const { T sum = T(0); for (int i=0;i inline T Vec::normalize() { T l = norm(); if (l > T(0)) for (int i=0;i inline Vec Vec::normalized() const { Vec v(x); v.normalize(); return v; } // Maximum/Minimum value and Sum /** Find the maximum value of the vector * @returns the maximum value */ template inline T Vec::max() const { T m = x[0]; for (int i=1;im) m = x[i]; return m; } /** Find the minimum value of the vector * @returns the minimum value */ template inline T Vec::min() const { T m = x[0]; for (int i=1;i inline T Vec::sum() const { T s = T(0); for (int i=0;i inline T Vec::prod() const { T p = T(1); for (int i=0;i inline int Vec::argmax(int active_m) const { int im = 0; for (int i=1;ix[im]) im = i; return im; } // General elementwise operations /** Pass each element through the given single-arg math function, replacing the current vector with the result. */ template inline void Vec::perform(T (*mathFun)(T)) { for (int i=0;i inline void Vec::perform(T (*mathFun)(T,T), const T arg2) { for (int i=0;i inline void Vec::perform(T (*mathFun)(T,T), const Vec& v) { for (int i=0;i inline Vec Vec::performed(T (*mathFun)(T)) { Vec v; for (int i=0;i inline Vec Vec::performed(T (*mathFun)(T,T), const T arg2) { Vec v; for (int i=0;i inline Vec Vec::performed(T (*mathFun)(T,T), const Vec& vp) { Vec v; for (int i=0;i inline T Vec::dot(const Vec& v) const { T sum = T(0); for (int i=0;i inline SMat Vec::outer(const Vec& v) const { SMat m; for (int i=0,k=0;i inline SMat Vec::outer() const { SMat m; for (int i=0,k=0;i inline Vec Vec::uniformRand(const T a, const T b) { Vec v; for (int i=0;i(a,b); return v; } /** Create vector with samples from a normal distribution. * @param mean mean of normal distribution * @param stdev standard deviation of normal distribution * @return vector of normal samples */ template inline Vec Vec::normalRand(const T mean, const T stdev) { Vec v; for (int i=0;i(mean, stdev); return v; } /** Sort elements in increasing order. * @return sorted vector */ template inline void Vec::sort(bool ascending) { int count; do { count = 0; for (int i=0;i<(M-1);i++) { if (ascending) { if (x[i] > x[i+1]) { swap(x[i],x[i+1]); count++; } } else { if (x[i] < x[i+1]) { swap(x[i+1],x[i]); count++; } } } } while (count > 0); } /** Create a copy of the vector with elements sorted in increasing order. * @return sorted vector */ template inline Vec Vec::sorted(bool ascending) { Vec v(x); v.sort(ascending); return v; } /** Finds the index of an element in the vector * @param element is the element to find * @return an int: the index of the element. -1 if it could not be found. */ template inline int Vec::find(const T element, const int active_m) const { for (int i=0;i inline bool Vec::contains(const T element, const int active_m) const { return find(element, active_m) >= 0; } /** Checks if this vector contains all the elements of the given vector, up to element active_m * @param v is the other vector to which we are comparing * @return a bool: true if contains all of other elements */ template inline bool Vec::containsAll(const Vec& v, const int active_m) const { for (int i=0;i inline void Vec::shiftBack(const T element) { for (int i=1;i inline Vec Vec::operator + (const Vec& v) const { Vec vp; for (int i=0;i inline void Vec::operator += (const Vec& v) { for (int i=0;i inline Vec Vec::operator - (const Vec& v) const { Vec vp; for (int i=0;i inline void Vec::operator -= (const Vec& v) { for (int i=0;i inline Vec Vec::operator - () const { Vec vp; for (int i=0;i inline Vec Vec::operator + (const T a) const { Vec vp; for (int i=0;i inline void Vec::operator += (const T a) { for (int i=0;i inline Vec Vec::operator - (const T a) const { Vec vp; for (int i=0;i inline void Vec::operator -= (const T a) { for (int i=0;i inline Vec operator + (const T a, const Vec& v) { Vec vp; for (int i=0;i inline Vec operator - (const T a, const Vec& v) { Vec vp; for (int i=0;i inline Vec Vec::operator * (const T a) const { Vec vp; for (int i=0;i inline Vec Vec::operator / (const T a) const { Vec vp; for (int i=0;i inline void Vec::operator *= (const T a) { for (int i=0;i inline void Vec::operator /= (const T a) { for (int i=0;i inline Vec operator * (const T a, const Vec& v) { Vec vp; for (int i=0;i inline Vec Vec::operator == (const Vec& v) const { Vec b(false); for (int i=0;i inline Vec Vec::operator != (const Vec& v) const { Vec b(false); for (int i=0;i inline Vec Vec::operator >= (const Vec& v) const { Vec b(false); for (int i=0;i= v.x[i]) b.x[i] = true; return b; } /** Element-wise test for less or equal. * @return vector of boolean results */ template inline Vec Vec::operator <= (const Vec& v) const { Vec b(false); for (int i=0;i inline Vec Vec::operator > (const Vec& v) const { Vec b(false); for (int i=0;i v.x[i]) b.x[i] = true; return b; } /** Element-wise test for less. * @return vector of boolean results */ template inline Vec Vec::operator < (const Vec& v) const { Vec b(false); for (int i=0;i inline int Vec::compareTo(const Vec& v) const { int g=0, l=0; for (int i=0;i v.x[i]) g++; } if (l==M) return -1; else if (g==M) return 1; else return 0; } /** Compare the entire vector to the passed vector. * @returns true if all corresponding elements are equal */ template inline bool Vec::equalTo(const Vec& v, const int active_m) const { for (int i=0;i inline bool Vec::nearTo(const Vec& v, const T tol, const int active_m) const { for (int i=0;i tol) return false; return true; } /** General compare functions for use with QSort, etc. */ template inline int compareVecAscending(const void* a, const void* b) { T an = (*(Vec*)(a)).norm(); T bn = (*(Vec*)(b)).norm(); if (an == bn) return 0; else return 2*int(an > bn)-1; } template inline int compareVecDescending(const void* a, const void* b) { T an = (*(Vec*)(a)).norm(); T bn = (*(Vec*)(b)).norm(); if (an == bn) return 0; else return 2*int(an < bn)-1; } template inline int compareVecElementAscending(const void* a, const void* b) { T an = (*(Vec*)(a))(K); T bn = (*(Vec*)(b))(K); if (an == bn) return 0; else return 2*int(an > bn)-1; } template inline int compareVecElementDescending(const void* a, const void* b) { T an = (*(Vec*)(a))(K); T bn = (*(Vec*)(b))(K); if (an == bn) return 0; else return 2*int(an < bn)-1; } // Element-wise multiplication and division /** Element-wise multiplication. */ template inline Vec Vec::operator * (const Vec& v) const { Vec vp; for (int i=0;i inline Vec Vec::operator / (const Vec& v) const { Vec vp; for (int i=0;i inline void Vec::operator *= (const Vec& v) { for (int i=0;i inline void Vec::operator /= (const Vec& v) { for (int i=0;i inline void Vec::writeTo(std::ostream& os) const { os.write((char *)(x),M*sizeof(T)); } /** Restores state from a binary stream. */ template inline void Vec::readFrom(std::istream& is) { is.read((char *)(x),M*sizeof(T)); } /** Write state to stream as formated ASCII */ template void Vec::print(std::ostream& os, const int active_m) const { if (active_m<8) { Mat tmpMat; tmpMat.setRow(0,*this); tmpMat.print(os,1,active_m); } else { Mat tmpMat; tmpMat.setCol(0,*this); tmpMat.print(os,active_m,1); } } /** Pretty-print in format easily imported into Matlab */ template void Vec::matlab_print(const std::string name, std::ostream& os, const int active_m) const { os << std::endl << name << " = ... " << std::endl; print(os, active_m); if (active_m<8) os << "\'"; os << ";" << std::endl; } /** Write state to stream as formated ASCII */ template std::ostream& operator<<(std::ostream& os, const Vec& vec) { vec.print(os); return os; } } // end namespace sla #endif