Coverage Report

Created: 2026-03-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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