Matrix.h

Go to the documentation of this file.
00001 #ifndef Matrix_HEADER
00002 #define Matrix_HEADER
00003 
00004 #ifdef HAVE_CONFIG_H
00005 # include <config.h>
00006 #endif
00007 
00008 #include <boost/array.hpp>
00009 #include <utilities/foreach.h>
00010 #include "Point.h"
00011 
00012 #if 0
00013 #define dprintf(...) printf(__VA_ARGS__);
00014 #else
00015 #define dprintf(...)
00016 #endif
00017 
00018 namespace Geometry {
00019 
00020 template <unsigned rows, unsigned cols>
00021 class Matrix {
00022   // Stored in column-major order, for interoperability with LAPACK
00023   static const unsigned n = rows * cols;
00024   boost::array<double, n> data_;
00025 
00026   public:
00027   Matrix() { }
00028   Matrix(double value) {
00029     data_.assign(value);
00030   }
00031   // Outer product pq^T constructor
00032   Matrix(const Point<rows>& p, const Point<cols>& q) {
00033     for(unsigned r = 0; r < rows; ++r) {
00034       for(unsigned c = 0; c < cols; ++c) {
00035         get(r, c) = p[r] * q[c];
00036       }
00037     }
00038   }
00039 
00040   const double *column_major_array() const {
00041     return data_.c_array();
00042   }
00043   double *column_major_array() {
00044     return data_.c_array();
00045   }
00046 
00047   double operator() (unsigned r, unsigned c) const {
00048     return data_[r * cols + c];
00049   }
00050   double& operator() (unsigned r, unsigned c) {
00051     return data_[r * cols + c];
00052   }
00053   double get(unsigned r, unsigned c) const {
00054     return data_[r * cols + c];
00055   }
00056   double& get(unsigned r, unsigned c) {
00057     return data_[r * cols + c];
00058   }
00059 
00060   void operator+= (const Matrix& other) {
00061     for(unsigned i = 0; i < n; ++i) {
00062       data_[i] += other.data_[i];
00063     }
00064   }
00065   void operator-= (const Matrix& other) {
00066     for(unsigned i = 0; i < n; ++i) {
00067       data_[i] -= other.data_[i];
00068     }
00069   }
00070   void operator*= (double x) {
00071     for(unsigned i = 0; i < n; ++i) {
00072       data_[i] *= x;
00073     }
00074   }
00075   void operator/= (double x) {
00076     for(unsigned i = 0; i < n; ++i) {
00077       data_[i] /= x;
00078     }
00079   }
00080 
00081 
00082   Point<rows> operator * (const Point<cols>& p) const {
00083     Point<rows> q;
00084     for(unsigned i = 0; i < rows; ++i) {
00085       q[i] = 0.0;
00086       for(unsigned j = 0; j < cols; ++j) {
00087         q[i] += (*this)(i,j) * p[j];
00088       }
00089     }
00090     return q;
00091   }
00092 
00093   void qd_print()
00094     {
00095       for(unsigned i = 0; i < rows; ++i) {
00096         for(unsigned j = 0; j < cols; ++j) {
00097           dprintf("%f   ",get(i,j));
00098         }
00099         dprintf("\n");
00100       }
00101       return;
00102     }
00103 
00104   /***************************************************************************
00105     Functions that assume square matrices
00106    ***************************************************************************/
00107 
00108   template <unsigned newcols>
00109   Matrix<rows, newcols>
00110   operator * (const Matrix<cols, newcols>& other) {
00111     Matrix<rows, newcols> m;
00112     for(unsigned i = 0; i < newcols; ++i) {
00113       for(unsigned j = 0; j < rows; ++j) {
00114         double d = 0.0;
00115         for(unsigned k = 0; k < cols; ++k) {
00116           d += get(j, k) * other.get(i, k);
00117         }
00118         m(i, j) = d;
00119       }
00120     }
00121     return m;
00122   }
00123 
00124   private:
00125   void largest_eigenvector(Matrix<rows, rows> M, Point<rows>& v) const {
00126     // get the largest eigenvector by repeated squaring
00127     enum { NSQUARE = 20 };
00128 
00129     for (unsigned i = 0 ; i < NSQUARE; ++i) {
00130       M = M * M;
00131       double maxabs = 0.0;
00132       BOOST_FOREACH(double d, M.data_) {
00133         d = fabs(d);
00134         maxabs = maxabs > d ? maxabs : d;
00135       }
00136       if (maxabs != 0.0) {
00137         M /= maxabs;
00138       } 
00139     }
00140 
00141     // Look for a non-zero column
00142     unsigned use_col = 0;
00143     for (unsigned c = 0; c < cols; ++c) {
00144       for(unsigned r = 0; r < rows; ++r) {
00145         if (M(r,c) != 0.0) { 
00146           use_col = c;
00147           break;
00148         }
00149       }
00150     }
00151 
00152     // compute the eigenvector, and normalize it
00153     for (unsigned r = 0; r < rows; ++r) {
00154       v[r] = M(r,use_col);
00155     }
00156     if (v.norm2() != 0.0) {
00157       v /= sqrt(v.norm2());
00158     }
00159   }
00160 
00161 
00162   public:
00168  template<unsigned k> void eigenvectors(boost::array<Point<rows>, k>& vectors) const {
00169     BOOST_STATIC_ASSERT(rows == cols);
00170 
00171     Matrix<rows, rows> M = *this;
00172     for (unsigned eigen = 0; eigen < k; ++eigen) {
00173       largest_eigenvector(M, vectors[eigen]);
00174 
00175       dprintf("Big EIV is %f %f %f\n",vectors[eigen][0],vectors[eigen][1],vectors[eigen][2]);
00176 
00177       // Find the associated eigenvalue by computing the Rayleigh quotient.
00178       const Point<rows>& v = vectors[eigen];
00179       double lambda = v.dot(M * v);  // vTv is 1.0 by construction
00180       assert(lambda != 0); // don't run out of eigenvalues
00181 
00182       dprintf("L is %f\n",lambda);
00183 
00184       // subtract out this eigenvector and move on to the next
00185       Matrix<rows,rows> vv(v, v);
00186       vv *= lambda;
00187       M -= vv;
00188 
00189       dprintf("Lvv then M-Lvv\n");
00190       vv.qd_print();
00191       dprintf("----\n");
00192       M.qd_print();
00193     }
00194   }
00195 
00196 };
00197 
00198 }
00199 
00200 #undef dprintf
00201 #endif

Generated on Thu Mar 27 19:04:14 2008 by  doxygen 1.4.6