~ubuntu-branches/debian/stretch/openbabel/stretch

« back to all changes in this revision

Viewing changes to src/formats/inchi102/ichirvr3.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Leidert (dale)
  • Date: 2009-07-17 00:18:06 UTC
  • mfrom: (6.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090717001806-sy3mzs3e1d1adbs9
Tags: 2.2.2-2
* debian/control (Uploaders): Removed LI Daobing. Thanks for your work!
  (Standards-Version): Bumped to 3.8.2.
  (Vcs-Svn): Fixed vcs-field-uses-not-recommended-uri-format.
* debian/patches/537102_fix_tr1_memory_detection.patch: Added.
  - configure.in, configure, src/config.h.in: Fix detection of tr1/memory to
    prevent building the package with boost (closes: #537102).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * International Chemical Identifier (InChI)
 
3
 * Version 1
 
4
 * Software version 1.02
 
5
 * October 31, 2008
 
6
 * Developed at NIST
 
7
 *
 
8
 * The InChI library and programs are free software developed under the
 
9
 * auspices of the International Union of Pure and Applied Chemistry (IUPAC);
 
10
 * you can redistribute this software and/or modify it under the terms of 
 
11
 * the GNU Lesser General Public License as published by the Free Software 
 
12
 * Foundation:
 
13
 * http://www.opensource.org/licenses/lgpl-license.php
 
14
 */
 
15
 
 
16
 
 
17
#include <stdio.h>
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
 
 
21
/*#define CHECK_WIN32_VC_HEAP*/
 
22
#include "mode.h"
 
23
 
 
24
#if( READ_INCHI_STRING == 1 )
 
25
 
 
26
#include "ichi.h"
 
27
#include "ichitime.h"
 
28
 
 
29
#include "inpdef.h"
 
30
#include "ichimain.h"
 
31
#include "ichierr.h"
 
32
#include "incomdef.h"
 
33
#include "ichiring.h"
 
34
#include "extr_ct.h"
 
35
#include "ichitaut.h"
 
36
#include "ichinorm.h"
 
37
#include "util.h"
 
38
 
 
39
#include "ichicomp.h"
 
40
#include "ichister.h"
 
41
 
 
42
#include "ichi_bns.h"
 
43
 
 
44
#include "strutil.h"
 
45
 
 
46
#include "ichirvrs.h"
 
47
 
 
48
#define INC_ADD_EDGE 64
 
49
 
 
50
/* local types */
 
51
 
 
52
/* types for TgDiffHChgFH */
 
53
#define fNumRPosChgH 0 /* number of positive charges on endpoints that have H in at2[] */
 
54
#define fNumRPosChgU 1 /* number of positive charges on endpoints that have no H in at2[] */
 
55
#define fNumRNegChgO 2 /* number of negative charges on O endpoints */
 
56
#define fNumRNegChgN 3 /* number of negative charges on N endpoints */
 
57
#define fNumRNeutrlH 4 /* number of neutral endp that have H in at2[] */
 
58
 
 
59
#define fNumNPosChgH 5 /* number of positive charges on endpoints that have H in atf[] */
 
60
#define fNumNPosChgU 6 /* number of positive charges on endpoints that have no H in atf[] */
 
61
#define fNumNNegChgO 7 /* number of negative charges on O endpoints */
 
62
#define fNumNNegChgN 8 /* number of negative charges on N endpoints */
 
63
#define fNumNNeutrlH 9 /* number of neutral endp that have H in atf[] */
 
64
 
 
65
#define fNumAllChgT 10 /* total  number of fNum... */
 
66
 
 
67
typedef struct tagTgDiffHChgFH {
 
68
    short  itg; /* t-group index; endpoint = itg+1 */
 
69
    short  nNumHInchi;  /* number of H in t-group from orig. InChI */
 
70
    short  nNumHRevrs;  /* number of H in at2[] */
 
71
    short  nNumHNorml;  /* number of H in Normalized atfMobile_H_Revrs[] */
 
72
    short  nNumMInchi;  /* number of (-) in InChI */
 
73
    short  nNumMRevrs;  /* number of (-) in at2[] */
 
74
    short  nNumMNorml;  /* number of (-) in atf[] */
 
75
    short  nNumPRevrs;  /* number of (+) in at2[] */
 
76
    short  nNumPNorml;  /* number of (+) in Normalized atfMobile_H_Revrs[] */
 
77
    short n[fNumAllChgT]; /* all numbers */
 
78
    short i[fNumAllChgT]; /* all indices */
 
79
} TgDiffHChgFH;
 
80
 
 
81
/* local prototypes */
 
82
static int FillTgDiffHChgFH( TgDiffHChgFH tdhc[], int max_tdhc, inp_ATOM at2[], inp_ATOM atf[],
 
83
                            AT_NUMB  *nCanon2AtnoRevrs, VAL_AT *pVA, T_GROUP_INFO *ti, EDGE_LIST *pAtomIndList );
 
84
 
 
85
 
 
86
/************************************************************/
 
87
int bHas_N_V( inp_ATOM *at2, int num_atoms )
 
88
{
 
89
    static U_CHAR el_number_N;
 
90
    int i, num_found = 0;
 
91
    if ( !el_number_N ) {
 
92
        el_number_N = get_periodic_table_number( "N" );
 
93
    }
 
94
    for ( i = 0; i < num_atoms; i ++ ) {
 
95
        if ( at2[i].el_number == el_number_N && !at2[i].charge &&
 
96
             !at2[i].num_H && !at2[i].radical &&
 
97
             at2[i].chem_bonds_valence == 5 &&
 
98
             (at2[i].valence==3) ) {
 
99
            num_found ++;
 
100
        }
 
101
    }
 
102
    return num_found;
 
103
}
 
104
/*************************************************************************************/
 
105
int FillTgDiffHChgFH( TgDiffHChgFH tdhc[], int max_tdhc, inp_ATOM at2[],
 
106
                      inp_ATOM atf[], AT_NUMB  *nCanon2AtnoRevrs, VAL_AT *pVA,
 
107
                      T_GROUP_INFO *ti, EDGE_LIST *pAtomIndList )
 
108
{
 
109
 
 
110
    int i, j, iat, itg, itg_prev, num, itg_out, bOverflow;
 
111
    EDGE_LIST IndList;   /* type, itg */
 
112
    TgDiffHChgFH cur_tdhc;
 
113
    AT_NUMB    *pEndp0;
 
114
    inp_ATOM   *at2i, *atfi;
 
115
    int         typeR, typeN, type, ret = 0, nCurIndListLen;
 
116
 
 
117
    AllocEdgeList( &IndList, EDGE_LIST_CLEAR );
 
118
    pAtomIndList->num_edges = 0;
 
119
    itg_out = 0;
 
120
    bOverflow = 0;
 
121
    memset( tdhc, 0, max_tdhc * sizeof(tdhc[0]) );
 
122
 
 
123
    for ( itg = 0; itg < ti->num_t_groups; itg ++ ) {
 
124
        memset( &cur_tdhc, 0, sizeof(cur_tdhc) );
 
125
 
 
126
        cur_tdhc.itg = itg;
 
127
        cur_tdhc.nNumHInchi = ti->t_group[itg].num[0] - ti->t_group[itg].num[1];
 
128
        cur_tdhc.nNumMInchi = ti->t_group[itg].num[1];
 
129
        
 
130
        pEndp0 = ti->nEndpointAtomNumber + ti->t_group[itg].nFirstEndpointAtNoPos;
 
131
        nCurIndListLen = IndList.num_edges;
 
132
        for ( j = 0; j < ti->t_group[itg].nNumEndpoints; j ++ ) {
 
133
            i = pEndp0[j];
 
134
            iat = nCanon2AtnoRevrs[i];
 
135
            
 
136
            at2i = at2 + iat;
 
137
            atfi = atf + iat;
 
138
            
 
139
            typeR = typeN = -1;
 
140
            if ( at2i->charge == 1 ) {
 
141
                if ( at2i->num_H ) {
 
142
                    typeR = fNumRPosChgH;
 
143
                } else {
 
144
                    typeR = fNumRPosChgU;
 
145
                }
 
146
                cur_tdhc.nNumPRevrs ++;
 
147
            } else
 
148
            if ( at2i->charge == -1 ) {
 
149
                if ( pVA[iat].cNumValenceElectrons == 6) {
 
150
                    typeR = fNumRNegChgO;
 
151
                } else
 
152
                if ( pVA[iat].cNumValenceElectrons == 5) {
 
153
                    typeR = fNumRNegChgN;
 
154
                }
 
155
                cur_tdhc.nNumMRevrs ++;
 
156
            } else
 
157
            if ( at2i->num_H && at2i->valence == at2i->chem_bonds_valence ) {
 
158
                typeR = fNumRNeutrlH;
 
159
            }
 
160
            cur_tdhc.nNumHRevrs += at2i->num_H;
 
161
 
 
162
            if ( atfi->charge == 1 ) {
 
163
                if ( atfi->num_H ) {
 
164
                    typeN = fNumNPosChgH;
 
165
                } else {
 
166
                    typeN = fNumNPosChgU;
 
167
                }
 
168
                cur_tdhc.nNumPNorml ++;
 
169
            } else
 
170
            if ( atfi->charge == -1 ) {
 
171
                if ( pVA[iat].cNumValenceElectrons == 6) {
 
172
                    typeN = fNumNNegChgO;
 
173
                } else
 
174
                if ( pVA[iat].cNumValenceElectrons == 5) {
 
175
                    typeN = fNumNNegChgN;
 
176
                }
 
177
                cur_tdhc.nNumMNorml ++;
 
178
            } else
 
179
            if ( atfi->num_H && atfi->valence == atfi->chem_bonds_valence ) {
 
180
                typeN = fNumNNeutrlH;
 
181
            }
 
182
            cur_tdhc.nNumHNorml += atfi->num_H;
 
183
            if ( at2[iat].charge < 0 || 0 < pVA[iat].nCPlusGroupEdge ) {
 
184
                if ( typeR >= 0 && (
 
185
                     (ret = AddToEdgeList( &IndList, typeR, INC_ADD_EDGE )) ||
 
186
                     (ret = AddToEdgeList( &IndList, itg, INC_ADD_EDGE )) ||
 
187
                     (ret = AddToEdgeList( &IndList, iat, INC_ADD_EDGE )) ) ) {
 
188
                    goto exit_function;
 
189
                }
 
190
                if ( typeN >= 0 && (
 
191
                     (ret = AddToEdgeList( &IndList, typeN, INC_ADD_EDGE )) ||
 
192
                     (ret = AddToEdgeList( &IndList, itg, INC_ADD_EDGE )) ||
 
193
                     (ret = AddToEdgeList( &IndList, iat, INC_ADD_EDGE )) ) ) {
 
194
                    goto exit_function;
 
195
                }
 
196
            }
 
197
 
 
198
        }
 
199
        if ( cur_tdhc.nNumHNorml == cur_tdhc.nNumHInchi &&
 
200
             cur_tdhc.nNumMNorml == cur_tdhc.nNumMInchi ) {
 
201
            IndList.num_edges = nCurIndListLen; /* t-group seems to be correct */
 
202
            continue;
 
203
        }
 
204
        if ( itg_out < max_tdhc ) {
 
205
            tdhc[itg_out ++] = cur_tdhc;
 
206
        } else {
 
207
            bOverflow |= 1;
 
208
            IndList.num_edges = nCurIndListLen;
 
209
            break;
 
210
        }
 
211
    }
 
212
    /* fill out atom index list */
 
213
    if ( itg_out ) {
 
214
        itg_prev = IndList.pnEdges[1]; /* the 1st saved t-group number */
 
215
        for ( type = 0; type < fNumAllChgT; type ++ ) {
 
216
            j = 0;
 
217
            for ( i = 0; i < itg_out; i ++ ) {
 
218
                num = 0;
 
219
                itg = tdhc[i].itg;
 
220
                tdhc[i].i[type] = -999; /* empty */
 
221
                while( IndList.pnEdges[j+1] == itg ) {
 
222
                    if ( IndList.pnEdges[j] == type ) {
 
223
                        if ( !num ++ ) {
 
224
                            tdhc[i].i[type] = pAtomIndList->num_edges;
 
225
                        }
 
226
                        if ( ret = AddToEdgeList( pAtomIndList, IndList.pnEdges[j+2], INC_ADD_EDGE )) {
 
227
                            goto exit_function;
 
228
                        }
 
229
                    }
 
230
                    j += 3;
 
231
                }
 
232
                tdhc[i].n[type] = num;
 
233
            }
 
234
        }
 
235
    }
 
236
    ret = itg_out;
 
237
exit_function:
 
238
    AllocEdgeList( &IndList, EDGE_LIST_FREE );
 
239
    return ret;
 
240
 
 
241
/*
 
242
#undef fNumRPosChgH
 
243
#undef fNumRPosChgU
 
244
#undef fNumRNegChgO
 
245
#undef fNumRNegChgN
 
246
 
 
247
#undef fNumNPosChgH
 
248
#undef fNumNPosChgU
 
249
#undef fNumNNegChgO
 
250
#undef fNumNNegChgN
 
251
 
 
252
#undef fNumAllChgT    
 
253
*/
 
254
}
 
255
 
 
256
/***********************************************************************************************/
 
257
int FixFixedHRestoredStructure(ICHICONST INPUT_PARMS *ip, STRUCT_DATA *sd, BN_STRUCT *pBNS, BN_DATA *pBD,
 
258
                        StrFromINChI *pStruct, inp_ATOM *at, inp_ATOM *at2, inp_ATOM *at3, VAL_AT *pVA,
 
259
                        ALL_TC_GROUPS *pTCGroups, T_GROUP_INFO **ppt_group_info, inp_ATOM **ppat_norm,
 
260
                        inp_ATOM **ppat_prep, INChI *pInChI[], long num_inp, int bHasSomeFixedH,
 
261
                        int *pnNumRunBNS, int *pnTotalDelta, int forbidden_edge_mask, int forbidden_stereo_edge_mask)
 
262
{
 
263
    /*--------- process extra or missing Fixed-H on non-tautomeric atoms ------*/
 
264
    /* at2 should be the most recently restored atom, Fixed-H */
 
265
    int i, j, k, delta, num_try, tot_succes, cur_success, ret = 0, bAllowedNFlowerEdges=0, num_zero_ret;
 
266
    CMP2FHINCHI c2i;
 
267
    CMP2FHINCHI *pc2i = &c2i;
 
268
 
 
269
    EDGE_LIST AllChargeEdges, CurrEdges, SFlowerEdges, NFlowerEdges, OtherNFlowerEdges, FixedLargeRingStereoEdges;
 
270
    EDGE_LIST AllBondEdges;
 
271
    
 
272
    EdgeIndex e;
 
273
    BNS_EDGE  *pe;
 
274
    Vertex v1, v2;
 
275
    BNS_VERTEX *pv1, *pv2;
 
276
 
 
277
    Vertex     vPathStart, vPathEnd;
 
278
    int        nPathLen, nDeltaH, nDeltaCharge, nNumVisitedAtoms;
 
279
 
 
280
    int        nNumRunBNS = 0, forbidden_edge_mask_inv = ~forbidden_edge_mask;
 
281
 
 
282
    INCHI_HEAPCHK
 
283
 
 
284
    AllocEdgeList( &AllChargeEdges, EDGE_LIST_CLEAR );
 
285
    AllocEdgeList( &CurrEdges, EDGE_LIST_CLEAR );
 
286
    AllocEdgeList( &NFlowerEdges, EDGE_LIST_CLEAR );
 
287
    AllocEdgeList( &SFlowerEdges, EDGE_LIST_CLEAR );
 
288
    AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_CLEAR );
 
289
    AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_CLEAR );
 
290
    AllocEdgeList( &AllBondEdges, EDGE_LIST_CLEAR );
 
291
 
 
292
    tot_succes = 0;
 
293
    
 
294
    if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
295
        goto exit_function;  /* no fixed-H found */
 
296
    }
 
297
 
 
298
    for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
299
        if ( (e=pVA[i].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
300
             (ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE )) ) {
 
301
            goto exit_function;
 
302
        }
 
303
        if ( (e=pVA[i].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
304
            if ( ret = AddToEdgeList( &AllChargeEdges, e, INC_ADD_EDGE ) ) {
 
305
                goto exit_function;
 
306
            }
 
307
 
 
308
            /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
 
309
            if ( pVA[i].cNumValenceElectrons == 5 && !pVA[i].cMetal && /* N, P, As */
 
310
                 NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e ))) {
 
311
 
 
312
                if ( pBNS->edge[j].forbidden ) {
 
313
                    continue;
 
314
                }
 
315
 
 
316
                if ( pBNS->edge[j].flow ) {
 
317
                    if ( ret = AddToEdgeList( &AllChargeEdges, j, INC_ADD_EDGE ) ) {
 
318
                        goto exit_function;
 
319
                    }
 
320
                    if ( ret = AddToEdgeList( &NFlowerEdges, j, INC_ADD_EDGE ) ) {
 
321
                        goto exit_function;
 
322
                    }
 
323
                } else {
 
324
                    if ( ret = AddToEdgeList( &OtherNFlowerEdges, j, INC_ADD_EDGE ) ) {
 
325
                        goto exit_function;
 
326
                    }
 
327
                }
 
328
            } else
 
329
            /* in addition, disallow N(V) creation by forbidding charge flower edge that has flow=1 */
 
330
            if ( pVA[i].cNumValenceElectrons == 6 && !pVA[i].cMetal && /* N, P, As */
 
331
                 NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e ))) {
 
332
 
 
333
                if ( pBNS->edge[j].forbidden ) {
 
334
                    continue;
 
335
                }
 
336
 
 
337
                if ( pBNS->edge[j].flow ) {
 
338
                    if ( ret = AddToEdgeList( &SFlowerEdges, j, INC_ADD_EDGE ) ) {
 
339
                        goto exit_function;
 
340
                    }
 
341
                }
 
342
            }
 
343
 
 
344
        }
 
345
        for ( j = 0; j < at2[i].valence; j ++ ) {
 
346
            k = at2[i].neighbor[j];
 
347
            if ( k < i && !pBNS->edge[e=pBNS->vert[i].iedge[j]].forbidden ) {
 
348
                if ( ret = AddToEdgeList( &AllBondEdges, e, INC_ADD_EDGE ) ) {
 
349
                    goto exit_function;
 
350
                }
 
351
            }
 
352
        }
 
353
    }
 
354
    if ( forbidden_stereo_edge_mask ) {
 
355
        for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
356
            for ( j = 0; j < at2[i].valence; j ++ ) {
 
357
                if ( pBNS->edge[k = pBNS->vert[i].iedge[j]].forbidden == forbidden_stereo_edge_mask ) {
 
358
                    int nMinRingSize = is_bond_in_Nmax_memb_ring( at2, i, j, pStruct->pbfsq->q,
 
359
                                                             pStruct->pbfsq->nAtomLevel,
 
360
                                                             pStruct->pbfsq->cSource, 99 /* max ring size */ );
 
361
                    if ( 0 < nMinRingSize && (ret = AddToEdgeList( &FixedLargeRingStereoEdges, k, INC_ADD_EDGE ))) {
 
362
                        goto exit_function;
 
363
                    }
 
364
                }
 
365
            }
 
366
        }
 
367
    }
 
368
 
 
369
    INCHI_HEAPCHK
 
370
    if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
371
        goto exit_function;
 
372
    }
 
373
    INCHI_HEAPCHK
 
374
    if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
375
        goto exit_function;
 
376
    }
 
377
 
 
378
    INCHI_HEAPCHK
 
379
 
 
380
    if ( !pc2i->bHasDifference ||
 
381
         !pc2i->len_c2at && pc2i->nNumTgRevrs == pc2i->nNumTgInChI &&
 
382
         pc2i->nNumEndpRevrs == pc2i->nNumRemHInChI &&
 
383
         pc2i->nNumEndpRevrs == pc2i->nNumEndpInChI &&
 
384
         !pc2i->nNumTgDiffMinus && !pc2i->nNumTgDiffH ) {
 
385
        goto exit_function; /* nothing to do */
 
386
    }
 
387
 
 
388
    /*goto exit_function;*/ /* debug only*/
 
389
 
 
390
    if ( pc2i->len_c2at >= 2 ) {
 
391
        /*----------------------------------------------------*/
 
392
        /* case 01: restored: O=AB-O(-)  original:  (-)O-AB=O */
 
393
        /* FixH:              0    -1                 -1    0 */
 
394
        /* MobH:              0     1                  1    0 */
 
395
        /*                         non-taut      non-taut     */
 
396
        /* O = O, S, Se; charged atoms O are not tautomeric   */
 
397
        /* Solution: move (-) from B-O(-) to O=A              */
 
398
        /*----------------------------------------------------*/
 
399
        int num_DB_O = 0, num_SB_O_Minus = 0, iat;
 
400
        short iat_DB_O[MAX_DIFF_FIXH], iat_SB_O_Minus[MAX_DIFF_FIXH];
 
401
        cur_success = 0;
 
402
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
403
            iat = pc2i->c2at[i].atomNumber;
 
404
            if ( pc2i->c2at[i].nValElectr == 6 /* && !pc2i->c2at[i].endptInChI -- mod#1*/ &&
 
405
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
406
                if ( /* orig. InChI info: */
 
407
                     num_SB_O_Minus < MAX_DIFF_FIXH && 
 
408
                     pc2i->c2at[i].nFixHInChI ==  0 && pc2i->c2at[i].nMobHInChI == 0 &&
 
409
                     /* reversed structure info: */
 
410
                     pc2i->c2at[i].nFixHRevrs == -1 && pc2i->c2at[i].nMobHRevrs == 1 &&
 
411
                     pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H && /* at2 is Fixed-H */
 
412
                     at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 ) {
 
413
                    iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
 
414
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
415
                        goto exit_function;
 
416
                    }
 
417
                } else
 
418
                if ( /* orig. InChI info: */
 
419
                     num_DB_O < MAX_DIFF_FIXH &&
 
420
                     pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI ==  1 &&
 
421
                     /* reversed structure info: */
 
422
                     pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs ==  0 &&
 
423
                     pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
424
                     at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
 
425
                    iat_DB_O[num_DB_O ++] = iat;
 
426
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
427
                        goto exit_function;
 
428
                    }
 
429
                }
 
430
            }
 
431
        }
 
432
        if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O ) ) {
 
433
            /* detected; attempt to fix */
 
434
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
435
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
436
            delta = 1;
 
437
            for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
 
438
                iat = iat_SB_O_Minus[i];
 
439
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
440
                if ( !pe->flow )
 
441
                    continue;
 
442
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
443
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
444
 
 
445
                pe->forbidden |= forbidden_edge_mask;
 
446
                pe->flow -= delta; /* remove (-) from AB-O(-) */
 
447
                pv1->st_edge.flow -= delta;
 
448
                pv2->st_edge.flow -= delta;
 
449
                pBNS->tot_st_flow -= 2*delta;
 
450
 
 
451
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
452
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
453
 
 
454
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
455
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
456
                    /* Added (-)charge to O=AB => nDeltaCharge == -1 */
 
457
                    /* Flow change on pe (-)charge edge (atom B-O(-)) is not known to RunBnsTestOnce()) */
 
458
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
459
                    if ( ret > 0 ) {
 
460
                        nNumRunBNS ++;
 
461
                        cur_success ++; /* 01 */
 
462
                    }
 
463
                } else {
 
464
                    pe->forbidden &= forbidden_edge_mask_inv;
 
465
                    pe->flow += delta;
 
466
                    pv1->st_edge.flow += delta;
 
467
                    pv2->st_edge.flow += delta;
 
468
                    pBNS->tot_st_flow += 2*delta;
 
469
                }
 
470
                INCHI_HEAPCHK
 
471
            }
 
472
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
473
            CurrEdges.num_edges = 0; /* clear current edge list */
 
474
        }
 
475
        if ( cur_success ) {
 
476
            tot_succes += cur_success;
 
477
            /* recalculate InChI from the structure */
 
478
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
479
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
480
                goto exit_function;
 
481
            }
 
482
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
483
                goto exit_function;
 
484
            }
 
485
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
486
                goto exit_function;  /* no fixed-H found */
 
487
            }
 
488
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
489
                goto exit_function;
 
490
            }
 
491
            if ( !pc2i->bHasDifference ) {
 
492
                goto exit_function; /* nothing to do */
 
493
            }
 
494
        }
 
495
    }
 
496
 
 
497
    if ( pc2i->len_c2at >= 1 ) {
 
498
        /*--------------------------------------------------------------*/
 
499
        /* case 02: restored: -O(+)=AB-NH2  original:  -O-AB=NH2(+)     */
 
500
        /* FixH:               0        0               0      1        */
 
501
        /* MobH:               0        2               0      1        */
 
502
        /* O = P, As, Sb, O, S, Se, F, Cl, Br, I; not taut. in InChI    */
 
503
        /* N = N, O, S, Se, Te; has H; tautomeric or not tautomeric     */
 
504
        /* Solution: move (+) from O(+) to NH2                          */
 
505
        /*--------------------------------------------------------------*/
 
506
        int num_DB_O_Plus = 0, num_SB_NH = 0, iat;
 
507
        short iat_DB_O_Plus[MAX_DIFF_FIXH], iat_SB_NH[MAX_DIFF_FIXH];
 
508
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
509
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
510
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : NULL;
 
511
        cur_success = 0;
 
512
        num_zero_ret = 0;
 
513
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
514
            iat = pc2i->c2at[i].atomNumber;
 
515
            if ( /* orig. InChI info: =NH2(+), =OH(+) */
 
516
                 num_SB_NH < MAX_DIFF_FIXH &&
 
517
                 (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1 ||
 
518
                  pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ &&
 
519
                 /*!pc2i->c2at[i].endptInChI &&*/ /* <=== relaxation */
 
520
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
521
                 pc2i->c2at[i].nFixHInChI>0 /*== 1 --modification#2*/ && /*pc2i->c2at[i].nMobHInChI ==  1 &&*/
 
522
                 /* reversed structure info: */
 
523
                 pc2i->c2at[i].nFixHRevrs ==  0 && /* pc2i->c2at[i].nMobHRevrs == 0 &&*/
 
524
                 pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H &&
 
525
                 at2[iat].valence == at2[iat].chem_bonds_valence ) {
 
526
                iat_SB_NH[num_SB_NH ++] = iat;
 
527
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
528
                    goto exit_function;
 
529
                }
 
530
            }
 
531
        }
 
532
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
533
            iat = nCanon2AtnoRevrs[i];
 
534
            if ( /* in restored atom: charge=+1, no H, has double bond, P, As, O, S, Se, Te, F, Cl, Br, I */
 
535
                 num_DB_O_Plus < MAX_DIFF_FIXH &&
 
536
                 at2[iat].charge == 1 && !at2[iat].num_H &&
 
537
                 at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
538
                 (pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cNumValenceElectrons == 7 ||
 
539
                  pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber > 1) &&
 
540
                 /* in orig.InChI: not an endpoint, has no H */
 
541
                 !pStruct->endpoint[i] && 
 
542
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
543
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
544
                 /* has (+) edge */
 
545
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
546
                iat_DB_O_Plus[num_DB_O_Plus ++] = iat;
 
547
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
548
                    goto exit_function;
 
549
                }
 
550
            }
 
551
        }
 
552
        if ( num_try = inchi_min( num_DB_O_Plus, num_SB_NH ) ) {
 
553
            /* detected; attempt to fix */
 
554
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
555
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
556
            delta = 1;
 
557
repeat_02_allow_NV:
 
558
            for ( i = 0; i < num_SB_NH && cur_success < num_try; i ++ ) {
 
559
                iat = iat_SB_NH[i];
 
560
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
561
                if ( !pe->flow )
 
562
                    continue;
 
563
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
564
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
565
 
 
566
                pe->forbidden |= forbidden_edge_mask;
 
567
                pe->flow -= delta;
 
568
                pv1->st_edge.flow -= delta;
 
569
                pv2->st_edge.flow -= delta;
 
570
                pBNS->tot_st_flow -= 2*delta;
 
571
 
 
572
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
573
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
574
                
 
575
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
576
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
577
                    /* Removed charge from O(+) => nDeltaCharge == -1 */
 
578
                    /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
 
579
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
580
                    if ( ret > 0 ) {
 
581
                        nNumRunBNS ++;
 
582
                        cur_success ++; /* 02 */
 
583
                    }
 
584
                } else {
 
585
                    num_zero_ret += !ret;
 
586
                    pe->forbidden &= forbidden_edge_mask_inv;
 
587
                    pe->flow += delta;
 
588
                    pv1->st_edge.flow += delta;
 
589
                    pv2->st_edge.flow += delta;
 
590
                    pBNS->tot_st_flow += 2*delta;
 
591
                }
 
592
                INCHI_HEAPCHK
 
593
            }
 
594
            if ( num_zero_ret == num_try && !bAllowedNFlowerEdges && NFlowerEdges.num_edges ) {
 
595
                RemoveForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask  );
 
596
                bAllowedNFlowerEdges = 1;
 
597
                goto repeat_02_allow_NV;
 
598
            }
 
599
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
600
            bAllowedNFlowerEdges = 0;
 
601
        }
 
602
        CurrEdges.num_edges = 0; /* clear current edge list */
 
603
        if ( cur_success ) {
 
604
            tot_succes += cur_success;
 
605
            /* recalculate InChI from the structure */
 
606
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
607
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
608
                goto exit_function;
 
609
            }
 
610
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
611
                goto exit_function;
 
612
            }
 
613
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
614
                goto exit_function;  /* no fixed-H found */
 
615
            }
 
616
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
617
                goto exit_function;
 
618
            }
 
619
            if ( !pc2i->bHasDifference ) {
 
620
                goto exit_function; /* nothing to do */
 
621
            }
 
622
        }
 
623
    }
 
624
 
 
625
    if ( pc2i->len_c2at >= 1 && pc2i->nNumTgRevrs == 1 &&
 
626
         (pc2i->nNumEndpRevrs > pc2i->nNumEndpInChI || pc2i->nNumTgInChI > 1) /* ADP in Revrs */ ) {
 
627
        /*--------------------------------------------------------------*/
 
628
        /* case 03: restored: -N(-)-AB=O    original:  -N=AB-O(-)       */
 
629
        /* FixH:               0       0                0     -1        */
 
630
        /* MobH:               0       0                0      1        */
 
631
        /* O = O, S, Se; N = N;                                         */
 
632
        /* restored atoms are tautomeric; original atoms are not taut.  */
 
633
        /* restored struct has 1 t-group; original has less endpoints   */
 
634
        /*                                and possibly >1 t-groups      */  
 
635
        /* Solution: move (-) from N(-) to =O                           */
 
636
        /*           these atoms are tautomeric in restored structure   */
 
637
        /*--------------------------------------------------------------*/
 
638
        int num_SB_N_Minus = 0, num_DB_O = 0, iat;
 
639
        short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
 
640
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
641
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
642
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
643
        /*
 
644
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
645
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
646
        */
 
647
        cur_success = 0;
 
648
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
649
            iat = pc2i->c2at[i].atomNumber;
 
650
            if ( /* orig. InChI info: -O(-) */
 
651
                 num_DB_O < MAX_DIFF_FIXH &&
 
652
                 pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
 
653
                 !pc2i->c2at[i].endptInChI &&
 
654
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
655
                 pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI ==  1 &&
 
656
                 /* reversed structure info: */
 
657
                 pc2i->c2at[i].endptRevrs &&
 
658
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 0 &&
 
659
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
660
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
 
661
                iat_DB_O[num_DB_O ++] = iat;
 
662
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
663
                    goto exit_function;
 
664
                }
 
665
            }
 
666
        }
 
667
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
668
            iat = nCanon2AtnoRevrs[i];
 
669
            if ( /* in restored atom N: charge=-1, no H, has no double bond, endpoint */
 
670
                 num_SB_N_Minus < MAX_DIFF_FIXH &&
 
671
                 at2[iat].charge == -1 && /*!at2[iat].num_H &&*/
 
672
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
673
                 pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
674
                 at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint &&
 
675
                 /* in orig.InChI: not an endpoint, has no H */
 
676
                 /* !pStruct->endpoint[i] && */
 
677
               /*  
 
678
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
679
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
680
                */
 
681
                 /* has (-) edge */
 
682
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
683
                iat_SB_N_Minus[num_SB_N_Minus ++] = iat;
 
684
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
685
                    goto exit_function;
 
686
                }
 
687
            }
 
688
        }
 
