//-*-c++-*- #ifndef SMAT_H #define SMAT_H /** * @file mat.h * @brief Basic static square matric 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 * * @todo this seems to be working pretty well, but it needs to be looked at * again to check for bugs one final time. All functionality is complete, * however, except possibly some eigenvalue routines. */ #include #include /** * @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 //////////////////// SMat //////////////////// /** * 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 setDiag(const T a); void setDiag(const Vec& diagVec); // Accessors Vec getDiag(); // Basic square matrix functions T trace() const; void transpose(); T det() const; SMat inverted() const; int invert(); void symmetrize(); SMat symmetrized() const; // Decompositions int luDecomp(Vec& indx, T* d = NULL); void luSolve(const Vec& indx, Vec& b); int choleskyDecomp(const int active_m = M); int choleskyUpdate(const int j); template void choleskySolve(Mat& B, Mat& Result, const int active_m = M, const int active_n = N); void choleskySolve(Vec& b, Vec& result, const int active_m = M); void choleskySolve(T* b_x, T* result_x, const int active_m = M); }; // end class SMat // Non-member functions that involve this type template void operator *= (const Vec& v, const SMat& m); // Declare a few common typdefs typedef SMat SMat5b; typedef SMat SMat5c; typedef SMat SMat5uc; typedef SMat SMat5i; typedef SMat SMat5f; typedef SMat SMat5d; typedef SMat SMat6b; typedef SMat SMat6c; typedef SMat SMat6uc; typedef SMat SMat6i; typedef SMat SMat6f; typedef SMat SMat6d; //////////////////////////////////////////////////////////////////////////// // DEFINITIONS //////////////////////////////////////////////////////////////////////////// //////////////////// 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 /** Vector-Matrix multiplication asignment operator. */ template void operator *= (const Vec& v, const SMat& m) { Vec vp(T(0)); for (int j=0,k=0;j 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 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 j=0;j inline void SMat::symmetrize() { for (int j=0;j inline SMat SMat::symmetrized() const { SMat m; m.symmetrize(); return m; } /** Return the determinant of this matrix. * This uses the LU decomposition. Matrices of size 3 and under have * specialized implementations. */ template 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); tmp.invert(); return tmp; } /** 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)) { std::cerr << "SMat<" << M << ">::invert(): warning, " << "can't take inverse of singular matrix." << std::endl << std::flush; return 1; } 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,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(const int active_m) { for (int ij=0;ij inline int SMat::choleskyUpdate(const int ij) { // First the elements in the row for (int j=0;j inline void SMat::choleskySolve(Vec& b, Vec& result, const int active_m) { choleskySolve(b.x, result.x, active_m); } template template inline void SMat::choleskySolve(Mat& B, Mat& Result, const int active_m, const int active_n) { for (int j=0;j inline void SMat::choleskySolve(T* b_x, T* result_x, const int active_m) { T sum; int k; for (int i=0;i=0;k--) sum -= x[i+k*M]*result_x[k]; result_x[i] = T(sum/x[i+i*M]); } for (int i=active_m-1;i>=0;i--) { sum = result_x[i]; for (k=i+1;k inline void SMat::choleskySolve(Vec& b) { T sum; int k; for (int i=0;i=0;k--) sum -= x[i+k*M]*b.x[k]; b.x[i] = sum/x[i+i*M]; } for (int i=M-1;i>=0;i--) { for (sum=b.x[i],k=i+1;k