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,1287 @@
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 FixRestoredStructureStereo( INCHI_MODE cmpInChI, ICR *icr, INCHI_MODE cmpInChI2, ICR *icr2,
45
+ ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
46
+ StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
47
+ ALL_TC_GROUPS *pTCGroups, T_GROUP_INFO **ppt_group_info, inp_ATOM **ppat_norm,
48
+ inp_ATOM **ppat_prep, INChI *pInChI[], long num_inp,
49
+ int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
50
+ {
51
+ /*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
52
+ /* at2 should be the most recently restored atom, Fixed-H */
53
+ int i, j, k, delta, tot_succes, max_success, cur_success, ret = 0;
54
+ int err, iOrigInChI, iRevrInChI;
55
+ int j12, v1, v2, e, vRad;
56
+ BNS_VERTEX *pv1, *pv2, *pvRad;
57
+ BNS_EDGE *pe, *peRad;
58
+ EDGE_LIST AllChargeEdges, CurrEdges, NFlowerEdges, OtherNFlowerEdges, FixedStereoEdges, AllRadList;
59
+ EDGE_LIST TautMinusEdges[2]; /* 0 -> O & O(+), 1=> N & N(+) */
60
+
61
+ Vertex vPathStart, vPathEnd;
62
+ int nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
63
+ INChI_Stereo *pStereoInChI, *pStereo2InChI, *pStereoRevrs, *pStereo2Revrs;
64
+
65
+ /* Stereo */
66
+
67
+ /* currently being processed layer */
68
+ pStereoInChI = (pInChI[0]->StereoIsotopic &&
69
+ pInChI[0]->StereoIsotopic->nNumberOfStereoBonds +
70
+ pInChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
71
+ pInChI[0]->StereoIsotopic : pInChI[0]->Stereo;
72
+
73
+ /* mobile-H layer in case of Fixed-H */
74
+ pStereo2InChI = (pStruct->bMobileH == TAUT_YES || !pInChI[1] ||
75
+ !pInChI[1]->nNumberOfAtoms || pInChI[1]->bDeleted)?
76
+ NULL:
77
+ (pInChI[1]->StereoIsotopic &&
78
+ pInChI[1]->StereoIsotopic->nNumberOfStereoBonds +
79
+ pInChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
80
+ pInChI[1]->StereoIsotopic :
81
+ pInChI[1]->Stereo;
82
+
83
+ /* currently being processed layer */
84
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
85
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
86
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
87
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
88
+
89
+ /* mobile-H layer in case of Fixed-H */
90
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
91
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
92
+ NULL:
93
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
94
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
95
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
96
+ pStruct->pOneINChI[1]->StereoIsotopic :
97
+ pStruct->pOneINChI[1]->Stereo;
98
+
99
+ INCHI_HEAPCHK
100
+
101
+ AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
102
+ AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
103
+ AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
104
+ AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
105
+ AllocEdgeList( &FixedStereoEdges, EDGE_LIST_CLEAR );
106
+ AllocEdgeList( &AllRadList, EDGE_LIST_CLEAR );
107
+
108
+ AllocEdgeList( TautMinusEdges+0, EDGE_LIST_CLEAR );
109
+ AllocEdgeList( TautMinusEdges+1, EDGE_LIST_CLEAR );
110
+
111
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
112
+ if ( cmpInChI & IDIF_PROBLEM ) {
113
+ ret = RI_ERR_PROGR; /* severe restore problem */
114
+ goto exit_function;
115
+ }
116
+ if ( err ) {
117
+ ret = RI_ERR_ALLOC;
118
+ goto exit_function;
119
+ }
120
+
121
+ cmpInChI2 = 0;
122
+
123
+ if ( pStruct->bMobileH == TAUT_NON ) {
124
+ /* these indexes are used to compare Mobile-H InChI */
125
+ iOrigInChI = (pInChI[1] && pInChI[1]->nNumberOfAtoms && !pInChI[1]->bDeleted)? 1 : 0;
126
+ iRevrInChI = (pStruct->pOneINChI[1] &&pStruct->pOneINChI[1]->nNumberOfAtoms && !pStruct->pOneINChI[1]->bDeleted)? 1 : 0;
127
+ } else {
128
+ iOrigInChI = 0;
129
+ iRevrInChI = 0;
130
+ }
131
+
132
+ memset ( icr2, 0, sizeof(*icr2) );
133
+ if ( iRevrInChI || iOrigInChI ) {
134
+ /* additional mobile-H compare in case of Fixed-H */
135
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
136
+ if ( cmpInChI & IDIF_PROBLEM ) {
137
+ ret = RI_ERR_PROGR; /* severe restore problem */
138
+ goto exit_function;
139
+ }
140
+ if ( err ) {
141
+ ret = RI_ERR_ALLOC;
142
+ goto exit_function;
143
+ }
144
+ }
145
+
146
+
147
+ if ( !(cmpInChI & IDIFF_SB) && !(cmpInChI2 & IDIFF_SB) ) {
148
+ goto exit_function;
149
+ }
150
+ /* need to temporarily remove fixing of stereogenic bonds */
151
+ for ( i = 0; i < pStruct->num_atoms; i ++ ) {
152
+ pv1 = pBNS->vert + i;
153
+ for ( j = 0; j < at2[i].valence; j ++ ) {
154
+ pe = pBNS->edge + (e=pv1->iedge[j]);
155
+ if ( j == pe->neighbor1 ) {
156
+ /* do not store same bond 2 times */
157
+ if ( (pe->forbidden & forbidden_stereo_edge_mask) &&
158
+ (ret = AddToEdgeList( &FixedStereoEdges, e, INC_ADD_EDGE ) ) ) {
159
+ goto exit_function;
160
+ }
161
+ }
162
+ }
163
+ }
164
+
165
+
166
+ tot_succes = 0;
167
+ cur_success = 0;
168
+ if ( (cmpInChI & IDIF_SB_MISS) && (!cmpInChI2 || (cmpInChI2 & IDIF_SB_MISS)) &&
169
+ 0 < (max_success = pBNS->tot_st_cap - pBNS->tot_st_flow) ) {
170
+ /*----------------------------------------------------*/
171
+ /* case 01: extra stereogenic bond, radical present */
172
+ /* X=N-O* => X=N=O and eliminate radical */
173
+ /*----------------------------------------------------*/
174
+ int aN;
175
+ BNS_VERTEX *pvO, *pvN;
176
+ BNS_EDGE *peNO;
177
+
178
+ RemoveForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
179
+
180
+ for ( i = 0; i < icr->num_sb_in2_only && cur_success < max_success; i ++ ) {
181
+ j12 = icr->sb_in2_only[i];
182
+ pv1 = pBNS->vert + (v1 = pStereoInChI->nBondAtom1[j12]-1);
183
+ pv2 = pBNS->vert + (v2 = pStereoInChI->nBondAtom2[j12]-1);
184
+ for ( k = 0; k < at2[v1].valence; k ++ ) {
185
+ pe = pBNS->edge + (e = pv1->iedge[k]);
186
+ if ( v2 == (pe->neighbor12 ^ v1) )
187
+ break; /* the edge has been found */
188
+ }
189
+ if ( k == at2[v1].valence ) {
190
+ ret = RI_ERR_SYNTAX;
191
+ goto exit_function;
192
+ }
193
+ /* check v1 */
194
+ pv1->st_edge.cap --;
195
+ pv1->st_edge.flow --;
196
+ pv2->st_edge.flow --;
197
+ pe->flow --; /* new radical on v2 */
198
+ vRad = NO_VERTEX;
199
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
200
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
201
+ pv1->st_edge.cap ++;
202
+ pv1->st_edge.flow ++;
203
+ pv2->st_edge.flow ++;
204
+ pe->flow ++; /* remove new radical on v2 */
205
+
206
+ if ( ret == 1 /*&& !nDeltaH*/ && !nDeltaCharge && (v2 == vPathStart || v2 == vPathEnd) ) {
207
+ vRad = (v2 == vPathStart)? vPathEnd : vPathStart;
208
+ } else {
209
+ pv2->st_edge.cap --;
210
+ pv2->st_edge.flow --;
211
+ pv1->st_edge.flow --;
212
+ pe->flow --; /* new radical on v1 */
213
+ vRad = NO_VERTEX;
214
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
215
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
216
+ pv2->st_edge.cap ++;
217
+ pv2->st_edge.flow ++;
218
+ pv1->st_edge.flow ++;
219
+ pe->flow ++; /* remove new radical on v1 */
220
+ if ( ret == 1 /*&& !nDeltaH*/ && !nDeltaCharge && (v1 == vPathStart || v1 == vPathEnd) ) {
221
+ vRad = (v1 == vPathStart)? vPathEnd : vPathStart;
222
+ }
223
+ }
224
+ if ( vRad == NO_VERTEX ) {
225
+ continue; /* radical did not affect this bond */
226
+ }
227
+ pvRad = pBNS->vert + vRad;
228
+ /* detect =N-O* */
229
+ if ( pVA[vRad].cNumValenceElectrons == 6 && at2[vRad].valence == 1 &&
230
+ (peRad = pBNS->edge + pvRad->iedge[0])->flow == 0 &&
231
+ pVA[aN = peRad->neighbor12 ^ vRad].cNumValenceElectrons == 5 &&
232
+ at2[aN].valence == 2 ) {
233
+ /*------------------------------------------------------------
234
+ Fix Metal disconnection/normalization inconsistency :
235
+ disconnected restored
236
+ R=N(+)-M R=N--M R=N + M R=N + M
237
+ | -> || -> || -> |
238
+ O(-) O O O* <- radical
239
+
240
+ The correct R=N + M(+)
241
+ disconnection |
242
+ would be this: O(-)
243
+ --------------------------------------------------------------*/
244
+ pvN = pBNS->vert + aN;
245
+ pvO = pvRad;
246
+ peNO = peRad;
247
+
248
+ /* N-O* => N=O */
249
+ peNO->flow ++;
250
+ pvO->st_edge.flow ++;
251
+ pvN->st_edge.cap ++;
252
+ pvN->st_edge.flow ++;
253
+ pBNS->tot_st_cap += 1;
254
+ pBNS->tot_st_flow += 2;
255
+ cur_success ++;
256
+ } else {
257
+ /* all other radicals that affect stereo */
258
+ delta = pvRad->st_edge.cap - pvRad->st_edge.flow;
259
+ pvRad->st_edge.cap -= delta;
260
+ pBNS->tot_st_cap -= delta;
261
+ }
262
+ }
263
+ /*exit_case_01:*/
264
+ SetForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
265
+ if ( cur_success ) {
266
+ tot_succes += cur_success;
267
+ /* recalculate InChI from the structure */
268
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
269
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
270
+ goto exit_function;
271
+ }
272
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
273
+ goto exit_function;
274
+ }
275
+ /*
276
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
277
+ goto exit_function;
278
+ }
279
+ */
280
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
281
+ if ( cmpInChI & IDIF_PROBLEM ) {
282
+ ret = RI_ERR_PROGR; /* severe restore problem */
283
+ goto exit_function;
284
+ }
285
+ if ( err ) {
286
+ ret = RI_ERR_ALLOC;
287
+ goto exit_function;
288
+ }
289
+ cmpInChI2 = 0;
290
+ memset ( icr2, 0, sizeof(*icr2) );
291
+ if ( iRevrInChI || iOrigInChI ) {
292
+ /* additional mobile-H compare in case of Fixed-H */
293
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
294
+ if ( cmpInChI & IDIF_PROBLEM ) {
295
+ ret = RI_ERR_PROGR; /* severe restore problem */
296
+ goto exit_function;
297
+ }
298
+ if ( err ) {
299
+ ret = RI_ERR_ALLOC;
300
+ goto exit_function;
301
+ }
302
+ }
303
+
304
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
305
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
306
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
307
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
308
+
309
+
310
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
311
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
312
+ NULL:
313
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
314
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
315
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
316
+ pStruct->pOneINChI[1]->StereoIsotopic :
317
+ pStruct->pOneINChI[1]->Stereo;
318
+
319
+ }
320
+ }
321
+
322
+ cur_success = 0;
323
+ if ( !(cmpInChI & IDIF_SB_MISS) && (cmpInChI2 & IDIF_SB_MISS) &&
324
+ icr2->num_sb_in2_only &&
325
+ 0 < (max_success = pBNS->tot_st_cap - pBNS->tot_st_flow) ) {
326
+ /*----------------------------------------------------*/
327
+ /* case 02: missing stereogenic bond in Mobile-H only */
328
+ /* X=N-O* => X=N=O and eliminate radical */
329
+ /*----------------------------------------------------*/
330
+ int retC, ret2C, retS, ret2S;
331
+ INCHI_MODE cmpInChI_Prev, cmpInChI2_Prev;
332
+ ICR icr_Prev, icr2_Prev;
333
+
334
+ /* blind attepmt */
335
+ icr_Prev = *icr;
336
+ icr2_Prev = *icr2;
337
+ cmpInChI_Prev = cmpInChI;
338
+ cmpInChI2_Prev = cmpInChI2;
339
+ for ( i = AllRadList.num_edges = 0; i < pStruct->num_atoms; i ++ ) {
340
+ if ( pBNS->vert[i].st_edge.cap - pBNS->vert[i].st_edge.flow == 1 &&
341
+ (ret = AddToEdgeList( &AllRadList, i, INC_ADD_EDGE ) ) ) {
342
+ goto exit_function;
343
+ }
344
+ }
345
+ for ( i = 0; i < AllRadList.num_edges; i ++ ) {
346
+ j = AllRadList.pnEdges[i];
347
+ pBNS->vert[j].st_edge.cap -= 1;
348
+ pBNS->tot_st_cap -= 1;
349
+ }
350
+ /*-------------------------------------------------*/
351
+ /* re-create InChI and see whether it looks better */
352
+ /*-------------------------------------------------*/
353
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
354
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
355
+ goto exit_function;
356
+ }
357
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
358
+ goto exit_function;
359
+ }
360
+ /*
361
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
362
+ goto exit_function;
363
+ }
364
+ */
365
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
366
+ if ( cmpInChI & IDIF_PROBLEM ) {
367
+ ret = RI_ERR_PROGR; /* severe restore problem */
368
+ goto exit_function;
369
+ }
370
+ if ( err ) {
371
+ ret = RI_ERR_ALLOC;
372
+ goto exit_function;
373
+ }
374
+ cmpInChI2 = 0;
375
+ memset ( icr2, 0, sizeof(*icr2) );
376
+ if ( iRevrInChI || iOrigInChI ) {
377
+ /* additional mobile-H compare in case of Fixed-H */
378
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
379
+ if ( cmpInChI & IDIF_PROBLEM ) {
380
+ ret = RI_ERR_PROGR; /* severe restore problem */
381
+ goto exit_function;
382
+ }
383
+ if ( err ) {
384
+ ret = RI_ERR_ALLOC;
385
+ goto exit_function;
386
+ }
387
+ }
388
+ retC = CompareIcr( icr, &icr_Prev, NULL, NULL, IDIFF_CONSTIT );
389
+ retS = CompareIcr( icr, &icr_Prev, NULL, NULL, IDIFF_STEREO );
390
+ ret2C = CompareIcr( icr2, &icr2_Prev, NULL, NULL, IDIFF_CONSTIT );
391
+ ret2S = CompareIcr( icr2, &icr2_Prev, NULL, NULL, IDIFF_STEREO );
392
+
393
+ if ( 0 >= retC &&
394
+ 0 >= retS &&
395
+ 0 >= ret2C &&
396
+ 0 > ret2S ) {
397
+ ; /* accept */
398
+ } else {
399
+ /* reject */
400
+ for ( i = 0; i < AllRadList.num_edges; i ++ ) {
401
+ j = AllRadList.pnEdges[i];
402
+ pBNS->vert[j].st_edge.cap += 1;
403
+ pBNS->tot_st_cap += 1;
404
+ }
405
+
406
+ /*-------------------------------------------------*/
407
+ /* re-create InChI-- return to previous state */
408
+ /*-------------------------------------------------*/
409
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
410
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
411
+ goto exit_function;
412
+ }
413
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
414
+ goto exit_function;
415
+ }
416
+ /*
417
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
418
+ goto exit_function;
419
+ }
420
+ */
421
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
422
+ if ( cmpInChI & IDIF_PROBLEM ) {
423
+ ret = RI_ERR_PROGR; /* severe restore problem */
424
+ goto exit_function;
425
+ }
426
+ if ( err ) {
427
+ ret = RI_ERR_ALLOC;
428
+ goto exit_function;
429
+ }
430
+ cmpInChI2 = 0;
431
+ memset ( icr2, 0, sizeof(*icr2) );
432
+ if ( iRevrInChI || iOrigInChI ) {
433
+ /* additional mobile-H compare in case of Fixed-H */
434
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
435
+ if ( cmpInChI & IDIF_PROBLEM ) {
436
+ ret = RI_ERR_PROGR; /* severe restore problem */
437
+ goto exit_function;
438
+ }
439
+ if ( err ) {
440
+ ret = RI_ERR_ALLOC;
441
+ goto exit_function;
442
+ }
443
+ }
444
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
445
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
446
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
447
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
448
+
449
+
450
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
451
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
452
+ NULL:
453
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
454
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
455
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
456
+ pStruct->pOneINChI[1]->StereoIsotopic :
457
+ pStruct->pOneINChI[1]->Stereo;
458
+ }
459
+ /*exit_case_02:;*/
460
+ }
461
+
462
+ cur_success = 0;
463
+ if ( pStruct->bMobileH == TAUT_NON && (cmpInChI & IDIF_SB_EXTRA_UNDF) &&
464
+ pStruct->endpoint ) {
465
+ /*------------------------------------------------------*/
466
+ /* case 03: extra stereogenic bond in Fixed-H only */
467
+ /* in Mobile-H this bond is not stereogenic. */
468
+ /* Since this bond parity is not known, it is UNDEFINED */
469
+ /*------------------------------------------------------*/
470
+ int bDone, num_endpoints;
471
+
472
+ TautMinusEdges[0].num_edges = 0;
473
+ TautMinusEdges[1].num_edges = 0;
474
+ AllChargeEdges.num_edges = 0;
475
+ /* in1 => in restored structure; in2 => in original InChI */
476
+ for ( i = 0; i < icr->num_sb_undef_in1_only; i ++ ) {
477
+ j12 = icr->sb_undef_in1_only[i];
478
+ pv1 = pBNS->vert + (v1 = pStereoRevrs->nBondAtom1[j12]-1);
479
+ pv2 = pBNS->vert + (v2 = pStereoRevrs->nBondAtom2[j12]-1);
480
+
481
+ if ( pStereo2Revrs ) {
482
+ /* reject if it is extra in Mobile-H also */
483
+ if ( icr2->num_sb_undef_in1_only ) {
484
+ for ( j = 0; j < icr2->num_sb_undef_in1_only; j ++ ) {
485
+ k = icr2->sb_undef_in1_only[j];
486
+ if ( v1 == pStereo2Revrs->nBondAtom1[k] &&
487
+ v2 == pStereo2Revrs->nBondAtom2[k] ) {
488
+ break;
489
+ }
490
+ }
491
+ if ( j < icr->num_sb_in1_only ) {
492
+ continue; /* extra stereobond in Mobile H also */
493
+ }
494
+ }
495
+ }
496
+ /* reject if it is a stereobond in Mobile-H also */
497
+ if ( pStereo2InChI && pStereo2InChI->nNumberOfStereoBonds ) {
498
+ for ( j = 0; j < pStereo2InChI->nNumberOfStereoBonds; j ++ ) {
499
+ if ( v1 == pStereo2InChI->nBondAtom1[j] &&
500
+ v2 == pStereo2InChI->nBondAtom1[j] ) {
501
+ break;
502
+ }
503
+ }
504
+ if ( j < pStereo2InChI->nNumberOfStereoBonds ) {
505
+ continue; /* ignore this extra stereo bond: it is in Mobile-H */
506
+ }
507
+ }
508
+ /* find the edge between v1 and v2 */
509
+ for ( k = 0; k < at2[v1].valence; k ++ ) {
510
+ pe = pBNS->edge + (e = pv1->iedge[k]);
511
+ if ( v2 == (pe->neighbor12 ^ v1) )
512
+ break; /* the edge has been found */
513
+ }
514
+ if ( k == at2[v1].valence ) {
515
+ ret = RI_ERR_SYNTAX;
516
+ goto exit_function;
517
+ }
518
+ /* Fix all charges except negative charges on tautomeric endpoints */
519
+ if ( !AllChargeEdges.num_edges && !TautMinusEdges[0].num_edges && !TautMinusEdges[1].num_edges ) {
520
+ for ( j = 0; j < pStruct->num_atoms; j ++ ) {
521
+ if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
522
+ if ( !pStruct->endpoint[j] ) {
523
+ if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
524
+ goto exit_function;
525
+ }
526
+ } else
527
+ if ( pVA[j].cNumValenceElectrons == 6 ) {
528
+ /* O */
529
+ if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
530
+ goto exit_function;
531
+ }
532
+ } else {
533
+ /* N */
534
+ if (ret = AddToEdgeList( TautMinusEdges+1, k, INC_ADD_EDGE ) ) {
535
+ goto exit_function;
536
+ }
537
+ }
538
+ }
539
+ if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
540
+ if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
541
+ goto exit_function;
542
+ }
543
+ /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
544
+ if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
545
+ NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
546
+
547
+ if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
548
+ if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
549
+ goto exit_function;
550
+ }
551
+ }
552
+ }
553
+ }
554
+ }
555
+ }
556
+ if ( !pe->flow )
557
+ continue;
558
+ /* fix all charges except tautomeric; first allow only O, then only N, finally both N and O */
559
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
560
+ for ( k = 1, bDone = 0; k < 4 && !bDone; k ++ ) {
561
+ /* fix tautomeric charges */
562
+ num_endpoints = (TautMinusEdges+0)->num_edges + (TautMinusEdges+1)->num_edges;
563
+ if ( k == 2 ) {
564
+ /* fix charges on O */
565
+ SetForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
566
+ num_endpoints -= (TautMinusEdges+0)->num_edges;
567
+ }
568
+ if ( k == 1 ) {
569
+ SetForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
570
+ num_endpoints -= (TautMinusEdges+1)->num_edges;
571
+ }
572
+ if ( num_endpoints >= 2 ) {
573
+ delta = 1;
574
+ pv1 = pBNS->vert + (v1 = pe->neighbor1);
575
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
576
+
577
+ pe->forbidden |= forbidden_edge_mask; /* fix stereobond */
578
+ pe->flow -= delta; /* decrement stereobond order */
579
+ pv1->st_edge.flow -= delta;
580
+ pv2->st_edge.flow -= delta;
581
+ pBNS->tot_st_flow -= 2*delta;
582
+
583
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
584
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
585
+
586
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
587
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
588
+ /* Negative charge has been moved, no change in number of charges */
589
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
590
+ if ( ret > 0 ) {
591
+ (*pnNumRunBNS) ++;
592
+ cur_success ++; /* 01 */
593
+ bDone = 1;
594
+ }
595
+ } else {
596
+ pe->forbidden &= ~forbidden_edge_mask;
597
+ pe->flow += delta;
598
+ pv1->st_edge.flow += delta;
599
+ pv2->st_edge.flow += delta;
600
+ pBNS->tot_st_flow += 2*delta;
601
+ }
602
+ }
603
+ /* unfix tautomeric charges */
604
+ if ( k == 2 )
605
+ RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
606
+ if ( k == 1 )
607
+ RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
608
+ }
609
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
610
+ }
611
+ /*exit_case_03:*/
612
+ if ( cur_success ) {
613
+ tot_succes += cur_success;
614
+ /* recalculate InChI from the structure */
615
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
616
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
617
+ goto exit_function;
618
+ }
619
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
620
+ goto exit_function;
621
+ }
622
+ /*
623
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
624
+ goto exit_function;
625
+ }
626
+ */
627
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
628
+ if ( cmpInChI & IDIF_PROBLEM ) {
629
+ ret = RI_ERR_PROGR; /* severe restore problem */
630
+ goto exit_function;
631
+ }
632
+ if ( err ) {
633
+ ret = RI_ERR_ALLOC;
634
+ goto exit_function;
635
+ }
636
+ cmpInChI2 = 0;
637
+ memset ( icr2, 0, sizeof(*icr2) );
638
+ if ( iRevrInChI || iOrigInChI ) {
639
+ /* additional mobile-H compare in case of Fixed-H */
640
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
641
+ if ( cmpInChI & IDIF_PROBLEM ) {
642
+ ret = RI_ERR_PROGR; /* severe restore problem */
643
+ goto exit_function;
644
+ }
645
+ if ( err ) {
646
+ ret = RI_ERR_ALLOC;
647
+ goto exit_function;
648
+ }
649
+ }
650
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
651
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
652
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
653
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
654
+
655
+
656
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
657
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
658
+ NULL:
659
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
660
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
661
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
662
+ pStruct->pOneINChI[1]->StereoIsotopic :
663
+ pStruct->pOneINChI[1]->Stereo;
664
+
665
+ }
666
+ }
667
+
668
+ cur_success = 0;
669
+ if ( (cmpInChI & IDIF_SB_EXTRA_UNDF) ) {
670
+ /*------------------------------------------------------*/
671
+ /* case 04: extra stereogenic bond */
672
+ /* Since this bond parity is not known, it is UNDEFINED */
673
+ /*------------------------------------------------------*/
674
+ int bDone, num_endpoints;
675
+
676
+ TautMinusEdges[0].num_edges = 0;
677
+ TautMinusEdges[1].num_edges = 0;
678
+ AllChargeEdges.num_edges = 0;
679
+ /* in1 => in restored structure; in2 => in original InChI */
680
+ for ( i = 0; i < icr->num_sb_undef_in1_only; i ++ ) {
681
+ j12 = icr->sb_undef_in1_only[i];
682
+ pv1 = pBNS->vert + (v1 = pStereoRevrs->nBondAtom1[j12]-1);
683
+ pv2 = pBNS->vert + (v2 = pStereoRevrs->nBondAtom2[j12]-1);
684
+
685
+ /* find the edge between v1 and v2 */
686
+ for ( k = 0; k < at2[v1].valence; k ++ ) {
687
+ pe = pBNS->edge + (e = pv1->iedge[k]);
688
+ if ( v2 == (pe->neighbor12 ^ v1) )
689
+ break; /* the edge has been found */
690
+ }
691
+ if ( k == at2[v1].valence ) {
692
+ ret = RI_ERR_SYNTAX;
693
+ goto exit_function;
694
+ }
695
+ if ( pStereo2Revrs ) {
696
+ /* reject if it is not extra in Mobile-H also */
697
+ if ( icr2->num_sb_undef_in1_only ) {
698
+ for ( j = 0; j < icr2->num_sb_undef_in1_only; j ++ ) {
699
+ k = icr2->sb_undef_in1_only[j];
700
+ if ( v1 == pStereo2Revrs->nBondAtom1[k] &&
701
+ v2 == pStereo2Revrs->nBondAtom2[k] ) {
702
+ break;
703
+ }
704
+ }
705
+ if ( j == icr->num_sb_in1_only ) {
706
+ continue; /* extra stereobond only in Fixed-H, not in Mobile H also */
707
+ }
708
+ }
709
+ }
710
+
711
+ /* Fix all charges except negative charges on tautomeric endpoints */
712
+ if ( !AllChargeEdges.num_edges && !TautMinusEdges[0].num_edges && !TautMinusEdges[1].num_edges ) {
713
+ for ( j = 0; j < pStruct->num_atoms; j ++ ) {
714
+ if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
715
+ if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
716
+ goto exit_function;
717
+ }
718
+ }
719
+ if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
720
+ int bMayBeUnfixed = !at2[j].num_H && !(pStruct->endpoint && pStruct->endpoint[j]);
721
+ if ( bMayBeUnfixed && pVA[j].cNumValenceElectrons == 6 ||
722
+ pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber > 1 ) {
723
+ /* O & P */
724
+ if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
725
+ goto exit_function;
726
+ }
727
+ } else
728
+ if ( bMayBeUnfixed &&
729
+ pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 ) {
730
+ /* N */
731
+ if (ret = AddToEdgeList( TautMinusEdges+1, k, INC_ADD_EDGE ) ) {
732
+ goto exit_function;
733
+ }
734
+ } else {
735
+ if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
736
+ goto exit_function;
737
+ }
738
+ }
739
+ /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
740
+ if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
741
+ NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
742
+ if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
743
+ if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
744
+ goto exit_function;
745
+ }
746
+ }
747
+ }
748
+ }
749
+ }
750
+ }
751
+ if ( !pe->flow )
752
+ continue;
753
+ /* fix all charges except tautomeric; first allow only O, then only N, finally both N and O */
754
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
755
+ for ( k = 1, bDone = 0; k < 4 && !bDone; k ++ ) {
756
+ /* fix positive charges on heteroatoms */
757
+ num_endpoints = (TautMinusEdges+0)->num_edges + (TautMinusEdges+1)->num_edges;
758
+ if ( k == 2 ) {
759
+ /* fix charges on O */
760
+ SetForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
761
+ num_endpoints -= (TautMinusEdges+0)->num_edges;
762
+ }
763
+ if ( k == 1 ) {
764
+ /* fix charges on N */
765
+ SetForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
766
+ num_endpoints -= (TautMinusEdges+1)->num_edges;
767
+ }
768
+ if ( num_endpoints >= 2 ) {
769
+ delta = 1;
770
+ pv1 = pBNS->vert + (v1 = pe->neighbor1);
771
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
772
+
773
+ pe->forbidden |= forbidden_edge_mask; /* fix stereobond */
774
+ pe->flow -= delta; /* decrement stereobond order */
775
+ pv1->st_edge.flow -= delta;
776
+ pv2->st_edge.flow -= delta;
777
+ pBNS->tot_st_flow -= 2*delta;
778
+
779
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
780
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
781
+
782
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
783
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
784
+ /* Negative charge has been moved, no change in number of charges */
785
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
786
+ if ( ret > 0 ) {
787
+ (*pnNumRunBNS) ++;
788
+ cur_success ++; /* 01 */
789
+ bDone = 1;
790
+ }
791
+ } else {
792
+ pe->forbidden &= ~forbidden_edge_mask;
793
+ pe->flow += delta;
794
+ pv1->st_edge.flow += delta;
795
+ pv2->st_edge.flow += delta;
796
+ pBNS->tot_st_flow += 2*delta;
797
+ }
798
+ }
799
+ /* unfix tautomeric charges */
800
+ if ( k == 2 )
801
+ RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+0, forbidden_edge_mask );
802
+ if ( k == 1 )
803
+ RemoveForbiddenEdgeMask( pBNS, TautMinusEdges+1, forbidden_edge_mask );
804
+ }
805
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
806
+ }
807
+ /*exit_case_04:*/
808
+ if ( cur_success ) {
809
+ tot_succes += cur_success;
810
+ /* recalculate InChI from the structure */
811
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
812
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
813
+ goto exit_function;
814
+ }
815
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
816
+ goto exit_function;
817
+ }
818
+ /*
819
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
820
+ goto exit_function;
821
+ }
822
+ */
823
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
824
+ if ( cmpInChI & IDIF_PROBLEM ) {
825
+ ret = RI_ERR_PROGR; /* severe restore problem */
826
+ goto exit_function;
827
+ }
828
+ if ( err ) {
829
+ ret = RI_ERR_ALLOC;
830
+ goto exit_function;
831
+ }
832
+ cmpInChI2 = 0;
833
+ memset ( icr2, 0, sizeof(*icr2) );
834
+ if ( iRevrInChI || iOrigInChI ) {
835
+ /* additional mobile-H compare in case of Fixed-H */
836
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
837
+ if ( cmpInChI & IDIF_PROBLEM ) {
838
+ ret = RI_ERR_PROGR; /* severe restore problem */
839
+ goto exit_function;
840
+ }
841
+ if ( err ) {
842
+ ret = RI_ERR_ALLOC;
843
+ goto exit_function;
844
+ }
845
+ }
846
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
847
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
848
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
849
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
850
+
851
+
852
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
853
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
854
+ NULL:
855
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
856
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
857
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
858
+ pStruct->pOneINChI[1]->StereoIsotopic :
859
+ pStruct->pOneINChI[1]->Stereo;
860
+
861
+ }
862
+ }
863
+
864
+ cur_success = 0;
865
+ if ( pStruct->bMobileH == TAUT_YES &&
866
+ (cmpInChI & IDIF_SB_EXTRA_UNDF &&
867
+ !pStruct->ti.num_t_groups)
868
+ /*pStruct->bMobileH == TAUT_NON && (cmpInChI2 & IDIF_SB_EXTRA_UNDF)*/) {
869
+ /*----------------------------------------------------------*/
870
+ /* case 05: extra stereogenic bond on =NH2(+), (B, Mobile-H)*/
871
+ /* H H */
872
+ /* original: N(+)=-N< -> N--==N/ */
873
+ /* (A) H */
874
+ /* double bond is marked as */
875
+ /* not stereogenic due to */
876
+ /* its change during proton */
877
+ /* removal => No Stereo bond */
878
+ /* (=NH may be tautomeric) */
879
+ /* */
880
+ /* H H */
881
+ /* original: N=-N(+)< -> N--==N/ */
882
+ /* (B) H */
883
+ /* double bond was not */
884
+ /* changed during proton */
885
+ /* In Fixed-H this bond removal => Undef Stereo */
886
+ /* may not be stereogenic (=NH is not tautomeric) */
887
+ /* (a) due to (+) movement */
888
+ /* (b) due to symmetry (2H), even if isotopic */
889
+ /* */
890
+ /* Fixed-H: move (+) to or from NH2 for Undef or No stereo */
891
+ /* respectively */
892
+ /* Mobile-H: Add H(+) to =NH and move the charge to =N- */
893
+ /* to eliminate Undef stereo */
894
+ /* Move charge from N to -NH2 to create */
895
+ /* Undef Stereo */
896
+ /* Since this bond parity is not known, it is UNDEFINED */
897
+ /* */
898
+ /* Solution: Add H(+) to =NH and move charge to -N= */
899
+ /* */
900
+ /*----------------------------------------------------------*/
901
+ int aN, aC, i1, i2, vPlusMinus;
902
+ AllChargeEdges.num_edges = 0;
903
+ /* in1 => in restored structure; in2 => in original InChI */
904
+ for ( i = 0; i < icr->num_sb_undef_in1_only; i ++ ) {
905
+ j12 = icr->sb_undef_in1_only[i];
906
+ pv1 = pBNS->vert + (v1 = pStereoRevrs->nBondAtom1[j12]-1);
907
+ pv2 = pBNS->vert + (v2 = pStereoRevrs->nBondAtom2[j12]-1);
908
+ /* indicators of -NH: */
909
+ i1 = at2[v1].valence == 1 && at2[v1].num_H == 1 && !at2[v1].endpoint &&
910
+ pVA[v1].cNumValenceElectrons == 5 && pVA[v1].cPeriodicRowNumber == 1;
911
+ i2 = at2[v2].valence == 1 && at2[v2].num_H == 1 && !at2[v2].endpoint &&
912
+ pVA[v2].cNumValenceElectrons == 5 && pVA[v2].cPeriodicRowNumber == 1;
913
+ if ( !i1 && !i2 || i1 && i2 ) {
914
+ continue;
915
+ }
916
+ /* find the edge between v1 and v2 */
917
+ for ( k = 0; k < at2[v1].valence; k ++ ) {
918
+ pe = pBNS->edge + (e = pv1->iedge[k]);
919
+ if ( v2 == (pe->neighbor12 ^ v1) )
920
+ break; /* the edge has been found */
921
+ }
922
+ if ( k == at2[v1].valence ) {
923
+ ret = RI_ERR_SYNTAX;
924
+ goto exit_function;
925
+ }
926
+ if ( pe->flow != 1 ) {
927
+ continue; /* already charged */
928
+ }
929
+ aN = i1? v1 : v2; /* -NH atom */
930
+ aC = i1? v2 : v1; /* neighbor */
931
+ /* Replace =NH with -NH2
932
+ Create such a charge on some -N< that may be moved to NH2 to remove H(+):
933
+ transformation:
934
+ from: HN=C-=-N=(+vert)-Y=(+super)-(+/-)
935
+ to: 2HN-C*-=-N=(+vert)-Y=(+super)-(+/-)*
936
+ Run BNS to obtain:
937
+ 2HN-C=-=N(+)-(+vert)=Y-(+super)=(+/-)
938
+ */
939
+ vPlusMinus = GetPlusMinusVertex( pBNS, pTCGroups, 1, 0 );
940
+ if ( NO_VERTEX == vPlusMinus ) {
941
+ break; /* cannot do anything */
942
+ }
943
+ /* increase edges to -Y-(+/-)-Y- capacities */
944
+ delta = 1;
945
+ for ( i1 = 0; i1 < pBNS->vert[vPlusMinus].num_adj_edges; i1 ++ ) {
946
+ i2 = pBNS->edge[pBNS->vert[vPlusMinus].iedge[i1]].neighbor12 ^ vPlusMinus;
947
+ for ( k = 0; k < pBNS->vert[i2].num_adj_edges; k ++ ) {
948
+ pBNS->edge[pBNS->vert[i2].iedge[k]].cap += delta;
949
+ }
950
+ }
951
+ /* Fix all charges except (+) on -N< */
952
+ if ( !AllChargeEdges.num_edges ) {
953
+ for ( j = 0; j < pStruct->num_atoms; j ++ ) {
954
+ if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
955
+ if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
956
+ goto exit_function;
957
+ }
958
+ }
959
+ if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
960
+ if ( pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 &&
961
+ !at2[j].num_H && at2[j].valence == 3 &&
962
+ !(at2[j].endpoint || pStruct->endpoint && pStruct->endpoint[j]) ) {
963
+ ; /* do not fix -N< or =N(+)< */
964
+ } else {
965
+ /* all others */
966
+ if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
967
+ goto exit_function;
968
+ }
969
+ }
970
+ /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
971
+ if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
972
+ NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
973
+ if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
974
+ if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
975
+ goto exit_function;
976
+ }
977
+ }
978
+ }
979
+ }
980
+ }
981
+ }
982
+ /* Make bond to =NH single, add radical to aC */
983
+ pe->flow -= delta; /* make single bond */
984
+ pBNS->vert[aN].st_edge.flow -= delta;
985
+ pBNS->vert[aN].st_edge.cap -= delta; /* avoid radical on N */
986
+ pBNS->vert[aC].st_edge.flow -= delta; /* create radical on C */
987
+ pBNS->vert[vPlusMinus].st_edge.cap += delta; /* create radical on (+/-) */
988
+ pBNS->tot_st_flow -= 2*delta;
989
+ /* fix C-NH bond */
990
+ if ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) ) {
991
+ goto exit_function;
992
+ }
993
+ /* pBNS->tot_st_cap is unchanged */
994
+ /* find all aC edges except pe to fix them */
995
+ /* 2. Check whether it would work and do if it would */
996
+ SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
997
+ pe->cap ++;
998
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
999
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1000
+
1001
+ if ( ret == 1 && (vPathEnd == vPlusMinus && vPathStart == aC ||
1002
+ vPathEnd == aC && vPathStart == vPlusMinus) && nDeltaCharge == 1 ) {
1003
+ /* Negative charge has been moved, no change in number of charges */
1004
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1005
+ if ( ret > 0 ) {
1006
+ (*pnNumRunBNS) ++;
1007
+ /* 3. Add H to -NH and register increaded charge */
1008
+ pStruct->at[aN].num_H ++;
1009
+ pTCGroups->total_charge ++;
1010
+ cur_success ++; /* 01 */
1011
+ }
1012
+ } else {
1013
+ pe->flow += delta; /* make single bond */
1014
+ pBNS->vert[aN].st_edge.flow += delta;
1015
+ pBNS->vert[aN].st_edge.cap += delta; /* avoid radical on N */
1016
+ pBNS->vert[aC].st_edge.flow += delta; /* create radical on C */
1017
+ pBNS->vert[vPlusMinus].st_edge.cap -= delta; /* create radical on (+/-) */
1018
+ pBNS->tot_st_flow += 2*delta;
1019
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1020
+ AllChargeEdges.num_edges --; /* remove pe from the list */
1021
+ CurrEdges.num_edges = 0;
1022
+ continue; /* should not happen */
1023
+ }
1024
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1025
+ AllChargeEdges.num_edges --; /* remove pe from the list */
1026
+ CurrEdges.num_edges = 0;
1027
+ }
1028
+ /*exit_case_05:*/
1029
+ if ( cur_success ) {
1030
+ tot_succes += cur_success;
1031
+ /* recalculate InChI from the structure */
1032
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1033
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1034
+ goto exit_function;
1035
+ }
1036
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1037
+ goto exit_function;
1038
+ }
1039
+ /*
1040
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1041
+ goto exit_function;
1042
+ }
1043
+ */
1044
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr, &err );
1045
+ if ( cmpInChI & IDIF_PROBLEM ) {
1046
+ ret = RI_ERR_PROGR; /* severe restore problem */
1047
+ goto exit_function;
1048
+ }
1049
+ if ( err ) {
1050
+ ret = RI_ERR_ALLOC;
1051
+ goto exit_function;
1052
+ }
1053
+ cmpInChI2 = 0;
1054
+ memset ( icr2, 0, sizeof(*icr2) );
1055
+ if ( iRevrInChI || iOrigInChI ) {
1056
+ /* additional mobile-H compare in case of Fixed-H */
1057
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
1058
+ if ( cmpInChI & IDIF_PROBLEM ) {
1059
+ ret = RI_ERR_PROGR; /* severe restore problem */
1060
+ goto exit_function;
1061
+ }
1062
+ if ( err ) {
1063
+ ret = RI_ERR_ALLOC;
1064
+ goto exit_function;
1065
+ }
1066
+ }
1067
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
1068
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1069
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
1070
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
1071
+
1072
+
1073
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1074
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
1075
+ NULL:
1076
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
1077
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1078
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
1079
+ pStruct->pOneINChI[1]->StereoIsotopic :
1080
+ pStruct->pOneINChI[1]->Stereo;
1081
+
1082
+ }
1083
+ }
1084
+
1085
+ cur_success = 0;
1086
+ if ( pStruct->bMobileH == TAUT_NON && pStereo2Revrs /* added check 2006-04-05 */ &&
1087
+ (cmpInChI2 & IDIF_SB_EXTRA_UNDF &&
1088
+ !pStruct->ti.num_t_groups)
1089
+ /*pStruct->bMobileH == TAUT_NON && (cmpInChI2 & IDIF_SB_EXTRA_UNDF)*/) {
1090
+ /*----------------------------------------------------------*/
1091
+ /* case 06: extra stereogenic bond on =NH2(+), (B, Fixed-H) */
1092
+ /* H H =========== */
1093
+ /* original: N(+)=-N< -> N--==N(+)< */
1094
+ /* (A) H H */
1095
+ /* double bond in Mobile-H */
1096
+ /* layer has Undef stereo */
1097
+ /* */
1098
+ /* */
1099
+ /* Fixed-H: move (+) to or from NH2 for Undef or No stereo */
1100
+ /* respectively */
1101
+ /* Mobile-H: Add H(+) to =NH and move the charge to =N- */
1102
+ /* to eliminate Undef stereo */
1103
+ /* Move charge from N to -NH2 to create */
1104
+ /* Undef Stereo */
1105
+ /* Since this bond parity is not known, it is UNDEFINED */
1106
+ /* */
1107
+ /* Solution: Move (+) from -NH2(+) to othe -N< */
1108
+ /* */
1109
+ /*----------------------------------------------------------*/
1110
+ int aN, aC, i1, i2, ePlus;
1111
+ BNS_EDGE *pePlus;
1112
+ AllChargeEdges.num_edges = 0;
1113
+ /* in1 => in restored structure; in2 => in original InChI */
1114
+ for ( i = 0; i < icr2->num_sb_undef_in1_only; i ++ ) {
1115
+ j12 = icr2->sb_undef_in1_only[i];
1116
+ pv1 = pBNS->vert + (v1 = pStereo2Revrs->nBondAtom1[j12]-1);
1117
+ pv2 = pBNS->vert + (v2 = pStereo2Revrs->nBondAtom2[j12]-1);
1118
+ /* indicators of -NH: */
1119
+ i1 = at2[v1].valence == 1 && at2[v1].num_H == 2 && !at2[v1].endpoint &&
1120
+ pVA[v1].cNumValenceElectrons == 5 && pVA[v1].cPeriodicRowNumber == 1;
1121
+ i2 = at2[v2].valence == 1 && at2[v2].num_H == 2 && !at2[v2].endpoint &&
1122
+ pVA[v2].cNumValenceElectrons == 5 && pVA[v2].cPeriodicRowNumber == 1;
1123
+ if ( !i1 && !i2 || i1 && i2 ) {
1124
+ continue;
1125
+ }
1126
+ /* find the edge between v1 and v2 */
1127
+ for ( k = 0; k < at2[v1].valence; k ++ ) {
1128
+ pe = pBNS->edge + (e = pv1->iedge[k]);
1129
+ if ( v2 == (pe->neighbor12 ^ v1) )
1130
+ break; /* the edge has been found */
1131
+ }
1132
+ if ( k == at2[v1].valence ) {
1133
+ ret = RI_ERR_SYNTAX;
1134
+ goto exit_function;
1135
+ }
1136
+ if ( pe->flow != 1 ) {
1137
+ continue; /* already charged */
1138
+ }
1139
+ aN = i1? v1 : v2; /* -NH atom */
1140
+ aC = i1? v2 : v1; /* neighbor */
1141
+ if ( 0 > (ePlus = pVA[aN].nCPlusGroupEdge-1) ||
1142
+ (pePlus = pBNS->edge + ePlus)->flow || /* must be (+) charged */
1143
+ pePlus->forbidden ) {
1144
+ continue;
1145
+ }
1146
+ /* Move (+) from =NH2(+) to some other -N<
1147
+ */
1148
+ /* Fix all charges except (+) on -N< */
1149
+ if ( !AllChargeEdges.num_edges ) {
1150
+ for ( j = 0; j < pStruct->num_atoms; j ++ ) {
1151
+ if ( (k=pVA[j].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
1152
+ if (ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
1153
+ goto exit_function;
1154
+ }
1155
+ }
1156
+ if ( (k=pVA[j].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[k].forbidden ) {
1157
+ if ( pVA[j].cNumValenceElectrons == 5 && pVA[j].cPeriodicRowNumber == 1 &&
1158
+ !at2[j].num_H && at2[j].valence == 3 &&
1159
+ !(at2[j].endpoint || pStruct->endpoint && pStruct->endpoint[j]) ) {
1160
+ ; /* do not fix -N< or =N(+)< */
1161
+ } else {
1162
+ /* all others */
1163
+ if (ret = AddToEdgeList( TautMinusEdges+0, k, INC_ADD_EDGE ) ) {
1164
+ goto exit_function;
1165
+ }
1166
+ }
1167
+ /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
1168
+ if ( pVA[j].cNumValenceElectrons == 5 && !pVA[j].cMetal && /* N, P, As */
1169
+ NO_VERTEX != (k = GetChargeFlowerUpperEdge( pBNS, pVA, k ))) {
1170
+ if ( !pBNS->edge[j].forbidden && pBNS->edge[k].flow ) {
1171
+ if ( ret = AddToEdgeList( &AllChargeEdges, k, INC_ADD_EDGE ) ) {
1172
+ goto exit_function;
1173
+ }
1174
+ }
1175
+ }
1176
+ }
1177
+ }
1178
+ }
1179
+ /* pePlus edge is already fixed; unfix it */
1180
+ /* To decrement (+) on =NH2(+) decrement its double bond order */
1181
+ delta = 1;
1182
+ if ( !pe->flow )
1183
+ continue;
1184
+ pv1 = pBNS->vert + (v1 = pe->neighbor1);
1185
+ pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
1186
+
1187
+ delta = 1;
1188
+ pe->flow -= delta;
1189
+ pv1->st_edge.flow -= delta;
1190
+ pv2->st_edge.flow -= delta;
1191
+ pBNS->tot_st_flow -= 2*delta;
1192
+
1193
+ pe->forbidden |= forbidden_edge_mask;
1194
+ pePlus->forbidden &= ~forbidden_edge_mask;
1195
+
1196
+ ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
1197
+ &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
1198
+
1199
+ if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
1200
+ vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
1201
+ /* (+)charge was just moved, no change in number of charges */
1202
+ ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
1203
+ if ( ret > 0 ) {
1204
+ (*pnNumRunBNS) ++;
1205
+ cur_success ++; /* 01 */
1206
+ }
1207
+ } else {
1208
+ pe->flow += delta; /* roll back */
1209
+ pv1->st_edge.flow += delta;
1210
+ pv2->st_edge.flow += delta;
1211
+ pBNS->tot_st_flow += 2*delta;
1212
+ }
1213
+ pe->forbidden &= ~forbidden_edge_mask;
1214
+ RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );/* fix aC edges */
1215
+ }
1216
+ /*exit_case_06:*/
1217
+ if ( cur_success ) {
1218
+ tot_succes += cur_success;
1219
+ /* recalculate InChI from the structure */
1220
+ if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
1221
+ ppt_group_info, ppat_norm, ppat_prep ) ) ) {
1222
+ goto exit_function;
1223
+ }
1224
+ if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
1225
+ goto exit_function;
1226
+ }
1227
+ /*
1228
+ if ( ret = FillOutCMP2MHINCHI( pStruct, pTCGroups, at2, pVA, pInChI, pc2i ) ) {
1229
+ goto exit_function;
1230
+ }
1231
+ */
1232
+ cmpInChI = CompareReversedINChI2( pStruct->pOneINChI[0], pInChI[0], pStruct->pOneINChI_Aux[0], NULL /*INChI_Aux *v2*/, icr2, &err );
1233
+ if ( cmpInChI & IDIF_PROBLEM ) {
1234
+ ret = RI_ERR_PROGR; /* severe restore problem */
1235
+ goto exit_function;
1236
+ }
1237
+ if ( err ) {
1238
+ ret = RI_ERR_ALLOC;
1239
+ goto exit_function;
1240
+ }
1241
+ cmpInChI2 = 0;
1242
+ memset ( icr2, 0, sizeof(*icr2) );
1243
+ if ( iRevrInChI || iOrigInChI ) {
1244
+ /* additional mobile-H compare in case of Fixed-H */
1245
+ cmpInChI2 = CompareReversedINChI2( pStruct->pOneINChI[iRevrInChI], pInChI[iOrigInChI], pStruct->pOneINChI_Aux[iRevrInChI], NULL /*INChI_Aux *v2*/, icr2, &err );
1246
+ if ( cmpInChI & IDIF_PROBLEM ) {
1247
+ ret = RI_ERR_PROGR; /* severe restore problem */
1248
+ goto exit_function;
1249
+ }
1250
+ if ( err ) {
1251
+ ret = RI_ERR_ALLOC;
1252
+ goto exit_function;
1253
+ }
1254
+ }
1255
+ pStereoRevrs = (pStruct->pOneINChI[0]->StereoIsotopic &&
1256
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoBonds +
1257
+ pStruct->pOneINChI[0]->StereoIsotopic->nNumberOfStereoCenters)?
1258
+ pStruct->pOneINChI[0]->StereoIsotopic : pStruct->pOneINChI[0]->Stereo;
1259
+
1260
+
1261
+ pStereo2Revrs = (pStruct->bMobileH == TAUT_YES || !pStruct->pOneINChI[1] ||
1262
+ !pStruct->pOneINChI[1]->nNumberOfAtoms || pStruct->pOneINChI[1]->bDeleted)?
1263
+ NULL:
1264
+ (pStruct->pOneINChI[1]->StereoIsotopic &&
1265
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoBonds +
1266
+ pStruct->pOneINChI[1]->StereoIsotopic->nNumberOfStereoCenters)?
1267
+ pStruct->pOneINChI[1]->StereoIsotopic :
1268
+ pStruct->pOneINChI[1]->Stereo;
1269
+
1270
+ }
1271
+ }
1272
+
1273
+
1274
+ exit_function:
1275
+ SetForbiddenEdgeMask( pBNS, &FixedStereoEdges, forbidden_stereo_edge_mask );
1276
+ AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
1277
+ AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
1278
+ AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
1279
+ AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
1280
+ AllocEdgeList( &FixedStereoEdges, EDGE_LIST_FREE );
1281
+ AllocEdgeList( &AllRadList, EDGE_LIST_FREE ); /* eliminate memory leak */
1282
+ AllocEdgeList( TautMinusEdges+0, EDGE_LIST_FREE );
1283
+ AllocEdgeList( TautMinusEdges+1, EDGE_LIST_FREE );
1284
+
1285
+ return ret;
1286
+ }
1287
+ #endif