689
        if ( num_try = inchi_min( num_SB_N_Minus, num_DB_O ) ) {
 
690
            /* detected; attempt to fix */
 
691
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
692
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
693
            delta = 1;
 
694
            for ( i = 0; i < num_SB_N_Minus && cur_success < num_try; i ++ ) {
 
695
                iat = iat_SB_N_Minus[i];
 
696
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1; /* 2006-03-03: changed from CPlusGroupEdge */
 
697
                if ( !pe->flow )
 
698
                    continue;
 
699
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
700
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
701
 
 
702
                pe->forbidden |= forbidden_edge_mask;
 
703
                pe->flow -= delta;
 
704
                pv1->st_edge.flow -= delta;
 
705
                pv2->st_edge.flow -= delta;
 
706
                pBNS->tot_st_flow -= 2*delta;
 
707
 
 
708
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
709
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
710
 
 
711
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
712
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
713
                    /* Added (-) charge to =O => nDeltaCharge == 1 */
 
714
                    /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
 
715
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
716
                    if ( ret > 0 ) {
 
717
                        nNumRunBNS ++;
 
718
                        cur_success ++; /* 03 */
 
719
                    }
 
720
                } else {
 
721
                    pe->forbidden &= forbidden_edge_mask_inv;
 
722
                    pe->flow += delta;
 
723
                    pv1->st_edge.flow += delta;
 
724
                    pv2->st_edge.flow += delta;
 
725
                    pBNS->tot_st_flow += 2*delta;
 
726
                }
 
727
                INCHI_HEAPCHK
 
728
            }
 
729
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
730
        }
 
731
        CurrEdges.num_edges = 0; /* clear current edge list */
 
732
        if ( cur_success ) {
 
733
            tot_succes += cur_success;
 
734
            /* recalculate InChI from the structure */
 
735
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
736
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
737
                goto exit_function;
 
738
            }
 
739
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
740
                goto exit_function;
 
741
            }
 
742
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
743
                goto exit_function;  /* no fixed-H found */
 
744
            }
 
745
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
746
                goto exit_function;
 
747
            }
 
748
            if ( !pc2i->bHasDifference ) {
 
749
                goto exit_function; /* nothing to do */
 
750
            }
 
751
        }
 
752
    }
 
753
    
 
754
    if ( pc2i->nNumTgRevrs == 1 && /* pc2i->nNumRemHInChI < 0 &&*/
 
755
         (pc2i->nNumEndpRevrs > pc2i->nNumEndpInChI || pc2i->nNumTgInChI > 1) /* ADP in Revrs */ ) {
 
756
        /*--------------------------------------------------------------*/
 
757
        /* case 03a:restored: -N(-)-AB=O    original:  -N=AB-O(-)       */
 
758
        /* FixH:               0       0                0      0        */
 
759
        /* MobH:               0       0                0      0        */
 
760
        /* O = O, S, Se; N = N;                              taut       */
 
761
        /* restored atoms are tautomeric; original atom is; N may be.   */
 
762
        /* restored struct has 1 t-group; original has less endpoints   */
 
763
        /*                                and possibly >1 t-groups      */  
 
764
        /* Solution: move (-) from N(-) to =O                           */
 
765
        /*           these atoms are tautomeric in restored structure   */
 
766
        /*--------------------------------------------------------------*/
 
767
        int num_SB_N_Minus = 0, num_DB_O = 0, iat;
 
768
        short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
 
769
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
770
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
771
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
772
        S_CHAR   *pnMobHInChI = (pInChI[1] && pInChI[1]->nNum_H)? pInChI[1]->nNum_H :
 
773
                                (pInChI[0] && pInChI[0]->nNum_H)? pInChI[0]->nNum_H : NULL;
 
774
        S_CHAR   *pnFixHInChI = pStruct->fixed_H;
 
775
 
 
776
        cur_success = 0;
 
777
        CurrEdges.num_edges = 0;
 
778
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
779
            iat = nCanon2AtnoRevrs[i];
 
780
            if ( /* in restored atom N: charge=-1, no H, has no double bond, endpoint */
 
781
                 num_SB_N_Minus < MAX_DIFF_FIXH &&
 
782
                 at2[iat].charge == -1 && /*!at2[iat].num_H &&*/
 
783
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
784
                 pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
785
                 at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint &&
 
786
                 /* in orig.InChI: may be an endpoint, has no H */
 
787
                 /* has (-) edge */
 
788
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
789
                iat_SB_N_Minus[num_SB_N_Minus ++] = iat;
 
790
            } else
 
791
            if ( num_DB_O < MAX_DIFF_FIXH &&
 
792
                 at2[iat].charge == 0 && /*!at2[iat].num_H &&*/
 
793
                 at2[iat].valence+1 == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
794
                 pVA[iat].cNumValenceElectrons == 6 &&
 
795
                 at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint && /* endpoint in Reconstructed */
 
796
                 (pStruct->endpoint[i] || /* endpoint or H(+) acceptor in original */
 
797
                  pnMobHInChI && pnMobHInChI[i] == 1 && pnFixHInChI && pnFixHInChI[i] == -1 ) &&
 
798
                 /* has (-) edge */
 
799
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
800
                iat_DB_O[num_DB_O ++] = iat;
 
801
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
802
                    goto exit_function;
 
803
                }
 
804
            }    
 
805
        }
 
806
        if ( num_try = inchi_min( num_SB_N_Minus, num_DB_O ) ) {
 
807
            /* detected; attempt to fix */
 
808
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
809
            /* allow charge transfer to all found =O */
 
810
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
811
            delta = 1;
 
812
            for ( i = 0; i < num_SB_N_Minus && cur_success < num_try; i ++ ) {
 
813
                iat = iat_SB_N_Minus[i];
 
814
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
815
                if ( !pe->flow )
 
816
                    continue;
 
817
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
818
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
819
 
 
820
                pe->forbidden |= forbidden_edge_mask;
 
821
                pe->flow -= delta;
 
822
                pv1->st_edge.flow -= delta;
 
823
                pv2->st_edge.flow -= delta;
 
824
                pBNS->tot_st_flow -= 2*delta;
 
825
 
 
826
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
827
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
828
 
 
829
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
830
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
831
                    /* Added (-) charge to =O => nDeltaCharge == 1 */
 
832
                    /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
 
833
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
834
                    if ( ret > 0 ) {
 
835
                        nNumRunBNS ++;
 
836
                        cur_success ++; /* 03a */
 
837
                    }
 
838
                } else {
 
839
                    pe->forbidden &= forbidden_edge_mask_inv;
 
840
                    pe->flow += delta;
 
841
                    pv1->st_edge.flow += delta;
 
842
                    pv2->st_edge.flow += delta;
 
843
                    pBNS->tot_st_flow += 2*delta;
 
844
                }
 
845
                INCHI_HEAPCHK
 
846
            }
 
847
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
848
        }
 
849
        CurrEdges.num_edges = 0; /* clear current edge list */
 
850
        if ( cur_success ) {
 
851
            tot_succes += cur_success;
 
852
            /* recalculate InChI from the structure */
 
853
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
854
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
855
                goto exit_function;
 
856
            }
 
857
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
858
                goto exit_function;
 
859
            }
 
860
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
861
                goto exit_function;  /* no fixed-H found */
 
862
            }
 
863
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
864
                goto exit_function;
 
865
            }
 
866
            if ( !pc2i->bHasDifference ) {
 
867
                goto exit_function; /* nothing to do */
 
868
            }
 
869
        }
 
870
    }
 
871
 
 
872
    if ( pc2i->len_c2at >= 1 && pc2i->nNumTgInChI == 1 && /* ADP in InChI */
 
873
         (pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1) ) {
 
874
        /*--------------------------------------------------------------*/
 
875
        /* case 04: restored: OH(+)=AB-O- OH- orig.  HO-AB=O(+)- OH-    */
 
876
        /* FixH:               1       0   0          1      0   1      */
 
877
        /* MobH:               0       0   1          0      0   0      */
 
878
        /*                 non-taut.                taut        taut    */
 
879
        /*                                    ADP: one t-group or more endpoints */
 
880
        /* O(+) = N, P, As, As, O, S, Se; OH = N, O, S, Se, Te          */
 
881
        /* Solution: move (+) from O(+) to NH2                          */
 
882
        /*--------------------------------------------------------------*/
 
883
        int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
 
884
        short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
 
885
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
886
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
887
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
888
        cur_success = 0;
 
889
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
890
            iat = nCanon2AtnoRevrs[i];
 
891
            if ( /* in restored atom: charge=+1, has H, has double bond, N, O, S, Se, Te */
 
892
                 num_DB_Charged < MAX_DIFF_FIXH &&
 
893
                 at2[iat].charge == 1 && at2[iat].num_H &&
 
894
                 at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
895
                 (pVA[iat].cNumValenceElectrons == 6 ||
 
896
                  pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1) &&
 
897
                 /* in orig.InChI: an endpoint, has fixed-H */
 
898
                 pStruct->endpoint[i] && 
 
899
                 (pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
900
                 /*!(nMobHInChI && nMobHInChI[i] ) &&*/
 
901
                 /* has (+) edge */
 
902
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
903
 
 
904
                iat_DB_Charged[num_DB_Charged ++] = iat;
 
905
                
 
906
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
907
                    goto exit_function;
 
908
                }
 
909
            } else
 
910
            if ( /* in restored atom: charge=0, has no H, has no double bond, N, P, O, S, Se, Te */
 
911
                 num_SB_Neutr < MAX_DIFF_FIXH &&
 
912
                 at2[iat].charge == 0 && !at2[iat].num_H &&
 
913
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
914
                 (pVA[iat].cNumValenceElectrons == 6 ||
 
915
                  pVA[iat].cNumValenceElectrons == 5 ) &&
 
916
                 /* in orig.InChI: an endpoint, has fixed-H */
 
917
                 /* pStruct->endpoint[i] && */
 
918
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
919
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
920
                 /* has (+) edge */
 
921
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 &&
 
922
                 0 == pBNS->edge[e].forbidden ) {
 
923
 
 
924
                iat_SB_Neutr[num_SB_Neutr ++] = iat;
 
925
                
 
926
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
927
                    goto exit_function;
 
928
                }
 
929
            }
 
930
        }
 
931
        if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
 
932
            /* detected; attempt to fix */
 
933
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
934
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
935
            delta = 1;
 
936
            for ( i = 0; i < num_SB_Neutr && cur_success < num_try; i ++ ) {
 
937
                iat = iat_SB_Neutr[i];
 
938
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
939
                if ( !pe->flow )
 
940
                    continue;
 
941
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
942
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
943
 
 
944
                pe->forbidden |= forbidden_edge_mask;
 
945
                pe->flow -= delta;
 
946
                pv1->st_edge.flow -= delta;
 
947
                pv2->st_edge.flow -= delta;
 
948
                pBNS->tot_st_flow -= 2*delta;
 
949
 
 
950
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
951
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
952
 
 
953
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
954
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
955
                    /* Removed charge from O(+) => nDeltaCharge == -1 */
 
956
                    /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
 
957
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
958
                    if ( ret > 0 ) {
 
959
                        nNumRunBNS ++;
 
960
                        cur_success ++; /* 04 */
 
961
                    }
 
962
                } else {
 
963
                    pe->forbidden &= forbidden_edge_mask_inv;
 
964
                    pe->flow += delta;
 
965
                    pv1->st_edge.flow += delta;
 
966
                    pv2->st_edge.flow += delta;
 
967
                    pBNS->tot_st_flow += 2*delta;
 
968
                }
 
969
                INCHI_HEAPCHK
 
970
            }
 
971
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
972
        }
 
973
        CurrEdges.num_edges = 0; /* clear current edge list */
 
974
        if ( cur_success ) {
 
975
            tot_succes += cur_success;
 
976
            /* recalculate InChI from the structure */
 
977
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
978
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
979
                goto exit_function;
 
980
            }
 
981
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
982
                goto exit_function;
 
983
            }
 
984
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
985
                goto exit_function;  /* no fixed-H found */
 
986
            }
 
987
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
988
                goto exit_function;
 
989
            }
 
990
            if ( !pc2i->bHasDifference ) {
 
991
                goto exit_function; /* nothing to do */
 
992
            }
 
993
        }
 
994
    }
 
995
 
 
996
    if ( pc2i->len_c2at > 1 ) {
 
997
        /*--------------------------------------------------------------*/
 
998
        /* case 05: restored:  O=AB-NH      original:(-)O-AB=NH(+)      */
 
999
        /* FixH:               0     0                 -1     1         */
 
1000
        /* MobH:               0     1                  1     0         */
 
1001
        /* O = O, S, Se; N = N, O, S, Se, Te; all atoms not tautomeric  */
 
1002
        /* Solution: Separate charges                                   */
 
1003
        /*--------------------------------------------------------------*/
 
1004
        int num_DB_O = 0, num_SB_NH = 0, iat;
 
1005
        short iat_DB_O[MAX_DIFF_FIXH], iat_SB_NH[MAX_DIFF_FIXH];
 
1006
        cur_success = 0;
 
1007
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
1008
            iat = pc2i->c2at[i].atomNumber;
 
1009
            if ( /* orig. InChI info: =NH2(+), =OH(+) */
 
1010
                 num_SB_NH < MAX_DIFF_FIXH &&
 
1011
                 (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1 ||
 
1012
                  pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ &&
 
1013
                 !pc2i->c2at[i].endptInChI &&
 
1014
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
1015
                 pc2i->c2at[i].nFixHInChI == 1 && /*pc2i->c2at[i].nMobHInChI ==  1 &&*/
 
1016
                 /* reversed structure info: */
 
1017
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs &&
 
1018
                 pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H &&
 
1019
                 !pc2i->c2at[i].endptRevrs &&
 
1020
                 at2[iat].valence == at2[iat].chem_bonds_valence ) {
 
1021
                iat_SB_NH[num_SB_NH ++] = iat;
 
1022
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1023
                    goto exit_function;
 
1024
                }
 
1025
            } else
 
1026
            if ( /* orig. InChI info: -O(-) */
 
1027
                 num_DB_O < MAX_DIFF_FIXH &&
 
1028
                 (pc2i->c2at[i].nValElectr == 6 ) /* O, S, Se, Te */ &&
 
1029
                 !pc2i->c2at[i].endptInChI &&
 
1030
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
1031
                 pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI ==  1 &&
 
1032
                 /* reversed structure info: */
 
1033
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 0 &&
 
1034
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
1035
                 !pc2i->c2at[i].endptRevrs &&
 
1036
                 at2[iat].valence + 1 == at2[iat].chem_bonds_valence ) {
 
1037
                iat_DB_O[num_DB_O ++] = iat;
 
1038
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1039
                    goto exit_function;
 
1040
                }
 
1041
            }
 
1042
        }
 
1043
        if ( num_try = inchi_min( num_DB_O, num_SB_NH ) ) {
 
1044
            /* detected; attempt to fix */
 
1045
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1046
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
1047
            delta = 1;
 
1048
            for ( i = 0; i < num_SB_NH && cur_success < num_try; i ++ ) {
 
1049
                iat = iat_SB_NH[i];
 
1050
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
1051
                if ( !pe->flow )
 
1052
                    continue;
 
1053
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1054
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1055
 
 
1056
                pe->forbidden |= forbidden_edge_mask;
 
1057
                pe->flow -= delta;
 
1058
                pv1->st_edge.flow -= delta;
 
1059
                pv2->st_edge.flow -= delta;
 
1060
                pBNS->tot_st_flow -= 2*delta;
 
1061
 
 
1062
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1063
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1064
 
 
1065
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
1066
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
1067
                    /* Added charge to =O => nDeltaCharge == 1 */
 
1068
                    /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
 
1069
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1070
                    if ( ret > 0 ) {
 
1071
                        nNumRunBNS ++;
 
1072
                        cur_success ++; /* 05 */
 
1073
                    }
 
1074
                } else {
 
1075
                    pe->forbidden &= forbidden_edge_mask_inv;
 
1076
                    pe->flow += delta;
 
1077
                    pv1->st_edge.flow += delta;
 
1078
                    pv2->st_edge.flow += delta;
 
1079
                    pBNS->tot_st_flow += 2*delta;
 
1080
                }
 
1081
                INCHI_HEAPCHK
 
1082
            }
 
1083
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1084
        }
 
1085
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1086
        if ( cur_success ) {
 
1087
            tot_succes += cur_success;
 
1088
            /* recalculate InChI from the structure */
 
1089
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1090
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1091
                goto exit_function;
 
1092
            }
 
1093
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1094
                goto exit_function;
 
1095
            }
 
1096
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1097
                goto exit_function;  /* no fixed-H found */
 
1098
            }
 
1099
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1100
                goto exit_function;
 
1101
            }
 
1102
            if ( !pc2i->bHasDifference ) {
 
1103
                goto exit_function; /* nothing to do */
 
1104
            }
 
1105
        }
 
1106
    }
 
1107
 
 
1108
    if ( pStruct->fixed_H && pStruct->endpoint && pc2i->nChargeFixHInChI > 0 && pc2i->nChargeFixHInChI > pc2i->nChargeMobHInChI ) {
 
1109
        /*----------------------------------------------------------*/
 
1110
        /* case 06c: restored -NH- or -NH(+)  orig: -NH-            */
 
1111
        /*  Fixed-H            1       1             0              */
 
1112
        /*  Mobile-H           0       0             1              */
 
1113
        /*                     not tautomeric    not tautomeric     */
 
1114
        /*           has adjacent (+)                               */
 
1115
        /*           charges                                        */
 
1116
        /*  Solution: move (+) charges to the -NH- unless it already*/
 
1117
        /*            N = N, O, S, Se, Te                           */
 
1118
        /*            has (+) charge blocked by adjacent (+)        */
 
1119
        /*----------------------------------------------------------*/
 
1120
        int iat;
 
1121
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
1122
        /*
 
1123
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
1124
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
1125
        inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
 
1126
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
 
1127
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL;
 
1128
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
1129
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : NULL;
 
1130
        */
 
1131
        EDGE_LIST CurChargeEdges;
 
1132
        EdgeIndex e2;
 
1133
        cur_success = 0;
 
1134
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
 
1135
        CurrEdges.num_edges = 0;
 
1136
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
1137
            /* atoms -NH- from which H(+) were removed by the Normalization in orig. InChI */
 
1138
            iat = pc2i->c2at[i].atomNumber;
 
1139
            if ( (pc2i->c2at[i].nValElectr == 6 ||
 
1140
                  pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
 
1141
                 !pc2i->c2at[i].endptInChI &&
 
1142
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
1143
                if ( /* orig. InChI info: -NH- */
 
1144
                     pc2i->c2at[i].nFixHInChI == 1 && pc2i->c2at[i].nMobHInChI == 0 &&
 
1145
                     /* reversed structure info: */
 
1146
                     pc2i->c2at[i].nFixHRevrs == 0 && pc2i->c2at[i].nMobHRevrs == 1 && /* was not removed */
 
1147
                     /*pc2i->c2at[i].nAtChargeRevrs == 0 &&*/ at2[iat].num_H && /* at2 is Fixed-H */
 
1148
                     at2[iat].valence == at2[iat].chem_bonds_valence ) {
 
1149
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1150
                        goto exit_function;
 
1151
                    }
 
1152
                }
 
1153
            }
 
1154
        }
 
1155
        for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
1156
            /* find adjacent charged atoms */
 
1157
            iat = nCanon2AtnoRevrs[i];
 
1158
            if ( pStruct->endpoint[i] || at2[iat].charge != 1 || at2[iat].radical || pVA[iat].cMetal ) {
 
1159
                continue;
 
1160
            }
 
1161
            if ( 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow && pVA[iat].cNumValenceElectrons >= 5 ) {
 
1162
                /* positively charged atom */
 
1163
                for ( j = 0; j < at2[iat].valence; j ++ ) {
 
1164
                    if ( at2[k=(int)at2[iat].neighbor[j]].charge == 1 && !pVA[k].cMetal &&
 
1165
                         0 <= (e2=pVA[k].nCPlusGroupEdge-1) && !pBNS->edge[e2].forbidden && !pBNS->edge[e2].flow) {
 
1166
                        if ( 0 > FindInEdgeList( &CurrEdges, e ) &&
 
1167
                             0 > FindInEdgeList( &CurChargeEdges, e ) &&
 
1168
                             ( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) ) ) {
 
1169
                            goto exit_case_06c;
 
1170
                        }
 
1171
                        if ( 0 > FindInEdgeList( &CurrEdges, e2 ) &&
 
1172
                             0 > FindInEdgeList( &CurChargeEdges, e2 ) &&
 
1173
                             ( ret = AddToEdgeList( &CurChargeEdges, e2, INC_ADD_EDGE ) ) ) {
 
1174
                            goto exit_case_06c;
 
1175
                        }
 
1176
                    }
 
1177
                }
 
1178
            }
 
1179
        }
 
1180
        if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
 
1181
            /* detected; attempt to fix */
 
1182
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1183
            RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask  );
 
1184
            delta = 1;
 
1185
            for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
 
1186
                e = CurrEdges.pnEdges[i];
 
1187
                pe   = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
 
1188
                if ( !pe->flow )
 
1189
                    continue;
 
1190
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1191
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1192
 
 
1193
                pe->flow -= delta; /* add (+) to -NHm */
 
1194
                pv1->st_edge.flow -= delta;
 
1195
                pv2->st_edge.flow -= delta;
 
1196
                pBNS->tot_st_flow -= 2*delta;
 
1197
 
 
1198
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1199
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1200
 
 
1201
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
1202
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
1203
                    /* Removed (+)charge from -NH- => nDeltaCharge == -1 */
 
1204
                    /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
1205
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1206
                    if ( ret > 0 ) {
 
1207
                        nNumRunBNS ++;
 
1208
                        cur_success ++; /* 06c */
 
1209
                    }
 
1210
                } else {
 
1211
                    pe->flow += delta;
 
1212
                    pv1->st_edge.flow += delta;
 
1213
                    pv2->st_edge.flow += delta;
 
1214
                    pBNS->tot_st_flow += 2*delta;
 
1215
                }
 
1216
                INCHI_HEAPCHK
 
1217
            }
 
1218
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1219
        }
 
1220
exit_case_06c:
 
1221
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1222
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
 
1223
        if ( ret < 0 ) {
 
1224
            goto exit_function;
 
1225
        }
 
1226
        if ( cur_success ) {
 
1227
            tot_succes += cur_success;
 
1228
            /* recalculate InChI from the structure */
 
1229
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1230
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1231
                goto exit_function;
 
1232
            }
 
1233
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1234
                goto exit_function;
 
1235
            }
 
1236
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1237
                goto exit_function;  /* no fixed-H found */
 
1238
            }
 
1239
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1240
                goto exit_function;
 
1241
            }
 
1242
            if ( !pc2i->bHasDifference ) {
 
1243
                goto exit_function; /* nothing to do */
 
1244
            }
 
1245
        }
 
1246
    }
 
1247
 
 
1248
    if (  pc2i->len_c2at >= 2 ) {
 
1249
        /*------------------------------------------------------------*/
 
1250
        /* case 06d: restored: XH(+)=-AB-NH    orig.: XH-=AB=NH(+)    */
 
1251
        /* FixH:                1       1 0          0 1      1       */
 
1252
        /* MobH:                0    taut 1          1 taut   0       */
 
1253
        /*                                                            */
 
1254
        /*                                                            */
 
1255
        /* N  = N, O, S, Se; atoms N are not tautomeric in orig InChI */
 
1256
        /* X  = N, O, S, Se, Te, F, Cl, Br, I; atom X is non-taut     */
 
1257
        /* Solution: move (+) from X  to NH                           */
 
1258
        /*------------------------------------------------------------*/
 
1259
        int iat;
 
1260
        /*
 
1261
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
1262
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
1263
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
1264
        inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
 
1265
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
 
1266
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : 
 
1267
                                      pStruct->pOne_norm_data[TAUT_NON]->at;
 
1268
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
1269
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
1270
        */
 
1271
        EDGE_LIST CurChargeEdges;
 
1272
        cur_success = 0;
 
1273
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
 
1274
        CurrEdges.num_edges = 0;
 
1275
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
1276
            iat = pc2i->c2at[i].atomNumber;
 
1277
            /* XH(+) */
 
1278
            if ( /* reconstructed: non-taut and (+) */
 
1279
                 (pc2i->c2at[i].nMobHRevrs+1 == pc2i->c2at[i].nFixHRevrs &&
 
1280
                 pc2i->c2at[i].nFixHRevrs > 0 && !pc2i->c2at[i].endptRevrs &&
 
1281
                 pc2i->c2at[i].nAtChargeRevrs == 1 &&
 
1282
                 /* original InChI: non-taut & has H or an endpoint, has Fixed H */
 
1283
                 (!pc2i->c2at[i].nFixHInChI && pc2i->c2at[i].nMobHInChI == pc2i->c2at[i].nFixHRevrs ||
 
1284
                 pc2i->c2at[i].nFixHInChI == pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].endptInChI ))  &&
 
1285
                 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow) {
 
1286
 
 
1287
                if (ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE )) {
 
1288
                    goto exit_case_06d;
 
1289
                }
 
1290
            } else
 
1291
            /* -NH- */
 
1292
            if ( /* original InChI: has H and is not an endpoint */
 
1293
                (pc2i->c2at[i].nMobHInChI+1 == pc2i->c2at[i].nFixHInChI && 
 
1294
                 pc2i->c2at[i].nFixHInChI > 0 && !pc2i->c2at[i].endptInChI &&
 
1295
                 pc2i->c2at[i].nAtChargeRevrs == 0 &&
 
1296
                 /* reconstructed InChI: non-taut & has H or an endpoint, has Fixed H */
 
1297
                 (!pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].nMobHRevrs == pc2i->c2at[i].nFixHInChI ||
 
1298
                 pc2i->c2at[i].nFixHRevrs == pc2i->c2at[i].nFixHInChI && pc2i->c2at[i].endptRevrs ))  &&
 
1299
                 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && 
 
1300
                 pBNS->edge[e].flow) {
 
1301
 
 
1302
                if (ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE )) {
 
1303
                    goto exit_case_06d;
 
1304
                }
 
1305
            }
 
1306
        }
 
1307
        if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
 
1308
            /* detected; attempt to fix */
 
1309
            int bSFlowerEdgesMayBeForbidden = (SFlowerEdges.num_edges > 0);
 
1310
            int bSFlowerEdgesIsForbidden;
 
1311
            for ( bSFlowerEdgesIsForbidden = bSFlowerEdgesMayBeForbidden;
 
1312
                     0 <= bSFlowerEdgesIsForbidden; bSFlowerEdgesIsForbidden -- ) {
 
1313
                if ( bSFlowerEdgesIsForbidden ) {
 
1314
                    /* on the 1st pass disallow -S(+)= => =S=, allow only -S(+)= => -S- */
 
1315
                    SetForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
 
1316
                }
 
1317
                SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1318
                RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask  );
 
1319
                delta = 1;
 
1320
                for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
 
1321
                    e = CurrEdges.pnEdges[i];
 
1322
                    pe   = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
 
1323
                    if ( !pe->flow )
 
1324
                        continue;
 
1325
                    pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1326
                    pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1327
 
 
1328
                    pe->flow -= delta; /* add (+) to -NHm */
 
1329
                    pv1->st_edge.flow -= delta;
 
1330
                    pv2->st_edge.flow -= delta;
 
1331
                    pBNS->tot_st_flow -= 2*delta;
 
1332
 
 
1333
                    ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1334
                                          &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1335
 
 
1336
                    if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
1337
                                      vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
1338
                        /* Removed (+)charge from -NH- => nDeltaCharge == -1 */
 
1339
                        /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
1340
                        ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1341
                        if ( ret > 0 ) {
 
1342
                            nNumRunBNS ++;
 
1343
                            cur_success ++; /* 06d */
 
1344
                        }
 
1345
                    } else {
 
1346
                        pe->flow += delta;
 
1347
                        pv1->st_edge.flow += delta;
 
1348
                        pv2->st_edge.flow += delta;
 
1349
                        pBNS->tot_st_flow += 2*delta;
 
1350
                    }
 
1351
                    INCHI_HEAPCHK
 
1352
                }
 
1353
                RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1354
                RemoveForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
 
1355
            }
 
1356
 
 
1357
        }
 
1358
exit_case_06d:
 
1359
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1360
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
 
1361
        if ( cur_success ) {
 
1362
            tot_succes += cur_success;
 
1363
            /* recalculate InChI from the structure */
 
1364
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1365
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1366
                goto exit_function;
 
1367
            }
 
1368
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1369
                goto exit_function;
 
1370
            }
 
1371
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1372
                goto exit_function;  /* no fixed-H found */
 
1373
            }
 
1374
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1375
                goto exit_function;
 
1376
            }
 
1377
            if ( !pc2i->bHasDifference ) {
 
1378
                goto exit_function; /* nothing to do */
 
1379
            }
 
1380
        }
 
1381
    }
 
1382
 
 
1383
 
 
1384
    if ( pc2i->len_c2at >= 2 ) {
 
1385
        /*--------------------------------------------------------*/
 
1386
        /* case 06: restored: NHn(+)=AB-NHm  orig.: NHn-AB=NHm(+) */
 
1387
        /* FixH:               1        0            0     1      */
 
1388
        /* MobH:              n-1       m            n    m-1     */
 
1389
        /* N = N, O, S, Se; atoms N are not tautomeric            */
 
1390
        /* Solution: move (+) from NHn(+) to NHn                  */
 
1391
        /*--------------------------------------------------------*/
 
1392
        int num_DB_NHn_Plus = 0, num_SB_NHm_Neutr = 0, iat;
 
1393
        short iat_DB_NHn_Plus[MAX_DIFF_FIXH], iat_SB_NHm_Neutr[MAX_DIFF_FIXH];
 
1394
        cur_success = 0;
 
1395
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
1396
            iat = pc2i->c2at[i].atomNumber;
 
1397
            if ( (pc2i->c2at[i].nValElectr == 6 ||
 
1398
                  pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
 
1399
                 !pc2i->c2at[i].endptInChI &&
 
1400
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
1401
                if ( /* orig. InChI info: NHm */
 
1402
                     num_SB_NHm_Neutr < MAX_DIFF_FIXH &&
 
1403
                     pc2i->c2at[i].nFixHInChI == 1 && /*pc2i->c2at[i].nMobHInChI == 0 &&*/
 
1404
                     /* reversed structure info: */
 
1405
                     pc2i->c2at[i].nFixHRevrs == 0 && /*pc2i->c2at[i].nMobHRevrs == 1 &&*/
 
1406
                     pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H && /* at2 is Fixed-H */
 
1407
                     at2[iat].valence == at2[iat].chem_bonds_valence ) {
 
1408
                    iat_SB_NHm_Neutr[num_SB_NHm_Neutr ++] = iat;
 
1409
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1410
                        goto exit_function;
 
1411
                    }
 
1412
                } else
 
1413
                if ( /* orig. InChI info: */
 
1414
                     num_DB_NHn_Plus < MAX_DIFF_FIXH &&
 
1415
                     pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI &&*/
 
1416
                     /* reversed structure info: */
 
1417
                     pc2i->c2at[i].nFixHRevrs ==  1 && /*pc2i->c2at[i].nMobHRevrs ==  0 &&*/
 
1418
                     pc2i->c2at[i].nAtChargeRevrs == 1 && at2[iat].num_H &&
 
1419
                     at2[iat].valence < at2[iat].chem_bonds_valence ) {
 
1420
                    iat_DB_NHn_Plus[num_DB_NHn_Plus ++] = iat;
 
1421
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1422
                        goto exit_function;
 
1423
                    }
 
1424
                }
 
1425
            }
 
1426
        }
 
1427
        if ( num_try = inchi_min( num_SB_NHm_Neutr, num_DB_NHn_Plus ) ) {
 
1428
            /* detected; attempt to fix */
 
1429
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1430
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
1431
            delta = 1;
 
1432
            for ( i = 0; i < num_SB_NHm_Neutr && cur_success < num_try; i ++ ) {
 
1433
                iat = iat_SB_NHm_Neutr[i];
 
1434
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
1435
                if ( !pe->flow )
 
1436
                    continue;
 
1437
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1438
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1439
 
 
1440
                pe->forbidden |= forbidden_edge_mask;
 
1441
                pe->flow -= delta; /* add (+) to -NHm */
 
1442
                pv1->st_edge.flow -= delta;
 
1443
                pv2->st_edge.flow -= delta;
 
1444
                pBNS->tot_st_flow -= 2*delta;
 
1445
 
 
1446
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1447
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1448
 
 
1449
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
1450
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
1451
                    /* Removed (+)charge from -NHn => nDeltaCharge == -1 */
 
1452
                    /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
1453
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1454
                    if ( ret > 0 ) {
 
1455
                        nNumRunBNS ++;
 
1456
                        cur_success ++; /* 06 */
 
1457
                    }
 
1458
                } else {
 
1459
                    pe->forbidden &= forbidden_edge_mask_inv;
 
1460
                    pe->flow += delta;
 
1461
                    pv1->st_edge.flow += delta;
 
1462
                    pv2->st_edge.flow += delta;
 
1463
                    pBNS->tot_st_flow += 2*delta;
 
1464
                }
 
1465
                INCHI_HEAPCHK
 
1466
            }
 
1467
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1468
        }
 
1469
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1470
        if ( cur_success ) {
 
1471
            tot_succes += cur_success;
 
1472
            /* recalculate InChI from the structure */
 
1473
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1474
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1475
                goto exit_function;
 
1476
            }
 
1477
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1478
                goto exit_function;
 
1479
            }
 
1480
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1481
                goto exit_function;  /* no fixed-H found */
 
