1 //
2 //  Copyright (C) 2004-2006 Rational Discovery LLC
3 //
4 //   @@ All Rights Reserved @@
5 //  This file is part of the RDKit.
6 //  The contents are covered by the terms of the BSD license
7 //  which is included in the file license.txt, found at the root
8 //  of the RDKit source tree.
9 //
10 #include <RDGeneral/export.h>
11 #ifndef __RD_MATRIX_H__
12 #define __RD_MATRIX_H__
13 
14 #include <RDGeneral/Invariant.h>
15 #include "Vector.h"
16 #include <iostream>
17 #include <iomanip>
18 #include <cstring>
19 #include <boost/smart_ptr.hpp>
20 
21 //#ifndef INVARIANT_SILENT_METHOD
22 //#define INVARIANT_SILENT_METHOD
23 //#endif
24 
25 namespace RDNumeric {
26 
27 //! A matrix class for general, non-square matrices
28 template <class TYPE>
29 class Matrix {
30  public:
31   typedef boost::shared_array<TYPE> DATA_SPTR;
32 
33   //! Initialize with a size.
Matrix(unsigned int nRows,unsigned int nCols)34   Matrix(unsigned int nRows, unsigned int nCols)
35       : d_nRows(nRows), d_nCols(nCols), d_dataSize(nRows * nCols) {
36     TYPE *data = new TYPE[d_dataSize];
37     memset(static_cast<void *>(data), 0, d_dataSize * sizeof(TYPE));
38     d_data.reset(data);
39   };
40 
41   //! Initialize with a size and default value.
Matrix(unsigned int nRows,unsigned int nCols,TYPE val)42   Matrix(unsigned int nRows, unsigned int nCols, TYPE val)
43       : d_nRows(nRows), d_nCols(nCols), d_dataSize(nRows * nCols) {
44     TYPE *data = new TYPE[d_dataSize];
45     unsigned int i;
46     for (i = 0; i < d_dataSize; i++) {
47       data[i] = val;
48     }
49     d_data.reset(data);
50   }
51 
52   //! Initialize from a pointer.
53   /*!
54     <b>NOTE:</b> this does not take ownership of the data,
55     if you delete the data externally, this Matrix will be sad.
56   */
Matrix(unsigned int nRows,unsigned int nCols,DATA_SPTR data)57   Matrix(unsigned int nRows, unsigned int nCols, DATA_SPTR data)
58       : d_nRows(nRows), d_nCols(nCols), d_dataSize(nRows * nCols) {
59     d_data = data;
60   }
61 
62   //! copy constructor
63   /*! We make a copy of the other vector's data.
64    */
Matrix(const Matrix<TYPE> & other)65   Matrix(const Matrix<TYPE> &other)
66       : d_nRows(other.numRows()),
67         d_nCols(other.numCols()),
68         d_dataSize(d_nRows * d_nCols) {
69     TYPE *data = new TYPE[d_dataSize];
70     const TYPE *otherData = other.getData();
71     memcpy(static_cast<void *>(data), static_cast<const void *>(otherData),
72            d_dataSize * sizeof(TYPE));
73     d_data.reset(data);
74   }
75 
~Matrix()76   virtual ~Matrix() {}
77 
78   //! returns the number of rows
numRows()79   inline unsigned int numRows() const { return d_nRows; }
80 
81   //! returns the number of columns
numCols()82   inline unsigned int numCols() const { return d_nCols; }
83 
getDataSize()84   inline unsigned int getDataSize() const { return d_dataSize; }
85 
86   //! returns a particular element of the matrix
getVal(unsigned int i,unsigned int j)87   inline virtual TYPE getVal(unsigned int i, unsigned int j) const {
88     PRECONDITION(i < d_nRows, "bad index");
89     PRECONDITION(j < d_nCols, "bad index");
90     unsigned int id = i * d_nCols + j;
91     return d_data[id];
92   }
93 
94   //! sets a particular element of the matrix
setVal(unsigned int i,unsigned int j,TYPE val)95   inline virtual void setVal(unsigned int i, unsigned int j, TYPE val) {
96     PRECONDITION(i < d_nRows, "bad index");
97     PRECONDITION(j < d_nCols, "bad index");
98     unsigned int id = i * d_nCols + j;
99 
100     d_data[id] = val;
101   }
102 
103   //! returns a copy of a row of the matrix
getRow(unsigned int i,Vector<TYPE> & row)104   inline virtual void getRow(unsigned int i, Vector<TYPE> &row) const {
105     PRECONDITION(i < d_nRows, "bad index");
106     PRECONDITION(d_nCols == row.size(), "");
107     unsigned int id = i * d_nCols;
108     TYPE *rData = row.getData();
109     TYPE *data = d_data.get();
110     memcpy(static_cast<void *>(rData), static_cast<void *>(&data[id]),
111            d_nCols * sizeof(TYPE));
112   }
113 
114   //! returns a copy of a column of the matrix
getCol(unsigned int i,Vector<TYPE> & col)115   inline virtual void getCol(unsigned int i, Vector<TYPE> &col) const {
116     PRECONDITION(i < d_nCols, "bad index");
117     PRECONDITION(d_nRows == col.size(), "");
118     unsigned int j, id;
119     TYPE *rData = col.getData();
120     TYPE *data = d_data.get();
121     for (j = 0; j < d_nRows; j++) {
122       id = j * d_nCols + i;
123       rData[j] = data[id];
124     }
125   }
126 
127   //! returns a pointer to our data array
getData()128   inline TYPE *getData() { return d_data.get(); }
129 
130   //! returns a const pointer to our data array
getData()131   inline const TYPE *getData() const { return d_data.get(); }
132 
133   //! Copy operator.
134   /*! We make a copy of the other Matrix's data.
135    */
136 
assign(const Matrix<TYPE> & other)137   Matrix<TYPE> &assign(const Matrix<TYPE> &other) {
138     PRECONDITION(d_nRows == other.numRows(),
139                  "Num rows mismatch in matrix copying");
140     PRECONDITION(d_nCols == other.numCols(),
141                  "Num cols mismatch in matrix copying");
142     const TYPE *otherData = other.getData();
143     TYPE *data = d_data.get();
144     memcpy(static_cast<void *>(data), static_cast<const void *>(otherData),
145            d_dataSize * sizeof(TYPE));
146     return *this;
147   }
148 
149   //! Matrix addition.
150   /*! Perform a element by element addition of other Matrix to this Matrix
151    */
152   virtual Matrix<TYPE> &operator+=(const Matrix<TYPE> &other) {
153     PRECONDITION(d_nRows == other.numRows(),
154                  "Num rows mismatch in matrix addition");
155     PRECONDITION(d_nCols == other.numCols(),
156                  "Num cols mismatch in matrix addition");
157     const TYPE *oData = other.getData();
158     unsigned int i;
159     TYPE *data = d_data.get();
160     for (i = 0; i < d_dataSize; i++) {
161       data[i] += oData[i];
162     }
163     return *this;
164   }
165 
166   //! Matrix subtraction.
167   /*! Perform a element by element subtraction of other Matrix from this Matrix
168    */
169   virtual Matrix<TYPE> &operator-=(const Matrix<TYPE> &other) {
170     PRECONDITION(d_nRows == other.numRows(),
171                  "Num rows mismatch in matrix addition");
172     PRECONDITION(d_nCols == other.numCols(),
173                  "Num cols mismatch in matrix addition");
174     const TYPE *oData = other.getData();
175     unsigned int i;
176     TYPE *data = d_data.get();
177     for (i = 0; i < d_dataSize; i++) {
178       data[i] -= oData[i];
179     }
180     return *this;
181   }
182 
183   //! Multiplication by a scalar
184   virtual Matrix<TYPE> &operator*=(TYPE scale) {
185     unsigned int i;
186     TYPE *data = d_data.get();
187     for (i = 0; i < d_dataSize; i++) {
188       data[i] *= scale;
189     }
190     return *this;
191   }
192 
193   //! division by a scalar
194   virtual Matrix<TYPE> &operator/=(TYPE scale) {
195     unsigned int i;
196     TYPE *data = d_data.get();
197     for (i = 0; i < d_dataSize; i++) {
198       data[i] /= scale;
199     }
200     return *this;
201   }
202 
203   //! copies the transpose of this Matrix into another, returns the result
204   /*!
205     \param transpose the Matrix to store the results
206 
207     \return the transpose of this matrix.
208        This is just a reference to the argument.
209 
210    */
transpose(Matrix<TYPE> & transpose)211   virtual Matrix<TYPE> &transpose(Matrix<TYPE> &transpose) const {
212     unsigned int tRows = transpose.numRows();
213     unsigned int tCols = transpose.numCols();
214     PRECONDITION(d_nCols == tRows, "Size mismatch during transposing");
215     PRECONDITION(d_nRows == tCols, "Size mismatch during transposing");
216     unsigned int i, j;
217     unsigned int idA, idAt, idT;
218     TYPE *tData = transpose.getData();
219     TYPE *data = d_data.get();
220     for (i = 0; i < d_nRows; i++) {
221       idA = i * d_nCols;
222       for (j = 0; j < d_nCols; j++) {
223         idAt = idA + j;
224         idT = j * tCols + i;
225         tData[idT] = data[idAt];
226       }
227     }
228     return transpose;
229   }
230 
231  protected:
Matrix()232   Matrix() :  d_data(){};
233   unsigned int d_nRows{0};
234   unsigned int d_nCols{0};
235   unsigned int d_dataSize{0};
236   DATA_SPTR d_data;
237 
238  private:
239   Matrix<TYPE> &operator=(const Matrix<TYPE> &other);
240 };
241 
242 //! Matrix multiplication
243 /*!
244   Multiply a Matrix A with a second Matrix B
245   so the result is C = A*B
246 
247   \param A  the first Matrix used in the multiplication
248   \param B  the Matrix by which to multiply
249   \param C  Matrix to use for the results
250 
251   \return the results of multiplying A by B.
252   This is just a reference to C.
253 */
254 template <class TYPE>
multiply(const Matrix<TYPE> & A,const Matrix<TYPE> & B,Matrix<TYPE> & C)255 Matrix<TYPE> &multiply(const Matrix<TYPE> &A, const Matrix<TYPE> &B,
256                        Matrix<TYPE> &C) {
257   unsigned int aRows = A.numRows();
258   unsigned int aCols = A.numCols();
259   unsigned int cRows = C.numRows();
260   unsigned int cCols = C.numCols();
261   unsigned int bRows = B.numRows();
262   unsigned int bCols = B.numCols();
263   CHECK_INVARIANT(aCols == bRows, "Size mismatch during multiplication");
264   CHECK_INVARIANT(aRows == cRows, "Size mismatch during multiplication");
265   CHECK_INVARIANT(bCols == cCols, "Size mismatch during multiplication");
266 
267   // we have the sizes check do do the multiplication
268   TYPE *cData = C.getData();
269   const TYPE *bData = B.getData();
270   const TYPE *aData = A.getData();
271   unsigned int i, j, k;
272   unsigned int idA, idAt, idB, idC, idCt;
273   for (i = 0; i < aRows; i++) {
274     idC = i * cCols;
275     idA = i * aCols;
276     for (j = 0; j < cCols; j++) {
277       idCt = idC + j;
278       cData[idCt] = (TYPE)0.0;
279       for (k = 0; k < aCols; k++) {
280         idAt = idA + k;
281         idB = k * bCols + j;
282         cData[idCt] += (aData[idAt] * bData[idB]);
283       }
284     }
285   }
286   return C;
287 };
288 
289 //! Matrix-Vector multiplication
290 /*!
291   Multiply a Matrix A with a Vector x
292   so the result is y = A*x
293 
294   \param A  the matrix used in the multiplication
295   \param x  the Vector by which to multiply
296   \param y  Vector to use for the results
297 
298   \return the results of multiplying x by this
299   This is just a reference to y.
300 */
301 template <class TYPE>
multiply(const Matrix<TYPE> & A,const Vector<TYPE> & x,Vector<TYPE> & y)302 Vector<TYPE> &multiply(const Matrix<TYPE> &A, const Vector<TYPE> &x,
303                        Vector<TYPE> &y) {
304   unsigned int aRows = A.numRows();
305   unsigned int aCols = A.numCols();
306   unsigned int xSiz = x.size();
307   unsigned int ySiz = y.size();
308   CHECK_INVARIANT(aCols == xSiz, "Size mismatch during multiplication");
309   CHECK_INVARIANT(aRows == ySiz, "Size mismatch during multiplication");
310   unsigned int i, j;
311   unsigned int idA, idAt;
312   const TYPE *xData = x.getData();
313   const TYPE *aData = A.getData();
314   TYPE *yData = y.getData();
315   for (i = 0; i < aRows; i++) {
316     idA = i * aCols;
317     yData[i] = (TYPE)(0.0);
318     for (j = 0; j < aCols; j++) {
319       idAt = idA + j;
320       yData[i] += (aData[idAt] * xData[j]);
321     }
322   }
323   return y;
324 };
325 
326 typedef Matrix<double> DoubleMatrix;
327 };  // namespace RDNumeric
328 
329 //! ostream operator for Matrix's
330 template <class TYPE>
331 std::ostream &operator<<(std::ostream &target,
332                          const RDNumeric::Matrix<TYPE> &mat) {
333   unsigned int nr = mat.numRows();
334   unsigned int nc = mat.numCols();
335   target << "Rows: " << mat.numRows() << " Columns: " << mat.numCols() << "\n";
336 
337   unsigned int i, j;
338   for (i = 0; i < nr; i++) {
339     for (j = 0; j < nc; j++) {
340       target << std::setw(7) << std::setprecision(3) << mat.getVal(i, j);
341     }
342     target << "\n";
343   }
344   return target;
345 }
346 
347 #endif
348