rino 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,741 @@
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 "inpdef.h"
17
+ #include "extr_ct.h"
18
+ #include "ichitaut.h"
19
+ #include "ichinorm.h"
20
+ #include "ichierr.h"
21
+ #include "util.h"
22
+
23
+ #include "ichicomp.h"
24
+
25
+ #ifndef INCHI_ALL_CPP
26
+ #ifdef __cplusplus
27
+ extern "C" {
28
+ #endif
29
+ #endif
30
+
31
+ /* defined in ichisort.c, prototype in ichicomn.h */
32
+ int insertions_sort_AT_RANK( AT_RANK *base, int num );
33
+
34
+ #ifndef INCHI_ALL_CPP
35
+ #ifdef __cplusplus
36
+ }
37
+ #endif
38
+ #endif
39
+
40
+
41
+ /* local prototypes */
42
+ int cmp_iso_atw_diff_component_no( const void *a1, const void *a2 );
43
+
44
+ /********************************************************************************/
45
+ int cmp_iso_atw_diff_component_no( const void *a1, const void *a2 )
46
+ {
47
+ int ret = (int)((const inp_ATOM*)a1)->iso_atw_diff - (int)((const inp_ATOM*)a2)->iso_atw_diff;
48
+ if ( !ret ) /* make the sort stable */
49
+ ret = (int)((const inp_ATOM*)a1)->component - (int)((const inp_ATOM*)a2)->component;
50
+ return ret;
51
+ }
52
+ typedef struct tagTreeAtom {
53
+ AT_NUMB neighbor[MAXVAL]; /* positions (from 0) of the neighbors in the inp_ATOM array */
54
+ S_CHAR valence; /* number of bonds = number of neighbors */
55
+ AT_NUMB nRingSystem;
56
+ AT_NUMB nBlockSystem;
57
+ S_CHAR bCutVertex;
58
+ } tre_ATOM;
59
+
60
+ #if( FIND_RING_SYSTEMS == 1 ) /* { */
61
+ /********************************************************************************/
62
+ int MarkRingSystemsInp( inp_ATOM *at, int num_atoms )
63
+ {
64
+ AT_NUMB *nStackAtom = NULL;
65
+ int nTopStackAtom=-1;
66
+ AT_NUMB *nRingStack = NULL;
67
+ int nTopRingStack=-1; /* was AT_NUMB */
68
+ AT_NUMB *nDfsNumber = NULL;
69
+ AT_NUMB *nLowNumber = NULL;
70
+ S_CHAR *cNeighNumb = NULL;
71
+ AT_NUMB nDfs;
72
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
73
+ AT_NUMB nRs, *nRsConnect = NULL;
74
+ int k;
75
+ AT_NUMB *tree = NULL;
76
+ int nNumConnect, nMaxNumConnect, nLenConnect;
77
+ #endif
78
+ AT_NUMB nNumAtInRingSystem;
79
+ int i, j, u, start, nNumRingSystems, nNumStartChildren;
80
+
81
+ /* allocate arrays */
82
+ nStackAtom = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nStackAtom[0]));
83
+ nRingStack = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nRingStack[0]));
84
+ nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
85
+ nLowNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nLowNumber[0]));
86
+ cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
87
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
88
+ nRsConnect = (AT_NUMB *)inchi_calloc(3*num_atoms+3,sizeof(nRsConnect[0]));
89
+ #endif
90
+ /* check allocation */
91
+ if ( !nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || !cNeighNumb
92
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
93
+ || !nRsConnect
94
+ #endif
95
+ ) {
96
+ nNumRingSystems = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
97
+ goto exit_function;
98
+ }
99
+
100
+ /********************************************
101
+ *
102
+ * Find Cut-vertices & Blocks
103
+ *
104
+ ********************************************/
105
+
106
+ /* initiation */
107
+ start = 0;
108
+ nNumRingSystems = 0;
109
+ u = start; /* start atom */
110
+ nDfs = 0;
111
+ nTopStackAtom =-1;
112
+ nTopRingStack =-1;
113
+ memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
114
+ memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
115
+ /* push the start atom on the stack */
116
+ nLowNumber[u] = nDfsNumber[u] = ++nDfs;
117
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
118
+ nRingStack[++nTopRingStack] = (AT_NUMB)u;
119
+
120
+ nNumStartChildren = 0;
121
+
122
+ do {
123
+ /* advance */
124
+ advance_block:
125
+ if ( (int)at[i=nStackAtom[nTopStackAtom]].valence > (j = (int)cNeighNumb[i]) ) {
126
+ cNeighNumb[i] ++;
127
+ u = (int)at[i].neighbor[j];
128
+ if ( !nDfsNumber[u] ) {
129
+ /* tree edge, 1st visit -- advance */
130
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
131
+ nRingStack[++nTopRingStack] = (AT_NUMB)u;
132
+ nLowNumber[u] = nDfsNumber[u] = ++nDfs;
133
+ nNumStartChildren += (i == start);
134
+ } else
135
+ if ( !nTopStackAtom || u != (int)nStackAtom[nTopStackAtom-1] ) { /* may comment out ? */
136
+ /* back edge: u is not a predecessor of i */
137
+ if ( nDfsNumber[u] < nDfsNumber[i] ) {
138
+ /* Back edge, 1st visit: u is an ancestor of i. Compare */
139
+ if ( nLowNumber[i] > nDfsNumber[u] ) {
140
+ nLowNumber[i] = nDfsNumber[u];
141
+ }
142
+ }
143
+ } /* may comment out ? */
144
+ goto advance_block;
145
+ } else {
146
+ cNeighNumb[i] = 0;
147
+ }
148
+
149
+ /* back up */
150
+ if ( i != start ) {
151
+ u = (int)nStackAtom[nTopStackAtom-1]; /* predecessor of i */
152
+ if ( nLowNumber[i] >= nDfsNumber[u] ) {
153
+ /* output the block */
154
+ nNumRingSystems ++;
155
+ at[u].nBlockSystem = nNumRingSystems;
156
+ if ( u != start || nNumStartChildren > 1 ) {
157
+ at[u].bCutVertex += 1;
158
+ }
159
+ while ( nTopRingStack >= 0 ) {
160
+ j = nRingStack[nTopRingStack--];
161
+ at[j].nBlockSystem = nNumRingSystems; /* mark the atom */
162
+ if ( i == j ) {
163
+ break;
164
+ }
165
+ }
166
+ } else
167
+ if ( nLowNumber[u] > nLowNumber[i] ) {
168
+ /* inherit */
169
+ nLowNumber[u] = nLowNumber[i];
170
+ }
171
+ }
172
+ } while ( --nTopStackAtom >= 0 );
173
+
174
+
175
+ /********************************************
176
+ *
177
+ * Find Ring Systems
178
+ * Including chain atoms X: A-X-B, where the bonds (of any kind) are bridges.
179
+ *
180
+ ********************************************/
181
+
182
+ /* initiation */
183
+ start = 0;
184
+ nNumRingSystems = 0;
185
+ u = start; /* start atom */
186
+ nDfs = 0;
187
+ nTopStackAtom =-1;
188
+ nTopRingStack =-1;
189
+ memset( nDfsNumber, 0, num_atoms*sizeof(nDfsNumber[0]));
190
+ memset( cNeighNumb, 0, num_atoms*sizeof(cNeighNumb[0]));
191
+ /* push the start atom on the stack */
192
+ nLowNumber[u] = nDfsNumber[u] = ++nDfs;
193
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
194
+ nRingStack[++nTopRingStack] = (AT_NUMB)u;
195
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
196
+ nNumConnect = nLenConnect = nMaxNumConnect = 0;
197
+ #endif
198
+
199
+ do {
200
+ /* advance */
201
+ advance_ring:
202
+ if ( (int)at[i=nStackAtom[nTopStackAtom]].valence > (j = (int)cNeighNumb[i]) ) {
203
+ cNeighNumb[i] ++;
204
+ u = (int)at[i].neighbor[j];
205
+ if ( !nDfsNumber[u] ) {
206
+ /* tree edge, 1st visit -- advance */
207
+ nStackAtom[++nTopStackAtom] = (AT_NUMB)u;
208
+ nRingStack[++nTopRingStack] = (AT_NUMB)u;
209
+ nLowNumber[u] = nDfsNumber[u] = ++nDfs;
210
+ } else
211
+ if ( !nTopStackAtom || u != (int)nStackAtom[nTopStackAtom-1] ) {
212
+ /* back edge: u is not a predecessor of i */
213
+ if ( nDfsNumber[u] < nDfsNumber[i] ) {
214
+ /* Back edge, 1st visit: u is ancestor of i. Compare */
215
+ if ( nLowNumber[i] > nDfsNumber[u] ) {
216
+ nLowNumber[i] = nDfsNumber[u];
217
+ }
218
+ }
219
+ }
220
+ goto advance_ring;
221
+ } else {
222
+ cNeighNumb[i] = 0;
223
+ }
224
+
225
+ /* back up */
226
+ if ( nDfsNumber[i] == nLowNumber[i] ) {
227
+ /* found a ring system */
228
+ nNumRingSystems ++;
229
+ /* unwind nRingStack[] down to i */
230
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
231
+ nNumConnect = 2;
232
+ /* data structure: for each ring system nRsConnect[] contains:
233
+ * 1) nNumConnect+1 = (number of already discovered neighboring "ring systems" + 1)+1
234
+ * 2) nNumAtInRingSystem
235
+ * 3) (nNumConnect-1) numbers (IDs) of neighboring ring systems.
236
+ * BFS guarantees that each neighboring ring system is encountered only one time
237
+ * Number of all neighboring ring systems = (nNumConnect-1)+1 = nNumConnect
238
+ * (One additional ring system is where the BFS retracts from the vertex #i,
239
+ * except when i=DFS root node. In the latter case there is/are only (nNumConnect-1)
240
+ * neighboring ring system(s).
241
+ */
242
+ #endif
243
+ /* count atoms in a ring system */
244
+ for ( nNumAtInRingSystem = 0, j = nTopRingStack; 0 <= j; j -- ) {
245
+ nNumAtInRingSystem ++;
246
+ if ( i == (int)nRingStack[j] ) {
247
+ break;
248
+ }
249
+ }
250
+ while ( nTopRingStack >= 0 ) {
251
+ j = (int)nRingStack[nTopRingStack--];
252
+ at[j].nRingSystem = (AT_NUMB)nNumRingSystems; /* ring system id */
253
+ at[j].nNumAtInRingSystem = nNumAtInRingSystem;
254
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
255
+ for ( k = 0; k < at[j].valence; k ++ ) {
256
+ if ( (nRs = at[at[j].neighbor[k]].nRingSystem) && (int)nRs != nNumRingSystems ) {
257
+ nRsConnect[nLenConnect + (nNumConnect++)] = nRs; /* adjacent ring system id */
258
+ }
259
+ }
260
+ #endif
261
+ if ( i == j ) {
262
+ /* reached atom on the top of nStackAtom[] stack */
263
+ break;
264
+ }
265
+ }
266
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
267
+ nRsConnect[nLenConnect] = nNumConnect;
268
+ nRsConnect[nLenConnect+1] = nNumAtInRingSystem;
269
+ nLenConnect += nNumConnect;
270
+ if ( nMaxNumConnect < nNumConnect ) {
271
+ /* max number of neighboring ring systems */
272
+ nMaxNumConnect = nNumConnect;
273
+ }
274
+ #endif
275
+ } else
276
+ if ( nTopStackAtom > 0 ) {
277
+ j = (int)nStackAtom[nTopStackAtom-1];
278
+ /* inherit nLowNumber */
279
+ if ( nLowNumber[j] > nLowNumber[i] ) {
280
+ nLowNumber[j] = nLowNumber[i];
281
+ }
282
+ }
283
+ } while ( --nTopStackAtom >= 0 );
284
+
285
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 ) /* normally disabled */
286
+ nMaxNumConnect ++;
287
+ if ( nNumRingSystems > 1 ) {
288
+ int nCol = nMaxNumConnect+1;
289
+ int nNumInSyst= nMaxNumConnect;
290
+ int nMaxNeigh = nMaxNumConnect-1;
291
+ #define T(a,b) tree[(a)*nCol+b]
292
+ if ( tree = (AT_NUMB *)inchi_calloc( nCol * (nNumRingSystems+1), sizeof(tree[0])) ) {
293
+ int len, neigh;
294
+ /* reuse previous allocations */
295
+ AT_NUMB *nNumVisitedNeighbors = nStackAtom;
296
+ AT_NUMB *nDistanceFromTerminal = nRingStack;
297
+ AT_NUMB *nCurrActiveRingSystem = nDfsNumber;
298
+ AT_NUMB *nNextActiveRingSystem = nLowNumber;
299
+ int nNumCurrActiveRingSystems, nNumNextActiveRingSystems, pass;
300
+ /* build a "condensation graph (actually, a tree)" in which
301
+ * each vertex corresponds to a ring system T(row, col) = T(ring syst, neighbors)
302
+ * Number of rows = column length = max. number of ring system neighbors + 2
303
+ * Number of cols = row length = number of ring systems + 1
304
+ * Neighboring ring systems are contiguously stored in a row
305
+ * T(i,0) = number of neighbors, 1 <= i <= nNumRingSystems;
306
+ * T(i,k) = number of a neighboring ring system, 1 <= k <= T(i,0)
307
+ * T(i,nCol-1) = number of atoms in the system #i
308
+ */
309
+ for ( i = 1, j = 0; len=nRsConnect[j]; i ++ ) {
310
+ T(i, nNumInSyst) = nRsConnect[j+1];
311
+ for ( k = 2; k < len; k ++ ) {
312
+ neigh = nRsConnect[j+k];
313
+ if ( T(i,0) < nMaxNeigh && T(neigh,0) < nMaxNeigh ) {
314
+ T(i,0) ++;
315
+ T(neigh,0) ++;
316
+ T(i,T(i,0)) = neigh;
317
+ T(neigh,T(neigh,0)) = i;
318
+ } else {
319
+ nNumRingSystems = CT_OVERFLOW; /* program error */ /* <BRKPT> */
320
+ goto exit_function;
321
+ }
322
+ }
323
+ j += len;
324
+ }
325
+ /* clear memory */
326
+ memset( nNumVisitedNeighbors, 0, nNumRingSystems*sizeof(nNumVisitedNeighbors[0]) );
327
+ memset( nDistanceFromTerminal, 0, nNumRingSystems*sizeof(nDistanceFromTerminal[0]) );
328
+ memset( nCurrActiveRingSystem, 0, nNumRingSystems*sizeof(nCurrActiveRingSystem[0]) );
329
+ memset( nNextActiveRingSystem, 0, nNumRingSystems*sizeof(nNextActiveRingSystem[0]) );
330
+ nNumNextActiveRingSystems = 0;
331
+ for ( i = 0; i < nNumRingSystems; i ++ ) {
332
+ if ( 1 == T(i+1,0) ) {
333
+ nNextActiveRingSystem[i] = 1; /* number of traversed neighbors + 1 */
334
+ nDistanceFromTerminal[i] = 1;
335
+ nNumNextActiveRingSystems ++;
336
+ } else {
337
+ nNextActiveRingSystem[i] = 0;
338
+ nDistanceFromTerminal[i] = 0;
339
+ }
340
+ nNumVisitedNeighbors[i] = 0;
341
+ }
342
+
343
+ /* nCurrActiveRingSystem[i] = a sum of:
344
+ * 1) +1 if it is or was active
345
+ * 2) +(number of neighbors from which it was reached)
346
+ * 3) +1 if it was left and not active anymore
347
+ */
348
+ pass = 0;
349
+ do {
350
+ nNumCurrActiveRingSystems = nNumNextActiveRingSystems;
351
+ nNumNextActiveRingSystems = 0;
352
+ memcpy( nCurrActiveRingSystem, nNextActiveRingSystem,
353
+ nNumRingSystems*sizeof(nNextActiveRingSystem[0]));
354
+ for ( i = 0; i < nNumRingSystems; i ++ ) {
355
+ if ( T(i+1,0) == nCurrActiveRingSystem[i] ) {
356
+ /* on the previous pass currently active ring system i+1 bas been reached
357
+ * from all neighbors except one;
358
+ * the neighbors from which it was reached have
359
+ * T(neigh,0)+1 == nCurrActiveRingSystem[i]
360
+ * this ring system has not been left yet
361
+ */
362
+ for ( k = 1, len=T(i+1,0); k <= len; k ++ ) {
363
+ neigh = (int)T(i+1,k);
364
+ if ( T(neigh,0) >= nCurrActiveRingSystem[neigh-1] ) {
365
+ if ( 0 == pass ) {
366
+ nDistanceFromTerminal[i] = 1;
367
+ }
368
+ break;
369
+ }
370
+ }
371
+ if ( k <= len ) {
372
+ /* neigh was not reached from at least 2 neighbors
373
+ * walk along -R- chain (T(neigh,0)==2) up to
374
+ * 1) a terminal system, not including it or
375
+ * 2) a branching point.
376
+ *
377
+ * pass = 0: started from terminal systems:
378
+ * reach the branching point.
379
+ * If chain system next to a terminal system has already been reached
380
+ * then walk along it according to Note below
381
+ *
382
+ * pass > 0: started from branching points
383
+ * 2a) If the branching point has not been reached from 2 or more neighbors,
384
+ * then include it
385
+ * 2b) If the branching point has not been reached from 1 neighbor only,
386
+ * then do not include it: it will be a starting point later
387
+ * Note: if a chain atom already has nDistanceFromTerminal[i] > 0, then
388
+ * the last atom should be the one such that
389
+ * its nDistanceFromTerminal[]+1>= nDistanceFromTerminal[] of the
390
+ * next in the chain
391
+ */
392
+ int bOk = 0;
393
+ k = i+1; /* starting point */
394
+ if ( 0 == pass && T(k,nNumInSyst) > 1 ) {
395
+ nNumNextActiveRingSystems ++; /* request next pass */
396
+ continue; /* stop a the terminal ring system */
397
+ }
398
+ while( 2 == T(neigh,0) ) {
399
+ /* walk along a chain */
400
+ if ( !nNextActiveRingSystem[neigh-1] ) {
401
+ nNextActiveRingSystem[neigh-1] = 1; /* make neighbor active */
402
+ } else
403
+ if ( nDistanceFromTerminal[k-1]+1 <= nDistanceFromTerminal[neigh-1] ) {
404
+ /* walking along the chain; already have had a walk */
405
+ /* in the opposite direction at this pass */
406
+ } else {
407
+ /* k is the last; neigh (it is a bridge -X-) has not been reached */
408
+ bOk = 1;
409
+ break;
410
+ }
411
+ nNextActiveRingSystem[k-1] ++; /* leave system k */
412
+ if ( nNextActiveRingSystem[neigh-1] < T(neigh,0) ) {
413
+ nNextActiveRingSystem[neigh-1] ++; /* add one connection to neigh */
414
+ }
415
+ nDistanceFromTerminal[neigh-1] = nDistanceFromTerminal[k-1]+1;
416
+ j = (T(neigh,1)==k)? 2:1;
417
+ k = neigh;
418
+ neigh = T(k,j); /* next in the chain */
419
+ nNumNextActiveRingSystems ++;
420
+ if ( T(k,nNumInSyst) > 1 ) {
421
+ bOk = 1;
422
+ break; /* stop on a ring system */
423
+ }
424
+ }
425
+ /* neigh is a terminal or a bridge or a branching point */
426
+ if ( 2 > T(neigh,0) ) {
427
+ /* neighbor is a terminal atom */
428
+ if ( 1 < pass ) {
429
+ nNumRingSystems = CT_UNKNOWN_ERR; /* error (debug only) */ /* <BRKPT> */
430
+ goto exit_function;
431
+ }
432
+ continue;
433
+ }
434
+ if ( 2 == T(neigh,0) ) {
435
+ /* neighbor is a bridge */
436
+ continue;
437
+ }
438
+ /* neighbor is a branching point */
439
+ if ( T(neigh,0) > nCurrActiveRingSystem[neigh-1] ) {
440
+ /* move to the neigh (make neigh active): on previous pass it */
441
+ /* has not been reached from 2 or more neighbors */
442
+ if ( !nNextActiveRingSystem[neigh-1] ) {
443
+ nNextActiveRingSystem[neigh-1] = 1;
444
+ }
445
+ if ( nDistanceFromTerminal[neigh-1] < nDistanceFromTerminal[k-1]+1 ) {
446
+ nDistanceFromTerminal[neigh-1] = nDistanceFromTerminal[k-1]+1;
447
+ }
448
+ nNextActiveRingSystem[k-1] ++; /* leave system k */
449
+ if ( nNextActiveRingSystem[neigh-1] < T(neigh,0) ) {
450
+ nNextActiveRingSystem[neigh-1] ++; /* add one connection to neigh */
451
+ }
452
+ nNumNextActiveRingSystems ++;
453
+ }
454
+ }
455
+ }
456
+ }
457
+ pass ++;
458
+ } while ( nNumNextActiveRingSystems );
459
+
460
+ for ( i = 0; i < num_atoms; i ++ ) {
461
+ at[i].nDistanceFromTerminal = nDistanceFromTerminal[(int)at[i].nRingSystem-1];
462
+ }
463
+
464
+ inchi_free( tree );
465
+ tree = NULL;
466
+ #undef T
467
+ } else {
468
+ nNumRingSystems = CT_OUT_OF_RAM; /* error */ /* <BRKPT> */
469
+ goto exit_function;
470
+ }
471
+ }
472
+ #endif
473
+
474
+
475
+ exit_function:
476
+ if ( nStackAtom )
477
+ inchi_free( nStackAtom );
478
+ if ( nRingStack )
479
+ inchi_free( nRingStack );
480
+ if ( nDfsNumber )
481
+ inchi_free( nDfsNumber );
482
+ if ( nLowNumber )
483
+ inchi_free( nLowNumber );
484
+ if ( cNeighNumb )
485
+ inchi_free( cNeighNumb );
486
+ #if( FIND_RINS_SYSTEMS_DISTANCES == 1 )
487
+ if ( nRsConnect )
488
+ inchi_free( nRsConnect );
489
+ if ( tree )
490
+ inchi_free( tree );
491
+ #endif
492
+ return nNumRingSystems;
493
+ }
494
+
495
+
496
+ #endif /* } FIND_RING_SYSTEMS */
497
+
498
+ /********************************************************************************/
499
+ /* Return value: new number of atoms > 0 or -1=out of RAM */
500
+ int remove_terminal_HDT( int num_atoms, inp_ATOM *at )
501
+ {
502
+ AT_NUMB *new_ord;
503
+ inp_ATOM *new_at;
504
+ char *p;
505
+ const static char szHDT[]="HDT";
506
+ const static int kMax = sizeof(szHDT); /* = 4 */
507
+ int ret = -1;
508
+ int num_hydrogens=0, num_H = 0; /* number of terminal H, D, T */
509
+ int i, j, k, n, m;
510
+ int val;
511
+ AT_RANK new_HydrogenAt_order[NUM_H_ISOTOPES+1];
512
+ AT_RANK new_OtherNeigh_order[MAXVAL];
513
+ S_CHAR old_trans[MAX_NUM_STEREO_BONDS];
514
+
515
+ int num_OtherNeigh, num_HydrogenAt;
516
+
517
+ new_ord=(AT_NUMB *)inchi_calloc(num_atoms, sizeof(new_ord[0])); /* changed malloc to calloc 9-11-2003 */
518
+ new_at =(inp_ATOM *)inchi_malloc(sizeof(new_at[0]) *num_atoms);
519
+ if (!new_ord || !new_at)
520
+ goto exit_function;
521
+ /* move H. D, T to the end of the list of atoms */
522
+ for ( i = 0; i < num_atoms; i ++ ) {
523
+ at[i].component = i; /* temporarily save original numbering */
524
+ /* get k = temp. hydrogen isotope/non-hydrogen atom type: */
525
+ /* k=0:H, k=2:D, k=3:T, k=4=kMax: not a hydrogen */
526
+ k = at[i].elname[1]? kMax : (p=strchr(szHDT, at[i].elname[0]))? p-szHDT : kMax;
527
+ /* set hydrogen isotope atw differences */
528
+ /* Notes: k-value of isotopic H is incremented to correct iso_atw_diff value later. */
529
+ /* 1H isotope cannot be detected here. */
530
+ if ( k == ATW_H || k == ATW_H+1 ) { /* D or T, k = 1 or 2 */
531
+ at[i].elname[0] = 'H'; /* hydrogen isotope */
532
+ at[i].iso_atw_diff = ++k; /* increment k to make k = iso_atw_diff ( 2 for D, 3 for T ) */
533
+ }
534
+ num_H += (k != kMax && at[i].valence == 1 && at[i].chem_bonds_valence == 1 && !NUMH(at,i) );
535
+ }
536
+
537
+ /* special case: HD, HT, DT, HH: the only non-isotopic H or
538
+ * the lightest isotopic H out of two is removed
539
+ * to become implicit (make the heavier H the "central atom").
540
+ * Note: This must be consistent with mol_to_atom()
541
+ * treatment of isotopic Hn aliases.
542
+ */
543
+ if ( 2 == num_H && 2 == num_atoms && !NUMH(at,0) && !NUMH(at,1) ) {
544
+
545
+ if ( at[0].iso_atw_diff >= at[1].iso_atw_diff ) {
546
+ new_ord[0] = 0;
547
+ new_ord[1] = 1;
548
+ } else {
549
+ new_ord[0] = 1;
550
+ new_ord[1] = 0;
551
+ }
552
+ if ( at[new_ord[1]].charge ) {
553
+ at[new_ord[0]].charge += at[new_ord[1]].charge;
554
+ at[new_ord[1]].charge = 0;
555
+ }
556
+ new_at[new_ord[0]] = at[0];
557
+ new_at[new_ord[1]] = at[1];
558
+ num_hydrogens = 1;
559
+
560
+ } else {
561
+ /* general case except H-H */
562
+ for ( i = 0; i < num_atoms; i ++ ) {
563
+ k = (at[i].elname[1] || NUMH(at,i))? kMax : (at[i].elname[0]=='H')? at[i].iso_atw_diff : kMax;
564
+ if ( k < kMax && at[i].valence == 1 && at[i].chem_bonds_valence == 1 &&
565
+ /* the order of comparison is important */
566
+ ((n=(int)at[i].neighbor[0]) > i /* at[n] has not been encountered yet*/ ||
567
+ (int)new_ord[n] < num_atoms - num_hydrogens) /* at[n] might have been encountered; it has not been moved */ ) {
568
+ /* found an explicit terminal hydrogen */
569
+ num_hydrogens ++;
570
+ if ( k==0 && ATW_H <= at[i].iso_atw_diff && at[i].iso_atw_diff < ATW_H+NUM_H_ISOTOPES ) {
571
+ k = at[i].iso_atw_diff; /* H isotope has already been marked above or elsewhere */
572
+ }
573
+ if ( at[i].charge ) { /* transfer charge from the hydrogen */
574
+ at[n].charge += at[i].charge;
575
+ at[i].charge = 0;
576
+ }
577
+ new_ord[i] = num_atoms - num_hydrogens; /* move hydrogens to the end of the list */
578
+ } else {
579
+ new_ord[i] = i - num_hydrogens; /* adjust non-hydrogens positions */
580
+ }
581
+ new_at[new_ord[i]] = at[i]; /* copy atoms to their new positions */
582
+ }
583
+ }
584
+
585
+ if ( num_hydrogens ) {
586
+ int num_others = num_atoms-num_hydrogens; /* atoms which are not terminal H, D, T */
587
+ if ( num_hydrogens > 1 ) {
588
+ /* sort hydrogen isotopes in ascending order, */
589
+ /* orig, numbers being the secondary sorting key */
590
+ qsort( new_at+num_others, num_hydrogens, sizeof(new_at[0]), cmp_iso_atw_diff_component_no );
591
+ }
592
+ /* save new numbering of hydrogen atoms using temporarily saved orig numbering */
593
+ for ( i = num_others; i < num_atoms; i ++ ) {
594
+ new_ord[(int)new_at[i].component] = i;
595
+ }
596
+
597
+ /* renumber neighbors according to new_ord[] and detach terminal hydrogens */
598
+ for ( i = 0; i < num_others; i++ ) {
599
+ memset( new_HydrogenAt_order, 0, sizeof(new_HydrogenAt_order) );
600
+ memset( new_OtherNeigh_order, 0, sizeof(new_OtherNeigh_order) );
601
+ num_OtherNeigh = 0;
602
+ num_HydrogenAt = 0;
603
+ num_H = 0;
604
+
605
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
606
+ old_trans[m] = 2 - (new_at[i].sn_ord[m] + new_at[i].sb_ord[m] + (new_at[i].sn_ord[m] > new_at[i].sb_ord[m]))%2;
607
+ }
608
+
609
+ for ( k = j = val = 0; k < new_at[i].valence; k++ ) {
610
+ if ( num_others <= ( n = new_ord[new_at[i].neighbor[k]] ) ) {
611
+ /* discovered neighbor = disconnected explicit hydrogen
612
+ * i = new atom new_at[i] ordering number
613
+ * n = new number of the explicit H
614
+ * k = ordering number of the explicit H in new_at[i] adjacency list
615
+ */
616
+ if ( 0 < new_at[n].iso_atw_diff && new_at[n].iso_atw_diff < ATW_H+NUM_H_ISOTOPES ) {
617
+ /* make explicit isotopic H implicit */
618
+ new_at[i].num_iso_H[new_at[n].iso_atw_diff-1] ++; /* isotopic H */
619
+ num_HydrogenAt += !new_HydrogenAt_order[new_at[n].iso_atw_diff];
620
+ new_HydrogenAt_order[new_at[n].iso_atw_diff] = k+1;
621
+ } else {
622
+ /* make explicit non-isotopic H implicit */
623
+ new_at[i].num_H ++; /* non-isotopic H */
624
+ num_HydrogenAt += !num_H;
625
+ num_H ++;
626
+ new_HydrogenAt_order[0] = k+1;
627
+ }
628
+ /* decrement chem. bonds valence because one bond is removed */
629
+ new_at[i].chem_bonds_valence = inchi_max( 0, new_at[i].chem_bonds_valence-1 );
630
+ new_at[n].neighbor[0] = i; /* update removed hydrogen neighbor number */
631
+ if ( new_at[i].sb_parity[0] ) {
632
+ /* if the removed H is an SB neighbor then mark it as removed */
633
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
634
+ if ( k == (int)new_at[i].sn_ord[m] ) {
635
+ new_at[i].sn_ord[m] = -(new_at[n].iso_atw_diff+1);
636
+ /* means the SB neighbor has been removed; (-4)=H, (-3)=1H, (-2)=D, (-1)=T */
637
+ }
638
+ }
639
+ }
640
+ } else {
641
+ /* discovered a regular (not an explicit H) neighbor */
642
+ if ( new_at[i].sb_parity[0] ) {
643
+ if ( num_OtherNeigh < MAX_NUM_STEREO_BONDS ) {
644
+ new_OtherNeigh_order[num_OtherNeigh] = k+1;
645
+ }
646
+ num_OtherNeigh ++; /* increment outside of if() to detect overflow */
647
+ if ( val != k ) {
648
+ /* store new stereobond and sb-neighbor ordering numbers */
649
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
650
+ if ( k == (int)new_at[i].sb_ord[m] )
651
+ new_at[i].sb_ord[m] = val;
652
+ else
653
+ if ( k == (int)new_at[i].sn_ord[m] )
654
+ new_at[i].sn_ord[m] = val;
655
+ }
656
+ }
657
+ }
658
+ new_at[i].neighbor[val] = new_ord[new_at[i].neighbor[k]];
659
+ new_at[i].bond_type[val] = new_at[i].bond_type[k];
660
+ new_at[i].bond_stereo[val] = new_at[i].bond_stereo[k];
661
+ val ++;
662
+ }
663
+ }
664
+ if ( new_at[i].valence > val && new_at[i].sb_parity[0] ) {
665
+ if ( num_HydrogenAt == new_at[i].valence - val && num_HydrogenAt + num_OtherNeigh <= MAXVAL ) {
666
+ /* recalculate parity so that it would describe neighbor sequence H,1H,D,T,neigh[0],neigh[1]... */
667
+ memmove( new_OtherNeigh_order + num_HydrogenAt, new_OtherNeigh_order, num_OtherNeigh*sizeof(new_OtherNeigh_order[0]));
668
+ for ( k = 0, j = 1; k <= NUM_H_ISOTOPES; k ++ ) {
669
+ if ( new_HydrogenAt_order[k] ) {
670
+ new_OtherNeigh_order[num_HydrogenAt - j] = new_HydrogenAt_order[k];
671
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
672
+ if ( (int)new_at[i].sn_ord[m] == -(k+1) ) {
673
+ new_at[i].sn_ord[m] = -j;
674
+ /* negative means explicit H isotope ord are
675
+ (contiguously) in front of the adjacency list */
676
+ }
677
+ }
678
+ j ++;
679
+ }
680
+ }
681
+ /* at this point new_OtherNeigh_order[] contains
682
+ incremented old ordering numbers in new order */
683
+ k = insertions_sort_AT_RANK( new_OtherNeigh_order, num_HydrogenAt + num_OtherNeigh );
684
+ k = k%2; /* seems to be of no use */
685
+ /*if ( k ) {*/
686
+ /*
687
+ for ( m = 0; m < MAX_NUM_STEREO_BONDS && new_at[i].sb_parity[m]; m ++ ) {
688
+ if ( PARITY_WELL_DEF(new_at[i].sb_parity[m]) ) {
689
+ if ( old_trans[m] != 2 - (4 + new_at[i].sn_ord[m] + new_at[i].sb_ord[m] + (new_at[i].sn_ord[m] > new_at[i].sb_ord[m]))%2 ) {
690
+ new_at[i].sb_parity[m] = 3 - new_at[i].sb_parity[m];
691
+ }
692
+ }
693
+ }
694
+ */
695
+ /*}*/
696
+ }
697
+ #ifdef _DEBUG
698
+ else {
699
+ /* error */
700
+ int stop = 1;
701
+ }
702
+ #endif
703
+ }
704
+ new_at[i].valence = val;
705
+ }
706
+ memcpy( at, new_at, sizeof(at[0])*num_atoms );
707
+ ret = num_others;
708
+ } else {
709
+ ret = num_atoms;
710
+ }
711
+ exit_function:
712
+ if ( new_ord )
713
+ inchi_free ( new_ord );
714
+ if ( new_at )
715
+ inchi_free ( new_at );
716
+ return ret;
717
+ }
718
+ /************************************************************************/
719
+ int add_DT_to_num_H( int num_atoms, inp_ATOM *at )
720
+ /* assume num_1H, num_D and num_T are not included in num_H */
721
+ {
722
+ int i, j;
723
+ for ( i = 0; i < num_atoms; i ++ ) {
724
+ for ( j = 0; j < NUM_H_ISOTOPES; j ++ )
725
+ at[i].num_H += at[i].num_iso_H[j];
726
+ }
727
+ return 0;
728
+ }
729
+ /***************************************************************/
730
+ /* not used ---
731
+ int FixAromaticOxygenAndSulfur( inp_ATOM *atom )
732
+ {
733
+ if ( !atom->elname[1] && (atom->elname[0]=='O' || atom->elname[0]=='S') &&
734
+ atom->valence==2 && !atom->charge && !atom->radical &&
735
+ atom->bond_type[0] + atom->bond_type[1] == 3 ) {
736
+ atom->charge = 1;
737
+ return 1; // fixed
738
+ }
739
+ return 0;
740
+ }
741
+ */