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;
}