~ubuntu-branches/debian/stretch/openbabel/stretch

« back to all changes in this revision

Viewing changes to src/formats/libinchi/ichimap2.c

  • Committer: Package Import Robot
  • Author(s): Daniel Leidert
  • Date: 2013-05-22 19:08:27 UTC
  • mfrom: (1.1.11) (7.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20130522190827-72q0fnx5y2nm3bc0
Tags: 2.3.2+dfsg-1
* New upstream release.
* debian/control: Dropped DM-Upload-Allowed field.
  (Standards-Version): Bumped to 3.9.4.
* debian/copyright: Massive update.
* debian/upstream: Author name update.
* debian/get-orig-source.sh: Remove the windows-*/ directory too.
* debian/openbabel.install: Removed roundtrip manpage.
* debian/openbabel-gui.install: Fixed manpage name.
* debian/openbabel-gui.links: Removed unused file.
* debian/rules: Enable OpenMP. Disable tests on `nocheck'.
* debian/patches/gaussformat_nosym.patch: Dropped. Applied upstream.
* debian/patches/moldenformat_coordonly.patch: Ditto.
* debian/patches/obspectrophore_man.patch: Ditto.
* debian/patches/fix_ftbfs.patch: Added.
  - Fix several FTBFS issues in upstream build system.
* debian/patches/series: Adjusted.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * International Chemical Identifier (InChI)
 
3
 * Version 1
 
4
 * Software version 1.04
 
5
 * September 9, 2011
 
6
 *
 
7
 * The InChI library and programs are free software developed under the
 
8
 * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
 
9
 * Originally developed at NIST. Modifications and additions by IUPAC 
 
10
 * and the InChI Trust.
 
11
 *
 
12
 * IUPAC/InChI-Trust Licence for the International Chemical Identifier (InChI) 
 
13
 * Software version 1.0.
 
14
 * Copyright (C) IUPAC and InChI Trust Limited
 
15
 * 
 
16
 * This library is free software; you can redistribute it and/or modify it under the 
 
17
 * terms of the IUPAC/InChI Trust Licence for the International Chemical Identifier 
 
18
 * (InChI) Software version 1.0; either version 1.0 of the License, or 
 
19
 * (at your option) any later version.
 
20
 * 
 
21
 * This library is distributed in the hope that it will be useful, 
 
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 
24
 * See the IUPAC/InChI Trust Licence for the International Chemical Identifier (InChI) 
 
25
 * Software version 1.0 for more details.
 
26
 * 
 
27
 * You should have received a copy of the IUPAC/InChI Trust Licence for the 
 
28
 * International Chemical Identifier (InChI) Software version 1.0 along with 
 
29
 * this library; if not, write to:
 
30
 * 
 
31
 * The InChI Trust
 
32
 * c/o FIZ CHEMIE Berlin
 
33
 * Franklinstrasse 11
 
34
 * 10587 Berlin
 
35
 * GERMANY
 
36
 * 
 
37
 */
 
38
 
 
39
 
 
40
#include <stdio.h>
 
41
#include <stdlib.h>
 
42
#include <string.h>
 
43
 
 
44
 
 
45
#include "mode.h"
 
46
 
 
47
#include "incomdef.h"
 
48
#include "extr_ct.h"
 
49
#include "ichitaut.h"
 
50
#include "ichicant.h"
 
51
#include "ichicomn.h"
 
52
 
 
53
#include "ichicomp.h"
 
54
 
 
55
#define MAP_MODE_STD  0 /* Standard approach: switch 2 neighbors */
 
56
#define MAP_MODE_C2v  1 /* Check for C2v reflection leading to parity inversion */
 
57
#define MAP_MODE_C2   2 /* Check for C2 rotation preserving parities */
 
58
#define MAP_MODE_S4   3 /* Check for S4 rotation/reflection leading to parity inversion */
 
59
/* important: MAP_MODE_STD < (MAP_MODE_C2v, MAP_MODE_C2) < MAP_MODE_S4 */
 
60
 
 
61
/* local prototypes */
 
62
void DeAllocateForNonStereoRemoval( AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
 
63
                                    NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 );
 
64
int AllocateForNonStereoRemoval( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank, AT_RANK *nCanonRank,
 
65
                            AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
 
66
                            NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 );
 
67
AT_RANK GetMinNewRank(AT_RANK *nAtomRank, AT_RANK *nAtomNumb, AT_RANK nRank1 );
 
68
int BreakNeighborsTie(  sp_ATOM *at, int num_atoms, int num_at_tg, int ib, int ia,
 
69
                        AT_RANK *neigh_num, int in1, int in2, int mode,
 
70
                        AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
71
                        const AT_RANK *nSymmRank, AT_RANK *nCanonRank, NEIGH_LIST *nl1, NEIGH_LIST *nl2, long *lNumIter );
 
72
int CheckNextSymmNeighborsAndBonds( sp_ATOM *at, AT_RANK cur1, AT_RANK cur2, AT_RANK n1, AT_RANK n2,
 
73
                                    AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
 
74
                                    AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2, const AT_RANK *nRank1, const AT_RANK *nRank2 );
 
75
int CreateCheckSymmPaths( sp_ATOM *at, AT_RANK prev1, AT_RANK cur1, AT_RANK prev2, AT_RANK cur2,
 
76
                         AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
 
77
                         AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2,
 
78
                         NEIGH_LIST *nl1, NEIGH_LIST *nl2, const AT_RANK *nRank1, const AT_RANK *nRank2,
 
79
                         AT_RANK *nCanonRank, AT_RANK *nLength, int *bParitiesInverted, int mode );
 
80
int CalculatedPathsParitiesAreIdentical( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank,
 
81
                         AT_RANK *nCanonRank, AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
 
82
                         AT_RANK *nVisited1, AT_RANK *nVisited2,
 
83
                         AT_RANK prev_sb_neigh, AT_RANK cur, AT_RANK next1, AT_RANK next2, int nNeighMode,
 
84
                         int bParitiesInverted, int mode, CANON_STAT *pCS,
 
85
                         int vABParityUnknown);
 
86
int RemoveCalculatedNonStereoBondParities( sp_ATOM *at, int num_atoms, int num_at_tg,
 
87
                                          AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
88
                                          AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
 
89
                                          AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
 
90
                                          NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2,
 
91
                                          AT_RANK *nVisited1, AT_RANK *nVisited2, CANON_STAT *pCS,
 
92
                                          int vABParityUnknown);
 
93
int RemoveCalculatedNonStereoCenterParities( sp_ATOM *at, int num_atoms, int num_at_tg,
 
94
                                          AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
95
                                          AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
 
96
                                          AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
 
97
                                          NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2, 
 
98
                                          AT_RANK *nVisited1, AT_RANK *nVisited2, CANON_STAT *pCS,
 
99
                                          int vABParityUnknown);
 
100
 
 
101
int SortNeighLists3( int num_atoms, AT_RANK *nRank, NEIGH_LIST *NeighList, AT_RANK *nAtomNumber );
 
102
 
 
103
 
 
104
 
 
105
 
 
106
 
 
107
/**************************************************************************************
 
108
 *
 
109
 *   Convert sorted equivalence information (nSymmRank) to ranks (nRank)
 
110
 *   nSymmRank and nRank may point to the same array
 
111
 *
 
112
 */
 
113
int SortedEquInfoToRanks( const AT_RANK* nSymmRank, AT_RANK* nRank, const AT_RANK* nAtomNumber, int num_atoms, int *bChanged )
 
114
{
 
115
    AT_RANK        rNew, rOld, nNumDiffRanks;
 
116
    int            i, j, nNumChanges = 0;
 
117
    for ( i = num_atoms-1, j = (int)nAtomNumber[i],
 
118
          rOld = nSymmRank[j], rNew = nRank[j] = (AT_RANK)num_atoms,
 
119
          nNumDiffRanks = 1;
 
120
             i > 0;
 
121
                 i -- ) {
 
122
 
 
123
        j = (int)nAtomNumber[i-1];
 
124
        
 
125
        if ( nSymmRank[j] != rOld ) {
 
126
            nNumDiffRanks ++;
 
127
            rNew = (AT_RANK)i;
 
128
            nNumChanges += (rOld != rNew+1);
 
129
            rOld = nSymmRank[j];
 
130
        }
 
131
 
 
132
        nRank[j] = rNew;
 
133
    }
 
134
    if ( bChanged ) {
 
135
        *bChanged = (0 != nNumChanges);
 
136
    }
 
137
    return nNumDiffRanks;
 
138
}
 
139
/**************************************************************************************
 
140
 *
 
141
 *   Convert sorted ranks (nRank) to sorted equivalence information (nSymmRank)
 
142
 *   nSymmRank and nRank may point to the same array
 
143
 *
 
144
 */
 
145
int SortedRanksToEquInfo( AT_RANK* nSymmRank, const AT_RANK* nRank, const AT_RANK* nAtomNumber, int num_atoms )
 
146
{
 
147
    AT_RANK        rNew, rOld, nNumDiffRanks;
 
148
    int            i, j;
 
149
    for ( i = 1, j = (int)nAtomNumber[0],
 
150
          rOld = nRank[j], rNew = nSymmRank[j] = 1,
 
151
          nNumDiffRanks = 1;
 
152
          i < num_atoms;
 
153
          i ++ ) {
 
154
        j = (int)nAtomNumber[i];
 
155
        if ( nRank[j] != rOld ) {
 
156
            nNumDiffRanks ++;
 
157
            rNew = (AT_RANK)(i+1);
 
158
            rOld = nRank[j];
 
159
        }
 
160
        nSymmRank[j] = rNew;
 
161
    }
 
162
    return nNumDiffRanks;
 
163
}
 
164
 
 
165
/**************************************************************************************/
 
166
void switch_ptrs( AT_RANK **p1, AT_RANK **p2 )
 
167
{
 
168
    AT_RANK *tmp = *p1;
 
169
    *p1 = *p2;
 
170
    *p2 = tmp;
 
171
}
 
172
 
 
173
/**************************************************************************************/
 
174
/*  Set ranks from the products vector and previous ranks                             */
 
175
/*  nRank[] and nNewRank[] should refer to different arrays for now                   */
 
176
/**************************************************************************************/
 
177
int SetNewRanksFromNeighLists3( int num_atoms, NEIGH_LIST *NeighList, AT_RANK *nRank,
 
178
                                AT_RANK *nNewRank, AT_RANK *nAtomNumber )
 
179
{
 
180
    int     i, j, nNumDiffRanks, nNumNewRanks;
 
181
    AT_RANK r1, r2;
 
182
    /*  -- nAtomNumber[] is already properly set --
 
183
    for ( i = 0; i < num_atoms; i++ ) {
 
184
        nAtomNumber[i] = (AT_RANK)i;
 
185
    }
 
186
    */
 
187
    /*  set globals for qsort */
 
188
    pNeighList_RankForSort = NeighList;
 
189
    pn_RankForSort         = nRank;
 
190
    nNumDiffRanks          = 0;
 
191
    nNumNewRanks           = 0;
 
192
 
 
193
    memset(nNewRank, 0, num_atoms*sizeof(nNewRank[0]));
 
194
    
 
195
    /*  sorting */
 
196
    for ( i = 0, r1 = 1; i < num_atoms; r1++ ) {
 
197
        if ( r1 == (r2 = nRank[j=(int)nAtomNumber[i]]) ) {
 
198
            nNewRank[j] = r2;
 
199
            nNumDiffRanks ++;
 
200
            i ++;
 
201
            continue;
 
202
        }
 
203
        r1 = r2;
 
204
        insertions_sort_AT_NUMBERS( nAtomNumber+i, (int)r2-i, CompNeighLists );
 
205
        /*insertions_sort( nAtomNumber+i, r2-i, sizeof( nAtomNumber[0] ), CompNeighLists );*/
 
206
        j = r2-1;
 
207
        nNewRank[(int)nAtomNumber[j]] = r2;
 
208
        nNumDiffRanks ++;
 
209
        while( j > i ) {
 
210
            if ( CompareNeighListLex( NeighList[(int)nAtomNumber[j-1]],
 
211
                                      NeighList[(int)nAtomNumber[j]], nRank ) ) {
 
212
                r2 = j;
 
213
                nNumDiffRanks ++;
 
214
                nNumNewRanks ++;
 
215
            }
 
216
            j --;
 
217
            nNewRank[(int)nAtomNumber[j]] = r2;
 
218
        }
 
219
        i = r1;
 
220
    }
 
221
    return nNumNewRanks? -nNumDiffRanks : nNumDiffRanks;
 
222
}
 
223
/**************************************************************************************/
 
224
/*  Set ranks from the products vector and previous ranks                             */
 
225
/*  When comparing neigh lists ignore ranks > max_at_no                               */
 
226
/*  nRank[] and nNewRank[] should refer to different arrays for now                   */
 
227
/**************************************************************************************/
 
228
int SetNewRanksFromNeighLists4( int num_atoms, NEIGH_LIST *NeighList, AT_RANK *nRank,
 
229
                                AT_RANK *nNewRank, AT_RANK *nAtomNumber, AT_RANK nMaxAtRank )
 
230
{
 
231
    int     i, j, nNumDiffRanks, nNumNewRanks;
 
232
    AT_RANK r1, r2;
 
233
    /*  -- nAtomNumber[] is already properly set --
 
234
    for ( i = 0; i < num_atoms; i++ ) {
 
235
        nAtomNumber[i] = (AT_RANK)i;
 
236
    }
 
237
    */
 
238
    /*  set globals for CompNeighListsUpToMaxRank */
 
239
    pNeighList_RankForSort = NeighList;
 
240
    pn_RankForSort         = nRank;
 
241
    nNumDiffRanks          = 0;
 
242
    nNumNewRanks           = 0;
 
243
    nMaxAtNeighRankForSort = nMaxAtRank;
 
244
 
 
245
    memset(nNewRank, 0, num_atoms*sizeof(nNewRank[0]));
 
246
    
 
247
    /*  sorting */
 
248
    for ( i = 0, r1 = 1; i < num_atoms; r1++ ) {
 
249
        if ( r1 == (r2 = nRank[j=(int)nAtomNumber[i]]) ) {
 
250
            /* non-tied rank: singleton */
 
251
            nNewRank[j] = r2;
 
252
            nNumDiffRanks ++;
 
253
            i ++;
 
254
            continue;
 
255
        }
 
256
        /* tied rank r2
 
257
           r2-i atoms have rank r2
 
258
           next atom after them is in position r2
 
259
        */
 
260
        r1 = r2;
 
261
        insertions_sort_AT_NUMBERS( nAtomNumber+i, (int)r2-i, CompNeighListsUpToMaxRank );
 
262
        /*insertions_sort( nAtomNumber+i, r2-i, sizeof( nAtomNumber[0] ),  CompNeighListsUpToMaxRank );*/
 
263
        j = r2-1; /* prepare cycle backward, from j to i step -1 */
 
264
        nNewRank[(int)nAtomNumber[j]] = r2;
 
265
        nNumDiffRanks ++;
 
266
        while( j > i ) {
 
267
            if ( CompareNeighListLexUpToMaxRank( NeighList[nAtomNumber[j-1]],
 
268
                                                 NeighList[nAtomNumber[j]], nRank, nMaxAtRank ) ) {
 
269
                r2 = j;
 
270
                nNumDiffRanks ++;
 
271
                nNumNewRanks ++;
 
272
            }
 
273
            j --;
 
274
            nNewRank[(int)nAtomNumber[j]] = r2;
 
275
        }
 
276
        i = r1;
 
277
    }
 
278
    return nNumNewRanks? -nNumDiffRanks : nNumDiffRanks;
 
279
}
 
280
/**************************************************************************************/
 
281
/*  Set ranks from the products vector and previous ranks                             */
 
282
/*  nRank[] and nNewRank[] should refer to different arrays for now                   */
 
283
/**************************************************************************************/
 
284
int SetNewRanksFromNeighLists( int num_atoms, NEIGH_LIST *NeighList, AT_RANK *nRank, AT_RANK *nNewRank,
 
285
                             AT_RANK *nAtomNumber, int bUseAltSort, int ( *comp )(const void *, const void *) )
 
286
{
 
287
    int     i,  nNumDiffRanks;
 
288
    AT_RANK nCurrentRank;
 
289
    /*  -- nAtomNumber[] is already properly set --
 
290
    for ( i = 0; i < num_atoms; i++ ) {
 
291
        nAtomNumber[i] = (AT_RANK)i;
 
292
    }
 
293
    */
 
294
    /*  set globals for qsort */
 
295
    pNeighList_RankForSort = NeighList;
 
296
    pn_RankForSort         = nRank;
 
297
    
 
298
    /*  sorting */
 
299
    if ( bUseAltSort & 1 )
 
300
        tsort( nAtomNumber, num_atoms, sizeof( nAtomNumber[0] ), comp /*CompNeighListRanksOrd*/ );
 
301
    else
 
302
        qsort( nAtomNumber, num_atoms, sizeof( nAtomNumber[0] ), comp /*CompNeighListRanksOrd*/ );
 
303
 
 
304
    for ( i=num_atoms-1, nCurrentRank=nNewRank[(int)nAtomNumber[i]] = (AT_RANK)num_atoms, nNumDiffRanks = 1;
 
305
          0 < i ;
 
306
          i -- ) {
 
307
        /*  Note: CompNeighListRanks() in following line implicitly reads nRank pointed by pn_RankForSort */
 
308
        if ( CompNeighListRanks( &nAtomNumber[i-1], &nAtomNumber[i] ) ) {
 
309
            nNumDiffRanks ++;
 
310
            nCurrentRank = (AT_RANK)i;
 
311
        }
 
312
        nNewRank[(int)nAtomNumber[i - 1]] = nCurrentRank;
 
313
    }
 
314
    
 
315
    return nNumDiffRanks;
 
316
}
 
317
/**************************************************************************************/
 
318
/*   Sort NeighList[] lists of neighbors according to the ranks of the neighbors      */
 
319
/**************************************************************************************/
 
320
void SortNeighListsBySymmAndCanonRank( int num_atoms, NEIGH_LIST *NeighList, const AT_RANK *nSymmRank, const AT_RANK *nCanonRank )
 
321
{
 
322
    int i;
 
323
    for ( i = 0; i < num_atoms; i ++ ) {
 
324
        insertions_sort_NeighListBySymmAndCanonRank( NeighList[i], nSymmRank, nCanonRank );
 
325
    }
 
326
}
 
327
/**************************************************************************************/
 
328
int SortNeighLists2( int num_atoms, AT_RANK *nRank, NEIGH_LIST *NeighList, AT_RANK *nAtomNumber )
 
329
{
 
330
    int k, i;
 
331
    AT_RANK nPrevRank = 0;
 
332
    /*
 
333
     * on entry nRank[nAtomNumber[k]] <= nRank[nAtomNumber[k+1]]  ( k < num_atoms-1 )
 
334
     *          nRank[nAtomNumber[k]] >= k+1                      ( k < num_atoms )
 
335
     *          nRank[nAtomNumber[k]] == k+1 if this nRank value is not tied OR if
 
336
     *                nRank[nAtomNumber[k]] < nRank[nAtomNumber[k+1]] OR if k = num_atoms-1.
 
337
     *
 
338
     */
 
339
    for ( k = 0; k < num_atoms; k ++ ) {
 
340
        i = nAtomNumber[k];
 
341
        if ( (nRank[i] != k+1 || nRank[i] == nPrevRank) && NeighList[i][0] > 1 ) {
 
342
            /*  nRank[i] is tied (duplicated) */
 
343
            insertions_sort_NeighList_AT_NUMBERS( NeighList[i], nRank );
 
344
        }
 
345
        nPrevRank = nRank[i];
 
346
    }
 
347
    return 0;
 
348
}
 
349
/**************************************************************************************/
 
350
int SortNeighLists3( int num_atoms, AT_RANK *nRank, NEIGH_LIST *NeighList, AT_RANK *nAtomNumber )
 
351
{
 
352
    int k, i;
 
353
    AT_RANK nPrevRank = 0;
 
354
    /*
 
355
     * on entry nRank[nAtomNumber[k]] <= nRank[nAtomNumber[k+1]]  ( k < num_atoms-1 )
 
356
     *          nRank[nAtomNumber[k]] >= k+1                      ( k < num_atoms )
 
357
     *          nRank[nAtomNumber[k]] == k+1 if this nRank value is not tied OR if
 
358
     *                nRank[nAtomNumber[k]] < nRank[nAtomNumber[k+1]] OR if k = num_atoms-1.
 
359
     *
 
360
     */
 
361
    for ( k = 0; k < num_atoms; k ++ ) {
 
362
        i = nAtomNumber[k];
 
363
        if ( (nRank[i] != k+1 || nRank[i] == nPrevRank) && NeighList[i][0] > 1 ) {
 
364
            /*  nRank[i] is tied (duplicated) */
 
365
            insertions_sort_NeighList_AT_NUMBERS3( NeighList[i], nRank );
 
366
        }
 
367
        nPrevRank = nRank[i];
 
368
    }
 
369
    return 0;
 
370
}
 
371
/**************************************************************************************
 
372
 *
 
373
 *  Differentiate2
 
374
 *
 
375
 * Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
 
376
 *       for example, nAtomNumber[i] = i;
 
377
 * Note2: this version does not calculate neighbor lists for non-tied ranks
 
378
 */
 
379
int  DifferentiateRanks2( int num_atoms, NEIGH_LIST *NeighList,
 
380
                                 int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
 
381
                                 AT_RANK *nAtomNumber, long *lNumIter, int bUseAltSort )
 
382
{
 
383
    /*int nNumPrevRanks;*/
 
384
 
 
385
    /*  SortNeighLists2 needs sorted ranks */
 
386
    pn_RankForSort = pnCurrRank;
 
387
    if ( bUseAltSort & 1 )
 
388
        tsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRank /* CompRanksOrd*/ );
 
389
    else
 
390
        qsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRanksOrd );
 
391
 
 
392
    do {
 
393
        *lNumIter += 1;
 
394
        /*nNumPrevRanks = nNumCurrRanks;*/
 
395
        switch_ptrs( &pnCurrRank, &pnPrevRank );
 
396
        SortNeighLists2( num_atoms, pnPrevRank, NeighList, nAtomNumber );
 
397
        /*  the following call creates pnCurrRank out of pnPrevRank */
 
398
        nNumCurrRanks = SetNewRanksFromNeighLists( num_atoms, NeighList, pnPrevRank, pnCurrRank, nAtomNumber,
 
399
                                                 1, CompNeighListRanksOrd );
 
400
    } while ( /*nNumPrevRanks != nNumCurrRanks ||*/ memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) ) );
 
401
 
 
402
    return nNumCurrRanks;
 
403
}
 
404
/**************************************************************************************
 
405
 *
 
406
 *  Differentiate3
 
407
 *
 
408
 * Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
 
409
 *       for example, nAtomNumber[i] = i;
 
410
 * Note2: this version does not calculate neighbor lists for non-tied ranks
 
411
 */
 
412
int  DifferentiateRanks3( int num_atoms, NEIGH_LIST *NeighList,
 
413
                          int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
 
414
                          AT_RANK *nAtomNumber, long *lNumIter )
 
415
{
 
416
/*    
 
417
    static long count = 0;
 
418
    count ++;
 
419
    if ( count == 103 ) {
 
420
        int stop=1;
 
421
    }
 
422
*/
 
423
 
 
424
    /*  SortNeighLists3 needs sorted ranks: ranks/atnumbers must have been already sorted */
 
425
    do {
 
426
        *lNumIter += 1;
 
427
        switch_ptrs( &pnCurrRank, &pnPrevRank );
 
428
        SortNeighLists3( num_atoms, pnPrevRank, NeighList, nAtomNumber );
 
429
        /*  the following call creates pnCurrRank out of pnPrevRank */
 
430
        nNumCurrRanks = SetNewRanksFromNeighLists3( num_atoms, NeighList, pnPrevRank,
 
431
                                                    pnCurrRank, nAtomNumber);
 
432
    } while ( nNumCurrRanks < 0 /* memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) )*/ );
 
433
 
 
434
    return nNumCurrRanks;
 
435
}
 
436
/**************************************************************************************
 
437
 *
 
438
 *  Differentiate4: ignore neighbors with rank > num_atoms
 
439
 *
 
440
 * Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
 
441
 *       for example, nAtomNumber[i] = i;
 
442
 * Note2: this version does not sort neighbor lists for non-tied ranks
 
443
 */
 
444
int  DifferentiateRanks4( int num_atoms, NEIGH_LIST *NeighList,
 
445
                          int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
 
446
                          AT_RANK *nAtomNumber, AT_RANK nMaxAtRank, long *lNumIter )
 
447
{
 
448
/*    
 
449
    static long count = 0;
 
450
    count ++;
 
451
    if ( count == 103 ) {
 
452
        int stop=1;
 
453
    }
 
454
*/
 
455
    /*  SortNeighLists4 needs sorted ranks: ranks/atnumbers must have been already sorted */
 
456
    do {
 
457
        *lNumIter += 1;
 
458
        switch_ptrs( &pnCurrRank, &pnPrevRank );
 
459
        SortNeighLists3( num_atoms, pnPrevRank, NeighList, nAtomNumber );
 
460
        /*  the following call creates pnCurrRank out of pnPrevRank */
 
461
        nNumCurrRanks = SetNewRanksFromNeighLists4( num_atoms, NeighList, pnPrevRank,
 
462
                                                    pnCurrRank, nAtomNumber, nMaxAtRank );
 
463
    } while ( nNumCurrRanks < 0 /* memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) )*/ );
 
464
 
 
465
    return nNumCurrRanks;
 
466
}
 
467
/**************************************************************************************
 
468
 *
 
469
 *  DifferentiateBasic (sort according to ranks only)
 
470
 *
 
471
 * Note: on entry nAtomNumber[] must contain a valid transposition of num_atoms length
 
472
 *       for example, nAtomNumber[i] = i;
 
473
 * Note2: this version does not calculate neighbor lists for non-tied ranks
 
474
 */
 
475
int  DifferentiateRanksBasic( int num_atoms, NEIGH_LIST *NeighList,
 
476
                                 int nNumCurrRanks, AT_RANK *pnCurrRank, AT_RANK *pnPrevRank,
 
477
                                 AT_RANK *nAtomNumber, long *lNumIter, int bUseAltSort )
 
478
{
 
479
    int nNumPrevRanks;
 
480
 
 
481
    /*  SortNeighLists2 needs sorted ranks */
 
482
    pn_RankForSort     = pnCurrRank;
 
483
    if ( bUseAltSort & 1 )
 
484
        tsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRank );
 
485
    else
 
486
        qsort( nAtomNumber, num_atoms, sizeof(nAtomNumber[0]), CompRank );
 
487
 
 
488
    do {
 
489
        *lNumIter += 1;
 
490
        nNumPrevRanks = nNumCurrRanks;
 
491
        switch_ptrs( &pnCurrRank, &pnPrevRank );
 
492
        SortNeighLists2( num_atoms, pnPrevRank, NeighList, nAtomNumber );
 
493
        /*  the following call creates pnCurrRank out of pnPrevRank */
 
494
        nNumCurrRanks = SetNewRanksFromNeighLists( num_atoms, NeighList, pnPrevRank, pnCurrRank, nAtomNumber, bUseAltSort, CompNeighListRanks );
 
495
    } while ( nNumPrevRanks != nNumCurrRanks || memcmp( pnPrevRank, pnCurrRank, num_atoms*sizeof(pnCurrRank[0]) ) );
 
496
    return nNumCurrRanks;
 
497
}
 
498
 
 
499
/**************************************************************************************
 
500
 * For the purpose of mapping an atom to an atom:
 
501
 * (a) find number of tied ranks
 
502
 * (b) if number of tied ranks > 1 then:
 
503
 *    1) find the rank for breaking a tie
 
504
 *    2) allocate memory for breaking the tie if it has not been allocated
 
505
 *    3) find out if atom 1 ("from") has already been mapped
 
506
 * Return value:
 
507
 *  < 0: error
 
508
 *  = 1: has already been mapped, to tie to break
 
509
 *  > 1: we need to break a tie
 
510
 */
 
511
int NumberOfTies( AT_RANK **pRankStack1, AT_RANK **pRankStack2, int length,
 
512
                  int at_no1, int at_no2, AT_RANK *nNewRank, int *bAddStack, int *bMapped1 )
 
513
{
 
514
 
 
515
    AT_RANK *nRank1       = *pRankStack1++;
 
516
    AT_RANK *nAtomNumber1 = *pRankStack1++;  /*  ranks for mapping "1", "from" */
 
517
 
 
518
    AT_RANK *nRank2       = *pRankStack2++;
 
519
    AT_RANK *nAtomNumber2 = *pRankStack2++;  /*  ranks for mapping "2", "to" */
 
520
 
 
521
    AT_RANK r, *pTempArray;
 
522
 
 
523
    int iMax, i, i1, i2;
 
524
 
 
525
    *bAddStack = 0;
 
526
    *bMapped1  = 0;
 
527
    *nNewRank  = 0;
 
528
    r = nRank1[at_no1];
 
529
    if ( r != nRank2[at_no2] )
 
530
        return CT_MAPCOUNT_ERR; /*  atoms cannot be mapped onto each other: they have different ranks */ /*   <BRKPT> */
 
531
    iMax = r - 1;
 
532
    /*  find i1 and i2 = numbers of ranks in nRank1[] and nRank2[] equal to r:  */
 
533
    for ( i1 = 1; i1 <= iMax && r == nRank1[nAtomNumber1[iMax-i1]]; i1 ++ )
 
534
        ;
 
535
    for ( i2 = 1; i2 <= iMax && r == nRank2[nAtomNumber2[iMax-i2]]; i2 ++ )
 
536
        ;
 
537
    if ( i2 != i1 )
 
538
        return CT_MAPCOUNT_ERR; /*  program error: must be identical number of equal ranks */ /*   <BRKPT> */
 
539
    /*  found i1 equal rank(s); preceding (smaller) non-equal rank is r-i1 */
 
540
    /*  To break the tie we have to reduce the rank r to r-i1+1 */
 
541
 
 
542
    /************ Note *******************************
 
543
     * IF ( i=r-1 && 0 <= i && i < num_atoms AND 
 
544
     *      nRank[nAtomNumber1[i]] == r )
 
545
     * THEN:
 
546
     * nRank[nAtomNumber1[i+1]] >  r; (if i+1 < num_atoms)
 
547
     * nRank[nAtomNumber1[i-1]] <= r; (if i > 0)
 
548
     *
 
549
     * IF r = nRank[i] THEN
 
550
     * nRank[nAtomNumber1[r-1]] == r
 
551
     * nRank[nAtomNumber1[r-i-1]] <= nRank[nAtomNumber1[r-i]] (for 1 <= i < r )
 
552
     */
 
553
    if ( i1 > 1 ) {
 
554
        /* int bAtFromHasAlreadyBeenMapped = 0; */
 
555
        *nNewRank = r - i1 + 1;
 
556
        /*  grab an existing or allocate a new array */
 
557
        /*  we need 4 arrays: 2 for ranks + 2 for numbers */
 
558
        for ( i = 0; i < 4; i ++ ) {
 
559
            if ( i < 2 ) {
 
560
                pTempArray = *pRankStack1;
 
561
                *bMapped1 += (pTempArray && pTempArray[0]);
 
562
            } else {
 
563
                pTempArray = *pRankStack2;
 
564
            }
 
565
            if ( !pTempArray && !(pTempArray = (AT_RANK *) inchi_malloc(length)))
 
566
                return CT_OUT_OF_RAM;  /*  out of RAM */ /*   <BRKPT> */
 
567
            /*  copy "to" contents */
 
568
            switch( i ) {
 
569
            case 2:
 
570
                memcpy( pTempArray, nRank2, length );
 
571
                break;
 
572
            case 3:
 
573
                memcpy( pTempArray, nAtomNumber2, length );
 
574
                break;
 
575
            }
 
576
            if ( i < 2 )
 
577
                *pRankStack1 ++ = pTempArray;
 
578
            else {
 
579
                *pRankStack2 ++ = pTempArray;
 
580
            }
 
581
        }
 
582
        *bAddStack = 2; /*  to break the tie we added 2 more arrays to pRankStack1 and pRankStack2 */
 
583
    }
 
584
    return i1;
 
585
}    
 
586
 
 
587
 
 
588
/**************************************************************************************
 
589
 *
 
590
 *
 
591
 *
 
592
 *               Stereo Mappings
 
593
 *
 
594
 *
 
595
 *
 
596
 **************************************************************************************/
 
597
 
 
598
/**************************************************************************************
 
599
 * Parity for a half of a stereo bond. If both halfs have the same parity
 
600
 * then the bond is "trans" (E,-,1), otherwise it is "cis" (Z,+,2).
 
601
 * The advantage of this approach is: The bond parity does not depend on the
 
602
 * rank of the atom located on the opposite end of the stereogenic bond.
 
603
 * As the result all bond parities of, for example, benzene, can be calculated
 
604
 * from equivalence ranks only, without any mappings.
 
605
 *
 
606
 * Input: at_no1     = number of atom for which the half-bond parity is calculated
 
607
 *        i_sb_neigh = ordering number of the stereo bond in at->stereo_bond_neighbor[]
 
608
 *
 
609
 * Returns: 0=> no parity can be found; 1=> odd parity; 2=> even parity
 
610
 *
 
611
 */
 
612
int HalfStereoBondParity( sp_ATOM *at, int at_no1, int i_sb_neigh, const AT_RANK *nRank )
 
613
{
 
614
/*
 
615
   Suppose neighbors #0,#1,#2 have ranks a, b, c. Remove rank of the neighbor connected
 
616
   by the stereogenic bond (NCSB) from the a, b, c list and denote the two left as r[0], r[1],
 
617
   in the same order. Let iNCSB be an ordering number (0,1,or 2) of the NCSB.
 
618
   Assume the neighbor connected by the stereogenic bond has infinite positive rank.
 
619
   Position the half-bond so that the stereogenic bond neighbor is to the right from the atom (see below)
 
620
   
 
621
   Definition.
 
622
   ===========
 
623
                   if rank(X) != rank(Y) then Half-bond parity = (rank(X) > rank(Y)), that is,
 
624
    Y              
 
625
     \             if ( rank(X) < rank(Y) ) then Half-bond parity is Even
 
626
      C==NCSB      if ( rank(X) > rank(Y) ) then Half-bond parity is Odd
 
627
     /             if ( rank(X) = rank(Y) ) then Half-bond parity cannot be defined
 
628
    X
 
629
    
 
630
    1                          2             1         
 
631
     \                          \             \        
 
632
      C==NCSB       C==NCSB      C==NCSB       C==NCSB 
 
633
     /             /            /                      
 
634
    2             1            1                       
 
635
                                                       
 
636
    Parity = 1    Parity = 1   Parity = 2    Parity = 2
 
637
    (Odd)         (Odd)       (Even) or 0   (Even) or 0
 
638
    
 
639
   Half-bond parity =  (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
 
640
 
 
641
   Consider the following cases to prove the formula:
 
642
 
 
643
   Case 1: 3 explicit neighbors
 
644
   ============================
 
645
   If  (1) atom's geometric parity = even (which means neighbors #0, #1, #2 are located clockwise),
 
646
   and (2) neighbors other than NCSB have different ranks, then,
 
647
   assuming that NCSB always has the largest (infinite) rank (this is consistent with
 
648
   the assumption that implicit hydrogens have smallest ranks), we have 3 possibilities:
 
649
 
 
650
                             c         a          b       
 
651
                              \         \          \      
 
652
                               C==a      C==b       C==c  
 
653
                              /         /          /      
 
654
                             b         c          a       
 
655
                                                          
 
656
            iNCSB      =      0          1          2    
 
657
       Half-bond parity =     b>c        a<c        a>b     (0=even, 1=odd)
 
658
                           r[0]>r[1]  r[0]<r[1]  r[0]>r[1]
 
659
       Half-bond parity
 
660
       for all 3 cases      =    (iNCSB + (r[0] > r[1]))%2
 
661
 
 
662
       The following slight modification will work for both odd and even geometric parity:
 
663
 
 
664
       Half-bond parity     =    (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
 
665
 
 
666
       even parity (0) => atom above the bond has lower rank than the atom below the bond.
 
667
 
 
668
 
 
669
   Case 2: 2 explicit neighbors
 
670
   ============================
 
671
   One implicit hydrogen atom H or hydrogen isotope (implicit rank=0). Assume r[1]=0
 
672
 
 
673
                             H         a            Note. The same method 
 
674
                              \         \                 works for              
 
675
                               C==a      C==b                 
 
676
                              /         /             N==a   and   a     
 
677
                             b         H             /              \    
 
678
                                                    b                N==b
 
679
            iNCSB       =      0         1     
 
680
       Half-bond parity =     b>0       a<0    
 
681
       (r[1]=0, r[0]>0)    r[0]>r[1]  r[0]<r[1] 
 
682
 
 
683
       Half-bond parity =  (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
 
684
 
 
685
   Case 3: 1 explicit neighbor (NCSB)
 
686
   ==================================
 
687
   Two implicit hydrogens, (number of neighbors on non-streogenic bonds)==0:
 
688
 
 
689
   Atom C geometric parity:  Even               Odd          Note. The same method
 
690
                                                                   works for                          
 
691
                             D                  H                       
 
692
                              \                  \           Even   and   Odd               
 
693
                               C==a               C==a                                      
 
694
                              /                  /           H               N==a           
 
695
                             H                  D             \             /               
 
696
                                                               N==a        H     
 
697
            iNCSB =           0                0
 
698
       Half-bond parity =    (0<0)=0         (0<0)+1 = 1
 
699
       (r[1]=0, r[0]=0)    r[1]<r[0]         (r[1]<r[0])+atom_parity
 
700
 
 
701
       Half-parity
 
702
       for this case  =    (iNCSB + (r[0] > r[1]) + (Atom C geometric parity))%2
 
703
 
 
704
*/
 
705
    int i, j, k, iNeigh, parity, at1_parity, at_no2;
 
706
    AT_RANK r[MAX_NUM_STEREO_BOND_NEIGH];
 
707
 
 
708
    if ( at[at_no1].valence > MAX_NUM_STEREO_BOND_NEIGH || ( at1_parity = at[at_no1].parity ) <= 0 ) {
 
709
        return 0;
 
710
    }
 
711
    if ( !PARITY_WELL_DEF( at1_parity ) ) {
 
712
        if ( PARITY_KNOWN( at1_parity ) ) {
 
713
            return at1_parity;
 
714
        }
 
715
        return -at1_parity;
 
716
    }
 
717
    if ( 0 > i_sb_neigh || i_sb_neigh >= MAX_NUM_STEREO_BOND_NEIGH ) {
 
718
        return CT_STEREOBOND_ERROR;  /*   <BRKPT> */
 
719
    }
 
720
    for ( i = 0; i <= i_sb_neigh; i ++ ) {
 
721
        if ( !at[at_no1].stereo_bond_neighbor[i] ) {
 
722
            return CT_STEREOBOND_ERROR;  /*   <BRKPT> */
 
723
        }
 
724
    }
 
725
    at_no2 = at[at_no1].neighbor[(int)at[at_no1].stereo_bond_ord[i_sb_neigh]];
 
726
    memset( r, 0, sizeof( r ) ); 
 
727
    for ( i = j = 0, iNeigh = -1; i < at[at_no1].valence; i ++ ) {
 
728
        if ( (k = (int)at[at_no1].neighbor[i]) == at_no2 ) {
 
729
            iNeigh = i;
 
730
        } else {
 
731
            r[j++] = nRank[k];
 
732
        }
 
733
    }
 
734
    if ( iNeigh < 0 || iNeigh != at[at_no1].stereo_bond_ord[i_sb_neigh] ) {
 
735
        return CT_STEREOBOND_ERROR;  /*   <BRKPT> */
 
736
    }
 
737
    if ( j > 0 && !r[0] || j > 1 && !r[1] )
 
738
        return 0; /*  undefined ranks */
 
739
 
 
740
    if ( j == 2 && r[0] == r[1] || iNeigh < 0 ) {
 
741
        parity = AB_PARITY_CALC;  /*  cannot calculate bond parity without additional breaking ties. */
 
742
    } else {
 
743
        parity = 2 - (at[at_no1].parity + iNeigh + (r[1] < r[0])) % 2;
 
744
    }
 
745
    return parity;
 
746
}
 
747
/**************************************************************************************/
 
748
int parity_of_mapped_half_bond( int from_at, int to_at, int from_neigh, int to_neigh,
 
749
                           sp_ATOM *at, EQ_NEIGH *pEN,
 
750
                           const AT_RANK *nCanonRankFrom, const AT_RANK *nRankFrom, const AT_RANK *nRankTo )
 
751
{
 
752
    int     i, j, k, num_neigh;
 
753
    int     to_sb_neigh_ord, from_sb_neigh_ord, parity;
 
754
    AT_RANK r_to[MAX_NUM_STEREO_BOND_NEIGH], at_no_to[MAX_NUM_STEREO_BOND_NEIGH];
 
755
    AT_RANK r_canon_from[MAX_NUM_STEREO_BOND_NEIGH], at_no_from[MAX_NUM_STEREO_BOND_NEIGH];
 
756
    AT_RANK r, r_sb_neigh;
 
757
 
 
758
    for ( i = 0; i < MAX_NUM_STEREO_BOND_NEIGH; i ++ ) {
 
759
        r_to[i] = r_canon_from[i] = 0;
 
760
    }
 
761
    
 
762
    if ( pEN ) {
 
763
        memset( pEN, 0, sizeof(*pEN));
 
764
    }
 
765
 
 
766
    /*  for debug only */
 
767
    if ( nRankFrom[from_at] != nRankTo[to_at] ||
 
768
         nRankFrom[from_neigh] != nRankTo[to_neigh] ||
 
769
         at[to_at].valence != at[from_at].valence ) {
 
770
        return 0;  /*  program error: both atoms must be mapped */ /*   <BRKPT> */
 
771
    }
 
772
 
 
773
    parity = PARITY_VAL(at[to_at].parity);
 
774
    num_neigh = at[to_at].valence;
 
775
    
 
776
    if ( num_neigh > MAX_NUM_STEREO_BOND_NEIGH || num_neigh < MIN_NUM_STEREO_BOND_NEIGH ) {
 
777
        /*  2 neighbors are possible in case of stereo bond with implicit H */
 
778
        /*  or a stereocenter -CHD- with an implicit H */
 
779
        if ( num_neigh == 1 && at[to_at].stereo_bond_neighbor[0] ) {
 
780
            /*  1 neighbor can happen in case of a terminal =CHD */
 
781
            if ( PARITY_WELL_DEF(parity) )
 
782
                return 2 - parity % 2;
 
783
            else
 
784
            if ( parity )
 
785
                return parity;
 
786
            else
 
787
                return AB_PARITY_UNDF; /*  undefined parity */
 
788
        }
 
789
        return 0;  /*  program error */ /*   <BRKPT> */
 
790
    }
 
791
    if ( ATOM_PARITY_KNOWN(parity) ) {
 
792
        if ( !ATOM_PARITY_WELL_DEF(parity) )
 
793
            return parity;
 
794
    } else
 
795
    if ( parity ) {
 
796
        return 0; /* parity; */
 
797
    } else {
 
798
        return 0; /* AB_PARITY_UNDF; */ /*  possibly program error: undefined parity */
 
799
    }
 
800
    /*  locate at[to_at].stereo_bond_neighbor[] ordering numbers */
 
801
    for ( i = 0, to_sb_neigh_ord=-1; i < MAX_NUM_STEREO_BONDS && (k=(int)at[to_at].stereo_bond_neighbor[i]); i ++ ) {
 
802
        if ( k == to_neigh+1 ) {
 
803
            to_sb_neigh_ord = i;
 
804
            break;
 
805
        }
 
806
    }
 
807
    if ( to_sb_neigh_ord < 0 ) {
 
808
        return 0;  /*  program error: not a stereo bond */ /*   <BRKPT> */
 
809
    }
 
810
    to_sb_neigh_ord = (int)at[to_at].stereo_bond_ord[to_sb_neigh_ord];
 
811
    r_sb_neigh   = nRankTo[(int)at[to_at].neighbor[to_sb_neigh_ord]];
 
812
    for ( i = j = 0; i < num_neigh; i ++ ) {
 
813
        if ( i != to_sb_neigh_ord ) {
 
814
            r_to[j] = nRankTo[(int)(at_no_to[j]=at[to_at].neighbor[i])];
 
815
            if ( r_sb_neigh == r_to[j] ) {
 
816
                return 0; /*  stereo bond atoms are not fully mapped */
 
817
            }
 
818
            j ++;
 
819
        }
 
820
    }
 
821
    if ( j+1 != num_neigh ) {
 
822
        return 0; /*  program error */ /*   <BRKPT> */
 
823
    }
 
824
    if ( j == 1 ) {
 
825
        /*  only one neighbor; no mapping needed */
 
826
        return 2-(parity+1+to_sb_neigh_ord)%2;
 
827
    }
 
828
    if ( j != 2 ) {
 
829
        return 0; /*  program error: j can be only 0, 1, or 2 */ /*   <BRKPT> */
 
830
    }
 
831
    
 
832
    if ( r_to[0] == r_to[1] ) {
 
833
        /*  double bond neighbors need to be mapped */
 
834
        j = 0;
 
835
        from_sb_neigh_ord = -1;
 
836
        for ( i = 0; i < num_neigh; i ++ ) {
 
837
            k = at[from_at].neighbor[i];
 
838
            r = nRankFrom[k];
 
839
            if ( r == r_sb_neigh ) {
 
840
                from_sb_neigh_ord = i;   /*  we need this value only for error-checking */
 
841
            } else
 
842
            if ( r == r_to[0] ) {
 
843
                r_canon_from[j] = nCanonRankFrom[k];
 
844
                at_no_from[j]   = (AT_RANK)k;
 
845
                j ++;
 
846
            } else {
 
847
                return 0; /*  program error: unexpected rank, not fully mapped adjacent to the stereo bond atoms */ /*   <BRKPT> */
 
848
            }
 
849
        }
 
850
        if ( from_sb_neigh_ord < 0 || j != 2 ) {
 
851
            return 0; /*  program error: rank of a neighbor not found */ /*   <BRKPT> */
 
852
        }
 
853
        if ( pEN ) { /*  j == 2 */
 
854
            pEN->to_at[0] = at_no_to[0];
 
855
            pEN->to_at[1] = at_no_to[1];
 
856
            pEN->num_to   = 2;           /*  number of stored in pEN->to_at[] central atom neighbors */
 
857
            pEN->rank     = r_to[0];     /*  mapping rank of the tied neighbors */
 
858
             /*  i := index of the smaller out of r_canon_from[1] and r_canon_from[0] */
 
859
            i = (r_canon_from[1] < r_canon_from[0]);
 
860
            pEN->from_at    = at_no_from[i];
 
861
            pEN->canon_rank = r_canon_from[i];
 
862
        }
 
863
        return -((int)r_to[0]);
 
864
    }
 
865
    /*  double bond neighbors a mapped: r_to[0] != r_to[1] */
 
866
    from_sb_neigh_ord = -1;
 
867
    for ( i = 0; i < num_neigh; i ++ ) {
 
868
        k = at[from_at].neighbor[i];
 
869
        r = nRankFrom[k];
 
870
        if ( r == r_sb_neigh ) {
 
871
            from_sb_neigh_ord = i;  /*  we need this value only for error-checking */
 
872
        } else
 
873
        if ( r == r_to[0] ) {
 
874
            r_canon_from[0] = nCanonRankFrom[k];
 
875
            /* at_no_from[0]   = (AT_RANK)k; */
 
876
        } else
 
877
        if ( r == r_to[1] ) {
 
878
            r_canon_from[1] = nCanonRankFrom[k];
 
879
            /* at_no_from[1]   = (AT_RANK)k; */
 
880
        } else {
 
881
            return 0; /*  program error: unexpected rank, not fully mapped adjacent to the stereo bond atoms */ /*   <BRKPT> */
 
882
        }
 
883
    }
 
884
    if ( !r_canon_from[0] || !r_canon_from[1] || from_sb_neigh_ord < 0 ) {
 
885
        return 0; /*  program error: neighbor rank not found */ /*   <BRKPT> */
 
886
    }
 
887
    return 2 - (parity + to_sb_neigh_ord + (r_canon_from[1]<r_canon_from[0]))%2;
 
888
}
 
889
 
 
890
/**************************************************************************************/
 
891
int parity_of_mapped_atom2( int from_at, int to_at, const sp_ATOM *at, EQ_NEIGH *pEN,
 
892
                           const AT_RANK *nCanonRankFrom, const AT_RANK *nRankFrom, const AT_RANK *nRankTo )
 
893
{
 
894
    AT_RANK nNeighRankFrom[4], nNeighNumberFrom[4], nNeighRankTo[4], nNeighNumberTo[4];
 
895
    AT_RANK nNeighRankFromCanon[4], nNeighRankToCanon[4];
 
896
    int     i, j, k, num_neigh;
 
897
    int     r1, r2, r, r_canon_from_min, neigh_canon_from_min, r_canon_from;
 
898
    int     num_trans_to, num_trans_from, neigh1, neigh2;
 
899
 
 
900
 
 
901
    num_neigh = at[to_at].valence;
 
902
    
 
903
    if ( pEN ) {
 
904
        memset( pEN, 0, sizeof(*pEN));
 
905
    }
 
906
 
 
907
    /*  for debug only */
 
908
    if ( nRankFrom[from_at] != nRankTo[to_at] )
 
909
        return 0;  /*  program error */ /*   <BRKPT> */
 
910
    if ( num_neigh > MAX_NUM_STEREO_ATOM_NEIGH || num_neigh < 2 ) {
 
911
        /*  2 neighbors are possible in case of stereo bond with implicit H */
 
912
        /*  or a stereocenter >CHD with two implicit H */
 
913
        if ( num_neigh == 1 ) {
 
914
            /*  1 neighbor can happen in case of a terminal -CHDT or =CHD */
 
915
            if ( at[to_at].parity )
 
916
                return at[to_at].parity;
 
917
            else
 
918
                return AB_PARITY_UNDF; /*  undefined parity */
 
919
        }
 
920
        return 0;  /*  program error */ /*   <BRKPT> */
 
921
    }
 
922
    for ( i = 0; i < num_neigh; i ++ ) { /*  initialization of locals */
 
923
        nNeighNumberTo[i]      =
 
924
        nNeighNumberFrom[i]    = i;
 
925
        nNeighRankTo[i]        = nRankTo[(int)at[to_at].neighbor[i]];       /* mapping rank */
 
926
        nNeighRankFrom[i]      = nRankFrom[j=(int)at[from_at].neighbor[i]]; /* mapping rank */
 
927
        nNeighRankFromCanon[i] = nCanonRankFrom[j];                     /* canonical number */
 
928
    }
 
929
 
 
930
    pn_RankForSort = nNeighRankFrom;
 
931
    nNumCompNeighborsRanksCountEql = 0; /*  sort mapping ranks-from */
 
932
    num_trans_from = insertions_sort( nNeighNumberFrom, num_neigh, sizeof(nNeighNumberFrom[0]), CompNeighborsRanksCountEql );
 
933
 
 
934
    if ( nNumCompNeighborsRanksCountEql ) {
 
935
        /*  At least 2 neighbors have equal mapping ranks (are tied). */
 
936
        /*  Find tied from-neighbors with minimal canonical rank (nCanonRankFrom[]) */
 
937
        r_canon_from_min = MAX_ATOMS+1; /*  max possible rank + 1 */
 
938
        for ( i = 1, r = 0, r1 = nNeighRankFrom[neigh1=nNeighNumberFrom[0]]; i < num_neigh; i ++, r1 = r2, neigh1 = neigh2 ) {
 
939
            r2 = nNeighRankFrom[neigh2=nNeighNumberFrom[i]];
 
940
            if ( r2 == r1 ) {
 
941
                /*  found neighbors with tied ranks */
 
942
                if ( r != r2 ) {
 
943
                    /*  the 1st pair of neighbor with this rank */
 
944
                    r = r2;
 
945
                    if ( (r_canon_from=nNeighRankFromCanon[neigh1]) < r_canon_from_min ) {
 
946
                        r_canon_from_min     = r_canon_from; /*  min canon rank */
 
947
                        neigh_canon_from_min = neigh1;       /*  neighbor number */
 
948
                    }
 
949
                }
 
950
                if ( (r_canon_from=nNeighRankFromCanon[neigh2]) < r_canon_from_min ) {
 
951
                    r_canon_from_min     = r_canon_from;
 
952
                    neigh_canon_from_min = neigh2;
 
953
                }
 
954
            }
 
955
        }
 
956
        if ( r ) {
 
957
            /*  neighbors with tied ranks have been found => parity cannot be determined without additional mapping */
 
958
            /*  find to-neighbors on which neigh_canon_from_min can be mapped */
 
959
            r1 = nNeighRankFrom[neigh_canon_from_min];
 
960
            if ( pEN ) {
 
961
                for ( i = j = 0; i < num_neigh; i ++ ) {
 
962
                    if ( r1 == nNeighRankTo[i] ) {
 
963
                        pEN->to_at[j++] = at[to_at].neighbor[i];
 
964
                    }
 
965
                }
 
966
                insertions_sort( pEN->to_at, j, sizeof(pEN->to_at[0]), CompRanksInvOrd );
 
967
                pEN->num_to     = j;  /*  number of stored in pEN->to_at[] central atom neighbors */
 
968
                pEN->from_at    = at[from_at].neighbor[neigh_canon_from_min]; /*  neighbor with min. canon number */
 
969
                pEN->rank       = r1; /*  mapping rank of the tied neighbors */
 
970
                pEN->canon_rank = r_canon_from_min;  /*  canon. rank of the pEN->from_at */
 
971
            } else {
 
972
                /*  debug only */
 
973
                for ( i = j = 0; i < num_neigh; i ++ ) {
 
974
                    if ( r1 == nNeighRankTo[i] ) {
 
975
                        j++;
 
976
                    }
 
977
                }
 
978
            }
 
979
            /*  debug only */
 
980
            if ( j <= 1 || !r1 || r_canon_from_min > MAX_ATOMS ) {
 
981
                return 0; /*  program error */ /*   <BRKPT> */
 
982
            }
 
983
            return -r; /*  means parity cannot be determined */
 
984
        }
 
985
        return 0; /* program error */
 
986
    }
 
987
    /*  All neighbors have different mapping ranks; */
 
988
    /*  therefore no additional mapping of the neighbors is necessary */
 
989
    if ( !ATOM_PARITY_WELL_DEF(at[to_at].parity) )
 
990
        return at[to_at].parity; /*  unknown parity or cannot be determined */
 
991
 
 
992
    pn_RankForSort = nNeighRankTo;
 
993
    num_trans_to   = insertions_sort( nNeighNumberTo, num_neigh, sizeof(nNeighNumberTo[0]), CompNeighborsRanksCountEql );
 
994
    
 
995
    /*  Map canonical ranks of neighbors. Mapped on each other "to" and "from" atoms have equal mapping ranks */
 
996
    for ( i = 0; i < num_neigh; i ++ ) {
 
997
        if ( nNeighRankTo[j=nNeighNumberTo[i]] != nNeighRankFrom[k=nNeighNumberFrom[i]] )
 
998
            return 0; /*  program error: mapping ranks not equal, from_at neigborhood cannot be mapped on to_at neighbood. */ /*   <BRKPT> */
 
999
        nNeighRankToCanon[j] = nNeighRankFromCanon[k]; /*  potential problem: other atom(s) may have same mapping rank and */
 
1000
                                                       /*  different canon. rank(s). */
 
1001
        /*  we may save some memory by eliminating nNeighRankFromCanon[]: */
 
1002
        /*  nNeighRankToCanon[j] = nCanonRankFrom[at[from_at].neighbor[k]] */
 
1003
    }
 
1004
 
 
1005
    pn_RankForSort  = nNeighRankToCanon;
 
1006
    num_trans_to   += insertions_sort( nNeighNumberTo, num_neigh, sizeof(nNeighNumberTo[0]), CompNeighborsRanksCountEql );
 
1007
#ifndef CT_NEIGH_INCREASE
 
1008
    num_trans_to   += ((num_neigh*(num_neigh-1))/2)%2;  /*  get correct parity for ascending order of canon. numbers */
 
1009
#endif
 
1010
 
 
1011
    return 2 - (num_trans_to + at[to_at].parity)%2;
 
1012
}
 
1013
 
 
1014
/**************************************************************************************
 
1015
 *
 
1016
 *   Phase II: map canonicaly numbrered structure onto itself
 
1017
 *             to obtain a minimal or maximal stereo part of the CT
 
1018
 *
 
1019
 **************************************************************************************/
 
1020
 
 
1021
int ClearPreviousMappings( AT_RANK **pRankStack1 )
 
1022
{
 
1023
    int i;
 
1024
    for ( i = 0; pRankStack1[i]; i ++ ) {
 
1025
        pRankStack1[i][0] = 0;
 
1026
    }
 
1027
    return i;
 
1028
 
 
1029
}
 
1030
/**************************************************************************************/
 
1031
/*  map one atom ("from") onto another ("to"): untie their mapping ranks if they are tied. */
 
1032
int map_an_atom2( int num_atoms, int num_max, int at_no1/*from*/, int at_no2/*to*/,
 
1033
                AT_RANK *nTempRank,
 
1034
                int nNumMappedRanks, int *pnNewNumMappedRanks,
 
1035
                CANON_STAT *pCS,
 
1036
                NEIGH_LIST    *NeighList,
 
1037
                AT_RANK  **pRankStack1, AT_RANK  **pRankStack2, int *bAddStack )
 
1038
{
 
1039
    AT_RANK *nRank1,  *nAtomNumber1;  /*  ranks for mapping "1", "from" */
 
1040
    AT_RANK *nRank2,  *nAtomNumber2;  /*  ranks for mapping "2", "to" */
 
1041
    AT_RANK *nNewRank1=NULL,  *nNewAtomNumber1=NULL;  /*  ranks for mapping "1", "from" */
 
1042
    AT_RANK *nNewRank2=NULL,  *nNewAtomNumber2=NULL;  /*  ranks for mapping "2", "to" */
 
1043
    int     length = num_max*sizeof(AT_RANK);
 
1044
    int     nNewNumRanks2, nNewNumRanks1;
 
1045
    int     i, bAtFromHasAlreadyBeenMapped, nNumTies;
 
1046
    AT_RANK nNewRank;
 
1047
 
 
1048
    nNumTies = NumberOfTies( pRankStack1, pRankStack2, length, at_no1, at_no2, &nNewRank, bAddStack, &bAtFromHasAlreadyBeenMapped );
 
1049
    
 
1050
    if ( RETURNED_ERROR(nNumTies) )
 
1051
        return nNumTies;  /*  error */
 
1052
 
 
1053
    nRank1       = *pRankStack1++;
 
1054
    nAtomNumber1 = *pRankStack1++;  /*  ranks for mapping "1", "from" */
 
1055
 
 
1056
    nRank2       = *pRankStack2++;
 
1057
    nAtomNumber2 = *pRankStack2++;  /*  ranks for mapping "2", "to" */
 
1058
    
 
1059
    if ( nNumTies > 1 ) {
 
1060
 
 
1061
        nNewRank1       = *pRankStack1++;
 
1062
        nNewAtomNumber1 = *pRankStack1++;  /*  ranks for mapping "1", "from" */
 
1063
 
 
1064
        nNewRank2       = *pRankStack2++;
 
1065
        nNewAtomNumber2 = *pRankStack2++;  /*  ranks for mapping "2", "to" */
 
1066
        /*  break a tie for "to" */
 
1067
        memcpy( nNewRank2, nRank2, length );
 
1068
        memcpy( nNewAtomNumber2, nAtomNumber2, length );
 
1069
        nNewRank2[at_no2] = nNewRank;
 
1070
        nNewNumRanks2 = DifferentiateRanks2( num_atoms, NeighList,
 
1071
                                         nNumMappedRanks, nNewRank2, nTempRank,
 
1072
                                         nNewAtomNumber2, &pCS->lNumNeighListIter, 1 );
 
1073
        pCS->lNumBreakTies ++;
 
1074
 
 
1075
        /*  Check whether the old mapping can be reused */
 
1076
        if ( 2 == bAtFromHasAlreadyBeenMapped && nNewRank == nNewRank1[at_no1] ) {
 
1077
            for ( i = 0; i < num_atoms; i ++ ) {
 
1078
                if ( nNewRank1[nNewAtomNumber1[i]] != nNewRank2[nNewAtomNumber2[i]] ) {
 
1079
                    bAtFromHasAlreadyBeenMapped = 0; /*  It cannot. */
 
1080
                    break;
 
1081
                }
 
1082
            }
 
1083
        } else {
 
1084
            bAtFromHasAlreadyBeenMapped = 0;
 
1085
        }
 
1086
        if ( 2 != bAtFromHasAlreadyBeenMapped ) {
 
1087
            /*  break a tie for "from" */
 
1088
            for ( i = 0; pRankStack1[i]; i ++ ) {
 
1089
                pRankStack1[i][0] = 0;
 
1090
            }
 
1091
            memcpy( nNewRank1, nRank1, length );
 
1092
            memcpy( nNewAtomNumber1, nAtomNumber1, length );  /* GPF: bad nAtomNumber1 */
 
1093
            nNewRank1[at_no1] = nNewRank;
 
1094
            nNewNumRanks1 = DifferentiateRanks2( num_atoms, NeighList,
 
1095
                                             nNumMappedRanks, nNewRank1, nTempRank,
 
1096
                                             nNewAtomNumber1, &pCS->lNumNeighListIter, 1 );
 
1097
            pCS->lNumBreakTies ++;
 
1098
        } else {
 
1099
            nNewNumRanks1 = nNewNumRanks2;
 
1100
        }
 
1101
 
 
1102
        if ( nNewNumRanks1 != nNewNumRanks2 )
 
1103
            return CT_MAPCOUNT_ERR; /*  program error */ /*   <BRKPT> */
 
1104
        *pnNewNumMappedRanks = nNewNumRanks2;
 
1105
        /*  debug only */
 
1106
        for ( i = 0; i < num_atoms; i ++ ) {
 
1107
            if ( nNewRank1[nNewAtomNumber1[i]] != nNewRank2[nNewAtomNumber2[i]] ) {
 
1108
                return CT_MAPCOUNT_ERR; /*  program error */ /*   <BRKPT> */
 
1109
            }
 
1110
        }
 
1111
    } else {
 
1112
        *pnNewNumMappedRanks = nNumMappedRanks;
 
1113
    }
 
1114
    return ( nNewRank1 )? nNewRank1[at_no1] : nRank1[at_no1]; /*  mapping rank value */
 
1115
}
 
1116
 
 
1117
/**************************************************************************************/
 
1118
int might_change_other_atom_parity( sp_ATOM *at, int num_atoms, int at_no, AT_RANK *nRank2, AT_RANK *nRank1 )
 
1119
{
 
1120
    int     i, j, neighbor_no;
 
1121
    for ( i = 0; i < num_atoms; i ++ ) {
 
1122
        if ( nRank2[i] != nRank1[i] ) {
 
1123
            if ( i != at_no /*&& ATOM_PARITY_WELL_DEF(at[i].parity)*/
 
1124
                && at[i].bHasStereoOrEquToStereo
 
1125
                && !(at[i].stereo_atom_parity & KNOWN_PARITIES_EQL )
 
1126
                && !at[i].stereo_bond_neighbor[0]
 
1127
                ) {
 
1128
 
 
1129
                return 1; /*  may have changed stereo atoms order */
 
1130
            }
 
1131
            for ( j = 0; j < at[i].valence; j ++ ) {
 
1132
                neighbor_no = at[i].neighbor[j];
 
1133
                if ( neighbor_no != at_no
 
1134
                     /*&& ATOM_PARITY_WELL_DEF(at[neighbor_no].parity)*/ 
 
1135
                     && at[neighbor_no].bHasStereoOrEquToStereo
 
1136
                     && !(at[neighbor_no].stereo_atom_parity & KNOWN_PARITIES_EQL )
 
1137
                     && !at[neighbor_no].stereo_bond_neighbor[0]
 
1138
                   )
 
1139
                    return 1; /*  may have changed stereo atom parity */
 
1140
            }
 
1141
        }
 
1142
    }
 
1143
    return 0;
 
1144
}
 
1145
/**************************************************************************************/
 
1146
#if ( REMOVE_CALC_NONSTEREO == 1 ) /* { */
 
1147
/**************************************************************************************/
 
1148
void DeAllocateForNonStereoRemoval( AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
 
1149
                                    NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 )
 
1150
{
 
1151
    if ( *nAtomNumberCanon1 ) {
 
1152
        inchi_free( *nAtomNumberCanon1 );
 
1153
        *nAtomNumberCanon1 = NULL;
 
1154
    }
 
1155
    if ( *nAtomNumberCanon2 ) {
 
1156
        inchi_free( *nAtomNumberCanon2 );
 
1157
        *nAtomNumberCanon2 = NULL;
 
1158
    }
 
1159
    if ( *nl ) {
 
1160
        FreeNeighList( *nl );
 
1161
        *nl = 0;
 
1162
    }
 
1163
    if ( *nl1 ) {
 
1164
        FreeNeighList( *nl1 );
 
1165
        *nl1 = 0;
 
1166
    }
 
1167
    if ( *nl2 ) {
 
1168
        FreeNeighList( *nl2 );
 
1169
        *nl2 = 0;
 
1170
    }
 
1171
    if ( *nVisited1 ) {
 
1172
        inchi_free( *nVisited1 );
 
1173
        *nVisited1 = NULL;
 
1174
    }
 
1175
    if ( *nVisited2 ) {
 
1176
        inchi_free( *nVisited2 );
 
1177
        *nVisited2 = NULL;
 
1178
    }
 
1179
 
 
1180
}
 
1181
/**************************************************************************************/
 
1182
int AllocateForNonStereoRemoval( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank, AT_RANK *nCanonRank,
 
1183
                            AT_RANK **nAtomNumberCanon1, AT_RANK **nAtomNumberCanon2,
 
1184
                            NEIGH_LIST **nl, NEIGH_LIST **nl1, NEIGH_LIST **nl2, AT_RANK **nVisited1, AT_RANK **nVisited2 )
 
1185
{
 
1186
    DeAllocateForNonStereoRemoval( nAtomNumberCanon1, nAtomNumberCanon2, nl, nl1, nl2, nVisited1, nVisited2 );
 
1187
    *nAtomNumberCanon1 = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nAtomNumberCanon1) );
 
1188
    *nAtomNumberCanon2 = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nAtomNumberCanon2) );
 
1189
    *nl                = CreateNeighList( num_atoms, num_atoms, at, 0, NULL );
 
1190
    *nl1               = CreateNeighList( num_atoms, num_atoms, at, 0, NULL );
 
1191
    *nl2               = CreateNeighList( num_atoms, num_atoms, at, 0, NULL );
 
1192
    *nVisited1         = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nVisited1) );
 
1193
    *nVisited2         = (AT_RANK *) inchi_malloc( num_atoms * sizeof(**nVisited2) );
 
1194
 
 
1195
    if ( !*nl || !*nl1 || !*nl2 || !*nVisited1 || !*nVisited2 || !*nAtomNumberCanon1 || !*nAtomNumberCanon2 ) {
 
1196
        DeAllocateForNonStereoRemoval( nAtomNumberCanon1, nAtomNumberCanon2, nl, nl1, nl2, nVisited1, nVisited2 );
 
1197
        return 0;
 
1198
    }
 
1199
    /*  Sort neighbors according to symm. ranks (primary key) and canon. ranks (secondary key), in descending order */
 
1200
    SortNeighListsBySymmAndCanonRank( num_atoms, *nl,  nSymmRank, nCanonRank );
 
1201
    SortNeighListsBySymmAndCanonRank( num_atoms, *nl1, nSymmRank, nCanonRank );
 
1202
    SortNeighListsBySymmAndCanonRank( num_atoms, *nl2, nSymmRank, nCanonRank );
 
1203
    return 1;
 
1204
}
 
1205
/**************************************************************************************/
 
1206
AT_RANK GetMinNewRank(AT_RANK *nAtomRank, AT_RANK *nAtomNumb, AT_RANK nRank1 )
 
1207
{
 
1208
    int i;
 
1209
    AT_RANK nRank2;
 
1210
    for ( i = (int)nRank1-1; 0 <= i && nRank1 == (nRank2 = nAtomRank[(int)nAtomNumb[i]]); i -- )
 
1211
        ;
 
1212
    if ( i >= 0 )
 
1213
        nRank2 ++;
 
1214
    else
 
1215
        nRank2 = 1;
 
1216
    return nRank2;
 
1217
}
 
1218
/**************************************************************************************/
 
1219
int BreakNeighborsTie(  sp_ATOM *at, int num_atoms, int num_at_tg, int ib, int ia,
 
1220
                        AT_RANK *neigh_num, int in1, int in2, int mode,
 
1221
                        AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
1222
                        const AT_RANK *nSymmRank, AT_RANK *nCanonRank, NEIGH_LIST *nl1, NEIGH_LIST *nl2, long *lNumIter )
 
1223
{
 
1224
    AT_RANK nRank1, nRank2;
 
1225
    int     nNumDiffRanks, nNumDiffRanks1, nNumDiffRanks2, i;
 
1226
    int n1  = (int)neigh_num[in1];
 
1227
    int n2  = (int)neigh_num[in2];
 
1228
    int other_neigh[2], other_neig_ord[2], num_other_neigh;
 
1229
    /*  asymmetric calculation */
 
1230
 
 
1231
    if ( mode == MAP_MODE_S4  && in1 || /* for S4 we need only (in1,in2) = (0,1) (0,2) (0,3) pairs of neighbors */
 
1232
         mode != MAP_MODE_STD && at[ia].valence != MAX_NUM_STEREO_ATOM_NEIGH ||
 
1233
         mode != MAP_MODE_STD && nSymmRank[n1]  != nSymmRank[n2] ) {
 
1234
        return 0;
 
1235
    }
 
1236
    /*  1. Create initial ranks from equivalence information stored in nSymmRank */
 
1237
    memcpy( pRankStack1[0], nSymmRank, num_at_tg * sizeof(pRankStack1[0][0]) );
 
1238
    pn_RankForSort = pRankStack1[0];
 
1239
    tsort( pRankStack1[1], num_at_tg, sizeof(pRankStack1[1][0]), CompRanksOrd );
 
1240
    nNumDiffRanks = SortedEquInfoToRanks( pRankStack1[0]/*inp*/, pRankStack1[0]/*out*/, pRankStack1[1], num_at_tg, NULL );
 
1241
    
 
1242
    /* other neighbors */
 
1243
    num_other_neigh = 0;
 
1244
    if ( at[ia].valence <= MAX_NUM_STEREO_ATOM_NEIGH && mode ) {
 
1245
        for ( i = 0; i < at[ia].valence; i ++ ) {
 
1246
            if ( i != in1 && i != in2 ) {
 
1247
                other_neigh[num_other_neigh]    = (int)neigh_num[i];
 
1248
                other_neig_ord[num_other_neigh] = i;
 
1249
                num_other_neigh ++;
 
1250
            }
 
1251
        }
 
1252
    }
 
1253
    if ( mode != MAP_MODE_STD && nSymmRank[other_neigh[0]] != nSymmRank[other_neigh[1]] ||
 
1254
         mode == MAP_MODE_S4  && nSymmRank[n1]             != nSymmRank[other_neigh[1]] ) {
 
1255
        return 0;
 
1256
    }
 
1257
 
 
1258
    /*  2. Fix at[ia] */
 
1259
    if ( pRankStack1[0][ia] != nSymmRank[ia] ) {
 
1260
        /*  at[ia] is constitutionally equivalent to some other atom. Fix at[ia]. */
 
1261
        pRankStack1[0][ia] = nSymmRank[ia];
 
1262
        nNumDiffRanks = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1263
                                     nNumDiffRanks, pRankStack1[0], nTempRank,
 
1264
                                     pRankStack1[1], lNumIter, 1 );
 
1265
    }
 
1266
    /*  3. In case of a double bond/cumulene only: */
 
1267
    /*     fix at[ib] -- the opposite double bond/cumulene atom */
 
1268
    if ( ib < num_atoms ) {
 
1269
        /*  find the smallest possible rank */
 
1270
        nRank1 = pRankStack1[0][ib];
 
1271
        nRank2 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank1 );
 
1272
        /*  if the rank is smaller than pRankStack1[0][ib] then fix at[ib] */
 
1273
        if ( nRank2 != nRank1 ) {
 
1274
            pRankStack1[0][ib] = nRank2;
 
1275
            nNumDiffRanks = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1276
                                         nNumDiffRanks, pRankStack1[0], nTempRank,
 
1277
                                         pRankStack1[1], lNumIter, 1 );
 
1278
        }
 
1279
    }
 
1280
    
 
1281
    /**************************************************************************************
 
1282
     * Note: It may (or may not?) make sense to fix "other neighbors":
 
1283
     *       in case of a stereo center fix neighbors other than n1, n2
 
1284
     *       in case of a double bond/cumulene fix the opposite atom neighbors
 
1285
     *       The ranks assigned to the other neighbors in case of their equivalence
 
1286
     *       should be in the ascending order of their canonical ranks ????
 
1287
     *       *** For now we do not fix other neighbors ***
 
1288
     **************************************************************************************/
 
1289
 
 
1290
    /*  4. Check whether the neighbors still have equal ranks */
 
1291
    if ( pRankStack1[0][n1] != pRankStack1[0][n2] ) {
 
1292
        return 0; /*  the two neighbors are not constitutionally equivalent */
 
1293
    }
 
1294
    /*  5. Find new smallest possible rank for n1 and n2 */
 
1295
    nRank1 = pRankStack1[0][n1];
 
1296
    nRank2 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank1 );
 
1297
 
 
1298
    /*  6. Copy the results to the 2nd eq. rank arrays */
 
1299
    memcpy( pRankStack2[0], pRankStack1[0], num_at_tg * sizeof(pRankStack2[0][0]) );
 
1300
    memcpy( pRankStack2[1], pRankStack1[1], num_at_tg * sizeof(pRankStack2[0][0]) );
 
1301
 
 
1302
    /*  7. Break neighbor tie: map n1(1) <--> n2(2) */
 
1303
    pRankStack1[0][n1] = nRank2;
 
1304
    nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1305
                                 nNumDiffRanks, pRankStack1[0], nTempRank,
 
1306
                                 pRankStack1[1], lNumIter, 1 );
 
1307
    
 
1308
    pRankStack2[0][n2] = nRank2;
 
1309
    nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1310
                                 nNumDiffRanks, pRankStack2[0], nTempRank,
 
1311
                                 pRankStack2[1], lNumIter, 1 );
 
1312
 
 
1313
    if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
 
1314
        return -1; /*  <BRKPT> */
 
1315
    }
 
1316
    if ( mode == MAP_MODE_C2v || mode == MAP_MODE_C2 ) {
 
1317
        /* Check for C2v reflection leading to parity inversion (mode=1) or C2 rotation (mode=2) */
 
1318
        AT_RANK nRank10, nRank20;
 
1319
        int     nn1, nn2;
 
1320
        /*
 
1321
         * C2v & C2: map
 
1322
         * n1(1) <--> n2(2) -- at this point already done
 
1323
         * n1(2) <--> n2(1) --> do at i = 0
 
1324
         *
 
1325
         * C2v: other neighbors must be unmoved: map
 
1326
         * other_neigh[0](1) <--> other_neigh[0](2)
 
1327
         * other_neigh[1](1) <--> other_neigh[1](2)
 
1328
         *
 
1329
         * C2:  other neighbors should be mapped on each other
 
1330
         * other_neigh[0](1) <--> other_neigh[1](2)
 
1331
         * other_neigh[1](1) <--> other_neigh[0](2)
 
1332
         */
 
1333
        for ( i = 0; i <= 2; i ++ ) {
 
1334
            if ( i == 0 ) {
 
1335
                /* C2v & C2. Map n2(1) <--> n1(2) */
 
1336
                nn1     = n2;
 
1337
                nn2     = n1;
 
1338
            } else
 
1339
            if ( mode == MAP_MODE_C2v ) {   /* was '=', pointed by WDI */
 
1340
                /* i = 1 or 2
 
1341
                 * C2v. Other neighbors must be unmoved: map
 
1342
                 * i=1: other_neigh[0](1) <--> other_neigh[0](2)
 
1343
                 * i=2: other_neigh[1](1) <--> other_neigh[1](2)
 
1344
                 */
 
1345
                nn1 = other_neigh[i-1]; /* 0 or 1 */
 
1346
                nn2 = other_neigh[i-1]; /* 0 or 1 */
 
1347
            } else
 
1348
            if ( mode == MAP_MODE_C2 ) {  /* was '=', pointed by WDI */
 
1349
                /* i = 1 or 2
 
1350
                 * C2.  Other neighbors should be mapped on each other
 
1351
                 * i=1: other_neigh[0](1) <--> other_neigh[1](2)
 
1352
                 * i=2: other_neigh[1](1) <--> other_neigh[0](2)
 
1353
                 */
 
1354
                nn1 = other_neigh[i-1]; /* 0 or 1 */
 
1355
                nn2 = other_neigh[2-i]; /* 1 or 0 */
 
1356
            } else {
 
1357
                return -1; /* program error */
 
1358
            }
 
1359
            /* map nn1(1) <--> nn2(2) */
 
1360
            nRank10 = pRankStack1[0][nn1];
 
1361
            nRank20 = pRankStack2[0][nn2];
 
1362
            nRank1 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank10 );
 
1363
            nRank2 = GetMinNewRank(pRankStack2[0], pRankStack2[1], nRank20 );
 
1364
            if ( nRank10 == nRank20 && nRank1 == nRank2 ) {
 
1365
                if ( nRank10 == nRank1 ) {
 
1366
                    ;/* atoms are already mapped */
 
1367
                } else {
 
1368
                    /* need additional mapping: ranks are not fixed yet */
 
1369
                    pRankStack1[0][nn1] = nRank1;
 
1370
                    nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1371
                                                 nNumDiffRanks, pRankStack1[0], nTempRank,
 
1372
                                                 pRankStack1[1], lNumIter, 1 );
 
1373
                    pRankStack2[0][nn2] = nRank2;
 
1374
                    nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1375
                                                 nNumDiffRanks, pRankStack2[0], nTempRank,
 
1376
                                                 pRankStack2[1], lNumIter, 1 );
 
1377
                    if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
 
1378
                        return -1; /*  <BRKPT> */
 
1379
                    }
 
1380
                }
 
1381
            } else {
 
1382
                return 0;  /* mapping is not possible */
 
1383
            }
 
1384
        }
 
1385
    }
 
1386
    if ( mode == MAP_MODE_S4 ) {
 
1387
        /* 
 
1388
         *  Check for S4 reflection/rotation leading to parity inversion (mode=3)
 
1389
         *
 
1390
         * At this point n1(1) <--> n2(2) have been mapped and n1 has index in1 = 0
 
1391
         * Below indexes in neigh_num[] are in brackets; [i] means neigh_num[i].
 
1392
         * Numbers (#) in parentheses refer to pRankStack#
 
1393
         *
 
1394
         * in2=1: [0](1) <--> [1](2)  mapping has been done; add more mappings:
 
1395
         *        [1](1) <--> [2](2)  [x]=[2]
 
1396
         *        [2](1) <--> [3](2)  [y]=[3]
 
1397
         *        [3](1) <--> [0](2)
 
1398
         *        this will succeed if C2 axis crosses middle of [0]-[2] and [1]-[3] lines 
 
1399
         *
 
1400
         * in2=2: [0](1) <--> [2](2) mapping has been done; add more mappings:
 
1401
         *        [2](1) <--> [3](2)  [x]=[3]
 
1402
         *        [3](1) <--> [1](2)  [y]=[1]
 
1403
         *        [1](1) <--> [0](2)
 
1404
         *        this will succeed if C2 axis crosses middle of [0]-[3] and [1]-[2] lines
 
1405
         *
 
1406
         * in2=3: [0](1) <--> [3](2) mapping has been done; add more mappings:
 
1407
         *        [3](1) <--> [1](2)  [x]=[1]
 
1408
         *        [1](1) <--> [2](2)  [y]=[2]
 
1409
         *        [2](1) <--> [0](2)
 
1410
         *        this will succeed if C2 axis crosses middle of [0]-[1] and [2]-[3] lines
 
1411
         *
 
1412
         * In general:
 
1413
         *        [in1](1) <--> [in2](2)
 
1414
         *        [in2](1) <--> [x]  (2)  i=0
 
1415
         *        [x]  (1) <--> [y]  (2)  i=1
 
1416
         *        [y]  (1) <--> [in1](2)  i=2
 
1417
         *
 
1418
         *    in1=0    always
 
1419
         *    ===== how to find x, y from in2 ====
 
1420
         *    in2=1 => x,y = 2, 3  or [x] = other_neigh[0], [y] = other_neigh[1] 
 
1421
         *    in2=2 => x,y = 3, 1  or [x] = other_neigh[1], [y] = other_neigh[0]
 
1422
         *    in2=3 => x,y = 1, 2  or [x] = other_neigh[0], [y] = other_neigh[1]
 
1423
         *    ====================================
 
1424
         */
 
1425
        AT_RANK nRank10, nRank20;
 
1426
        int     nn1, nn2;
 
1427
        for ( i = 0; i <= 2; i ++ ) {
 
1428
            switch( i ) {
 
1429
            case 0:  /* [in2](1) <--> [x](2);  */
 
1430
                nn1 = n2;                    /* [in2] */
 
1431
                nn2 = other_neigh[1-in2%2];  /* [x]   */
 
1432
                break;
 
1433
            case 1:  /* [x](1) <--> [y](2) */
 
1434
                nn1 = other_neigh[1-in2%2];  /* [x]   */
 
1435
                nn2 = other_neigh[  in2%2];  /* [y]   */
 
1436
                break;
 
1437
            case 2:
 
1438
                nn1 = other_neigh[  in2%2];  /* [y]   */
 
1439
                nn2 = n1;                    /* [in1] */
 
1440
                break;
 
1441
            default:
 
1442
                return -1; /* program error */
 
1443
            }
 
1444
            /* map nn1(1) <--> nn2(2) */
 
1445
            nRank10 = pRankStack1[0][nn1];
 
1446
            nRank20 = pRankStack2[0][nn2];
 
1447
            nRank1 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank10 );
 
1448
            nRank2 = GetMinNewRank(pRankStack2[0], pRankStack2[1], nRank20 );
 
1449
            if ( nRank10 == nRank20 && nRank1 == nRank2 ) {
 
1450
                if ( nRank10 == nRank1 ) {
 
1451
                    ;/* atoms are already mapped */
 
1452
                } else {
 
1453
                    /* need additional mapping: ranks are not fixed yet */
 
1454
                    pRankStack1[0][nn1] = nRank1;
 
1455
                    nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1456
                                                 nNumDiffRanks, pRankStack1[0], nTempRank,
 
1457
                                                 pRankStack1[1], lNumIter, 1 );
 
1458
                    pRankStack2[0][nn2] = nRank2;
 
1459
                    nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1460
                                                 nNumDiffRanks, pRankStack2[0], nTempRank,
 
1461
                                                 pRankStack2[1], lNumIter, 1 );
 
1462
                    if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
 
1463
                        return -1; /*  <BRKPT> */
 
1464
                    }
 
1465
                }
 
1466
            } else {
 
1467
                return 0;  /* mapping is not possible */
 
1468
            }
 
1469
        }
 
1470
    }
 
1471
 
 
1472
 
 
1473
 
 
1474
#if ( BREAK_ONE_MORE_SC_TIE == 1 ) /* { */
 
1475
    /* Check for a very highly symmetrical stereo center 12-06-2002 */
 
1476
    if ( ib >= num_atoms && at[ia].valence == MAX_NUM_STEREO_ATOM_NEIGH ) {
 
1477
        int num_eq;
 
1478
        nRank1 = pRankStack1[0][n2];
 
1479
        for ( i = 0, num_eq = 0; i < at[ia].valence; i ++ ) {
 
1480
            num_eq += ( nRank1 == pRankStack1[0][at[ia].neighbor[i]]);
 
1481
        }
 
1482
        if ( num_eq == MAX_NUM_STEREO_ATOM_NEIGH-1 ) {
 
1483
            for ( i = (int)nRank1-1; 0 <= i && nRank1 == (nRank2 = pRankStack1[0][(int)pRankStack1[1][i]]); i -- )
 
1484
                ;
 
1485
            if ( i >= 0 )
 
1486
                nRank2 ++;
 
1487
            else
 
1488
                nRank2 = 1;
 
1489
 
 
1490
            /*  7a. Break another neighbor tie */
 
1491
 
 
1492
            nNumDiffRanks = nNumDiffRanks1;
 
1493
 
 
1494
            pRankStack1[0][n2] = nRank2;
 
1495
            nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1496
                                         nNumDiffRanks, pRankStack1[0], nTempRank,
 
1497
                                         pRankStack1[1], lNumIter, 1 );
 
1498
    
 
1499
            pRankStack2[0][n1] = nRank2;
 
1500
            nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1501
                                         nNumDiffRanks, pRankStack2[0], nTempRank,
 
1502
                                         pRankStack2[1], lNumIter, 1 );
 
1503
        }
 
1504
    }
 
1505
 
 
1506
    if ( nNumDiffRanks1 != nNumDiffRanks2 ) {
 
1507
        return -1; /*  <BRKPT> */
 
1508
    }
 
1509
#endif /* } BREAK_ONE_MORE_SC_TIE */
 
1510
 
 
1511
#if ( BREAK_ALSO_NEIGH_TIE == 1 )
 
1512
    /* check whether neighbor's neighbors are tied and untie them */
 
1513
    if ( at[n1].nRingSystem == at[n2].nRingSystem &&  ib >= num_atoms ) {
 
1514
        AT_RANK NeighNeighList[MAX_NUM_STEREO_ATOM_NEIGH+1];
 
1515
        int m, neigh1=-1, neigh2=-1;
 
1516
        nRank1 = nRank2 = 0;
 
1517
        /* n1 */
 
1518
        NeighNeighList[0] = at[n1].valence-1; /* for insertions_sort_NeighListBySymmAndCanonRank() */
 
1519
        for ( i = 0, m = 1; i < at[n1].valence; i ++ ) {
 
1520
            int neigh = at[n1].neighbor[i];
 
1521
            if ( neigh != ia ) {
 
1522
                NeighNeighList[m ++] = neigh;
 
1523
            }
 
1524
        }
 
1525
        insertions_sort_NeighListBySymmAndCanonRank( NeighNeighList, pRankStack1[0], nCanonRank );
 
1526
        for ( m = 2; m < at[n1].valence; m ++ ) {
 
1527
            if ( pRankStack1[0][NeighNeighList[m]] == pRankStack1[0][NeighNeighList[m-1]] ) {
 
1528
                neigh1 = NeighNeighList[m-1];
 
1529
                break;
 
1530
            }
 
1531
        }
 
1532
        /* n2 */
 
1533
        NeighNeighList[0] = at[n2].valence-1; /* for insertions_sort_NeighListBySymmAndCanonRank() */
 
1534
        for ( i = 0, m = 1; i < at[n2].valence; i ++ ) {
 
1535
            int neigh = at[n2].neighbor[i];
 
1536
            if ( neigh != ia ) {
 
1537
                NeighNeighList[m ++] = neigh;
 
1538
            }
 
1539
        }
 
1540
        insertions_sort_NeighListBySymmAndCanonRank( NeighNeighList, pRankStack2[0], nCanonRank );
 
1541
        for ( m = 2; m < at[n2].valence; m ++ ) {
 
1542
            if ( pRankStack2[0][NeighNeighList[m]] == pRankStack2[0][NeighNeighList[m-1]] ) {
 
1543
#if ( BREAK_ALSO_NEIGH_TIE_ROTATE == 1 )
 
1544
                neigh2 = NeighNeighList[m];    /* [m] to obtain same axis orientation  around ia<neigh */
 
1545
#else
 
1546
                neigh2 = NeighNeighList[m-1];  /* [m-1] to obtain reflection ??? */
 
1547
#endif
 
1548
                break;
 
1549
            }
 
1550
        }
 
1551
        if ( neigh1 >= 0 && neigh2 >= 0 && pRankStack1[0][neigh1] == pRankStack2[0][neigh2] ) {
 
1552
            /* neighbors' neighbors are tied */
 
1553
            nRank1 = pRankStack1[0][neigh1];
 
1554
            nRank2 = GetMinNewRank(pRankStack1[0], pRankStack1[1], nRank1 );
 
1555
 
 
1556
            /*  Break neighbor's neighbor tie */
 
1557
 
 
1558
            nNumDiffRanks = nNumDiffRanks1;
 
1559
 
 
1560
            pRankStack1[0][neigh1] = nRank2;
 
1561
            nNumDiffRanks1 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1562
                                         nNumDiffRanks, pRankStack1[0], nTempRank,
 
1563
                                         pRankStack1[1], lNumIter, 1 );
 
1564
 
 
1565
            pRankStack2[0][neigh2] = nRank2;
 
1566
            nNumDiffRanks2 = DifferentiateRanksBasic( num_at_tg, NeighList,
 
1567
                                         nNumDiffRanks, pRankStack2[0], nTempRank,
 
1568
                                         pRankStack2[1], lNumIter, 1 );
 
1569
        }
 
1570
    }
 
1571
#endif
 
1572
 
 
1573
 
 
1574
    /*  for debug only */
 
1575
    for ( i = 0; i < num_at_tg; i ++ ) {
 
1576
        if ( pRankStack1[0][(int)pRankStack1[1][i]] != pRankStack2[0][(int)pRankStack2[1][i]] ) {
 
1577
            return -1;  /*  <BRKPT> */
 
1578
        }
 
1579
    }
 
1580
    /*  Resort lists of  neighbors */
 
1581
    SortNeighListsBySymmAndCanonRank( num_atoms, nl1,  pRankStack1[0], nCanonRank );
 
1582
    SortNeighListsBySymmAndCanonRank( num_atoms, nl2,  pRankStack2[0], nCanonRank );
 
1583
 
 
1584
    return nNumDiffRanks1+1;
 
1585
}
 
1586
 
 
1587
/**************************************************************************************/
 
1588
int CheckNextSymmNeighborsAndBonds( sp_ATOM *at, AT_RANK cur1, AT_RANK cur2, AT_RANK n1, AT_RANK n2,
 
1589
                                    AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
 
1590
                                    AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2, const AT_RANK *nRank1, const AT_RANK *nRank2 )
 
1591
{
 
1592
    AT_RANK s1, s2;
 
1593
    int     i1, i2, k1, k2;
 
1594
    if ( nRank1[n1] != nRank2[n2] ) {
 
1595
        return -1; /*  parallel traversal in stereo removal failed */ /*   <BRKPT> */
 
1596
    }
 
1597
    switch ( !nVisited1[n1] + !nVisited2[n2] ) {
 
1598
    case 0:
 
1599
        if ( nVisited1[n1] != n2+1 || nVisited2[n2] != n1+1 ) {
 
1600
            return -1; /*  0; */ /*  possibly error???: we have come to an alreardy traversed pair and */
 
1601
                       /*  found that the pair previously has not been traversed synchroneously. */
 
1602
        }              /*  -- Happens in C60. */
 
1603
        break;
 
1604
    case 1:
 
1605
        return -1; /*  0; */ /*  possibly error: one is zero, another is not a zero. Happens in C60 */
 
1606
 
 
1607
    /*  case 2: */
 
1608
        /* both are zero, OK. */
 
1609
    }
 
1610
    
 
1611
    if ( nVisitOrd1[n1] != nVisitOrd2[n2] ) {
 
1612
        return -1; /*  0; */ /*  different DFS trees */
 
1613
    }
 
1614
    /*  at[n1] and at[n2] are next to at[cur1] and at[cur2] respectively */
 
1615
    /*  Even though the bond might have already been checked, check whether */
 
1616
    /*  it is a stereo bond/cumulene. If it is, check the bond/cumulene parity. */
 
1617
 
 
1618
    /*  Even though the bond or cumulene might have already been checked, check it: this is */
 
1619
    /*  the only place we can check stereo bonds and cumulenes that are not edges of the DFS tree */
 
1620
    /*  The code works both for a stereo bond and a stereogenic cumulene. */
 
1621
 
 
1622
    for ( i1 = 0, k1 = 0; i1 < MAX_NUM_STEREO_BONDS &&
 
1623
                          (s1=at[cur1].stereo_bond_neighbor[i1]) &&
 
1624
                         !(k1=(at[cur1].neighbor[(int)at[cur1].stereo_bond_ord[i1]] == n1)); i1 ++ )
 
1625
        ;
 
1626
    for ( i2 = 0, k2 = 0; i2 < MAX_NUM_STEREO_BONDS &&
 
1627
                          (s2=at[cur2].stereo_bond_neighbor[i2]) &&
 
1628
                         !(k2=(at[cur2].neighbor[(int)at[cur2].stereo_bond_ord[i2]] == n2)); i2 ++ )
 
1629
        ;
 
1630
 
 
1631
    /* -- this does not work in case of cumulenes --
 
1632
    for ( i1 = 0, k1 = 0; i1 < MAX_NUM_STEREO_BONDS && (s1=at[cur1].stereo_bond_neighbor[i1]) && !(k1=(s1-1 == n1)); i1 ++ )
 
1633
        ;
 
1634
    for ( i2 = 0, k2 = 0; i2 < MAX_NUM_STEREO_BONDS && (s2=at[cur2].stereo_bond_neighbor[i2]) && !(k2=(s2-1 == n2)); i2 ++ )
 
1635
        ;
 
1636
    */
 
1637
 
 
1638
    if ( k1 != k2 ) {    
 
1639
        return 0; /*  not an error: a stereo bond and not a stereo bond */
 
1640
    }
 
1641
    if ( k1 ) {
 
1642
        /* here k1 == k2 */
 
1643
        int bCheckBond1, bCheckBond2;
 
1644
        s1 --;
 
1645
        s2 --;
 
1646
 
 
1647
        bCheckBond1 = (cur1 != nAvoidCheckAtom[0] || s1 != nAvoidCheckAtom[1]) &&
 
1648
                      (cur1 != nAvoidCheckAtom[1] || s1 != nAvoidCheckAtom[0]);
 
1649
        bCheckBond2 = (cur2 != nAvoidCheckAtom[0] || s2 != nAvoidCheckAtom[1]) &&
 
1650
                      (cur2 != nAvoidCheckAtom[1] || s2 != nAvoidCheckAtom[0]);
 
1651
        
 
1652
        if ( bCheckBond1 != bCheckBond2 )
 
1653
            return 0;
 
1654
        
 
1655
        if ( !bCheckBond1 && !bCheckBond2 ) {
 
1656
            return 1; /*  do not go any further in this direction */
 
1657
        }
 
1658
 
 
1659
        if ( at[cur1].stereo_bond_parity[i1] != at[cur2].stereo_bond_parity[i2] ) {
 
1660
            /*  different values of  at[].stereo_bond_parity: definitely different bonds */
 
1661
            /*  known parities */
 
1662
            if ( PARITY_KNOWN(at[cur1].stereo_bond_parity[i1] ) &&
 
1663
                 PARITY_KNOWN(at[cur2].stereo_bond_parity[i2] )  ) {
 
1664
                return 0; /*  different currently known stereo bond parities */
 
1665
            }
 
1666
#if ( PROPAGATE_ILL_DEF_STEREO != 1 )
 
1667
            /*  well defined and to be calculated from the ranks */
 
1668
            if ( !(PARITY_CALCULATE(at[cur1].stereo_bond_parity[i1]) && PARITY_WELL_DEF (at[cur2].stereo_bond_parity[i2]) ||
 
1669
                   PARITY_WELL_DEF (at[cur1].stereo_bond_parity[i1]) && PARITY_CALCULATE(at[cur2].stereo_bond_parity[i2]) ||
 
1670
                   PARITY_CALCULATE(at[cur1].stereo_bond_parity[i1]) && PARITY_CALCULATE(at[cur2].stereo_bond_parity[i2]) ) ) {
 
1671
                /*  do not reject if: "well defined" and "calculate" or "calculate" and "calculate" */
 
1672
                return 0; 
 
1673
            }
 
1674
#endif
 
1675
        }
 
1676
   
 
1677
#if ( PROPAGATE_ILL_DEF_STEREO != 1 )
 
1678
        if ( (cur1 != cur2 || s1 != s2) && (cur1 != s2 || cur2 != s1) ) {
 
1679
            /*  two different stereo bonds */
 
1680
            if ( PARITY_ILL_DEF( at[cur1].stereo_bond_parity[i1] ) ||
 
1681
                 PARITY_ILL_DEF( at[cur2].stereo_bond_parity[i2] ) ) {
 
1682
                return 0;
 
1683
            }
 
1684
        }
 
1685
#endif
 
1686
    }
 
1687
    return 1; /*  stereo bonds to n1 and n2 have same known parities or are not stereo bonds */
 
1688
}
 
1689
/**************************************************************************************/
 
1690
int CreateCheckSymmPaths( sp_ATOM *at, AT_RANK prev1, AT_RANK cur1, AT_RANK prev2, AT_RANK cur2,
 
1691
                         AT_RANK *nAvoidCheckAtom, AT_RANK *nVisited1, AT_RANK *nVisited2,
 
1692
                         AT_RANK *nVisitOrd1, AT_RANK *nVisitOrd2,
 
1693
                         NEIGH_LIST *nl1, NEIGH_LIST *nl2, const AT_RANK *nRank1, const AT_RANK *nRank2,
 
1694
                         AT_RANK *nCanonRank, AT_RANK *nLength, int *bParitiesInverted, int mode  )
 
1695
{
 
1696
    int k, k1, k2, ret=0, bParitiesInvertedZero=0, *pbParitiesInverted;
 
1697
    AT_RANK n1, n2;
 
1698
 
 
1699
    nVisited1[cur1] = cur2+1;  /*  symmetrically exchange atom numbers */
 
1700
    nVisited2[cur2] = cur1+1;
 
1701
 
 
1702
    (*nLength) ++;
 
1703
 
 
1704
    nVisitOrd1[cur1] = *nLength; /*  save DFS visit order */
 
1705
    nVisitOrd2[cur2] = *nLength;
 
1706
 
 
1707
    /* new version allows all inverted parities */
 
1708
    if ( PARITY_WELL_DEF(at[cur1].stereo_atom_parity) &&
 
1709
         PARITY_WELL_DEF(at[cur2].stereo_atom_parity) ) {
 
1710
        if ( *bParitiesInverted < 0 ) {
 
1711
            *bParitiesInverted = (at[cur1].stereo_atom_parity + at[cur2].stereo_atom_parity) % 2;
 
1712
        } else
 
1713
        if ( *bParitiesInverted != (at[cur1].stereo_atom_parity + at[cur2].stereo_atom_parity) % 2 ) {
 
1714
            return 0; /*  Different known in advance parities have wrong "inverted" relation */
 
1715
        }
 
1716
    } else
 
1717
    if ( PARITY_KNOWN(at[cur1].stereo_atom_parity) &&
 
1718
         PARITY_KNOWN(at[cur2].stereo_atom_parity) &&
 
1719
         at[cur1].stereo_atom_parity != at[cur2].stereo_atom_parity ) {
 
1720
        return 0;  /*  Different known in advance parities */
 
1721
    }
 
1722
 
 
1723
    if ( cur1 != cur2 &&
 
1724
         !at[cur1].stereo_bond_neighbor[0] && !at[cur2].stereo_bond_neighbor[0] &&
 
1725
         PARITY_KNOWN(at[cur1].parity) != PARITY_KNOWN(at[cur2].parity) ) {
 
1726
        return 0; /*  one atom is stereogenic, another (presumably equivalent) is not. 9-11-2002 */
 
1727
    }
 
1728
#if ( PROPAGATE_ILL_DEF_STEREO != 1 )
 
1729
    if ( cur1 != cur2 &&
 
1730
         (PARITY_ILL_DEF(at[cur1].stereo_atom_parity) ||
 
1731
          PARITY_ILL_DEF(at[cur2].stereo_atom_parity)) 
 
1732
       ) {
 
1733
        return 0;  /*  Cannot detect whether the paths are same or different */
 
1734
    }
 
1735
#endif
 
1736
 
 
1737
    if ( at[cur1].valence != at[cur2].valence ) {
 
1738
        return CT_REMOVE_STEREO_ERR; /*  program error */ /*   <BRKPT> */
 
1739
    }
 
1740
    if ( at[cur1].valence == 1 ) {
 
1741
        return 1; /*  so far success */
 
1742
    }
 
1743
    
 
1744
    if ( nl1[(int)cur1][0] != nl2[(int)cur2][0] || nl1[(int)cur1][0] != at[cur1].valence ) {
 
1745
        return CT_REMOVE_STEREO_ERR; /*  error: different valences */ /*   <BRKPT> */
 
1746
    }
 
1747
 
 
1748
 
 
1749
    for ( k = 1, k1 = 1, k2 = 1; k < at[cur1].valence; k ++, k1 ++, k2 ++ ) {
 
1750
        if ( (n1 = nl1[(int)cur1][k1]) == prev1 ) {
 
1751
            n1 = nl1[(int)cur1][++k1]; /*  don't go back */
 
1752
        }
 
1753
        if ( (n2 = nl2[(int)cur2][k2]) == prev2 ) {
 
1754
            n2 = nl2[(int)cur2][++k2]; /*  don't go back */
 
1755
        }
 
1756
        
 
1757
        if ( 0 >= (ret = CheckNextSymmNeighborsAndBonds( at, cur1, cur2, n1, n2, nAvoidCheckAtom,
 
1758
                                              nVisited1, nVisited2, nVisitOrd1, nVisitOrd2, nRank1, nRank2 ) ) ) {
 
1759
            return ret; /*  different neighbors or bonds                       */
 
1760
        }
 
1761
 
 
1762
        if ( !nVisited1[n1] ) { /*  recursion */
 
1763
            /* allow all inverted parities only inside a single ring system containing the starting point */
 
1764
            pbParitiesInverted = (at[cur1].nRingSystem == at[n1].nRingSystem)? bParitiesInverted:&bParitiesInvertedZero;
 
1765
            if ( 0 >= (ret = CreateCheckSymmPaths( at, cur1, n1, cur2, n2, nAvoidCheckAtom,
 
1766
                                         nVisited1, nVisited2, nVisitOrd1, nVisitOrd2,
 
1767
                                         nl1, nl2, nRank1, nRank2, nCanonRank, nLength, pbParitiesInverted, mode ) ) ) {
 
1768
                return ret;
 
1769
            }
 
1770
        }
 
1771
    }
 
1772
    return 1; /*  Success */
 
1773
 
 
1774
}
 
1775
/**************************************************************************************/
 
1776
/*  Compare parities */
 
1777
#define MAX_OTHER_NEIGH        2
 
1778
/*  nNeighMode */
 
1779
#define NEIGH_MODE_RING        1
 
1780
#define NEIGH_MODE_CHAIN       2
 
1781
 
 
1782
#define CHECKING_STEREOCENTER  1
 
1783
#define CHECKING_STEREOBOND    2
 
1784
 
 
1785
#define COMP_STEREO_SUCCESS    1
 
1786
#define NOT_WELL_DEF_UNKN      2
 
1787
#define NOT_WELL_DEF_UNDF      4
 
1788
 
 
1789
#define PARITY_IMPOSSIBLE    999
 
1790
/**************************************************************************************
 
1791
  Note:    the following C2v/S4 stereo center symmetry recognition
 
1792
           is not included in the final InChI version released in April 2005
 
1793
           It is disabled in the mode.h (CHECK_C2v_S4_SYMM = 0)
 
1794
           As the result, the only central atom in S4 or atoms on C2v axis
 
1795
           may have pasrity (-) even though these atoms are not stereogenic.
 
1796
 
 
1797
  Reason:  Not finished/tested yet
 
1798
 **************************************************************************************
 
1799
 
 
1800
  In case of stereocenter with 2 pairs of constitutionally identical neighbors :
 
1801
  
 
1802
  G(n) > H(m) means group G has n elements; group H has m elements and
 
1803
                                            group H is a subgroup of G
 
1804
 
 
1805
  Td(24) > D2d(8> > D2(4)
 
1806
                  > S4(4)  > C2(2) -- Test for S4
 
1807
                  > C2v(4) > C2(2) -- Test for C2v
 
1808
                           > Cs(2)
 
1809
                  
 
1810
  Td(24) > C3v(6) > C3(3) -- does not have 2 pairs of constitutionally identical neighbors
 
1811
                  > Cs(2)
 
1812
 
 
1813
  The pair of atoms to check for the existence of a steregenic atom: X, Y
 
1814
 
 
1815
       X   Y
 
1816
        \ /
 
1817
         C
 
1818
        / \
 
1819
       A   B
 
1820
 
 
1821
  Conditions to check:
 
1822
 
 
1823
  (a) Old #0: Map canonical numbers X1 <--> Y2
 
1824
      Traverse DFS from X and Y
 
1825
      If all parities vs. canon. numbers unchanged except that of C
 
1826
      then C is not stereogenic
 
1827
 
 
1828
  (b) C2v  #1: discover ACB symmetry plain Cv
 
1829
      o Map canonical numbers X1 <--> Y2, Fix(Ai), Fix(Bi)
 
1830
      o Make sure that after mapping X1 <--> Y2 the atoms Ai and
 
1831
        Bi still have equal mapping ranks
 
1832
      Traverse DFS from X and Y
 
1833
      In this case canonical numbers will be reflected in plane ACB if it exists.
 
1834
      o Criterion of the presence of the symmetry plain is:
 
1835
        --> all stereogenic atoms and allenes parities are inverted
 
1836
  (c) C2v  #2: discover vertical axis C2
 
1837
      o Map canonical numbers X1 <--> Y2 and A1 <--> B2
 
1838
      o Make sure that after mapping X1 <--> Y2 the atoms Ai and
 
1839
        Bi still have equal mapping ranks
 
1840
      o Traverse DFS from X1 and Y2
 
1841
        In this case canonical numbers will be rotated by
 
1842
                     180 degrees around the vertical axis
 
1843
         (this may be considered as a superposition of two Cv
 
1844
          reflections in perpendicular vertical planes)
 
1845
      o Criterion of the presence of the C2 axis is:
 
1846
        --> all stereogenic atoms and allenes parities are not changed
 
1847
  (d) S4  #3: discover axis horizontal S4 axis
 
1848
      o Map canonical numbers X1 <--> Y2, Y1 <--> A2, A1 <--> B2, B1 <--> X2
 
1849
      o Traverse DFS from X1 and Y2
 
1850
        In this case the canonical numbers will be rotated by
 
1851
                     90 degrees and reflected in a horizontal plane.
 
1852
        3 attempts corrresponding to transpositions 0132, 0213, 0321
 
1853
                                 are sufficient (XY=01,02,03)
 
1854
      o Criterion of the presence of the S4 symmetry axis is:
 
1855
        --> all stereogenic atoms and allenes parities are inverted
 
1856
 
 
1857
***************************************************************************************/
 
1858
 
 
1859
/**************************************************************************************/
 
1860
int CalculatedPathsParitiesAreIdentical( sp_ATOM *at, int num_atoms, const AT_RANK *nSymmRank,
 
1861
                         AT_RANK *nCanonRank, AT_RANK *nAtomNumberCanon,
 
1862
                         AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
 
1863
                         AT_RANK *nVisited1, AT_RANK *nVisited2,
 
1864
                         AT_RANK prev_sb_neigh, AT_RANK cur, AT_RANK next1, AT_RANK next2, int nNeighMode,
 
1865
                         int bParitiesInverted, int mode, CANON_STAT *pCS,
 
1866
                         int vABParityUnknown)
 
1867
{
 
1868
    int i, i01, i02, i11, i12, i21, i22, k, parity, parity1, parity2, parity12, num_other_neigh;
 
1869
    int nNumEqStereogenic, nCheckingMode, not_well_def_parities;
 
1870
    AT_RANK other_neigh[MAX_NUM_STEREO_ATOM_NEIGH], neigh, r1, r2;
 
1871
    int  nNumComparedCenters = 0, nNumComparedBonds = 0, bCurParityInv1=0 /*, bCurParityInv2=0*/;
 
1872
    int  bCurRotated=0, nNumDiff=0, nNumInv=0;
 
1873
    int  s1, s2;
 
1874
 
 
1875
    nCheckingMode = ( prev_sb_neigh < num_atoms )? CHECKING_STEREOBOND : CHECKING_STEREOCENTER;
 
1876
    not_well_def_parities = 0;
 
1877
    nNumEqStereogenic = 0;
 
1878
 
 
1879
    if ( nNeighMode != NEIGH_MODE_RING &&
 
1880
         bParitiesInverted != 0 || abs(bParitiesInverted) != 1 ) {
 
1881
        bParitiesInverted = 0;
 
1882
    }
 
1883
 
 
1884
    if ( bParitiesInverted ) {
 
1885
        for ( i = 0, i11 = i22 = 0; i < num_atoms; i ++ ) {
 
1886
            /* count number of atoms that have not been visited */
 
1887
            i11 += !nVisited1[i];
 
1888
            i22 += !nVisited2[i];
 
1889
            nAtomNumberCanon1[i] = MAX_ATOMS+1;  /*  mark unchanged */
 
1890
            nAtomNumberCanon2[i] = MAX_ATOMS+1;  /*  mark unchanged */
 
1891
        }
 
1892
        if ( i11 || i22 ) {
 
1893
            if ( bParitiesInverted == 1 )
 
1894
                return 0; /* only a part of the structure has been inverted */
 
1895
            else
 
1896
                bParitiesInverted = 0;
 
1897
        }
 
1898
    } else {
 
1899
        for ( i = 0; i < num_atoms; i ++ ) {
 
1900
            nAtomNumberCanon1[i] = MAX_ATOMS+1;  /*  mark unchanged */
 
1901
            nAtomNumberCanon2[i] = MAX_ATOMS+1;  /*  mark unchanged */
 
1902
        }
 
1903
    }
 
1904
    if ( bParitiesInverted  > 0 && !(mode == MAP_MODE_C2v || mode == MAP_MODE_S4) ||
 
1905
         bParitiesInverted == 0 && !(mode == MAP_MODE_C2  || mode == MAP_MODE_STD)) {
 
1906
        return 0;
 
1907
    }
 
1908
    /**************************************************************************************
 
1909
     *    The following discussion assumes that the canonical numbers are
 
1910
     *    switched for some pairs of constitutionally identical atoms
 
1911
     *    in such a way that the new numbering is an equivalent to the
 
1912
     *    nCanonRank[] canonical numbering (the transposition belongs to the
 
1913
     *    automorphism group of the chemical structure having no stereo).
 
1914
     *    At this point non-zero elements of nVisited1[] and nVisited2[]
 
1915
     *    together contain transposition P of the atom numbers.
 
1916
     *    and P2 respectively of the ordering atom numbers: nVisitedi[k] = Pi(k)+1;
 
1917
     *    In this implementation:
 
1918
     *       P1(k)=k for all k
 
1919
     *       P2(cur)=cur, P2(next1)=next2, P2(next2)=next1 
 
1920
     *
 
1921
     *    Below we call one of the numberings "old", another "new".
 
1922
     *
 
1923
     *    *IF* the old and the new canonical numberings produce same parities for stereogenic
 
1924
     *    elements for the same canonical number(s)
 
1925
     *    (that is, old_parity(canon_number) == new_parity(canon_number)
 
1926
     *    *except* the currently being tested stereocenter at[cur] or stereobond/cumulene
 
1927
     *    at[cur]=at[prev_sb_neigh], whose parity MUST be inverted
 
1928
     *
 
1929
     *    *THEN* the stereocenter or stereobond/cumulene is not stereogenic with one
 
1930
     *
 
1931
     *    *EXCEPTION* If the currently tested stereogenic element is constitutionally
 
1932
     *    equivalent to two or more other stereogenic elements that have been
 
1933
     *    permuted then the currently tested one is still stereogenic.
 
1934
     **************************************************************************************/
 
1935
 
 
1936
     /*
 
1937
     * 1. replace the assigned in each of the parallel traversals atom numbers
 
1938
     *    with the canon. ranks corresponding to the atom numbers in the
 
1939
     *    currently numbered atoms at[].
 
1940
     *    One of obtained this way canonical numberings (probably nVisited1[])
 
1941
     *    is same as the nCanonRank[] because usually nVisited1[i] = i+1 or 0
 
1942
     */
 
1943
    for ( i = 0; i < num_atoms; i ++ ) {
 
1944
 
 
1945
        if ( nVisited1[i] ) {
 
1946
            /* canonical number of the atom mapped on atom #i in 'left' path */
 
1947
            nVisited1[i] = nCanonRank[ (int)nVisited1[i] - 1 ];
 
1948
            /* reverse: atom # from the mapped canonical rank in 'left' path */
 
1949
            nAtomNumberCanon1[nVisited1[i] - 1] = i;
 
1950
        }
 
1951
        if ( nVisited2[i] ) {
 
1952
            /* canonical number of the atom mapped on atom #i in 'right' path */
 
1953
            nVisited2[i] = nCanonRank[ (int)nVisited2[i] - 1 ];
 
1954
            /* reverse: atom # from the mapped canonical rank in 'right' path */
 
1955
            nAtomNumberCanon2[nVisited2[i] - 1] = i;
 
1956
        }
 
1957
        /* if 'left' and 'right' path do not have atoms in common except the
 
1958
           starting atom (and in case of stereobond, the end atom) some of
 
1959
           nVisitedi[i] elements may be zero.
 
1960
        */
 
1961
    }
 
1962
    
 
1963
    /*
 
1964
     * if started with a stereobond then check whether its parity has changed.
 
1965
     * If yes then continue, otherwise parities are different
 
1966
     *
 
1967
     * if started with a stereo center then prev_sb_neigh = MAX_ATOMS+1
 
1968
     *
 
1969
     * If the transposition of next1 and next2 changes only the parity of the starting stereo atom or stereo bond
 
1970
     * then the stereo bond or stereo atom is not stereogenic
 
1971
     *
 
1972
     * The exception: the stereogenic elememt in question is equivalent
 
1973
     *    to two or more traversed other stereogenic elememts
 
1974
     *    (see nNumEqStereogenic below, case similar to trimethylcyclopropane:
 
1975
     *     3 or more constitutionally equivalent stereogenic elements)
 
1976
     */
 
1977
    if ( nCheckingMode == CHECKING_STEREOBOND ) {
 
1978
        /******************************************************************************
 
1979
         *
 
1980
         *  Possibly stereogenic starting bond or cumulene at[cur]-at[prev_sb_neigh]
 
1981
         *
 
1982
         *******************************************************************************/
 
1983
        /*  checking the starting stereo bond */
 
1984
        if ( nVisited1[prev_sb_neigh] || nVisited2[prev_sb_neigh] ) {
 
1985
            /*  the bond or cumulene is in the ring and the opposite atom has been visited */
 
1986
            if ( nVisited1[prev_sb_neigh]  != nVisited2[prev_sb_neigh] ||
 
1987
                 nCanonRank[prev_sb_neigh] != nVisited2[prev_sb_neigh] ) {
 
1988
                return 0; /*  error: we came back to the same bond/cumulene and */ /*   <BRKPT> */
 
1989
                          /*  assigned different canon. ranks to the opposite atom. */
 
1990
            }
 
1991
            if ( at[prev_sb_neigh].valence + at[prev_sb_neigh].num_H > 3 )
 
1992
                return 0; /*  at[prev_sb_neigh] atom can not be adjacent to a stereo bond/cumulene */
 
1993
                          /*  or does not have 3 attachments (hydrogens are not considered here) */
 
1994
            for ( i = 0, k = 0; i < MAX_NUM_STEREO_BONDS &&
 
1995
                                  (neigh=at[prev_sb_neigh].stereo_bond_neighbor[i]) && !(k=(neigh-1 == cur)); i ++ )
 
1996
                ;
 
1997
            if ( !k ) {
 
1998
                return -1; /*  program error: could not locate stereogenic bond mark on the opposite atom */
 
1999
            }
 
2000
            k = (int)at[prev_sb_neigh].stereo_bond_ord[i]; /*  seq. number of the double or cumulene bond on at[prev_sb_neigh] */
 
2001
 
 
2002
            for ( i = 0, num_other_neigh = 0; i < at[prev_sb_neigh].valence && num_other_neigh <= MAX_OTHER_NEIGH; i ++ ) {
 
2003
                if ( i != k ) { /*  do not include the double or cumulene bond */
 
2004
                    other_neigh[num_other_neigh ++] = at[prev_sb_neigh].neighbor[i];
 
2005
                }
 
2006
            }
 
2007
            if ( num_other_neigh + at[prev_sb_neigh].num_H > MAX_OTHER_NEIGH ) {
 
2008
                return CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
 
2009
            }
 
2010
            for ( i = 0; i < num_other_neigh; i ++ ) {
 
2011
                k = (int)other_neigh[i];
 
2012
                if ( nVisited1[k] && nVisited1[k] != nCanonRank[k] ) {
 
2013
                    return 0; /*  parity of the statring stereo bond/cumulene has not changed. */
 
2014
                }
 
2015
                if ( nVisited2[k] && nVisited2[k] != nCanonRank[k] ) {
 
2016
                    return 0; /*  parity of the statring stereo bond/cumulene has not changed. */
 
2017
                }
 
2018
            }
 
2019
        }
 
2020
    }
 
2021
    if ( nCheckingMode == CHECKING_STEREOCENTER ) {
 
2022
        /**************************************************
 
2023
         *
 
2024
         *  Possibly stereogenic starting atom at[cur]
 
2025
         *
 
2026
         **************************************************/
 
2027
        /*  checking the starting stereo center */
 
2028
        for ( i = 0, num_other_neigh = 0; i < at[cur].valence && num_other_neigh <= MAX_OTHER_NEIGH; i ++ ) {
 
2029
            neigh  = at[cur].neighbor[i];
 
2030
            if ( neigh != next1 && neigh != next2 ) {
 
2031
                other_neigh[num_other_neigh ++] = neigh;
 
2032
            }
 
2033
        }
 
2034
        if ( num_other_neigh + at[cur].num_H > MAX_OTHER_NEIGH ) {
 
2035
            return CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
 
2036
        }
 
2037
        /*
 
2038
        if ( bParitiesInverted && at[cur].valence == MAX_NUM_STEREO_ATOM_NEIGH ) {
 
2039
            if ( nVisited1[other_neigh[0]] == nCanonRank[other_neigh[0]] ||
 
2040
                 nVisited2[other_neigh[0]] == nCanonRank[other_neigh[0]] ||
 
2041
                 nVisited1[other_neigh[1]] == nCanonRank[other_neigh[1]] ||
 
2042
                 nVisited2[other_neigh[1]] == nCanonRank[other_neigh[1]] ) {
 
2043
                bParitiesInverted = 0;
 
2044
                bCurRotated = 1;
 
2045
            }
 
2046
        }
 
2047
        */
 
2048
        /* bParitiesInverted = -1 means no predefined stereocenter has been checked */
 
2049
        if ( bParitiesInverted && at[cur].valence == MAX_NUM_STEREO_ATOM_NEIGH ) {
 
2050
            /* special case: 4 canonically eq. neighbors */
 
2051
            int canon_parity, parity_vis_1, parity_vis_2;
 
2052
            canon_parity = GetPermutationParity( at+cur, MAX_ATOMS+1, nCanonRank );
 
2053
            parity_vis_1 = GetPermutationParity( at+cur, MAX_ATOMS+1, nVisited1 );
 
2054
            parity_vis_2 = GetPermutationParity( at+cur, MAX_ATOMS+1, nVisited2 );
 
2055
            if ( parity_vis_1 != parity_vis_2 ) {
 
2056
                return 0;
 
2057
            }
 
2058
            if ( bParitiesInverted ==  1 && parity_vis_1 == canon_parity ) {
 
2059
                return 0; /* not a typical case of inversion during the mapping of D4h stereocenter */
 
2060
            } else
 
2061
            if ( bParitiesInverted == -1 ) {
 
2062
                if ( parity_vis_1 == canon_parity ) {
 
2063
                    bParitiesInverted = 0;
 
2064
                } else {
 
2065
                    bParitiesInverted = 1;
 
2066
                }
 
2067
            }
 
2068
        }
 
2069
        /* at this point bParitiesInverted >= 0 */
 
2070
        if ( !bParitiesInverted && !bCurRotated ) {
 
2071
            for ( i = 0; i < num_other_neigh; i ++ ) {
 
2072
                k = (int)other_neigh[i];
 
2073
                if ( nVisited1[k] && nVisited1[k] != nCanonRank[k] ) {
 
2074
                    return 0; /*  parity of the statring stereo center has not changed. */
 
2075
                }
 
2076
                if ( nVisited2[k] && nVisited2[k] != nCanonRank[k] ) {
 
2077
                    return 0; /*  parity of the statring stereo center has not changed. */
 
2078
                }
 
2079
            }
 
2080
        }
 
2081
    }
 
2082
    
 
2083
    /*****************************************************
 
2084
     * Check other (non-starting) stereo centers
 
2085
     ******************************************************/
 
2086
    for ( i = 0; i < pCS->nLenLinearCTStereoCarb; i ++, nNumComparedCenters += (k > 0) ) {
 
2087
        r1     = pCS->LinearCTStereoCarb[i].at_num;
 
2088
        i01    = nAtomNumberCanon[r1-1]; /*  ord. number of the atom that has canon rank r1 */
 
2089
        
 
2090
        i11     = nAtomNumberCanon1[r1-1]; /*  = (MAX_ATOMS+1) > num_atoms if the atom has not been traversed */
 
2091
        i12     = nAtomNumberCanon2[r1-1]; /*  = otherwise < num_atoms */
 
2092
 
 
2093
        s1 = (i11 < num_atoms); /*  1 => the center was traversed on path #1 */
 
2094
        s2 = (i12 < num_atoms); /*  1 => the center was traversed on path #2 */
 
2095
 
 
2096
        bCurParityInv1 = (bParitiesInverted &&
 
2097
                          at[cur].nRingSystem == at[i11].nRingSystem &&
 
2098
                          at[cur].nRingSystem == at[i12].nRingSystem );
 
2099
 
 
2100
 
 
2101
        k  = 0;
 
2102
        
 
2103
        /*  check whether the two stereo centers (they can be one and the same atom) have been traversed */
 
2104
        if ( !s1 && !s2 ) {
 
2105
            continue;  /*  Both stereo centers have not been traversed; check the next pair. */
 
2106
        }
 
2107
 
 
2108
        if ( nCheckingMode == CHECKING_STEREOCENTER ) {
 
2109
            /*  check whether the stereocenters are the starting stereocenter */
 
2110
            switch( (cur == i11) + (cur == i12) ) {
 
2111
            case 2:
 
2112
                continue; /*  do not recheck the starting atom */
 
2113
            case 1:
 
2114
                return -1; /*  possibly program error */ /*   <BRKPT> */
 
2115
            /* case 0: */
 
2116
            /*     break;  */  /*  the stereo centers are not the sarting stereo center */
 
2117
            }
 
2118
            if ( cur == i01 ) {
 
2119
                return -1;  /*  program error: in this case at least one of the i11, i12 must be == cur */ /*   <BRKPT> */
 
2120
            }
 
2121
        }
 
2122
        
 
2123
        if ( nNeighMode == NEIGH_MODE_RING ) {
 
2124
            if ( i11 != i12 && !bCurParityInv1 ) {
 
2125
                return -1; /*  failed: the two stereo atoms have not been traversed synchronously */
 
2126
            }
 
2127
            if ( !at[i11].parity || !at[i12].parity ) {
 
2128
                return 0; /*  another atom does not have parity (it might have been removed) 9-11-2002 */
 
2129
            }
 
2130
        }
 
2131
        if ( nNeighMode == NEIGH_MODE_CHAIN ) {
 
2132
            if ( s1+s2 != 1 ) {
 
2133
                return -1; /*  program error: only one out of s1 and s2 must be 1, another must be 0. */
 
2134
            }
 
2135
            if ( s1 && !at[i11].parity || s2 && !at[i12].parity ) {
 
2136
                return 0; /*  another atom does not have parity (it might have been removed) 9-11-2002 */
 
2137
            }
 
2138
        }
 
2139
        
 
2140
        parity  = pCS->LinearCTStereoCarb[i].parity;
 
2141
        if ( nNeighMode == NEIGH_MODE_RING  && (i11 != i01) && (i12 != i01) ||
 
2142
             /*  in NEIGH_MODE_RING case we know that i11 == i12 except bCurParityInv1 == 1 */
 
2143
             nNeighMode == NEIGH_MODE_CHAIN 
 
2144
             /*  in NEIGH_MODE_CHAIN case here we always have 2 different atoms */
 
2145
        ) {
 
2146
            /****************************************************************
 
2147
             * Case of two transposed atoms or a circular permutation in D4h
 
2148
             */
 
2149
            parity1 = s1? GetStereoCenterParity( at, i11, nVisited1 ) : PARITY_IMPOSSIBLE;
 
2150
            parity2 = s2? GetStereoCenterParity( at, i12, nVisited2 ) : PARITY_IMPOSSIBLE;
 
2151
            if ( !ATOM_PARITY_KNOWN(parity1) && !ATOM_PARITY_KNOWN(parity2) ) {
 
2152
                return -1; /*  should not happen: must have been detected at the time of the traversal */
 
2153
            }
 
2154
            if ( s1 && s2 ) {
 
2155
                if ( bCurParityInv1 ) {
 
2156
                    int parity1orig = GetStereoCenterParity( at, i11, nCanonRank ); 
 
2157
                    int parity2orig = GetStereoCenterParity( at, i12, nCanonRank ); 
 
2158
                    if ( i11 == i12 ||
 
2159
                         (parity1 == parity1orig || parity2 == parity2orig || parity1 != parity2) &&
 
2160
                         ATOM_PARITY_WELL_DEF(parity1) ||
 
2161
                         parity1 != parity2 && (!ATOM_PARITY_WELL_DEF(parity1) ||
 
2162
                                                !ATOM_PARITY_WELL_DEF(parity2)) )
 
2163
                        /*return -1; */ /* should be different atoms with inverted parities */
 
2164
                        nNumDiff ++;
 
2165
                } else {
 
2166
                    if ( i11 != i12 || parity1 != parity2 )
 
2167
                        return -1; /*  program error: must be the same atom */
 
2168
                }
 
2169
            }
 
2170
            parity12 = s1? parity1 : parity2;
 
2171
 
 
2172
            if ( ATOM_PARITY_WELL_DEF(parity) && parity == parity12 ) {
 
2173
                /*  symmetrical neighbors have well-defined equal parities */
 
2174
                k ++;
 
2175
                if ( nCheckingMode == CHECKING_STEREOCENTER && nNeighMode == NEIGH_MODE_RING ) {
 
2176
                    /*  all 3: cur, i01, i11 are different atoms (here i11==i12) */
 
2177
                    /*  here nSymmRank[i01]==nSymmRank[i11] due to the parallel traversal */
 
2178
                    if ( nSymmRank[cur] == nSymmRank[i01] ) {
 
2179
                        nNumEqStereogenic ++;  /*  all 3 are equ */
 
2180
                    }
 
2181
                }
 
2182
            } else
 
2183
            if ( ATOM_PARITY_WELL_DEF(parity) && ATOM_PARITY_WELL_DEF(parity12) ) {
 
2184
                /*  apparently different well-defined parities */
 
2185
                if ( !bCurParityInv1 ) {
 
2186
                    nNumInv ++;
 
2187
                    /* return 0; */
 
2188
                }
 
2189
            } else {
 
2190
#if ( PROPAGATE_ILL_DEF_STEREO == 1 )
 
2191
                /*  at least one parity is ill-defined. Use parity1 and parity2 to temporarily save bitmaps */
 
2192
                parity1 = (parity  ==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
 
2193
                          (parity  ==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
 
2194
                parity2 = (parity12==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
 
2195
                          (parity12==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
 
2196
                if ( parity1 | parity2 ) {
 
2197
                    not_well_def_parities |= ( parity1 | parity2 );
 
2198
                    k ++;
 
2199
                } else {
 
2200
                    return -1;  /*  program error */ /*   <BRKPT> */
 
2201
                }
 
2202
#else
 
2203
                return 0;
 
2204
#endif
 
2205
            }
 
2206
        } else
 
2207
        if ( i11 == i01 && i12 == i01 ) {
 
2208
            /********************************************************************/
 
2209
            /*  i11 == i12 are same atom as i01, nNeighMode == NEIGH_MODE_RING */
 
2210
            if ( !s1 || !s2 ) {
 
2211
                return -1;
 
2212
            }
 
2213
            /*  the parity of the new neighbors permutation must be same as the old one */
 
2214
            /*  this must work for well-defined and ill-defined parities. */
 
2215
            /*  actual parity (that includes the geometry) is not important here. */
 
2216
            /*  old permutation */
 
2217
            parity  = GetPermutationParity( at+i01, MAX_ATOMS+1, nCanonRank );
 
2218
            /*  new parmutation */
 
2219
            parity1 = GetPermutationParity( at+i01, MAX_ATOMS+1, nVisited1 );
 
2220
            parity2 = GetPermutationParity( at+i01, MAX_ATOMS+1, nVisited2 );
 
2221
            if ( parity != parity1 || parity != parity2 ) {
 
2222
                return 0;
 
2223
            }
 
2224
            k ++;
 
2225
        } else {
 
2226
            /* nNeighMode == NEIGH_MODE_RING and only one out of the two (i11 == i01) (i12 == i01) is true */
 
2227
            return -1; 
 
2228
        }
 
2229
        /* nNumComparedCenters += (k > 0); */
 
2230
    }
 
2231
    if ( bCurRotated || nNumDiff || nNumInv ) {
 
2232
        return 0;
 
2233
    }
 
2234
 
 
2235
     /* !!!! Add here bParitiesInverted == 1 case !!!! */
 
2236
    /******************************************************/
 
2237
    /*  Check other (non-starting) stereo bonds/cumulenes */
 
2238
    /******************************************************/
 
2239
    for ( i = 0; i < pCS->nLenLinearCTStereoDble; i ++, nNumComparedBonds += (k > 0) ) {
 
2240
        r1     = pCS->LinearCTStereoDble[i].at_num1;
 
2241
        r2     = pCS->LinearCTStereoDble[i].at_num2;
 
2242
        i01    = nAtomNumberCanon[r1-1];  /*  ord. number of the atom that originally has canon rank r1 */
 
2243
        i02    = nAtomNumberCanon[r2-1];  /*  ord. number of the atom that originally has canon rank r2 */
 
2244
 
 
2245
        i11     = nAtomNumberCanon1[r1-1]; /*  ord. number of the atom that got canon rank r1 during the parallel traversal */
 
2246
        i12     = nAtomNumberCanon1[r2-1]; /*  ord. number of the atom that got canon rank r2 during the parallel traversal */
 
2247
 
 
2248
        i21     = nAtomNumberCanon2[r1-1];
 
2249
        i22     = nAtomNumberCanon2[r2-1];
 
2250
 
 
2251
 
 
2252
        s1 = (i11 < num_atoms && i12 < num_atoms);
 
2253
        s2 = (i21 < num_atoms && i22 < num_atoms);
 
2254
 
 
2255
        k  = 0;
 
2256
 
 
2257
        /*  check whether the two stereo bonds/allenes (they can be one and the same) have been traversed */
 
2258
        if ( !s1 && !s2 ) {
 
2259
            continue; /*  Both stereo bonds/cumulenes have not been traversed; check the next pair. */
 
2260
        }
 
2261
 
 
2262
        if ( nCheckingMode == CHECKING_STEREOBOND ) {
 
2263
            switch ( (i11 == cur && i12 == prev_sb_neigh || i12 == cur && i11 == prev_sb_neigh) +
 
2264
                     (i21 == cur && i22 == prev_sb_neigh || i22 == cur && i21 == prev_sb_neigh) ) {
 
2265
            case 2:
 
2266
                continue; /*  do not recheck the starting bond/cumulene */
 
2267
            case 1:
 
2268
                return -1; /*  possibly program error  */ /*   <BRKPT> */
 
2269
            /* case 0: */
 
2270
            /*     break; */   /*  the stereo centers are not the sarting stereo center */
 
2271
            }
 
2272
            if ( (i01 == cur && i02 == prev_sb_neigh) || (i02 == cur && i01 == prev_sb_neigh) ) {
 
2273
                return -1;  /*  program error: in this case at least one of the i1x, i2x must be == cur */ /*   <BRKPT> */
 
2274
            }
 
2275
        }
 
2276
 
 
2277
        if ( nNeighMode == NEIGH_MODE_RING ) {
 
2278
            if ( (i11 != i21 || i12 != i22) && (i11 != i22 || i12 != i21) ) {
 
2279
                return -1; /*  failed: the two bonds/cumulenes have not been traversed synchronously */
 
2280
            }
 
2281
            if ( 0 > GetStereoNeighborPos( at, i11, i12 ) ) {
 
2282
                return 0; /*  another bond is not stereo (the stereo might have been removed) 9-11-2002 */
 
2283
            }
 
2284
 
 
2285
        }
 
2286
        if ( nNeighMode == NEIGH_MODE_CHAIN ) {
 
2287
            if ( s1+s2 != 1 ) {
 
2288
                return -1; /*  program error: only one out of s1 and s2 must be 1, another must be 0. */
 
2289
            }
 
2290
            if ( s1 && 0 > GetStereoNeighborPos( at, i11, i12 ) ||
 
2291
                 s2 && 0 > GetStereoNeighborPos( at, i21, i22 ) ) {
 
2292
                return 0; /*  another bond is not stereo (the stereo might have been removed) 9-11-2002 */
 
2293
            }
 
2294
        }
 
2295
 
 
2296
        parity = pCS->LinearCTStereoDble[i].parity;
 
2297
        /* bMustBeIdentical  = ATOM_PARITY_ILL_DEF(parity); */
 
2298
        /* nNumEqStereogenic = 0; */
 
2299
 
 
2300
        if ( nNeighMode == NEIGH_MODE_RING  && (i11 != i01 || i12 != i02) && (i11 != i02 || i12 != i01) ||
 
2301
             nNeighMode == NEIGH_MODE_CHAIN                    /*  in NEIGH_MODE_CHAIN case here we always have 2 different atoms */
 
2302
        ) {
 
2303
            /*******************************************/
 
2304
            /*  case of two transposed bonds/cumulenes */
 
2305
            parity1 = s1? GetStereoBondParity( at, i11, i12, nVisited1 ) : PARITY_IMPOSSIBLE;
 
2306
            parity2 = s2? GetStereoBondParity( at, i21, i22, nVisited2 ) : PARITY_IMPOSSIBLE;
 
2307
            if ( !ATOM_PARITY_KNOWN(parity1) && !ATOM_PARITY_KNOWN(parity2) ) {
 
2308
                return -1; /*  should not happen: must have been detected at the time of traversal */
 
2309
            }
 
2310
            if ( s1 && s2 && ((i11 != i21 || i12 != i22) && (i11 != i22 || i12 != i21) || parity1 != parity2 ) ) {
 
2311
                return -1; /*  program error: must be the same bond/cumulene */
 
2312
            }
 
2313
            parity12 = s1? parity1 : parity2;
 
2314
            if ( ATOM_PARITY_WELL_DEF(parity) && parity == parity12 ) {
 
2315
                /*  symmetrical neighbors have well-defined equal parities */
 
2316
                k ++;
 
2317
                if ( nCheckingMode == CHECKING_STEREOBOND && nNeighMode == NEIGH_MODE_RING ) {
 
2318
                    /*  all 3 bonds: cur-prev_sb_neigh, i01-i02, i11-i12 are different */
 
2319
                    /*  (here <i11,i12>==<i21,i22> compared as unordered pairs) */
 
2320
                    if ( nSymmRank[cur] == nSymmRank[i01] && nSymmRank[prev_sb_neigh] == nSymmRank[i02] ||
 
2321
                         nSymmRank[cur] == nSymmRank[i02] && nSymmRank[prev_sb_neigh] == nSymmRank[i01] ) {
 
2322
                        nNumEqStereogenic ++;
 
2323
                    }
 
2324
                }
 
2325
            } else
 
2326
            if ( ATOM_PARITY_WELL_DEF(parity) && ATOM_PARITY_WELL_DEF(parity12) ) {
 
2327
                /*  apparently different well-defined parities */
 
2328
                return 0;
 
2329
            } else {
 
2330
                /*  at least one parity is ill-defined. Use parity1 and parity2 to temporarily save bitmaps */
 
2331
#if ( PROPAGATE_ILL_DEF_STEREO == 1 )
 
2332
                parity1 = (parity  ==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
 
2333
                          (parity  ==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
 
2334
                parity2 = (parity12==vABParityUnknown /*AB_PARITY_UNKN*/)? NOT_WELL_DEF_UNKN :
 
2335
                          (parity12==AB_PARITY_UNDF)? NOT_WELL_DEF_UNDF : 0;
 
2336
                if ( parity1 | parity2 ) {
 
2337
                    not_well_def_parities |= ( parity1 | parity2 );
 
2338
                    k ++;
 
2339
                } else {
 
2340
                    return -1;  /*  program error */
 
2341
                }
 
2342
#else
 
2343
                return 0;
 
2344
#endif
 
2345
            }
 
2346
        } else {
 
2347
            /*****************************************************************************************/
 
2348
            /*  i11-i12 and i21-i22 are same as i01-i02 bond/cumulene, nNeighMode == NEIGH_MODE_RING */
 
2349
            AT_NUMB n1, n2;
 
2350
            int       j;
 
2351
            if ( !s1 || !s2 ) {
 
2352
                return -1;
 
2353
            }
 
2354
            /*  find neighbors along the stereo bond/cumulene */
 
2355
            for ( j = 0, n1 = MAX_ATOMS+1; j < MAX_NUM_STEREO_BOND_NEIGH && at[i01].stereo_bond_neighbor[j]; j ++ ) {
 
2356
                if ( (int)at[i01].stereo_bond_neighbor[j] == i02+1 ) {
 
2357
                    n1 = at[i01].neighbor[ (int)at[i01].stereo_bond_ord[j] ];
 
2358
                    break;
 
2359
                }
 
2360
            }
 
2361
            for ( j = 0, n2 = MAX_ATOMS+1; j < MAX_NUM_STEREO_BOND_NEIGH && at[i02].stereo_bond_neighbor[j]; j ++ ) {
 
2362
                if ( (int)at[i02].stereo_bond_neighbor[j] == i01+1 ) {
 
2363
                    n2 = at[i02].neighbor[ (int)at[i02].stereo_bond_ord[j] ];
 
2364
                    break;
 
2365
                }
 
2366
            }
 
2367
            if ( n1 > MAX_ATOMS || n2 > MAX_ATOMS ) {
 
2368
                return CT_REMOVE_STEREO_ERR;
 
2369
            }
 
2370
            /*  the parity of the new neighbors permutation must be same as the old one */
 
2371
            /*  this must work for well-defined and ill-defined parities. */
 
2372
            /*  actual parity (that includes the geometry) is not important here. */
 
2373
            /*  old permutation */
 
2374
            parity  = GetPermutationParity( at+i01, n1, nCanonRank) + GetPermutationParity( at+i02, n2, nCanonRank);
 
2375
            /*  new parmutation */
 
2376
            parity1 = GetPermutationParity( at+i01, n1, nVisited1 ) + GetPermutationParity( at+i02, n2, nVisited1 );
 
2377
            parity2 = GetPermutationParity( at+i01, n1, nVisited2 ) + GetPermutationParity( at+i02, n2, nVisited2 );
 
2378
            if ( parity %2 != parity1 % 2 || parity1 % 2 != parity2 % 2 ) {
 
2379
                return 0;
 
2380
            }
 
2381
            k ++;
 
2382
        }
 
2383
 
 
2384
        /* nNumComparedBonds += ( k > 0 ); */
 
2385
    }
 
2386
 
 
2387
    if ( nNumEqStereogenic > 0 ) {
 
2388
        /*  case similar to trimethylcyclopropane: 3 constitutionally equivalent stereogenic elements */
 
2389
        /*  the transposition does not change the parities */
 
2390
#if ( bRELEASE_VERSION == 0 )
 
2391
        pCS->bExtract |= EXTR_2EQL2CENTER_TO_REMOVE_PARITY;
 
2392
#endif
 
2393
        return 0;
 
2394
    }
 
2395
/* =========================================================================================
 
2396
    Note
 
2397
    ====
 
2398
    At this point the comparison is complete and no difference sufficient to establish
 
2399
    absence of stereo parity has been found.
 
2400
    However, non-zero not_well_def_parities means that an ill-defined parity was
 
2401
    compared to an ill-defined or well-defined parity. This means that the parity
 
2402
    of the atom or bond being checked cannot be well-defined anymore.
 
2403
   ========================================================================================*/
 
2404
 
 
2405
 
 
2406
    not_well_def_parities |= COMP_STEREO_SUCCESS;
 
2407
 
 
2408
    return not_well_def_parities;
 
2409
 
 
2410
   /*  Add 1 to indicate success. The stereogenic elements might have been */
 
2411
   /*  removed while checking existence of the previous atom/bond stereo */
 
2412
   /* return (nNumComparedCenters + nNumComparedBonds + 1);  */
 
2413
}
 
2414
/********************************************************************************/
 
2415
/*  Remove stereo marks from the bonds that are calculated to be non-stereo     */
 
2416
/*  Such bonds must have 2 constitutionally equivalent attachments              */
 
2417
/*  (can find two canonical numberings that change only one stereo bond parity) */
 
2418
int RemoveCalculatedNonStereoBondParities( sp_ATOM *at, int num_atoms, int num_at_tg,
 
2419
                                          AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
2420
                                          AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
 
2421
                                          AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
 
2422
                                          NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2, 
 
2423
                                          AT_RANK *nVisited1, AT_RANK *nVisited2, 
 
2424
                                          CANON_STAT *pCS,
 
2425
                                          int vABParityUnknown)
 
2426
{
 
2427
    int j, n, m, ret, ret1, ret2, ret_failed=0;
 
2428
    
 
2429
    int i1, n1, s2;  /*  n1 must be SIGNED integer */
 
2430
    AT_RANK nAtomRank1, nAtomRank2, neigh[3], nAvoidCheckAtom[2], opposite_atom, nLength;
 
2431
    int         nNeighMode = NEIGH_MODE_CHAIN;
 
2432
    int         nNumEqRingNeigh = 0, bRingNeigh, bSymmNeigh, bParitiesInverted;
 
2433
    NEIGH_LIST *nl01, *nl02;
 
2434
    const AT_RANK    *nSymmRank1, *nSymmRank2;
 
2435
 
 
2436
    ret = 0;
 
2437
 
 
2438
second_pass:
 
2439
 
 
2440
    for ( i1 = 0; i1 < num_atoms && !RETURNED_ERROR(ret_failed); i1 ++ ) {
 
2441
        if ( at[i1].valence != 3 || !at[i1].stereo_bond_neighbor[0] ) {
 
2442
            continue;
 
2443
        }
 
2444
        for ( n1 = 0; n1 < MAX_NUM_STEREO_BONDS && !RETURNED_ERROR(ret_failed) && (s2=at[i1].stereo_bond_neighbor[n1]); n1++ ) {
 
2445
            if ( !PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) && PARITY_WELL_DEF(at[i1].stereo_bond_parity[n1]) ) {
 
2446
                continue;
 
2447
            }
 
2448
            opposite_atom = (AT_RANK)(s2-1);
 
2449
            s2 = at[i1].neighbor[(int)at[i1].stereo_bond_ord[n1]]; /*  different from opposite_atom in case of a cumulene */
 
2450
            for ( j = 1, n = 0; j <= (int)at[i1].valence; j ++ ) {      
 
2451
                if ( nl[i1][j] != s2 ) {
 
2452
                    neigh[n++] = nl[i1][j]; /*  sorting guarantees that canon. rank of neigh[0] is greater or equal */
 
2453
                }
 
2454
            }
 
2455
            if ( n != 2 ) {
 
2456
                ret = CT_STEREOBOND_ERROR;  /*   <BRKPT> */
 
2457
                goto exit_function;
 
2458
            }
 
2459
            if ( nSymmRank[(int)neigh[0]] != nSymmRank[(int)neigh[1]] ) {
 
2460
                continue; /*  may happen if another half-bond has not a defined parity */
 
2461
            }
 
2462
 
 
2463
            bRingNeigh = (at[(int)neigh[0]].nRingSystem == at[(int)neigh[1]].nRingSystem);
 
2464
            switch ( nNeighMode ) {
 
2465
            case NEIGH_MODE_CHAIN:
 
2466
                if ( bRingNeigh ) {
 
2467
                    nNumEqRingNeigh ++;
 
2468
                    continue;
 
2469
                }
 
2470
                nl01 = nl;
 
2471
                nl02 = nl;
 
2472
                nSymmRank1 = nSymmRank;
 
2473
                nSymmRank2 = nSymmRank;
 
2474
                break;
 
2475
 
 
2476
            case NEIGH_MODE_RING:
 
2477
                if ( !bRingNeigh )
 
2478
                    continue;
 
2479
                /*  break a tie between the two contitutionally equivalent neighbors, */
 
2480
                /*  refine the two partitions, sort neighbors lists nl1, nl2 */
 
2481
                bSymmNeigh = BreakNeighborsTie(  at, num_atoms, num_at_tg, opposite_atom, i1,
 
2482
                                    neigh, 0, 1, 0,
 
2483
                                    pRankStack1, pRankStack2, nTempRank, NeighList, nSymmRank, nCanonRank,
 
2484
                                    nl1, nl2, &pCS->lNumNeighListIter );
 
2485
                if ( bSymmNeigh <= 0 ) {
 
2486
                    if ( ret_failed > bSymmNeigh )
 
2487
                        ret_failed = bSymmNeigh;
 
2488
                    continue;
 
2489
                }
 
2490
                nl01 = nl1;
 
2491
                nl02 = nl2;
 
2492
                nSymmRank1 = pRankStack1[0];
 
2493
                nSymmRank2 = pRankStack2[0];
 
2494
                break;
 
2495
            default:
 
2496
                return CT_STEREOCOUNT_ERR;  /*  <BRKPT> */
 
2497
            }
 
2498
 
 
2499
            /*  initialize arrays */
 
2500
            memset( nVisited1, 0, sizeof(nVisited1[0])*num_atoms );
 
2501
            memset( nVisited2, 0, sizeof(nVisited2[0])*num_atoms );
 
2502
            memset( nAtomNumberCanon1, 0, sizeof(nAtomNumberCanon1[0])*num_atoms );
 
2503
            memset( nAtomNumberCanon2, 0, sizeof(nAtomNumberCanon2[0])*num_atoms );
 
2504
            nLength       = 1;
 
2505
            nVisited1[i1] = i1+1;   /*  start atoms are the same */
 
2506
            nVisited2[i1] = i1+1;
 
2507
            nAtomNumberCanon1[i1] = nLength;
 
2508
            nAtomNumberCanon2[i1] = nLength;
 
2509
            nAvoidCheckAtom[0] = i1;
 
2510
            nAvoidCheckAtom[1] = opposite_atom;
 
2511
            bParitiesInverted  = (nNeighMode == NEIGH_MODE_RING &&
 
2512
                                  IS_ALLENE_CHAIN(at[i1].stereo_bond_parity[n1]) &&
 
2513
                                  PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) &&
 
2514
                                  at[i1].nRingSystem == at[opposite_atom].nRingSystem &&
 
2515
                                  at[opposite_atom].valence==MAX_NUM_STEREO_BONDS)? -1 : 0;
 
2516
            ret1 = ret2 = 0;
 
2517
            if ( 0 < (ret1=CreateCheckSymmPaths( at, (AT_RANK)i1, neigh[0], (AT_RANK)i1, neigh[1], nAvoidCheckAtom,
 
2518
                                       nVisited1, nVisited2, nAtomNumberCanon1, nAtomNumberCanon2,
 
2519
                                       nl01, nl02, nSymmRank1, nSymmRank2, nCanonRank, &nLength, &bParitiesInverted, 0 ) ) &&
 
2520
                 0 < (ret2=CalculatedPathsParitiesAreIdentical( at, num_atoms, nSymmRank,
 
2521
                                       nCanonRank, nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
 
2522
                                       nVisited1, nVisited2, opposite_atom, (AT_RANK)i1,
 
2523
                                       neigh[0], neigh[1], nNeighMode, bParitiesInverted, 0, 
 
2524
                                       pCS, vABParityUnknown ) ) ) {
 
2525
                if ( ret2 & ( NOT_WELL_DEF_UNKN | NOT_WELL_DEF_UNDF ) ) {
 
2526
                    /*  possibly change the parity to unknown or undefined */
 
2527
                    int new_parity = (ret2 & NOT_WELL_DEF_UNKN)? vABParityUnknown /*AB_PARITY_UNKN*/: AB_PARITY_UNDF;
 
2528
                    if ( PARITY_ILL_DEF(at[i1].stereo_bond_parity[n1]) && PARITY_VAL(at[i1].stereo_bond_parity[n1]) > new_parity ||
 
2529
                         PARITY_CALCULATE(at[i1].stereo_bond_parity[n1]) ) {
 
2530
                        /*  set new unknown or undefined parity */
 
2531
                        SetOneStereoBondIllDefParity( at, i1, /* atom number*/ n1 /* stereo bond ord. number*/, new_parity );
 
2532
                        /*  change in pCS */
 
2533
                        nAtomRank1 = inchi_max( nCanonRank[i1], nCanonRank[opposite_atom]);
 
2534
                        nAtomRank2 = inchi_min( nCanonRank[i1], nCanonRank[opposite_atom]);
 
2535
                        for ( n = 0, m = pCS->nLenLinearCTStereoDble-1; n <= m; n ++ ) {
 
2536
                            if ( pCS->LinearCTStereoDble[n].at_num1 == nAtomRank1 &&
 
2537
                                 pCS->LinearCTStereoDble[n].at_num2 == nAtomRank2 ) {
 
2538
                                pCS->LinearCTStereoDble[n].parity = new_parity;
 
2539
#if ( bRELEASE_VERSION == 0 )
 
2540
                                pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
 
2541
#endif
 
2542
                                m = -1;
 
2543
                                break;
 
2544
                            }
 
2545
                        }
 
2546
                        if ( m >= 0 ) {
 
2547
                            ret = CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
 
2548
                            goto exit_function;
 
2549
                        }
 
2550
                        ret ++;
 
2551
                    }
 
2552
                } else {
 
2553
                    /*  remove the parity */
 
2554
                    if ( !RemoveOneStereoBond( at, i1, /* atom number*/ n1 /* stereo bond ord. number*/ ) ) {
 
2555
                        ret = CT_STEREOBOND_ERROR;  /*   <BRKPT> */
 
2556
                        goto exit_function;
 
2557
                    }
 
2558
                    n1 --;  /*  cycle counter may temporarily become negative */
 
2559
                    /*  Remove from the pCS */
 
2560
                    nAtomRank1 = inchi_max( nCanonRank[i1], nCanonRank[opposite_atom]);
 
2561
                    nAtomRank2 = inchi_min( nCanonRank[i1], nCanonRank[opposite_atom]);
 
2562
                    for ( n = 0, m = pCS->nLenLinearCTStereoDble-1; n <= m; n ++ ) {
 
2563
                        if ( pCS->LinearCTStereoDble[n].at_num1 == nAtomRank1 &&
 
2564
                             pCS->LinearCTStereoDble[n].at_num2 == nAtomRank2 ) {
 
2565
                            if ( n < m ) { /*  remove pCS->LinearCTStereoDble[n] */
 
2566
                                memmove( pCS->LinearCTStereoDble + n,
 
2567
                                         pCS->LinearCTStereoDble + n + 1,
 
2568
                                         (m-n)*sizeof(pCS->LinearCTStereoDble[0]) );
 
2569
                            }
 
2570
                            pCS->nLenLinearCTStereoDble --;
 
2571
#if ( bRELEASE_VERSION == 0 )
 
2572
                            pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
 
2573
#endif
 
2574
                            m = -1;
 
2575
                            break;
 
2576
                        }
 
2577
                    }
 
2578
                    if ( m >= 0 ) {
 
2579
                        ret = CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
 
2580
                        goto exit_function;
 
2581
                    }
 
2582
                    ret ++;
 
2583
                }
 
2584
            } else {
 
2585
                if ( !ret_failed ) {
 
2586
                    ret_failed = (ret1<0)? ret1 : (ret2<0)? ret2 : 0;
 
2587
                }
 
2588
                if ( !RETURNED_ERROR(ret_failed) ) {
 
2589
                    if ( RETURNED_ERROR( ret1 ) )
 
2590
                        ret_failed = ret1;
 
2591
                    else
 
2592
                    if ( RETURNED_ERROR( ret2 ) )
 
2593
                        ret_failed = ret2;
 
2594
                }
 
2595
            }
 
2596
        }
 
2597
    }
 
2598
    if ( nNeighMode == NEIGH_MODE_CHAIN && nNumEqRingNeigh && !RETURNED_ERROR(ret_failed) ) {
 
2599
        nNeighMode = NEIGH_MODE_RING;
 
2600
        goto second_pass;
 
2601
    }
 
2602
 
 
2603
exit_function:
 
2604
 
 
2605
    return RETURNED_ERROR(ret_failed)? ret_failed : ret_failed? -(ret_failed+1) : ret;
 
2606
}
 
2607
/****************************************************************************/
 
2608
/*  Remove stereo marks from the atoms that are calculated to be non-stereo */
 
2609
/*  (can find two numberings that change only one stereo center parity)     */
 
2610
int RemoveCalculatedNonStereoCenterParities( sp_ATOM *at, int num_atoms, int num_at_tg,
 
2611
                                          AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
2612
                                          AT_RANK *nCanonRank, const AT_RANK *nSymmRank,
 
2613
                                          AT_RANK *nAtomNumberCanon, AT_RANK *nAtomNumberCanon1, AT_RANK *nAtomNumberCanon2,
 
2614
                                          NEIGH_LIST *nl, NEIGH_LIST *nl1, NEIGH_LIST *nl2, 
 
2615
                                          AT_RANK *nVisited1, AT_RANK *nVisited2, 
 
2616
                                          CANON_STAT *pCS,
 
2617
                                          int vABParityUnknown)
 
2618
{
 
2619
    int j, n, m, ret;
 
2620
    
 
2621
    int i, k, ret1, ret2, ret_failed=0, mode, max_mode;
 
2622
    AT_RANK nAtomRank1, neigh[MAX_NUM_STEREO_ATOM_NEIGH], nAvoidCheckAtom[2], nLength;
 
2623
    int         nNeighMode = NEIGH_MODE_CHAIN;
 
2624
    int         nNumEqRingNeigh = 0, bRingNeigh, bSymmNeigh, bParitiesInverted;
 
2625
    NEIGH_LIST *nl01, *nl02;
 
2626
    const AT_RANK    *nSymmRank1, *nSymmRank2;
 
2627
    
 
2628
    ret = 0;
 
2629
 
 
2630
second_pass:
 
2631
    for ( i = 0; i < num_atoms && !RETURNED_ERROR(ret_failed); i ++ ) {
 
2632
        if ( !at[i].parity || at[i].stereo_bond_neighbor[0] ) {
 
2633
            continue;
 
2634
        }
 
2635
        if ( at[i].valence > MAX_NUM_STEREO_ATOM_NEIGH ) {
 
2636
            continue; /*  error: stereo center cannot have more than 4 neighbors */ /*   <BRKPT> */
 
2637
        }
 
2638
        /*  at[i1] is a stereo center */
 
2639
        if ( !PARITY_CALCULATE(at[i].stereo_atom_parity) && !PARITY_ILL_DEF(at[i].stereo_atom_parity) ) {
 
2640
            continue;
 
2641
        }
 
2642
        /* neighbors sorted according to symm. ranks (primary key) and canon. ranks (secondary key), in descending order */
 
2643
        /* sorting guarantees that for two constit. equ. neighbors canon. ranks of the first is greater */
 
2644
        /* !!! previously (but not anymore) the canon. rank of neigh[0] was greater than the others !!! */
 
2645
        for ( j = 0; j < at[i].valence; j ++ ) {
 
2646
            neigh[j] = nl[i][j+1]; /*  sorting does NOT guarantee that canon. rank of neigh[0] is greater than others */
 
2647
        }
 
2648
        /* 
 
2649
         *  mode = 0 => Standard approach: switch 2 neighbors
 
2650
         *         1 => Check for C2v reflection leading to parity inversion
 
2651
         *         2 => Check for C2 rotation preserving parities
 
2652
         *         3 => Check for S4 rotation/reflection leading to parity inversion
 
2653
         */
 
2654
#if ( CHECK_C2v_S4_SYMM == 1 )
 
2655
        if ( nNeighMode = NEIGH_MODE_RING && at[i].valence == 4 &&
 
2656
             nSymmRank[(int)neigh[0]] == nSymmRank[(int)neigh[1]] &&
 
2657
             nSymmRank[(int)neigh[2]] == nSymmRank[(int)neigh[3]] &&
 
2658
             !at[i].bCutVertex 
 
2659
           ) {
 
2660
            if ( nSymmRank[(int)neigh[1]] == nSymmRank[(int)neigh[2]] ) {
 
2661
                max_mode = MAP_MODE_S4;
 
2662
            } else {
 
2663
                max_mode = inchi_max(MAP_MODE_C2v, MAP_MODE_C2);
 
2664
            }
 
2665
        } else {
 
2666
            max_mode = MAP_MODE_STD;
 
2667
        }
 
2668
#else
 
2669
        max_mode = MAP_MODE_STD;
 
2670
#endif
 
2671
        for ( j = 0; j < at[i].valence && at[i].parity && !RETURNED_ERROR(ret_failed); j ++ ) {
 
2672
            for ( k = j+1; k < at[i].valence && at[i].parity && !RETURNED_ERROR(ret_failed); k ++ ) {
 
2673
                for ( mode = 0; mode <= max_mode && at[i].parity && !RETURNED_ERROR(ret_failed); mode ++ ) {
 
2674
                    if ( nSymmRank[(int)neigh[j]] != nSymmRank[(int)neigh[k]] ) {
 
2675
                        continue; /*  the two neighbors are not constitutionally identical */
 
2676
                    }
 
2677
                    bRingNeigh = (at[(int)neigh[j]].nRingSystem == at[(int)neigh[k]].nRingSystem);
 
2678
                    switch ( nNeighMode ) {
 
2679
                    case NEIGH_MODE_CHAIN:
 
2680
                        if ( bRingNeigh ) {
 
2681
                            nNumEqRingNeigh ++;
 
2682
                            continue;
 
2683
                        }
 
2684
                        nl01 = nl;
 
2685
                        nl02 = nl;
 
2686
                        nSymmRank1 = nSymmRank;
 
2687
                        nSymmRank2 = nSymmRank;
 
2688
                        break;
 
2689
                    case NEIGH_MODE_RING:
 
2690
                        if ( !bRingNeigh )
 
2691
                            continue;
 
2692
                        /*  break a tie between the two contitutionally equivalent neighbors, */
 
2693
                        /*  refine the two partitions, sort neighbors lists nl1, nl2 */
 
2694
                        bSymmNeigh = BreakNeighborsTie(  at, num_atoms, num_at_tg, MAX_ATOMS+1, i,
 
2695
                                            neigh, j, k, mode,
 
2696
                                            pRankStack1, pRankStack2, nTempRank, NeighList, nSymmRank, nCanonRank,
 
2697
                                            nl1, nl2, &pCS->lNumNeighListIter );
 
2698
                        if ( bSymmNeigh <= 0 ) {
 
2699
                            if ( ret_failed > bSymmNeigh )
 
2700
                                ret_failed = bSymmNeigh;
 
2701
                            continue;
 
2702
                        }
 
2703
                        nl01 = nl1;
 
2704
                        nl02 = nl2;
 
2705
                        nSymmRank1 = pRankStack1[0];
 
2706
                        nSymmRank2 = pRankStack2[0];
 
2707
                        break;
 
2708
                    default:
 
2709
                        return CT_STEREOCOUNT_ERR;  /*  <BRKPT> */
 
2710
                    }
 
2711
 
 
2712
                    /*  initialize arrays */
 
2713
                    memset( nVisited1, 0, sizeof(nVisited1[0])*num_atoms );
 
2714
                    memset( nVisited2, 0, sizeof(nVisited2[0])*num_atoms );
 
2715
                    memset( nAtomNumberCanon1, 0, sizeof(nAtomNumberCanon1[0])*num_atoms );
 
2716
                    memset( nAtomNumberCanon2, 0, sizeof(nAtomNumberCanon2[0])*num_atoms );
 
2717
                    nLength = 1;
 
2718
                    nVisited1[i] = i+1;   /*  start atom is same */
 
2719
                    nVisited2[i] = i+1;
 
2720
                    nAtomNumberCanon1[i] = nLength;
 
2721
                    nAtomNumberCanon2[i] = nLength;
 
2722
                    nAvoidCheckAtom[0] = i;
 
2723
                    nAvoidCheckAtom[1] = MAX_ATOMS+1;
 
2724
                
 
2725
                    bParitiesInverted  = (mode==MAP_MODE_C2v || mode==MAP_MODE_S4)? -1 : 0;
 
2726
                    /*
 
2727
                    if (nNeighMode==NEIGH_MODE_RING && at[i].valence==MAX_NUM_STEREO_ATOM_NEIGH) {
 
2728
                        AT_RANK other_neigh[2];
 
2729
                        int     n;
 
2730
                        for ( m = n = 0; m < MAX_NUM_STEREO_ATOM_NEIGH; m ++ ) {
 
2731
                            if ( at[i].neighbor[m] != neigh[j] && at[i].neighbor[m] != neigh[k] )
 
2732
                                other_neigh[n++] = at[i].neighbor[m];
 
2733
                        }
 
2734
                        if ( nSymmRank[(int)other_neigh[0]] == nSymmRank[(int)other_neigh[1]] )
 
2735
                            bParitiesInverted = -1;
 
2736
                    }
 
2737
                    */
 
2738
                    /* allow matching inverted centers only in case all equivalent neighbors in same ring system */
 
2739
 
 
2740
                    ret2 = 0; /* initilize. 1/8/2002 */
 
2741
                
 
2742
                    if ( 0 < (ret1 = CreateCheckSymmPaths( at, (AT_RANK)i, neigh[j], (AT_RANK)i, neigh[k],
 
2743
                                               nAvoidCheckAtom,
 
2744
                                               nVisited1, nVisited2, nAtomNumberCanon1, nAtomNumberCanon2,
 
2745
                                               nl01, nl02, nSymmRank1, nSymmRank2, nCanonRank, &nLength,
 
2746
                                               &bParitiesInverted, mode ) ) &&
 
2747
                         0 < (ret2 = CalculatedPathsParitiesAreIdentical( at, num_atoms, nSymmRank,
 
2748
                                               nCanonRank, nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
 
2749
                                               nVisited1, nVisited2, (AT_RANK)MAX_ATOMS, (AT_RANK)i,
 
2750
                                               neigh[j], neigh[k], nNeighMode, 
 
2751
                                               bParitiesInverted, mode, pCS,
 
2752
                                               vABParityUnknown) ) ) {
 
2753
                        if ( ret2 & ( NOT_WELL_DEF_UNKN | NOT_WELL_DEF_UNDF ) ) {
 
2754
                            /*  possibly change the parity to unknown or undefined */
 
2755
                            int new_parity = (ret2 & NOT_WELL_DEF_UNKN)? vABParityUnknown /*AB_PARITY_UNKN*/: AB_PARITY_UNDF;
 
2756
                            if ( PARITY_ILL_DEF(at[i].stereo_atom_parity) &&
 
2757
                                 PARITY_VAL(at[i].stereo_atom_parity) > new_parity ||
 
2758
                                 PARITY_CALCULATE(at[i].stereo_atom_parity) ) {
 
2759
                                /*  set new unknown or undefined parity */
 
2760
                                at[i].stereo_atom_parity = (at[i].stereo_atom_parity ^ PARITY_VAL(at[i].stereo_atom_parity)) | PARITY_VAL(new_parity);
 
2761
                                at[i].parity = PARITY_VAL(new_parity);
 
2762
                                /*  Remove from pCS */
 
2763
                                nAtomRank1 = nCanonRank[i];
 
2764
                                for ( n = 0, m = pCS->nLenLinearCTStereoCarb-1; n <= m; n ++ ) {
 
2765
                                    if ( pCS->LinearCTStereoCarb[n].at_num == nAtomRank1 ) {
 
2766
                                        pCS->LinearCTStereoCarb[n].parity = PARITY_VAL(new_parity);
 
2767
    #if ( bRELEASE_VERSION == 0 )
 
2768
                                        pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
 
2769
    #endif
 
2770
                                        m = -1;
 
2771
                                        break;
 
2772
                                    }
 
2773
                                }
 
2774
                                if ( m >= 0 ) {
 
2775
                                    ret = CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
 
2776
                                    goto exit_function;
 
2777
                                }
 
2778
                                ret ++; /*  number of removed or set unknown/undefined parities */
 
2779
                            }
 
2780
                        } else {
 
2781
                            RemoveOneStereoCenter( at, i /* atom number*/ );
 
2782
                            /*  Remove from pCS */
 
2783
                            nAtomRank1 = nCanonRank[i];
 
2784
                            for ( n = 0, m = pCS->nLenLinearCTStereoCarb-1; n <= m; n ++ ) {
 
2785
                                if ( pCS->LinearCTStereoCarb[n].at_num == nAtomRank1 ) {
 
2786
                                    if ( n < m ) { /*  remove pCS->LinearCTStereoDble[n] */
 
2787
                                        memmove( pCS->LinearCTStereoCarb + n,
 
2788
                                                 pCS->LinearCTStereoCarb + n + 1,
 
2789
                                                 (m-n)*sizeof(pCS->LinearCTStereoCarb[0]) );
 
2790
                                    }
 
2791
                                    pCS->nLenLinearCTStereoCarb --;
 
2792
    #if ( bRELEASE_VERSION == 0 )
 
2793
                                    pCS->bExtract |= EXTR_CALC_USED_TO_REMOVE_PARITY;
 
2794
    #endif
 
2795
                                    m = -1;
 
2796
                                    break;
 
2797
                                }
 
2798
                            }
 
2799
                            if ( m >= 0 ) {
 
2800
                                ret = CT_STEREOCOUNT_ERR;  /*   <BRKPT> */
 
2801
                                goto exit_function;
 
2802
                            }
 
2803
                            ret ++;  /*  number of removed or set unknown/undefined parities */
 
2804
                        }
 
2805
                    } else {
 
2806
                        if ( !ret_failed ) {
 
2807
                            if ( ret1 < 0 ) {
 
2808
                                ret_failed = ret1;
 
2809
                            } else
 
2810
                            if ( ret2 < 0 ) {
 
2811
                                ret_failed = ret2;
 
2812
                            }
 
2813
                        }
 
2814
                        if ( !RETURNED_ERROR(ret_failed) ) {
 
2815
                            if ( RETURNED_ERROR( ret1 ) )
 
2816
                                ret_failed = ret1;
 
2817
                            else
 
2818
                            if ( RETURNED_ERROR( ret2 ) )
 
2819
                                ret_failed = ret2;
 
2820
                        }
 
2821
                    }
 
2822
                }
 
2823
            }
 
2824
        }
 
2825
    }
 
2826
    if ( nNeighMode == NEIGH_MODE_CHAIN && nNumEqRingNeigh && !RETURNED_ERROR(ret_failed) ) {
 
2827
        nNeighMode = NEIGH_MODE_RING;
 
2828
        goto second_pass;
 
2829
    }
 
2830
 
 
2831
exit_function:
 
2832
 
 
2833
    return RETURNED_ERROR(ret_failed)? ret_failed : ret_failed? -(ret+1) : ret;
 
2834
}
 
2835
 
 
2836
/**************************************************************************************/
 
2837
int RemoveCalculatedNonStereo( sp_ATOM *at, int num_atoms, int num_at_tg,
 
2838
                              AT_RANK **pRankStack1, AT_RANK **pRankStack2, AT_RANK *nTempRank, NEIGH_LIST *NeighList,
 
2839
                              const AT_RANK *nSymmRank, AT_RANK *nCanonRank, 
 
2840
                              AT_RANK *nAtomNumberCanon, CANON_STAT *pCS,
 
2841
                              int vABParityUnknown)
 
2842
{
 
2843
    NEIGH_LIST *nl = NULL, *nl1 = NULL, *nl2 = NULL;
 
2844
    AT_RANK    *nVisited1 = NULL, *nVisited2 = NULL, *nAtomNumberCanon1 = NULL, *nAtomNumberCanon2 = NULL;
 
2845
    int        nNumRemoved = 0, nTotRemoved = 0, ret = 0, ret1 = 0, ret2 = 0;
 
2846
    
 
2847
    if ( !AllocateForNonStereoRemoval( at, num_atoms, nSymmRank, nCanonRank,
 
2848
                                       &nAtomNumberCanon1, &nAtomNumberCanon2,
 
2849
                                       &nl, &nl1, &nl2, &nVisited1, &nVisited2 ) ) {
 
2850
        return CT_OUT_OF_RAM;  /*   <BRKPT> */
 
2851
    }
 
2852
    
 
2853
    do {
 
2854
        nNumRemoved = 0;
 
2855
        /*  bonds */
 
2856
        ret = RemoveCalculatedNonStereoBondParities( at, num_atoms, num_at_tg,
 
2857
                                              pRankStack1, pRankStack2, nTempRank, NeighList,
 
2858
                                              nCanonRank, nSymmRank,
 
2859
                                              nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
 
2860
                                              nl, nl1, nl2, nVisited1, nVisited2, pCS,
 
2861
                                              vABParityUnknown);
 
2862
        if ( RETURNED_ERROR( ret ) ) {
 
2863
            goto exit_function;
 
2864
        }
 
2865
        if ( ret < 0  ) {
 
2866
            if ( ret < ret1 ) {  /*   <BRKPT> */
 
2867
                ret1 = ret;          
 
2868
            }
 
2869
            ret = - ( ret + 1 ); /*  number of removed */
 
2870
        }
 
2871
        nNumRemoved += ret;
 
2872
 
 
2873
        /*  centers */
 
2874
        ret = RemoveCalculatedNonStereoCenterParities( at, num_atoms, num_at_tg,
 
2875
                                              pRankStack1, pRankStack2, nTempRank, NeighList,
 
2876
                                              nCanonRank, nSymmRank,
 
2877
                                              nAtomNumberCanon, nAtomNumberCanon1, nAtomNumberCanon2,
 
2878
                                              nl, nl1, nl2, nVisited1, nVisited2, pCS,
 
2879
                                              vABParityUnknown);
 
2880
        if ( RETURNED_ERROR( ret ) ) {
 
2881
            goto exit_function;
 
2882
        }
 
2883
        if ( ret < 0  ) {
 
2884
            if ( ret < ret2 ) {  /*   <BRKPT> */
 
2885
                ret2 = ret;          
 
2886
            }
 
2887
            ret = - ( ret + 1 ); /*  number of removed */
 
2888
        }
 
2889
        nNumRemoved += ret;
 
2890
 
 
2891
        nTotRemoved += nNumRemoved;
 
2892
 
 
2893
    } while ( nNumRemoved );
 
2894
 
 
2895
    if ( !RETURNED_ERROR( ret1 ) && !RETURNED_ERROR( ret2 ) ) {
 
2896
        ret = inchi_min( ret1, ret2 );
 
2897
        ret = (ret >= 0)? nTotRemoved : -(1+nTotRemoved);
 
2898
    }
 
2899
 
 
2900
exit_function:
 
2901
    
 
2902
    DeAllocateForNonStereoRemoval( &nAtomNumberCanon1, &nAtomNumberCanon2, &nl, &nl1, &nl2, &nVisited1, &nVisited2 );
 
2903
    
 
2904
    return ret;
 
2905
}
 
2906
#endif /* } REMOVE_CALC_NONSTEREO */