Skip to content

Commit

Permalink
#1372 Wildcard symbol ('any') with logical operators at custom query…
Browse files Browse the repository at this point in the history
… for bond is missing at SMARTS (#1386)
  • Loading branch information
AliaksandrDziarkach authored Oct 30, 2023
1 parent 4f550a7 commit c89ae0f
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 1 deletion.
4 changes: 4 additions & 0 deletions api/tests/integration/ref/formats/smarts.py.out
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,7 @@ Smarts [C]!-[C] loaded as smarts - OK.
Smarts [C]-,=[C] loaded as smarts - OK.
Smarts [C]-;=[C] loaded as smarts - OK.
Smarts [C]-&=[C] loaded as smarts - OK.
******* Any wildcard '~' in bond custom query *******
[#7]~,-[#6] is ok. smarts_in==smarts_out
[#7]~,-[#6] is ok. json_in==json_out
[#7]~,-[#6] is ok. expected string found in json
4 changes: 4 additions & 0 deletions api/tests/integration/tests/formats/smarts.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,7 @@ def test_smarts_load_save_through_ket(
print("Smarts %s loaded as smarts - OK." % smarts)
else:
print("Smarts %s loaded as %s - FAILED" % (smarts, format))
print("******* Any wildcard '~' in bond custom query *******")
smarts = "[#7]~,-[#6]"
expected = '"bonds":[{"customQuery":"~,-","atoms":[0,1]}]}}'
test_smarts_load_save_through_ket(smarts, expected)
3 changes: 3 additions & 0 deletions core/indigo-core/molecule/query_molecule.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace indigo

BOND_ORDER,
BOND_TOPOLOGY,
BOND_ANY,

HIGHLIGHTING
};
Expand Down Expand Up @@ -147,6 +148,7 @@ namespace indigo
// Check if there is no other constraint, except specified ones
bool hasNoConstraintExcept(int what_type);
bool hasNoConstraintExcept(int what_type1, int what_type2);
bool hasNoConstraintExcept(std::vector<int> what_types);

// Remove all constraints of the given type
void removeConstraints(int what_type);
Expand Down Expand Up @@ -248,6 +250,7 @@ namespace indigo
{
public:
Bond();
Bond(int type_);
Bond(int type_, int value_);
Bond(int type_, int value_, int direction_);
~Bond() override;
Expand Down
2 changes: 1 addition & 1 deletion core/indigo-core/molecule/src/molecule_arom_match.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ bool AromaticityMatcher::match(int* core_sub, int* core_super)
return false;
}

bool has_other = !qbond.hasNoConstraintExcept(QueryMolecule::BOND_ORDER, QueryMolecule::BOND_TOPOLOGY);
bool has_other = !qbond.hasNoConstraintExcept({QueryMolecule::BOND_ORDER, QueryMolecule::BOND_TOPOLOGY, QueryMolecule::BOND_ANY});
if (has_other)
throw Error("Only bond with order and topology constraints are supported");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ bool MoleculeSubstructureMatcher::matchQueryBond(QueryMolecule::Bond* query, Bas
case QueryMolecule::OP_NOT:
return !matchQueryBond(query->child(0), target, sub_idx, super_idx, am, flags ^ MATCH_DISABLED_AS_TRUE);

case QueryMolecule::BOND_ANY:
return true;
case QueryMolecule::BOND_ORDER: {
if (flags & MATCH_BOND_TYPE)
{
Expand Down
32 changes: 32 additions & 0 deletions core/indigo-core/molecule/src/query_molecule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,10 @@ void QueryMolecule::writeSmartsBond(Output& output, Bond* bond, bool has_or_pare
output.writeString("!@");
break;
}
case BOND_ANY: {
output.writeChar('~');
break;
}
default:
throw Error("Unexpected bond type: %d", bond->type);
}
Expand Down Expand Up @@ -743,6 +747,9 @@ void QueryMolecule::_getBondDescription(Bond* bond, Output& out)
case BOND_TOPOLOGY:
out.printf("%s", bond->value == TOPOLOGY_RING ? "ring" : "chain");
return;
case BOND_ANY:
out.writeChar('~');
return;
default:
out.printf("<constraint of type %d>", bond->type);
}
Expand Down Expand Up @@ -931,6 +938,10 @@ QueryMolecule::Bond::Bond() : Node(OP_NONE), value(0), direction(0)
{
}

QueryMolecule::Bond::Bond(int type_) : Node(type_), value(0), direction(0)
{
}

QueryMolecule::Bond::Bond(int type_, int value_) : Node(type_), value(value_), direction(0)
{
}
Expand Down Expand Up @@ -1768,6 +1779,8 @@ bool QueryMolecule::Bond::_possibleValuePair(int what_type1, int what_value1, in
return what_value1 == value;
if (type == what_type2)
return what_value2 == value;
if (type == BOND_ANY)
return true;
return false;
}

Expand Down Expand Up @@ -1947,6 +1960,25 @@ bool QueryMolecule::Node::hasNoConstraintExcept(int what_type1, int what_type2)
return type == what_type1 || type == what_type2;
}

bool QueryMolecule::Node::hasNoConstraintExcept(std::vector<int> what_types)
{
if (type == OP_NONE)
return true;

if (type == OP_AND || type == OP_OR || type == OP_NOT)
{
int i;

for (i = 0; i < children.size(); i++)
if (!children[i]->hasNoConstraintExcept(what_types))
return false;

return true;
}

return std::any_of(what_types.cbegin(), what_types.cend(), [this](int i) { return type == i; });
}

void QueryMolecule::Node::removeConstraints(int what_type)
{
if (type == what_type)
Expand Down
7 changes: 7 additions & 0 deletions core/indigo-core/molecule/src/smiles_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2636,6 +2636,13 @@ void SmilesLoader::_readBondSub(Array<char>& bond_str, _BondDesc& bond, std::uni
else if (order == _ANY_BOND)
{
bond.type = order;
if (qbond.get() != 0)
{
if (subqbond.get() == 0)
subqbond = std::make_unique<QueryMolecule::Bond>(QueryMolecule::BOND_ANY);
else
subqbond.reset(QueryMolecule::Bond::und(subqbond.release(), new QueryMolecule::Bond(QueryMolecule::BOND_ANY)));
}
}

if (topology > 0)
Expand Down

0 comments on commit c89ae0f

Please sign in to comment.