bool MoleculeSubstructureMatcher::matchQueryAtom()

in core/indigo-core/molecule/src/molecule_substructure_matcher.cpp [378:516]


bool MoleculeSubstructureMatcher::matchQueryAtom(QueryMolecule::Atom* query, BaseMolecule& target, int super_idx, FragmentMatchCache* fmcache, dword flags)
{
    int i;

    switch (query->type)
    {
    case QueryMolecule::OP_NONE:
        return true;
    case QueryMolecule::OP_AND:
        for (i = 0; i < query->children.size(); i++)
            if (!matchQueryAtom(query->child(i), target, super_idx, fmcache, flags))
                return false;
        return true;
    case QueryMolecule::OP_OR:
        for (i = 0; i < query->children.size(); i++)
            if (matchQueryAtom(query->child(i), target, super_idx, fmcache, flags))
                return true;
        return false;
    case QueryMolecule::OP_NOT:
        return !matchQueryAtom(query->child(0), target, super_idx, fmcache, flags ^ MATCH_DISABLED_AS_TRUE);

    case QueryMolecule::ATOM_NUMBER:
        return query->valueWithinRange(target.getAtomNumber(super_idx));
    case QueryMolecule::ATOM_PSEUDO:
        return target.isPseudoAtom(super_idx) && strcmp(query->alias.ptr(), target.getPseudoAtom(super_idx)) == 0;
    case QueryMolecule::ATOM_TEMPLATE:
        return target.isTemplateAtom(super_idx) && strcmp(query->alias.ptr(), target.getTemplateAtom(super_idx)) == 0;
    case QueryMolecule::ATOM_RSITE:
        return true;
    case QueryMolecule::ATOM_ISOTOPE:
        return query->valueWithinRange(target.getAtomIsotope(super_idx));
    case QueryMolecule::ATOM_CHARGE: {
        if (flags & MATCH_ATOM_CHARGE)
            return query->valueWithinRange(target.getAtomCharge(super_idx));
        return (flags & MATCH_DISABLED_AS_TRUE) != 0;
    }
    case QueryMolecule::ATOM_RADICAL: {
        if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
            return false;
        int radical = target.getAtomRadical_NoThrow(super_idx, -1);
        if (radical == -1)
            return false;
        return query->valueWithinRange(radical);
    }
    case QueryMolecule::ATOM_VALENCE: {
        if (flags & MATCH_ATOM_VALENCE)
        {
            if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
                return false;
            int valence = target.getAtomValence_NoThrow(super_idx, -1);
            if (valence == -1)
                return false;
            return query->valueWithinRange(valence);
        }
        return (flags & MATCH_DISABLED_AS_TRUE) != 0;
    }
    case QueryMolecule::ATOM_CONNECTIVITY: {
        int conn = target.getVertex(super_idx).degree();
        if (!target.isPseudoAtom(super_idx) && !target.isRSite(super_idx))
            conn += target.asMolecule().getImplicitH_NoThrow(super_idx, 0);
        return query->valueWithinRange(conn);
    }
    case QueryMolecule::ATOM_TOTAL_BOND_ORDER: {
        // TODO: target.isPseudoAtom(super_idx) || target.isRSite(super_idx)
        int conn = target.asMolecule().getAtomConnectivity_NoThrow(super_idx, -1);
        if (conn == -1)
            return false;
        return query->valueWithinRange(conn);
    }
    case QueryMolecule::ATOM_TOTAL_H: {
        if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx) || target.isTemplateAtom(super_idx))
            return false;
        return query->valueWithinRange(target.getAtomTotalH(super_idx));
    }
    case QueryMolecule::ATOM_SUBSTITUENTS:
    case QueryMolecule::ATOM_SUBSTITUENTS_AS_DRAWN:
        return query->valueWithinRange(target.getAtomSubstCount(super_idx));
    case QueryMolecule::ATOM_SSSR_RINGS:
        return query->valueWithinRange(target.vertexCountSSSR(super_idx));
    case QueryMolecule::ATOM_SMALLEST_RING_SIZE:
        return query->valueWithinRange(target.vertexSmallestRingSize(super_idx));
    case QueryMolecule::ATOM_RING_BONDS:
    case QueryMolecule::ATOM_RING_BONDS_AS_DRAWN:
        return query->valueWithinRange(target.getAtomRingBondsCount(super_idx));
    case QueryMolecule::ATOM_PI_BONDED: {
        return query->valueWithinRange(static_cast<int>(target.asMolecule().isPiBonded(super_idx)));
    }
    case QueryMolecule::ATOM_UNSATURATION:
        return !target.isSaturatedAtom(super_idx);
    case QueryMolecule::ATOM_FRAGMENT: {
        if (fmcache == 0)
            throw Error("unexpected 'fragment' constraint");

        QueryMolecule* fragment = query->fragment.get();
        const char* smarts = fragment->fragment_smarts.ptr();

        if (fragment->vertexCount() == 0)
            throw Error("empty fragment");

        if (smarts != 0 && strlen(smarts) > 0)
        {
            fmcache->expand(super_idx + 1);
            int* value = fmcache->at(super_idx).at2(smarts);

            if (value != 0)
                return *value != 0;
        }

        MoleculeSubstructureMatcher matcher(target.asMolecule());

        matcher.not_ignore_first_atom = true;
        matcher.setQuery(*fragment);
        matcher.fmcache = fmcache;

        bool result = matcher.fix(fragment->vertexBegin(), super_idx);

        if (result)
            result = matcher.find();

        if (smarts != 0 && strlen(smarts) > 0)
        {
            fmcache->expand(super_idx + 1);
            fmcache->at(super_idx).insert(smarts, result ? 1 : 0);
        }

        return result;
    }
    case QueryMolecule::ATOM_AROMATICITY:
        return query->valueWithinRange(target.getAtomAromaticity(super_idx));
    case QueryMolecule::HIGHLIGHTING:
        return query->valueWithinRange((int)target.isAtomHighlighted(super_idx));
    case QueryMolecule::ATOM_IMPLICIT_H:
        return query->valueWithinRange(target.asMolecule().getImplicitH(super_idx));
    case QueryMolecule::ATOM_CHIRALITY:
        return target.stereocenters.getType(super_idx) == MoleculeStereocenters::ATOM_ABS; // TODO: Investigate right way to match
    default:
        throw Error("bad query atom type: %d", query->type);
    }
}