int TautomerChainChecker::isFeasiblePair()

in core/indigo-core/molecule/src/molecule_tautomer_chain.cpp [561:840]


int TautomerChainChecker::isFeasiblePair(int n1, int n2, TautomerChainChecker& next1, TautomerChainChecker& next2)
{
    // if (n1 == -1 && _prev_n1 == -1)
    //   return 0;

    // if (n2 != -1 && _context.chains_2[n2] > 0)
    //   return 0;

    if (_prev_n1 != -1 && n1 != -1 && _context.decomposer1.getComponent(_prev_n1) != _context.decomposer1.getComponent(n1))
        return 0;
    if (_prev_n2 != -1 && n2 != -1 && _context.decomposer2.getComponent(_prev_n2) != _context.decomposer2.getComponent(n2))
        return 0;

    if (_context.g2.isPseudoAtom(n2) || _context.g2.isTemplateAtom(n2)) // n1 are checked in matchAtomsTau later
        return 0;

    int h_diff = _h_difference;

    int edge2 = _context.g2.findEdgeIndex(_prev_n2, n2);

    int type1 = 0;
    int type2 = 0;

    bool zero_bond = _is_zero_bond_present;
    bool query_bond = _is_query_bond_present;
    bool na_bond = _is_non_aromatic_bond_present;

    int bond_type2 = 0;

    bool tau_bond = true;

    if (edge2 == -1)
    {
        zero_bond = true;
    }
    else
    {
        type2 = _context.g2.getBondOrder(edge2);

        if (type2 == -1 && _context.g2.possibleBondOrder(edge2, BOND_SINGLE))
            type2 = BOND_ZEROED;

        if (type2 == BOND_ZEROED)
        {
            if (_is_zero_bond_present)
                return 0;

            zero_bond = true;
        }
    }

    int edge1 = -1;

    if (n1 != -1)
    {
        if (_prev_n1 != -1)
            edge1 = _context.g1.findEdgeIndex(_prev_n1, n1);

        if (edge1 != -1)
        {
            type1 = _context.g1.getBondOrder(edge1);

            if (type1 == -1)
                return 0;
        }
    }

    if (type1 == BOND_AROMATIC || type1 == BOND_TRIPLE || type2 == BOND_TRIPLE)
        return 0;

    // Check degrees on previous vertices
    if (_prev_n1 != -1 && _path_length != 1)
    {
        const Vertex& prev_vert1 = _context.g1.getVertex(_prev_n1);
        const Vertex& prev_vert2 = _context.g2.getVertex(_prev_n2);

        int i;

        int bond_count1 = prev_vert1.degree();
        int prev_value_chain = _context.chains_2[_core_1[_prev_n1]];

        for (i = prev_vert1.neiBegin(); i < prev_vert1.neiEnd(); i = prev_vert1.neiNext(i))
        {
            int value_chain = _context.chains_2[_core_1[prev_vert1.neiVertex(i)]];

            if (value_chain > 0 && abs(value_chain - prev_value_chain) == 1)
                bond_count1--;
        }

        int bond_count2 = prev_vert2.degree();

        for (i = prev_vert2.neiBegin(); i < prev_vert2.neiEnd(); i = prev_vert2.neiNext(i))
        {
            int value_chain = _context.chains_2[prev_vert2.neiVertex(i)];

            if ((value_chain > 0 && abs(value_chain - prev_value_chain) == 1) ||
                (_context.g2.getBondOrder(prev_vert2.neiEdge(i)) == -1 && _context.g2.possibleBondOrder(prev_vert2.neiEdge(i), BOND_SINGLE)))
                bond_count2--;
        }

        if (type1 == 0)
            bond_count1++;

        if (type2 == 0)
            bond_count2++;

        // if (bond_count1 != bond_count2)
        if (bond_count1 > bond_count2 || bond_count2 - bond_count1 > 1)
            return 0;
    }

    // zero bond must be
    if (edge1 == -1 && type2 == BOND_SINGLE && _h_difference == 1)
    {
        if (zero_bond)
            return 0;

        zero_bond = true;
    }

    if (zero_bond && !_is_zero_bond_present)
    {
        // Assume that aromatic ring cannot be destroyed
        if (type2 > 1)
            return 0;
        if (type2 == BOND_SINGLE)
        {
            if (_h_difference != 0)
            {
                if (_h_difference != 1)
                    return 0;
            }
            else
                h_diff = 1;
        }
    }

    if (edge1 == -1 || type2 == BOND_AROMATIC)
        tau_bond = false;

    if (edge1 != -1)
        query_bond = true;

    if (type2 != BOND_AROMATIC)
        na_bond = true;

    if (type1 != 0)
    {
        if (type2 != BOND_AROMATIC) // both non-aromatic
        {
            if (_h_difference != 0)
            {
                if (type1 + _h_difference != type2)
                    return 0;
            }
            else if (abs(h_diff = (type2 - type1)) != 1)
                return 0;
        }
        else // exactly one aromatic
        {
            if (_h_difference != 0)
            {
                bond_type2 = type1 + _h_difference;

                if (bond_type2 < 1 || bond_type2 > 2)
                    return 0;

                if (!_context.dearomatizationMatcher->isAbleToFixBond(edge2, bond_type2))
                    return 0;
            }
            else
            {
                if (type1 == BOND_SINGLE)
                {
                    h_diff = 1;
                    bond_type2 = 2;
                }
                else if (type1 == BOND_DOUBLE)
                {
                    h_diff = -1;
                    bond_type2 = 1;
                }

                if (bond_type2 > 0 && !_context.dearomatizationMatcher->isAbleToFixBond(edge2, bond_type2))
                    return 0;
            }
        }
    }

    int rc = 0;

    if (n1 != -1)
    {
        if (!TautomerMatcher::matchAtomsTau(_context.g1, _context.g2, n1, n2))
            return 0;

        int h_rep_1 = 0;
        int h_count_2 = _context.g2.getAtomTotalH(n2);

        if (!_context.force_hydrogens)
        {
            h_rep_1 = _context.h_rep_count_1[n1];
            h_count_2 += _context.h_rep_count_2[n2];
        }

        if (query_bond && na_bond)
        {
            if (h_diff != 0)
            {
                if (!(_path_length & 1))
                    if (_context.g1.possibleAtomTotalH(n1, h_count_2 + h_diff - h_rep_1))
                    {
                        if (_context.cb_check_rules == 0 || _context.cb_check_rules(_context, _start_idx1, _start_idx2, n1, n2))
                            rc += 2;
                    }
            }
            else if (!(_path_length & 1))
                if (_context.g1.possibleAtomTotalH(n1, h_count_2 + 1 - h_rep_1) || _context.g1.possibleAtomTotalH(n1, h_count_2 - 1 - h_rep_1))
                {
                    if (_context.cb_check_rules == 0 || _context.cb_check_rules(_context, _start_idx1, _start_idx2, n1, n2))
                        rc += 2;
                }
        }

        if (_context.g1.possibleAtomTotalH(n1, h_count_2 - h_rep_1))
        {
            int charge_2 = _context.g2.getAtomCharge(n2);

            if (_context.g1.possibleAtomCharge(n1, charge_2))
                rc++;
        }
    }
    else
    {
        rc++;

        if (!(_path_length & 1) && query_bond && na_bond)
        {
            if (_context.cb_check_rules == 0 || _context.cb_check_rules(_context, _start_idx1, _start_idx2, n1, n2))
                rc += 2;
        }
    }

    if (rc & 1)
    {
        next1._path_length++;
        next1._h_difference = -h_diff;
        next1._is_zero_bond_present = zero_bond;
        next1._is_query_bond_present = query_bond;
        next1._is_non_aromatic_bond_present = na_bond;

        if (tau_bond)
            next1._tau_bonds_to_match--;

        next1._bond_idx1 = edge1;
        next1._bond_idx2 = edge2;
        next1._bond_type2 = bond_type2 > 0 ? bond_type2 : type2;
    }

    if (rc & 2)
    {
        next2._final_path_length = next2._path_length + 1;
        next2._path_length = 0;
        next2._h_difference = 0;
        next2._final_h_difference = -h_diff;
        next2._is_query_bond_present = false;
        next2._is_non_aromatic_bond_present = false;
        // next2._is_zero_bond_present = false;
        next2._is_zero_bond_present = true;

        if (tau_bond)
            next2._tau_bonds_to_match--;

        next2._bond_idx1 = edge1;
        next2._bond_idx2 = edge2;
        next2._bond_type2 = bond_type2 > 0 ? bond_type2 : type2;
    }

    return rc;
}