SymmMatrix.h

Go to the documentation of this file.
00001 //
00002 //  Copyright (C) 2004-2006 Rational Discovery LLC
00003 //
00004 //   @@ All Rights Reserved @@
00005 //  This file is part of the RDKit.
00006 //  The contents are covered by the terms of the BSD license
00007 //  which is included in the file license.txt, found at the root
00008 //  of the RDKit source tree.
00009 //
00010 #ifndef __RD_SYMM_MATRIX_H__
00011 #define __RD_SYMM_MATRIX_H__
00012 
00013 #include "Matrix.h"
00014 #include "SquareMatrix.h"
00015 #include <cstring>
00016 #include <boost/smart_ptr.hpp>
00017 
00018 //#ifndef INVARIANT_SILENT_METHOD
00019 //#define INVARIANT_SILENT_METHOD
00020 //#endif
00021 namespace RDNumeric {
00022   //! A symmetric matrix class
00023   /*! 
00024     The data is stored as the lower triangle, so
00025      A[i,j] = data[i*(i+1) + j] when i >= j and
00026      A[i,j] = data[j*(j+1) + i] when i < j
00027   */
00028   template <class TYPE> class SymmMatrix {
00029   public:
00030     typedef boost::shared_array<TYPE> DATA_SPTR;
00031 
00032     explicit SymmMatrix(unsigned int N) : 
00033       d_size(N), d_dataSize(N*(N+1)/2)  {
00034       TYPE *data = new TYPE[d_dataSize];
00035       memset(static_cast<void *>(data),0,d_dataSize*sizeof(TYPE));
00036       d_data.reset(data);
00037     }
00038 
00039     SymmMatrix(unsigned int N, TYPE val) : 
00040       d_size(N), d_dataSize(N*(N+1)/2)  {
00041       TYPE *data = new TYPE[d_dataSize];
00042       unsigned int i;
00043       for (i = 0; i < d_dataSize; i++) {
00044         data[i] = val;
00045       }
00046       d_data.reset(data);
00047     }
00048     
00049     SymmMatrix(unsigned int N, DATA_SPTR data) :
00050       d_size(N), d_dataSize(N*(N+1)/2)  {
00051       d_data = data;
00052     }
00053     
00054     SymmMatrix(const SymmMatrix<TYPE> &other) :
00055       d_size(other.numRows()), d_dataSize(other.getDataSize())  {
00056       TYPE *data = new TYPE[d_dataSize];
00057       const TYPE *otherData = other.getData();
00058 
00059       memcpy(static_cast<void *>(data), static_cast<const void *>(otherData),
00060              d_dataSize*sizeof(TYPE));
00061       d_data.reset(data);
00062     }
00063 
00064     ~SymmMatrix() {}
00065     
00066     //! returns the number of rows
00067     inline unsigned int numRows() const {
00068       return d_size;
00069     }
00070 
00071     //! returns the number of columns
00072     inline unsigned int numCols() const {
00073       return d_size;
00074     }
00075 
00076     inline unsigned int getDataSize() const {
00077       return d_dataSize;
00078     }
00079 
00080     void setToIdentity() {
00081       TYPE *data = d_data.get();
00082       memset(static_cast<void *>(data), 0, d_dataSize*sizeof(TYPE));
00083       for (unsigned int i = 0; i < d_size; i++) {
00084         data[i*(i+3)/2] = (TYPE)1.0;
00085       }
00086     }
00087 
00088     TYPE getVal(unsigned int i, unsigned int j) const {
00089       RANGE_CHECK(0, i, d_size-1);
00090       RANGE_CHECK(0, j, d_size-1);
00091       unsigned int id;
00092       if (i >= j) {
00093         id = i*(i+1)/2 + j;
00094       } else {
00095         id = j*(j+1)/2 + i;
00096       }
00097       return d_data[id];
00098     }
00099 
00100     void setVal(unsigned int i, unsigned int j, TYPE val) {
00101       RANGE_CHECK(0, i, d_size-1);
00102       RANGE_CHECK(0, j, d_size-1);
00103       unsigned int id;
00104       if (i >= j) {
00105         id = i*(i+1)/2 + j;
00106       } else {
00107         id = j*(j+1)/2 + i;
00108       }
00109       d_data[id] = val;
00110     }
00111 
00112     void getRow(unsigned int i, Vector<TYPE> &row) { 
00113       CHECK_INVARIANT(d_size == row.size(), "");
00114       TYPE *rData  = row.getData(); 
00115       TYPE *data = d_data.get();
00116       for (unsigned int j = 0; j < d_size; j++) {
00117         unsigned int id;
00118         if (j <= i) {
00119           id = i*(i+1)/2 + j;
00120         } else {
00121           id = j*(j+1)/2 + i;
00122         }
00123         rData[j] = data[id];
00124       }
00125     }
00126      
00127     void getCol(unsigned int i, Vector<TYPE> &col) { 
00128       CHECK_INVARIANT(d_size == col.size(), "");
00129       TYPE *rData  = col.getData();
00130       TYPE *data = d_data.get();
00131       for (unsigned int j = 0; j < d_size; j++) {
00132         unsigned int id;
00133         if (i <= j) {
00134           id = j*(j+1)/2 + i;
00135         } else {
00136           id = i*(i+1)/2 + j;
00137         }
00138         rData[j] = data[id];
00139       }
00140     }
00141 
00142     //! returns a pointer to our data array
00143     inline TYPE *getData() {
00144       return d_data.get();
00145     }
00146     
00147     //! returns a const pointer to our data array
00148     inline const TYPE *getData() const {
00149       return d_data.get();
00150     }
00151 
00152     SymmMatrix<TYPE>& operator*=(TYPE scale) {
00153       TYPE *data = d_data.get();
00154       for (unsigned int i = 0; i < d_dataSize; i++) {
00155         data[i] *= scale;
00156       }
00157       return *this;
00158     }
00159 
00160     SymmMatrix<TYPE>& operator/=(TYPE scale) {
00161       TYPE *data = d_data.get();
00162       for (unsigned int i = 0; i < d_dataSize; i++) {
00163         data[i] /= scale;
00164       }
00165       return *this;
00166     }
00167 
00168     SymmMatrix<TYPE>& operator+=(const SymmMatrix<TYPE> &other) {
00169       CHECK_INVARIANT(d_size == other.numRows(), "Sizes don't match in the addition");
00170       const TYPE *oData = other.getData();
00171       TYPE *data = d_data.get();
00172       for (unsigned int i = 0; i < d_dataSize; i++) {
00173         data[i] += oData[i];
00174       }
00175       return *this;
00176     }
00177 
00178     SymmMatrix<TYPE>& operator-=(const SymmMatrix<TYPE> &other) {
00179       CHECK_INVARIANT(d_size == other.numRows(), "Sizes don't match in the addition");
00180       const TYPE *oData = other.getData();
00181       TYPE *data = d_data.get();
00182       for (unsigned int i = 0; i < d_dataSize; i++) {
00183         data[i] -= oData[i];
00184       }
00185       return *this;
00186     }
00187 
00188     //! in-place matrix multiplication
00189     SymmMatrix<TYPE>& operator*=(const SymmMatrix<TYPE> &B) {
00190       CHECK_INVARIANT(d_size == B.numRows(), "Size mismatch during multiplication");
00191       TYPE *cData = new TYPE[d_dataSize];
00192       const TYPE *bData = B.getData();
00193       TYPE *data = d_data.get();
00194       for (unsigned int i = 0; i < d_size; i++) {
00195         unsigned int idC = i*(i+1)/2;
00196         for (unsigned int j = 0; j < i+1; j++) {
00197           unsigned int idCt = idC + j;
00198           cData[idCt] = (TYPE)0.0;
00199           for (unsigned int k = 0; k < d_size; k++) {
00200             unsigned int idA,idB;
00201             if (k <= i) {
00202               idA = i*(i+1)/2 + k;
00203             } else {
00204               idA = k*(k+1)/2 + i;
00205             } 
00206             if (k <= j) {
00207               idB = j*(j+1)/2 + k;
00208             } else {
00209               idB = k*(k+1)/2 + j;
00210             }
00211             cData[idCt] += (data[idA]*bData[idB]);
00212           }
00213         }
00214       }
00215       
00216       for (unsigned int i = 0; i < d_dataSize; i++) {
00217         data[i] = cData[i];
00218       }
00219       delete [] cData;
00220       return (*this);
00221     }
00222 
00223     /* Transpose will basically return a copy of itself
00224      */
00225     SymmMatrix<TYPE>& transpose(SymmMatrix<TYPE> &transpose) const { 
00226       CHECK_INVARIANT(d_size == transpose.numRows(), "Size mismatch during transposing");
00227       TYPE *tData = transpose.getData(); 
00228       TYPE *data = d_data.get();
00229       for (unsigned int i = 0; i < d_dataSize; i++) {
00230         tData[i] = data[i];
00231       }
00232       return transpose;
00233     }
00234 
00235     SymmMatrix<TYPE> &transposeInplace() {
00236       // nothing to be done we are symmetric
00237       return (*this);
00238     }
00239 
00240   protected: 
00241     
00242     SymmMatrix() : d_size(0), d_dataSize(0), d_data(0){};
00243     unsigned int d_size;
00244     unsigned int d_dataSize;
00245     DATA_SPTR d_data;
00246 
00247   private:
00248     SymmMatrix<TYPE>& operator=(const SymmMatrix<TYPE> &other);
00249   };
00250   
00251   //! SymmMatrix-SymmMatrix multiplication 
00252   /*!
00253     Multiply SymmMatrix A with a second SymmMatrix B 
00254     and write the result to C = A*B
00255 
00256     \param A  the first SymmMatrix 
00257     \param B  the second SymmMatrix to multiply 
00258     \param C  SymmMatrix to use for the results
00259     
00260     \return the results of multiplying A by B.
00261     This is just a reference to C.
00262     
00263     This method is reimplemented here for efficiency reasons
00264     (we basically don't want to use getter and setter functions)
00265     
00266   */
00267   template <class TYPE>
00268     SymmMatrix<TYPE>& multiply(const SymmMatrix<TYPE> &A,
00269                                const SymmMatrix<TYPE> &B, 
00270                                SymmMatrix<TYPE> &C) {
00271     unsigned int aSize = A.numRows();
00272     CHECK_INVARIANT(B.numRows() == aSize, "Size mismatch in matric multiplication");
00273     CHECK_INVARIANT(C.numRows() == aSize, "Size mismatch in matric multiplication");
00274     TYPE *cData = C.getData();
00275     const TYPE *aData = A.getData();
00276     const TYPE *bData = B.getData();
00277     for (unsigned int i = 0; i < aSize; i++) {
00278       unsigned int idC = i*(i+1)/2;
00279       for (unsigned int j = 0; j < i+1; j++) {
00280         unsigned int idCt = idC + j;
00281         cData[idCt] = (TYPE)0.0;
00282         for (unsigned int k = 0; k < aSize; k++) {
00283           unsigned int idA,idB;
00284           if (k <= i) {
00285             idA = i*(i+1)/2 + k;
00286           } else {
00287             idA = k*(k+1)/2 + i;
00288           } 
00289           if (k <= j) {
00290             idB = j*(j+1)/2 + k;
00291           } else {
00292             idB = k*(k+1)/2 + j;
00293           }
00294           cData[idCt] += (aData[idA]*bData[idB]);
00295         }
00296       }
00297     }
00298     return C;
00299   }
00300 
00301   //! SymmMatrix-Vector multiplication
00302   /*!
00303     Multiply a SymmMatrix A with a Vector x
00304     so the result is y = A*x
00305     
00306     \param A  the SymmMatrix for multiplication 
00307     \param x  the Vector by which to multiply
00308     \param y  Vector to use for the results
00309     
00310     \return the results of multiplying x by A
00311     This is just a reference to y.
00312     
00313     This method is reimplemented here for efficiency reasons
00314     (we basically don't want to use getter and setter functions)
00315     
00316   */
00317   template <class TYPE>
00318     Vector<TYPE>& multiply(const SymmMatrix<TYPE> &A, const Vector<TYPE> &x, 
00319                                    Vector<TYPE> &y) {
00320     unsigned int aSize = A.numRows();
00321     CHECK_INVARIANT(aSize == x.size(), "Size mismatch during multiplication");
00322     CHECK_INVARIANT(aSize == y.size(), "Size mismatch during multiplication");
00323     const TYPE *xData = x.getData();
00324     const TYPE *aData = A.getData();
00325     TYPE *yData = y.getData();
00326     for (unsigned int i = 0; i < aSize; i++) {
00327       yData[i] = (TYPE)(0.0);
00328       unsigned int idA = i*(i+1)/2;
00329       for (unsigned int j = 0; j < i+1; j++) {
00330         //idA = i*(i+1)/2 + j;
00331         yData[i] += (aData[idA]*xData[j]);
00332         idA++;
00333       }
00334       idA--;
00335       for (unsigned int j = i+1; j < aSize; j++) {
00336         //idA = j*(j+1)/2 + i;
00337         idA += j;
00338         yData[i] += (aData[idA]*xData[j]);
00339       }
00340     }
00341     return y;
00342   }
00343 
00344   typedef SymmMatrix<double> DoubleSymmMatrix;
00345   typedef SymmMatrix<int> IntSymmMatrix;
00346   typedef SymmMatrix<unsigned int> UintSymmMatrix;
00347 }
00348 
00349 //! ostream operator for Matrix's
00350 template <class TYPE > std::ostream & operator<<(std::ostream& target, 
00351                                                  const RDNumeric::SymmMatrix<TYPE> &mat) {
00352   unsigned int nr = mat.numRows();
00353   unsigned int nc = mat.numCols();
00354   target << "Rows: " << mat.numRows() << " Columns: " << mat.numCols() << "\n";
00355 
00356   for (unsigned int i = 0; i < nr; i++) {
00357     for (unsigned int j = 0; j < nc; j++) {
00358       target << std::setw(7) << std::setprecision(3) << mat.getVal(i, j);
00359     }
00360     target << "\n";
00361   }
00362   return target;
00363 }
00364 
00365 #endif
00366