mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
Add Molecular Interaction Fields (#7993)
* Add RealValueVect.
* Add UniformRealValueGrid3D
* Add Molecular Interaction Fields (MIFs)
* line endings
* cherry-pick f1bc94a4c8
* format
* Adapt tests for python3.
* Adapt RealValueVector pickling for python3.
* Speed-up of MIF calculations.
* Bugfix in MIFDescriptors.cpp.
* all tests pass
* clean up some memory leaks
* update copyrights
* rename
* rename the library
* complete the rename
* lost file
* another forgotten file
* cleanup
* clang-tidy
* clang-tidy
* windows DLL builds work
* python wrapper and tests cleanup
* convert to catch2 testing
* switch RealValueVect to use std::vector
* remove obsolete friend
* - Replace explicit loops with stdlib implicit equivalents
- Replace explicit types with auto where possible
- Avoid unnecessary copy operations where possible
- Replace raw pointers with exception-safe unique_ptr
- Replace C-style #define with constexpr
- Replace C-style casts with C++ casts
- Replace C-style arrays with std::vector
- Avoid code duplication with templated operators
- Replace VdWaals class taking multiple atom type definitions and force-field name as string parameter with force-field-specific classes deriving from an abstract VdWaals class
- Replace x,y,z doubles with Point3D class where possible
- Removed unused (and untested) DistanceToClosestAtom class
- Renamed some variables and functions for better clarity
- Converted tabs to spaces
- Made the mol parameter in cube read/write functions optional for convenience
- Made the Python wrappers more pythonic (e.g., avoid C++-style passing objects as parameters which are modified in place)
- Implemented alternative Python class constructors using boost::python::make_constructor rather than with external non-class functions
- The Python wrappers taking a sequence of Point3D now take a sequence of sequences, such that the output of Conformer.GetPositions() can be passed
- Made the Python wrapper sequence parsing more robust
- Removed duplicated code from Python wrappers
* - avoid an unnecessary copy
* progress
* works
* more cleanup
* all tests pass
* changes in response to review
---------
Co-authored-by: dfhahn <dfhahn@users.noreply.github.com>
Co-authored-by: ptosco <paolo.tosco@novartis.com>
This commit is contained in:
@@ -7,6 +7,7 @@ rdkit_library(DataStructs
|
||||
BitVect.cpp SparseBitVect.cpp ExplicitBitVect.cpp Utils.cpp
|
||||
base64.cpp BitOps.cpp DiscreteDistMat.cpp
|
||||
DiscreteValueVect.cpp FPBReader.cpp MultiFPBReader.cpp
|
||||
RealValueVect.cpp
|
||||
LINK_LIBRARIES RDGeneral)
|
||||
target_compile_definitions(DataStructs PRIVATE RDKIT_DATASTRUCTS_BUILD)
|
||||
|
||||
@@ -19,6 +20,7 @@ rdkit_headers(base64.h
|
||||
DatastructsStreamOps.h
|
||||
DiscreteDistMat.h
|
||||
DiscreteValueVect.h
|
||||
RealValueVect.h
|
||||
ExplicitBitVect.h
|
||||
SparseBitVect.h
|
||||
SparseIntVect.h
|
||||
|
||||
@@ -41,7 +41,7 @@ class RDKIT_DATASTRUCTS_EXPORT DiscreteValueVect {
|
||||
d_valsPerInt = BITS_PER_INT / d_bitsPerVal;
|
||||
d_numInts = (length + d_valsPerInt - 1) / d_valsPerInt;
|
||||
d_mask = ((1 << d_bitsPerVal) - 1);
|
||||
std::uint32_t *data = new std::uint32_t[d_numInts];
|
||||
auto *data = new std::uint32_t[d_numInts];
|
||||
memset(static_cast<void *>(data), 0, d_numInts * sizeof(std::uint32_t));
|
||||
d_data.reset(data);
|
||||
}
|
||||
|
||||
164
Code/DataStructs/RealValueVect.cpp
Normal file
164
Code/DataStructs/RealValueVect.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
|
||||
// other RDKit contributors
|
||||
//
|
||||
// @@ 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 "RealValueVect.h"
|
||||
#include <RDGeneral/Invariant.h>
|
||||
#include <RDGeneral/StreamOps.h>
|
||||
#include "DatastructsException.h"
|
||||
|
||||
constexpr double VAL_TOL = 0.01;
|
||||
|
||||
namespace RDKit {
|
||||
const int ci_REALVALUEVECTPICKLE_VERSION = 0x1;
|
||||
|
||||
double RealValueVect::getVal(unsigned int i) const {
|
||||
if (i >= d_length) {
|
||||
throw IndexErrorException(i);
|
||||
}
|
||||
return d_data[i];
|
||||
}
|
||||
|
||||
void RealValueVect::setVal(unsigned int i, double val) {
|
||||
if (i >= d_length) {
|
||||
throw IndexErrorException(i);
|
||||
}
|
||||
d_data[i] = val;
|
||||
}
|
||||
|
||||
double RealValueVect::getTotalVal() const {
|
||||
return std::accumulate(d_data.begin(), d_data.end(), 0.0,
|
||||
std::plus<double>());
|
||||
}
|
||||
|
||||
bool RealValueVect::compareVectors(const RealValueVect &other) const {
|
||||
if (getLength() != other.getLength()) {
|
||||
throw ValueErrorException("Comparing vectors of different lengths");
|
||||
}
|
||||
return std::equal(this->d_data.begin(), this->d_data.end(),
|
||||
other.d_data.begin(), [](auto v1, auto v2) {
|
||||
return fabs((v1 - v2) / (v1 != 0 ? v1 : 1)) <= VAL_TOL;
|
||||
});
|
||||
}
|
||||
|
||||
double computeL1Norm(const RealValueVect &v1, const RealValueVect &v2) {
|
||||
if (v1.getLength() != v2.getLength()) {
|
||||
throw ValueErrorException("Comparing vectors of different lengths");
|
||||
}
|
||||
double res = 0.0;
|
||||
for (auto i = 0u; i < v1.getLength(); ++i) {
|
||||
res += fabs(v1.getData()[i] - v2.getData()[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string RealValueVect::toString() const {
|
||||
std::stringstream ss(std::ios_base::binary | std::ios_base::out |
|
||||
std::ios_base::in);
|
||||
|
||||
std::int32_t tVers = ci_REALVALUEVECTPICKLE_VERSION * -1;
|
||||
streamWrite(ss, tVers);
|
||||
std::uint32_t tInt = d_length;
|
||||
streamWrite(ss, tInt);
|
||||
|
||||
#if defined(BOOST_BIG_ENDIAN)
|
||||
std::vector<double> td(d_length);
|
||||
std::transform(d_data.begin(), d_data.end(), td.begin(), [](const auto v) {
|
||||
return EndianSwapBytes<HOST_ENDIAN_ORDER, LITTLE_ENDIAN_ORDER>(v);
|
||||
});
|
||||
ss.write(reinterpret_cast<const char *>(td.data()),
|
||||
d_length * sizeof(double));
|
||||
const auto *data = td.data();
|
||||
#else
|
||||
const auto *data = d_data.data();
|
||||
#endif
|
||||
ss.write(reinterpret_cast<const char *>(data), d_length * sizeof(double));
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
void RealValueVect::initFromText(const char *pkl, const unsigned int len) {
|
||||
std::stringstream ss(std::ios_base::binary | std::ios_base::in |
|
||||
std::ios_base::out);
|
||||
ss.write(pkl, len);
|
||||
std::int32_t tVers;
|
||||
streamRead(ss, tVers);
|
||||
tVers *= -1;
|
||||
if (tVers != 0x1) {
|
||||
throw ValueErrorException("bad version in RealValueVect pickle");
|
||||
}
|
||||
std::uint32_t tInt;
|
||||
streamRead(ss, tInt);
|
||||
d_length = tInt;
|
||||
d_data.resize(d_length);
|
||||
auto *data = d_data.data();
|
||||
ss.read(reinterpret_cast<char *>(data), d_length * sizeof(double));
|
||||
|
||||
#if defined(BOOST_BIG_ENDIAN)
|
||||
std::transform(d_data.begin(), d_data.end(), d_data.begin(), [](auto &v) {
|
||||
return EndianSwapBytes<LITTLE_ENDIAN_ORDER, HOST_ENDIAN_ORDER>(v);
|
||||
});
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename O>
|
||||
RealValueVect &RealValueVect::applyBinaryOp(const RealValueVect &other, O op) {
|
||||
PRECONDITION(other.d_length == d_length, "length mismatch");
|
||||
for (unsigned int i = 0; i < d_length; ++i) {
|
||||
double v1 = getVal(i);
|
||||
double v2 = other.getVal(i);
|
||||
setVal(i, op(v1, v2));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RealValueVect &RealValueVect::operator&=(const RealValueVect &other) {
|
||||
static const double &(*minOp)(const double &, const double &) =
|
||||
std::min<double>;
|
||||
return applyBinaryOp(other, minOp);
|
||||
}
|
||||
|
||||
RealValueVect &RealValueVect::operator|=(const RealValueVect &other) {
|
||||
static const double &(*maxOp)(const double &, const double &) =
|
||||
std::max<double>;
|
||||
return applyBinaryOp(other, maxOp);
|
||||
}
|
||||
|
||||
RealValueVect &RealValueVect::operator+=(const RealValueVect &other) {
|
||||
return applyBinaryOp(other, std::plus<double>());
|
||||
}
|
||||
|
||||
RealValueVect &RealValueVect::operator-=(const RealValueVect &other) {
|
||||
return applyBinaryOp(other, std::minus<double>());
|
||||
}
|
||||
|
||||
RealValueVect operator+(const RealValueVect &p1, const RealValueVect &p2) {
|
||||
RealValueVect res(p1);
|
||||
res += p2;
|
||||
return res;
|
||||
}
|
||||
|
||||
RealValueVect operator-(const RealValueVect &p1, const RealValueVect &p2) {
|
||||
RealValueVect res(p1);
|
||||
res -= p2;
|
||||
return res;
|
||||
}
|
||||
|
||||
RealValueVect operator|(const RealValueVect &p1, const RealValueVect &p2) {
|
||||
RealValueVect res(p1);
|
||||
res |= p2;
|
||||
return res;
|
||||
};
|
||||
|
||||
RealValueVect operator&(const RealValueVect &p1, const RealValueVect &p2) {
|
||||
RealValueVect res(p1);
|
||||
res &= p2;
|
||||
return res;
|
||||
};
|
||||
|
||||
} // end of namespace RDKit
|
||||
137
Code/DataStructs/RealValueVect.h
Normal file
137
Code/DataStructs/RealValueVect.h
Normal file
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
|
||||
// other RDKit contributors
|
||||
//
|
||||
// @@ 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_REAL_VALUE_VECT_20140407
|
||||
#define RD_REAL_VALUE_VECT_20140407
|
||||
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
namespace RDGeom {
|
||||
class UniformRealValueGrid3D;
|
||||
}
|
||||
namespace RDKit {
|
||||
|
||||
//! a class for efficiently storing vectors of double values
|
||||
//! Has additional features compared to std::vector<double>:
|
||||
//! construct from and write to pickle
|
||||
class RDKIT_DATASTRUCTS_EXPORT RealValueVect {
|
||||
public:
|
||||
RealValueVect() = default;
|
||||
//! initialize with a particular size
|
||||
RealValueVect(unsigned int length) : d_length(length) {
|
||||
d_data.resize(d_length, 0.0);
|
||||
}
|
||||
|
||||
//! initialize with a particular size and initial value
|
||||
RealValueVect(unsigned int length, double val) : d_length(length) {
|
||||
d_data.resize(d_length, val);
|
||||
}
|
||||
|
||||
//! constructor from a pickle
|
||||
RealValueVect(const std::string &pkl) {
|
||||
initFromText(pkl.c_str(), pkl.size());
|
||||
};
|
||||
|
||||
//! constructor from a pickle
|
||||
RealValueVect(const char *pkl, unsigned int len) { initFromText(pkl, len); };
|
||||
|
||||
//! return the value at an index
|
||||
double getVal(unsigned int i) const;
|
||||
|
||||
//! support indexing using []
|
||||
double operator[](unsigned int idx) const { return getVal(idx); };
|
||||
|
||||
//! set the value at an index
|
||||
void setVal(unsigned int i, double val);
|
||||
|
||||
//! returns the sum of all the elements in the vect
|
||||
double getTotalVal() const;
|
||||
|
||||
//! returns the length
|
||||
unsigned int getLength() const { return d_length; };
|
||||
|
||||
//! returns the length
|
||||
unsigned int size() const { return getLength(); };
|
||||
|
||||
//! compares 2 vectors and returns false if different
|
||||
bool compareVectors(const RealValueVect &other) const;
|
||||
|
||||
//! in-place operator&
|
||||
RealValueVect &operator&=(const RealValueVect &other);
|
||||
|
||||
//! in-place operator|
|
||||
RealValueVect &operator|=(const RealValueVect &other);
|
||||
|
||||
//! in-place operator+
|
||||
RealValueVect &operator+=(const RealValueVect &other);
|
||||
|
||||
//! in-place operator-
|
||||
RealValueVect &operator-=(const RealValueVect &other);
|
||||
|
||||
//! returns a binary string representation (pickle)
|
||||
std::string toString() const;
|
||||
|
||||
void setLength(unsigned int sz) {
|
||||
d_length = sz;
|
||||
d_data.resize(sz);
|
||||
}
|
||||
void setToVal(double val) { std::fill(d_data.begin(), d_data.end(), val); }
|
||||
|
||||
const std::vector<double> &getData() const { return d_data; }
|
||||
std::vector<double> &getData() { return d_data; }
|
||||
|
||||
private:
|
||||
void initFromText(const char *pkl, const unsigned int len);
|
||||
unsigned int d_length = 0;
|
||||
std::vector<double> d_data;
|
||||
|
||||
template <typename O>
|
||||
RealValueVect &applyBinaryOp(const RealValueVect &other, O op);
|
||||
}; // end of declaration of class RealValueVect
|
||||
|
||||
//! returns L1 Norm of vectors
|
||||
RDKIT_DATASTRUCTS_EXPORT double computeL1Norm(const RealValueVect &v1,
|
||||
const RealValueVect &v2);
|
||||
|
||||
//! returns the sum of vectors
|
||||
RDKIT_DATASTRUCTS_EXPORT RealValueVect operator+(const RealValueVect &p1,
|
||||
const RealValueVect &p2);
|
||||
|
||||
//! returns the difference of vectors
|
||||
RDKIT_DATASTRUCTS_EXPORT RealValueVect operator-(const RealValueVect &p1,
|
||||
const RealValueVect &p2);
|
||||
|
||||
//! support rvv3 = rvv1|rvv2
|
||||
/*!
|
||||
|
||||
operator| returns the maximum value for each element.
|
||||
e.g.:
|
||||
[0,1,2,0] | [0,1,1,1] -> [0,1,2,1]
|
||||
|
||||
*/
|
||||
RDKIT_DATASTRUCTS_EXPORT RealValueVect operator|(const RealValueVect &p1,
|
||||
const RealValueVect &p2);
|
||||
|
||||
//! support rvv3 = rvv1&rvv2
|
||||
/*!
|
||||
operator& returns the minimum value for each element.
|
||||
e.g.:
|
||||
[0,1,2,0] & [0,1,1,1] -> [0,1,1,0]
|
||||
|
||||
*/
|
||||
RDKIT_DATASTRUCTS_EXPORT RealValueVect operator&(const RealValueVect &p1,
|
||||
const RealValueVect &p2);
|
||||
|
||||
} // end of namespace RDKit
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,7 @@
|
||||
remove_definitions(-DRDKIT_DATASTRUCTS_BUILD)
|
||||
rdkit_python_extension(cDataStructs
|
||||
DataStructs.cpp DiscreteValueVect.cpp SparseIntVect.cpp
|
||||
RealValueVect.cpp
|
||||
wrap_SparseBV.cpp wrap_ExplicitBV.cpp wrap_BitOps.cpp
|
||||
wrap_FPB.cpp
|
||||
wrap_Utils.cpp
|
||||
@@ -12,6 +13,8 @@ add_pytest(pyBV
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testBV.py)
|
||||
add_pytest(pyDiscreteValueVect
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testDiscreteValueVect.py)
|
||||
add_pytest(pyRealValueVect
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testRealValueVect.py)
|
||||
add_pytest(pySparseIntVect
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/testSparseIntVect.py)
|
||||
add_pytest(pyFPB
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <DataStructs/BitVects.h>
|
||||
#include <DataStructs/DiscreteValueVect.h>
|
||||
#include <DataStructs/SparseIntVect.h>
|
||||
|
||||
#include <DataStructs/RealValueVect.h>
|
||||
#include <RDBoost/boost_numpy.h>
|
||||
#include <numpy/npy_common.h>
|
||||
#include <RDBoost/import_array.h>
|
||||
@@ -28,11 +28,13 @@ void wrap_EBV();
|
||||
void wrap_BitOps();
|
||||
void wrap_Utils();
|
||||
void wrap_discreteValVect();
|
||||
void wrap_realValVect();
|
||||
void wrap_sparseIntVect();
|
||||
void wrap_FPB();
|
||||
|
||||
template <typename T>
|
||||
void convertToNumpyArray(const T &v, python::object destArray) {
|
||||
namespace {
|
||||
template <typename T, typename U>
|
||||
void converter(const T &v, python::object destArray, U func) {
|
||||
if (!PyArray_Check(destArray.ptr())) {
|
||||
throw_value_error("Expecting a Numeric array object");
|
||||
}
|
||||
@@ -44,12 +46,22 @@ void convertToNumpyArray(const T &v, python::object destArray) {
|
||||
dims.len = 1;
|
||||
PyArray_Resize(destP, &dims, 0, NPY_ANYORDER);
|
||||
for (unsigned int i = 0; i < v.size(); ++i) {
|
||||
PyObject *iItem = PyInt_FromLong(v[i]);
|
||||
PyObject *iItem = func(v[i]);
|
||||
PyArray_SETITEM(destP, static_cast<char *>(PyArray_GETPTR1(destP, i)),
|
||||
iItem);
|
||||
Py_DECREF(iItem);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
void convertToIntNumpyArray(const T &v, python::object destArray) {
|
||||
converter(v, destArray, PyLong_FromLong);
|
||||
}
|
||||
template <typename T>
|
||||
void convertToDoubleNumpyArray(const T &v, python::object destArray) {
|
||||
converter(v, destArray, PyFloat_FromDouble);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(cDataStructs) {
|
||||
rdkit_import_array();
|
||||
@@ -72,31 +84,36 @@ BOOST_PYTHON_MODULE(cDataStructs) {
|
||||
wrap_EBV();
|
||||
wrap_BitOps();
|
||||
wrap_discreteValVect();
|
||||
wrap_realValVect();
|
||||
wrap_sparseIntVect();
|
||||
wrap_FPB();
|
||||
|
||||
python::def(
|
||||
"ConvertToNumpyArray",
|
||||
(void (*)(const ExplicitBitVect &, python::object))convertToNumpyArray,
|
||||
(void (*)(const ExplicitBitVect &, python::object))convertToIntNumpyArray,
|
||||
(python::arg("bv"), python::arg("destArray")));
|
||||
python::def("ConvertToNumpyArray",
|
||||
(void (*)(const RDKit::DiscreteValueVect &,
|
||||
python::object))convertToNumpyArray,
|
||||
python::object))convertToIntNumpyArray,
|
||||
(python::arg("bv"), python::arg("destArray")));
|
||||
python::def("ConvertToNumpyArray",
|
||||
(void (*)(const RDKit::SparseIntVect<std::int32_t> &,
|
||||
python::object))convertToNumpyArray,
|
||||
python::object))convertToIntNumpyArray,
|
||||
(python::arg("bv"), python::arg("destArray")));
|
||||
python::def("ConvertToNumpyArray",
|
||||
(void (*)(const RDKit::SparseIntVect<boost::int64_t> &,
|
||||
python::object))convertToNumpyArray,
|
||||
python::object))convertToIntNumpyArray,
|
||||
(python::arg("bv"), python::arg("destArray")));
|
||||
python::def("ConvertToNumpyArray",
|
||||
(void (*)(const RDKit::SparseIntVect<std::uint32_t> &,
|
||||
python::object))convertToNumpyArray,
|
||||
python::object))convertToIntNumpyArray,
|
||||
(python::arg("bv"), python::arg("destArray")));
|
||||
python::def("ConvertToNumpyArray",
|
||||
(void (*)(const RDKit::SparseIntVect<boost::uint64_t> &,
|
||||
python::object))convertToNumpyArray,
|
||||
python::object))convertToIntNumpyArray,
|
||||
(python::arg("bv"), python::arg("destArray")));
|
||||
python::def("ConvertToNumpyArray",
|
||||
(void (*)(const RDKit::RealValueVect &,
|
||||
python::object))convertToDoubleNumpyArray,
|
||||
(python::arg("rvv"), python::arg("destArray")));
|
||||
}
|
||||
|
||||
73
Code/DataStructs/Wrap/RealValueVect.cpp
Executable file
73
Code/DataStructs/Wrap/RealValueVect.cpp
Executable file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright (c) 2014-2024, Novartis Institutes for BioMedical Research and
|
||||
// other RDKit contributors
|
||||
//
|
||||
// @@ 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 <boost/python.hpp>
|
||||
|
||||
#include <RDGeneral/types.h>
|
||||
#include <RDGeneral/Invariant.h>
|
||||
#include <RDBoost/PySequenceHolder.h>
|
||||
#include <DataStructs/RealValueVect.h>
|
||||
|
||||
using namespace RDKit;
|
||||
|
||||
struct rvv_pickle_suite : rdkit_pickle_suite {
|
||||
static python::tuple getinitargs(const RealValueVect &self) {
|
||||
std::string res = self.toString();
|
||||
python::object retval = python::object(
|
||||
python::handle<>(PyBytes_FromStringAndSize(res.c_str(), res.length())));
|
||||
return python::make_tuple(retval);
|
||||
};
|
||||
};
|
||||
|
||||
std::string realValVectDoc =
|
||||
"A container class for storing real\n\
|
||||
values.\n\
|
||||
\n\
|
||||
The length of the vector is set at construction time.\n\
|
||||
\n\
|
||||
As you would expect, _RealValueVects_ support a set of binary operations\n\
|
||||
so you can do things like:\n\
|
||||
rvv3 = rvv1 & rvv2 the result contains the smallest value in each entry\n\
|
||||
rvv3 = rvv1 | rvv2 the result contains the largest value in each entry\n\
|
||||
rvv1 += rvv2 \n\
|
||||
rvv3 = rvv1 + rvv2 \n\
|
||||
rvv1 -= rvv3 \n\
|
||||
rvv3 = rvv1 - rvv2 \n\
|
||||
\n\
|
||||
Elements can be set and read using indexing (i.e. bv[i] = 4 or val=bv[i])\n\
|
||||
\n";
|
||||
|
||||
struct realValVec_wrapper {
|
||||
static void wrap() {
|
||||
python::class_<RealValueVect>("RealValueVect", realValVectDoc.c_str(),
|
||||
python::init<unsigned int>("Constructor"))
|
||||
.def(python::init<std::string>())
|
||||
.def("__len__", &RealValueVect::getLength,
|
||||
"Get the number of entries in the vector")
|
||||
.def("__setitem__", &RealValueVect::setVal,
|
||||
"Set the value at a specified location")
|
||||
.def("__getitem__", &RealValueVect::getVal,
|
||||
"Get the value at a specified location")
|
||||
.def(python::self & python::self)
|
||||
.def(python::self | python::self)
|
||||
.def(python::self - python::self)
|
||||
.def(python::self -= python::self)
|
||||
.def(python::self + python::self)
|
||||
.def(python::self += python::self)
|
||||
.def("GetTotalVal", &RealValueVect::getTotalVal,
|
||||
"Get the sum of the values in the vector, basically L1 norm")
|
||||
.def_pickle(rvv_pickle_suite());
|
||||
python::def("ComputeL1Norm", computeL1Norm,
|
||||
"Compute the distance between two real vector values\n");
|
||||
}
|
||||
};
|
||||
|
||||
void wrap_realValVect() { realValVec_wrapper::wrap(); }
|
||||
6
Code/DataStructs/Wrap/testData/rvvs.pkl
Normal file
6
Code/DataStructs/Wrap/testData/rvvs.pkl
Normal file
@@ -0,0 +1,6 @@
|
||||
crdkit.DataStructs.cDataStructs
|
||||
RealValueVect
|
||||
p1
|
||||
(S'\xff\xff\xff\xff\x1e\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xcc\xcc\xcc\xcc\xcc\xf4?\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
tRp2
|
||||
.
|
||||
118
Code/DataStructs/Wrap/testRealValueVect.py
Normal file
118
Code/DataStructs/Wrap/testRealValueVect.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# testRealValueVect.py
|
||||
#
|
||||
# 14.04.2014 by David Hahn, hahnda6
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
from rdkit import RDConfig
|
||||
import os, sys, pickle
|
||||
import unittest
|
||||
from rdkit import DataStructs as ds
|
||||
|
||||
|
||||
class TestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def test1Real(self):
|
||||
v1 = ds.RealValueVect(30)
|
||||
for i in range(30):
|
||||
v1[i] = i / 10.0
|
||||
|
||||
self.assertTrue(len(v1) == 30)
|
||||
self.assertAlmostEqual(v1.GetTotalVal(), 43.5)
|
||||
|
||||
for i in range(len(v1)):
|
||||
self.assertAlmostEqual(v1[i], 0.1 * i)
|
||||
|
||||
def test2RealVectDistances(self):
|
||||
v1 = ds.RealValueVect(30)
|
||||
v2 = ds.RealValueVect(30)
|
||||
for i in range(15):
|
||||
v1[2 * i] = 1.3
|
||||
v2[2 * i] = 1.3
|
||||
self.assertAlmostEqual(ds.ComputeL1Norm(v1, v2), 0)
|
||||
for i in range(30):
|
||||
if (i % 3 == 0):
|
||||
v2[i] = 1.3
|
||||
else:
|
||||
v2[i] = 0
|
||||
self.assertAlmostEqual(ds.ComputeL1Norm(v1, v2), 19.5)
|
||||
|
||||
def test3Pickles(self):
|
||||
#outF = file('../testData/rvvs.pkl','wb+')
|
||||
with open(os.path.join(RDConfig.RDBaseDir, 'Code/DataStructs/Wrap/testData/rvvs.pkl'),
|
||||
'rb') as inF:
|
||||
v1 = ds.RealValueVect(30)
|
||||
for i in range(15):
|
||||
v1[2 * i] = 1.3
|
||||
v2 = pickle.loads(pickle.dumps(v1))
|
||||
self.assertAlmostEqual(ds.ComputeL1Norm(v1, v2), 0)
|
||||
#pickle.dump(v1,outF)
|
||||
v2 = pickle.load(inF, encoding='bytes')
|
||||
self.assertAlmostEqual(ds.ComputeL1Norm(v1, v2), 0)
|
||||
self.assertAlmostEqual(v1.GetTotalVal(), v2.GetTotalVal())
|
||||
self.assertTrue(v2.GetTotalVal() != 0)
|
||||
#outF.close()
|
||||
|
||||
def test4RealVectOps(self):
|
||||
v1 = ds.RealValueVect(8)
|
||||
for i in range(4):
|
||||
v1[2 * i] = 2.1
|
||||
self.assertAlmostEqual(v1.GetTotalVal(), 8.4)
|
||||
v2 = ds.RealValueVect(8)
|
||||
for i in range(4):
|
||||
v2[2 * i + 1] = 2.1
|
||||
v2[2 * i] = 1.1
|
||||
self.assertAlmostEqual(v2.GetTotalVal(), 12.8)
|
||||
|
||||
v3 = v1 | v2
|
||||
self.assertTrue(len(v3) == len(v2))
|
||||
self.assertAlmostEqual(v3.GetTotalVal(), 16.8)
|
||||
|
||||
v3 = v1 & v2
|
||||
self.assertTrue(len(v3) == len(v2))
|
||||
self.assertAlmostEqual(v3.GetTotalVal(), 4.4)
|
||||
|
||||
v4 = v1 + v2
|
||||
self.assertTrue(len(v4) == len(v2))
|
||||
self.assertAlmostEqual(v4.GetTotalVal(), 21.2)
|
||||
|
||||
v4 = v1 - v2
|
||||
self.assertAlmostEqual(v4.GetTotalVal(), -4.4)
|
||||
v4 = v2 - v1
|
||||
self.assertAlmostEqual(v4.GetTotalVal(), 4.4)
|
||||
|
||||
v4 = v2
|
||||
v4 -= v1
|
||||
self.assertAlmostEqual(v4.GetTotalVal(), 4.4)
|
||||
v4 -= v4
|
||||
self.assertAlmostEqual(v4.GetTotalVal(), 0)
|
||||
|
||||
def testIterator(self):
|
||||
v1 = ds.RealValueVect(30)
|
||||
for i in range(15):
|
||||
v1[2 * i] = 1.1
|
||||
l1 = list(v1)
|
||||
self.assertTrue(len(l1) == len(v1))
|
||||
for i, v in enumerate(v1):
|
||||
self.assertAlmostEqual(l1[i], v)
|
||||
with self.assertRaises(IndexError):
|
||||
v1[40]
|
||||
|
||||
def test9ToNumpy(self):
|
||||
import numpy
|
||||
bv = ds.RealValueVect(32)
|
||||
bv[0] = 1.1
|
||||
bv[1] = 4.4
|
||||
bv[17] = 1.2
|
||||
bv[23] = 8.3
|
||||
bv[31] = 12.2
|
||||
arr = numpy.zeros((32, ), numpy.double)
|
||||
ds.ConvertToNumpyArray(bv, arr)
|
||||
for i in range(len(bv)):
|
||||
self.assertAlmostEqual(bv[i], arr[i])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "base64.h"
|
||||
#include <cmath>
|
||||
#include "DiscreteValueVect.h"
|
||||
#include "RealValueVect.h"
|
||||
#include <RDGeneral/Invariant.h>
|
||||
#include <RDGeneral/RDLog.h>
|
||||
#include <RDGeneral/Exceptions.h>
|
||||
@@ -1450,6 +1451,117 @@ void test17Github3994() {
|
||||
TEST_ASSERT(siv1 == siv2);
|
||||
}
|
||||
|
||||
void test14RealVect() {
|
||||
RealValueVect vect1(30);
|
||||
unsigned int i;
|
||||
for (i = 0; i < 15; ++i) {
|
||||
vect1.setVal(2 * i, 1.0);
|
||||
}
|
||||
|
||||
TEST_ASSERT(vect1.getLength() == 30);
|
||||
TEST_ASSERT(feq(vect1.getTotalVal(), 15.0));
|
||||
for (i = 0; i < vect1.getLength(); ++i) {
|
||||
TEST_ASSERT(feq(vect1.getVal(i), (i + 1) % 2));
|
||||
}
|
||||
|
||||
RealValueVect vect2(30);
|
||||
for (i = 0; i < vect2.getLength(); ++i) {
|
||||
vect2.setVal(i, double(1.0 / (i + 1.0)));
|
||||
}
|
||||
|
||||
TEST_ASSERT(vect2.getLength() == 30);
|
||||
for (i = 0; i < vect2.getLength(); ++i) {
|
||||
TEST_ASSERT(feq(vect2.getVal(i), double(1.0 / (i + 1.0))));
|
||||
}
|
||||
|
||||
// test copy constructor and operator[]
|
||||
RealValueVect vect3(vect2);
|
||||
TEST_ASSERT(vect3.getLength() == 30);
|
||||
for (i = 0; i < vect3.getLength(); ++i) {
|
||||
TEST_ASSERT(feq(vect3[i], double(1.0 / (i + 1.0))));
|
||||
}
|
||||
|
||||
double Pi = 3.141592;
|
||||
RealValueVect vect4(60, Pi);
|
||||
TEST_ASSERT(feq(vect4.getTotalVal(), 60 * Pi));
|
||||
}
|
||||
|
||||
void test15RealVectDists() {
|
||||
RealValueVect v1(30);
|
||||
RealValueVect v2(30);
|
||||
unsigned int i;
|
||||
for (i = 0; i < 15; ++i) {
|
||||
v1.setVal(2 * i, 1.0);
|
||||
v2.setVal(2 * i, 1.0);
|
||||
}
|
||||
TEST_ASSERT(feq(computeL1Norm(v1, v2), 0));
|
||||
for (i = 0; i < 30; ++i) {
|
||||
v2.setVal(i, i % 2);
|
||||
}
|
||||
|
||||
TEST_ASSERT(feq(computeL1Norm(v1, v2), 30.0));
|
||||
|
||||
for (i = 0; i < 30; ++i) {
|
||||
if (i % 3 == 0) {
|
||||
v2.setVal(i, 1.0);
|
||||
} else {
|
||||
v2.setVal(i, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT(feq(computeL1Norm(v1, v2), 15.0));
|
||||
|
||||
for (i = 0; i < 30; ++i) {
|
||||
v1.setVal(i, 0.0);
|
||||
v2.setVal(i, i / 10.0);
|
||||
}
|
||||
|
||||
TEST_ASSERT(feq(computeL1Norm(v1, v2), 43.5))
|
||||
}
|
||||
|
||||
void test16RealVectPickles() {
|
||||
RealValueVect v1(30);
|
||||
unsigned int i;
|
||||
for (i = 0; i < 15; ++i) {
|
||||
v1.setVal(2 * i, 1.1);
|
||||
}
|
||||
RealValueVect v2(v1.toString());
|
||||
TEST_ASSERT(feq(computeL1Norm(v1, v2), 0.0));
|
||||
}
|
||||
|
||||
void test17RealVectOps() {
|
||||
RealValueVect vect1(8);
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
vect1.setVal(2 * i, 2.1);
|
||||
}
|
||||
TEST_ASSERT(vect1.getLength() == 8);
|
||||
TEST_ASSERT(feq(vect1.getTotalVal(), 8.4));
|
||||
|
||||
RealValueVect vect2(8);
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
vect2.setVal(2 * i + 1, 2.2);
|
||||
vect2.setVal(2 * i, 1.1);
|
||||
}
|
||||
TEST_ASSERT(feq(vect2.getTotalVal(), 13.2));
|
||||
|
||||
RealValueVect vect3 = vect1 & vect2;
|
||||
TEST_ASSERT(vect3.getLength() == 8);
|
||||
TEST_ASSERT(feq(vect3.getTotalVal(), 4.4));
|
||||
|
||||
RealValueVect vect4 = vect1 | vect2;
|
||||
TEST_ASSERT(vect4.getLength() == 8);
|
||||
TEST_ASSERT(feq(vect4.getTotalVal(), 17.2));
|
||||
|
||||
RealValueVect vect5 = vect1 + vect2;
|
||||
TEST_ASSERT(vect5.getLength() == 8);
|
||||
TEST_ASSERT(feq(vect5.getTotalVal(), 21.6));
|
||||
|
||||
vect5 = vect1 - vect2;
|
||||
TEST_ASSERT(feq(vect5.getTotalVal(), -4.8));
|
||||
vect5 = vect2 - vect1;
|
||||
TEST_ASSERT(feq(vect5.getTotalVal(), 4.8));
|
||||
}
|
||||
|
||||
int main() {
|
||||
RDLog::InitLogs();
|
||||
boost::logging::enable_logs("rdApp.info");
|
||||
@@ -1561,5 +1673,21 @@ int main() {
|
||||
<< std::endl;
|
||||
test17Github3994();
|
||||
|
||||
BOOST_LOG(rdInfoLog)
|
||||
<< " Test RealValue Vectors 1: Constructors and Accessing Values -------------------------------"
|
||||
<< std::endl;
|
||||
test14RealVect();
|
||||
BOOST_LOG(rdInfoLog)
|
||||
<< " Test RealValue Vectors 2: L1Norm -------------------------------"
|
||||
<< std::endl;
|
||||
test15RealVectDists();
|
||||
BOOST_LOG(rdInfoLog)
|
||||
<< " Test RealValue Vectors 3: Pickles -------------------------------"
|
||||
<< std::endl;
|
||||
test16RealVectPickles();
|
||||
BOOST_LOG(rdInfoLog)
|
||||
<< " Test RealValue Vectors 4: Vector Operations -------------------------------"
|
||||
<< std::endl;
|
||||
test17RealVectOps();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user