third_party/inchi/INCHI_BASE/src/ichicans.c
int InvertStereo( sp_ATOM    *at,
                  int        num_at_tg,
                  AT_RANK    *nCanonRank,
                  AT_RANK    *nAtomNumberCanon,
                  CANON_STAT *pCS,
                  int        bInvertLinearCTStereo )
{
    int i, j, j1, j2, num_changes, parity, cumulene_len;

    num_changes = 0;
    for (i = 0; i < num_at_tg; i++)
    {
        nAtomNumberCanon[(int) nCanonRank[i] - 1] = i;
    }
    for (i = 0; i < pCS->nLenLinearCTStereoCarb; i++)
    {
        parity = pCS->LinearCTStereoCarb[i].parity;
        if (ATOM_PARITY_WELL_DEF( parity ))
        {
            j = nAtomNumberCanon[(int) pCS->LinearCTStereoCarb[i].at_num - 1];
            if (PARITY_WELL_DEF( at[j].parity ))
            {
                at[j].parity ^= AB_INV_PARITY_BITS;
            }
            else
            {
                goto exit_error; /* inconsistency */
            }
            if (bInvertLinearCTStereo)
            {
#ifdef FIX_STEREOCOUNT_ERR
                pCS->LinearCTStereoCarb[i].parity = AB_PARITY_EVEN; /* deliberately worse */
#else
                pCS->LinearCTStereoCarb[i].parity ^= AB_INV_PARITY_BITS;
#endif
            }
            num_changes++;
            if (PARITY_WELL_DEF( at[j].stereo_atom_parity ))
            {
                at[j].stereo_atom_parity ^= AB_INV_PARITY_BITS;
            }
            if (PARITY_WELL_DEF( at[j].final_parity ))
            {
                at[j].final_parity ^= AB_INV_PARITY_BITS;
            }
        }
    }
    for (i = 0; i < pCS->nLenLinearCTStereoDble; i++)
    {
        parity = pCS->LinearCTStereoDble[i].parity;
        if (ATOM_PARITY_WELL_DEF( parity ))
        {
            j1 = nAtomNumberCanon[(int) pCS->LinearCTStereoDble[i].at_num1 - 1];
            cumulene_len = BOND_CHAIN_LEN( at[j1].stereo_bond_parity[0] );
            if (cumulene_len % 2)
            {
                /* invert only in case of allene */
                j2 = nAtomNumberCanon[(int) pCS->LinearCTStereoDble[i].at_num2 - 1];
                /* checks for debug only */
                if (1 < MAX_NUM_STEREO_BONDS)
                {
                    if (at[j1].stereo_bond_neighbor[1] ||
                         at[j2].stereo_bond_neighbor[1])
                    {
                        goto exit_error; /* inconsitency: atom has more than one cumulene bond */
                    }
                }
                if (cumulene_len != BOND_CHAIN_LEN( at[j2].stereo_bond_parity[0] ) ||
                     j1 + 1 != at[j2].stereo_bond_neighbor[0] ||
                     j2 + 1 != at[j1].stereo_bond_neighbor[0])
                {
                    goto exit_error; /* inconsitency: atoms should refer to each other */
                }
                /* invert parities */
                if (PARITY_WELL_DEF( at[j1].parity ) && PARITY_WELL_DEF( at[j2].parity ))
                {
                    j = inchi_min( j1, j2 );
                    at[j].parity ^= AB_INV_PARITY_BITS; /* for reversability always invert only atom with the smaller number */
                }
                else
                {
                    goto exit_error; /* inconsistency */
                }
                if (bInvertLinearCTStereo)
                {
                    pCS->LinearCTStereoDble[i].parity ^= AB_INV_PARITY_BITS;
                }
                num_changes++;
                if (PARITY_WELL_DEF( at[j1].stereo_bond_parity[0] ))
                {
                    at[j1].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
                }
                if (PARITY_WELL_DEF( at[j2].stereo_bond_parity[0] ))
                {
                    at[j2].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
                }
            }
        }
    }

    return num_changes;

exit_error:
    return CT_STEREOCOUNT_ERR;
}
/*****************************************************************************/
/* invert known parities in at[] and in pCS->LinearCTStereoDble              */
/*                                      pCS->LinearCTStereoCarb              */
/* nCanonRank[] contains canonical ranks used to fill pCS->LinearCTStereo... */
/* nAtomNumberCanon[] will be filled with atom numbers in canonical order    */
/*****************************************************************************/
invert known parities in at[] and in pCS->LinearCTStereoDble
pCS->LinearCTStereoCarb
nCanonRank[] contains canonical ranks used to fill pCS->LinearCTStereo
nAtomNumberCanon[] will be filled with atom numbers in canonical order
invert known parities in at [] and in pCS - > LinearCTStereoDble pCS - > LinearCTStereoCarb nCanonRank [] contains canonical ranks used to fill pCS - > LinearCTStereo nAtomNumberCanon [] will be filled with atom numbers in canonical order
int InvertStereo( sp_ATOM    *at,
                  int        num_at_tg,
                  AT_RANK    *nCanonRank,
                  AT_RANK    *nAtomNumberCanon,
                  CANON_STAT *pCS,
                  int        bInvertLinearCTStereo )
{
    int i, j, j1, j2, num_changes, parity, cumulene_len;
    num_changes = 0;
    for (i = 0; i < num_at_tg; i++)
    {
        nAtomNumberCanon[(int) nCanonRank[i] - 1] = i;
    }
    for (i = 0; i < pCS->nLenLinearCTStereoCarb; i++)
    {
        parity = pCS->LinearCTStereoCarb[i].parity;
        if (ATOM_PARITY_WELL_DEF( parity ))
        {
            j = nAtomNumberCanon[(int) pCS->LinearCTStereoCarb[i].at_num - 1];
            if (PARITY_WELL_DEF( at[j].parity ))
            {
                at[j].parity ^= AB_INV_PARITY_BITS;
            }
            else
            {
                goto exit_error; 
            }
            if (bInvertLinearCTStereo)
            {
#ifdef FIX_STEREOCOUNT_ERR
                pCS->LinearCTStereoCarb[i].parity = AB_PARITY_EVEN; 
#else
                pCS->LinearCTStereoCarb[i].parity ^= AB_INV_PARITY_BITS;
#endif
            }
            num_changes++;
            if (PARITY_WELL_DEF( at[j].stereo_atom_parity ))
            {
                at[j].stereo_atom_parity ^= AB_INV_PARITY_BITS;
            }
            if (PARITY_WELL_DEF( at[j].final_parity ))
            {
                at[j].final_parity ^= AB_INV_PARITY_BITS;
            }
        }
    }
    for (i = 0; i < pCS->nLenLinearCTStereoDble; i++)
    {
        parity = pCS->LinearCTStereoDble[i].parity;
        if (ATOM_PARITY_WELL_DEF( parity ))
        {
            j1 = nAtomNumberCanon[(int) pCS->LinearCTStereoDble[i].at_num1 - 1];
            cumulene_len = BOND_CHAIN_LEN( at[j1].stereo_bond_parity[0] );
            if (cumulene_len % 2)
            {
                j2 = nAtomNumberCanon[(int) pCS->LinearCTStereoDble[i].at_num2 - 1];
                if (1 < MAX_NUM_STEREO_BONDS)
                {
                    if (at[j1].stereo_bond_neighbor[1] ||
                         at[j2].stereo_bond_neighbor[1])
                    {
                        goto exit_error; 
                    }
                }
                if (cumulene_len != BOND_CHAIN_LEN( at[j2].stereo_bond_parity[0] ) ||
                     j1 + 1 != at[j2].stereo_bond_neighbor[0] ||
                     j2 + 1 != at[j1].stereo_bond_neighbor[0])
                {
                    goto exit_error; 
                }
                if (PARITY_WELL_DEF( at[j1].parity ) && PARITY_WELL_DEF( at[j2].parity ))
                {
                    j = inchi_min( j1, j2 );
                    at[j].parity ^= AB_INV_PARITY_BITS; 
                }
                else
                {
                    goto exit_error; 
                }
                if (bInvertLinearCTStereo)
                {
                    pCS->LinearCTStereoDble[i].parity ^= AB_INV_PARITY_BITS;
                }
                num_changes++;
                if (PARITY_WELL_DEF( at[j1].stereo_bond_parity[0] ))
                {
                    at[j1].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
                }
                if (PARITY_WELL_DEF( at[j2].stereo_bond_parity[0] ))
                {
                    at[j2].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
                }
            }
        }
    }
    return num_changes;
exit_error:
    return CT_STEREOCOUNT_ERR;
}
int InvertStereo ( sp_ATOM * at , int num_at_tg , AT_RANK * nCanonRank , AT_RANK * nAtomNumberCanon , CANON_STAT * pCS , int bInvertLinearCTStereo ) { int i , j , j1 , j2 , num_changes , parity , cumulene_len ; num_changes = 0 ; for ( i = 0 ; i < num_at_tg ; i ++ ) { nAtomNumberCanon [ ( int ) nCanonRank [ i ] - 1 ] = i ; } for ( i = 0 ; i < pCS -> nLenLinearCTStereoCarb ; i ++ ) { parity = pCS -> LinearCTStereoCarb [ i ] . parity ; if ( ATOM_PARITY_WELL_DEF ( parity ) ) { j = nAtomNumberCanon [ ( int ) pCS -> LinearCTStereoCarb [ i ] . at_num - 1 ] ; if ( PARITY_WELL_DEF ( at [ j ] . parity ) ) { at [ j ] . parity ^= AB_INV_PARITY_BITS ; } else { goto exit_error ; } if ( bInvertLinearCTStereo ) { #ifdef FIX_STEREOCOUNT_ERR pCS -> LinearCTStereoCarb [ i ] . parity = AB_PARITY_EVEN ; #else pCS -> LinearCTStereoCarb [ i ] . parity ^= AB_INV_PARITY_BITS ; #endif } num_changes ++ ; if ( PARITY_WELL_DEF ( at [ j ] . stereo_atom_parity ) ) { at [ j ] . stereo_atom_parity ^= AB_INV_PARITY_BITS ; } if ( PARITY_WELL_DEF ( at [ j ] . final_parity ) ) { at [ j ] . final_parity ^= AB_INV_PARITY_BITS ; } } } for ( i = 0 ; i < pCS -> nLenLinearCTStereoDble ; i ++ ) { parity = pCS -> LinearCTStereoDble [ i ] . parity ; if ( ATOM_PARITY_WELL_DEF ( parity ) ) { j1 = nAtomNumberCanon [ ( int ) pCS -> LinearCTStereoDble [ i ] . at_num1 - 1 ] ; cumulene_len = BOND_CHAIN_LEN ( at [ j1 ] . stereo_bond_parity [ 0 ] ) ; if ( cumulene_len % 2 ) { j2 = nAtomNumberCanon [ ( int ) pCS -> LinearCTStereoDble [ i ] . at_num2 - 1 ] ; if ( 1 < MAX_NUM_STEREO_BONDS ) { if ( at [ j1 ] . stereo_bond_neighbor [ 1 ] || at [ j2 ] . stereo_bond_neighbor [ 1 ] ) { goto exit_error ; } } if ( cumulene_len != BOND_CHAIN_LEN ( at [ j2 ] . stereo_bond_parity [ 0 ] ) || j1 + 1 != at [ j2 ] . stereo_bond_neighbor [ 0 ] || j2 + 1 != at [ j1 ] . stereo_bond_neighbor [ 0 ] ) { goto exit_error ; } if ( PARITY_WELL_DEF ( at [ j1 ] . parity ) && PARITY_WELL_DEF ( at [ j2 ] . parity ) ) { j = inchi_min ( j1 , j2 ) ; at [ j ] . parity ^= AB_INV_PARITY_BITS ; } else { goto exit_error ; } if ( bInvertLinearCTStereo ) { pCS -> LinearCTStereoDble [ i ] . parity ^= AB_INV_PARITY_BITS ; } num_changes ++ ; if ( PARITY_WELL_DEF ( at [ j1 ] . stereo_bond_parity [ 0 ] ) ) { at [ j1 ] . stereo_bond_parity [ 0 ] ^= AB_INV_PARITY_BITS ; } if ( PARITY_WELL_DEF ( at [ j2 ] . stereo_bond_parity [ 0 ] ) ) { at [ j2 ] . stereo_bond_parity [ 0 ] ^= AB_INV_PARITY_BITS ; } } } } return num_changes ; exit_error : return CT_STEREOCOUNT_ERR ; }
invert known parities in at[] and in pCS->LinearCTStereoDble
pCS->LinearCTStereoCarb
nCanonRank[] contains canonical ranks used to fill pCS->LinearCTStereo...
nAtomNumberCanon[] will be filled with atom numbers in canonical order
invert known parities in at [] and in pCS - > LinearCTStereoDble pCS - > LinearCTStereoCarb nCanonRank [] contains canonical ranks used to fill pCS - > LinearCTStereo ... nAtomNumberCanon [] will be filled with atom numbers in canonical order
/* inconsistency */ /* deliberately worse */ /* invert only in case of allene */ /* checks for debug only */ /* inconsitency: atom has more than one cumulene bond */ /* inconsitency: atoms should refer to each other */ /* invert parities */ /* for reversability always invert only atom with the smaller number */ /* inconsistency */