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:
Ricardo Rodriguez
2024-10-29 01:46:43 -04:00
committed by greg landrum
parent 4552642d97
commit 8884e6e6ef
12 changed files with 137 additions and 127 deletions

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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(),

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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

View File

@@ -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", &registerPropertyHelper,
python::arg("propertyFunctor"),
"Register a new property object (not thread safe)")
.staticmethod("RegisterProperty");

View File

@@ -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()

View File

@@ -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"),

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}