mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* Remove accidentally tracked files and unset x flag * Ignore ComicNeue * Unify test tag to `reader` * Trivial destructors * Bump CMAKE_CXX_STANDARD to 14 (#4165)
362 lines
9.9 KiB
C++
362 lines
9.9 KiB
C++
//
|
|
// Copyright (C) 2004-2006 Rational Discovery LLC
|
|
//
|
|
// @@ All Rights Reserved @@
|
|
// This file is part of the RDKit.
|
|
// The contents are covered by the terms of the BSD license
|
|
// which is included in the file license.txt, found at the root
|
|
// of the RDKit source tree.
|
|
//
|
|
#include <RDGeneral/export.h>
|
|
#ifndef __RD_SYMM_MATRIX_H__
|
|
#define __RD_SYMM_MATRIX_H__
|
|
|
|
#include "Matrix.h"
|
|
#include "SquareMatrix.h"
|
|
#include <cstring>
|
|
#include <boost/smart_ptr.hpp>
|
|
|
|
//#ifndef INVARIANT_SILENT_METHOD
|
|
//#define INVARIANT_SILENT_METHOD
|
|
//#endif
|
|
namespace RDNumeric {
|
|
//! A symmetric matrix class
|
|
/*!
|
|
The data is stored as the lower triangle, so
|
|
A[i,j] = data[i*(i+1) + j] when i >= j and
|
|
A[i,j] = data[j*(j+1) + i] when i < j
|
|
*/
|
|
template <class TYPE>
|
|
class SymmMatrix {
|
|
public:
|
|
typedef boost::shared_array<TYPE> DATA_SPTR;
|
|
|
|
explicit SymmMatrix(unsigned int N) : d_size(N), d_dataSize(N * (N + 1) / 2) {
|
|
TYPE *data = new TYPE[d_dataSize];
|
|
memset(static_cast<void *>(data), 0, d_dataSize * sizeof(TYPE));
|
|
d_data.reset(data);
|
|
}
|
|
|
|
SymmMatrix(unsigned int N, TYPE val)
|
|
: d_size(N), d_dataSize(N * (N + 1) / 2) {
|
|
TYPE *data = new TYPE[d_dataSize];
|
|
unsigned int i;
|
|
for (i = 0; i < d_dataSize; i++) {
|
|
data[i] = val;
|
|
}
|
|
d_data.reset(data);
|
|
}
|
|
|
|
SymmMatrix(unsigned int N, DATA_SPTR data)
|
|
: d_size(N), d_dataSize(N * (N + 1) / 2) {
|
|
d_data = data;
|
|
}
|
|
|
|
SymmMatrix(const SymmMatrix<TYPE> &other)
|
|
: d_size(other.numRows()), d_dataSize(other.getDataSize()) {
|
|
TYPE *data = new TYPE[d_dataSize];
|
|
const TYPE *otherData = other.getData();
|
|
|
|
memcpy(static_cast<void *>(data), static_cast<const void *>(otherData),
|
|
d_dataSize * sizeof(TYPE));
|
|
d_data.reset(data);
|
|
}
|
|
|
|
~SymmMatrix() = default;
|
|
|
|
//! returns the number of rows
|
|
inline unsigned int numRows() const { return d_size; }
|
|
|
|
//! returns the number of columns
|
|
inline unsigned int numCols() const { return d_size; }
|
|
|
|
inline unsigned int getDataSize() const { return d_dataSize; }
|
|
|
|
void setToIdentity() {
|
|
TYPE *data = d_data.get();
|
|
memset(static_cast<void *>(data), 0, d_dataSize * sizeof(TYPE));
|
|
for (unsigned int i = 0; i < d_size; i++) {
|
|
data[i * (i + 3) / 2] = (TYPE)1.0;
|
|
}
|
|
}
|
|
|
|
TYPE getVal(unsigned int i, unsigned int j) const {
|
|
URANGE_CHECK(i, d_size);
|
|
URANGE_CHECK(j, d_size);
|
|
unsigned int id;
|
|
if (i >= j) {
|
|
id = i * (i + 1) / 2 + j;
|
|
} else {
|
|
id = j * (j + 1) / 2 + i;
|
|
}
|
|
return d_data[id];
|
|
}
|
|
|
|
void setVal(unsigned int i, unsigned int j, TYPE val) {
|
|
URANGE_CHECK(i, d_size);
|
|
URANGE_CHECK(j, d_size);
|
|
unsigned int id;
|
|
if (i >= j) {
|
|
id = i * (i + 1) / 2 + j;
|
|
} else {
|
|
id = j * (j + 1) / 2 + i;
|
|
}
|
|
d_data[id] = val;
|
|
}
|
|
|
|
void getRow(unsigned int i, Vector<TYPE> &row) {
|
|
CHECK_INVARIANT(d_size == row.size(), "");
|
|
TYPE *rData = row.getData();
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int j = 0; j < d_size; j++) {
|
|
unsigned int id;
|
|
if (j <= i) {
|
|
id = i * (i + 1) / 2 + j;
|
|
} else {
|
|
id = j * (j + 1) / 2 + i;
|
|
}
|
|
rData[j] = data[id];
|
|
}
|
|
}
|
|
|
|
void getCol(unsigned int i, Vector<TYPE> &col) {
|
|
CHECK_INVARIANT(d_size == col.size(), "");
|
|
TYPE *rData = col.getData();
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int j = 0; j < d_size; j++) {
|
|
unsigned int id;
|
|
if (i <= j) {
|
|
id = j * (j + 1) / 2 + i;
|
|
} else {
|
|
id = i * (i + 1) / 2 + j;
|
|
}
|
|
rData[j] = data[id];
|
|
}
|
|
}
|
|
|
|
//! returns a pointer to our data array
|
|
inline TYPE *getData() { return d_data.get(); }
|
|
|
|
//! returns a const pointer to our data array
|
|
inline const TYPE *getData() const { return d_data.get(); }
|
|
|
|
SymmMatrix<TYPE> &operator*=(TYPE scale) {
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int i = 0; i < d_dataSize; i++) {
|
|
data[i] *= scale;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
SymmMatrix<TYPE> &operator/=(TYPE scale) {
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int i = 0; i < d_dataSize; i++) {
|
|
data[i] /= scale;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
SymmMatrix<TYPE> &operator+=(const SymmMatrix<TYPE> &other) {
|
|
CHECK_INVARIANT(d_size == other.numRows(),
|
|
"Sizes don't match in the addition");
|
|
const TYPE *oData = other.getData();
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int i = 0; i < d_dataSize; i++) {
|
|
data[i] += oData[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
SymmMatrix<TYPE> &operator-=(const SymmMatrix<TYPE> &other) {
|
|
CHECK_INVARIANT(d_size == other.numRows(),
|
|
"Sizes don't match in the addition");
|
|
const TYPE *oData = other.getData();
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int i = 0; i < d_dataSize; i++) {
|
|
data[i] -= oData[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//! in-place matrix multiplication
|
|
SymmMatrix<TYPE> &operator*=(const SymmMatrix<TYPE> &B) {
|
|
CHECK_INVARIANT(d_size == B.numRows(),
|
|
"Size mismatch during multiplication");
|
|
TYPE *cData = new TYPE[d_dataSize];
|
|
const TYPE *bData = B.getData();
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int i = 0; i < d_size; i++) {
|
|
unsigned int idC = i * (i + 1) / 2;
|
|
for (unsigned int j = 0; j < i + 1; j++) {
|
|
unsigned int idCt = idC + j;
|
|
cData[idCt] = (TYPE)0.0;
|
|
for (unsigned int k = 0; k < d_size; k++) {
|
|
unsigned int idA, idB;
|
|
if (k <= i) {
|
|
idA = i * (i + 1) / 2 + k;
|
|
} else {
|
|
idA = k * (k + 1) / 2 + i;
|
|
}
|
|
if (k <= j) {
|
|
idB = j * (j + 1) / 2 + k;
|
|
} else {
|
|
idB = k * (k + 1) / 2 + j;
|
|
}
|
|
cData[idCt] += (data[idA] * bData[idB]);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (unsigned int i = 0; i < d_dataSize; i++) {
|
|
data[i] = cData[i];
|
|
}
|
|
delete[] cData;
|
|
return (*this);
|
|
}
|
|
|
|
/* Transpose will basically return a copy of itself
|
|
*/
|
|
SymmMatrix<TYPE> &transpose(SymmMatrix<TYPE> &transpose) const {
|
|
CHECK_INVARIANT(d_size == transpose.numRows(),
|
|
"Size mismatch during transposing");
|
|
TYPE *tData = transpose.getData();
|
|
TYPE *data = d_data.get();
|
|
for (unsigned int i = 0; i < d_dataSize; i++) {
|
|
tData[i] = data[i];
|
|
}
|
|
return transpose;
|
|
}
|
|
|
|
SymmMatrix<TYPE> &transposeInplace() {
|
|
// nothing to be done we are symmetric
|
|
return (*this);
|
|
}
|
|
|
|
protected:
|
|
SymmMatrix() : d_data(0) {}
|
|
unsigned int d_size{0};
|
|
unsigned int d_dataSize{0};
|
|
DATA_SPTR d_data;
|
|
|
|
private:
|
|
SymmMatrix<TYPE> &operator=(const SymmMatrix<TYPE> &other);
|
|
};
|
|
|
|
//! SymmMatrix-SymmMatrix multiplication
|
|
/*!
|
|
Multiply SymmMatrix A with a second SymmMatrix B
|
|
and write the result to C = A*B
|
|
|
|
\param A the first SymmMatrix
|
|
\param B the second SymmMatrix to multiply
|
|
\param C SymmMatrix to use for the results
|
|
|
|
\return the results of multiplying A by B.
|
|
This is just a reference to C.
|
|
|
|
This method is reimplemented here for efficiency reasons
|
|
(we basically don't want to use getter and setter functions)
|
|
|
|
*/
|
|
template <class TYPE>
|
|
SymmMatrix<TYPE> &multiply(const SymmMatrix<TYPE> &A, const SymmMatrix<TYPE> &B,
|
|
SymmMatrix<TYPE> &C) {
|
|
unsigned int aSize = A.numRows();
|
|
CHECK_INVARIANT(B.numRows() == aSize,
|
|
"Size mismatch in matric multiplication");
|
|
CHECK_INVARIANT(C.numRows() == aSize,
|
|
"Size mismatch in matric multiplication");
|
|
TYPE *cData = C.getData();
|
|
const TYPE *aData = A.getData();
|
|
const TYPE *bData = B.getData();
|
|
for (unsigned int i = 0; i < aSize; i++) {
|
|
unsigned int idC = i * (i + 1) / 2;
|
|
for (unsigned int j = 0; j < i + 1; j++) {
|
|
unsigned int idCt = idC + j;
|
|
cData[idCt] = (TYPE)0.0;
|
|
for (unsigned int k = 0; k < aSize; k++) {
|
|
unsigned int idA, idB;
|
|
if (k <= i) {
|
|
idA = i * (i + 1) / 2 + k;
|
|
} else {
|
|
idA = k * (k + 1) / 2 + i;
|
|
}
|
|
if (k <= j) {
|
|
idB = j * (j + 1) / 2 + k;
|
|
} else {
|
|
idB = k * (k + 1) / 2 + j;
|
|
}
|
|
cData[idCt] += (aData[idA] * bData[idB]);
|
|
}
|
|
}
|
|
}
|
|
return C;
|
|
}
|
|
|
|
//! SymmMatrix-Vector multiplication
|
|
/*!
|
|
Multiply a SymmMatrix A with a Vector x
|
|
so the result is y = A*x
|
|
|
|
\param A the SymmMatrix for multiplication
|
|
\param x the Vector by which to multiply
|
|
\param y Vector to use for the results
|
|
|
|
\return the results of multiplying x by A
|
|
This is just a reference to y.
|
|
|
|
This method is reimplemented here for efficiency reasons
|
|
(we basically don't want to use getter and setter functions)
|
|
|
|
*/
|
|
template <class TYPE>
|
|
Vector<TYPE> &multiply(const SymmMatrix<TYPE> &A, const Vector<TYPE> &x,
|
|
Vector<TYPE> &y) {
|
|
unsigned int aSize = A.numRows();
|
|
CHECK_INVARIANT(aSize == x.size(), "Size mismatch during multiplication");
|
|
CHECK_INVARIANT(aSize == y.size(), "Size mismatch during multiplication");
|
|
const TYPE *xData = x.getData();
|
|
const TYPE *aData = A.getData();
|
|
TYPE *yData = y.getData();
|
|
for (unsigned int i = 0; i < aSize; i++) {
|
|
yData[i] = (TYPE)(0.0);
|
|
unsigned int idA = i * (i + 1) / 2;
|
|
for (unsigned int j = 0; j < i + 1; j++) {
|
|
// idA = i*(i+1)/2 + j;
|
|
yData[i] += (aData[idA] * xData[j]);
|
|
idA++;
|
|
}
|
|
idA--;
|
|
for (unsigned int j = i + 1; j < aSize; j++) {
|
|
// idA = j*(j+1)/2 + i;
|
|
idA += j;
|
|
yData[i] += (aData[idA] * xData[j]);
|
|
}
|
|
}
|
|
return y;
|
|
}
|
|
|
|
typedef SymmMatrix<double> DoubleSymmMatrix;
|
|
typedef SymmMatrix<int> IntSymmMatrix;
|
|
typedef SymmMatrix<unsigned int> UintSymmMatrix;
|
|
} // namespace RDNumeric
|
|
|
|
//! ostream operator for Matrix's
|
|
template <class TYPE>
|
|
std::ostream &operator<<(std::ostream &target,
|
|
const RDNumeric::SymmMatrix<TYPE> &mat) {
|
|
unsigned int nr = mat.numRows();
|
|
unsigned int nc = mat.numCols();
|
|
target << "Rows: " << mat.numRows() << " Columns: " << mat.numCols() << "\n";
|
|
|
|
for (unsigned int i = 0; i < nr; i++) {
|
|
for (unsigned int j = 0; j < nc; j++) {
|
|
target << std::setw(7) << std::setprecision(3) << mat.getVal(i, j);
|
|
}
|
|
target << "\n";
|
|
}
|
|
return target;
|
|
}
|
|
|
|
#endif
|