394 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
		
		
			
		
	
	
			394 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
|  | /**
 | ||
|  |  * @file    Matrix.h | ||
|  |  * @brief   typedef and functions to augment Boost's ublas::matrix<double> | ||
|  |  * @author  Christian Potthast | ||
|  |  * @author  Kai Ni | ||
|  |  * @author  Frank Dellaert | ||
|  |  */ | ||
|  | 
 | ||
|  | // \callgraph
 | ||
|  | 
 | ||
|  | #pragma once
 | ||
|  | 
 | ||
|  | #include <list>
 | ||
|  | #include <boost/format.hpp>
 | ||
|  | #include <boost/numeric/ublas/matrix.hpp>
 | ||
|  | #include <boost/tuple/tuple.hpp>
 | ||
|  | #include "Vector.h"
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Vector is a *global* typedef | ||
|  |  * wrap-matlab does this typedef as well | ||
|  |  * we use the default < double,row_major,unbounded_array<double> > | ||
|  |  */ | ||
|  | 
 | ||
|  | #if ! defined (MEX_H)
 | ||
|  | typedef boost::numeric::ublas::matrix<double> Matrix; | ||
|  | #endif
 | ||
|  | 
 | ||
|  | namespace gtsam { | ||
|  | 
 | ||
|  | /**
 | ||
|  |  *  constructor with size and initial data, row order ! | ||
|  |  */ | ||
|  | Matrix Matrix_(size_t m, size_t n, const double* const data); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  *  constructor with size and vector data, column order !!! | ||
|  |  */ | ||
|  | Matrix Matrix_(size_t m, size_t n, const Vector& v); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  *  constructor from Vector yielding v.size()*1 vector | ||
|  |  */ | ||
|  | inline Matrix Matrix_(const Vector& v) { return Matrix_(v.size(),1,v);} | ||
|  | 
 | ||
|  | /**
 | ||
|  |  *  nice constructor, dangerous as number of arguments must be exactly right | ||
|  |  *  and you have to pass doubles !!! always use 0.0 never 0 | ||
|  | */ | ||
|  | Matrix Matrix_(size_t m, size_t n, ...); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * MATLAB like constructors | ||
|  |  */ | ||
|  | Matrix zeros(size_t m, size_t n); | ||
|  | Matrix eye(size_t m, size_t n); | ||
|  | inline Matrix eye( size_t m ) { return eye(m,m); } | ||
|  | Matrix diag(const Vector& v); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * equals with an tolerance | ||
|  |  */ | ||
|  | bool equal_with_abs_tol(const Matrix& A, const Matrix& B, double tol = 1e-9); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * equality is just equal_with_abs_tol 1e-9 | ||
|  |  */ | ||
|  | inline bool operator==(const Matrix& A, const Matrix& B) { | ||
|  |   return equal_with_abs_tol(A,B,1e-9); | ||
|  | } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * inequality  | ||
|  |  */ | ||
|  | inline bool operator!=(const Matrix& A, const Matrix& B) { | ||
|  |   return !(A==B); | ||
|  |  } | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * equals with an tolerance, prints out message if unequal | ||
|  |  */ | ||
|  | bool assert_equal(const Matrix& A, const Matrix& B, double tol = 1e-9); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * equals with an tolerance, prints out message if unequal | ||
|  |  */ | ||
|  | bool assert_equal(const std::list<Matrix>& As, const std::list<Matrix>& Bs, double tol = 1e-9); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * check whether the rows of two matrices are linear indepdent | ||
|  |  */ | ||
|  | bool linear_dependent(const Matrix& A, const Matrix& B, double tol = 1e-9); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * overload * for matrix-vector multiplication (as BOOST does not) | ||
|  |  */ | ||
|  | inline Vector operator*(const Matrix& A, const Vector & v) { return prod(A,v);} | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * BLAS Level-2 style e <- e + alpha*A*x | ||
|  |  */ | ||
|  | void multiplyAdd(double alpha, const Matrix& A, const Vector& x, Vector& e); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * BLAS Level-2 style e <- e + A*x | ||
|  |  */ | ||
|  | void multiplyAdd(const Matrix& A, const Vector& x, Vector& e); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * overload ^ for trans(A)*v | ||
|  |  * We transpose the vectors for speed. | ||
|  |  */ | ||
|  | Vector operator^(const Matrix& A, const Vector & v); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * BLAS Level-2 style x <- x + alpha*A'*e | ||
|  |  */ | ||
|  | void transposeMultiplyAdd(double alpha, const Matrix& A, const Vector& e, Vector& x); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * BLAS Level-2 style x <- x + A'*e | ||
|  |  */ | ||
|  | void transposeMultiplyAdd(const Matrix& A, const Vector& e, Vector& x); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * BLAS Level-2 style x <- x + alpha*A'*e | ||
|  |  */ | ||
|  | void transposeMultiplyAdd(double alpha, const Matrix& A, const Vector& e, SubVector x); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * overload * for vector*matrix multiplication (as BOOST does not) | ||
|  |  */ | ||
|  | inline Vector operator*(const Vector & v, const Matrix& A) { return prod(v,A);} | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * overload * for matrix multiplication (as BOOST does not) | ||
|  |  */ | ||
|  | inline Matrix operator*(const Matrix& A, const Matrix& B) { return prod(A,B);} | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * convert to column vector, column order !!! | ||
|  |  */ | ||
|  | Vector Vector_(const Matrix& A); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * print a matrix | ||
|  |  */ | ||
|  | void print(const Matrix& A, const std::string& s = "", std::ostream& stream = std::cout); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * save a matrix to file, which can be loaded by matlab | ||
|  |  */ | ||
|  | void save(const Matrix& A, const std::string &s, const std::string& filename); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * extract submatrix, slice semantics, i.e. range = [i1,i2[ excluding i2 | ||
|  |  * @param A matrix | ||
|  |  * @param i1 first row index | ||
|  |  * @param i2 last  row index + 1 | ||
|  |  * @param j1 first col index | ||
|  |  * @param j2 last  col index + 1 | ||
|  |  * @return submatrix A(i1:i2-1,j1:j2-1) | ||
|  |  */ | ||
|  | Matrix sub(const Matrix& A, size_t i1, size_t i2, size_t j1, size_t j2); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * insert a submatrix IN PLACE at a specified location in a larger matrix | ||
|  |  * NOTE: there is no size checking | ||
|  |  * @param large matrix to be updated | ||
|  |  * @param small matrix to be inserted | ||
|  |  * @param i is the row of the upper left corner insert location | ||
|  |  * @param j is the column of the upper left corner insert location | ||
|  |  */ | ||
|  | void insertSub(Matrix& big, const Matrix& small, size_t i, size_t j); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * extracts a column from a matrix | ||
|  |  * NOTE: using this without the underscore is the ublas version! | ||
|  |  * @param matrix to extract column from | ||
|  |  * @param index of the column | ||
|  |  * @return the column in vector form | ||
|  |  */ | ||
|  | Vector column_(const Matrix& A, size_t j); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * inserts a column into a matrix IN PLACE | ||
|  |  * NOTE: there is no size checking | ||
|  |  * Alternate form allows for vectors smaller than the whole column to be inserted | ||
|  |  * @param A matrix to be modified in place | ||
|  |  * @param col is the vector to be inserted | ||
|  |  * @param j is the index to insert the column | ||
|  |  */ | ||
|  | void insertColumn(Matrix& A, const Vector& col, size_t j); | ||
|  | void insertColumn(Matrix& A, const Vector& col, size_t i, size_t j); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * extracts a row from a matrix | ||
|  |  * @param matrix to extract row from | ||
|  |  * @param index of the row | ||
|  |  * @return the row in vector form | ||
|  |  */ | ||
|  | Vector row_(const Matrix& A, size_t j); | ||
|  | 
 | ||
|  | // left multiply with scalar
 | ||
|  | //inline Matrix operator*(double s, const Matrix& A) { return A*s;}
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * solve AX=B via in-place Lu factorization and backsubstitution | ||
|  |  * After calling, A contains LU, B the solved RHS vectors | ||
|  |  */ | ||
|  | void solve(Matrix& A, Matrix& B); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * invert A | ||
|  |  */ | ||
|  | Matrix inverse(const Matrix& A); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * QR factorization, inefficient, best use imperative householder below | ||
|  |  * m*n matrix -> m*m Q, m*n R | ||
|  |  * @param A a matrix | ||
|  |  * @return <Q,R> rotation matrix Q, upper triangular R | ||
|  |  */  | ||
|  | std::pair<Matrix,Matrix> qr(const Matrix& A); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Imperative version of Householder rank 1 update | ||
|  |  */ | ||
|  | void householder_update(Matrix &A, size_t j, double beta, const Vector& vjm); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Imperative algorithm for in-place full elimination with | ||
|  |  * weights and constraint handling | ||
|  |  * @param A is a matrix to eliminate | ||
|  |  * @param b is the rhs | ||
|  |  * @param sigmas is a vector of the measurement standard deviation | ||
|  |  * @return list of r vectors, d  and sigma | ||
|  |  */ | ||
|  | std::list<boost::tuple<Vector, double, double> > | ||
|  | weighted_eliminate(Matrix& A, Vector& b, const Vector& sigmas); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Householder tranformation, Householder vectors below diagonal | ||
|  |  * @param k number of columns to zero out below diagonal | ||
|  |  * @param A matrix | ||
|  |  * @return nothing: in place !!! | ||
|  |  */ | ||
|  | void householder_(Matrix& A, size_t k); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Householder tranformation, zeros below diagonal | ||
|  |  * @param k number of columns to zero out below diagonal | ||
|  |  * @param A matrix | ||
|  |  * @return nothing: in place !!! | ||
|  |  */ | ||
|  | void householder(Matrix& A, size_t k); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Householder tranformation, zeros below diagonal | ||
|  |  * @param k number of columns to zero out below diagonal | ||
|  |  * @return nothing: in place !!! | ||
|  |  */ | ||
|  | #ifdef GT_USE_LAPACK
 | ||
|  | #ifdef YA_BLAS
 | ||
|  | void householder(Matrix &A); | ||
|  | #endif
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * backSubstitute U*x=b | ||
|  |  * @param U an upper triangular matrix | ||
|  |  * @param b an RHS vector | ||
|  |  * @param unit, set true if unit triangular | ||
|  |  * @return the solution x of U*x=b | ||
|  |  * TODO: use boost | ||
|  |  */ | ||
|  | Vector backSubstituteUpper(const Matrix& U, const Vector& b, bool unit=false); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * backSubstitute x'*U=b' | ||
|  |  * @param U an upper triangular matrix | ||
|  |  * @param b an RHS vector | ||
|  |  * @param unit, set true if unit triangular | ||
|  |  * @return the solution x of x'*U=b' | ||
|  |  * TODO: use boost | ||
|  |  */ | ||
|  | Vector backSubstituteUpper(const Vector& b, const Matrix& U, bool unit=false); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * backSubstitute L*x=b | ||
|  |  * @param L an lower triangular matrix | ||
|  |  * @param b an RHS vector | ||
|  |  * @param unit, set true if unit triangular | ||
|  |  * @return the solution x of L*x=b | ||
|  |  * TODO: use boost | ||
|  |  */  | ||
|  | Vector backSubstituteLower(const Matrix& L, const Vector& d, bool unit=false); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * create a matrix by stacking other matrices | ||
|  |  * Given a set of matrices: A1, A2, A3... | ||
|  |  * @return combined matrix [A1; A2; A3] | ||
|  |  */ | ||
|  | Matrix stack(size_t nrMatrices, ...); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * create a matrix by concatenating | ||
|  |  * Given a set of matrices: A1, A2, A3... | ||
|  |  * If all matrices have the same size, specifying single matrix dimensions | ||
|  |  * will avoid the lookup of dimensions | ||
|  |  * @param matrices is a vector of matrices in the order to be collected | ||
|  |  * @param m is the number of rows of a single matrix | ||
|  |  * @param n is the number of columns of a single matrix | ||
|  |  * @return combined matrix [A1 A2 A3] | ||
|  |  */ | ||
|  | Matrix collect(const std::vector<const Matrix *>& matrices, size_t m = 0, size_t n = 0); | ||
|  | Matrix collect(size_t nrMatrices, ...); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * scales a matrix row or column by the values in a vector | ||
|  |  * Arguments (Matrix, Vector) scales the columns, | ||
|  |  * (Vector, Matrix) scales the rows | ||
|  |  */ | ||
|  | void vector_scale_inplace(const Vector& v, Matrix& A); // row
 | ||
|  | Matrix vector_scale(const Vector& v, const Matrix& A); // row
 | ||
|  | Matrix vector_scale(const Matrix& A, const Vector& v); // column
 | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * skew symmetric matrix returns this: | ||
|  |  *   0  -wz   wy | ||
|  |  *  wz    0  -wx | ||
|  |  * -wy   wx    0 | ||
|  |  * @param wx 3 dimensional vector | ||
|  |  * @param wy | ||
|  |  * @param wz | ||
|  |  * @return a 3*3 skew symmetric matrix | ||
|  | */ | ||
|  | Matrix skewSymmetric(double wx, double wy, double wz); | ||
|  | inline Matrix skewSymmetric(const Vector& w) { return skewSymmetric(w(0),w(1),w(2));} | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * SVD computes economy SVD A=U*S*V' | ||
|  |  * @param A an m*n matrix | ||
|  |  * @param U output argument: rotation matrix | ||
|  |  * @param S output argument: vector of singular values, sorted by default, pass false as last argument to avoid sorting!!! | ||
|  |  * @param V output argument: rotation matrix | ||
|  |  * @param sort boolean flag to sort singular values and V | ||
|  |  * if m > n then U*S*V' = (m*n)*(n*n)*(n*n) (the m-n columns of U are of no use) | ||
|  |  * if m < n then U*S*V' = (m*m)*(m*m)*(m*n) (the n-m columns of V are of no use) | ||
|  |  */  | ||
|  | void svd(const Matrix& A, Matrix& U, Vector& S, Matrix& V, bool sort=true); | ||
|  | 
 | ||
|  | /*
 | ||
|  |  * In place SVD, will throw an exception when m < n | ||
|  |  * @param A an m*n matrix is modified to contain U | ||
|  |  * @param S output argument: vector of singular values, sorted by default, pass false as last argument to avoid sorting!!! | ||
|  |  * @param V output argument: rotation matrix | ||
|  |  * @param sort boolean flag to sort singular values and V | ||
|  |  * if m > n then U*S*V' = (m*n)*(n*n)*(n*n) (the m-n columns of U are of no use) | ||
|  |  */ | ||
|  | void svd(Matrix& A, Vector& S, Matrix& V, bool sort=true); | ||
|  | 
 | ||
|  | /** Use SVD to calculate inverse square root of a matrix */ | ||
|  | Matrix inverse_square_root(const Matrix& A); | ||
|  | 
 | ||
|  | /** Use SVD to calculate the positive square root of a matrix */ | ||
|  | Matrix square_root_positive(const Matrix& A); | ||
|  | 
 | ||
|  | /** Calculate the LL^t decomposition of a S.P.D matrix */ | ||
|  | Matrix LLt(const Matrix& A); | ||
|  | 
 | ||
|  | /** Calculate the R^tR decomposition of a S.P.D matrix */ | ||
|  | Matrix RtR(const Matrix& A); | ||
|  | 
 | ||
|  | /** Return the inverse of a S.P.D. matrix.  Inversion is done via Cholesky decomposition. */ | ||
|  | Matrix cholesky_inverse(const Matrix &A); | ||
|  | 
 | ||
|  | /** Solve Ax=b with S.P.D. matrix using Davis' LDL code */ | ||
|  | Vector solve_ldl(const Matrix& A, const Vector& b); | ||
|  | 
 | ||
|  | /**
 | ||
|  |  * Numerical exponential map, naive approach, not industrial strength !!! | ||
|  |  * @param A matrix to exponentiate | ||
|  |  * @param K number of iterations | ||
|  |  */ | ||
|  | Matrix expm(const Matrix& A, size_t K=7); | ||
|  | 
 | ||
|  | // macro for unit tests
 | ||
|  | #define EQUALITY(expected,actual)\
 | ||
|  |   { if (!assert_equal(expected,actual)) \ | ||
|  |     result_.addFailure(Failure(name_, __FILE__, __LINE__, #expected, #actual)); } | ||
|  | 
 | ||
|  | } // namespace gtsam
 |