1 //  Copyright (c) 2015, Novartis Institutes for BioMedical Research Inc.
2 //  All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 //       notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 //       copyright notice, this list of conditions and the following
12 //       disclaimer in the documentation and/or other materials provided
13 //       with the distribution.
14 //     * Neither the name of Novartis Institutes for BioMedical Research Inc.
15 //       nor the names of its contributors may be used to endorse or promote
16 //       products derived from this software without specific prior written
17 //       permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 //
31 
32 #include "FilterMatchers.h"
33 #include <GraphMol/SmilesParse/SmilesParse.h>
34 
35 #include <utility>
36 
37 namespace RDKit {
38 const char *DEFAULT_FILTERMATCHERBASE_NAME = "Unnamed FilterMatcherBase";
39 const char *SMARTS_MATCH_NAME_DEFAULT = "Unnamed SmartsMatcher";
40 namespace {
41 const int debugParse = 0;
42 const bool mergeHs = true;
43 }  // namespace
SmartsMatcher(const ROMol & pattern,unsigned int minCount,unsigned int maxCount)44 SmartsMatcher::SmartsMatcher(const ROMol &pattern, unsigned int minCount,
45                              unsigned int maxCount)
46     : FilterMatcherBase(SMARTS_MATCH_NAME_DEFAULT),
47       d_pattern(new ROMol(pattern)),
48       d_min_count(minCount),
49       d_max_count(maxCount) {}
50 
SmartsMatcher(const std::string & name,const ROMol & pattern,unsigned int minCount,unsigned int maxCount)51 SmartsMatcher::SmartsMatcher(const std::string &name, const ROMol &pattern,
52                              unsigned int minCount, unsigned int maxCount)
53     : FilterMatcherBase(name),
54       d_pattern(new ROMol(pattern)),
55       d_min_count(minCount),
56       d_max_count(maxCount) {}
57 
SmartsMatcher(const std::string & name,const std::string & smarts,unsigned int minCount,unsigned int maxCount)58 SmartsMatcher::SmartsMatcher(const std::string &name, const std::string &smarts,
59                              unsigned int minCount, unsigned int maxCount)
60     : FilterMatcherBase(name),
61       d_pattern(SmartsToMol(smarts, debugParse, mergeHs)),
62       d_min_count(minCount),
63       d_max_count(maxCount) {}
64 
SmartsMatcher(const std::string & name,ROMOL_SPTR pattern,unsigned int minCount,unsigned int maxCount)65 SmartsMatcher::SmartsMatcher(const std::string &name, ROMOL_SPTR pattern,
66                              unsigned int minCount, unsigned int maxCount)
67     : FilterMatcherBase(name),
68       d_pattern(std::move(pattern)),
69       d_min_count(minCount),
70       d_max_count(maxCount) {}
71 
setPattern(const std::string & smarts)72 void SmartsMatcher::setPattern(const std::string &smarts) {
73   d_pattern.reset(SmartsToMol(smarts, debugParse, mergeHs));
74 }
75 
setPattern(const ROMol & mol)76 void SmartsMatcher::setPattern(const ROMol &mol) {
77   d_pattern.reset(new ROMol(mol));
78 }
79 
SmartsMatcher(const SmartsMatcher & rhs)80 SmartsMatcher::SmartsMatcher(const SmartsMatcher &rhs)
81     : FilterMatcherBase(rhs),
82       d_pattern(rhs.d_pattern),
83       d_min_count(rhs.d_min_count),
84       d_max_count(rhs.d_max_count) {}
85 
getMatches(const ROMol & mol,std::vector<FilterMatch> & matchVect) const86 bool SmartsMatcher::getMatches(const ROMol &mol,
87                                std::vector<FilterMatch> &matchVect) const {
88   PRECONDITION(d_pattern.get(), "bad on pattern");
89 
90   bool onPatExists = false;
91   std::vector<RDKit::MatchVectType> matches;
92 
93   if (d_min_count == 1 && d_max_count == UINT_MAX) {
94     RDKit::MatchVectType match;
95     onPatExists = RDKit::SubstructMatch(mol, *d_pattern.get(), match);
96     if (onPatExists) {
97       matchVect.emplace_back(copy(), match);
98     }
99   } else {  // need to count
100     const bool uniquify = true;
101     unsigned int count =
102         RDKit::SubstructMatch(mol, *d_pattern.get(), matches, uniquify);
103     onPatExists = (count >= d_min_count &&
104                    (d_max_count == UINT_MAX || count <= d_max_count));
105     if (onPatExists) {
106       boost::shared_ptr<FilterMatcherBase> clone = copy();
107       for (auto &match : matches) {
108         matchVect.emplace_back(clone, match);
109       }
110     }
111   }
112   return onPatExists;
113 }
114 
hasMatch(const ROMol & mol) const115 bool SmartsMatcher::hasMatch(const ROMol &mol) const {
116   PRECONDITION(d_pattern.get(), "bad on pattern");
117 
118   if (d_min_count == 1 && d_max_count == UINT_MAX) {
119     RDKit::MatchVectType matches;
120     return SubstructMatch(mol, *d_pattern.get(), matches);
121   } else {  // need to count
122     const bool uniquify = true;
123     std::vector<RDKit::MatchVectType> matches;
124     unsigned int count =
125         RDKit::SubstructMatch(mol, *d_pattern.get(), matches, uniquify);
126     return (count >= d_min_count &&
127             (d_max_count == UINT_MAX || count <= d_max_count));
128   }
129 }
130 
getMatches(const ROMol & mol,std::vector<FilterMatch> & m) const131 bool FilterHierarchyMatcher::getMatches(const ROMol &mol,
132                                         std::vector<FilterMatch> &m) const {
133   // a null matcher is root, just goes to the children
134 
135   std::vector<FilterMatch> temp;
136   bool result = d_matcher->getMatches(mol, temp);
137 
138   if (result) {
139     std::vector<FilterMatch> children;
140 
141     for (auto matcher : d_children) {
142       matcher->getMatches(mol, children);
143     }
144 
145     if (children.size()) {
146       m.insert(m.end(), children.begin(), children.end());
147     } else {
148       m.insert(m.end(), temp.begin(), temp.end());
149     }
150   }
151 
152   return result;
153 }
154 }  // namespace RDKit
155