mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
* Add PRECONDITION for attempt to expand empty query. * Improved test, maybe. --------- Co-authored-by: David Cosgrove <david@cozchemix.co.uk>
197 lines
6.2 KiB
C++
197 lines
6.2 KiB
C++
// $Id$
|
|
//
|
|
// Copyright (C) 2001-2006 Greg Landrum and Rational Discovery LLC
|
|
//
|
|
// @@ 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 <GraphMol/QueryAtom.h>
|
|
#include <GraphMol/QueryOps.h>
|
|
#include <Query/NullQueryAlgebra.h>
|
|
|
|
namespace RDKit {
|
|
|
|
QueryAtom::~QueryAtom() {
|
|
delete dp_query;
|
|
dp_query = nullptr;
|
|
};
|
|
|
|
Atom *QueryAtom::copy() const {
|
|
auto *res = new QueryAtom(*this);
|
|
return static_cast<Atom *>(res);
|
|
}
|
|
|
|
void QueryAtom::expandQuery(QUERYATOM_QUERY *what,
|
|
Queries::CompositeQueryType how,
|
|
bool maintainOrder) {
|
|
PRECONDITION(dp_query, "Can't expand empty query");
|
|
bool thisIsNullQuery = dp_query->getDescription() == "AtomNull";
|
|
bool otherIsNullQuery = what->getDescription() == "AtomNull";
|
|
|
|
if (thisIsNullQuery || otherIsNullQuery) {
|
|
mergeNullQueries(dp_query, thisIsNullQuery, what, otherIsNullQuery, how);
|
|
delete what;
|
|
return;
|
|
}
|
|
|
|
QUERYATOM_QUERY *origQ = dp_query;
|
|
std::string descrip;
|
|
switch (how) {
|
|
case Queries::COMPOSITE_AND:
|
|
dp_query = new ATOM_AND_QUERY;
|
|
descrip = "AtomAnd";
|
|
break;
|
|
case Queries::COMPOSITE_OR:
|
|
dp_query = new ATOM_OR_QUERY;
|
|
descrip = "AtomOr";
|
|
break;
|
|
case Queries::COMPOSITE_XOR:
|
|
dp_query = new ATOM_XOR_QUERY;
|
|
descrip = "AtomXor";
|
|
break;
|
|
default:
|
|
UNDER_CONSTRUCTION("unrecognized combination query");
|
|
}
|
|
dp_query->setDescription(descrip);
|
|
if (maintainOrder) {
|
|
dp_query->addChild(QUERYATOM_QUERY::CHILD_TYPE(origQ));
|
|
dp_query->addChild(QUERYATOM_QUERY::CHILD_TYPE(what));
|
|
} else {
|
|
dp_query->addChild(QUERYATOM_QUERY::CHILD_TYPE(what));
|
|
dp_query->addChild(QUERYATOM_QUERY::CHILD_TYPE(origQ));
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
bool localMatch(ATOM_EQUALS_QUERY const *q1, ATOM_EQUALS_QUERY const *q2) {
|
|
if (q1->getNegation() == q2->getNegation()) {
|
|
return q1->getVal() == q2->getVal();
|
|
} else {
|
|
return q1->getVal() != q2->getVal();
|
|
}
|
|
}
|
|
bool queriesMatch(QueryAtom::QUERYATOM_QUERY const *q1,
|
|
QueryAtom::QUERYATOM_QUERY const *q2) {
|
|
PRECONDITION(q1, "no q1");
|
|
PRECONDITION(q2, "no q2");
|
|
|
|
static const unsigned int nQueries = 20;
|
|
static std::string equalityQueries[nQueries] = {"AtomType",
|
|
"AtomRingBondCount",
|
|
"AtomRingSize",
|
|
"AtomMinRingSize",
|
|
"AtomImplicitValence",
|
|
"AtomExplicitValence",
|
|
"AtomTotalValence",
|
|
"AtomAtomicNum",
|
|
"AtomExplicitDegree",
|
|
"AtomTotalDegree",
|
|
"AtomHCount",
|
|
"AtomIsAromatic",
|
|
"AtomIsAliphatic",
|
|
"AtomUnsaturated",
|
|
"AtomMass",
|
|
"AtomFormalCharge",
|
|
"AtomNegativeFormalCharge",
|
|
"AtomHybridization",
|
|
"AtomInRing",
|
|
"AtomInNRings"};
|
|
|
|
bool res = false;
|
|
std::string d1 = q1->getDescription();
|
|
std::string d2 = q2->getDescription();
|
|
if (d1 == "AtomNull" || d2 == "AtomNull") {
|
|
res = true;
|
|
} else if (d1 == "AtomOr") {
|
|
// FIX: handle negation on AtomOr and AtomAnd
|
|
for (auto iter1 = q1->beginChildren(); iter1 != q1->endChildren();
|
|
++iter1) {
|
|
if (d2 == "AtomOr") {
|
|
for (auto iter2 = q2->beginChildren(); iter2 != q2->endChildren();
|
|
++iter2) {
|
|
if (queriesMatch(iter1->get(), iter2->get())) {
|
|
res = true;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (queriesMatch(iter1->get(), q2)) {
|
|
res = true;
|
|
}
|
|
}
|
|
if (res) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (d1 == "AtomAnd") {
|
|
res = true;
|
|
for (auto iter1 = q1->beginChildren(); iter1 != q1->endChildren();
|
|
++iter1) {
|
|
bool matched = false;
|
|
if (d2 == "AtomAnd") {
|
|
for (auto iter2 = q2->beginChildren(); iter2 != q2->endChildren();
|
|
++iter2) {
|
|
if (queriesMatch(iter1->get(), iter2->get())) {
|
|
matched = true;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
matched = queriesMatch(iter1->get(), q2);
|
|
}
|
|
if (!matched) {
|
|
res = false;
|
|
break;
|
|
}
|
|
}
|
|
// FIX : handle AtomXOr
|
|
} else if (d2 == "AtomOr") {
|
|
// FIX: handle negation on AtomOr and AtomAnd
|
|
for (auto iter2 = q2->beginChildren(); iter2 != q2->endChildren();
|
|
++iter2) {
|
|
if (queriesMatch(q1, iter2->get())) {
|
|
res = true;
|
|
break;
|
|
}
|
|
}
|
|
} else if (d2 == "AtomAnd") {
|
|
res = true;
|
|
for (auto iter2 = q2->beginChildren(); iter2 != q2->endChildren();
|
|
++iter2) {
|
|
if (!queriesMatch(q1, iter2->get())) {
|
|
res = false;
|
|
break;
|
|
}
|
|
}
|
|
} else if (d1 == d2) {
|
|
if (std::find(&equalityQueries[0], &equalityQueries[nQueries], d1) !=
|
|
&equalityQueries[nQueries]) {
|
|
res = localMatch(static_cast<ATOM_EQUALS_QUERY const *>(q1),
|
|
static_cast<ATOM_EQUALS_QUERY const *>(q2));
|
|
}
|
|
} else {
|
|
}
|
|
return res;
|
|
}
|
|
} // namespace
|
|
|
|
bool QueryAtom::Match(Atom const *what) const {
|
|
PRECONDITION(what, "bad query atom");
|
|
PRECONDITION(dp_query, "no query set");
|
|
return dp_query->Match(what);
|
|
}
|
|
bool QueryAtom::QueryMatch(QueryAtom const *what) const {
|
|
PRECONDITION(what, "bad query atom");
|
|
PRECONDITION(dp_query, "no query set");
|
|
if (!what->hasQuery()) {
|
|
return dp_query->Match(what);
|
|
} else {
|
|
return queriesMatch(dp_query, what->getQuery());
|
|
}
|
|
}
|
|
|
|
}; // namespace RDKit
|