// // 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 namespace RDKit { namespace AtomPair { using namespace AtomPairs; AtomPairAtomInvGenerator::AtomPairAtomInvGenerator( bool includeChirality, bool topologicalTorsionCorrection) : df_includeChirality(includeChirality), df_topologicalTorsionCorrection(topologicalTorsionCorrection) {} std::vector *AtomPairAtomInvGenerator::getAtomInvariants( const ROMol &mol) const { auto *atomInvariants = new std::vector(mol.getNumAtoms()); for (const auto atom : mol.atoms()) { (*atomInvariants)[atom->getIdx()] = getAtomCode(atom, 0, df_includeChirality) - (df_topologicalTorsionCorrection ? 2 : 0); } return atomInvariants; } std::string AtomPairAtomInvGenerator::infoString() const { return "AtomPairInvariantGenerator topologicalTorsionCorrection=" + std::to_string(df_topologicalTorsionCorrection); } void AtomPairAtomInvGenerator::toJSON(boost::property_tree::ptree &pt) const { pt.put("type", "AtomPairAtomInvGenerator"); pt.put("includeChirality", df_includeChirality); pt.put("topologicalTorsionCorrection", df_topologicalTorsionCorrection); AtomInvariantsGenerator::toJSON(pt); } void AtomPairAtomInvGenerator::fromJSON(const boost::property_tree::ptree &pt) { df_includeChirality = pt.get("includeChirality", df_includeChirality); df_topologicalTorsionCorrection = pt.get( "topologicalTorsionCorrection", df_topologicalTorsionCorrection); AtomInvariantsGenerator::fromJSON(pt); } AtomPairAtomInvGenerator *AtomPairAtomInvGenerator::clone() const { return new AtomPairAtomInvGenerator(df_includeChirality, df_topologicalTorsionCorrection); } template OutputType AtomPairEnvGenerator::getResultSize() const { OutputType result = 1; return (result << (numAtomPairFingerprintBits + 2 * (this->dp_fingerprintArguments->df_includeChirality ? numChiralBits : 0))); } AtomPairArguments::AtomPairArguments( const bool countSimulation, const bool includeChirality, const bool use2D, const unsigned int minDistance, const unsigned int maxDistance, const std::vector countBounds, const std::uint32_t fpSize) : FingerprintArguments(countSimulation, countBounds, fpSize, 1, includeChirality), df_use2D(use2D), d_minDistance(minDistance), d_maxDistance(maxDistance) { PRECONDITION(minDistance <= maxDistance, "bad distances provided"); } std::string AtomPairArguments::infoString() const { return "AtomPairArguments use2D=" + std::to_string(df_use2D) + " minDistance=" + std::to_string(d_minDistance) + " maxDistance=" + std::to_string(d_maxDistance); } void AtomPairArguments::toJSON(boost::property_tree::ptree &pt) const { pt.put("type", "AtomPairArguments"); pt.put("use2D", df_use2D); pt.put("minDistance", d_minDistance); pt.put("maxDistance", d_maxDistance); FingerprintArguments::toJSON(pt); } void AtomPairArguments::fromJSON(const boost::property_tree::ptree &pt) { df_use2D = pt.get("use2D", df_use2D); d_minDistance = pt.get("minDistance", d_minDistance); d_maxDistance = pt.get("maxDistance", d_maxDistance); FingerprintArguments::fromJSON(pt); } template void AtomPairAtomEnv::updateAdditionalOutput( AdditionalOutput *additionalOutput, size_t bitId) const { PRECONDITION(additionalOutput, "bad output pointer"); if (additionalOutput->bitInfoMap) { (*additionalOutput->bitInfoMap)[bitId].emplace_back(d_atomIdFirst, d_atomIdSecond); } if (additionalOutput->atomToBits) { additionalOutput->atomToBits->at(d_atomIdFirst).push_back(bitId); additionalOutput->atomToBits->at(d_atomIdSecond).push_back(bitId); } if (additionalOutput->atomCounts) { additionalOutput->atomCounts->at(d_atomIdFirst)++; additionalOutput->atomCounts->at(d_atomIdSecond)++; } if (additionalOutput->atomsPerBit) { (*additionalOutput->atomsPerBit)[bitId].push_back(std::vector{ static_cast(d_atomIdFirst), static_cast(d_atomIdSecond)}); } } template OutputType AtomPairAtomEnv::getBitId( FingerprintArguments *arguments, const std::vector *atomInvariants, const std::vector *, // bondInvariants AdditionalOutput *, // additionalOutput, const bool hashResults, const std::uint64_t // fpSize ) const { PRECONDITION((atomInvariants->size() >= d_atomIdFirst) && (atomInvariants->size() >= d_atomIdSecond), "bad atom invariants size"); auto *atomPairArguments = dynamic_cast(arguments); std::uint32_t codeSizeLimit = (1 << (codeSize + (atomPairArguments->df_includeChirality ? numChiralBits : 0))) - 1; std::uint32_t atomCodeFirst = (*atomInvariants)[d_atomIdFirst] % codeSizeLimit; std::uint32_t atomCodeSecond = (*atomInvariants)[d_atomIdSecond] % codeSizeLimit; std::uint32_t bitId = 0; if (hashResults) { gboost::hash_combine(bitId, std::min(atomCodeFirst, atomCodeSecond)); gboost::hash_combine(bitId, d_distance); gboost::hash_combine(bitId, std::max(atomCodeFirst, atomCodeSecond)); } else { bitId = getAtomPairCode(atomCodeFirst, atomCodeSecond, d_distance, atomPairArguments->df_includeChirality); } return bitId; } template AtomPairAtomEnv::AtomPairAtomEnv(const unsigned int atomIdFirst, const unsigned int atomIdSecond, const unsigned int distance) : d_atomIdFirst(atomIdFirst), d_atomIdSecond(atomIdSecond), d_distance(distance) {} template std::vector *> AtomPairEnvGenerator::getEnvironments( const ROMol &mol, FingerprintArguments *arguments, const std::vector *fromAtoms, const std::vector *ignoreAtoms, const int confId, const AdditionalOutput *additionalOutput, const std::vector *, // atomInvariants const std::vector *, // bondInvariants, const bool // hashResults ) const { const unsigned int atomCount = mol.getNumAtoms(); PRECONDITION(!additionalOutput || !additionalOutput->atomToBits || additionalOutput->atomToBits->size() == atomCount, "bad atomToBits size in AdditionalOutput"); auto *atomPairArguments = dynamic_cast(arguments); std::vector *> result = std::vector *>(); const double *distanceMatrix; if (atomPairArguments->df_use2D) { distanceMatrix = MolOps::getDistanceMat(mol); } else { distanceMatrix = MolOps::get3DDistanceMat(mol, confId); } for (unsigned int i = 0; i < atomCount; ++i) { if (ignoreAtoms && std::find(ignoreAtoms->begin(), ignoreAtoms->end(), i) != ignoreAtoms->end()) { continue; } for (unsigned int j = i + 1; j < atomCount; ++j) { if (ignoreAtoms && std::find(ignoreAtoms->begin(), ignoreAtoms->end(), j) != ignoreAtoms->end()) { continue; } if (fromAtoms && (std::find(fromAtoms->begin(), fromAtoms->end(), i) == fromAtoms->end()) && (std::find(fromAtoms->begin(), fromAtoms->end(), j) == fromAtoms->end())) { continue; } auto distance = static_cast(floor(distanceMatrix[i * atomCount + j])); if (distance >= atomPairArguments->d_minDistance && distance <= atomPairArguments->d_maxDistance) { result.push_back(new AtomPairAtomEnv(i, j, distance)); } } } return result; } template std::string AtomPairEnvGenerator::infoString() const { return "AtomPairEnvironmentGenerator"; } template void AtomPairEnvGenerator::toJSON( boost::property_tree::ptree &pt) const { pt.put("type", "AtomPairEnvGenerator"); AtomEnvironmentGenerator::toJSON(pt); } template FingerprintGenerator *getAtomPairGenerator( const AtomPairArguments &args, AtomInvariantsGenerator *atomInvariantsGenerator, const bool ownsAtomInvGen) { AtomEnvironmentGenerator *atomPairEnvGenerator = new AtomPair::AtomPairEnvGenerator(); bool ownsAtomInvGenerator = ownsAtomInvGen; if (!atomInvariantsGenerator) { atomInvariantsGenerator = new AtomPairAtomInvGenerator(args.df_includeChirality); ownsAtomInvGenerator = true; } return new FingerprintGenerator( atomPairEnvGenerator, new AtomPairArguments(args), atomInvariantsGenerator, nullptr, ownsAtomInvGenerator, false); } template FingerprintGenerator *getAtomPairGenerator( const unsigned int minDistance, const unsigned int maxDistance, const bool includeChirality, const bool use2D, AtomInvariantsGenerator *atomInvariantsGenerator, const bool useCountSimulation, const std::uint32_t fpSize, const std::vector countBounds, const bool ownsAtomInvGen) { AtomPair::AtomPairArguments arguments(useCountSimulation, includeChirality, use2D, minDistance, maxDistance, countBounds, fpSize); return getAtomPairGenerator(arguments, atomInvariantsGenerator, ownsAtomInvGen); } template RDKIT_FINGERPRINTS_EXPORT FingerprintGenerator * getAtomPairGenerator(const AtomPairArguments &, AtomInvariantsGenerator *, const bool); template RDKIT_FINGERPRINTS_EXPORT FingerprintGenerator * getAtomPairGenerator(const AtomPairArguments &, AtomInvariantsGenerator *, const bool); template RDKIT_FINGERPRINTS_EXPORT FingerprintGenerator * getAtomPairGenerator(const unsigned int minDistance, const unsigned int maxDistance, const bool includeChirality, const bool use2D, AtomInvariantsGenerator *atomInvariantsGenerator, const bool useCountSimulation, const std::uint32_t fpSize, const std::vector countBounds, const bool ownsAtomInvGen); template RDKIT_FINGERPRINTS_EXPORT FingerprintGenerator * getAtomPairGenerator(const unsigned int minDistance, const unsigned int maxDistance, const bool includeChirality, const bool use2D, AtomInvariantsGenerator *atomInvariantsGenerator, const bool useCountSimulation, const std::uint32_t fpSize, const std::vector countBounds, const bool ownsAtomInvGen); } // namespace AtomPair } // namespace RDKit