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