// // Copyright (C) 2018-2025 Boran Adas 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef RDK_BUILD_THREADSAFE_SSS #include #include #endif namespace RDKit { FingerprintArguments::FingerprintArguments( const bool countSimulation, const std::vector countBounds, std::uint32_t fpSize, std::uint32_t numBitsPerFeature, bool includeChirality) : df_countSimulation(countSimulation), df_includeChirality(includeChirality), d_countBounds(countBounds), d_fpSize(fpSize), d_numBitsPerFeature(numBitsPerFeature) { PRECONDITION(!countSimulation || !countBounds.empty(), "bad count bounds provided"); PRECONDITION(d_numBitsPerFeature > 0, "numBitsPerFeature must be >0"); } std::string FingerprintArguments::commonArgumentsString() const { return "Common arguments : countSimulation=" + std::to_string(df_countSimulation) + " fpSize=" + std::to_string(d_fpSize) + " bitsPerFeature=" + std::to_string(d_numBitsPerFeature) + " includeChirality=" + std::to_string(df_includeChirality); } void FingerprintArguments::toJSON(boost::property_tree::ptree &pt) const { pt.put("countSimulation", df_countSimulation); pt.put("fpSize", d_fpSize); pt.put("numBitsPerFeature", d_numBitsPerFeature); pt.put("includeChirality", df_includeChirality); boost::property_tree::ptree countBoundsNode; for (const auto &bound : d_countBounds) { boost::property_tree::ptree boundNode; boundNode.put("", bound); countBoundsNode.push_back(std::make_pair("", boundNode)); } pt.add_child("countBounds", countBoundsNode); } void FingerprintArguments::fromJSON(const boost::property_tree::ptree &pt) { df_countSimulation = pt.get("countSimulation", df_countSimulation); d_fpSize = pt.get("fpSize", d_fpSize); d_numBitsPerFeature = pt.get("numBitsPerFeature", d_numBitsPerFeature); df_includeChirality = pt.get("includeChirality", df_includeChirality); d_countBounds.clear(); auto countBoundsNode = pt.get_child_optional("countBounds"); if (countBoundsNode) { for (const auto &boundNode : *countBoundsNode) { d_countBounds.push_back(boundNode.second.get_value()); } } } template FingerprintGenerator::FingerprintGenerator( AtomEnvironmentGenerator *atomEnvironmentGenerator, FingerprintArguments *fingerprintArguments, AtomInvariantsGenerator *atomInvariantsGenerator, BondInvariantsGenerator *bondInvariantsGenerator, bool ownsAtomInvGenerator, bool ownsBondInvGenerator) : df_ownsAtomInvGenerator(ownsAtomInvGenerator), df_ownsBondInvGenerator(ownsBondInvGenerator) { this->dp_atomEnvironmentGenerator = atomEnvironmentGenerator; this->dp_atomEnvironmentGenerator->dp_fingerprintArguments = fingerprintArguments; this->dp_fingerprintArguments = fingerprintArguments; this->dp_atomInvariantsGenerator = atomInvariantsGenerator; this->dp_bondInvariantsGenerator = bondInvariantsGenerator; } template FingerprintGenerator::FingerprintGenerator( AtomEnvironmentGenerator *atomEnvironmentGenerator, FingerprintArguments *fingerprintArguments, AtomInvariantsGenerator *atomInvariantsGenerator, BondInvariantsGenerator *bondInvariantsGenerator, bool ownsAtomInvGenerator, bool ownsBondInvGenerator); template FingerprintGenerator::FingerprintGenerator( AtomEnvironmentGenerator *atomEnvironmentGenerator, FingerprintArguments *fingerprintArguments, AtomInvariantsGenerator *atomInvariantsGenerator, BondInvariantsGenerator *bondInvariantsGenerator, bool ownsAtomInvGenerator, bool ownsBondInvGenerator); template FingerprintGenerator::~FingerprintGenerator() { delete dp_atomEnvironmentGenerator; delete dp_fingerprintArguments; if (df_ownsAtomInvGenerator) { delete dp_atomInvariantsGenerator; } if (df_ownsBondInvGenerator) { delete dp_bondInvariantsGenerator; } } namespace { void reinitAdditionalOutput(AdditionalOutput &ao, size_t numAtoms) { if (ao.atomCounts) { ao.atomCounts->resize(numAtoms); std::fill(ao.atomCounts->begin(), ao.atomCounts->end(), 0); } if (ao.atomToBits) { ao.atomToBits->resize(numAtoms); std::fill(ao.atomToBits->begin(), ao.atomToBits->end(), std::vector()); } if (ao.bitInfoMap) { ao.bitInfoMap->clear(); } if (ao.bitPaths) { ao.bitPaths->clear(); } } } // namespace template FingerprintGenerator::~FingerprintGenerator(); template FingerprintGenerator::~FingerprintGenerator(); template std::string FingerprintGenerator::infoString() const; template std::string FingerprintGenerator::infoString() const; template std::string FingerprintGenerator::infoString() const { std::string separator = " --- "; return dp_fingerprintArguments->commonArgumentsString() + separator + dp_fingerprintArguments->infoString() + separator + dp_atomEnvironmentGenerator->infoString() + separator + (dp_atomInvariantsGenerator ? (dp_atomInvariantsGenerator->infoString() + separator) : ("No atom invariants generator" + separator)) + (dp_bondInvariantsGenerator ? (dp_bondInvariantsGenerator->infoString()) : "No bond invariants generator"); } template RDKIT_FINGERPRINTS_EXPORT void FingerprintGenerator< std::uint32_t>::toJSON(boost::property_tree::ptree &pt) const; template RDKIT_FINGERPRINTS_EXPORT void FingerprintGenerator< std::uint64_t>::toJSON(boost::property_tree::ptree &pt) const; template void FingerprintGenerator::toJSON( boost::property_tree::ptree &pt) const { pt.put("name", "FingerprintGenerator"); boost::property_tree::ptree argsNode; dp_fingerprintArguments->toJSON(argsNode); pt.add_child("fingerprintArguments", argsNode); boost::property_tree::ptree envGenNode; dp_atomEnvironmentGenerator->toJSON(envGenNode); pt.add_child("atomEnvironmentGenerator", envGenNode); if (dp_atomInvariantsGenerator) { boost::property_tree::ptree atomInvGenNode; dp_atomInvariantsGenerator->toJSON(atomInvGenNode); pt.add_child("atomInvariantsGenerator", atomInvGenNode); } if (dp_bondInvariantsGenerator) { boost::property_tree::ptree bondInvGenNode; dp_bondInvariantsGenerator->toJSON(bondInvGenNode); pt.add_child("bondInvariantsGenerator", bondInvGenNode); } } template void FingerprintGenerator::fromJSON( const boost::property_tree::ptree &pt); template void FingerprintGenerator::fromJSON( const boost::property_tree::ptree &pt); template void FingerprintGenerator::fromJSON( const boost::property_tree::ptree &) {} template RDKIT_FINGERPRINTS_EXPORT std::string generatorToJSON( const FingerprintGenerator &generator); template RDKIT_FINGERPRINTS_EXPORT std::string generatorToJSON( const FingerprintGenerator &generator); template std::string generatorToJSON(const FingerprintGenerator &generator) { boost::property_tree::ptree pt; generator.toJSON(pt); std::ostringstream buf; boost::property_tree::write_json(buf, pt, false); auto str = buf.str(); boost::algorithm::trim(str); return str; } std::unique_ptr> generatorFromJSON( const std::string &json) { std::istringstream ss; ss.str(json); boost::property_tree::ptree pt; boost::property_tree::read_json(ss, pt); std::unique_ptr> envGen; std::unique_ptr fpArgs; std::unique_ptr atomInvGen; std::unique_ptr bondInvGen; auto fpArgsNode = pt.get_child_optional("fingerprintArguments"); if (fpArgsNode) { auto typ = fpArgsNode->get_optional("type"); if (!typ) { throw ValueErrorException( "FingerprintArguments type not specified in JSON"); } if (*typ == "MorganArguments") { fpArgs.reset(new MorganFingerprint::MorganArguments()); } else if (*typ == "RDKitFPArguments") { fpArgs.reset(new RDKitFP::RDKitFPArguments()); } else if (*typ == "AtomPairArguments") { fpArgs.reset(new AtomPair::AtomPairArguments()); } else if (*typ == "TopologicalTorsionArguments") { fpArgs.reset(new TopologicalTorsion::TopologicalTorsionArguments()); } else { throw ValueErrorException("Unknown FingerprintArguments type: " + *typ); } fpArgs->fromJSON(*fpArgsNode); } auto envGenNode = pt.get_child_optional("atomEnvironmentGenerator"); if (envGenNode) { auto typ = envGenNode->get_optional("type"); if (!typ) { throw ValueErrorException( "AtomEnvironmentGenerator type not specified in JSON"); } if (*typ == "MorganEnvGenerator") { envGen.reset(new MorganFingerprint::MorganEnvGenerator()); } else if (*typ == "RDKitFPEnvGenerator") { envGen.reset(new RDKitFP::RDKitFPEnvGenerator()); } else if (*typ == "AtomPairEnvGenerator") { envGen.reset(new AtomPair::AtomPairEnvGenerator()); } else if (*typ == "TopologicalTorsionEnvGenerator") { envGen.reset(new TopologicalTorsion::TopologicalTorsionEnvGenerator< std::uint64_t>()); } else { throw ValueErrorException("Unknown AtomEnvGenerator type: " + *typ); } envGen->fromJSON(*envGenNode); } auto atomInvGenNode = pt.get_child_optional("atomInvariantsGenerator"); if (atomInvGenNode) { auto typ = atomInvGenNode->get_optional("type"); if (!typ) { throw ValueErrorException( "AtomInvariantsGenerator type not specified in JSON"); } if (*typ == "MorganAtomInvGenerator") { atomInvGen.reset(new MorganFingerprint::MorganAtomInvGenerator()); } else if (*typ == "MorganFeatureAtomInvGenerator") { atomInvGen.reset(new MorganFingerprint::MorganFeatureAtomInvGenerator()); } else if (*typ == "RDKitFPAtomInvGenerator") { atomInvGen.reset(new RDKitFP::RDKitFPAtomInvGenerator()); } else if (*typ == "AtomPairAtomInvGenerator") { atomInvGen.reset(new AtomPair::AtomPairAtomInvGenerator()); } else { throw ValueErrorException("Unknown AtomInvariantsGenerator type: " + *typ); } atomInvGen->fromJSON(*atomInvGenNode); } auto bondInvGenNode = pt.get_child_optional("bondInvariantsGenerator"); if (bondInvGenNode) { auto typ = bondInvGenNode->get_optional("type"); if (!typ) { throw ValueErrorException( "BondInvariantsGenerator type not specified in JSON"); } if (*typ == "MorganBondInvGenerator") { bondInvGen.reset(new MorganFingerprint::MorganBondInvGenerator()); } else { throw ValueErrorException("Unknown BondInvariantsGenerator type: " + *typ); } bondInvGen->fromJSON(*bondInvGenNode); } return std::make_unique>( envGen.release(), fpArgs.release(), atomInvGen ? atomInvGen.release() : nullptr, bondInvGen ? bondInvGen.release() : nullptr, true, true); } template std::unique_ptr> FingerprintGenerator::getFingerprintHelper( const ROMol &mol, FingerprintFuncArguments &args, const std::uint64_t fpSize) const { const ROMol *lmol = &mol; std::unique_ptr tmol; if (dp_fingerprintArguments->df_includeChirality && !mol.hasProp(common_properties::_StereochemDone)) { tmol = std::unique_ptr(new ROMol(mol)); MolOps::assignStereochemistry(*tmol); lmol = tmol.get(); } if (args.additionalOutput) { reinitAdditionalOutput(*args.additionalOutput, mol.getNumAtoms()); } bool hashResults = false; if (fpSize != 0) { hashResults = true; } std::unique_ptr> atomInvariants = nullptr; if (args.customAtomInvariants) { atomInvariants.reset( new std::vector(*args.customAtomInvariants)); } else if (dp_atomInvariantsGenerator) { atomInvariants.reset(dp_atomInvariantsGenerator->getAtomInvariants(mol)); } std::unique_ptr> bondInvariants = nullptr; if (args.customBondInvariants) { bondInvariants.reset( new std::vector(*args.customBondInvariants)); } else if (dp_bondInvariantsGenerator) { bondInvariants.reset(dp_bondInvariantsGenerator->getBondInvariants(mol)); } // create all atom environments that will generate the bit-ids that will // make up the fingerprint auto atomEnvironments = dp_atomEnvironmentGenerator->getEnvironments( *lmol, dp_fingerprintArguments, args.fromAtoms, args.ignoreAtoms, args.confId, args.additionalOutput, atomInvariants.get(), bondInvariants.get(), hashResults); // allocate the result auto res = std::make_unique>( fpSize ? fpSize : dp_atomEnvironmentGenerator->getResultSize()); // define a mersenne twister with customized parameters. // The standard parameters (used to create boost::mt19937) // result in an RNG that's much too computationally intensive // to seed. // These are the parameters that have been used for the RDKit fingerprint. typedef boost::random::mersenne_twister rng_type; typedef boost::uniform_int<> distrib_type; typedef boost::variate_generator source_type; std::unique_ptr generator; // // if we generate arbitrarily sized ints then mod them down to the // appropriate size, we can guarantee that a fingerprint of // size x has the same bits set as one of size 2x that's been folded // in half. This is a nice guarantee to have. // std::unique_ptr dist; std::unique_ptr randomSource; if (dp_fingerprintArguments->d_numBitsPerFeature > 1) { // we will only create the RNG if we're going to need it generator.reset(new rng_type(42u)); dist.reset(new distrib_type(0, INT_MAX)); randomSource.reset(new source_type(*generator, *dist)); } // iterate over every atom environment and generate bit-ids that will make // up the fingerprint for (const auto env : atomEnvironments) { OutputType seed = env->getBitId(dp_fingerprintArguments, atomInvariants.get(), bondInvariants.get(), args.additionalOutput, hashResults, fpSize); auto bitId = seed; if (fpSize != 0) { bitId %= fpSize; } res->setVal(bitId, res->getVal(bitId) + 1); if (args.additionalOutput) { env->updateAdditionalOutput(args.additionalOutput, bitId); } // do the additional bits if required: if (dp_fingerprintArguments->d_numBitsPerFeature > 1) { generator->seed(static_cast(seed)); for (boost::uint32_t bitN = 1; bitN < dp_fingerprintArguments->d_numBitsPerFeature; ++bitN) { bitId = (*randomSource)(); if (fpSize != 0) { bitId %= fpSize; } res->setVal(bitId, res->getVal(bitId) + 1); if (args.additionalOutput) { env->updateAdditionalOutput(args.additionalOutput, bitId); } } } delete env; } return res; } namespace { template void duplicateAdditionalOutputBit(AdditionalOutput &oldAO, AdditionalOutput &newAO, OutputType origBitId, OutputType newBitId) { PRECONDITION(!((oldAO.bitInfoMap != nullptr) ^ (newAO.bitInfoMap != nullptr)), "bitInfoMap not allocated"); PRECONDITION(!((oldAO.atomToBits != nullptr) ^ (newAO.atomToBits != nullptr)), "atomToBits not allocated"); PRECONDITION(!((oldAO.bitPaths != nullptr) ^ (newAO.bitPaths != nullptr)), "bitPaths not allocated"); // we don't need to do anything with atomCounts if (oldAO.atomToBits) { if (newAO.atomToBits->empty()) { newAO.atomToBits->resize(oldAO.atomToBits->size()); } for (unsigned int i = 0; i < oldAO.atomToBits->size(); ++i) { const auto &nv = oldAO.atomToBits->at(i); if (std::find(nv.begin(), nv.end(), origBitId) != nv.end()) { newAO.atomToBits->at(i).push_back(newBitId); } } } if (oldAO.bitInfoMap) { const auto v = oldAO.bitInfoMap->find(origBitId); if (v != oldAO.bitInfoMap->end()) { (*newAO.bitInfoMap)[newBitId] = v->second; } } if (oldAO.bitPaths) { const auto v = oldAO.bitPaths->find(origBitId); if (v != oldAO.bitPaths->end()) { (*newAO.bitPaths)[newBitId] = v->second; } } if (oldAO.atomsPerBit) { const auto v = oldAO.atomsPerBit->find(origBitId); if (v != oldAO.atomsPerBit->end()) { (*newAO.atomsPerBit)[newBitId] = v->second; } } } void setupTempAdditionalOutput(RDKit::FingerprintFuncArguments &args, AdditionalOutput &countSimulationOutput, size_t numAtoms) { if (args.additionalOutput->atomToBits) { countSimulationOutput.allocateAtomToBits(); } if (args.additionalOutput->atomCounts) { countSimulationOutput.allocateAtomCounts(); } if (args.additionalOutput->bitInfoMap) { countSimulationOutput.allocateBitInfoMap(); } if (args.additionalOutput->bitPaths) { countSimulationOutput.allocateBitPaths(); } if (args.additionalOutput->atomsPerBit) { countSimulationOutput.allocateAtomsPerBit(); } reinitAdditionalOutput(*args.additionalOutput, numAtoms); } } // namespace template std::unique_ptr> FingerprintGenerator::getSparseCountFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const { return getFingerprintHelper(mol, args); } // todo getSparseFingerprint does not completely produce the same output as // getSparseCountFingerprint. Count simulation and potential 64 bit outputs // makes size limiting necessary for getSparseFingerprint. This can be // changed if there is another way to avoid the size limitation of // SparseBitVect template std::unique_ptr FingerprintGenerator::getSparseFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const { // make sure the result will fit into SparseBitVect std::uint32_t resultSize = std::min((std::uint64_t)std::numeric_limits::max(), (std::uint64_t)dp_atomEnvironmentGenerator->getResultSize()); std::uint32_t effectiveSize = resultSize; if (dp_fingerprintArguments->df_countSimulation) { // effective size needs to be smaller than result size to compansate for // count simulation effectiveSize /= dp_fingerprintArguments->d_countBounds.size(); } AdditionalOutput countSimulationOutput; AdditionalOutput *origAO = nullptr; if (dp_fingerprintArguments->df_countSimulation && args.additionalOutput) { setupTempAdditionalOutput(args, countSimulationOutput, mol.getNumAtoms()); origAO = args.additionalOutput; args.additionalOutput = &countSimulationOutput; } auto tempResult = getFingerprintHelper(mol, args, effectiveSize); auto result = std::make_unique(resultSize); for (auto val : tempResult->getNonzeroElements()) { if (dp_fingerprintArguments->df_countSimulation) { for (unsigned int i = 0; i < dp_fingerprintArguments->d_countBounds.size(); ++i) { // for every bound in the d_countBounds in dp_fingerprintArguments, // set a bit if the occurrence count is equal or higher than the bound // for that bit const auto &bounds_count = dp_fingerprintArguments->d_countBounds; if (val.second >= static_cast(bounds_count[i])) { OutputType nBitId = val.first * bounds_count.size() + i; result->setBit(nBitId); if (args.additionalOutput) { duplicateAdditionalOutputBit(*args.additionalOutput, *origAO, static_cast(val.first), nBitId); } } } } else { result->setBit(val.first); } } if (origAO) { if (origAO->atomCounts) { *origAO->atomCounts = *countSimulationOutput.atomCounts; } args.additionalOutput = origAO; } return result; } template std::unique_ptr> FingerprintGenerator::getCountFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const { auto tempResult = getFingerprintHelper(mol, args, dp_fingerprintArguments->d_fpSize); auto result = std::make_unique>( dp_fingerprintArguments->d_fpSize); for (auto val : tempResult->getNonzeroElements()) { result->setVal(val.first, val.second); } return result; } template std::unique_ptr FingerprintGenerator::getFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const { std::uint32_t effectiveSize = dp_fingerprintArguments->d_fpSize; if (dp_fingerprintArguments->df_countSimulation) { if (dp_fingerprintArguments->d_countBounds.empty()) { throw ValueErrorException("Count bounds are empty"); } if (dp_fingerprintArguments->d_countBounds.size() >= effectiveSize) { throw ValueErrorException("Count bounds size is >= fingerprint size"); } // effective size needs to be smaller than result size to compensate for // count simulation effectiveSize /= dp_fingerprintArguments->d_countBounds.size(); } AdditionalOutput countSimulationOutput; AdditionalOutput *origAO = nullptr; if (dp_fingerprintArguments->df_countSimulation && args.additionalOutput) { setupTempAdditionalOutput(args, countSimulationOutput, mol.getNumAtoms()); origAO = args.additionalOutput; args.additionalOutput = &countSimulationOutput; } auto tempResult = getFingerprintHelper(mol, args, effectiveSize); auto result = std::make_unique(dp_fingerprintArguments->d_fpSize); for (auto val : tempResult->getNonzeroElements()) { if (dp_fingerprintArguments->df_countSimulation) { for (unsigned int i = 0; i < dp_fingerprintArguments->d_countBounds.size(); ++i) { // for every bound in the d_countBounds in dp_fingerprintArguments, // set a bit if the occurrence count is equal or higher than the bound // for that bit const auto &bounds_count = dp_fingerprintArguments->d_countBounds; if (val.second >= static_cast(bounds_count[i])) { OutputType nBitId = val.first * bounds_count.size() + i; result->setBit(nBitId); if (args.additionalOutput) { duplicateAdditionalOutputBit(*args.additionalOutput, *origAO, static_cast(val.first), nBitId); } } } } else { result->setBit(val.first); } } if (origAO) { if (origAO->atomCounts) { *origAO->atomCounts = *countSimulationOutput.atomCounts; } args.additionalOutput = origAO; } return result; } namespace { template std::vector> mtgetFingerprints( FuncType func, const std::vector &mols, int numThreads) { std::vector *fromAtoms = nullptr; std::vector *ignoreAtoms = nullptr; std::vector *customAtomInvariants = nullptr; std::vector *customBondInvariants = nullptr; int confId = -1; AdditionalOutput *additionalOutput = nullptr; FingerprintFuncArguments args(fromAtoms, ignoreAtoms, confId, additionalOutput, customAtomInvariants, customBondInvariants); std::vector> result; auto numThreadsToUse = getNumThreadsToUse(numThreads); unsigned int nmols = mols.size(); result.reserve(nmols); if (numThreadsToUse == 1) { for (auto i = 0u; i < nmols; ++i) { if (!mols[i]) { result.emplace_back(std::unique_ptr()); } else { result.emplace_back(std::move(func(*mols[i], args))); } } } #ifdef RDK_BUILD_THREADSAFE_SSS else { std::vector>> accum( numThreadsToUse); std::vector tg; for (auto ti = 0u; ti < numThreadsToUse; ++ti) { auto lfunc = [&](unsigned int tidx) { for (auto midx = tidx; midx < mols.size(); midx += numThreadsToUse) { if (!mols[midx]) { accum[tidx].emplace_back(std::unique_ptr()); } else { accum[tidx].emplace_back(std::move(func(*mols[midx], args))); } } }; tg.emplace_back(std::thread(lfunc, ti)); } for (auto &thread : tg) { if (thread.joinable()) { thread.join(); } } for (auto midx = 0u; midx < mols.size(); ++midx) { auto tidx = midx % numThreadsToUse; auto jidx = midx / numThreadsToUse; result.emplace_back(std::move(accum[tidx][jidx])); } } #endif return result; } } // namespace template std::vector> FingerprintGenerator::getFingerprints( const std::vector &mols, int numThreads) const { auto fpfunc = [&](const ROMol &mol, FingerprintFuncArguments &args) { return this->getFingerprint(mol, args); }; return mtgetFingerprints(fpfunc, mols, numThreads); } template std::vector> FingerprintGenerator::getSparseFingerprints( const std::vector &mols, int numThreads) const { auto fpfunc = [&](const ROMol &mol, FingerprintFuncArguments &args) { return this->getSparseFingerprint(mol, args); }; return mtgetFingerprints(fpfunc, mols, numThreads); } template std::vector>> FingerprintGenerator::getCountFingerprints( const std::vector &mols, int numThreads) const { auto fpfunc = [&](const ROMol &mol, FingerprintFuncArguments &args) { return this->getCountFingerprint(mol, args); }; return mtgetFingerprints, decltype(fpfunc)>( fpfunc, mols, numThreads); } template std::vector>> FingerprintGenerator::getSparseCountFingerprints( const std::vector &mols, int numThreads) const { auto fpfunc = [&](const ROMol &mol, FingerprintFuncArguments &args) { return this->getSparseCountFingerprint(mol, args); }; return mtgetFingerprints, decltype(fpfunc)>( fpfunc, mols, numThreads); } template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr> FingerprintGenerator::getSparseCountFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr> FingerprintGenerator::getSparseCountFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr FingerprintGenerator::getSparseFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr FingerprintGenerator::getSparseFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr> FingerprintGenerator::getCountFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr> FingerprintGenerator::getCountFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr FingerprintGenerator::getFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::unique_ptr FingerprintGenerator::getFingerprint( const ROMol &mol, FingerprintFuncArguments &args) const; template RDKIT_FINGERPRINTS_EXPORT std::vector> FingerprintGenerator::getFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector> FingerprintGenerator::getFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector> FingerprintGenerator::getSparseFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector> FingerprintGenerator::getSparseFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector>> FingerprintGenerator::getCountFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector>> FingerprintGenerator::getCountFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector>> FingerprintGenerator::getSparseCountFingerprints( const std::vector &mols, int numThreads) const; template RDKIT_FINGERPRINTS_EXPORT std::vector>> FingerprintGenerator::getSparseCountFingerprints( const std::vector &mols, int numThreads) const; SparseIntVect *getSparseCountFP(const ROMol &mol, FPType fPType) { std::vector tempVect(1, &mol); return (*getSparseCountFPBulk(tempVect, fPType))[0]; } SparseBitVect *getSparseFP(const ROMol &mol, FPType fPType) { std::vector tempVect(1, &mol); return (*getSparseFPBulk(tempVect, fPType))[0]; } SparseIntVect *getCountFP(const ROMol &mol, FPType fPType) { std::vector tempVect(1, &mol); return (*getCountFPBulk(tempVect, fPType))[0]; } ExplicitBitVect *getFP(const ROMol &mol, FPType fPType) { std::vector tempVect(1, &mol); return (*getFPBulk(tempVect, fPType))[0]; } std::vector *> *getSparseCountFPBulk( const std::vector molVector, FPType fPType) { FingerprintGenerator *generator = nullptr; switch (fPType) { case FPType::AtomPairFP: { generator = AtomPair::getAtomPairGenerator(); break; } case FPType::MorganFP: { generator = MorganFingerprint::getMorganGenerator(2); break; } case FPType::RDKitFP: { generator = RDKitFP::getRDKitFPGenerator(); break; } case FPType::TopologicalTorsionFP: { generator = TopologicalTorsion::getTopologicalTorsionGenerator(); break; } default: { throw UnimplementedFPException( "Fingerprint type not implemented for getSparseCountFP"); } } auto *res = new std::vector *>(); for (const auto *mol : molVector) { res->push_back(generator->getSparseCountFingerprint(*mol)); } delete generator; return res; } std::vector *getSparseFPBulk( const std::vector molVector, FPType fPType) { FingerprintGenerator *generator = nullptr; switch (fPType) { case FPType::AtomPairFP: { generator = AtomPair::getAtomPairGenerator(); break; } case FPType::MorganFP: { generator = MorganFingerprint::getMorganGenerator(2); break; } case FPType::RDKitFP: { generator = RDKitFP::getRDKitFPGenerator(); break; } case FPType::TopologicalTorsionFP: { generator = TopologicalTorsion::getTopologicalTorsionGenerator(); break; } default: { throw UnimplementedFPException( "Fingerprint type not implemented for getSparseFP"); } } auto *res = new std::vector(); for (const auto *mol : molVector) { res->push_back(generator->getSparseFingerprint(*mol)); } delete generator; return res; } std::vector *> *getCountFPBulk( const std::vector molVector, FPType fPType) { FingerprintGenerator *generator = nullptr; switch (fPType) { case FPType::AtomPairFP: { generator = AtomPair::getAtomPairGenerator(); break; } case FPType::MorganFP: { generator = MorganFingerprint::getMorganGenerator(2); break; } case FPType::RDKitFP: { generator = RDKitFP::getRDKitFPGenerator(); break; } case FPType::TopologicalTorsionFP: { generator = TopologicalTorsion::getTopologicalTorsionGenerator(); break; } default: { throw UnimplementedFPException( "Fingerprint type not implemented for getCountFP"); } } auto *res = new std::vector *>(); for (const auto *mol : molVector) { res->push_back(generator->getCountFingerprint(*mol)); } delete generator; return res; } std::vector *getFPBulk( const std::vector molVector, FPType fPType) { FingerprintGenerator *generator = nullptr; switch (fPType) { case FPType::AtomPairFP: { generator = AtomPair::getAtomPairGenerator(); break; } case FPType::MorganFP: { generator = MorganFingerprint::getMorganGenerator(2); break; } case FPType::RDKitFP: { generator = RDKitFP::getRDKitFPGenerator(); break; } case FPType::TopologicalTorsionFP: { generator = TopologicalTorsion::getTopologicalTorsionGenerator(); break; } default: { throw UnimplementedFPException( "Fingerprint type not implemented for getFP"); } } auto *res = new std::vector(); for (const auto *mol : molVector) { res->push_back(generator->getFingerprint(*mol)); } delete generator; return res; } } // namespace RDKit