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 <string.h>
42 : :
43 : : #include "mode.h"
44 : : #include "ichicomn.h"
45 : : #include "ichicant.h"
46 : :
47 : : #include "bcf_s.h"
48 : :
49 : : #if 0
50 : : #define RET_MAX 32767
51 : : #define CUTOFF 8 /* testing shows that this is good value */
52 : : #endif
53 : :
54 : : /* Note: the theoretical number of stack entries required is
55 : : no more than 1 + log2(num). But we switch to insertion
56 : : sort for CUTOFF elements or less, so we really only need
57 : : 1 + log2(num) - log2(CUTOFF) stack entries. For a CUTOFF
58 : : of 8, that means we need no more than 30 stack entries for
59 : : 32 bit platforms, and 62 for 64-bit platforms. */
60 : : #define STKSIZ (8*sizeof(void*) - 2)
61 : :
62 : :
63 : : /****************************************************************************
64 : : inchi's qsort
65 : : ****************************************************************************/
66 : 338 : void inchi_qsort( void *pParam,
67 : : void *base,
68 : : size_t num,
69 : : size_t width,
70 : : int( *comp )( const void *, const void *, void * ) )
71 : : {
72 : : char *lo, *hi; /* ends of sub-array currently sorting */
73 : : char *mid; /* points to middle of subarray */
74 : : char *loguy, *higuy; /* traveling pointers for partition step */
75 : : size_t size; /* size of the sub-array */
76 : : char *lostk[STKSIZ], *histk[STKSIZ];
77 : : int stkptr; /* stack for saving sub-array to be processed */
78 : :
79 [ + + ]: 338 : if (num < 2)
80 : 26 : return; /* nothing to do */
81 : :
82 : 312 : stkptr = 0; /* initialize stack */
83 : :
84 : 312 : lo = (char *) base;
85 : 312 : hi = (char *) base + width * ( num - 1 ); /* initialize limits */
86 : :
87 : : /* This entry point is for pseudo-recursion calling: setting
88 : : lo and hi and jumping to here is like recursion, but stkptr is
89 : : preserved, locals aren't, so we preserve stuff on the stack */
90 : 1347 : recurse:
91 : :
92 : 1659 : size = ( hi - lo ) / width + 1; /* number of el's to sort */
93 : :
94 : : /* First we pick a partitioning element. The efficiency of the
95 : : algorithm demands that we find one that is approximately the median
96 : : of the values, but also that we select one fast. We choose the
97 : : median of the first, middle, and last elements, to avoid bad
98 : : performance in the face of already sorted data, or data that is made
99 : : up of multiple sorted runs appended together. Testing shows that a
100 : : median-of-three algorithm provides better performance than simply
101 : : picking the middle element for the latter case. */
102 : :
103 : 1659 : mid = lo + ( size / 2 ) * width; /* find middle element */
104 : :
105 : : /* Sort the first, middle, last elements into order */
106 [ + + ]: 1659 : if (comp( lo, mid, pParam ) > 0)
107 : : {
108 : 137 : inchi_swap( lo, mid, width );
109 : : }
110 [ + + ]: 1659 : if (comp( lo, hi, pParam ) > 0)
111 : : {
112 : 77 : inchi_swap( lo, hi, width );
113 : : }
114 [ + + ]: 1659 : if (comp( mid, hi, pParam ) > 0)
115 : : {
116 : 204 : inchi_swap( mid, hi, width );
117 : : }
118 : :
119 : : /* We now wish to partition the array into three pieces, one consisting
120 : : of elements <= partition element, one of elements equal to the
121 : : partition element, and one of elements > than it. This is done
122 : : below; comments indicate conditions established at every step. */
123 : :
124 : 1659 : loguy = lo;
125 : 1659 : higuy = hi;
126 : :
127 : : /* Note that higuy decreases and loguy increases on every iteration,
128 : : so loop must terminate. */
129 : : for (;;)
130 : : {
131 : : /* lo <= loguy < hi, lo < higuy <= hi,
132 : : A[i] <= A[mid] for lo <= i <= loguy,
133 : : A[i] > A[mid] for higuy <= i < hi,
134 : : A[hi] >= A[mid] */
135 : :
136 : : /* The doubled loop is to avoid calling comp(mid,mid), since some
137 : : existing comparison funcs don't work when passed the same
138 : : value for both pointers. */
139 : :
140 [ + + ]: 1840 : if (mid > loguy)
141 : : {
142 : : do
143 : : {
144 : 3493 : loguy += width;
145 : : }
146 [ + + + + ]: 3493 : while (loguy < mid && comp( loguy, mid, pParam ) <= 0);
147 : : }
148 [ + + ]: 1840 : if (mid <= loguy)
149 : : {
150 : : do
151 : : {
152 : 1816 : loguy += width;
153 : : }
154 [ + + + + ]: 1816 : while (loguy <= hi && comp( loguy, mid, pParam ) <= 0);
155 : : }
156 : :
157 : : /* lo < loguy <= hi+1, A[i] <= A[mid] for lo <= i < loguy,
158 : : either loguy > hi or A[loguy] > A[mid] */
159 : :
160 : : do
161 : : {
162 : 3157 : higuy -= width;
163 : : }
164 [ + + + + ]: 3157 : while (higuy > mid && comp( higuy, mid, pParam ) > 0);
165 : :
166 : : /* lo <= higuy < hi, A[i] > A[mid] for higuy < i < hi,
167 : : either higuy == lo or A[higuy] <= A[mid] */
168 : :
169 [ + + ]: 1840 : if (higuy < loguy)
170 : : {
171 : 1659 : break;
172 : : }
173 : :
174 : : /* if loguy > hi or higuy == lo, then we would have exited, so
175 : : A[loguy] > A[mid], A[higuy] <= A[mid],
176 : : loguy <= hi, higuy > lo */
177 : :
178 : 181 : inchi_swap( loguy, higuy, width );
179 : :
180 : : /* If the partition element was moved, follow it. Only need
181 : : to check for mid == higuy, since before the swap,
182 : : A[loguy] > A[mid] implies loguy != mid. */
183 : :
184 [ + + ]: 181 : if (mid == higuy)
185 : : {
186 : 93 : mid = loguy;
187 : : }
188 : :
189 : : /* A[loguy] <= A[mid], A[higuy] > A[mid]; so condition at top
190 : : of loop is re-established */
191 : : }
192 : :
193 : : /* A[i] <= A[mid] for lo <= i < loguy,
194 : : A[i] > A[mid] for higuy < i < hi,
195 : : A[hi] >= A[mid]
196 : : higuy < loguy
197 : : implying:
198 : : higuy == loguy-1
199 : : or higuy == hi - 1, loguy == hi + 1, A[hi] == A[mid] */
200 : :
201 : : /* Find adjacent elements equal to the partition element. The
202 : : doubled loop is to avoid calling comp(mid,mid), since some
203 : : existing comparison funcs don't work when passed the same value
204 : : for both pointers. */
205 : :
206 : 1659 : higuy += width;
207 [ + + ]: 1659 : if (mid < higuy)
208 : : {
209 : : do
210 : : {
211 : 1140 : higuy -= width;
212 : : }
213 [ + + - + ]: 1140 : while (higuy > mid && comp( higuy, mid, pParam ) == 0);
214 : : }
215 [ + + ]: 1659 : if (mid >= higuy)
216 : : {
217 : : do
218 : : {
219 : 1568 : higuy -= width;
220 : : }
221 [ + + - + ]: 1568 : while (higuy > lo && comp( higuy, mid, pParam ) == 0);
222 : : }
223 : :
224 : : /* OK, now we have the following:
225 : : higuy < loguy
226 : : lo <= higuy <= hi
227 : : A[i] <= A[mid] for lo <= i <= higuy
228 : : A[i] == A[mid] for higuy < i < loguy
229 : : A[i] > A[mid] for loguy <= i < hi
230 : : A[hi] >= A[mid] */
231 : :
232 : : /* We've finished the partition, now we want to sort the subarrays
233 : : [lo, higuy] and [loguy, hi].
234 : : We do the smaller one first to minimize stack usage.
235 : : We only sort arrays of length 2 or more.*/
236 : :
237 [ + + ]: 1659 : if (higuy - lo >= hi - loguy)
238 : : {
239 [ + + ]: 1569 : if (lo < higuy)
240 : : {
241 : 804 : lostk[stkptr] = lo;
242 : 804 : histk[stkptr] = higuy;
243 : 804 : ++stkptr;
244 : : } /* save big recursion for later */
245 : :
246 [ + + ]: 1569 : if (loguy < hi)
247 : : {
248 : 424 : lo = loguy;
249 : 424 : goto recurse; /* do small recursion */
250 : : }
251 : : }
252 : : else
253 : : {
254 [ + - ]: 90 : if (loguy < hi)
255 : : {
256 : 90 : lostk[stkptr] = loguy;
257 : 90 : histk[stkptr] = hi;
258 : 90 : ++stkptr; /* save big recursion for later */
259 : : }
260 : :
261 [ + + ]: 90 : if (lo < higuy)
262 : : {
263 : 29 : hi = higuy;
264 : 29 : goto recurse; /* do small recursion */
265 : : }
266 : : }
267 : :
268 : : /* We have sorted the array, except for any pending sorts on the stack.
269 : : Check if there are any, and do them. */
270 : :
271 : 1206 : --stkptr;
272 [ + + ]: 1206 : if (stkptr >= 0)
273 : : {
274 : 894 : lo = lostk[stkptr];
275 : 894 : hi = histk[stkptr];
276 : 894 : goto recurse; /* pop subarray from stack */
277 : : }
278 : : else
279 : : {
280 : 312 : return; /* all subarrays done */
281 : : }
282 : : }
283 : :
284 : :
285 : : /****************************************************************************/
286 : 3422 : void inchi_swap( char *a, char *b, size_t width )
287 : : {
288 : : char tmp;
289 [ + - ]: 3422 : if (a != b)
290 : : {
291 [ + + ]: 11628 : while (width--)
292 : : {
293 : 8206 : tmp = *a;
294 : 8206 : *a++ = *b;
295 : 8206 : *b++ = tmp;
296 : : }
297 : : }
298 : 3422 : }
299 : :
300 : :
301 : : /****************************************************************************
302 : : Sort by insertions
303 : : ****************************************************************************/
304 : 3363 : int insertions_sort( void *pCG,
305 : : void *base,
306 : : size_t num, size_t width,
307 : : int( *compare )( const void *, const void *, void * ) ) /* djb-rwth: types of variables are sufficient */
308 : : {
309 : 3363 : char *i, *j, *pk = (char*) base;
310 : 3363 : int num_trans = 0;
311 : : size_t k;
312 [ + + ]: 10617 : for (k = 1; k < num; k++, pk += width)
313 : : {
314 : : /*for( i = pk, j = pk + width; j > (char*)base && (*compare)(i,j) > 0; j=i, i -= width )*/
315 : 7254 : for (i = j = pk + width;
316 [ + + + + ]: 9839 : j > ( char* )base && ( i -= width, ( *compare )( i, j, pCG ) ) > 0;
317 : 2585 : j = i) /* changed to keep BoundsChecker happy 2007-09-24 DT */
318 : : {
319 : 2585 : inchi_swap( i, j, width );
320 : 2585 : num_trans++;
321 : : }
322 : : }
323 : :
324 : 3363 : return num_trans;
325 : : }
326 : :
327 : :
328 : : /****************************************************************************
329 : : Sort by insertions
330 : : ****************************************************************************/
331 : 108 : int insertions_sort_AT_NUMBERS( void *pCG,
332 : : AT_NUMB *base,
333 : : int num,
334 : : int( *compare )( const void *e1, const void *e2, void * ) )
335 : : {
336 : : AT_NUMB *i, *j, *pk, tmp;
337 : 108 : int k, num_trans = 0;
338 [ + + ]: 244 : for (k = 1, pk = base; k < num; k++, pk++)
339 : : {
340 [ + + + + ]: 163 : for (j = ( i = pk ) + 1, tmp = *j; j > base && ( *compare )( i, &tmp, pCG ) > 0; j = i, i--)
341 : : {
342 : 27 : *j = *i;
343 : 27 : num_trans++;
344 : : }
345 : 136 : *j = tmp;
346 : : }
347 : :
348 : 108 : return num_trans;
349 : : }
350 : :
351 : :
352 : : /****************************************************************************
353 : : Sort neighbors according to ranks in ascending order
354 : : ****************************************************************************/
355 : 1512 : void insertions_sort_NeighList_AT_NUMBERS( NEIGH_LIST base, AT_RANK *nRank )
356 : : {
357 : : AT_NUMB *i, *j, *pk, tmp;
358 : : AT_RANK rj; /* optimization */
359 : 1512 : int k, num = (int) *base++;
360 [ + + ]: 4135 : for (k = 1, pk = base; k < num; k++, pk++)
361 : : {
362 [ + + + + ]: 2966 : for (j = ( i = pk ) + 1, rj = nRank[(int) *j]; j > base && nRank[(int) *i] > rj; j = i, i--)
363 : : {
364 : 343 : tmp = *i;
365 : 343 : *i = *j;
366 : 343 : *j = tmp;
367 : : }
368 : : }
369 : 1512 : }
370 : :
371 : :
372 : : /****************************************************************************
373 : : Sort neighbors according to ranks in ascending order
374 : : ****************************************************************************/
375 : 0 : int insertions_sort_AT_RANK( AT_RANK *base, int num )
376 : : {
377 : : AT_RANK *i, *j, *pk, tmp;
378 : 0 : int k, num_trans = 0;
379 [ # # ]: 0 : for (k = 1, pk = base; k < num; k++, pk++)
380 : : {
381 [ # # # # ]: 0 : for (j = ( i = pk ) + 1, tmp = *j; j > base && *i > tmp; j = i, i--)
382 : : {
383 : 0 : *j = *i;
384 : 0 : num_trans++;
385 : : }
386 : 0 : *j = tmp;
387 : : }
388 : :
389 : 0 : return num_trans;
390 : : }
391 : :
392 : :
393 : : /****************************************************************************
394 : : Sort neighbors according to ranks in ascending order
395 : : ****************************************************************************/
396 : 120 : int insertions_sort_NeighList_AT_NUMBERS3( NEIGH_LIST base, AT_RANK *nRank )
397 : : {
398 : : AT_NUMB *i, *j, *pk, tmp;
399 : : AT_RANK rj;
400 : 120 : int k, n, num = (int) *base++;
401 [ + + ]: 292 : for (k = 1, pk = base, n = 0; k < num; k++, pk++)
402 : : {
403 : 172 : for (j = ( i = pk ) + 1, rj = nRank[(int) ( tmp = *j )];
404 [ + + + + ]: 179 : j > base && nRank[(int) *i] > rj;
405 : 7 : j = i, i--)
406 : : {
407 : 7 : *j = *i;
408 : 7 : n++;
409 : : }
410 : 172 : *j = tmp;
411 : : }
412 : :
413 : 120 : return n;
414 : : }
415 : :
416 : :
417 : : /****************************************************************************
418 : : Sort neighbors according to symm. ranks (primary key) and canon.
419 : : ranks (secondary key), in descending order
420 : : ****************************************************************************/
421 : 3258 : void insertions_sort_NeighListBySymmAndCanonRank( NEIGH_LIST base,
422 : : const AT_RANK *nSymmRank,
423 : : const AT_RANK *nCanonRank )
424 : : {
425 : : AT_NUMB *i, *j, *pk, tmp;
426 : : int diff;
427 : 3258 : int k, num = (int) *base++;
428 [ + + ]: 6012 : for (k = 1, pk = base; k < num; k++, pk++)
429 : : {
430 : 2754 : for (j = ( i = pk ) + 1;
431 [ + + ]: 4857 : j > base && /* always j > i */
432 [ + + + + ]: 3639 : ( 0 > ( diff = (int) nSymmRank[(int) *i] - (int) nSymmRank[(int) *j] ) ||
433 [ + - ]: 60 : (!diff && nCanonRank[(int) *i] < nCanonRank[(int) *j]) ); /* djb-rwth: addressing LLVM warning */
434 : 2103 : j = i, i--)
435 : : {
436 : 2103 : tmp = *i;
437 : 2103 : *i = *j;
438 : 2103 : *j = tmp;
439 : : }
440 : : }
441 : :
442 : 3258 : }
443 : :
444 : :
445 : : /****************************************************************************
446 : : *
447 : : * Comparison functions
448 : : *
449 : : ****************************************************************************/
450 : :
451 : :
452 : : /****************************************************************************/
453 : 1952 : int CompNeighborsAT_NUMBER( const void* a1, const void* a2, void *p )
454 : : {
455 : 1952 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
456 : : #ifdef CT_NEIGH_INCREASE
457 : 3904 : return (int) pCG->m_pn_RankForSort[pCG->m_pNeighborsForSort[( int )*(const AT_NUMB*) a1]] -
458 : 1952 : (int) pCG->m_pn_RankForSort[pCG->m_pNeighborsForSort[( int )*(const AT_NUMB*) a2]];
459 : : #else
460 : : return (int) ( (CANON_GLOBALS *) pCG )->m_pn_RankForSort[pNeighborsForSort[( int )*(const AT_NUMB*) a2]] -
461 : : (int) ( (CANON_GLOBALS *) pCG )->m_pn_RankForSort[pNeighborsForSort[( int )*(const AT_NUMB*) a1]];
462 : : #endif
463 : : }
464 : :
465 : :
466 : : /**********************************************************************************/
467 : 741 : int comp_AT_RANK( const void* a1, const void* a2, void *p )
468 : : {
469 : 741 : return ( int )*(const AT_RANK*) a1 - ( int )*(const AT_RANK*) a2;
470 : : }
471 : :
472 : :
473 : : /**********************************************************************************/
474 : : /* Compare for sorting Ranks only */
475 : 1394 : int CompRank( const void* a1, const void* a2, void *p )
476 : : {
477 : 1394 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
478 : 1394 : int ret = (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a1] -
479 : 1394 : (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a2];
480 : :
481 : 1394 : return ret;
482 : : }
483 : :
484 : :
485 : : /**********************************************************************************/
486 : 8028 : int CompRanksOrd( const void* a1, const void* a2, void *p )
487 : : {
488 : : int ret;
489 : 8028 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
490 : 8028 : ret = (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a1] -
491 : 8028 : (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a2];
492 [ + + ]: 8028 : if (!ret)
493 : : {
494 : 1649 : ret = ( int )*(const AT_RANK*) a1 - ( int )*(const AT_RANK*) a2;
495 : : }
496 : :
497 : 8028 : return ret;
498 : : }
499 : :
500 : :
501 : : /**********************************************************************************/
502 : 3116 : int CompAtomInvariants2Only( const void* a1, const void* a2, void *p )
503 : : {
504 : 3116 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
505 : 3116 : const ATOM_INVARIANT2 *pAI1 = pCG->m_pAtomInvariant2ForSort + ( int )*(const AT_RANK*) a1;
506 : 3116 : const ATOM_INVARIANT2 *pAI2 = pCG->m_pAtomInvariant2ForSort + ( int )*(const AT_RANK*) a2;
507 : : int i;
508 [ + + ]: 15047 : for (i = 0; i < AT_INV_BREAK1; i++)
509 : : {
510 [ + + ]: 13431 : if (pAI1->val[i] == pAI2->val[i])
511 : 11931 : continue;
512 : 1500 : return (int) pAI1->val[i] - (int) pAI2->val[i];
513 : : }
514 [ - + ]: 1616 : if (pAI1->iso_sort_key != pAI2->iso_sort_key)
515 : : {
516 [ # # ]: 0 : return ( pAI1->iso_sort_key > pAI2->iso_sort_key ) ? 1 : -1;
517 : : }
518 [ + - ]: 1616 : for (; i < AT_INV_LENGTH; i++)
519 : : {
520 [ - + ]: 1616 : if (pAI1->val[i] != pAI2->val[i])
521 : : {
522 : 0 : continue;
523 : : }
524 : 1616 : return (int) pAI1->val[i] - (int) pAI2->val[i];
525 : : }
526 [ # # ]: 0 : if (pAI1->iso_aux_key != pAI2->iso_aux_key)
527 : : {
528 [ # # ]: 0 : return ( pAI1->iso_aux_key > pAI2->iso_aux_key ) ? 1 : -1;
529 : : }
530 : :
531 : 0 : return 0;
532 : : }
533 : :
534 : :
535 : : /**********************************************************************************/
536 : 2566 : int CompAtomInvariants2( const void* a1, const void* a2, void *p )
537 : : {
538 : : /* Warning: the following line may be compiler implementation dependent */
539 : 2566 : int ret = CompAtomInvariants2Only( a1, a2, p );
540 [ + + ]: 2566 : if (!ret)
541 : : {
542 : 1249 : ret = ( int )*(const AT_RANK*) a1 - ( int )*(const AT_RANK*) a2;
543 : : }
544 : :
545 : 2566 : return ret;
546 : : }
547 : :
548 : :
549 : : /**********************************************************************************/
550 : : /* Compare two elements lexicographically */
551 : 46 : int CompChemElemLex( const void *a1, const void *a2 )
552 : : {
553 : 46 : return memcmp( a1, a2, 2 );
554 : : }
555 : :
556 : :
557 : : /****************************************************************************
558 : : Lexicographic compare
559 : : ****************************************************************************/
560 : 2402 : int CompareNeighListLex( NEIGH_LIST pp1, NEIGH_LIST pp2, const AT_RANK *nRank )
561 : : {
562 : 2402 : int len1 = (int) *pp1++;
563 : 2402 : int len2 = (int) *pp2++;
564 : 2402 : int len = inchi_min( len1, len2 );
565 : 2402 : int diff = 0;
566 : : int ret;
567 : : /* djb-rwth: fixing oss-fuzz issue #25642 */
568 [ + + + + ]: 5718 : while ((len > 0) && !diff)
569 : : {
570 : 3316 : len--;
571 : 3316 : diff = (int)nRank[*pp1++] - (int)nRank[*pp2++];
572 : : };
573 : :
574 [ + + ]: 2402 : ret = diff ? diff : (len1 - len2);
575 : 2402 : return ret;
576 : : }
577 : :
578 : :
579 : : /****************************************************************************
580 : : Lexicographic compare
581 : : ****************************************************************************/
582 : 0 : int CompareNeighListLexUpToMaxRank( NEIGH_LIST pp1, NEIGH_LIST pp2, const AT_RANK *nRank, AT_RANK nMaxAtNeighRank )
583 : : {
584 : 0 : int len1 = (int) *pp1++;
585 : 0 : int len2 = (int) *pp2++;
586 : 0 : int diff = 0;
587 : : int len;
588 [ # # # # ]: 0 : while (0 < len1 && nRank[pp1[len1 - 1]] > nMaxAtNeighRank)
589 : : {
590 : 0 : len1--;
591 : : }
592 [ # # # # ]: 0 : while (0 < len2 && nRank[pp2[len2 - 1]] > nMaxAtNeighRank)
593 : : {
594 : 0 : len2--;
595 : : }
596 : 0 : len = inchi_min( len1, len2 );
597 [ # # # # ]: 0 : while (len-- > 0 && !( diff = (int) nRank[*pp1++] - (int) nRank[*pp2++] ))
598 : : {
599 : : ;
600 : : }
601 : :
602 [ # # ]: 0 : return diff ? diff : ( len1 - len2 );
603 : : }
604 : :
605 : :
606 : : /****************************************************************************/
607 : 2266 : int compare_NeighLists( const NEIGH_LIST *op1, const NEIGH_LIST *op2, void *p )
608 : : {
609 : 2266 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
610 : 2266 : return CompareNeighListLex( *op1, *op2, pCG->m_pn_RankForSort );
611 : : }
612 : :
613 : :
614 : : /****************************************************************************/
615 : 6057 : int CompNeighListRanks( const void* a1, const void* a2, void *p )
616 : : {
617 : 6057 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
618 : : int ret;
619 : 6057 : ret = (int) pCG->m_pn_RankForSort[*( (const AT_RANK*) a1 )] -
620 : 6057 : (int) pCG->m_pn_RankForSort[*( (const AT_RANK*) a2 )];
621 [ + + ]: 6057 : if (!ret)
622 : : {
623 : 2124 : ret = compare_NeighLists( pCG->m_pNeighList_RankForSort + *( (const AT_RANK*) a1 ),
624 : 2124 : pCG->m_pNeighList_RankForSort + *( (const AT_RANK*) a2 ), p );
625 : : }
626 : :
627 : 6057 : return ret;
628 : : }
629 : :
630 : :
631 : : /****************************************************************************/
632 : 142 : int CompNeighLists( const void* a1, const void* a2, void *p )
633 : : {
634 : 142 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
635 : : int ret;
636 : 142 : ret = compare_NeighLists( pCG->m_pNeighList_RankForSort + *( (const AT_RANK*) a1 ),
637 : 142 : pCG->m_pNeighList_RankForSort + *( (const AT_RANK*) a2 ), p );
638 : :
639 : 142 : return ret;
640 : : }
641 : :
642 : :
643 : : /****************************************************************************/
644 : 0 : int CompNeighListsUpToMaxRank( const void* a1, const void* a2, void *p )
645 : : {
646 : 0 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
647 : : int ret;
648 : 0 : ret = CompareNeighListLexUpToMaxRank( pCG->m_pNeighList_RankForSort[*( (const AT_RANK*) a1 )],
649 : 0 : pCG->m_pNeighList_RankForSort[*( (const AT_RANK*) a2 )],
650 : 0 : pCG->m_pn_RankForSort, pCG->m_nMaxAtNeighRankForSort );
651 : :
652 : 0 : return ret;
653 : : }
654 : :
655 : :
656 : : /****************************************************************************/
657 : 3275 : int CompNeighListRanksOrd( const void* a1, const void* a2, void *p )
658 : : {
659 : 3275 : int ret = CompNeighListRanks( a1, a2, p );
660 [ + + ]: 3275 : if (!ret)
661 : : {
662 : 532 : ret = ( int )*( (const AT_RANK*) a1 ) - ( int )*( (const AT_RANK*) a2 ); /* keep original order if identical */
663 : : }
664 : :
665 : 3275 : return ret;
666 : : }
667 : :
668 : :
669 : : /****************************************************************************/
670 : 0 : int CompRanksInvOrd( const void* a1, const void* a2, void *p )
671 : : {
672 : 0 : return ( int )*(const AT_RANK*) a2 - ( int )*(const AT_RANK*) a1;
673 : : }
674 : :
675 : :
676 : : /****************************************************************************/
677 : 0 : int CompNeighborsRanksCountEql( const void* a1, const void* a2, void *p )
678 : : {
679 : 0 : CANON_GLOBALS *pCG = (CANON_GLOBALS *) p;
680 : : #ifdef CT_NEIGH_INCREASE
681 : 0 : int ret = (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a1] -
682 : 0 : (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a2];
683 : : #else
684 : : int ret = (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a2] -
685 : : (int) pCG->m_pn_RankForSort[( int )*(const AT_RANK*) a1];
686 : : #endif
687 : 0 : pCG->m_nNumCompNeighborsRanksCountEql += !ret;
688 : :
689 : 0 : return ret;
690 : : }
691 : :
692 : :
693 : : /****************************************************************************
694 : : *
695 : : * In this neighbor list the (vertex number) = (canonical number) - 1
696 : : * Since LinearCT is sorted so that parents are in ascending order
697 : : * and all neighbors of a parent are smaller than the parent and are
698 : : * in ascending order, the neighbors in the NEIGH_LIST are automatically
699 : : * sorted in ascending order
700 : : ****************************************************************************/
701 : 58 : NEIGH_LIST *CreateNeighListFromLinearCT( AT_NUMB *LinearCT, int nLenCT, int num_atoms )
702 : : {
703 : : /* Atom numbers in LinearCT are canonical numbers
704 : : * order: parent[i] > neigh[i][0] < neigh[i][1]...<neigh[i][n] < parent[i+1] > neigh[i+1][0] < ...
705 : : * parent[i] < parent[i+1]
706 : : */
707 : : int i, j;
708 : 58 : S_CHAR *valence = NULL;
709 : 58 : NEIGH_LIST *pp = NULL;
710 : 58 : AT_NUMB *pAtList = NULL;
711 : : AT_RANK n_vertex, n_neigh;
712 : 58 : int err = 1, num_bonds;
713 : : int length, start;
714 : :
715 [ - + ]: 58 : if ((int) LinearCT[0] > num_atoms)
716 : : {
717 : 0 : goto exit_function;
718 : : }
719 : 58 : valence = (S_CHAR*)inchi_calloc((long long)num_atoms + 1, sizeof(valence[0]));
720 [ - + ]: 58 : if (!valence) /* djb-rwth: cast operator added */
721 : : {
722 : 0 : goto exit_function;
723 : : }
724 : :
725 [ + + ]: 1018 : for (i = 1, num_bonds = 0, n_vertex = LinearCT[0]; i < nLenCT; i++)
726 : : {
727 [ + + ]: 960 : if (( n_neigh = LinearCT[i] ) < n_vertex)
728 : : {
729 : 488 : valence[n_neigh] ++;
730 : 488 : valence[n_vertex] ++;
731 : 488 : num_bonds += 2;
732 : : }
733 : : else
734 : : {
735 [ - + ]: 472 : if ((int) ( n_vertex = n_neigh ) > num_atoms)
736 : : {
737 : 0 : goto exit_function;
738 : : }
739 : : }
740 : : }
741 [ - + ]: 58 : if ((int) n_vertex != num_atoms)
742 : : {
743 : 0 : goto exit_function;
744 : : }
745 : 58 : length = num_bonds + num_atoms + 1;
746 : 58 : pp = (NEIGH_LIST*)inchi_calloc(((long long)num_atoms + 1), sizeof(NEIGH_LIST));
747 : 58 : pAtList = (AT_NUMB*)inchi_malloc(length * sizeof(AT_NUMB));
748 [ - + - + ]: 58 : if (pp && pAtList) /* djb-rwth: cast operator added; addressing LLVM warning */
749 : : {
750 : : /* Create empty connection table */
751 [ + + ]: 588 : for (i = 1, length = 0; i <= num_atoms; i++)
752 : : {
753 : 530 : start = length;
754 : 530 : length += ( valence[i] + 1 );
755 : 530 : pp[i - 1] = pAtList + start;
756 : 530 : pp[i - 1][0] = 0;
757 : : }
758 : : /* Fill out the CT */
759 [ + + ]: 1018 : for (i = 1, n_vertex = LinearCT[0] - 1; i < nLenCT; i++)
760 : : {
761 [ + + ]: 960 : if (( n_neigh = LinearCT[i] - 1 ) < n_vertex)
762 : : {
763 : : /* Vertex - neighbor connection */
764 : 488 : j = (int) ( ++pp[(int) n_vertex][0] );
765 : 488 : pp[(int) n_vertex][j] = n_neigh;
766 : : /* neighbor - vertex connection */
767 : 488 : j = (int) ( ++pp[(int) n_neigh][0] );
768 : 488 : pp[(int) n_neigh][j] = n_vertex;
769 : : }
770 : : else
771 : : {
772 [ - + ]: 472 : if ((int) ( n_vertex = n_neigh ) >= num_atoms)
773 : : {
774 : 0 : goto exit_function;
775 : : }
776 : : }
777 : : }
778 : 58 : err = 0;
779 : : }
780 : :
781 : 0 : exit_function:
782 [ + - ]: 58 : if (valence)
783 : : {
784 [ + - ]: 58 : inchi_free( valence );
785 : : }
786 [ - + ]: 58 : if (err) /* djb-rwth: ignoring LLVM warning */
787 : : {
788 [ # # ]: 0 : if (pAtList)
789 : : {
790 [ # # ]: 0 : inchi_free( pAtList );
791 : : }
792 [ # # ]: 0 : if (pp)
793 : : {
794 [ # # ]: 0 : inchi_free( pp );
795 : 0 : pp = NULL;
796 : : }
797 : : }
798 : :
799 : 58 : return pp; /* djb-rwth: ignoring LLVM warning: since a pointer is returned, memory should be freed in a function which calls *CreateNeighListFromLinearCT */
800 : : }
801 : :
802 : :
803 : : /****************************************************************************
804 : : NEIGH_LIST pp[] is an array of pointers to the lists of neighboring
805 : : atoms numbers. The first number in each list is a number of neighbors.
806 : : In case of bDoubleBondSquare != 0 neighbors connected by the double bond
807 : : appear 2 times. The first element pp[0] is a pointer to be deallocated
808 : : to free all the lists.
809 : : ****************************************************************************/
810 : 393 : NEIGH_LIST *CreateNeighList( int num_atoms,
811 : : int num_at_tg,
812 : : sp_ATOM* at,
813 : : int bDoubleBondSquare,
814 : : T_GROUP_INFO *t_group_info )
815 : : {
816 : : /* +1 to add NULL termination */
817 : 393 : NEIGH_LIST *pp = (NEIGH_LIST *) inchi_calloc( ( (long long)num_at_tg + 1 ), sizeof( NEIGH_LIST ) ); /* djb-rwth: cast operator added */
818 : 393 : T_GROUP *t_group = NULL;
819 : 393 : AT_NUMB *nEndpointAtomNumber = NULL;
820 : 393 : int num_t_groups = 0;
821 : : int nFirstEndpointAtNoPos;
822 : :
823 : 393 : AT_NUMB *pAtList = NULL;
824 : : int length, start, val, i, j;
825 [ + - ]: 393 : if (pp)
826 : : {
827 [ - + ]: 393 : if (num_at_tg > num_atoms)
828 : : {
829 : 0 : t_group = t_group_info->t_group;
830 : 0 : num_t_groups = t_group_info->num_t_groups;
831 : 0 : nEndpointAtomNumber = t_group_info->nEndpointAtomNumber;
832 : : }
833 : :
834 [ + - ]: 393 : if (!bDoubleBondSquare)
835 : : {
836 [ + + ]: 4273 : for (i = 0, length = 0; i < num_atoms; i++)
837 : : {
838 [ - + - - ]: 3880 : length += (int) at[i].valence + ( num_t_groups && at[i].endpoint );
839 : : }
840 : 393 : length += num_atoms;
841 [ - + ]: 393 : for (i = 0; i < num_t_groups; i++)
842 : : {
843 : 0 : length += (int) t_group[i].nNumEndpoints;
844 : : }
845 : 393 : length += num_t_groups;
846 : : }
847 : : else
848 : : {
849 [ # # ]: 0 : for (i = 0, length = 0; i < num_atoms; i++)
850 : : {
851 : 0 : val = (int) at[i].valence;
852 [ # # ]: 0 : for (j = 0; j < val; j++)
853 : : {
854 [ # # # # ]: 0 : length += 1 + ( bDoubleBondSquare && BOND_DOUBLE == at[i].bond_type[j] );
855 : : }
856 [ # # # # ]: 0 : length += ( num_t_groups && at[i].endpoint );
857 : : }
858 : 0 : length += num_atoms;
859 [ # # ]: 0 : for (i = 0; i < num_t_groups; i++)
860 : : {
861 : 0 : length += (int) t_group[i].nNumEndpoints;
862 : : }
863 : 0 : length += num_t_groups;
864 : : }
865 : 393 : length++; /* +1 to save number of neighbors */
866 : 393 : pAtList = (AT_NUMB*)inchi_malloc(length * sizeof(AT_NUMB));
867 [ + - ]: 393 : if (pAtList) /* djb-rwth: addressing LLVM warning */
868 : : {
869 [ + - ]: 393 : if (!bDoubleBondSquare)
870 : : {
871 [ + + ]: 4273 : for (i = 0, length = 0; i < num_atoms; i++)
872 : : {
873 : 3880 : val = at[i].valence;
874 : 3880 : start = length++;
875 [ + + ]: 11026 : for (j = 0; j < val; j++)
876 : : {
877 : 7146 : pAtList[length++] = at[i].neighbor[j];
878 : : }
879 : : /* add endpoint */
880 [ - + - - ]: 3880 : if (num_t_groups && at[i].endpoint)
881 : : {
882 : 0 : pAtList[length++] = num_atoms + (int) at[i].endpoint - 1;
883 : : }
884 : 3880 : pAtList[start] = length - start - 1; /* number of neighbors before the list of neighbors */
885 : 3880 : pp[i] = pAtList + start; /* pointer to the <num.neigh.><list of neigh> */
886 : : }
887 : : }
888 : : else
889 : : {
890 [ # # ]: 0 : for (i = 0, length = 0; i < num_atoms; i++)
891 : : {
892 : 0 : val = at[i].valence;
893 : 0 : start = length++;
894 [ # # ]: 0 : for (j = 0; j < val; j++)
895 : : {
896 : 0 : pAtList[length++] = at[i].neighbor[j]; /* djb-rwth: buffer overrun avoided implicitly */
897 [ # # # # ]: 0 : if (bDoubleBondSquare && BOND_DOUBLE == at[i].bond_type[j])
898 : : {
899 : 0 : pAtList[length++] = at[i].neighbor[j]; /* a list of neighbor orig. numbers */
900 : : }
901 : : }
902 : : /* Add endpoint */
903 [ # # # # ]: 0 : if (num_t_groups && at[i].endpoint)
904 : : {
905 : 0 : pAtList[length++] = num_atoms + (int) at[i].endpoint - 1;
906 : : }
907 : 0 : pAtList[start] = length - start - 1; /* number of neighbors before the list of neighbors */
908 : 0 : pp[i] = pAtList + start; /* pointer to the <num.neigh.><list of neigh> */
909 : : }
910 : : }
911 : :
912 : : /* Add t-groups */
913 [ - + ]: 393 : for (i = 0; i < num_t_groups; i++)
914 : : {
915 : 0 : val = (int) t_group[i].nNumEndpoints;
916 : 0 : start = length++;
917 : 0 : nFirstEndpointAtNoPos = (int) t_group[i].nFirstEndpointAtNoPos;
918 [ # # ]: 0 : for (j = 0; j < val; j++)
919 : : {
920 : 0 : pAtList[length++] = nEndpointAtomNumber[nFirstEndpointAtNoPos + j];
921 : : }
922 : 0 : pAtList[start] = length - start - 1; /* number of neighbors before the list of neighbors */
923 : 0 : pp[num_atoms + i] = pAtList + start; /* pointer to the <num.neigh.><list of neigh> */
924 : : }
925 : : }
926 : : else
927 : : {
928 [ # # ]: 0 : inchi_free(pAtList); /* djb-rwth: fixing coverity ID #499598 */
929 [ # # ]: 0 : inchi_free( pp );
930 : 0 : return NULL;
931 : : }
932 : : } /* djb-rwth: ignoring LLVM warning */
933 : :
934 : : /* djb-rwth: fixing coverity ID #499598 -- pp uses pAtList values */
935 : :
936 : 393 : return pp; /* djb-rwth: ignoring LLVM warning: since a pointer is returned, memory should be freed in a function which calls *CreateNeighList */
937 : : }
938 : :
939 : :
940 : : /****************************************************************************/
941 : 793 : void FreeNeighList( NEIGH_LIST *pp )
942 : : {
943 [ + + ]: 793 : if (pp)
944 : : {
945 [ + - ]: 451 : if (pp[0])
946 : : {
947 [ + - ]: 451 : inchi_free( pp[0] );
948 : : }
949 [ + - ]: 451 : inchi_free( pp );
950 : : }
951 : :
952 : 793 : }
953 : :
954 : :
955 : : /****************************************************************************/
956 : 214 : int BreakAllTies( CANON_GLOBALS *pCG,
957 : : int num_atoms,
958 : : int num_max,
959 : : AT_RANK **pRankStack,
960 : : NEIGH_LIST *NeighList,
961 : : AT_RANK *nTempRank,
962 : : CANON_STAT *pCS )
963 : : {
964 : 214 : int i, nRet = -1, nNumRanks = 1 /* value does not matter*/;
965 : :
966 : 214 : AT_RANK *nPrevRank = *pRankStack++;
967 : 214 : AT_RANK *nPrevAtomNumber = *pRankStack++;
968 : :
969 : 214 : AT_RANK *nNewRank = NULL;
970 : 214 : AT_RANK *nNewAtomNumber = NULL;
971 : :
972 [ + + ]: 214 : if (!pRankStack[0])
973 : : {
974 : 96 : pRankStack[0] = (AT_RANK *) inchi_malloc( num_max * sizeof( *nNewRank ) );
975 : : }
976 [ + + ]: 214 : if (!pRankStack[1])
977 : : {
978 : 96 : pRankStack[1] = (AT_RANK *) inchi_malloc( num_max * sizeof( *nNewAtomNumber ) );
979 : : }
980 [ + - - + ]: 214 : if (!pRankStack[0] || !pRankStack[1])
981 : : {
982 : 0 : return CT_OUT_OF_RAM; /* <BRKPT> */
983 : : }
984 : 214 : nNewRank = pRankStack[0];
985 : 214 : nNewAtomNumber = pRankStack[1];
986 : :
987 [ + - + - ]: 214 : if (nNewRank && nNewAtomNumber)
988 : : {
989 : 214 : memcpy(nNewAtomNumber, nPrevAtomNumber, num_atoms * sizeof(nNewAtomNumber[0]));
990 : 214 : memcpy(nNewRank, nPrevRank, num_atoms * sizeof(nNewRank[0]));
991 [ + + ]: 2172 : for (i = 1, nRet = 0; i < num_atoms; i++)
992 : : {
993 : : /* 12-12-2001: replaced Prev... with New... */
994 [ + + ]: 1958 : if (nNewRank[(int) nNewAtomNumber[i - 1]] == nNewRank[(int) nNewAtomNumber[i]])
995 : : {
996 : 38 : nNewRank[nNewAtomNumber[i - 1]] = (AT_RANK) i;
997 : 38 : nNumRanks = DifferentiateRanks2( pCG, num_atoms, NeighList,
998 : : nNumRanks, nNewRank, nTempRank,
999 : : nNewAtomNumber,
1000 : : &pCS->lNumNeighListIter, 1 );
1001 : 38 : pCS->lNumBreakTies++;
1002 : 38 : nRet++;
1003 : : }
1004 : : }
1005 : : }
1006 : :
1007 : 214 : return nRet;
1008 : : }
1009 : :
1010 : :
1011 : : /****************************************************************************
1012 : : Int insertions sort
1013 : : ****************************************************************************/
1014 : 0 : int * iisort( int *list, int num )
1015 : : {
1016 : : int i;
1017 [ # # ]: 0 : for (i = 1; i < num; i++)
1018 : : {
1019 : 0 : int tmp = list[i];
1020 : 0 : int j = i - 1;
1021 [ # # # # ]: 0 : while (j >= 0 && list[j] > tmp)
1022 : : {
1023 : 0 : list[j + 1] = list[j];
1024 : 0 : j--;
1025 : : }
1026 : 0 : list[j + 1] = tmp;
1027 : : }
1028 : :
1029 : 0 : return list;
1030 : : }
|