rino 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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