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 <stdio.h>
42 : : #include <stdlib.h>
43 : : #include <string.h>
44 : : #include <ctype.h>
45 : : #include <time.h>
46 : : #include <sys/timeb.h>
47 : : #include <limits.h>
48 : :
49 : : #include "mode.h"
50 : : #include "ichicano.h"
51 : :
52 : : #include "ichitime.h"
53 : : #include "ichi.h"
54 : : #include "ichicomn.h"
55 : :
56 : : #include "bcf_s.h"
57 : :
58 : : /****************************************************************************
59 : : *
60 : : * Globals for sorting
61 : : ****************************************************************************/
62 : :
63 : : #define tsort insertions_sort
64 : :
65 : : /* local prototypes */
66 : :
67 : : void FillOutAtomInvariant( sp_ATOM* at,
68 : : int num_atoms,
69 : : int num_at_tg,
70 : : ATOM_INVARIANT* pAtomInvariant,
71 : : CANON_STAT* pCS );
72 : :
73 : : int Canon_INChI1( int num_atoms,
74 : : int num_at_tg,
75 : : sp_ATOM* at,
76 : : CANON_STAT* pCS,
77 : : INCHI_MODE nMode );
78 : :
79 : : int Canon_INChI2( int num_atoms,
80 : : int num_at_tg,
81 : : sp_ATOM* at,
82 : : CANON_STAT* pCS,
83 : : INCHI_MODE nMode );
84 : :
85 : : int Canon_INChI3( INCHI_CLOCK *ic,
86 : : int num_atoms,
87 : : int num_at_tg,
88 : : sp_ATOM* at,
89 : : CANON_STAT* pCS,
90 : : CANON_GLOBALS *pCG,
91 : : INCHI_MODE nMode,
92 : : int bTautFtcn );
93 : :
94 : :
95 : : #ifdef COMPILE_ANSI_ONLY
96 : :
97 : : static clock_t InchiClock( void );
98 : :
99 : : #ifdef INCHI_USETIMES
100 : : static clock_t InchiClock( void )
101 : : {
102 : : struct tms buf;
103 : : clock_t c = times( &buf );
104 : : if (c != (clock_t) -1)
105 : : {
106 : : return buf.tms_utime;
107 : : }
108 : : return 0;
109 : : }
110 : : #else
111 : 798 : static clock_t InchiClock( void )
112 : : {
113 : 798 : clock_t c = clock( );
114 [ + - ]: 798 : if (c != (clock_t) -1)
115 : : {
116 : 798 : return c;
117 : : }
118 : 0 : return 0;
119 : : }
120 : : #endif
121 : :
122 : : #define INCHI_MSEC(X) (long)((1000.0/(double)CLOCKS_PER_SEC)*(X))
123 : : #define INCHI_CLOCK_T(X) (clock_t)( (double)(X) / 1000.0 * (double)CLOCKS_PER_SEC )
124 : : const clock_t FullMaxClock = (clock_t) ( -1 );
125 : : const clock_t HalfMaxClock = (clock_t) ( -1 ) / 2;
126 : :
127 : : static void FillMaxMinClock( INCHI_CLOCK *ic ); /* keep compiler happy */
128 : 651 : static void FillMaxMinClock( INCHI_CLOCK *ic )
129 : : {
130 [ + + ]: 651 : if (!ic->m_MaxPositiveClock)
131 : : {
132 : 54 : clock_t valPos = 0, val1 = 1;
133 [ + + ]: 3402 : while (0 < ( ( val1 <<= 1 ), ( val1 |= 1 ) )) /* djb-rwth: ignoring GH issue #59.3 -- LLONG_MIN/LLONG_MAX not found in <limits.h> on Linux */
134 : : {
135 : 3348 : valPos = val1;
136 : : }
137 : 54 : ic->m_MaxPositiveClock = valPos;
138 : 54 : ic->m_MinNegativeClock = -valPos;
139 : 54 : ic->m_HalfMaxPositiveClock = ic->m_MaxPositiveClock / 2;
140 : 54 : ic->m_HalfMinNegativeClock = ic->m_MinNegativeClock / 2;
141 : : }
142 : 651 : }
143 : :
144 : :
145 : : /******** get current process time ****************************************/
146 : 798 : void InchiTimeGet( inchiTime *TickEnd )
147 : : {
148 : 798 : TickEnd->clockTime = InchiClock( );
149 : 798 : }
150 : : /******** returns difference TickEnd - TickStart in milliseconds **********/
151 : 399 : long InchiTimeMsecDiff( INCHI_CLOCK *ic, inchiTime *TickEnd, inchiTime *TickStart )
152 : : {
153 [ - + ]: 399 : if (FullMaxClock > 0)
154 : : {
155 : : clock_t delta;
156 [ # # # # ]: 0 : if (!TickEnd || !TickStart)
157 : 0 : return 0;
158 : : /* clock_t is unsigned */
159 [ # # ]: 0 : if (TickEnd->clockTime > TickStart->clockTime)
160 : : {
161 [ # # ]: 0 : if (TickEnd->clockTime > HalfMaxClock &&
162 [ # # ]: 0 : TickEnd->clockTime - TickStart->clockTime > HalfMaxClock)
163 : : {
164 : : /* overflow in TickStart->clockTime, actually TickStart->clockTime was later */
165 : 0 : delta = ( FullMaxClock - TickEnd->clockTime ) + TickStart->clockTime;
166 : 0 : return -INCHI_MSEC( delta );
167 : : }
168 : 0 : delta = TickEnd->clockTime - TickStart->clockTime;
169 : 0 : return INCHI_MSEC( delta );
170 : : }
171 [ # # ]: 0 : else if (TickEnd->clockTime < TickStart->clockTime)
172 : : {
173 [ # # ]: 0 : if (TickStart->clockTime > HalfMaxClock &&
174 [ # # ]: 0 : TickStart->clockTime - TickEnd->clockTime > HalfMaxClock)
175 : : {
176 : : /* overflow in TickEnd->clockTime, actually TickEnd->clockTime was later */
177 : 0 : delta = ( FullMaxClock - TickStart->clockTime ) + TickEnd->clockTime;
178 : 0 : return INCHI_MSEC( delta );
179 : : }
180 : 0 : delta = TickStart->clockTime - TickEnd->clockTime;
181 : 0 : return -INCHI_MSEC( delta );
182 : : }
183 : 0 : return 0; /* TickEnd->clockTime == TickStart->clockTime */
184 : : }
185 : : else
186 : : {
187 : : /* may happen under Win32 only where clock_t is SIGNED long */
188 : : clock_t delta;
189 : 399 : FillMaxMinClock( ic );
190 [ + - - + ]: 399 : if (!TickEnd || !TickStart)
191 : 0 : return 0;
192 [ + - - + ]: 399 : if ((TickEnd->clockTime >= 0 && TickStart->clockTime >= 0) ||
193 [ # # # # ]: 0 : (TickEnd->clockTime <= 0 && TickStart->clockTime <= 0)) /* djb-rwth: addressing LLVM warnings */
194 : : {
195 : 399 : delta = TickEnd->clockTime - TickStart->clockTime;
196 : : }
197 : : else
198 [ # # ]: 0 : if (TickEnd->clockTime >= ic->m_HalfMaxPositiveClock &&
199 [ # # ]: 0 : TickStart->clockTime <= ic->m_HalfMinNegativeClock)
200 : : {
201 : : /* end is earlier than start */
202 : 0 : delta = ( ic->m_MaxPositiveClock - TickEnd->clockTime ) + ( TickStart->clockTime - ic->m_MinNegativeClock );
203 : 0 : delta = -delta;
204 : : }
205 : : else
206 [ # # ]: 0 : if (TickEnd->clockTime <= ic->m_HalfMinNegativeClock &&
207 [ # # ]: 0 : TickStart->clockTime >= ic->m_HalfMaxPositiveClock)
208 : : {
209 : : /* start was earlier than end */
210 : 0 : delta = ( ic->m_MaxPositiveClock - TickStart->clockTime ) + ( TickEnd->clockTime - ic->m_MinNegativeClock );
211 : : }
212 : : else
213 : : {
214 : : /* there was no overflow, clock passed zero */
215 : 0 : delta = TickEnd->clockTime - TickStart->clockTime;
216 : : }
217 : 399 : return INCHI_MSEC( delta );
218 : : }
219 : : }
220 : :
221 : :
222 : : /******************* get elapsed time from TickStart ************************/
223 : 330 : long InchiTimeElapsed( INCHI_CLOCK *ic, inchiTime *TickStart )
224 : : {
225 : : inchiTime TickEnd;
226 [ - + ]: 330 : if (!TickStart)
227 : 0 : return 0;
228 : 330 : InchiTimeGet( &TickEnd );
229 : 330 : return InchiTimeMsecDiff( ic, &TickEnd, TickStart );
230 : : }
231 : :
232 : :
233 : : /******************* add number of milliseconds to time *********************/
234 : 0 : void InchiTimeAddMsec( INCHI_CLOCK *ic, inchiTime *TickEnd, unsigned long nNumMsec )
235 : : {
236 : : clock_t delta;
237 [ # # ]: 0 : if (!TickEnd)
238 : 0 : return;
239 [ # # ]: 0 : if (FullMaxClock > 0)
240 : : {
241 : : /* clock_t is unsigned */
242 : 0 : delta = INCHI_CLOCK_T( nNumMsec );
243 : 0 : TickEnd->clockTime += delta;
244 : : }
245 : : else
246 : : {
247 : : /* may happen under Win32 only where clock_t is SIGNED long */
248 : : /* clock_t is unsigned */
249 : 0 : FillMaxMinClock( ic );
250 : 0 : delta = INCHI_CLOCK_T( nNumMsec );
251 : 0 : TickEnd->clockTime += delta;
252 : : }
253 : : }
254 : :
255 : :
256 : : /******************* check whether time has expired *********************/
257 : 252 : int bInchiTimeIsOver( INCHI_CLOCK *ic, inchiTime *TickStart )
258 : : {
259 [ - + ]: 252 : if (FullMaxClock > 0)
260 : : {
261 : : clock_t clockCurrTime;
262 [ # # ]: 0 : if (!TickStart)
263 : 0 : return 0;
264 : 0 : clockCurrTime = InchiClock( );
265 : : /* clock_t is unsigned */
266 [ # # ]: 0 : if (TickStart->clockTime > clockCurrTime)
267 : : {
268 [ # # ]: 0 : if (TickStart->clockTime > HalfMaxClock &&
269 [ # # ]: 0 : TickStart->clockTime - clockCurrTime > HalfMaxClock)
270 : : {
271 : : /* overflow in clockCurrTime, actually clockCurrTime was later */
272 : 0 : return 1;
273 : : }
274 : 0 : return 0;
275 : : }
276 [ # # ]: 0 : else if (TickStart->clockTime < clockCurrTime)
277 : : {
278 [ # # ]: 0 : if (clockCurrTime > HalfMaxClock &&
279 [ # # ]: 0 : clockCurrTime - TickStart->clockTime > HalfMaxClock)
280 : : {
281 : : /* overflow in TickStart->clockTime, actually TickStart->clockTime was later */
282 : 0 : return 0;
283 : : }
284 : 0 : return 1;
285 : : }
286 : 0 : return 0; /* TickStart->clockTime == clockCurrTime */
287 : : }
288 : : else
289 : : {
290 : : /* may happen under Win32 only where clock_t is SIGNED long */
291 : : clock_t clockCurrTime;
292 : 252 : FillMaxMinClock( ic );
293 [ + - ]: 252 : if (!TickStart)
294 : 252 : return 0;
295 : 0 : clockCurrTime = InchiClock( );
296 [ # # # # : 0 : if ((clockCurrTime >= 0 && TickStart->clockTime >= 0) ||
# # ]
297 [ # # ]: 0 : (clockCurrTime <= 0 && TickStart->clockTime <= 0)) /* djb-rwth: addressing LLVM warning */
298 : : {
299 : 0 : return ( clockCurrTime > TickStart->clockTime );
300 : : }
301 : : else
302 [ # # ]: 0 : if (clockCurrTime >= ic->m_HalfMaxPositiveClock &&
303 [ # # ]: 0 : TickStart->clockTime <= ic->m_HalfMinNegativeClock)
304 : : {
305 : : /* curr is earlier than start */
306 : 0 : return 0;
307 : : }
308 : : else
309 [ # # ]: 0 : if (clockCurrTime <= ic->m_HalfMinNegativeClock &&
310 [ # # ]: 0 : TickStart->clockTime >= ic->m_HalfMaxPositiveClock)
311 : : {
312 : : /* start was earlier than curr */
313 : 0 : return 1;
314 : : }
315 : : else
316 : : {
317 : : /* there was no overflow, clock passed zero */
318 : 0 : return ( clockCurrTime > TickStart->clockTime );
319 : : }
320 : : }
321 : : }
322 : :
323 : :
324 : :
325 : : #else
326 : :
327 : : /******** get current process time ****************************************/
328 : : void InchiTimeGet( inchiTime *TickEnd )
329 : : {
330 : : if (TickEnd)
331 : : {
332 : : struct _timeb timeb;
333 : : _ftime( &timeb );
334 : : TickEnd->clockTime = (unsigned long) timeb.time;
335 : : TickEnd->millitime = (long) timeb.millitm;
336 : : }
337 : : }
338 : :
339 : :
340 : : /******** returns difference TickEnd - TickStart in milliseconds **********/
341 : : long InchiTimeMsecDiff( INCHI_CLOCK *ic, inchiTime *TickEnd, inchiTime *TickStart )
342 : : {
343 : : long delta;
344 : : if (!TickEnd || !TickStart)
345 : : {
346 : : return 0;
347 : : }
348 : : if (TickEnd->clockTime >= TickStart->clockTime)
349 : : {
350 : : delta = (long) ( TickEnd->clockTime - TickStart->clockTime );
351 : : delta *= 1000;
352 : : delta += TickEnd->millitime - TickStart->millitime;
353 : : }
354 : : else
355 : : {
356 : : delta = -(long) ( TickStart->clockTime - TickEnd->clockTime );
357 : : delta *= 1000;
358 : : delta += TickEnd->millitime - TickStart->millitime;
359 : : }
360 : : return delta;
361 : : }
362 : :
363 : :
364 : : /******************* get elapsed time from TickStart ************************/
365 : : long InchiTimeElapsed( INCHI_CLOCK *ic, inchiTime *TickStart )
366 : : {
367 : : inchiTime TickEnd;
368 : : if (!TickStart)
369 : : {
370 : : return 0;
371 : : }
372 : : InchiTimeGet( &TickEnd );
373 : : return InchiTimeMsecDiff( ic, &TickEnd, TickStart );
374 : : }
375 : :
376 : :
377 : : /******************* add number of milliseconds to time *********************/
378 : : void InchiTimeAddMsec( INCHI_CLOCK *ic, inchiTime *TickEnd, unsigned long nNumMsec )
379 : : {
380 : : long delta;
381 : : if (!TickEnd)
382 : : {
383 : : return;
384 : : }
385 : : TickEnd->clockTime += nNumMsec / 1000;
386 : : delta = nNumMsec % 1000 + TickEnd->millitime;
387 : : TickEnd->clockTime += delta / 1000;
388 : : TickEnd->millitime = delta % 1000;
389 : : }
390 : :
391 : :
392 : : /******************* check whether time has expired *********************/
393 : : int bInchiTimeIsOver( INCHI_CLOCK *ic, inchiTime *TickEnd )
394 : : {
395 : : struct _timeb timeb;
396 : : if (!TickEnd)
397 : : {
398 : : return 0;
399 : : }
400 : : _ftime( &timeb );
401 : : if (TickEnd->clockTime > (unsigned long) timeb.time)
402 : : {
403 : : return 0;
404 : : }
405 : : if (TickEnd->clockTime < (unsigned long) timeb.time || TickEnd->millitime < (long) timeb.millitm)
406 : : {
407 : : return 1;
408 : : }
409 : : return 0;
410 : : }
411 : :
412 : : #endif
413 : :
414 : :
415 : : /****************************************************************************
416 : : length of canonic representation in sizeof(AT_NUMB) units
417 : : ****************************************************************************/
418 : 69 : int GetCanonLengths( int num_at,
419 : : sp_ATOM* at,
420 : : ATOM_SIZES *s,
421 : : T_GROUP_INFO *t_group_info )
422 : : {
423 : : /* include taut. groups as additional "atoms" to the connection table 07-22-2002 */
424 : :
425 : 69 : int i, nNumCT, nNumBonds, nNumTBonds = 0, nNumDblBondsStereo = 0, nNumAsymCarbStereo = 0, nNumIsotopic = 0;
426 [ + + + - ]: 69 : T_GROUP *t_group = ( s->nLenLinearCTTautomer && t_group_info ) ? t_group_info->t_group : NULL;
427 : :
428 [ + + ]: 688 : for (nNumBonds = 0, i = 0; i < num_at; i++)
429 : : {
430 : 619 : nNumBonds += at[i].valence;
431 [ - + ]: 619 : if (at[i].iso_sort_key)
432 : : {
433 : 0 : nNumIsotopic++; /* not including tautomeric endpoints that are isotopic only due to mobile atoms */
434 : : }
435 : :
436 [ + + ]: 619 : if (at[i].parity > 0)
437 : : {
438 : : /* ignore hydrogen isotope parities in at[i].parity2 */
439 : 199 : int j = 0, nStereoBondsToAtom = 0; /* number of stereo double bonds at this atom */
440 : : int k;
441 [ + - - + ]: 199 : for (; j < MAX_NUM_STEREO_BONDS && ( k = at[i].stereo_bond_neighbor[j] ); j++)
442 : : {
443 : 0 : nStereoBondsToAtom += ( at[k - 1].parity > 0 );
444 : : }
445 : 199 : nNumDblBondsStereo += nStereoBondsToAtom;
446 : 199 : nNumAsymCarbStereo += !j;
447 : : }
448 : : }
449 : :
450 : 69 : nNumDblBondsStereo /= 2;
451 : 69 : nNumBonds /= 2;
452 : :
453 : 69 : s->nLenBonds = inchi_max( s->nLenBonds, nNumBonds );
454 : 69 : nNumCT = nNumBonds; /* total number of neighbors in the CT */
455 : :
456 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
457 : 69 : nNumCT += num_at;
458 : : #endif
459 : :
460 : 69 : s->nLenCTAtOnly = inchi_max( s->nLenCTAtOnly, nNumCT );
461 : :
462 [ + + ]: 69 : if (t_group)
463 : : {
464 [ - + ]: 3 : for (i = 0; i < t_group_info->num_t_groups; i++)
465 : : {
466 : 0 : nNumTBonds += t_group[i].nNumEndpoints;
467 : : }
468 : 3 : nNumCT += nNumTBonds;
469 : :
470 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
471 : 3 : nNumCT += t_group_info->num_t_groups;
472 : : #endif
473 : : }
474 : :
475 : 69 : nNumCT = inchi_max( 1, nNumCT ); /* keep GetBaseCanonRanking() happy */
476 : 69 : s->nLenCT = inchi_max( s->nLenCT, nNumCT );
477 : 69 : s->nLenIsotopic = inchi_max( s->nLenIsotopic, nNumIsotopic );
478 : 69 : s->nLenLinearCTStereoDble = inchi_max( s->nLenLinearCTStereoDble, nNumDblBondsStereo );
479 : 69 : s->nLenLinearCTStereoCarb = inchi_max( s->nLenLinearCTStereoCarb, nNumAsymCarbStereo );
480 : :
481 [ + - ]: 69 : if (t_group_info)
482 : : {
483 : 69 : s->nLenIsotopicEndpoints = inchi_max( s->nLenIsotopicEndpoints, t_group_info->nNumIsotopicEndpoints );
484 : : }
485 : :
486 : 69 : return 0;
487 : : }
488 : :
489 : :
490 : : /****************************************************************************/
491 : 69 : int DeAllocateCS( CANON_STAT *pCS )
492 : : {
493 : : #define LOCAL_FREE( X) do{if(X){inchi_free( X); X=NULL;}}while(0)
494 : :
495 : : /* connection table */
496 [ + - + - ]: 69 : LOCAL_FREE( pCS->LinearCT );
497 [ + - + - ]: 69 : LOCAL_FREE( pCS->nCanonOrd );
498 [ + - + - ]: 69 : LOCAL_FREE( pCS->nSymmRank );
499 [ + - + - ]: 69 : LOCAL_FREE( pCS->nNum_H );
500 [ + - + - ]: 69 : LOCAL_FREE( pCS->nNum_H_fixed );
501 [ + - + - ]: 69 : LOCAL_FREE( pCS->nExchgIsoH );
502 : : /* isotopic */
503 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTIsotopic );
504 [ - + - - ]: 69 : LOCAL_FREE( pCS->nSymmRankIsotopic );
505 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdIsotopic );
506 : : /* isotopic tautomeric */
507 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTIsotopicTautomer );
508 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdIsotopicTaut );
509 [ - + - - ]: 69 : LOCAL_FREE( pCS->nSymmRankIsotopicTaut );
510 : : /* stereo */
511 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTStereoDble );
512 [ + + + - ]: 69 : LOCAL_FREE( pCS->LinearCTStereoCarb );
513 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTStereoDbleInv );
514 [ + + + - ]: 69 : LOCAL_FREE( pCS->LinearCTStereoCarbInv );
515 [ + + + - ]: 69 : LOCAL_FREE( pCS->nCanonOrdStereo );
516 [ + + + - ]: 69 : LOCAL_FREE( pCS->nCanonOrdStereoInv );
517 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdStereoTaut );
518 : : /* isotopic stereo */
519 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTIsotopicStereoDble );
520 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTIsotopicStereoCarb );
521 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTIsotopicStereoDbleInv );
522 [ - + - - ]: 69 : LOCAL_FREE( pCS->LinearCTIsotopicStereoCarbInv );
523 [ + + + - ]: 69 : LOCAL_FREE( pCS->bRankUsedForStereo );
524 [ + + + - ]: 69 : LOCAL_FREE( pCS->bAtomUsedForStereo );
525 : :
526 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdIsotopicStereo );
527 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdIsotopicStereoInv );
528 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdIsotopicStereoTaut );
529 : : /* tautomeric part of the connection table */
530 [ + + + - ]: 69 : LOCAL_FREE( pCS->LinearCTTautomer );
531 [ - + - - ]: 69 : LOCAL_FREE( pCS->nCanonOrdTaut );
532 [ - + - - ]: 69 : LOCAL_FREE( pCS->nSymmRankTaut );
533 : :
534 [ + - + - ]: 69 : LOCAL_FREE( pCS->LinearCT2 );
535 : :
536 : : /* for establishing constitutional equivalence */
537 [ + - + - ]: 69 : LOCAL_FREE( pCS->nPrevAtomNumber );
538 : :
539 : 69 : FreeNeighList( pCS->NeighList );
540 : 69 : pCS->NeighList = NULL;
541 : :
542 : : /* set zero lengths */
543 : 69 : pCS->nMaxLenLinearCTStereoDble = 0;
544 : 69 : pCS->nLenLinearCTStereoDble = 0;
545 : 69 : pCS->nMaxLenLinearCTStereoCarb = 0;
546 : 69 : pCS->nLenLinearCTStereoCarb = 0;
547 : 69 : pCS->nMaxLenLinearCTIsotopicStereoDble = 0;
548 : 69 : pCS->nLenLinearCTIsotopicStereoDble = 0;
549 : 69 : pCS->nMaxLenLinearCTIsotopicStereoCarb = 0;
550 : 69 : pCS->nLenLinearCTIsotopicStereoCarb = 0;
551 : 69 : pCS->nMaxLenLinearCTTautomer = 0;
552 : 69 : pCS->nLenLinearCTTautomer = 0;
553 : 69 : pCS->nMaxLenLinearCTIsotopic = 0;
554 : 69 : pCS->nLenLinearCTIsotopic = 0;
555 : 69 : pCS->nMaxLenLinearCTIsotopicTautomer = 0;
556 : 69 : pCS->nLenLinearCTIsotopicTautomer = 0;
557 : :
558 : : /* set canon numbering lengths to zero */
559 : 69 : pCS->nLenCanonOrd = 0;
560 : 69 : pCS->nLenCanonOrdIsotopic = 0;
561 : 69 : pCS->nLenCanonOrdIsotopicTaut = 0;
562 : 69 : pCS->nLenCanonOrdStereo = 0;
563 : 69 : pCS->nLenCanonOrdStereoTaut = 0;
564 : 69 : pCS->nLenCanonOrdIsotopicStereo = 0;
565 : 69 : pCS->nLenCanonOrdIsotopicStereoTaut = 0;
566 : 69 : pCS->nLenCanonOrdTaut = 0;
567 : :
568 : 69 : return 0;
569 : :
570 : : #undef LOCAL_FREE
571 : : }
572 : :
573 : :
574 : : /****************************************************************************/
575 : 69 : int AllocateCS( CANON_STAT *pCS,
576 : : int num_at,
577 : : int num_at_tg,
578 : : int nLenCT,
579 : : int nLenCTAtOnly,
580 : : int nLenLinearCTStereoDble,
581 : : int nLenLinearCTIsotopicStereoDble,
582 : : int nLenLinearCTStereoCarb,
583 : : int nLenLinearCTIsotopicStereoCarb,
584 : : int nLenLinearCTTautomer,
585 : : int nLenLinearCTIsotopicTautomer,
586 : : int nLenIsotopic,
587 : : INCHI_MODE nMode,
588 : : BCN *pBCN )
589 : : {
590 : : #define pCS_CALLOC( PTR,TYPE,LEN) (pCS->PTR=(TYPE*)inchi_calloc( (size_t)(LEN),sizeof(*pCS->PTR)))
591 : :
592 : 69 : int num_err = 0;
593 : 69 : int num_t_groups = num_at_tg - num_at;
594 : :
595 : 69 : pCS->nMode = nMode;
596 : :
597 : : /* connection table */
598 [ + - + - ]: 69 : if (( nMode & CMODE_CT ) && nLenCT > 0)
599 : : {
600 : 69 : num_err += !pCS_CALLOC( LinearCT, AT_NUMB, nLenCT );
601 : 69 : pCS->nMaxLenLinearCT =
602 : 69 : pCS->nLenLinearCT = nLenCT;
603 : 69 : pCS->nLenLinearCTAtOnly = nLenCTAtOnly;
604 : 69 : num_err += !pCS_CALLOC( nCanonOrd, AT_RANK, num_at_tg );
605 : 69 : num_err += !pCS_CALLOC( nSymmRank, AT_RANK, num_at_tg );
606 [ + - ]: 69 : if (pBCN)
607 : : {
608 : 69 : num_err += !pCS_CALLOC( nNum_H, S_CHAR, num_at );
609 : 69 : num_err += !pCS_CALLOC( nNum_H_fixed, S_CHAR, num_at );
610 : 69 : num_err += !pCS_CALLOC( nExchgIsoH, S_CHAR, num_at );
611 : : }
612 : : }
613 : :
614 : : /* isotopic */
615 [ - + - - ]: 69 : if (( nMode & CMODE_ISO ) && nLenIsotopic > 0)
616 : : {
617 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopic, AT_ISOTOPIC, nLenIsotopic );
618 : 0 : pCS->nMaxLenLinearCTIsotopic =
619 : 0 : pCS->nLenLinearCTIsotopic = nLenIsotopic;
620 : : }
621 : :
622 : : /* isotopic tautomeric */
623 [ - + - - ]: 69 : if (( nMode & CMODE_ISO ) && CANON_MODE_TAUT == ( nMode & CANON_MODE_TAUT ))
624 : : {
625 [ # # ]: 0 : if (nLenLinearCTIsotopicTautomer > 0)
626 : : {
627 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicTautomer, AT_ISO_TGROUP, nLenLinearCTIsotopicTautomer );
628 : 0 : pCS->nMaxLenLinearCTIsotopicTautomer =
629 : 0 : pCS->nLenLinearCTIsotopicTautomer = nLenLinearCTIsotopicTautomer;
630 : : }
631 [ # # ]: 0 : if (num_t_groups > 0)
632 : : {
633 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicTaut, AT_RANK, num_t_groups );
634 : 0 : num_err += !pCS_CALLOC( nSymmRankIsotopicTaut, AT_RANK, num_t_groups );
635 : : }
636 : : }
637 : : /* isotopic atoms & t-groups */
638 [ + - ]: 69 : if (( nMode & CMODE_ISO ) /*&& nLenIsotopic > 0*/ ||
639 [ - + - - : 69 : (( nMode & CMODE_ISO ) && CANON_MODE_TAUT == ( nMode & CANON_MODE_TAUT ) && nLenLinearCTIsotopicTautomer > 0
- - ]
640 : : )) /* djb-rwth: addressing LLVM warning */
641 : : {
642 : 0 : num_err += !pCS_CALLOC( nSymmRankIsotopic, AT_RANK, num_at_tg );
643 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopic, AT_RANK, num_at_tg );
644 : : }
645 : : /* stereo */
646 [ + + - + ]: 69 : if (( nMode & CMODE_STEREO ) && nLenLinearCTStereoDble > 0)
647 : : {
648 : 0 : num_err += !pCS_CALLOC( LinearCTStereoDble, AT_STEREO_DBLE, nLenLinearCTStereoDble );
649 : 0 : num_err += !pCS_CALLOC( LinearCTStereoDbleInv, AT_STEREO_DBLE, nLenLinearCTStereoDble );
650 : 0 : pCS->nLenLinearCTStereoDbleInv =
651 : 0 : pCS->nMaxLenLinearCTStereoDble =
652 : 0 : pCS->nLenLinearCTStereoDble = nLenLinearCTStereoDble;
653 : : }
654 [ + + + + ]: 69 : if (( nMode & CMODE_STEREO ) && nLenLinearCTStereoCarb > 0)
655 : : {
656 : 56 : num_err += !pCS_CALLOC( LinearCTStereoCarb, AT_STEREO_CARB, nLenLinearCTStereoCarb );
657 : 56 : num_err += !pCS_CALLOC( LinearCTStereoCarbInv, AT_STEREO_CARB, nLenLinearCTStereoCarb );
658 : 56 : pCS->nLenLinearCTStereoCarbInv =
659 : 56 : pCS->nMaxLenLinearCTStereoCarb =
660 : 56 : pCS->nLenLinearCTStereoCarb = nLenLinearCTStereoCarb;
661 : : }
662 [ + + + - : 69 : if (( nMode & CMODE_STEREO ) && ( nLenLinearCTStereoDble > 0 || nLenLinearCTStereoCarb > 0 ))
+ + ]
663 : : {
664 : 56 : num_err += !pCS_CALLOC( nCanonOrdStereo, AT_RANK, num_at_tg );
665 : 56 : num_err += !pCS_CALLOC( nCanonOrdStereoInv, AT_RANK, num_at_tg );
666 [ - + - - : 56 : if (( nMode & CMODE_TAUT ) && nLenLinearCTTautomer > 0 && num_t_groups > 0)
- - ]
667 : : {
668 : 0 : num_err += !pCS_CALLOC( nCanonOrdStereoTaut, AT_RANK, num_t_groups );
669 : : }
670 : : }
671 : : /* isotopic stereo */
672 [ - + - - ]: 69 : if (( nMode & CMODE_ISO_STEREO ) && nLenLinearCTIsotopicStereoDble > 0)
673 : : {
674 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoDble, AT_STEREO_DBLE, nLenLinearCTIsotopicStereoDble );
675 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoDbleInv, AT_STEREO_DBLE, nLenLinearCTIsotopicStereoDble );
676 : 0 : pCS->nLenLinearCTIsotopicStereoDbleInv =
677 : 0 : pCS->nMaxLenLinearCTIsotopicStereoDble =
678 : 0 : pCS->nLenLinearCTIsotopicStereoDble = nLenLinearCTIsotopicStereoDble;
679 : : }
680 [ - + - - ]: 69 : if (( nMode & CMODE_ISO_STEREO ) && nLenLinearCTIsotopicStereoCarb > 0)
681 : : {
682 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoCarb, AT_STEREO_CARB, nLenLinearCTIsotopicStereoCarb );
683 : 0 : num_err += !pCS_CALLOC( LinearCTIsotopicStereoCarbInv, AT_STEREO_CARB, nLenLinearCTIsotopicStereoCarb );
684 : 0 : pCS->nLenLinearCTIsotopicStereoCarbInv =
685 : 0 : pCS->nMaxLenLinearCTIsotopicStereoCarb =
686 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = nLenLinearCTIsotopicStereoCarb;
687 : : }
688 [ - + - - : 69 : if (( nMode & CMODE_ISO_STEREO ) && ( nLenLinearCTIsotopicStereoDble > 0 || nLenLinearCTIsotopicStereoCarb > 0 ))
- - ]
689 : : {
690 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicStereo, AT_RANK, num_at_tg );
691 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicStereoInv, AT_RANK, num_at_tg );
692 [ # # # # : 0 : if (( nMode & CMODE_TAUT ) && nLenLinearCTTautomer > 0 && num_t_groups > 0)
# # ]
693 : : {
694 : 0 : num_err += !pCS_CALLOC( nCanonOrdIsotopicStereoTaut, AT_RANK, num_t_groups );
695 : : }
696 : : }
697 [ + + + - : 69 : if ((( nMode & CMODE_STEREO ) && ( nLenLinearCTStereoDble > 0 || nLenLinearCTStereoCarb > 0 )) ||
+ + ]
698 [ - + - - : 13 : (( nMode & CMODE_ISO_STEREO ) && ( nLenLinearCTIsotopicStereoDble > 0 || nLenLinearCTIsotopicStereoCarb > 0 ))) /* djb-rwth: addressing LLVM warning */
- - ]
699 : : {
700 : 56 : num_err += !pCS_CALLOC( bRankUsedForStereo, S_CHAR, num_at );
701 : 56 : num_err += !pCS_CALLOC( bAtomUsedForStereo, S_CHAR, num_at );
702 : : }
703 : : /* tautomeric part of the connection table */
704 [ + - + + : 69 : if (( nMode & CMODE_CT ) && ( nMode & CMODE_TAUT ) && nLenLinearCTTautomer > 0)
+ - ]
705 : : {
706 : 3 : num_err += !pCS_CALLOC( LinearCTTautomer, AT_TAUTOMER, nLenLinearCTTautomer );
707 : 3 : pCS->nMaxLenLinearCTTautomer =
708 : 3 : pCS->nLenLinearCTTautomer = nLenLinearCTTautomer;
709 [ - + ]: 3 : if (num_t_groups > 0)
710 : : {
711 : 0 : num_err += !pCS_CALLOC( nCanonOrdTaut, AT_RANK, num_t_groups );
712 : 0 : num_err += !pCS_CALLOC( nSymmRankTaut, AT_RANK, num_t_groups );
713 : : }
714 : : }
715 : :
716 [ + - ]: 69 : if (nMode & CMODE_CT)
717 : : {
718 : 69 : num_err += !pCS_CALLOC( LinearCT2, AT_NUMB, nLenCT );
719 : : }
720 : :
721 : : /* for establishing constitutional equivalence */
722 : 69 : num_err += !pCS_CALLOC( nPrevAtomNumber, AT_RANK, num_at_tg );
723 : :
724 : : /* set canon numbering lengths to zero */
725 : 69 : pCS->nLenCanonOrd = 0;
726 : 69 : pCS->nLenCanonOrdIsotopic = 0;
727 : 69 : pCS->nLenCanonOrdIsotopicTaut = 0;
728 : 69 : pCS->nLenCanonOrdStereo = 0;
729 : 69 : pCS->nLenCanonOrdStereoTaut = 0;
730 : 69 : pCS->nLenCanonOrdIsotopicStereo = 0;
731 : 69 : pCS->nLenCanonOrdIsotopicStereoTaut = 0;
732 : 69 : pCS->nLenCanonOrdTaut = 0;
733 : :
734 : :
735 [ - + ]: 69 : if (num_err)
736 : : {
737 : 0 : DeAllocateCS( pCS );
738 : 0 : return CT_OUT_OF_RAM; /* <BRKPT> */
739 : : }
740 : 69 : return 0;
741 : :
742 : : #undef pCS_CALLOC
743 : : }
744 : :
745 : :
746 : : /****************************************************************************/
747 : :
748 : :
749 : : #define COMPARE_WITH_CT(CT, CTLEN, VALUE, CONDITION) \
750 : : if ( CONDITION ) { \
751 : : if ( (VALUE) CT_GREATER_THAN (CT)[CTLEN] ) \
752 : : return 1; /* not a minimal CT */ \
753 : : (CONDITION) = (VALUE) == (CT)[CTLEN]; \
754 : : } \
755 : : (CT)[CTLEN] = VALUE; \
756 : : (CTLEN)++
757 : :
758 : : #define COMPARE_WITH_CTVAL(CTVAL, VALUE, CONDITION) \
759 : : if ( CONDITION ) { \
760 : : if ( (VALUE) CT_GREATER_THAN (CTVAL) ) \
761 : : return 1; /* not a minimal CT */ \
762 : : (CONDITION) = (VALUE) == (CTVAL); \
763 : : } \
764 : : (CTVAL) = VALUE
765 : :
766 : : #define COMPARE_WITH_CT2(CT, CTLEN, VALUE, CONDITION, OPER) \
767 : : if ( CONDITION ) { \
768 : : if ( (VALUE) CT_GREATER_THAN (CT)[CTLEN] ) { \
769 : : (OPER); \
770 : : return 1; /* not a minimal CT */ \
771 : : } \
772 : : (CONDITION) = (VALUE) == (CT)[CTLEN]; \
773 : : } \
774 : : (CT)[CTLEN] = VALUE; \
775 : : (CTLEN)++
776 : :
777 : :
778 : :
779 : : /****************************************************************************/
780 : 0 : int FillIsotopicAtLinearCT( int num_atoms,
781 : : sp_ATOM* at,
782 : : const AT_RANK *nAtomNumber,
783 : : AT_ISOTOPIC *LinearCTIsotopic,
784 : : int nMaxLenLinearCTIsotopic,
785 : : int *pnLenLinearCTIsotopic )
786 : : {
787 : : /* at[i].init_rank = initial ranks before canonizing */
788 : : /* nRank[i] = new ordering number for atoms: nRank=1,2,.. */
789 : : /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
790 : : /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
791 : : /* nAtomNumber[nRank[i]-1] = i; */
792 : :
793 : : int i, k, rank;
794 : 0 : int nLinearCTIsotopicLen = 0;
795 : :
796 : : /* the following parts of the "name" should be compared */
797 : : /* after the connection table comparison is done */
798 : : /* to avoid wrong difference sign. So, these parts */
799 : : /* go to a separate buffers. */
800 [ # # # # ]: 0 : if (LinearCTIsotopic && nMaxLenLinearCTIsotopic > 0)
801 : : {
802 : 0 : memset( LinearCTIsotopic, 0, nMaxLenLinearCTIsotopic * sizeof( LinearCTIsotopic[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
803 : : }
804 : : else
805 : : {
806 : 0 : return 0;
807 : : }
808 : :
809 : : /* rank = nRank[nAtomNumber[rank-1]] -- proposed atoms canon. numbers */
810 [ # # ]: 0 : for (rank = 1; rank <= num_atoms; rank++)
811 : : {
812 : :
813 : 0 : i = (int) nAtomNumber[rank - 1]; /* current atom */
814 : :
815 : : /****************************************************
816 : : add isotopic atom info to LinearCTIsotopic
817 : : *****************************************************/
818 : :
819 : : /* if the atom itself is not isotopic then add it only if */
820 : : /* the atom is not an endpoint AND has attached T or D or 1H. */
821 [ # # # # : 0 : k = ( !at[i].endpoint && !( at[i].cFlags & AT_FLAG_ISO_H_POINT ) && ( at[i].num_iso_H[0] || at[i].num_iso_H[1] || at[i].num_iso_H[2] ) );
# # # # #
# ]
822 [ # # # # ]: 0 : if (at[i].iso_atw_diff || k)
823 : : {
824 [ # # ]: 0 : if (CHECK_OVERFLOW( nLinearCTIsotopicLen, nMaxLenLinearCTIsotopic ))
825 : : {
826 : 0 : return CT_OVERFLOW; /* <BRKPT> */
827 : : }
828 : 0 : LinearCTIsotopic[nLinearCTIsotopicLen].at_num = (AT_RANK) rank;
829 : 0 : LinearCTIsotopic[nLinearCTIsotopicLen].iso_atw_diff = at[i].iso_atw_diff;
830 [ # # ]: 0 : LinearCTIsotopic[nLinearCTIsotopicLen].num_1H = (NUM_H) ( k ? at[i].num_iso_H[0] : 0 );
831 [ # # ]: 0 : LinearCTIsotopic[nLinearCTIsotopicLen].num_D = (NUM_H) ( k ? at[i].num_iso_H[1] : 0 );
832 [ # # ]: 0 : LinearCTIsotopic[nLinearCTIsotopicLen].num_T = (NUM_H) ( k ? at[i].num_iso_H[2] : 0 );
833 : 0 : nLinearCTIsotopicLen++;
834 : : }
835 : : } /* end of cycle over all atoms. */
836 : :
837 [ # # ]: 0 : if (LinearCTIsotopic)
838 : : {
839 [ # # ]: 0 : if (*pnLenLinearCTIsotopic)
840 : : {
841 [ # # ]: 0 : if (*pnLenLinearCTIsotopic != nLinearCTIsotopicLen)
842 : : {
843 : 0 : return CT_LEN_MISMATCH; /* <BRKPT> */
844 : : }
845 : : }
846 : : else
847 : : {
848 : 0 : *pnLenLinearCTIsotopic = nLinearCTIsotopicLen;
849 : : }
850 : : }
851 : :
852 : : /* Return value: >0 => OK */
853 : 0 : return nLinearCTIsotopicLen;
854 : : }
855 : :
856 : :
857 : : /****************************************************************************/
858 : 0 : int FillTautLinearCT2( CANON_GLOBALS *pCG,
859 : : int num_atoms,
860 : : int num_at_tg,
861 : : int bIsoTaut,
862 : : const AT_RANK *nRank,
863 : : const AT_RANK *nAtomNumber,
864 : : const AT_RANK *nSymmRank,
865 : : const AT_RANK *nRankIso,
866 : : const AT_RANK *nAtomNumberIso,
867 : : const AT_RANK *nSymmRankIso,
868 : : AT_TAUTOMER *LinearCTTautomer,
869 : : int nMaxLenLinearCTTautomer,
870 : : int *pnLenLinearCTTautomer,
871 : : AT_ISO_TGROUP *LinearCTIsotopicTautomer,
872 : : int nMaxLenLinearCTIsotopicTautomer,
873 : : int *pnLenLinearCTIsotopicTautomer,
874 : : T_GROUP_INFO *t_group_info )
875 : : {
876 : : /* nRank[i] = Canonical numbers of atoms,.. */
877 : : /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
878 : : /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
879 : : /* nAtomNumber[nRank[i]-1] = i; */
880 : :
881 : : T_GROUP *t_group;
882 : :
883 : 0 : int i, j, len = 0, g, offset, max_len = 0, len_iso = 0; /* djb-rwth: removing redundant variable */
884 : : static const int max_num_num = sizeof( t_group->num ) / sizeof( t_group->num[0] );
885 : : static const int max_num_iso = sizeof( LinearCTIsotopicTautomer->num ) / sizeof( LinearCTIsotopicTautomer->num[0] ) + T_NUM_NO_ISOTOPIC;
886 : :
887 : : /****************************************************************************
888 : :
889 : : Tautomeric groups 07-22-2002, modified 12-2003
890 : :
891 : : ****************************************************************************/
892 : :
893 [ # # # # : 0 : if (num_at_tg > num_atoms && t_group_info && t_group_info->num_t_groups)
# # ]
894 : : {
895 : 0 : int num_t_groups = t_group_info->num_t_groups;
896 : 0 : AT_NUMB *tGroupNumber = t_group_info->tGroupNumber;
897 : 0 : AT_NUMB *tSymmRank = tGroupNumber + TGSO_SYMM_RANK*num_t_groups; /* equivalence */
898 : 0 : AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*(long long)num_t_groups; /* djb-rwth: cast operator added */
899 : 0 : AT_NUMB *tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER*(long long)num_t_groups; /* djb-rwth: cast operator added */
900 : 0 : AT_RANK nOffset = (AT_RANK) num_atoms;
901 : :
902 : : /* Fill Canonical ranks and Symmetry Ranks */
903 : : /* memcpy( tPrevGroupNumber, tGroupNumber, num_t_groups*sizeof(tPrevGroupNumber[0])); */
904 [ # # ]: 0 : for (i = num_atoms, j = 0; i < num_at_tg; i++, j++)
905 : : {
906 : : /* tPrevGroupNumber[j] = */
907 : 0 : tGroupNumber[j] = nAtomNumber[i] - nOffset;
908 : 0 : tSymmRank[j] = nSymmRank[i] - nOffset;
909 [ # # ]: 0 : if (bIsoTaut)
910 : : {
911 : 0 : tiGroupNumber[j] = nAtomNumberIso[i] - nOffset;
912 : 0 : tiSymmRank[j] = nSymmRankIso[i] - nOffset;
913 : : }
914 : : }
915 : :
916 : : /* Sort enpoints within each tautomeric group according to the canonical ranks */
917 : 0 : pCG->m_pn_RankForSort = nRank;
918 [ # # ]: 0 : for (i = 0; i < num_t_groups; i++)
919 : : {
920 : 0 : inchi_qsort( pCG,
921 : 0 : t_group_info->nEndpointAtomNumber + (int) t_group_info->t_group[i].nFirstEndpointAtNoPos,
922 : 0 : t_group_info->t_group[i].nNumEndpoints,
923 : : sizeof( t_group_info->nEndpointAtomNumber[0] ),
924 : : CompRank );
925 : : }
926 : : /* fill out LinearCTTautomer */
927 [ # # ]: 0 : if (nMaxLenLinearCTTautomer)
928 : : {
929 : 0 : max_len = T_GROUP_HDR_LEN * t_group_info->num_t_groups + t_group_info->nNumEndpoints + 1;
930 [ # # ]: 0 : if (max_len > nMaxLenLinearCTTautomer)
931 : : {
932 : 0 : return CT_OVERFLOW; /* <BRKPT> */
933 : : }
934 : : }
935 : :
936 : : /****************************************************************
937 : : * tautomer group format (#: is an offset)
938 : : ****************************************************************
939 : : * HEADER (T_GROUP_HDR_LEN=3+3iso)
940 : : * 0: N = number of endpoints ( t_group->nNumEndpoints )
941 : : * 1: number of mobile groups ( t_group->num[0] )
942 : : * 2: number of neg. charges ( t_group->num[1] ) {note: T_NUM_NO_ISOTOPIC=2}
943 : : * ENDPOINT RANKS
944 : : * 3..N+2: sorted tautomer group endpoint ranks; the sorting order is in
945 : : * t_group_info->nEndpointAtomNumber[t_group->nFirstEndpointAtNoPos+j], j=0..N-1
946 : : *
947 : : * End mark : N==0
948 : : ****************************************************************/
949 : : /* num_num = t_group_info->bIgnoreIsotopic? T_NUM_NO_ISOTOPIC : max_num_num; */
950 : : /* num_num = max_num_num; always include isotopic info; ignore it at the CT comparison step. */ /* djb-rwth: removing redundant code */
951 [ # # ]: 0 : for (i = 0; i < t_group_info->num_t_groups; i++)
952 : : {
953 : 0 : g = tGroupNumber[i]; /* ith tautomeric group number in canonical order */
954 : 0 : t_group = t_group_info->t_group + g;
955 : : /*******************************************************
956 : : * Tautomer non-isotopic part: LinearCTTautomer
957 : : *******************************************************/
958 : : /* check length */
959 [ # # ]: 0 : if (CHECK_OVERFLOW( len + T_GROUP_HDR_LEN + t_group->nNumEndpoints, max_len ))
960 : : {
961 : 0 : return CT_OVERFLOW; /* <BRKPT> */
962 : : }
963 : :
964 : : /* t_group header: number of endpoints */
965 : 0 : LinearCTTautomer[len++] = t_group->nNumEndpoints;
966 : : /* t_group header: */
967 : : /* (a) number of mobile groups in the t_group (number of H + number of (-) ) and */
968 : : /* (b) number of mobile negative charges (-) in the t_group */
969 [ # # ]: 0 : for (j = 0; j < T_NUM_NO_ISOTOPIC; j++)
970 : : {
971 : 0 : LinearCTTautomer[len++] = t_group->num[j];
972 : : }
973 : : /* t_group endpoint ranks link the group to the tautomeric endpoint atoms in the structure */
974 : : /* according to their ranks */
975 [ # # ]: 0 : for (j = 0, offset = t_group->nFirstEndpointAtNoPos; j < t_group->nNumEndpoints; j++)
976 : : {
977 : 0 : LinearCTTautomer[len++] = nRank[(int) t_group_info->nEndpointAtomNumber[offset + j]];
978 : : }
979 : : }
980 [ # # ]: 0 : if (nMaxLenLinearCTTautomer)
981 : : {
982 : 0 : LinearCTTautomer[len++] = 0; /* or CT_INITVALUE ??? */
983 [ # # ]: 0 : if (len != max_len)
984 : : {
985 : 0 : len = -len; /* program error */ /* <BRKPT> */
986 : : }
987 [ # # # # ]: 0 : else if (*pnLenLinearCTTautomer && *pnLenLinearCTTautomer != len)
988 : : {
989 : 0 : return CT_LEN_MISMATCH;
990 : : }
991 : : else
992 : : {
993 : 0 : *pnLenLinearCTTautomer = len;
994 : : }
995 : : }
996 : : else
997 : : {
998 : 0 : *pnLenLinearCTTautomer = 0;
999 : : }
1000 : :
1001 : : /******************************************************************
1002 : : * Isotopic Tautomeric mobile groups part: LinearCTIsotopicTautomer
1003 : : ******************************************************************/
1004 [ # # # # ]: 0 : if (nMaxLenLinearCTIsotopicTautomer && !t_group_info->nNumIsotopicEndpoints)
1005 : : {
1006 [ # # ]: 0 : for (i = 0; i < t_group_info->num_t_groups; i++)
1007 : : {
1008 : 0 : g = tiGroupNumber[i]; /* ith tautomeric group number in canonical order */
1009 : 0 : t_group = t_group_info->t_group + g;
1010 : : /* find if mobile hydrogens are isotopic */
1011 [ # # ]: 0 : if (!t_group->iWeight)
1012 : : {
1013 : 0 : continue; /* no isotopic H */
1014 : : }
1015 [ # # ]: 0 : if (CHECK_OVERFLOW( len_iso, nMaxLenLinearCTIsotopicTautomer ))
1016 : : {
1017 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1018 : : }
1019 [ # # # # ]: 0 : for (j = T_NUM_NO_ISOTOPIC; j < max_num_num && j < max_num_iso; j++)
1020 : : {
1021 : : /* num_T, num_D, num_1H */
1022 : 0 : LinearCTIsotopicTautomer[len_iso].num[j - T_NUM_NO_ISOTOPIC] = t_group->num[j];
1023 : : }
1024 : : /* link to tautomer group LinearCTTautomer[i]: */
1025 : 0 : LinearCTIsotopicTautomer[len_iso++].tgroup_num = (AT_NUMB) ( i + 1 ); /* t_group isotopic rank */
1026 : : }
1027 : : }
1028 [ # # ]: 0 : if (nMaxLenLinearCTIsotopicTautomer)
1029 : : {
1030 [ # # # # ]: 0 : if (*pnLenLinearCTIsotopicTautomer && *pnLenLinearCTIsotopicTautomer != len_iso)
1031 : : {
1032 : 0 : return CT_LEN_MISMATCH;
1033 : : }
1034 : 0 : *pnLenLinearCTIsotopicTautomer = len_iso;
1035 : : }
1036 : : else
1037 : : {
1038 : 0 : *pnLenLinearCTIsotopicTautomer = 0;
1039 : : }
1040 : : }
1041 : :
1042 : 0 : return len;
1043 : : }
1044 : :
1045 : :
1046 : : /****************************************************************************
1047 : : *
1048 : : * Update a linear connection table out of final ranks
1049 : : */
1050 : 69 : int UpdateFullLinearCT( int num_atoms,
1051 : : int num_at_tg,
1052 : : sp_ATOM* at,
1053 : : AT_RANK *nRank,
1054 : : AT_RANK *nAtomNumber,
1055 : : CANON_STAT* pCS,
1056 : : CANON_GLOBALS *pCG,
1057 : : int bFirstTime )
1058 : : {
1059 : : /* at[i].init_rank = initial ranks before canonizing */
1060 : : /* nRank[i] = new ordering number for atoms: nRank=1,2,.. */
1061 : : /* nAtomNumber[r] = orig. atom number= 0,1,... for r = nRank-1 */
1062 : : /* nRank[nAtomNumber[r]] = r; r = 0,1,... */
1063 : : /* nAtomNumber[nRank[i]-1] = i; */
1064 : :
1065 : : AT_NUMB nNeighborNumber[MAXVAL];
1066 : : int i, j, k, num_neigh, rank, bCompare; /*, nRetVal; */
1067 : :
1068 : 69 : T_GROUP_INFO *t_group_info = NULL;
1069 : 69 : T_GROUP *t_group = NULL;
1070 : 69 : AT_NUMB *nEndpointAtomNumber = NULL;
1071 : :
1072 : 69 : int nCTLen = 0, nCTLenAtOnly = 0;
1073 : :
1074 : :
1075 : : AT_NUMB r_neigh;
1076 : 69 : AT_NUMB *LinearCT = pCS->LinearCT;
1077 : :
1078 : : /* the following parts of the "name" should be compared */
1079 : : /* after the connection table comparison is done */
1080 : : /* to avoid wrong difference sign. So, these parts */
1081 : : /* go to a separate buffers. */
1082 : : /* -- currently not used at all at all -- */
1083 : :
1084 : : #if CT_ATOMID != CT_ATOMID_DONTINCLUDE
1085 : : AT_NUMB r0_at_type;
1086 : : #endif
1087 : :
1088 : 69 : num_neigh = 0; /* Moved from above 2024-09-01 DT; djb-rwth: num_neigh initialisation added */
1089 : :
1090 : 69 : bCompare = bFirstTime ? 0 : 1;
1091 : :
1092 [ - + ]: 69 : if (num_at_tg > num_atoms)
1093 : : {
1094 : 0 : t_group_info = pCS->t_group_info;
1095 : 0 : t_group = t_group_info->t_group;
1096 : : }
1097 : : else
1098 : : {
1099 : 69 : t_group_info = NULL;
1100 : 69 : t_group = NULL;
1101 : : }
1102 : :
1103 : : /**********************************************************************/
1104 : : /* */
1105 : : /* CYCLE 1: FILL OUT CONNECTION TABLE(S) FOR ALL ATOMS */
1106 : : /* ** NOT INCLUDING ISOTOPIC ATOMS AND 1H, 2H(D), 3H(T) ** */
1107 : : /* */
1108 : : /* rank = nRank[nAtomNumber[rank-1]] -- proposed atoms canon. numbers */
1109 : : /**********************************************************************/
1110 [ + + ]: 688 : for (rank = 1; rank <= num_atoms; rank++)
1111 : : {
1112 : 619 : i = (int) nAtomNumber[rank - 1]; /* current atom */
1113 : :
1114 : : #if ( CT_ATOMID == CT_ATOMID_IS_CURRANK )
1115 : 619 : r0_at_type = (AT_NUMB) rank; /* current Rank */
1116 : : #else
1117 : : #if ( CT_ATOMID == CT_ATOMID_IS_INITRANK )
1118 : : r0_at_type = (AT_NUMB) at[i].init_rank; /* chemical + neighborhood ID */
1119 : : #else
1120 : : #if ( CT_ATOMID == CT_ATOMID_DONTINCLUDE )
1121 : : #else
1122 : : #error Undefined or wrong definition of CT_ATOMID
1123 : : #endif
1124 : : #endif
1125 : : #endif
1126 : :
1127 : : /* add atom to the CT */
1128 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
1129 [ - + ]: 619 : if (CHECK_OVERFLOW( nCTLen, pCS->nMaxLenLinearCT ))
1130 : : {
1131 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1132 : : }
1133 [ + - - + ]: 619 : COMPARE_WITH_CT( LinearCT, nCTLen, r0_at_type, bCompare );
1134 : : #endif
1135 : :
1136 : : /*******************************************************
1137 : : add neighbors and (if required) bonds to CT
1138 : : ********************************************************/
1139 : :
1140 : : /* sort neighbors */
1141 : 619 : num_neigh = at[i].valence;
1142 [ + + ]: 1753 : for (k = 0; k < num_neigh; k++)
1143 : : {
1144 : 1134 : nNeighborNumber[k] = (AT_NUMB) k;
1145 : : }
1146 : 619 : pCG->m_pNeighborsForSort = at[i].neighbor;
1147 : 619 : pCG->m_pn_RankForSort = nRank;
1148 : 619 : insertions_sort( pCG, nNeighborNumber, (size_t) num_neigh, sizeof( nNeighborNumber[0] ), CompNeighborsAT_NUMBER );
1149 : :
1150 [ + + ]: 1753 : for (k = 0; k < num_neigh; k++)
1151 : : {
1152 : : /* rank = (new current atom Rank) */
1153 [ + + ]: 1134 : if ((int) ( r_neigh = (AT_NUMB) nRank[(int) at[i].neighbor[(int) nNeighborNumber[k]]] )
1154 : : CT_NEIGH_SMALLER_THAN rank)
1155 : : {
1156 [ - + ]: 567 : if (CHECK_OVERFLOW( nCTLen, pCS->nMaxLenLinearCT ))
1157 : : {
1158 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1159 : : }
1160 [ + - - + ]: 567 : COMPARE_WITH_CT( LinearCT, nCTLen, r_neigh, bCompare );
1161 : : }
1162 : : }
1163 : :
1164 : : /* add CT row delimiter */
1165 : : } /* end of cycle over all atoms. */
1166 : :
1167 : 69 : nCTLenAtOnly = nCTLen;
1168 : :
1169 : : /**************************************************************
1170 : :
1171 : : Tautomeric groups 07-22-2002
1172 : :
1173 : : ***************************************************************/
1174 : :
1175 [ - + ]: 69 : for (rank = num_atoms + 1; rank <= num_at_tg; rank++)
1176 : : {
1177 : 0 : j = (int) nAtomNumber[rank - 1]; /* current "atom" */
1178 : 0 : i = j - num_atoms; /* current t-group */
1179 : :
1180 : : #if ( CT_ATOMID == CT_ATOMID_IS_CURRANK )
1181 : 0 : r0_at_type = (AT_NUMB) rank; /* current Rank */
1182 : : #else
1183 : : #if ( CT_ATOMID == CT_ATOMID_IS_INITRANK )
1184 : : r0_at_type = (AT_NUMB) rank; /* current Rank or (AT_NUMB)at[i].init_rank; ==> chemical + neighborhood ID */
1185 : : #else
1186 : : #if ( CT_ATOMID == CT_ATOMID_DONTINCLUDE )
1187 : : #else
1188 : : #error Undefined or wrong definition of CT_ATOMID
1189 : : #endif
1190 : : #endif
1191 : : #endif
1192 : :
1193 : : /* add atom to the CT */
1194 : : #if ( CT_ATOMID != CT_ATOMID_DONTINCLUDE )
1195 [ # # ]: 0 : if (CHECK_OVERFLOW( nCTLen, pCS->nMaxLenLinearCT ))
1196 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1197 [ # # # # ]: 0 : COMPARE_WITH_CT( LinearCT, nCTLen, r0_at_type, bCompare );
1198 : : #endif
1199 : :
1200 : : /*******************************************************
1201 : : add neighbors and (if required) bonds to CT
1202 : : ********************************************************/
1203 : :
1204 : : /* sort endpoints */
1205 [ # # ]: 0 : if (t_group_info)
1206 : 0 : nEndpointAtomNumber = t_group_info->nEndpointAtomNumber + (int) t_group[i].nFirstEndpointAtNoPos; /* djb-rwth: fixing a NULL pointer dereference */
1207 : 0 : pCG->m_pn_RankForSort = nRank;
1208 [ # # ]: 0 : if (t_group + i) /* djb-rwth: ignoring GCC warning */
1209 : 0 : num_neigh = (int)t_group[i].nNumEndpoints;
1210 : 0 : insertions_sort( pCG, nEndpointAtomNumber, (size_t) num_neigh, sizeof( nEndpointAtomNumber[0] ), CompRank );
1211 : :
1212 [ # # ]: 0 : for (k = 0; k < num_neigh; k++)
1213 : : {
1214 : : /* rank = (new current atom Rank) */
1215 [ # # ]: 0 : if (nEndpointAtomNumber + k) /* djb-rwth: fixing a NULL pointer dereference; ignoring GCC warning */
1216 : : {
1217 [ # # ]: 0 : if ((int)(r_neigh = (AT_NUMB)nRank[(int)nEndpointAtomNumber[k]]) CT_NEIGH_SMALLER_THAN rank)
1218 : : {
1219 [ # # ]: 0 : if (CHECK_OVERFLOW(nCTLen, pCS->nMaxLenLinearCT))
1220 : : {
1221 : 0 : return CT_OVERFLOW; /* <BRKPT> */
1222 : : }
1223 [ # # # # ]: 0 : COMPARE_WITH_CT(LinearCT, nCTLen, r_neigh, bCompare);
1224 : : }
1225 : : }
1226 : : }
1227 : : } /* end of cycle over all tautomeric groups. */
1228 : :
1229 : : /* compare bonds types */
1230 : : /* compare elements */
1231 : :
1232 [ + - ]: 69 : if (LinearCT)
1233 : : {
1234 : :
1235 [ + - ]: 69 : if (pCS->nLenLinearCT)
1236 : : {
1237 [ - + ]: 69 : if (pCS->nLenLinearCT != nCTLen)
1238 : : {
1239 : 0 : return CT_LEN_MISMATCH; /* <BRKPT> */
1240 : : }
1241 : : }
1242 : : else
1243 : : {
1244 : 0 : pCS->nLenLinearCT = nCTLen;
1245 : : }
1246 : :
1247 [ + - ]: 69 : if (pCS->nLenLinearCT)
1248 : : {
1249 [ - + ]: 69 : if (pCS->nLenLinearCTAtOnly != nCTLenAtOnly)
1250 : : {
1251 : 0 : return CT_LEN_MISMATCH; /* <BRKPT> */
1252 : : }
1253 : : }
1254 : : else
1255 : : {
1256 : 0 : pCS->nLenLinearCTAtOnly = nCTLenAtOnly;
1257 : : }
1258 : : }
1259 : :
1260 : : /* Return: 0=> identical CT; -1=> new CT is smaller than the previous one */
1261 : 69 : return ( bCompare - 1 );
1262 : : }
1263 : :
1264 : :
1265 : : /****************************************************************************
1266 : : If (*bChanged & 1) then nSymmRank has been rearranged because for some r
1267 : : min{i: r=nSymmRank[nAtomNumber[i]]}+1 != r
1268 : : If (*bChanged & 2) then ranks nTempRank[]
1269 : : from nSymmRank[] differ from input nCurrRank[]
1270 : :
1271 : : On exit:
1272 : : nSymmRank[] have been updated if (*bChanged & 1)
1273 : : nCurrRank[] have been updated if (*bChanged & 1)
1274 : : nTempRank[] is always same as nCurrRank[]
1275 : : nAtomNumber[] have been sorted so that
1276 : : (i < j) <=> (nSymmRank[nAtomNumber[i]] <= nSymmRank[nAtomNumber[j]])
1277 : : ****************************************************************************/
1278 : 125 : int FixCanonEquivalenceInfo( CANON_GLOBALS *pCG,
1279 : : int num_at_tg,
1280 : : AT_RANK *nSymmRank,
1281 : : AT_RANK *nCurrRank,
1282 : : AT_RANK *nTempRank,
1283 : : AT_NUMB *nAtomNumber,
1284 : : int *bChanged )
1285 : : {
1286 : 125 : int nNumDiffRanks, bChangeSymmRank, bChangeCurrRank = 0;
1287 : : /* sort equivalence information */
1288 : : /*
1289 : : int i;
1290 : : for ( i = 0; i < num_at_tg; i ++ )
1291 : : {
1292 : : nAtomNumber[i] = i;
1293 : : }
1294 : : */
1295 : :
1296 : 125 : pCG->m_pn_RankForSort = nSymmRank; /* minimal class representatives: min ranks for equiv. atoms */
1297 : 125 : inchi_qsort( pCG, nAtomNumber, num_at_tg, sizeof( nAtomNumber[0] ), CompRanksOrd );
1298 : :
1299 : : /* convert equivalence information nSymmRank[] into ranks array nTempRank[] */
1300 : : /* eq. info contains min. possible ranks for eq. atoms; nCurrRank contains max. possible ranks */
1301 : 125 : nNumDiffRanks = SortedEquInfoToRanks( nSymmRank/*inp*/, nTempRank/*out*/, nAtomNumber, num_at_tg, &bChangeSymmRank );
1302 : :
1303 : : /* check whether nCurrRank is same as new initial ranks calculated from nSymmRank[] */
1304 : 125 : bChangeCurrRank = memcmp( nCurrRank, nTempRank, num_at_tg * sizeof( nTempRank[0] ) );
1305 : :
1306 : : /*-----------------------------------------------------------------------
1307 : : if ( bChangeSymmRank || bChangeCurrRank ) {
1308 : : This is the case when the initial equitable partitioning does not produce
1309 : : constitutionally equivalent classes of atoms.
1310 : : Rebuild nSymmRank[] according to the new nCurrRank[] := nTempRank[]
1311 : : For such structures the found canonical numbers of the constitutionally equivalent atoms
1312 : : are not contiguous (see nCanonRank and nSymmRank examples below). Here arrays
1313 : : nCurrRank, nAtomNumber, and nSymmRank are changed so that later the
1314 : : contiguous canonical numbers for equivalent atoms can be obtained
1315 : : (see GetCanonRanking under
1316 : : "III. Get final canonical numbering (no stereo, no isotopic)".
1317 : :
1318 : : Example: for CAS=37520-11-9 (ID=21247: Ethane, 1,2-dicyclopropyl-),
1319 : :
1320 : : the numbers are the "final canon. numbers, nCanonRank"
1321 : : 1
1322 : :
1323 : : HC 7 5 3
1324 : : | \
1325 : : | >CH--CH2 CH
1326 : : | / \ / |
1327 : : HC H2C--CH< |
1328 : : \ |
1329 : : 2 6 8 CH
1330 : :
1331 : : 4
1332 : :
1333 : : the arrays (arranged according to ordering in nAtomNumberTemp) are:
1334 : : before SortedEquInfoToRanks after SortedRanksToEquInfo
1335 : : orig. atom nos.,nAtomNumberTemp: {4 5 6 7 0 1 2 3} {4 5 6 7 0 1 2 3}
1336 : : order numbers for sorted ranks: {0 1 2 3 4 5 6 7} {0 1 2 3 4 5 6 7}
1337 : : canonical numbering, nCanonRank: {1 2 5 6 3 4 7 8} {1 2 5 6 3 4 7 8}
1338 : : constit. equivalence, nSymmRank: {1 1 1 1 3 3 7 7} {1 1 1 1 5 5 7 7} used later
1339 : : initial equivalence, nCurrRank: {6 6 6 6 6 6 8 8} {4 4 4 4 6 6 8 8} used later
1340 : : initial numbering, nAtomNumber: {2 3 4 7 0 1 6 7} {0 1 2 3 4 5 6 7} used later
1341 : : final, no stereo, no isotopic, after III. GetCanonRanking:
1342 : : final canon. numbers, nCanonRank: {1 2 3 4 5 6 7 8} final
1343 : : }
1344 : : ----------------------------------------------------------------------------------*/
1345 [ + + ]: 125 : if (bChangeCurrRank)
1346 : : {
1347 : 8 : memcpy(nCurrRank, nTempRank, num_at_tg * sizeof(nCurrRank[0]));
1348 : : }
1349 [ - + ]: 125 : if (bChangeSymmRank)
1350 : : {
1351 : 0 : SortedRanksToEquInfo( nSymmRank/*out*/, nTempRank/*inp*/, nAtomNumber, num_at_tg );
1352 : : }
1353 [ + + ]: 125 : if (bChanged)
1354 : : {
1355 [ - + ]: 69 : *bChanged = ( 0 != bChangeSymmRank ) | 2 * ( 0 != bChangeCurrRank );
1356 : : }
1357 : :
1358 : 125 : return nNumDiffRanks;
1359 : : }
1360 : :
1361 : :
1362 : : /* Isotopic canonicalization */
1363 : :
1364 : :
1365 : : /****************************************************************************
1366 : :
1367 : : Canon_INChI (former GetCanonRankingUsingEquivInfo)
1368 : :
1369 : : ****************************************************************************/
1370 : 69 : int Canon_INChI3( INCHI_CLOCK *ic,
1371 : : int num_atoms,
1372 : : int num_at_tg,
1373 : : sp_ATOM* at,
1374 : : CANON_STAT* pCS,
1375 : : CANON_GLOBALS *pCG,
1376 : : INCHI_MODE nMode,
1377 : : int bTautFtcn )
1378 : : {
1379 : :
1380 : : /****************************************************************
1381 : :
1382 : : 0. Initiation, Prepare initial ranks for GetCanonRanking()
1383 : :
1384 : : I. Find constitutionally equivalent atoms and possibly canonical numbering
1385 : : I.1 Set tautomer=On, stereo=isotopic=Off
1386 : : I.2 GetCanonRanking(): Find constitutionally equivalent atoms and possibly canonical numbering
1387 : : 1.3 Fix canonical equivalence info if needed (if the fix is needed then the numbering is not canonical)
1388 : :
1389 : : II. Get final non-isotopic canonical numbering. Simultaneously obtain non-minimal isotopic and stereo CTs
1390 : : GetCanonRanking() with pCS->bKeepSymmRank = 1
1391 : : FillOutStereoParities() (create initial stereo descriptors)
1392 : : save non-isotopic canonicalization final results
1393 : : hide isotopic and tautomeric results (for historical reasons only)
1394 : :
1395 : :
1396 : : III. Find constitutionally equivalent isotopic atoms (for isotopic stereo canonicalization)
1397 : : III.1 Allocate more memory
1398 : : III.2 fill allocated memory with the initial data
1399 : : III.3 duplicate, save old and add isotopic info to the new pCS->t_group_info
1400 : : III.4 Prepare initial isotopic ranks for GetCanonRanking()
1401 : : III.5 GetCanonRanking() to Find constitutionally equivalent ISOTOPIC atoms and tautomer groups
1402 : : III.6 Fix canonical isotopic equivalence information and derive ranks out of it
1403 : :
1404 : : IV. Prepare a second Rank/AtomNumber Stack for mapping.
1405 : :
1406 : : V. Optimize isotopic part (optimized)
1407 : : map_isotopic_atoms2()
1408 : : save isotopic canonical numbering
1409 : :
1410 : : VI. Optimize stereo descriptors (optimized)
1411 : : map_stereo_bonds4()
1412 : :
1413 : :
1414 : : VII. Optimize isotopic stereo descriptors (optimized)
1415 : : SwitchAtomStereoAndIsotopicStereo()
1416 : : SetCtToIsotopicStereo()
1417 : : FillOutStereoParities()
1418 : : SetUseAtomForStereo()
1419 : : map_stereo_bonds4()
1420 : :
1421 : : SwitchAtomStereoAndIsotopicStereo()
1422 : : SetCtToNonIsotopicStereo()
1423 : :
1424 : :
1425 : :
1426 : :
1427 : : *****************************************************************/
1428 : :
1429 : 69 : int nRet = 0, i, n;
1430 : :
1431 : :
1432 : : /********************************************************
1433 : : input non-stereo canonical info
1434 : : ********************************************************/
1435 : 69 : BCN *pBCN = pCS->pBCN;
1436 : 69 : FTCN *ftcn = pBCN->ftcn + bTautFtcn;
1437 : :
1438 : : /********************************************************
1439 : : set mode flags
1440 : : ********************************************************/
1441 : :
1442 : : /* tautomeric structure */
1443 [ - + - - : 69 : int bTaut = ( num_at_tg > num_atoms ) && pCS->t_group_info && pCS->t_group_info->num_t_groups && pCS->t_group_info->t_group;
- - - - ]
1444 : :
1445 : : /* special case: induced by exchangable isotopic H inequivalence of atoms in formally non-tautomeric structure */
1446 [ - + ]: 69 : int bIsoXchgH = pCS->t_group_info && pCS->t_group_info->nNumIsotopicEndpoints > 1 &&
1447 [ + - - - : 138 : pCS->t_group_info->nIsotopicEndpointAtomNumber && pCS->t_group_info->nIsotopicEndpointAtomNumber[0] &&
- - ]
1448 [ # # ]: 0 : ( pCS->t_group_info->bTautFlagsDone & ( TG_FLAG_FOUND_ISOTOPIC_H_DONE | TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE ) )
1449 : : /* && (ftcn->nCanonFlags & CANON_FLAG_ISO_TAUT_DIFF)*/;
1450 [ - + - - : 69 : int bHasIsotopicCanonData = ( ftcn->PartitionCtIso.AtNumber && ftcn->PartitionCtIso.Rank && ftcn->nSymmRankCtIso );
- - ]
1451 : :
1452 : : /* bHasIsotopicCanonData==0 means
1453 : : * (1) No isotopic atoms in the component OR
1454 : : * (2) the component has only exchangable isotopic H that do not change canonical numbering and equivalence.
1455 : : */
1456 [ - + ]: 69 : T_GROUP_INFO *t_group_info1 = bTaut ? pCS->t_group_info : NULL;
1457 : :
1458 : : /*int bIsoXchgH = t_group_info1 && t_group_info1->nNumIsotopicEndpoints && t_group_info1->nIsotopicEndpointAtomNumber;*/
1459 : : /* isotopic canonicalization */
1460 [ - + - - : 69 : int bCanonIsotopic = bHasIsotopicCanonData && ( nMode & CMODE_ISO ) && ( pCS->LinearCTIsotopic || pCS->LinearCTIsotopicTautomer || bIsoXchgH );
- - - - -
- ]
1461 : :
1462 : : /* stereo canonicalization */
1463 [ + + + - : 69 : int bCanonStereo = ( nMode & CMODE_STEREO ) && ( pCS->LinearCTStereoDble || pCS->LinearCTStereoCarb );
+ + ]
1464 : :
1465 : : /* stereo isotopic canonicalization */
1466 [ - + - - : 69 : int bCanonIsoStereo = bHasIsotopicCanonData && ( nMode & CMODE_ISO_STEREO ) && ( pCS->LinearCTIsotopicStereoDble || pCS->LinearCTIsotopicStereoCarb ) && bCanonIsotopic;
- - - - -
- ]
1467 [ - + - - ]: 69 : int bIsoTaut = ( bTaut && bCanonIsotopic );
1468 : :
1469 : : int bIgnoreIsotopicInputGroups;
1470 : : int bIgnoreIsotopicInputAtoms;
1471 : :
1472 : 69 : AT_RANK **pRankStack1 = pBCN->pRankStack;
1473 : 69 : int nRankStackLen = pBCN->nMaxLenRankStack;
1474 : 69 : int num_max = pBCN->num_max; /* allocation lengths in *pRankStack1[] */
1475 : 69 : NEIGH_LIST *NeighList = ftcn->NeighList;
1476 : :
1477 : 69 : int nNumCurrRanks = 0;
1478 : 69 : AT_RANK *nTempRank = NULL;
1479 : :
1480 : 69 : AT_RANK *nSymmRank = NULL;
1481 : :
1482 : 69 : AT_RANK *nAtomNumber = NULL;
1483 : 69 : AT_RANK *nRank = NULL;
1484 : :
1485 : 69 : AT_RANK **pRankStack2 = NULL;
1486 : 69 : AT_RANK *nCanonRankStereo = NULL;
1487 : 69 : AT_RANK *nCanonRankStereoInv = NULL;
1488 : 69 : AT_RANK *nSymmStereo = NULL;
1489 : :
1490 : 69 : AT_RANK *nCanonRankIsotopicStereo = NULL;
1491 : 69 : AT_RANK *nCanonRankIsotopicStereoInv = NULL;
1492 : :
1493 : 69 : CUR_TREE *cur_tree = NULL;
1494 : : CUR_TREE CurrentTree;
1495 : :
1496 : :
1497 : : /*AT_ISO_TGROUP *LinearCTIsotopicTautomer = NULL; */
1498 : :
1499 : :
1500 : : CANON_STAT CS2;
1501 : 69 : CANON_STAT* pCS2 = &CS2;
1502 : :
1503 : : inchiTime ulStartTime, ulEndTime;
1504 : : /*=========== Mode Bits (low 8 bits, bit 0 is Least Significant Bit) ===========
1505 : :
1506 : : Mode Bits Description
1507 : : '0' c 0 Only one connection table canonicalization
1508 : : '1' C 1 Recalculate CT using fixed nSymmRank
1509 : : '2' i 1|2 Isotopic canonicalization (internal)
1510 : : '3' I 1|2|4 Isotopic canonicalization (output)
1511 : : '4' s 1|8 Stereo canonicalization
1512 : : '5' S 1|2|4|16 Stereo isotopic canonicalization
1513 : : '6' A 1|2|4|8|16 Output All
1514 : :
1515 : : --- high 8 bits ----
1516 : : --- obsolete, only historical interest. ------
1517 : : 1-2 : 0 => at[i].init_rank from Morgan+NeighList
1518 : : 1 => at[i].init_rank from Atom Invariants
1519 : : 2 => at[i].init_rank from nSymmRank[]
1520 : : (at[i].init_rank is included in LinearCT
1521 : : depending on CT_ATOMID definition)
1522 : : 3 : 1 => Get Stereo canonical info
1523 : : 4 : 1 => Get Isotopic canonical info
1524 : : 5 : 1 => Get Charge/Radical canonical info
1525 : : ==================================================================*/
1526 : : /*int nOutputMode = 0;*/ /* obsolete */
1527 : :
1528 : :
1529 : 69 : int bSwitchedAtomToIsotopic = 0;
1530 : :
1531 : :
1532 : : /* vABParityUnknown holds actual value of an internal constant signifying */
1533 : : /* unknown parity: either the same as for undefined parity (default==standard) */
1534 : : /* or a specific one (non-std; requested by SLUUD switch). */
1535 : 69 : int vABParityUnknown = AB_PARITY_UNDF;
1536 [ - + ]: 69 : if (0 != ( nMode & REQ_MODE_DIFF_UU_STEREO ))
1537 : : {
1538 : : /* Make labels for unknown and undefined stereo different */
1539 : 0 : vABParityUnknown = AB_PARITY_UNKN;
1540 : : }
1541 : :
1542 : 69 : InchiTimeGet( &ulStartTime );
1543 : :
1544 : 69 : *pCS2 = *pCS; /* save input information and pointers to allocated memory */
1545 : :
1546 : : /* Set "ignore isotopic differences in tautomer groups" true */
1547 [ - + ]: 69 : if (bTaut)
1548 : : {
1549 : : /* save request for isotopic tautomeric groups */
1550 : 0 : bIgnoreIsotopicInputGroups = pCS->t_group_info->bIgnoreIsotopic;
1551 : 0 : pCS->t_group_info->bIgnoreIsotopic = 1;
1552 : : }
1553 : : else
1554 : : {
1555 : 69 : bIgnoreIsotopicInputGroups = 1;
1556 : : }
1557 : : /* Save request for isotopic name */
1558 : 69 : bIgnoreIsotopicInputAtoms = pCS->bIgnoreIsotopic;
1559 : : /* set "ignore isotopic differences in atoms" true */
1560 : 69 : pCS->bIgnoreIsotopic = 1;
1561 : :
1562 : :
1563 : : /* Save non-isotopic and isotopic canonicalization results */
1564 : 69 : pCS->nCanonFlags = ftcn->nCanonFlags;
1565 : : /* 1. non-isotopic */
1566 : :
1567 : : /* linear CT, H */
1568 : 69 : memcpy(pCS->LinearCT, ftcn->LinearCt, ftcn->nLenLinearCt * sizeof(pCS->LinearCT[0]));
1569 [ + - + - ]: 69 : if (pCS->nNum_H && ftcn->nNumH)
1570 : : {
1571 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
1572 : : {
1573 : 619 : pCS->nNum_H[i] = /*(S_CHAR)*/( CHAR_MASK & ftcn->nNumH[i] );
1574 : : }
1575 : : }
1576 [ + - - + ]: 69 : if (pCS->nNum_H_fixed && ftcn->nNumHFixH)
1577 : : {
1578 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1579 : : {
1580 : 0 : pCS->nNum_H_fixed[i] = /*(S_CHAR)*/( CHAR_MASK & ftcn->nNumHFixH[i] );
1581 : : }
1582 : : }
1583 : 69 : pCS->nLenLinearCT = ftcn->nLenLinearCt;
1584 : 69 : pCS->nLenLinearCTAtOnly = ftcn->nLenLinearCtAtOnly;
1585 : :
1586 : : /* save non-isotopic atoms equivalence and numbering */
1587 [ + - ]: 69 : if (pCS->nSymmRank)
1588 : : {
1589 : 69 : memcpy(pCS->nSymmRank, ftcn->nSymmRankCt, num_at_tg * sizeof(pCS->nSymmRank[0]));
1590 : : }
1591 [ + - ]: 69 : if (pCS->nCanonOrd)
1592 : : {
1593 : 69 : memcpy(pCS->nCanonOrd, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(pCS->nCanonOrd[0]));
1594 : 69 : pCS->nLenCanonOrd = num_atoms;
1595 : : }
1596 [ - + - - ]: 69 : if (ftcn->iso_exchg_atnos && pCS->nExchgIsoH)
1597 : : {
1598 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1599 : : {
1600 : 0 : pCS->nExchgIsoH[i] = !ftcn->iso_exchg_atnos[i]; /* (pCS->nExchgIsoH[i]==1) => tautomeric or hetero atoms that may exchange isotopic H */
1601 : : }
1602 : : }
1603 : : /* 2. isotopic */
1604 : :
1605 [ - + ]: 69 : if (bCanonIsotopic)
1606 : : {
1607 : : /* linear CT, num_H are same as non-isotopic */
1608 : : /* save atoms equivalence and numbering */
1609 [ # # ]: 0 : if (pCS->nSymmRankIsotopic)
1610 : : {
1611 : 0 : memcpy(pCS->nSymmRankIsotopic, ftcn->nSymmRankCtIso, num_at_tg * sizeof(pCS->nSymmRankIsotopic[0]));
1612 : : }
1613 [ # # ]: 0 : if (pCS->nCanonOrdIsotopic)
1614 : : {
1615 : 0 : memcpy(pCS->nCanonOrdIsotopic, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(pCS->nCanonOrdIsotopic[0]));
1616 : 0 : pCS->nLenCanonOrdIsotopic = num_at_tg;
1617 : : }
1618 : :
1619 : 0 : nRet = FillIsotopicAtLinearCT( num_atoms, at,
1620 : 0 : ftcn->PartitionCtIso.AtNumber,
1621 : : pCS->LinearCTIsotopic,
1622 : : pCS->nMaxLenLinearCTIsotopic,
1623 : : &pCS->nLenLinearCTIsotopic );
1624 : :
1625 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
1626 : : {
1627 : 0 : goto exit_function;
1628 : : }
1629 [ # # ]: 0 : if (nRet < 0)
1630 : : {
1631 : 0 : nRet = CT_TAUCOUNT_ERR;
1632 : 0 : goto exit_function;
1633 : : }
1634 : : }
1635 : : else
1636 : : {
1637 : 69 : pCS->nMaxLenLinearCTIsotopic = 0;
1638 : 69 : pCS->nMaxLenLinearCTIsotopicTautomer = 0;
1639 : : }
1640 : :
1641 : : /* fill out tautomeric groups, isotopic and non-isotopic tautomeric CT and t_group_info1->tGroupNumber */
1642 [ - + ]: 69 : if (bTaut)
1643 : : {
1644 [ # # ]: 0 : bIsoTaut = bIsoTaut && ftcn->PartitionCtIso.Rank &&
1645 [ # # # # : 0 : ftcn->PartitionCtIso.AtNumber && ftcn->nSymmRankCtIso;
# # ]
1646 : :
1647 : 0 : nRet = FillTautLinearCT2( pCG, num_atoms, num_at_tg, bIsoTaut,
1648 : 0 : ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber, ftcn->nSymmRankCt,
1649 : 0 : ftcn->PartitionCtIso.Rank, ftcn->PartitionCtIso.AtNumber, ftcn->nSymmRankCtIso,
1650 : : pCS->LinearCTTautomer, pCS->nMaxLenLinearCTTautomer, &pCS->nLenLinearCTTautomer,
1651 : : pCS->LinearCTIsotopicTautomer, pCS->nMaxLenLinearCTIsotopicTautomer, &pCS->nLenLinearCTIsotopicTautomer,
1652 : : t_group_info1 );
1653 : :
1654 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
1655 : : {
1656 : 0 : goto exit_function;
1657 : : }
1658 [ # # ]: 0 : if (nRet <= 0)
1659 : : {
1660 : 0 : nRet = CT_TAUCOUNT_ERR;
1661 : 0 : goto exit_function;
1662 : : }
1663 : : else
1664 : : {
1665 : : /* tautomeric groups: save non-isotopic symmetry & t_group order */
1666 : 0 : int num_t_groups = t_group_info1->num_t_groups;
1667 : 0 : AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1668 : 0 : AT_NUMB *tSymmRank = tGroupNumber + TGSO_SYMM_RANK*num_t_groups;
1669 [ # # ]: 0 : if (pCS->nSymmRankTaut)
1670 : : {
1671 : 0 : memcpy(pCS->nSymmRankTaut, tSymmRank, num_t_groups * sizeof(pCS->nSymmRank[0])); /* fixed 5-23-02 */
1672 : : }
1673 [ # # ]: 0 : if (pCS->nCanonOrdTaut)
1674 : : {
1675 : 0 : memcpy(pCS->nCanonOrdTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdTaut[0]));
1676 : 0 : pCS->nLenCanonOrdTaut = num_t_groups;
1677 : : }
1678 [ # # ]: 0 : if (bCanonIsotopic /*&& pCS->nLenLinearCTIsotopicTautomer*/)
1679 : : {
1680 : : /* tautomeric groups: save isotopic symmetry & t_group order */
1681 : : /*AT_NUMB ntRankOffset = (AT_RANK)num_atoms;*/
1682 : 0 : AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*(long long)num_t_groups; /* djb-rwth: cast operator added */
1683 : 0 : AT_NUMB *tiGroupNumber = tGroupNumber + TGSO_SYMM_IORDER*(long long)num_t_groups; /* djb-rwth: cast operator added */
1684 [ # # ]: 0 : if (pCS->nSymmRankIsotopicTaut)
1685 : : {
1686 : 0 : memcpy(pCS->nSymmRankIsotopicTaut, tiSymmRank, num_t_groups * sizeof(pCS->nSymmRankIsotopicTaut[0]));
1687 : : }
1688 : 0 : memcpy(pCS->nCanonOrdIsotopicTaut, tiGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdIsotopicTaut[0]));
1689 : 0 : pCS->nLenCanonOrdIsotopicTaut = num_t_groups;
1690 : : }
1691 : : }
1692 : : }
1693 : : /* save connection table if requested */
1694 [ + - ]: 69 : if (pCS->LinearCT2)
1695 : : {
1696 : 69 : memcpy(pCS->LinearCT2, pCS->LinearCT, sizeof(pCS->LinearCT2[0])* pCS->nLenLinearCT);
1697 : 69 : pCS->nLenLinearCT2 = pCS->nLenLinearCT;
1698 : 69 : pCS->nLenLinearCTAtOnly2 = pCS->nLenLinearCTAtOnly;
1699 : : }
1700 : :
1701 [ + + ]: 69 : if (num_atoms <= 1)
1702 : : {
1703 : 5 : bCanonStereo = 0; /* a sinle atom + possibly terminal hydrogen atoms */
1704 [ + - + - ]: 5 : if (num_atoms < 1 || !at[0].parity2)
1705 : : {
1706 : 5 : bCanonIsoStereo = 0; /* structure; for example Cl- or CH4 */
1707 : : }
1708 : : }
1709 : :
1710 [ + + - + : 69 : if (!bCanonStereo && !( bCanonIsotopic && bCanonIsoStereo ))
- - ]
1711 : : {
1712 : 13 : goto exit_function; /* skip stereo canonicalization */
1713 : : }
1714 : :
1715 : :
1716 : :
1717 : : /**********************************************************
1718 : : Mode
1719 : : ***********************************************************/
1720 : 56 : nMode = nMode & CANON_MODE_MASK;
1721 : :
1722 : : /* memory allocation */
1723 : :
1724 : 56 : nAtomNumber = (AT_RANK *) qmalloc( num_max * sizeof( *nAtomNumber ) );
1725 : 56 : nRank = (AT_RANK *) qmalloc( num_max * sizeof( *nRank ) );
1726 : 56 : nTempRank = (AT_RANK *) qmalloc( num_max * sizeof( *nTempRank ) );
1727 : 56 : nSymmRank = (AT_RANK *) qmalloc( num_max * sizeof( *nSymmRank ) );
1728 : :
1729 : : /***********************************************
1730 : : 0.1 Initialization
1731 : : ************************************************/
1732 : :
1733 : :
1734 [ + - + - : 56 : if (!NeighList || !nAtomNumber || !nTempRank ||
+ - + - ]
1735 [ - + ]: 56 : !nRank || !pCS->LinearCT)
1736 : : {
1737 : 0 : nRet = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
1738 : 0 : goto exit_function;
1739 : : }
1740 : :
1741 : 56 : pCS->NeighList = NeighList;
1742 : :
1743 : 56 : *pCS2 = *pCS; /* save input information and pointers to allocated memory */
1744 : :
1745 [ + - - + : 56 : if (!( nMode & CMODE_NOEQ_STEREO ) && ( bCanonStereo || bCanonIsoStereo ))
- - ]
1746 : : {
1747 : : /* will be used to discover vertex equivalences in stereo canonicalization */
1748 : 56 : memset( &CurrentTree, 0, sizeof( CurrentTree ) ); /* djb-rwth: memset_s C11/Annex K variant? */
1749 : 56 : cur_tree = &CurrentTree;
1750 : : }
1751 : :
1752 : :
1753 : 56 : pCS->bCmpStereo = 0;
1754 : 56 : pCS->bCmpIsotopicStereo = 0;
1755 : :
1756 : :
1757 [ - + - - ]: 56 : if (bCanonStereo || bCanonIsoStereo)
1758 : : {
1759 : : int ii, nn;
1760 : :
1761 : : /* stereo or isotopic canonicalization: we need a second set of ranks for mapping */
1762 : : /* (isotopic atoms or stereo can only increase nNumCurrRanks) */
1763 : 56 : pRankStack2 = (AT_RANK **) inchi_calloc( nRankStackLen, sizeof( AT_RANK * ) );
1764 [ + - ]: 56 : if (pRankStack2)
1765 : : {
1766 : : /* prepare for ranks reuse */
1767 [ + - + + ]: 94 : for (nn = 2; nn < nRankStackLen && pRankStack1[nn]; nn++)
1768 : : {
1769 : 38 : pRankStack1[nn][0] = 0; /* means ranks have to be calculated */
1770 : : }
1771 : : /* reuse memory to reduce number of allocations: */
1772 : : /* move last half of pointers from pRankStack1 to pRankStack2 */
1773 : : /* The first 2 elements will be assigned separately */
1774 [ + + ]: 56 : if (( nn = ( nn - 2 ) / 2 ) > 0)
1775 : : {
1776 [ + - + + ]: 27 : for (ii = 2 + nn; ii < nRankStackLen && pRankStack1[ii]; ii++)
1777 : : {
1778 : 19 : pRankStack2[ii - nn] = pRankStack1[ii];
1779 : 19 : pRankStack1[ii] = NULL;
1780 : : }
1781 : : }
1782 : : }
1783 : : else
1784 : : {
1785 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1786 : 0 : goto exit_function; /* program error */
1787 : : }
1788 : : }
1789 : :
1790 [ + - ]: 56 : if (bCanonStereo)
1791 : : {
1792 : :
1793 : : /* *pCS2 = *pCS; */ /* save input information and pointers to allocated memory */
1794 : :
1795 : : /* initial ranking for non-isotopic mapping */
1796 : 56 : memcpy(nAtomNumber, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
1797 : 56 : memcpy(nRank, ftcn->PartitionCt.Rank, num_at_tg * sizeof(nRank[0]));
1798 : 56 : memcpy(nSymmRank, ftcn->nSymmRankCt, num_at_tg * sizeof(nSymmRank[0]));
1799 : :
1800 : : /* nSymmRank changes if canonical numbers of constitutionally equivalent atoms are not contiguous */
1801 : 56 : nNumCurrRanks = FixCanonEquivalenceInfo( pCG, num_at_tg,
1802 : : nSymmRank /* in&out*/,
1803 : : nRank, nTempRank /* out */,
1804 : : nAtomNumber /* in&out */,
1805 : : NULL );
1806 : : /* atom numbers in canonical order */
1807 : 56 : memcpy(pCS->nPrevAtomNumber, ftcn->PartitionCt.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
1808 : :
1809 : : /* fill stereo part of the connection table with initial (not optimized) parities */
1810 : : /* input
1811 : : pCS->LinearCTStereoDble
1812 : : pCS->LinearCTStereoCarb
1813 : : pCS->nMaxLenLinearCTStereoCarb
1814 : : pCS->nMaxLenLinearCTStereoDble
1815 : : */
1816 : :
1817 : 56 : nRet = FillOutStereoParities( at, num_atoms, ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1818 : : nRank, nAtomNumber, pCS, pCG, 0 /* bIsotopic */ );
1819 : :
1820 : : /* output
1821 : : pCS->LinearCTStereoDble
1822 : : pCS->LinearCTStereoCarb
1823 : : pCS2->nLenLinearCTStereoCarb
1824 : : pCS2->nLenLinearCTStereoDble
1825 : : */
1826 : :
1827 [ + - - + ]: 56 : if (RETURNED_ERROR( nRet ))
1828 : : {
1829 : 0 : goto exit_function;
1830 : : }
1831 [ - + ]: 56 : if (nRet < 0)
1832 : : {
1833 : 0 : nRet = CT_STEREOCOUNT_ERR;
1834 : 0 : goto exit_function;
1835 : : }
1836 : :
1837 : : /***************************************************************
1838 : : *
1839 : : * VI. Optimize non-isotopic stereo descriptors (optimized)
1840 : : *
1841 : : ***************************************************************/
1842 : :
1843 : : /* allocate memory for stereo canonicalization */
1844 : :
1845 [ + - ]: 56 : if (!nCanonRankStereo)
1846 : : {
1847 : 56 : nCanonRankStereo = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankStereo ) );
1848 : : }
1849 [ + - + - ]: 56 : if (!nSymmStereo && !( nMode & CMODE_NOEQ_STEREO ))
1850 : : {
1851 : 56 : nSymmStereo = (AT_RANK *) qmalloc( ( (long long)num_max + 1 ) * sizeof( *nSymmStereo ) ); /* djb-rwth: cast operator added */
1852 : : }
1853 : :
1854 [ + - - + ]: 56 : if (!( nMode & CMODE_NOEQ_STEREO ) && 0 > CurTreeAlloc( cur_tree, num_at_tg ))
1855 : : {
1856 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1857 : 0 : goto exit_function;
1858 : : }
1859 : : /* check allocations and assign first 2 elements of pRankStack2 */
1860 [ + - + - : 56 : if (pRankStack1 && pRankStack2 &&
+ - ]
1861 [ - + ]: 56 : nCanonRankStereo &&
1862 : : /* nCurrRankStereo && nAtomNumberCurrStereo &&*/
1863 [ # # ]: 0 : ( nSymmStereo || ( nMode & CMODE_NOEQ_STEREO ) ))
1864 : : {
1865 : 56 : pRankStack1[0] = pRankStack2[0] = nRank;
1866 : 56 : pRankStack1[1] = pRankStack2[1] = nAtomNumber;
1867 : : }
1868 : : else
1869 : : {
1870 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
1871 : 0 : goto exit_function;
1872 : : }
1873 : :
1874 : : /****************************************************************
1875 : : *
1876 : : * VI-A. Optimize non-isotopic non-inverted stereo descriptors
1877 : : *
1878 : : ****************************************************************/
1879 : :
1880 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
1881 [ + - + + ]: 75 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
1882 : : {
1883 : 19 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
1884 : : }
1885 : : /* set the 1st ranks to zero: prepare for ranks reuse */
1886 [ + - + + ]: 75 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
1887 : : {
1888 : 19 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
1889 : : }
1890 : :
1891 : : /* for debugging or statistics */
1892 : 56 : pCS->lNumBreakTies =
1893 : 56 : pCS->lNumNeighListIter =
1894 : 56 : pCS->lNumTotCT =
1895 : 56 : pCS->lNumDecreasedCT =
1896 : 56 : pCS->lNumRejectedCT =
1897 : 56 : pCS->lNumEqualCT = 0;
1898 : 56 : pCS->bKeepSymmRank = 0;
1899 : 56 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
1900 : :
1901 : : /******************************************************************************
1902 : : nCanonRank contains input canonical numbering
1903 : : nCanonRankStereo will be filled with a transposition of canonical numbering
1904 : : which (1) keeps connection table unchanged and
1905 : : (2) provides minimal stereo descriptors in
1906 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
1907 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
1908 : : */
1909 : :
1910 : 56 : nRet = map_stereo_bonds4( ic, pCG, at, num_atoms, num_at_tg, num_max, 0,
1911 : 56 : ftcn->PartitionCt.Rank, ftcn->PartitionCt.AtNumber,
1912 : : nCanonRankStereo, nSymmRank,
1913 : : pRankStack1, pRankStack2,
1914 : : nTempRank, nNumCurrRanks,nSymmStereo,
1915 : : NeighList, pCS, cur_tree, 0 /* nNumMappedBonds */,
1916 : : vABParityUnknown );
1917 : :
1918 [ + - - + ]: 56 : if (RETURNED_ERROR( nRet ))
1919 : : {
1920 [ # # ]: 0 : if (nRet == CT_TIMEOUT_ERR)
1921 : : {
1922 : 0 : goto exit_function;
1923 : : }
1924 : : else
1925 : : {
1926 : 0 : goto exit_function; /* program error */
1927 : : }
1928 : : }
1929 : : else
1930 : : {
1931 : 56 : int bFailed = 0;
1932 [ - + ]: 56 : if (!nRet)
1933 : : {
1934 : : /* djb-rwth: removing redundant code */
1935 : 0 : pCS2->nLenLinearCTStereoCarb =
1936 : 0 : pCS->nLenLinearCTStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
1937 : 0 : pCS2->nLenLinearCTStereoDble =
1938 : 0 : pCS->nLenLinearCTStereoDble = -abs( pCS->nLenLinearCTStereoDble );
1939 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
1940 : 0 : goto exit_function; /* program error */
1941 : : }
1942 : : else
1943 : : {
1944 : : /* save non-isotopic lengths */
1945 : 56 : pCS2->nLenLinearCTStereoDble = pCS->nLenLinearCTStereoDble;
1946 : 56 : pCS2->nLenLinearCTStereoCarb = pCS->nLenLinearCTStereoCarb;
1947 : : /* djb-rwth: removing redundant code */
1948 : : }
1949 : :
1950 : : /* save stereo canonical numbering */
1951 [ + - ]: 56 : if (pCS->nCanonOrdStereo)
1952 : : {
1953 [ + + ]: 620 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
1954 : : {
1955 [ + - + - ]: 564 : if (nCanonRankStereo[i] && (int) nCanonRankStereo[i] <= num_at_tg)
1956 : : {
1957 : 564 : pCS->nCanonOrdStereo[(int) nCanonRankStereo[i] - 1] = (AT_NUMB) i;
1958 : : }
1959 : : else
1960 : : {
1961 : 0 : bFailed++;
1962 : : }
1963 : : }
1964 [ - + ]: 56 : pCS->nLenCanonOrdStereo = ( bFailed ) ? -num_atoms : num_atoms;
1965 : : }
1966 : :
1967 : : /* save stereo tautomer groups numbering */
1968 [ - + - - ]: 56 : if (bTaut && pCS->nCanonOrdStereoTaut)
1969 : : {
1970 [ # # ]: 0 : if (0 < ( nRet = SortTautomerGroupsAndEndpoints( pCG, t_group_info1, num_atoms, num_at_tg, nCanonRankStereo ) ))
1971 : : {
1972 : : /*non-isotopic contains symmetry ranks */
1973 : 0 : int num_t_groups = t_group_info1->num_t_groups;
1974 : 0 : AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
1975 : : /*AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups; */
1976 : 0 : memcpy(pCS->nCanonOrdStereoTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdStereoTaut[0]));
1977 : 0 : pCS->nLenCanonOrdStereoTaut = ( bFailed ) ? -num_t_groups
1978 [ # # ]: 0 : : num_t_groups;
1979 : : }
1980 : : else
1981 : : {
1982 [ # # # # ]: 0 : if (RETURNED_ERROR(nRet))
1983 : : {
1984 : 0 : goto exit_function;
1985 : : }
1986 : : }
1987 : : /* djb-rwth: removing redundant code */
1988 : : /*SortTautomerGroupsAndEndpoints( t_group_info1, nCanonRank ); */ /* ??? return to non-isotopic canonical numbering */
1989 : : }
1990 : : }
1991 : :
1992 : :
1993 : : /****************************************************
1994 : : *
1995 : : * VI-B. Optimize INVERTED stereo descriptors
1996 : : *
1997 : : ****************************************************/
1998 [ + - ]: 56 : if (!nCanonRankStereoInv)
1999 : : {
2000 : 56 : nCanonRankStereoInv = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankStereoInv ) );
2001 : : }
2002 [ - + ]: 56 : if (!nCanonRankStereoInv)
2003 : : {
2004 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2005 : 0 : goto exit_function;
2006 : : }
2007 : :
2008 : : /* copy previous non-isotopic stereo canonicalization results to Inv initial data */
2009 : : /* assign pointers */
2010 : 56 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDbleInv;
2011 : 56 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarbInv;
2012 : :
2013 : : /* copy the lengths */
2014 : 56 : pCS2->nLenLinearCTStereoDbleInv =
2015 : 56 : pCS->nLenLinearCTStereoDbleInv =
2016 : 56 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
2017 : :
2018 : 56 : pCS2->nLenLinearCTStereoCarbInv =
2019 : 56 : pCS->nLenLinearCTStereoCarbInv =
2020 : 56 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
2021 : :
2022 [ + - + + ]: 56 : if (pCS->nLenLinearCTStereoDble > 0 || pCS->nLenLinearCTStereoCarb > 0)
2023 : : {
2024 : : /* copy previous results, the canonical stereo CT */
2025 : 55 : memcpy(pCS->LinearCTStereoDble, pCS2->LinearCTStereoDble, pCS->nLenLinearCTStereoDble * sizeof(pCS->LinearCTStereoDble[0]));
2026 : 55 : memcpy(pCS->LinearCTStereoCarb, pCS2->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb * sizeof(pCS->LinearCTStereoCarb[0]));
2027 : : }
2028 : 56 : memcpy(nCanonRankStereoInv, nCanonRankStereo, num_max * sizeof(nCanonRankStereoInv[0]));
2029 [ + - + - ]: 56 : if (pCS->nCanonOrdStereoInv && pCS->nCanonOrdStereo)
2030 : : {
2031 : : /* in case there is nothing to invert */
2032 : 56 : memcpy(pCS->nCanonOrdStereoInv, pCS->nCanonOrdStereo, num_at_tg * sizeof(pCS->nCanonOrdStereoInv[0]));
2033 : : }
2034 : :
2035 : : /******************************
2036 : : *
2037 : : * Invert stereo
2038 : : *
2039 : : ******************************/
2040 : :
2041 : : /*********************************************************************************
2042 : : * Create initial approximation for the minimization of the stereo descriptors:
2043 : : * invert stereogenic atom parities, one parity in each allene, all parities in
2044 : : * pCS->LinearCTStereoCarb and allene parities in pCS->nLenLinearCTStereoDble
2045 : : */
2046 : 56 : nRet = InvertStereo( at, num_at_tg, nCanonRankStereo, nTempRank, pCS, 1 /* bInvertLinearCTStereo */ );
2047 [ + - - + ]: 56 : if (RETURNED_ERROR( nRet ))
2048 : : {
2049 : 0 : goto exit_function;
2050 : : }
2051 [ + + ]: 56 : else if (nRet > 0)
2052 : : {
2053 : : /* InvertStereo() has done some changes */
2054 : : /* djb-rwth: removing redundant code */
2055 : : /* FillOutStereoParities() has already been called to fill out these 2 LinearCTs */
2056 : :
2057 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2058 [ + - + + ]: 155 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
2059 : : {
2060 : 104 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2061 : : }
2062 : : /* set the 1st ranks to zero: prepare for ranks reuse */
2063 [ + - + + ]: 155 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2064 : : {
2065 : 104 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2066 : : }
2067 : :
2068 : : /* for debugging or statistics */
2069 : 51 : pCS->lNumBreakTies =
2070 : 51 : pCS->lNumNeighListIter =
2071 : 51 : pCS->lNumTotCT =
2072 : 51 : pCS->lNumDecreasedCT =
2073 : 51 : pCS->lNumRejectedCT =
2074 : 51 : pCS->lNumEqualCT = 0;
2075 : 51 : pCS->bKeepSymmRank = 0;
2076 : 51 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2077 : :
2078 : : #ifdef FIX_STEREOCOUNT_ERR
2079 : 51 : CurTreeSetPos( cur_tree, 0 );
2080 : : #endif
2081 : :
2082 : : /******************************************************************************
2083 : : ftcn->PartitionCt.Rank contains input canonical numbering
2084 : : nCanonRankStereoInv will be filled with a transposition of canonical numbering
2085 : : which (1) keeps connection table unchanged and
2086 : : (2) provides minimal stereo descriptors in
2087 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2088 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2089 : : ******************************************************************************/
2090 : :
2091 : 51 : nRet = map_stereo_bonds4( ic,pCG, at, num_atoms, num_at_tg, num_max, 0,
2092 : 51 : ftcn->PartitionCt.Rank,
2093 : 51 : ftcn->PartitionCt.AtNumber,
2094 : : nCanonRankStereoInv,
2095 : : nSymmRank, pRankStack1, pRankStack2,
2096 : : nTempRank, nNumCurrRanks, nSymmStereo,
2097 : : NeighList, pCS, cur_tree, 0,
2098 : : vABParityUnknown );
2099 : :
2100 [ + - - + ]: 51 : if (RETURNED_ERROR( nRet ))
2101 : : {
2102 [ # # ]: 0 : if (nRet == CT_TIMEOUT_ERR)
2103 : : {
2104 : 0 : goto exit_function;
2105 : : }
2106 : : else
2107 : : {
2108 : 0 : goto exit_function; /* program error */
2109 : : }
2110 : : }
2111 : : else
2112 : : {
2113 : 51 : int bFailed = 0;
2114 [ - + ]: 51 : if (!nRet)
2115 : : {
2116 : : /* djb-rwth: removing redundant code */
2117 : 0 : pCS2->nLenLinearCTStereoCarb =
2118 : 0 : pCS->nLenLinearCTStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
2119 : 0 : pCS2->nLenLinearCTStereoDble =
2120 : 0 : pCS->nLenLinearCTStereoDble = -abs( pCS->nLenLinearCTStereoDble );
2121 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2122 : 0 : goto exit_function; /* program error */
2123 : : }
2124 : :
2125 : : /* save non-isotopic pointers & lengths for INVERTED stereo */
2126 : 51 : pCS->nLenLinearCTStereoDbleInv =
2127 : 51 : pCS2->nLenLinearCTStereoDbleInv = pCS->nLenLinearCTStereoDble;
2128 : 51 : pCS->nLenLinearCTStereoCarbInv =
2129 : 51 : pCS2->nLenLinearCTStereoCarbInv = pCS->nLenLinearCTStereoCarb;
2130 : :
2131 : : /* restore pointers and lengths to non-inverted stereo */
2132 : : /* -- this is needed for InvertStereo() back, see below */
2133 : 51 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble;
2134 : 51 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
2135 : 51 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
2136 : 51 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
2137 : : /* consistency check */
2138 [ + - ]: 51 : if (pCS->nLenLinearCTStereoDbleInv != pCS->nLenLinearCTStereoDble ||
2139 [ - + ]: 51 : pCS->nLenLinearCTStereoCarbInv != pCS->nLenLinearCTStereoCarb)
2140 : : {
2141 : 0 : nRet = CT_CALC_STEREO_ERR;
2142 : 0 : goto exit_function; /* program error */
2143 : : }
2144 : :
2145 : : /******************************
2146 : : *
2147 : : * Invert stereo back
2148 : : *
2149 : : ******************************
2150 : : * (make sure that pointers
2151 : : * pCS->LinearCTStereoCarb,
2152 : : * pCS->LinearCTStereoDble
2153 : : * and corresponding lengths
2154 : : * have been restored)
2155 : : ******************************/
2156 : : /*********************************************************************************
2157 : : * invert only stereogenic atom parities and one parity in each allene, DO NOT
2158 : : * change parities in pCS->LinearCTStereoCarb and pCS->nLenLinearCTStereoDble
2159 : : */
2160 : 51 : nRet = InvertStereo( at,
2161 : : num_at_tg,
2162 : : nCanonRankStereo,
2163 : : nTempRank,
2164 : : pCS,
2165 : : 0 );
2166 : :
2167 [ + - - + ]: 51 : if (RETURNED_ERROR( nRet ))
2168 : : {
2169 : 0 : goto exit_function;
2170 : : }
2171 : 51 : nRet = 0;
2172 : :
2173 : :
2174 : : /* save stereo canonical numbering */
2175 [ + - ]: 51 : if (pCS->nCanonOrdStereoInv)
2176 : : {
2177 [ + + ]: 573 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
2178 : : {
2179 [ + - + - ]: 522 : if (nCanonRankStereoInv[i] && (int) nCanonRankStereoInv[i] <= num_at_tg)
2180 : : {
2181 : 522 : pCS->nCanonOrdStereoInv[(int) nCanonRankStereoInv[i] - 1] = (AT_NUMB) i;
2182 : : }
2183 : : else
2184 : : {
2185 : 0 : bFailed++;
2186 : : }
2187 : : }
2188 [ - + ]: 51 : pCS->nLenCanonOrdStereo = ( bFailed ) ? -num_atoms : num_atoms;
2189 : : }
2190 : :
2191 : : /* compare inverted and non-inverted stereo */
2192 : 51 : pCS->bCmpStereo = 2 + CompareLinCtStereo(
2193 : : pCS->LinearCTStereoDbleInv, pCS->nLenLinearCTStereoDbleInv,
2194 : : pCS->LinearCTStereoCarbInv, pCS->nLenLinearCTStereoCarbInv,
2195 : : pCS->LinearCTStereoDble, pCS->nLenLinearCTStereoDble,
2196 : : pCS->LinearCTStereoCarb, pCS->nLenLinearCTStereoCarb
2197 : : );
2198 : : }
2199 : : }
2200 [ + - ]: 5 : else if (0 == nRet)
2201 : : {
2202 : : /* nothing has been done, restore pointers and lengths for stereo */
2203 : 5 : pCS->LinearCTStereoDble = pCS2->LinearCTStereoDble;
2204 : 5 : pCS->LinearCTStereoCarb = pCS2->LinearCTStereoCarb;
2205 : 5 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTStereoDble;
2206 : 5 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTStereoCarb;
2207 : : }
2208 : : }
2209 : :
2210 : : /* restore "ignore isotopic differences in tautomer groups" */
2211 [ - + ]: 56 : if (bTaut)
2212 : : {
2213 : : /* save request for isotopic tautomeric groups */
2214 : 0 : pCS->t_group_info->bIgnoreIsotopic = bIgnoreIsotopicInputGroups;
2215 : : }
2216 : :
2217 : : /* restore request for isotopic name */
2218 : 56 : pCS->bIgnoreIsotopic = bIgnoreIsotopicInputAtoms;
2219 : :
2220 [ + - - - ]: 56 : if (bCanonIsoStereo && bCanonIsotopic)
2221 : : {
2222 : :
2223 : : /****************************************************************
2224 : : *
2225 : : * VII. Optimize isotopic stereo descriptors (optimized)
2226 : : *
2227 : : ****************************************************************/
2228 : : /*
2229 : : pCS->LinearCTIsotopic = NULL;
2230 : : */
2231 : :
2232 : : /* Initial ranking for isotopic mapping */
2233 : 0 : memcpy(nAtomNumber, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
2234 : 0 : memcpy(nRank, ftcn->PartitionCtIso.Rank, num_at_tg * sizeof(nRank[0]));
2235 : 0 : memcpy(nSymmRank, ftcn->nSymmRankCtIso, num_at_tg * sizeof(nSymmRank[0]));
2236 : : /* nSymmRank will change if canonical numbers of of constitutionally equivalent atoms are not contiguous */
2237 : 0 : nNumCurrRanks = FixCanonEquivalenceInfo( pCG, num_at_tg, nSymmRank /* in&out*/,
2238 : : nRank, nTempRank /* out */, nAtomNumber /* in&out */, NULL );
2239 : 0 : memcpy(pCS->nPrevAtomNumber, ftcn->PartitionCtIso.AtNumber, num_at_tg * sizeof(nAtomNumber[0]));
2240 : : /* Allocate memory for optimized stereo canonicalization */
2241 : : /* for stereo canonical numbering to be found. */
2242 [ # # ]: 0 : if (!nCanonRankIsotopicStereo)
2243 : : {
2244 : 0 : nCanonRankIsotopicStereo = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankIsotopicStereo ) );
2245 : : }
2246 [ # # # # ]: 0 : if (!nSymmStereo && !( nMode & CMODE_NOEQ_STEREO ))
2247 : : {
2248 : 0 : nSymmStereo = (AT_RANK *) qmalloc( ( (long long)num_max + 1 ) * sizeof( *nSymmStereo ) ); /* djb-rwth: cast operator added */
2249 : : }
2250 [ # # # # ]: 0 : if (!( nMode & CMODE_NOEQ_STEREO ) && CurTreeAlloc( cur_tree, num_at_tg ))
2251 : : {
2252 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2253 : 0 : goto exit_function;
2254 : : }
2255 : :
2256 : : /* Check allocations and assign first 2 elements of pRankStack2 */
2257 [ # # # # : 0 : if (pRankStack1 && pRankStack2 &&
# # ]
2258 [ # # ]: 0 : nCanonRankIsotopicStereo &&
2259 [ # # ]: 0 : ( nSymmStereo || ( nMode & CMODE_NOEQ_STEREO ) ))
2260 : : {
2261 : :
2262 : 0 : pRankStack1[0] = pRankStack2[0] = nRank; /* pRankStack1[0,1] shall be unchanged */
2263 : 0 : pRankStack1[1] = pRankStack2[1] = nAtomNumber;
2264 : : }
2265 : : else
2266 : : {
2267 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2268 : 0 : goto exit_function;
2269 : : }
2270 : :
2271 : : /******************************************************************
2272 : : Important: fill out a list of stereo atoms and bonds including
2273 : : those which are stereo due to isotopic atoms only and create
2274 : : LinearCT stereo descriptors for the canonical numbering
2275 : : ******************************************************************/
2276 : :
2277 : :
2278 : : /* at[] has certain members for non-isotopic and isotopic stereo; switch them */
2279 : 0 : SwitchAtomStereoAndIsotopicStereo( at, num_atoms, &bSwitchedAtomToIsotopic );
2280 : :
2281 : : /* Prepare stereo connection tables' pointers */
2282 : 0 : SetCtToIsotopicStereo( pCS, pCS2 );
2283 : :
2284 : 0 : nRet = FillOutStereoParities( at, num_atoms,
2285 : 0 : ftcn->PartitionCtIso.Rank,
2286 : 0 : ftcn->PartitionCtIso.AtNumber,
2287 : : nRank, nAtomNumber,
2288 : : pCS, pCG, 1 /* bIsotopic */ );
2289 : :
2290 : :
2291 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2292 : : {
2293 : 0 : goto exit_function; /* program error */
2294 : : }
2295 : : else
2296 : : {
2297 [ # # ]: 0 : if (!nRet)
2298 : : {
2299 : : /* no isotopic stereo */
2300 : 0 : pCS2->nLenLinearCTIsotopicStereoDble = pCS->nLenLinearCTIsotopicStereoDble = 0;
2301 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb = pCS->nLenLinearCTIsotopicStereoCarb = 0;
2302 : 0 : pCS->nLenCanonOrdIsotopicStereo = 0;
2303 : 0 : pCS->nLenCanonOrdIsotopicStereoTaut = 0;
2304 : 0 : pCS2->nLenLinearCTIsotopicStereoDbleInv = pCS->nLenLinearCTIsotopicStereoDbleInv = 0;
2305 : 0 : pCS2->nLenLinearCTIsotopicStereoCarbInv = pCS->nLenLinearCTIsotopicStereoCarbInv = 0;
2306 : 0 : goto bypass_isotopic_stereo;
2307 : : }
2308 : : }
2309 : :
2310 : : /* djb-rwth: removing redundant code */
2311 : :
2312 : :
2313 : : /*************************************************************
2314 : : *
2315 : : * VII-A. Optimize non-inverted isotopic stereo descriptors
2316 : : *
2317 : : *************************************************************/
2318 : :
2319 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2320 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
2321 : : {
2322 : 0 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2323 : : }
2324 : : /* set the 1st ranks to zero: prepare for ranks reuse */
2325 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2326 : : {
2327 : 0 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2328 : : }
2329 : :
2330 : : /* for debugging or statistics */
2331 : 0 : pCS->lNumBreakTies =
2332 : 0 : pCS->lNumNeighListIter =
2333 : 0 : pCS->lNumTotCT =
2334 : 0 : pCS->lNumDecreasedCT =
2335 : 0 : pCS->lNumRejectedCT =
2336 : 0 : pCS->lNumEqualCT = 0;
2337 : 0 : pCS->bKeepSymmRank = 0;
2338 : 0 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2339 : :
2340 : : /**************************************************************************************
2341 : : nCanonRankIsotopic contains input canonical numbering
2342 : : nCanonRankIsotopicStereo will be filled with a transposition of canonical numbering
2343 : : that (1) keeps connection table unchanged and
2344 : : (2) provides minimal stereo descriptors in
2345 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2346 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2347 : : ***************************************************************************************/
2348 : :
2349 : 0 : nRet = map_stereo_bonds4( ic, pCG,at, num_atoms, num_at_tg, num_max, 0,
2350 : 0 : ftcn->PartitionCtIso.Rank,
2351 : 0 : ftcn->PartitionCtIso.AtNumber,
2352 : : nCanonRankIsotopicStereo,
2353 : : nSymmRank, pRankStack1, pRankStack2,
2354 : : nTempRank, nNumCurrRanks, nSymmStereo,
2355 : : NeighList, pCS, cur_tree,
2356 : : 0, vABParityUnknown );
2357 : :
2358 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2359 : : {
2360 : 0 : goto exit_function;
2361 : : }
2362 : : else
2363 : : {
2364 : 0 : int bFailed = 0;
2365 : :
2366 [ # # ]: 0 : if (!nRet)
2367 : : {
2368 : : /* djb-rwth: removing redundant code */
2369 : 0 : pCS2->nLenLinearCTIsotopicStereoDble =
2370 : 0 : pCS->nLenLinearCTIsotopicStereoDble = -abs( pCS->nLenLinearCTStereoDble );
2371 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb =
2372 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
2373 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2374 : 0 : goto exit_function; /* program error */
2375 : : }
2376 : : else
2377 : : {
2378 : : /* save isotopic lengths */
2379 : 0 : pCS->nLenLinearCTIsotopicStereoDble =
2380 : 0 : pCS2->nLenLinearCTIsotopicStereoDble = pCS->nLenLinearCTStereoDble;
2381 : 0 : pCS->nLenLinearCTIsotopicStereoCarb =
2382 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb = pCS->nLenLinearCTStereoCarb;
2383 : :
2384 : : /* save stereo canonical numbering */
2385 [ # # ]: 0 : if (pCS->nCanonOrdIsotopicStereo)
2386 : : {
2387 [ # # ]: 0 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
2388 : : {
2389 [ # # # # ]: 0 : if (nCanonRankIsotopicStereo[i] && (int) nCanonRankIsotopicStereo[i] <= num_at_tg)
2390 : : {
2391 : 0 : pCS->nCanonOrdIsotopicStereo[(int) nCanonRankIsotopicStereo[i] - 1] = (AT_NUMB) i;
2392 : : }
2393 : : else
2394 : : {
2395 : 0 : bFailed++;
2396 : : }
2397 : : }
2398 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereo = bFailed ? -num_atoms : num_atoms;
2399 : : }
2400 : :
2401 : : /* save stereo tautomer groups numbering */
2402 [ # # ]: 0 : if (pCS->nCanonOrdIsotopicStereoTaut)
2403 : : {
2404 [ # # ]: 0 : if (0 < ( nRet = SortTautomerGroupsAndEndpoints( pCG, t_group_info1, num_atoms, num_at_tg, nCanonRankIsotopicStereo ) ))
2405 : : {
2406 : : /*non-isotopic contains symmetry ranks */
2407 : 0 : int num_t_groups = t_group_info1->num_t_groups;
2408 : 0 : AT_NUMB *tGroupNumber = t_group_info1->tGroupNumber;
2409 : : /*AT_NUMB *tiSymmRank = tGroupNumber + TGSO_SYMM_IRANK*num_t_groups; */
2410 : 0 : memcpy(pCS->nCanonOrdIsotopicStereoTaut, tGroupNumber, num_t_groups * sizeof(pCS->nCanonOrdIsotopicStereoTaut[0]));
2411 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereoTaut = bFailed ? -num_t_groups : num_t_groups;
2412 : :
2413 : : /*SortTautomerGroupsAndEndpoints( t_group_info1, nCanonRank ); */ /* ??? return to non-isotopic canonical numbering */
2414 : : }
2415 : : else
2416 : : {
2417 [ # # # # ]: 0 : if (RETURNED_ERROR(nRet))
2418 : : {
2419 : 0 : goto exit_function;
2420 : : }
2421 : : }
2422 : : /* djb-rwth: removing redundant code */
2423 : : }
2424 : : }
2425 : : }
2426 : :
2427 : : /**********************************************************
2428 : : *
2429 : : * VII-B. Optimize INVERTED isotopic stereo descriptors
2430 : : *
2431 : : **********************************************************/
2432 [ # # ]: 0 : if (!nCanonRankIsotopicStereoInv)
2433 : 0 : nCanonRankIsotopicStereoInv = (AT_RANK *) qmalloc( num_max * sizeof( *nCanonRankIsotopicStereoInv ) );
2434 [ # # ]: 0 : if (!nCanonRankIsotopicStereoInv)
2435 : : {
2436 : 0 : nRet = CT_OUT_OF_RAM; /* <BRKPT> */
2437 : 0 : goto exit_function;
2438 : : }
2439 : :
2440 : : /* copy previous isotopic stereo canonicalization results to Inv initial data */
2441 : : /* assign pointers */
2442 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDbleInv; /* enable stereo */
2443 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarbInv;
2444 : :
2445 : : /* copy the lengths */
2446 : 0 : pCS2->nLenLinearCTIsotopicStereoDbleInv =
2447 : 0 : pCS->nLenLinearCTStereoDbleInv =
2448 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2449 : :
2450 : 0 : pCS2->nLenLinearCTIsotopicStereoCarbInv =
2451 : 0 : pCS->nLenLinearCTStereoCarbInv =
2452 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2453 : :
2454 [ # # # # ]: 0 : if (pCS->nLenLinearCTStereoDble > 0 || pCS->nLenLinearCTStereoCarb > 0)
2455 : : {
2456 : : /* copy previous results, the canonical stereo CT */
2457 : 0 : memcpy(pCS->LinearCTStereoDble, pCS2->LinearCTIsotopicStereoDble, pCS->nLenLinearCTStereoDble * sizeof(pCS->LinearCTStereoDble[0]));
2458 : 0 : memcpy(pCS->LinearCTStereoCarb, pCS2->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTStereoCarb * sizeof(pCS->LinearCTStereoCarb[0]));
2459 : : }
2460 : 0 : memcpy(nCanonRankIsotopicStereoInv, nCanonRankIsotopicStereo, num_max * sizeof(nCanonRankIsotopicStereoInv[0]));
2461 [ # # # # ]: 0 : if (pCS->nCanonOrdIsotopicStereoInv && pCS->nCanonOrdIsotopicStereo)
2462 : : {
2463 : : /* in case there is nothing to invert */
2464 : 0 : memcpy(pCS->nCanonOrdIsotopicStereoInv, pCS->nCanonOrdIsotopicStereo, num_at_tg * sizeof(pCS->nCanonOrdIsotopicStereoInv[0]));
2465 : : }
2466 : :
2467 : : /******************************
2468 : : *
2469 : : * Invert isotopic stereo
2470 : : *
2471 : : ******************************/
2472 : :
2473 : : /*********************************************************************************
2474 : : * Create initial approximation for the minimization of the stereo descriptors:
2475 : : * invert stereogenic atom parities, one parity in each allene, all parities in
2476 : : * pCS->LinearCTStereoCarb and allene parities in pCS->nLenLinearCTStereoDble
2477 : : */
2478 : :
2479 : 0 : nRet = InvertStereo( at,
2480 : : num_at_tg,
2481 : : nCanonRankIsotopicStereo,
2482 : : nTempRank,
2483 : : pCS,
2484 : : 1 );
2485 : :
2486 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2487 : : {
2488 : 0 : goto exit_function;
2489 : : }
2490 [ # # ]: 0 : else if (nRet > 0)
2491 : : {
2492 : : /* InvertStereo() has done some changes */
2493 : : /* djb-rwth: removing redundant code */
2494 : : /* FillOutStereoParities() has already been called to fill out these 2 LinearCTs */
2495 : :
2496 : : /* set the 1st ranks in the rest of the stack to zero: prepare for ranks reuse */
2497 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack1[n]; n++)
2498 : : {
2499 : 0 : pRankStack1[n][0] = 0; /* means ranks have to be recalculated */
2500 : : }
2501 : : /* set the 1st ranks to zero: prepare for ranks reuse */
2502 [ # # # # ]: 0 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2503 : : {
2504 : 0 : pRankStack2[n][0] = 0; /* means ranks have to be recalculated */
2505 : : }
2506 : : /* for debugging or statistics */
2507 : 0 : pCS->lNumBreakTies =
2508 : 0 : pCS->lNumNeighListIter =
2509 : 0 : pCS->lNumTotCT =
2510 : 0 : pCS->lNumDecreasedCT =
2511 : 0 : pCS->lNumRejectedCT =
2512 : 0 : pCS->lNumEqualCT = 0;
2513 : 0 : pCS->bKeepSymmRank = 0;
2514 : 0 : pCS->bFirstCT = 1; /* To fill out nCanonRankStereo[] in map_stero_atoms2() */
2515 : :
2516 : : /**************************************************************************************
2517 : : nCanonRankIsotopic contains input canonical numbering
2518 : : nCanonRankIsotopicStereo will be filled with a transposition of canonical numbering
2519 : : that (1) keeps connection table unchanged and
2520 : : (2) provides minimal stereo descriptors in
2521 : : pCS->LinearCTStereoDble (length=pCS->nLenLinearCTStereoDble)
2522 : : pCS->LinearCTStereoCarb (length=pCS->nLenLinearCTStereoCarb)
2523 : : */
2524 : 0 : nRet = map_stereo_bonds4( ic, pCG,
2525 : : at,
2526 : : num_atoms,
2527 : : num_at_tg,
2528 : : num_max,
2529 : : 0,
2530 : 0 : ftcn->PartitionCtIso.Rank,
2531 : 0 : ftcn->PartitionCtIso.AtNumber,
2532 : : nCanonRankIsotopicStereoInv,
2533 : : nSymmRank,
2534 : : pRankStack1,
2535 : : pRankStack2,
2536 : : nTempRank,
2537 : : nNumCurrRanks,
2538 : : nSymmStereo,
2539 : : NeighList,
2540 : : pCS,
2541 : : cur_tree,
2542 : : 0,
2543 : : vABParityUnknown );
2544 : :
2545 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2546 : : {
2547 [ # # ]: 0 : if (nRet == CT_TIMEOUT_ERR)
2548 : 0 : goto exit_function;
2549 : : else
2550 : 0 : goto exit_function; /* program error */
2551 : : }
2552 : : else
2553 : : {
2554 : 0 : int bFailed = 0;
2555 : :
2556 [ # # ]: 0 : if (!nRet)
2557 : : {
2558 : : /* djb-rwth: removing redundant code */
2559 : 0 : pCS2->nLenLinearCTIsotopicStereoDble =
2560 : 0 : pCS->nLenLinearCTIsotopicStereoDble = -abs( pCS->nLenLinearCTStereoDble );
2561 : 0 : pCS2->nLenLinearCTIsotopicStereoCarb =
2562 : 0 : pCS->nLenLinearCTIsotopicStereoCarb = -abs( pCS->nLenLinearCTStereoCarb );
2563 : 0 : nRet = CT_STEREOCOUNT_ERR; /* <BRKPT> */
2564 : 0 : goto exit_function; /* program error */
2565 : : }
2566 : :
2567 : : /* save isotopic pointers & lengths for INVERTED stereo */
2568 : :
2569 : : /* save isotopic lengths */
2570 : 0 : pCS->nLenLinearCTIsotopicStereoDbleInv =
2571 : 0 : pCS2->nLenLinearCTIsotopicStereoDbleInv = pCS->nLenLinearCTStereoDble;
2572 : 0 : pCS->nLenLinearCTIsotopicStereoCarbInv =
2573 : 0 : pCS2->nLenLinearCTIsotopicStereoCarbInv = pCS->nLenLinearCTStereoCarb;
2574 : :
2575 : : /* restore pointers and lengths to non-inverted isotopic stereo */
2576 : : /* -- this is needed for InvertStereo() back, see below */
2577 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble;
2578 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
2579 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2580 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2581 : :
2582 : : /* consistency check */
2583 [ # # ]: 0 : if (pCS->nLenLinearCTIsotopicStereoDbleInv != pCS->nLenLinearCTIsotopicStereoDble ||
2584 [ # # ]: 0 : pCS->nLenLinearCTIsotopicStereoCarbInv != pCS->nLenLinearCTIsotopicStereoCarb)
2585 : : {
2586 : 0 : nRet = CT_CALC_STEREO_ERR;
2587 : 0 : goto exit_function; /* program error */
2588 : : }
2589 : :
2590 : : /******************************
2591 : : *
2592 : : * Invert stereo back
2593 : : *
2594 : : ******************************
2595 : : * (make sure that pointers
2596 : : * pCS->LinearCTStereoCarb,
2597 : : * pCS->LinearCTStereoDble
2598 : : * and corresponding lengths
2599 : : * have been restored)
2600 : : ******************************/
2601 : :
2602 : 0 : nRet = InvertStereo( at, num_at_tg, nCanonRankIsotopicStereo,
2603 : : nTempRank, pCS, 0 );
2604 : :
2605 [ # # # # ]: 0 : if (RETURNED_ERROR( nRet ))
2606 : : {
2607 : 0 : goto exit_function;
2608 : : }
2609 : 0 : nRet = 0;
2610 : :
2611 : : /* save stereo canonical numbering */
2612 [ # # ]: 0 : if (pCS->nCanonOrdIsotopicStereoInv)
2613 : : {
2614 [ # # ]: 0 : for (i = 0; i < num_at_tg; i++) /* djb-rwth: removing redundant code */
2615 : : {
2616 [ # # # # ]: 0 : if (nCanonRankIsotopicStereoInv[i] && (int) nCanonRankIsotopicStereoInv[i] <= num_at_tg)
2617 : : {
2618 : 0 : pCS->nCanonOrdIsotopicStereoInv[(int) nCanonRankIsotopicStereoInv[i] - 1] = (AT_NUMB) i;
2619 : : }
2620 : : else
2621 : : {
2622 : 0 : bFailed++;
2623 : : }
2624 : : }
2625 [ # # ]: 0 : pCS->nLenCanonOrdIsotopicStereo = bFailed ? -num_atoms : num_atoms;
2626 : : }
2627 : :
2628 : : /* compare inverted and non-inverted isotopic stereo */
2629 : 0 : pCS->bCmpIsotopicStereo = 2 + CompareLinCtStereo(
2630 : : pCS->LinearCTIsotopicStereoDbleInv, pCS->nLenLinearCTIsotopicStereoDbleInv,
2631 : : pCS->LinearCTIsotopicStereoCarbInv, pCS->nLenLinearCTIsotopicStereoCarbInv,
2632 : : pCS->LinearCTIsotopicStereoDble, pCS->nLenLinearCTIsotopicStereoDble,
2633 : : pCS->LinearCTIsotopicStereoCarb, pCS->nLenLinearCTIsotopicStereoCarb
2634 : : );
2635 : : }
2636 : : }
2637 [ # # ]: 0 : else if (0 == nRet)
2638 : : {
2639 : : /* nothing has been done, restore pointers and lengths for stereo */
2640 : 0 : pCS->LinearCTStereoDble = pCS2->LinearCTIsotopicStereoDble;
2641 : 0 : pCS->LinearCTStereoCarb = pCS2->LinearCTIsotopicStereoCarb;
2642 : 0 : pCS->nLenLinearCTStereoDble = pCS2->nLenLinearCTIsotopicStereoDble;
2643 : 0 : pCS->nLenLinearCTStereoCarb = pCS2->nLenLinearCTIsotopicStereoCarb;
2644 : : }
2645 : :
2646 : :
2647 : 0 : bypass_isotopic_stereo:; /* ??? */
2648 : :
2649 : 0 : pCS->LinearCTIsotopic = pCS2->LinearCTIsotopic;
2650 : : }
2651 : :
2652 : :
2653 : :
2654 : 56 : exit_function:
2655 : :
2656 [ - + ]: 69 : if (bSwitchedAtomToIsotopic)
2657 : : {
2658 : 0 : SwitchAtomStereoAndIsotopicStereo( at, num_atoms, &bSwitchedAtomToIsotopic );
2659 : 0 : SetCtToNonIsotopicStereo( pCS, pCS2 ); /* ??? */
2660 : : }
2661 : :
2662 : : /* restore non-isotopic connection table */
2663 [ + - ]: 69 : if (pCS->LinearCT2)
2664 : : {
2665 : 69 : inchi_swap( (char*) &pCS->LinearCT, (char*) &pCS->LinearCT2, sizeof( pCS->LinearCT ) );
2666 : 69 : inchi_swap( (char*) &pCS->nLenLinearCT, (char*) &pCS->nLenLinearCT2, sizeof( pCS->nLenLinearCT ) );
2667 : 69 : inchi_swap( (char*) &pCS->nLenLinearCTAtOnly, (char*) &pCS->nLenLinearCTAtOnly2, sizeof( pCS->nLenLinearCTAtOnly ) );
2668 : : }
2669 : :
2670 : : /* free memory */
2671 : 69 : i = 2;
2672 [ + - ]: 69 : if (pRankStack1)
2673 : : {
2674 : 69 : pRankStack1[0] =
2675 : 69 : pRankStack1[1] = NULL; /* deallocated separately */
2676 [ + - + + ]: 232 : for (; i < nRankStackLen && pRankStack1[i]; i++)
2677 : : {
2678 : : ;
2679 : : }
2680 : : }
2681 [ + - + + ]: 69 : if (pRankStack1 && pRankStack2)
2682 : : {
2683 [ + - + + ]: 171 : for (n = 2; n < nRankStackLen && pRankStack2[n]; n++)
2684 : : {
2685 [ + - ]: 115 : if (i < nRankStackLen - 1)
2686 : : {
2687 : 115 : pRankStack1[i++] = pRankStack2[n];
2688 : : }
2689 : : else
2690 : : {
2691 [ # # ]: 0 : inchi_free( pRankStack2[n] );
2692 : : }
2693 : : }
2694 : : }
2695 : :
2696 [ + + ]: 69 : inchi_free(pRankStack2); /* djb-rwth: fixing coverity ID #499631 */
2697 : :
2698 : 69 : pCS->NeighList = NULL; /* keep the pointer in pBCN->ftcn[bTaut].NeighList for further deallocation */
2699 [ + + + - ]: 69 : qfree( nAtomNumber );
2700 [ + + + - ]: 69 : qfree( nTempRank );
2701 [ + + + - ]: 69 : qfree( nRank );
2702 [ + + + - ]: 69 : qfree( nSymmRank );
2703 : :
2704 [ + + + - ]: 69 : qfree( nSymmStereo );
2705 : 69 : CurTreeFree( cur_tree );
2706 : : /* memory leak fix */
2707 : : /*
2708 : : qfree ( nCurrRankIsotopicStereo );
2709 : : qfree ( nAtomNumberCurrIsotopicStereo);
2710 : : */
2711 [ - + - - ]: 69 : qfree( nCanonRankIsotopicStereo );
2712 [ - + - - ]: 69 : qfree( nCanonRankIsotopicStereoInv );
2713 : :
2714 [ + + + - ]: 69 : qfree( nCanonRankStereo );
2715 [ + + + - ]: 69 : qfree( nCanonRankStereoInv );
2716 : :
2717 : 69 : InchiTimeGet( &ulEndTime );
2718 : :
2719 : 69 : pCS->lTotalTime = InchiTimeMsecDiff( ic, &ulEndTime, &ulStartTime );
2720 : :
2721 [ + - ]: 69 : return ( nRet >= -1 ) ? num_atoms : nRet;
2722 : : /* cannot easily get number of ranks for now */
2723 : : }
2724 : :
2725 : :
2726 : : /****************************************************************************/
2727 : 69 : int Canon_INChI( INCHI_CLOCK *ic,
2728 : : int num_atoms,
2729 : : int num_at_tg,
2730 : : sp_ATOM* at,
2731 : : CANON_STAT* pCS,
2732 : : CANON_GLOBALS *pCG,
2733 : : INCHI_MODE nMode,
2734 : : int bTautFtcn )
2735 : : {
2736 [ + - + - ]: 69 : if (pCS->pBCN && !pCS->NeighList)
2737 : : {
2738 : 69 : return Canon_INChI3( ic, num_atoms, num_at_tg, at, pCS, pCG, nMode, bTautFtcn );
2739 : : }
2740 : :
2741 : 0 : return CT_CANON_ERR;
2742 : : }
|