RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
SynthonSpaceSearcher.h
Go to the documentation of this file.
1//
2// Copyright (C) David Cosgrove 2024.
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 an abstract base class for searching a synthon
12// space. Concrete base classes include SynthonSpaceSubstructureSearcher
13// and SynthonSpaceFingerprintSearcher.
14
15#ifndef SYNTHONSPACESEARCHER_H
16#define SYNTHONSPACESEARCHER_H
17
18#include <atomic>
19#include <chrono>
20#include <functional>
21#include <mutex>
22#include <random>
23
24#include <RDGeneral/export.h>
25#include <GraphMol/ROMol.h>
29
30using Clock = std::chrono::steady_clock;
31using TimePoint = std::chrono::time_point<Clock>;
32
33namespace RDKit {
34
35namespace SynthonSpaceSearch {
36
37// Abstract base class for searching the SynthonSpace.
39 public:
42 const SynthonSpaceSearchParams &params,
43 SynthonSpace *space);
48
49 virtual ~SynthonSpaceSearcher() = default;
50
52 void search(const SearchResultCallback &cb, ThreadMode threadMode);
53 // Take the contents of d_params.possibleHitsFile between the
54 // given lines, build them, check against the query and return
55 // any that match.
56 SearchResults checkPossibleHits(std::uint64_t startLine,
57 std::uint64_t finishLine);
58
59 SynthonSpace *getSpace() const { return d_space; }
60 const ROMol &getQuery() const { return d_query; }
61 const SynthonSpaceSearchParams &getParams() const { return d_params; }
62
63 // Do the search of this fragSet against the SynthonSet in the
64 // appropriate way, for example by substructure or fingerprint
65 // similarity.
66 virtual std::vector<std::unique_ptr<SynthonSpaceHitSet>> searchFragSet(
67 const std::vector<std::shared_ptr<ROMol>> &fragSet,
68 const SynthonSet &reaction) const = 0;
69
70 // Make the hit, constructed from a specific combination of
71 // synthons in the hitset, and verify that it matches the
72 // query in the appropriate way. There'll be 1 entry in synthNums
73 // for each synthon list in the hitset. Returns an empty pointer
74 // if the hit isn't accepted for whatever reason.
75 std::unique_ptr<ROMol> buildAndVerifyHit(
76 const SynthonSpaceHitSet *hitset, const std::vector<size_t> &synthNums);
77
78 // Checks that the given molecule is definitely a hit according to
79 // the derived class' criteria. This function checks the chiralAtomCount
80 // if appropriate, which required a non-const ROMol. Some derived classes
81 // will also update d_bestHitFound.
82 virtual bool verifyHit(ROMol &mol, const std::string &,
83 const std::vector<const std::string *> &);
84
85 protected:
86 // Build the hit, as used by buildAndVerifyHit. Fills in the synthon
87 // names, assuming the vector is already the correct size.
88 virtual std::unique_ptr<ROMol> buildHit(
89 const SynthonSpaceHitSet *hitset, const std::vector<size_t> &synthNums,
90 std::vector<const std::string *> &synthNames) const;
91
92 // Compute an approximate similarity between the hit and query. It's used
93 // to sort the possible hits in descending approximate similarity to try
94 // and get the most similar hits to the top of the list. It will probably
95 // be the same one as used in quickVerify, if appropriate.
96 virtual double approxSimilarity(
97 const SynthonSpaceHitSet *hitset,
98 const std::vector<size_t> &synthNums) const = 0;
99
100 // Do a check against number of heavy atoms etc. if options call for it
101 // which can be done without having to build the full molecule from the
102 // synthons. Some of the search methods (fingerprints, for example) can do
103 // additional quick checks on whether this set of synthons can match the query
104 // without building the full molecule.
105 virtual bool quickVerify(const SynthonSpaceHitSet *hitset,
106 const std::vector<size_t> &synthNums) const;
107
108 // If the similarity found is greater than d_bestSimilarity, replace
109 // d_bestHitFound with a copy of possBest and update d_bestSimilarity.
110 void updateBestHitSoFar(const ROMol &possBest, double sim);
111 double getBestSimilaritySoFar() const { return d_bestSimilarity; }
112
114 const std::vector<
115 std::pair<const SynthonSpaceHitSet *, std::vector<size_t>>> &toTry,
116 const TimePoint *endTime, std::vector<std::unique_ptr<ROMol>> &results,
117 std::atomic<std::int64_t> &numHitsFound,
118 std::uint64_t &numPossHitsWritten);
119
120 // Passed to details::splitMolecule to determine how the fragment
121 // sets are uniquified.
123
124 private:
125 std::unique_ptr<std::mt19937> d_randGen;
126
127 const ROMol d_query;
128 const SynthonSpaceSearchParams d_params;
129 SynthonSpace *d_space;
130 std::unique_ptr<ROMol> d_bestHitFound;
131 double d_bestSimilarity{0.0};
132
133 // This for updating d_bestHitFound and d_bestSimilarity
134 std::mutex d_bestHitsMutex;
135
136 // Generally, the search needs the query fragmented into no more than
137 // the largest number synthon sets in any reaction. Substructure search
138 // needs more than that, sometimes.
139 virtual unsigned int getNumQueryFragmentsRequired();
140 // Some of the search methods might need extra setup of the fragment
141 // sets. The FingerprintSearcher, for example, needs fingerprints
142 // for all the fragments. The SubstructureSearcher needs connector
143 // regions and information about them.
144 virtual bool extraSearchSetup(
145 std::vector<std::vector<std::shared_ptr<ROMol>>> &, const TimePoint *) {
146 return true;
147 }
148
149 std::vector<std::unique_ptr<SynthonSpaceHitSet>> assembleHitSets(
150 const TimePoint *endTime, bool &timedOut, std::uint64_t &totHits,
151 ThreadMode threadMode);
152
153 std::vector<std::unique_ptr<SynthonSpaceHitSet>> doTheSearch(
154 std::vector<std::vector<std::shared_ptr<ROMol>>> &fragSets,
155 const TimePoint *endTime, bool &timedOut, std::uint64_t &totHits,
156 ThreadMode threadMode);
157
158 // Build the molecules from the synthons identified in hitsets.
159 // Checks that all the results produced match the
160 // query. Duplicates by name are not returned,
161 // but duplicate SMILES from different reactions will be.
162 // Hitsets will be re-ordered on exit.
163 void buildHits(std::vector<std::unique_ptr<SynthonSpaceHitSet>> &hitsets,
164 const TimePoint *endTime, bool &timedOut,
165 std::vector<std::unique_ptr<ROMol>> &results);
166 void buildAllHits(
167 const std::vector<std::unique_ptr<SynthonSpaceHitSet>> &hitsets,
168 const TimePoint *endTime, bool &timedOut,
169 std::vector<std::unique_ptr<ROMol>> &results);
170 void sortToTryByApproxSimilarity(
171 std::vector<std::pair<const SynthonSpaceHitSet *, std::vector<size_t>>>
172 &toTry) const;
173 virtual void processToTrySet(
174 std::vector<std::pair<const SynthonSpaceHitSet *, std::vector<size_t>>>
175 &toTry,
176 const TimePoint *endTime, std::vector<std::unique_ptr<ROMol>> &results,
177 std::atomic<std::int64_t> &numHitsFound,
178 std::uint64_t &numPossHitsWritten);
179
180 // get the subset of synthons for the given reaction to use for this
181 // enumeration.
182 std::vector<std::vector<ROMol *>> getSynthonsToUse(
183 const std::vector<boost::dynamic_bitset<>> &synthonsToUse,
184 const std::string &reaction_id) const;
185};
186
187} // namespace SynthonSpaceSearch
188} // namespace RDKit
189#endif // SYNTHONSPACESEARCHER_H
Defines the primary molecule class ROMol as well as associated typedefs.
std::chrono::steady_clock Clock
std::chrono::time_point< Clock > TimePoint
contains a class for searching combinatorial libraries in Synthon format such as Enamine REAL.
SynthonSpaceSearcher(SynthonSpaceSearcher &&other)=delete
virtual bool verifyHit(ROMol &mol, const std::string &, const std::vector< const std::string * > &)
virtual double approxSimilarity(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums) const =0
SynthonSpaceSearcher(const ROMol &query, const SynthonSpaceSearchParams &params, SynthonSpace *space)
SynthonSpaceSearcher(const SynthonSpaceSearcher &other)=delete
void updateBestHitSoFar(const ROMol &possBest, double sim)
SearchResults search(ThreadMode threadMode)
virtual std::unique_ptr< ROMol > buildHit(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums, std::vector< const std::string * > &synthNames) const
void search(const SearchResultCallback &cb, ThreadMode threadMode)
SynthonSpaceSearcher & operator=(const SynthonSpaceSearcher &other)=delete
virtual std::vector< std::unique_ptr< SynthonSpaceHitSet > > searchFragSet(const std::vector< std::shared_ptr< ROMol > > &fragSet, const SynthonSet &reaction) const =0
std::unique_ptr< ROMol > buildAndVerifyHit(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums)
const SynthonSpaceSearchParams & getParams() const
SearchResults checkPossibleHits(std::uint64_t startLine, std::uint64_t finishLine)
void makeHitsFromToTry(const std::vector< std::pair< const SynthonSpaceHitSet *, std::vector< size_t > > > &toTry, const TimePoint *endTime, std::vector< std::unique_ptr< ROMol > > &results, std::atomic< std::int64_t > &numHitsFound, std::uint64_t &numPossHitsWritten)
SynthonSpaceSearcher & operator=(SynthonSpaceSearcher &&other)=delete
virtual bool quickVerify(const SynthonSpaceHitSet *hitset, const std::vector< size_t > &synthNums) const
std::function< bool(std::vector< std::unique_ptr< ROMol > > &)> SearchResultCallback
Std stuff.