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