RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
SynthonSpaceShapeSearcher.h
Go to the documentation of this file.
1//
2// Copyright (C) David Cosgrove 2025.
3//
4// @@ All Rights Reserved @@
5// This file is part of the RDKit.
6// The contents are covered by the terms of the BSD license
7// which is included in the file license.txt, found at the root
8// of the RDKit source tree.
9//
10
11// This file declares a concrete class derived from SynthonSpaceSearcher
12// that does shape similarity searching of the SynthonSpace using
13// the GaussianShape module.
14
15#ifndef SYNTHONSPACESHAPESEARCHER_H
16#define SYNTHONSPACESHAPESEARCHER_H
17
18#include <RDGeneral/export.h>
22
24
25// A hash function used to hash a pair of any kind. Taken from
26// https://stackoverflow.com/questions/32685540/why-cant-i-compile-an-unordered-map-with-a-pair-as-key
27// But with the hash combining from
28// https://stackoverflow.com/questions/5889238/why-is-xor-the-default-way-to-combine-hashes/27952689#27952689
29// Which is apparently effectively how boost::hash_combine does it.
31 size_t operator()(const std::pair<const void *, const void *> &p) const {
32 // Hash the first element
33 size_t hash1 = std::hash<const void *>{}(p.first);
34 // Hash the second element
35 size_t hash2 = std::hash<const void *>{}(p.second);
36 // Combine the two hash values
37 return hash1 ^ (hash2 + 0x517cc1b727220a95 + (hash1 << 6) + (hash1 >> 2));
38 }
39};
40
41// Used for storing the pre-computed similarities between fragments and
42// synthons. The actual type of the first address in the pair will vary,
43// the second should always be Synthon *. There's an entry only if
44// the fragment->synthon similarity exceeded the threshold. Stores the
45// combination score, the number of the shape and the transformation
46// to apply to the shape to get the overlay that gave the score.
48 std::tuple<double, unsigned int, std::shared_ptr<RDGeom::Transform3D>>;
50 std::unordered_map<std::pair<const void *, const void *>, SynthonOverlay,
52
53// Concrete class that does the search by Gaussian shape similarity.
55 public:
58 const SynthonSpaceSearchParams &params,
59 SynthonSpace *space);
60
61 std::vector<std::unique_ptr<SynthonSpaceHitSet>> searchFragSet(
62 const std::vector<std::shared_ptr<ROMol>> &fragSet,
63 const SynthonSet &reaction) const override;
64
65 bool verifyHit(ROMol &hit, const std::string &rxnId,
66 const std::vector<const std::string *> &synthNames) override;
67
68 // Use d_fragSynthonSims to decide if the fragment matched the
69 // Synthon.
70 bool fragMatchedSynthon(const void *frag, const void *synthon,
71 SynthonOverlay &sim) const;
72 bool hasPrecomputedSims() const { return !d_fragSynthonSims.empty(); }
73
74 protected:
75 bool quickVerify(const SynthonSpaceHitSet *hitset,
76 const std::vector<size_t> &synthNums) const override;
78 const std::vector<size_t> &synthNums) const override;
79 // Build the hit, doing its best to line the synthons up correctly.
80 // It may not do a great job, however for at least 2 reasons.
81 // The synthon may not match a fragment, in which case there is no
82 // good way of lining it up on the query. Also, molzip lines the
83 // fragments up using the bond vectors to the dummy atoms, but this
84 // fails if it's building a ring. The product geometry should be
85 // checked for bad bond lengths.
86 std::unique_ptr<ROMol> buildHit(
87 const SynthonSpaceHitSet *hitset, const std::vector<size_t> &synthNums,
88 std::vector<const std::string *> &synthNames) const override;
89
90 private:
91 // Shape for the query - only ever 1 conformer.
92 std::unique_ptr<SynthonShapeInput> dp_queryShape;
93 // These are the fragment shapes for this search, derived from
94 // d_query. The shapes in d_fragShapes are sorted on the address
95 // of the corresponding fragment. d_fragShapesPool is never read,
96 // it is just used a repository of the shapes for the duration of
97 // the search.
98 std::vector<std::unique_ptr<SynthonShapeInput>> d_fragShapesPool;
99 std::vector<std::pair<void *, SynthonShapeInput *>> d_fragShapes;
100
101 // Precomputed similarities between fragments and synthons. This
102 // speeds things up because synthons are re-used and for the shape
103 // search we have to calculate the similarity between every query
104 // fragment and all the synthons in each SynthonSet. Fingerprint
105 // and RASCAL searching can dismiss a lot of fragment/synthon pairs
106 // as not matching without calculating the full similarity so doing
107 // the full set of similarity calculations up front slows things
108 // down for them.
109 FragSynthonSims d_fragSynthonSims;
110
111 bool extraSearchSetup(
112 std::vector<std::vector<std::shared_ptr<ROMol>>> &fragSets,
113 const TimePoint *endTime) override;
114
115 void buildQueryShape(const ROMol &mol,
116 std::vector<GaussianShape::CustomFeature> &allFeatures);
117
118 // Fill in the d_fragSynthonSims map.
119 bool computeFragSynthonSims(
120 const TimePoint *endTime,
121 std::unordered_map<void *, unsigned int> &minFragSetSize);
122
123 void processToTrySet(
124 std::vector<std::pair<const SynthonSpaceHitSet *, std::vector<size_t>>>
125 &toTry,
126 const TimePoint *endTime, std::vector<std::unique_ptr<ROMol>> &results,
127 std::atomic<std::int64_t> &numHitsFound,
128 std::uint64_t &numPossHitsWritten) override;
129
130 // Given the frag, return the corresponding frag shape. Returns nullptr
131 // if not found.
132 SynthonShapeInput *getFragShape(const void *frag) const;
133};
134} // namespace RDKit::SynthonSpaceSearch
135#endif // SYNTHONSPACESHAPESEARCHER_H
std::chrono::time_point< Clock > TimePoint
bool fragMatchedSynthon(const void *frag, const void *synthon, SynthonOverlay &sim) const
std::vector< std::unique_ptr< SynthonSpaceHitSet > > searchFragSet(const std::vector< std::shared_ptr< ROMol > > &fragSet, const SynthonSet &reaction) const override
bool quickVerify(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums) const override
bool verifyHit(ROMol &hit, const std::string &rxnId, const std::vector< const std::string * > &synthNames) override
SynthonSpaceShapeSearcher(const ROMol &query, const SynthonSpaceSearchParams &params, SynthonSpace *space)
std::unique_ptr< ROMol > buildHit(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums, std::vector< const std::string * > &synthNames) const override
double approxSimilarity(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums) const override
std::unordered_map< std::pair< const void *, const void * >, SynthonOverlay, hash_address_pair > FragSynthonSims
std::tuple< double, unsigned int, std::shared_ptr< RDGeom::Transform3D > > SynthonOverlay
size_t operator()(const std::pair< const void *, const void * > &p) const