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,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