rino 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/Rakefile +1 -1
  2. data/ext/extconf.rb +1 -24
  3. data/ext/libinchi.so +0 -0
  4. data/ext/src/aux2atom.h +120 -39
  5. data/ext/src/comdef.h +3 -3
  6. data/ext/src/dispstru.c +2547 -0
  7. data/ext/src/dispstru.h +73 -0
  8. data/ext/src/extr_ct.h +5 -2
  9. data/ext/src/ichi.h +27 -11
  10. data/ext/src/ichi_bns.c +1800 -254
  11. data/ext/src/ichi_bns.h +205 -4
  12. data/ext/src/ichican2.c +197 -86
  13. data/ext/src/ichicano.c +8 -13
  14. data/ext/src/ichicano.h +2 -2
  15. data/ext/src/ichicans.c +11 -6
  16. data/ext/src/ichicant.h +2 -2
  17. data/ext/src/ichicomn.h +2 -2
  18. data/ext/src/ichicomp.h +19 -4
  19. data/ext/src/ichidrp.h +9 -5
  20. data/ext/src/ichierr.h +5 -3
  21. data/ext/src/ichiisot.c +2 -2
  22. data/ext/src/ichimain.c +461 -0
  23. data/ext/src/ichimain.h +23 -15
  24. data/ext/src/ichimak2.c +6 -6
  25. data/ext/src/ichimake.c +843 -42
  26. data/ext/src/ichimake.h +4 -2
  27. data/ext/src/ichimap1.c +5 -5
  28. data/ext/src/ichimap2.c +2 -2
  29. data/ext/src/ichimap4.c +34 -21
  30. data/ext/src/ichinorm.c +11 -5
  31. data/ext/src/ichinorm.h +3 -2
  32. data/ext/src/ichiparm.c +2 -2
  33. data/ext/src/ichiparm.h +232 -30
  34. data/ext/src/ichiprt1.c +35 -11
  35. data/ext/src/ichiprt2.c +78 -7
  36. data/ext/src/ichiprt3.c +300 -120
  37. data/ext/src/ichiqueu.c +17 -2
  38. data/ext/src/ichiread.c +6932 -0
  39. data/ext/src/ichiring.c +3 -2
  40. data/ext/src/ichiring.h +2 -2
  41. data/ext/src/ichirvr1.c +4891 -0
  42. data/ext/src/ichirvr2.c +6344 -0
  43. data/ext/src/ichirvr3.c +5499 -0
  44. data/ext/src/ichirvr4.c +3177 -0
  45. data/ext/src/ichirvr5.c +1166 -0
  46. data/ext/src/ichirvr6.c +1287 -0
  47. data/ext/src/ichirvr7.c +2319 -0
  48. data/ext/src/ichirvrs.h +882 -0
  49. data/ext/src/ichisize.h +2 -2
  50. data/ext/src/ichisort.c +5 -5
  51. data/ext/src/ichister.c +281 -86
  52. data/ext/src/ichister.h +9 -3
  53. data/ext/src/ichitaut.c +208 -9
  54. data/ext/src/ichitaut.h +13 -11
  55. data/ext/src/ichitime.h +16 -2
  56. data/ext/src/inchicmp.h +107 -0
  57. data/ext/src/inpdef.h +6 -3
  58. data/ext/src/libinchi_wrap.c +912 -0
  59. data/ext/src/lreadmol.h +34 -31
  60. data/ext/src/mode.h +244 -7
  61. data/ext/src/mol2atom.c +1060 -0
  62. data/ext/src/mol2atom.h +31 -0
  63. data/ext/src/readinch.c +239 -0
  64. data/ext/src/readmol.c +28 -0
  65. data/ext/src/{e_readmol.h → readmol.h} +7 -9
  66. data/ext/src/runichi.c +251 -177
  67. data/ext/src/strutil.c +444 -238
  68. data/ext/src/strutil.h +150 -11
  69. data/ext/src/util.c +176 -118
  70. data/ext/src/util.h +15 -3
  71. data/lib/rino.rb +71 -3
  72. data/test/test.rb +33 -4
  73. metadata +22 -34
  74. data/ext/ruby_inchi_main.so +0 -0
  75. data/ext/src/e_0dstereo.c +0 -3014
  76. data/ext/src/e_0dstereo.h +0 -31
  77. data/ext/src/e_comdef.h +0 -57
  78. data/ext/src/e_ctl_data.h +0 -147
  79. data/ext/src/e_ichi_io.c +0 -498
  80. data/ext/src/e_ichi_io.h +0 -40
  81. data/ext/src/e_ichi_parms.c +0 -37
  82. data/ext/src/e_ichi_parms.h +0 -41
  83. data/ext/src/e_ichicomp.h +0 -50
  84. data/ext/src/e_ichierr.h +0 -40
  85. data/ext/src/e_ichimain.c +0 -593
  86. data/ext/src/e_ichisize.h +0 -43
  87. data/ext/src/e_inchi_atom.c +0 -75
  88. data/ext/src/e_inchi_atom.h +0 -33
  89. data/ext/src/e_inpdef.h +0 -41
  90. data/ext/src/e_mode.h +0 -706
  91. data/ext/src/e_mol2atom.c +0 -649
  92. data/ext/src/e_readinch.c +0 -58
  93. data/ext/src/e_readmol.c +0 -54
  94. data/ext/src/e_readstru.c +0 -251
  95. data/ext/src/e_readstru.h +0 -33
  96. data/ext/src/e_util.c +0 -284
  97. data/ext/src/e_util.h +0 -61
  98. data/ext/src/ichilnct.c +0 -286
  99. data/ext/src/inchi_api.h +0 -670
  100. data/ext/src/inchi_dll.c +0 -1480
  101. data/ext/src/inchi_dll.h +0 -34
  102. data/ext/src/inchi_dll_main.c +0 -23
  103. data/ext/src/inchi_dll_main.h +0 -31
  104. data/ext/src/ruby_inchi_main.c +0 -558