1482
            }
 
1483
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1484
                goto exit_function;
 
1485
            }
 
1486
            if ( !pc2i->bHasDifference ) {
 
1487
                goto exit_function; /* nothing to do */
 
1488
            }
 
1489
        }
 
1490
    }
 
1491
 
 
1492
    if ( (pc2i->nNumTgInChI > pc2i->nNumTgRevrs && pc2i->nNumTgRevrs == 1 ||
 
1493
          pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) &&
 
1494
          pStruct->nNumRemovedProtonsMobHInChI == pStruct->One_ti.tni.nNumRemovedProtons &&
 
1495
          pStruct->fixed_H && pStruct->endpoint && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ) {
 
1496
        /*----------------------------------------------------------*/
 
1497
        /* case 06a: restored: N'(+)=-AB-NH    orig.: N'-=AB=NH(+)  */
 
1498
        /* FixH:               0         1            0      1      */
 
1499
        /* MobH:               0         0            0      0      */
 
1500
        /*                    single t-group      multiple t-groups */
 
1501
        /* N  = N, O, S, Se; atoms N are not tautomeric             */
 
1502
        /* N' = N            atom N' is not tautomeric              */
 
1503
        /* Solution: move (+) from N' to NH                         */
 
1504
        /*----------------------------------------------------------*/
 
1505
        int iat;
 
1506
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
1507
        /*
 
1508
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
1509
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
1510
        */
 
1511
        inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
 
1512
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
 
1513
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL;
 
1514
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
1515
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
1516
        EDGE_LIST CurChargeEdges;
 
1517
        cur_success = 0;
 
1518
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
 
1519
        CurrEdges.num_edges = 0;
 
1520
        for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
1521
            iat = nCanon2AtnoRevrs[i];
 
1522
            if ( pStruct->endpoint[i] ) {
 
1523
                continue;
 
1524
            }
 
1525
            /* -NH-, -OH */
 
1526
            if ( pStruct->fixed_H[i] && !nMobHInChI[i] &&
 
1527
                 at2[iat].charge == 0 && at2[iat].radical == 0 &&
 
1528
                 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
1529
                 (ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) {
 
1530
                goto exit_case_06a;
 
1531
            } else
 
1532
            /* >N(+)= */
 
1533
            if ( at2[iat].charge == 1 && !at2[iat].num_H &&
 
1534
                 pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
1535
                 atfMobile_H_Revrs && atfMobile_H_Revrs[iat].charge == 0 &&
 
1536
                 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow &&
 
1537
                 (ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ))) {
 
1538
                goto exit_case_06a;
 
1539
            }
 
1540
        }
 
1541
        if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
 
1542
            /* detected; attempt to fix */
 
1543
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1544
            RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask  );
 
1545
            delta = 1;
 
1546
            for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
 
1547
                e = CurrEdges.pnEdges[i];
 
1548
                pe   = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
 
1549
                if ( !pe->flow )
 
1550
                    continue;
 
1551
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1552
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1553
 
 
1554
                pe->flow -= delta; /* add (+) to -NHm */
 
1555
                pv1->st_edge.flow -= delta;
 
1556
                pv2->st_edge.flow -= delta;
 
1557
                pBNS->tot_st_flow -= 2*delta;
 
1558
 
 
1559
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1560
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1561
 
 
1562
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
1563
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
1564
                    /* Removed (+)charge from -NH- => nDeltaCharge == -1 */
 
1565
                    /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
1566
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1567
                    if ( ret > 0 ) {
 
1568
                        nNumRunBNS ++;
 
1569
                        cur_success ++; /* 06a */
 
1570
                    }
 
1571
                } else {
 
1572
                    pe->flow += delta;
 
1573
                    pv1->st_edge.flow += delta;
 
1574
                    pv2->st_edge.flow += delta;
 
1575
                    pBNS->tot_st_flow += 2*delta;
 
1576
                }
 
1577
                INCHI_HEAPCHK
 
1578
            }
 
1579
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1580
        }
 
1581
exit_case_06a:
 
1582
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1583
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
 
1584
        if ( cur_success ) {
 
1585
            tot_succes += cur_success;
 
1586
            /* recalculate InChI from the structure */
 
1587
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1588
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1589
                goto exit_function;
 
1590
            }
 
1591
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1592
                goto exit_function;
 
1593
            }
 
1594
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1595
                goto exit_function;  /* no fixed-H found */
 
1596
            }
 
1597
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1598
                goto exit_function;
 
1599
            }
 
1600
            if ( !pc2i->bHasDifference ) {
 
1601
                goto exit_function; /* nothing to do */
 
1602
            }
 
1603
        }
 
1604
    }
 
1605
    if ( (pc2i->nNumTgInChI > pc2i->nNumTgRevrs && pc2i->nNumTgRevrs == 1 ||
 
1606
          pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) &&
 
1607
          (pStruct->nNumRemovedProtonsMobHInChI == pStruct->One_ti.tni.nNumRemovedProtons ||
 
1608
           pStruct->nNumRemovedProtonsMobHInChI > pStruct->One_ti.tni.nNumRemovedProtons ) &&
 
1609
          pStruct->fixed_H && pStruct->endpoint && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ) {
 
1610
        /*----------------------------------------------------------*/
 
1611
        /* case 06b: restored: X(+)=-AB-NH    orig.: X-=AB=NH(+)    */
 
1612
        /* FixH:               0        1 1          0      1       */
 
1613
        /* MobH:               0        0 t          0      0       */
 
1614
        /*                    single t-group      multiple t-groups */
 
1615
        /*                                        or no t-groupd    */
 
1616
        /* N  = N, O, S, Se; atoms N are not tautomeric             */
 
1617
        /* X  = O, S, Se, Te, F, Cl, Br, I; atom X is not tautomeric*/
 
1618
        /* Solution: move (+) from X  to NH                         */
 
1619
        /*----------------------------------------------------------*/
 
1620
        int iat;
 
1621
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
1622
        /*
 
1623
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
1624
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
1625
        */
 
1626
        inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
 
1627
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
 
1628
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds : NULL;
 
1629
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
1630
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
1631
        EDGE_LIST CurChargeEdges;
 
1632
        cur_success = 0;
 
1633
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
 
1634
        CurrEdges.num_edges = 0;
 
1635
        for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
1636
            iat = nCanon2AtnoRevrs[i];
 
1637
            if ( pStruct->endpoint[i] ) {
 
1638
                continue;
 
1639
            }
 
1640
            /* -NH-, -OH */
 
1641
            if ( pStruct->fixed_H[i] && !nMobHInChI[i] &&
 
1642
                 at2[iat].charge == 0 && at2[iat].radical == 0 &&
 
1643
                 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
1644
                 (ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ))) {
 
1645
                goto exit_case_06b;
 
1646
            } else
 
1647
            /* X(+)= */
 
1648
            if ( at2[iat].charge == 1 && !at2[iat].num_H &&
 
1649
                 (pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cPeriodicRowNumber == 7) &&
 
1650
                 atfMobile_H_Revrs && atfMobile_H_Revrs[iat].charge == 1 &&
 
1651
                 0 <= (e=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && !pBNS->edge[e].flow &&
 
1652
                 (ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ))) {
 
1653
                goto exit_case_06b;
 
1654
            }
 
1655
        }
 
1656
        if ( num_try = inchi_min( CurrEdges.num_edges, CurChargeEdges.num_edges ) ) {
 
1657
            /* detected; attempt to fix */
 
1658
            int bSFlowerEdgesMayBeForbidden = (SFlowerEdges.num_edges > 0);
 
1659
            int bSFlowerEdgesIsForbidden;
 
1660
            for ( bSFlowerEdgesIsForbidden = bSFlowerEdgesMayBeForbidden;
 
1661
                     0 <= bSFlowerEdgesIsForbidden; bSFlowerEdgesIsForbidden -- ) {
 
1662
                if ( bSFlowerEdgesIsForbidden ) {
 
1663
                    /* on the 1st pass disallow -S(+)= => =S=, allow only -S(+)= => -S- */
 
1664
                    SetForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
 
1665
                }
 
1666
                SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1667
                RemoveForbiddenEdgeMask( pBNS, &CurChargeEdges, forbidden_edge_mask  );
 
1668
                delta = 1;
 
1669
                for ( i = 0; i < CurrEdges.num_edges && cur_success < num_try; i ++ ) {
 
1670
                    e = CurrEdges.pnEdges[i];
 
1671
                    pe   = pBNS->edge + e; /* (+)charge edge of -NH- or -OH */
 
1672
                    if ( !pe->flow )
 
1673
                        continue;
 
1674
                    pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1675
                    pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1676
 
 
1677
                    pe->flow -= delta; /* add (+) to -NHm */
 
1678
                    pv1->st_edge.flow -= delta;
 
1679
                    pv2->st_edge.flow -= delta;
 
1680
                    pBNS->tot_st_flow -= 2*delta;
 
1681
 
 
1682
                    ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1683
                                          &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1684
 
 
1685
                    if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
1686
                                      vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
1687
                        /* Removed (+)charge from -NH- => nDeltaCharge == -1 */
 
1688
                        /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
1689
                        ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1690
                        if ( ret > 0 ) {
 
1691
                            nNumRunBNS ++;
 
1692
                            cur_success ++; /* 06b */
 
1693
                        }
 
1694
                    } else {
 
1695
                        pe->flow += delta;
 
1696
                        pv1->st_edge.flow += delta;
 
1697
                        pv2->st_edge.flow += delta;
 
1698
                        pBNS->tot_st_flow += 2*delta;
 
1699
                    }
 
1700
                    INCHI_HEAPCHK
 
1701
                }
 
1702
                RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1703
                RemoveForbiddenEdgeMask( pBNS, &SFlowerEdges, forbidden_edge_mask );
 
1704
            }
 
1705
 
 
1706
        }
 
1707
exit_case_06b:
 
1708
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1709
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
 
1710
        if ( cur_success ) {
 
1711
            tot_succes += cur_success;
 
1712
            /* recalculate InChI from the structure */
 
1713
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1714
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1715
                goto exit_function;
 
1716
            }
 
1717
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1718
                goto exit_function;
 
1719
            }
 
1720
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1721
                goto exit_function;  /* no fixed-H found */
 
1722
            }
 
1723
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1724
                goto exit_function;
 
1725
            }
 
1726
            if ( !pc2i->bHasDifference ) {
 
1727
                goto exit_function; /* nothing to do */
 
1728
            }
 
1729
        }
 
1730
    }
 
1731
 
 
1732
 
 
1733
 
 
1734
    if ( pc2i->nNumTgInChI > 1 &&
 
1735
          (pStruct->nNumRemovedProtonsMobHInChI > 0 || pStruct->ti.tni.nNumRemovedProtons > 0 ) &&
 
1736
          pStruct->fixed_H && pStruct->endpoint && 
 
1737
          pStruct->pOne_norm_data[TAUT_YES] && pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds ) {
 
1738
        /*----------------------------------------------------------*/
 
1739
        /* case 06e:restored: XHn(+)=-AB-YHm  orig.: XHn-=AB=YHm(+) */
 
1740
        /* FixH:               1          0           1      1      */
 
1741
        /* MobH:               0          1           t      t      */
 
1742
        /*                   non-taut atoms       multiple t-groups */
 
1743
        /*                                                          */
 
1744
        /* 1. orig. t-group has more H on its endpoints counted     */
 
1745
        /*          in atf and has no (+) on endpoint that has H    */
 
1746
        /* 2. orig. t-group has less H on its endpoints counted     */
 
1747
        /*          in atf and has (+) on endpoint that has H       */
 
1748
        /*          in reconstructed struct and less H in atf       */
 
1749
        /* Solution: move (+) from (2) to atom in (1) that has H    */
 
1750
        /*                                                          */
 
1751
        /*   tg1  reconstr:   XHn and more H than in orig t-group   */
 
1752
        /*             atf:   XHn                                   */
 
1753
        /*   tg2  reconstr:   XHm(+) and less H than in             */
 
1754
        /*             atf:   XH(m-1)           orig in t-group     */
 
1755
        /*                                                          */
 
1756
        /* N  = N, O, S, Se; atoms N are not tautomeric             */
 
1757
        /* X  = O, S, Se, Te, F, Cl, Br, I; atom X is not tautomeric*/
 
1758
        /* Solution: move (+) from X  to NH                         */
 
1759
        /*----------------------------------------------------------*/
 
1760
 
 
1761
        int iat, nNumWrongTg, jjoffs, jj, nNum2RemovePlus, nNum2AddPlus, nNum2MovePlus;
 
1762
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
1763
        /*
 
1764
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
1765
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
1766
        */
 
1767
        inp_ATOM *atfMobile_H_Revrs = pStruct->pOne_norm_data[TAUT_YES] &&
 
1768
                                      pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds?
 
1769
                                            pStruct->pOne_norm_data[TAUT_YES]->at_fixed_bonds :
 
1770
                                      pStruct->pOne_norm_data[TAUT_YES] &&
 
1771
                                      pStruct->pOne_norm_data[TAUT_YES]->at?
 
1772
                                            pStruct->pOne_norm_data[TAUT_YES]->at : NULL;
 
1773
        /*
 
1774
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
1775
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
1776
        */
 
1777
        EDGE_LIST CurChargeEdges /* source of (+)*/, EndpList;
 
1778
        TgDiffHChgFH tdhc[MAX_DIFF_FIXH];
 
1779
        BNS_VERTEX *pv1n, *pv2n;
 
1780
        BNS_EDGE   *pe1n, *pe2n;
 
1781
        Vertex      v1n, v2n;
 
1782
 
 
1783
        cur_success = 0;
 
1784
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_CLEAR );
 
1785
        AllocEdgeList( &EndpList, EDGE_LIST_CLEAR );
 
1786
        CurrEdges.num_edges = 0; /* receptors of (+) */
 
1787
        if ( !atfMobile_H_Revrs ) {
 
1788
            goto exit_case_06e;
 
1789
        }
 
1790
        nNumWrongTg = FillTgDiffHChgFH( tdhc, MAX_DIFF_FIXH, at2, atfMobile_H_Revrs,
 
1791
                                       nCanon2AtnoRevrs, pVA, &pStruct->ti, &EndpList );
 
1792
        if ( nNumWrongTg < 1 ) {
 
1793
            goto exit_case_06e; /* for now only transfer (+) from one Mobile-H group to another */
 
1794
        }
 
1795
        nNum2RemovePlus = nNum2AddPlus = nNum2MovePlus = 0;
 
1796
        for ( i = 0; i < nNumWrongTg; i ++ ) {
 
1797
            /* detect t-group that has extra (+) on H */
 
1798
            if ( tdhc[i].nNumHInchi > tdhc[i].nNumHNorml &&
 
1799
                 tdhc[i].nNumPRevrs > tdhc[i].nNumPNorml && tdhc[i].n[fNumRPosChgH] ) {
 
1800
                /* count how many (+) to remove */
 
1801
                /* store XH(+) atom numbers */
 
1802
                int nNumNeeded = inchi_min( tdhc[i].nNumHInchi-tdhc[i].nNumHNorml, tdhc[i].n[fNumRPosChgH]);
 
1803
                nNum2RemovePlus += nNumNeeded;
 
1804
                jjoffs = tdhc[i].i[ fNumRPosChgH ];
 
1805
                for ( jj = 0; jj < tdhc[i].n[fNumRPosChgH]; jj ++ ) {
 
1806
                    iat = EndpList.pnEdges[ jjoffs + jj ];
 
1807
                    e = pVA[iat].nCPlusGroupEdge-1;
 
1808
                    if ( ret = AddToEdgeList( &CurChargeEdges, e, INC_ADD_EDGE ) ) {
 
1809
                        goto exit_case_06e;
 
1810
                    }
 
1811
                }
 
1812
            } else
 
1813
            /* detect t-group that needs (+) on XH to reduce number of H */
 
1814
            if ( tdhc[i].nNumHInchi < tdhc[i].nNumHNorml && tdhc[i].n[fNumRNeutrlH] ) {
 
1815
                /* store XH atom numbers */
 
1816
                int nNumNeeded = inchi_min( tdhc[i].nNumHNorml-tdhc[i].nNumHInchi, tdhc[i].n[fNumRNeutrlH]);
 
1817
                nNum2AddPlus += nNumNeeded;
 
1818
                jjoffs = tdhc[i].i[ fNumRNeutrlH ];
 
1819
                for ( jj = 0; jj < tdhc[i].n[fNumRNeutrlH]; jj ++ ) {
 
1820
                    iat = EndpList.pnEdges[ jjoffs + jj ];
 
1821
                    e = pVA[iat].nCPlusGroupEdge-1;
 
1822
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1823
                        goto exit_case_06e;
 
1824
                    }
 
1825
                }
 
1826
            }
 
1827
        }
 
1828
        nNum2MovePlus = inchi_min( nNum2RemovePlus, nNum2AddPlus );
 
1829
        if ( CurrEdges.num_edges > 0 && CurChargeEdges.num_edges > 0 ) {
 
1830
            for ( i = 0; 0 < nNum2MovePlus && i < nNumWrongTg; i ++ ) {
 
1831
                /* detect t-group that has extra (+) on H */
 
1832
                if ( tdhc[i].nNumHInchi > tdhc[i].nNumHNorml &&
 
1833
                     tdhc[i].nNumPRevrs > tdhc[i].nNumPNorml && tdhc[i].n[fNumRPosChgH] ) {
 
1834
                    int nNum2Remove = tdhc[i].nNumHInchi - tdhc[i].nNumHNorml;
 
1835
                    if ( nNum2Remove < tdhc[i].n[fNumRPosChgH] ) {
 
1836
                        nNum2Remove = tdhc[i].n[fNumRPosChgH];
 
1837
                    }
 
1838
                    /* store XH(+) atom numbers */
 
1839
                    jjoffs = tdhc[i].i[ fNumRPosChgH ];
 
1840
                    SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1841
                    RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
1842
                    for ( jj = 0; 0 < nNum2MovePlus && 0 < nNum2Remove && jj < tdhc[i].n[fNumRPosChgH]; jj ++ ) {
 
1843
                        iat = EndpList.pnEdges[ jjoffs + jj ];
 
1844
                        e = pVA[iat].nCPlusGroupEdge-1;
 
1845
                        pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
1846
                        if ( pe->flow )
 
1847
                            continue;
 
1848
                        pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
1849
                        pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
1850
 
 
1851
                        for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
 
1852
                            pe1n = pBNS->edge + pv1->iedge[j];
 
1853
                            if ( pe1n->flow && !pe1n->forbidden ) {
 
1854
                                pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
 
1855
                                break;
 
1856
                            }
 
1857
                        }
 
1858
                        if ( j < 0 )
 
1859
                            continue; /* not found */
 
1860
                        
 
1861
                        for ( j = pv2->num_adj_edges-2; 0 <= j; j -- ) {
 
1862
                            pe2n = pBNS->edge + pv2->iedge[j];
 
1863
                            if ( pe2n->flow && !pe2n->forbidden ) {
 
1864
                                pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
 
1865
                                break;
 
1866
                            }
 
1867
                        }
 
1868
                        if ( j < 0 )
 
1869
                            continue; /* not found */
 
1870
                        delta = 1;
 
1871
                        pe->flow   += delta;
 
1872
                        pe1n->flow -= delta;
 
1873
                        pe2n->flow -= delta;
 
1874
                        pv1n->st_edge.flow -= delta;
 
1875
                        pv2n->st_edge.flow -= delta;
 
1876
                        pBNS->tot_st_flow -= 2*delta;
 
1877
 
 
1878
                        ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
1879
                                              &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
1880
 
 
1881
                        if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
 
1882
                                          vPathEnd == v2n && vPathStart == v1n) &&
 
1883
                                          (nDeltaCharge == 0 || nDeltaCharge == 1) ) {
 
1884
                            ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
1885
                            if ( ret > 0 ) {
 
1886
                                nNumRunBNS ++;
 
1887
                                nNum2Remove --;
 
1888
                                nNum2MovePlus --;
 
1889
                                cur_success ++; /* 06e */
 
1890
                            }
 
1891
                        } else {
 
1892
                            pe->flow   -= delta;
 
1893
                            pe1n->flow += delta;
 
1894
                            pe2n->flow += delta;
 
1895
                            pv1n->st_edge.flow += delta;
 
1896
                            pv2n->st_edge.flow += delta;
 
1897
                            pBNS->tot_st_flow += 2*delta;
 
1898
                        }
 
1899
                        if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1900
                            goto exit_case_06e;
 
1901
                        }
 
1902
                    }
 
1903
                    RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
1904
                }
 
1905
            }
 
1906
        }
 
1907
exit_case_06e:
 
1908
        CurrEdges.num_edges = 0; /* clear current edge list */
 
1909
        AllocEdgeList( &CurChargeEdges, EDGE_LIST_FREE );
 
1910
        AllocEdgeList( &EndpList, EDGE_LIST_FREE );
 
1911
        if ( cur_success ) {
 
1912
            tot_succes += cur_success;
 
1913
            /* recalculate InChI from the structure */
 
1914
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
1915
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
1916
                goto exit_function;
 
1917
            }
 
1918
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
1919
                goto exit_function;
 
1920
            }
 
1921
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
1922
                goto exit_function;  /* no fixed-H found */
 
1923
            }
 
1924
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
1925
                goto exit_function;
 
1926
            }
 
1927
            if ( !pc2i->bHasDifference ) {
 
1928
                goto exit_function; /* nothing to do */
 
1929
            }
 
1930
        }
 
1931
    }
 
1932
 
 
1933
 
 
1934
 
 
1935
    if ( pc2i->len_c2at >= 1 ) {
 
1936
        /*--------------------------------------------------------------*/
 
1937
        /* case 07: restored:  O(-)-AB=O  original:  O=AB-O(-)          */
 
1938
        /* FixH:               0       0             0     -1           */
 
1939
        /* MobH:               0       0             0      1           */
 
1940
        /*                    taut  (non-taut)     (taut) non-taut      */
 
1941
        /*                    taut  (taut)     (non-taut) non-taut      */   
 
1942
        /* O = O, S, Se, Te                                             */
 
1943
        /* Solution: move (-) from O(-)-AB to AB=O                      */
 
1944
        /*--------------------------------------------------------------*/
 
1945
        int num_SB_O_Minus = 0, num_DB_O_Neutr = 0, iat;
 
1946
        short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_DB_O_Neutr[MAX_DIFF_FIXH];
 
1947
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
1948
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
1949
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
1950
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
1951
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
1952
        cur_success = 0;
 
1953
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
1954
            iat = pc2i->c2at[i].atomNumber;
 
1955
            if ( /* orig. InChI info: -O(-), non-taut */
 
1956
                 num_DB_O_Neutr < MAX_DIFF_FIXH &&
 
1957
                 pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
 
1958
                 !pc2i->c2at[i].endptInChI &&
 
1959
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
1960
                 pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI ==  1 &&
 
1961
                 /* reversed structure info: */
 
1962
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 0 &&
 
1963
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
1964
                 at2[iat].valence < at2[iat].chem_bonds_valence ) {
 
1965
                iat_DB_O_Neutr[num_DB_O_Neutr ++] = iat;
 
1966
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1967
                    goto exit_function;
 
1968
                }
 
1969
            }
 
1970
        }
 
1971
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
1972
            iat = nCanon2AtnoRevrs[i];
 
1973
            if ( /* in restored atom: charge=-1, no H, has single bond, O, S, Se, Te */
 
1974
                 num_SB_O_Minus < MAX_DIFF_FIXH &&
 
1975
                 at2[iat].charge == -1 && !at2[iat].num_H &&
 
1976
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
1977
                 pVA[iat].cNumValenceElectrons == 6 &&
 
1978
                 at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint &&
 
1979
                 /* in orig.InChI: not an endpoint, has no H */
 
1980
                 /*pStruct->endpoint[i] && -- modificatuion#1 */
 
1981
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
1982
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
1983
                 /* has (-) edge */
 
1984
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
1985
                iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
 
1986
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
1987
                    goto exit_function;
 
1988
                }
 
1989
            }
 
1990
        }
 
1991
        if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O_Neutr ) ) {
 
1992
            /* detected; attempt to fix */
 
1993
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
1994
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
1995
            delta = 1;
 
1996
            for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
 
1997
                iat = iat_SB_O_Minus[i];
 
1998
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
1999
                if ( !pe->flow )
 
2000
                    continue;
 
2001
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2002
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2003
 
 
2004
                pe->forbidden |= forbidden_edge_mask;
 
2005
                pe->flow -= delta;
 
2006
                pv1->st_edge.flow -= delta;
 
2007
                pv2->st_edge.flow -= delta;
 
2008
                pBNS->tot_st_flow -= 2*delta;
 
2009
 
 
2010
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2011
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2012
 
 
2013
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
2014
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
2015
                    /* Moved (-) charge to AB=O => nDeltaCharge == 1 */
 
2016
                    /* Flow change on pe (-)charge edge (O(-)-AB) is not known to RunBnsTestOnce()) */
 
2017
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2018
                    if ( ret > 0 ) {
 
2019
                        nNumRunBNS ++;
 
2020
                        cur_success ++; /* 07 */
 
2021
                    }
 
2022
                } else {
 
2023
                    pe->forbidden &= forbidden_edge_mask_inv;
 
2024
                    pe->flow += delta;
 
2025
                    pv1->st_edge.flow += delta;
 
2026
                    pv2->st_edge.flow += delta;
 
2027
                    pBNS->tot_st_flow += 2*delta;
 
2028
                }
 
2029
                INCHI_HEAPCHK
 
2030
            }
 
2031
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
2032
        }
 
2033
        CurrEdges.num_edges = 0; /* clear current edge list */
 
2034
        if ( cur_success ) {
 
2035
            tot_succes += cur_success;
 
2036
            /* recalculate InChI from the structure */
 
2037
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2038
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2039
                goto exit_function;
 
2040
            }
 
2041
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2042
                goto exit_function;
 
2043
            }
 
2044
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2045
                goto exit_function;  /* no fixed-H found */
 
2046
            }
 
2047
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2048
                goto exit_function;
 
2049
            }
 
2050
            if ( !pc2i->bHasDifference ) {
 
2051
                goto exit_function; /* nothing to do */
 
2052
            }
 
2053
        }
 
2054
    }
 
2055
 
 
2056
    if ( pc2i->len_c2at >= 1 ) {
 
2057
        /*--------------------------------------------------------------*/
 
2058
        /* case 07a: restored: O(-)-N(V)B=O  original:  O=N(V)B-O(-)    */
 
2059
        /* FixH:               0          0             0      -1       */
 
2060
        /* MobH:               0          0             0       1       */
 
2061
        /*                non-taut  (non-taut)  non-taut  non-taut      */
 
2062
        /*                non-taut  (taut)      non-taut  non-taut      */   
 
2063
        /* O = O, S, Se, Te                                             */
 
2064
        /* Solution: move (-) from O(-)-AB to AB=O                      */
 
2065
        /*--------------------------------------------------------------*/
 
2066
        int num_SB_O_Minus = 0, num_DB_O_Neutr = 0, iat, iN;
 
2067
        short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_DB_O_Neutr[MAX_DIFF_FIXH];
 
2068
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
2069
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
2070
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
2071
        cur_success = 0;
 
2072
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
2073
            iat = pc2i->c2at[i].atomNumber;
 
2074
            if ( /* orig. InChI info: -O(-), non-taut */
 
2075
                 num_DB_O_Neutr < MAX_DIFF_FIXH &&
 
2076
                 pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
 
2077
                 !pc2i->c2at[i].endptInChI &&
 
2078
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
2079
                 pc2i->c2at[i].nFixHInChI == -1 && pc2i->c2at[i].nMobHInChI ==  1 &&
 
2080
                 /* reversed structure info: */
 
2081
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 0 &&
 
2082
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
2083
                 at2[iat].valence < at2[iat].chem_bonds_valence ) {
 
2084
                iat_DB_O_Neutr[num_DB_O_Neutr ++] = iat;
 
2085
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2086
                    goto exit_function;
 
2087
                }
 
2088
            }
 
2089
        }
 
2090
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
2091
            iat = nCanon2AtnoRevrs[i];
 
2092
            if ( /* in restored atom: charge=-1, no H, has single bond, O, S, Se, Te */
 
2093
                 num_SB_O_Minus < MAX_DIFF_FIXH &&
 
2094
                 at2[iat].charge == -1 && !at2[iat].num_H &&
 
2095
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
2096
                 pVA[iat].cNumValenceElectrons == 6 &&
 
2097
                 /*at_Mobile_H_Revrs && !at_Mobile_H_Revrs[iat].endpoint &&*/
 
2098
                 /* in orig.InChI: not an endpoint, has no H */
 
2099
                 !pStruct->endpoint[i] &&
 
2100
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
2101
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
2102
                 /* has N(V) neighbor */
 
2103
                 1 == at2[iat].valence && at2[iN=at2[iat].neighbor[0]].chem_bonds_valence==5 &&
 
2104
                 !at2[iN].charge && pVA[iN].cNumValenceElectrons == 5 &&
 
2105
                 /* has (-) edge */
 
2106
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
2107
                iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
 
2108
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2109
                    goto exit_function;
 
2110
                }
 
2111
            }
 
2112
        }
 
2113
        if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O_Neutr ) ) {
 
2114
            /* detected; attempt to fix */
 
2115
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2116
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
2117
            delta = 1;
 
2118
            for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
 
2119
                iat = iat_SB_O_Minus[i];
 
2120
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
2121
                if ( !pe->flow )
 
2122
                    continue;
 
2123
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2124
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2125
 
 
2126
                pe->forbidden |= forbidden_edge_mask;
 
2127
                pe->flow -= delta;
 
2128
                pv1->st_edge.flow -= delta;
 
2129
                pv2->st_edge.flow -= delta;
 
2130
                pBNS->tot_st_flow -= 2*delta;
 
2131
 
 
2132
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2133
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2134
 
 
2135
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
2136
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
2137
                    /* Moved (-) charge to AB=O => nDeltaCharge == 1 */
 
2138
                    /* Flow change on pe (-)charge edge (O(-)-AB) is not known to RunBnsTestOnce()) */
 
2139
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2140
                    if ( ret > 0 ) {
 
2141
                        nNumRunBNS ++;
 
2142
                        cur_success ++; /* 07 */
 
2143
                    }
 
2144
                } else {
 
2145
                    pe->forbidden &= forbidden_edge_mask_inv;
 
2146
                    pe->flow += delta;
 
2147
                    pv1->st_edge.flow += delta;
 
2148
                    pv2->st_edge.flow += delta;
 
2149
                    pBNS->tot_st_flow += 2*delta;
 
2150
                }
 
2151
                INCHI_HEAPCHK
 
2152
            }
 
2153
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
2154
        }
 
2155
        CurrEdges.num_edges = 0; /* clear current edge list */
 
2156
        if ( cur_success ) {
 
2157
            tot_succes += cur_success;
 
2158
            /* recalculate InChI from the structure */
 
2159
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2160
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2161
                goto exit_function;
 
2162
            }
 
2163
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2164
                goto exit_function;
 
2165
            }
 
2166
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2167
                goto exit_function;  /* no fixed-H found */
 
2168
            }
 
2169
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2170
                goto exit_function;
 
2171
            }
 
2172
            if ( !pc2i->bHasDifference ) {
 
2173
                goto exit_function; /* nothing to do */
 
2174
            }
 
2175
        }
 
2176
    }
 
2177
    if ( /*(pc2i->len_c2at >= 1 || pc2i->nNumRemHRevrs) &&*/ pc2i->nNumTgInChI == 1 && /* ADP in InChI */
 
2178
         (pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1) ) {
 
2179
        /*----------------------------------------------------------------*/
 
2180
        /* case 08: restored: O(-)-AB=N- OH- orig.   O=AB-N(-)- OH-       */
 
2181
        /* FixH:               1      0   0          0      0   1         */
 
2182
        /* MobH:               0      0   1          0      0   0         */
 
2183
        /*           may be taut or not  non-taut   taut  taut taut       */
 
2184
        /*                                    ADP: one t-group or more endpoints */
 
2185
        /* O(-) = S, Se, Te; N = N;                                       */
 
2186
        /* Solution: move (-) from O(-) to =N-; avoid stereogenic DB on N */
 
2187
        /*----------------------------------------------------------------*/
 
2188
        int num_DB_N_Neutr = 0, num_SB_O_Minus = 0, iat;
 
2189
        short iat_DB_N_Neutr[MAX_DIFF_FIXH], iat_SB_O_Minus[MAX_DIFF_FIXH];
 
2190
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
2191
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
2192
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
2193
        cur_success = 0;
 
2194
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
2195
            iat = nCanon2AtnoRevrs[i];
 
2196
            if ( /* in restored atom: charge=-1, has no H, has single bond, O, S, Se, Te */
 
2197
                 num_SB_O_Minus < MAX_DIFF_FIXH &&
 
2198
                 at2[iat].charge == -1 && !at2[iat].num_H &&
 
2199
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
2200
                 pVA[iat].cNumValenceElectrons == 6 &&
 
2201
                 /* in orig.InChI: an endpoint, may have fixed-H */
 
2202
                 pStruct->endpoint[i] && 
 
2203
                 /*!(pStruct->fixed_H && pStruct->fixed_H[i]) &&*/
 
2204
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
2205
                 /* has (-) edge */
 
2206
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
2207
 
 
2208
                iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
 
2209
                
 
2210
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2211
                    goto exit_function;
 
2212
                }
 
2213
            } else
 
