/** * @file Matrix.cpp * @brief matrix class * @author Christian Potthast */ #include #include #include #include #include #include #include #include #include "Matrix.h" #include "Vector.h" #include "svdcmp.h" using namespace std; namespace ublas = boost::numeric::ublas; namespace gtsam { /* ************************************************************************* */ Matrix Matrix_( size_t m, size_t n, const double* const data) { Matrix A(m,n); copy(data, data+m*n, A.data().begin()); return A; } /* ************************************************************************* */ Matrix Matrix_( size_t m, size_t n, const Vector& v) { Matrix A(m,n); // column-wise copy for( size_t j = 0, k=0 ; j < n ; j++) for( size_t i = 0; i < m ; i++,k++) A(i,j) = v(k); return A; } /* ************************************************************************* */ Matrix Matrix_(size_t m, size_t n, ...) { Matrix A(m,n); va_list ap; va_start(ap, n); for( size_t i = 0 ; i < m ; i++) for( size_t j = 0 ; j < n ; j++) { double value = va_arg(ap, double); A(i,j) = value; } va_end(ap); return A; } /* ************************************************************************* */ /** create a matrix with value zero */ /* ************************************************************************* */ Matrix zeros( size_t m, size_t n ) { Matrix A(m,n, 0.0); return A; } /** * Identity matrix */ Matrix eye( size_t m, size_t n){ Matrix A = zeros(m,n); for(size_t i = 0; i tol) return false; } return true; } /* ************************************************************************* */ bool assert_equal(const Matrix& expected, const Matrix& actual, double tol) { if (equal_with_abs_tol(expected,actual,tol)) return true; size_t n1 = expected.size2(), m1 = expected.size1(); size_t n2 = actual.size2(), m2 = actual.size1(); cout << "not equal:" << endl; print(expected,"expected = "); print(actual,"actual = "); if(m1!=m2 || n1!=n2) cout << m1 << "," << n1 << " != " << m2 << "," << n2 << endl; else print(actual-expected, "actual - expected = "); return false; } /* ************************************************************************ */ /** negation */ /* ************************************************************************ */ /* Matrix operator-() const { size_t m = size1(),n=size2(); Matrix M(m,n); for(size_t i = 0; i < m; i++) for(size_t j = 0; j < n; j++) M(i,j) = -matrix_(i,j); return M; } */ /* ************************************************************************* */ Vector Vector_(const Matrix& A) { size_t m = A.size1(), n = A.size2(); Vector v(m*n); for( size_t j = 0, k=0 ; j < n ; j++) for( size_t i = 0; i < m ; i++,k++) v(k) = A(i,j); return v; } /* ************************************************************************* */ Vector column(const Matrix& A, size_t j) { if (j>=A.size2()) throw invalid_argument("Column index out of bounds!"); size_t m = A.size1(); Vector a(m); for (int i=0; i=A.size1()) throw invalid_argument("Row index out of bounds!"); size_t n = A.size2(); Vector a(n); for (int j=0; j(A, B); } /* ************************************************************************* */ Matrix inverse(const Matrix& originalA) { Matrix A(originalA); Matrix B = eye(A.size2()); solve(A,B); return B; } /* ************************************************************************* */ /** Householder QR factorization, Golub & Van Loan p 224, explicit version */ /* ************************************************************************* */ pair qr(const Matrix& A) { const size_t m = A.size1(), n = A.size2(), kprime = min(m,n); Matrix Q=eye(m,m),R(A); Vector v(m); // loop over the kprime first columns for(size_t j=0; j < kprime; j++){ // we now work on the matrix (m-j)*(n-j) matrix A(j:end,j:end) const size_t mm=m-j; // copy column from matrix to xjm, i.e. x(j:m) = A(j:m,j) Vector xjm(mm); for(size_t k = 0 ; k < mm; k++) xjm(k) = R(j+k, j); // calculate the Householder vector v double beta; Vector vjm; boost::tie(beta,vjm) = house(xjm); // pad with zeros to get m-dimensional vector v for(size_t k = 0 ; k < m; k++) v(k) = k > weighted_eliminate(Matrix& A, Vector& b, const Vector& sigmas) { size_t m = A.size1(), n = A.size2(); // get size(A) size_t maxRank = min(m,n); // create list list > results; Vector pseudo(m); // allocate storage for pseudo-inverse // TODO: calculate weights once // Vector weights = // We loop over all columns, because the columns that can be eliminated // are not necessarily contiguous. For each one, estimate the corresponding // scalar variable x as d-rS, with S the separator (remaining columns). // Then update A and b by substituting x with d-rS, zero-ing out x's column. for (int j=0; j=maxRank) break; // update A, b, expensive, suing outer product // A' \define A_{S}-a*r and b'\define b-d*a updateAb(A, b, j, a, r, d); } return results; } /* ************************************************************************* */ /** Imperative version of Householder QR factorization, Golub & Van Loan p 224 * version with Householder vectors below diagonal, as in GVL */ /* ************************************************************************* */ void householder_(Matrix &A, size_t k) { const size_t m = A.size1(), n = A.size2(), kprime = min(k,min(m,n)); // loop over the kprime first columns for(size_t j=0; j < kprime; j++){ // below, the indices r,c always refer to original A // copy column from matrix to xjm, i.e. x(j:m) = A(j:m,j) Vector xjm(m-j); for(size_t r = j ; r < m; r++) xjm(r-j) = A(r,j); // calculate the Householder vector double beta; Vector vjm; boost::tie(beta,vjm) = house(xjm); // do outer product update A = (I-beta vv')*A = A - v*(beta*A'*v)' = A - v*w' householder_update(A, j, beta, vjm) ; // the Householder vector is copied in the zeroed out part for( size_t r = j+1 ; r < m ; r++ ) A(r,j) = vjm(r-j); } // column j } /* ************************************************************************* */ /** version with zeros below diagonal */ /* ************************************************************************* */ void householder(Matrix &A, size_t k) { householder_(A,k); const size_t m = A.size1(), n = A.size2(), kprime = min(k,min(m,n)); for(size_t j=0; j < kprime; j++) for( size_t i = j+1 ; i < m ; i++ ) A(i,j) = 0.0; } /* ************************************************************************* */ Vector backSubstituteUpper(const Matrix& U, const Vector& b, bool unit) { size_t m = U.size1(), n = U.size2(); #ifndef NDEBUG if (m!=n) throw invalid_argument("backSubstituteUpper: U must be square"); #endif Vector result(n); for (size_t i = n; i > 0; i--) { double zi = b(i-1); for (size_t j = i+1; j <= n; j++) zi -= U(i-1,j-1) * result(j-1); if (!unit) zi /= U(i-1,i-1); result(i-1) = zi; } return result; } /* ************************************************************************* */ Vector backSubstituteUpper(const Vector& b, const Matrix& U, bool unit) { size_t m = U.size1(), n = U.size2(); #ifndef NDEBUG if (m!=n) throw invalid_argument("backSubstituteUpper: U must be square"); #endif Vector result(n); for (size_t i = 1; i <= n; i++) { double zi = b(i-1); for (size_t j = 1; j < i; j++) zi -= U(j-1,i-1) * result(j-1); if (!unit) zi /= U(i-1,i-1); result(i-1) = zi; } return result; } /* ************************************************************************* */ Vector backSubstituteLower(const Matrix& L, const Vector& b, bool unit) { size_t m = L.size1(), n = L.size2(); #ifndef NDEBUG if (m!=n) throw invalid_argument("backSubstituteLower: L must be square"); #endif Vector result(n); for (size_t i = 1; i <= n; i++) { double zi = b(i-1); for (size_t j = 1; j < i; j++) zi -= L(i-1,j-1) * result(j-1); if (!unit) zi /= L(i-1,i-1); result(i-1) = zi; } return result; } /* ************************************************************************* */ Matrix stack(size_t nrMatrices, ...) { int dimA1 = 0; int dimA2 = 0; va_list ap; va_start(ap, nrMatrices); for(size_t i = 0 ; i < nrMatrices ; i++) { Matrix *M = va_arg(ap, Matrix *); dimA1 += M->size1(); dimA2 = M->size2(); // TODO: should check if all the same ! } va_end(ap); va_start(ap, nrMatrices); Matrix A(dimA1, dimA2); int vindex = 0; for( size_t i = 0 ; i < nrMatrices ; i++) { Matrix *M = va_arg(ap, Matrix *); for(size_t d1 = 0; d1 < M->size1(); d1++) for(size_t d2 = 0; d2 < M->size2(); d2++) A(vindex+d1, d2) = (*M)(d1, d2); vindex += M->size1(); } return A; } /* ************************************************************************* */ Matrix collect(vector matrices) { int dimA1 = 0; int dimA2 = 0; BOOST_FOREACH(const Matrix* M, matrices) { dimA1 = M->size1(); // TODO: should check if all the same ! dimA2 += M->size2(); } Matrix A(dimA1, dimA2); int hindex = 0; BOOST_FOREACH(const Matrix* M, matrices) { for(size_t d1 = 0; d1 < M->size1(); d1++) for(size_t d2 = 0; d2 < M->size2(); d2++) A(d1, d2+hindex) = (*M)(d1, d2); hindex += M->size2(); } return A; } /* ************************************************************************* */ Matrix collect(size_t nrMatrices, ...) { vector matrices; va_list ap; va_start(ap, nrMatrices); for( size_t i = 0 ; i < nrMatrices ; i++) { Matrix *M = va_arg(ap, Matrix *); matrices.push_back(M); } return collect(matrices); } /* ************************************************************************* */ // row scaling Matrix vector_scale(const Vector& v, const Matrix& A) { Matrix M(A); for (int i=0; i