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