2214
            if ( /* in restored atom: charge=0, has no H, has double non-stereogenic bond, N */
 
2215
                 num_DB_N_Neutr < MAX_DIFF_FIXH &&
 
2216
                 at2[iat].charge == 0 && !at2[iat].num_H && !at2[iat].sb_parity[0] &&
 
2217
                 at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
2218
                 pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
2219
                 /* in orig.InChI: an endpoint, has no fixed-H */
 
2220
                 pStruct->endpoint[i] &&
 
2221
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
2222
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
2223
                 /* has (-) edge */
 
2224
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 &&
 
2225
                 0 == pBNS->edge[e].forbidden ) {
 
2226
 
 
2227
                iat_DB_N_Neutr[num_DB_N_Neutr ++] = iat;
 
2228
                
 
2229
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2230
                    goto exit_function;
 
2231
                }
 
2232
            }
 
2233
        }
 
2234
        if ( num_try = inchi_min( num_DB_N_Neutr, num_SB_O_Minus ) ) {
 
2235
            /* detected; attempt to fix */
 
2236
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2237
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
2238
            /* allow stereobonds in rings change */
 
2239
            if ( forbidden_stereo_edge_mask )
 
2240
                RemoveForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
 
2241
 
 
2242
            delta = 1;
 
2243
            for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
 
2244
                iat = iat_SB_O_Minus[i];
 
2245
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
2246
                if ( !pe->flow )
 
2247
                    continue;
 
2248
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2249
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2250
 
 
2251
                pe->forbidden |= forbidden_edge_mask;
 
2252
                pe->flow -= delta;
 
2253
                pv1->st_edge.flow -= delta;
 
2254
                pv2->st_edge.flow -= delta;
 
2255
                pBNS->tot_st_flow -= 2*delta;
 
2256
 
 
2257
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2258
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2259
 
 
2260
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
2261
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
2262
                    /* Moved (-) charge to =N- => nDeltaCharge == 1 */
 
2263
                    /* Flow change on pe (-)charge edge (atom (-)O-) is not known to RunBnsTestOnce()) */
 
2264
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2265
                    if ( ret > 0 ) {
 
2266
                        nNumRunBNS ++;
 
2267
                        cur_success ++; /* 08 */
 
2268
                    }
 
2269
                } else {
 
2270
                    pe->forbidden &= forbidden_edge_mask_inv;
 
2271
                    pe->flow += delta;
 
2272
                    pv1->st_edge.flow += delta;
 
2273
                    pv2->st_edge.flow += delta;
 
2274
                    pBNS->tot_st_flow += 2*delta;
 
2275
                }
 
2276
                INCHI_HEAPCHK
 
2277
            }
 
2278
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2279
            if ( forbidden_stereo_edge_mask )
 
2280
                SetForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
 
2281
        }
 
2282
        CurrEdges.num_edges = 0; /* clear current edge list */
 
2283
        if ( cur_success ) {
 
2284
            tot_succes += cur_success;
 
2285
            /* recalculate InChI from the structure */
 
2286
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2287
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2288
                goto exit_function;
 
2289
            }
 
2290
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2291
                goto exit_function;
 
2292
            }
 
2293
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2294
                goto exit_function;  /* no fixed-H found */
 
2295
            }
 
2296
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2297
                goto exit_function;
 
2298
            }
 
2299
            if ( !pc2i->bHasDifference ) {
 
2300
                goto exit_function; /* nothing to do */
 
2301
            }
 
2302
        }
 
2303
    }
 
2304
 
 
2305
    if ( pc2i->len_c2at >= 2 ) {
 
2306
        /*--------------------------------------------------------*/
 
2307
        /* case 09: restored: NH2(+)=C--NH2 orig.: NH2-C(+)-NH2   */
 
2308
        /* FixH:               2     |  2            0  |   0     */
 
2309
        /* MobH:               0        0            2      2     */
 
2310
        /* N = N,            taut      taut     non-taut  non-taut*/
 
2311
        /* Solution: move (+) from NH2(+) to C                    */
 
2312
        /*--------------------------------------------------------*/
 
2313
        int iat;
 
2314
        cur_success = 0;
 
2315
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
2316
            iat = pc2i->c2at[i].atomNumber;
 
2317
            if ( (pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
 
2318
                 /* orig. InChI info: */
 
2319
                 !pc2i->c2at[i].endptInChI &&
 
2320
                 pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI &&
 
2321
                 /* reversed structure info: */
 
2322
                 pc2i->c2at[i].endptRevrs &&
 
2323
                 pc2i->c2at[i].nFixHRevrs && !pc2i->c2at[i].nMobHRevrs &&
 
2324
                 pc2i->c2at[i].nAtChargeRevrs == 1 &&
 
2325
                 at2[iat].valence + 1 == at2[iat].chem_bonds_valence &&
 
2326
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
2327
                EdgeIndex eNC = NO_VERTEX, eCPlusC;
 
2328
                int       iNH2, iatC, iatNH2, icNH2;
 
2329
                /* found NH2(+)=; locate =C< and find whether it has -NH2 neighbor */
 
2330
                for ( j = 0; j < at2[iat].valence; j ++ ) {
 
2331
                    if ( at2[iat].bond_type[j] == BOND_TYPE_DOUBLE )
 
2332
                        break;
 
2333
                }
 
2334
                if ( j == at2[iat].valence )
 
2335
                    continue;
 
2336
                eNC = pBNS->vert[iat].iedge[j]; /* edge NH2(+)=C */
 
2337
                iatC = at2[iat].neighbor[j];
 
2338
                if ( pVA[iatC].cNumValenceElectrons != 4 || pVA[iatC].cMetal || at2[iatC].charge ||
 
2339
                     at2[iatC].valence != 3 || at2[iatC].valence+1 != at2[iatC].chem_bonds_valence ||
 
2340
                     (eCPlusC=pVA[iatC].nCPlusGroupEdge-1) < 0 || pBNS->edge[eCPlusC].forbidden)
 
2341
                    continue;
 
2342
                for ( j = 0; j < at2[iatC].valence; j ++ ) {
 
2343
                    iatNH2 = at2[iatC].neighbor[j];
 
2344
                    if ( iatNH2 == iat || pVA[iatNH2].cNumValenceElectrons != 5 ||
 
2345
                         pVA[iatNH2].cPeriodicRowNumber != 1 || !at2[iatNH2].num_H || at2[iatNH2].charge)
 
2346
                        continue;
 
2347
                    icNH2 = pStruct->nAtno2Canon[0][iatNH2];
 
2348
                    for ( iNH2 = 0; iNH2 < pc2i->len_c2at; iNH2 ++ ) {
 
2349
                        if ( iatNH2 == pc2i->c2at[iNH2].atomNumber )
 
2350
                            break;
 
2351
                    }
 
2352
                    if ( iNH2 == pc2i->len_c2at )
 
2353
                        continue;
 
2354
 
 
2355
                    if ( (pc2i->c2at[iNH2].nValElectr == 5 && pc2i->c2at[iNH2].nPeriodNum == 1) &&
 
2356
                         /* orig. InChI info: */
 
2357
                         !pc2i->c2at[iNH2].endptInChI &&
 
2358
                         pc2i->c2at[iNH2].nFixHInChI == 0 && pc2i->c2at[iNH2].nMobHInChI &&
 
2359
                         /* reversed structure info: */
 
2360
                         pc2i->c2at[iNH2].endptRevrs &&
 
2361
                         pc2i->c2at[iNH2].nFixHRevrs && !pc2i->c2at[iNH2].nMobHRevrs &&
 
2362
                         pc2i->c2at[iNH2].nAtChargeRevrs == 0 &&
 
2363
                         at2[iatNH2].valence == at2[iatNH2].chem_bonds_valence ) {
 
2364
                        /* we have found NH2(+)=, =C<, and bond between them */
 
2365
 
 
2366
                        if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2367
                            goto exit_function;
 
2368
                        }
 
2369
                        if ( ret = AddToEdgeList( &CurrEdges, eCPlusC, INC_ADD_EDGE ) ) {
 
2370
                            goto exit_function;
 
2371
                        }
 
2372
                        SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2373
                        RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
2374
                        delta = 1;
 
2375
 
 
2376
                        pe   = pBNS->edge + eNC;
 
2377
                        if ( !pe->flow )
 
2378
                            continue;
 
2379
                        pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2380
                        pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2381
 
 
2382
                        pe->forbidden |= forbidden_edge_mask;
 
2383
                        pe->flow -= delta; /* add (+) to -NHm */
 
2384
                        pv1->st_edge.flow -= delta;
 
2385
                        pv2->st_edge.flow -= delta;
 
2386
                        pBNS->tot_st_flow -= 2*delta;
 
2387
 
 
2388
                        ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2389
                                              &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2390
 
 
2391
                        if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
2392
                                          vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
 
2393
                            /* Removed (+)charge from -NHn => nDeltaCharge == -1 */
 
2394
                            /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
2395
                            ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2396
                            if ( ret > 0 ) {
 
2397
                                nNumRunBNS ++;
 
2398
                                cur_success ++; /* 09 */
 
2399
                            }
 
2400
                        } else {
 
2401
                            pe->flow += delta;
 
2402
                            pv1->st_edge.flow += delta;
 
2403
                            pv2->st_edge.flow += delta;
 
2404
                            pBNS->tot_st_flow += 2*delta;
 
2405
                        }
 
2406
                        INCHI_HEAPCHK
 
2407
                        pe->forbidden &= forbidden_edge_mask_inv;
 
2408
                        RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
2409
                        CurrEdges.num_edges = 0; /* clear current edge list */
 
2410
                        break;
 
2411
                    }
 
2412
                }
 
2413
            }
 
2414
        }
 
2415
        if ( cur_success ) {
 
2416
            tot_succes += cur_success;
 
2417
            /* recalculate InChI from the structure */
 
2418
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2419
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2420
                goto exit_function;
 
2421
            }
 
2422
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2423
                goto exit_function;
 
2424
            }
 
2425
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2426
                goto exit_function;  /* no fixed-H found */
 
2427
            }
 
2428
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2429
                goto exit_function;
 
2430
            }
 
2431
            if ( !pc2i->bHasDifference ) {
 
2432
                goto exit_function; /* nothing to do */
 
2433
            }
 
2434
        }
 
2435
    }
 
2436
 
 
2437
 
 
2438
    if ( pc2i->len_c2at >= 2 ) {
 
2439
        /*--------------------------------------------------------*/
 
2440
        /* case 10: restored: NH2-X(+)-NH-  orig.: NH2(+)=X-NH-   */
 
2441
        /* FixH:               0        0            2      1     */
 
2442
        /* MobH:               2        1            0      0     */
 
2443
        /* N = N,O,S,Se,Te non-taut  non-taut       taut   taut   */
 
2444
        /* Solution: move (+) from X(+) to NH2 or NH              */
 
2445
        /*--------------------------------------------------------*/
 
2446
        int iat;
 
2447
        cur_success = 0;
 
2448
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
2449
            if ( pc2i->c2at[i].nValue )
 
2450
                continue;
 
2451
            iat = pc2i->c2at[i].atomNumber;
 
2452
            if ( (pc2i->c2at[i].nValElectr == 6 ||
 
2453
                  pc2i->c2at[i].nValElectr == 5 && pc2i->c2at[i].nPeriodNum == 1) &&
 
2454
                 /* orig. InChI info: */
 
2455
                 pc2i->c2at[i].endptInChI &&
 
2456
                 pc2i->c2at[i].nFixHInChI && !pc2i->c2at[i].nMobHInChI &&
 
2457
                 /* reversed structure info: */
 
2458
                 !pc2i->c2at[i].endptRevrs &&
 
2459
                 !pc2i->c2at[i].nFixHRevrs && pc2i->c2at[i].nMobHRevrs &&
 
2460
                 pc2i->c2at[i].nAtChargeRevrs == 0 &&
 
2461
                 at2[iat].valence == at2[iat].chem_bonds_valence &&
 
2462
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
2463
 
 
2464
                EdgeIndex eCPlusC, eCPlusNH2, bContinue=1;
 
2465
                int       iNH2, iatC, iatNH2, icNH2, j1, j2;
 
2466
                BNS_EDGE *pe_iat, *pe_iNH2;
 
2467
                /* found NH2- locate -X(+) and find whether it has another -NH2 neighbor */
 
2468
                for ( j1 = 0; j1 < at2[iat].valence && bContinue; j1 ++ ) {
 
2469
                    if ( at2[iat].bond_type[j1] == BOND_TYPE_SINGLE &&
 
2470
                         at2[iatC = at2[iat].neighbor[j1]].charge == 1 &&
 
2471
                         (4 <= pVA[iatC].cNumValenceElectrons && pVA[iatC].cNumValenceElectrons <= 6) &&
 
2472
                         at2[iatC].valence == at2[iatC].chem_bonds_valence &&
 
2473
                         (eCPlusC=pVA[iatC].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[eCPlusC].forbidden) {
 
2474
                        /* found a candidate for X; find another NH2 */
 
2475
                        for ( j2 = 0; j2 < at2[iatC].valence && bContinue; j2 ++ ) {
 
2476
                            if ( at2[iatC].bond_type[j2] == BOND_TYPE_SINGLE &&
 
2477
                                 iat != (iatNH2 = at2[iatC].neighbor[j2]) &&
 
2478
                                 at2[iatNH2].charge == 0 && at2[iatNH2].num_H &&
 
2479
                                 (pVA[iatNH2].cNumValenceElectrons==5 || pVA[iatNH2].cNumValenceElectrons==6) &&
 
2480
                                 at2[iatNH2].valence == at2[iatNH2].chem_bonds_valence &&
 
2481
                                 (eCPlusNH2=pVA[iatNH2].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[eCPlusNH2].forbidden) {
 
2482
                                for ( iNH2 = 0; iNH2 < pc2i->len_c2at; iNH2 ++ ) {
 
2483
                                    if ( iatNH2 != pc2i->c2at[iNH2].atomNumber || pc2i->c2at[iNH2].nValue )
 
2484
                                        continue;
 
2485
                                    /* check the second -NH */
 
2486
                                    icNH2 = pStruct->nAtno2Canon[0][iatNH2]; /* canon number -1 */
 
2487
                                    if ( /* orig. InChI info: */
 
2488
                                         pc2i->c2at[iNH2].endptInChI &&
 
2489
                                         pc2i->c2at[iNH2].nFixHInChI && !pc2i->c2at[iNH2].nMobHInChI &&
 
2490
                                         /* reversed structure info: */
 
2491
                                         !pc2i->c2at[iNH2].endptRevrs &&
 
2492
                                         !pc2i->c2at[iNH2].nFixHRevrs && pc2i->c2at[iNH2].nMobHRevrs &&
 
2493
                                         pc2i->c2at[iNH2].nAtChargeRevrs == 0 ) {
 
2494
                                        /* we have found NH-X(+)-NH; remove charge from X(+) */
 
2495
                                        pe_iat  = pBNS->edge + pBNS->vert[iat].iedge[j1];
 
2496
                                        pe_iNH2 = pBNS->edge + pBNS->vert[iatC].iedge[j2];
 
2497
                                        /* pick up one of -NH to move (+) to it */
 
2498
                                        if ( !pe_iat->forbidden && pBNS->edge[e].flow ) {
 
2499
                                            pe = pBNS->edge + e;
 
2500
                                        } else
 
2501
                                        if ( !pe_iNH2->forbidden && pBNS->edge[eCPlusNH2].flow ) {
 
2502
                                            pe = pBNS->edge + eCPlusNH2;
 
2503
                                        } else {
 
2504
                                            continue; /* none of the two -X(+)- bonds may be changed */
 
2505
                                        }
 
2506
                                        if ( ret = AddToEdgeList( &CurrEdges, eCPlusC, INC_ADD_EDGE ) ) {
 
2507
                                            goto exit_function;
 
2508
                                        }
 
2509
                                        SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2510
                                        RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
2511
                                        delta = 1;
 
2512
 
 
2513
                                        pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2514
                                        pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2515
 
 
2516
                                        /*pe->forbidden |= forbidden_edge_mask;*/
 
2517
                                        pe->flow -= delta; /* add (+) to -NHm */
 
2518
                                        pv1->st_edge.flow -= delta;
 
2519
                                        pv2->st_edge.flow -= delta;
 
2520
                                        pBNS->tot_st_flow -= 2*delta;
 
2521
 
 
2522
                                        ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2523
                                                              &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2524
 
 
2525
                                        if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
2526
                                                          vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == -1 ) {
 
2527
                                            /* Removed (+)charge from -NHn => nDeltaCharge == -1 */
 
2528
                                            /* Flow change on pe (+)charge edge (atom NHm(+)) is not known to RunBnsTestOnce()) */
 
2529
                                            ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2530
                                            if ( ret > 0 ) {
 
2531
                                                nNumRunBNS ++;
 
2532
                                                cur_success ++; /* 10 */
 
2533
                                                bContinue = 0;
 
2534
                                                pc2i->c2at[i].nValue    = 1;    /* mark as used */
 
2535
                                                pc2i->c2at[iNH2].nValue = 1; /* mark as used */
 
2536
                                            }
 
2537
                                        } else {
 
2538
                                            pe->flow += delta;
 
2539
                                            pv1->st_edge.flow += delta;
 
2540
                                            pv2->st_edge.flow += delta;
 
2541
                                            pBNS->tot_st_flow += 2*delta;
 
2542
                                        }
 
2543
                                        INCHI_HEAPCHK
 
2544
 
 
2545
                                        /*pe->forbidden &= forbidden_edge_mask_inv;*/
 
2546
                                        RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
2547
                                        CurrEdges.num_edges = 0; /* clear current edge list */
 
2548
                                        break;
 
2549
                                    }
 
2550
                                } /* iNH2: pc2i->c2at[iNH2] cycle */
 
2551
                            }
 
2552
                        } /* j2: iatC neighbors cycle */
 
2553
                    }
 
2554
                } /* j1: iat neighbors cycle */
 
2555
            }
 
2556
        } /* i: pc2i->c2at[i] cycle */
 
2557
        if ( cur_success ) {
 
2558
            /*
 
2559
            for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
2560
                pc2i->c2at[i].nValue = 0;
 
2561
            }
 
2562
            */
 
2563
            tot_succes += cur_success;
 
2564
            /* recalculate InChI from the structure */
 
2565
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2566
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2567
                goto exit_function;
 
2568
            }
 
2569
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2570
                goto exit_function;
 
2571
            }
 
2572
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2573
                goto exit_function;  /* no fixed-H found */
 
2574
            }
 
2575
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2576
                goto exit_function;
 
2577
            }
 
2578
            if ( !pc2i->bHasDifference ) {
 
2579
                goto exit_function; /* nothing to do */
 
2580
            }
 
2581
        }
 
2582
    }
 
2583
 
 
2584
    if ( /*pc2i->len_c2at >= 1 &&*/ pc2i->nNumTgInChI == 1 && /* ADP in InChI */
 
2585
         (pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI || pc2i->nNumTgRevrs > 1) ) {
 
2586
        /*--------------------------------------------------------------*/
 
2587
        /* case 11: restored: NH(+)=AB-N< OH- orig.  NH-AB=N(+)< OH-    */
 
2588
        /* FixH:               0       0   0          1      0   1      */
 
2589
        /* MobH:               1       0   1          0      0   0      */
 
2590
        /*                 non-taut.                taut        taut    */
 
2591
        /*                                    ADP: one t-group or more endpoints */
 
2592
        /* NH(+)= => N, O, S, Se; -N< => N                              */
 
2593
        /* Solution: move (+) from NH(+) to -N<                         */
 
2594
        /*--------------------------------------------------------------*/
 
2595
        int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
 
2596
        short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
 
2597
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
2598
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
2599
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
2600
        cur_success = 0;
 
2601
        /* search for NH(+)= */
 
2602
        /* search for -N< */
 
2603
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
2604
            iat = nCanon2AtnoRevrs[i];
 
2605
            if ( /* in restored atom: charge=0, has no H, has no double bond, N only */
 
2606
                 num_DB_Charged < MAX_DIFF_FIXH &&
 
2607
                 at2[iat].charge == 1 && at2[iat].num_H &&
 
2608
                 at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
2609
                 (pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 ||
 
2610
                  pVA[iat].cNumValenceElectrons == 6 ) &&
 
2611
                 /* in orig.InChI: an endpoint, has fixed-H */
 
2612
                 /*pStruct->endpoint[i] &&*/
 
2613
                 (pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
2614
                 /*!(nMobHInChI && nMobHInChI[i] ) &&*/
 
2615
                 /* has (+) edge */
 
2616
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
 
2617
 
 
2618
                iat_DB_Charged[num_DB_Charged ++] = iat;
 
2619
                /*
 
2620
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2621
                    goto exit_function;
 
2622
                }
 
2623
                */
 
2624
            } else
 
2625
            if ( /* in restored atom: charge=0, has no H, has no double bond, N only */
 
2626
                 num_SB_Neutr < MAX_DIFF_FIXH &&
 
2627
                 at2[iat].charge == 0 && !at2[iat].num_H &&
 
2628
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
2629
                 (pVA[iat].cNumValenceElectrons == 5 &&
 
2630
                  pVA[iat].cPeriodicRowNumber == 1 ) &&
 
2631
                 /* in orig.InChI: an endpoint, has fixed-H */
 
2632
                 /*pStruct->endpoint[i] &&*/
 
2633
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
2634
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
2635
                 /* has (+) edge */
 
2636
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
 
2637
 
 
2638
                iat_SB_Neutr[num_SB_Neutr ++] = iat;
 
2639
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2640
                    goto exit_function;
 
2641
                }
 
2642
            }
 
2643
        }
 
2644
        if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
 
2645
            /* detected; attempt to fix */
 
2646
            BNS_VERTEX *pv1n, *pv2n;
 
2647
            BNS_EDGE   *pe1n, *pe2n;
 
2648
            Vertex      v1n, v2n;
 
2649
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2650
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
2651
            delta = 1;
 
2652
            for ( i = 0; i < num_DB_Charged && cur_success < num_try; i ++ ) {
 
2653
                iat = iat_DB_Charged[i];
 
2654
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
2655
                if ( pe->flow )
 
2656
                    continue;
 
2657
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2658
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2659
 
 
2660
                for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
 
2661
                    pe1n = pBNS->edge + pv1->iedge[j];
 
2662
                    if ( pe1n->flow && !pe1n->forbidden ) {
 
2663
                        pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
 
2664
                        break;
 
2665
                    }
 
2666
                }
 
2667
                if ( j < 0 )
 
2668
                    continue; /* not found */
 
2669
                
 
2670
                for ( j = pv2->num_adj_edges-2; 0 <= j; j -- ) {
 
2671
                    pe2n = pBNS->edge + pv2->iedge[j];
 
2672
                    if ( pe2n->flow && !pe2n->forbidden ) {
 
2673
                        pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
 
2674
                        break;
 
2675
                    }
 
2676
                }
 
2677
                if ( j < 0 )
 
2678
                    continue; /* not found */
 
2679
 
 
2680
                pe->flow   += delta;
 
2681
                pe1n->flow -= delta;
 
2682
                pe2n->flow -= delta;
 
2683
                pv1n->st_edge.flow -= delta;
 
2684
                pv2n->st_edge.flow -= delta;
 
2685
                pBNS->tot_st_flow -= 2*delta;
 
2686
 
 
2687
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2688
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2689
 
 
2690
                if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
 
2691
                                  vPathEnd == v2n && vPathStart == v1n) &&
 
2692
                                  (nDeltaCharge == 0 || nDeltaCharge == 1) ) {
 
2693
                    /* before setting flows the structure could be:
 
2694
                       [NH+ neigh, v1n]=e1n=[NH+,v1]-pe-[+,v2]=e2n=[another at or its chargeStruct]
 
2695
                       or
 
2696
                        
 
2697
                         [NH+ or ChStr, v1n]=pe1n=[NH+ or ChStr, v1]-pe-[+,v2]=pe2n=[at2 or ChStr, v2n]
 
2698
                                                                     ^    ^    ^
 
2699
                                                               NH+(+)edge |  N (+) edge: only
 
2700
                                                                          |  these are not forbidden
 
2701
                                                                          |
 
2702
                                                                   hetero (+) vertex
 
2703
 
 
2704
                        After setting flows (* mark radicals, =pe= is forbidden):
 
2705
                       
 
2706
                       *[NH+ or ChStr, v1n]-pe1n-[NH+ or ChStr, v1]=pe=[+,v2]-pe2n-[at2 or ChStr, v2n]*
 
2707
                                                                     ^    ^    ^
 
2708
                                                               NH+(+)edge |  N (+) edge: only
 
2709
                                                                          |  these are not forbidden
 
2710
                                                                          |
 
2711
                                                                   hetero (+) vertex
 
2712
 
 
2713
                        Flow in
 
2714
                        pe1n and pe2n will or will not change, depending on the structure.
 
2715
 
 
2716
                        Consider what happens if pe2n changes. It may only increment.
 
2717
                        If pe2n flow increments then another (+)edge flow dectrements. If
 
2718
                        [at2 or ChStr, v2n] is at2 then at2 charge would change from (+) to 0,
 
2719
                        and another N charge would change from 0 to (+), giving tot. change of
 
2720
                        number of charges  (-1)+(+1)=0. However, if [at2 or ChStr, v2n] is
 
2721
                        ChargeStruct then at2 will not be on the alt path and only the creation
 
2722
                        of another (+) will be detected.
 
2723
                    */
 
2724
                    /* Removed charge from O(+) => nDeltaCharge == -1 */
 
2725
                    /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
 
2726
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2727
                    if ( ret > 0 ) {
 
2728
                        nNumRunBNS ++;
 
2729
                        cur_success ++; /* 11 */
 
2730
                    }
 
2731
                } else {
 
2732
                    pe->flow   -= delta;
 
2733
                    pe1n->flow += delta;
 
2734
                    pe2n->flow += delta;
 
2735
                    pv1n->st_edge.flow += delta;
 
2736
                    pv2n->st_edge.flow += delta;
 
2737
                    pBNS->tot_st_flow += 2*delta;
 
2738
                }
 
2739
                INCHI_HEAPCHK
 
2740
            }
 
2741
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
2742
        }
 
2743
        CurrEdges.num_edges = 0; /* clear current edge list */
 
2744
        if ( cur_success ) {
 
2745
            tot_succes += cur_success;
 
2746
            /* recalculate InChI from the structure */
 
2747
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2748
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2749
                goto exit_function;
 
2750
            }
 
2751
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2752
                goto exit_function;
 
2753
            }
 
2754
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2755
                goto exit_function;  /* no fixed-H found */
 
2756
            }
 
2757
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2758
                goto exit_function;
 
2759
            }
 
2760
            if ( !pc2i->bHasDifference ) {
 
2761
                goto exit_function; /* nothing to do */
 
2762
            }
 
2763
        }
 
2764
    }
 
2765
 
 
2766
    if ( pc2i->len_c2at >= 1 && pc2i->nNumTgInChI == 1 &&
 
2767
         pc2i->nNumRemHInChI >= -1 && /* 2006-03-03 */
 
2768
         (pc2i->nNumEndpInChI > pc2i->nNumEndpRevrs || pc2i->nNumTgRevrs > 1) /* ADP in InChI */ ) {
 
2769
        /*--------------------------------------------------------------*/
 
2770
        /* case 12: restored: O=AB-N<         original: (-)O-AB=N(+)<   */
 
2771
        /* FixH:              0    0                     0        0     */
 
2772
        /* MobH:              0    0                     0        0     */
 
2773
        /*                   non-taut                   taut            */
 
2774
        /* O = O, S, Se, N; N = N;                                         */
 
2775
        /* restored atom O is not tautomeric; original atom O is taut.  */
 
2776
        /* original struct has 1 t-group; restored has less endpoints   */
 
2777
        /*                             and/or possibly >1 t-groups      */  
 
2778
        /* Solution: separate charges between O= and -N<                */
 
2779
        /*           allow moving charge to N(V) to make it N(IV)(+)    */
 
2780
        /*--------------------------------------------------------------*/
 
2781
        int bOnly_N_V = 1;
 
2782
        cur_success = 0;
 
2783
        while( 1 ) {
 
2784
            int num_SB_N_Neutr = 0, num_DB_O = 0, iat, num_N_V=0, bN_V;
 
2785
            short iat_SB_N_Neutr[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
 
2786
            AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
2787
            inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
2788
                                 pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
2789
            S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
2790
                                   pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
2791
            cur_success = 0;
 
2792
            for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
2793
                iat = pc2i->c2at[i].atomNumber;
 
2794
                if ( /* orig. InChI info: -O(-) */
 
2795
                     num_DB_O < MAX_DIFF_FIXH &&
 
2796
                     (pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ ||
 
2797
                      pc2i->c2at[i].nValElectr == 5 &&
 
2798
                      pc2i->c2at[i].nPeriodNum == 1 /* N */ ) &&
 
2799
                     pc2i->c2at[i].endptInChI &&
 
2800
                     (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
2801
                     pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
 
2802
                     /* reversed structure info: */
 
2803
                     !pc2i->c2at[i].endptRevrs &&
 
2804
                     pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 0 &&
 
2805
                     pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
2806
                     ((pc2i->c2at[i].nValElectr == 6)? 
 
2807
                           (at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2):
 
2808
                      (pc2i->c2at[i].nValElectr == 5)?
 
2809
                           (at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 3):
 
2810
                           0)) {
 
2811
                
 
2812
                    iat_DB_O[num_DB_O ++] = iat;
 
2813
                    /*
 
2814
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2815
                        goto exit_function;
 
2816
                    }
 
2817
                    */
 
2818
                }
 
2819
            }
 
2820
            for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
2821
                iat = nCanon2AtnoRevrs[i];
 
2822
                bN_V = 0;
 
2823
                if ( /* in restored atom N: charge=0, no H, has no double bond, not an endpoint */
 
2824
                     num_SB_N_Neutr < MAX_DIFF_FIXH &&
 
2825
                     at2[iat].charge == 0 && !at2[iat].num_H &&
 
2826
                     (at2[iat].valence == at2[iat].chem_bonds_valence ||
 
2827
                     (bN_V = at2[iat].valence+2 == at2[iat].chem_bonds_valence)) &&
 
2828
                     !pVA[iat].cMetal &&
 
2829
                     pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
2830
                     !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
 
2831
                     /* in orig.InChI: not an endpoint, has no H */
 
2832
                     !pStruct->endpoint[i] &&
 
2833
                     !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
2834
                     !(nMobHInChI && nMobHInChI[i]) &&
 
2835
                     /* has (+) edge */
 
2836
                     (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
2837
 
 
2838
                    if ( bOnly_N_V && bN_V &&
 
2839
                         NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) &&
 
2840
                         !pBNS->edge[j].forbidden && !pBNS->edge[j].flow ) {
 
2841
                        if ( !num_N_V ) {
 
2842
                            /* switch to N(V) only mode */
 
2843
                            CurrEdges.num_edges = 0;
 
2844
                            num_SB_N_Neutr = 0;
 
2845
                        }
 
2846
                        iat_SB_N_Neutr[num_SB_N_Neutr ++] = iat;
 
2847
                        num_N_V ++;
 
2848
                        if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2849
                            goto exit_function;
 
2850
                        }
 
2851
                        if ( ret = AddToEdgeList( &CurrEdges, j, INC_ADD_EDGE ) ) {
 
2852
                            goto exit_function;
 
2853
                        }
 
2854
                    } else
 
2855
                    if ( !num_N_V ) {
 
2856
                        iat_SB_N_Neutr[num_SB_N_Neutr ++] = iat;
 
2857
                        if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
2858
                            goto exit_function;
 
2859
                        }
 
2860
                        /* in addition, permit N(V)=>N(IV)(+) change by allowing charge flower edge change flow */
 
2861
                        if ( bN_V && NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) &&
 
2862
                             !pBNS->edge[j].forbidden && !pBNS->edge[j].flow ) {
 
2863
                            if ( ret = AddToEdgeList( &CurrEdges, j, INC_ADD_EDGE ) ) {
 
2864
                                goto exit_function;
 
2865
                            }
 
2866
                        }
 
2867
                    }
 
2868
                }
 
2869
            }
 
