/* * Copyright (C) 2009 * Robert Bosch LLC * Research and Technology Center North America * Palo Alto, California * * All rights reserved. * *------------------------------------------------------------------------------ * project ....: Autonomous Technologies * file .......: rtcSMat.h * authors ....: Benjamin Pitzer * organization: Robert Bosch LLC * creation ...: 08/16/2006 * modified ...: $Date: 2009-01-21 18:19:16 -0800 (Wed, 21 Jan 2009) $ * changed by .: $Author: benjaminpitzer $ * revision ...: $Revision: 14 $ */ #ifndef RTC_SMAT_H #define RTC_SMAT_H //== INCLUDES ================================================================== #include "rtcMath.h" #include "rtcVec.h" #include "rtcMat.h" //== NAMESPACES ================================================================ namespace rtc { // Forward declarations template class Vec; // M-d vector template class Mat; // MxN Matrix template class SMat; // MxM Square Matrix /** * A square matrix. * A specialization of a general matrix that provides operations only * possible on square matrices like guassian elimination and Cholesky * decomposition. */ template class SMat: public Mat { public: // Data using Mat::x; using Mat::set; // Constructors SMat(); SMat(const T* d); SMat(const T diagVal); SMat(const Vec& diagVec); SMat(const Mat& m); // Casting Operation template SMat(const Mat& m); // Mutators void setIdentity(); void setDiag(const T a); void setDiag(const Vec& diagVec); SMat& leftMultiply(const SMat& m); // Accessors Vec getDiag(); // Basic square matrix functions T trace() const; void transpose(); SMat minorMat(const int ip, const int jp) const; T det() const; SMat inverted() const; int invert(); // Decompositions int luDecomp(Vec& indx, T* d = NULL); void luSolve(const Vec& indx, Vec& b); int choleskyDecomp(); int choleskyDecomp(SMat& r); void choleskySolve(Vec& b); }; //============================================================================== // SMat //============================================================================== // Constructors /** Ctor that doesn't initialize anything. */ template inline SMat::SMat() {} /** Ctor that initializes from an array. * @param d the (row major) data array of length M*M */ template inline SMat::SMat(const T* d) : Mat(d) {} /** Ctor that makes a multiple of the identity matrix. * @param diagVal the value to which all diagonal entries will be set */ template inline SMat::SMat(const T diagVal) { set(T(0)); setDiag(diagVal); } /** Ctor that makes a (mostly) zero matrix with diagonal entries from vec. * @param diagVec the vector of values that should appear on the diagonal */ template inline SMat::SMat(const Vec& diagVec) { set(T(0)); setDiag(diagVec); } /** Ctor that initializes from a Mat */ template inline SMat::SMat(const Mat& m) : Mat(m) {} // Casting Operation /** Casting Ctor that initializes from a Mat */ template template inline SMat::SMat(const Mat& m) : Mat(m) {} // Mutators /** Sets matrix to an identiy matrix, where the diagonal elements are equal to * 1 and every other element equals 0. */ template inline void SMat::setIdentity() { set(T(0)); setDiag(T(1)); } /** Sets matrix to a multiple of the identity matrix. * @param diagVal the value to which all diagonal entries will be set */ template inline void SMat::setDiag(const T diagVal) { for (int i=0,k=0;i inline void SMat::setDiag(const Vec& diagVec) { for (int i=0,k=0;i inline SMat& SMat::leftMultiply(const SMat& m) { (*this) = m*(*this); return *this; } // Accessors /** Get the diagonal entries of the matrix. * @return vector of the diagonal entries. */ template inline Vec SMat::getDiag() { Vec v; for (int i=0,k=0;i inline T SMat::trace() const { T sum = T(0); for (int i=0,k=0;i inline void SMat::transpose() { for (int i=0;i inline SMat SMat::minorMat(const int ip, const int jp) const { #if MATMATH_CHECK_BOUNDS if (ip<0 || ip>M || jp<0 || jp>M) { std::stringstream ss; ss << "SMat<" << M << ">::minorMat(" << ip; ss << ", " << jp << "): index out of range\n"; ss << std::flush; throw Exception(ss.str()); } #endif SMat m; for (int i=0,k=0;i inline T SMat::det() const { SMat tmp(*this); Vec indx; T d; tmp.luDecomp(indx,&d); return d*tmp.getDiag().prod(); } /** Return the inverse of this matrix * This uses the LU decomposition */ template inline SMat SMat::inverted() const { SMat tmp(*this); Vec indx; T d; if (tmp.luDecomp(indx,&d)) { throw Exception("SMat::inverted(): error, can't take the inverse of a singular matrix."); } SMat inv; for (int i=0;i col(T(0)); col(i) = T(1); tmp.luSolve(indx,col); inv.setCol(i,col); } return inv; } /** Return the inverse of this matrix * This uses the LU decomposition */ template inline int SMat::invert() { SMat tmp(*this); Vec indx; T d; if (tmp.luDecomp(indx,&d)) throw Exception("SMat::invert(): error, can't take the inverse of a singular matrix."); for (int i=0;i col(T(0)); col(i) = T(1); tmp.luSolve(indx,col); this->setCol(i,col); } return 0; } // Decomposition and Solve Routines (compliments of Numerical Recipes in C) /** Perform the LU Decomposition in place * @return indx output vector that records the row permutation effected by * the partial pivoting * @return d (optional) is +/- 1 depending on if there were an even (+) or * odd (-) number of row-interchanges (used to compute determinant). * @returns 1 on failure (matrix singular), 0 on success */ template inline int SMat::luDecomp(Vec& indx, T* d) { int i,imax=0,j,k; T big,dum,sum,temp; Vec vv; if (d) *d=1.0; for (i=0;i big) big=temp; if (big == 0.0) return 1; vv(i)=T(1)/big; } for (j=0;j= big) { big=dum; imax=i; } } if (j != imax) { for (k=0;k inline void SMat::luSolve(const Vec& indx, Vec& b) { int i,ii=-1,ip,j; float sum; for (i=0;i=0) for (j=ii;j=0;i--) { sum=b.x[i]; for (j=i+1;j inline int SMat::choleskyDecomp() { T sum; T p[M]; for (int i=0;i=0;k--) sum -= x[i*M+k]*x[j*M+k]; if (i == j) { if (sum <= T(0)) return 1; p[i] = sqrt(double(sum)); } else x[j*M+i] = sum/p[i]; } for (int i=0;i inline int SMat::choleskyDecomp(SMat& r) { r.set(*this); r.choleskyDecomp(); for (int i=0;i inline void SMat::choleskySolve(Vec& b) { T sum; for (int i=0,k;i=0;k--) sum -= x[i*M+k]*b.x[k]; b.x[i] = sum/x[i*M+i]; } for (int i=M-1,k;i>=0;i--) { for (sum=b.x[i],k=i+1;k