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