third_party/inchi/INCHI_BASE/src/ichicans.c
int SetKnownStereoCenterParities( CANON_GLOBALS *pCG,
                                  sp_ATOM       *at,
                                  int           num_atoms,
                                  const AT_RANK *nCanonRank,
                                  const AT_RANK *nRank,
                                  const AT_RANK *nAtomNumber )
{
    int i, j, n, m, j1, k, num_neigh, iMax, trans_i, trans_k, prev_trans, num_set;
    AT_RANK nAtomRank;
    AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH];
    AT_RANK nNeighCanonRank[MAX_NUM_STEREO_ATOM_NEIGH];

    for (i = 0, num_set = 0; i < num_atoms; i++)
    {
        if (!at[i].parity || at[i].stereo_bond_neighbor[0])
        {
            continue;
        }
        if (at[i].stereo_atom_parity != AB_PARITY_CALC ||
             !PARITY_WELL_DEF( at[i].parity ))
        {
            continue;
        }
        num_neigh = at[i].valence;
        for (j = 0; j < num_neigh; j++)
        {
            nNeighRank[j] = nRank[(int) at[i].neighbor[j]];
        }
        nAtomRank = nRank[i];
        if (num_neigh == 1)
        {
            /* other neighbors must be implicit H */
            at[i].stereo_atom_parity = at[i].parity;
            trans_i = 0;
        }
        else
        {
            /* sort constitutional equivalence ranks of the neighbors */
            trans_i = insertions_sort( pCG, nNeighRank, num_neigh, sizeof( nNeighRank[0] ), comp_AT_RANK );
            for (j = 1; j < num_neigh; j++)
            {
                if (nNeighRank[j - 1] == nNeighRank[j])
                {
                    break; /* at[i] has consitutionally identical neighbors */
                }
            }
            if (j < num_neigh)
            {
                /*  at least 2 neighbors are const. identical; parity cannot be calculated at this time */
                continue; /*  try next stereo atom */
            }
        }
        prev_trans = -1;
        trans_k = 0;
        /*  find neighbors of constitutionally equivalent stereo centers */
        /*  and at[i] parities in case those centers are mapped on at[i] */
        for (iMax = (int) nAtomRank - 1, j1 = 0;
                j1 <= iMax && nAtomRank == nRank[k = (int) nAtomNumber[iMax - j1]];
                    j1++)
        {
            /*  at[k] is constitutionally equivalent to at[i] */
            if ((int) at[k].valence != num_neigh)
            {
                return CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
            }
            /* -- commented out to accept  non-stereogenic atoms since     --
               -- they may participate in mapping stereocenters 12-16-2003 --
            if ( !PARITY_VAL(at[k].parity) ) {
                continue; // not a stereogenic atom
            }
            */
            for (j = 0, m = 0; m < num_neigh; m++)
            {
                for (n = 0; n < num_neigh; n++)
                {
                    if (nRank[(int) at[k].neighbor[n]] == nNeighRank[m])
                    {
                        /* save canonical numbers (ranks) of the neighbors in
                         * order of increasing constit. equivalence ranks */
                        nNeighCanonRank[m] = nCanonRank[(int) at[k].neighbor[n]];
                        j++;
                        break;
                    }
                }
            }
            if (j != num_neigh)
            {
                return CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
            }
            trans_k = insertions_sort( pCG, nNeighCanonRank, num_neigh, sizeof( nNeighCanonRank[0] ), comp_AT_RANK );
            trans_k %= 2;
            if (prev_trans < 0)
            {
                prev_trans = trans_k;
            }
            else if (trans_k != prev_trans)
            {
                /*  different mappings may produce different parities. Cannot find the parity at this time */
                /*  this may happen when a set of constit. equivalent atoms has non-contiguous canonical numbers */
                break;
            }
        }
        if (trans_k == prev_trans)
        {
            at[i].stereo_atom_parity = 2 - ( at[i].parity + trans_i + prev_trans ) % 2;
            num_set++;
        }
    }

    return num_set;
}
/****************************************************************************
 Find stereo center parities known in advance
****************************************************************************/
Find stereo center parities known in advance
Find stereo center parities known in advance
int SetKnownStereoCenterParities( CANON_GLOBALS *pCG,
                                  sp_ATOM       *at,
                                  int           num_atoms,
                                  const AT_RANK *nCanonRank,
                                  const AT_RANK *nRank,
                                  const AT_RANK *nAtomNumber )
{
    int i, j, n, m, j1, k, num_neigh, iMax, trans_i, trans_k, prev_trans, num_set;
    AT_RANK nAtomRank;
    AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH];
    AT_RANK nNeighCanonRank[MAX_NUM_STEREO_ATOM_NEIGH];
    for (i = 0, num_set = 0; i < num_atoms; i++)
    {
        if (!at[i].parity || at[i].stereo_bond_neighbor[0])
        {
            continue;
        }
        if (at[i].stereo_atom_parity != AB_PARITY_CALC ||
             !PARITY_WELL_DEF( at[i].parity ))
        {
            continue;
        }
        num_neigh = at[i].valence;
        for (j = 0; j < num_neigh; j++)
        {
            nNeighRank[j] = nRank[(int) at[i].neighbor[j]];
        }
        nAtomRank = nRank[i];
        if (num_neigh == 1)
        {
            at[i].stereo_atom_parity = at[i].parity;
            trans_i = 0;
        }
        else
        {
            trans_i = insertions_sort( pCG, nNeighRank, num_neigh, sizeof( nNeighRank[0] ), comp_AT_RANK );
            for (j = 1; j < num_neigh; j++)
            {
                if (nNeighRank[j - 1] == nNeighRank[j])
                {
                    break; 
                }
            }
            if (j < num_neigh)
            {
                continue; 
            }
        }
        prev_trans = -1;
        trans_k = 0;
        for (iMax = (int) nAtomRank - 1, j1 = 0;
                j1 <= iMax && nAtomRank == nRank[k = (int) nAtomNumber[iMax - j1]];
                    j1++)
        {
            if ((int) at[k].valence != num_neigh)
            {
                return CT_STEREOCOUNT_ERR;  
            }
            for (j = 0, m = 0; m < num_neigh; m++)
            {
                for (n = 0; n < num_neigh; n++)
                {
                    if (nRank[(int) at[k].neighbor[n]] == nNeighRank[m])
                    {
                        nNeighCanonRank[m] = nCanonRank[(int) at[k].neighbor[n]];
                        j++;
                        break;
                    }
                }
            }
            if (j != num_neigh)
            {
                return CT_STEREOCOUNT_ERR;  
            }
            trans_k = insertions_sort( pCG, nNeighCanonRank, num_neigh, sizeof( nNeighCanonRank[0] ), comp_AT_RANK );
            trans_k %= 2;
            if (prev_trans < 0)
            {
                prev_trans = trans_k;
            }
            else if (trans_k != prev_trans)
            {
                break;
            }
        }
        if (trans_k == prev_trans)
        {
            at[i].stereo_atom_parity = 2 - ( at[i].parity + trans_i + prev_trans ) % 2;
            num_set++;
        }
    }
    return num_set;
}
int SetKnownStereoCenterParities ( CANON_GLOBALS * pCG , sp_ATOM * at , int num_atoms , const AT_RANK * nCanonRank , const AT_RANK * nRank , const AT_RANK * nAtomNumber ) { int i , j , n , m , j1 , k , num_neigh , iMax , trans_i , trans_k , prev_trans , num_set ; AT_RANK nAtomRank ; AT_RANK nNeighRank [ MAX_NUM_STEREO_ATOM_NEIGH ] ; AT_RANK nNeighCanonRank [ MAX_NUM_STEREO_ATOM_NEIGH ] ; for ( i = 0 , num_set = 0 ; i < num_atoms ; i ++ ) { if ( ! at [ i ] . parity || at [ i ] . stereo_bond_neighbor [ 0 ] ) { continue ; } if ( at [ i ] . stereo_atom_parity != AB_PARITY_CALC || ! PARITY_WELL_DEF ( at [ i ] . parity ) ) { continue ; } num_neigh = at [ i ] . valence ; for ( j = 0 ; j < num_neigh ; j ++ ) { nNeighRank [ j ] = nRank [ ( int ) at [ i ] . neighbor [ j ] ] ; } nAtomRank = nRank [ i ] ; if ( num_neigh == 1 ) { at [ i ] . stereo_atom_parity = at [ i ] . parity ; trans_i = 0 ; } else { trans_i = insertions_sort ( pCG , nNeighRank , num_neigh , sizeof ( nNeighRank [ 0 ] ) , comp_AT_RANK ) ; for ( j = 1 ; j < num_neigh ; j ++ ) { if ( nNeighRank [ j - 1 ] == nNeighRank [ j ] ) { break ; } } if ( j < num_neigh ) { continue ; } } prev_trans = -1 ; trans_k = 0 ; for ( iMax = ( int ) nAtomRank - 1 , j1 = 0 ; j1 <= iMax && nAtomRank == nRank [ k = ( int ) nAtomNumber [ iMax - j1 ] ] ; j1 ++ ) { if ( ( int ) at [ k ] . valence != num_neigh ) { return CT_STEREOCOUNT_ERR ; } for ( j = 0 , m = 0 ; m < num_neigh ; m ++ ) { for ( n = 0 ; n < num_neigh ; n ++ ) { if ( nRank [ ( int ) at [ k ] . neighbor [ n ] ] == nNeighRank [ m ] ) { nNeighCanonRank [ m ] = nCanonRank [ ( int ) at [ k ] . neighbor [ n ] ] ; j ++ ; break ; } } } if ( j != num_neigh ) { return CT_STEREOCOUNT_ERR ; } trans_k = insertions_sort ( pCG , nNeighCanonRank , num_neigh , sizeof ( nNeighCanonRank [ 0 ] ) , comp_AT_RANK ) ; trans_k %= 2 ; if ( prev_trans < 0 ) { prev_trans = trans_k ; } else if ( trans_k != prev_trans ) { break ; } } if ( trans_k == prev_trans ) { at [ i ] . stereo_atom_parity = 2 - ( at [ i ] . parity + trans_i + prev_trans ) % 2 ; num_set ++ ; } } return num_set ; }
Find stereo center parities known in advance
Find stereo center parities known in advance
/* other neighbors must be implicit H */ /* sort constitutional equivalence ranks of the neighbors */ /* at[i] has consitutionally identical neighbors */ /*  at least 2 neighbors are const. identical; parity cannot be calculated at this time */ /*  try next stereo atom */ /*  find neighbors of constitutionally equivalent stereo centers */ /*  and at[i] parities in case those centers are mapped on at[i] */ /*  at[k] is constitutionally equivalent to at[i] */ /*   <BRKPT> */ /* -- commented out to accept  non-stereogenic atoms since     --
               -- they may participate in mapping stereocenters 12-16-2003 --
            if ( !PARITY_VAL(at[k].parity) ) {
                continue; // not a stereogenic atom
            }
            */ /* save canonical numbers (ranks) of the neighbors in
                         * order of increasing constit. equivalence ranks */ /*   <BRKPT> */ /*  different mappings may produce different parities. Cannot find the parity at this time */ /*  this may happen when a set of constit. equivalent atoms has non-contiguous canonical numbers */