RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
SynthonSet.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#ifndef RDKIT_SYNTHONSET_H
12#define RDKIT_SYNTHONSET_H
13
14#include <iosfwd>
15#include <string>
16#include <vector>
17
18#include <boost/dynamic_bitset.hpp>
19
20#include <RDGeneral/export.h>
24
25namespace RDKit {
26class ROMol;
27
28namespace SynthonSpaceSearch {
29class Synthon;
30class SynthonSpace;
32struct ShapeBuildParams;
33
34// For holding a sample molecule from this set, based on the given
35// synthon which is in the d_synthonSetNum vector of d_synthons
36// of the SynthonSet. Used for building shapes. The d_mol isn't
37// built immediately to save memory, so the information needed to
38// produce it is all captured.
40 const class SynthonSet *d_synthonSet{nullptr};
41 Synthon *d_synthon{nullptr};
42 std::vector<size_t> d_synthonNums;
44 std::unique_ptr<ROMol> d_mol{nullptr};
45 unsigned int d_numAtoms{0};
46};
47
48// This class holds pointers to all the synthons for a particular
49// reaction. The synthons themselves are in a pool in the
50// SynthonSpace.
52 public:
53 SynthonSet() = default;
54 explicit SynthonSet(const std::string &id) : d_id(id) {}
55 SynthonSet(const SynthonSet &rhs) = delete;
56 SynthonSet(SynthonSet &&rhs) = delete;
57
58 const std::string &getId() const { return d_id; }
59 const std::vector<std::vector<std::pair<std::string, Synthon *>>> &
60 getSynthons() const {
61 return d_synthons;
62 }
63 // Return the synthon of the given number in the given set, based on
64 // the sorted order rather than the input order. Returns empty string
65 // and nullptr if the numbers are invalid.
66 const std::pair<std::string, Synthon *> getSubstructureOrderedSynthon(
67 size_t setNum, size_t synthonNum) const;
68 const std::pair<std::string, Synthon *> getFingerprintOrderedSynthon(
69 size_t setNum, size_t synthonNum) const;
70 const std::pair<std::string, Synthon *> getRascalOrderedSynthon(
71 size_t setNum, size_t synthonNum) const;
72 // Return the actual synthon number given its ordered number. Returns
73 // "-1" if the numbers are invalid.
75 size_t synthonNum) const;
76 size_t getFingerprintOrderedSynthonNum(size_t setNum,
77 size_t synthonNum) const;
78 size_t getRascalOrderedSynthonNum(size_t setNum, size_t synthonNum) const;
79
80 const boost::dynamic_bitset<> &getConnectors() const { return d_connectors; }
81 const std::vector<boost::dynamic_bitset<>> &getSynthonConnectorPatterns()
82 const {
83 return d_synthConnPatts;
84 }
85 const std::vector<std::shared_ptr<ROMol>> &getConnectorRegions() const;
86 const std::vector<std::string> &getConnectorRegionSmiles() const;
87 const std::vector<std::unique_ptr<ExplicitBitVect>> &getConnRegFPs() const;
88 const std::unique_ptr<ExplicitBitVect> &getAddFP() const;
89 const std::unique_ptr<ExplicitBitVect> &getSubtractFP() const;
90 const std::vector<int> &getNumConnectors() const;
91 std::uint64_t getNumProducts() const;
92 bool hasFingerprints() const;
94 unsigned int getNumRingFormers() const { return d_numRingFormers; }
95
96 // Writes to/reads from a binary stream.
97 void writeToDBStream(std::ostream &os) const;
98 void readFromDBStream(std::istream &is, const SynthonSpace &space,
99 std::uint32_t version);
100 // write the enumerated molecules to the stream in SMILES format.
101 void enumerateToStream(std::ostream &os) const;
102
103 // This stores the pointer to the Synthon, but doesn't manage
104 // it and should never delete it.
105 void addSynthon(int synthonSetNum, Synthon *newSynthon,
106 const std::string &synthonId);
107
108 // Sometimes the synthon sets are numbered from 1 in the text file,
109 // in which case there'll be an empty set 0.
111
112 // The bonds in the synthons may not be the same as in the products, and
113 // this is a problem for aromatic ring creation in particular. Such as:
114 // [1*]=CC=C[2*] and [1*]Nc1c([2*])cccc1 giving c1ccc2ncccc2c1. So
115 // make versions of the synthons that reflect this, stored as searchMol
116 // in each synthon.
118
119 // Build the connector regions and their fingerprints. Only used when
120 // creating a SynthonSpace from a text file.
122
123 // Scan through the connectors ([1*], [2*] etc.) in the synthons
124 // and set bits in d_connectors accordingly. Also removes any empty
125 // reagent sets, which might be because the synthon numbers start from
126 // 1 rather than 0. Only used when creating a SynthonSpace from a text
127 // file.
129
133 unsigned int numBits);
134
135 // Return the molecules for synthons for which the bits are true.
136 // Obviously requires that reqSynths is the same dimensions as
137 // d_synthons.
138 std::vector<std::vector<ROMol *>> getSynthons(
139 const std::vector<boost::dynamic_bitset<>> &reqSynths) const;
140
141 std::string buildProductName(const std::vector<size_t> &synthNums) const;
142 std::unique_ptr<ROMol> buildProduct(
143 const std::vector<size_t> &synthNums) const;
144
146 std::vector<std::vector<size_t>> orderSynthonsForSearch(
147 const std::function<bool(const Synthon *synthon1,
148 const Synthon *synthon2)> &cmp);
149
150 // make a SampleMolRec for this synthon, which is expected
151 // to be in the SynthonSet. Returns an empty object if it isn't,
152 // but that really shouldn't happen.
153 std::unique_ptr<SampleMolRec> makeSampleMolecule(Synthon *synthon) const;
154 // Make a molecule from the given synthonNums, which index into d_synthons.
155 std::unique_ptr<ROMol> buildMolecule(
156 const std::vector<size_t> &synthonNums) const;
157
159
160 private:
161 std::string d_id;
162 // The lists of synthons. A product of the reaction is created by
163 // combining 1 synthon from each of the outer vectors. The actual
164 // Synthon objects are held in the SynthonSpace which manages all
165 // the memory. In different reactions/SynthonSets the same Synthon
166 // can have different IDs, so we need to keep the ID here rather
167 // than in the Synthon, whose primary key is its SMILES string.
168 std::vector<std::vector<std::pair<std::string, Synthon *>>> d_synthons;
169
170 // The order that the synthons should be searched in. It will
171 // be the same shape as d_synthons. The substructure
172 // search will order in ascending size of number of heavy atoms,
173 // the fingerprint search in ascending number of set bits and
174 // the Rascal search in ascending number of heavy atoms and bonds.
175 // This allows for a marginally more efficient search since either
176 // or both ends of a synthon set can be ignored as not being able
177 // to yield a match. There is no advantage in sorting the shapes.
178 std::vector<std::vector<size_t>> d_substructureSearchOrders;
179 std::vector<std::vector<size_t>> d_fingerprintSearchOrders;
180 std::vector<std::vector<size_t>> d_rascalSearchOrders;
181
182 // MAX_CONNECTOR_NUM+1 bits showing which connectors are present in all the
183 // synthon sets.
184 boost::dynamic_bitset<> d_connectors;
185 // And the connector patterns for each synthon set. If synthon set 0
186 // has connectors 1 and 3, then d_synthConnPatts[0] will have bits
187 // 1 and 3 set.
188 std::vector<boost::dynamic_bitset<>> d_synthConnPatts;
189
190 // The connector regions of a molecule are the pieces of up to 3 bonds from
191 // a connector atom into the molecule. We keep a vector of all the ones
192 // present in the synthons in the set, plus a fingerprint for each.
193 // If a query fragment doesn't have a connector region in common with
194 // any of the synthons it can be assumed that the fragment won't have
195 // a match in this SynthonSet.
196 std::vector<std::shared_ptr<ROMol>> d_connectorRegions;
197 std::vector<std::string> d_connRegSmis;
198 // The fingerprints of the connector regions.
199 std::vector<std::unique_ptr<ExplicitBitVect>> d_connRegFPs;
200
201 // When doing an approximate FP similarity by ORing together
202 // the synthonFPs, adding d_addFP and subtracting d_subtractFP
203 // accounts (a bit) for the joins and the dummy atoms
204 // respectively. Not used at present, but left in for
205 // compatibility with old databases.
206 std::unique_ptr<ExplicitBitVect> d_addFP;
207 std::unique_ptr<ExplicitBitVect> d_subtractFP;
208
209 // The number of connectors in the synthons in each synthon set.
210 std::vector<int> d_numConnectors;
211
212 // Synthons are shared, so sometimes we need to copy the molecules into a
213 // new set that we can fiddle with without upsetting anything else.
214 std::unique_ptr<RWMol> copySynthon(size_t synthonSetNum,
215 size_t synthonIdx) const;
216 std::vector<std::vector<std::unique_ptr<RWMol>>> copySynthons() const;
217
218 // Take the synthons and build molecules from them. longVecNum is the number
219 // of the vector containing the synthon set of interest. Each product is
220 // a molecule made from the corresponding member of longVecNum and a small
221 // element of the other vectors. synthonMols are from copySynthons.
222 std::vector<std::unique_ptr<ROMol>> buildSampleMolecules(
223 const std::vector<std::vector<std::unique_ptr<RWMol>>> &synthonMols,
224 size_t longVecNum) const;
225 // The number of rings that may be formed by the synthons. If there
226 // are a pair of synthons A([1*])[2*] and B([1*])[2*] 1 ring can be
227 // formed.
228 unsigned int d_numRingFormers{0};
229};
230
231} // namespace SynthonSpaceSearch
232
233} // namespace RDKit
234
235#endif // RDKIT_SYNTHONSET_H
class that generates same fingerprint style for different output formats
std::vector< std::vector< size_t > > orderSynthonsForSearch(const std::function< bool(const Synthon *synthon1, const Synthon *synthon2)> &cmp)
const std::pair< std::string, Synthon * > getRascalOrderedSynthon(size_t setNum, size_t synthonNum) const
const std::unique_ptr< ExplicitBitVect > & getSubtractFP() const
const std::vector< std::vector< std::pair< std::string, Synthon * > > > & getSynthons() const
Definition SynthonSet.h:60
const std::unique_ptr< ExplicitBitVect > & getAddFP() const
const std::vector< std::unique_ptr< ExplicitBitVect > > & getConnRegFPs() const
SynthonSet(SynthonSet &&rhs)=delete
void enumerateToStream(std::ostream &os) const
size_t getFingerprintOrderedSynthonNum(size_t setNum, size_t synthonNum) const
const std::pair< std::string, Synthon * > getSubstructureOrderedSynthon(size_t setNum, size_t synthonNum) const
void addSynthon(int synthonSetNum, Synthon *newSynthon, const std::string &synthonId)
std::unique_ptr< ROMol > buildProduct(const std::vector< size_t > &synthNums) const
void writeToDBStream(std::ostream &os) const
void buildAddAndSubtractFPs(const FingerprintGenerator< std::uint64_t > &fpGen, unsigned int numBits)
void readFromDBStream(std::istream &is, const SynthonSpace &space, std::uint32_t version)
void buildSynthonFingerprints(const FingerprintGenerator< std::uint64_t > &fpGen)
std::unique_ptr< SampleMolRec > makeSampleMolecule(Synthon *synthon) const
const std::vector< std::shared_ptr< ROMol > > & getConnectorRegions() const
size_t getRascalOrderedSynthonNum(size_t setNum, size_t synthonNum) const
std::unique_ptr< ROMol > buildMolecule(const std::vector< size_t > &synthonNums) const
SynthonSet(const std::string &id)
Definition SynthonSet.h:54
std::string buildProductName(const std::vector< size_t > &synthNums) const
const std::vector< int > & getNumConnectors() const
std::uint64_t getNumProducts() const
std::vector< std::vector< ROMol * > > getSynthons(const std::vector< boost::dynamic_bitset<> > &reqSynths) const
const std::pair< std::string, Synthon * > getFingerprintOrderedSynthon(size_t setNum, size_t synthonNum) const
unsigned int getNumRingFormers() const
Definition SynthonSet.h:94
const std::vector< boost::dynamic_bitset<> > & getSynthonConnectorPatterns() const
Definition SynthonSet.h:81
const std::vector< std::string > & getConnectorRegionSmiles() const
size_t getSubstructureOrderedSynthonNum(size_t setNum, size_t synthonNum) const
const boost::dynamic_bitset & getConnectors() const
Definition SynthonSet.h:80
SynthonSet(const SynthonSet &rhs)=delete
const std::string & getId() const
Definition SynthonSet.h:58
#define RDKIT_SYNTHONSPACESEARCH_EXPORT
Definition export.h:731
Std stuff.
std::vector< size_t > d_synthonNums
Definition SynthonSet.h:42
std::unique_ptr< ROMol > d_mol
Definition SynthonSet.h:44
const class SynthonSet * d_synthonSet
Definition SynthonSet.h:40