PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

/src/formats/inchi103/ichiring.c

https://github.com/baoilleach/openbabel-svn-mirror
C | 336 lines | 239 code | 29 blank | 68 comment | 66 complexity | 2053d8291f9641c4cd570dbb0a57ea54 MD5 | raw file
  1. /*
  2. * International Chemical Identifier (InChI)
  3. * Version 1
  4. * Software version 1.03
  5. * May 9, 2010
  6. *
  7. * Originally developed at NIST
  8. * Modifications and additions by IUPAC and the InChI Trust
  9. *
  10. * The InChI library and programs are free software developed under the
  11. * auspices of the International Union of Pure and Applied Chemistry (IUPAC);
  12. * you can redistribute this software and/or modify it under the terms of
  13. * the GNU Lesser General Public License as published by the Free Software
  14. * Foundation:
  15. * http://www.opensource.org/licenses/lgpl-2.1.php
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include "mode.h"
  21. #include "inpdef.h"
  22. #include "extr_ct.h"
  23. #include "ichiring.h"
  24. /* local prototypes */
  25. int GetMinRingSize( inp_ATOM* atom, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK nMaxRingSize );
  26. /*******************************************************************/
  27. /* add to the queue */
  28. int QueueAdd( QUEUE *q, QINT_TYPE *Val );
  29. /* read & remove from the queue */
  30. int QueueGet( QUEUE *q, QINT_TYPE *Val );
  31. /* read from the queue */
  32. int QueueGetAny( QUEUE *q, QINT_TYPE *, int ord );
  33. /* initialize the queue */
  34. int QueueReinit( QUEUE *q );
  35. /* current queue length */
  36. int QueueLength( QUEUE *q );
  37. /* number of used queue internal elements */
  38. int QueueWrittenLength( QUEUE *q );
  39. #if( QUEUE_QINT == 1 ) /* { */
  40. QUEUE *QueueCreate( int nTotLength, int nSize )
  41. {
  42. QUEUE *q = NULL;
  43. QINT_TYPE *Val = NULL;
  44. if ( nTotLength < 1 || nSize != (int)sizeof(QINT_TYPE) ||
  45. !(q = (QUEUE *) inchi_calloc( 1, sizeof(QUEUE)) ) ||
  46. !(Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize) )) {
  47. if ( q ) inchi_free(q);
  48. return NULL;
  49. }
  50. q->Val = Val;
  51. /* q->nSize = nSize; */
  52. q->nTotLength = nTotLength;
  53. return q;
  54. }
  55. int QueueAdd( QUEUE *q, QINT_TYPE *Val )
  56. {
  57. if ( q && Val && q->nLength < q->nTotLength ) {
  58. q->Val[ (q->nFirst + q->nLength) % q->nTotLength ] = *Val;
  59. q->nLength ++;
  60. return q->nLength;
  61. }
  62. return -1;
  63. }
  64. int QueueGet( QUEUE *q, QINT_TYPE *Val )
  65. {
  66. if ( q && Val && q->nLength > 0 ) {
  67. *Val = q->Val[ q->nFirst ];
  68. /* new: do not allow to overwrite the retrieved value */
  69. q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
  70. q->nLength --;
  71. /* -- old --
  72. if ( -- q->nLength ) {
  73. q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
  74. }
  75. */
  76. return q->nLength;
  77. }
  78. return -1;
  79. }
  80. int QueueGetAny( QUEUE *q, QINT_TYPE *Val, int ord )
  81. {
  82. if ( 0 <= ord && ord < q->nTotLength ) {
  83. *Val = q->Val[ ord ];
  84. return 1; /* success */
  85. } else {
  86. return -1; /* error */
  87. }
  88. }
  89. #else /* } QUEUE_QINT == 1 { */
  90. QUEUE *QueueCreate( int nTotLength, int nSize )
  91. {
  92. QUEUE *q = NULL;
  93. QINT_TYPE *Val = NULL;
  94. if ( nTotLength < 1 || nSize < 1 ||
  95. !(q = (QUEUE *) inchi_calloc( 1, sizeof(QUEUE)) ) ||
  96. !(Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize) )) {
  97. if ( q ) inchi_free(q);
  98. return NULL;
  99. }
  100. q->Val = Val;
  101. q->nSize = nSize;
  102. q->nTotLength = nTotLength;
  103. return q;
  104. }
  105. int QueueAdd( QUEUE *q, QINT_TYPE *Val )
  106. {
  107. if ( q && Val && q->nLength < q->nTotLength ) {
  108. memcpy( (char*)q->Val + ((q->nFirst + q->nLength) % q->nTotLength)*q->nSize, Val, q->nSize);
  109. q->nLength ++;
  110. return q->nLength;
  111. }
  112. return -1;
  113. }
  114. int QueueGet( QUEUE *q, QINT_TYPE *Val )
  115. {
  116. if ( q && Val && q->nLength > 0 ) {
  117. memcpy( Val, (char*)q->Val + q->nFirst * q->nSize, q->nSize);
  118. if ( -- q->nLength ) {
  119. q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
  120. }
  121. return q->nLength;
  122. }
  123. return -1;
  124. }
  125. int QueueGetAny( QUEUE *q, QINT_TYPE *Val, int ord )
  126. {
  127. if ( 0 <= ord && ord < q->nTotLength ) {
  128. memcpy( Val, (char*)q->Val + ord * q->nSize, q->nSize);
  129. return 1; /* success */
  130. } else {
  131. return -1; /* error */
  132. }
  133. }
  134. #endif /* } QUEUE_QINT == 1 */
  135. QUEUE *QueueDelete( QUEUE *q )
  136. {
  137. if ( q ) {
  138. if ( q->Val ) inchi_free(q->Val);
  139. inchi_free( q );
  140. }
  141. return NULL;
  142. }
  143. int QueueReinit( QUEUE *q )
  144. {
  145. if ( q ) {
  146. q->nFirst = 0;
  147. q->nLength = 0;
  148. /* memset( q->Val, 0, q->nTotLength*sizeof(q->Val[0])); */ /* for debug only */
  149. return q->nTotLength;
  150. }
  151. return -1;
  152. }
  153. int QueueLength( QUEUE *q )
  154. {
  155. if ( q ) {
  156. return q->nLength;
  157. } else {
  158. return 0;
  159. }
  160. }
  161. int QueueWrittenLength( QUEUE *q )
  162. {
  163. if ( q ) {
  164. int len = q->nFirst+q->nLength;
  165. return (len > q->nTotLength)? q->nTotLength : len;
  166. } else {
  167. return 0;
  168. }
  169. }
  170. /**********************************************************************************/
  171. /* BFS: Breadth First Search */
  172. int GetMinRingSize( inp_ATOM* atom, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK nMaxRingSize )
  173. {
  174. int qLen, i, j;
  175. AT_RANK nCurLevel, nRingSize, nMinRingSize=MAX_ATOMS+1;
  176. qInt at_no, next;
  177. int iat_no, inext;
  178. while ( qLen = QueueLength( q ) ) {
  179. /* traverse the next level (next outer ring) */
  180. for ( i = 0; i < qLen; i ++ ) {
  181. if ( 0 <= QueueGet( q, &at_no ) ) {
  182. iat_no = (int)at_no;
  183. nCurLevel = nAtomLevel[iat_no] + 1;
  184. if ( 2*nCurLevel > nMaxRingSize + 4 ) {
  185. /* 2*nCurLevel = nRingSize + 3 + k, k = 0 or 1 */
  186. if ( nMinRingSize < MAX_ATOMS+1 ) {
  187. return (nMinRingSize >= nMaxRingSize)? 0 : nMinRingSize;
  188. }
  189. return 0; /* min. ring size > nMaxRingSize */
  190. }
  191. for ( j = 0; j < atom[iat_no].valence; j ++ ) {
  192. next = (qInt)atom[iat_no].neighbor[j];
  193. inext = (int)next;
  194. if ( !nAtomLevel[inext] ) {
  195. /* the at_no neighbor has not been traversed yet. Add it to the queue */
  196. if ( 0 <= QueueAdd( q, &next ) ) {
  197. nAtomLevel[inext] = nCurLevel;
  198. cSource[inext] = cSource[iat_no]; /* keep the path number */
  199. } else {
  200. return -1; /* error */
  201. }
  202. } else
  203. if ( nAtomLevel[inext]+1 >= nCurLevel &&
  204. cSource[inext] != cSource[iat_no]
  205. /* && cSource[(int)next] != -1 */
  206. ) {
  207. /* found a ring closure */
  208. /* debug */
  209. if ( cSource[inext] == -1 ) {
  210. return -1; /* error */
  211. }
  212. if ( (nRingSize = nAtomLevel[inext] + nCurLevel - 2) < nMinRingSize ) {
  213. nMinRingSize = nRingSize;
  214. }
  215. /* return (nRingSize >= nMaxRingSize)? 0 : nRingSize; */
  216. }
  217. }
  218. } else {
  219. return -1; /* error */
  220. }
  221. }
  222. }
  223. if ( nMinRingSize < MAX_ATOMS+1 ) {
  224. return (nMinRingSize >= nMaxRingSize)? 0 : nMinRingSize;
  225. }
  226. return 0;
  227. }
  228. /*******************************************************************/
  229. /* Return value:
  230. 0: nMaxRingSize < 3 or
  231. min. ring size >= nMaxRingSize or
  232. not a ring bond (the last is currently impossible: bond is known to belong to a ring system.
  233. n>0: min. ring size < nMaxRingSize
  234. n<0: error
  235. Input:
  236. atom[]
  237. at_no number of the 1st atom adjacent to the bond
  238. neigh_ord ordering number of the bond in question: at[at_no].bond_type[neigh_ord]
  239. q queue structure
  240. nAtomLevel work array, DFS distance
  241. cSource work array, origin mark
  242. */
  243. 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 )
  244. {
  245. int nMinRingSize = -1, i;
  246. qInt n;
  247. int nTotLen;
  248. if ( nMaxRingSize < 3 ) {
  249. return 0;
  250. }
  251. QueueReinit( q );
  252. /* mark the starting atom */
  253. nAtomLevel[at_no] = 1;
  254. cSource[at_no] = -1;
  255. /* add neighbors */
  256. for ( i = 0; i < atom[at_no].valence; i ++ ) {
  257. n = (qInt)atom[at_no].neighbor[i];
  258. nAtomLevel[(int)n] = 2;
  259. cSource[(int)n] = 1 + (i==neigh_ord);
  260. QueueAdd( q, &n );
  261. }
  262. nMinRingSize = GetMinRingSize( atom, q, nAtomLevel, cSource, nMaxRingSize );
  263. /* cleanup */
  264. nTotLen = QueueWrittenLength( q );
  265. for ( i = 0; i < nTotLen; i ++ ) {
  266. if ( 0 < QueueGetAny( q, &n, i ) ) {
  267. nAtomLevel[(int)n] = 0;
  268. cSource[(int)n] = 0;
  269. }
  270. }
  271. nAtomLevel[at_no] = 0;
  272. cSource[at_no] = 0;
  273. /*
  274. if ( nAtomLevel )
  275. inchi_free ( nAtomLevel );
  276. if ( cSource )
  277. inchi_free ( cSource );
  278. QueueDelete( q );
  279. */
  280. return nMinRingSize;
  281. }
  282. /*******************************************************************/
  283. int is_atom_in_3memb_ring( inp_ATOM* atom, int at_no )
  284. {
  285. AT_NUMB neigh_neigh;
  286. int i, j, k, val, val_neigh, neigh;
  287. if ( atom[at_no].nNumAtInRingSystem < 3 ) {
  288. return 0;
  289. }
  290. for ( i = 0, val = atom[at_no].valence; i < val; i ++ ) {
  291. neigh = (int)atom[at_no].neighbor[i];
  292. if ( atom[at_no].nRingSystem != atom[neigh].nRingSystem )
  293. continue;
  294. for ( j = 0, val_neigh = atom[neigh].valence; j < val_neigh; j ++ ) {
  295. neigh_neigh = atom[neigh].neighbor[j];
  296. if ( (int)neigh_neigh == at_no )
  297. continue;
  298. for ( k = 0; k < val; k ++ ) {
  299. if ( atom[at_no].neighbor[k] == neigh_neigh ) {
  300. return 1;
  301. }
  302. }
  303. }
  304. }
  305. return 0;
  306. }