2870
            if ( num_try = inchi_min( num_SB_N_Neutr, num_DB_O ) ) {
 
2871
                /* detected; attempt to fix */
 
2872
                BNS_EDGE *pe_CMinus;
 
2873
                SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
2874
                RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
2875
                delta = 1;
 
2876
                for ( i = 0; i < num_DB_O && cur_success < num_try; i ++ ) {
 
2877
                    iat = iat_DB_O[i];
 
2878
                    pe_CMinus = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
2879
                    pe_CMinus->forbidden &= forbidden_edge_mask_inv;
 
2880
 
 
2881
                    pe   = pBNS->edge + pBNS->vert[iat].iedge[0]; /* double bond O=...*/
 
2882
                    if ( !pe->flow )
 
2883
                        continue;
 
2884
                    pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
2885
                    pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
2886
 
 
2887
                    pe->forbidden |= forbidden_edge_mask; /* change bond O=X to O(rad)-X(rad) */
 
2888
                    pe->flow -= delta;
 
2889
                    pv1->st_edge.flow -= delta;
 
2890
                    pv2->st_edge.flow -= delta;
 
2891
                    pBNS->tot_st_flow -= 2*delta;
 
2892
 
 
2893
                    ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
2894
                                          &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
2895
 
 
2896
                    if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
2897
                                      vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
 
2898
                        /* Added (-) charge to =O and (+) charge to N => nDeltaCharge == 2 */
 
2899
                        ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
2900
                        if ( ret > 0 ) {
 
2901
                            nNumRunBNS ++;
 
2902
                            cur_success ++; /* 12 */
 
2903
                        }
 
2904
                    } else {
 
2905
                        pe->flow += delta;
 
2906
                        pv1->st_edge.flow += delta;
 
2907
                        pv2->st_edge.flow += delta;
 
2908
                        pBNS->tot_st_flow += 2*delta;
 
2909
                    }
 
2910
                    pe->forbidden        &= forbidden_edge_mask_inv; /* allow changes to O=X bond */
 
2911
                    INCHI_HEAPCHK
 
2912
                }
 
2913
                RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
2914
            }
 
2915
            CurrEdges.num_edges = 0; /* clear current edge list */
 
2916
            if ( cur_success ) {
 
2917
                tot_succes += cur_success;
 
2918
                /* recalculate InChI from the structure */
 
2919
                if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
2920
                                                                ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
2921
                    goto exit_function;
 
2922
                }
 
2923
                if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
2924
                    goto exit_function;
 
2925
                }
 
2926
                if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
2927
                    goto exit_function;  /* no fixed-H found */
 
2928
                }
 
2929
                if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
2930
                    goto exit_function;
 
2931
                }
 
2932
                if ( !pc2i->bHasDifference ) {
 
2933
                    goto exit_function; /* nothing to do */
 
2934
                }
 
2935
                break;
 
2936
            } else
 
2937
            if ( bOnly_N_V ) {
 
2938
                bOnly_N_V = 0;
 
2939
            } else {
 
2940
                break;
 
2941
            }
 
2942
        }
 
2943
    }
 
2944
 
 
2945
    if ( pc2i->nNumTgDiffMinus /*|| pc2i->nNumTgDiffH */ /* no ADP in InChI needed */ ) {
 
2946
        /*--------------------------------------------------------------*/
 
2947
        /*                         |                            |       */
 
2948
        /* case 13: restored: O=AB=N=         original: (-)O-AB-N(+)=   */
 
2949
        /* FixH:              0    0                     0        0     */
 
2950
        /* MobH:              0    0                     0        0     */
 
2951
        /*                        non-taut              taut   non-taut */
 
2952
        /* O = O, S, Se, N; N = N, P, ...                               */
 
2953
        /* t-group in original has same num. endpoints                  */
 
2954
        /*       same num_H and less (-) than in the restored structure */
 
2955
        /* original atom O is tautomeric, N is not taut in both         */
 
2956
        /* original struct has 1 t-group; restored has less endpoints   */
 
2957
        /*                             and/or possibly >1 t-groups      */  
 
2958
        /* Solution: separate charges between O= and -N<                */
 
2959
        /*           allow moving charge to N(V) to make it N(IV)(+)    */
 
2960
        /*--------------------------------------------------------------*/
 
2961
        int itg;
 
2962
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
2963
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
2964
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
2965
 
 
2966
        S_CHAR   *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed? pStruct->pOneINChI[0]->nNum_H_fixed : NULL;
 
2967
        S_CHAR   *pnMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
 
2968
                                   pStruct->pOneINChI[1]->nNum_H : 
 
2969
                                (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
 
2970
                                   pStruct->pOneINChI[0]->nNum_H : NULL;
 
2971
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
2972
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
2973
        cur_success = 0;
 
2974
        /* find whether this may help */
 
2975
        for ( itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg ++ ) {
 
2976
            if ( pStruct->ti.t_group[itg].nNumEndpoints == pStruct->One_ti.t_group[itg].nNumEndpoints &&
 
2977
                 pStruct->ti.t_group[itg].num[0] - pStruct->ti.t_group[itg].num[1] == 
 
2978
                 pStruct->One_ti.t_group[itg].num[0] - pStruct->One_ti.t_group[itg].num[1] &&
 
2979
                 pStruct->ti.t_group[itg].num[1] > pStruct->One_ti.t_group[itg].num[1]) {
 
2980
                /* restored InChI t-group has more (-) and same number of H */
 
2981
 
 
2982
                int num_SB_N_Neutr = 0, num_DB_O = 0, iat;
 
2983
                short iat_SB_N_Neutr[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
 
2984
                cur_success = 0;
 
2985
                for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
2986
                    iat = nCanon2AtnoRevrs[i];
 
2987
                    if ( /* orig. InChI info: -O(-) */
 
2988
                         num_DB_O < MAX_DIFF_FIXH &&
 
2989
                         (pVA[i].cNumValenceElectrons == 6 /* O, S, Se, Te */ ) &&
 
2990
                         pStruct->endpoint[i] == itg+1 &&
 
2991
                         (e=pVA[i].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
2992
                         !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
2993
                         !(nMobHInChI && nMobHInChI[i]) &&
 
2994
                         /* reversed structure info: */
 
2995
                         /*!pc2i->c2at[i].endptRevrs &&*/
 
2996
                         !(num_Fixed_H_Revrs && num_Fixed_H_Revrs[iat]) &&
 
2997
                         !(pnMobHRevrs && pnMobHRevrs[iat]) &&
 
2998
                         at2[iat].charge == 0 && at2[iat].num_H == 0 &&
 
2999
                         at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
 
3000
            
 
3001
                        iat_DB_O[num_DB_O ++] = iat;
 
3002
                        /*
 
3003
                        if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3004
                            goto exit_function;
 
3005
                        }
 
3006
                        */
 
3007
                    } else
 
3008
                    if ( /* in restored atom N: charge=0, no H, has no double bond, not an endpoint */
 
3009
                         num_SB_N_Neutr < MAX_DIFF_FIXH &&
 
3010
                         at2[iat].charge == 0 && !at2[iat].num_H &&
 
3011
                         /*at2[iat].valence == at2[iat].chem_bonds_valence ||*/
 
3012
                         (at2[iat].valence==4 && at2[iat].chem_bonds_valence==5) &&
 
3013
                         !pVA[iat].cMetal &&
 
3014
                         pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber >= 1 &&
 
3015
                         !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
 
3016
                         /* in orig.InChI: not an endpoint, has no H */
 
3017
                         !pStruct->endpoint[i] &&
 
3018
                         !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
3019
                         !(nMobHInChI && nMobHInChI[i]) &&
 
3020
                         /* has (+) edge */
 
3021
                         (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
3022
 
 
3023
                        iat_SB_N_Neutr[num_SB_N_Neutr ++] = iat;
 
3024
                        if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3025
                            goto exit_function;
 
3026
                        }
 
3027
                    }
 
3028
                }
 
3029
                if ( num_try = inchi_min( num_SB_N_Neutr, num_DB_O ) ) {
 
3030
                    /* detected; attempt to fix */
 
3031
                    BNS_EDGE *pe_CMinus;
 
3032
                    SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3033
                    RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
3034
                    delta = 1;
 
3035
                    for ( i = 0; i < num_DB_O && cur_success < num_try; i ++ ) {
 
3036
                        iat = iat_DB_O[i];
 
3037
                        pe_CMinus = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
3038
                        pe_CMinus->forbidden &= forbidden_edge_mask_inv;
 
3039
 
 
3040
                        pe   = pBNS->edge + pBNS->vert[iat].iedge[0]; /* double bond O=...*/
 
3041
                        if ( !pe->flow )
 
3042
                            continue;
 
3043
                        pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
3044
                        pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
3045
 
 
3046
                        pe->forbidden |= forbidden_edge_mask; /* change bond O=X to O(rad)-X(rad) */
 
3047
                        pe->flow -= delta;
 
3048
                        pv1->st_edge.flow -= delta;
 
3049
                        pv2->st_edge.flow -= delta;
 
3050
                        pBNS->tot_st_flow -= 2*delta;
 
3051
 
 
3052
                        ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3053
                                              &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3054
 
 
3055
                        if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
3056
                                          vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 2 ) {
 
3057
                            /* Added (-) charge to =O and (+) charge to N => nDeltaCharge == 2 */
 
3058
                            ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
3059
                            if ( ret > 0 ) {
 
3060
                                nNumRunBNS ++;
 
3061
                                cur_success ++; /* 13 */
 
3062
                            }
 
3063
                        } else {
 
3064
                            pe->flow += delta;
 
3065
                            pv1->st_edge.flow += delta;
 
3066
                            pv2->st_edge.flow += delta;
 
3067
                            pBNS->tot_st_flow += 2*delta;
 
3068
                        }
 
3069
                        pe->forbidden        &= forbidden_edge_mask_inv; /* allow changes to O=X bond */
 
3070
                        INCHI_HEAPCHK
 
3071
                    }
 
3072
                    RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
3073
                }
 
3074
                CurrEdges.num_edges = 0; /* clear current edge list */
 
3075
                if ( cur_success ) {
 
3076
                    tot_succes += cur_success;
 
3077
                    /* recalculate InChI from the structure */
 
3078
                    if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
3079
                                                                    ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
3080
                        goto exit_function;
 
3081
                    }
 
3082
                    if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
3083
                        goto exit_function;
 
3084
                    }
 
3085
                    if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
3086
                        goto exit_function;  /* no fixed-H found */
 
3087
                    }
 
3088
                    if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
3089
                        goto exit_function;
 
3090
                    }
 
3091
                    if ( !pc2i->bHasDifference ) {
 
3092
                        goto exit_function; /* nothing to do */
 
3093
                    }
 
3094
                    break;
 
3095
                }/* else
 
3096
                if ( bOnly_N_V ) {
 
3097
                    bOnly_N_V = 0;
 
3098
                }
 
3099
                */
 
3100
                break;
 
3101
            }
 
3102
        }
 
3103
    }
 
3104
 
 
3105
    if ( (pc2i->nNumTgInChI <= 1 &&
 
3106
        pc2i->nNumRemHInChI > pc2i->nNumRemHRevrs || pc2i->len_c2at) &&
 
3107
         bHas_N_V( at2, pStruct->num_atoms) ) {
 
3108
        /*-----------------------------------------------------------------*/
 
3109
        /*                         |                         |             */
 
3110
        /* case 14: restored:-N=AB=N=CD-XH original: (-)N-AB-N(+)=CD-XH    */
 
3111
        /* FixH:              0    0   0/1              0            1     */
 
3112
        /* MobH:              0    0   1/0              0            0     */
 
3113
        /*                   non-taut  n/t             any  non     any    */
 
3114
        /*                                                  taut           */
 
3115
        /* X = O, S, Se, N; N = N                                          */
 
3116
        /* t-group in original may have more (-) than in restored          */
 
3117
        /*       same num_H and less (-) than in the restored structure    */
 
3118
        /* atom N(V)/N(IV)(+) is not taut in both                          */
 
3119
        /* The following transformation should be possible:                */
 
3120
        /*        |                         |                              */
 
3121
        /*   N=AB=N=CD-XH    ->     (-)N-AB-N-CD=XH(+)                     */
 
3122
        /* This allows ADP to remove H(+) from -XH                         */
 
3123
        /* As the result, the original structure has 0 or 1 t-group        */
 
3124
        /* Solution: separate charges between -N(III)= and  N(V)           */
 
3125
        /*-----------------------------------------------------------------*/
 
3126
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
3127
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
3128
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
3129
 
 
3130
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
3131
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
3132
        int num_N_V = 0, iat, i1, i2, i3, e1Flower, e1Plus, e2Plus, e2Minus, e3Plus;
 
3133
        int max_success = pc2i->nNumRemHInChI - pc2i->nNumRemHRevrs;
 
3134
        short iat_N_V_Array[MAX_DIFF_FIXH];
 
3135
        EDGE_LIST iat_X_List, iat_N_III_List;
 
3136
        AllocEdgeList( &iat_X_List, EDGE_LIST_CLEAR );
 
3137
        AllocEdgeList( &iat_N_III_List, EDGE_LIST_CLEAR );
 
3138
        cur_success = 0;
 
3139
        ret = 0;
 
3140
        for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
3141
            iat = nCanon2AtnoRevrs[i];
 
3142
            /* search for N(V), 3 bonds */
 
3143
            if ( /* restored structure */
 
3144
                 num_N_V < MAX_DIFF_FIXH &&
 
3145
                 at2[iat].chem_bonds_valence == 5 && at2[iat].valence == 3 &&
 
3146
                 !at2[iat].charge && !at2[iat].radical &&
 
3147
                 pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
3148
                 !( at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint ) &&
 
3149
                 !at2[iat].num_H &&
 
3150
                 (e = pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
3151
                 pBNS->edge[e].flow /* no charge */ &&
 
3152
                 NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) && !pBNS->edge[j].forbidden &&
 
3153
                 !pBNS->edge[j].flow /* neutral, valence=5 */ &&
 
3154
                 /* orig. InChI */
 
3155
                 !pStruct->endpoint[i] &&
 
3156
                 !(nMobHInChI && nMobHInChI[i]) && !pStruct->fixed_H[i] ) {
 
3157
                iat_N_V_Array[num_N_V ++] = iat;
 
3158
            } else
 
3159
            /* search for -N= */
 
3160
            if ( /* restored structure */
 
3161
                 at2[iat].chem_bonds_valence == 3 && at2[iat].valence == 2 &&
 
3162
                 !at2[iat].charge && !at2[iat].radical &&
 
3163
                 pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
3164
                 !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint ) &&
 
3165
                 !at2[iat].num_H &&
 
3166
                 (e = pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
3167
                 !pBNS->edge[e].flow /* no charge */ &&
 
3168
                 /* orig. InChI */
 
3169
                 /*!pStruct->endpoint[i] &&*/
 
3170
                 !(nMobHInChI && nMobHInChI[i]) && !pStruct->fixed_H[i] ) {
 
3171
 
 
3172
                if ( ret = AddToEdgeList( &iat_N_III_List, iat, 32 ) ) {
 
3173
                    goto exit_case_14;
 
3174
                }
 
3175
            } else
 
3176
            /* search for -OH -NH-, -NH2 */
 
3177
            if ( /* restored structure */
 
3178
                 at2[iat].chem_bonds_valence == at2[iat].valence &&
 
3179
                 !at2[iat].charge && !at2[iat].radical &&
 
3180
                 (pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 ||
 
3181
                 pVA[iat].cNumValenceElectrons == 6 ) &&
 
3182
                 at2[iat].num_H &&
 
3183
                 (e = pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
3184
                 pBNS->edge[e].flow /* no charge */ &&
 
3185
                 /* orig. InChI */
 
3186
                 !(nMobHInChI && nMobHInChI[i]) && pStruct->fixed_H[i] ) {
 
3187
 
 
3188
                if ( ret = AddToEdgeList( &iat_X_List, iat, 32 ) ) {
 
3189
                    goto exit_case_14;
 
3190
                }
 
3191
            }
 
3192
        }
 
3193
        if ( !max_success ) {
 
3194
            max_success = inchi_min( num_N_V, iat_N_III_List.num_edges );
 
3195
            max_success = inchi_min( max_success, iat_X_List.num_edges );
 
3196
        }
 
3197
        if ( num_N_V && iat_N_III_List.num_edges && iat_X_List.num_edges ) {
 
3198
            for ( i1 = 0; i1 < num_N_V && cur_success < max_success; i1 ++ ) {
 
3199
                int iat_N_V = iat_N_V_Array[i1];
 
3200
                if ( NO_VERTEX == iat_N_V ||
 
3201
                     0 >= (e1Plus = pVA[iat_N_V].nCPlusGroupEdge-1) ||
 
3202
                     NO_VERTEX == (e1Flower = GetChargeFlowerUpperEdge( pBNS, pVA, e1Plus )) ||
 
3203
                     1 != pBNS->edge[e1Plus].flow ||
 
3204
                     0 != pBNS->edge[e1Flower].flow ) {
 
3205
                    continue;
 
3206
                }
 
3207
                for ( i2 = iat_N_III_List.num_edges-1; 0 <= i2 && cur_success < max_success; i2 -- ) {
 
3208
                    int iat_N_III = iat_N_III_List.pnEdges[i2];
 
3209
                    if ( NO_VERTEX == iat_N_III ||
 
3210
                         0 >= (e2Minus = pVA[iat_N_III].nCMinusGroupEdge-1) ||
 
3211
                         0 >= (e2Plus  = pVA[iat_N_III].nCPlusGroupEdge-1) ||
 
3212
                         0 != pBNS->edge[e2Minus].flow ||
 
3213
                         1 != pBNS->edge[e2Plus].flow ) {
 
3214
                        /* do not consider this atom anymore */
 
3215
                        iat_N_III_List.pnEdges[i2] = NO_VERTEX;
 
3216
                        continue;
 
3217
                    }
 
3218
                    for ( i3 = iat_X_List.num_edges-1; 0 <= i3 && cur_success < max_success; i3 -- ) {
 
3219
                        int iat_X = iat_X_List.pnEdges[i3];
 
3220
                        BNS_VERTEX *pv1n, *pv2n;
 
3221
                        BNS_EDGE   *pe1n, *pe2n, *pe1Plus, *pe2Minus, *pe3Plus;
 
3222
                        Vertex      v1n, v2n;
 
3223
                        ret = 0;
 
3224
                        if ( NO_VERTEX == iat_X ||
 
3225
                             0 >= (e3Plus  = pVA[iat_X].nCPlusGroupEdge-1) ||
 
3226
                             1 != pBNS->edge[e3Plus].flow ) {
 
3227
                            /* do not consider this atom anymore */
 
3228
                            iat_X_List.pnEdges[i3] = NO_VERTEX;
 
3229
                            continue;
 
3230
                        }
 
3231
                        /* all is ready to check whether the following applies:
 
3232
                           forbid changes of all charges and N,P,... flowers
 
3233
                           allow to change edges: e2Minus, e3Plus
 
3234
                           Increment flow in e1Flower
 
3235
                           The result should be: increase in number of charges by 2
 
3236
                        */
 
3237
                        pe1Plus  = pBNS->edge + e1Plus;  /* N(V) positive charge edge */
 
3238
                        pe2Minus = pBNS->edge + e2Minus; /* =N- negative charge edge */
 
3239
                        pe3Plus  = pBNS->edge + e3Plus;  /* -XH positive charge edge */
 
3240
                        pe       = pBNS->edge + e1Flower; /* N(V) flower edge */
 
3241
                        pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
3242
                        pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
3243
                        for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
 
3244
                            pe1n = pBNS->edge + pv1->iedge[j];
 
3245
                            if ( pe1n->flow && !pe1n->forbidden && pe1n != pe1Plus ) {
 
3246
                                pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
 
3247
                                break;
 
3248
                            }
 
3249
                        }
 
3250
                        if ( j < 0 )
 
3251
                            continue; /* not found -- should not happen */
 
3252
                        for ( j = pv2->num_adj_edges-1; 0 <= j; j -- ) { /* was -2; changed 2006-2-28 12:35pm*/
 
3253
                            pe2n = pBNS->edge + pv2->iedge[j];
 
3254
                            if ( pe2n->flow && !pe2n->forbidden && pe2n != pe1Plus ) {
 
3255
                                pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
 
3256
                                break;
 
3257
                            }
 
3258
                        }
 
3259
                        if ( j < 0 )
 
3260
                            continue; /* not found -- should not happen */
 
3261
                        delta = 1;
 
3262
                        pe->flow           += delta;
 
3263
                        pe1n->flow         -= delta;
 
3264
                        pe2n->flow         -= delta;
 
3265
                        pv1n->st_edge.flow -= delta;
 
3266
                        pv2n->st_edge.flow -= delta;
 
3267
                        pBNS->tot_st_flow  -= 2*delta;
 
3268
                        
 
3269
                        SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3270
                        SetForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
 
3271
 
 
3272
                        /* allow two charges to change */
 
3273
                        pe2Minus->forbidden &= forbidden_edge_mask_inv;
 
3274
                        pe3Plus->forbidden  &= forbidden_edge_mask_inv;
 
3275
                        /* test #1 */
 
3276
                        ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3277
                                              &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3278
                        INCHI_HEAPCHK
 
3279
                        if ( ret < 0 ) {
 
3280
                            goto exit_case_14;
 
3281
                        } else
 
3282
                        if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
 
3283
                                          vPathEnd == v2n && vPathStart == v1n) &&
 
3284
                                          nDeltaCharge == 2 ) {
 
3285
                            ; /* success */
 
3286
                        } else {
 
3287
                            ret = 0;
 
3288
                        }
 
3289
                        /* restore BNS */
 
3290
                        pe2Minus->forbidden |= forbidden_edge_mask;
 
3291
                        pe3Plus->forbidden  |= forbidden_edge_mask;
 
3292
                        pe->flow           -= delta;
 
3293
                        pe1n->flow         += delta;
 
3294
                        pe2n->flow         += delta;
 
3295
                        pv1n->st_edge.flow += delta;
 
3296
                        pv2n->st_edge.flow += delta;
 
3297
                        pBNS->tot_st_flow  += 2*delta;
 
3298
                        if ( ret == 1 ) {
 
3299
                            /* test #2: check if charge separation is possible */
 
3300
                            pe->flow           += delta;
 
3301
                            pe1n->flow         -= delta;
 
3302
                            pe2n->flow         -= delta;
 
3303
                            pv1n->st_edge.flow -= delta;
 
3304
                            pv2n->st_edge.flow -= delta;
 
3305
                            pBNS->tot_st_flow  -= 2*delta;
 
3306
 
 
3307
                            /* allow two charges (N(V) and N(III)) to change */
 
3308
                            pe2Minus->forbidden &= forbidden_edge_mask_inv;
 
3309
                            pe1Plus->forbidden  &= forbidden_edge_mask_inv;
 
3310
                            /* test #2 */
 
3311
                            ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3312
                                              &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3313
                            if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
 
3314
                                              vPathEnd == v2n && vPathStart == v1n) &&
 
3315
                                              nDeltaCharge == 2 ) {
 
3316
                                /* success; actually change charges */
 
3317
                                ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
3318
                                if ( ret > 0 ) {
 
3319
                                    nNumRunBNS ++;
 
3320
                                    cur_success ++; /* 14 */
 
3321
                                }
 
3322
                            }
 
3323
                            if ( ret <= 0 ) {
 
3324
                                /* failed: restore BNS flow */
 
3325
                                pe->flow           -= delta;
 
3326
                                pe1n->flow         += delta;
 
3327
                                pe2n->flow         += delta;
 
3328
                                pv1n->st_edge.flow += delta;
 
3329
                                pv2n->st_edge.flow += delta;
 
3330
                                pBNS->tot_st_flow  += 2*delta;
 
3331
                            }
 
3332
                            INCHI_HEAPCHK
 
3333
                        }
 
3334
                        RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
3335
                        RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask  );
 
3336
                        if ( ret > 0 ) {
 
3337
                            /* do not repeat for the same atoms */
 
3338
                            iat_N_V_Array[i1] = NO_VERTEX;
 
3339
                            iat_N_III_List.pnEdges[i2] = NO_VERTEX;
 
3340
                            iat_X_List.pnEdges[i3] = NO_VERTEX;
 
3341
                        }
 
3342
                        if ( ret < 0 ) {
 
3343
                            goto exit_case_14;
 
3344
                        }
 
3345
                        if ( ret > 0 ) {
 
3346
                            break;
 
3347
                        }
 
3348
                    } /* i3 cycle */
 
3349
                    if ( ret > 0 ) {
 
3350
                        break;
 
3351
                    }
 
3352
                } /* i2 cycle */
 
3353
            }
 
3354
        }
 
3355
exit_case_14:
 
3356
        AllocEdgeList( &iat_X_List, EDGE_LIST_FREE );
 
3357
        AllocEdgeList( &iat_N_III_List, EDGE_LIST_FREE );
 
3358
        RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
3359
        RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask  );
 
3360
        CurrEdges.num_edges = 0; /* clear current edge list */
 
3361
        if ( ret < 0 ) {
 
3362
            goto exit_function;
 
3363
        }
 
3364
        if ( cur_success ) {
 
3365
            tot_succes += cur_success;
 
3366
            /* recalculate InChI from the structure */
 
3367
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
3368
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
3369
                goto exit_function;
 
3370
            }
 
3371
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
3372
                goto exit_function;
 
3373
            }
 
3374
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
3375
                goto exit_function;  /* no fixed-H found */
 
3376
            }
 
3377
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
3378
                goto exit_function;
 
3379
            }
 
3380
            if ( !pc2i->bHasDifference ) {
 
3381
                goto exit_function; /* nothing to do */
 
3382
            }
 
3383
        }
 
3384
    }
 
3385
 
 
3386
 
 
3387
    if ( pc2i->nNumTgMRevrs > pc2i->nNumTgMInChI ||
 
3388
         pc2i->nNumRemHRevrs < pc2i->nNumRemHInChI ||
 
3389
         pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI ||
 
3390
         pc2i->nNumTgInChI <= 1 && pc2i->nNumTgRevrs > pc2i->nNumTgInChI ) {
 
3391
        /*--------------------------------------------------------------*/
 
3392
        /* case 15: restored: -(+)O=AB-N<  orig: -O-AB=N(+)<            */
 
3393
        /* (a) restored t-groups have more (-) than in original InChI   */
 
3394
        /* (b) Mobile-H    charge: restored > original InChI *and*      */
 
3395
        /*              removed H: restored < original InChI            */
 
3396
        /* (c) restored t-groups have less endpnoits than in orig InChI */
 
3397
        /* O = O, S, Se, Te; N = N                                      */
 
3398
        /* Solution: move (+) from -O(+)= to -N<                        */
 
3399
        /*--------------------------------------------------------------*/
 
3400
        int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
 
3401
        short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
 
3402
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
3403
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
3404
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
3405
        cur_success = 0;
 
3406
        /* search for -O(+)= */
 
3407
        /* search for -N< */
 
3408
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
3409
            iat = nCanon2AtnoRevrs[i];
 
3410
            if ( /* -O(+)= in restored atom: charge=1, has no H, a double bond */
 
3411
                 num_DB_Charged < MAX_DIFF_FIXH &&
 
3412
                 at2[iat].charge == 1 && !at2[iat].num_H &&
 
3413
                 at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
3414
                 (pVA[iat].cNumValenceElectrons == 6 ) &&
 
3415
                 /* in orig.InChI: an endpoint, has fixed-H */
 
3416
                 /*pStruct->endpoint[i] &&*/
 
3417
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
3418
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
3419
                 /* has (+) edge */
 
3420
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
 
3421
 
 
3422
                iat_DB_Charged[num_DB_Charged ++] = iat;
 
3423
                /*
 
3424
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3425
                    goto exit_function;
 
3426
                }
 
3427
                */
 
3428
            } else
 
3429
            if ( /* -N< in restored atom: charge=0, has no H, has no double bond, N only */
 
3430
                 num_SB_Neutr < MAX_DIFF_FIXH &&
 
3431
                 at2[iat].charge == 0 && !at2[iat].num_H &&
 
3432
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
3433
                 (pVA[iat].cNumValenceElectrons == 5 &&
 
3434
                  pVA[iat].cPeriodicRowNumber == 1 ) &&
 
3435
                 /* in orig.InChI: an endpoint, has fixed-H */
 
3436
                 /*pStruct->endpoint[i] &&*/
 
3437
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
3438
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
3439
                 /* has (+) edge */
 
3440
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && 0 == pBNS->edge[e].forbidden ) {
 
3441
 
 
3442
                iat_SB_Neutr[num_SB_Neutr ++] = iat;
 
3443
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3444
                    goto exit_function;
 
3445
                }
 
3446
            }
 
3447
        }
 
3448
        if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
 
3449
            /* detected; attempt to fix */
 
3450
            BNS_VERTEX *pv1n, *pv2n;
 
3451
            BNS_EDGE   *pe1n, *pe2n;
 
3452
            Vertex      v1n, v2n;
 
3453
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3454
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
3455
            delta = 1;
 
3456
            for ( i = 0; i < num_DB_Charged && cur_success < num_try; i ++ ) {
 
3457
                iat = iat_DB_Charged[i];
 
3458
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
3459
                if ( pe->flow )
 
3460
                    continue;
 
3461
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
3462
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
3463
 
 
3464
                for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
 
3465
                    pe1n = pBNS->edge + pv1->iedge[j];
 
3466
                    if ( pe1n->flow && !pe1n->forbidden ) {
 
3467
                        pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
 
3468
                        break;
 
3469
                    }
 
3470
                }
 
3471
                if ( j < 0 )
 
3472
                    continue; /* not found */
 
3473
                
 
3474
                for ( j = pv2->num_adj_edges-1; 0 <= j; j -- ) { /* was -2; changed 2006-2-28 12:35pm*/
 
3475
                    pe2n = pBNS->edge + pv2->iedge[j];
 
3476
                    if ( pe2n->flow && !pe2n->forbidden ) {
 
3477
                        pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
 
3478
                        break;
 
3479
                    }
 
3480
                }
 
3481
                if ( j < 0 )
 
3482
                    continue; /* not found */
 
3483
 
 
3484
                pe->flow   += delta;
 
3485
                pe1n->flow -= delta;
 
3486
                pe2n->flow -= delta;
 
3487
                pv1n->st_edge.flow -= delta;
 
3488
                pv2n->st_edge.flow -= delta;
 
3489
                pBNS->tot_st_flow -= 2*delta;
 
3490
 
 
3491
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3492
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3493
 
 
3494
                if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
 
3495
                                  vPathEnd == v2n && vPathStart == v1n) &&
 
3496
                                  (nDeltaCharge == 0 || nDeltaCharge == 1) ) {
 
3497
                    /* Moved charge from O(+) to -N< => nDeltaCharge == 1 or 0 if pe2n = -N< charge edge */
 
3498
                    /* Flow change on pe (+)charge edge (atom NH2) is not known to RunBnsTestOnce()) */
 
3499
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
3500
                    if ( ret > 0 ) {
 
3501
                        nNumRunBNS ++;
 
3502
                        cur_success ++; /* 15 */
 
3503
                    }
 
3504
                } else {
 
3505
                    pe->flow   -= delta;
 
3506
                    pe1n->flow += delta;
 
3507
                    pe2n->flow += delta;
 
3508
                    pv1n->st_edge.flow += delta;
 
3509
                    pv2n->st_edge.flow += delta;
 
3510
                    pBNS->tot_st_flow += 2*delta;
 
3511
                }
 
3512
                INCHI_HEAPCHK
 
3513
            }
 
3514
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
3515
        }
 
3516
        CurrEdges.num_edges = 0; /* clear current edge list */
 
3517
        if ( cur_success ) {
 
3518
            tot_succes += cur_success;
 
3519
            /* recalculate InChI from the structure */
 
3520
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
3521
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
3522
                goto exit_function;
 
3523
            }
 
3524
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
3525
                goto exit_function;
 
3526
            }
 
3527
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
3528
                goto exit_function;  /* no fixed-H found */
 
3529
            }
 
3530
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
3531
                goto exit_function;
 
3532
            }
 
3533
            if ( !pc2i->bHasDifference ) {
 
3534
                goto exit_function; /* nothing to do */
 
3535
            }
 
3536
        }
 
3537
    }
 
