rino 0.1.0

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