Coverage Report

Created: 2026-09-03 07:22

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