rino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/README +44 -0
  2. data/Rakefile +123 -0
  3. data/ext/extconf.rb +26 -0
  4. data/ext/ruby_inchi_main.so +0 -0
  5. data/ext/src/aux2atom.h +2786 -0
  6. data/ext/src/comdef.h +148 -0
  7. data/ext/src/e_0dstereo.c +3014 -0
  8. data/ext/src/e_0dstereo.h +31 -0
  9. data/ext/src/e_comdef.h +57 -0
  10. data/ext/src/e_ctl_data.h +147 -0
  11. data/ext/src/e_ichi_io.c +498 -0
  12. data/ext/src/e_ichi_io.h +40 -0
  13. data/ext/src/e_ichi_parms.c +37 -0
  14. data/ext/src/e_ichi_parms.h +41 -0
  15. data/ext/src/e_ichicomp.h +50 -0
  16. data/ext/src/e_ichierr.h +40 -0
  17. data/ext/src/e_ichimain.c +593 -0
  18. data/ext/src/e_ichisize.h +43 -0
  19. data/ext/src/e_inchi_atom.c +75 -0
  20. data/ext/src/e_inchi_atom.h +33 -0
  21. data/ext/src/e_inpdef.h +41 -0
  22. data/ext/src/e_mode.h +706 -0
  23. data/ext/src/e_mol2atom.c +649 -0
  24. data/ext/src/e_readinch.c +58 -0
  25. data/ext/src/e_readmol.c +54 -0
  26. data/ext/src/e_readmol.h +180 -0
  27. data/ext/src/e_readstru.c +251 -0
  28. data/ext/src/e_readstru.h +33 -0
  29. data/ext/src/e_util.c +284 -0
  30. data/ext/src/e_util.h +61 -0
  31. data/ext/src/extr_ct.h +251 -0
  32. data/ext/src/ichi.h +206 -0
  33. data/ext/src/ichi_bns.c +7999 -0
  34. data/ext/src/ichi_bns.h +231 -0
  35. data/ext/src/ichican2.c +5000 -0
  36. data/ext/src/ichicano.c +2195 -0
  37. data/ext/src/ichicano.h +49 -0
  38. data/ext/src/ichicans.c +1625 -0
  39. data/ext/src/ichicant.h +379 -0
  40. data/ext/src/ichicomn.h +260 -0
  41. data/ext/src/ichicomp.h +50 -0
  42. data/ext/src/ichidrp.h +119 -0
  43. data/ext/src/ichierr.h +124 -0
  44. data/ext/src/ichiisot.c +101 -0
  45. data/ext/src/ichilnct.c +286 -0
  46. data/ext/src/ichimain.h +132 -0
  47. data/ext/src/ichimak2.c +1189 -0
  48. data/ext/src/ichimake.c +3812 -0
  49. data/ext/src/ichimake.h +205 -0
  50. data/ext/src/ichimap1.c +851 -0
  51. data/ext/src/ichimap2.c +2856 -0
  52. data/ext/src/ichimap4.c +1609 -0
  53. data/ext/src/ichinorm.c +741 -0
  54. data/ext/src/ichinorm.h +67 -0
  55. data/ext/src/ichiparm.c +45 -0
  56. data/ext/src/ichiparm.h +1441 -0
  57. data/ext/src/ichiprt1.c +3612 -0
  58. data/ext/src/ichiprt2.c +1511 -0
  59. data/ext/src/ichiprt3.c +3011 -0
  60. data/ext/src/ichiqueu.c +1003 -0
  61. data/ext/src/ichiring.c +326 -0
  62. data/ext/src/ichiring.h +49 -0
  63. data/ext/src/ichisize.h +35 -0
  64. data/ext/src/ichisort.c +539 -0
  65. data/ext/src/ichister.c +3538 -0
  66. data/ext/src/ichister.h +35 -0
  67. data/ext/src/ichitaut.c +3843 -0
  68. data/ext/src/ichitaut.h +387 -0
  69. data/ext/src/ichitime.h +74 -0
  70. data/ext/src/inchi_api.h +670 -0
  71. data/ext/src/inchi_dll.c +1480 -0
  72. data/ext/src/inchi_dll.h +34 -0
  73. data/ext/src/inchi_dll_main.c +23 -0
  74. data/ext/src/inchi_dll_main.h +31 -0
  75. data/ext/src/inpdef.h +328 -0
  76. data/ext/src/lreadmol.h +1246 -0
  77. data/ext/src/mode.h +706 -0
  78. data/ext/src/ruby_inchi_main.c +558 -0
  79. data/ext/src/runichi.c +4179 -0
  80. data/ext/src/strutil.c +3861 -0
  81. data/ext/src/strutil.h +182 -0
  82. data/ext/src/util.c +1130 -0
  83. data/ext/src/util.h +85 -0
  84. data/lib/clean_tempfile.rb +220 -0
  85. data/lib/rino.rb +111 -0
  86. data/test/test.rb +386 -0
  87. metadata +130 -0
