RDCode: Matrix.h Source File

# Matrix.h

Go to the documentation of this file.

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