2
* International Chemical Identifier (InChI)
4
* Software version 1.02-beta
8
* The InChI library and programs are free software developed under the
9
* auspices of the International Union of Pure and Applied Chemistry (IUPAC);
10
* you can redistribute this software and/or modify it under the terms of
11
* the GNU Lesser General Public License as published by the Free Software
13
* http://www.opensource.org/licenses/lgpl-license.php
34
/**************************************************************************************/
35
/* Check if all equivalent to cr1 possibly stereogenic atoms: */
36
/* 1) have KNOWN parity, and */
37
/* 2) their parities are same */
38
/**************************************************************************************/
39
int All_SC_Same( AT_RANK canon_rank1, /* canonical number */
40
const ppAT_RANK pRankStack1, const ppAT_RANK pRankStack2,
41
const AT_RANK *nAtomNumberCanonFrom,
44
int n1 = (int)nAtomNumberCanonFrom[(int)canon_rank1-1];
45
AT_RANK r1 = pRankStack1[0][n1];
48
int bFound=0, stereo_atom_parity=-1;
50
/* find one stereo atom such that canon_rank1 can be mapped on it */
51
for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
52
if ( at[s1].stereo_bond_neighbor[0] ) {
53
bFound=0; /* at[s1] is not sp3-stereogenic: it belongs to a stereobond */
57
stereo_atom_parity = PARITY_VAL(at[s1].stereo_atom_parity);
58
if ( !ATOM_PARITY_KNOWN(stereo_atom_parity) ) {
59
bFound=0; /* at[s1] does not have a KNOWN parity */
63
if ( stereo_atom_parity != PARITY_VAL(at[s1].stereo_atom_parity) ) {
64
bFound=0; /* two equivalent atoms have different parities */
71
/**************************************************************************************/
72
/* get next available (not mapped yet) rank for a stereo center atom */
73
int Next_SC_At_CanonRank2( AT_RANK *canon_rank1, /* 1st call input: largest canon number mapped so far or 0 */
74
/* output: suggested canon. rank > than input if success */
75
AT_RANK *canon_rank1_min, /* 1st call:0 next calls: first tried canon. number */
76
int *bFirstTime, /* 1 at the time of the 1st call */
77
S_CHAR *bAtomUsedForStereo, /* STEREO_AT_MARK if the atom has not been mapped yet */
78
const ppAT_RANK pRankStack1, /* mapping ranks/sort order of atoms with canon. numbers (from) */
79
const ppAT_RANK pRankStack2, /* mapping ranks/sort order of atoms with stereo (to) */
80
const AT_RANK *nAtomNumberCanonFrom, /* sorted order of the canon. numbers */
83
AT_RANK canon_rank1_inp = *canon_rank1;
84
AT_RANK cr1; /* canonical rank (canonical number) */
85
AT_RANK r1; /* mapping rank */
86
int n1; /* ord. number of an atom with the canon. number */
87
int s1; /* ord. number of an atom with stereo */
91
if ( canon_rank1_inp < *canon_rank1_min ) {
92
canon_rank1_inp = *canon_rank1_min;
94
if ( canon_rank1_inp < 1 ) {
97
canon_rank1_inp ++; /* next canonical rank */
99
cr1 = canon_rank1_inp;
101
while ( (int) cr1 <= num_atoms ) {
102
n1 = (int)nAtomNumberCanonFrom[(int)cr1-1]; /* atom1 (which has canon. rank cr1) ord. number */
103
iMax1 = (int)(r1 = pRankStack1[0][n1]); /* mapping rank of atom1 */
104
/* find atoms "to" to which the canon. number can be mapped; they have mapping rank r1, number s1 */
105
for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
106
/* looking for a stereo center atom that has mapping rank r1 */
107
if ( bAtomUsedForStereo[s1] == STEREO_AT_MARK ) {
108
/* found a sterogenic atom that has not been mapped yet */
114
/* one stereogenic not mapped yet atom "to" has been found */
116
*canon_rank1_min = cr1;
121
/* a not mapped yet stereogenic atom has not found */
122
/* for the mapping rank r1 defined by the canonical rank cr1; try next cr1 */
133
/**********************************************************************/
134
int CompareLinCtStereoDble ( AT_STEREO_DBLE *LinearCTStereoDble1, int nLenLinearCTStereoDble1,
135
AT_STEREO_DBLE *LinearCTStereoDble2, int nLenLinearCTStereoDble2 )
139
/* compare double bonds */
140
if ( LinearCTStereoDble1 && LinearCTStereoDble2 ) {
141
num = inchi_min(nLenLinearCTStereoDble1, nLenLinearCTStereoDble2);
142
for ( i = 0; i < num; i ++ ) {
143
if ( ret = (int)LinearCTStereoDble1[i].at_num1 - (int)LinearCTStereoDble2[i].at_num1 )
145
if ( ret = (int)LinearCTStereoDble1[i].at_num2 - (int)LinearCTStereoDble2[i].at_num2 )
147
if ( ret = (int)LinearCTStereoDble1[i].parity - (int)LinearCTStereoDble2[i].parity )
151
ret = nLenLinearCTStereoDble1 - nLenLinearCTStereoDble2;
154
if ( LinearCTStereoDble1 && nLenLinearCTStereoDble1 > 0 ) {
157
if ( LinearCTStereoDble2 && nLenLinearCTStereoDble2 > 0 ) {
162
/**********************************************************************/
163
int CompareLinCtStereoCarb ( AT_STEREO_CARB *LinearCTStereoCarb1, int nLenLinearCTStereoCarb1,
164
AT_STEREO_CARB *LinearCTStereoCarb2, int nLenLinearCTStereoCarb2 )
168
/* compare stereocenters */
169
if ( LinearCTStereoCarb1 && LinearCTStereoCarb2 ) {
170
num = inchi_min(nLenLinearCTStereoCarb1, nLenLinearCTStereoCarb2);
171
for ( i = 0; i < num; i ++ ) {
172
if ( ret = (int)LinearCTStereoCarb1[i].at_num - (int)LinearCTStereoCarb2[i].at_num )
174
if ( ret = (int)LinearCTStereoCarb1[i].parity - (int)LinearCTStereoCarb2[i].parity )
178
ret = nLenLinearCTStereoCarb1 - nLenLinearCTStereoCarb2;
181
if ( LinearCTStereoCarb1 && nLenLinearCTStereoCarb1 > 0 ) {
184
if ( LinearCTStereoCarb2 && nLenLinearCTStereoCarb2 > 0 ) {
190
/**********************************************************************/
191
int CompareLinCtStereo ( AT_STEREO_DBLE *LinearCTStereoDble1, int nLenLinearCTStereoDble1,
192
AT_STEREO_CARB *LinearCTStereoCarb1, int nLenLinearCTStereoCarb1,
193
AT_STEREO_DBLE *LinearCTStereoDble2, int nLenLinearCTStereoDble2,
194
AT_STEREO_CARB *LinearCTStereoCarb2, int nLenLinearCTStereoCarb2 )
198
/* compare double bonds */
199
ret = CompareLinCtStereoDble ( LinearCTStereoDble1, nLenLinearCTStereoDble1,
200
LinearCTStereoDble2, nLenLinearCTStereoDble2 );
202
ret = CompareLinCtStereoCarb ( LinearCTStereoCarb1, nLenLinearCTStereoCarb1,
203
LinearCTStereoCarb2, nLenLinearCTStereoCarb2 );
207
/**************************************************************************************/
208
int CompareLinCtStereoAtomToValues( AT_STEREO_CARB *LinearCTStereoCarb,
209
AT_RANK at_rank_canon1, U_CHAR parity )
211
if ( LinearCTStereoCarb->at_num CT_GREATER_THAN at_rank_canon1 )
213
if ( LinearCTStereoCarb->at_num != at_rank_canon1 )
215
if ( LinearCTStereoCarb->parity CT_GREATER_THAN parity )
217
if ( LinearCTStereoCarb->parity != parity )
221
/**************************************************************************************/
222
/* Find atom number from the mapping rank and return 1, or */
223
/* if the mapping rank is tied and the atom number is not unique then return 0 */
224
int bUniqueAtNbrFromMappingRank( AT_RANK **pRankStack, AT_RANK nAtRank, AT_NUMB *nAtNumber )
226
int r = (int)nAtRank-1;
227
AT_NUMB i = pRankStack[1][r];
228
if ( nAtRank == pRankStack[0][(int)i] &&
229
(!r || nAtRank != pRankStack[0][pRankStack[1][r-1]])
236
/**************************************************************************************/
237
/* Get minimal set (class) representative and partially compress the partitioning */
238
/* mcr = minimal class representative. */
239
AT_RANK nGetMcr( AT_RANK *nEqArray, AT_RANK n )
241
AT_RANK n1, n2, mcr; /* recursive version is much shorter. */
247
/* 1st pass: find mcr */
248
while ( n1 != (n2=nEqArray[(int)n1])) {
251
/* 2nd pass: copy mcr to each element of the set starting from nEqArray[n] */
254
while ( /*n1*/ mcr != (n2=nEqArray[(int)n1]) ) {
255
nEqArray[(int)n1]=mcr;
260
/**************************************************************************************/
261
/* Join 2 sets (classes) that have members n1 and n2 */
262
int nJoin2Mcrs( AT_RANK *nEqArray, AT_RANK n1, AT_RANK n2 )
264
n1 = nGetMcr( nEqArray, n1 );
265
n2 = nGetMcr( nEqArray, n2 );
268
return 1; /* a change has been made */
272
return 1; /* a change has been made */
274
return 0; /* no changes */
277
/*********************************************************************************
278
* For all pairs of atoms that are: *
279
* (a) connected by a possibly stereogenic bond *
280
* (b) "equivalent" at this point to canon_rank1-canon_rank2 : *
282
* 1) are connected by a stereo bond or cumulene bonds of the same length *
283
* 2) have KNOWN parity, and *
284
* 3) their parities are same *
285
*********************************************************************************/
286
int All_SB_Same( AT_RANK canon_rank1, AT_RANK canon_rank2, /* canonical numbers */
287
const ppAT_RANK pRankStack1, const ppAT_RANK pRankStack2,
288
const AT_RANK *nAtomNumberCanonFrom, sp_ATOM *at )
290
int n1 = (int)nAtomNumberCanonFrom[(int)canon_rank1-1]; /* at1 has canon_rank1 */
291
int n2 = (int)nAtomNumberCanonFrom[(int)canon_rank2-1]; /* at2 has canon_rank2 */
292
AT_RANK r1 = pRankStack1[0][n1]; /* at1 mapping rank */
293
AT_RANK r2 = pRankStack1[0][n2]; /* at2 mapping rank */
294
AT_RANK rNeigh1, rNeigh2;
296
/* int iMax2 = (int)r2; */
297
int i1, i2, s1, s2, k1, k2, m, k, num_equal;
298
int bNotFound=1, cumulene_len, stereo_bond_parity;
300
/* at the first atom that possibly may have canon_rank1 find one stereo bond such that */
301
/* canon_rank1-canon_rank2 possibly may be mapped on it */
302
for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
303
/* at[n1] may be possible to map on at[s1] */
304
for ( k1 = 0, s2= 0, bNotFound=1;
305
k1 < MAX_NUM_STEREO_BONDS && (s2=(int)at[s1].stereo_bond_neighbor[k1]) &&
306
(bNotFound = (r2 != pRankStack2[0][--s2])); k1 ++ )
307
; /* continue until the 1st at[s2] (to which at[n2] may be mapped) have been found */
309
break; /* stop at 1st found */
313
return -1; /* error: no mapping exists */
315
for ( k2 = 0, m = 0; k2 < MAX_NUM_STEREO_BONDS && (m=(int)at[s2].stereo_bond_neighbor[k2]) && m-1 != s1; k2 ++ )
318
return -1; /* program error: stereo bond in opposite direction not found */
320
stereo_bond_parity = at[s1].stereo_bond_parity[k1];
321
if ( !PARITY_KNOWN(stereo_bond_parity) ) {
324
cumulene_len = BOND_CHAIN_LEN(stereo_bond_parity);
325
rNeigh1 = pRankStack2[0][(int)at[s1].neighbor[(int)at[s1].stereo_bond_ord[k1]]];
326
rNeigh2 = pRankStack2[0][(int)at[s2].neighbor[(int)at[s2].stereo_bond_ord[k2]]];
329
/* Search among ALL neighbors because sometimes a stereo bond may be mapped on a non-stereo bond. */
330
/* If is so then return 0: not all mappings are stereo-equivalent */
331
for ( s1 = 1; s1 <= iMax1 && r1 == pRankStack2[0][i1=(int)pRankStack2[1][iMax1-s1]]; s1++ ) {
332
for ( k = 0; k < at[i1].valence; k ++ ) {
333
n1 = at[i1].neighbor[k];
334
if ( rNeigh1 != pRankStack2[0][n1] ) {
335
continue; /* wrong neighbor */
337
if ( cumulene_len ) {
338
int prev, next, len, j;
339
for ( prev=i1, len=0, next = n1; len < cumulene_len; len ++ ) {
340
if ( at[next].valence == 2 && !at[next].num_H ) {
341
j = ((int)at[next].neighbor[0] == prev);
343
next = at[next].neighbor[j];
345
break; /* cannot continue */
348
if ( len != cumulene_len ||
349
r2 != pRankStack2[0][next] ||
350
rNeigh2 != pRankStack2[0][prev] ) {
351
/* cumulene chain not found */
358
/* find if a stereogenic bond between at[i1]-at[i2] exists */
359
for ( k1 = 0; k1 < MAX_NUM_STEREO_BONDS &&
360
(m=(int)at[i1].stereo_bond_neighbor[k1]) && m-1 != i2; k1 ++ )
365
for ( k2 = 0; k2 < MAX_NUM_STEREO_BONDS &&
366
(m=(int)at[i2].stereo_bond_neighbor[k2]) && m-1 != i1; k2 ++ )
371
if ( at[i1].stereo_bond_parity[k1] != at[i2].stereo_bond_parity[k2] ) {
372
return -1; /* program error */
374
if ( stereo_bond_parity != at[i1].stereo_bond_parity[k1] ) {
383
/**************************************************************************************/
384
/* get min. ranks for the stereo bond atoms */
385
int Next_SB_At_CanonRanks2( AT_RANK *canon_rank1, AT_RANK *canon_rank2, /* canonical numbers */
386
AT_RANK *canon_rank1_min, AT_RANK *canon_rank2_min,
387
int *bFirstTime, S_CHAR *bAtomUsedForStereo,
388
const ppAT_RANK pRankStack1, const ppAT_RANK pRankStack2,
389
const AT_RANK *nCanonRankFrom, const AT_RANK *nAtomNumberCanonFrom,
390
const sp_ATOM *at, int num_atoms, int bAllene )
392
AT_RANK canon_rank1_inp = *canon_rank1;
393
AT_RANK canon_rank2_inp = *canon_rank2;
394
AT_RANK cr1, cr2; /* canonical ranks (canonical numbers) */
395
AT_RANK r1, r2; /* mapping ranks */
396
int n1, n2; /* ord. numbers of atoms with stereo */
397
int s1, s2; /* ord. numbers of atoms with canon. numbers */
401
if ( canon_rank1_inp < *canon_rank1_min ||
402
canon_rank1_inp == *canon_rank1_min &&
403
canon_rank2_inp < *canon_rank2_min ) {
405
canon_rank1_inp = *canon_rank1_min;
406
canon_rank2_inp = *canon_rank2_min;
408
if ( canon_rank1_inp < 2 ) {
412
cr1 = canon_rank1_inp;
413
cr2 = num_atoms; /* initialize. 1/8/2002 */
414
while ( (int) cr1 <= num_atoms ) {
416
n1 = (int)nAtomNumberCanonFrom[(int)cr1-1]; /* atom1=at[n1] (which has canon. rank) ord. number */
417
iMax1 = (int)(r1 = pRankStack1[0][n1]); /* mapping rank of atom1 */
418
for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
419
/* looking for a stereo bond atom that has mapping rank r1 */
420
/* found at[s1] such that rank cr1 can be mapped on at[s1] because cr1 and s1 have equal */
421
/* mapping rank = r1. Check at[s1] stereo bonds */
422
if ( bAtomUsedForStereo[s1] && bAtomUsedForStereo[s1] < STEREO_AT_MARK ) {
423
for ( k = 0, s2 = 0; k < MAX_NUM_STEREO_BONDS && (s2=(int)at[s1].stereo_bond_neighbor[k]); k ++ ) {
424
/* stereo bond at[s1]-at[s2] has been found */
425
if ( bAtomUsedForStereo[--s2] ) {
426
/* stereo bonds have not been mapped. however, this check is not needed */
427
int cumulene_len = BOND_CHAIN_LEN(at[s1].stereo_bond_parity[k]);
428
if ( cumulene_len%2 && !bAllene || /* 09-26-2003 */
429
!(cumulene_len%2) && bAllene ) { /* 08-17-2003 Fix05 */
432
iMax2 = (int)(r2 = pRankStack2[0][s2]); /* mapping rank of atom2 */
433
/* Go back to canonical ranks and find an atom that has mapping rank r2 */
434
/* and is connected to the atom with canonical rank cr1 (possibly by cumulene chain) */
435
/* These cr1-cr2 canon. ranks possibly can be mapped on at[s1]-at[s2] stereo bond */
436
for ( i2 = 1; i2 <= iMax2 && r2 == pRankStack1[0][n2=(int)pRankStack1[1][iMax2-i2]]; i2++ ) {
437
if ( cumulene_len ) {
438
int prev, next, len, j;
439
for ( m = 0; m < at[n1].valence; m ++ ) {
440
for ( prev=n1, len=0, next = (int)at[n1].neighbor[m]; len < cumulene_len; len ++ ) {
441
if ( at[next].valence == 2 && !at[next].num_H ) {
442
j = ((int)at[next].neighbor[0] == prev);
444
next = at[next].neighbor[j];
446
break; /* cannot continue */
449
if ( len == cumulene_len && n2 == next ) {
454
for ( m = 0; m < at[n1].valence && n2 != (int)at[n1].neighbor[m]; m ++ )
457
if ( m < at[n1].valence &&
458
nCanonRankFrom[n2] < cr2 &&
459
nCanonRankFrom[n2] > canon_rank2_inp ) {
461
cr2 = nCanonRankFrom[n2]; /* found a candidate for cr2 */
469
/* not found for this r1 */
473
/* found cr2 < cr1 */
475
*canon_rank1_min = cr1;
476
*canon_rank2_min = cr2;
482
if ( cr1 > cr2 && cr1 <= num_atoms ) {
490
/******************************************************************************************/
491
int NextStereoParity2Test( int *stereo_bond_parity, int *sb_parity_calc,
492
int nNumBest, int nNumWorse, int nNumUnkn, int nNumUndf, int nNumCalc)
494
/* sequence of (stereo_bond_parity, sb_parity_calc) pairs:
496
(BEST_PARITY, BEST_PARITY) <calc>
498
(BEST_PARITY, WORSE_PARITY) <known>
500
(WORSE_PARITY, WORSE_PARITY) <calc> (BEST_PARITY, 0) <known>
501
\___________________________________________/
503
(WORSE_PARITY, 0) <known>
505
(AB_PARITY_UNKN, 0) <known>
507
(AB_PARITY_UNDF, 0) <known>
511
stereo_bond_parity is the parity we are looking for
512
stereo_bond_parity==sb_parity_calc => parity to be calculated from canonical numbers
513
stereo_bond_parity!=sb_parity_calc => parity is already known
516
switch ( *stereo_bond_parity ) {
518
switch ( *sb_parity_calc ) {
519
case 0: /* BEST_PARITY(known) : (BEST_PARITY, 0) -> */
520
*stereo_bond_parity = WORSE_PARITY; /* WORSE_PARITY(known): (WORSE_PARITY, 0) */
522
goto get_next_parity;
525
case BEST_PARITY: /* BEST_PARITY(calc) : (BEST_PARITY, BEST_PARITY) -> */
526
*sb_parity_calc = WORSE_PARITY; /* BEST_PARITY(known): (BEST_PARITY, WORSE_PARITY) */
528
goto get_next_parity;
531
case WORSE_PARITY: /* BEST_PARITY(known): (BEST_PARITY, WORSE_PARITY)-> */
532
*stereo_bond_parity = WORSE_PARITY; /* WORSE_PARITY(calc): (WORSE_PARITY,WORSE_PARITY) */
533
if ( !nNumCalc ) { /* added 12-17-2003 */
534
goto get_next_parity;
540
switch ( *sb_parity_calc ) {
541
case 0: /* WORSE_PARITY(known) : (WORSE_PARITY, 0) -> */
542
*stereo_bond_parity = AB_PARITY_UNKN;/* AB_PARITY_UNKN(known): (AB_PARITY_UNKN, 0) */
544
goto get_next_parity;
547
case BEST_PARITY: /* error */
548
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
549
case WORSE_PARITY: /* WORSE_PARITY(calc) : (WORSE_PARITY,WORSE_PARITY)-> */
550
*sb_parity_calc = 0; /* WORSE_PARITY(known): (WORSE_PARITY, 0) */
552
goto get_next_parity;
557
case AB_PARITY_UNKN: /* AB_PARITY_UNKN(known): (AB_PARITY_UNKN, 0) -> */
558
if ( *sb_parity_calc ) { /* error */
559
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
561
*stereo_bond_parity = AB_PARITY_UNDF; /* AB_PARITY_UNDF(known): (AB_PARITY_UNDF, 0) */
563
return 1; /*goto next_canon_ranks;*/
566
case AB_PARITY_UNDF: /* AB_PARITY_UNDF(known): (AB_PARITY_UNDF, 0) -> */
567
if ( *sb_parity_calc ) { /* error */
568
return CT_STEREOCOUNT_ERR; /* <BRKPT> */
570
return 1; /*goto next_canon_ranks;*/ /* next canon ranks */
574
/**************************************************************************************/
575
int CompareLinCtStereoDoubleToValues( AT_STEREO_DBLE *LinearCTStereoDble,
576
AT_RANK at_rank_canon1, AT_RANK at_rank_canon2, U_CHAR bond_parity )
578
if ( LinearCTStereoDble->at_num1 CT_GREATER_THAN at_rank_canon1 )
580
if ( LinearCTStereoDble->at_num1 != at_rank_canon1 )
582
if ( LinearCTStereoDble->at_num2 CT_GREATER_THAN at_rank_canon2 )
584
if ( LinearCTStereoDble->at_num2 != at_rank_canon2 )
586
if ( LinearCTStereoDble->parity CT_GREATER_THAN bond_parity )
588
if ( LinearCTStereoDble->parity != bond_parity )
592
/**************************************************************************************/
594
/* 0 if atom has no parity */
595
/* STEREO_AT_MARK=8 if atom has stereo parity and has no stereo bonds */
596
/* num_stereo_bonds number of stereogenic bonds adjacent to the atom <= 3 */
597
void SetUseAtomForStereo( S_CHAR *bAtomUsedForStereo, sp_ATOM *at, int num_atoms )
600
memset( bAtomUsedForStereo, 0, sizeof( bAtomUsedForStereo[0] )*num_atoms );
601
for ( i = 0; i < num_atoms; i ++ ) {
602
if ( at[i].parity ) {
603
for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[i].stereo_bond_neighbor[k]; k ++ )
605
bAtomUsedForStereo[i] = k? k : STEREO_AT_MARK;
610
/*********************************************************************************
611
* tree structure: one segment
614
* at.no // orig. atom numbers on which the canon.
615
* // rank has been successfully mapped
617
* at.no // except the last at.no: it is not known if
618
* // it has been mapped until all atoms are mapped
619
* num.at+1 // number of atoms in this segment plus one canon. rank
621
*********************************************************************************/
624
/********************************************************************************
625
typedef struct tagCurTree {
627
int max_len; // allocated length of tree in sizeof(tree[0]) units
628
int cur_len; // currently used length
629
int incr_len; // reallocation increment
631
*********************************************************************************/
634
/**************************************************************************************/
635
int CurTreeAlloc( CUR_TREE *cur_tree, int num_atoms )
638
if ( cur_tree->tree && cur_tree->max_len > 0 && !(cur_tree->max_len % num_atoms) ) {
639
/* do not reallocate */
640
cur_tree->cur_len = 0;
641
cur_tree->incr_len = num_atoms;
642
memset( cur_tree->tree, 0, cur_tree->max_len * sizeof(cur_tree->tree[0]) );
645
inchi_free( cur_tree->tree );
646
memset( cur_tree, 0, sizeof(*cur_tree) );
647
if ( cur_tree->tree = (AT_NUMB *)inchi_calloc( num_atoms, sizeof(cur_tree->tree[0]) ) ) {
649
cur_tree->max_len = num_atoms;
653
return -1; /* error */ /* <BRKPT> */
655
/**************************************************************************************/
656
int CurTreeReAlloc( CUR_TREE *cur_tree )
659
if ( cur_tree->tree && cur_tree->max_len > 0 && cur_tree->incr_len > 0 ) {
660
void *p = cur_tree->tree;
661
if ( cur_tree->tree = (AT_NUMB *)inchi_calloc( cur_tree->max_len + cur_tree->incr_len, sizeof(cur_tree->tree[0]) ) ) {
662
memcpy( cur_tree->tree, p, cur_tree->cur_len * sizeof(cur_tree->tree[0]) );
664
cur_tree->max_len += cur_tree->incr_len;
669
return -1; /* error */ /* <BRKPT> */
671
/**************************************************************************************/
672
void CurTreeFree( CUR_TREE *cur_tree )
675
inchi_free( cur_tree->tree );
676
memset( cur_tree, 0, sizeof(*cur_tree) );
679
/**************************************************************************************/
680
int CurTreeAddRank( CUR_TREE *cur_tree, AT_NUMB rank )
683
if ( cur_tree->cur_len + 2 > cur_tree->max_len ) {
684
if ( CurTreeReAlloc( cur_tree ) ) {
685
return -1; /* error */ /* <BRKPT> */
688
cur_tree->tree[cur_tree->cur_len++] = rank;
689
cur_tree->tree[cur_tree->cur_len++] = 1;
692
return -1; /* error */ /* <BRKPT> */
694
/**************************************************************************************/
695
int CurTreeIsLastRank( CUR_TREE *cur_tree, AT_NUMB rank )
697
if ( cur_tree && cur_tree->cur_len > 0 ) {
699
rank_pos = cur_tree->cur_len-1;
700
rank_pos -= cur_tree->tree[rank_pos];
701
if ( rank_pos >= 0 ) {
702
return (rank == cur_tree->tree[rank_pos]);
705
return 0; /* not found */
707
/**************************************************************************************/
708
int CurTreeRemoveLastRankIfNoAtoms( CUR_TREE *cur_tree )
710
if ( cur_tree && cur_tree->tree && cur_tree->cur_len >= 2 ) {
711
if ( 1 == cur_tree->tree[ cur_tree->cur_len - 1 ] ) {
712
return CurTreeRemoveLastRank( cur_tree ); /* 0=> success, -1=>failed */
714
return 1; /* cannot remove */
716
return -1; /* error */ /* <BRKPT> */
718
/**************************************************************************************/
719
int CurTreeAddAtom( CUR_TREE *cur_tree, int at_no )
722
if ( cur_tree->cur_len + 1 > cur_tree->max_len ) {
723
if ( CurTreeReAlloc( cur_tree ) ) {
724
return -1; /* error */ /* <BRKPT> */
727
if ( cur_tree->cur_len > 0 ) {
728
AT_NUMB new_len = cur_tree->tree[ --cur_tree->cur_len ] + 1;
729
cur_tree->tree[cur_tree->cur_len++] = (AT_NUMB)at_no;
730
cur_tree->tree[cur_tree->cur_len++] = new_len;
736
/**************************************************************************************/
737
void CurTreeKeepLastAtomsOnly( CUR_TREE *cur_tree, int tpos, int shift )
738
{ /* on first entry: shift = 1; other values may occur in subsequent recursion */
739
/* cur_tree[cur_tree->cur_len - shift] is the length of a segment */
740
/* action: remove all atoms except the last from all segments
741
that have length value positon to the right from tpos */
743
if ( cur_tree && cur_tree->tree && (cur_length_pos = cur_tree->cur_len - shift) > tpos ) {
744
if ( cur_tree->tree[ cur_length_pos ] > 2 ) {
745
/* current segment contains more than 1 atom. Leave in the segment: rank, the last atom, length value */
746
/* subtract (old segment length)-(new segment length) from the tree length */
747
/* actual segment length including segment length value = (cur_tree->tree[cur_length_pos]+1) */
748
cur_tree->cur_len -= (int)cur_tree->tree[ cur_length_pos ] - 2;
749
memmove( cur_tree->tree + cur_length_pos - cur_tree->tree[ cur_length_pos ] + 1, /* 1st atom pos */
750
cur_tree->tree + cur_length_pos - 1, /* last atom in the current segment position */
751
(shift+1)*sizeof(cur_tree->tree[0]) );
752
/* (current segment length) distance from the last tree element has not changed */
753
cur_tree->tree[ cur_tree->cur_len - shift] = 2;
754
/* add 3 to move to the previous segment length position */
755
shift += 3; /* lenghth = 3 accounts for 3 currently present. segment items:
756
(1) the last atom, (2) rank, (3) length value */
758
shift += (int)cur_tree->tree[ cur_length_pos ] + 1; /* cur_tree->cur_len - (previous segment length position) */
760
CurTreeKeepLastAtomsOnly( cur_tree, tpos, shift );
763
/**************************************************************************************/
764
int CurTreeRemoveIfLastAtom( CUR_TREE *cur_tree, int at_no )
766
if ( cur_tree && cur_tree->tree && cur_tree->cur_len > 2 ) {
767
AT_NUMB len = cur_tree->tree[ cur_tree->cur_len - 1 ];
768
if ( len >= 2 && (int)cur_tree->tree[ cur_tree->cur_len - 2 ] == at_no ) {
769
cur_tree->tree[--cur_tree->cur_len-1] = len-1;
772
return 1; /* not found */
774
return -1; /* error */ /* <BRKPT> */
776
/**************************************************************************************/
777
int CurTreeGetPos( CUR_TREE *cur_tree )
780
return cur_tree->cur_len;
784
/**************************************************************************************/
785
int CurTreeSetPos( CUR_TREE *cur_tree, int len )
788
cur_tree->cur_len = len;
793
/**************************************************************************************/
794
int CurTreeRemoveLastRank( CUR_TREE *cur_tree )
796
if ( cur_tree && cur_tree->cur_len > 0 ) {
797
cur_tree->cur_len -= cur_tree->tree[cur_tree->cur_len-1]+1;
798
if ( cur_tree->cur_len >= 0 ) {
804
/**************************************************************************************/
805
/* Find if the atom is equivalent to already successfully tried current atoms */
806
int CurTreeIsLastAtomEqu( CUR_TREE *cur_tree, int at_no, AT_NUMB *nSymmStereo )
808
if ( cur_tree && cur_tree->tree && nSymmStereo && cur_tree->cur_len > 1 ) {
809
AT_NUMB nEq = nSymmStereo[at_no];
810
int end = cur_tree->cur_len-1;
811
int len = cur_tree->tree[end]-1;
812
for ( ; len > 0; len -- ) {
813
if ( nSymmStereo[(int)cur_tree->tree[end-len]] == nEq )
818
return -1; /* error */ /* <BRKPT> */
820
#ifdef NEVER /* not used */
821
/**************************************************************************************/
822
int CurTreeRemoveLastAtom( CUR_TREE *cur_tree )
824
if ( cur_tree && cur_tree->tree && cur_tree->cur_len > 2 ) {
825
AT_NUMB len = cur_tree->tree[ --cur_tree->cur_len ];
827
cur_tree->tree[cur_tree->cur_len-1] = len-1;
833
/**************************************************************************************/
834
int CurTreeReplaceLastRank( CUR_TREE *cur_tree, AT_NUMB rank )
836
if ( !CurTreeRemoveLastRank( cur_tree ) ) {
837
return CurTreeAddRank( cur_tree, rank );
841
/**************************************************************************************/
842
/* returns cur_tree->cur_len for the block containing the rank */
843
int CurTreeFindTheRankPos( CUR_TREE *cur_tree, AT_NUMB rank )
846
if ( cur_tree && cur_tree->tree && (i=cur_tree->cur_len) > 0 ) {
847
while( 0 <= (k = i-(int)cur_tree->tree[i-1]-1) ) {
848
if ( cur_tree->tree[k] == rank ) {
854
return -1; /* error */ /* <BRKPT> */