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 : :
42 : : #include <stdlib.h>
43 : : #include <string.h>
44 : :
45 : : #include "mode.h"
46 : : #include "ichicant.h"
47 : : #include "ichicomn.h"
48 : : #include "ichister.h"
49 : :
50 : : #include "bcf_s.h"
51 : :
52 : : typedef struct tagStereoBondNeighbor
53 : : {
54 : : /* *n = sort key */
55 : : AT_RANK nRank; /* 1 opposite atom rank; equal ranks mean constit. equivalence */
56 : : AT_RANK nNeighRank1; /* rank of the neighbor in the direction to the opposite atom */
57 : : AT_RANK nNeighRank2; /* rank of the opposite atom neighbor in the direction */
58 : : /* to the current atom */
59 : : AT_RANK num; /* number of same type bonds to constitutionally */
60 : : /* equivalent neighbors */
61 : : AT_RANK num_any_parity; /* at least one atom has parity in 1..4 range */
62 : : AT_RANK num_defined_parity; /* number of neighbors with defined parity <= num */
63 : : /* AT_RANK num_undef_parity; */
64 : : /* AT_RANK num_unkn_parity; */
65 : : AT_RANK what2do;
66 : : U_CHAR cumulene_len; /* high nimble bits: (cumulene length - 1) */
67 : : U_CHAR bond_type; /* *2 all same, not a real bond type */
68 : : } STEREO_BOND_NEIGH;
69 : :
70 : :
71 : :
72 : : /* Local prototypes */
73 : :
74 : : int SetHalfStereoBondIllDefPariy( sp_ATOM *at,
75 : : int jn, /* atom number*/
76 : : int k1 /* stereo bond number*/,
77 : : int new_parity );
78 : :
79 : : int RemoveHalfStereoBond( sp_ATOM *at,
80 : : int jn, /* atom number*/
81 : : int k1 /* stereo bond number*/ );
82 : :
83 : : int SetKnownStereoBondParities( CANON_GLOBALS *pCG,
84 : : sp_ATOM *at,
85 : : int num_atoms,
86 : : const AT_RANK *nCanonRank,
87 : : const AT_RANK *nRank,
88 : : const AT_RANK *nAtomNumber );
89 : :
90 : : int MarkKnownEqualStereoBondParities( sp_ATOM *at,
91 : : int num_atoms,
92 : : const AT_RANK *nRank,
93 : : const AT_RANK *nAtomNumber );
94 : :
95 : : int GetNextNeighborAndRank( sp_ATOM *at,
96 : : AT_RANK cur,
97 : : AT_RANK prev,
98 : : AT_RANK *n,
99 : : AT_RANK *cr,
100 : : const AT_RANK *nCanonRank );
101 : :
102 : : int GetAndCheckNextNeighbors( sp_ATOM *at,
103 : : AT_RANK cur1,
104 : : AT_RANK prev1,
105 : : AT_RANK cur2,
106 : : AT_RANK prev2,
107 : : AT_RANK *n1,
108 : : AT_RANK *n2,
109 : : AT_RANK *nVisited1,
110 : : AT_RANK *nVisited2,
111 : : const AT_RANK *nRank,
112 : : const AT_RANK *nCanonRank );
113 : :
114 : : AT_RANK PathsHaveIdenticalKnownParities( sp_ATOM *at,
115 : : AT_RANK prev1,
116 : : AT_RANK cur1,
117 : : AT_RANK prev2,
118 : : AT_RANK cur2,
119 : : AT_RANK *nVisited1,
120 : : AT_RANK *nVisited2,
121 : : const AT_RANK *nRank,
122 : : const AT_RANK *nCanonRank,
123 : : AT_RANK nLength );
124 : :
125 : : int RemoveKnownNonStereoBondParities( sp_ATOM *at,
126 : : int num_atoms,
127 : : const AT_RANK *nCanonRank,
128 : : const AT_RANK *nRank,
129 : : CANON_STAT *pCS );
130 : :
131 : : int SetKnownStereoCenterParities( CANON_GLOBALS *pCG,
132 : : sp_ATOM *at,
133 : : int num_atoms,
134 : : const AT_RANK *nCanonRank,
135 : : const AT_RANK *nRank,
136 : : const AT_RANK *nAtomNumber );
137 : : int RemoveKnownNonStereoCenterParities( CANON_GLOBALS *pCG,
138 : : sp_ATOM *at,
139 : : int num_atoms,
140 : : const AT_RANK *nCanonRank,
141 : : const AT_RANK *nRank,
142 : : CANON_STAT *pCS );
143 : :
144 : : int MarkKnownEqualStereoCenterParities( sp_ATOM *at,
145 : : int num_atoms,
146 : : const AT_RANK *nRank,
147 : : const AT_RANK *nAtomNumber );
148 : :
149 : :
150 : :
151 : :
152 : : /****************************************************************************
153 : : Depth First Search for an atom with parity
154 : : ****************************************************************************/
155 : 36 : int find_atoms_with_parity( sp_ATOM *at,
156 : : S_CHAR *visited,
157 : : int from_atom,
158 : : int cur_atom )
159 : : {
160 : : int i, next_atom;
161 : :
162 [ - + ]: 36 : if (visited[cur_atom])
163 : : {
164 : 0 : return 0;
165 : : }
166 [ - + ]: 36 : if (at[cur_atom].parity)
167 : : {
168 : 0 : return 1;
169 : : }
170 : :
171 : 36 : visited[cur_atom] = 1;
172 : :
173 [ + + ]: 84 : for (i = 0; i < at[cur_atom].valence; i++)
174 : : {
175 : 48 : next_atom = at[cur_atom].neighbor[i];
176 : :
177 [ + + - + ]: 60 : if (next_atom != from_atom &&
178 : 12 : find_atoms_with_parity( at, visited, cur_atom, next_atom ))
179 : : {
180 : 0 : return 1;
181 : : }
182 : : }
183 : :
184 : 36 : return 0;
185 : : }
186 : :
187 : :
188 : : /****************************************************************************/
189 : 0 : int SetHalfStereoBondIllDefPariy( sp_ATOM *at,
190 : : int jn, /* atom number*/
191 : : int k1 /* stereo bond number*/,
192 : : int new_parity )
193 : : {
194 : : int parity;
195 [ # # # # ]: 0 : if (k1 < MAX_NUM_STEREO_BOND_NEIGH && at[jn].stereo_bond_neighbor[k1])
196 : : {
197 : 0 : parity = at[jn].stereo_bond_parity[k1] ^ PARITY_VAL( at[jn].stereo_bond_parity[k1] );
198 : 0 : at[jn].stereo_bond_parity[k1] = parity | PARITY_VAL( new_parity );
199 : 0 : at[jn].parity = PARITY_VAL( new_parity );
200 : 0 : return 1; /* success */
201 : : }
202 : :
203 : 0 : return 0; /* failed */
204 : : }
205 : :
206 : :
207 : : /****************************************************************************/
208 : 0 : int RemoveHalfStereoBond( sp_ATOM *at,
209 : : int jn, /* atom number*/
210 : : int k1 /* stereo bond number*/ )
211 : : {
212 : : int k2;
213 [ # # # # ]: 0 : if (k1 < MAX_NUM_STEREO_BOND_NEIGH && at[jn].stereo_bond_neighbor[k1])
214 : : {
215 [ # # ]: 0 : for (k2 = k1; k2 < MAX_NUM_STEREO_BOND_NEIGH - 1; k2++) /* djb-rwth: loop condition corrected (buffer error) */
216 : : {
217 : 0 : at[jn].stereo_bond_neighbor[k2] = at[jn].stereo_bond_neighbor[k2 + 1];
218 : 0 : at[jn].stereo_bond_ord[k2] = at[jn].stereo_bond_ord[k2 + 1];
219 : 0 : at[jn].stereo_bond_z_prod[k2] = at[jn].stereo_bond_z_prod[k2 + 1];
220 : 0 : at[jn].stereo_bond_parity[k2] = at[jn].stereo_bond_parity[k2 + 1];
221 : : }
222 : 0 : at[jn].stereo_bond_neighbor[k2] = 0;
223 : 0 : at[jn].stereo_bond_ord[k2] = 0;
224 : 0 : at[jn].stereo_bond_z_prod[k2] = 0;
225 : 0 : at[jn].stereo_bond_parity[k2] = 0;
226 : :
227 [ # # ]: 0 : if (!at[jn].stereo_bond_neighbor[0])
228 : : { /* curled braces added 6-6-2002 */
229 : 0 : at[jn].parity = 0;
230 : 0 : at[jn].stereo_atom_parity = 0;
231 : 0 : at[jn].final_parity = 0;
232 : : /* at[jn].bHasStereoOrEquToStereo = 0; */
233 : : }
234 : 0 : return 1; /* success */
235 : : }
236 : :
237 : 0 : return 0; /* failed */
238 : : }
239 : :
240 : :
241 : : /****************************************************************************/
242 : 0 : int SetOneStereoBondIllDefParity( sp_ATOM *at,
243 : : int jc, /* atom number */
244 : : int k, /* stereo bond ord. number */
245 : : int new_parity )
246 : : {
247 : 0 : int k1, ret = 0, kn, jn = (int) at[jc].stereo_bond_neighbor[k] - 1;
248 : :
249 : : /* opposite end */
250 : 0 : for (k1 = ret = 0;
251 [ # # # # ]: 0 : k1 < MAX_NUM_STEREO_BOND_NEIGH && ( kn = at[jn].stereo_bond_neighbor[k1] );
252 : 0 : k1++) /* djb-rwth: removing redundant code */
253 : : {
254 [ # # ]: 0 : if (kn - 1 == jc)
255 : : {
256 : 0 : ret = SetHalfStereoBondIllDefPariy( at, jn, /* atom number*/ k1 /* stereo bond number*/, new_parity );
257 : 0 : break;
258 : : }
259 : : }
260 : :
261 [ # # ]: 0 : if (ret)
262 : : {
263 : 0 : ret = SetHalfStereoBondIllDefPariy( at, jc, k, new_parity );
264 : : }
265 : :
266 : 0 : return ret;
267 : : }
268 : :
269 : :
270 : : /****************************************************************************/
271 : 0 : int RemoveOneStereoBond( sp_ATOM *at,
272 : : int jc, /* atom number */
273 : : int k /* stereo bond number */
274 : : )
275 : : {
276 : 0 : int k1, ret = 0, kn, jn = (int) at[jc].stereo_bond_neighbor[k] - 1;
277 : :
278 : : /* opposite end */
279 : 0 : for (k1 = ret = 0;
280 [ # # # # ]: 0 : k1 < MAX_NUM_STEREO_BOND_NEIGH && ( kn = at[jn].stereo_bond_neighbor[k1] );
281 : 0 : k1++) /* djb-rwth: removing redundant code */
282 : : {
283 [ # # ]: 0 : if (kn - 1 == jc)
284 : : {
285 : 0 : ret = RemoveHalfStereoBond( at, jn, k1 );
286 : 0 : break;
287 : : }
288 : : }
289 : :
290 [ # # ]: 0 : if (ret)
291 : : {
292 : 0 : ret = RemoveHalfStereoBond( at, jc, k );
293 : : }
294 : :
295 : 0 : return ret;
296 : : }
297 : :
298 : :
299 : : /****************************************************************************/
300 : 0 : int RemoveOneStereoCenter( sp_ATOM *at,
301 : : int jc /* atom number*/ )
302 : : {
303 [ # # ]: 0 : if (at[jc].parity)
304 : : {
305 : 0 : at[jc].parity = 0; /* remove parity */
306 : 0 : at[jc].stereo_atom_parity = 0;
307 : 0 : at[jc].final_parity = 0;
308 : : /* at[jc].bHasStereoOrEquToStereo = 0; */
309 : 0 : return 1;
310 : : }
311 : :
312 : 0 : return 0; /* failed: not a stereo center */
313 : : }
314 : :
315 : :
316 : : /****************************************************************************
317 : : Remove stereo parity from centers having constitutionally equivalent
318 : : cut-vertex neighbors whose attachments do not have stereogenic elements.
319 : : Currently checks ALL constitutionally equivalent neighbors.
320 : : To optimize, check only one.
321 : : ****************************************************************************/
322 : 56 : int UnmarkNonStereo( CANON_GLOBALS *pCG,
323 : : sp_ATOM *at,
324 : : int num_atoms,
325 : : const AT_RANK *nRank,
326 : : const AT_RANK *nAtomNumber,
327 : : int bIsotopic )
328 : : {
329 : : int i, i1, i2, j, k, k1, k2, kn /* neigh*/, val, ic/* center*/, jc, num_implicit_H;
330 : 56 : int num_neighbors_with_parity, num_no_parity_atoms, num_removed_parities = -1, num_removed_parities0;
331 : : AT_RANK nNeighborNumber[MAX_NUM_STEREO_ATOM_NEIGH];
332 : : AT_RANK nPrevAtomRank, nPrevNeighRank;
333 : : #ifdef FIX_OLEAN_SPIRO_CHIRALITY_DETECTION_BUG
334 : 56 : int num_in_same_ring_system = 1, nRingSystem, num_with_eq_neigh_in_same_ring_system = 0; /* djb-rwth: although unlikely to ever occur, uninitialised num_in_same_ring_system variable can lead to garbage value, including 0 which leads to various errors and inconsistency with 1.06 outputs -- function rewriting and discussion required */
335 : : #endif
336 : :
337 : :
338 : 56 : S_CHAR *visited = (S_CHAR *) inchi_malloc( num_atoms * sizeof( visited[0] ) );
339 : :
340 [ - + ]: 56 : if (!visited)
341 : : {
342 : 0 : goto exit_function;
343 : : }
344 : :
345 : 56 : num_removed_parities = 0;
346 : 56 : num_no_parity_atoms = 0;
347 : :
348 : : do
349 : : {
350 : 62 : num_removed_parities0 = num_removed_parities;
351 : :
352 [ + + ]: 745 : for (i = i1 = 0, nPrevAtomRank = 0; i <= num_atoms; i++)
353 : : {
354 : : /* bounds violation check (i!=num_atoms) added 6-21-2002 */
355 [ + + + + ]: 683 : if (i == num_atoms || nPrevAtomRank != nRank[j = nAtomNumber[i]]
356 : : /* at[j].parity && 1 < at[j].valence && at[j].valence < MAX_NUM_STEREO_ATOM_NEIGH*/)
357 : : {
358 : : /* end of constitutionally equivalent atoms sequence */
359 : : /* nPrevRank = nRank[j]; */
360 : 650 : i2 = i;
361 [ + + ]: 650 : if (i2 - i1 > num_no_parity_atoms /*&& at[jc = nAtomNumber[i1]].parity*/)
362 : : {
363 : : /* at[nAtomNumber[i1]]..at[nAtomNumber[i2-1]] are constitutionally equivalent and some of them have parity */
364 : 204 : jc = nAtomNumber[i1];
365 : 204 : num_no_parity_atoms = 0;
366 : 204 : val = at[jc].valence; /* all equivalent atoms have equal valences, etc. (except parities) */
367 [ + - ]: 204 : num_implicit_H = at[jc].endpoint ? 0 : at[jc].num_H;
368 : : /* Only atoms with valence <= MAX_NUM_STEREO_ATOM_NEIGH may have parity. However, check: */
369 [ - + ]: 204 : if (val + num_implicit_H > MAX_NUM_STEREO_ATOM_NEIGH)
370 : : {
371 : 0 : continue; /* program error ??? */ /* <BRKPT> */
372 : : }
373 [ + + ]: 816 : for (k = 0; k < val; k++)
374 : : {
375 : 612 : nNeighborNumber[k] = k; /* initialize an array of indexes for sorting */
376 : : }
377 : : /* check parities */
378 [ + + ]: 411 : for (ic = i1; ic < i2; ic++)
379 : : {
380 : 207 : jc = nAtomNumber[ic];
381 : : /* sort neighbors according to their canon. equivalence ranks */
382 : 207 : pCG->m_pNeighborsForSort = at[jc].neighbor;
383 : 207 : pCG->m_pn_RankForSort = nRank;
384 : 207 : insertions_sort( pCG, nNeighborNumber, val, sizeof( nNeighborNumber[0] ), CompNeighborsAT_NUMBER );
385 : 207 : num_neighbors_with_parity = -1; /* non-zero */
386 [ + - ]: 622 : for (k = k1 = 0, nPrevNeighRank = 0; k <= val; k++)
387 : : {
388 [ + + + + ]: 622 : if (k == val || nPrevNeighRank != nRank[at[jc].neighbor[nNeighborNumber[k]]])
389 : : {
390 : 610 : k2 = k;
391 [ + + ]: 610 : if (k2 - k1 > 1)
392 : : {
393 : : /* found 2 or more constitutionally equivalent neighbors */
394 : : /* Check if they have only non-stereogenic neighbors */
395 : : #ifdef FIX_OLEAN_SPIRO_CHIRALITY_DETECTION_BUG
396 : 12 : num_in_same_ring_system = nRingSystem = 0;
397 [ + + ]: 36 : for (kn = k1; kn < k2; kn++) /* djb-rwth: removing redundant code */
398 : : {
399 : 24 : int nCurNeighRingSystem = at[(int) at[jc].neighbor[nNeighborNumber[kn]]].nRingSystem;
400 [ + + ]: 24 : if (!nRingSystem)
401 : : {
402 : 12 : nRingSystem = nCurNeighRingSystem;
403 : : }
404 : : else
405 : : {
406 : 12 : num_in_same_ring_system += ( nRingSystem == nCurNeighRingSystem );
407 : : }
408 : : }
409 : : #endif
410 : :
411 [ + + ]: 36 : for (kn = k1, num_neighbors_with_parity = 0; kn < k2; kn++)
412 : : {
413 : 24 : memset( visited, 0, num_atoms * sizeof( visited[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
414 : 24 : visited[jc] = 1; /* starting point; the only atom with parity */
415 : 24 : num_neighbors_with_parity +=
416 : 24 : find_atoms_with_parity( at, visited, jc, (int) at[jc].neighbor[nNeighborNumber[kn]] );
417 : : }
418 : : }
419 : : /* if ( !num_neighbors_with_parity ) */
420 : : #ifdef FIX_OLEAN_SPIRO_CHIRALITY_DETECTION_BUG
421 [ + + + - ]: 610 : if (!num_neighbors_with_parity && !num_in_same_ring_system)
422 : : #else
423 : : if (!num_neighbors_with_parity)
424 : : #endif
425 : : {
426 : 12 : break; /* at[jc] cannot have defined parity */
427 : : }
428 [ + + ]: 598 : if (k + 1 < val)
429 : : {
430 : 403 : k1 = k; /* at least 2 more neighbors left */
431 : 403 : nPrevNeighRank = nRank[at[jc].neighbor[nNeighborNumber[k]]];
432 : : }
433 : : else
434 : : {
435 : 195 : break;
436 : : }
437 : : }
438 : : }
439 [ - + ]: 207 : if (num_implicit_H > 1)
440 : : {
441 [ # # # # ]: 0 : if ((bIsotopic && ( at[jc].num_iso_H[0] > 1 ||
442 [ # # ]: 0 : at[jc].num_iso_H[1] > 1 ||
443 [ # # # # ]: 0 : at[jc].num_iso_H[2] > 1 )) ||
444 [ # # ]: 0 : num_implicit_H > NUM_H_ISOTOPES ||
445 : : !bIsotopic) /* djb-rwth: addressing LLVM warning */
446 : : {
447 : 0 : num_neighbors_with_parity = 0;
448 : : }
449 : : }
450 : : /* increment if: */
451 : : /* (a) constitutionally equivalent neighbors do exist, and */
452 : : /* (b) all constitutionally equivalent neighbors do not have parity, and */
453 : : /* (c) all constitutionally equivalent neighbors are not connected to atoms with parity */
454 : 207 : num_no_parity_atoms += !num_neighbors_with_parity;
455 : : #ifdef FIX_OLEAN_SPIRO_CHIRALITY_DETECTION_BUG
456 : 207 : num_with_eq_neigh_in_same_ring_system += ( num_in_same_ring_system != 0 ); /* djb-rwth: initialisation of num_in_same_ring_system is required to avoid garbage value */
457 : : #endif
458 : : }
459 : : #ifdef FIX_OLEAN_SPIRO_CHIRALITY_DETECTION_BUG
460 [ + + + + ]: 204 : if (num_no_parity_atoms == i2 - i1 && num_with_eq_neigh_in_same_ring_system != i2 - i1)
461 : : #else
462 : : if (num_no_parity_atoms == i2 - i1)
463 : : #endif
464 : :
465 : : {
466 : : /* all atoms at[nAtomNumber[i1]]..at[nAtomNumber[i2-1]] cannot be */
467 : : /* stereo centers or belong to stereo bonds */
468 [ + + ]: 20 : for (ic = i1; ic < i2; ic++)
469 : : {
470 : : int jn;
471 : 11 : jc = nAtomNumber[ic];
472 : 11 : at[jc].parity = 0; /* remove parity */
473 : 11 : at[jc].stereo_atom_parity = 0;
474 : 11 : at[jc].final_parity = 0;
475 : 11 : at[jc].bHasStereoOrEquToStereo = 0;
476 : : /* remove stereo bonds */
477 [ + - - + ]: 11 : for (k = 0; k < MAX_NUM_STEREO_BOND_NEIGH && ( jn = at[jc].stereo_bond_neighbor[k] ); k++)
478 : : {
479 : 0 : jn--; /* stereo bond neighbor */
480 : : /* opposite end */
481 [ # # # # ]: 0 : for (k1 = 0; k1 < MAX_NUM_STEREO_BOND_NEIGH && ( kn = at[jn].stereo_bond_neighbor[k1] ); k1++)
482 : : {
483 [ # # ]: 0 : if (kn - 1 == jc)
484 : : {
485 : 0 : RemoveHalfStereoBond( at, jn, k1 );
486 : 0 : break;
487 : : }
488 : : }
489 : : /* at at[jc] stereo bond end; since references to all at[jc] */
490 : : /* stereo bond neighbors are to be removed, do not shift them */
491 : 0 : at[jc].stereo_bond_neighbor[k] = 0;
492 : 0 : at[jc].stereo_bond_ord[k] = 0;
493 : 0 : at[jc].stereo_bond_z_prod[k] = 0;
494 : 0 : at[jc].stereo_bond_parity[k] = 0;
495 : : }
496 : : }
497 : 9 : num_removed_parities += num_no_parity_atoms;
498 : : }
499 : : }
500 [ + + ]: 650 : if (i < num_atoms)
501 : : {
502 : 588 : nPrevAtomRank = nRank[j];
503 : 588 : i1 = i;
504 : : }
505 : 650 : num_no_parity_atoms = 0;
506 : : }
507 [ + + + + ]: 683 : num_no_parity_atoms += ( i < num_atoms && !at[j].parity );
508 : : }
509 : : }
510 [ + + ]: 62 : while (num_removed_parities != num_removed_parities0);
511 : :
512 : 56 : exit_function:
513 [ + - ]: 56 : if (visited)
514 : : {
515 [ + - ]: 56 : inchi_free( visited );
516 : : }
517 : :
518 : 56 : return num_removed_parities;
519 : : }
520 : :
521 : :
522 : : /****************************************************************************
523 : : Add stereo descriptor(s) for atom #i
524 : : ****************************************************************************/
525 : 1128 : int FillSingleStereoDescriptors( CANON_GLOBALS *pCG,
526 : : sp_ATOM *at,
527 : : int i,
528 : : int num_trans,
529 : : const AT_RANK *nRank,
530 : : AT_STEREO_CARB *LinearCTStereoCarb,
531 : : int *nStereoCarbLen,
532 : : int nMaxStereoCarbLen,
533 : : AT_STEREO_DBLE *LinearCTStereoDble,
534 : : int *nStereoDbleLen,
535 : : int nMaxStereoDbleLen,
536 : : int bAllene )
537 : : {
538 : :
539 [ + - - + ]: 1128 : if (!LinearCTStereoDble && !LinearCTStereoCarb)
540 : : {
541 : 0 : return 0; /* return immediately if no stereo have been requested */
542 : : }
543 : :
544 : : /***************************************************
545 : : add stereo centers and stereo bonds to the CT
546 : : ***************************************************/
547 [ + + - + ]: 1128 : if (at[i].parity || at[i].stereo_bond_neighbor[0])
548 : : {
549 : 376 : AT_RANK r_neigh, rank = nRank[i];
550 : : AT_NUMB nNeighborNumber2[MAXVAL];
551 : : unsigned parity;
552 : : int k;
553 : 376 : int num_allene = 0;
554 : :
555 [ + - + + : 376 : if (ATOM_PARITY_WELL_DEF( at[i].parity ) && num_trans < 0)
+ - ]
556 : : {
557 : : /* number of neighbors transpositions to the sorted order is unknown. Find it. */
558 : : /* If parity is not well-defined then doing this is a waste of time */
559 : 334 : int num_neigh = at[i].valence;
560 [ + + ]: 1336 : for (k = 0; k < num_neigh; k++)
561 : : {
562 : 1002 : nNeighborNumber2[k] = k;
563 : : }
564 : :
565 : 334 : pCG->m_pNeighborsForSort = at[i].neighbor;
566 : 334 : pCG->m_pn_RankForSort = nRank;
567 : 334 : num_trans = insertions_sort( pCG, nNeighborNumber2, num_neigh, sizeof( nNeighborNumber2[0] ), CompNeighborsAT_NUMBER );
568 : :
569 : : #ifndef CT_NEIGH_INCREASE
570 : : num_trans += ( ( num_neigh*( num_neigh - 1 ) ) / 2 ) % 2; /* get correct parity for ascending order */
571 : : #endif
572 : : }
573 : :
574 : : /* stereo bonds */
575 [ - + - - ]: 376 : if (LinearCTStereoDble && at[i].stereo_bond_neighbor[0])
576 : : {
577 : :
578 : : /* HalfStereoBondParity( sp_ATOM *at, int at_no1, int i_sb_neigh, AT_RANK *nRank ) */
579 : : AT_NUMB nStereoNeighNumber[MAX_NUM_STEREO_BONDS], nStereoNeigh[MAX_NUM_STEREO_BONDS], n;
580 : : int num_stereo, stereo_neigh, stereo_neigh_ord, stereo_bond_parity;
581 : 0 : for (num_stereo = 0;
582 [ # # ]: 0 : num_stereo < MAX_NUM_STEREO_BONDS &&
583 [ # # ]: 0 : ( n = at[i].stereo_bond_neighbor[num_stereo] ); num_stereo++)
584 : : {
585 : 0 : nStereoNeighNumber[num_stereo] = num_stereo;
586 : 0 : nStereoNeigh[num_stereo] = n - 1;
587 : 0 : num_allene += IS_ALLENE_CHAIN( at[i].stereo_bond_parity[num_stereo] );
588 : : }
589 [ # # # # : 0 : if ((bAllene > 0 && !num_allene) || (bAllene == 0 && num_allene)) /* djb-rwth: addressing LLVM warning */
# # # # ]
590 : : {
591 : 0 : return 0;
592 : : }
593 : :
594 : : /* sort stereo bonds according to the ranks of the neighbors */
595 : 0 : pCG->m_pNeighborsForSort = nStereoNeigh;
596 : 0 : pCG->m_pn_RankForSort = nRank;
597 : 0 : insertions_sort( pCG, nStereoNeighNumber, num_stereo, sizeof( nStereoNeighNumber[0] ), CompNeighborsAT_NUMBER );
598 : :
599 : : /* process stereo bonds one by one */
600 [ # # ]: 0 : for (k = 0; k < num_stereo; k++)
601 : : {
602 : 0 : stereo_neigh = nStereoNeigh[stereo_neigh_ord = (int) nStereoNeighNumber[k]];
603 : :
604 [ # # ]: 0 : if (( r_neigh = (AT_NUMB) nRank[stereo_neigh] ) CT_NEIGH_SMALLER_THAN rank)
605 : : {
606 : : /* accept only neighbors that have smaller ranks */
607 : 0 : stereo_bond_parity = PARITY_VAL( at[i].stereo_bond_parity[stereo_neigh_ord] );
608 [ # # ]: 0 : if (stereo_bond_parity == AB_PARITY_NONE)
609 : : {
610 : 0 : continue;
611 : : }
612 : :
613 : : /* stereo_neigh = at[i].stereo_bond_neighbor[nStereoNeighNumber[k]]-1; */
614 [ # # # # ]: 0 : if (ATOM_PARITY_KNOWN( stereo_bond_parity ))
615 : : {
616 : 0 : parity = stereo_bond_parity;
617 : : }
618 [ # # # # ]: 0 : else if (ATOM_PARITY_WELL_DEF( at[i].parity ) &&
619 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF( at[stereo_neigh].parity ) &&
620 [ # # ]: 0 : MIN_DOT_PROD <= abs( at[i].stereo_bond_z_prod[stereo_neigh_ord] ))
621 : 0 : {
622 : : /* bond parity can be calculated */
623 : : int half_parity1, half_parity2, j, nn, stereo_neigh_ord2;
624 : 0 : stereo_neigh_ord2 = -1;
625 [ # # ]: 0 : for (j = 0; j < MAX_NUM_STEREO_BONDS &&
626 [ # # ]: 0 : ( nn = (int) at[stereo_neigh].stereo_bond_neighbor[j] );
627 : 0 : j++)
628 : : {
629 [ # # ]: 0 : if (i + 1 == nn)
630 : : {
631 : : /* found the opposite end of the stereo bond */
632 : 0 : stereo_neigh_ord2 = j;
633 : 0 : break;
634 : : }
635 : : }
636 [ # # ]: 0 : if (stereo_neigh_ord2 >= 0)
637 : : {
638 : 0 : half_parity1 = HalfStereoBondParity( at, i, stereo_neigh_ord, nRank );
639 : 0 : half_parity2 = HalfStereoBondParity( at, stereo_neigh, stereo_neigh_ord2, nRank );
640 [ # # # # : 0 : if (ATOM_PARITY_WELL_DEF( half_parity1 ) &&
# # ]
641 [ # # ]: 0 : ATOM_PARITY_WELL_DEF( half_parity2 ))
642 : : {
643 : 0 : parity = 2 - ( half_parity1 + half_parity2
644 : 0 : + ( at[i].stereo_bond_z_prod[stereo_neigh_ord] < 0 ) ) % 2;
645 : : }
646 : : else
647 : : {
648 : 0 : return CT_STEREOBOND_ERROR; /* <BRKPT> */
649 : : }
650 : : }
651 : : else
652 : : {
653 : 0 : return CT_STEREOBOND_ERROR; /* <BRKPT> */
654 : : }
655 : : }
656 : : else
657 : : {
658 : : /* parity cannot be calculated: not enough info or 'unknown' */
659 [ # # ]: 0 : if (AB_PARITY_NONE == ( parity = inchi_max( at[i].parity, at[stereo_neigh].parity ) ))
660 : : {
661 : 0 : continue;
662 : : }
663 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( parity ))
664 : : {
665 : 0 : parity = AB_PARITY_UNDF; /* should not happen */
666 : : }
667 : : }
668 [ # # ]: 0 : if (CHECK_OVERFLOW( *nStereoDbleLen, nMaxStereoDbleLen ))
669 : 0 : return CT_OVERFLOW; /* <BRKPT> */
670 : : /* first stereo bond atom */
671 : 0 : LinearCTStereoDble[*nStereoDbleLen].at_num1 = rank;
672 : : /* second stereo bond atom (opposite end) */
673 : 0 : LinearCTStereoDble[*nStereoDbleLen].at_num2 = r_neigh;
674 : : /* bond parity */
675 : 0 : LinearCTStereoDble[*nStereoDbleLen].parity = parity;
676 : 0 : ( *nStereoDbleLen )++;
677 : : }
678 : : }
679 : : }
680 : :
681 : : /* stereo carbon */
682 [ + + ]: 376 : if (bAllene > 0)
683 : : {
684 : 188 : return 0;
685 : : }
686 : :
687 [ + - + - ]: 188 : if (LinearCTStereoCarb && !at[i].stereo_bond_neighbor[0])
688 : : {
689 [ - + ]: 188 : if (CHECK_OVERFLOW( *nStereoCarbLen, nMaxStereoCarbLen ))
690 : 0 : return CT_OVERFLOW; /* <BRKPT> */
691 : : /* stereo atom rank */
692 : 188 : LinearCTStereoCarb[*nStereoCarbLen].at_num = rank;
693 : : /* stereo atom parity */
694 [ + - + + ]: 188 : parity = ATOM_PARITY_WELL_DEF( at[i].parity ) ? ( 2 - ( at[i].parity + num_trans ) % 2 ) : at[i].parity;
695 : 188 : LinearCTStereoCarb[*nStereoCarbLen].parity = parity;
696 : 188 : ( *nStereoCarbLen )++;
697 : : }
698 : : }
699 : :
700 : 940 : return 0;
701 : : }
702 : :
703 : :
704 : : /****************************************************************************/
705 : 0 : void SwitchAtomStereoAndIsotopicStereo( sp_ATOM *at,
706 : : int num_atoms,
707 : : int *bSwitched )
708 : : {
709 : : int i;
710 : : /* switch atom stereo data */
711 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
712 : : {
713 : 0 : inchi_swap( (char*) &at[i].parity, (char*) &at[i].parity2, sizeof( at[i].parity ) );
714 : 0 : inchi_swap( (char*) &at[i].final_parity, (char*) &at[i].final_parity2, sizeof( at[i].final_parity ) );
715 : 0 : inchi_swap( (char*) &at[i].stereo_atom_parity, (char*) &at[i].stereo_atom_parity2, sizeof( at[i].stereo_atom_parity ) );
716 : 0 : inchi_swap( (char*) &at[i].bHasStereoOrEquToStereo, (char*) &at[i].bHasStereoOrEquToStereo2, sizeof( at[i].bHasStereoOrEquToStereo ) );
717 : :
718 : 0 : inchi_swap( (char*) at[i].stereo_bond_neighbor, (char*) at[i].stereo_bond_neighbor2, sizeof( at[i].stereo_bond_neighbor ) );
719 : 0 : inchi_swap( (char*) at[i].stereo_bond_ord, (char*) at[i].stereo_bond_ord2, sizeof( at[i].stereo_bond_ord ) );
720 : 0 : inchi_swap( (char*) at[i].stereo_bond_z_prod, (char*) at[i].stereo_bond_z_prod2, sizeof( at[i].stereo_bond_z_prod ) );
721 : 0 : inchi_swap( (char*) at[i].stereo_bond_parity, (char*) at[i].stereo_bond_parity2, sizeof( at[i].stereo_bond_parity ) );
722 : : }
723 : :
724 : 0 : *bSwitched = !*bSwitched;
725 : 0 : }
726 : :
727 : :
728 : : /****************************************************************************/
729 : 0 : void SetCtToIsotopicStereo( CANON_STAT *pCS,
730 : : CANON_STAT *pCS2 )
731 : : {
732 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble; /* enable stereo */
733 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
734 : :
735 : 0 : pCS->LinearCTStereoDbleInv = pCS2->LinearCTIsotopicStereoDbleInv; /* enable inv. stereo */
736 : 0 : pCS->LinearCTStereoCarbInv = pCS2->LinearCTIsotopicStereoCarbInv;
737 : 0 : pCS->nMaxLenLinearCTStereoDble = pCS2->nMaxLenLinearCTIsotopicStereoDble;
738 : 0 : pCS->nMaxLenLinearCTStereoCarb = pCS2->nMaxLenLinearCTIsotopicStereoCarb;
739 : :
740 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
741 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
742 : 0 : }
743 : :
744 : :
745 : : /****************************************************************************/
746 : 0 : void SetCtToNonIsotopicStereo( CANON_STAT *pCS,
747 : : CANON_STAT *pCS2 )
748 : : {
749 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble; /* enable stereo */
750 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
751 : :
752 : 0 : pCS->LinearCTStereoDbleInv = pCS2->LinearCTStereoDbleInv; /* enable inv. stereo */
753 : 0 : pCS->LinearCTStereoCarbInv = pCS2->LinearCTStereoCarbInv;
754 : 0 : pCS->nMaxLenLinearCTStereoDble = pCS2->nMaxLenLinearCTStereoDble;
755 : 0 : pCS->nMaxLenLinearCTStereoCarb = pCS2->nMaxLenLinearCTStereoCarb;
756 : :
757 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
758 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
759 : :
760 : 0 : pCS->nLenLinearCTIsotopicStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
761 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
762 : 0 : }
763 : :
764 : :
765 : : /****************************************************************************/
766 : 56 : int FillAllStereoDescriptors( CANON_GLOBALS *pCG,
767 : : sp_ATOM *at,
768 : : int num_atoms,
769 : : const AT_RANK *nCanonRank,
770 : : const AT_RANK *nAtomNumberCanon,
771 : : CANON_STAT *pCS )
772 : : {
773 : 56 : int ret = 0, i;
774 : : /* initialize zero lengths */
775 : 56 : pCS->nLenLinearCTStereoCarb = 0;
776 : 56 : pCS->nLenLinearCTStereoDble = 0;
777 : :
778 : : /* fill atom by atom */
779 [ + - + + ]: 620 : for (i = 0; !ret && i < num_atoms; i++)
780 : : {
781 : 564 : ret = FillSingleStereoDescriptors( pCG, at, (int) nAtomNumberCanon[i], -1, nCanonRank
782 : : , pCS->LinearCTStereoCarb, &pCS->nLenLinearCTStereoCarb, pCS->nMaxLenLinearCTStereoCarb
783 : : , pCS->LinearCTStereoDble, &pCS->nLenLinearCTStereoDble, pCS->nMaxLenLinearCTStereoDble
784 : : , 0 /* bAllene */ );
785 : : }
786 [ + - + + ]: 620 : for (i = 0; !ret && i < num_atoms; i++)
787 : : {
788 : 564 : ret = FillSingleStereoDescriptors( pCG, at, (int) nAtomNumberCanon[i], -1, nCanonRank
789 : : , pCS->LinearCTStereoCarb, &pCS->nLenLinearCTStereoCarb, pCS->nMaxLenLinearCTStereoCarb
790 : : , pCS->LinearCTStereoDble, &pCS->nLenLinearCTStereoDble, pCS->nMaxLenLinearCTStereoDble
791 : : , 1 /* bAllene */ );
792 : : }
793 : :
794 : 56 : return ret;
795 : : }
796 : :
797 : :
798 : : /****************************************************************************
799 : : Find stereo bond parities known in advance
800 : : ****************************************************************************/
801 : 56 : int SetKnownStereoBondParities( CANON_GLOBALS *pCG,
802 : : sp_ATOM *at,
803 : : int num_atoms,
804 : : const AT_RANK *nCanonRank,
805 : : const AT_RANK *nRank,
806 : : const AT_RANK *nAtomNumber )
807 : : {
808 : : int i, j, n, m, j1, k, num_neigh1, num_neigh2, iMax1, parity;
809 : : int trans_i1, trans_i2, trans_k1, trans_k2, prev_trans, trans_k, num_set;
810 : : int i1, i2, k1, k2, n1, n2, m1, m2, /*stereo_bond_parity,*/ cumulene_len;
811 : :
812 : : AT_RANK nAtomRank1, nAtomRank2, nAtom1NeighRank;
813 : : AT_RANK nNeighRank1[MAX_NUM_STEREO_BONDS],
814 : : nNeighRank2[MAX_NUM_STEREO_BONDS];
815 : : AT_RANK nNeighCanonRank1[MAX_NUM_STEREO_BONDS],
816 : : nNeighCanonRank2[MAX_NUM_STEREO_BONDS];
817 : :
818 [ + + ]: 620 : for (i1 = 0, num_set = 0; i1 < num_atoms; i1++)
819 : : {
820 [ + + + - ]: 564 : if (!at[i1].parity || !at[i1].stereo_bond_neighbor[0])
821 : : {
822 : 564 : continue;
823 : : }
824 : :
825 [ # # # # ]: 0 : if (!PARITY_WELL_DEF( at[i1].parity ))
826 : : {
827 : 0 : continue;
828 : : }
829 : :
830 : 0 : nAtomRank1 = nRank[i1];
831 : 0 : iMax1 = (int) nAtomRank1 - 1;
832 : 0 : num_neigh1 = at[i1].valence;
833 : :
834 [ # # ]: 0 : for (n1 = 0; n1 < MAX_NUM_STEREO_BONDS &&
835 [ # # ]: 0 : ( i2 = (int) at[i1].stereo_bond_neighbor[n1] );
836 : 0 : n1++)
837 : : {
838 : 0 : i2--;
839 : :
840 : : /* found a stereo bond at[i1]-at[i2] adjacent to at[i1] */
841 : 0 : for (n2 = 0, m = 0;
842 : 0 : n2 < MAX_NUM_STEREO_BONDS &&
843 [ # # # # : 0 : ( m = (int) at[i2].stereo_bond_neighbor[n2] ) && m - 1 != i1;
# # ]
844 : 0 : n2++)
845 : : ; /* locate stereo bond (#n2) at the opposite atom at[i2] */
846 : :
847 [ # # # # ]: 0 : if (m - 1 != i1 || at[i1].stereo_bond_parity[n1] != at[i2].stereo_bond_parity[n2])
848 : : {
849 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
850 : : }
851 [ # # ]: 0 : if (i1 < i2)
852 : : {
853 : 0 : continue; /* do not process same bond 2 times */
854 : : }
855 [ # # # # ]: 0 : if (PARITY_KNOWN( at[i1].stereo_bond_parity[n1] ) ||
856 [ # # ]: 0 : !PARITY_VAL( at[i1].stereo_bond_parity[n1] ))
857 : : {
858 : 0 : continue;
859 : : }
860 [ # # # # ]: 0 : if (!PARITY_WELL_DEF( at[i1].parity ) ||
861 [ # # # # ]: 0 : !PARITY_WELL_DEF( at[i2].parity ))
862 : : {
863 : 0 : continue;
864 : : }
865 [ # # ]: 0 : if (PARITY_VAL( at[i1].stereo_bond_parity[n1] ) != AB_PARITY_CALC)
866 : : {
867 : 0 : continue; /* ?? program error ?? should not happen */ /* <BRKPT> */
868 : : }
869 : :
870 : : /*stereo_bond_parity = PARITY_VAL(at[i1].stereo_bond_parity[n1]);*/
871 : 0 : cumulene_len = BOND_CHAIN_LEN( at[i1].stereo_bond_parity[n1] );
872 : 0 : nAtomRank2 = nRank[i2];
873 : 0 : nAtom1NeighRank = nRank[(int) at[i1].neighbor[(int) at[i1].stereo_bond_ord[n1]]];
874 : 0 : num_neigh2 = at[i2].valence;
875 : :
876 : : /* store ranks of at[i1] stereo bond neighbors except one connected by a stereo bond */
877 : 0 : k = (int) at[i1].stereo_bond_ord[n1];
878 : 0 : trans_i1 = 0;
879 [ # # ]: 0 : for (i = j = 0; i < num_neigh1; i++)
880 : : {
881 [ # # ]: 0 : if (i != k)
882 : : {
883 : 0 : nNeighRank1[j] = nRank[(int) at[i1].neighbor[i]];
884 : 0 : j++;
885 : : }
886 : : }
887 [ # # ]: 0 : if (j == 2)
888 : : {
889 [ # # ]: 0 : if (nNeighRank1[0] == nNeighRank1[1])
890 : : {
891 : : /* neighbors are constitutionally identical, can't find bond parity */
892 : 0 : continue;
893 : : }
894 : 0 : trans_i1 = insertions_sort( pCG, nNeighRank1, j, sizeof( nNeighRank1[0] ), comp_AT_RANK );
895 : : }
896 : :
897 : : /* store ranks of at[i2] stereo bond neighbors except one connected by a stereo bond */
898 : 0 : k = (int) at[i2].stereo_bond_ord[n2];
899 : 0 : trans_i2 = 0;
900 [ # # ]: 0 : for (i = j = 0; i < num_neigh2; i++)
901 : : {
902 [ # # ]: 0 : if (i != k)
903 : : {
904 : 0 : nNeighRank2[j] = nRank[(int) at[i2].neighbor[i]];
905 : 0 : j++;
906 : : }
907 : : }
908 : :
909 [ # # ]: 0 : if (j == 2)
910 : : {
911 [ # # ]: 0 : if (nNeighRank2[0] == nNeighRank2[1])
912 : : {
913 : : /* neighbors are constitutionally identical, can't find bond parity */
914 : 0 : continue;
915 : : }
916 : 0 : trans_i2 = insertions_sort( pCG, nNeighRank2, j, sizeof( nNeighRank2[0] ), comp_AT_RANK );
917 : : }
918 : :
919 : 0 : prev_trans = -1;
920 : 0 : trans_k1 = -2; /* djb-rwth: ignoring LLVM warning: value used */
921 : 0 : trans_k = -4; /* 2004-04-28 */
922 : :
923 : : /* find all pairs of atoms that can be mapped on at[i1], at[i2] pair */
924 : 0 : for (j1 = 0;
925 [ # # # # ]: 0 : j1 <= iMax1 && nAtomRank1 == nRank[k1 = (int) nAtomNumber[iMax1 - j1]];
926 : 0 : j1++)
927 : : {
928 : : /* at[k1] is constitutionally equivalent to at[i1] */
929 : : /* find all at[k1] neighbors that have rank nAtomRank2; */
930 : : /* then find at[k2] constitutionally equivalent at at[i2] */
931 [ # # ]: 0 : if (at[k1].valence != num_neigh1)
932 : : {
933 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
934 : : }
935 [ # # ]: 0 : for (m1 = 0; m1 < num_neigh1; m1++)
936 : : {
937 : : int prev, next, len;
938 [ # # ]: 0 : if (nAtom1NeighRank != nRank[k2 = (int) at[k1].neighbor[m1]])
939 : : {
940 : 0 : continue;
941 : : }
942 : 0 : m2 = -1; /* undefined yet */
943 : 0 : prev = k1;
944 : : /* djb-rwth: removing redundant code */
945 [ # # ]: 0 : if (cumulene_len)
946 : : {
947 [ # # ]: 0 : for (len = 0, next = (int) at[k1].neighbor[m1]; len < cumulene_len; len++)
948 : : {
949 [ # # # # ]: 0 : if (at[next].valence == 2 && !at[next].num_H)
950 : : {
951 : 0 : j = ( (int) at[next].neighbor[0] == prev );
952 : 0 : prev = next;
953 : 0 : next = at[next].neighbor[j];
954 : : }
955 : : else
956 : : {
957 : : break; /* cannot continue */
958 : : }
959 : : }
960 [ # # # # ]: 0 : if (len != cumulene_len || nAtomRank2 != nRank[next])
961 : : {
962 : 0 : continue; /* not found */
963 : : }
964 : 0 : k2 = next;
965 : : }
966 [ # # ]: 0 : if (at[k2].valence != num_neigh2)
967 : : {
968 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
969 : : }
970 : :
971 : : /* store canon. ranks of at[k1] neighbors */ /* use i,j,k,m,n */
972 [ # # ]: 0 : for (n = j = 0; n < num_neigh1; n++)
973 : : {
974 [ # # ]: 0 : if (n != m1)
975 : : {
976 : 0 : i = (int) at[k1].neighbor[n];
977 [ # # ]: 0 : for (m = 0; m < num_neigh1 - 1; m++)
978 : : {
979 [ # # ]: 0 : if (nRank[i] == nNeighRank1[m])
980 : : {
981 : 0 : nNeighCanonRank1[m] = nCanonRank[i];
982 : 0 : j++;
983 : 0 : break;
984 : : }
985 : : }
986 : : }
987 : : }
988 [ # # ]: 0 : if (j != num_neigh1 - 1)
989 : : {
990 : 0 : return CT_STEREOCOUNT_ERR; /* <BRKPT> */
991 : : }
992 [ # # ]: 0 : if (j == 2)
993 : : {
994 : 0 : trans_k1 = insertions_sort( pCG, nNeighCanonRank1, j, sizeof( nNeighCanonRank1[0] ), comp_AT_RANK );
995 : : }
996 : : else
997 : : {
998 : 0 : trans_k1 = 0;
999 : : }
1000 : :
1001 : : /* store canon. ranks of at[k2] neighbors */ /* use i,j,k,m,n */
1002 [ # # ]: 0 : for (n = j = 0; n < num_neigh2; n++)
1003 : : {
1004 : 0 : i = (int) at[k2].neighbor[n];
1005 [ # # ]: 0 : if (i == prev)
1006 : : {
1007 : : /* neighbor belongs to the stereobond */
1008 : 0 : m2 = n;
1009 : : }
1010 : : else
1011 : : {
1012 [ # # ]: 0 : for (m = 0; m < num_neigh2 - 1; m++)
1013 : : {
1014 [ # # ]: 0 : if (nRank[i] == nNeighRank2[m])
1015 : : {
1016 : 0 : nNeighCanonRank2[m] = nCanonRank[i];
1017 : 0 : j++;
1018 : 0 : break;
1019 : : }
1020 : : }
1021 : : }
1022 : : }
1023 [ # # # # ]: 0 : if (j != num_neigh2 - 1 || m2 < 0)
1024 : : {
1025 : 0 : return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1026 : : }
1027 [ # # ]: 0 : if (j == 2)
1028 : : {
1029 : 0 : trans_k2 = insertions_sort( pCG, nNeighCanonRank2, j, sizeof( nNeighCanonRank2[0] ), comp_AT_RANK );
1030 : : }
1031 : : else
1032 : : {
1033 : 0 : trans_k2 = 0;
1034 : : }
1035 : 0 : trans_k = ( trans_k1 + trans_k2 ) % 2;
1036 [ # # ]: 0 : if (prev_trans < 0)
1037 : : {
1038 : 0 : prev_trans = trans_k;
1039 : : }
1040 [ # # ]: 0 : else if (prev_trans != trans_k)
1041 : : {
1042 : : /* was != trans_k1, changed 9-23-2003 */
1043 : 0 : break; /* different number of transpositions */
1044 : : }
1045 : : } /* end of the second atom mapping cycle */
1046 [ # # # # ]: 0 : if (prev_trans >= 0 && prev_trans != trans_k)
1047 : : { /* was != trans_k1, changed 9-23-2003 */
1048 : 0 : break;
1049 : : }
1050 : : } /* end of the first atom mapping cycle */
1051 : :
1052 [ # # ]: 0 : if (prev_trans == trans_k)
1053 : : {
1054 : : /* was == trans_k1, changed 9-23-2003 */
1055 : : int z_prod;
1056 : :
1057 : : /* all mappings of canonical numbers on the */
1058 : : /* stereo bond at[i1]-at[i2] produce equivalent numberings. */
1059 : : /* Therefore the stereo bond parity is known at this time. */
1060 : : /* parity_1 = at[i1].parity + (trans_i1 + trans_k1 + num_neigh1 - 1) + (int)at[i1].stereo_bond_ord[n1] */
1061 : : /* expression in parentheses is equivalent to rank[first neigh] > rank[second neigh] */
1062 : : /* same for parity_2. */
1063 : : /* parity_2 = at[i2].parity + (trans_i2 + trans_k2 + num_neigh2 - 1) + (int)at[i2].stereo_bond_ord[n2] */
1064 : : /* Sum of the two parities (without stereo_bond_z_prod) is: */
1065 : :
1066 : 0 : parity = ( at[i1].parity + at[i2].parity + prev_trans + trans_i1 + trans_i2
1067 : 0 : + num_neigh1 + num_neigh2
1068 : 0 : + (int) at[i1].stereo_bond_ord[n1] + (int) at[i2].stereo_bond_ord[n2] ) % 2;
1069 : :
1070 : 0 : z_prod = at[i1].stereo_bond_z_prod[n1];
1071 [ # # # # ]: 0 : if (MIN_DOT_PROD > abs( z_prod ))
1072 : : {
1073 : 0 : parity = AB_PARITY_UNDF; /* undefined because of geometry */
1074 : : }
1075 : : else
1076 : : {
1077 [ # # ]: 0 : parity = ( z_prod > 0 ) ? 2 - parity : 1 + parity;
1078 : : }
1079 : 0 : at[i1].stereo_bond_parity[n1] = ALL_BUT_PARITY( at[i1].stereo_bond_parity[n1] ) | parity;
1080 : 0 : at[i2].stereo_bond_parity[n2] = ALL_BUT_PARITY( at[i2].stereo_bond_parity[n2] ) | parity;
1081 : 0 : num_set++;
1082 : : }
1083 : : }
1084 : : }
1085 : :
1086 : 56 : return num_set;
1087 : : }
1088 : :
1089 : :
1090 : : /****************************************************************************
1091 : : Find stereo center parities known in advance
1092 : : ****************************************************************************/
1093 : 56 : int MarkKnownEqualStereoBondParities( sp_ATOM *at,
1094 : : int num_atoms,
1095 : : const AT_RANK *nRank,
1096 : : const AT_RANK *nAtomNumber )
1097 : : {
1098 : : int j, n, m, j1, num_neigh1, num_neigh2, iMax1;
1099 : : int num_set, /*num_sb1, num_sb2,*/ bDifferentParities;
1100 : : int i1, i2, k1, k2, n1, n2, m1, m2, s1, s2, stereo_bond_parity, stereo_bond_parity2, cumulene_len;
1101 : : AT_RANK nAtomRank1, nAtomRank2, nAtom1NeighRank, nAtom2NeighRank;
1102 : :
1103 : : /* djb-rwth: removing redundant code */
1104 : :
1105 [ + + ]: 620 : for (i1 = 0, num_set = 0; i1 < num_atoms; i1++)
1106 : : {
1107 [ + + + - ]: 564 : if (!at[i1].parity || !at[i1].stereo_bond_neighbor[0])
1108 : : {
1109 : 564 : continue;
1110 : : }
1111 : :
1112 : 0 : nAtomRank1 = nRank[i1];
1113 : 0 : iMax1 = (int) nAtomRank1 - 1;
1114 : 0 : num_neigh1 = at[i1].valence;
1115 : :
1116 : : /* count stereogenic bonds adjacent to at[i1] */
1117 : 0 : for (n1 = 0;
1118 [ # # # # ]: 0 : n1 < MAX_NUM_STEREO_BONDS && at[i1].stereo_bond_neighbor[n1];
1119 : 0 : n1++);
1120 : :
1121 : :
1122 : : /*num_sb1 = n1;*/
1123 : : /* search for bonds possibly constitutionally equivalent to each of the adjacent bonds */
1124 : : /* and find if all of them have same already known parity */
1125 : :
1126 : 0 : for (n1 = 0;
1127 [ # # # # ]: 0 : n1 < MAX_NUM_STEREO_BONDS && ( i2 = (int) at[i1].stereo_bond_neighbor[n1] );
1128 : 0 : n1++) /* djb-rwth: removing redundant code */
1129 : : {
1130 : 0 : i2--;
1131 : :
1132 : 0 : nAtomRank2 = nRank[i2];
1133 [ # # # # : 0 : if (nAtomRank2 < nAtomRank1 || (nAtomRank2 == nAtomRank1 && i1 < i2)) /* djb-rwth: addressing LLVM warning */
# # ]
1134 : : {
1135 : : /* An attempt to reduce unnecessary repetitions. */
1136 : : /* We still have repetitions because we do not accumulate a list of */
1137 : : /* processed (nAtomRank2, nAtomRank1) pairs. */
1138 : 0 : continue;
1139 : : }
1140 : :
1141 : 0 : bDifferentParities = -1; /* parities have not been compared yet */
1142 : :
1143 : : /* found a stereo bond at[i1]-at[i2] (adjacent to at[i1]) */
1144 : : /*
1145 : : if ( !PARITY_KNOWN(at[i1].stereo_bond_parity[n1]) || (at[i1].stereo_bond_parity[n1] & KNOWN_PARITIES_EQL) )
1146 : : {
1147 : : continue;
1148 : : }
1149 : : */
1150 [ # # ]: 0 : if (at[i1].stereo_bond_parity[n1] & KNOWN_PARITIES_EQL)
1151 : : {
1152 : 0 : continue;
1153 : : }
1154 : :
1155 : :
1156 : : /* stereo bond has known or unknown parity; we have not checked it yet */
1157 : :
1158 : 0 : for (n2 = 0;
1159 [ # # # # ]: 0 : n2 < MAX_NUM_STEREO_BONDS && at[i2].stereo_bond_neighbor[n2];
1160 : 0 : n2++)
1161 : : {
1162 : : ;
1163 : : }
1164 : :
1165 : : /*num_sb2 = n2;*/
1166 : 0 : for (n2 = 0, m = 0;
1167 : 0 : n2 < MAX_NUM_STEREO_BONDS &&
1168 [ # # # # ]: 0 : ( m = (int) at[i2].stereo_bond_neighbor[n2] ) &&
1169 [ # # ]: 0 : m - 1 != i1;
1170 : 0 : n2++)
1171 : : {
1172 : : ;
1173 : : }
1174 : :
1175 [ # # # # ]: 0 : if (m - 1 != i1 || at[i1].stereo_bond_parity[n1] != at[i2].stereo_bond_parity[n2])
1176 : : {
1177 : 0 : return CT_STEREOCOUNT_ERR; /* program error: stereo bonds data in two directions are different */ /* <BRKPT> */
1178 : : }
1179 : :
1180 : 0 : stereo_bond_parity = PARITY_VAL( at[i1].stereo_bond_parity[n1] );
1181 : 0 : cumulene_len = BOND_CHAIN_LEN( at[i1].stereo_bond_parity[n1] );
1182 : 0 : nAtom1NeighRank = nRank[(int) at[i1].neighbor[(int) at[i1].stereo_bond_ord[n1]]];
1183 : 0 : nAtom2NeighRank = nRank[(int) at[i2].neighbor[(int) at[i2].stereo_bond_ord[n2]]];
1184 : 0 : num_neigh2 = at[i2].valence;
1185 : :
1186 : : /* find all pairs of atoms that possibly can be mapped on at[i1], at[i2] pair */
1187 : : /* (we may also find pairs that cannot be mapped, but we cannot miss any pair */
1188 : : /* that can be mapped) */
1189 : :
1190 [ # # # # ]: 0 : for (j1 = 0; j1 <= iMax1 && nAtomRank1 == nRank[k1 = (int) nAtomNumber[iMax1 - j1]]; j1++)
1191 : : {
1192 : : /* at[k1] is constitutionally equivalent to at[i1] */
1193 : : /* find all at[k1] stereo bond neighbors at[k2] that have rank nAtomRank2; */
1194 : : /* then find at[k2] constitutionally equivalent at at[i2] */
1195 : :
1196 [ # # ]: 0 : if (at[k1].valence != num_neigh1)
1197 : : {
1198 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1199 : : }
1200 : :
1201 [ # # ]: 0 : if (!at[k1].bHasStereoOrEquToStereo)
1202 : : {
1203 : 0 : at[k1].bHasStereoOrEquToStereo = 1;
1204 : : }
1205 : :
1206 : : /* -- do not check number of stereo bonds, check bonds themselves --
1207 : : for ( s1 = 0; s1 < MAX_NUM_STEREO_BONDS && at[k1].stereo_bond_neighbor[s1]; s1++ )
1208 : : {
1209 : : ;
1210 : : }
1211 : : if ( num_sb1 != s1 )
1212 : : {
1213 : : bDifferentParities = 1;
1214 : : }
1215 : : */
1216 : :
1217 [ # # ]: 0 : for (m1 = 0; m1 < num_neigh1; m1++)
1218 : : {
1219 : : /* Looking for at[k1] neighbor with nRank=nAtom1NeighRank. */
1220 : : /* This neighbor may be on the bond constit. equivalent to at[i1]-at[i2] stereo bond */
1221 : : /* (or may be constit. equivalent an adjacent to at[i1] atom in a stereogenic cumulene chain) */
1222 : : int prev, next, len;
1223 [ # # ]: 0 : if (nAtom1NeighRank != nRank[k2 = (int) at[k1].neighbor[m1]])
1224 : 0 : continue;
1225 : :
1226 : : /* found at[k1] neighbor with nRank=nAtom1NeighRank */
1227 : :
1228 : 0 : m2 = -1; /* undefined yet */
1229 : 0 : prev = k1;
1230 : : /* djb-rwth: removing redundant code */
1231 : :
1232 : : /* if cumulene then bypass the cumulene chain */
1233 : :
1234 [ # # ]: 0 : if (cumulene_len)
1235 : : {
1236 : :
1237 [ # # ]: 0 : for (len = 0, next = (int) at[k1].neighbor[m1]; len < cumulene_len; len++)
1238 : : {
1239 [ # # # # ]: 0 : if (at[next].valence == 2 && !at[next].num_H)
1240 : : {
1241 : 0 : j = ( (int) at[next].neighbor[0] == prev );
1242 : 0 : prev = next;
1243 : 0 : next = at[next].neighbor[j];
1244 : : }
1245 : : else
1246 : : {
1247 : : break; /* cannot continue: end of cumulene chain */
1248 : : }
1249 : : }
1250 : :
1251 [ # # # # ]: 0 : if (len != cumulene_len || nAtomRank2 != nRank[next])
1252 : : {
1253 : 0 : continue; /* cumulene chain not found at this neighbor */
1254 : : }
1255 : :
1256 [ # # ]: 0 : if (nAtom2NeighRank != nRank[prev])
1257 : : {
1258 : : /* continue; */ /* ??? program error ??? If not, must be a very rare event */
1259 : 0 : return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1260 : : }
1261 : :
1262 : 0 : k2 = next;
1263 : : }
1264 : :
1265 : : /* a connected pair of constit. equivalent atoms found */
1266 : :
1267 [ # # ]: 0 : if (at[k2].valence != num_neigh2)
1268 : : {
1269 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1270 : : }
1271 : :
1272 [ # # ]: 0 : for (n = 0; n < num_neigh2; n++)
1273 : : {
1274 [ # # ]: 0 : if (prev == (int) at[k2].neighbor[n])
1275 : : {
1276 : 0 : m2 = n; /* found bond from the opposite end of a possibly stereogenic bond */
1277 : 0 : break;
1278 : : }
1279 : : }
1280 : :
1281 [ # # ]: 0 : if (m2 < 0)
1282 : : {
1283 : 0 : return CT_STEREOCOUNT_ERR; /* program error: opposite direction bond not found */ /* <BRKPT> */
1284 : : }
1285 : :
1286 [ # # ]: 0 : if (!at[k2].bHasStereoOrEquToStereo)
1287 : : {
1288 : 0 : at[k2].bHasStereoOrEquToStereo = 1;
1289 : : }
1290 : :
1291 : :
1292 : : /* check if atoms at[k1] and at[k2] are connected by a stereo bond */
1293 : 0 : for (s1 = 0, m = 0;
1294 : 0 : s1 < MAX_NUM_STEREO_BONDS &&
1295 [ # # # # ]: 0 : ( m = (int) at[k1].stereo_bond_neighbor[s1] ) &&
1296 [ # # ]: 0 : m - 1 != k2;
1297 : 0 : s1++)
1298 : : {
1299 : : ;
1300 : : }
1301 [ # # ]: 0 : if (m - 1 != k2)
1302 : : {
1303 : 0 : bDifferentParities = 1; /* cannot find the stereo bond */
1304 : 0 : at[k1].bHasStereoOrEquToStereo =
1305 : 0 : at[k2].bHasStereoOrEquToStereo = 2;
1306 : 0 : continue;
1307 : : }
1308 : :
1309 : : /* -- do not check number of stereo bonds, check bonds themselves --
1310 : : for ( s2 = 0; s2 < MAX_NUM_STEREO_BONDS && at[k2].stereo_bond_neighbor[s2]; s2++ )
1311 : : {
1312 : : ;
1313 : : }
1314 : : if ( num_sb2 != s2 )
1315 : : {
1316 : : bDifferentParities = 1;
1317 : : continue;
1318 : : }
1319 : : */
1320 : :
1321 : 0 : for (s2 = 0, m = 0;
1322 : 0 : s2 < MAX_NUM_STEREO_BONDS &&
1323 [ # # # # ]: 0 : ( m = (int) at[k2].stereo_bond_neighbor[s2] ) &&
1324 [ # # ]: 0 : m - 1 != k1;
1325 : 0 : s2++)
1326 : : {
1327 : : ;
1328 : : }
1329 : :
1330 [ # # ]: 0 : if (m - 1 != k1)
1331 : : {
1332 : : /*
1333 : : bDifferentParities = 1; // cannot find the stereo bond
1334 : : continue;
1335 : : */
1336 : 0 : return CT_STEREOCOUNT_ERR; /* program error: opposite direction bond not found */ /* <BRKPT> */
1337 : : }
1338 : :
1339 [ # # ]: 0 : if (at[k1].stereo_bond_parity[s1] != at[k2].stereo_bond_parity[s2])
1340 : : {
1341 : 0 : bDifferentParities = 1;
1342 : 0 : continue;
1343 : : }
1344 : 0 : stereo_bond_parity2 = PARITY_VAL( at[k1].stereo_bond_parity[s1] );
1345 [ # # ]: 0 : if (stereo_bond_parity2 != stereo_bond_parity)
1346 : : {
1347 : 0 : bDifferentParities = 1;
1348 : 0 : continue;
1349 : : }
1350 [ # # # # ]: 0 : if (stereo_bond_parity2 == stereo_bond_parity && bDifferentParities < 0)
1351 : : {
1352 : 0 : bDifferentParities = 0;
1353 : : }
1354 : : }
1355 : : }
1356 : :
1357 : : /* mark equal parities */
1358 [ # # # # : 0 : if (0 == bDifferentParities && PARITY_KNOWN( stereo_bond_parity ))
# # ]
1359 : : {
1360 : 0 : for (j1 = 0;
1361 [ # # # # ]: 0 : j1 <= iMax1 && nAtomRank1 == nRank[k1 = (int) nAtomNumber[iMax1 - j1]];
1362 : 0 : j1++)
1363 : : {
1364 : : /* at[k1] is constitutionally equivalent to at[i1] */
1365 [ # # # # ]: 0 : for (s1 = 0; s1 < MAX_NUM_STEREO_BONDS && ( k2 = (int) at[k1].stereo_bond_neighbor[s1] ); s1++) /* djb-rwth: removing redundant code */
1366 : : {
1367 : 0 : k2--;
1368 [ # # ]: 0 : if (nRank[k2] == nAtomRank2)
1369 : : {
1370 : : int b1, b2;
1371 : 0 : for (s2 = 0, m = 0;
1372 : 0 : s2 < MAX_NUM_STEREO_BONDS &&
1373 [ # # # # ]: 0 : ( m = (int) at[k2].stereo_bond_neighbor[s2] ) &&
1374 [ # # ]: 0 : m - 1 != k1;
1375 : 0 : s2++)
1376 : : {
1377 : : ;
1378 : : }
1379 : :
1380 [ # # ]: 0 : if (m - 1 != k1)
1381 : : {
1382 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1383 : : }
1384 : : /* mark the stereo bonds */
1385 : 0 : b1 = !( at[k1].stereo_bond_parity[s1] & KNOWN_PARITIES_EQL );
1386 : 0 : b2 = !( at[k2].stereo_bond_parity[s2] & KNOWN_PARITIES_EQL );
1387 [ # # ]: 0 : if (2 == b1 + b2)
1388 : : {
1389 : 0 : at[k1].stereo_bond_parity[s1] |= KNOWN_PARITIES_EQL;
1390 : 0 : at[k2].stereo_bond_parity[s2] |= KNOWN_PARITIES_EQL;
1391 : 0 : num_set++;
1392 : : }
1393 [ # # # # ]: 0 : else if (b1 || b2)
1394 : : {
1395 : 0 : return CT_STEREOCOUNT_ERR; /* program error */ /* <BRKPT> */
1396 : : }
1397 : : }
1398 : : }
1399 : : }
1400 : : }
1401 : : }
1402 : : }
1403 : :
1404 : 56 : return num_set;
1405 : : }
1406 : :
1407 : :
1408 : :
1409 : : #if ( REMOVE_KNOWN_NONSTEREO == 1 ) /* { */
1410 : :
1411 : :
1412 : : /****************************************************************************
1413 : : Return next atom number (and its canon. rank) on the path prev->cur->next
1414 : : in order of ascending canonical ranks of the next atoms:
1415 : : *cr(output) > *cr(input)
1416 : : To start the sequence let *cr=0
1417 : : If no more neighbors available the return value = 0; on success, returns 1.
1418 : : ****************************************************************************/
1419 : 8 : int GetNextNeighborAndRank( sp_ATOM *at,
1420 : : AT_RANK cur,
1421 : : AT_RANK prev,
1422 : : AT_RANK *n,
1423 : : AT_RANK *cr,
1424 : : const AT_RANK *nCanonRank )
1425 : : {
1426 : : int i, val;
1427 : 8 : AT_RANK cr1 = MAX_ATOMS + 1, j, j1 = MAX_ATOMS + 1, crj;
1428 : :
1429 [ + + ]: 24 : for (i = 0, val = at[(int) cur].valence; i < val; i++)
1430 : : {
1431 [ + + ]: 16 : if (( j = at[cur].neighbor[i] ) != prev &&
1432 [ + - + - ]: 8 : cr1 > ( crj = nCanonRank[(int) j] ) && crj > *cr)
1433 : : {
1434 : 8 : cr1 = crj;
1435 : 8 : j1 = j;
1436 : : }
1437 : : }
1438 [ + - ]: 8 : if (cr1 <= MAX_ATOMS)
1439 : : {
1440 : 8 : *cr = cr1;
1441 : 8 : *n = (AT_RANK) j1;
1442 : 8 : return 1;
1443 : : }
1444 : :
1445 : 0 : return 0; /* program error */ /* <BRKPT> */
1446 : : }
1447 : :
1448 : :
1449 : : /****************************************************************************
1450 : : Find next pair of neighbors having the next greater canon. rank
1451 : : The neighbors should be constitutionally identical and traversed
1452 : : simultaneouslyor not traversed at all
1453 : : If a bond cur1-*n1 or cur2-*n2 is a stereo bond then reject if their stereo
1454 : : bond parities are different or cannot be calculated without breaking ties.
1455 : : ****************************************************************************/
1456 : 4 : int GetAndCheckNextNeighbors( sp_ATOM *at,
1457 : : AT_RANK cur1,
1458 : : AT_RANK prev1,
1459 : : AT_RANK cur2,
1460 : : AT_RANK prev2,
1461 : : AT_RANK *n1,
1462 : : AT_RANK *n2,
1463 : : AT_RANK *nVisited1,
1464 : : AT_RANK *nVisited2,
1465 : : const AT_RANK *nRank,
1466 : : const AT_RANK *nCanonRank )
1467 : : {
1468 : : AT_RANK cr1, cr2, s1, s2;
1469 : : int i1, i2, k1, k2;
1470 : :
1471 [ - + ]: 4 : cr1 = ( *n1 > MAX_ATOMS ) ? 0 : nCanonRank[(int) *n1];
1472 [ - + ]: 4 : cr2 = ( *n2 > MAX_ATOMS ) ? 0 : nCanonRank[(int) *n2];
1473 : :
1474 [ + - + - ]: 8 : if (!GetNextNeighborAndRank( at, cur1, prev1, n1, &cr1, nCanonRank ) ||
1475 : 4 : !GetNextNeighborAndRank( at, cur2, prev2, n2, &cr2, nCanonRank ) ||
1476 [ + - - + ]: 4 : nRank[(int) *n1] != nRank[(int) *n2] || nVisited1[(int) *n1] != nVisited2[(int) *n2])
1477 : : {
1478 : 0 : return 0; /* program error; no breakpoint here */ /* <BRKPT> */
1479 : : }
1480 : :
1481 : : /* Even though the bond or cumulene might have already been checked, check it: this is */
1482 : : /* the only place we can check stereo bonds and cumulenes that are not edges of the DFS tree */
1483 : : /* The code works both for a stereo bond and a stereogenic cumulene. */
1484 : 4 : for (i1 = 0, k1 = 0;
1485 : 4 : i1 < MAX_NUM_STEREO_BONDS &&
1486 [ + - - + ]: 4 : ( s1 = at[cur1].stereo_bond_neighbor[i1] ) &&
1487 [ # # ]: 0 : !( k1 = ( at[cur1].neighbor[(int) at[cur1].stereo_bond_ord[i1]] == *n1 ) );
1488 : 0 : i1++) /* djb-rwth: ignoring LLVM warning: variable used */
1489 : : {
1490 : : ;
1491 : : }
1492 : :
1493 : 4 : for (i2 = 0, k2 = 0;
1494 : 4 : i2 < MAX_NUM_STEREO_BONDS &&
1495 [ + - - + ]: 4 : ( s2 = at[cur2].stereo_bond_neighbor[i2] ) &&
1496 [ # # ]: 0 : !( k2 = ( at[cur2].neighbor[(int) at[cur2].stereo_bond_ord[i2]] == *n2 ) );
1497 : 0 : i2++) /* djb-rwth: ignoring LLVM warning: variable used */
1498 : : {
1499 : : ;
1500 : : }
1501 : :
1502 [ - + ]: 4 : if (k1 != k2)
1503 : : {
1504 : 0 : return 0; /* possibly not an error: constit. equivalent atoms on a stereo bond and not on a stereo bond */
1505 : : }
1506 : :
1507 [ - + ]: 4 : if (k1 /* yes, it is a stereo bond */ &&
1508 [ # # ]: 0 : ( at[cur1].stereo_bond_parity[i1] != at[cur2].stereo_bond_parity[i2] ||
1509 : : /* PARITY_KNOWN (at[cur1].stereo_bond_parity[i1] ) */ /* replaced 08-13-2002 with the next: */
1510 [ # # # # ]: 0 : !PARITY_WELL_DEF( at[cur1].stereo_bond_parity[i1] ) /* it suffices to check only one parity */
1511 : : ))
1512 : : {
1513 : 0 : return 0; /* different or (currently) unknown stereo bond parities */
1514 : : }
1515 : :
1516 : 4 : return 1; /* stereo bonds have known parities */
1517 : : }
1518 : :
1519 : :
1520 : : /********************************************************************************************/
1521 : : /* Simultaneously DFS-traverse 2 paths starting at the bonds prev1->cur1 and prev2->cur2 */
1522 : : /* The two paths MUST go through the pairs of constitutionally identical atoms, */
1523 : : /* each atom being on one path. */
1524 : : /* Reject if encountered atoms having currently unknown (without breaking ties) */
1525 : : /* parities or having different known or unknown or undefined parities. */
1526 : : /* Save length of the path into nVisited[cur. atom number]. */
1527 : : /* Only one nVisited[] array is sufficient because the paths from the beginning are */
1528 : : /* in different ring systems. */
1529 : : /********************************************************************************************/
1530 : 3 : AT_RANK PathsHaveIdenticalKnownParities( sp_ATOM *at,
1531 : : AT_RANK prev1,
1532 : : AT_RANK cur1,
1533 : : AT_RANK prev2,
1534 : : AT_RANK cur2,
1535 : : AT_RANK *nVisited1,
1536 : : AT_RANK *nVisited2,
1537 : : const AT_RANK *nRank,
1538 : : const AT_RANK *nCanonRank,
1539 : : AT_RANK nLength )
1540 : : {
1541 : : int k;
1542 : : AT_RANK n1, n2;
1543 : :
1544 : 3 : nLength++; /* number of successfully traversed pairs of atoms */
1545 : 3 : nVisited1[cur1] = nLength;
1546 : 3 : nVisited2[cur2] = nLength;
1547 : :
1548 : : /* the atoms must be either both stereogenic and have well-defined parities or non-stereogenic at all. */
1549 [ + - ]: 3 : if (at[cur1].stereo_atom_parity != at[cur2].stereo_atom_parity ||
1550 [ - + - - : 3 : (at[cur1].stereo_atom_parity && !PARITY_WELL_DEF( at[cur1].stereo_atom_parity )) ) /* djb-rwth: addressing LLVM warning */
- - ]
1551 : : {
1552 : 0 : return 0; /* Reject: Different or unknown in advance parities */
1553 : : }
1554 : :
1555 [ - + ]: 3 : if (at[cur1].valence != at[cur2].valence)
1556 : : {
1557 : 0 : return 0; /* program error */ /* <BRKPT> */
1558 : : }
1559 : :
1560 [ + + ]: 3 : if (at[cur1].valence == 1)
1561 : : {
1562 : 1 : return nLength; /* so far success */
1563 : : }
1564 : :
1565 : :
1566 [ + + ]: 4 : for (k = 1, n1 = MAX_ATOMS + 1, n2 = MAX_ATOMS + 1; k < at[cur1].valence; k++)
1567 : : {
1568 : : /* start from 1: since we do not go back, we have only (at[cur1].valence-1) bonds to try */
1569 : :
1570 [ - + ]: 2 : if (!GetAndCheckNextNeighbors( at, cur1, prev1, cur2, prev2,
1571 : : &n1, &n2, nVisited1, nVisited2,
1572 : : nRank, nCanonRank ))
1573 : : {
1574 : 0 : return 0; /* different neighbors */
1575 : : }
1576 : :
1577 : : /* In a DFS we do not traverse already visited atoms */
1578 [ + - ]: 2 : if (!nVisited1[n1])
1579 : : {
1580 : : /* recursion */
1581 [ - + ]: 2 : if (!( nLength = PathsHaveIdenticalKnownParities( at, cur1, n1, cur2, n2, nVisited1, nVisited2, nRank, nCanonRank, nLength ) ))
1582 : : {
1583 : 0 : return 0;
1584 : : }
1585 : : }
1586 : : }
1587 : :
1588 : : /* To be on a safe side, recheck after all nVisited[] have been set */
1589 [ + + ]: 4 : for (k = 1, n1 = MAX_ATOMS + 1, n2 = MAX_ATOMS + 1; k < at[cur1].valence; k++)
1590 : : {
1591 : : /* start from 1: since we do not go back, we have only (at[cur1].valence-1) bonds to try */
1592 [ - + ]: 2 : if (!GetAndCheckNextNeighbors( at, cur1, prev1, cur2, prev2,
1593 : : &n1, &n2, nVisited1, nVisited2,
1594 : : nRank, nCanonRank ))
1595 : : {
1596 : 0 : return 0; /* different neighbors */
1597 : : }
1598 : : }
1599 : :
1600 : 2 : return nLength;
1601 : : }
1602 : :
1603 : :
1604 : : /****************************************************************************/
1605 : : /* Remove stereo marks from the bonds that are known to be non-stereo */
1606 : : /* (compare neighbors if they are attached by cut-edges) */
1607 : : /****************************************************************************/
1608 : 57 : int RemoveKnownNonStereoBondParities( sp_ATOM *at,
1609 : : int num_atoms,
1610 : : const AT_RANK *nCanonRank,
1611 : : const AT_RANK *nRank,
1612 : : CANON_STAT *pCS )
1613 : : {
1614 : : int j, n, m, ret;
1615 : :
1616 : : int i1, n1, s2;
1617 : 57 : AT_RANK nAtomRank1, nAtomRank2, neigh[3], opposite_atom, *nVisited = NULL;
1618 : 57 : ret = 0;
1619 [ + + ]: 634 : for (i1 = 0; i1 < num_atoms; i1++)
1620 : : {
1621 [ + + + - ]: 577 : if (at[i1].valence != 3 || !at[i1].stereo_bond_neighbor[0])
1622 : : {
1623 : 577 : continue;
1624 : : }
1625 [ # # # # ]: 0 : for (n1 = 0; n1 < MAX_NUM_STEREO_BONDS && ( s2 = at[i1].stereo_bond_neighbor[n1] ); n1++)
1626 : : {
1627 [ # # # # : 0 : if (!PARITY_CALCULATE( at[i1].stereo_bond_parity[n1] ) && PARITY_WELL_DEF( at[i1].stereo_bond_parity[n1] ))
# # ]
1628 : : {
1629 : 0 : continue;
1630 : : }
1631 : 0 : opposite_atom = (AT_RANK) ( s2 - 1 );
1632 : : /* s2 = at[i1].neighbor[m=(int)at[i1].stereo_bond_ord[n1]]; */
1633 : 0 : m = (int) at[i1].stereo_bond_ord[n1];
1634 [ # # ]: 0 : for (j = 0, n = 0; j < at[i1].valence; j++)
1635 : : {
1636 : : /* if ( at[i1].neighbor[j] != s2 ) */
1637 [ # # ]: 0 : if (j != m)
1638 : : {
1639 : 0 : neigh[n++] = at[i1].neighbor[j];
1640 : : }
1641 : : }
1642 [ # # ]: 0 : if (n > 2)
1643 : : {
1644 : 0 : ret = CT_STEREOBOND_ERROR; /* <BRKPT> */
1645 : 0 : goto exit_function;
1646 : : }
1647 [ # # # # ]: 0 : if (n != 2 || nRank[(int) neigh[0]] != nRank[(int) neigh[1]])
1648 : : {
1649 : 0 : continue; /* may happen if another half-bond has not a defined parity */
1650 : : }
1651 [ # # ]: 0 : if (at[i1].nRingSystem == at[(int) neigh[0]].nRingSystem)
1652 : : {
1653 : 0 : continue; /* no more ring system membership check is necessary because */
1654 : : } /* the two neighbors are to be constitutionally equivalent atoms */
1655 [ # # # # ]: 0 : if (!nVisited && !( nVisited = (AT_RANK*) inchi_malloc( sizeof( nVisited[0] )*num_atoms ) ))
1656 : : {
1657 : 0 : ret = CT_OUT_OF_RAM; /* <BRKPT> */
1658 : 0 : goto exit_function;
1659 : : }
1660 : 0 : memset( nVisited, 0, sizeof( nVisited[0] )*num_atoms ); /* djb-rwth: memset_s C11/Annex K variant? */
1661 : 0 : nVisited[i1] = 1;
1662 [ # # ]: 0 : if (PathsHaveIdenticalKnownParities( at, (AT_RANK) i1, neigh[0], (AT_RANK) i1, neigh[1], nVisited, nVisited, nRank, nCanonRank, 1 ))
1663 : : {
1664 [ # # ]: 0 : if (!RemoveOneStereoBond( at, i1, /* atom number*/ n1 /* stereo bond number*/ ))
1665 : : {
1666 : 0 : ret = CT_STEREOBOND_ERROR; /* <BRKPT> */
1667 : 0 : goto exit_function;
1668 : : }
1669 : 0 : n1--; /* cycle counter may temporarily become negative */
1670 : : /* Remove from pCS */
1671 : 0 : nAtomRank1 = inchi_max( nCanonRank[i1], nCanonRank[opposite_atom] );
1672 : 0 : nAtomRank2 = inchi_min( nCanonRank[i1], nCanonRank[opposite_atom] );
1673 [ # # ]: 0 : for (n = 0, m = pCS->nLenLinearCTStereoDble - 1; n <= m; n++)
1674 : : {
1675 [ # # ]: 0 : if (pCS->LinearCTStereoDble[n].at_num1 == nAtomRank1 &&
1676 [ # # ]: 0 : pCS->LinearCTStereoDble[n].at_num2 == nAtomRank2)
1677 : : {
1678 [ # # ]: 0 : if (n < m)
1679 : : { /* remove pCS->LinearCTStereoDble[n] */
1680 : 0 : memmove( pCS->LinearCTStereoDble + n, pCS->LinearCTStereoDble + n + 1, ( (long long)m - (long long)n ) * sizeof( pCS->LinearCTStereoDble[0] ) ); /* djb-rwth: cast operators added */
1681 : : }
1682 : 0 : pCS->nLenLinearCTStereoDble--;
1683 : : #if ( bRELEASE_VERSION == 0 )
1684 : : pCS->bExtract |= EXTR_KNOWN_USED_TO_REMOVE_PARITY;
1685 : : #endif
1686 : 0 : m = -1; /* set flag "found" */
1687 : 0 : break;
1688 : : }
1689 : : }
1690 [ # # ]: 0 : if (m >= 0)
1691 : : {
1692 : 0 : ret = CT_STEREOCOUNT_ERR; /* bond not found <BRKPT> */
1693 : 0 : goto exit_function;
1694 : : }
1695 : 0 : ret++; /* number of removed known in advance non-stereo bonds */
1696 : : }
1697 : : }
1698 : : }
1699 : :
1700 : 57 : exit_function:
1701 [ - + ]: 57 : if (nVisited)
1702 : : {
1703 [ # # ]: 0 : inchi_free( nVisited );
1704 : : }
1705 : :
1706 : 57 : return ret;
1707 : : }
1708 : : #endif /* } REMOVE_KNOWN_NONSTEREO */
1709 : :
1710 : :
1711 : : /****************************************************************************
1712 : : Find stereo center parities known in advance
1713 : : ****************************************************************************/
1714 : 56 : int SetKnownStereoCenterParities( CANON_GLOBALS *pCG,
1715 : : sp_ATOM *at,
1716 : : int num_atoms,
1717 : : const AT_RANK *nCanonRank,
1718 : : const AT_RANK *nRank,
1719 : : const AT_RANK *nAtomNumber )
1720 : : {
1721 : : int i, j, n, m, j1, k, num_neigh, iMax, trans_i, trans_k, prev_trans, num_set;
1722 : : AT_RANK nAtomRank;
1723 : : AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH];
1724 : : AT_RANK nNeighCanonRank[MAX_NUM_STEREO_ATOM_NEIGH];
1725 : :
1726 [ + + ]: 620 : for (i = 0, num_set = 0; i < num_atoms; i++)
1727 : : {
1728 [ + + - + ]: 564 : if (!at[i].parity || at[i].stereo_bond_neighbor[0])
1729 : : {
1730 : 376 : continue;
1731 : : }
1732 [ + + ]: 188 : if (at[i].stereo_atom_parity != AB_PARITY_CALC ||
1733 [ + - - + ]: 167 : !PARITY_WELL_DEF( at[i].parity ))
1734 : : {
1735 : 21 : continue;
1736 : : }
1737 : 167 : num_neigh = at[i].valence;
1738 [ + + ]: 668 : for (j = 0; j < num_neigh; j++)
1739 : : {
1740 : 501 : nNeighRank[j] = nRank[(int) at[i].neighbor[j]];
1741 : : }
1742 : 167 : nAtomRank = nRank[i];
1743 [ - + ]: 167 : if (num_neigh == 1)
1744 : : {
1745 : : /* other neighbors must be implicit H */
1746 : 0 : at[i].stereo_atom_parity = at[i].parity;
1747 : 0 : trans_i = 0;
1748 : : }
1749 : : else
1750 : : {
1751 : : /* sort constitutional equivalence ranks of the neighbors */
1752 : 167 : trans_i = insertions_sort( pCG, nNeighRank, num_neigh, sizeof( nNeighRank[0] ), comp_AT_RANK );
1753 [ + + ]: 501 : for (j = 1; j < num_neigh; j++)
1754 : : {
1755 [ - + ]: 334 : if (nNeighRank[j - 1] == nNeighRank[j])
1756 : : {
1757 : 0 : break; /* at[i] has consitutionally identical neighbors */
1758 : : }
1759 : : }
1760 [ - + ]: 167 : if (j < num_neigh)
1761 : : {
1762 : : /* at least 2 neighbors are const. identical; parity cannot be calculated at this time */
1763 : 0 : continue; /* try next stereo atom */
1764 : : }
1765 : : }
1766 : 167 : prev_trans = -1;
1767 : 167 : trans_k = 0;
1768 : : /* find neighbors of constitutionally equivalent stereo centers */
1769 : : /* and at[i] parities in case those centers are mapped on at[i] */
1770 : 167 : for (iMax = (int) nAtomRank - 1, j1 = 0;
1771 [ + - + + ]: 336 : j1 <= iMax && nAtomRank == nRank[k = (int) nAtomNumber[iMax - j1]];
1772 : 169 : j1++)
1773 : : {
1774 : : /* at[k] is constitutionally equivalent to at[i] */
1775 [ - + ]: 169 : if ((int) at[k].valence != num_neigh)
1776 : : {
1777 : 0 : return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1778 : : }
1779 : : /* -- commented out to accept non-stereogenic atoms since --
1780 : : -- they may participate in mapping stereocenters 12-16-2003 --
1781 : : if ( !PARITY_VAL(at[k].parity) ) {
1782 : : continue; // not a stereogenic atom
1783 : : }
1784 : : */
1785 [ + + ]: 676 : for (j = 0, m = 0; m < num_neigh; m++)
1786 : : {
1787 [ + - ]: 1014 : for (n = 0; n < num_neigh; n++)
1788 : : {
1789 [ + + ]: 1014 : if (nRank[(int) at[k].neighbor[n]] == nNeighRank[m])
1790 : : {
1791 : : /* save canonical numbers (ranks) of the neighbors in
1792 : : * order of increasing constit. equivalence ranks */
1793 : 507 : nNeighCanonRank[m] = nCanonRank[(int) at[k].neighbor[n]];
1794 : 507 : j++;
1795 : 507 : break;
1796 : : }
1797 : : }
1798 : : }
1799 [ - + ]: 169 : if (j != num_neigh)
1800 : : {
1801 : 0 : return CT_STEREOCOUNT_ERR; /* <BRKPT> */
1802 : : }
1803 : 169 : trans_k = insertions_sort( pCG, nNeighCanonRank, num_neigh, sizeof( nNeighCanonRank[0] ), comp_AT_RANK );
1804 : 169 : trans_k %= 2;
1805 [ + + ]: 169 : if (prev_trans < 0)
1806 : : {
1807 : 167 : prev_trans = trans_k;
1808 : : }
1809 [ - + ]: 2 : else if (trans_k != prev_trans)
1810 : : {
1811 : : /* different mappings may produce different parities. Cannot find the parity at this time */
1812 : : /* this may happen when a set of constit. equivalent atoms has non-contiguous canonical numbers */
1813 : 0 : break;
1814 : : }
1815 : : }
1816 [ + - ]: 167 : if (trans_k == prev_trans)
1817 : : {
1818 : 167 : at[i].stereo_atom_parity = 2 - ( at[i].parity + trans_i + prev_trans ) % 2;
1819 : 167 : num_set++;
1820 : : }
1821 : : }
1822 : :
1823 : 56 : return num_set;
1824 : : }
1825 : :
1826 : :
1827 : : #if ( REMOVE_KNOWN_NONSTEREO == 1 ) /* { */
1828 : :
1829 : :
1830 : : /****************************************************************************
1831 : : DFS along paths starting from the stereocenter through pairs of cut-edges
1832 : : ****************************************************************************/
1833 : 57 : int RemoveKnownNonStereoCenterParities( CANON_GLOBALS *pCG,
1834 : : sp_ATOM *at,
1835 : : int num_atoms,
1836 : : const AT_RANK *nCanonRank,
1837 : : const AT_RANK *nRank,
1838 : : CANON_STAT *pCS )
1839 : : {
1840 : 57 : int i, j, n, m, k, num_neigh, ret = 0;
1841 : : /*AT_RANK nAtomRank;*/
1842 : : AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH], nNeighOrd[MAX_NUM_STEREO_ATOM_NEIGH];
1843 : 57 : AT_RANK *nVisited = NULL;
1844 : :
1845 [ + + ]: 634 : for (i = 0; i < num_atoms; i++)
1846 : : {
1847 [ + + - + ]: 577 : if (!at[i].parity || at[i].stereo_bond_neighbor[0])
1848 : : {
1849 : 388 : continue;
1850 : : }
1851 [ + - + - : 189 : if (!PARITY_CALCULATE( at[i].stereo_atom_parity ) && PARITY_WELL_DEF( at[i].stereo_atom_parity ))
+ + ]
1852 : : {
1853 : 167 : continue;
1854 : : }
1855 : 22 : num_neigh = at[i].valence;
1856 [ + + ]: 88 : for (j = 0; j < num_neigh; j++)
1857 : : {
1858 : 66 : nNeighRank[j] = nRank[(int) at[i].neighbor[j]];
1859 : 66 : nNeighOrd[j] = j;
1860 : : }
1861 : : /*nAtomRank = nRank[i];*/
1862 [ - + ]: 22 : if (num_neigh == 1)
1863 : : {
1864 : 0 : continue;
1865 : : }
1866 : 22 : pCG->m_pn_RankForSort = nNeighRank;
1867 : 22 : insertions_sort( pCG, nNeighOrd, num_neigh, sizeof( nNeighRank[0] ), CompRanksOrd );
1868 [ + + + + ]: 65 : for (j = k = 1; k && j < num_neigh; j++)
1869 : : {
1870 [ + + ]: 43 : if (at[i].nRingSystem != at[(int) at[i].neighbor[(int) nNeighOrd[j]]].nRingSystem &&
1871 : : /* no more ring system membership check is necessary because */
1872 : : /* the two neighbors are to be constitutionally equivalent atoms: */
1873 [ + + ]: 35 : nNeighRank[nNeighOrd[j - 1]] == nNeighRank[nNeighOrd[j]])
1874 : : {
1875 : 1 : k = j;
1876 : : do
1877 : : {
1878 [ + - - + ]: 1 : if (!nVisited && !( nVisited = (AT_RANK*) inchi_malloc( sizeof( nVisited[0] )*num_atoms ) ))
1879 : : {
1880 : 0 : ret = CT_OUT_OF_RAM; /* <BRKPT> */
1881 : 0 : goto exit_function;
1882 : : }
1883 : 1 : memset( nVisited, 0, sizeof( nVisited[0] )*num_atoms ); /* djb-rwth: memset_s C11/Annex K variant? */
1884 : 1 : nVisited[i] = 1;
1885 [ + - ]: 1 : if (PathsHaveIdenticalKnownParities( at, (AT_RANK) i, at[i].neighbor[(int) nNeighOrd[j - 1]],
1886 : 1 : (AT_RANK) i, at[i].neighbor[(int) nNeighOrd[k]],
1887 : : nVisited, nVisited, nRank, nCanonRank, 1 ))
1888 : : {
1889 : 1 : at[i].parity = 0; /* remove parity */
1890 : 1 : at[i].stereo_atom_parity = 0;
1891 : 1 : at[i].final_parity = 0;
1892 : : /* at[i].bHasStereoOrEquToStereo = 0; */
1893 [ + - ]: 2 : for (n = 0, m = pCS->nLenLinearCTStereoCarb - 1; n <= m; n++)
1894 : : {
1895 [ + + ]: 2 : if (pCS->LinearCTStereoCarb[n].at_num == nCanonRank[i])
1896 : : {
1897 [ - + ]: 1 : if (n < m)
1898 : : { /* remove pCS->LinearCTStereoCarb[n] */
1899 : 0 : memmove( pCS->LinearCTStereoCarb + n, pCS->LinearCTStereoCarb + n + 1, ( (long long)m - (long long)n ) * sizeof( pCS->LinearCTStereoCarb[0] ) ); /* djb-rwth: cast operators added */
1900 : : }
1901 : 1 : pCS->nLenLinearCTStereoCarb--;
1902 : 1 : k = 0;
1903 : :
1904 : : #if ( bRELEASE_VERSION == 0 )
1905 : : pCS->bExtract |= EXTR_KNOWN_USED_TO_REMOVE_PARITY;
1906 : : #endif
1907 : :
1908 : 1 : break;
1909 : : }
1910 : : }
1911 [ - + ]: 1 : if (k)
1912 : : {
1913 : 0 : ret = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1914 : 0 : goto exit_function;
1915 : : }
1916 : 1 : ret++;
1917 : 1 : break;
1918 : : }
1919 : : }
1920 [ # # # # ]: 0 : while (++k < num_neigh && nNeighRank[nNeighOrd[j - 1]] == nNeighRank[nNeighOrd[k]]);
1921 : : }
1922 : : }
1923 : : }
1924 : :
1925 : 57 : exit_function:
1926 [ + + ]: 57 : if (nVisited)
1927 : : {
1928 [ + - ]: 1 : inchi_free( nVisited );
1929 : : }
1930 : :
1931 : 57 : return ret;
1932 : : }
1933 : :
1934 : :
1935 : :
1936 : : #endif /* } REMOVE_KNOWN_NONSTEREO */
1937 : :
1938 : :
1939 : : /****************************************************************************
1940 : : Find stereo center parities known in advance
1941 : : ****************************************************************************/
1942 : 56 : int MarkKnownEqualStereoCenterParities( sp_ATOM *at,
1943 : : int num_atoms,
1944 : : const AT_RANK *nRank,
1945 : : const AT_RANK *nAtomNumber )
1946 : : {
1947 : : int i, j1, k, num_centers, iMax, bDifferentParities;
1948 : : AT_RANK nAtomRank;
1949 : : int parity, parity_k;
1950 : :
1951 : 56 : num_centers = 0;
1952 [ + + ]: 620 : for (i = 0; i < num_atoms; i++)
1953 : : {
1954 [ + + - + ]: 564 : if (!at[i].parity || at[i].stereo_bond_neighbor[0])
1955 : : {
1956 : 376 : continue;
1957 : : }
1958 [ + + ]: 188 : if (at[i].bHasStereoOrEquToStereo)
1959 : : {
1960 : 1 : continue; /* already marked */
1961 : : }
1962 [ - + ]: 187 : if ( /*!PARITY_KNOWN(at[i].stereo_atom_parity) ||*/ ( at[i].stereo_atom_parity & KNOWN_PARITIES_EQL ))
1963 : : {
1964 : 0 : continue;
1965 : : }
1966 : 187 : parity = PARITY_VAL( at[i].stereo_atom_parity );
1967 [ - + ]: 187 : if (parity == AB_PARITY_NONE)
1968 : : {
1969 : 0 : continue;
1970 : : }
1971 : 187 : nAtomRank = nRank[i];
1972 : 187 : bDifferentParities = -1;
1973 : : /* find constitutionally equivalent stereo centers and compare their known at this time parities */
1974 [ + - + + ]: 375 : for (iMax = (int) nAtomRank - 1, j1 = 0; j1 <= iMax && nAtomRank == nRank[k = (int) nAtomNumber[iMax - j1]]; j1++)
1975 : : {
1976 : : /* at[k] is constitutionally equivalent to at[i] */
1977 : 188 : parity_k = PARITY_VAL( at[k].stereo_atom_parity );
1978 [ - + ]: 188 : if (parity_k != parity)
1979 : : {
1980 : 0 : bDifferentParities = 1;
1981 : : }
1982 [ + - + + ]: 188 : else if (parity_k == parity && bDifferentParities < 0)
1983 : : {
1984 : 187 : bDifferentParities = 0;
1985 : : }
1986 [ - + ]: 188 : if (!parity_k)
1987 : : {
1988 : 0 : at[k].bHasStereoOrEquToStereo = 2;
1989 : : }
1990 [ + - ]: 188 : else if (!at[k].bHasStereoOrEquToStereo)
1991 : : {
1992 : 188 : at[k].bHasStereoOrEquToStereo = 1;
1993 : : }
1994 : : }
1995 [ + - + - : 187 : if (0 == bDifferentParities && PARITY_KNOWN( parity ))
+ - ]
1996 : : {
1997 [ + - + + ]: 375 : for (iMax = (int) nAtomRank - 1, j1 = 0; j1 <= iMax && nAtomRank == nRank[k = (int) nAtomNumber[iMax - j1]]; j1++)
1998 : : {
1999 : : /* at[k] is constitutionally equivalent to at[i] */
2000 : 188 : at[k].stereo_atom_parity |= KNOWN_PARITIES_EQL;
2001 : 188 : num_centers++;
2002 : : }
2003 : : }
2004 : : }
2005 : :
2006 : 56 : return num_centers;
2007 : : }
2008 : :
2009 : :
2010 : : /*****************************************************************************/
2011 : : /* invert known parities in at[] and in pCS->LinearCTStereoDble */
2012 : : /* pCS->LinearCTStereoCarb */
2013 : : /* nCanonRank[] contains canonical ranks used to fill pCS->LinearCTStereo... */
2014 : : /* nAtomNumberCanon[] will be filled with atom numbers in canonical order */
2015 : : /*****************************************************************************/
2016 : 107 : int InvertStereo( sp_ATOM *at,
2017 : : int num_at_tg,
2018 : : AT_RANK *nCanonRank,
2019 : : AT_RANK *nAtomNumberCanon,
2020 : : CANON_STAT *pCS,
2021 : : int bInvertLinearCTStereo )
2022 : : {
2023 : : int i, j, j1, j2, num_changes, parity, cumulene_len;
2024 : :
2025 : 107 : num_changes = 0;
2026 [ + + ]: 1193 : for (i = 0; i < num_at_tg; i++)
2027 : : {
2028 : 1086 : nAtomNumberCanon[(int) nCanonRank[i] - 1] = i;
2029 : : }
2030 [ + + ]: 474 : for (i = 0; i < pCS->nLenLinearCTStereoCarb; i++)
2031 : : {
2032 : 367 : parity = pCS->LinearCTStereoCarb[i].parity;
2033 [ + - + + ]: 367 : if (ATOM_PARITY_WELL_DEF( parity ))
2034 : : {
2035 : 334 : j = nAtomNumberCanon[(int) pCS->LinearCTStereoCarb[i].at_num - 1];
2036 [ + - + - ]: 334 : if (PARITY_WELL_DEF( at[j].parity ))
2037 : : {
2038 : 334 : at[j].parity ^= AB_INV_PARITY_BITS;
2039 : : }
2040 : : else
2041 : : {
2042 : 0 : goto exit_error; /* inconsistency */
2043 : : }
2044 [ + + ]: 334 : if (bInvertLinearCTStereo)
2045 : : {
2046 : : #ifdef FIX_STEREOCOUNT_ERR
2047 : 167 : pCS->LinearCTStereoCarb[i].parity = AB_PARITY_EVEN; /* deliberately worse */
2048 : : #else
2049 : : pCS->LinearCTStereoCarb[i].parity ^= AB_INV_PARITY_BITS;
2050 : : #endif
2051 : : }
2052 : 334 : num_changes++;
2053 [ + - + - ]: 334 : if (PARITY_WELL_DEF( at[j].stereo_atom_parity ))
2054 : : {
2055 : 334 : at[j].stereo_atom_parity ^= AB_INV_PARITY_BITS;
2056 : : }
2057 [ - + - - ]: 334 : if (PARITY_WELL_DEF( at[j].final_parity ))
2058 : : {
2059 : 0 : at[j].final_parity ^= AB_INV_PARITY_BITS;
2060 : : }
2061 : : }
2062 : : }
2063 [ - + ]: 107 : for (i = 0; i < pCS->nLenLinearCTStereoDble; i++)
2064 : : {
2065 : 0 : parity = pCS->LinearCTStereoDble[i].parity;
2066 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( parity ))
2067 : : {
2068 : 0 : j1 = nAtomNumberCanon[(int) pCS->LinearCTStereoDble[i].at_num1 - 1];
2069 : 0 : cumulene_len = BOND_CHAIN_LEN( at[j1].stereo_bond_parity[0] );
2070 [ # # ]: 0 : if (cumulene_len % 2)
2071 : : {
2072 : : /* invert only in case of allene */
2073 : 0 : j2 = nAtomNumberCanon[(int) pCS->LinearCTStereoDble[i].at_num2 - 1];
2074 : : /* checks for debug only */
2075 : : if (1 < MAX_NUM_STEREO_BONDS)
2076 : : {
2077 [ # # ]: 0 : if (at[j1].stereo_bond_neighbor[1] ||
2078 [ # # ]: 0 : at[j2].stereo_bond_neighbor[1])
2079 : : {
2080 : 0 : goto exit_error; /* inconsitency: atom has more than one cumulene bond */
2081 : : }
2082 : : }
2083 [ # # ]: 0 : if (cumulene_len != BOND_CHAIN_LEN( at[j2].stereo_bond_parity[0] ) ||
2084 [ # # ]: 0 : j1 + 1 != at[j2].stereo_bond_neighbor[0] ||
2085 [ # # ]: 0 : j2 + 1 != at[j1].stereo_bond_neighbor[0])
2086 : : {
2087 : 0 : goto exit_error; /* inconsitency: atoms should refer to each other */
2088 : : }
2089 : : /* invert parities */
2090 [ # # # # : 0 : if (PARITY_WELL_DEF( at[j1].parity ) && PARITY_WELL_DEF( at[j2].parity ))
# # # # ]
2091 : : {
2092 : 0 : j = inchi_min( j1, j2 );
2093 : 0 : at[j].parity ^= AB_INV_PARITY_BITS; /* for reversability always invert only atom with the smaller number */
2094 : : }
2095 : : else
2096 : : {
2097 : 0 : goto exit_error; /* inconsistency */
2098 : : }
2099 [ # # ]: 0 : if (bInvertLinearCTStereo)
2100 : : {
2101 : 0 : pCS->LinearCTStereoDble[i].parity ^= AB_INV_PARITY_BITS;
2102 : : }
2103 : 0 : num_changes++;
2104 [ # # # # ]: 0 : if (PARITY_WELL_DEF( at[j1].stereo_bond_parity[0] ))
2105 : : {
2106 : 0 : at[j1].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
2107 : : }
2108 [ # # # # ]: 0 : if (PARITY_WELL_DEF( at[j2].stereo_bond_parity[0] ))
2109 : : {
2110 : 0 : at[j2].stereo_bond_parity[0] ^= AB_INV_PARITY_BITS;
2111 : : }
2112 : : }
2113 : : }
2114 : : }
2115 : :
2116 : 107 : return num_changes;
2117 : :
2118 : 0 : exit_error:
2119 : 0 : return CT_STEREOCOUNT_ERR;
2120 : : }
2121 : :
2122 : :
2123 : : /********************************************************************************/
2124 : : /* Make sure atoms stereo descriptors fit molecular symmetry and remove */
2125 : : /* parity from obviously non-stereo atoms and bonds */
2126 : : /********************************************************************************/
2127 : 56 : int FillOutStereoParities( sp_ATOM *at,
2128 : : int num_atoms,
2129 : : const AT_RANK *nCanonRank,
2130 : : const AT_RANK *nAtomNumberCanon,
2131 : : const AT_RANK *nRank,
2132 : : const AT_RANK *nAtomNumber,
2133 : : CANON_STAT *pCS,
2134 : : CANON_GLOBALS *pCG,
2135 : : int bIsotopic )
2136 : : {
2137 : : int ret;
2138 : : /* unmark atoms with 2 or more constitutionally equivalent neighbors */
2139 : : /* such that there is no path through them to an atom with parity */
2140 : 56 : ret = UnmarkNonStereo( pCG, at, num_atoms, nRank, nAtomNumber, bIsotopic );
2141 [ - + ]: 56 : if (ret < 0)
2142 : 0 : return ret; /* program error? */ /* <BRKPT> */
2143 : 56 : ret = FillAllStereoDescriptors( pCG, at, num_atoms, nCanonRank, nAtomNumberCanon, pCS ); /* ret<0: error */
2144 [ + - ]: 56 : if (!ret)
2145 : : {
2146 : 56 : ret = pCS->nLenLinearCTStereoCarb + pCS->nLenLinearCTStereoDble;
2147 : : }
2148 [ - + ]: 56 : if (ret < 0)
2149 : : {
2150 : 0 : return ret; /* program error? */ /* <BRKPT> */
2151 : : }
2152 : :
2153 [ + - ]: 56 : if (ret >= 0)
2154 : : {
2155 : : int ret2;
2156 : 56 : ret2 = SetKnownStereoCenterParities( pCG, at, num_atoms, nCanonRank, nRank, nAtomNumber );
2157 [ + - ]: 56 : if (ret2 >= 0)
2158 : : {
2159 : 56 : ret2 = MarkKnownEqualStereoCenterParities( at, num_atoms, nRank, nAtomNumber );
2160 : : }
2161 [ + - ]: 56 : if (ret2 >= 0)
2162 : : {
2163 : 56 : ret2 = SetKnownStereoBondParities( pCG, at, num_atoms, nCanonRank, nRank, nAtomNumber );
2164 [ + - ]: 56 : if (ret2 >= 0)
2165 : : {
2166 : 56 : ret2 = MarkKnownEqualStereoBondParities( at, num_atoms, nRank, nAtomNumber );
2167 : : }
2168 : : }
2169 : : #if ( REMOVE_KNOWN_NONSTEREO == 1 ) /* { */
2170 [ + - ]: 56 : if (ret2 >= 0)
2171 : : {
2172 : : int ret3;
2173 : : do
2174 : : {
2175 : 57 : ret2 = RemoveKnownNonStereoCenterParities( pCG, at, num_atoms, nCanonRank, nRank, pCS );
2176 [ + - ]: 57 : if (ret2 >= 0)
2177 : : {
2178 : 57 : ret3 = RemoveKnownNonStereoBondParities( at, num_atoms, nCanonRank, nRank, pCS );
2179 [ + - ]: 57 : ret2 = ret3 >= 0 ? ret2 + ret3 : ret3;
2180 : : }
2181 : : }
2182 [ + + ]: 57 : while (ret2 > 0);
2183 : : }
2184 [ + - - + ]: 56 : if (RETURNED_ERROR( ret2 ))
2185 : : {
2186 : 0 : ret = ret2;
2187 : : }
2188 : : #endif /* } REMOVE_KNOWN_NONSTEREO */
2189 : : }
2190 : :
2191 : 56 : return ret; /* non-zero means error */
2192 : : }
2193 : :
2194 : :
2195 : :
2196 : : /****************************************************************************/
2197 : 0 : int GetStereoNeighborPos( sp_ATOM *at,
2198 : : int iAt1,
2199 : : int iAt2 )
2200 : : {
2201 : : int k1;
2202 : 0 : AT_RANK sNeigh = (AT_RANK) ( iAt2 + 1 );
2203 : : AT_RANK s;
2204 [ # # # # ]: 0 : for (k1 = 0; k1 < MAX_NUM_STEREO_BONDS && ( s = at[iAt1].stereo_bond_neighbor[k1] ); k1++)
2205 : : {
2206 [ # # ]: 0 : if (s == sNeigh)
2207 : : {
2208 : 0 : return k1;
2209 : : }
2210 : : }
2211 : :
2212 : 0 : return -1; /* neighbor not found */
2213 : : }
2214 : :
2215 : :
2216 : : /****************************************************************************
2217 : : Extracted from FillSingleStereoDescriptors(...)
2218 : : ****************************************************************************/
2219 : 0 : int GetStereoBondParity( sp_ATOM *at,
2220 : : int i,
2221 : : int n,
2222 : : AT_RANK *nRank )
2223 : : {
2224 : : int k1, k2, s, parity;
2225 : :
2226 [ # # ]: 0 : if (at[i].stereo_bond_neighbor[0])
2227 : : {
2228 [ # # # # ]: 0 : for (k1 = 0; k1 < MAX_NUM_STEREO_BONDS && ( s = (int) at[i].stereo_bond_neighbor[k1] ); k1++)
2229 : : {
2230 [ # # ]: 0 : if (--s == n)
2231 : : {
2232 : 0 : goto neigh1_found;
2233 : : }
2234 : : }
2235 : 0 : return -1; /* error: not a stereo neighbor */
2236 : 0 : neigh1_found:
2237 [ # # # # ]: 0 : if (PARITY_KNOWN( at[i].stereo_bond_parity[k1] ))
2238 : : {
2239 : 0 : return PARITY_VAL( at[i].stereo_bond_parity[k1] );
2240 : : }
2241 [ # # # # ]: 0 : for (k2 = 0; k2 < MAX_NUM_STEREO_BONDS && ( s = (int) at[n].stereo_bond_neighbor[k2] ); k2++)
2242 : : {
2243 [ # # ]: 0 : if (--s == i)
2244 : : {
2245 : 0 : goto neigh2_found;
2246 : : }
2247 : : }
2248 : 0 : return -1; /* error: not a stereo neighbor */
2249 : 0 : neigh2_found:;
2250 : : }
2251 : : else
2252 : : {
2253 : 0 : return -1; /* error: not a stereo bond */
2254 : : }
2255 : :
2256 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[i].parity ) &&
2257 [ # # # # ]: 0 : ATOM_PARITY_WELL_DEF( at[n].parity ) &&
2258 [ # # ]: 0 : MIN_DOT_PROD <= abs( at[i].stereo_bond_z_prod[k1] ))
2259 : 0 : {
2260 : : /* bond parity can be calculated */
2261 : : int half_parity1, half_parity2;
2262 : : /* check whether all neighbors are defined */
2263 : :
2264 : :
2265 : 0 : half_parity1 = HalfStereoBondParity( at, i, k1, nRank );
2266 : 0 : half_parity2 = HalfStereoBondParity( at, n, k2, nRank );
2267 [ # # # # ]: 0 : if (!half_parity1 || !half_parity2)
2268 : 0 : return 0; /* ranks undefined or not a stereo bond */
2269 [ # # # # : 0 : if (ATOM_PARITY_WELL_DEF( half_parity1 ) &&
# # ]
2270 [ # # ]: 0 : ATOM_PARITY_WELL_DEF( half_parity2 ))
2271 : : {
2272 : 0 : parity = 2 - ( half_parity1 + half_parity2
2273 : 0 : + ( at[i].stereo_bond_z_prod[k1] < 0 ) ) % 2;
2274 : : }
2275 : : else
2276 : : {
2277 : 0 : return CT_STEREOBOND_ERROR; /* <BRKPT> */
2278 : : }
2279 : : }
2280 : : else
2281 : : {
2282 : : /* parity cannot be calculated: not enough info or 'unknown' */
2283 [ # # ]: 0 : if (AB_PARITY_NONE != ( parity = inchi_max( at[i].parity, at[n].parity ) ))
2284 : : {
2285 : 0 : parity = AB_PARITY_UNDF; /* should not happen */
2286 : : }
2287 : : }
2288 : :
2289 : 0 : return parity;
2290 : : }
2291 : :
2292 : :
2293 : : /****************************************************************************
2294 : : Extracted from FillSingleStereoDescriptors(...)
2295 : : ****************************************************************************/
2296 : 0 : int GetPermutationParity( CANON_GLOBALS *pCG,
2297 : : sp_ATOM *at,
2298 : : AT_RANK nAvoidNeighbor,
2299 : : AT_RANK *nCanonRank )
2300 : : {
2301 : : AT_RANK nNeighRank[MAX_NUM_STEREO_ATOM_NEIGH];
2302 : : int j, k, parity;
2303 [ # # ]: 0 : if (at->valence > MAX_NUM_STEREO_ATOM_NEIGH)
2304 : : {
2305 : 0 : parity = -1; /* error */
2306 : : }
2307 : : else
2308 : : {
2309 [ # # ]: 0 : for (j = k = 0; j < at->valence; j++)
2310 : : {
2311 [ # # ]: 0 : if (at->neighbor[j] != nAvoidNeighbor)
2312 : : {
2313 : 0 : nNeighRank[k++] = nCanonRank[(int) at->neighbor[j]];
2314 : : }
2315 : : }
2316 [ # # ]: 0 : if (k)
2317 : : {
2318 : 0 : parity = insertions_sort( pCG, nNeighRank, k, sizeof( nNeighRank[0] ), comp_AT_RANK );
2319 [ # # ]: 0 : if (nNeighRank[0])
2320 : : {
2321 : 0 : parity = 2 - parity % 2;
2322 : : }
2323 : : else
2324 : : {
2325 : 0 : parity = 0; /* not all ranks are known */
2326 : : }
2327 : : }
2328 : : else
2329 : : {
2330 : : /* special case: HX= with implicit H */
2331 : 0 : parity = 2;
2332 : : }
2333 : : }
2334 : :
2335 : 0 : return parity;
2336 : : }
2337 : :
2338 : :
2339 : : /****************************************************************************/
2340 : 0 : int GetStereoCenterParity( CANON_GLOBALS *pCG,
2341 : : sp_ATOM *at,
2342 : : int i,
2343 : : AT_RANK *nRank )
2344 : : {
2345 : : AT_NUMB nNeighborNumber2[MAXVAL];
2346 : : int parity;
2347 : : int k, num_trans;
2348 : :
2349 [ # # ]: 0 : if (!at[i].parity)
2350 : : {
2351 : 0 : return 0; /* not a stereo center */
2352 : : }
2353 [ # # ]: 0 : if (at[i].stereo_bond_neighbor[0])
2354 : : {
2355 : 0 : return -1; /* a stereo bond atom, not a stereo center */
2356 : : }
2357 : :
2358 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[i].parity ))
2359 : 0 : {
2360 : : /* number of neighbors transpositions to the sorted order is unknown. Find it. */
2361 : : /* If parity is not well-defined then doing this is a waste of time */
2362 : 0 : int num_neigh = at[i].valence;
2363 [ # # ]: 0 : for (k = 0; k < num_neigh; k++)
2364 : : {
2365 [ # # ]: 0 : if (!nRank[(int) at[i].neighbor[k]])
2366 : 0 : return 0; /* stereo at[i] does not belong to the traversed part of the structure */
2367 : 0 : nNeighborNumber2[k] = k;
2368 : : }
2369 : 0 : pCG->m_pNeighborsForSort = at[i].neighbor;
2370 : 0 : pCG->m_pn_RankForSort = nRank;
2371 : 0 : num_trans = insertions_sort( pCG, nNeighborNumber2, num_neigh, sizeof( nNeighborNumber2[0] ), CompNeighborsAT_NUMBER );
2372 : : #ifndef CT_NEIGH_INCREASE
2373 : : num_trans += ( ( num_neigh*( num_neigh - 1 ) ) / 2 ) % 2; /* get correct parity for ascending order */
2374 : : #endif
2375 : 0 : parity = 2 - ( at[i].parity + num_trans ) % 2;
2376 : : }
2377 : : else
2378 : : {
2379 : 0 : parity = at[i].parity;
2380 : : }
2381 : :
2382 : 0 : return parity;
2383 : : }
|