@@ -0,0 +1,851 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.00
6
+ * April 13, 2005
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ #include "mode.h"
15
+
16
+ #include "comdef.h"
17
+ #include "extr_ct.h"
18
+ #include "ichitaut.h"
19
+ #include "ichicant.h"
20
+ #include "ichicomn.h"
21
+
22
+ #include "ichicomp.h"
23
+
24
+
25
+
26
+
27
+ /**************************************************************************************/
28
+ /* Check if all equivalent to cr1 possibly stereogenic atoms: */
29
+ /* 1) have KNOWN parity, and */
30
+ /* 2) their parities are same */
31
+ /**************************************************************************************/
32
+ int All_SC_Same( AT_RANK canon_rank1, /* canonical number */
33
+ const ppAT_RANK pRankStack1, const ppAT_RANK pRankStack2,
34
+ const AT_RANK *nAtomNumberCanonFrom,
35
+ const sp_ATOM *at )
36
+ {
37
+ int n1 = (int)nAtomNumberCanonFrom[(int)canon_rank1-1];
38
+ AT_RANK r1 = pRankStack1[0][n1];
39
+ int iMax1 = (int)r1;
40
+ int i1, s1;
41
+ int bFound=0, stereo_atom_parity;
42
+
43
+ /* find one stereo atom such that canon_rank1 can be mapped on it */
44
+ for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
45
+ if ( at[s1].stereo_bond_neighbor[0] ) {
46
+ bFound=0; /* at[s1] is not sp3-stereogenic: it belongs to stereobond */
47
+ break;
48
+ } else
49
+ if ( i1 == 1 ) {
50
+ stereo_atom_parity = PARITY_VAL(at[s1].stereo_atom_parity);
51
+ if ( !ATOM_PARITY_KNOWN(stereo_atom_parity) ) {
52
+ bFound=0; /* at[s1] does not have KNOWN parity */
53
+ break;
54
+ }
55
+ } else
56
+ if ( stereo_atom_parity != PARITY_VAL(at[s1].stereo_atom_parity) ) {
57
+ bFound=0; /* two equivalent atoms have different parities */
58
+ break;
59
+ }
60
+ bFound ++;
61
+ }
62
+ return bFound;
63
+ }
64
+ /**************************************************************************************/
65
+ /* get next available (not mapped yet) rank for a stereo center atom */
66
+ int Next_SC_At_CanonRank2( AT_RANK *canon_rank1, /* 1st call input: largest canon number mapped so far or 0 */
67
+ /* output: suggested canon. rank > than input if success */
68
+ AT_RANK *canon_rank1_min, /* 1st call:0 next calls: first tried canon. number */
69
+ int *bFirstTime, /* 1 at the time of the 1st call */
70
+ S_CHAR *bAtomUsedForStereo, /* STEREO_AT_MARK if the atom has not been mapped yet */
71
+ const ppAT_RANK pRankStack1, /* mapping ranks/sort order of atoms with canon. numbers (from) */
72
+ const ppAT_RANK pRankStack2, /* mapping ranks/sort order of atoms with stereo (to) */
73
+ const AT_RANK *nAtomNumberCanonFrom, /* sorted order of the canon. numbers */
74
+ int num_atoms )
75
+ {
76
+ AT_RANK canon_rank1_inp = *canon_rank1;
77
+ AT_RANK cr1; /* canonical rank (canonical number) */
78
+ AT_RANK r1; /* mapping rank */
79
+ int n1; /* ord. number of an atom with the canon. number */
80
+ int s1; /* ord. number of an atom with stereo */
81
+ int i1, bFound=0;
82
+ int iMax1;
83
+
84
+ if ( canon_rank1_inp < *canon_rank1_min ) {
85
+ canon_rank1_inp = *canon_rank1_min;
86
+ } else
87
+ if ( canon_rank1_inp < 1 ) {
88
+ canon_rank1_inp = 1;
89
+ } else {
90
+ canon_rank1_inp ++; /* next canonical rank */
91
+ }
92
+ cr1 = canon_rank1_inp;
93
+
94
+ while ( (int) cr1 <= num_atoms ) {
95
+ n1 = (int)nAtomNumberCanonFrom[(int)cr1-1]; /* atom1 (which has canon. rank cr1) ord. number */
96
+ iMax1 = (int)(r1 = pRankStack1[0][n1]); /* mapping rank of atom1 */
97
+ /* find atoms "to" to which the canon. number can be mapped; they have mapping rank r1, number s1 */
98
+ for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
99
+ /* looking for a stereo center atom that has mapping rank r1 */
100
+ if ( bAtomUsedForStereo[s1] == STEREO_AT_MARK ) {
101
+ /* found a sterogenic atom that has not been mapped yet */
102
+ bFound = 1;
103
+ break;
104
+ }
105
+ }
106
+ if ( bFound ) {
107
+ /* one stereogenic not mapped yet atom "to" has been found */
108
+ if ( *bFirstTime ) {
109
+ *canon_rank1_min = cr1;
110
+ *bFirstTime = 0;
111
+ }
112
+ break;
113
+ } else {
114
+ /* a not mapped yet stereogenic atom has not found */
115
+ /* for the mapping rank r1 defined by the canonical rank cr1; try next cr1 */
116
+ cr1 ++;
117
+ }
118
+ }
119
+ if ( bFound ) {
120
+ /* success */
121
+ *canon_rank1 = cr1;
122
+ return 1;
123
+ }
124
+ return 0;
125
+ }
126
+ /**********************************************************************/
127
+ int CompareLinCtStereoDble ( AT_STEREO_DBLE *LinearCTStereoDble1, int nLenLinearCTStereoDble1,
128
+ AT_STEREO_DBLE *LinearCTStereoDble2, int nLenLinearCTStereoDble2 )
129
+ {
130
+ int i, num, ret = 0;
131
+
132
+ /* compare double bonds */
133
+ if ( LinearCTStereoDble1 && LinearCTStereoDble2 ) {
134
+ num = inchi_min(nLenLinearCTStereoDble1, nLenLinearCTStereoDble2);
135
+ for ( i = 0; i < num; i ++ ) {
136
+ if ( ret = (int)LinearCTStereoDble1[i].at_num1 - (int)LinearCTStereoDble2[i].at_num1 )
137
+ break;
138
+ if ( ret = (int)LinearCTStereoDble1[i].at_num2 - (int)LinearCTStereoDble2[i].at_num2 )
139
+ break;
140
+ if ( ret = (int)LinearCTStereoDble1[i].parity - (int)LinearCTStereoDble2[i].parity )
141
+ break;
142
+ }
143
+ if ( !ret ) {
144
+ ret = nLenLinearCTStereoDble1 - nLenLinearCTStereoDble2;
145
+ }
146
+ } else
147
+ if ( LinearCTStereoDble1 && nLenLinearCTStereoDble1 > 0 ) {
148
+ ret = 1;
149
+ } else
150
+ if ( LinearCTStereoDble2 && nLenLinearCTStereoDble2 > 0 ) {
151
+ ret = -1;
152
+ }
153
+ return ret;
154
+ }
155
+ /**********************************************************************/
156
+ int CompareLinCtStereoCarb ( AT_STEREO_CARB *LinearCTStereoCarb1, int nLenLinearCTStereoCarb1,
157
+ AT_STEREO_CARB *LinearCTStereoCarb2, int nLenLinearCTStereoCarb2 )
158
+ {
159
+ int i, num, ret = 0;
160
+
161
+ /* compare stereocenters */
162
+ if ( LinearCTStereoCarb1 && LinearCTStereoCarb2 ) {
163
+ num = inchi_min(nLenLinearCTStereoCarb1, nLenLinearCTStereoCarb2);
164
+ for ( i = 0; i < num; i ++ ) {
165
+ if ( ret = (int)LinearCTStereoCarb1[i].at_num - (int)LinearCTStereoCarb2[i].at_num )
166
+ break;
167
+ if ( ret = (int)LinearCTStereoCarb1[i].parity - (int)LinearCTStereoCarb2[i].parity )
168
+ break;
169
+ }
170
+ if ( !ret ) {
171
+ ret = nLenLinearCTStereoCarb1 - nLenLinearCTStereoCarb2;
172
+ }
173
+ } else
174
+ if ( LinearCTStereoCarb1 && nLenLinearCTStereoCarb1 > 0 ) {
175
+ ret = 1;
176
+ } else
177
+ if ( LinearCTStereoCarb2 && nLenLinearCTStereoCarb2 > 0 ) {
178
+ ret = -1;
179
+ }
180
+
181
+ return ret;
182
+ }
183
+ /**********************************************************************/
184
+ int CompareLinCtStereo ( AT_STEREO_DBLE *LinearCTStereoDble1, int nLenLinearCTStereoDble1,
185
+ AT_STEREO_CARB *LinearCTStereoCarb1, int nLenLinearCTStereoCarb1,
186
+ AT_STEREO_DBLE *LinearCTStereoDble2, int nLenLinearCTStereoDble2,
187
+ AT_STEREO_CARB *LinearCTStereoCarb2, int nLenLinearCTStereoCarb2 )
188
+ {
189
+ int ret;
190
+
191
+ /* compare double bonds */
192
+ ret = CompareLinCtStereoDble ( LinearCTStereoDble1, nLenLinearCTStereoDble1,
193
+ LinearCTStereoDble2, nLenLinearCTStereoDble2 );
194
+ if ( !ret ) {
195
+ ret = CompareLinCtStereoCarb ( LinearCTStereoCarb1, nLenLinearCTStereoCarb1,
196
+ LinearCTStereoCarb2, nLenLinearCTStereoCarb2 );
197
+ }
198
+ return ret;
199
+ }
200
+ /**************************************************************************************/
201
+ int CompareLinCtStereoAtomToValues( AT_STEREO_CARB *LinearCTStereoCarb,
202
+ AT_RANK at_rank_canon1, U_CHAR parity )
203
+ {
204
+ if ( LinearCTStereoCarb->at_num CT_GREATER_THAN at_rank_canon1 )
205
+ return 1;
206
+ if ( LinearCTStereoCarb->at_num != at_rank_canon1 )
207
+ return -1;
208
+ if ( LinearCTStereoCarb->parity CT_GREATER_THAN parity )
209
+ return 1;
210
+ if ( LinearCTStereoCarb->parity != parity )
211
+ return -1;
212
+ return 0;
213
+ }
214
+ /**************************************************************************************/
215
+ /* Find atom number from the mapping rank and return 1, or */
216
+ /* if the mapping rank is tied and the atom number is not unique then return 0 */
217
+ int bUniqueAtNbrFromMappingRank( AT_RANK **pRankStack, AT_RANK nAtRank, AT_NUMB *nAtNumber )
218
+ {
219
+ int r = (int)nAtRank-1;
220
+ AT_NUMB i = pRankStack[1][r];
221
+ if ( nAtRank == pRankStack[0][(int)i] &&
222
+ (!r || nAtRank != pRankStack[0][pRankStack[1][r-1]])
223
+ ) {
224
+ *nAtNumber = i;
225
+ return 1;
226
+ }
227
+ return 0;
228
+ }
229
+ /**************************************************************************************/
230
+ /* Get minimal set (class) representative and partially compress the partitioning */
231
+ /* mcr = minimal class representative. */
232
+ AT_RANK nGetMcr( AT_RANK *nEqArray, AT_RANK n )
233
+ {
234
+ AT_RANK n1, n2, mcr; /* recursive version is much shorter. */
235
+
236
+ n1=nEqArray[(int)n];
237
+ if ( n == n1 ) {
238
+ return n;
239
+ }
240
+ /* 1st pass: find mcr */
241
+ while ( n1 != (n2=nEqArray[(int)n1])) {
242
+ n1 = n2;
243
+ }
244
+ /* 2nd pass: copy mcr to each element of the set starting from nEqArray[n] */
245
+ mcr = n1;
246
+ n1 = n;
247
+ while ( /*n1*/ mcr != (n2=nEqArray[(int)n1]) ) {
248
+ nEqArray[(int)n1]=mcr;
249
+ n1 = n2;
250
+ }
251
+ return ( mcr );
252
+ }
253
+ /**************************************************************************************/
254
+ /* Join 2 sets (classes) that have members n1 and n2 */
255
+ int nJoin2Mcrs( AT_RANK *nEqArray, AT_RANK n1, AT_RANK n2 )
256
+ {
257
+ n1 = nGetMcr( nEqArray, n1 );
258
+ n2 = nGetMcr( nEqArray, n2 );
259
+ if ( n1 < n2 ) {
260
+ nEqArray[n2] = n1;
261
+ return 1; /* a change has been made */
262
+ }
263
+ if ( n2 < n1 ) {
264
+ nEqArray[n1] = n2;
265
+ return 1; /* a change has been made */
266
+ }
267
+ return 0; /* no changes */
268
+ }
269
+
270
+ /*********************************************************************************
271
+ * For all pairs of atoms that are: *
272
+ * (a) connected by a possibly stereogenic bond *
273
+ * (b) "equivalent" at this point to canon_rank1-canon_rank2 : *
274
+ * Check if they: *
275
+ * 1) are connected by a stereo bond or cumulene bonds of the same length *
276
+ * 2) have KNOWN parity, and *
277
+ * 3) their parities are same *
278
+ *********************************************************************************/
279
+ int All_SB_Same( AT_RANK canon_rank1, AT_RANK canon_rank2, /* canonical numbers */
280
+ const ppAT_RANK pRankStack1, const ppAT_RANK pRankStack2,
281
+ const AT_RANK *nAtomNumberCanonFrom, sp_ATOM *at )
282
+ {
283
+ int n1 = (int)nAtomNumberCanonFrom[(int)canon_rank1-1]; /* at1 has canon_rank1 */
284
+ int n2 = (int)nAtomNumberCanonFrom[(int)canon_rank2-1]; /* at2 has canon_rank2 */
285
+ AT_RANK r1 = pRankStack1[0][n1]; /* at1 mapping rank */
286
+ AT_RANK r2 = pRankStack1[0][n2]; /* at2 mapping rank */
287
+ AT_RANK rNeigh1, rNeigh2;
288
+ int iMax1 = (int)r1;
289
+ /* int iMax2 = (int)r2; */
290
+ int i1, i2, s1, s2, k1, k2, m, k, num_equal;
291
+ int bNotFound=1, cumulene_len, stereo_bond_parity;
292
+
293
+ /* at the first atom that possibly may have canon_rank1 find one stereo bond such that */
294
+ /* canon_rank1-canon_rank2 possibly may be mapped on it */
295
+ for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
296
+ /* at[n1] may be possible to map on at[s1] */
297
+ for ( k1 = 0, s2= 0, bNotFound=1;
298
+ k1 < MAX_NUM_STEREO_BONDS && (s2=(int)at[s1].stereo_bond_neighbor[k1]) &&
299
+ (bNotFound = (r2 != pRankStack2[0][--s2])); k1 ++ )
300
+ ; /* continue until the 1st at[s2] (to which at[n2] may be mapped) have been found */
301
+ if ( !bNotFound ) {
302
+ break; /* stop at 1st found */
303
+ }
304
+ }
305
+ if ( bNotFound ) {
306
+ return -1; /* error: no mapping exists */
307
+ }
308
+ for ( k2 = 0, m = 0; k2 < MAX_NUM_STEREO_BONDS && (m=(int)at[s2].stereo_bond_neighbor[k2]) && m-1 != s1; k2 ++ )
309
+ ;
310
+ if ( m-1 != s1 ) {
311
+ return -1; /* program error: stereo bond in opposite direction not found */
312
+ }
313
+ stereo_bond_parity = at[s1].stereo_bond_parity[k1];
314
+ if ( !PARITY_KNOWN(stereo_bond_parity) ) {
315
+ return 0;
316
+ }
317
+ cumulene_len = BOND_CHAIN_LEN(stereo_bond_parity);
318
+ rNeigh1 = pRankStack2[0][(int)at[s1].neighbor[(int)at[s1].stereo_bond_ord[k1]]];
319
+ rNeigh2 = pRankStack2[0][(int)at[s2].neighbor[(int)at[s2].stereo_bond_ord[k2]]];
320
+
321
+ num_equal = 0;
322
+ /* Search among ALL neighbors because sometimes a stereo bond may be mapped on a non-stereo bond. */
323
+ /* If is so then return 0: not all mappings are stereo-equivalent */
324
+ for ( s1 = 1; s1 <= iMax1 && r1 == pRankStack2[0][i1=(int)pRankStack2[1][iMax1-s1]]; s1++ ) {
325
+ for ( k = 0; k < at[i1].valence; k ++ ) {
326
+ n1 = at[i1].neighbor[k];
327
+ if ( rNeigh1 != pRankStack2[0][n1] ) {
328
+ continue; /* wrong neighbor */
329
+ }
330
+ if ( cumulene_len ) {
331
+ int prev, next, len, j;
332
+ for ( prev=i1, len=0, next = n1; len < cumulene_len; len ++ ) {
333
+ if ( at[next].valence == 2 && !at[next].num_H ) {
334
+ j = ((int)at[next].neighbor[0] == prev);
335
+ prev = next;
336
+ next = at[next].neighbor[j];
337
+ } else {
338
+ break; /* cannot continue */
339
+ }
340
+ }
341
+ if ( len != cumulene_len ||
342
+ r2 != pRankStack2[0][next] ||
343
+ rNeigh2 != pRankStack2[0][prev] ) {
344
+ /* cumulene chain not found */
345
+ continue;
346
+ }
347
+ i2 = next;
348
+ } else {
349
+ i2 = n1;
350
+ }
351
+ /* find if a stereogenic bond between at[i1]-at[i2] exists */
352
+ for ( k1 = 0; k1 < MAX_NUM_STEREO_BONDS &&
353
+ (m=(int)at[i1].stereo_bond_neighbor[k1]) && m-1 != i2; k1 ++ )
354
+ ;
355
+ if ( m-1 != i2 ) {
356
+ return 0;
357
+ }
358
+ for ( k2 = 0; k2 < MAX_NUM_STEREO_BONDS &&
359
+ (m=(int)at[i2].stereo_bond_neighbor[k2]) && m-1 != i1; k2 ++ )
360
+ ;
361
+ if ( m-1 != i1 ) {
362
+ return 0;
363
+ }
364
+ if ( at[i1].stereo_bond_parity[k1] != at[i2].stereo_bond_parity[k2] ) {
365
+ return -1; /* program error */
366
+ }
367
+ if ( stereo_bond_parity != at[i1].stereo_bond_parity[k1] ) {
368
+ return 0;
369
+ }
370
+ num_equal ++;
371
+ }
372
+ }
373
+ return num_equal;
374
+ }
375
+
376
+ /**************************************************************************************/
377
+ /* get min. ranks for the stereo bond atoms */
378
+ int Next_SB_At_CanonRanks2( AT_RANK *canon_rank1, AT_RANK *canon_rank2, /* canonical numbers */
379
+ AT_RANK *canon_rank1_min, AT_RANK *canon_rank2_min,
380
+ int *bFirstTime, S_CHAR *bAtomUsedForStereo,
381
+ const ppAT_RANK pRankStack1, const ppAT_RANK pRankStack2,
382
+ const AT_RANK *nCanonRankFrom, const AT_RANK *nAtomNumberCanonFrom,
383
+ const sp_ATOM *at, int num_atoms, int bAllene )
384
+ {
385
+ AT_RANK canon_rank1_inp = *canon_rank1;
386
+ AT_RANK canon_rank2_inp = *canon_rank2;
387
+ AT_RANK cr1, cr2; /* canonical ranks (canonical numbers) */
388
+ AT_RANK r1, r2; /* mapping ranks */
389
+ int n1, n2; /* ord. numbers of atoms with stereo */
390
+ int s1, s2; /* ord. numbers of atoms with canon. numbers */
391
+ int i1, i2, k, m;
392
+ int iMax1, iMax2;
393
+
394
+ if ( canon_rank1_inp < *canon_rank1_min ||
395
+ canon_rank1_inp == *canon_rank1_min &&
396
+ canon_rank2_inp < *canon_rank2_min ) {
397
+
398
+ canon_rank1_inp = *canon_rank1_min;
399
+ canon_rank2_inp = *canon_rank2_min;
400
+ } else
401
+ if ( canon_rank1_inp < 2 ) {
402
+ canon_rank1_inp = 2;
403
+ canon_rank2_inp = 0;
404
+ }
405
+ cr1 = canon_rank1_inp;
406
+ cr2 = num_atoms; /* initialize. 1/8/2002 */
407
+ while ( (int) cr1 <= num_atoms ) {
408
+ cr2 = cr1;
409
+ n1 = (int)nAtomNumberCanonFrom[(int)cr1-1]; /* atom1=at[n1] (which has canon. rank) ord. number */
410
+ iMax1 = (int)(r1 = pRankStack1[0][n1]); /* mapping rank of atom1 */
411
+ for ( i1 = 1; i1 <= iMax1 && r1 == pRankStack2[0][s1=(int)pRankStack2[1][iMax1-i1]]; i1++ ) {
412
+ /* looking for a stereo bond atom that has mapping rank r1 */
413
+ /* found at[s1] such that rank cr1 can be mapped on at[s1] because cr1 and s1 have equal */
414
+ /* mapping rank = r1. Check at[s1] stereo bonds */
415
+ if ( bAtomUsedForStereo[s1] && bAtomUsedForStereo[s1] < STEREO_AT_MARK ) {
416
+ for ( k = 0, s2 = 0; k < MAX_NUM_STEREO_BONDS && (s2=(int)at[s1].stereo_bond_neighbor[k]); k ++ ) {
417
+ /* stereo bond at[s1]-at[s2] has been found */
418
+ if ( bAtomUsedForStereo[--s2] ) {
419
+ /* stereo bonds have not been mapped. however, this check is not needed */
420
+ int cumulene_len = BOND_CHAIN_LEN(at[s1].stereo_bond_parity[k]);
421
+ if ( cumulene_len%2 && !bAllene || /* 09-26-2003 */
422
+ !(cumulene_len%2) && bAllene ) { /* 08-17-2003 Fix05 */
423
+ continue;
424
+ }
425
+ iMax2 = (int)(r2 = pRankStack2[0][s2]); /* mapping rank of atom2 */
426
+ /* Go back to canonical ranks and find an atom that has mapping rank r2 */
427
+ /* and is connected to the atom with canonical rank cr1 (possibly by cumulene chain) */
428
+ /* These cr1-cr2 canon. ranks possibly can be mapped on at[s1]-at[s2] stereo bond */
429
+ for ( i2 = 1; i2 <= iMax2 && r2 == pRankStack1[0][n2=(int)pRankStack1[1][iMax2-i2]]; i2++ ) {
430
+ if ( cumulene_len ) {
431
+ int prev, next, len, j;
432
+ for ( m = 0; m < at[n1].valence; m ++ ) {
433
+ for ( prev=n1, len=0, next = (int)at[n1].neighbor[m]; len < cumulene_len; len ++ ) {
434
+ if ( at[next].valence == 2 && !at[next].num_H ) {
435
+ j = ((int)at[next].neighbor[0] == prev);
436
+ prev = next;
437
+ next = at[next].neighbor[j];
438
+ } else {
439
+ break; /* cannot continue */
440
+ }
441
+ }
442
+ if ( len == cumulene_len && n2 == next ) {
443
+ break;
444
+ }
445
+ }
446
+ } else {
447
+ for ( m = 0; m < at[n1].valence && n2 != (int)at[n1].neighbor[m]; m ++ )
448
+ ;
449
+ }
450
+ if ( m < at[n1].valence &&
451
+ nCanonRankFrom[n2] < cr2 &&
452
+ nCanonRankFrom[n2] > canon_rank2_inp ) {
453
+
454
+ cr2 = nCanonRankFrom[n2]; /* found a candidate for cr2 */
455
+ }
456
+ }
457
+ }
458
+ }
459
+ }
460
+ }
461
+ if ( cr2 >= cr1 ) {
462
+ /* not found for this r1 */
463
+ cr1 ++;
464
+ canon_rank2_inp = 0;
465
+ } else {
466
+ /* found cr2 < cr1 */
467
+ if ( *bFirstTime ) {
468
+ *canon_rank1_min = cr1;
469
+ *canon_rank2_min = cr2;
470
+ *bFirstTime = 0;
471
+ }
472
+ break;
473
+ }
474
+ }
475
+ if ( cr1 > cr2 && cr1 <= num_atoms ) {
476
+ /* success */
477
+ *canon_rank1 = cr1;
478
+ *canon_rank2 = cr2;
479
+ return 1;
480
+ }
481
+ return 0;
482
+ }
483
+ /******************************************************************************************/
484
+ int NextStereoParity2Test( int *stereo_bond_parity, int *sb_parity_calc,
485
+ int nNumBest, int nNumWorse, int nNumUnkn, int nNumUndf, int nNumCalc)
486
+ {
487
+ /* sequence of (stereo_bond_parity, sb_parity_calc) pairs:
488
+
489
+ (BEST_PARITY, BEST_PARITY) <calc>
490
+ |
491
+ (BEST_PARITY, WORSE_PARITY) <known>
492
+ |
493
+ (WORSE_PARITY, WORSE_PARITY) <calc> (BEST_PARITY, 0) <known>
494
+ \___________________________________________/
495
+ |
496
+ (WORSE_PARITY, 0) <known>
497
+ |
498
+ (AB_PARITY_UNKN, 0) <known>
499
+ |
500
+ (AB_PARITY_UNDF, 0) <known>
501
+ |
502
+ <next pair of ranks>
503
+ Meaning:
504
+ stereo_bond_parity is the parity we are looking for
505
+ stereo_bond_parity==sb_parity_calc => parity to be calculated from canonical numbers
506
+ stereo_bond_parity!=sb_parity_calc => parity is already known
507
+ */
508
+ get_next_parity:
509
+ switch ( *stereo_bond_parity ) {
510
+ case BEST_PARITY:
511
+ switch ( *sb_parity_calc ) {
512
+ case 0: /* BEST_PARITY(known) : (BEST_PARITY, 0) -> */
513
+ *stereo_bond_parity = WORSE_PARITY; /* WORSE_PARITY(known): (WORSE_PARITY, 0) */
514
+ if ( !nNumWorse ) {
515
+ goto get_next_parity;
516
+ }
517
+ break;
518
+ case BEST_PARITY: /* BEST_PARITY(calc) : (BEST_PARITY, BEST_PARITY) -> */
519
+ *sb_parity_calc = WORSE_PARITY; /* BEST_PARITY(known): (BEST_PARITY, WORSE_PARITY) */
520
+ if ( !nNumBest ) {
521
+ goto get_next_parity;
522
+ }
523
+ break;
524
+ case WORSE_PARITY: /* BEST_PARITY(known): (BEST_PARITY, WORSE_PARITY)-> */
525
+ *stereo_bond_parity = WORSE_PARITY; /* WORSE_PARITY(calc): (WORSE_PARITY,WORSE_PARITY) */
526
+ if ( !nNumCalc ) { /* added 12-17-2003 */
527
+ goto get_next_parity;
528
+ }
529
+ break;
530
+ }
531
+ break;
532
+ case WORSE_PARITY:
533
+ switch ( *sb_parity_calc ) {
534
+ case 0: /* WORSE_PARITY(known) : (WORSE_PARITY, 0) -> */
535
+ *stereo_bond_parity = AB_PARITY_UNKN;/* AB_PARITY_UNKN(known): (AB_PARITY_UNKN, 0) */
536
+ if ( !nNumUnkn ) {
537
+ goto get_next_parity;
538
+ }
539
+ break;
540
+ case BEST_PARITY: /* error */
541
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
542
+ case WORSE_PARITY: /* WORSE_PARITY(calc) : (WORSE_PARITY,WORSE_PARITY)-> */
543
+ *sb_parity_calc = 0; /* WORSE_PARITY(known): (WORSE_PARITY, 0) */
544
+ if ( !nNumWorse ) {
545
+ goto get_next_parity;
546
+ }
547
+ break;
548
+ }
549
+ break;
550
+ case AB_PARITY_UNKN: /* AB_PARITY_UNKN(known): (AB_PARITY_UNKN, 0) -> */
551
+ if ( *sb_parity_calc ) { /* error */
552
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
553
+ }
554
+ *stereo_bond_parity = AB_PARITY_UNDF; /* AB_PARITY_UNDF(known): (AB_PARITY_UNDF, 0) */
555
+ if ( !nNumUndf ) {
556
+ return 1; /*goto next_canon_ranks;*/
557
+ }
558
+ break;
559
+ case AB_PARITY_UNDF: /* AB_PARITY_UNDF(known): (AB_PARITY_UNDF, 0) -> */
560
+ if ( *sb_parity_calc ) { /* error */
561
+ return CT_STEREOCOUNT_ERR; /* <BRKPT> */
562
+ }
563
+ return 1; /*goto next_canon_ranks;*/ /* next canon ranks */
564
+ }
565
+ return 0;
566
+ }
567
+ /**************************************************************************************/
568
+ int CompareLinCtStereoDoubleToValues( AT_STEREO_DBLE *LinearCTStereoDble,
569
+ AT_RANK at_rank_canon1, AT_RANK at_rank_canon2, U_CHAR bond_parity )
570
+ {
571
+ if ( LinearCTStereoDble->at_num1 CT_GREATER_THAN at_rank_canon1 )
572
+ return 1;
573
+ if ( LinearCTStereoDble->at_num1 != at_rank_canon1 )
574
+ return -1;
575
+ if ( LinearCTStereoDble->at_num2 CT_GREATER_THAN at_rank_canon2 )
576
+ return 1;
577
+ if ( LinearCTStereoDble->at_num2 != at_rank_canon2 )
578
+ return -1;
579
+ if ( LinearCTStereoDble->parity CT_GREATER_THAN bond_parity )
580
+ return 1;
581
+ if ( LinearCTStereoDble->parity != bond_parity )
582
+ return -1;
583
+ return 0;
584
+ }
585
+ /**************************************************************************************/
586
+ /* Set for at[i]: */
587
+ /* 0 if atom has no parity */
588
+ /* STEREO_AT_MARK=8 if atom has stereo parity and has no stereo bonds */
589
+ /* num_stereo_bonds number of stereogenic bonds adjacent to the atom <= 3 */
590
+ void SetUseAtomForStereo( S_CHAR *bAtomUsedForStereo, sp_ATOM *at, int num_atoms )
591
+ {
592
+ int i, k;
593
+ memset( bAtomUsedForStereo, 0, sizeof( bAtomUsedForStereo[0] )*num_atoms );
594
+ for ( i = 0; i < num_atoms; i ++ ) {
595
+ if ( at[i].parity ) {
596
+ for ( k = 0; k < MAX_NUM_STEREO_BONDS && at[i].stereo_bond_neighbor[k]; k ++ )
597
+ ;
598
+ bAtomUsedForStereo[i] = k? k : STEREO_AT_MARK;
599
+ }
600
+ }
601
+ }
602
+
603
+ /*********************************************************************************
604
+ * tree structure: one segment
605
+ *
606
+ * canon. rank
607
+ * at.no // orig. atom numbers on which the canon.
608
+ * // rank has been successfully mapped
609
+ * ...
610
+ * at.no // except the last at.no: it is not known if
611
+ * // it has been mapped until all atoms are mapped
612
+ * num.at+1 // number of atoms in this segment plus one canon. rank
613
+ *
614
+ *********************************************************************************/
615
+
616
+
617
+ /********************************************************************************
618
+ typedef struct tagCurTree {
619
+ AT_NUMB *tree;
620
+ int max_len; // allocated length of tree in sizeof(tree[0]) units
621
+ int cur_len; // currently used length
622
+ int incr_len; // reallocation increment
623
+ } CUR_TREE;
624
+ *********************************************************************************/
625
+
626
+
627
+ /**************************************************************************************/
628
+ int CurTreeAlloc( CUR_TREE *cur_tree, int num_atoms )
629
+ {
630
+ if ( cur_tree ) {
631
+ if ( cur_tree->tree && cur_tree->max_len > 0 && !(cur_tree->max_len % num_atoms) ) {
632
+ /* do not reallocate */
633
+ cur_tree->cur_len = 0;
634
+ cur_tree->incr_len = num_atoms;
635
+ memset( cur_tree->tree, 0, cur_tree->max_len * sizeof(cur_tree->tree[0]) );
636
+ return 0; /* ok */
637
+ }
638
+ inchi_free( cur_tree->tree );
639
+ memset( cur_tree, 0, sizeof(*cur_tree) );
640
+ if ( cur_tree->tree = (AT_NUMB *)inchi_calloc( num_atoms, sizeof(cur_tree->tree[0]) ) ) {
641
+ cur_tree->incr_len =
642
+ cur_tree->max_len = num_atoms;
643
+ return 0; /* ok */
644
+ }
645
+ }
646
+ return -1; /* error */ /* <BRKPT> */
647
+ }
648
+ /**************************************************************************************/
649
+ int CurTreeReAlloc( CUR_TREE *cur_tree )
650
+ {
651
+ if ( cur_tree ) {
652
+ if ( cur_tree->tree && cur_tree->max_len > 0 && cur_tree->incr_len > 0 ) {
653
+ void *p = cur_tree->tree;
654
+ if ( cur_tree->tree = (AT_NUMB *)inchi_calloc( cur_tree->max_len + cur_tree->incr_len, sizeof(cur_tree->tree[0]) ) ) {
655
+ memcpy( cur_tree->tree, p, cur_tree->cur_len * sizeof(cur_tree->tree[0]) );
656
+ inchi_free( p );
657
+ cur_tree->max_len += cur_tree->incr_len;
658
+ return 0; /* ok */
659
+ }
660
+ }
661
+ }
662
+ return -1; /* error */ /* <BRKPT> */
663
+ }
664
+ /**************************************************************************************/
665
+ void CurTreeFree( CUR_TREE *cur_tree )
666
+ {
667
+ if ( cur_tree ) {
668
+ inchi_free( cur_tree->tree );
669
+ memset( cur_tree, 0, sizeof(*cur_tree) );
670
+ }
671
+ }
672
+ /**************************************************************************************/
673
+ int CurTreeAddRank( CUR_TREE *cur_tree, AT_NUMB rank )
674
+ {
675
+ if ( cur_tree ) {
676
+ if ( cur_tree->cur_len + 2 > cur_tree->max_len ) {
677
+ if ( CurTreeReAlloc( cur_tree ) ) {
678
+ return -1; /* error */ /* <BRKPT> */
679
+ }
680
+ }
681
+ cur_tree->tree[cur_tree->cur_len++] = rank;
682
+ cur_tree->tree[cur_tree->cur_len++] = 1;
683
+ return 0;
684
+ }
685
+ return -1; /* error */ /* <BRKPT> */
686
+ }
687
+ /**************************************************************************************/
688
+ int CurTreeIsLastRank( CUR_TREE *cur_tree, AT_NUMB rank )
689
+ {
690
+ if ( cur_tree && cur_tree->cur_len > 0 ) {
691
+ int rank_pos;
692
+ rank_pos = cur_tree->cur_len-1;
693
+ rank_pos -= cur_tree->tree[rank_pos];
694
+ if ( rank_pos >= 0 ) {
695
+ return (rank == cur_tree->tree[rank_pos]);
696
+ }
697
+ }
698
+ return 0; /* not found */
699
+ }
700
+ /**************************************************************************************/
701
+ int CurTreeRemoveLastRankIfNoAtoms( CUR_TREE *cur_tree )
702
+ {
703
+ if ( cur_tree && cur_tree->tree && cur_tree->cur_len >= 2 ) {
704
+ if ( 1 == cur_tree->tree[ cur_tree->cur_len - 1 ] ) {
705
+ return CurTreeRemoveLastRank( cur_tree ); /* 0=> success, -1=>failed */
706
+ }
707
+ return 1; /* cannot remove */
708
+ }
709
+ return -1; /* error */ /* <BRKPT> */
710
+ }
711
+ /**************************************************************************************/
712
+ int CurTreeAddAtom( CUR_TREE *cur_tree, int at_no )
713
+ {
714
+ if ( cur_tree ) {
715
+ if ( cur_tree->cur_len + 1 > cur_tree->max_len ) {
716
+ if ( CurTreeReAlloc( cur_tree ) ) {
717
+ return -1; /* error */ /* <BRKPT> */
718
+ }
719
+ }
720
+ if ( cur_tree->cur_len > 0 ) {
721
+ AT_NUMB new_len = cur_tree->tree[ --cur_tree->cur_len ] + 1;
722
+ cur_tree->tree[cur_tree->cur_len++] = (AT_NUMB)at_no;
723
+ cur_tree->tree[cur_tree->cur_len++] = new_len;
724
+ return 0;
725
+ }
726
+ }
727
+ return -1;
728
+ }
729
+ /**************************************************************************************/
730
+ void CurTreeKeepLastAtomsOnly( CUR_TREE *cur_tree, int tpos, int shift )
731
+ { /* on first entry: shift = 1; other values may occur in subsequent recursion */
732
+ /* cur_tree[cur_tree->cur_len - shift] is the length of a segment */
733
+ /* action: remove all atoms except the last from all segments
734
+ that have length value positon to the right from tpos */
735
+ int cur_length_pos;
736
+ if ( cur_tree && cur_tree->tree && (cur_length_pos = cur_tree->cur_len - shift) > tpos ) {
737
+ if ( cur_tree->tree[ cur_length_pos ] > 2 ) {
738
+ /* current segment contains more than 1 atom. Leave in the segment: rank, the last atom, length value */
739
+ /* subtract (old segment length)-(new segment length) from the tree length */
740
+ /* actual segment length including segment length value = (cur_tree->tree[cur_length_pos]+1) */
741
+ cur_tree->cur_len -= (int)cur_tree->tree[ cur_length_pos ] - 2;
742
+ memmove( cur_tree->tree + cur_length_pos - cur_tree->tree[ cur_length_pos ] + 1, /* 1st atom pos */
743
+ cur_tree->tree + cur_length_pos - 1, /* last atom in the current segment position */
744
+ (shift+1)*sizeof(cur_tree->tree[0]) );
745
+ /* (current segment length) distance from the last tree element has not changed */
746
+ cur_tree->tree[ cur_tree->cur_len - shift] = 2;
747
+ /* add 3 to move to the previous segment length position */
748
+ shift += 3; /* lenghth = 3 accounts for 3 currently present. segment items:
749
+ (1) the last atom, (2) rank, (3) length value */
750
+ } else {
751
+ shift += (int)cur_tree->tree[ cur_length_pos ] + 1; /* cur_tree->cur_len - (previous segment length position) */
752
+ }
753
+ CurTreeKeepLastAtomsOnly( cur_tree, tpos, shift );
754
+ }
755
+ }
756
+ /**************************************************************************************/
757
+ int CurTreeRemoveIfLastAtom( CUR_TREE *cur_tree, int at_no )
758
+ {
759
+ if ( cur_tree && cur_tree->tree && cur_tree->cur_len > 2 ) {
760
+ AT_NUMB len = cur_tree->tree[ cur_tree->cur_len - 1 ];
761
+ if ( len >= 2 && (int)cur_tree->tree[ cur_tree->cur_len - 2 ] == at_no ) {
762
+ cur_tree->tree[--cur_tree->cur_len-1] = len-1;
763
+ return 0;
764
+ }
765
+ return 1; /* not found */
766
+ }
767
+ return -1; /* error */ /* <BRKPT> */
768
+ }
769
+ /**************************************************************************************/
770
+ int CurTreeGetPos( CUR_TREE *cur_tree )
771
+ {
772
+ if ( cur_tree ) {
773
+ return cur_tree->cur_len;
774
+ }
775
+ return -1;
776
+ }
777
+ /**************************************************************************************/
778
+ int CurTreeSetPos( CUR_TREE *cur_tree, int len )
779
+ {
780
+ if ( cur_tree ) {
781
+ cur_tree->cur_len = len;
782
+ return 0;
783
+ }
784
+ return -1;
785
+ }
786
+ /**************************************************************************************/
787
+ int CurTreeRemoveLastRank( CUR_TREE *cur_tree )
788
+ {
789
+ if ( cur_tree && cur_tree->cur_len > 0 ) {
790
+ cur_tree->cur_len -= cur_tree->tree[cur_tree->cur_len-1]+1;
791
+ if ( cur_tree->cur_len >= 0 ) {
792
+ return 0;
793
+ }
794
+ }
795
+ return -1;
796
+ }
797
+ /**************************************************************************************/
798
+ /* Find if the atom is equivalent to already successfully tried current atoms */
799
+ int CurTreeIsLastAtomEqu( CUR_TREE *cur_tree, int at_no, AT_NUMB *nSymmStereo )
800
+ {
801
+ if ( cur_tree && cur_tree->tree && nSymmStereo && cur_tree->cur_len > 1 ) {
802
+ AT_NUMB nEq = nSymmStereo[at_no];
803
+ int end = cur_tree->cur_len-1;
804
+ int len = cur_tree->tree[end]-1;
805
+ for ( ; len > 0; len -- ) {
806
+ if ( nSymmStereo[(int)cur_tree->tree[end-len]] == nEq )
807
+ return 1;
808
+ }
809
+ return 0;
810
+ }
811
+ return -1; /* error */ /* <BRKPT> */
812
+ }
813
+ #ifdef NEVER /* not used */
814
+ /**************************************************************************************/
815
+ int CurTreeRemoveLastAtom( CUR_TREE *cur_tree )
816
+ {
817
+ if ( cur_tree && cur_tree->tree && cur_tree->cur_len > 2 ) {
818
+ AT_NUMB len = cur_tree->tree[ --cur_tree->cur_len ];
819
+ if ( len >= 2 ) {
820
+ cur_tree->tree[cur_tree->cur_len-1] = len-1;
821
+ return 0;
822
+ }
823
+ }
824
+ return -1;
825
+ }
826
+ /**************************************************************************************/
827
+ int CurTreeReplaceLastRank( CUR_TREE *cur_tree, AT_NUMB rank )
828
+ {
829
+ if ( !CurTreeRemoveLastRank( cur_tree ) ) {
830
+ return CurTreeAddRank( cur_tree, rank );
831
+ }
832
+ return -1;
833
+ }
834
+ /**************************************************************************************/
835
+ /* returns cur_tree->cur_len for the block containing the rank */
836
+ int CurTreeFindTheRankPos( CUR_TREE *cur_tree, AT_NUMB rank )
837
+ {
838
+ int i, k;
839
+ if ( cur_tree && cur_tree->tree && (i=cur_tree->cur_len) > 0 ) {
840
+ while( 0 <= (k = i-(int)cur_tree->tree[i-1]-1) ) {
841
+ if ( cur_tree->tree[k] == rank ) {
842
+ return i;
843
+ }
844
+ i = k;
845
+ }
846
+ }
847
+ return -1; /* error */ /* <BRKPT> */
848
+ }
849
+ #endif
850
+
851
+