2
* International Chemical Identifier (InChI)
4
* Software version 1.02-beta
8
* The InChI library and programs are free software developed under the
9
* auspices of the International Union of Pure and Applied Chemistry (IUPAC);
10
* you can redistribute this software and/or modify it under the terms of
11
* the GNU Lesser General Public License as published by the Free Software
13
* http://www.opensource.org/licenses/lgpl-license.php
27
/* local prototypes */
28
int GetMinRingSize( inp_ATOM* atom, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK nMaxRingSize );
33
/*******************************************************************/
34
/* add to the queue */
35
int QueueAdd( QUEUE *q, QINT_TYPE *Val );
36
/* read & remove from the queue */
37
int QueueGet( QUEUE *q, QINT_TYPE *Val );
38
/* read from the queue */
39
int QueueGetAny( QUEUE *q, QINT_TYPE *, int ord );
40
/* initialize the queue */
41
int QueueReinit( QUEUE *q );
42
/* current queue length */
43
int QueueLength( QUEUE *q );
44
/* number of used queue internal elements */
45
int QueueWrittenLength( QUEUE *q );
48
#if( QUEUE_QINT == 1 ) /* { */
50
QUEUE *QueueCreate( int nTotLength, int nSize )
53
QINT_TYPE *Val = NULL;
54
if ( nTotLength < 1 || nSize != (int)sizeof(QINT_TYPE) ||
55
!(q = (QUEUE *) inchi_calloc( 1, sizeof(QUEUE)) ) ||
56
!(Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize) )) {
57
if ( q ) inchi_free(q);
61
/* q->nSize = nSize; */
62
q->nTotLength = nTotLength;
65
int QueueAdd( QUEUE *q, QINT_TYPE *Val )
67
if ( q && Val && q->nLength < q->nTotLength ) {
68
q->Val[ (q->nFirst + q->nLength) % q->nTotLength ] = *Val;
74
int QueueGet( QUEUE *q, QINT_TYPE *Val )
76
if ( q && Val && q->nLength > 0 ) {
77
*Val = q->Val[ q->nFirst ];
78
/* new: do not allow to overwrite the retrieved value */
79
q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
82
if ( -- q->nLength ) {
83
q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
90
int QueueGetAny( QUEUE *q, QINT_TYPE *Val, int ord )
92
if ( 0 <= ord && ord < q->nTotLength ) {
94
return 1; /* success */
96
return -1; /* error */
100
#else /* } QUEUE_QINT == 1 { */
102
QUEUE *QueueCreate( int nTotLength, int nSize )
105
QINT_TYPE *Val = NULL;
106
if ( nTotLength < 1 || nSize < 1 ||
107
!(q = (QUEUE *) inchi_calloc( 1, sizeof(QUEUE)) ) ||
108
!(Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize) )) {
109
if ( q ) inchi_free(q);
114
q->nTotLength = nTotLength;
117
int QueueAdd( QUEUE *q, QINT_TYPE *Val )
119
if ( q && Val && q->nLength < q->nTotLength ) {
120
memcpy( (char*)q->Val + ((q->nFirst + q->nLength) % q->nTotLength)*q->nSize, Val, q->nSize);
126
int QueueGet( QUEUE *q, QINT_TYPE *Val )
128
if ( q && Val && q->nLength > 0 ) {
129
memcpy( Val, (char*)q->Val + q->nFirst * q->nSize, q->nSize);
130
if ( -- q->nLength ) {
131
q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
137
int QueueGetAny( QUEUE *q, QINT_TYPE *Val, int ord )
139
if ( 0 <= ord && ord < q->nTotLength ) {
140
memcpy( Val, (char*)q->Val + ord * q->nSize, q->nSize);
141
return 1; /* success */
143
return -1; /* error */
147
#endif /* } QUEUE_QINT == 1 */
149
QUEUE *QueueDelete( QUEUE *q )
152
if ( q->Val ) inchi_free(q->Val);
157
int QueueReinit( QUEUE *q )
162
/* memset( q->Val, 0, q->nTotLength*sizeof(q->Val[0])); */ /* for debug only */
163
return q->nTotLength;
167
int QueueLength( QUEUE *q )
175
int QueueWrittenLength( QUEUE *q )
178
int len = q->nFirst+q->nLength;
179
return (len > q->nTotLength)? q->nTotLength : len;
185
/**********************************************************************************/
186
/* BFS: Breadth First Search */
187
int GetMinRingSize( inp_ATOM* atom, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK nMaxRingSize )
190
AT_RANK nCurLevel, nRingSize, nMinRingSize=MAX_ATOMS+1;
194
while ( qLen = QueueLength( q ) ) {
195
/* traverse the next level (next outer ring) */
196
for ( i = 0; i < qLen; i ++ ) {
197
if ( 0 <= QueueGet( q, &at_no ) ) {
199
nCurLevel = nAtomLevel[iat_no] + 1;
200
if ( 2*nCurLevel > nMaxRingSize + 4 ) {
201
/* 2*nCurLevel = nRingSize + 3 + k, k = 0 or 1 */
202
if ( nMinRingSize < MAX_ATOMS+1 ) {
203
return (nMinRingSize >= nMaxRingSize)? 0 : nMinRingSize;
205
return 0; /* min. ring size > nMaxRingSize */
207
for ( j = 0; j < atom[iat_no].valence; j ++ ) {
208
next = (qInt)atom[iat_no].neighbor[j];
210
if ( !nAtomLevel[inext] ) {
211
/* the at_no neighbor has not been traversed yet. Add it to the queue */
212
if ( 0 <= QueueAdd( q, &next ) ) {
213
nAtomLevel[inext] = nCurLevel;
214
cSource[inext] = cSource[iat_no]; /* keep the path number */
216
return -1; /* error */
219
if ( nAtomLevel[inext]+1 >= nCurLevel &&
220
cSource[inext] != cSource[iat_no]
221
/* && cSource[(int)next] != -1 */
223
/* found a ring closure */
225
if ( cSource[inext] == -1 ) {
226
return -1; /* error */
228
if ( (nRingSize = nAtomLevel[inext] + nCurLevel - 2) < nMinRingSize ) {
229
nMinRingSize = nRingSize;
231
/* return (nRingSize >= nMaxRingSize)? 0 : nRingSize; */
235
return -1; /* error */
240
if ( nMinRingSize < MAX_ATOMS+1 ) {
241
return (nMinRingSize >= nMaxRingSize)? 0 : nMinRingSize;
246
/*******************************************************************/
248
0: nMaxRingSize < 3 or
249
min. ring size >= nMaxRingSize or
250
not a ring bond (the last is currently impossible: bond is known to belong to a ring system.
251
n>0: min. ring size < nMaxRingSize
256
at_no number of the 1st atom adjacent to the bond
257
neigh_ord ordering number of the bond in question: at[at_no].bond_type[neigh_ord]
259
nAtomLevel work array, DFS distance
260
cSource work array, origin mark
263
int is_bond_in_Nmax_memb_ring( inp_ATOM* atom, int at_no, int neigh_ord, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK nMaxRingSize )
265
int nMinRingSize = -1, i;
269
if ( nMaxRingSize < 3 ) {
275
/* mark the starting atom */
276
nAtomLevel[at_no] = 1;
279
for ( i = 0; i < atom[at_no].valence; i ++ ) {
280
n = (qInt)atom[at_no].neighbor[i];
281
nAtomLevel[(int)n] = 2;
282
cSource[(int)n] = 1 + (i==neigh_ord);
286
nMinRingSize = GetMinRingSize( atom, q, nAtomLevel, cSource, nMaxRingSize );
288
nTotLen = QueueWrittenLength( q );
289
for ( i = 0; i < nTotLen; i ++ ) {
290
if ( 0 < QueueGetAny( q, &n, i ) ) {
291
nAtomLevel[(int)n] = 0;
295
nAtomLevel[at_no] = 0;
301
inchi_free ( nAtomLevel );
303
inchi_free ( cSource );
308
/*******************************************************************/
309
int is_atom_in_3memb_ring( inp_ATOM* atom, int at_no )
312
int i, j, k, val, val_neigh, neigh;
314
if ( atom[at_no].nNumAtInRingSystem < 3 ) {
318
for ( i = 0, val = atom[at_no].valence; i < val; i ++ ) {
319
neigh = (int)atom[at_no].neighbor[i];
320
if ( atom[at_no].nRingSystem != atom[neigh].nRingSystem )
322
for ( j = 0, val_neigh = atom[neigh].valence; j < val_neigh; j ++ ) {
323
neigh_neigh = atom[neigh].neighbor[j];
324
if ( (int)neigh_neigh == at_no )
326
for ( k = 0; k < val; k ++ ) {
327
if ( atom[at_no].neighbor[k] == neigh_neigh ) {