@@ -0,0 +1,1166 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.01
6
+ * July 21, 2006
7
+ * Developed at NIST
8
+ */
9
+
10
+ #include <stdio.h>
11
+ #include <stdlib.h>
12
+ #include <string.h>
13
+
14
+ /*#define CHECK_WIN32_VC_HEAP*/
15
+ #include "mode.h"
16
+
17
+ #if( READ_INCHI_STRING == 1 )
18
+
19
+ #include "ichi.h"
20
+ #include "ichitime.h"
21
+
22
+ #include "inpdef.h"
23
+ #include "ichimain.h"
24
+ #include "ichierr.h"
25
+ #include "comdef.h"
26
+ #include "ichiring.h"
27
+ #include "extr_ct.h"
28
+ #include "ichitaut.h"
29
+ #include "ichinorm.h"
30
+ #include "util.h"
31
+
32
+ #include "ichicomp.h"
33
+ #include "ichister.h"
34
+
35
+ #include "ichi_bns.h"
36
+
37
+ #include "strutil.h"
38
+
39
+ #include "ichirvrs.h"
40
+
41
+
42
+ #define INC_ADD_EDGE 64
43
+ /***********************************************************************************************/
44
+ int GetPlusMinusVertex( BN_STRUCT *pBNS, ALL_TC_GROUPS *pTCGroups, int bCheckForbiddenPlus, int bCheckForbiddenMinus )
45
+ {
46
+ int k, ePlusSuper, eMinusSuper, vPlusSuper, vMinusSuper, vPlusMinus1 = NO_VERTEX, vPlusMinus2 = NO_VERTEX;
47
+ BNS_EDGE *pEdge;
48
+ if ( (k = pTCGroups->nGroup[TCG_Plus]) >= 0 &&
49
+ (ePlusSuper = pTCGroups->pTCG[k].nForwardEdge) > 0 &&
50
+ (vPlusSuper = pTCGroups->pTCG[k].nVertexNumber) >= pBNS->num_atoms &&
51
+ !((pEdge=pBNS->edge + ePlusSuper)->forbidden && bCheckForbiddenPlus) ) {
52
+
53
+ vPlusMinus1 = pEdge->neighbor12 ^ vPlusSuper;
54
+ }
55
+ if ( (k = pTCGroups->nGroup[TCG_Minus]) >= 0 &&
56
+ (eMinusSuper = pTCGroups->pTCG[k].nForwardEdge) > 0 &&
57
+ (vMinusSuper = pTCGroups->pTCG[k].nVertexNumber) >= pBNS->num_atoms &&
58
+ !((pEdge=pBNS->edge + eMinusSuper)->forbidden && bCheckForbiddenMinus) ) {
59
+
60
+ vPlusMinus2 = pEdge->neighbor12 ^ eMinusSuper;
61
+ }
62
+ if ( bCheckForbiddenPlus && NO_VERTEX == vPlusMinus1 ||
63
+ bCheckForbiddenMinus && NO_VERTEX == vPlusMinus2 ) {
64
+ return NO_VERTEX;
65
+ }
66
+ return (NO_VERTEX != vPlusMinus1)? vPlusMinus1 : vPlusMinus2;
67
+ }
68
+ /***********************************************************************************************/
69
+ int bIsUnsatCarbonInASmallRing( inp_ATOM *at2, VAL_AT *pVA, int iat, BFS_Q *pbfsq, int min_ring_size )
70
+ {
71
+ int j, nCurRingSize, nMinRingSize;
72
+ if ( min_ring_size < 5 ) {
73
+ /* =C= in a small ring */
74
+ if ( at2[iat].valence == 2 &&
75
+ pVA[iat].cMinRingSize <= 5 &&
76
+ at2[iat].chem_bonds_valence == 4 ) {
77
+ return 1;
78
+ }
79
+ } else {
80
+ if ( at2[iat].valence == 2 &&
81
+ pVA[iat].cMinRingSize &&
82
+ pVA[iat].cMinRingSize <= min_ring_size &&
83
+ at2[iat].chem_bonds_valence == 3 ) {
84
+ return 1;
85
+ }
86
+ nCurRingSize = nMinRingSize = min_ring_size+1;
87
+ if ( (at2[iat].valence == 2 || at2[iat].valence == 3) &&
88
+ at2[iat].chem_bonds_valence == at2[iat].valence+1 ) {
89
+ for ( j = 0; j < at2[iat].valence; j ++ ) {
90
+ nCurRingSize = is_bond_in_Nmax_memb_ring( at2, iat, j, pbfsq->q,
91
+ pbfsq->nAtomLevel,
92
+ pbfsq->cSource, (AT_RANK)nMinRingSize /* max ring size */ );
93
+ if ( 0 < nCurRingSize && nCurRingSize < nMinRingSize ) {
94
+ nMinRingSize = nCurRingSize;
95
+ }
96
+ }
97
+ return (0 <= nCurRingSize)? (nMinRingSize <= min_ring_size) : nCurRingSize;
98
+ }
99
+ }
100
+ return 0;
101
+ }
102
+ /***********************************************************************************************/
103
+ int FixMobileHRestoredStructure(ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
104
+ StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
105
+ ALL_TC_GROUPS *pTCGroups, T_GROUP_INFO **ppt_group_info, inp_ATOM **ppat_norm,
106
+ inp_ATOM **ppat_prep, INChI *pInChI[], long num_inp, int bHasSomeFixedH,
107
+ int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
108
+ {
109
+ /*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
110
+ /* at2 should be the most recently restored atom, Fixed-H */
111
+ int i, j, k, iat, delta, tot_succes, cur_success, ret = 0;
112
+ CMP2MHINCHI c2i;
113
+ CMP2MHINCHI *pc2i = &c2i;
114
+
115
+ EDGE_LIST AllChargeEdges, CurrEdges, CurrEdges2, CurrEdges3, TautEdges, NFlowerEdges, OtherNFlowerEdges, FixedLargeRingStereoEdges;
116
+ EDGE_LIST *pEdgeList = NULL;
117
+
118
+ EdgeIndex e;
119
+ BNS_EDGE *pe;
120
+ Vertex v1, v2, vPlusMinus;
121
+ BNS_VERTEX *pv1, *pv2;
122
+
123
+ Vertex vPathStart, vPathEnd;
124
+ int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
125
+
126
+ int nNumRunBNS = 0, forbidden_edge_mask_inv = ~forbidden_edge_mask;
127
+
128
+ INCHI_HEAPCHK
129
+
130
+ AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
131
+ AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
132
+ AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
133
+ AllocEdgeList( &CurrEdges2, EDGE_LIST_CLEAR );
134
+ AllocEdgeList( &CurrEdges3, EDGE_LIST_CLEAR );
135
+ AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
136
+ AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_CLEAR );
137
+ AllocEdgeList( &TautEdges, EDGE_LIST_CLEAR );
138
+
139
+ tot_succes = 0;
140
+
141
+ if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
142
+ goto exit_function; /* no fixed-H found */
143
+ }
144
+ /* taut group edges */
145
+ for ( i = 0; i < pTCGroups->num_tgroups; i ++ ) {
146
+ pv1 = pBNS->vert + (v1=pTCGroups->pTCG[i].nVertexNumber); /* t-group vertex */
147
+ for ( j = 0; j < pv1->num_adj_edges; j ++ ) {
148
+ /* e, pe - tautomeric atom edge; pv2 - endpoint vertex */
149
+ /* Note: pe, pv2, v1 are not used here; they are to show how to traverse t-group */
150
+ pv2 = pBNS->vert + (pe = pBNS->edge + (e=pv1->iedge[j]))->neighbor1;
151
+ if ( ret = AddToEdgeList( &TautEdges, e, INC_ADD_EDGE ) ) {
152
+ goto exit_function;
153
+ }
154
+ }
155
+ }
156
+ /* charge and flower edges */
157
+ for ( i = 0; i < pStruct->num_atoms; i ++ ) {
158
+ if ( (e=pVA[i].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
159
+ (ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE )) ) {
160
+ goto exit_function;
161
+ }
162
+ if ( (e=pVA[i].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
163
+ if ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) ) {
164
+ goto exit_function;
165
+ }
166
+
167
+ /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
168
+ if ( pVA[i].cNumValenceElectrons == 5 && !pVA[i].cMetal && /* N, P, As */
169
+ NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e ))) {
170
+
171
+ if ( !pBNS->edge[j].forbidden && pBNS->edge[j].flow ) {
172
+ if ( ret = AddToEdgeList( &AllChargeEdges, j, INC_ADD_EDGE ) ) {
173
+ goto exit_function;
174
+ }
175
+ if ( ret = AddToEdgeList( &NFlowerEdges, j, INC_ADD_EDGE ) ) {
176
+ goto exit_function;
177
+ }
178
+ } else {
179
+ if ( ret = AddToEdgeList( &OtherNFlowerEdges, j, INC_ADD_EDGE ) ) {
180
+ goto exit_function;
181
+ }
182
+ }
183
+ }
184
+
185
+ }
186
+ }
187
+ if ( forbidden_stereo_edge_mask ) {
188
+ for ( i = 0; i < pStruct->num_atoms; i ++ ) {
189
+ for ( j = 0; j < at2[i].valence; j ++ ) {
190
+ if ( pBNS->edge[k = pBNS->vert[i].iedge[j]].forbidden == forbidden_stereo_edge_mask ) {
191
+ int nMinRingSize = is_bond_in_Nmax_memb_ring( at2, i, j, pStruct->pbfsq->q,
192
+ pStruct->pbfsq->nAtomLevel,
193
+ pStruct->pbfsq->cSource, 99 /* max ring size */ );
194
+ if ( 0 < nMinRingSize && (ret = AddToEdgeList( &FixedLargeRingStereoEdges, k, INC_ADD_EDGE ))) {
195
+ goto exit_function;
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ INCHI_HEAPCHK
203
+
204
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
205
+ goto exit_function;
206
+ }
207
+ INCHI_HEAPCHK
208
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
209
+ goto exit_function;
210
+ }
211
+
212
+ INCHI_HEAPCHK
213
+
214
+
215
+
216
+
217
+ if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) &&
218
+ pc2i->nNumTgDBNMinusRevrs + pc2i->nNumTgNHMinusRevrs == 0 && pc2i->nNumTgOMinusInChI &&
219
+ !(pTCGroups->pTCG[0].tg_RestoreFlags & TGRF_MINUS_FIRST) ) {
220
+ /*----------------------------------------------------*/
221
+ /* case 01: restored has -O(-) and does not have N(-) */
222
+ /* endpoints defined by the original InChI */
223
+ /* restored has single taut. group or more */
224
+ /* tautomeric endpoints. */
225
+ /* Solution: move (-) from endp. -O(-) to endpoints N */
226
+ /*----------------------------------------------------*/
227
+ pTCGroups->pTCG[0].tg_RestoreFlags |= TGRF_MINUS_FIRST;
228
+ /* recalculate InChI from the structure */
229
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
230
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
231
+ goto exit_function;
232
+ }
233
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
234
+ goto exit_function;
235
+ }
236
+ if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
237
+ goto exit_function; /* no fixed-H found */
238
+ }
239
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
240
+ goto exit_function;
241
+ }
242
+ if ( !pc2i->bHasDifference ) {
243
+ goto exit_function; /* nothing to do */
244
+ }
245
+ }
246
+ if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) &&
247
+ pc2i->nNumTgDBNMinusRevrs + pc2i->nNumTgNHMinusRevrs == 0 && pc2i->nNumTgOMinusInChI == 0 ) {
248
+ /*-------------------------------------------------------*/
249
+ /* case 02: restored has no -O(-) and does not have N(-) */
250
+ /* restored has single taut. group or more */
251
+ /* tautomeric endpoints. */
252
+ /* Solution: >N-AB=N- => >N(+)=AB-NH- (add H(+)) */
253
+ /* Solution: >N-AB=NH => >N(+)=AB-NH2 (add H(+)) */
254
+ /* SB_N_III DB_N_III */
255
+ /*-------------------------------------------------------*/
256
+ int iat_SB_N_III[MAX_DIFF_MOBH], iat_DB_N_III[MAX_DIFF_MOBH];
257
+ int num_SB_N_III = 0, num_DB_N_III = 0, k1, k2;
258
+ CurrEdges.num_edges = 0;
259
+ cur_success = 0;
260
+ for ( i = 0; i < pStruct->num_atoms; i ++ ) {
261
+ iat = i;
262
+ if ( pVA[iat].cNumValenceElectrons == 5 && pVA[i].cPeriodicRowNumber == 1 &&
263
+ !at2[iat].endpoint && !at2[iat].charge && !at2[iat].radical ) {
264
+ if ( num_DB_N_III < MAX_DIFF_MOBH && !at2[iat].num_H &&
265
+ at2[iat].valence == 2 &&
266
+ at2[iat].chem_bonds_valence == 3 &&
267
+ !at2[iat].sb_parity[0] && /* do not eliminate stereobonds */
268
+ (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
269
+ pBNS->edge[e].cap && !pBNS->edge[e].flow ) {
270
+ /* -N= */
271
+ iat_DB_N_III[ num_DB_N_III ++ ] = iat;
272
+ } else
273
+ if ( num_DB_N_III < MAX_DIFF_MOBH && 1 == at2[iat].num_H &&
274
+ at2[iat].valence == 1 &&
275
+ at2[iat].chem_bonds_valence == 2 &&
276
+ !at2[iat].sb_parity[0] && /* do not eliminate stereobonds */
277
+ (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
278
+ pBNS->edge[e].cap && !pBNS->edge[e].flow ) {
279
+ /* -N= */
280
+ iat_DB_N_III[ num_DB_N_III ++ ] = iat;
281
+ } else
282
+ if ( num_SB_N_III < MAX_DIFF_MOBH && !at2[iat].num_H &&
283
+ at2[iat].valence == 3 &&
284
+ at2[iat].chem_bonds_valence == 3 &&
285
+ (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
286
+ pBNS->edge[e].cap && pBNS->edge[e].flow) {
287
+ /* -N< */
288
+ iat_SB_N_III[ num_SB_N_III ++ ] = iat;
289
+ if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
290
+ goto exit_function;
291
+ }
292
+ }
293
+ }
294
+ }
295
+ if ( num_DB_N_III && num_SB_N_III ) {
296
+ EdgeIndex ieMinus;
297
+ BNS_EDGE *peMinus;
298
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
299
+ RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
300
+ for ( i = 0; i < num_DB_N_III && !cur_success; i ++ ) {
301
+ iat = iat_DB_N_III[ i ];
302
+ e = pBNS->edge[k1=pBNS->vert[iat].iedge[0]].flow? k1 :
303
+ pBNS->edge[k2=pBNS->vert[iat].iedge[1]].flow? k2 : NO_VERTEX;
304
+ if ( e == NO_VERTEX ) {
305
+ continue; /* should not happen */
306
+ }
307
+ ieMinus = pVA[iat].nCMinusGroupEdge-1;
308
+ peMinus = pBNS->edge + ieMinus;
309
+ pe = pBNS->edge + e;
310
+ if ( !pe->flow )
311
+ continue;
312
+ pv1 = pBNS->vert + (v1 = pe->neighbor1);
313
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
314
+
315
+ pe->forbidden |= forbidden_edge_mask; /* fix double bond */
316
+ peMinus->forbidden &= forbidden_edge_mask_inv; /* allow negative charge */
317
+ delta = 1;
318
+ pe->flow -= delta; /* remove (-) from AB-O(-) */
319
+ pv1->st_edge.flow -= delta;
320
+ pv2->st_edge.flow -= delta;
321
+ pBNS->tot_st_flow -= 2*delta;
322
+
323
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
324
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
325
+
326
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
327
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
328
+ /* Added (-)charge -N= and (+) to -N< => nDeltaCharge == 2 */
329
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
330
+ if ( ret > 0 ) {
331
+ nNumRunBNS ++;
332
+ cur_success ++; /* 01 */
333
+
334
+ /* eliminate (-) charge and add H */
335
+ pv1 = pBNS->vert + (v1 = peMinus->neighbor1); /* atom */
336
+ pv2 = pBNS->vert + (v2 = peMinus->neighbor12 ^ v1);/* (=) vertex */
337
+ /* effectively eliminate (-) edge by setting its cap=flow= 0 */
338
+ peMinus->cap --;
339
+ peMinus->flow --;
340
+ pv1->st_edge.cap --;
341
+ pv1->st_edge.flow --;
342
+ pv2->st_edge.cap --;
343
+ pv2->st_edge.flow --;
344
+ pBNS->tot_st_flow -= 2;
345
+ pBNS->tot_st_cap -= 2;
346
+ /* add H */
347
+ pStruct->at[iat].num_H ++;
348
+ /* register total charge increase */
349
+ pTCGroups->total_charge ++;
350
+ pStruct->nNumRemovedProtonsByRevrs -= 1;
351
+ }
352
+ } else {
353
+ pe->forbidden &= forbidden_edge_mask_inv;
354
+ peMinus->forbidden |= forbidden_edge_mask;
355
+ pe->flow += delta;
356
+ pv1->st_edge.flow += delta;
357
+ pv2->st_edge.flow += delta;
358
+ pBNS->tot_st_flow += 2*delta;
359
+ }
360
+ }
361
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
362
+ CurrEdges.num_edges = 0; /* clear current edge list */
363
+
364
+ if ( cur_success ) {
365
+ tot_succes += cur_success;
366
+ /* recalculate InChI from the structure */
367
+ /* recalculate InChI from the structure */
368
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
369
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
370
+ goto exit_function;
371
+ }
372
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
373
+ goto exit_function;
374
+ }
375
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
376
+ goto exit_function;
377
+ }
378
+ if ( !pc2i->bHasDifference ) {
379
+ goto exit_function; /* nothing to do */
380
+ }
381
+ }
382
+ }
383
+ }
384
+ if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) && /* ADP */
385
+ pc2i->nNumTgMInChI == 0 && pc2i->nNumTgNInChI && pc2i->nNumTgOInChI ) {
386
+ /*-------------------------------------------------------*/
387
+ /* case 03: restored has N and O endpoints, no (-) endp */
388
+ /* case 04: original has single taut. group or more */
389
+ /* tautomeric endpoints. */
390
+ /* Solution: 1. Move taut attachment from O to N */
391
+ /* Solution: 2. Replace the attachment with (-) */
392
+ /* SB_N_III DB_N_III */
393
+ /*-------------------------------------------------------*/
394
+ /*
395
+ int iat_SB_N_III[MAX_DIFF_MOBH], iat_DB_N_III[MAX_DIFF_MOBH];
396
+ int num_SB_N_III = 0, num_DB_N_III = 0, k1, k2,
397
+ */
398
+ int itg, j1, j2, bAction = 0;
399
+ BNS_VERTEX *pTg, *pvEndp, *pvEndp2, *pvCent;
400
+ Vertex vEndp, vEndp2, vCent;
401
+ BNS_EDGE *peTg, *peTg2, *peCent1, *peCent2;
402
+ EdgeIndex eTg, eTg2;
403
+
404
+ CurrEdges.num_edges = 0;
405
+ CurrEdges2.num_edges = 0;
406
+ cur_success = 0;
407
+
408
+ /* 1st attempt: -NH-=O => -N(-)-=O or -N=-OH => -N(-)-=O */
409
+ for ( itg = 0; itg < pTCGroups->num_tgroups && !cur_success; itg ++ ) {
410
+ pTg = pBNS->vert + pTCGroups->pTCG[itg].nVertexNumber;
411
+ for ( i = 0; i < pTg->num_adj_edges && !cur_success; i ++ ) {
412
+ pvEndp = pBNS->vert + (vEndp = (peTg = pBNS->edge + (eTg=pTg->iedge[i]))->neighbor1);
413
+ eTg2 = -1;
414
+ if ( pVA[vEndp].cNumValenceElectrons == 6 && peTg->cap ) {
415
+ /* endpoint -OH or =O found; search for a possible centerpoint */
416
+ for ( j1 = 0; j1 < at2[vEndp].valence && eTg2 < 0; j1 ++ ) {
417
+ peCent1 = pBNS->edge + pvEndp->iedge[j1]; /* edge from O to a centerpoint */
418
+ pvCent = pBNS->vert + (vCent = peCent1->neighbor12 ^ vEndp); /* centerpoint */
419
+ if ( at2[vCent].endpoint || !peCent1->cap ||
420
+ peCent1->flow + (peTg->cap == peTg->flow) != 1 ) {
421
+ continue;
422
+ }
423
+ /* search for another endpoint, N, around vCent */
424
+ for ( j2 = 0; j2 < at2[vCent].valence; j2 ++ ) {
425
+ peCent2 = pBNS->edge + pvCent->iedge[j2];
426
+ pvEndp2 = pBNS->vert + (vEndp2 = peCent2->neighbor12 ^ vCent);
427
+ if ( !peCent2->cap || peCent2->flow+peCent1->flow != 1 ||
428
+ at2[vEndp2].endpoint != itg+1 ||
429
+ pVA[vEndp2].cNumValenceElectrons != 5 ||
430
+ 0 > (j=pVA[vEndp2].nTautGroupEdge-1) ||
431
+ (peTg2 = pBNS->edge + j)->forbidden ||
432
+ peCent2->flow + (peTg2->cap == peTg2->flow) != 1 ) {
433
+ continue;
434
+ }
435
+ eTg2 = j;
436
+ break; /* found OH-C=N- or O=C-NH- */
437
+ }
438
+ }
439
+ }
440
+ if ( eTg2 >= 0 ) {
441
+ /*--------------------------------------------
442
+ tg tg
443
+ eTg //\ eTg2 eTg / \\eTg2
444
+ // \ / \\
445
+ vEndp HO--C==N vEndp2 --> vEndp O==C--NH vEndp2
446
+ ^ ^ ^ ^ ^ ^
447
+ eCent1 | eCent2 eCent1 | eCent2
448
+ vCent vCent
449
+
450
+ additional action: -OH-C=N- => O=C-NH-
451
+ -------------------------------------------*/
452
+ if ( 0 == peTg->cap - peTg->flow && 1 == peTg2->cap - peTg2->flow &&
453
+ 0 == peCent1->flow && 1 == peCent2->flow ) {
454
+ peTg->flow --; /* 03 prepare */
455
+ peTg2->flow ++;
456
+ peCent2->flow --;
457
+ peCent1->flow ++;
458
+ bAction |= 1; /* switched H position */
459
+ }
460
+ if ( 1 == peTg->cap - peTg->flow && 0 == peTg2->cap - peTg2->flow &&
461
+ 1 == peCent1->flow && 0 == peCent2->flow ) {
462
+ /* replace -NH- with -N(-)- */
463
+ pTCGroups->pTCG[itg].tg_num_H --;
464
+ pTCGroups->pTCG[itg].tg_num_Minus ++;
465
+ pTCGroups->pTCG[itg].tg_RestoreFlags |= TGRF_MINUS_FIRST;
466
+ pTCGroups->pTCG[itg].tg_set_Minus = vEndp2+1;
467
+ pStruct->ti.t_group[itg].num[1] ++; /* increment number of (-), keep number of taut attachments */
468
+ pTCGroups->total_charge --;
469
+ pTCGroups->tgroup_charge --;
470
+ pStruct->nNumRemovedProtonsByRevrs += 1;
471
+ bAction |= 2; /* single NH (at2[vEndp2]) replaced with N(-) */
472
+ cur_success ++; /* 03/04 */
473
+ }
474
+ }
475
+ }
476
+ }
477
+
478
+ if ( 0 == pc2i->nNumTgNHInChI+ pc2i->nNumTgNH2InChI && pc2i->nNumTgOHInChI && !cur_success ) {
479
+ /* transfer an attachement to N */
480
+ for ( itg = 0; itg < pTCGroups->num_tgroups; itg ++ ) {
481
+ pTg = pBNS->vert + pTCGroups->pTCG[itg].nVertexNumber;
482
+ for ( i = 0; i < pTg->num_adj_edges; i ++ ) {
483
+ pvEndp = pBNS->vert + (vEndp = (peTg = pBNS->edge + (eTg=pTg->iedge[i]))->neighbor1);
484
+ if ( pVA[vEndp].cNumValenceElectrons == 6 &&
485
+ at2[vEndp].valence == at2[vEndp].chem_bonds_valence &&
486
+ peTg->flow && peTg->flow == peTg->cap ) {
487
+ /* endpoint -OH found; save the tautomeric group edge */
488
+ if ( ret = AddToEdgeList( &CurrEdges, eTg, INC_ADD_EDGE ) ) {
489
+ goto exit_function;
490
+ }
491
+ } else
492
+ if ( pVA[vEndp].cNumValenceElectrons == 5 &&
493
+ pVA[vEndp].cPeriodicRowNumber == 1 &&
494
+ at2[vEndp].valence + 1 == at2[vEndp].chem_bonds_valence &&
495
+ peTg->cap && peTg->flow + 1 == peTg->cap ) {
496
+ /* endpoint -N= or =NH found, check for -N=-OH */
497
+ e = -1;
498
+ for ( j1 = 0; j1 < at2[vEndp].valence && e < 0; j1 ++ ) {
499
+ peCent1 = pBNS->edge + pvEndp->iedge[j1];
500
+ if ( peCent1->flow == 1 ) {
501
+ /* double bond */
502
+ pvCent = pBNS->vert + (vCent = peCent1->neighbor12 ^ vEndp);
503
+ if ( at2[vCent].endpoint )
504
+ continue;
505
+ for ( j2 = 0; j2 < at2[vCent].valence; j2 ++ ) {
506
+ peCent2 = pBNS->edge + pvCent->iedge[j2];
507
+ pvEndp2 = pBNS->vert + (vEndp2 = peCent2->neighbor12 ^ vCent);
508
+ if ( peCent2->flow || at2[vEndp2].endpoint != itg+1 ||
509
+ pVA[vEndp2].cNumValenceElectrons != 6 ||
510
+ 0 >= (e=pVA[vEndp2].nTautGroupEdge-1) ||
511
+ pBNS->edge[e].forbidden || !pBNS->edge[e].flow ) {
512
+ e = -1;
513
+ continue;
514
+ }
515
+ /*********************/
516
+ /* found -N=X-OH */
517
+ /* vEndp ^ vEndp2 */
518
+ /* vCent */
519
+ /*********************/
520
+ /* save this -OH taut edge */
521
+ if ( ret = AddToEdgeList( &CurrEdges2, e, INC_ADD_EDGE ) ) {
522
+ goto exit_function;
523
+ }
524
+ break;
525
+ }
526
+ }
527
+ }
528
+ if ( e < 0 && (ret = AddToEdgeList( &CurrEdges, eTg, INC_ADD_EDGE )) ) {
529
+ goto exit_function;
530
+ }
531
+ }
532
+ }
533
+ }
534
+ /* rearrange the flows */
535
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
536
+ SetForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
537
+ SetForbiddenEdgeMask( pBNS, &CurrEdges2, forbidden_edge_mask );
538
+ pEdgeList = CurrEdges2.num_edges? &CurrEdges2 : CurrEdges.num_edges? &CurrEdges : NULL;
539
+
540
+ for ( i = 0; pEdgeList && i < pEdgeList->num_edges && !cur_success; i ++ ) {
541
+ pe = pBNS->edge + pEdgeList->pnEdges[i]; /* pe->flow = 1 <=> -OH */
542
+ if ( !pe->flow )
543
+ continue;
544
+ pv1 = pBNS->vert + (v1 = pe->neighbor1); /* -OH atom */
545
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1); /* t-group vertex */
546
+ /* locate the t-group */
547
+ for ( itg = 0; itg < pTCGroups->num_tgroups; itg ++ ) {
548
+ if ( v2 == pTCGroups->pTCG[itg].nVertexNumber ) {
549
+ break;
550
+ }
551
+ }
552
+ if ( itg == pTCGroups->num_tgroups ) {
553
+ /* tgroup not found -- should not happen */
554
+ continue;
555
+ }
556
+
557
+ delta = 1;
558
+ pe->flow -= delta; /* add one attachment to */
559
+ pv1->st_edge.flow -= delta;
560
+ pv2->st_edge.flow -= delta;
561
+ pBNS->tot_st_flow -= 2*delta;
562
+
563
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
564
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
565
+
566
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
567
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
568
+ /* Added (-)charge -N= and (+) to -N< => nDeltaCharge == 2 */
569
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
570
+ if ( ret > 0 ) {
571
+ nNumRunBNS ++;
572
+ cur_success ++; /* 03 */
573
+ /* replace -NH- with -N(-)- */
574
+ pTCGroups->pTCG[itg].tg_num_H --;
575
+ pTCGroups->pTCG[itg].tg_num_Minus ++;
576
+ pTCGroups->pTCG[itg].tg_RestoreFlags |= TGRF_MINUS_FIRST;
577
+ pStruct->ti.t_group[itg].num[1] ++;
578
+ pTCGroups->total_charge --;
579
+ pTCGroups->tgroup_charge --;
580
+ pStruct->nNumRemovedProtonsByRevrs += 1;
581
+ bAction |= 4; /* H in the 1st available NH was replaced with (-) */
582
+ }
583
+ } else {
584
+ pe->flow += delta;
585
+ pv1->st_edge.flow += delta;
586
+ pv2->st_edge.flow += delta;
587
+ pBNS->tot_st_flow += 2*delta;
588
+ }
589
+ }
590
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
591
+ RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
592
+ RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
593
+ } else
594
+ if ( pc2i->nNumTgNHInChI+ pc2i->nNumTgNH2InChI && pc2i->nNumTgOInChI && !cur_success ) {
595
+ /* change an attachement to N from H to (-) */
596
+ for ( itg = 0; itg < pTCGroups->num_tgroups && !cur_success; itg ++ ) {
597
+ pTg = pBNS->vert + pTCGroups->pTCG[itg].nVertexNumber;
598
+ for ( i = 0; i < pTg->num_adj_edges && !cur_success; i ++ ) {
599
+ pvEndp2 = pBNS->vert + (vEndp2 = (peTg = pBNS->edge + pTg->iedge[i])->neighbor1);
600
+ if ( pVA[vEndp2].cNumValenceElectrons == 5 && pVA[vEndp2].cPeriodicRowNumber == 1 &&
601
+ at2[vEndp2].valence == at2[vEndp2].chem_bonds_valence &&
602
+ peTg->flow && peTg->flow == peTg->cap ) {
603
+ /* endpoint -NHn found; change its charge */
604
+ cur_success ++; /* 04 */
605
+ /* replace -NH- with -N(-)- */
606
+ pTCGroups->pTCG[itg].tg_num_H --;
607
+ pTCGroups->pTCG[itg].tg_num_Minus ++;
608
+ pTCGroups->pTCG[itg].tg_RestoreFlags |= TGRF_MINUS_FIRST;
609
+ pTCGroups->pTCG[itg].tg_set_Minus = vEndp2 + 1;
610
+ pStruct->ti.t_group[itg].num[1] ++;
611
+ pTCGroups->total_charge --;
612
+ pTCGroups->tgroup_charge --;
613
+ pStruct->nNumRemovedProtonsByRevrs += 1;
614
+ bAction |= 8; /* manually set (-) charge to NH atom, vEndp2 */
615
+ }
616
+ }
617
+ }
618
+ }
619
+ if ( cur_success ) {
620
+ tot_succes += cur_success;
621
+ /* recalculate InChI from the structure */
622
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
623
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
624
+ goto exit_function;
625
+ }
626
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
627
+ goto exit_function;
628
+ }
629
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
630
+ goto exit_function;
631
+ }
632
+ if ( pStruct->One_ti.num_t_groups == 1 && pStruct->One_ti.t_group[0].num[1] ) {
633
+ /* this method did not work: no alt path from N(-) to =O */
634
+ itg = 0;
635
+ if ( bAction & (8 | 2 ) ) {
636
+ /* roll back NH -> N(-) replacement; H move from OH to N is not undone */
637
+ pTCGroups->pTCG[itg].tg_num_H ++;
638
+ pTCGroups->pTCG[itg].tg_num_Minus --;
639
+ pTCGroups->pTCG[itg].tg_RestoreFlags &= ~TGRF_MINUS_FIRST;
640
+ pTCGroups->pTCG[itg].tg_set_Minus = 0;
641
+ pStruct->ti.t_group[itg].num[1] --;
642
+ pTCGroups->total_charge ++;
643
+ pTCGroups->tgroup_charge ++;
644
+ pStruct->nNumRemovedProtonsByRevrs -= 1;
645
+ cur_success --;
646
+ } else
647
+ if ( bAction & 4 ) {
648
+ pTCGroups->pTCG[itg].tg_num_H ++;
649
+ pTCGroups->pTCG[itg].tg_num_Minus --;
650
+ pTCGroups->pTCG[itg].tg_RestoreFlags &= ~TGRF_MINUS_FIRST;
651
+ pStruct->ti.t_group[itg].num[1] --;
652
+ pTCGroups->total_charge ++;
653
+ pTCGroups->tgroup_charge ++;
654
+ pStruct->nNumRemovedProtonsByRevrs -= 1;
655
+ cur_success --;
656
+ } else {
657
+ ret = RI_ERR_PROGR;
658
+ goto exit_function;
659
+ }
660
+ /* recalculate InChI from the structure */
661
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
662
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
663
+ goto exit_function;
664
+ }
665
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
666
+ goto exit_function;
667
+ }
668
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
669
+ goto exit_function;
670
+ }
671
+ }
672
+ if ( !pc2i->bHasDifference ) {
673
+ goto exit_function; /* nothing to do */
674
+ }
675
+ }
676
+ }
677
+
678
+ if ( pc2i->nNumTgInChI == 1 && ( pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1 ) && /* ADP */
679
+ pc2i->nNumTgMInChI == 0 && (pc2i->nNumTgNInChI || pc2i->nNumTgOInChI) &&
680
+ NO_VERTEX != (vPlusMinus = GetPlusMinusVertex( pBNS, pTCGroups, 1, 1 )) ) {
681
+ /*---------------------------------------------------------------------------*/
682
+ /* case 05: restored has N endpoints, no (-) endpoints */
683
+ /* original has single taut. group or more */
684
+ /* tautomeric endpoints. */
685
+ /* Solution: Find -N< and allow (+) charge change */
686
+ /* Fix all charges and taut attachments exept */
687
+ /* =N- and =O (taut. endpoints) */
688
+ /* Increment st_edge.cap on (+/-) vertex => add (+) charge to -N< */
689
+ /* Increment tot. charge in other places */
690
+ /* Increment t-group st_edge.cap */
691
+ /* Run BNS */
692
+ /* */
693
+ /* (+/-)* (+/-) Result: */
694
+ /* | || */
695
+ /* | || - Added (+) to -N< */
696
+ /* (+)super (+)super - Added attachment point to O */
697
+ /* || | */
698
+ /* || => | To make this attachment H, */
699
+ /* (Y) (Y) increment */
700
+ /* | || pTCGroups->pTCG[itg].tg_num_H */
701
+ /* | || */
702
+ /* (+)hetero (+)hetero Technical details: */
703
+ /* \\ \ increase capacities of */
704
+ /* N N(+) edges to (+/-) otherwise */
705
+ /* | || flow may not be able to */
706
+ /* *(t)--O=R. (t)==O-R. increase */
707
+ /* */
708
+ /* */
709
+ /*---------------------------------------------------------------------------*/
710
+ int itg;
711
+ BNS_VERTEX *pTg, *pvEndp;
712
+ Vertex vEndp, vTg;
713
+ BNS_EDGE *peTg;
714
+ EdgeIndex eTg;
715
+ AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
716
+
717
+ CurrEdges.num_edges = 0;
718
+ CurrEdges2.num_edges = 0;
719
+ cur_success = 0;
720
+ /* find -N< and non-taut =N- or =O */
721
+ for ( i = 0; i < pStruct->num_atoms; i ++ ) {
722
+ iat = nCanon2AtnoRevrs[i];
723
+ /* -N< */
724
+ if ( !at2[iat].endpoint && !at2[iat].charge && !at2[iat].radical && !at2[iat].num_H &&
725
+ pVA[i].cNumValenceElectrons == 5 && pVA[i].cPeriodicRowNumber == 1 &&
726
+ 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && pBNS->edge[e].flow && !pBNS->edge[e].forbidden) {
727
+
728
+ if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
729
+ goto exit_function;
730
+ }
731
+ }
732
+ }
733
+ if ( !CurrEdges.num_edges ) {
734
+ goto exit_case_05;
735
+ }
736
+ /* find taut -N= and =O */
737
+ for ( itg = 0; itg < pTCGroups->num_tgroups && !cur_success; itg ++ ) {
738
+ CurrEdges2.num_edges = 0;
739
+ pTg = pBNS->vert + (vTg = pTCGroups->pTCG[itg].nVertexNumber);
740
+ for ( i = 0; i < pTg->num_adj_edges; i ++ ) {
741
+ pvEndp = pBNS->vert + (vEndp = (peTg = pBNS->edge + (eTg=pTg->iedge[i]))->neighbor1);
742
+ if ( at2[vEndp].charge || at2[vEndp].radical || peTg->cap - peTg->flow != 1 ) {
743
+ continue;
744
+ }
745
+ /* t-group edges to -N= and =O */
746
+ if ( ret = AddToEdgeList( &CurrEdges2, eTg, INC_ADD_EDGE ) ) {
747
+ goto exit_function;
748
+ }
749
+ }
750
+ if ( !CurrEdges2.num_edges ) {
751
+ goto exit_case_05;
752
+ }
753
+ /* fix all charge edges except -N< and all taut. edges except =O and =N- */
754
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
755
+ SetForbiddenEdgeMask( pBNS, &TautEdges, forbidden_edge_mask );
756
+ RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
757
+ RemoveForbiddenEdgeMask( pBNS, &CurrEdges2, forbidden_edge_mask );
758
+ delta = 1;
759
+ /* Increment st_edge.cap on (+/-) vertex */
760
+ pBNS->vert[vPlusMinus].st_edge.cap += delta;
761
+ /* Increment st_edge.cap on t-group */
762
+ pTg->st_edge.cap += delta;
763
+ /* total cap count */
764
+ pBNS->tot_st_cap += 2*delta;
765
+
766
+ v1 = vPlusMinus;
767
+ v2 = vTg;
768
+
769
+ /* increase capacities of edges to Y */
770
+ for ( i = 0; i < pBNS->vert[vPlusMinus].num_adj_edges; i ++ ) {
771
+ j = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i]].neighbor12 ^ vPlusMinus;
772
+ for ( k = 0; k < pBNS->vert[j].num_adj_edges; k ++ ) {
773
+ pBNS->edge[pBNS->vert[j].iedge[k]].cap += delta;
774
+ }
775
+ }
776
+
777
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
778
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
779
+
780
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
781
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
782
+ /* Added (+)charge to -N< => nDeltaCharge == 1 */
783
+ /* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */
784
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
785
+ if ( ret > 0 ) {
786
+ nNumRunBNS ++;
787
+ cur_success ++; /* 01 */
788
+ /* update bookkeeping */
789
+ pTCGroups->total_charge += delta;
790
+ pTCGroups->pTCG[itg].edges_cap += delta;
791
+ pTCGroups->pTCG[itg].tg_num_H += delta;
792
+ pStruct->nNumRemovedProtonsByRevrs -= delta;
793
+ }
794
+ } else {
795
+ pBNS->vert[vPlusMinus].st_edge.cap -= delta;
796
+ pTg->st_edge.cap -= delta;
797
+ /*pTCGroups->pTCG[itg].edges_cap -= delta;*/ /* ???bug??? - commented out 2006-03-22 */
798
+ pBNS->tot_st_cap -= 2*delta;
799
+ /* decrease capacities of edges to Y */
800
+ for ( i = 0; i < pBNS->vert[vPlusMinus].num_adj_edges; i ++ ) {
801
+ j = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i]].neighbor12 ^ vPlusMinus;
802
+ for ( k = 0; k < pBNS->vert[j].num_adj_edges; k ++ ) {
803
+ pBNS->edge[pBNS->vert[j].iedge[k]].cap -= delta;
804
+ }
805
+ }
806
+ }
807
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
808
+ RemoveForbiddenEdgeMask( pBNS, &TautEdges, forbidden_edge_mask );
809
+ }
810
+ if ( cur_success ) {
811
+ tot_succes += cur_success;
812
+ /* recalculate InChI from the structure */
813
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
814
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
815
+ goto exit_function;
816
+ }
817
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
818
+ goto exit_function;
819
+ }
820
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
821
+ goto exit_function;
822
+ }
823
+ if ( !pc2i->bHasDifference ) {
824
+ goto exit_function; /* nothing to do */
825
+ }
826
+ }
827
+
828
+ exit_case_05:;
829
+ }
830
+
831
+ while ( pc2i->nNumDiffMobH && pc2i->nChargeMobHRevrs > pc2i->nChargeMobHInChI ) {
832
+ /*----------------------------------------------------*/
833
+ /* case 06: restored has extra H attached to -O(-) */
834
+ /* while the chrge should be on C, most pro- */
835
+ /* bably in a small ring.ut. group or more */
836
+ /* tautomeric endpoints. */
837
+ /* Solution: move (-) from O to C */
838
+ /*----------------------------------------------------*/
839
+ int iO, mode;
840
+ EdgeIndex e2;
841
+ BNS_EDGE *pe2;
842
+ cur_success = 0;
843
+ for ( i = 0; !cur_success && i < pc2i->len_c2at; i ++ ) {
844
+
845
+ if ( pc2i->c2at[i].nMobHRevrs == pc2i->c2at[i].nMobHInChI + 1 &&
846
+ pc2i->c2at[i].nNumHRevrs == pc2i->c2at[i].nMobHInChI &&
847
+ !pc2i->c2at[i].endptInChI && !pc2i->c2at[i].endptRevrs &&
848
+ at2[iO = pc2i->c2at[i].atomNumber].charge == -1 &&
849
+ 0 <= (e=pVA[iO].nCMinusGroupEdge-1) && (pe=pBNS->edge+e)->flow ) {
850
+
851
+ /* try suitable atoms C */
852
+ /* first look for =C= in a small ring */
853
+
854
+ for( mode = 4; !cur_success && mode <= 8; mode ++ ) {
855
+
856
+ if ( mode == 8 )
857
+ mode = 99;
858
+
859
+ for ( iat = 0; !cur_success && iat < pStruct->num_atoms; iat ++ ) {
860
+
861
+ if ( !at2[iat].charge && !at2[iat].radical &&
862
+ pVA[iat].cNumValenceElectrons == 4 &&
863
+ 0 <= (e2=pVA[iat].nCMinusGroupEdge-1) && !(pe2=pBNS->edge+e2)->flow &&
864
+ 0 < bIsUnsatCarbonInASmallRing( at2, pVA, iat, pStruct->pbfsq, mode ) ) {
865
+
866
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
867
+ /* allow negative charge on the chosen carbon */
868
+ pe2->forbidden &= forbidden_edge_mask_inv;
869
+
870
+ delta = 1;
871
+ if ( !pe->flow )
872
+ continue;
873
+ pv1 = pBNS->vert + (v1 = pe->neighbor1);
874
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
875
+ pe->flow -= delta;
876
+ pv1->st_edge.flow -= delta;
877
+ pv2->st_edge.flow -= delta;
878
+ pBNS->tot_st_flow -= 2*delta;
879
+
880
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
881
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
882
+
883
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
884
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
885
+ /* Added (-)charge to unsaturated C => nDeltaCharge == 2 */
886
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
887
+ if ( ret > 0 ) {
888
+ nNumRunBNS ++;
889
+ cur_success ++; /* 01 */
890
+ tot_succes += cur_success;
891
+ }
892
+ } else {
893
+ pe->forbidden |= forbidden_edge_mask;
894
+ pe->flow += delta;
895
+ pv1->st_edge.flow += delta;
896
+ pv2->st_edge.flow += delta;
897
+ pBNS->tot_st_flow += 2*delta;
898
+ }
899
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
900
+ }
901
+ }
902
+ }
903
+ }
904
+ }
905
+ if ( cur_success ) {
906
+ /* recalculate InChI from the structure */
907
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
908
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
909
+ goto exit_function;
910
+ }
911
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
912
+ goto exit_function;
913
+ }
914
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
915
+ goto exit_function;
916
+ }
917
+ if ( !pc2i->bHasDifference ) {
918
+ goto exit_function; /* nothing to do */
919
+ }
920
+ } else {
921
+ break;
922
+ }
923
+ }
924
+ if ( pc2i->len_c2at && pc2i->nChargeMobHRevrs > pc2i->nChargeMobHInChI ) {
925
+ /*------------------------------------------------------------------*/
926
+ /* case 07: -NO2 are to be tautomeric but they are not AND */
927
+ /* InChI has a SINGLE tautomeric group */
928
+ /* */
929
+ /* (-)O (-)O */
930
+ /* Solution: convert \ \ */
931
+ /* N-X=...-Z(-) => N(+)=X- ...=Z */
932
+ /* // / */
933
+ /* O (-)O */
934
+ /* */
935
+ /* O O */
936
+ /* or \\ \\ */
937
+ /* N-X=...-Z(-) => N=X- ...=Z */
938
+ /* // / */
939
+ /* O (-)O */
940
+ /* */
941
+ /* */
942
+ /* (a) move (-) from other tautomeric atom to O in O=N-X */
943
+ /* or from other atom that has to be tautomeric */
944
+ /* but is not */
945
+ /* (b) create (+) [ion pair creation] on N as in */
946
+ /* */
947
+ /* OH OH */
948
+ /* / / */
949
+ /* -C=N => =C-N(+) */
950
+ /* \\ \\ */
951
+ /* O O */
952
+ /* */
953
+ /*------------------------------------------------------------------*/
954
+ int num_DB_O = 0;
955
+ short iat_DB_O[MAX_DIFF_FIXH], iat_NO2[MAX_DIFF_FIXH];
956
+ AT_NUMB *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
957
+ /*
958
+ AT_NUMB *nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
959
+ */
960
+ inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[0] &&
961
+ pStruct->pOne_norm_data[0]->at)? pStruct->pOne_norm_data[0]->at : NULL;
962
+
963
+ int iN, one_success;
964
+ BNS_EDGE *peDB_O_Minus;
965
+ int neigh, nNumO, nNumOthers;
966
+ #define CHG_SET_WRONG_TAUT_N 0
967
+ #define CHG_SET_WRONG_TAUT_O 1
968
+ #define CHG_SET_WRONG_TAUT_ALL 2
969
+ #define CHG_LAST_SET 2 /* the last index in trying */
970
+ #define CHG_SET_O_FIXED 3
971
+ #define CHG_SET_NUM 4
972
+ EDGE_LIST ChangeableEdges[CHG_SET_NUM];
973
+ memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
974
+ /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
975
+ /*
976
+ S_CHAR *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
977
+ pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
978
+ */
979
+ CurrEdges.num_edges = 0; /* clear current edge list */
980
+ cur_success = 0;
981
+ for ( i = 0; i < pStruct->num_atoms; i ++ ) {
982
+ iat = nCanon2AtnoRevrs[i];
983
+ if ( /* orig. InChI info: taut in orig. InChI =O located in -NO2 that is not taut in Reconstructed InChI */
984
+ num_DB_O < MAX_DIFF_FIXH &&
985
+ pVA[iat].cNumValenceElectrons == 6 /* O, S, Se, Te */ &&
986
+ (!at2[iat].endpoint /*|| pc2i->c2at[i].nMobHInChI*/) &&
987
+ (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
988
+ at2[iat].num_H == 0 && /*pc2i->c2at[i].nMobHInChI == 1 &&*/
989
+ /* reversed structure info: */
990
+ !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) /*|| pc2i->c2at[i].nMobHRevrs*/ &&
991
+ !at2[iat].charge &&
992
+ at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 &&
993
+ /* find whether it belongs to NO2 */
994
+ pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons == 5 &&
995
+ at2[iN].valence == 3 && (at2[iN].charge == 0 || at2[iN].charge == 1) &&
996
+ at2[iN].chem_bonds_valence == 5 - at2[iN].charge ) {
997
+ /* find the second O */
998
+ nNumO = nNumOthers = 0;
999
+ for ( k = 0; k < at2[iN].valence; k ++ ) {
1000
+ neigh = at2[iN].neighbor[k];
1001
+ if ( neigh == iat ) {
1002
+ continue;
1003
+ }
1004
+ if ( pVA[neigh].cNumValenceElectrons == 6 &&
1005
+ !at2[neigh].endpoint &&
1006
+ !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[neigh].endpoint) &&
1007
+ at2[neigh].valence == 1 && at2[neigh].num_H == 0 &&
1008
+ at2[neigh].radical == 0 && (at2[neigh].charge == 0 || at2[neigh].charge == -1) &&
1009
+ at2[neigh].chem_bonds_valence - at2[neigh].charge == 2) {
1010
+ nNumO ++;
1011
+ } else
1012
+ if ( at2[iN].bond_type[k] == BOND_TYPE_SINGLE &&
1013
+ at2[neigh].valence > 1 &&
1014
+ at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
1015
+ nNumOthers ++;
1016
+ }
1017
+ }
1018
+ if ( nNumO != 1 || nNumOthers != 1 ) {
1019
+ continue;
1020
+ }
1021
+ for ( k = 0; k < num_DB_O; k ++ ) {
1022
+ if ( iat_NO2[k] == iN ) {
1023
+ break;
1024
+ }
1025
+ }
1026
+ if ( k == num_DB_O ) {
1027
+ iat_NO2[num_DB_O] = iN;
1028
+ iat_DB_O[num_DB_O ++] = iat;
1029
+ }
1030
+ /* save the =O (-)-edge to avoid interference */
1031
+ if ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) ) {
1032
+ goto exit_case_07;
1033
+ }
1034
+ }
1035
+ }
1036
+ if ( num_DB_O ) {
1037
+ /* search for falsely tautomeric negatively charged atoms N and O */
1038
+ for ( i = 0; i < pc2i->len_c2at; i ++ ) {
1039
+ iat = pc2i->c2at[i].atomNumber;
1040
+ if ( pc2i->c2at[i].endptRevrs && !pc2i->c2at[i].endptInChI &&
1041
+ pc2i->c2at[i].nAtChargeRevrs == - 1 &&
1042
+ 0 <= (e=pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
1043
+ 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) ) {
1044
+ if ( pc2i->c2at[i].nValElectr == 6 ) {
1045
+ if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT_O], e, INC_ADD_EDGE ) ) {
1046
+ goto exit_case_07;
1047
+ }
1048
+ } else
1049
+ if ( pc2i->c2at[i].nValElectr == 5 ) {
1050
+ if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT_N], e, INC_ADD_EDGE ) ) {
1051
+ goto exit_case_07;
1052
+ }
1053
+ }
1054
+ if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT_ALL], e, INC_ADD_EDGE ) ) {
1055
+ goto exit_case_07;
1056
+ }
1057
+ }
1058
+ }
1059
+ /* ------- finally, try to move charges from O=N --------------*/
1060
+ for ( i = 0; i < num_DB_O; i ++ ) {
1061
+ int nDeltaChargeExpected;
1062
+ one_success = 0;
1063
+ delta = 1;
1064
+ iat = iat_DB_O[i];
1065
+ peDB_O_Minus = pBNS->edge + (pVA[iat].nCMinusGroupEdge-1);
1066
+ pe = pBNS->edge + pBNS->vert[iat].iedge[0];
1067
+
1068
+ if ( !pe->flow )
1069
+ continue;
1070
+ pv1 = pBNS->vert + (v1 = pe->neighbor1);
1071
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1072
+
1073
+ pe->forbidden |= forbidden_edge_mask;
1074
+
1075
+ pe->flow -= delta;
1076
+ pv1->st_edge.flow -= delta;
1077
+ pv2->st_edge.flow -= delta;
1078
+ pBNS->tot_st_flow -= 2*delta;
1079
+
1080
+ for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
1081
+ if ( !ChangeableEdges[k].num_edges ) {
1082
+ continue;
1083
+ }
1084
+ nDeltaChargeExpected = 0;
1085
+
1086
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1087
+ RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask );
1088
+ /* allow (-) charge to move to N=O */
1089
+ peDB_O_Minus->forbidden &= forbidden_edge_mask_inv;
1090
+
1091
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1092
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1093
+
1094
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1095
+ vPathEnd == v2 && vPathStart == v1) &&
1096
+ nDeltaCharge == nDeltaChargeExpected ) {
1097
+ /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
1098
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1099
+ if ( ret > 0 ) {
1100
+ nNumRunBNS ++;
1101
+ one_success ++; /* 07 */
1102
+ }
1103
+ }
1104
+ INCHI_HEAPCHK
1105
+ }
1106
+ cur_success += one_success;
1107
+
1108
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
1109
+ pe->forbidden &= forbidden_edge_mask_inv;
1110
+
1111
+ if ( !one_success ) {
1112
+ pe->flow += delta;
1113
+ pv1->st_edge.flow += delta;
1114
+ pv2->st_edge.flow += delta;
1115
+ pBNS->tot_st_flow += 2*delta;
1116
+ }
1117
+ }
1118
+ }
1119
+ exit_case_07:
1120
+ for ( i = 0; i < CHG_SET_NUM; i ++ ) {
1121
+ AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
1122
+ }
1123
+
1124
+ CurrEdges.num_edges = 0; /* clear current edge list */
1125
+ if ( cur_success ) {
1126
+ tot_succes += cur_success;
1127
+ /* recalculate InChI from the structure */
1128
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1129
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1130
+ goto exit_function;
1131
+ }
1132
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1133
+ goto exit_function;
1134
+ }
1135
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1136
+ goto exit_function;
1137
+ }
1138
+ if ( !pc2i->bHasDifference ) {
1139
+ goto exit_function; /* nothing to do */
1140
+ }
1141
+ }
1142
+ #undef CHG_SET_NOOH
1143
+ #undef CHG_SET_WRONG_TAUT
1144
+ #undef CHG_SET_TAUT
1145
+ #undef CHG_LAST_SET
1146
+ #undef CHG_SET_O_FIXED
1147
+ #undef CHG_SET_NUM
1148
+ }
1149
+
1150
+
1151
+
1152
+ exit_function:
1153
+ AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
1154
+ AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
1155
+ AllocEdgeList( &CurrEdges2, EDGE_LIST_FREE );
1156
+ AllocEdgeList( &CurrEdges3, EDGE_LIST_FREE );
1157
+ AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
1158
+ AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
1159
+ AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_FREE );
1160
+ AllocEdgeList( &TautEdges, EDGE_LIST_FREE );
1161
+
1162
+
1163
+ return ret;
1164
+ }
1165
+
1166
+ #endif