3538
 
 
3539
    if ( pc2i->nNumTgDiffMinus ) {
 
3540
        /*----------------------------------------------------------------*/
 
3541
        /* case 16: restored: O=X-NH(-)      orig.:  O(-)-X=NH            */
 
3542
        /*            t-group: (H,-)                  (2H)                */
 
3543
        /* O(-) = S, Se, Te; N = N;                                       */
 
3544
        /* Solution: move (-) from O(-) to -NH(-)                         */
 
3545
        /*----------------------------------------------------------------*/
 
3546
        int num_SB_N_Minus = 0, num_DB_O_Neutr = 0, iat, itg;
 
3547
        short iat_SB_N_Minus[MAX_DIFF_FIXH], iat_DB_O_Neutr[MAX_DIFF_FIXH];
 
3548
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
3549
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
3550
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
3551
        cur_success = 0;
 
3552
        for ( itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg ++ ) {
 
3553
            if ( pStruct->ti.t_group[itg].nNumEndpoints != pStruct->One_ti.t_group[itg].nNumEndpoints ||
 
3554
                 pStruct->ti.t_group[itg].num[1]  >= pStruct->One_ti.t_group[itg].num[1] ) {
 
3555
                continue;
 
3556
            }
 
3557
            CurrEdges.num_edges = num_SB_N_Minus = num_DB_O_Neutr = 0;
 
3558
            cur_success = 0;
 
3559
            for ( j = 0, k = pStruct->One_ti.t_group[itg].nFirstEndpointAtNoPos;
 
3560
                    j < pStruct->One_ti.t_group[itg].nNumEndpoints; j ++ ) {
 
3561
                i = pStruct->One_ti.nEndpointAtomNumber[k+j]; /* canonical number in restored struct. */
 
3562
                iat = nCanon2AtnoRevrs[i];
 
3563
                if ( /* in restored atom: charge=0, has no H, has double bond, O, S, Se, Te */
 
3564
                     num_DB_O_Neutr < MAX_DIFF_FIXH &&
 
3565
                     at2[iat].charge == 0 && !at2[iat].num_H &&
 
3566
                     at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
3567
                     pVA[iat].cNumValenceElectrons == 6 &&
 
3568
                     /* in orig.InChI: an endpoint, may have fixed-H */
 
3569
                     pStruct->endpoint[i] && 
 
3570
                     /*!(pStruct->fixed_H && pStruct->fixed_H[i]) &&*/
 
3571
                     !(nMobHInChI && nMobHInChI[i] ) &&
 
3572
                     /* has (-) edge */
 
3573
                     (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
3574
 
 
3575
                    iat_DB_O_Neutr[num_DB_O_Neutr ++] = iat;
 
3576
                    
 
3577
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3578
                        goto exit_function;
 
3579
                    }
 
3580
                    
 
3581
                } else
 
3582
                if ( /* in restored atom: charge=-1, has H, has double bond, N */
 
3583
                     num_SB_N_Minus < MAX_DIFF_FIXH &&
 
3584
                     at2[iat].charge == -1 && at2[iat].num_H &&
 
3585
                     at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
3586
                     pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1 &&
 
3587
                     /* in orig.InChI: an endpoint, has no fixed-H */
 
3588
                     pStruct->endpoint[i] &&
 
3589
                     (pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
3590
                     !(nMobHInChI && nMobHInChI[i] ) &&
 
3591
                     /* has (-) edge */
 
3592
                     (e=pVA[iat].nCMinusGroupEdge-1) >= 0 &&
 
3593
                     0 == pBNS->edge[e].forbidden ) {
 
3594
 
 
3595
                    iat_SB_N_Minus[num_SB_N_Minus ++] = iat;
 
3596
                    /*
 
3597
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3598
                        goto exit_function;
 
3599
                    }
 
3600
                    */
 
3601
                }
 
3602
            }
 
3603
            if ( num_try = inchi_min( num_SB_N_Minus, num_DB_O_Neutr ) ) {
 
3604
                /* detected; attempt to fix */
 
3605
                SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3606
                RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
3607
                /* allow stereobonds in rings change */
 
3608
                /*
 
3609
                if ( forbidden_stereo_edge_mask )
 
3610
                    RemoveForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
 
3611
                */
 
3612
                delta = 1;
 
3613
                for ( i = 0; i < num_SB_N_Minus && cur_success < num_try; i ++ ) {
 
3614
                    iat = iat_SB_N_Minus[i];
 
3615
                    pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
3616
                    if ( !pe->flow )
 
3617
                        continue;
 
3618
                    pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
3619
                    pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
3620
 
 
3621
                    /*pe->forbidden |= forbidden_edge_mask;*/
 
3622
                    pe->flow -= delta;
 
3623
                    pv1->st_edge.flow -= delta;
 
3624
                    pv2->st_edge.flow -= delta;
 
3625
                    pBNS->tot_st_flow -= 2*delta;
 
3626
 
 
3627
                    ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3628
                                          &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3629
 
 
3630
                    if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
3631
                                      vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
3632
                        /* Moved (-) charge to =O => nDeltaCharge == 1 */
 
3633
                        /* Flow change on pe (-)charge edge (atom -NH(-)) is not known to RunBnsTestOnce()) */
 
3634
                        ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
3635
                        if ( ret > 0 ) {
 
3636
                            nNumRunBNS ++;
 
3637
                            cur_success ++; /* 16 */
 
3638
                        }
 
3639
                    } else {
 
3640
                        pe->forbidden &= forbidden_edge_mask_inv;
 
3641
                        pe->flow += delta;
 
3642
                        pv1->st_edge.flow += delta;
 
3643
                        pv2->st_edge.flow += delta;
 
3644
                        pBNS->tot_st_flow += 2*delta;
 
3645
                    }
 
3646
                    INCHI_HEAPCHK
 
3647
                }
 
3648
                RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3649
                /*
 
3650
                if ( forbidden_stereo_edge_mask )
 
3651
                    SetForbiddenEdgeMask( pBNS, &FixedLargeRingStereoEdges, forbidden_stereo_edge_mask );
 
3652
                */
 
3653
            }
 
3654
            CurrEdges.num_edges = 0; /* clear current edge list */
 
3655
            if ( cur_success ) {
 
3656
                tot_succes += cur_success;
 
3657
                /* recalculate InChI from the structure */
 
3658
                if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
3659
                                                                ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
3660
                    goto exit_function;
 
3661
                }
 
3662
                if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
3663
                    goto exit_function;
 
3664
                }
 
3665
                if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
3666
                    goto exit_function;  /* no fixed-H found */
 
3667
                }
 
3668
                if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
3669
                    goto exit_function;
 
3670
                }
 
3671
                if ( !pc2i->bHasDifference ) {
 
3672
                    goto exit_function; /* nothing to do */
 
3673
                }
 
3674
            }
 
3675
        }
 
3676
    }
 
3677
 
 
3678
    if ( pc2i->nNumRemHInChI < pc2i->nNumRemHRevrs ) {
 
3679
        /*--------------------------------------------------------------*/
 
3680
        /* case 17: restored: OH(+)=AB-O-     orig.  HO-AB=O(+)-        */
 
3681
        /* number of removed H:  n+m                     n              */
 
3682
        /* OH(+) = N, O, S, Se; -O- = P,As,O,S,Se,Te,F,Cl,Br,I          */
 
3683
        /* Solution: move (+) from OH(+) to -O-                         */
 
3684
        /*--------------------------------------------------------------*/
 
3685
        int num_SB_Neutr = 0, num_DB_Charged = 0, iat;
 
3686
        short iat_SB_Neutr[MAX_DIFF_FIXH], iat_DB_Charged[MAX_DIFF_FIXH];
 
3687
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
3688
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
3689
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
3690
        cur_success = 0;
 
3691
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
3692
            iat = nCanon2AtnoRevrs[i];
 
3693
            if ( /* in restored atom: charge=+1, has H, has double bond, N, O, S, Se, Te */
 
3694
                 num_DB_Charged < MAX_DIFF_FIXH &&
 
3695
                 at2[iat].charge == 1 && at2[iat].num_H &&
 
3696
                 at2[iat].valence < at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
3697
                 (pVA[iat].cNumValenceElectrons == 6 ||
 
3698
                  pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber == 1) &&
 
3699
                 /* has (+) edge */
 
3700
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden ) {
 
3701
 
 
3702
                iat_DB_Charged[num_DB_Charged ++] = iat;
 
3703
                /*
 
3704
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3705
                    goto exit_function;
 
3706
                }
 
3707
                */
 
3708
            } else
 
3709
            if ( /* in restored atom: charge=0, has no H, has no double bond, N, P, O, S, Se, Te */
 
3710
                 num_SB_Neutr < MAX_DIFF_FIXH &&
 
3711
                 at2[iat].charge == 0 && !at2[iat].num_H &&
 
3712
                 at2[iat].valence == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
3713
                 (pVA[iat].cNumValenceElectrons == 6 || pVA[iat].cNumValenceElectrons == 7 ||
 
3714
                  pVA[iat].cNumValenceElectrons == 5 && pVA[iat].cPeriodicRowNumber > 1 ) &&
 
3715
                 /* in orig.InChI: not an endpoint */
 
3716
                 !pStruct->endpoint[i] &&
 
3717
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
3718
                 !(nMobHInChI && nMobHInChI[i] ) &&
 
3719
                 /* has (+) edge */
 
3720
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 &&
 
3721
                 0 == pBNS->edge[e].forbidden ) {
 
3722
 
 
3723
                iat_SB_Neutr[num_SB_Neutr ++] = iat;
 
3724
                
 
3725
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3726
                    goto exit_function;
 
3727
                }
 
3728
            }
 
3729
        }
 
3730
        if ( num_try = inchi_min( num_SB_Neutr, num_DB_Charged ) ) {
 
3731
            BNS_VERTEX *pv1n, *pv2n;
 
3732
            BNS_EDGE   *pe1n, *pe2n;
 
3733
            Vertex      v1n, v2n;
 
3734
 
 
3735
            num_try = inchi_min( num_try, pc2i->nNumRemHRevrs-pc2i->nNumRemHInChI);
 
3736
            /* detected; attempt to fix */
 
3737
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3738
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
3739
            delta = 1;
 
3740
            for ( i = 0; i < num_DB_Charged && cur_success < num_try; i ++ ) {
 
3741
                iat = iat_DB_Charged[i];
 
3742
                pe   = pBNS->edge + pVA[iat].nCPlusGroupEdge-1;
 
3743
                if ( pe->flow )
 
3744
                    continue;
 
3745
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
3746
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
3747
 
 
3748
                for ( j = pv1->num_adj_edges-1; 0 <= j; j -- ) {
 
3749
                    pe1n = pBNS->edge + pv1->iedge[j];
 
3750
                    if ( pe1n->flow && !pe1n->forbidden ) {
 
3751
                        pv1n = pBNS->vert + (v1n = pe1n->neighbor12 ^ v1);
 
3752
                        break;
 
3753
                    }
 
3754
                }
 
3755
                if ( j < 0 )
 
3756
                    continue; /* not found */
 
3757
                
 
3758
                for ( j = pv2->num_adj_edges-1; 0 <= j; j -- ) { /* was -2; changed 2006-2-28 12:35pm*/
 
3759
                    pe2n = pBNS->edge + pv2->iedge[j];
 
3760
                    if ( pe2n->flow && !pe2n->forbidden ) {
 
3761
                        pv2n = pBNS->vert + (v2n = pe2n->neighbor12 ^ v2);
 
3762
                        break;
 
3763
                    }
 
3764
                }
 
3765
                if ( j < 0 )
 
3766
                    continue; /* not found */
 
3767
 
 
3768
                pe->flow   += delta;
 
3769
                pe1n->flow -= delta;
 
3770
                pe2n->flow -= delta;
 
3771
                pv1n->st_edge.flow -= delta;
 
3772
                pv2n->st_edge.flow -= delta;
 
3773
                pBNS->tot_st_flow -= 2*delta;
 
3774
 
 
3775
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3776
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3777
 
 
3778
                if ( ret == 1 && (vPathEnd == v1n && vPathStart == v2n ||
 
3779
                                  vPathEnd == v2n && vPathStart == v1n) &&
 
3780
                                  (nDeltaCharge == 0 || nDeltaCharge == 1) ) {
 
3781
                    /* Moved charge from OH(+) to -O- => nDeltaCharge == 1 or 0 if pe2n = -O- charge edge */
 
3782
                    /* Flow change on pe (+)charge edge (atom OH(+)) is not known to RunBnsTestOnce()) */
 
3783
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
3784
                    if ( ret > 0 ) {
 
3785
                        nNumRunBNS ++;
 
3786
                        cur_success ++; /* 17 */
 
3787
                    }
 
3788
                } else {
 
3789
                    pe->flow   -= delta;
 
3790
                    pe1n->flow += delta;
 
3791
                    pe2n->flow += delta;
 
3792
                    pv1n->st_edge.flow += delta;
 
3793
                    pv2n->st_edge.flow += delta;
 
3794
                    pBNS->tot_st_flow += 2*delta;
 
3795
                }
 
3796
                INCHI_HEAPCHK
 
3797
            }
 
3798
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
3799
        }
 
3800
        CurrEdges.num_edges = 0; /* clear current edge list */
 
3801
        if ( cur_success ) {
 
3802
            tot_succes += cur_success;
 
3803
            /* recalculate InChI from the structure */
 
3804
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
3805
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
3806
                goto exit_function;
 
3807
            }
 
3808
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
3809
                goto exit_function;
 
3810
            }
 
3811
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
3812
                goto exit_function;  /* no fixed-H found */
 
3813
            }
 
3814
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
3815
                goto exit_function;
 
3816
            }
 
3817
            if ( !pc2i->bHasDifference ) {
 
3818
                goto exit_function; /* nothing to do */
 
3819
            }
 
3820
        }
 
3821
    }
 
3822
 
 
3823
    if ( (pc2i->nNumTgInChI && pStruct->endpoint &&
 
3824
         pc2i->nNumTgMInChI > pc2i->nNumTgMRevrs && pc2i->nNumEndpInChI > pc2i->nNumEndpRevrs ) ) {
 
3825
        /*-----------------------------------------------------------------*/
 
3826
        /*                                                                 */
 
3827
        /* case 18: restored:-N=AB-X                -(-)N-AB-X(+)          */
 
3828
        /* FixH:              0    0                    0    0             */
 
3829
        /* MobH:              0    0                    0    0             */
 
3830
        /*                   non  non                 taut  non            */
 
3831
        /*                  taut  taut                      taut           */
 
3832
        /* X = any heteroatom   N=N                                        */
 
3833
        /* t-group in original has (Hn,-m) in the restored: (Hn,-m+1)      */
 
3834
        /*       same num_H and more (-) than in the restored structure    */
 
3835
        /* atom X is not taut in both                                      */
 
3836
        /* Solution: separate charges between -N(III)= and  X              */
 
3837
        /*-----------------------------------------------------------------*/
 
3838
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
3839
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
3840
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
3841
        int iat, e1, itg, max_success;
 
3842
        CurrEdges.num_edges = 0;
 
3843
        cur_success = 0;
 
3844
        ret = 0;
 
3845
        /* search for -N= */
 
3846
        for ( itg = 0; itg < pStruct->ti.num_t_groups && itg < pStruct->One_ti.num_t_groups; itg ++ ) {
 
3847
            if ( pStruct->ti.t_group[itg].nNumEndpoints <= pStruct->One_ti.t_group[itg].nNumEndpoints ||
 
3848
                 pStruct->ti.t_group[itg].num[1]  <= pStruct->One_ti.t_group[itg].num[1] ) {
 
3849
                     continue;
 
3850
            }
 
3851
            CurrEdges.num_edges = 0;
 
3852
            cur_success = 0;
 
3853
            for ( j = 0, k = pStruct->ti.t_group[itg].nFirstEndpointAtNoPos;
 
3854
                    j < pStruct->ti.t_group[itg].nNumEndpoints; j ++ ) {
 
3855
                i = pStruct->ti.nEndpointAtomNumber[k+j]; /* canonical number in restored struct. */
 
3856
                iat = nCanon2AtnoRevrs[i];
 
3857
                if ( !pStruct->endpoint[i] || !at_Mobile_H_Revrs || at_Mobile_H_Revrs[iat].endpoint ||
 
3858
                     pVA[i].cNumValenceElectrons != 5 || pVA[i].cPeriodicRowNumber != 1 ||
 
3859
                     2 != at2[iat].valence || at2[iat].num_H || at2[iat].radical ||
 
3860
                     0 <= (e1=pVA[iat].nCPlusGroupEdge-1) && !pBNS->edge[e1].flow ||
 
3861
                     0 > (e=pVA[iat].nCMinusGroupEdge-1) || pBNS->edge[e].forbidden || pBNS->edge[e].flow ) {
 
3862
                    continue;
 
3863
                }
 
3864
                /* found -N= */
 
3865
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
3866
                    goto exit_function;
 
3867
                }
 
3868
            }
 
3869
        }
 
3870
        if ( !(max_success = CurrEdges.num_edges) ) {
 
3871
            goto exit_case_18;
 
3872
        }
 
3873
        /* search for X */
 
3874
        for ( i = 0; i < pStruct->num_atoms && cur_success < max_success; i ++ ) {
 
3875
            iat =  nCanon2AtnoRevrs[i];
 
3876
            if ( pStruct->endpoint[i] || !pVA[i].cNumValenceElectrons || pVA[i].cNumValenceElectrons == 4 ||
 
3877
                 at2[iat].num_H || at2[iat].radical ||
 
3878
                 0 <= (e1=pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e1].flow ||
 
3879
                 0 > (e=pVA[iat].nCPlusGroupEdge-1) || pBNS->edge[e].forbidden || pBNS->edge[e].flow != 1 ) {
 
3880
                continue;
 
3881
            }
 
3882
            /* try to move the charge */
 
3883
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3884
            SetForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask );
 
3885
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask );
 
3886
 
 
3887
            pe   = pBNS->edge + e;
 
3888
            if ( !pe->flow )
 
3889
                continue;
 
3890
            pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
3891
            pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
3892
 
 
3893
            delta = 1;
 
3894
            pe->flow -= delta;
 
3895
            pv1->st_edge.flow -= delta;
 
3896
            pv2->st_edge.flow -= delta;
 
3897
            pBNS->tot_st_flow -= 2*delta;
 
3898
 
 
3899
            ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
3900
                                  &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
3901
 
 
3902
            if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
3903
                              vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
3904
                /* Created (-) charge on -N= => nDeltaCharge == 1 */
 
3905
                /* Flow change on pe (+)charge edge (atom X) is not known to RunBnsTestOnce()) */
 
3906
                ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
3907
                if ( ret > 0 ) {
 
3908
                    nNumRunBNS ++;
 
3909
                    cur_success ++; /* 18 */
 
3910
                }
 
3911
            } else {
 
3912
                pe->flow += delta;
 
3913
                pv1->st_edge.flow += delta;
 
3914
                pv2->st_edge.flow += delta;
 
3915
                pBNS->tot_st_flow += 2*delta;
 
3916
            }
 
3917
            INCHI_HEAPCHK
 
3918
        }
 
3919
exit_case_18:
 
3920
        RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
3921
        RemoveForbiddenEdgeMask( pBNS, &OtherNFlowerEdges, forbidden_edge_mask  );
 
3922
        CurrEdges.num_edges = 0; /* clear current edge list */
 
3923
        if ( ret < 0 ) {
 
3924
            goto exit_function;
 
3925
        }
 
3926
        if ( cur_success ) {
 
3927
            tot_succes += cur_success;
 
3928
            /* recalculate InChI from the structure */
 
3929
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
3930
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
3931
                goto exit_function;
 
3932
            }
 
3933
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
3934
                goto exit_function;
 
3935
            }
 
3936
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
3937
                goto exit_function;  /* no fixed-H found */
 
3938
            }
 
3939
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
3940
                goto exit_function;
 
3941
            }
 
3942
            if ( !pc2i->bHasDifference ) {
 
3943
                goto exit_function; /* nothing to do */
 
3944
            }
 
3945
        }
 
3946
    }
 
3947
    if ( pc2i->len_c2at >= 1 ) {
 
3948
        /*--------------------------------------------------------------*/
 
3949
        /* case 19 restored:       M--OH   original:  M(-)==OH(+)       */
 
3950
        /* FixH:               metal  0                      1          */
 
3951
        /* MobH:                      1                      0          */
 
3952
        /* O =  O, S, Se, Te; not taut. in InChI                        */
 
3953
        /* In restored structure has H; tautomeric or not tautomeric    */
 
3954
        /* Solution: move (+) from -OH to M; charhe on M may vary       */
 
3955
        /*--------------------------------------------------------------*/
 
3956
        int iat;
 
3957
        EdgeIndex eOHPlus, eMPlus, eMMinus, eOMBond;
 
3958
        BNS_EDGE  *peOHPlus, *peMPlus, *peMMinus, *peOMBond;
 
3959
        int       iatMetal, ChargeOnMetal, DeltaChargeExpected;
 
3960
        cur_success = 0;
 
3961
        num_zero_ret = 0;
 
3962
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
3963
            iat = pc2i->c2at[i].atomNumber;
 
3964
            if ( /* orig. InChI info: =NH2(+), =OH(+) */
 
3965
                 (pc2i->c2at[i].nValElectr == 6 ) /* N, O, S, Se, Te */ &&
 
3966
                 /*!pc2i->c2at[i].endptInChI &&*/ /* <=== relaxation */
 
3967
                 (e=pVA[iat].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
3968
                 pc2i->c2at[i].nFixHInChI == 1 && pc2i->c2at[i].nMobHInChI == 0 &&
 
3969
                 /* reversed structure info: */
 
3970
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 1 &&
 
3971
                 pc2i->c2at[i].nAtChargeRevrs == 0 && at2[iat].num_H &&
 
3972
                 at2[iat].valence == 1 &&
 
3973
                 at2[iat].valence == at2[iat].chem_bonds_valence &&
 
3974
                 /* metal atom */
 
3975
                 pVA[iatMetal=at2[iat].neighbor[0]].cMetal && 
 
3976
                 (eMPlus=pVA[iatMetal].nCPlusGroupEdge-1) >= 0 && !pBNS->edge[eMPlus].forbidden &&
 
3977
                 (eMMinus=pVA[iatMetal].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[eMMinus].forbidden &&
 
3978
                 !pBNS->edge[eOMBond=pBNS->vert[iat].iedge[0]].forbidden
 
3979
                 ) {
 
3980
 
 
3981
                /* -OH charge edges */
 
3982
                if ( ret = AddToEdgeList( &CurrEdges, iat, INC_ADD_EDGE ) ) {
 
3983
                    goto exit_function;
 
3984
                }
 
3985
            }
 
3986
        }
 
3987
        if ( CurrEdges.num_edges ) {
 
3988
            /* detected; fix */
 
3989
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
3990
            SetForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask );
 
3991
            SetForbiddenEdgeMask( pBNS, &AllBondEdges, forbidden_edge_mask );
 
3992
            for ( i = 0; i < CurrEdges.num_edges; i ++ ) {
 
3993
                /* v1 is -OH, v2 is adjacent to it Metal */
 
3994
                iat      = CurrEdges.pnEdges[i];
 
3995
                iatMetal = at2[iat].neighbor[0];
 
3996
                peOHPlus = pBNS->edge + (eOHPlus = pVA[iat].nCPlusGroupEdge-1);
 
3997
                peMPlus  = pBNS->edge + (eMPlus  = pVA[iatMetal].nCPlusGroupEdge-1);
 
3998
                peMMinus = pBNS->edge + (eMMinus = pVA[iatMetal].nCMinusGroupEdge-1);
 
3999
                peOMBond = pBNS->edge + (eOMBond =pBNS->vert[iat].iedge[0]);
 
4000
                /* remove forbidden edge masks */
 
4001
                peMPlus->forbidden  &= forbidden_edge_mask_inv;
 
4002
                peMMinus->forbidden &= forbidden_edge_mask_inv;
 
4003
                peOMBond->forbidden &= forbidden_edge_mask_inv;
 
4004
 
 
4005
                ChargeOnMetal = (peMPlus->cap - peMPlus->flow) - peMMinus->flow;
 
4006
                if ( 1 == ChargeOnMetal ) {
 
4007
                    /* We are going to subtract 1 from the charge on Metal */
 
4008
                    /* Added (+)charge to -OH is not known to RunBnsTestOnce() */
 
4009
                    DeltaChargeExpected = -1; /* charge will become = 0 */
 
4010
                } else
 
4011
                if ( 0 == ChargeOnMetal ) {
 
4012
                    DeltaChargeExpected = 1; /* charge on Metal will be created */
 
4013
                } else {
 
4014
                    DeltaChargeExpected = 0;
 
4015
                }
 
4016
 
 
4017
                delta = 1;
 
4018
                pe   = peOHPlus;
 
4019
                if ( !pe->flow )
 
4020
                    continue;
 
4021
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
4022
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
4023
 
 
4024
                pe->flow -= delta; /* remove (-) from AB-O(-) */
 
4025
                pv1->st_edge.flow -= delta;
 
4026
                pv2->st_edge.flow -= delta;
 
4027
                pBNS->tot_st_flow -= 2*delta;
 
4028
 
 
4029
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
4030
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
4031
 
 
4032
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
4033
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == DeltaChargeExpected ) {
 
4034
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
4035
                    if ( ret > 0 ) {
 
4036
                        nNumRunBNS ++;
 
4037
                        cur_success ++; /* 19 */
 
4038
                    }
 
4039
                } else {
 
4040
                    pe->flow += delta;
 
4041
                    pv1->st_edge.flow += delta;
 
4042
                    pv2->st_edge.flow += delta;
 
4043
                    pBNS->tot_st_flow += 2*delta;
 
4044
                }
 
4045
                INCHI_HEAPCHK
 
4046
                /* set forbidden edge masks back */
 
4047
                peMPlus->forbidden  |= forbidden_edge_mask;
 
4048
                peMMinus->forbidden |= forbidden_edge_mask;
 
4049
                peOMBond->forbidden |= forbidden_edge_mask;
 
4050
            }
 
4051
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4052
            RemoveForbiddenEdgeMask( pBNS, &NFlowerEdges, forbidden_edge_mask );
 
4053
            RemoveForbiddenEdgeMask( pBNS, &AllBondEdges, forbidden_edge_mask );
 
4054
 
 
4055
            CurrEdges.num_edges = 0; /* clear current edge list */
 
4056
            if ( cur_success ) {
 
4057
                tot_succes += cur_success;
 
4058
                /* recalculate InChI from the structure */
 
4059
                if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
4060
                                                                ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
4061
                    goto exit_function;
 
4062
                }
 
4063
                if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
4064
                    goto exit_function;
 
4065
                }
 
4066
                if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
4067
                    goto exit_function;  /* no fixed-H found */
 
4068
                }
 
4069
                if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
4070
                    goto exit_function;
 
4071
                }
 
4072
                if ( !pc2i->bHasDifference ) {
 
4073
                    goto exit_function; /* nothing to do */
 
4074
                }
 
4075
            }
 
4076
        }
 
4077
    }
 
4078
    if ( pc2i->len_c2at > 1 && pc2i->nNumTgRevrs && pc2i->nNumTgInChI) {
 
4079
        /*--------------------------------------------------------------*/
 
4080
        /* case 20: restored:  O(-)-AB=N-   original:   O=AB-N(-)-      */
 
4081
        /* FixH:               0       0                0     -1        */
 
4082
        /* MobH:               0       0                0      1        */
 
4083
        /*                   taut    non-taut       non-taut taut       */
 
4084
        /*                           or taut                  no H      */
 
4085
        /*                           no H                               */
 
4086
        /* O = O, S, Se; N = N, O, S, Se, Te;                           */
 
4087
        /* restored atoms are taut/non-taut; original are opposite.     */
 
4088
        /* Solution: move (-) from O(-) to =N-                          */
 
4089
        /*--------------------------------------------------------------*/
 
4090
        int num_SB_O_Minus = 0, num_DB_N = 0, iat;
 
4091
        short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_DB_N[MAX_DIFF_FIXH];
 
4092
        
 
4093
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
4094
        /*
 
4095
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
4096
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
4097
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
4098
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
4099
        */
 
4100
        cur_success = 0;
 
4101
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4102
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
4103
            iat = pc2i->c2at[i].atomNumber;
 
4104
            if ( /* orig. InChI info: =O or -N= */
 
4105
                 num_DB_N < MAX_DIFF_FIXH &&
 
4106
                 pc2i->c2at[i].endptInChI &&
 
4107
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4108
                 pBNS->edge[e].flow == 0 &&
 
4109
                 pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
 
4110
                 /* if  more than 1 t-group are in orig. InChI then do not move (-) to N */
 
4111
                 (pc2i->nNumTgInChI == 1 || pc2i->c2at[i].nValElectr == 6) &&
 
4112
                 /* reversed structure info: */
 
4113
                 !pc2i->c2at[i].endptRevrs &&
 
4114
                 pc2i->c2at[i].nFixHRevrs ==  0 && /*pc2i->c2at[i].nMobHRevrs == 0 &&*/
 
4115
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
4116
                 at2[iat].valence + 1 == at2[iat].chem_bonds_valence ) {
 
4117
                iat_DB_N[num_DB_N ++] = iat;
 
4118
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
4119
                    goto exit_function;
 
4120
                }
 
4121
            } else
 
4122
            if ( /* orig. InChI info: -O(-) */
 
4123
                 num_SB_O_Minus < MAX_DIFF_FIXH &&
 
4124
                 !pc2i->c2at[i].endptInChI &&
 
4125
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4126
                 pBNS->edge[e].flow == 1 &&
 
4127
                 pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
 
4128
                 pc2i->c2at[i].nValElectr == 6 &&
 
4129
                 /* reversed structure info: */
 
4130
                 pc2i->c2at[i].endptRevrs &&
 
4131
                 pc2i->c2at[i].nFixHRevrs ==  0 && pc2i->c2at[i].nMobHRevrs == 0 &&
 
4132
                 pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H &&
 
4133
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 ) {
 
4134
                iat_SB_O_Minus[num_SB_O_Minus ++] = iat;
 
4135
            }
 
4136
        }
 
4137
        if ( !num_DB_N ) {
 
4138
            /* search among N that are tautomeric in both cases */
 
4139
            for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
4140
                if ( !pStruct->endpoint[i] ) {
 
4141
                    continue;
 
4142
                }
 
4143
                iat = nCanon2AtnoRevrs[i];
 
4144
                if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */
 
4145
                     num_DB_N < MAX_DIFF_FIXH &&
 
4146
                     at2[iat].charge == 0 && !at2[iat].num_H &&
 
4147
                     at2[iat].valence + 1 == at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
4148
                     /* in orig.InChI: an endpoint, has no H */
 
4149
                     !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
4150
                     /*!(nMobHInChI && nMobHInChI[i] ) &&*/
 
4151
                     /* has (-) edge */
 
4152
                     (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4153
                     !pBNS->edge[e].flow ) {
 
4154
 
 
4155
                    iat_DB_N[num_DB_N ++] = iat;
 
4156
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
4157
                        goto exit_function;
 
4158
                    }
 
4159
                }
 
4160
            }
 
4161
        }
 
4162
        if ( num_try = inchi_min( num_SB_O_Minus, num_DB_N ) ) {
 
4163
            /* detected; attempt to fix */
 
4164
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4165
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
4166
            delta = 1;
 
4167
            for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
 
4168
                iat = iat_SB_O_Minus[i];
 
4169
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
4170
                if ( !pe->flow )
 
4171
                    continue;
 
4172
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
4173
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
4174
 
 
4175
                pe->flow -= delta;
 
4176
                pv1->st_edge.flow -= delta;
 
4177
                pv2->st_edge.flow -= delta;
 
4178
                pBNS->tot_st_flow -= 2*delta;
 
4179
 
 
4180
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
4181
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
4182
 
 
4183
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
4184
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
4185
                    /* Added (-) charge to =N- => nDeltaCharge == 1 */
 
4186
                    /* Flow change on pe (-)charge edge (atom -O(-)) is not known to RunBnsTestOnce()) */
 
4187
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
4188
                    if ( ret > 0 ) {
 
4189
                        nNumRunBNS ++;
 
4190
                        cur_success ++; /* 20 */
 
4191
                    }
 
4192
                } else {
 
4193
                    pe->flow += delta;
 
4194
                    pv1->st_edge.flow += delta;
 
4195
                    pv2->st_edge.flow += delta;
 
4196
                    pBNS->tot_st_flow += 2*delta;
 
4197
                }
 
4198
                INCHI_HEAPCHK
 
4199
            }
 
4200
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
4201
        }
 
4202
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4203
        if ( cur_success ) {
 
4204
            tot_succes += cur_success;
 
4205
            /* recalculate InChI from the structure */
 
4206
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
4207
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
4208
                goto exit_function;
 
4209
            }
 
4210
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
4211
                goto exit_function;
 
4212
            }
 
4213
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
4214
                goto exit_function;  /* no fixed-H found */
 
4215
            }
 
4216
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
4217
                goto exit_function;
 
4218
            }
 
4219
            if ( !pc2i->bHasDifference ) {
 
4220
                goto exit_function; /* nothing to do */
 
4221
            }
 
4222
        }
 
4223
    }
 
