mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
One final round of mem errors (#7943)
* fix descriptors * fix filtercatalog wrapping * fix Chem reaction enumeration * register shared_ptr * change order of declarations * fixleaks in SimDivPickers * Manage ptr arrays in ForceField/BFGSOpt
This commit is contained in:
committed by
GitHub
parent
d0fcbdac0d
commit
1201f214c4
@@ -30,6 +30,27 @@ void wrap_MMcalc();
|
||||
namespace python = boost::python;
|
||||
namespace RDDataManip {
|
||||
|
||||
template <typename T>
|
||||
class PyObjectManager : public boost::noncopyable {
|
||||
public:
|
||||
PyObjectManager() = default;
|
||||
|
||||
PyObjectManager(T *obj) : d_obj(obj) {}
|
||||
|
||||
~PyObjectManager() { Py_XDECREF((PyObject *)d_obj); }
|
||||
|
||||
PyObjectManager &operator=(T *obj) {
|
||||
Py_XDECREF((PyObject *)d_obj);
|
||||
d_obj = obj;
|
||||
return *this;
|
||||
}
|
||||
T *get() { return d_obj; }
|
||||
T *release() { return std::exchange(d_obj, nullptr); }
|
||||
|
||||
private:
|
||||
T *d_obj = nullptr;
|
||||
};
|
||||
|
||||
PyObject *getEuclideanDistMat(python::object descripMat) {
|
||||
// Bit of a pain involved here, we accept three types of PyObjects here
|
||||
// 1. A Numeric Array
|
||||
@@ -61,7 +82,7 @@ PyObject *getEuclideanDistMat(python::object descripMat) {
|
||||
|
||||
// first deal with situation where we have an Numeric Array
|
||||
PyObject *descMatObj = descripMat.ptr();
|
||||
PyArrayObject *distRes;
|
||||
PyObjectManager<PyArrayObject> distRes;
|
||||
if (PyArray_Check(descMatObj)) {
|
||||
// get the dimensions of the array
|
||||
int nrows = PyArray_DIM((PyArrayObject *)descMatObj, 0);
|
||||
@@ -79,11 +100,12 @@ PyObject *getEuclideanDistMat(python::object descripMat) {
|
||||
// grab a pointer to the data in the array so that we can directly put
|
||||
// values in there
|
||||
// and avoid copying :
|
||||
auto *dMat = (double *)PyArray_DATA(distRes);
|
||||
auto *dMat = (double *)PyArray_DATA(distRes.get());
|
||||
|
||||
PyArrayObject *copy;
|
||||
copy = (PyArrayObject *)PyArray_ContiguousFromObject(
|
||||
descMatObj, PyArray_DESCR((PyArrayObject *)descMatObj)->type_num, 2, 2);
|
||||
PyObjectManager<PyArrayObject> copy(
|
||||
(PyArrayObject *)PyArray_ContiguousFromObject(
|
||||
descMatObj, PyArray_DESCR((PyArrayObject *)descMatObj)->type_num, 2,
|
||||
2));
|
||||
// if we have double array
|
||||
if (PyArray_DESCR((PyArrayObject *)descMatObj)->type_num == NPY_DOUBLE) {
|
||||
auto *desc = (double *)PyArray_DATA((PyArrayObject *)descMatObj);
|
||||
@@ -93,49 +115,46 @@ PyObject *getEuclideanDistMat(python::object descripMat) {
|
||||
|
||||
// here is the 2D array trick this so that when the distance calaculator
|
||||
// asks for desc2D[i] we basically get the ith row as double*
|
||||
auto **desc2D = new double *[nrows];
|
||||
std::unique_ptr<double *[]> desc2D(new double *[nrows]);
|
||||
for (i = 0; i < nrows; i++) {
|
||||
desc2D[i] = desc;
|
||||
desc += ncols;
|
||||
}
|
||||
MetricMatrixCalc<double **, double *> mmCalc;
|
||||
mmCalc.setMetricFunc(&EuclideanDistanceMetric<double *, double *>);
|
||||
mmCalc.calcMetricMatrix(desc2D, nrows, ncols, dMat);
|
||||
mmCalc.calcMetricMatrix(desc2D.get(), nrows, ncols, dMat);
|
||||
|
||||
delete[] desc2D;
|
||||
// we got the distance matrix we are happy so return
|
||||
return PyArray_Return(distRes);
|
||||
return PyArray_Return(distRes.release());
|
||||
}
|
||||
|
||||
// if we have a float array
|
||||
else if (PyArray_DESCR((PyArrayObject *)descMatObj)->type_num ==
|
||||
NPY_FLOAT) {
|
||||
auto *desc = (float *)PyArray_DATA(copy);
|
||||
auto **desc2D = new float *[nrows];
|
||||
auto *desc = (float *)PyArray_DATA(copy.get());
|
||||
std::unique_ptr<float *[]> desc2D(new float *[nrows]);
|
||||
for (i = 0; i < nrows; i++) {
|
||||
desc2D[i] = desc;
|
||||
desc += ncols;
|
||||
}
|
||||
MetricMatrixCalc<float **, float *> mmCalc;
|
||||
mmCalc.setMetricFunc(&EuclideanDistanceMetric<float *, float *>);
|
||||
mmCalc.calcMetricMatrix(desc2D, nrows, ncols, dMat);
|
||||
delete[] desc2D;
|
||||
return PyArray_Return(distRes);
|
||||
mmCalc.calcMetricMatrix(desc2D.get(), nrows, ncols, dMat);
|
||||
return PyArray_Return(distRes.release());
|
||||
}
|
||||
|
||||
// if we have an integer array
|
||||
else if (PyArray_DESCR((PyArrayObject *)descMatObj)->type_num == NPY_INT) {
|
||||
int *desc = (int *)PyArray_DATA(copy);
|
||||
auto **desc2D = new int *[nrows];
|
||||
int *desc = (int *)PyArray_DATA(copy.get());
|
||||
std::unique_ptr<int *[]> desc2D(new int *[nrows]);
|
||||
for (i = 0; i < nrows; i++) {
|
||||
desc2D[i] = desc;
|
||||
desc += ncols;
|
||||
}
|
||||
MetricMatrixCalc<int **, int *> mmCalc;
|
||||
mmCalc.setMetricFunc(&EuclideanDistanceMetric<int *, int *>);
|
||||
mmCalc.calcMetricMatrix(desc2D, nrows, ncols, dMat);
|
||||
delete[] desc2D;
|
||||
return PyArray_Return(distRes);
|
||||
mmCalc.calcMetricMatrix(desc2D.get(), nrows, ncols, dMat);
|
||||
return PyArray_Return(distRes.release());
|
||||
} else {
|
||||
// unrecognized type for the matrix, throw up
|
||||
throw_value_error(
|
||||
@@ -155,7 +174,7 @@ PyObject *getEuclideanDistMat(python::object descripMat) {
|
||||
|
||||
npy_intp dMatLen = nrows * (nrows - 1) / 2;
|
||||
distRes = (PyArrayObject *)PyArray_SimpleNew(1, &dMatLen, NPY_DOUBLE);
|
||||
auto *dMat = (double *)PyArray_DATA(distRes);
|
||||
auto *dMat = (double *)PyArray_DATA(distRes.get());
|
||||
|
||||
// assume that we a have a list of list of values (that can be extracted to
|
||||
// double)
|
||||
@@ -179,7 +198,7 @@ PyObject *getEuclideanDistMat(python::object descripMat) {
|
||||
PySequenceHolder<double>>);
|
||||
mmCalc.calcMetricMatrix(dData, nrows, ncols, dMat);
|
||||
}
|
||||
return PyArray_Return(distRes);
|
||||
return PyArray_Return(distRes.release());
|
||||
}
|
||||
|
||||
PyObject *getTanimotoDistMat(python::object bitVectList) {
|
||||
|
||||
@@ -283,18 +283,17 @@ int ForceField::minimize(unsigned int snapshotFreq,
|
||||
unsigned int numIters = 0;
|
||||
unsigned int dim = this->d_numPoints * d_dimension;
|
||||
double finalForce = 0.0;
|
||||
auto *points = new double[dim];
|
||||
std::vector<double> points(dim);
|
||||
|
||||
this->scatter(points);
|
||||
this->scatter(points.data());
|
||||
ForceFieldsHelper::calcEnergy eCalc(this);
|
||||
ForceFieldsHelper::calcGradient gCalc(this);
|
||||
|
||||
int res =
|
||||
BFGSOpt::minimize(dim, points, forceTol, numIters, finalForce, eCalc,
|
||||
BFGSOpt::minimize(dim, points.data(), forceTol, numIters, finalForce, eCalc,
|
||||
gCalc, snapshotFreq, snapshotVect, energyTol, maxIts);
|
||||
this->gather(points);
|
||||
this->gather(points.data());
|
||||
|
||||
delete[] points;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Novartis Institutues for BioMedical Research Inc.
|
||||
// * Neither the name of Novartis Institutes for BioMedical Research Inc.
|
||||
// nor the names of its contributors may be used to endorse or promote
|
||||
// products derived from this software without specific prior written
|
||||
// permission.
|
||||
@@ -144,7 +144,8 @@ struct enumeration_wrapper {
|
||||
|
||||
RegisterVectorConverter<MOL_SPTR_VECT>("VectMolVect");
|
||||
|
||||
python::class_<RDKit::EnumerateLibraryBase, RDKit::EnumerateLibraryBase *,
|
||||
python::class_<RDKit::EnumerateLibraryBase,
|
||||
boost::shared_ptr<RDKit::EnumerateLibraryBase>,
|
||||
RDKit::EnumerateLibraryBase &, boost::noncopyable>(
|
||||
"EnumerateLibraryBase", python::no_init)
|
||||
.def("__nonzero__", &EnumerateLibraryBase__nonzero__,
|
||||
@@ -210,7 +211,8 @@ Options:\n\
|
||||
does not pass sanitization, then none of the products will.\n\
|
||||
";
|
||||
|
||||
python::class_<RDKit::EnumerationParams, RDKit::EnumerationParams *,
|
||||
python::class_<RDKit::EnumerationParams,
|
||||
boost::shared_ptr<RDKit::EnumerationParams>,
|
||||
RDKit::EnumerationParams &>(
|
||||
"EnumerationParams", docString.c_str(),
|
||||
python::init<>(python::args("self")))
|
||||
@@ -315,7 +317,7 @@ for result in itertools.islice(libary2, 1000):\n\
|
||||
// iterator_wrappers<EnumerateLibrary>().wrap("EnumerateLibraryIterator");
|
||||
|
||||
python::class_<RDKit::EnumerationStrategyBase,
|
||||
RDKit::EnumerationStrategyBase *,
|
||||
boost::shared_ptr<RDKit::EnumerationStrategyBase>,
|
||||
RDKit::EnumerationStrategyBase &, boost::noncopyable>(
|
||||
"EnumerationStrategyBase", python::no_init)
|
||||
.def("__nonzero__", &EnumerationStrategyBase__nonzero__,
|
||||
@@ -364,7 +366,7 @@ for result in itertools.islice(libary2, 1000):\n\
|
||||
"(0,0,0), (1,0,0), (2,0,0) ...\n";
|
||||
|
||||
python::class_<RDKit::CartesianProductStrategy,
|
||||
RDKit::CartesianProductStrategy *,
|
||||
boost::shared_ptr<RDKit::CartesianProductStrategy>,
|
||||
RDKit::CartesianProductStrategy &,
|
||||
python::bases<EnumerationStrategyBase>>(
|
||||
"CartesianProductStrategy", docString.c_str(),
|
||||
@@ -376,7 +378,8 @@ for result in itertools.islice(libary2, 1000):\n\
|
||||
docString =
|
||||
"RandomSampleStrategy simply randomly samples from the reagent sets.\n"
|
||||
"Note that this strategy never halts and can produce duplicates.";
|
||||
python::class_<RDKit::RandomSampleStrategy, RDKit::RandomSampleStrategy *,
|
||||
python::class_<RDKit::RandomSampleStrategy,
|
||||
boost::shared_ptr<RDKit::RandomSampleStrategy>,
|
||||
RDKit::RandomSampleStrategy &,
|
||||
python::bases<EnumerationStrategyBase>>(
|
||||
"RandomSampleStrategy", docString.c_str(),
|
||||
@@ -391,7 +394,7 @@ for result in itertools.islice(libary2, 1000):\n\
|
||||
"possible.\n"
|
||||
"Note that this strategy never halts and can produce duplicates.";
|
||||
python::class_<RDKit::RandomSampleAllBBsStrategy,
|
||||
RDKit::RandomSampleAllBBsStrategy *,
|
||||
boost::shared_ptr<RDKit::RandomSampleAllBBsStrategy>,
|
||||
RDKit::RandomSampleAllBBsStrategy &,
|
||||
python::bases<EnumerationStrategyBase>>(
|
||||
"RandomSampleAllBBsStrategy", docString.c_str(),
|
||||
@@ -410,7 +413,7 @@ for result in itertools.islice(libary2, 1000):\n\
|
||||
"See EnumerationStrategyBase for more details.\n";
|
||||
|
||||
python::class_<RDKit::EvenSamplePairsStrategy,
|
||||
RDKit::EvenSamplePairsStrategy *,
|
||||
boost::shared_ptr<RDKit::EvenSamplePairsStrategy>,
|
||||
RDKit::EvenSamplePairsStrategy &,
|
||||
python::bases<EnumerationStrategyBase>>(
|
||||
"EvenSamplePairsStrategy", docString.c_str(),
|
||||
|
||||
@@ -108,16 +108,20 @@ void registerDescriptors() {
|
||||
}
|
||||
|
||||
std::vector<boost::shared_ptr<PropertyFunctor>> Properties::registry;
|
||||
int Properties::registerProperty(PropertyFunctor *prop) {
|
||||
int Properties::registerProperty(boost::shared_ptr<PropertyFunctor> prop) {
|
||||
for (size_t i = 0; i < Properties::registry.size(); ++i) {
|
||||
if (registry[i]->getName() == prop->getName()) {
|
||||
Properties::registry[i] = boost::shared_ptr<PropertyFunctor>(prop);
|
||||
Properties::registry[i] = std::move(prop);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// XXX Add mutex?
|
||||
Properties::registry.emplace_back(prop);
|
||||
return Properties::registry.size();
|
||||
Properties::registry.push_back(std::move(prop));
|
||||
return Properties::registry.size() - 1;
|
||||
}
|
||||
|
||||
int Properties::registerProperty(PropertyFunctor *prop) {
|
||||
return Properties::registerProperty(boost::shared_ptr<PropertyFunctor>(prop));
|
||||
}
|
||||
|
||||
std::vector<std::string> Properties::getAvailableProperties() {
|
||||
|
||||
@@ -59,7 +59,9 @@ struct RDKIT_DESCRIPTORS_EXPORT PropertyFunctor {
|
||||
virtual ~PropertyFunctor() {}
|
||||
|
||||
//! Compute the value of the property
|
||||
virtual double operator()(const RDKit::ROMol &) const = 0;
|
||||
virtual double operator()(const RDKit::ROMol &mol) const {
|
||||
return (*d_dataFunc)(mol);
|
||||
}
|
||||
|
||||
//! Return the name of the property
|
||||
const std::string getName() const { return propName; }
|
||||
@@ -83,6 +85,7 @@ class RDKIT_DESCRIPTORS_EXPORT Properties {
|
||||
|
||||
//! Register a property function - takes ownership
|
||||
static int registerProperty(PropertyFunctor *ptr);
|
||||
static int registerProperty(boost::shared_ptr<PropertyFunctor> prop);
|
||||
static boost::shared_ptr<PropertyFunctor> getProperty(
|
||||
const std::string &name);
|
||||
static std::vector<std::string> getAvailableProperties();
|
||||
|
||||
@@ -29,14 +29,9 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include <RDGeneral/export.h>
|
||||
#ifndef RDKIT_REGISTER_DESCRIPTOR_H
|
||||
#define RDKIT_REGISTER_DESCRIPTOR_H
|
||||
|
||||
#include <RDGeneral/BoostStartInclude.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <RDGeneral/BoostEndInclude.h>
|
||||
#include "Property.h"
|
||||
|
||||
namespace RDKit {
|
||||
@@ -65,19 +60,11 @@ NAME##PropertyFunctor(false)); \
|
||||
static NAME##PropertyFunctor NAME##PropertyFunctor__;
|
||||
*/
|
||||
|
||||
#define REGISTER_DESCRIPTOR(NAME, FUNC) \
|
||||
struct NAME##PropertyFunctor : public PropertyFunctor { \
|
||||
static double _func(const ROMol &m) { \
|
||||
return static_cast<double>(FUNC(m)); \
|
||||
} \
|
||||
NAME##PropertyFunctor(bool registerProp = true) \
|
||||
: PropertyFunctor(#NAME, NAME##Version, _func) { \
|
||||
if (registerProp) \
|
||||
Properties::registerProperty(new NAME##PropertyFunctor(false)); \
|
||||
} \
|
||||
double operator()(const RDKit::ROMol &mol) const { return _func(mol); } \
|
||||
}; \
|
||||
static NAME##PropertyFunctor NAME##PropertyFunctor__;
|
||||
#define REGISTER_DESCRIPTOR(NAME, FUNC) \
|
||||
Properties::registerProperty(new PropertyFunctor( \
|
||||
#NAME, NAME##Version, \
|
||||
[](const ROMol &m) { return static_cast<double>(FUNC(m)); }));
|
||||
|
||||
} // namespace Descriptors
|
||||
} // namespace RDKit
|
||||
|
||||
|
||||
@@ -898,16 +898,25 @@ struct PythonPropertyFunctor : public RDKit::Descriptors::PropertyFunctor {
|
||||
// we can't use python props in functions.
|
||||
PythonPropertyFunctor(PyObject *self, const std::string &name,
|
||||
const std::string &version)
|
||||
: PropertyFunctor(name, version), self(self) {
|
||||
python::incref(self);
|
||||
}
|
||||
|
||||
~PythonPropertyFunctor() override { python::decref(self); }
|
||||
: PropertyFunctor(name, version), self(self) {}
|
||||
|
||||
double operator()(const RDKit::ROMol &mol) const override {
|
||||
return python::call_method<double>(self, "__call__", boost::ref(mol));
|
||||
}
|
||||
};
|
||||
|
||||
int registerPropertyHelper(python::object o) {
|
||||
// We increase the refcount to make sure the original Python object
|
||||
// does not get cleaned up (we don't want that to happen once it's
|
||||
// registered, we may need to use its __call__() method; note there's
|
||||
// no matching decref). We register the shared_ptr so that Python
|
||||
// and the (static) registry can share ownership.
|
||||
|
||||
python::incref(o.ptr());
|
||||
python::extract<boost::shared_ptr<PythonPropertyFunctor>> ptr(o);
|
||||
return RDKit::Descriptors::Properties::registerProperty(ptr());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BOOST_PYTHON_MODULE(rdMolDescriptors) {
|
||||
@@ -1583,7 +1592,7 @@ BOOST_PYTHON_MODULE(rdMolDescriptors) {
|
||||
"";
|
||||
|
||||
python::class_<RDKit::Descriptors::Properties,
|
||||
RDKit::Descriptors::Properties *>(
|
||||
boost::shared_ptr<RDKit::Descriptors::Properties>>(
|
||||
"Properties", docString.c_str(), python::init<>(python::args("self")))
|
||||
.def(python::init<const std::vector<std::string> &>(
|
||||
python::args("self", "propNames")))
|
||||
@@ -1611,8 +1620,7 @@ BOOST_PYTHON_MODULE(rdMolDescriptors) {
|
||||
.def("GetProperty", &RDKit::Descriptors::Properties::getProperty,
|
||||
python::arg("propName"), "Return the named property if it exists")
|
||||
.staticmethod("GetProperty")
|
||||
.def("RegisterProperty",
|
||||
&RDKit::Descriptors::Properties::registerProperty,
|
||||
.def("RegisterProperty", ®isterPropertyHelper,
|
||||
python::arg("propertyFunctor"),
|
||||
"Register a new property object (not thread safe)")
|
||||
.staticmethod("RegisterProperty");
|
||||
|
||||
@@ -526,21 +526,21 @@ class TestCase(unittest.TestCase):
|
||||
class NumAtoms(Descriptors.PropertyFunctor):
|
||||
|
||||
def __init__(self):
|
||||
Descriptors.PropertyFunctor.__init__(self, "NumAtoms", "1.0.0")
|
||||
Descriptors.PropertyFunctor.__init__(self, "CustomNumAtoms", "1.0.0")
|
||||
|
||||
def __call__(self, mol):
|
||||
return mol.GetNumAtoms()
|
||||
|
||||
numAtoms = NumAtoms()
|
||||
rdMD.Properties.RegisterProperty(numAtoms)
|
||||
props = rdMD.Properties(["NumAtoms"])
|
||||
props = rdMD.Properties(["CustomNumAtoms"])
|
||||
self.assertEqual(1, props.ComputeProperties(Chem.MolFromSmiles("C"))[0])
|
||||
|
||||
self.assertTrue("NumAtoms" in rdMD.Properties.GetAvailableProperties())
|
||||
self.assertTrue("CustomNumAtoms" in rdMD.Properties.GetAvailableProperties())
|
||||
# check memory
|
||||
del numAtoms
|
||||
self.assertEqual(1, props.ComputeProperties(Chem.MolFromSmiles("C"))[0])
|
||||
self.assertTrue("NumAtoms" in rdMD.Properties.GetAvailableProperties())
|
||||
self.assertTrue("CustomNumAtoms" in rdMD.Properties.GetAvailableProperties())
|
||||
|
||||
m = Chem.MolFromSmiles("c1ccccc1")
|
||||
properties = rdMD.Properties()
|
||||
@@ -709,7 +709,7 @@ class TestCase(unittest.TestCase):
|
||||
bcut2 = rdMD.BCUT2D(m, "bad_prop")
|
||||
self.assertTrue(0, "Failed to handle bad prop (not a double)")
|
||||
except RuntimeError as e:
|
||||
self.assertTrue(re.search(r"[B,b]ad any[\ ,_]cast",str(e)))
|
||||
self.assertTrue(re.search(r"[B,b]ad any[\ ,_]cast", str(e)))
|
||||
|
||||
def testOxidationNumbers(self):
|
||||
# majority of tests are in the C++ layer. These are just to make
|
||||
@@ -741,7 +741,8 @@ class TestCase(unittest.TestCase):
|
||||
self.assertTrue(abs(default.GetPackingDensity() - 0.48303) < 0.05)
|
||||
|
||||
# test set depth and radius
|
||||
depthrad = rdMD.DoubleCubicLatticeVolume(mol1, isProtein=True, includeLigand=False, probeRadius=1.6, depth=6)
|
||||
depthrad = rdMD.DoubleCubicLatticeVolume(mol1, isProtein=True, includeLigand=False,
|
||||
probeRadius=1.6, depth=6)
|
||||
|
||||
self.assertTrue(abs(depthrad.GetSurfaceArea() - 8186.06) < 0.05)
|
||||
self.assertTrue(abs(depthrad.GetVolume() - 33464.5) < 0.05)
|
||||
@@ -757,11 +758,11 @@ class TestCase(unittest.TestCase):
|
||||
self.assertTrue(abs(withlig.GetVDWVolume() - 15155.7) < 0.05)
|
||||
self.assertTrue(abs(withlig.GetCompactness() - 1.67037) < 0.05)
|
||||
self.assertTrue(abs(withlig.GetPackingDensity() - 0.48532) < 0.05)
|
||||
|
||||
|
||||
fname2 = str(Path(rdbase) / 'Code' / 'GraphMol' / 'Descriptors' / 'test_data' / 'TZL_model.sdf')
|
||||
suppl = Chem.SDMolSupplier(fname2)
|
||||
for mol in suppl:
|
||||
mol2 = mol
|
||||
mol2 = mol
|
||||
|
||||
# test from SDF file with defaults
|
||||
sdf = rdMD.DoubleCubicLatticeVolume(mol2, isProtein=False)
|
||||
@@ -770,5 +771,6 @@ class TestCase(unittest.TestCase):
|
||||
self.assertTrue(abs(sdf.GetVolume() - 411.972) < 0.05)
|
||||
self.assertTrue(abs(sdf.GetVDWVolume() - 139.97) < 0.05)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -405,7 +405,8 @@ struct filtercat_wrapper {
|
||||
python::args("self", "base"),
|
||||
"Add a FilterMatcherBase that should not appear in a molecule");
|
||||
|
||||
python::class_<FilterHierarchyMatcher, FilterHierarchyMatcher *,
|
||||
python::class_<FilterHierarchyMatcher,
|
||||
boost::shared_ptr<FilterHierarchyMatcher>,
|
||||
python::bases<FilterMatcherBase>>(
|
||||
"FilterHierarchyMatcher", FilterHierarchyMatcherDoc,
|
||||
python::init<>(python::args("self")))
|
||||
@@ -425,7 +426,7 @@ struct filtercat_wrapper {
|
||||
bool noproxy = true;
|
||||
RegisterVectorConverter<RDKit::ROMol *>("MolList", noproxy);
|
||||
|
||||
python::class_<FilterCatalogEntry, FilterCatalogEntry *,
|
||||
python::class_<FilterCatalogEntry, boost::shared_ptr<FilterCatalogEntry>,
|
||||
boost::shared_ptr<const FilterCatalogEntry>>(
|
||||
"FilterCatalogEntry", FilterCatalogEntryDoc,
|
||||
python::init<>(python::args("self")))
|
||||
@@ -492,7 +493,8 @@ struct filtercat_wrapper {
|
||||
|
||||
{
|
||||
python::scope in_FilterCatalogParams =
|
||||
python::class_<FilterCatalogParams, FilterCatalogParams *>(
|
||||
python::class_<FilterCatalogParams,
|
||||
boost::shared_ptr<FilterCatalogParams>>(
|
||||
"FilterCatalogParams", python::init<>(python::args("self")))
|
||||
.def(python::init<FilterCatalogParams::FilterCatalogs>(
|
||||
python::args("self", "catalogs"),
|
||||
|
||||
@@ -155,15 +155,6 @@ void linearSearch(unsigned int dim, double *oldPt, double oldVal, double *grad,
|
||||
}
|
||||
}
|
||||
|
||||
#define CLEANUP() \
|
||||
{ \
|
||||
delete[] grad; \
|
||||
delete[] dGrad; \
|
||||
delete[] hessDGrad; \
|
||||
delete[] newPos; \
|
||||
delete[] xi; \
|
||||
delete[] invHessian; \
|
||||
}
|
||||
//! Do a BFGS minimization of a function.
|
||||
/*!
|
||||
See Numerical Recipes in C, Section 10.7 for a description of the algorithm.
|
||||
@@ -199,26 +190,19 @@ int minimize(unsigned int dim, double *pos, double gradTol,
|
||||
PRECONDITION(pos, "bad input array");
|
||||
PRECONDITION(gradTol > 0, "bad tolerance");
|
||||
|
||||
double sum, maxStep, fp;
|
||||
|
||||
double *grad, *dGrad, *hessDGrad;
|
||||
double *newPos, *xi;
|
||||
double *invHessian;
|
||||
|
||||
grad = new double[dim];
|
||||
dGrad = new double[dim];
|
||||
hessDGrad = new double[dim];
|
||||
newPos = new double[dim];
|
||||
xi = new double[dim];
|
||||
invHessian = new double[dim * dim];
|
||||
std::vector<double> grad(dim);
|
||||
std::vector<double> dGrad(dim);
|
||||
std::vector<double> hessDGrad(dim);
|
||||
std::vector<double> xi(dim);
|
||||
std::vector<double> invHessian(dim * dim, 0);
|
||||
std::unique_ptr<double[]> newPos(new double[dim]);
|
||||
snapshotFreq = std::min(snapshotFreq, maxIts);
|
||||
|
||||
// evaluate the function and gradient in our current position:
|
||||
fp = func(pos);
|
||||
gradFunc(pos, grad);
|
||||
double fp = func(pos);
|
||||
gradFunc(pos, grad.data());
|
||||
|
||||
sum = 0.0;
|
||||
memset(invHessian, 0, dim * dim * sizeof(double));
|
||||
double sum = 0.0;
|
||||
for (unsigned int i = 0; i < dim; i++) {
|
||||
unsigned int itab = i * dim;
|
||||
// initialize the inverse hessian to be identity:
|
||||
@@ -228,15 +212,15 @@ int minimize(unsigned int dim, double *pos, double gradTol,
|
||||
sum += pos[i] * pos[i];
|
||||
}
|
||||
// pick a max step size:
|
||||
maxStep = MAXSTEP * std::max(sqrt(sum), static_cast<double>(dim));
|
||||
double maxStep = MAXSTEP * std::max(sqrt(sum), static_cast<double>(dim));
|
||||
|
||||
for (unsigned int iter = 1; iter <= maxIts; iter++) {
|
||||
for (unsigned int iter = 1; iter <= maxIts; ++iter) {
|
||||
numIters = iter;
|
||||
int status;
|
||||
int status = -1;
|
||||
|
||||
// do the line search:
|
||||
linearSearch(dim, pos, fp, grad, xi, newPos, funcVal, func, maxStep,
|
||||
status);
|
||||
linearSearch(dim, pos, fp, grad.data(), xi.data(), newPos.get(), funcVal, func,
|
||||
maxStep, status);
|
||||
CHECK_INVARIANT(status >= 0, "bad direction in linearSearch");
|
||||
|
||||
// save the function value for the next search:
|
||||
@@ -257,16 +241,14 @@ int minimize(unsigned int dim, double *pos, double gradTol,
|
||||
// "<<TOLX<<std::endl;
|
||||
if (test < TOLX) {
|
||||
if (snapshotVect && snapshotFreq) {
|
||||
RDKit::Snapshot s(boost::shared_array<double>(newPos), fp);
|
||||
RDKit::Snapshot s(boost::shared_array<double>(newPos.release()), fp);
|
||||
snapshotVect->push_back(s);
|
||||
newPos = nullptr;
|
||||
}
|
||||
CLEANUP();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// update the gradient:
|
||||
double gradScale = gradFunc(pos, grad);
|
||||
double gradScale = gradFunc(pos, grad.data());
|
||||
|
||||
// is the gradient converged?
|
||||
test = 0.0;
|
||||
@@ -281,11 +263,9 @@ int minimize(unsigned int dim, double *pos, double gradTol,
|
||||
// "<<gradTol<<std::endl;
|
||||
if (test < gradTol) {
|
||||
if (snapshotVect && snapshotFreq) {
|
||||
RDKit::Snapshot s(boost::shared_array<double>(newPos), fp);
|
||||
RDKit::Snapshot s(boost::shared_array<double>(newPos.release()), fp);
|
||||
snapshotVect->push_back(s);
|
||||
newPos = nullptr;
|
||||
}
|
||||
CLEANUP();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -306,7 +286,7 @@ int minimize(unsigned int dim, double *pos, double gradTol,
|
||||
#else
|
||||
double *ivh = &(invHessian[i * dim]);
|
||||
double &hdgradi = hessDGrad[i];
|
||||
double *dgj = dGrad;
|
||||
double *dgj = dGrad.data();
|
||||
hdgradi = 0.0;
|
||||
for (unsigned int j = 0; j < dim; ++j, ++ivh, ++dgj) {
|
||||
hdgradi += *ivh * *dgj;
|
||||
@@ -353,19 +333,20 @@ int minimize(unsigned int dim, double *pos, double gradTol,
|
||||
xi[i] -= invHessian[itab + j] * grad[j];
|
||||
}
|
||||
#else
|
||||
double &pxi = xi[i], *ivh = &(invHessian[itab]), *gj = grad;
|
||||
double &pxi = xi[i];
|
||||
double *ivh = &(invHessian[itab]);
|
||||
double *gj = grad.data();
|
||||
for (unsigned int j = 0; j < dim; ++j, ++ivh, ++gj) {
|
||||
pxi -= *ivh * *gj;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (snapshotVect && snapshotFreq && !(iter % snapshotFreq)) {
|
||||
RDKit::Snapshot s(boost::shared_array<double>(newPos), fp);
|
||||
RDKit::Snapshot s(boost::shared_array<double>(newPos.release()), fp);
|
||||
snapshotVect->push_back(s);
|
||||
newPos = new double[dim];
|
||||
newPos.reset(new double[dim]);
|
||||
}
|
||||
}
|
||||
CLEANUP();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,8 +156,8 @@ RDKit::INT_VECT MaxMinPicker::lazyPick(T &func, unsigned int poolSize,
|
||||
RDKit::INT_VECT picks;
|
||||
|
||||
unsigned int memsize = (unsigned int)(poolSize * sizeof(MaxMinPickInfo));
|
||||
MaxMinPickInfo *pinfo = new MaxMinPickInfo[memsize];
|
||||
memset(pinfo, 0, memsize);
|
||||
std::unique_ptr<MaxMinPickInfo[]> pinfo(new MaxMinPickInfo[memsize]);
|
||||
memset(pinfo.get(), 0, memsize);
|
||||
|
||||
picks.reserve(pickSize);
|
||||
unsigned int picked = 0; // picks.size()
|
||||
@@ -189,7 +189,6 @@ RDKit::INT_VECT MaxMinPicker::lazyPick(T &func, unsigned int poolSize,
|
||||
pIdx != firstPicks.end(); ++pIdx) {
|
||||
pick = static_cast<unsigned int>(*pIdx);
|
||||
if (pick >= poolSize) {
|
||||
delete[] pinfo;
|
||||
throw ValueErrorException("pick index was larger than the poolSize");
|
||||
}
|
||||
picks.push_back(pick);
|
||||
@@ -200,7 +199,6 @@ RDKit::INT_VECT MaxMinPicker::lazyPick(T &func, unsigned int poolSize,
|
||||
|
||||
if (picked >= pickSize) {
|
||||
threshold = -1.0;
|
||||
delete[] pinfo;
|
||||
return picks;
|
||||
}
|
||||
|
||||
@@ -271,11 +269,10 @@ RDKit::INT_VECT MaxMinPicker::lazyPick(T &func, unsigned int poolSize,
|
||||
// now add the new pick to picks and remove it from the pool
|
||||
*pick_prev = pinfo[pick].next;
|
||||
picks.push_back(pick);
|
||||
picked++;
|
||||
++picked;
|
||||
}
|
||||
|
||||
threshold = tmpThreshold;
|
||||
delete[] pinfo;
|
||||
return picks;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,13 @@ RDKit::INT_VECT MaxMinPicks(MaxMinPicker *picker, python::object distMat,
|
||||
i < python::extract<unsigned int>(firstPicks.attr("__len__")()); ++i) {
|
||||
firstPickVect.push_back(python::extract<int>(firstPicks[i]));
|
||||
}
|
||||
RDKit::INT_VECT res =
|
||||
picker->pick(dMat, poolSize, pickSize, firstPickVect, seed);
|
||||
RDKit::INT_VECT res;
|
||||
try {
|
||||
res = picker->pick(dMat, poolSize, pickSize, firstPickVect, seed);
|
||||
} catch (...) {
|
||||
Py_DECREF(copy);
|
||||
throw;
|
||||
}
|
||||
Py_DECREF(copy);
|
||||
return res;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user