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,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
+ */