4224
    if ( pc2i->len_c2at && pc2i->nNumTgRevrs && pc2i->nNumTgHInChI && pStruct->endpoint ) {
 
4225
        /*--------------------------------------------------------------*/
 
4226
        /*                      O(-)                      O             */
 
4227
        /*                      |                         ||            */
 
4228
        /* case 21: restored: R=S=O         original:   R-S=O           */
 
4229
        /*                      |                         |             */
 
4230
        /*                      O(-)                      O(-)          */
 
4231
        /*                           All O are taut     R is not taut   */
 
4232
        /*                                                              */
 
4233
        /* In addition, another atom O that should have been tautomeric */
 
4234
        /* or has H(+) added in Mobile-H layer is not like that         */
 
4235
        /* O = O, S, Se;  S=S, Se, Te                                  */
 
4236
        /* Solution: move (-) from O(-) to =O                           */
 
4237
        /*           these atoms are tautomeric in restored structure   */
 
4238
        /*--------------------------------------------------------------*/
 
4239
        int num_SB_O_Minus = 0, num_DB_O = 0, iat, iS;
 
4240
        short iat_SB_O_Minus[MAX_DIFF_FIXH], iat_Central[MAX_DIFF_FIXH], iat_DB_O[MAX_DIFF_FIXH];
 
4241
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
4242
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
4243
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
4244
        /*
 
4245
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
4246
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
4247
        */
 
4248
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4249
        cur_success = 0;
 
4250
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
4251
            iat = pc2i->c2at[i].atomNumber;
 
4252
            if ( /* orig. InChI info: =O    */
 
4253
                 num_DB_O < MAX_DIFF_FIXH &&
 
4254
                 pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
 
4255
                 (pc2i->c2at[i].endptInChI || pc2i->c2at[i].nMobHInChI) &&
 
4256
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4257
                 pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI ==  1 &&*/
 
4258
                 /* reversed structure info: */
 
4259
                 !(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) &&
 
4260
                 pc2i->c2at[i].nFixHRevrs ==  0 &&
 
4261
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
4262
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
 
4263
                iat_DB_O[num_DB_O ++] = iat;
 
4264
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
4265
                    goto exit_function;
 
4266
                }
 
4267
            }
 
4268
        }
 
4269
        for ( i = 0; num_DB_O && i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
4270
            if ( !pStruct->endpoint[i] ) {
 
4271
                continue;
 
4272
            }
 
4273
            iat = nCanon2AtnoRevrs[i];
 
4274
            if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */
 
4275
                 num_SB_O_Minus < MAX_DIFF_FIXH &&
 
4276
                 at2[iat].charge == -1 && !at2[iat].num_H &&
 
4277
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence && !pVA[iat].cMetal &&
 
4278
                 pVA[iat].cNumValenceElectrons == 6 &&
 
4279
                 (at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
 
4280
                 /* in orig.InChI: an endpoint, has no H */
 
4281
                 !(pStruct->fixed_H && pStruct->fixed_H[i]) &&
 
4282
                 /*!(nMobHInChI && nMobHInChI[i] ) &&*/
 
4283
                 /* has (-) edge */
 
4284
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4285
                 pBNS->edge[e].flow ) {
 
4286
                int nNumTautSB = 0, nNumTautDB = 0, nNumOtherDB = 0, nNumOtherSB = 0, nNumOthers = 0, nNumNegEndp = 0;
 
4287
                /* traverse neighbors of the centerpoint iS */
 
4288
                iS = at2[i].neighbor[0];
 
4289
                for ( j = 0; j < num_SB_O_Minus; j ++ ) {
 
4290
                    if ( iat_Central[j] == iS )
 
4291
                        break;
 
4292
                }
 
4293
                if ( j < num_SB_O_Minus ) {
 
4294
                    continue;  /* have already been there */
 
4295
                }
 
4296
                for ( j = 0; j < at[iS].valence; j ++ ) {
 
4297
                    int bond_type = at2[iS].bond_type[j];
 
4298
                    k = at2[iS].neighbor[j];
 
4299
                    if ( k == i ) {
 
4300
                        continue;
 
4301
                    }
 
4302
                    if ( pStruct->endpoint[k] == pStruct->endpoint[i] ) {
 
4303
                        nNumTautSB += ( bond_type == BOND_TYPE_SINGLE );
 
4304
                        nNumTautDB += ( bond_type == BOND_TYPE_DOUBLE );
 
4305
                    } else
 
4306
                    if ( bond_type == BOND_TYPE_DOUBLE ) {
 
4307
                        nNumOtherDB ++;
 
4308
                    } else
 
4309
                    if ( bond_type == BOND_TYPE_SINGLE ) {
 
4310
                        nNumOtherSB ++;
 
4311
                    } else {
 
4312
                        nNumOthers ++;
 
4313
                    }
 
4314
                    if ( at2[k].endpoint == at2[i].endpoint && at2[k].valence == 1 &&
 
4315
                         at2[k].charge    == -1 && pVA[k].cNumValenceElectrons == 6 ) {
 
4316
                        nNumNegEndp ++;
 
4317
                    }
 
4318
                }
 
4319
                if ( !nNumTautSB ) {
 
4320
                    continue;
 
4321
                }
 
4322
                if ( !( nNumOtherDB && nNumTautDB ) ) {
 
4323
                    continue; /* ignore */
 
4324
                }
 
4325
                
 
4326
                iat_SB_O_Minus[num_SB_O_Minus] = iat;
 
4327
                iat_Central[num_SB_O_Minus ++] = iS;
 
4328
            }
 
4329
        }
 
4330
        if ( num_try = inchi_min( num_SB_O_Minus, num_DB_O ) ) {
 
4331
            /* detected; attempt to fix */
 
4332
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4333
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
4334
            delta = 1;
 
4335
            for ( i = 0; i < num_SB_O_Minus && cur_success < num_try; i ++ ) {
 
4336
                iat = iat_SB_O_Minus[i];
 
4337
                pe   = pBNS->edge + pVA[iat].nCMinusGroupEdge-1;
 
4338
                if ( !pe->flow )
 
4339
                    continue;
 
4340
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
4341
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
4342
 
 
4343
                pe->forbidden |= forbidden_edge_mask;
 
4344
                pe->flow -= delta;
 
4345
                pv1->st_edge.flow -= delta;
 
4346
                pv2->st_edge.flow -= delta;
 
4347
                pBNS->tot_st_flow -= 2*delta;
 
4348
 
 
4349
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
4350
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
4351
 
 
4352
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
4353
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
4354
                    /* Added (-) charge to =O => nDeltaCharge == 1 */
 
4355
                    /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
 
4356
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
4357
                    if ( ret > 0 ) {
 
4358
                        nNumRunBNS ++;
 
4359
                        cur_success ++; /* 21 */
 
4360
                    }
 
4361
                } else {
 
4362
                    pe->flow += delta;
 
4363
                    pv1->st_edge.flow += delta;
 
4364
                    pv2->st_edge.flow += delta;
 
4365
                    pBNS->tot_st_flow += 2*delta;
 
4366
                }
 
4367
                INCHI_HEAPCHK
 
4368
            }
 
4369
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
4370
        }
 
4371
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4372
        if ( cur_success ) {
 
4373
            tot_succes += cur_success;
 
4374
            /* recalculate InChI from the structure */
 
4375
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
4376
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
4377
                goto exit_function;
 
4378
            }
 
4379
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
4380
                goto exit_function;
 
4381
            }
 
4382
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
4383
                goto exit_function;  /* no fixed-H found */
 
4384
            }
 
4385
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
4386
                goto exit_function;
 
4387
            }
 
4388
            if ( !pc2i->bHasDifference ) {
 
4389
                goto exit_function; /* nothing to do */
 
4390
            }
 
4391
        }
 
4392
    }
 
4393
 
 
4394
    if ( pc2i->len_c2at && pc2i->nNumTgRevrs && pc2i->nNumEndpInChI < pc2i->nNumEndpRevrs ) {
 
4395
        /*--------------------------------------------------------------*/
 
4396
        /*                      O                         O             */
 
4397
        /*                      ||                        ||            */
 
4398
        /* case 21a:restored: R=S-R' =X     original:   R-S-R' -X(-)    */
 
4399
        /*                      |                         ||            */
 
4400
        /*                      O(-)                      O(-)          */
 
4401
        /*             All O and X are taut      O and X are not taut   */
 
4402
        /*             it is possible that X is R                       */
 
4403
        /*                                                              */
 
4404
        /* O = O, S, Se;  S=S, Se, Te; X = N, O, S, Se, Te              */
 
4405
        /* Solution: move (-) from O(-) to =X                           */
 
4406
        /*           these atoms are tautomeric in restored structure   */
 
4407
        /*--------------------------------------------------------------*/
 
4408
        int iat, iS;
 
4409
        /*
 
4410
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
4411
        */
 
4412
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
4413
                    pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
4414
        /*
 
4415
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
4416
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
4417
        */
 
4418
        EDGE_LIST  OtherSO, CentralS, SOMinus, MinusAcceptord;
 
4419
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4420
        AllocEdgeList( &OtherSO, EDGE_LIST_CLEAR );
 
4421
        AllocEdgeList( &CentralS, EDGE_LIST_CLEAR );
 
4422
        AllocEdgeList( &SOMinus, EDGE_LIST_CLEAR );
 
4423
        AllocEdgeList( &MinusAcceptord, EDGE_LIST_CLEAR );
 
4424
        cur_success = 0;
 
4425
        if ( !at_Mobile_H_Revrs ) {
 
4426
            goto exit_case_21a;
 
4427
        }
 
4428
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
4429
            iat = pc2i->c2at[i].atomNumber;
 
4430
            if ( /* orig. InChI info: -X(-)    */
 
4431
                 /*num_DB_O < MAX_DIFF_FIXH &&*/
 
4432
                 /*pc2i->c2at[i].nValElectr == 6 */ /* O, S, Se, Te */
 
4433
                 !pc2i->c2at[i].endptInChI &&
 
4434
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4435
                 pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI ==  1 &&*/
 
4436
                 /* reversed structure info: */
 
4437
                 (pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) &&
 
4438
                 pc2i->c2at[i].nFixHRevrs ==  0 &&
 
4439
                 /*pc2i->c2at[i].nAtChargeRevrs == 0 &&*/ !at2[iat].num_H ) {
 
4440
                if ( pVA[iat].cNumValenceElectrons == 6 && at2[iat].charge == -1 &&
 
4441
                     pBNS->edge[e].flow &&
 
4442
                     at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 1 &&
 
4443
                     pVA[iS=(int)at2[iat].neighbor[0]].cNumValenceElectrons == 6 && pVA[iS].cPeriodicRowNumber > 1 &&
 
4444
                     at2[iS].valence >= 4 ) {
 
4445
                    /* a candidate for S in -SO2- */
 
4446
                    int nNumTautSB = 0, nNumTautDB = 0, nNumOtherDB = 0, nNumOtherSB = 0;
 
4447
                    int nNumOthers = 0, nNumNegEndp = 0, nNumEndpO = 0;
 
4448
                    /* check whether we have already found it */
 
4449
                    if ( 0 <= FindInEdgeList( &CentralS, iS ) ) {
 
4450
                        continue;
 
4451
                    }
 
4452
                    for ( j = 0; j < at[iS].valence; j ++ ) {
 
4453
                        int bond_type = at2[iS].bond_type[j];
 
4454
                        k = at2[iS].neighbor[j];
 
4455
                        if ( k == iat ) {
 
4456
                            continue;
 
4457
                        }
 
4458
                        if ( pc2i->c2at[i].endptRevrs == at_Mobile_H_Revrs[k].endpoint && !at2[k].endpoint ) {
 
4459
                            nNumTautSB += ( bond_type == BOND_TYPE_SINGLE );
 
4460
                            nNumTautDB += ( bond_type == BOND_TYPE_DOUBLE );
 
4461
                            nNumEndpO  += (pVA[k].cNumValenceElectrons == 6 && at2[k].valence == 1);
 
4462
                        } else
 
4463
                        if ( bond_type == BOND_TYPE_DOUBLE ) {
 
4464
                            nNumOtherDB ++;
 
4465
                        } else
 
4466
                        if ( bond_type == BOND_TYPE_SINGLE ) {
 
4467
                            nNumOtherSB ++;
 
4468
                        } else {
 
4469
                            nNumOthers ++;
 
4470
                        }
 
4471
                        if ( at2[k].endpoint == at2[i].endpoint && at2[k].valence == 1 &&
 
4472
                             at2[k].charge    == -1 && pVA[k].cNumValenceElectrons == 6 ) {
 
4473
                            nNumNegEndp ++;
 
4474
                        }
 
4475
                    }
 
4476
                    if ( !nNumEndpO ) {
 
4477
                        continue;
 
4478
                    }
 
4479
                    if ( nNumTautSB + nNumTautDB + nNumOtherDB <= nNumEndpO  ) {
 
4480
                        continue; /* ignore */
 
4481
                    }
 
4482
                    /* collect double bond taut =O */
 
4483
                    for ( j = 0; j < at[iS].valence; j ++ ) {
 
4484
                        int bond_type = at2[iS].bond_type[j];
 
4485
                        k = at2[iS].neighbor[j];
 
4486
                        if ( pc2i->c2at[i].endptRevrs == at_Mobile_H_Revrs[k].endpoint &&
 
4487
                             !at2[k].endpoint && pVA[k].cNumValenceElectrons == 6 && at2[k].valence == 1 &&
 
4488
                             0 <= (e=pVA[k].nCMinusGroupEdge-1) && !pBNS->edge[e].forbidden ) {
 
4489
                            if ( bond_type == BOND_TYPE_DOUBLE && !at2[k].charge && !pBNS->edge[e].flow) {
 
4490
                                /* charges to be unchanged */
 
4491
                                if ( ret = AddToEdgeList( &OtherSO, e, INC_ADD_EDGE ) ) {
 
4492
                                    goto exit_case_21a;
 
4493
                                }
 
4494
                            } else
 
4495
                            if ( bond_type == BOND_TYPE_SINGLE && at2[k].charge == -1 && pBNS->edge[e].flow ) {
 
4496
                                /* charges to be removed */
 
4497
                                if ( ret = AddToEdgeList( &SOMinus, e, INC_ADD_EDGE ) ) {
 
4498
                                    goto exit_case_21a;
 
4499
                                }
 
4500
                            }
 
4501
                        }
 
4502
                    }
 
4503
                    if ( ret = AddToEdgeList( &CentralS, iS, INC_ADD_EDGE ) ) {
 
4504
                        goto exit_case_21a;
 
4505
                    }
 
4506
                } else
 
4507
                if ( at2[iat].charge == 0 && !pBNS->edge[e].flow &&
 
4508
                     at2[iat].valence + 1 == at2[iat].chem_bonds_valence ) {
 
4509
                    /* changeable charges */
 
4510
                    if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
4511
                        goto exit_function;
 
4512
                    }
 
4513
                }
 
4514
            }
 
4515
        }
 
4516
        /* remove unchangeable from changeable */
 
4517
        for ( i = 0; i < OtherSO.num_edges; i ++ ) {
 
4518
            RemoveFromEdgeListByValue( &CurrEdges, OtherSO.pnEdges[i] );
 
4519
        }
 
4520
 
 
4521
        if ( num_try = inchi_min( SOMinus.num_edges, CurrEdges.num_edges ) ) {
 
4522
            /* detected; attempt to fix */
 
4523
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4524
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
4525
            delta = 1;
 
4526
            for ( i = 0; i < SOMinus.num_edges && cur_success < num_try; i ++ ) {
 
4527
                pe   = pBNS->edge + SOMinus.pnEdges[i];
 
4528
                if ( !pe->flow )
 
4529
                    continue;
 
4530
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
4531
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
4532
 
 
4533
                /*pe->forbidden |= forbidden_edge_mask;*/
 
4534
                pe->flow -= delta;
 
4535
                pv1->st_edge.flow -= delta;
 
4536
                pv2->st_edge.flow -= delta;
 
4537
                pBNS->tot_st_flow -= 2*delta;
 
4538
 
 
4539
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
4540
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
4541
 
 
4542
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
4543
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 1 ) {
 
4544
                    /* Added (-) charge to =O => nDeltaCharge == 1 */
 
4545
                    /* Flow change on pe (-)charge edge (atom -N(-)-) is not known to RunBnsTestOnce()) */
 
4546
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
4547
                    if ( ret > 0 ) {
 
4548
                        nNumRunBNS ++;
 
4549
                        cur_success ++; /* 21a */
 
4550
                    }
 
4551
                } else {
 
4552
                    pe->flow += delta;
 
4553
                    pv1->st_edge.flow += delta;
 
4554
                    pv2->st_edge.flow += delta;
 
4555
                    pBNS->tot_st_flow += 2*delta;
 
4556
                }
 
4557
                INCHI_HEAPCHK
 
4558
            }
 
4559
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
4560
        }
 
4561
exit_case_21a:
 
4562
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4563
        AllocEdgeList( &OtherSO, EDGE_LIST_FREE );
 
4564
        AllocEdgeList( &CentralS, EDGE_LIST_FREE );
 
4565
        AllocEdgeList( &SOMinus, EDGE_LIST_FREE );
 
4566
        AllocEdgeList( &MinusAcceptord, EDGE_LIST_FREE );
 
4567
        if ( cur_success ) {
 
4568
            tot_succes += cur_success;
 
4569
            /* recalculate InChI from the structure */
 
4570
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
4571
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
4572
                goto exit_function;
 
4573
            }
 
4574
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
4575
                goto exit_function;
 
4576
            }
 
4577
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
4578
                goto exit_function;  /* no fixed-H found */
 
4579
            }
 
4580
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
4581
                goto exit_function;
 
4582
            }
 
4583
            if ( !pc2i->bHasDifference ) {
 
4584
                goto exit_function; /* nothing to do */
 
4585
            }
 
4586
        }
 
4587
    }
 
4588
 
 
4589
    if ( pc2i->len_c2at ) {
 
4590
        /*------------------------------------------------------------------*/
 
4591
        /* case 22: restored: N(-)=N(+)=C...=O orig: N#N-N=...-O(-)         */
 
4592
        /*     im InChI        -O(-) may have H(+) added by Normalization   */
 
4593
        /*                           or may be tautomeric                   */
 
4594
        /* Solution: move (-) from N(-) to =O                               */
 
4595
        /*                                                                  */
 
4596
        /*------------------------------------------------------------------*/
 
4597
        int num_DB_O = 0, iat;
 
4598
        short iat_DB_O[MAX_DIFF_FIXH];
 
4599
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
4600
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
4601
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
4602
        int iN2, iC;
 
4603
        BNS_EDGE *peDB_O_Minus;
 
4604
        /*
 
4605
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
4606
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
4607
        */
 
4608
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4609
        cur_success = 0;
 
4610
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
4611
            iat = pc2i->c2at[i].atomNumber;
 
4612
            if ( /* orig. InChI info: =O    */
 
4613
                 num_DB_O < MAX_DIFF_FIXH &&
 
4614
                 pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
 
4615
                 (pc2i->c2at[i].endptInChI || pc2i->c2at[i].nMobHInChI) &&
 
4616
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4617
                 pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI ==  1 &&*/
 
4618
                 /* reversed structure info: */
 
4619
                 !(pc2i->c2at[i].endptRevrs || pc2i->c2at[i].nMobHRevrs) &&
 
4620
                 pc2i->c2at[i].nFixHRevrs ==  0 &&
 
4621
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
4622
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 ) {
 
4623
                iat_DB_O[num_DB_O ++] = iat;
 
4624
            }
 
4625
        }
 
4626
        for ( i = 0; num_DB_O && i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
4627
            iat = nCanon2AtnoRevrs[i];
 
4628
            if ( /* in restored atom O: charge=-1, no H, has no double bond, endpoint */
 
4629
                 at2[iat].charge == -1 && !at2[iat].num_H &&
 
4630
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 && !pVA[iat].cMetal &&
 
4631
                 pVA[iat].cNumValenceElectrons == 5 &&
 
4632
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4633
                 pBNS->edge[e].flow &&
 
4634
                 !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) &&
 
4635
                 pVA[iN2=at2[iat].neighbor[0]].cNumValenceElectrons == 5 &&
 
4636
                 at2[iat].bond_type[0] == BOND_TYPE_DOUBLE &&
 
4637
                 at2[iN2].charge == 1 && at2[iN2].valence == 2 && at2[iN2].chem_bonds_valence == 4 &&
 
4638
                 pVA[iC=at2[iN2].neighbor[at2[iN2].neighbor[0]==iN2]].cNumValenceElectrons == 4 ) {
 
4639
                
 
4640
                if ( ret = AddToEdgeList( &CurrEdges, e, INC_ADD_EDGE ) ) {
 
4641
                    goto exit_function;
 
4642
                }
 
4643
            }
 
4644
        }
 
4645
        if ( num_try = inchi_min( CurrEdges.num_edges, num_DB_O ) ) {
 
4646
            /* detected; attempt to fix */
 
4647
            SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4648
            RemoveForbiddenEdgeMask( pBNS, &CurrEdges, forbidden_edge_mask  );
 
4649
            delta = 1;
 
4650
            for ( i = 0; i < num_DB_O && cur_success < num_try; i ++ ) {
 
4651
                iat = iat_DB_O[i];
 
4652
 
 
4653
                peDB_O_Minus = pBNS->edge + (pVA[iat].nCMinusGroupEdge-1);
 
4654
                pe           = pBNS->edge + pBNS->vert[iat].iedge[0];
 
4655
                if ( !pe->flow )
 
4656
                    continue;
 
4657
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
4658
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
4659
 
 
4660
                pe->forbidden            |= forbidden_edge_mask;
 
4661
                peDB_O_Minus->forbidden  &= forbidden_edge_mask_inv;
 
4662
 
 
4663
                pe->flow -= delta;
 
4664
                pv1->st_edge.flow -= delta;
 
4665
                pv2->st_edge.flow -= delta;
 
4666
                pBNS->tot_st_flow -= 2*delta;
 
4667
 
 
4668
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
4669
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
4670
 
 
4671
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
4672
                                  vPathEnd == v2 && vPathStart == v1) && nDeltaCharge == 0 ) {
 
4673
                    /* Added (-) charge to =O and removed from =N(-) => nDeltaCharge == 0 */
 
4674
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
4675
                    if ( ret > 0 ) {
 
4676
                        nNumRunBNS ++;
 
4677
                        cur_success ++; /* 22 */
 
4678
                    }
 
4679
                } else {
 
4680
                    pe->flow += delta;
 
4681
                    pv1->st_edge.flow += delta;
 
4682
                    pv2->st_edge.flow += delta;
 
4683
                    pBNS->tot_st_flow += 2*delta;
 
4684
                }
 
4685
                INCHI_HEAPCHK
 
4686
                pe->forbidden            &= forbidden_edge_mask_inv;
 
4687
                peDB_O_Minus->forbidden  |= forbidden_edge_mask;
 
4688
            }
 
4689
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask  );
 
4690
        }
 
4691
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4692
        if ( cur_success ) {
 
4693
            tot_succes += cur_success;
 
4694
            /* recalculate InChI from the structure */
 
4695
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
4696
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
4697
                goto exit_function;
 
4698
            }
 
4699
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
4700
                goto exit_function;
 
4701
            }
 
4702
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
4703
                goto exit_function;  /* no fixed-H found */
 
4704
            }
 
4705
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
4706
                goto exit_function;
 
4707
            }
 
4708
            if ( !pc2i->bHasDifference ) {
 
4709
                goto exit_function; /* nothing to do */
 
4710
            }
 
4711
        }
 
4712
    }
 
4713
    if ( pc2i->len_c2at && pc2i->nNumTgInChI == 1 ) {
 
4714
        /*------------------------------------------------------------------*/
 
4715
        /* case 23: -NO2 are to be tautomeric but they are not AND          */
 
4716
        /*          InChI has a SINGLE tautomeric group                     */
 
4717
        /*                                                                  */
 
4718
        /*                   (-)O                   (-)O                    */
 
4719
        /* Solution: convert     \                      \                   */
 
4720
        /*                        N-X=...-Z(-)   =>      N(+)=X- ...=Z      */
 
4721
        /*                      //                      /                   */
 
4722
        /*                     O                    (-)O                    */
 
4723
        /*                                                                  */
 
4724
        /*                     O                       O                    */
 
4725
        /*        or            \\                      \\                  */
 
4726
        /*                        N-X=...-Z(-)    =>      N=X-  ...=Z       */
 
4727
        /*                      //                       /                  */
 
4728
        /*                     O                     (-)O                   */
 
4729
        /*                                                                  */
 
4730
        /*                                                                  */
 
4731
        /*  (a) move (-) from other tautomeric atom to O in O=N-X           */
 
4732
        /*          or   from other atom that has to be tautomeric          */
 
4733
        /*               but is not                                         */
 
4734
        /*  (b) create (+) [ion pair creation] on N as in                   */
 
4735
        /*                                                                  */
 
4736
        /*       OH             OH                                          */
 
4737
        /*      /              /                                            */
 
4738
        /*  -C=N     =>  =C-N(+)                                            */
 
4739
        /*     \\             \\                                            */
 
4740
        /*       O              O                                           */
 
4741
        /*                                                                  */
 
4742
        /*------------------------------------------------------------------*/
 
4743
        int num_DB_O = 0, iat;
 
4744
        short iat_DB_O[MAX_DIFF_FIXH], iat_NO2[MAX_DIFF_FIXH];
 
4745
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
4746
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
4747
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
4748
        /*
 
4749
        inp_ATOM *atfMobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
4750
                             pStruct->pOne_norm_data[1]->at_fixed_bonds)?
 
4751
                             pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL;
 
4752
        */
 
4753
        S_CHAR   *num_Fixed_H_Revrs = pStruct->pOneINChI[0]->nNum_H_fixed? pStruct->pOneINChI[0]->nNum_H_fixed : NULL;
 
4754
        S_CHAR   *pnMobHRevrs = (pStruct->pOneINChI[1] && pStruct->pOneINChI[1]->nNum_H)?
 
4755
                               pStruct->pOneINChI[1]->nNum_H : 
 
4756
                            (pStruct->pOneINChI[0] && pStruct->pOneINChI[0]->nNum_H)?
 
4757
                               pStruct->pOneINChI[0]->nNum_H : NULL;
 
4758
        int iN, one_success;
 
4759
        BNS_EDGE *peDB_O_Minus;
 
4760
        int neigh, nNumO, nNumOthers;
 
4761
#define CHG_SET_NOOH         0
 
4762
#define CHG_SET_WRONG_TAUT   1
 
4763
#define CHG_SET_TAUT         2
 
4764
#define CHG_LAST_SET         2 /* the last index in trying */
 
4765
#define CHG_SET_O_FIXED      3
 
4766
#define CHG_SET_NUM          4
 
4767
        EDGE_LIST ChangeableEdges[CHG_SET_NUM];
 
4768
        memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
 
4769
        /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
 
4770
        /*
 
4771
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
4772
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
4773
        */
 
4774
        CurrEdges.num_edges = 0; /* clear current edge list */
 
4775
        cur_success = 0;
 
4776
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
4777
            iat = pc2i->c2at[i].atomNumber;
 
4778
            if ( /* orig. InChI info: taut in orig. InChI =O located in -NO2 that is not taut in Reconstructed InChI */
 
4779
                 num_DB_O < MAX_DIFF_FIXH &&
 
4780
                 pc2i->c2at[i].nValElectr == 6 /* O, S, Se, Te */ &&
 
4781
                 (pc2i->c2at[i].endptInChI /*|| pc2i->c2at[i].nMobHInChI*/) &&
 
4782
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
4783
                 pc2i->c2at[i].nFixHInChI == 0 && /*pc2i->c2at[i].nMobHInChI ==  1 &&*/
 
4784
                 /* reversed structure info: */
 
4785
                 !(pc2i->c2at[i].endptRevrs /*|| pc2i->c2at[i].nMobHRevrs*/) &&
 
4786
                 pc2i->c2at[i].nFixHRevrs ==  0 &&
 
4787
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
4788
                 at2[iat].valence == 1 && at2[iat].chem_bonds_valence == 2 &&
 
4789
                 /* find whether it belongs to NO2 */
 
4790
                 pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons == 5 &&
 
4791
                 at2[iN].valence == 3 && (at2[iN].charge == 0 || at2[iN].charge == 1) &&
 
4792
                 at2[iN].chem_bonds_valence == 5 - at2[iN].charge ) {
 
4793
                /* find the second O */
 
4794
                nNumO = nNumOthers = 0;
 
4795
                for ( k = 0; k < at2[iN].valence; k ++ ) {
 
4796
                    neigh = at2[iN].neighbor[k];
 
4797
                    if ( neigh == iat ) {
 
4798
                        continue;
 
4799
                    }
 
4800
                    if ( pVA[neigh].cNumValenceElectrons == 6 &&
 
4801
                         pStruct->endpoint[neigh] &&
 
4802
                         !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[neigh].endpoint) &&
 
4803
                         at2[neigh].valence == 1 && at2[neigh].num_H == 0 &&
 
4804
                         at2[neigh].radical == 0 && (at2[neigh].charge == 0 || at2[neigh].charge == -1) &&
 
4805
                         at2[neigh].chem_bonds_valence - at2[neigh].charge == 2) {
 
4806
                        nNumO ++;
 
4807
                    } else
 
4808
                    if ( at2[iN].bond_type[k] == BOND_TYPE_SINGLE &&
 
4809
                         at2[neigh].valence > 1 &&
 
4810
                         at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
 
4811
                        nNumOthers ++;
 
4812
                    }
 
4813
                }
 
4814
                if ( nNumO != 1 || nNumOthers != 1 ) {
 
4815
                    continue;
 
4816
                }
 
4817
                for ( k = 0; k < num_DB_O; k ++ ) {
 
4818
                    if ( iat_NO2[k] == iN ) {
 
4819
                        break;
 
4820
                    }
 
4821
                }
 
4822
                if ( k == num_DB_O ) {
 
4823
                    iat_NO2[num_DB_O]     = iN;
 
4824
                    iat_DB_O[num_DB_O ++] = iat;
 
4825
                }
 
4826
                /* save the edge to avoid interference */
 
4827
                if ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) ) {
 
4828
                    goto exit_case_23;
 
4829
                }
 
4830
            }
 
4831
        }
 
4832
        if ( num_DB_O ) {
 
4833
            /* 1. search for =N(=O)-OH; assume =N(+)(-O(-))(-OH) does not happen */
 
4834
            for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
4835
                /* find O=N(V) */
 
4836
                iat = nCanon2AtnoRevrs[i];
 
4837
                if ( !pStruct->endpoint[i] || pVA[i].cNumValenceElectrons != 6 ||
 
4838
                     at2[iat].valence != 1 || at2[iat].charge ||
 
4839
                     0 > (e = pVA[iat].nCMinusGroupEdge-1) ||
 
4840
                     at2[iat].num_H + at2[iat].chem_bonds_valence != 2 ||
 
4841
                     pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons != 5 ||
 
4842
                     0 > (e = pVA[iN].nCPlusGroupEdge-1) ||
 
4843
                     pBNS->edge[e].forbidden || !pBNS->edge[e].flow ||
 
4844
                     at2[iN].charge || at2[iN].valence != 3 || at2[iN].chem_bonds_valence != 5) {
 
4845
                    continue;
 
4846
                }
 
4847
                /* find the second O, -OH */
 
4848
                nNumO = nNumOthers = 0;
 
4849
                for ( k = 0; k < at2[iN].valence; k ++ ) {
 
4850
                    neigh = at2[iN].neighbor[k];
 
4851
                    if ( neigh == iat ) {
 
4852
                        continue;
 
4853
                    }
 
4854
                    if ( pVA[neigh].cNumValenceElectrons == 6 &&
 
4855
                         pStruct->endpoint[neigh] &&
 
4856
                         at2[neigh].valence == 1 && at2[neigh].num_H == 1 &&
 
4857
                         at2[neigh].radical == 0 && (at2[neigh].charge == 0 ) ) {
 
4858
                        nNumO ++;
 
4859
                    } else
 
4860
                    if ( at2[iN].bond_type[k] == BOND_TYPE_DOUBLE &&
 
4861
                         at2[neigh].valence >= 2 &&
 
4862
                         at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
 
4863
                        nNumOthers ++;
 
4864
                    }
 
4865
                }
 
4866
                if ( nNumO != 1 || nNumOthers != 1 ) {
 
4867
                    continue;
 
4868
                }
 
4869
                /* save edges to be changed */
 
4870
                if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NOOH], e, INC_ADD_EDGE )) ||
 
4871
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ))) {
 
4872
                    goto exit_case_23;
 
4873
                }
 
4874
                if ( NO_VERTEX != (j = GetChargeFlowerUpperEdge( pBNS, pVA, e )) &&
 
4875
                     (( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NOOH], j, INC_ADD_EDGE ) ) ||
 
4876
                      ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) ))) {
 
4877
                    goto exit_case_23;
 
4878
                }
 
4879
            }
 
4880
            /* 2. search for (-) atoms that are tautomeric but should not be  */
 
4881
            /*           or that got H from Normalization but they shouldn't  */
 
4882
            for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
4883
                iat = nCanon2AtnoRevrs[i];
 
4884
                if ( at2[iat].charge == -1 &&
 
4885
                     !pStruct->endpoint[i] &&
 
4886
                     (at_Mobile_H_Revrs && 
 
4887
                     (at_Mobile_H_Revrs[i].endpoint || at2[iat].num_H < at_Mobile_H_Revrs[i].num_H )) )  {
 
4888
 
 
4889
                    if ( 0 <= (e = pVA[iat].nCMinusGroupEdge-1) &&
 
4890
                         0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) &&
 
4891
                         !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
4892
                         (
 
4893
                          ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT], e, INC_ADD_EDGE ) ) ||
 
4894
                          ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) )
 
4895
                         ) ) {
 
4896
                        goto exit_case_23;
 
4897
                    }
 
4898
                } else
 
4899
                /* negatively charged atom in Reconstructed structure got H(+) from Normalization */
 
