rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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 */