Matrix.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_MATRIX_H__
00011 #define __RD_MATRIX_H__
00012 
00013 #include <RDGeneral/Invariant.h>
00014 #include "Vector.h"
00015 #include <iostream>
00016 #include <iomanip>
00017 #include <cstring>
00018 #include <boost/smart_ptr.hpp>
00019 
00020 //#ifndef INVARIANT_SILENT_METHOD
00021 //#define INVARIANT_SILENT_METHOD
00022 //#endif
00023 
00024 namespace RDNumeric {
00025   
00026   //! A matrix class for general, non-square matrices
00027   template <class TYPE> class Matrix {
00028   public:
00029 
00030     typedef boost::shared_array<TYPE> DATA_SPTR;
00031 
00032     //! Initialize with a size.
00033     Matrix(unsigned int nRows, unsigned int nCols) : 
00034       d_nRows(nRows), d_nCols(nCols), d_dataSize(nRows*nCols) {
00035       TYPE *data = new TYPE[d_dataSize];
00036       memset(static_cast<void *>(data),0,d_dataSize*sizeof(TYPE));
00037       d_data.reset(data);
00038     };
00039 
00040     //! Initialize with a size and default value.
00041     Matrix(unsigned int nRows, unsigned int nCols, TYPE val) :
00042       d_nRows(nRows), d_nCols(nCols), d_dataSize(nRows*nCols) {
00043       TYPE *data = new TYPE[d_dataSize];
00044       unsigned int i;
00045       for (i = 0; i < d_dataSize; i++) {
00046         data[i] = val;
00047       }
00048       d_data.reset(data);
00049     }
00050 
00051     //! Initialize from a pointer.
00052     /*!
00053       <b>NOTE:</b> this does not take ownership of the data,
00054       if you delete the data externally, this Matrix will be sad.
00055     */
00056     Matrix(unsigned int nRows, unsigned int nCols, DATA_SPTR data) :
00057       d_nRows(nRows), d_nCols(nCols), d_dataSize(nRows*nCols) {
00058       d_data = data;
00059     }
00060 
00061     //! copy constructor
00062     /*! We make a copy of the other vector's data.
00063      */
00064     Matrix(const Matrix<TYPE> &other) :
00065       d_nRows(other.numRows()), d_nCols(other.numCols()), d_dataSize(d_nRows*d_nCols) {
00066       TYPE *data = new TYPE[d_dataSize];
00067       const TYPE *otherData = other.getData();
00068       memcpy(static_cast<void *>(data), static_cast<const void *>(otherData),
00069              d_dataSize*sizeof(TYPE));
00070       d_data.reset(data);
00071     }
00072 
00073     virtual ~Matrix() {
00074     }
00075 
00076     //! returns the number of rows
00077     inline unsigned int numRows() const {
00078       return d_nRows;
00079     }
00080     
00081     //! returns the number of columns
00082     inline unsigned int numCols() const {
00083       return d_nCols;
00084     }
00085 
00086     inline unsigned int getDataSize() const {
00087       return d_dataSize;
00088     }
00089 
00090     //! returns a particular element of the matrix
00091     inline virtual TYPE getVal(unsigned int i, unsigned int j) const {
00092       RANGE_CHECK(0, i, d_nRows-1);
00093       RANGE_CHECK(0, j, d_nCols-1);
00094       unsigned int id = i*d_nCols + j;
00095       return d_data[id];
00096     }
00097 
00098     //! sets a particular element of the matrix
00099     inline virtual void setVal(unsigned int i, unsigned int j, TYPE val) {
00100       RANGE_CHECK(0, i, d_nRows-1);
00101       RANGE_CHECK(0, j, d_nCols-1);
00102       unsigned int id = i*d_nCols + j;
00103       
00104       d_data[id] = val;
00105     }
00106 
00107     //! returns a copy of a row of the matrix
00108     inline virtual void getRow(unsigned int i, Vector<TYPE> &row) const { 
00109       CHECK_INVARIANT(d_nCols == row.size(), "");
00110       RANGE_CHECK(0, i, d_nRows-1);
00111       unsigned int id = i*d_nCols;
00112       TYPE *rData  = row.getData(); 
00113       TYPE *data = d_data.get();
00114       memcpy(static_cast<void *>(rData), static_cast<void *>(&data[id]), d_nCols*sizeof(TYPE));
00115       
00116     }
00117      
00118     //! returns a copy of a column of the matrix
00119     inline virtual void getCol(unsigned int i, Vector<TYPE> &col) const { 
00120       CHECK_INVARIANT(d_nRows == col.size(), "");
00121       unsigned int j,id;
00122       TYPE *rData  = col.getData(); 
00123       TYPE *data = d_data.get();
00124       for (j = 0; j < d_nRows; j++) {
00125         id = j*d_nCols + i;
00126         rData[j] = data[id];
00127       }
00128     }
00129 
00130     //! returns a pointer to our data array
00131     inline TYPE *getData() {
00132       return d_data.get();
00133     }
00134     
00135     //! returns a const pointer to our data array
00136     inline const TYPE *getData() const {
00137       return d_data.get();
00138     }
00139 
00140 
00141     //! Copy operator.
00142     /*! We make a copy of the other Matrix's data.
00143      */
00144     
00145     Matrix<TYPE>& assign(const Matrix<TYPE> &other) {
00146       CHECK_INVARIANT(d_nRows == other.numRows(), "Num rows mismatch in matrix copying");
00147       CHECK_INVARIANT(d_nCols == other.numCols(), "Num cols mismatch in matrix copying");
00148       const TYPE *otherData = other.getData();
00149       TYPE *data = d_data.get();
00150       memcpy(static_cast<void *>(data), static_cast<const void *>(otherData), d_dataSize*sizeof(TYPE));
00151       return *this;
00152     }
00153 
00154     //! Matrix addition.
00155     /*! Perform a element by element addition of other Matrix to this Matrix
00156      */
00157     virtual Matrix<TYPE>& operator+=(const Matrix<TYPE> &other) {
00158       CHECK_INVARIANT(d_nRows == other.numRows(), "Num rows mismatch in matrix addition");
00159       CHECK_INVARIANT(d_nCols == other.numCols(), "Num cols mismatch in matrix addition");
00160       const TYPE *oData = other.getData();
00161       unsigned int i;
00162       TYPE *data = d_data.get();
00163       for (i = 0; i < d_dataSize; i++) {
00164         data[i] += oData[i];
00165       }
00166       return *this;
00167     }
00168 
00169     //! Matrix subtraction.
00170     /*! Perform a element by element subtraction of other Matrix from this Matrix
00171      */
00172     virtual Matrix<TYPE>& operator-=(const Matrix<TYPE> &other) {
00173       CHECK_INVARIANT(d_nRows == other.numRows(), "Num rows mismatch in matrix addition");
00174       CHECK_INVARIANT(d_nCols == other.numCols(), "Num cols mismatch in matrix addition");
00175       const TYPE *oData = other.getData();
00176       unsigned int i;
00177       TYPE *data = d_data.get();
00178       for (i = 0; i < d_dataSize; i++) {
00179         data[i] -= oData[i];
00180       }
00181       return *this;
00182     }
00183 
00184     //! Multiplication by a scalar
00185     virtual Matrix<TYPE>& operator*=(TYPE scale) {
00186       unsigned int i;
00187       TYPE *data = d_data.get();
00188       for (i = 0; i < d_dataSize; i++) {
00189         data[i] *= scale;
00190       }
00191       return *this;
00192     }
00193 
00194     //! division by a scalar
00195     virtual Matrix<TYPE>& operator/=(TYPE scale) {
00196       unsigned int i;
00197       TYPE *data = d_data.get();
00198       for (i = 0; i < d_dataSize; i++) {
00199         data[i] /= scale;
00200       }
00201       return *this;
00202     }
00203 
00204     //! copies the transpose of this Matrix into another, returns the result
00205     /*!
00206       \param transpose the Matrix to store the results
00207 
00208       \return the transpose of this matrix.
00209          This is just a reference to the argument.
00210 
00211      */
00212     virtual Matrix<TYPE>& transpose(Matrix<TYPE> &transpose) const {
00213       unsigned int tRows = transpose.numRows();
00214       unsigned int tCols = transpose.numCols();
00215       CHECK_INVARIANT(d_nCols == tRows, "Size mismatch during transposing");
00216       CHECK_INVARIANT(d_nRows == tCols, "Size mismatch during transposing");
00217       unsigned int i, j;
00218       unsigned int idA, idAt, idT;
00219       TYPE *tData = transpose.getData(); 
00220       TYPE *data = d_data.get();
00221       for (i = 0; i < d_nRows; i++) {
00222         idA = i*d_nCols;
00223         for (j = 0; j < d_nCols; j++) {
00224           idAt = idA + j;
00225           idT = j*tCols + i;
00226           tData[idT] = data[idAt];
00227         }
00228       }
00229       return transpose;
00230     }
00231 
00232   protected:
00233     Matrix() : d_nRows(0), d_nCols(0), d_dataSize(0), d_data(0){} ;
00234     unsigned int d_nRows;
00235     unsigned int d_nCols;
00236     unsigned int d_dataSize;
00237     DATA_SPTR d_data;
00238    
00239   private:
00240     Matrix<TYPE>& operator=(const Matrix<TYPE> &other);
00241   };
00242 
00243   //! Matrix multiplication
00244   /*!
00245     Multiply a Matrix A with a second Matrix B 
00246     so the result is C = A*B
00247     
00248     \param A  the the first Matrix used in the multiplication
00249     \param B  the Matrix by which to multiply
00250     \param C  Matrix to use for the results
00251     
00252     \return the results of multiplying A by B.
00253     This is just a reference to C.
00254   */
00255   template <class TYPE>
00256     Matrix<TYPE>& multiply(const Matrix<TYPE> &A, const Matrix<TYPE> &B, 
00257                            Matrix<TYPE> &C)  {
00258     unsigned int aRows = A.numRows();
00259     unsigned int aCols = A.numCols();
00260     unsigned int cRows = C.numRows(); 
00261     unsigned int cCols = C.numCols();
00262     unsigned int bRows = B.numRows();
00263     unsigned int bCols = B.numCols();
00264     CHECK_INVARIANT(aCols == bRows, "Size mismatch during multiplication");
00265     CHECK_INVARIANT(aRows == cRows, "Size mismatch during multiplication");
00266     CHECK_INVARIANT(bCols == cCols, "Size mismatch during multiplication");
00267     
00268     // we have the sizes check do do the multiplication
00269     TYPE *cData = C.getData();
00270     const TYPE *bData = B.getData();
00271     const TYPE *aData = A.getData();
00272     unsigned int i, j, k;
00273     unsigned int idA, idAt, idB, idC, idCt;
00274     for (i = 0; i < aRows; i++) {
00275       idC = i*cCols;
00276       idA = i*aCols;
00277       for (j = 0; j < cCols; j++) {
00278         idCt = idC + j;
00279         cData[idCt] = (TYPE)0.0;
00280         for (k = 0; k < aCols; k++) {
00281           idAt = idA + k;
00282           idB = k*bCols + j;
00283           cData[idCt] += (aData[idAt]*bData[idB]);
00284         }
00285       }
00286     }
00287     return C;
00288   };
00289 
00290   //! Matrix-Vector multiplication
00291   /*!
00292     Multiply a Matrix A with a Vector x
00293     so the result is y = A*x
00294     
00295     \param A  the matrix used in the multiplication
00296     \param x  the Vector by which to multiply
00297     \param y  Vector to use for the results
00298     
00299     \return the results of multiplying x by this
00300     This is just a reference to y.
00301   */
00302   template <class TYPE>
00303     Vector<TYPE>& multiply(const Matrix<TYPE> &A, const Vector<TYPE> &x, 
00304                            Vector<TYPE> &y) {
00305     unsigned int aRows = A.numRows();
00306     unsigned int aCols = A.numCols();
00307     unsigned int xSiz = x.size();
00308     unsigned int ySiz = y.size();
00309     CHECK_INVARIANT(aCols == xSiz, "Size mismatch during multiplication");
00310     CHECK_INVARIANT(aRows == ySiz, "Size mismatch during multiplication");
00311     unsigned int i, j;
00312     unsigned int idA, idAt;
00313     const TYPE *xData = x.getData();
00314     const TYPE *aData = A.getData();
00315     TYPE *yData = y.getData();
00316     for (i = 0; i < aRows; i++) {
00317       idA = i*aCols;
00318       yData[i] = (TYPE)(0.0);
00319       for (j = 0; j < aCols; j++) {
00320         idAt = idA + j;
00321         yData[i] += (aData[idAt]*xData[j]);
00322       }
00323     }
00324     return y;
00325   };
00326 
00327   typedef Matrix<double> DoubleMatrix;
00328 };
00329 
00330 //! ostream operator for Matrix's
00331 template <class TYPE > std::ostream & operator<<(std::ostream& target, 
00332                                                  const RDNumeric::Matrix<TYPE> &mat) {
00333   unsigned int nr = mat.numRows();
00334   unsigned int nc = mat.numCols();
00335   target << "Rows: " << mat.numRows() << " Columns: " << mat.numCols() << "\n";
00336 
00337   unsigned int i, j;
00338   for (i = 0; i < nr; i++) {
00339     for (j = 0; j < nc; j++) {
00340       target << std::setw(7) << std::setprecision(3) << mat.getVal(i, j);
00341     }
00342     target << "\n";
00343   }
00344   return target;
00345 }
00346 
00347 #endif