4900
                /* and is not tautomeric; in the original structure it is tautomeric */    
 
4901
                if ( at2[iat].charge == -1 &&
 
4902
                     pStruct->endpoint[i] &&
 
4903
                     !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) &&
 
4904
                     (num_Fixed_H_Revrs && num_Fixed_H_Revrs[i] == -1) &&
 
4905
                     (pnMobHRevrs       && pnMobHRevrs[i]       ==  1) && 
 
4906
                     pStruct->fixed_H[i] == 0 ) {
 
4907
 
 
4908
                    if ( 0 <= (e = pVA[iat].nCMinusGroupEdge-1) &&
 
4909
                         0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e ) &&
 
4910
                         !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
4911
                         (
 
4912
                          ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_WRONG_TAUT], e, INC_ADD_EDGE ) ) ||
 
4913
                          ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e, INC_ADD_EDGE ) )
 
4914
                         ) ) {
 
4915
                        goto exit_case_23;
 
4916
                    }
 
4917
                }
 
4918
            }
 
4919
            /* 3. Search for (-) atoms that are tautomeric */
 
4920
            for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
4921
                iat = nCanon2AtnoRevrs[i];
 
4922
                if ( pStruct->endpoint[i] &&
 
4923
                     (at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) &&
 
4924
                     at2[iat].charge == -1
 
4925
                    /*&& pVA[i].cNumValenceElectrons == 6*/ ) {
 
4926
                    if ( 0 <= (e = pVA[iat].nCMinusGroupEdge-1) &&
 
4927
                         !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
4928
                         0 > FindInEdgeList( &ChangeableEdges[CHG_SET_O_FIXED], e )  &&
 
4929
                         ( ret = AddToEdgeList( &ChangeableEdges[CHG_SET_TAUT], e, INC_ADD_EDGE ) ) ) {
 
4930
                        goto exit_case_23;
 
4931
                    }
 
4932
                }
 
4933
            }
 
4934
            /* ------- finally, try to move charges from O=N --------------*/
 
4935
            for ( i = 0; i < num_DB_O; i ++ ) {
 
4936
                int nDeltaChargeExpected;
 
4937
                one_success = 0;
 
4938
                delta = 1;
 
4939
                iat = iat_DB_O[i];
 
4940
                peDB_O_Minus = pBNS->edge + (pVA[iat].nCMinusGroupEdge-1);
 
4941
                pe =           pBNS->edge + pBNS->vert[iat].iedge[0];
 
4942
                
 
4943
                if ( !pe->flow )
 
4944
                    continue;
 
4945
                pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
4946
                pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
4947
 
 
4948
                pe->forbidden            |= forbidden_edge_mask;
 
4949
 
 
4950
                pe->flow -= delta;
 
4951
                pv1->st_edge.flow -= delta;
 
4952
                pv2->st_edge.flow -= delta;
 
4953
                pBNS->tot_st_flow -= 2*delta;
 
4954
 
 
4955
                for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
 
4956
                    if ( !ChangeableEdges[k].num_edges ) {
 
4957
                        continue;
 
4958
                    }
 
4959
                    nDeltaChargeExpected = (k==CHG_SET_NOOH)? 2 : 0;
 
4960
                    
 
4961
                    SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4962
                    RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask  );
 
4963
                    /* allow (-) charge to move to N=O */
 
4964
                    peDB_O_Minus->forbidden  &= forbidden_edge_mask_inv;
 
4965
                    
 
4966
                    ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
4967
                                          &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
4968
 
 
4969
                    if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
4970
                                      vPathEnd == v2 && vPathStart == v1) &&
 
4971
                                      nDeltaCharge == nDeltaChargeExpected ) {
 
4972
                        /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
 
4973
                        ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
4974
                        if ( ret > 0 ) {
 
4975
                            nNumRunBNS ++;
 
4976
                            one_success ++; /* 23 */
 
4977
                        }
 
4978
                    }
 
4979
                    INCHI_HEAPCHK
 
4980
                }
 
4981
                cur_success += one_success;
 
4982
                
 
4983
                RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
4984
                pe->forbidden            &= forbidden_edge_mask_inv;
 
4985
 
 
4986
                if ( !one_success ) {
 
4987
                    pe->flow += delta;
 
4988
                    pv1->st_edge.flow += delta;
 
4989
                    pv2->st_edge.flow += delta;
 
4990
                    pBNS->tot_st_flow += 2*delta;
 
4991
                }
 
4992
            }
 
4993
        }
 
4994
exit_case_23:
 
4995
        for ( i = 0; i < CHG_SET_NUM; i ++ ) {
 
4996
            AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
 
4997
        }
 
4998
 
 
4999
        CurrEdges.num_edges = 0; /* clear current edge list */
 
5000
        if ( cur_success ) {
 
5001
            tot_succes += cur_success;
 
5002
            /* recalculate InChI from the structure */
 
5003
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
5004
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
5005
                goto exit_function;
 
5006
            }
 
5007
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
5008
                goto exit_function;
 
5009
            }
 
5010
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
5011
                goto exit_function;  /* no fixed-H found */
 
5012
            }
 
5013
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
5014
                goto exit_function;
 
5015
            }
 
5016
            if ( !pc2i->bHasDifference ) {
 
5017
                goto exit_function; /* nothing to do */
 
5018
            }
 
5019
        }
 
5020
#undef CHG_SET_NOOH
 
5021
#undef CHG_SET_WRONG_TAUT
 
5022
#undef CHG_SET_TAUT
 
5023
#undef CHG_LAST_SET
 
5024
#undef CHG_SET_O_FIXED
 
5025
#undef CHG_SET_NUM
 
5026
    }
 
5027
 
 
5028
    if ( pc2i->len_c2at && pc2i->nNumTgInChI == 1 ) {
 
5029
        /*------------------------------------------------------------------*/
 
5030
        /* case 24: InChI norm. -N(-)-N(+)(IV) => -N=N(V) prevents tauto-   */
 
5031
        /*          merism on -N(-)- in case of ADP                         */
 
5032
        /*                                                                  */
 
5033
        /* Solution: convert       N(V)=N-   ...=X    -> N(IV)(+)-N=...-X(-)*/
 
5034
        /*                     N(IV)(+)-N(-)-...=X                          */
 
5035
        /*                                                                  */
 
5036
        /*      Orig InChI            taut      taut, 1 t-group only(ADP?)  */
 
5037
        /*   Reconstructed struct   non-taut    possibly not taut           */
 
5038
        /*                                                                  */
 
5039
        /*   Details: 1a. store next to N(V) (+)edge its flower edge        */
 
5040
        /*            1b. store next to N(-) edge NO_VERTEX                 */
 
5041
        /*            2.  Release (-) edges of other missing endpoints or   */
 
5042
        /*                all endpoints if no other is missing              */
 
5043
        /*            3.  Decrement flow on (+) edge                        */
 
5044
        /*                if flower edge is stored then expect DeltaCharge=2*/
 
5045
        /*                otherwise DeltaCharge = 0                         */
 
5046
        /*------------------------------------------------------------------*/
 
5047
        int iat;
 
5048
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
5049
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
5050
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
5051
        inp_ATOM *atf  = (pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->at_fixed_bonds)?
 
5052
                            pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL;
 
5053
        int iN, one_success;
 
5054
        EdgeIndex  ef, e1;
 
5055
        BNS_EDGE *pef;
 
5056
#define CHG_SET_MISSED_TAUT   0
 
5057
#define CHG_SET_OTHER_TAUT_O  1
 
5058
#define CHG_SET_OTHER_TAUT_N  2
 
5059
#define CHG_LAST_SET          2 /* the last index in trying */
 
5060
#define CHG_SET_NN            3
 
5061
#define CHG_SET_AVOID         4
 
5062
#define CHG_SET_NUM           5
 
5063
        EDGE_LIST ChangeableEdges[CHG_SET_NUM];
 
5064
        memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
 
5065
        /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
 
5066
        /*
 
5067
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
5068
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
5069
        */
 
5070
        CurrEdges.num_edges = 0; /* clear current edge list */
 
5071
        cur_success = 0;
 
5072
        for ( i = 0; i < pc2i->len_c2at; i ++ ) {
 
5073
            iat = pc2i->c2at[i].atomNumber;
 
5074
            if ( /* orig. InChI info: -N=N(V)    */
 
5075
                 pc2i->c2at[i].nValElectr == 5 /* N or P */ &&
 
5076
                 (pc2i->c2at[i].endptInChI /* only N */) &&
 
5077
                 (e1=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e1].forbidden &&
 
5078
                 pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
 
5079
                 /* reversed structure info: */
 
5080
                 !pc2i->c2at[i].endptRevrs &&
 
5081
                 pc2i->c2at[i].nFixHRevrs ==  0 &&
 
5082
                 pc2i->c2at[i].nAtChargeRevrs == 0 && !at2[iat].num_H &&
 
5083
                 at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 3 &&
 
5084
                 /* find whether -N= has =N(V) neighbor; Note: operator comma: (A,B) returns B */
 
5085
                 (iN = at2[iat].neighbor[at2[iat].bond_type[0] != BOND_TYPE_DOUBLE],
 
5086
                  pVA[iN].cNumValenceElectrons == 5) &&
 
5087
                 at2[iN].chem_bonds_valence == 5  && 
 
5088
                 at2[iN].charge == 0 && !at2[iN].num_H && !at2[iN].radical &&
 
5089
                 0 <= (e=pVA[iN].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
5090
                 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e )) {
 
5091
 
 
5092
                ef = GetChargeFlowerUpperEdge( pBNS, pVA, e ); /* == NO_VERTEX if N(V) has 4 bonds */
 
5093
                if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], e, INC_ADD_EDGE ))    ||
 
5094
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], ef, INC_ADD_EDGE ))   ||
 
5095
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], 1, INC_ADD_EDGE ))    || /* expected nDeltaCharge */
 
5096
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1, INC_ADD_EDGE )) ||
 
5097
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )) ||
 
5098
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], ef, INC_ADD_EDGE ))) {
 
5099
                    goto exit_case_24;
 
5100
                }
 
5101
                /* mark -N= so that (-) will not be moved to it */
 
5102
                if ( 0 <= (e = pVA[iat].nCMinusGroupEdge) && !pBNS->edge[e].forbidden &&
 
5103
                     0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) &&
 
5104
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ))) {
 
5105
                    goto exit_case_24;
 
5106
                }
 
5107
            } else
 
5108
            if ( /* orig. InChI info: -N(-)N(IV)(+)    */
 
5109
                 atf &&
 
5110
                 pc2i->c2at[i].nValElectr == 5 /* N or P */ &&
 
5111
                 pc2i->c2at[i].endptInChI /* only N */ &&
 
5112
                 (e=pVA[iat].nCMinusGroupEdge-1) >= 0 && !pBNS->edge[e].forbidden &&
 
5113
                 pc2i->c2at[i].nFixHInChI == 0 && pc2i->c2at[i].nMobHInChI == 0 &&
 
5114
                 /* reversed structure info: */
 
5115
                 !pc2i->c2at[i].endptRevrs &&
 
5116
                 pc2i->c2at[i].nFixHRevrs ==  0 &&
 
5117
                 pc2i->c2at[i].nAtChargeRevrs == -1 && !at2[iat].num_H &&
 
5118
                 at2[iat].valence == 2 && at2[iat].chem_bonds_valence == 2 &&
 
5119
                 atf[iat].valence == 2 && atf[iat].chem_bonds_valence == 3 && 
 
5120
                 /* find whether -N= has =N(V) neighbor; Note: operator comma: (A,B) returns B */
 
5121
                 (iN=atf[iat].neighbor[atf[iat].bond_type[0] != BOND_TYPE_DOUBLE],
 
5122
                  pVA[iN].cNumValenceElectrons == 5) &&
 
5123
                 at2[iN].charge == 1 && /* double bond neighbor */
 
5124
                 at2[iN].chem_bonds_valence == 4 &&
 
5125
                 atf[iN].charge == 0 &&
 
5126
                 atf[iN].chem_bonds_valence == 5  &&  /* InChI normalization created N(V)=N- out of N(IV)(+)-N(-)- */
 
5127
                 !at2[iN].num_H && !at2[iN].radical &&
 
5128
                 0 <= (e=pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e].forbidden && pBNS->edge[e].flow &&
 
5129
                 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) ) {
 
5130
                /* save (-) edge */
 
5131
                if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], e, INC_ADD_EDGE ))    ||
 
5132
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], NO_VERTEX, INC_ADD_EDGE ))   ||
 
5133
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NN], 1, INC_ADD_EDGE ))   || /* expected nDeltaCharge */
 
5134
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE ))) {
 
5135
                    goto exit_case_24;
 
5136
                }
 
5137
            }
 
5138
        }
 
5139
        if ( !ChangeableEdges[CHG_SET_NN].num_edges ) {
 
5140
            goto  exit_case_24;
 
5141
        }
 
5142
        /* Collect all relevant tautomeric atoms */
 
5143
        for ( i = 0; i < pStruct->num_atoms; i ++ ) { /* i = canonical number - 1 */
 
5144
            if ( !pStruct->endpoint[i] ) {
 
5145
                continue;
 
5146
            }
 
5147
            iat = nCanon2AtnoRevrs[i];
 
5148
            if ( at2[iat].charge || at2[iat].radical || at2[iat].valence == at2[iat].chem_bonds_valence ) {
 
5149
                continue; /* cannot be an acceptor of (-) */
 
5150
            }
 
5151
            if ( 0 > (e=pVA[iat].nCMinusGroupEdge-1) || pBNS->edge[e].forbidden || pBNS->edge[e].flow ) {
 
5152
                continue;
 
5153
            }
 
5154
            if ( 0 <= FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) ) {
 
5155
                continue; /* has already been used */
 
5156
            }
 
5157
            /* missing endpoint */ 
 
5158
            if ( !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[iat].endpoint) ) {
 
5159
                if ( 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && (
 
5160
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT], e, INC_ADD_EDGE ))   ||
 
5161
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )))) {
 
5162
                    goto exit_case_24;
 
5163
                }
 
5164
            } else
 
5165
            /* endpoint O */
 
5166
            if ( pVA[iat].cNumValenceElectrons == 6 ) {
 
5167
                 if ( 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && (
 
5168
                      (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_O], e, INC_ADD_EDGE ))   ||
 
5169
                      (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )))){
 
5170
                    goto exit_case_24;
 
5171
                 }
 
5172
            } else
 
5173
            /* endpoint N */
 
5174
            if ( pVA[iat].cNumValenceElectrons == 5 ) {
 
5175
                if ( 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) && ( 
 
5176
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_N], e, INC_ADD_EDGE ))   ||
 
5177
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )))){
 
5178
                    goto exit_case_24;
 
5179
                }
 
5180
            }
 
5181
        }
 
5182
        /* ------- finally, try to move charges from -N(-)-N(+) or to N(V) --------------*/
 
5183
        for ( i = 0; i < ChangeableEdges[CHG_SET_NN].num_edges; i += 3 ) {
 
5184
            int nDeltaChargeExpected;
 
5185
            one_success = 0;
 
5186
            delta = 1;
 
5187
            pe  = pBNS->edge + ChangeableEdges[CHG_SET_NN].pnEdges[i];
 
5188
            pef = (NO_VERTEX != ChangeableEdges[CHG_SET_NN].pnEdges[i+1])?
 
5189
                  pBNS->edge + ChangeableEdges[CHG_SET_NN].pnEdges[i+1] : NULL;
 
5190
            nDeltaChargeExpected = ChangeableEdges[CHG_SET_NN].pnEdges[i+2];
 
5191
 
 
5192
            if ( !pe->flow )
 
5193
                continue;
 
5194
            pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
5195
            pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
5196
 
 
5197
            pe->flow -= delta;
 
5198
            pv1->st_edge.flow -= delta;
 
5199
            pv2->st_edge.flow -= delta;
 
5200
            pBNS->tot_st_flow -= 2*delta;
 
5201
 
 
5202
            for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
 
5203
                if ( !ChangeableEdges[k].num_edges ) {
 
5204
                    continue;
 
5205
                }
 
5206
                SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
5207
                RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask  );
 
5208
                /* allow change of N(V) flower edge */
 
5209
                if ( pef ) {
 
5210
                    pef->forbidden  &= forbidden_edge_mask_inv;
 
5211
                }
 
5212
                
 
5213
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
5214
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
5215
 
 
5216
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
5217
                                  vPathEnd == v2 && vPathStart == v1) &&
 
5218
                                  nDeltaCharge == nDeltaChargeExpected ) {
 
5219
                    /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
 
5220
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
5221
                    if ( ret > 0 ) {
 
5222
                        nNumRunBNS ++;
 
5223
                        one_success ++; /* 24 */
 
5224
                    }
 
5225
                }
 
5226
                INCHI_HEAPCHK
 
5227
            }
 
5228
            cur_success += one_success;
 
5229
            
 
5230
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
5231
 
 
5232
            if ( !one_success ) {
 
5233
                pe->flow += delta;
 
5234
                pv1->st_edge.flow += delta;
 
5235
                pv2->st_edge.flow += delta;
 
5236
                pBNS->tot_st_flow += 2*delta;
 
5237
            }
 
5238
        }
 
5239
exit_case_24:
 
5240
        for ( i = 0; i < CHG_SET_NUM; i ++ ) {
 
5241
            AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
 
5242
        }
 
5243
 
 
5244
        CurrEdges.num_edges = 0; /* clear current edge list */
 
5245
        if ( cur_success ) {
 
5246
            tot_succes += cur_success;
 
5247
            /* recalculate InChI from the structure */
 
5248
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
5249
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
5250
                goto exit_function;
 
5251
            }
 
5252
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
5253
                goto exit_function;
 
5254
            }
 
5255
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
5256
                goto exit_function;  /* no fixed-H found */
 
5257
            }
 
5258
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
5259
                goto exit_function;
 
5260
            }
 
5261
            if ( !pc2i->bHasDifference ) {
 
5262
                goto exit_function; /* nothing to do */
 
5263
            }
 
5264
        }
 
5265
#undef CHG_SET_NN
 
5266
#undef CHG_SET_MISSED_TAUT
 
5267
#undef CHG_SET_OTHER_TAUT_O
 
5268
#undef CHG_SET_OTHER_TAUT_N
 
5269
#undef CHG_LAST_SET
 
5270
#undef CHG_SET_AVOID
 
5271
#undef CHG_SET_NUM
 
5272
    }
 
5273
 
 
5274
    /* pStruct->nNumRemovedProtonsMobHInChI == pc2i->nNumRemHInChI */
 
5275
 
 
5276
    if ( pc2i->len_c2at && pc2i->nNumTgInChI == 1 &&
 
5277
         pc2i->nNumRemHRevrs > pc2i->nNumRemHInChI && 0 > pc2i->nNumRemHInChI &&
 
5278
         (pc2i->nNumEndpRevrs < pc2i->nNumEndpInChI ||
 
5279
          pc2i->nNumTgRevrs > pc2i->nNumTgInChI ) ) {
 
5280
        /*------------------------------------------------------------------*/
 
5281
        /* case 25: Restored InChI does not have 2 or more added protons    */
 
5282
        /*                         possibly taut. endpoints are missing     */
 
5283
        /*                         has -N(-O(-))-O(-) group(s)              */
 
5284
        /*          Original InChI has only one t-group                     */
 
5285
        /*                                                                  */
 
5286
        /* Solution: convert       -N(-O(-))-O(-) -> -N(+)(=O)-O(-)         */
 
5287
        /*                         and direct 2(-) to the missing taut atoms*/
 
5288
        /*           at first attempt try to move (-) to N only             */
 
5289
        /*                                                                  */
 
5290
        /*------------------------------------------------------------------*/
 
5291
        int iat;
 
5292
        AT_NUMB  *nCanon2AtnoRevrs = pStruct->nCanon2Atno[0];
 
5293
        AT_NUMB  *nAtno2CanonRevrs = pStruct->nAtno2Canon[0];
 
5294
        inp_ATOM *at_Mobile_H_Revrs = (pStruct->pOne_norm_data[1] &&
 
5295
                             pStruct->pOne_norm_data[1]->at)? pStruct->pOne_norm_data[1]->at : NULL;
 
5296
        /*
 
5297
        inp_ATOM *atf  = (pStruct->pOne_norm_data[1] && pStruct->pOne_norm_data[1]->at_fixed_bonds)?
 
5298
                            pStruct->pOne_norm_data[1]->at_fixed_bonds : NULL;
 
5299
        */
 
5300
        int iN, neigh, one_success;
 
5301
        EdgeIndex  e1, bFirst;
 
5302
        BNS_EDGE *pef;
 
5303
#define CHG_SET_MISSED_TAUT_1   0
 
5304
#define CHG_SET_MISSED_TAUT_ALL 1
 
5305
#define CHG_SET_OTHER_TAUT_1    2
 
5306
#define CHG_SET_OTHER_TAUT_ALL  3
 
5307
#define CHG_LAST_SET            3 /* the last index in trying */
 
5308
#define CHG_SET_NO_IN_NO2M2     4
 
5309
#define CHG_SET_AVOID           5
 
5310
#define CHG_SET_NUM             6
 
5311
        EDGE_LIST ChangeableEdges[CHG_SET_NUM];
 
5312
        memset( ChangeableEdges, 0, sizeof(ChangeableEdges) );
 
5313
        /* equivalent to AllocEdgeList( &EdgeList, EDGE_LIST_CLEAR ); */
 
5314
        /*
 
5315
        S_CHAR   *nMobHInChI = pInChI[1] && pInChI[1]->nNum_H? pInChI[1]->nNum_H :
 
5316
                               pInChI[0] && pInChI[0]->nNum_H? pInChI[0]->nNum_H : 0;
 
5317
        */
 
5318
        CurrEdges.num_edges = 0; /* clear current edge list */
 
5319
        cur_success = 0;
 
5320
        /* find all -N(-O(-))-O(-) */
 
5321
        for ( i = 0; i < pStruct->num_atoms; i ++ ) {
 
5322
            iat = nCanon2AtnoRevrs[i];
 
5323
            if ( pStruct->endpoint[i] ) {
 
5324
                if ( 0 > (e=pVA[iat].nCMinusGroupEdge-1) || pBNS->edge[e].forbidden ||
 
5325
                     0 <= FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) ) {
 
5326
                    continue;
 
5327
                }
 
5328
                bFirst = ( pVA[iat].cNumValenceElectrons == 5 && pc2i->nNumTgInChI == 1 ||
 
5329
                           pVA[iat].cNumValenceElectrons == 6 && pc2i->nNumTgInChI != 1  );
 
5330
                    /* many or no t-groups -> try O only first */
 
5331
                    /* single t-group -> try only N first */
 
5332
                if ( !(at_Mobile_H_Revrs && at_Mobile_H_Revrs[i].endpoint) ) {
 
5333
                    /* missed tautomeric endpoint */
 
5334
                    if ( bFirst && 
 
5335
                         (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT_1], e, INC_ADD_EDGE ))) {
 
5336
                        goto exit_case_25;
 
5337
                    }
 
5338
                    if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_MISSED_TAUT_ALL], e, INC_ADD_EDGE )) {
 
5339
                        goto exit_case_25;
 
5340
                    }
 
5341
                }
 
5342
                if ( bFirst && 
 
5343
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_1], e, INC_ADD_EDGE ))) {
 
5344
                    goto exit_case_25;
 
5345
                }
 
5346
                if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_OTHER_TAUT_ALL], e, INC_ADD_EDGE )) {
 
5347
                    goto exit_case_25;
 
5348
                }
 
5349
                if (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )) {
 
5350
                    goto exit_case_25;
 
5351
                }
 
5352
            } else
 
5353
            if ( at2[iat].valence == 1 && at2[iat].charge == -1 &&
 
5354
                 pVA[iat].cNumValenceElectrons == 6 &&
 
5355
                 pVA[iN=at2[iat].neighbor[0]].cNumValenceElectrons == 5 && /* -O(-) */
 
5356
                 !pStruct->endpoint[nAtno2CanonRevrs[iN]] &&
 
5357
                 at2[iN].valence == 3 && at2[iN].chem_bonds_valence == 3 &&
 
5358
                 !at2[iN].charge && !at2[iN].radical && 
 
5359
                 0 <= (e=pVA[iN].nCPlusGroupEdge-1) && !pBNS->edge[e].forbidden &&
 
5360
                 pBNS->edge[e].flow && /* NPlus edge */
 
5361
                 0 <= (e1 = pVA[iat].nCMinusGroupEdge-1) && !pBNS->edge[e1].forbidden &&
 
5362
                 pBNS->edge[e1].flow &&  /* OMinus edge */
 
5363
                 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e ) &&
 
5364
                 0 > FindInEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1 )) {
 
5365
                /* found >N-O(-) */
 
5366
                int nNumO = 0, nNumOthers = 0;
 
5367
                for ( k = 0; k < at2[iN].valence; k ++ ) {
 
5368
                    neigh = at2[iN].neighbor[k];
 
5369
                    if ( neigh == iat ) {
 
5370
                        continue;
 
5371
                    }
 
5372
                    if ( pVA[neigh].cNumValenceElectrons == 6 &&
 
5373
                         !pStruct->endpoint[neigh] &&
 
5374
                         at2[neigh].valence == 1 && at2[neigh].num_H == 0 &&
 
5375
                         at2[neigh].radical == 0 && at2[neigh].charge == -1 &&
 
5376
                         at2[neigh].chem_bonds_valence == 1 ) {
 
5377
                        nNumO ++;
 
5378
                    } else
 
5379
                    if ( at2[iN].bond_type[k] == BOND_TYPE_SINGLE &&
 
5380
                         at2[neigh].valence > 1 &&
 
5381
                         at2[neigh].valence < at2[neigh].chem_bonds_valence ) {
 
5382
                        nNumOthers ++;
 
5383
                    }
 
5384
                }
 
5385
                if ( nNumO != 1 && nNumOthers != 1 ) {
 
5386
                    continue;
 
5387
                }
 
5388
                /* save charge edges: NPlus first, OMinus second */
 
5389
                if ( (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NO_IN_NO2M2], e, INC_ADD_EDGE )) ||
 
5390
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_NO_IN_NO2M2], e1, INC_ADD_EDGE ))   ||
 
5391
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e, INC_ADD_EDGE )) ||
 
5392
                     (ret = AddToEdgeList( &ChangeableEdges[CHG_SET_AVOID], e1, INC_ADD_EDGE ))) {
 
5393
                    goto exit_case_25;
 
5394
                }
 
5395
            }
 
5396
        }
 
5397
        if ( !ChangeableEdges[CHG_SET_NO_IN_NO2M2].num_edges ||
 
5398
             !ChangeableEdges[CHG_SET_OTHER_TAUT_ALL].num_edges ) {
 
5399
            goto exit_case_25;
 
5400
        }
 
5401
        /* ------- finally, try to move charges from -NO2(2-) or to tautomeric endpoints ----*/
 
5402
        for ( i = 0; i < ChangeableEdges[CHG_SET_NO_IN_NO2M2].num_edges; i += 2 ) {
 
5403
            int nDeltaChargeExpected = 3; 
 
5404
            /* change flow on O(-) to make it neutral; 3 new charges will be created:
 
5405
               N(+), and two (-) on InChI endpoints
 
5406
               alternatively, if we change flow on N to make N(+) then O(-) will
 
5407
               be nutralized (-1 charge) and two (-) charges on taut. endpoints will be
 
5408
               created (+2); the total change in this case would be (-1)+(+2) = +1
 
5409
            */
 
5410
            one_success = 0;
 
5411
            delta = 1;
 
5412
            pe  = pBNS->edge + ChangeableEdges[CHG_SET_NO_IN_NO2M2].pnEdges[i+1]; /* O(-) edge */
 
5413
            pef = pBNS->edge + ChangeableEdges[CHG_SET_NO_IN_NO2M2].pnEdges[i]; /* >N- (+) edge */
 
5414
 
 
5415
            if ( !pe->flow )
 
5416
                continue;
 
5417
            pv1 = pBNS->vert + (v1 = pe->neighbor1);
 
5418
            pv2 = pBNS->vert + (v2 = pe->neighbor12 ^ v1);
 
5419
 
 
5420
            pe->flow -= delta;
 
5421
            pv1->st_edge.flow -= delta;
 
5422
            pv2->st_edge.flow -= delta;
 
5423
            pBNS->tot_st_flow -= 2*delta;
 
5424
 
 
5425
            for ( k = 0; !one_success && k <= CHG_LAST_SET; k ++ ) {
 
5426
                if ( !ChangeableEdges[k].num_edges ) {
 
5427
                    continue;
 
5428
                }
 
5429
                SetForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
5430
                RemoveForbiddenEdgeMask( pBNS, &ChangeableEdges[k], forbidden_edge_mask  );
 
5431
                /* allow change of N(V) flower edge */
 
5432
                pef->forbidden  &= forbidden_edge_mask_inv;
 
5433
                
 
5434
                ret = RunBnsTestOnce( pBNS, pBD, pVA, &vPathStart, &vPathEnd, &nPathLen,
 
5435
                                      &nDeltaH, &nDeltaCharge, &nNumVisitedAtoms );
 
5436
 
 
5437
                if ( ret == 1 && (vPathEnd == v1 && vPathStart == v2 ||
 
5438
                                  vPathEnd == v2 && vPathStart == v1) &&
 
5439
                                  nDeltaCharge == nDeltaChargeExpected ) {
 
5440
                    /* Move (-) charge to =O and remove it an endpoint => nDeltaCharge == 0 */
 
5441
                    ret = RunBnsRestoreOnce( pBNS, pBD, pVA, pTCGroups );
 
5442
                    if ( ret > 0 ) {
 
5443
                        nNumRunBNS ++;
 
5444
                        one_success ++; /* 24 */
 
5445
                    }
 
5446
                }
 
5447
                INCHI_HEAPCHK
 
5448
            }
 
5449
            cur_success += one_success;
 
5450
            
 
5451
            RemoveForbiddenEdgeMask( pBNS, &AllChargeEdges, forbidden_edge_mask );
 
5452
 
 
5453
            if ( !one_success ) {
 
5454
                pe->flow += delta;
 
5455
                pv1->st_edge.flow += delta;
 
5456
                pv2->st_edge.flow += delta;
 
5457
                pBNS->tot_st_flow += 2*delta;
 
5458
            }
 
5459
        }
 
5460
exit_case_25:
 
5461
        for ( i = 0; i < CHG_SET_NUM; i ++ ) {
 
5462
            AllocEdgeList( &ChangeableEdges[i], EDGE_LIST_FREE );
 
5463
        }
 
5464
 
 
5465
        CurrEdges.num_edges = 0; /* clear current edge list */
 
5466
        if ( cur_success ) {
 
5467
            tot_succes += cur_success;
 
5468
            /* recalculate InChI from the structure */
 
5469
            if ( 0 > (ret = MakeOneInChIOutOfStrFromINChI2( ip, sd, pBNS, pStruct, at, at2, at3, pVA, pTCGroups,
 
5470
                                                            ppt_group_info, ppat_norm, ppat_prep ) ) ) {
 
5471
                goto exit_function;
 
5472
            }
 
5473
            if ( ret = FillOutExtraFixedHDataRestr( pStruct ) ) {
 
5474
                goto exit_function;
 
5475
            }
 
5476
            if ( !pInChI[0]->nNum_H_fixed && !pStruct->pOneINChI[0]->nNum_H_fixed ) {
 
5477
                goto exit_function;  /* no fixed-H found */
 
5478
            }
 
5479
            if ( ret = FillOutCMP2FHINCHI( pStruct, at2, pVA, pInChI, pc2i ) ) {
 
5480
                goto exit_function;
 
5481
            }
 
5482
            if ( !pc2i->bHasDifference ) {
 
5483
                goto exit_function; /* nothing to do */
 
5484
            }
 
5485
        }
 
5486
#undef CHG_SET_NN
 
5487
#undef CHG_SET_MISSED_TAUT
 
5488
#undef CHG_SET_OTHER_TAUT_O
 
5489
#undef CHG_SET_OTHER_TAUT_N
 
5490
#undef CHG_LAST_SET
 
5491
#undef CHG_SET_AVOID
 
5492
#undef CHG_SET_NUM
 
5493
    }
 
5494
 
 
5495
 
 
5496
exit_function:
 
5497
    AllocEdgeList( &AllChargeEdges, EDGE_LIST_FREE );
 
5498
    AllocEdgeList( &CurrEdges, EDGE_LIST_FREE );
 
5499
    AllocEdgeList( &NFlowerEdges, EDGE_LIST_FREE );
 
5500
    AllocEdgeList( &SFlowerEdges, EDGE_LIST_FREE );
 
5501
    AllocEdgeList( &OtherNFlowerEdges, EDGE_LIST_FREE );
 
5502
    AllocEdgeList( &FixedLargeRingStereoEdges, EDGE_LIST_FREE );
 
5503
    AllocEdgeList( &AllBondEdges, EDGE_LIST_FREE );
 
5504
    return ret < 0? ret : (pc2i->bHasDifference && tot_succes);
 
5505
}
 
5506
#endif