Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: MIT
3 : : * Copyright (c) 2024 IUPAC and InChI Trust
4 : : */
5 : :
6 : :
7 : : /*
8 : : Balanced Network Search
9 : :
10 : : Normalization related procedures
11 : : */
12 : :
13 : : #include <stdlib.h>
14 : : #include <string.h>
15 : : #include <stdint.h>
16 : :
17 : : #include "mode.h"
18 : : #include "ichitime.h"
19 : : #include "ichicant.h"
20 : : #include "ichierr.h"
21 : : #include "ichitaut.h"
22 : : #include "ichinorm.h"
23 : : #include "util.h"
24 : : #include "ichister.h"
25 : : #include "ichi_bns.h"
26 : :
27 : : #include "bcf_s.h"
28 : :
29 : : #include <string.h>
30 : : #include "logging.h" /*(@nnuk : Nauman Ullah Khan) :: Needed for logging functionality*/
31 : :
32 : : #define BNS_MARK_ONLY_BLOCKS 1 /* 1 => find only blocks, do not search for ring systems */
33 : : #define ALLOW_ONLY_SIMPLE_ALT_PATH 0 /* 0 => allow alt. path to contain same bond 2 times (in opposite directions) */
34 : : #define CHECK_TG_ALT_PATH 0 /* 1=> when chacking alt path of a tautomeric atom modify
35 : : t-group, not the atom */
36 : : /* 0=> old mode */
37 : :
38 : : #define FIX_CPOINT_BOND_CAP 1 /* 1=> fix bug in case of double bond from neutral cpoint */
39 : : #define RESET_EDGE_FORBIDDEN_MASK 1 /* 1: previous; 0: do not apply "edge->forbidden &= pBNS->edge_forbidden_mask" */
40 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
41 : : #define IS_FORBIDDEN(EDGE_FORBIDDEN, PBNS) (EDGE_FORBIDDEN)
42 : : #else
43 : : #define IS_FORBIDDEN(EDGE_FORBIDDEN, PBNS) (EDGE_FORBIDDEN & PBNS->edge_forbidden_mask)
44 : : #endif
45 : :
46 : :
47 : : typedef enum tagAtTypeTotals
48 : : {
49 : : /* counts do not include:
50 : : charged atom adjacent to another charged atom
51 : : atom in an unusual valence state or adjacent to an atom in an unusual valence state
52 : : radicals different from singlet
53 : : */
54 : : /*ATTOT_NUM_Plus. */ /* number of positive charges, +1, is (ATTOT_NUM_CHARGES + ATTOT_TOT_CHARGE)/2 */
55 : : /*ATTOT_NUM_Minus.*/ /* number of negative charges, -1, is (ATTOT_NUM_CHARGES - ATTOT_TOT_CHARGE)/2 */
56 : : ATTOT_NUM_NP_Plus, /* 0 no H: =N(+)=, #N(+)-, =N(+)<, does not include onium cations >P(+)<, >N(+)< */
57 : : ATTOT_NUM_NP_Proton, /* 1 H(+): -NH3(+), =NH2(+), >NH2(+), =NH(+)-, >NH(+)-, #NH(+), N=N,P */
58 : : ATTOT_NUM_NP_H, /* 2 H: -NH2, =NH, >NH -NH(-) */
59 : : ATTOT_NUM_N_Minus, /* 3 (-): -NH(-), >N(-), =N(-) */
60 : : ATTOT_NUM_NP, /* 4 no H: >N- =N-, #N */
61 : : ATTOT_NUM_ON, /* 5 -N=O: do not allow -N=O => -NH-OH during H(+) add/removal */
62 : : ATTOT_NUM_COH, /* 6 =C-OH, #C-OH; O=O,S,Se,Te */
63 : : ATTOT_NUM_CSH, /* 7 -C-SH, -C-SeH -C-TeH */
64 : : ATTOT_NUM_ZOH, /* 8 =Z-OH, #Z-OH; O=O,S,Se,Te; Z may have charge, Z != C */
65 : : ATTOT_NUM_OOH, /* 9 -O-OH, O=O,S,Se,Te */
66 : : ATTOT_NUM_ZOOH, /* 10 O=Z-OH, O=O,S,Se,Te */
67 : : ATTOT_NUM_NOH, /* 11 =N-OH, -N(-)-OH */
68 : : ATTOT_NUM_N_OH, /* 12 >N-OH, -NH-OH, >NH(+)-OH, -N(-)-OH */
69 : : ATTOT_NUM_CO, /* 13 -C=O, =C=O; O=O,S,Se,Te */
70 : : ATTOT_NUM_ZO, /* 14 -Z=O, =Z=O; O=O,S,Se,Te; Z may have charge */
71 : : ATTOT_NUM_NO, /* 15 -N=O, =N(+)=O */
72 : : ATTOT_NUM_N_O, /* 16 >N(+)=O, =N(+)=O */
73 : : ATTOT_NUM_CO_Minus, /* 17 =C-O(-), #C-O(-); O=O,S,Se,Te */
74 : : ATTOT_NUM_CS_Minus, /* 18 -C-S(-); S = S, Se, Te */
75 : : ATTOT_NUM_ZO_Minus, /* 19 =Z-O(-), #Z-O(-); O = O, S, Se, Te */
76 : : ATTOT_NUM_OO_Minus, /* 20 -O-O(-), O=O,S,Se,Te */
77 : : ATTOT_NUM_ZOO_Minus, /* 21 O=Z-O(-), O=O,S,Se,Te */
78 : : ATTOT_NUM_NO_Minus, /* 22 >N-O(-), -NH-O(-) */
79 : : ATTOT_NUM_N_O_Minus, /* 23 -NH-O(-), >N-O(-); O = O, S, Se, Te */
80 : : ATTOT_NUM_O_Minus, /* 24 -Z-O(-); O=O,S,Se,Te */
81 : : ATTOT_NUM_OH_Plus, /* 25 any OH(+) */
82 : : ATTOT_NUM_O_Plus, /* 26 any O(+) without H */
83 : : ATTOT_NUM_Proton, /* 27 proton */
84 : : ATTOT_NUM_HalAnion, /* 28 Halogen anion */
85 : : ATTOT_NUM_HalAcid, /* 29 Halogen acid */
86 : : ATTOT_NUM_Errors, /* 30 for debugging */
87 : : ATTOT_TOT_CHARGE, /* 31 total of positive and negative single charges, +1 and -1 */
88 : : ATTOT_NUM_CHARGES, /* 32 number of positive and negative single charges, +1 and -1 */
89 : : ATTOT_ARRAY_LEN /* 33 array length */
90 : : } AT_TYPE_TOTALS;
91 : :
92 : : #define ATBIT_NP_Plus (1 << ATTOT_NUM_NP_Plus)
93 : : #define ATBIT_NP_Proton (1 << ATTOT_NUM_NP_Proton)
94 : : #define ATBIT_NP_H (1 << ATTOT_NUM_NP_H)
95 : : #define ATBIT_N_Minus (1 << ATTOT_NUM_N_Minus)
96 : : #define ATBIT_NP (1 << ATTOT_NUM_NP)
97 : : #define ATBIT_ON (1 << ATTOT_NUM_ON)
98 : : #define ATBIT_COH (1 << ATTOT_NUM_COH)
99 : : #define ATBIT_CSH (1 << ATTOT_NUM_CSH)
100 : : #define ATBIT_ZOH (1 << ATTOT_NUM_ZOH)
101 : : #define ATBIT_OOH (1 << ATTOT_NUM_OOH)
102 : : #define ATBIT_ZOOH (1 << ATTOT_NUM_ZOOH)
103 : : #define ATBIT_NOH (1 << ATTOT_NUM_NOH)
104 : : #define ATBIT_N_OH (1 << ATTOT_NUM_N_OH)
105 : : #define ATBIT_CO (1 << ATTOT_NUM_CO)
106 : : #define ATBIT_ZO (1 << ATTOT_NUM_ZO)
107 : : #define ATBIT_NO (1 << ATTOT_NUM_NO)
108 : : #define ATBIT_N_O (1 << ATTOT_NUM_N_O)
109 : : #define ATBIT_CO_Minus (1 << ATTOT_NUM_CO_Minus)
110 : : #define ATBIT_CS_Minus (1 << ATTOT_NUM_CS_Minus)
111 : : #define ATBIT_ZO_Minus (1 << ATTOT_NUM_ZO_Minus)
112 : : #define ATBIT_OO_Minus (1 << ATTOT_NUM_OO_Minus)
113 : : #define ATBIT_ZOO_Minus (1 << ATTOT_NUM_ZOO_Minus)
114 : : #define ATBIT_NO_Minus (1 << ATTOT_NUM_NO_Minus)
115 : : #define ATBIT_N_O_Minus (1 << ATTOT_NUM_N_O_Minus)
116 : : #define ATBIT_O_Minus (1 << ATTOT_NUM_O_Minus)
117 : : #define ATBIT_OH_Plus (1 << ATTOT_NUM_OH_Plus)
118 : : #define ATBIT_O_Plus (1 << ATTOT_NUM_O_Plus)
119 : : #define ATBIT_Proton (1 << ATTOT_NUM_Proton)
120 : : #define ATBIT_HalAnion (1 << ATTOT_NUM_HalAnion)
121 : : #define ATBIT_HalAcid (1 << ATTOT_NUM_HalAcid)
122 : :
123 : :
124 : : #define ATBIT_Errors (1 << ATTOT_NUM_Errors)
125 : :
126 : : typedef struct tagProtonRemovalMaskAndType
127 : : {
128 : : int typePos; /* atoms accessible to positive charges */
129 : : int maskPos;
130 : : int typeNeg; /* atoms accessible to negative charges */
131 : : int maskNeg;
132 : : int typeH; /* atoms accessible to hydrogen atoms */
133 : : int maskH;
134 : : } PRMAT;
135 : :
136 : : #define PR_SIMPLE_MSK (ATBIT_NP_Proton | ATBIT_OH_Plus)
137 : : #define PR_SIMPLE_TYP (ATT_ATOM_N | ATT_ATOM_P | ATT_O_PLUS)
138 : :
139 : : #define ATBIT_MSK_NP (ATBIT_NP_Plus | ATBIT_NP_Proton | ATBIT_NP_H | ATBIT_N_Minus | ATBIT_NP)
140 : : #define KNOWN_ACIDIC_TYPE (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO)
141 : : #define ATBIT_MSK_OS (ATBIT_COH | ATBIT_CSH | ATBIT_ZOH | ATBIT_OOH | ATBIT_ZOOH | ATBIT_NOH | ATBIT_N_OH |\
142 : : ATBIT_CO | ATBIT_ZO | ATBIT_NO | ATBIT_N_O |\
143 : : ATBIT_CO_Minus | ATBIT_CS_Minus | ATBIT_ZO_Minus | ATBIT_OO_Minus |\
144 : : ATBIT_ZOO_Minus | ATBIT_NO_Minus | ATBIT_N_O_Minus /*| ATBIT_O_Minus*/ )
145 : : #define ATBIT_MSK_H (ATBIT_NP_Proton | ATBIT_NP_H | ATBIT_COH | ATBIT_CSH | ATBIT_ZOH | ATBIT_OOH |\
146 : : ATBIT_ZOOH | ATBIT_NOH | ATBIT_N_OH)
147 : :
148 : : #define ATTYP_OS (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO /*| ATT_OTHER_NEG_O*/ | ATT_OTHER_ZO)
149 : : #define ATTYP_NP (ATT_ATOM_N | ATT_ATOM_P)
150 : : #define ATTYP_N (ATT_ATOM_N)
151 : : #define ATTYP_P (ATT_ATOM_P)
152 : :
153 : : /************* simple proton removal from acids **************************/
154 : : #define AR_ANY_OH 0 /* 1 => create unknown to be acidic anions */
155 : : #define AR_SIMPLE_STEPS 3
156 : : /* acidic groups for proton removal, step 1 */
157 : : #define AR_SIMPLE_MSK1 (ATBIT_COH | ATBIT_CSH | ATBIT_OOH | ATBIT_ZOOH | ATBIT_NOH | ATBIT_HalAcid)
158 : : #define AR_SIMPLE_TYP1 (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO | ATT_HalAcid)
159 : : /* acidic groups for proton removal, step 2 */
160 : : #define AR_SIMPLE_MSK2 (AR_ANY_OH? (ATBIT_N_OH) :0)
161 : : #define AR_SIMPLE_TYP2 (AR_ANY_OH? (ATT_N_O) :0)
162 : : /* acidic groups for proton removal, step 3 */
163 : : #define AR_SIMPLE_MSK3 (AR_ANY_OH? (ATBIT_ZOH) :0)
164 : : #define AR_SIMPLE_TYP3 (AR_ANY_OH? (ATT_OTHER_ZO):0)
165 : :
166 : : /************* simple proton addition to acids **************************/
167 : : #define AA_ANY_O_Minus 0 /* 1 => neutralize unknown to be acidic anions */
168 : : #define AA_SIMPLE_STEPS 3
169 : : /* acidic groups for proton addition, step 1 */
170 : : #define AA_SIMPLE_MSK1 (ATBIT_CO_Minus | ATBIT_CS_Minus | ATBIT_OO_Minus | ATBIT_ZOO_Minus | ATBIT_NO_Minus | ATBIT_O_Minus | ATBIT_HalAnion)
171 : : #define AA_SIMPLE_TYP1 (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO | ATT_OH_MINUS | ATT_HalAnion )
172 : : /* acidic groups for proton addition, step 2 */
173 : : #define AA_SIMPLE_MSK2 (AA_ANY_O_Minus? (ATBIT_N_O_Minus) :0)
174 : : #define AA_SIMPLE_TYP2 (AA_ANY_O_Minus? (ATT_N_O) :0)
175 : : /* acidic groups for proton addition, step 3 */
176 : : #define AA_SIMPLE_MSK3 (AA_ANY_O_Minus? (ATBIT_ZO_Minus | ATBIT_O_Minus):0)
177 : : #define AA_SIMPLE_TYP3 (AA_ANY_O_Minus? (ATT_OTHER_ZO) :0)
178 : :
179 : : #if ( FIX_NP_MINUS_BUG == 1 )
180 : : /* allow to add H(+) to =N(-) which previously was #N */
181 : : #undef AA_SIMPLE_STEPS
182 : : #define AA_SIMPLE_STEPS 4
183 : : #define AA_SIMPLE_MSK4 ATBIT_N_Minus
184 : : #define AA_SIMPLE_TYP4 ATT_NP_MINUS_V23
185 : : #endif
186 : :
187 : : /************* hard proton removal from NP **************************/
188 : : /* (+) charge group for proton removal: mask & type */
189 : : #define PR_HARD_MSK_POS ATBIT_MSK_NP
190 : : #define PR_HARD_TYP_POS ATTYP_N
191 : : #define PR_HARD_TYP_POSP ATTYP_P
192 : : /* (-) charge group for proton removal */
193 : : #define PR_HARD_MSK_NEG (ATBIT_MSK_NP | ATBIT_MSK_OS)
194 : : #define PR_HARD_TYP_NEG (ATTYP_N | ATTYP_OS)
195 : : /* H-group for proton removal */
196 : : #define PR_HARD_MSK_H (ATBIT_MSK_NP | ATBIT_MSK_OS)
197 : : #define PR_HARD_TYP_H (ATTYP_N | ATTYP_OS)
198 : :
199 : : /************* hard proton removal from acids **************************/
200 : : /* (+) charge group for proton removal: mask & type */
201 : : #define AR_HARD_MSK_POS ATBIT_MSK_NP
202 : : #define AR_HARD_TYP_POS ATTYP_N
203 : : /* (-) charge group for proton removal */
204 : : #define AR_HARD_MSK_NEG (ATBIT_MSK_NP | ATBIT_MSK_OS)
205 : : #define AR_HARD_TYP_NEG (ATTYP_N | ATTYP_OS)
206 : : /* H-group acid for proton removal */
207 : : #define AR_HARD_MSK_HA (ATBIT_CO | ATBIT_NO )
208 : : #define AR_HARD_TYP_HA (ATT_ACIDIC_CO | ATT_NO)
209 : : /* H-group non-acid for proton removal */
210 : : #define AR_HARD_MSK_HN ((ATBIT_MSK_NP | ATBIT_MSK_OS) & ~AR_HARD_MSK_HA)
211 : : #define AR_HARD_TYP_HN ((ATTYP_N | ATTYP_OS) /*& ~AR_HARD_TYP_HA*/)
212 : :
213 : : /************* hard proton addition to acids **************************/
214 : : /* (+) charge group for proton removal: mask & type */
215 : : #define AA_HARD_MSK_POS ATBIT_MSK_NP
216 : : #define AA_HARD_TYP_POS ATTYP_N
217 : : /* (-) charge group for negative charge removal */
218 : : #define AA_HARD_MSK_NEG ((ATBIT_MSK_NP | ATBIT_MSK_OS) & ~(ATBIT_CO | ATBIT_NO ))
219 : : #define AA_HARD_TYP_NEG (ATTYP_N | ATTYP_OS)
220 : : /* (-) charge group to accept negative charges */
221 : : #define AA_HARD_MSK_CO (ATBIT_CO | ATBIT_NO )
222 : : #define AA_HARD_TYP_CO (ATT_ACIDIC_CO | ATT_NO)
223 : : /* H-group non-acid for proton removal */
224 : : #define AA_HARD_MSK_H (ATBIT_MSK_NP | ATBIT_MSK_OS)
225 : : #define AA_HARD_TYP_H (ATTYP_N | ATTYP_OS)
226 : :
227 : :
228 : : /*****************************************************************************/
229 : : #define BNS_MAX_NUM_FLOW_CHANGES (1+2*MAX_BOND_EDGE_CAP)
230 : :
231 : : /* -- opiginal Pascal values --
232 : : #define NO_VERTEX 0
233 : : #define BLOSSOM_BASE -1
234 : : #define FIRST_INDX 1
235 : : */
236 : :
237 : : #define TREE_NOT_IN_M 0 /* not in T or T' */
238 : : #define TREE_IN_2 1 /* in T' and not s-reachable */
239 : : #define TREE_IN_2BLOSS 2 /* in T' and in a blossom, is s-reachable */
240 : : #define TREE_IN_1 3 /* in T and is s-reachable */
241 : :
242 : : #define TREE_IS_S_REACHABLE(X) (Tree[X] >= TREE_IN_2BLOSS)
243 : : #define TREE_IS_ON_SCANQ TREE_IS_S_REACHABLE
244 : : /* #define TREE_IS_ON_SCANQ(X) (Tree[X] != TREE_NOT_IN_M) */
245 : : #define TREE_MARK(X, MARK) do{ if( Tree[X] < MARK ) Tree[X]=MARK; }while(0)
246 : :
247 : :
248 : : /*****************************************************************************
249 : : * store changes done to check whether an alternating path exists
250 : : * (see bSetBnsToCheckAltPath, bRestoreBnsAfterCheckAltPath)
251 : : ******************************************************************************/
252 : : typedef struct tagAltPathChanges
253 : : {
254 : : /* caps changed in up to 2 vertices */
255 : : VertexFlow nOldCapsVert[2][MAXVAL + 1];
256 : : Vertex vOldVert[2];
257 : : S_CHAR bSetOldCapsVert[2]; /* number of caps to restore, including st-cap */
258 : : /* save ids of the newly created temporary vertices */
259 : : Vertex vNewVertex[2];
260 : : S_CHAR bSetNew[2]; /* indicators whether to remove vertices */
261 : : } ALT_PATH_CHANGES;
262 : :
263 : :
264 : :
265 : : /*****************************************************************************/
266 : :
267 : :
268 : : /* Local functions */
269 : :
270 : : int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at );
271 : : int bRadChangesAtomType( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex v, Vertex v_1, Vertex v_2 );
272 : : int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms );
273 : : int SetAtomRadAndChemValFromVertexCapFlow( BN_STRUCT *pBNS, inp_ATOM *atom, int v1 );
274 : : int bNeedToTestTheFlow( int bond_type, int nTestFlow, int bTestForNonStereoBond );
275 : : int RestoreEdgeFlow( BNS_EDGE *edge, int delta, int bChangeFlow );
276 : : int SetAtomBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, int delta, int bChangeFlow );
277 : : int RestoreBnStructFlow( BN_STRUCT *pBNS, int bChangeFlow );
278 : : int CompTGroupNumber( const void *tg1, const void *tg2, void *p );
279 : : int CompCGroupNumber( const void *cg1, const void *cg2, void *p );
280 : :
281 : : /* Rings, Blocks, Non-stereo bonds */
282 : : int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
283 : : int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo );
284 : : int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
285 : :
286 : : /* Called from BalancedNetworkSearch */
287 : : int GetVertexDegree( BN_STRUCT* pBNS, Vertex v );
288 : : /* Vertex Get2ndNeighbor1( BN_STRUCT* pBNS, Vertex u, EdgeIndex iedge ); not used */
289 : : Vertex Get2ndEdgeVertex( BN_STRUCT* pBNS, Edge uv );
290 : : Vertex GetVertexNeighbor( BN_STRUCT* pBNS, Vertex v, int neigh, EdgeIndex *iedge );
291 : : int GetEdgePointer( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv, BNS_EDGE **uv, S_CHAR *s_or_t );
292 : : int AugmentEdge( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv, int delta, S_CHAR bReverse, int bChangeFlow );
293 : : int rescap_mark( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv );
294 : : int rescap( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv );
295 : : Vertex FindBase( Vertex u, Vertex *BasePtr );
296 : : int FindPathToVertex_s( Vertex x, Edge *SwitchEdge, Vertex *BasePtr, Vertex *Path, int MaxPathLen );
297 : : Vertex MakeBlossom( BN_STRUCT* pBNS, Vertex *ScanQ, int *pQSize,
298 : : Vertex *Pu, Vertex *Pv, int max_len_Pu_Pv,
299 : : Edge *SwitchEdge, Vertex *BasePtr,
300 : : Vertex u, Vertex v, EdgeIndex iuv, Vertex b_u, Vertex b_v, S_CHAR *Tree );
301 : : int PullFlow( BN_STRUCT *pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta, S_CHAR bReverse, int bChangeFlow );
302 : : int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta );
303 : :
304 : : /*
305 : : int SetBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, int delta, int bChangeFlow );
306 : : int SetBondsRestoreBnStructFlow( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bChangeFlow );
307 : : */
308 : : int SetBondsFromBnStructFlow( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bChangeFlow0 );
309 : : int MarkAtomsAtTautGroups( BN_STRUCT *pBNS, int num_atoms, BN_AATG *pAATG, int nEnd1, int nEnd2 );
310 : :
311 : : int nMinFlow2Check( BN_STRUCT *pBNS, int iedge );
312 : : int nMaxFlow2Check( BN_STRUCT *pBNS, int iedge );
313 : : int nCurFlow2Check( BN_STRUCT *pBNS, int iedge );
314 : :
315 : : /* Bonds testing */
316 : : /*
317 : : int bRestoreFlowToCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd, int nTestFlow, inp_ATOM *at, int num_atoms, int bChangeFlow );
318 : : */
319 : : int bSetFlowToCheckOneBond( BN_STRUCT *pBNS, int iedge, int flow, BNS_FLOW_CHANGES *fcd );
320 : : int bRestoreFlowAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd );
321 : : int bSetBondsAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd, int nTestFlow, inp_ATOM *at, int num_atoms, int bChangeFlow );
322 : : int BnsTestAndMarkAltBonds( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms, BNS_FLOW_CHANGES *fcd, int bChangeFlow, int nBondTypeToTest );
323 : : /*
324 : : int bIsAltBond(int bond_type); -- djb-rwth: function definition not found
325 : : */
326 : :
327 : : /* Fix bonds */
328 : : int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int edge_forbidden_mask );
329 : : int TempFix_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
330 : : int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
331 : : int fix_explicitly_indicated_bonds( int nebend, int *ebend, BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
332 : :
333 : : /* Alt path testing */
334 : : int bSetBnsToCheckAltPath( BN_STRUCT *pBNS, int nVertDoubleBond, int nVertSingleBond, AT_NUMB type,
335 : : int path_type, ALT_PATH_CHANGES *apc, BNS_FLOW_CHANGES *fcd, int *nDots );
336 : : int bRestoreBnsAfterCheckAltPath( BN_STRUCT *pBNS, ALT_PATH_CHANGES *apc, int bChangeFlow );
337 : : Vertex GetGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type );
338 : : BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type );
339 : : int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, int nMaxAdjEdges, int *nDots );
340 : : int AddNewEdge( BNS_VERTEX *p1, BNS_VERTEX *p2, BN_STRUCT *pBNS, int nEdgeCap, int nEdgeFlow );
341 : : int bAddStCapToAVertex( BN_STRUCT *pBNS, Vertex v1, Vertex v2, VertexFlow *nOldCapVertSingleBond, int *nDots, int bAdjacentDonors );
342 : :
343 : : static void remove_alt_bond_marks( inp_ATOM *at, int num_atoms );
344 : : int bIsBnsEndpoint( BN_STRUCT *pBNS, int v );
345 : :
346 : : /* Protons removal, charge neutralization */
347 : : /* int is_acidic_CO(inp_ATOM* atom, int at_no); */ /* djb-rwth: function definition not found*/
348 : : int mark_at_type( inp_ATOM *atom, int num_atoms, int nAtTypeTotals[] );
349 : : int GetAtomChargeType( inp_ATOM *atom, int at_no, int nAtTypeTotals[], int *pMask, int bSubtract );
350 : : int AddChangedAtHChargeBNS( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], S_CHAR *mark );
351 : : int EliminatePlusMinusChargeAmbiguity( BN_STRUCT *pBNS, int num_atoms );
352 : : int AddOrRemoveExplOrImplH( int nDelta, inp_ATOM *at, int num_atoms, AT_NUMB at_no, T_GROUP_INFO *t_group_info );
353 : : int SubtractOrChangeAtHChargeBNS( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms,
354 : : int nAtTypeTotals[], S_CHAR *mark, T_GROUP_INFO *t_group_info, int bSubtract );
355 : : int is_Z_atom( U_CHAR el_number );
356 : : int IsZOX( inp_ATOM *atom, int at_x, int ord );
357 : : int SimpleRemoveHplusNPO( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], T_GROUP_INFO *t_group_info );
358 : : int CreateCGroupInBnStruct( inp_ATOM *at, int num_atoms,
359 : : BN_STRUCT *pBNS, int nType, int nMask, int nCharge );
360 : : int CreateTGroupInBnStruct( inp_ATOM *at, int num_atoms,
361 : : BN_STRUCT *pBNS, int nType, int nMask );
362 : : int RemoveLastGroupFromBnStruct( inp_ATOM *at, int num_atoms, int tg, BN_STRUCT *pBNS );
363 : : int SetInitCapFlowToCurrent( BN_STRUCT *pBNS );
364 : : int SimpleRemoveAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2remove );
365 : : int SimpleAddAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2add );
366 : : int HardRemoveAcidicProtons( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2remove,
367 : : int *nNumCanceledCharges, BN_STRUCT *pBNS, BN_DATA *pBD );
368 : : int HardAddAcidicProtons( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2add,
369 : : int *nNumCanceledCharges, BN_STRUCT *pBNS, BN_DATA *pBD );
370 : : int HardRemoveHplusNP( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, int bCancelChargesAlways, int *nNumCanceledCharges,
371 : : BN_AATG *pAATG, BN_STRUCT *pBNS, BN_DATA *pBD );
372 : : int RemoveNPProtonsAndAcidCharges( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, BN_AATG *pAATG, BN_STRUCT *pBNS, BN_DATA *pBD );
373 : : Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv );
374 : : int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v );
375 : : int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
376 : : int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v );
377 : : int bIsAggressiveDeprotonation( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
378 : :
379 : : int bIsAtomTypeHard( inp_ATOM *at, int endpoint, int nType, int nMask, int nCharge );
380 : : int bIsHDonorAccAtomType( inp_ATOM *at, int endpoint, int *cSubType );
381 : : int bIsNegAtomType( inp_ATOM *at, int i, int *cSubType );
382 : :
383 : : #if ( BNS_RAD_SEARCH == 1 )
384 : : int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u );
385 : : int cmp_rad_endpoints( const void *a1, const void *a2 );
386 : : int cmp_endpoints_rad( const void *a1, const void *a2 );
387 : : #endif
388 : :
389 : : int bHasChargedNeighbor( inp_ATOM *at, int iat );
390 : : /*****************************************************************************/
391 : : /**** prim(v) is v' *****/
392 : : #define prim(v) (Vertex)((v)^1)
393 : :
394 : : /*****************************************************************************/
395 : : #define SwitchEdge_Vert1(u) SwitchEdge[u][0]
396 : : #define SwitchEdge_Vert2(u) Get2ndEdgeVertex( pBNS, SwitchEdge[u] )
397 : : #define SwitchEdge_IEdge(u) SwitchEdge[u][1]
398 : : /*****************************************************************************/
399 : :
400 : :
401 : :
402 : :
403 : :
404 : : /****************************************************************************
405 : : Returns value > 0 if a bond has been changed
406 : : ****************************************************************************/
407 : 104 : int RestoreEdgeFlow( BNS_EDGE *edge, int delta, int bChangeFlow )
408 : : {
409 : : /*flow1 = edge->flow;*/ /* output from BNS */
410 [ - - + - : 104 : switch (bChangeFlow & BNS_EF_CHNG_RSTR)
- ]
411 : : {
412 : 0 : case 0:
413 : : /* the flow has not been permitted to change inside the BNS */
414 : : /* nothing to do */
415 : : /*flow1 = edge->flow;*/ /* output from BNS, the original flow value */
416 : : /*flow2 = flow1 + delta;*/ /* the flow would be changed to this value by the BNS if permitted */
417 : 0 : break;
418 : 0 : case BNS_EF_CHNG_FLOW:
419 : : /* the flow has been changed by the BNS; update flow0 */
420 : : /*flow2 = edge->flow;*/ /* output from BNS, the changed value */
421 : : /*flow1 = flow2 - delta;*/ /* the original flow value before the BNS */
422 : 0 : edge->flow0 = edge->flow; /* SAVE NEW EDGE FLOW AS THE INITIAL FLOW FROM CHEM. BONDS */
423 : 0 : break;
424 : 104 : case BNS_EF_CHNG_RSTR:
425 : : /* the flow has been changed by the BNS; requested to change it back */
426 : : /*flow2 = edge->flow;*/ /* output from BNS, the changed value */
427 : : /*flow1 = flow2 - delta;*/ /* the original flow value before the BNS */
428 : 104 : edge->flow = edge->flow - delta; /* CHANGE EDGE FLOW BACK (RESTORE) */
429 : 104 : break;
430 : 0 : case BNS_EF_RSTR_FLOW:
431 : : /* the flow has not been permitted to change inside the BNS */
432 : : /* nothing to do */
433 : : /*flow1 = edge->flow;*/ /* output from BNS, the original flow value */
434 : : /*flow2 = flow1 + delta;*/ /* the flow would be changed to this value by the BNS if permitted */
435 : 0 : break;
436 : : }
437 : :
438 : 104 : return 0;
439 : : }
440 : :
441 : :
442 : : /****************************************************************************
443 : : Returns value > 0 if a bond has been changed; do not change flow
444 : : ****************************************************************************/
445 : 100 : int SetAtomBondType( BNS_EDGE *edge,
446 : : U_CHAR *bond_type12,
447 : : U_CHAR *bond_type21,
448 : : int delta,
449 : : int bChangeFlow )
450 : : {
451 : 100 : int flow1, flow2, tmp, ret = 0;
452 : 100 : int bond_mark = 0, bond_type, new_bond_type; /* djb-rwth: addressing LLVM warning */
453 : :
454 [ + - - + ]: 100 : if (!edge->pass || !bond_type21)
455 : : {
456 : 0 : return 0;
457 : : }
458 : :
459 [ + + - ]: 100 : switch (bChangeFlow & BNS_EF_CHNG_RSTR)
460 : : {
461 : 37 : case 0: /* the flow has not been permitted to change inside the BNS: simulated in case of check one bond */
462 : : case BNS_EF_RSTR_FLOW: /* the flow has not been permitted to change inside the BNS: obsolete mode, unexpected bChangeFlow */
463 : 37 : flow1 = edge->flow0; /* output from BNS, the original (old) flow value */
464 : 37 : flow2 = flow1 + delta; /* the flow would be changed to this value by the BNS if permitted */
465 : 37 : break;
466 : 63 : case BNS_EF_CHNG_FLOW: /* the flow has been changed by the BNS */
467 : : case BNS_EF_CHNG_RSTR: /* the flow has been changed by the BNS; requested to change it back */
468 : 63 : flow2 = edge->flow; /* output from BNS, the changed (new) value */
469 : 63 : flow1 = edge->flow0; /* the original flow (old) value before the BNS */
470 : 63 : break;
471 : 0 : default:
472 : 0 : return 0; /* added 2006-03-21 */
473 : : }
474 : :
475 [ - + - - ]: 100 : if (( bChangeFlow & BNS_EF_CHNG_BONDS ) && ( bChangeFlow & BNS_EF_ALTR_NS ) != BNS_EF_ALTR_NS)
476 : : {
477 : : /* Set new bond types according to the new flow values */
478 : 0 : new_bond_type = flow2 + BOND_SINGLE;
479 [ # # ]: 0 : if (*bond_type12 != new_bond_type)
480 : : {
481 : 0 : *bond_type12 = *bond_type21 = new_bond_type;
482 : 0 : ret++;
483 : : }
484 : : }
485 : : else
486 : : {
487 [ + + ]: 100 : if (bChangeFlow & BNS_EF_ALTR_BONDS)
488 : : {
489 [ - + ]: 68 : if (flow1 == flow2)
490 : : {
491 : 0 : goto exit_function;
492 : : }
493 : : /* Update alternating bond information */
494 [ + + ]: 68 : if (flow1 > flow2)
495 : : {
496 : : /* Make sure flow2 > flow1 */
497 : 34 : tmp = flow1;
498 : 34 : flow1 = flow2;
499 : 34 : flow2 = tmp;
500 : : }
501 : : /* djb-rwth: removing redundant code */
502 [ + + - ]: 68 : switch (bond_type = ( *bond_type12 & BOND_TYPE_MASK ))
503 : : {
504 : 36 : case BOND_SINGLE:
505 : : case BOND_DOUBLE:
506 : : case BOND_TRIPLE:
507 : : /* assume that the input bond type fits either flow1 or flow2 */
508 [ + - + - ]: 36 : if (flow1 == 0 && flow2 == 1)
509 : : {
510 [ - + ]: 36 : if (bChangeFlow & BNS_EF_SET_NOSTEREO)
511 : : {
512 : 0 : bond_mark = BOND_MARK_ALT12NS;
513 : 0 : bond_type = BOND_ALT12NS;
514 : : }
515 : : else
516 : : {
517 : 36 : bond_mark = BOND_MARK_ALT12;
518 : 36 : bond_type = BOND_ALTERN;
519 : : }
520 : : }
521 : : else
522 : : {
523 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 2)
524 : : {
525 : 0 : bond_mark = BOND_MARK_ALT13;
526 : 0 : bond_type = BOND_ALT_13;
527 : : }
528 : : else
529 : : {
530 [ # # # # ]: 0 : if (flow1 == 1 && flow2 == 2)
531 : : {
532 : 0 : bond_mark = BOND_MARK_ALT23;
533 : 0 : bond_type = BOND_ALT_23;
534 : : }
535 : : else
536 : : {
537 : 0 : return BNS_BOND_ERR; /* error */
538 : : }
539 : : }
540 : : }
541 : 36 : break;
542 : 32 : case BOND_TAUTOM:
543 [ + - + - ]: 32 : if (flow1 == 0 && flow2 == 1)
544 : : {
545 : 32 : bond_mark = BOND_MARK_ALT12NS;
546 : : }
547 : : else
548 [ # # # # ]: 0 : if (flow1 == 1 && flow2 == 2) {
549 : 0 : bond_mark = BOND_MARK_ALT23;
550 : : }
551 : : else {
552 : 0 : return BNS_BOND_ERR; /* error */
553 : : }
554 : 32 : break;
555 : 0 : default:
556 : 0 : new_bond_type = bond_type;
557 : 0 : bond_mark = ( *bond_type12 & BOND_MARK_MASK );
558 [ # # # # : 0 : switch (bond_mark)
# # # ]
559 : : {
560 : 0 : case BOND_MARK_ALT12:
561 [ # # # # : 0 : if (( bChangeFlow & BNS_EF_SET_NOSTEREO ) && flow1 == 0 && flow2 == 1)
# # ]
562 : : {
563 : 0 : bond_mark = BOND_MARK_ALT12NS;
564 : 0 : new_bond_type = BOND_ALT12NS;
565 : 0 : break;
566 : : }
567 : : case BOND_MARK_ALT12NS:
568 [ # # # # ]: 0 : if (flow1 == 2 || flow2 == 2)
569 : : {
570 : 0 : bond_mark = BOND_MARK_ALT123;
571 : 0 : new_bond_type = BOND_ALT_123;
572 : : }
573 : 0 : break;
574 : 0 : case BOND_MARK_ALT13:
575 [ # # # # ]: 0 : if (flow1 == 1 || flow2 == 1)
576 : : {
577 : 0 : bond_mark = BOND_MARK_ALT123;
578 : 0 : new_bond_type = BOND_ALT_123;
579 : : }
580 : 0 : break;
581 : 0 : case BOND_MARK_ALT23:
582 [ # # # # ]: 0 : if (flow1 == 0 || flow2 == 0)
583 : : {
584 : 0 : bond_mark = BOND_MARK_ALT123;
585 : 0 : new_bond_type = BOND_ALT_123;
586 : : }
587 : 0 : break;
588 : 0 : case BOND_MARK_ALT123:
589 : 0 : break;
590 : :
591 : 0 : case 0: /* special case: second alt bond testing */
592 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 1)
593 : : {
594 : 0 : bond_mark = BOND_MARK_ALT12;
595 : : }
596 : : else
597 : : {
598 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 2)
599 : : {
600 : 0 : bond_mark = BOND_MARK_ALT13;
601 : : }
602 : : else
603 : : {
604 [ # # # # ]: 0 : if (flow1 == 1 && flow2 == 2)
605 : : {
606 : 0 : bond_mark = BOND_MARK_ALT23;
607 : : }
608 : : else
609 : : {
610 : 0 : return BNS_BOND_ERR; /* error */
611 : : }
612 : : }
613 : : }
614 : 0 : break;
615 : :
616 : 0 : default:
617 : 0 : return BNS_BOND_ERR; /* error */
618 : : }
619 : :
620 [ # # # ]: 0 : switch (bond_type)
621 : : {
622 : 0 : case BOND_TAUTOM:
623 : 0 : break;
624 : 0 : case BOND_ALTERN:
625 : : case BOND_ALT12NS:
626 : : case BOND_ALT_123:
627 : : case BOND_ALT_13:
628 : : case BOND_ALT_23:
629 : 0 : bond_type = new_bond_type;
630 : 0 : break;
631 : 0 : default:
632 : 0 : return BNS_BOND_ERR; /* error */
633 : : }
634 : : }
635 : :
636 : 68 : new_bond_type = bond_type | bond_mark;
637 [ + + ]: 68 : if (new_bond_type != *bond_type12)
638 : : {
639 : 64 : *bond_type12 = *bond_type21 = new_bond_type;
640 : 64 : ret++;
641 : : }
642 : : }
643 : : }
644 : :
645 : 36 : exit_function:
646 : :
647 : 100 : return ret;
648 : : }
649 : :
650 : :
651 : : /****************************************************************************
652 : : Run BalancedNetworkSearch( ... ) until no aug pass is found
653 : : ****************************************************************************/
654 : 210 : int RunBalancedNetworkSearch( BN_STRUCT *pBNS, BN_DATA *pBD, int bChangeFlow )
655 : : {
656 : 210 : int pass, delta = 0, nSumDelta;
657 : :
658 : 210 : nSumDelta = 0;
659 [ + - ]: 248 : for (pass = 0; pass < pBNS->max_altp; pass++)
660 : : {
661 : 248 : pBNS->alt_path = pBNS->altp[pass];
662 : 248 : pBNS->bChangeFlow = 0;
663 : 248 : delta = BalancedNetworkSearch( pBNS, pBD, bChangeFlow );
664 : 248 : ReInitBnData( pBD );
665 [ + + ]: 248 : if (0 < delta)
666 : : {
667 : 38 : pBNS->num_altp++;
668 : 38 : nSumDelta += abs( delta );
669 : : }
670 : : else
671 : : {
672 : 210 : break;
673 : : }
674 : : }
675 : :
676 [ + - - + ]: 210 : if (IS_BNS_ERROR( delta ))
677 : : {
678 : 0 : return delta;
679 : : }
680 : :
681 [ - + ]: 210 : if (bInchiTimeIsOver( pBNS->ic, pBNS->ulTimeOutTime ))
682 : : {
683 : 0 : return BNS_TIMEOUT;
684 : : }
685 : :
686 : 210 : return nSumDelta; /* number of eliminated pairs of "dots" */
687 : : }
688 : :
689 : :
690 : : /****************************************************************************/
691 : 0 : int SetAtomRadAndChemValFromVertexCapFlow( BN_STRUCT *pBNS,
692 : : inp_ATOM *atom,
693 : : int v1 )
694 : : {
695 : 0 : BNS_VERTEX *vert = pBNS->vert + v1;
696 : 0 : inp_ATOM *at = atom + v1;
697 : : S_CHAR cValue;
698 : 0 : int nChanges = 0;
699 : :
700 : : /* Set only on the 1st pass */
701 [ # # ]: 0 : if (!vert->st_edge.pass)
702 : : {
703 : 0 : return 0;
704 : : }
705 : :
706 : : /* Adjust chem_bonds_valence */
707 : 0 : cValue = at->chem_bonds_valence - at->valence;
708 [ # # # # ]: 0 : if (cValue >= 0 && cValue != vert->st_edge.flow)
709 : : {
710 : 0 : at->chem_bonds_valence = at->valence + vert->st_edge.flow;
711 : 0 : nChanges++;
712 : : }
713 : :
714 : : /* Adjist radical */
715 [ # # # # ]: 0 : switch (vert->st_edge.cap - vert->st_edge.flow)
716 : : {
717 : 0 : case 0:
718 : 0 : cValue = 0;
719 : 0 : break;
720 : 0 : case 1:
721 : 0 : cValue = RADICAL_DOUBLET;
722 : 0 : break;
723 : 0 : case 2:
724 : 0 : cValue = RADICAL_TRIPLET;
725 : 0 : break;
726 : 0 : default:
727 : 0 : return BNS_BOND_ERR;
728 : : }
729 [ # # ]: 0 : if (cValue != at->radical)
730 : : {
731 : 0 : at->radical = cValue;
732 : 0 : nChanges++;
733 : : }
734 : :
735 : 0 : return nChanges;
736 : : }
737 : :
738 : :
739 : : /****************************************************************************/
740 : 0 : int AddChangedAtHChargeBNS( inp_ATOM *at,
741 : : int num_atoms,
742 : : int nAtTypeTotals[],
743 : : S_CHAR *mark )
744 : : {
745 : : int i, mask, num;
746 [ # # ]: 0 : for (i = 0, num = 0; i < num_atoms; i++)
747 : : {
748 [ # # ]: 0 : if (mark[i])
749 : : {
750 : 0 : mark[i] = 0;
751 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
752 : : /* add ignoring adjacent charges */
753 : 0 : at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, -2 );
754 : : #else
755 : : at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 );
756 : : #endif
757 : 0 : num++;
758 : : }
759 : : }
760 : :
761 : 0 : return num;
762 : : }
763 : :
764 : :
765 : : /****************************************************************************
766 : : Eliminate neutral representation ambiguity:
767 : :
768 : : replace (+)--N==(-) with (+)==N--(-)
769 : :
770 : : here (+) is positive charge group,
771 : : (-) is negative charge group, N is N or P
772 : : This reduces possibility of creating ion pair -OH => -O(+) + H(+)
773 : : instead of removing H(+) from N or P
774 : :
775 : : !Call this function after alt path was found and new flows have been set.
776 : : ****************************************************************************/
777 : 0 : int EliminatePlusMinusChargeAmbiguity( BN_STRUCT *pBNS, int num_atoms )
778 : : {
779 : : int pass, i, v0, v1, v2, ineigh1, /*ineigh0,*/ /*ineigh2,*/
780 : 0 : vLast, n, delta, ret, err = 0;
781 : : int nFound, k;
782 : : BNS_EDGE *edge;
783 : :
784 [ # # ]: 0 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
785 : : {
786 : :
787 : 0 : pBNS->alt_path = pBNS->altp[pass];
788 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
789 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
790 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
791 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
792 : 0 : v0 = v2 = NO_VERTEX; /* negative number */
793 : :
794 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2 /*, ineigh0 = ineigh1*/)
795 : : {
796 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
797 : : /*ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i);*/ /* v2->v1 neighbor */
798 : 0 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
799 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
800 : : t-groups, c-groups or other fictitious edges/vertices
801 : : */
802 : 0 : v2 = edge->neighbor12 ^ v1;
803 [ # # # # ]: 0 : if (v1 < num_atoms &&
804 [ # # # # ]: 0 : ( (v0 >= num_atoms && ( pBNS->vert[v0].type & BNS_VERT_TYPE_C_GROUP )) ||
805 [ # # ]: 0 : (v2 >= num_atoms && ( pBNS->vert[v2].type & BNS_VERT_TYPE_C_GROUP ) ))) /* djb-rwth: addressing LLVM warning */
806 : : {
807 : 0 : int cgPos = 0, cgNeg = 0;
808 : 0 : int neighPos = -1, neighNeg = -1;
809 : : BNS_EDGE *edgePos, *edgeNeg;
810 : 0 : nFound = 0;
811 [ # # # # : 0 : for (k = pBNS->vert[v1].num_adj_edges - 1; k >= 0 && ( neighPos < 0 || neighNeg < 0 ); k--)
# # ]
812 : : {
813 : 0 : BNS_EDGE *next_edge = pBNS->edge + pBNS->vert[v1].iedge[k];
814 : 0 : int v = next_edge->neighbor12 ^ v1;
815 [ # # ]: 0 : if (pBNS->vert[v].type & BNS_VERT_TYPE_C_GROUP)
816 : : {
817 [ # # ]: 0 : if (pBNS->vert[v].type & BNS_VERT_TYPE_C_NEGATIVE)
818 : : {
819 : 0 : cgNeg = v;
820 : 0 : neighNeg = k;
821 : 0 : nFound++;
822 : : }
823 : : else
824 : : {
825 : 0 : cgPos = v;
826 : 0 : neighPos = k;
827 : 0 : nFound++;
828 : : }
829 : : }
830 : : }
831 [ # # # # : 0 : if (2 == nFound && neighPos >= 0 && neighNeg >= 0)
# # ]
832 : : {
833 : : /* both c-groups have been found */
834 : 0 : edgePos = pBNS->edge + pBNS->vert[v1].iedge[neighPos];
835 : 0 : edgeNeg = pBNS->edge + pBNS->vert[v1].iedge[neighNeg];
836 [ # # ]: 0 : if (edgePos->flow < edgeNeg->flow)
837 : : {
838 : : /* ambiguity found; replace (+cg)--N==(-cg) with (+cg)==N--(-cg) */
839 : 0 : int dflow = edgeNeg->flow - edgePos->flow;
840 : :
841 : 0 : edgePos->flow += dflow;
842 : 0 : pBNS->vert[cgPos].st_edge.cap += dflow;
843 : 0 : pBNS->vert[cgPos].st_edge.flow += dflow;
844 : :
845 : 0 : edgeNeg->flow -= dflow;
846 : 0 : pBNS->vert[cgNeg].st_edge.cap -= dflow;
847 : 0 : pBNS->vert[cgNeg].st_edge.flow -= dflow;
848 : 0 : ret++;
849 : : }
850 : : }
851 : : }
852 : : }
853 : :
854 [ # # ]: 0 : if (v2 != vLast)
855 : : {
856 : 0 : err = BNS_PROGRAM_ERR;
857 : : }
858 : : }
859 : :
860 [ # # ]: 0 : return err ? err : ret;
861 : : }
862 : :
863 : :
864 : : /****************************************************************************
865 : : Add or remove ixplicit or implicit hydrogens
866 : : ****************************************************************************/
867 : 21 : int AddOrRemoveExplOrImplH( int nDelta,
868 : : inp_ATOM *at,
869 : : int num_atoms,
870 : : AT_NUMB at_no,
871 : : T_GROUP_INFO *t_group_info )
872 : : {
873 : : int i, iso, tot_num_iso_H,
874 : : num_H, /* number of H before the removal, including explicit H */
875 : : nNum2Remove, /* number of H to remove */
876 : : nNumRemovedExplicitH; /* djb-rwth: removing redundant variables */
877 : : S_CHAR num_iso_H[NUM_H_ISOTOPES];
878 : : inp_ATOM *at_H;
879 : :
880 [ - + ]: 21 : if (!nDelta)
881 : : {
882 : 0 : return 0;
883 : : }
884 : : /* add */
885 [ + - ]: 21 : if (nDelta > 0)
886 : : {
887 : 21 : at[at_no].num_H += nDelta;
888 : 21 : t_group_info->tni.nNumRemovedProtons--;
889 : 21 : return nDelta;
890 : : }
891 : : /* remove */
892 : 0 : nNum2Remove = -nDelta;
893 : 0 : nNumRemovedExplicitH = t_group_info->tni.nNumRemovedExplicitH; /* number of explicit H saved separately in
894 : : at[num_atoms+i], i=0..nNumRemovedExplicitH-1 */
895 : 0 : tot_num_iso_H = NUM_ISO_H( at, at_no );
896 : 0 : num_H = at[at_no].num_H;
897 : : /*
898 : : tot_num_iso_H = NUM_ISO_H(at,at_no);
899 : : num_H = at[at_no].num_H;
900 : : nNumAtomExplicitH = 0;
901 : : nNumRemovedExplicitH = t_group_info->tni.nNumRemovedExplicitH;
902 : : tot_num_explicit_iso_H = 0;
903 : : */
904 : :
905 : 0 : at_H = at + num_atoms;
906 : 0 : memcpy(num_iso_H, at[at_no].num_iso_H, sizeof(num_iso_H));
907 : : /* Remove all explicit H, otherwise a false stereo can occur.
908 : : Example: remove H(+) from the following substructure:
909 : :
910 : : H H
911 : : A / A /
912 : : >X==N(+) produces false stereogenic bond: >X==N
913 : : B \ B
914 : : H
915 : :
916 : : To avoid this effect all explicit H atoms must be removed
917 : : */
918 : :
919 : : /* djb-rwth: removing redundant code */
920 [ # # ]: 0 : for (i = 0; i < nNumRemovedExplicitH; )
921 : : {
922 [ # # ]: 0 : if (at_H[i].neighbor[0] == at_no)
923 : : {
924 : 0 : int m, k, orig_no = at_H[i].orig_at_number;
925 : 0 : nNumRemovedExplicitH--;
926 : : /* djb-rwth: removing redundant code */
927 [ # # ]: 0 : if (nNumRemovedExplicitH > i)
928 : : {
929 : 0 : inp_ATOM at_i = at_H[i];
930 : 0 : memmove(at_H + i, at_H + i + 1, sizeof(at_H[0]) * ((long long)nNumRemovedExplicitH - i)); /* djb-rwth: cast operator added */
931 : 0 : at_H[nNumRemovedExplicitH] = at_i; /* save removed H (for debugging purposes?) */
932 : : }
933 : : /* Adjust 0D parities */
934 [ # # ]: 0 : if (at[at_no].sb_parity[0])
935 : : {
936 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[at_no].sb_parity[m]; m++)
937 : : {
938 [ # # ]: 0 : if (at[at_no].sn_orig_at_num[m] == orig_no)
939 : : {
940 [ # # ]: 0 : if (at[at_no].valence >= MIN_NUM_STEREO_BOND_NEIGH)
941 : : {
942 : 0 : at[at_no].sn_ord[m] = k = ( at[at_no].sb_ord[m] == 0 );
943 : 0 : at[at_no].sn_orig_at_num[m] = at[(int) at[at_no].neighbor[k]].orig_at_number;
944 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[at_no].sb_parity[m] ))
945 : : {
946 : 0 : at[at_no].sb_parity[m] = 3 - at[at_no].sb_parity[m];
947 : : }
948 : : }
949 : : else
950 : : {
951 : 0 : at[at_no].sn_ord[m] = -99; /* no sb neighbor exists anymore */
952 : 0 : at[at_no].sn_orig_at_num[m] = 0;
953 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[at_no].sb_parity[m] ))
954 : : {
955 : : int pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
956 [ # # ]: 0 : if (0 < get_opposite_sb_atom( at, at_no, at[at_no].sb_ord[m],
957 : : &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord ))
958 : : {
959 : 0 : at[at_no].sb_parity[m] =
960 : 0 : at[pnxt_atom].sb_parity[pinxt_sb_parity_ord] = AB_PARITY_UNDF;
961 : : }
962 : : }
963 : : }
964 : : }
965 : : }
966 : : }
967 : : /* do not increment i here: we have shifted next at_H[] element
968 : : to the ith position and decremented nNumRemovedExplicitH */
969 : : }
970 : : else
971 : : {
972 : 0 : i++;
973 : : }
974 : : }
975 : :
976 [ # # # # ]: 0 : for (iso = -1; iso < NUM_H_ISOTOPES && 0 < nNum2Remove; iso++)
977 : : {
978 : : /* Each pass removes up to one H */
979 [ # # ]: 0 : if (iso < 0)
980 : : {
981 : : /* Try to remove non-isotopic */
982 [ # # # # ]: 0 : while (tot_num_iso_H < num_H && 0 < nNum2Remove)
983 : : {
984 : : /* Non-isotopic H exists */
985 : 0 : num_H--;
986 : 0 : t_group_info->tni.nNumRemovedProtons++;
987 : 0 : nNum2Remove--;
988 : : }
989 : : }
990 : : else
991 : : {
992 : : /* Remove isotopic */
993 [ # # # # : 0 : while (num_iso_H[iso] && num_H && 0 < nNum2Remove)
# # ]
994 : : {
995 : : /* Isotopic H exists */
996 : 0 : num_H--;
997 : 0 : num_iso_H[iso] --;
998 : 0 : t_group_info->tni.nNumRemovedProtonsIsotopic[iso] ++;
999 : 0 : t_group_info->tni.nNumRemovedProtons++;
1000 : 0 : nNum2Remove--;
1001 : : }
1002 : : }
1003 : : }
1004 : : #if ( bRELEASE_VERSION != 1 )
1005 : : if (nNum2Remove)
1006 : : {
1007 : : int stop = 1; /* <BRKPT> Program error */
1008 : : }
1009 : : #endif
1010 [ # # ]: 0 : if (nDelta + nNum2Remove < 0)
1011 : : {
1012 : 0 : at[at_no].num_H = num_H;
1013 : 0 : memcpy(at[at_no].num_iso_H, num_iso_H, sizeof(at[0].num_iso_H));
1014 : 0 : t_group_info->tni.nNumRemovedExplicitH = nNumRemovedExplicitH;
1015 : : }
1016 : :
1017 : 0 : return nDelta + nNum2Remove;
1018 : : }
1019 : :
1020 : :
1021 : : /****************************************************************************/
1022 : 0 : int SubtractOrChangeAtHChargeBNS( BN_STRUCT *pBNS,
1023 : : inp_ATOM *at,
1024 : : int num_atoms,
1025 : : int nAtTypeTotals[],
1026 : : S_CHAR *mark,
1027 : : T_GROUP_INFO *t_group_info,
1028 : : int bSubtract )
1029 : : {
1030 : 0 : int pass, i, v0, v1, v2, ineigh1, /*ineigh2,*/ vLast, n, delta, ret, err = 0;
1031 : : BNS_EDGE *edge;
1032 : : int nDeltaH, nDeltaCharge;
1033 : : int mask, type; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1034 : :
1035 [ # # ]: 0 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
1036 : : {
1037 : :
1038 : 0 : pBNS->alt_path = pBNS->altp[pass];
1039 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1040 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
1041 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
1042 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1043 : 0 : v0 = v2 = NO_VERTEX;
1044 : :
1045 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2)
1046 : : {
1047 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1048 : : /*ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i);*/ /* v2->v1 neighbor */
1049 : 0 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1050 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
1051 : : t-groups, c-groups or other fictitious edges/vertices
1052 : : */
1053 : 0 : v2 = edge->neighbor12 ^ v1;
1054 [ # # # # : 0 : if (v1 < num_atoms && ( v0 >= num_atoms || v2 >= num_atoms ))
# # ]
1055 : : {
1056 : 0 : nDeltaH = nDeltaCharge = 0;
1057 [ # # ]: 0 : if (v0 >= num_atoms)
1058 : : {
1059 : : /* delta(v0-v1) = -delta(v1-v2) along the alternating path */
1060 [ # # ]: 0 : if (pBNS->vert[v0].type & BNS_VERT_TYPE_TGROUP)
1061 : : {
1062 : 0 : nDeltaH -= delta;
1063 : : }
1064 : : else
1065 : : {
1066 [ # # ]: 0 : if (pBNS->vert[v0].type & BNS_VERT_TYPE_C_GROUP)
1067 : : {
1068 : 0 : nDeltaCharge += delta;
1069 : : }
1070 : : }
1071 : : }
1072 [ # # ]: 0 : if (v2 >= num_atoms)
1073 : : {
1074 [ # # ]: 0 : if (pBNS->vert[v2].type & BNS_VERT_TYPE_TGROUP)
1075 : : {
1076 : 0 : nDeltaH += delta;
1077 : : }
1078 : : else
1079 : : {
1080 [ # # ]: 0 : if (pBNS->vert[v2].type & BNS_VERT_TYPE_C_GROUP)
1081 : : {
1082 : 0 : nDeltaCharge -= delta;
1083 : : }
1084 : : }
1085 : : }
1086 [ # # # # ]: 0 : if (nDeltaH || nDeltaCharge)
1087 : : {
1088 [ # # ]: 0 : if (bSubtract)
1089 : : {
1090 [ # # ]: 0 : if (!mark[v1])
1091 : : {
1092 : : /* first time the atom has been encountered: subtract */
1093 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1094 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
1095 : 0 : type = GetAtomChargeType(at, v1, nAtTypeTotals, &mask, 2);
1096 : : #else
1097 : : type = GetAtomChargeType(at, v1, nAtTypeTotals, &mask, 1);
1098 : : #endif
1099 : 0 : ret++; /* number of changed atoms */
1100 : 0 : mark[v1] ++;
1101 : : }
1102 : : }
1103 : : else
1104 : : {
1105 : : /* Change */
1106 : 0 : at[v1].charge += nDeltaCharge;
1107 [ # # ]: 0 : if (nDeltaH)
1108 : : {
1109 : 0 : AddOrRemoveExplOrImplH( nDeltaH, at, num_atoms, (AT_NUMB) v1, t_group_info );
1110 : : }
1111 : 0 : ret++; /* number of changed atoms */
1112 : : }
1113 : : }
1114 : : }
1115 : : }
1116 : :
1117 [ # # ]: 0 : if (v2 != vLast)
1118 : : {
1119 : 0 : err = BNS_PROGRAM_ERR;
1120 : : }
1121 : : }
1122 : :
1123 [ # # ]: 0 : return err ? err : ret;
1124 : : }
1125 : :
1126 : :
1127 : : /****************************************************************************
1128 : : Set Bonds From BnS Struct Flow
1129 : : ****************************************************************************/
1130 : 38 : int SetBondsFromBnStructFlow( BN_STRUCT *pBNS,
1131 : : inp_ATOM *at,
1132 : : int num_atoms,
1133 : : int bChangeFlow0 )
1134 : : {
1135 : 38 : int pass, i, v0, v1, v2, ineigh1, ineigh2, vLast, n, delta, ret, ret_val, err = 0;
1136 : : BNS_EDGE *edge;
1137 : : int bChangeFlowAdd; /* djb-rwth: removing redundant variables */
1138 : 38 : int bChangeFlow = ( bChangeFlow0 & ~BNS_EF_SET_NOSTEREO );
1139 : : /*
1140 : : bCheckMovingRad = (bChangeFlow & BNS_EF_ALTR_NS) == BNS_EF_ALTR_NS &&
1141 : : pBNS->tot_st_cap > pBNS->tot_st_flow;
1142 : : */
1143 [ + + ]: 76 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
1144 : : {
1145 : 38 : pBNS->alt_path = pBNS->altp[pass];
1146 : 38 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1147 : 38 : n = ALTP_PATH_LEN( pBNS->alt_path );
1148 : 38 : delta = ALTP_DELTA( pBNS->alt_path );
1149 : 38 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1150 [ - + ]: 38 : if (( bChangeFlow0 & BNS_EF_SET_NOSTEREO ) &&
1151 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.cap0 > pBNS->vert[v1].st_edge.flow0 ||
1152 [ # # ]: 0 : pBNS->vert[vLast].st_edge.cap0 > pBNS->vert[vLast].st_edge.flow0 ))
1153 : : {
1154 : : /* djb-rwth: removing redundant code */
1155 : 0 : bChangeFlowAdd = BNS_EF_SET_NOSTEREO;
1156 : 0 : ret |= 2;
1157 : : }
1158 : : else
1159 : : {
1160 : 38 : bChangeFlowAdd = 0;
1161 : : }
1162 : : /* start vertex */
1163 [ - + ]: 38 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1164 : : {
1165 : : /* Restore s-v1 edge flow to the BNS this pass input value */
1166 : : ; /*pBNS->vert[v1].st_edge.flow -= delta;*/
1167 : : }
1168 : : else
1169 : : {
1170 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1171 : : {
1172 [ # # ]: 0 : if (v1 < num_atoms)
1173 : : {
1174 : : /* Will produce wrong result if called for v1 next time? */
1175 : 0 : ret_val = SetAtomRadAndChemValFromVertexCapFlow( pBNS, at, v1 );
1176 [ # # ]: 0 : if (ret_val < 0)
1177 : : {
1178 : 0 : err = BNS_PROGRAM_ERR;
1179 : : }
1180 : : else
1181 : : {
1182 : 0 : ret |= ( ret_val > 0 );
1183 : : }
1184 : : }
1185 : : /*pBNS->vert[v1].st_edge.flow0 = pBNS->vert[v1].st_edge.flow;*/
1186 : : }
1187 : : }
1188 : :
1189 : 38 : pBNS->vert[v1].st_edge.pass = 0;
1190 : :
1191 : 38 : v0 = v2 = NO_VERTEX;
1192 [ + + ]: 142 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2)
1193 : : {
1194 : 104 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1195 : 104 : ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v2->v1 neighbor */
1196 : 104 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1197 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
1198 : : t-groups, c-groups or other fictitious edges/vertices
1199 : : */
1200 : :
1201 : 104 : v2 = edge->neighbor12 ^ v1;
1202 : :
1203 : : /* change at->chem_bonds_valence 2004-03-08 */
1204 [ - + - - ]: 104 : if (( bChangeFlow & BNS_EF_CHNG_BONDS ) && v1 < num_atoms)
1205 : : {
1206 [ # # # # ]: 0 : if (v0 >= num_atoms && v2 < num_atoms)
1207 : : {
1208 : 0 : at[v1].chem_bonds_valence += delta; /* change in v1-v2 bond order */
1209 : : }
1210 : : else
1211 : : {
1212 [ # # # # : 0 : if (v0 < num_atoms && v2 >= num_atoms && v0 != NO_VERTEX)
# # ]
1213 : : {
1214 : 0 : at[v1].chem_bonds_valence -= delta; /* change in v0-v1 bond order */
1215 : : }
1216 : : }
1217 : : }
1218 : :
1219 [ - + ]: 104 : if (!edge->pass)
1220 : : {
1221 : 0 : continue;
1222 : : }
1223 : :
1224 [ + + + + : 104 : if (v1 < num_atoms && ineigh1 < at[v1].valence &&
+ - ]
1225 [ + - ]: 63 : v2 < num_atoms && ineigh2 < at[v2].valence)
1226 : : {
1227 [ - + ]: 63 : if (( bChangeFlow0 & BNS_EF_ALTR_NS ) == BNS_EF_ALTR_NS &&
1228 [ # # ]: 0 : ( bChangeFlow0 & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1229 : : {
1230 : : /* 2004-07-02 special mode: save new ring bonds and mark as non-stereo non-ring bonds */
1231 [ # # ]: 0 : if (at[v1].nRingSystem != at[v2].nRingSystem)
1232 : : {
1233 : : /* Non-ring bond (bridge) */
1234 : 0 : bChangeFlowAdd = BNS_EF_ALTR_NS;
1235 : : }
1236 : : else
1237 : : {
1238 : : /* Ring bond */
1239 : 0 : bChangeFlowAdd = 0;
1240 : : }
1241 : : }
1242 : : /* Change bonds on the first pass only: in this case all flow correspond to the BNS output */
1243 : 63 : ret_val = SetAtomBondType( edge, &at[v1].bond_type[ineigh1], &at[v2].bond_type[ineigh2], delta, bChangeFlow | bChangeFlowAdd );
1244 [ - + ]: 63 : if (ret_val < 0)
1245 : : {
1246 : 0 : err = BNS_PROGRAM_ERR;
1247 : : }
1248 : : else
1249 : : {
1250 : 63 : ret |= ( ret_val > 0 );
1251 : : }
1252 : : }
1253 : 104 : edge->pass = 0;
1254 : : }
1255 : :
1256 [ - + ]: 38 : if (v2 != vLast)
1257 : : {
1258 : 0 : err = BNS_PROGRAM_ERR;
1259 : : }
1260 : : else
1261 : : {
1262 [ - + ]: 38 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1263 : : {
1264 : : /* Restore v2-t edge flow to the BNS this pass input value */
1265 : : /* "+=" instead of "-=" explanation: delta must have same sign as at the last edge */
1266 : : ; /*pBNS->vert[v2].st_edge.flow += delta; */
1267 : : }
1268 : : else
1269 : : {
1270 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1271 : : {
1272 [ # # ]: 0 : if (v2 < num_atoms)
1273 : : {
1274 : 0 : ret_val = SetAtomRadAndChemValFromVertexCapFlow( pBNS, at, v2 );
1275 [ # # ]: 0 : if (ret_val < 0)
1276 : : {
1277 : 0 : err = BNS_PROGRAM_ERR;
1278 : : }
1279 : : else
1280 : : {
1281 : 0 : ret |= ( ret_val > 0 );
1282 : : }
1283 : : }
1284 : : /*pBNS->vert[v2].st_edge.flow0 = pBNS->vert[v2].st_edge.flow;*/
1285 : : }
1286 : : }
1287 : : }
1288 : 38 : pBNS->vert[v2].st_edge.pass = 0;
1289 : : }
1290 : :
1291 [ - + ]: 38 : return err ? err : ret;
1292 : : }
1293 : :
1294 : :
1295 : : /****************************************************************************/
1296 : 0 : int MarkAtomsAtTautGroups( BN_STRUCT *pBNS,
1297 : : int num_atoms,
1298 : : BN_AATG *pAATG,
1299 : : int nEnd1,
1300 : : int nEnd2 )
1301 : : {
1302 : 0 : int pass, i, j, v1, v2, ineigh1, ineigh2, vLast, vFirst, n, delta, err = 0; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1303 : : BNS_EDGE *edge;
1304 : : S_CHAR cDelta[MAX_ALT_AATG_ARRAY_LEN];
1305 : : AT_NUMB nVertex[MAX_ALT_AATG_ARRAY_LEN];
1306 : 0 : int nLenDelta = 0, last_i, nNumFound;
1307 : :
1308 [ # # ]: 0 : for (pass = pBNS->num_altp - 1; 0 <= pass; pass--)
1309 : : {
1310 : 0 : pBNS->alt_path = pBNS->altp[pass];
1311 : 0 : vFirst =
1312 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1313 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
1314 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
1315 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1316 : 0 : v2 = NO_VERTEX;
1317 : 0 : pAATG->nNumFound = 0; /* initialize */
1318 : :
1319 [ # # # # ]: 0 : if (nEnd1 != vFirst && nEnd1 != vLast)
1320 : : {
1321 : 0 : nEnd1 = -1; /* really not the end */
1322 : : }
1323 [ # # # # ]: 0 : if (nEnd2 != vFirst && nEnd2 != vLast)
1324 : : {
1325 : 0 : nEnd2 = -1; /* really not the end */
1326 : : }
1327 : :
1328 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v1 = v2)
1329 : : {
1330 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1331 : 0 : ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i); /* v2->v1 neighbor */ /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1332 : 0 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1333 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
1334 : : t-groups, c-groups or other fictitious edges/vertices
1335 : : */
1336 : 0 : v2 = edge->neighbor12 ^ v1;
1337 : : /*
1338 : : if ( v1 < num_atoms && v2 < num_atoms ) {
1339 : : continue;
1340 : : }
1341 : : */
1342 : : /* BNS increased edge flow by delta */
1343 [ # # ]: 0 : if (v1 >= num_atoms &&
1344 [ # # # # : 0 : ( ( pBNS->vert[v1].type & BNS_VERT_TYPE_TGROUP ) || ( pBNS->vert[v1].type & BNS_VERT_TYPE_TEMP ) ) &&
# # ]
1345 [ # # # # ]: 0 : 0 <= v2 && v2 < num_atoms && ( pBNS->vert[v2].type & BNS_VERT_TYPE_ATOM ))
1346 : : {
1347 : : /*
1348 : : if ( !(pAATG->nMarkedAtom[v2] & AATG_MARK_IN_PATH) ) {
1349 : : pAATG->nMarkedAtom[v2] |= AATG_MARK_IN_PATH;
1350 : : pAATG->nNumFound ++;
1351 : : }
1352 : : */
1353 : :
1354 : : /* BNS increased bond order in v1(t-group)-v2(atom) by delta: added delta attachments */
1355 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1356 : : {
1357 : 0 : cDelta[nLenDelta] = delta;
1358 : 0 : nVertex[nLenDelta] = v2;
1359 : 0 : nLenDelta++;
1360 : : }
1361 : : }
1362 : : else
1363 : : {
1364 [ # # ]: 0 : if (v2 >= num_atoms &&
1365 [ # # # # : 0 : ( ( pBNS->vert[v2].type & BNS_VERT_TYPE_TGROUP ) || ( pBNS->vert[v2].type & BNS_VERT_TYPE_TEMP ) ) &&
# # ]
1366 [ # # # # ]: 0 : 0 <= v1 && v1 < num_atoms && ( pBNS->vert[v1].type & BNS_VERT_TYPE_ATOM ))
1367 : : {
1368 : : /*
1369 : : if ( !(pAATG->nMarkedAtom[v1] & AATG_MARK_IN_PATH) ) {
1370 : : pAATG->nMarkedAtom[v1] |= AATG_MARK_IN_PATH;
1371 : : pAATG->nNumFound ++;
1372 : : }
1373 : : */
1374 : :
1375 : : /* BNS increased bond order in v1(atom)-v2(t-group) by delta: added delta attachments */
1376 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1377 : : {
1378 : 0 : cDelta[nLenDelta] = delta;
1379 : 0 : nVertex[nLenDelta] = v1;
1380 : 0 : nLenDelta++;
1381 : : }
1382 : : }
1383 : : else
1384 : : {
1385 : : /* Special case when the testing 'dot' was placed on an atom (should be nEnd1 only) */
1386 [ # # # # : 0 : if ((0 <= v1 && v1 == nEnd1) || (v1 == nEnd2 && 0 <= v2 && v2 < num_atoms)) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
1387 : : {
1388 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1389 : : {
1390 : 0 : cDelta[nLenDelta] = -delta;
1391 : 0 : nVertex[nLenDelta] = v1;
1392 : 0 : nLenDelta++;
1393 : : }
1394 : : }
1395 : : else
1396 : : {
1397 [ # # # # : 0 : if ((0 <= v2 && v2 == nEnd1) || (v2 == nEnd2 && 0 <= v1 && v1 < num_atoms)) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
1398 : : {
1399 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1400 : : {
1401 : 0 : cDelta[nLenDelta] = -delta;
1402 : 0 : nVertex[nLenDelta] = v2;
1403 : 0 : nLenDelta++;
1404 : : }
1405 : : }
1406 : : }
1407 : : }
1408 : : }
1409 : : }
1410 : :
1411 [ # # ]: 0 : if (v2 != vLast)
1412 : : {
1413 : 0 : err = BNS_PROGRAM_ERR;
1414 : : }
1415 : : else
1416 : : {
1417 : 0 : last_i = -1;
1418 : 0 : nNumFound = 0;
1419 : : /* first run */
1420 [ # # ]: 0 : for (i = 1, j = 0; i < nLenDelta; j = i++)
1421 : : {
1422 : : /* Ignore sequences (-1,+1) and (+1,-1) in cDelta[] because they */
1423 : : /* describe ordinary aug. paths of moving a single attachment */
1424 : : /* we are looking for aug. paths describing movement of 2 or more */
1425 [ # # # # ]: 0 : if ((cDelta[j] > 0 && cDelta[i] > 0) ||
1426 [ # # # # ]: 0 : (cDelta[j] < 0 && cDelta[i] < 0)) /* djb-rwth: addressing LLVM warning */
1427 : : {
1428 [ # # ]: 0 : if (j == last_i)
1429 : : {
1430 : : /* Three attachments moved */
1431 : 0 : return 0;
1432 : : }
1433 : 0 : v1 = nVertex[j];
1434 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v1] & AATG_MARK_IN_PATH ))
1435 : : {
1436 : 0 : nNumFound++;
1437 : : }
1438 : 0 : v2 = nVertex[i];
1439 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v2] & AATG_MARK_IN_PATH ))
1440 : : {
1441 : 0 : nNumFound++;
1442 : : }
1443 : 0 : last_i = i;
1444 : : }
1445 : : }
1446 [ # # ]: 0 : if (!nNumFound)
1447 : : {
1448 : 0 : return 0;
1449 : : }
1450 [ # # ]: 0 : if (nNumFound > 4)
1451 : : {
1452 : 0 : return 0;
1453 : : }
1454 [ # # ]: 0 : if (nNumFound < 4)
1455 : : {
1456 : 0 : return 0;
1457 : : }
1458 : :
1459 : : /* Second run */
1460 [ # # ]: 0 : for (i = 1, j = 0; i < nLenDelta; j = i++)
1461 : : {
1462 : : /* Ignore sequences (-1,+1) and (+1,-1) in cDelta[] because they */
1463 : : /* describe ordinary aug. paths of moving a single attachment */
1464 : : /* we are looking for aug. paths describing movement of 2 or more */
1465 [ # # # # ]: 0 : if ((cDelta[j] > 0 && cDelta[i] > 0) ||
1466 [ # # # # ]: 0 : (cDelta[j] < 0 && cDelta[i] < 0)) /* djb-rwth: addressing LLVM warning */
1467 : : {
1468 : 0 : v1 = nVertex[i - 1];
1469 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v1] & AATG_MARK_IN_PATH ))
1470 : : {
1471 : 0 : pAATG->nMarkedAtom[v1] |= AATG_MARK_IN_PATH;
1472 : 0 : pAATG->nNumFound++;
1473 : : }
1474 : 0 : v2 = nVertex[i];
1475 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v2] & AATG_MARK_IN_PATH ))
1476 : : {
1477 : 0 : pAATG->nMarkedAtom[v2] |= AATG_MARK_IN_PATH;
1478 : 0 : pAATG->nNumFound++;
1479 : : }
1480 : : }
1481 : : }
1482 : : }
1483 : : }
1484 : :
1485 [ # # ]: 0 : return err ? err : pAATG->nNumFound;
1486 : : }
1487 : :
1488 : :
1489 : : /****************************************************************************/
1490 : 38 : int RestoreBnStructFlow( BN_STRUCT *pBNS, int bChangeFlow )
1491 : : {
1492 : 38 : int pass, i, v1, v2, ineigh1, ineigh2, vLast, n, delta, ret, err = 0; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1493 : : BNS_EDGE *edge;
1494 : :
1495 [ + + ]: 76 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
1496 : : {
1497 : 38 : pBNS->alt_path = pBNS->altp[pass];
1498 : 38 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1499 : 38 : n = ALTP_PATH_LEN( pBNS->alt_path );
1500 : 38 : delta = ALTP_DELTA( pBNS->alt_path );
1501 : 38 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1502 : 38 : v2 = NO_VERTEX;
1503 : : /* starting vertex */
1504 [ + - ]: 38 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1505 : : {
1506 : 38 : pBNS->vert[v1].st_edge.flow -= delta; /* restore s-v1 edge flow to the BNS input value */
1507 : : }
1508 : : else
1509 : : {
1510 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1511 : : {
1512 : 0 : pBNS->vert[v1].st_edge.flow0 = pBNS->vert[v1].st_edge.flow;
1513 : : }
1514 : : }
1515 : :
1516 : : /* Augmenting path edges */
1517 [ + + ]: 142 : for (i = 0; i < n; i++, delta = -delta, v1 = v2)
1518 : : {
1519 : 104 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1520 : 104 : ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i); /* v2->v1 neighbor */ /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1521 : 104 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1522 : 104 : v2 = edge->neighbor12 ^ v1;
1523 : 104 : RestoreEdgeFlow( edge, delta, bChangeFlow );
1524 : 104 : edge->pass = 0;
1525 : : }
1526 : :
1527 : : /* Ending vertex */
1528 [ - + ]: 38 : if (v2 != vLast)
1529 : : {
1530 : 0 : err = BNS_PROGRAM_ERR;
1531 : : }
1532 : : else
1533 : : {
1534 [ + - ]: 38 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1535 : : {
1536 : : /* Restore v2-t edge flow to the original value */
1537 : : /* "+=" instead of "-=" explanation: delta must have same sign as at the last edge */
1538 : 38 : pBNS->vert[v2].st_edge.flow += delta;
1539 : : }
1540 : : else
1541 : : {
1542 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1543 : : {
1544 : 0 : pBNS->vert[v2].st_edge.flow0 = pBNS->vert[v2].st_edge.flow;
1545 : : }
1546 : : }
1547 : : }
1548 : : }
1549 : :
1550 [ - + ]: 38 : return err ? err : ret;
1551 : : }
1552 : :
1553 : :
1554 : : /****************************************************************************/
1555 : 75 : int bNeedToTestTheFlow( int bond_type,
1556 : : int nTestFlow,
1557 : : int bTestForNonStereoBond )
1558 : : {
1559 : 75 : int nBondType = ( BOND_TYPE_MASK & bond_type );
1560 : 75 : int nBondAttrib = ( BOND_MARK_MASK & bond_type );
1561 : :
1562 [ - + ]: 75 : if (bTestForNonStereoBond)
1563 : : {
1564 [ # # # # : 0 : if (nBondAttrib || nBondType == BOND_ALTERN || nBondType == BOND_ALT12NS)
# # ]
1565 : : {
1566 [ # # # # ]: 0 : switch (nTestFlow)
1567 : : {
1568 : 0 : case 0: /* single: can be 1 (single)? */
1569 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT12NS ||
1570 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1571 : : nBondAttrib == BOND_MARK_ALT13)
1572 : : {
1573 : 0 : return 0; /* yes, already checked */
1574 : : }
1575 : 0 : break;
1576 : :
1577 : 0 : case 1: /* double: can be 2 (double)? */
1578 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT12NS ||
1579 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1580 : : nBondAttrib == BOND_MARK_ALT23)
1581 : : {
1582 : 0 : return 0; /* yes, already checked */
1583 : : }
1584 : 0 : break;
1585 : 0 : case 2: /* triple: can be 3 (triple)? */
1586 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT13 ||
1587 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1588 : : nBondAttrib == BOND_MARK_ALT23)
1589 : : {
1590 : 0 : return 0; /* yes, already checked */
1591 : : }
1592 : 0 : break;
1593 : : }
1594 : : }
1595 : : }
1596 : : else
1597 : : {
1598 [ + + + - : 75 : if (nBondAttrib || nBondType == BOND_ALTERN || nBondType == BOND_ALT12NS)
- + ]
1599 : : {
1600 [ + + - - ]: 42 : switch (nTestFlow)
1601 : : {
1602 : 21 : case 0: /* single: can be 1 (single)? */
1603 [ + + - + ]: 21 : if (nBondAttrib == BOND_MARK_ALT12 ||
1604 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT12NS ||
1605 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1606 : : nBondAttrib == BOND_MARK_ALT13)
1607 : : {
1608 : 21 : return 0;
1609 : : }
1610 : 0 : break;
1611 : :
1612 : 21 : case 1: /* double: can be 2 (double)? */
1613 [ + + - + ]: 21 : if (nBondAttrib == BOND_MARK_ALT12 ||
1614 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT12NS ||
1615 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1616 : : nBondAttrib == BOND_MARK_ALT23)
1617 : : {
1618 : 21 : return 0; /* yes */
1619 : : }
1620 : 0 : break;
1621 : 0 : case 2: /* triple: can be 3 (triple)? */
1622 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT13 ||
1623 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1624 : : nBondAttrib == BOND_MARK_ALT23)
1625 : : {
1626 : 0 : return 0;
1627 : : }
1628 : 0 : break;
1629 : : }
1630 : : }
1631 : : }
1632 : :
1633 : 33 : return 1;
1634 : : }
1635 : :
1636 : :
1637 : : /****************************************************************************/
1638 : 2424 : int nBondsValenceInpAt( const inp_ATOM *at,
1639 : : int *nNumAltBonds,
1640 : : int *nNumWrongBonds )
1641 : : {
1642 : 2424 : int j, bond_type, nBondsValence = 0, nAltBonds = 0, nNumWrong = 0;
1643 [ + + ]: 6622 : for (j = 0; j < at->valence; j++)
1644 : : {
1645 : 4198 : bond_type = at->bond_type[j] & BOND_TYPE_MASK;
1646 [ + - + ]: 4198 : switch (bond_type)
1647 : : {
1648 : 4106 : case 0: /* for structure from InChI reconstruction */
1649 : : case BOND_SINGLE:
1650 : : case BOND_DOUBLE:
1651 : : case BOND_TRIPLE:
1652 : 4106 : nBondsValence += bond_type;
1653 : 4106 : break;
1654 : 0 : case BOND_ALTERN:
1655 : 0 : nAltBonds++;
1656 : 0 : break;
1657 : 92 : default:
1658 : 92 : nNumWrong++;
1659 : : }
1660 : : }
1661 [ + - - ]: 2424 : switch (nAltBonds)
1662 : : {
1663 : 2424 : case 0:
1664 : 2424 : break;
1665 : 0 : case 1:
1666 : 0 : nBondsValence += 1; /* 1 or greater than 3 is wrong */
1667 : 0 : nNumWrong++;
1668 : 0 : break;
1669 : 0 : default:
1670 : 0 : nBondsValence += nAltBonds + 1;
1671 : 0 : break;
1672 : : }
1673 [ + + ]: 2424 : if (nNumAltBonds)
1674 : : {
1675 : 810 : *nNumAltBonds = nAltBonds;
1676 : : }
1677 [ + + ]: 2424 : if (nNumWrongBonds)
1678 : : {
1679 : 810 : *nNumWrongBonds = nNumWrong;
1680 : : }
1681 : :
1682 : 2424 : return nBondsValence;
1683 : : }
1684 : :
1685 : :
1686 : : /****************************************************************************
1687 : : If radical or has aromatic bonds,
1688 : : then augment to the lowest "multiplicity"
1689 : : ****************************************************************************/
1690 : 161 : int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS,
1691 : : BN_DATA *pBD,
1692 : : inp_ATOM *at,
1693 : : int num_atoms )
1694 : : {
1695 : 161 : int bError = 0, nOrigDelta = 0, ret, num_removed;
1696 : :
1697 : : #if( CHECK_AROMBOND2ALT == 1 )
1698 : 161 : int *pcValMinusBondsVal = NULL;
1699 : : int i, nValMinusBondsVal, nAltBonds, bIgnore, valen, is_rad, excess;
1700 : :
1701 : : /* Find valence excess (it may only be due to aromatic bonds) */
1702 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1703 : : {
1704 : 810 : valen = nBondsValenceInpAt( at + i, &nAltBonds, &bIgnore );
1705 : 810 : nValMinusBondsVal = (int) at[i].chem_bonds_valence - valen;
1706 : 810 : bIgnore += ( nAltBonds > 3 );
1707 [ + - - + ]: 810 : if (!bIgnore && nValMinusBondsVal > 0)
1708 : : {
1709 [ # # ]: 0 : if (!pcValMinusBondsVal &&
1710 [ # # ]: 0 : !( pcValMinusBondsVal = (int *) inchi_calloc( num_atoms, sizeof( pcValMinusBondsVal[0] ) ) ))
1711 : : {
1712 : 0 : bError = BNS_OUT_OF_RAM;
1713 : 0 : goto exit_function;
1714 : : }
1715 : : /* Mark atoms that have extra unsatisfied valence due to aromatic bonds */
1716 : 0 : is_rad = ( at[i].radical == RADICAL_DOUBLET );
1717 : 0 : excess = nValMinusBondsVal + is_rad;
1718 : 0 : pcValMinusBondsVal[i] = excess;
1719 : : }
1720 : : }
1721 : : #endif /* CHECK_AROMBOND2ALT */
1722 : :
1723 : : /* Match bonds to valences */
1724 : : do
1725 : : {
1726 : 161 : num_removed = 0;
1727 : 161 : ret = RunBalancedNetworkSearch( pBNS, pBD, BNS_EF_CHNG_FLOW );
1728 [ + - - + ]: 161 : if (IS_BNS_ERROR( ret ))
1729 : : {
1730 : 0 : bError = ret;
1731 : : }
1732 : : else
1733 : : {
1734 : 161 : nOrigDelta += ret;
1735 : 161 : num_removed = pBNS->num_altp; /* number of augmenting paths */
1736 [ - + ]: 161 : if (ret > 0)
1737 : : {
1738 : : /* save new bonds in at[] and flows in pBNS and at[] */
1739 : 0 : ret = SetBondsFromBnStructFlow( pBNS, at, num_atoms, BNS_EF_SAVE_ALL ); /* must include 1: 5=(4|1) */
1740 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
1741 : : {
1742 : 0 : bError = ret;
1743 : : }
1744 : 0 : ret = RestoreBnStructFlow( pBNS, BNS_EF_SAVE_ALL ); /* must include 1: 5=(4|1) */
1745 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
1746 : : {
1747 : 0 : bError = ret;
1748 : : }
1749 : : }
1750 : 161 : ReInitBnStructAltPaths( pBNS );
1751 : : }
1752 [ - + - - : 161 : } while (num_removed && num_removed == pBNS->max_altp && !bError);
- - ]
1753 : :
1754 : : #if( CHECK_AROMBOND2ALT == 1 )
1755 : : /* Check whether aromatic bonds have been replaced with alternating bonds */
1756 [ - + + - ]: 161 : if (!bError && pcValMinusBondsVal)
1757 : : {
1758 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1759 : : {
1760 [ # # ]: 0 : if (!pcValMinusBondsVal[i])
1761 : : {
1762 : 0 : continue;
1763 : : }
1764 : 0 : valen = nBondsValenceInpAt( at + i, &nAltBonds, &bIgnore );
1765 : 0 : nValMinusBondsVal = (int) at[i].chem_bonds_valence - valen;
1766 : 0 : is_rad = ( at[i].radical == RADICAL_DOUBLET );
1767 : 0 : excess = nValMinusBondsVal + is_rad;
1768 [ # # ]: 0 : if (bIgnore ||
1769 [ # # ]: 0 : ( pcValMinusBondsVal[i] - excess ) != 1)
1770 : : {
1771 : : /* radical excess has not been reduced */
1772 : 0 : bError = BNS_ALTBOND_ERR;
1773 : 0 : break;
1774 : : }
1775 : : }
1776 : : }
1777 : :
1778 : 161 : exit_function:
1779 [ - + ]: 161 : if (pcValMinusBondsVal)
1780 : : {
1781 [ # # ]: 0 : inchi_free( pcValMinusBondsVal );
1782 : : }
1783 : : #endif /* CHECK_AROMBOND2ALT */
1784 : :
1785 [ - + ]: 161 : return bError ? bError : nOrigDelta;
1786 : : }
1787 : :
1788 : :
1789 : : /****************************************************************************/
1790 : 168 : int BnsTestAndMarkAltBonds( BN_STRUCT *pBNS,
1791 : : BN_DATA *pBD,
1792 : : inp_ATOM *at,
1793 : : int num_atoms,
1794 : : BNS_FLOW_CHANGES *fcd,
1795 : : int bChangeFlow,
1796 : : int nBondTypeToTest )
1797 : : {
1798 : : int ret, iat, ineigh, neigh;
1799 : : int nMinFlow, nMaxFlow, nTestFlow, nCurFlow;
1800 : : int iedge, bError, nDots, nChanges, bTestForNonStereoBond; /* djb-rwth: removing redundant variables */
1801 : :
1802 : : /* Normalize bonds and find tautomeric groups */
1803 : 168 : bError = 0;
1804 : 168 : nChanges = 0;
1805 : 168 : bTestForNonStereoBond = pBNS->tot_st_cap > pBNS->tot_st_flow;
1806 : :
1807 [ + + + - ]: 1022 : for (iat = 0; iat < num_atoms && !bError; iat++)
1808 : : {
1809 [ + + + - ]: 2278 : for (ineigh = 0; ineigh < at[iat].valence && !bError; ineigh++)
1810 : : {
1811 : 1424 : neigh = at[iat].neighbor[ineigh];
1812 [ + + ]: 1424 : if (neigh < iat)
1813 : : {
1814 : 712 : continue; /* we have already tested the bond */
1815 : : }
1816 : 712 : iedge = pBNS->vert[iat].iedge[ineigh];
1817 [ + + ]: 712 : if (IS_FORBIDDEN( pBNS->edge[iedge].forbidden, pBNS ))
1818 : : {
1819 : 18 : continue;
1820 : : }
1821 [ - + - - ]: 694 : if (nBondTypeToTest && ( at[iat].bond_type[ineigh] & BOND_TYPE_MASK ) != nBondTypeToTest)
1822 : : {
1823 : 0 : continue;
1824 : : }
1825 : 694 : nMinFlow = nMinFlow2Check( pBNS, iedge );
1826 : 694 : nMaxFlow = nMaxFlow2Check( pBNS, iedge );
1827 : 694 : nCurFlow = nCurFlow2Check( pBNS, iedge );
1828 [ + + ]: 694 : if (nMinFlow == nMaxFlow)
1829 : : {
1830 [ + + - + ]: 619 : if (nMaxFlow && bTestForNonStereoBond)
1831 : : {
1832 : 0 : nTestFlow = nMaxFlow - (int) ( pBNS->tot_st_cap - pBNS->tot_st_flow ); /* temporary use of nTestFlow */
1833 : 0 : nMinFlow = inchi_max( 0, nTestFlow );
1834 : : }
1835 : : else
1836 : : {
1837 : 619 : continue;
1838 : : }
1839 : : }
1840 [ + + + - ]: 225 : for (nTestFlow = nMinFlow; nTestFlow <= nMaxFlow && !bError; nTestFlow++)
1841 : : {
1842 [ + + ]: 150 : if (nTestFlow == nCurFlow)
1843 : : {
1844 : 75 : continue;
1845 : : }
1846 [ + + ]: 75 : if (!bNeedToTestTheFlow( at[iat].bond_type[ineigh], nTestFlow, bTestForNonStereoBond ))
1847 : : {
1848 : 42 : continue;
1849 : : }
1850 : : /* djb-rwth: removing redundant code */
1851 : 33 : nDots = bSetFlowToCheckOneBond( pBNS, iedge, nTestFlow, fcd );
1852 : :
1853 [ + - - + ]: 33 : if (IS_BNS_ERROR( nDots ))
1854 : : {
1855 [ # # ]: 0 : if (nDots == BNS_CANT_SET_BOND)
1856 : : {
1857 : 0 : ret = bRestoreFlowAfterCheckOneBond( pBNS, fcd );
1858 [ # # # # ]: 0 : if (!IS_BNS_ERROR( ret ))
1859 : : {
1860 : 0 : continue;
1861 : : }
1862 : : }
1863 : 0 : bError = nDots;
1864 : : }
1865 : : else
1866 : : {
1867 [ + - ]: 33 : if (nDots > 0)
1868 : : {
1869 : 33 : ret = RunBalancedNetworkSearch( pBNS, pBD, bChangeFlow );
1870 [ + - - + ]: 33 : if (IS_BNS_ERROR( ret ))
1871 : : {
1872 : 0 : bError = ret;
1873 : : }
1874 : : else
1875 : : {
1876 [ + + ]: 33 : if (ret > 0)
1877 : : {
1878 [ + - ]: 22 : if (2 * ret == nDots)
1879 : : {
1880 : 22 : ret = bSetBondsAfterCheckOneBond( pBNS, fcd, nTestFlow, at, num_atoms, bChangeFlow );
1881 [ + - - + ]: 22 : if (IS_BNS_ERROR( ret ))
1882 : : {
1883 : 0 : bError = ret;
1884 : : }
1885 : : else
1886 : : {
1887 : 22 : nChanges += ( ret & 1 );
1888 : 22 : ret = SetBondsFromBnStructFlow( pBNS, at, num_atoms, bChangeFlow );
1889 [ + - - + ]: 22 : if (IS_BNS_ERROR( ret ))
1890 : : {
1891 : 0 : bError = ret;
1892 : : }
1893 : : else
1894 : : {
1895 [ + - ]: 22 : if (ret >= 0)
1896 : : {
1897 : 22 : nChanges += ( ret & 1 );
1898 : : /* djb-rwth: removing redundant code */
1899 : : }
1900 : : else
1901 : : {
1902 : 0 : bError = ret;
1903 : : }
1904 : : }
1905 : : }
1906 : : }
1907 : : /* typically 2*ret < nDots; 2*ret > nDots should not happen. Check later */
1908 : 22 : ret = RestoreBnStructFlow( pBNS, bChangeFlow & BNS_EF_CHNG_RSTR );
1909 [ + - - + ]: 22 : if (IS_BNS_ERROR( ret ))
1910 : : {
1911 : 0 : bError = ret;
1912 : : }
1913 : : }
1914 : : }
1915 : : /* --- Reinitialize to repeat the calculations --- */
1916 : 33 : ReInitBnStructAltPaths( pBNS );
1917 : : }
1918 : :
1919 : : else
1920 : : {
1921 [ # # ]: 0 : if (nDots == 0)
1922 : : {
1923 : 0 : ret = bSetBondsAfterCheckOneBond( pBNS, fcd, nTestFlow, at, num_atoms, bChangeFlow );
1924 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
1925 : : {
1926 : 0 : bError = ret;
1927 : : }
1928 : : else
1929 : : {
1930 : 0 : nChanges += ( ret & 1 );
1931 : : }
1932 : : }
1933 : : }
1934 : : }
1935 : :
1936 : 33 : ret = bRestoreFlowAfterCheckOneBond( pBNS, fcd );
1937 : :
1938 [ + - - + ]: 33 : if (IS_BNS_ERROR( ret ))
1939 : : {
1940 : 0 : bError = ret;
1941 : : }
1942 : :
1943 : : } /* for (nTestFlow = */
1944 : : } /* for (ineigh = */
1945 : : } /* for (iat = */
1946 : :
1947 [ - + ]: 168 : return bError ? bError : nChanges;
1948 : : }
1949 : :
1950 : :
1951 : : /****************************************************************************/
1952 : 161 : static void remove_alt_bond_marks( inp_ATOM *at, int num_atoms )
1953 : : {
1954 : : int i, j, val;
1955 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1956 : : {
1957 [ + + ]: 2160 : for (val = at[i].valence, j = 0; j < val; j++)
1958 : : {
1959 : 1350 : at[i].bond_type[j] &= BOND_TYPE_MASK;
1960 : : }
1961 : : }
1962 : :
1963 : 161 : }
1964 : :
1965 : :
1966 : : /****************************************************************************/
1967 : 161 : int SetForbiddenEdges( BN_STRUCT *pBNS,
1968 : : inp_ATOM *at,
1969 : : int num_atoms,
1970 : : int forbidden_mask,
1971 : : int nebend,
1972 : : int *ebend )
1973 : : {
1974 : :
1975 : :
1976 : : int i, j, neigh, num_found;
1977 : : BNS_IEDGE iedge;
1978 : : /*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
1979 : 161 : S_CHAR edge_forbidden_mask = forbidden_mask;
1980 : :
1981 : 161 : pBNS->edge_forbidden_mask |= forbidden_mask;
1982 : :
1983 : 161 : num_found = 0;
1984 : :
1985 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
1986 : : {
1987 : : /* acetyl */
1988 [ + + + + ]: 810 : if (at[i].el_number == EL_NUMBER_C && 3 == at[i].valence &&
1989 [ + + ]: 237 : 4 == at[i].chem_bonds_valence)
1990 : 36 : {
1991 : 36 : int num_O = 0;
1992 : 36 : int bond_to_O_val = 0;
1993 : 36 : int forbidden_bond_pos = -1;
1994 : 36 : int forbidden_bond_val = -1;
1995 [ + + ]: 144 : for (j = 0; j < at[i].valence; j++)
1996 : : {
1997 : 108 : neigh = at[i].neighbor[j];
1998 [ + + ]: 108 : if (at[neigh].el_number == EL_NUMBER_O &&
1999 [ + + ]: 36 : at[neigh].valence == 1)
2000 : : {
2001 : 28 : num_O++;
2002 : 28 : bond_to_O_val += ( at[i].bond_type[j] & BOND_TYPE_MASK );
2003 : : }
2004 : : else
2005 : : {
2006 : 80 : forbidden_bond_pos = j;
2007 : 80 : forbidden_bond_val = ( at[i].bond_type[j] & BOND_TYPE_MASK );
2008 : : }
2009 : : }
2010 [ + + + - : 36 : if (2 == num_O && 3 == bond_to_O_val && 1 == forbidden_bond_val)
+ - ]
2011 : : {
2012 : 10 : iedge = pBNS->vert[i].iedge[forbidden_bond_pos];
2013 : 10 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2014 : 10 : num_found++;
2015 : : }
2016 : : }
2017 : : else
2018 : : {
2019 : : /* nitro */
2020 [ + + - + ]: 774 : if (at[i].el_number == EL_NUMBER_N && 3 == at[i].valence &&
2021 [ # # # # ]: 0 : ( 4 == at[i].chem_bonds_valence || 5 == at[i].chem_bonds_valence ))
2022 : : {
2023 : 0 : int num_O = 0;
2024 : 0 : int bond_to_O_val = 0;
2025 : 0 : int forbidden_bond_pos = -1;
2026 : 0 : int forbidden_bond_val = -1;
2027 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
2028 : : {
2029 : 0 : neigh = at[i].neighbor[j];
2030 [ # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_O &&
2031 [ # # ]: 0 : at[neigh].valence == 1)
2032 : : {
2033 : 0 : num_O++;
2034 : 0 : bond_to_O_val += ( at[i].bond_type[j] & BOND_TYPE_MASK );
2035 : : }
2036 : : else
2037 : : {
2038 : 0 : forbidden_bond_pos = j;
2039 : 0 : forbidden_bond_val = ( at[i].bond_type[j] & BOND_TYPE_MASK );
2040 : : }
2041 : : }
2042 [ # # # # : 0 : if (2 == num_O && ( 3 == bond_to_O_val || 4 == bond_to_O_val ) && 1 == forbidden_bond_val)
# # # # ]
2043 : : {
2044 : 0 : iedge = pBNS->vert[i].iedge[forbidden_bond_pos];
2045 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2046 : 0 : num_found++;
2047 : : }
2048 : : }
2049 : : }
2050 : : }
2051 : :
2052 : : #ifdef FIX_SRU_CYCLIZING_PS_BONDS_IN_BNS
2053 : : if (nebend > 1)
2054 : : num_found += fix_explicitly_indicated_bonds( nebend, ebend, pBNS, at, num_atoms );
2055 : : #endif
2056 : :
2057 : : #if ( REMOVE_ION_PAIRS_FIX_BONDS == 1 )
2058 : 161 : num_found += fix_special_bonds( pBNS, at, num_atoms, edge_forbidden_mask );
2059 : : #endif
2060 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
2061 : : num_found += TempFix_NH_NH_Bonds( pBNS, at, num_atoms );
2062 : : #endif
2063 : :
2064 : 161 : return num_found;
2065 : : }
2066 : :
2067 : :
2068 : :
2069 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
2070 : :
2071 : :
2072 : : /****************************************************************************/
2073 : : int TempFix_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
2074 : : {
2075 : : int i, j, neigh, num_found;
2076 : : BNS_IEDGE iedge;
2077 : : S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_TEMP;
2078 : : for (i = 0, num_found = 0; i < num_atoms; i++)
2079 : : {
2080 : : /* -NH-NH- or -NH-NH3 */
2081 : : if (at[i].el_number == EL_NUMBER_N && at[i].valence < 3 && at[i].num_H &&
2082 : : 3 == at[i].chem_bonds_valence + at[i].num_H &&
2083 : : at[i].chem_bonds_valence == at[i].valence &&
2084 : : !at[i].charge && !at[i].radical)
2085 : : {
2086 : : for (j = 0; j < at[i].valence; j++)
2087 : : {
2088 : : neigh = at[i].neighbor[j];
2089 : : if (neigh < i &&
2090 : : at[neigh].el_number == EL_NUMBER_N && at[neigh].valence < 3 && at[neigh].num_H &&
2091 : : 3 == at[neigh].chem_bonds_valence + at[neigh].num_H &&
2092 : : at[neigh].chem_bonds_valence == at[neigh].valence &&
2093 : : !at[neigh].charge && !at[neigh].radical)
2094 : : {
2095 : : iedge = pBNS->vert[i].iedge[j];
2096 : : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2097 : : num_found++;
2098 : : }
2099 : : }
2100 : : }
2101 : : }
2102 : :
2103 : : return num_found;
2104 : : }
2105 : :
2106 : :
2107 : : /****************************************************************************/
2108 : : int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
2109 : : {
2110 : : int i, j, neigh, num_found;
2111 : : BNS_IEDGE iedge;
2112 : : S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_TEMP;
2113 : :
2114 : : for (i = 0, num_found = 0; i < num_atoms; i++)
2115 : : {
2116 : : /* -NH-NH- or -NH-NH3 */
2117 : : if (at[i].el_number == EL_NUMBER_N && at[i].valence < 3)
2118 : : {
2119 : : for (j = 0; j < at[i].valence; j++)
2120 : : {
2121 : : neigh = at[i].neighbor[j];
2122 : : if (neigh < i &&
2123 : : at[neigh].el_number == EL_NUMBER_N && at[neigh].valence < 3)
2124 : : {
2125 : : if (BOND_TYPE_SINGLE != ( at[i].bond_type[j] & BOND_TYPE_MASK ))
2126 : : {
2127 : : iedge = pBNS->vert[i].iedge[j];
2128 : : if (pBNS->edge[iedge].forbidden & edge_forbidden_mask)
2129 : : {
2130 : : pBNS->edge[iedge].forbidden &= ~edge_forbidden_mask;
2131 : : num_found++;
2132 : : }
2133 : : }
2134 : : }
2135 : : }
2136 : : }
2137 : : }
2138 : :
2139 : : return num_found;
2140 : : }
2141 : : #endif
2142 : :
2143 : : /****************************************************************************
2144 : : Fixes bonds which were set by remove_ion_pairs( ... )
2145 : : ****************************************************************************/
2146 : 161 : int fix_special_bonds( BN_STRUCT *pBNS,
2147 : : inp_ATOM *at,
2148 : : int num_atoms,
2149 : : int forbidden_mask )
2150 : : {
2151 : 161 : int num_changes = 0;
2152 : :
2153 : : #define MAX_NEIGH 6
2154 : :
2155 : : int i, k, n1, n2, n3, i1, i2, i3, i4, bond_type; /* djb-rwth: removing redundant variables */
2156 : : inp_ATOM *a;
2157 : : int j[3], m[3], num_O, k_O, num_N, num_OH, num_OM, num_X, num_other, k_N;
2158 : :
2159 : : BNS_IEDGE iedge;
2160 : : /*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
2161 : 161 : S_CHAR edge_forbidden_mask = forbidden_mask;
2162 : :
2163 : 161 : pBNS->edge_forbidden_mask |= edge_forbidden_mask;
2164 : :
2165 [ + + ]: 971 : for (i = 0, a = at; i < num_atoms; i++, a++)
2166 : : {
2167 : :
2168 [ + + + - ]: 810 : if (!a->charge && !a->radical &&
2169 [ + + + - ]: 763 : 2 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2170 : 4 : 0 == num_of_H( at, i ) &&
2171 [ + + - + ]: 5 : 2 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2172 : 1 : ion_el_group( at[i].el_number ) == EL_NUMBER_N )
2173 : : {
2174 : : /* Found N(V), no H */
2175 [ # # ]: 0 : if (2 == nNoMetalNumBonds( at, i ))
2176 : : {
2177 : : /* #N= */
2178 : : /* fix bonds: double and triple: =N# so that bonds cannot be changed by the normalization */
2179 : : #if ( FIX_N_V_METAL_BONDS_GPF == 1 )
2180 [ # # # # ]: 0 : if (0 > ( i1 = nNoMetalNeighIndex( at, i ) ) ||
2181 : 0 : 0 > ( i2 = nNoMetalOtherNeighIndex( at, i, n1 = a->neighbor[i1]/* non-metal neighbor #1 */ ) ))
2182 : : {
2183 : : /*num_err ++; */ /* do not count would-be original InChI v.1 buffer overflow GPF */
2184 : 0 : continue; /* v1 bug: 2 bonds to metal yield i1 < 0 and/or i2 < 0 => bounds violation */
2185 : : }
2186 : : #else
2187 : : i1 = nNoMetalNeighIndex( at, i );
2188 : : n1 = a->neighbor[i1]; /* non-metal neighbor #1 */
2189 : : i2 = nNoMetalOtherNeighIndex( at, i, n1 );
2190 : : #endif
2191 : 0 : n2 = a->neighbor[i2]; /* non-metal neighbor #2 */
2192 : : /* forbid all edges to non-metals */
2193 : 0 : iedge = pBNS->vert[i].iedge[i1];
2194 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
2195 : 0 : iedge = pBNS->vert[i].iedge[i2];
2196 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
2197 : 0 : num_changes++; /* added 11-15-2005 */
2198 : : /* i n3 */
2199 : : /* forbid single bond edge beyond the neighboring =N- as in #N=N- */
2200 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2201 [ # # ]: 0 : if (( at[i].bond_type[i1] & BOND_TYPE_MASK ) == BOND_TYPE_DOUBLE)
2202 : : {
2203 : 0 : i3 = i1; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2204 : 0 : n3 = n1;
2205 : : }
2206 : : else
2207 : : {
2208 : 0 : i3 = i2; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2209 : 0 : n3 = n2;
2210 : : }
2211 [ # # # # : 0 : if (0 == NUMH( at, n3 ) && 2 == nNoMetalNumBonds( at, n3 ) &&
# # ]
2212 [ # # ]: 0 : 3 == nNoMetalBondsValence( at, n3 ) &&
2213 [ # # ]: 0 : ion_el_group( at[n3].el_number ) == EL_NUMBER_N &&
2214 : 0 : 0 <= ( k = nNoMetalOtherNeighIndex( at, n3, i ) ))
2215 : : {
2216 : : /* found =N- ; forbid the edge*/
2217 : 0 : iedge = pBNS->vert[n3].iedge[k];
2218 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2219 : 0 : num_changes++;
2220 : : }
2221 : : }
2222 [ # # ]: 0 : else if (3 == nNoMetalNumBonds( at, i ) &&
2223 : : /* | */
2224 : : /* found =N= */
2225 : : /* locate all non-metal neighbors */
2226 [ # # ]: 0 : 0 <= ( j[0] = nNoMetalNeighIndex( at, i ) ) &&
2227 [ # # ]: 0 : 0 <= ( j[1] = nNoMetalOtherNeighIndex( at, i, m[0] = a->neighbor[j[0]] ) ) &&
2228 [ # # ]: 0 : 0 <= ( j[2] = nNoMetalOtherNeighIndex2( at, i, m[0], m[1] = a->neighbor[j[1]] ) ))
2229 : : {
2230 : : /* Count specific neighbors: N(V)=N, N(V)-N N(V)=O, and N(V)-N */
2231 : :
2232 : : /* if there is a single neighbor connected by a double bond, namely
2233 : : N(V)=N and/or N(V)=O, then fix the bond(s).
2234 : : If N(V)=O was fixed then do not fix another bond */
2235 : 0 : m[2] = a->neighbor[j[2]];
2236 : 0 : num_O = num_N = 0;
2237 [ # # ]: 0 : for (k = 0; k < 3; k++)
2238 : : {
2239 : 0 : n1 = m[k];
2240 : 0 : i1 = j[k]; /* djb-rwth: ignoring LLVM warning: variable used */
2241 [ # # ]: 0 : if (ion_el_group( at[n1].el_number ) == EL_NUMBER_N)
2242 : : {
2243 : 0 : k_N = k;
2244 : 0 : num_N++;
2245 : : }
2246 [ # # # # ]: 0 : else if (ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2247 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2248 : : {
2249 : 0 : k_O = k;
2250 : 0 : num_O++;
2251 : : }
2252 : : }
2253 : 0 : num_other = 0;
2254 [ # # ]: 0 : if (1 == num_O &&
2255 [ # # ]: 0 : 0 == at[n1 = m[k_O]].charge &&
2256 [ # # ]: 0 : 0 == at[n1].radical &&
2257 [ # # ]: 0 : BOND_TYPE_DOUBLE == ( at[i].bond_type[i1 = j[k_O]] & BOND_TYPE_MASK )
2258 : : )
2259 : : {
2260 : : /* Fix bond to neighbor =O */
2261 : 0 : iedge = pBNS->vert[i].iedge[i1];
2262 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2263 : 0 : num_changes++;
2264 : 0 : num_other++; /* indicator: double to a terminal O has been fixed */
2265 : : }
2266 [ # # # # ]: 0 : if (!num_other &&
2267 [ # # ]: 0 : num_O <= 1 &&
2268 : 0 : 1 == num_N &&
2269 [ # # ]: 0 : 0 == at[n1 = m[k_N]].charge &&
2270 [ # # ]: 0 : 0 == at[n1].radical &&
2271 [ # # ]: 0 : BOND_TYPE_DOUBLE == ( at[i].bond_type[i1 = j[k_N]] & BOND_TYPE_MASK ))
2272 : : {
2273 : : /* Fix bond to neighbor =N */
2274 : 0 : iedge = pBNS->vert[i].iedge[i1];
2275 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2276 : 0 : num_changes++;
2277 : : }
2278 : : }
2279 [ # # ]: 0 : else if (4 == nNoMetalNumBonds( at, i ))
2280 : : {
2281 : : /* | */
2282 : : /* found -N=N- */
2283 : : /* | */
2284 : : /* locate non-metal neighbor connected by a double bond;
2285 : : * if it is =N- then fix the double bond and the single bond beyond the neighbor
2286 : : */
2287 : 0 : num_N = 0;
2288 : 0 : num_other = 0; /* djb-rwth: ignoring LLVM warning: variable used */
2289 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
2290 : : {
2291 [ # # # # ]: 0 : if (BOND_TYPE_DOUBLE == ( at[i].bond_type[i1] & BOND_TYPE_MASK ) &&
2292 [ # # ]: 0 : !is_el_a_metal( at[n1 = (int) at[i].neighbor[i1]].el_number ) &&
2293 : 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_N)
2294 : : {
2295 : 0 : num_N++;
2296 : 0 : n2 = n1;
2297 : 0 : i2 = i1;
2298 : : }
2299 : : }
2300 [ # # # # : 0 : if (1 == num_N && 0 == NUMH( at, n2 ) &&
# # ]
2301 [ # # ]: 0 : 2 == nNoMetalNumBonds( at, n2 ) &&
2302 [ # # ]: 0 : 3 == nNoMetalBondsValence( at, n2 ) &&
2303 : 0 : 0 <= ( i3 = nNoMetalOtherNeighIndex( at, n2, i ) ) &&
2304 [ # # ]: 0 : BOND_TYPE_SINGLE == ( at[n2].bond_type[i3] & BOND_TYPE_MASK ))
2305 : : {
2306 : : /* fix the single bond beyond the N(V) neighbor N(V)=N- */
2307 : 0 : iedge = pBNS->vert[n2].iedge[i3];
2308 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2309 : 0 : num_changes++;
2310 : : /* fix the double bond */
2311 : 0 : iedge = pBNS->vert[i].iedge[i2];
2312 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2313 : 0 : num_changes++;
2314 : : }
2315 : : }
2316 : : }
2317 : :
2318 [ + + + - ]: 810 : else if (!a->charge && !a->radical &&
2319 [ + + + - ]: 763 : 2 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2320 : 4 : 0 == num_of_H( at, i ) &&
2321 [ + + ]: 4 : 2 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2322 [ + - - + : 1 : a->el_number != EL_NUMBER_O && ion_el_group( a->el_number ) == EL_NUMBER_O &&
- - ]
2323 : 0 : 3 == nNoMetalNumBonds( at, i ))
2324 : : {
2325 : : /* Found S(IV), no H, one double bond, total 3 bonds */
2326 : : /* OH
2327 : : /
2328 : : in O=S (X != O) fix single bond O-X (type 1)
2329 : : \
2330 : : X
2331 : :
2332 : : X
2333 : : /
2334 : : in Z=S (X, Y != OH) fix double bond Z=S (type 2)
2335 : : \
2336 : : Y
2337 : : */
2338 : 0 : num_N = 0; /* number of non-metal neighbors connected by a double bond */
2339 : 0 : num_OH = 0; /* number of neighbors OH connected by a single bond */
2340 : 0 : num_OM = 0; /* number of charged neighbors O connected by a single bond */
2341 : 0 : num_O = 0; /* number of neighbors =O connected by a double bond */
2342 : 0 : num_other = 0;
2343 : :
2344 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2345 : : {
2346 : 0 : n1 = (int) a->neighbor[i1];
2347 [ # # ]: 0 : if (is_el_a_metal( at[n1].el_number ))
2348 : : {
2349 : 0 : continue;
2350 : : }
2351 : :
2352 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2353 : :
2354 [ # # ]: 0 : if (BOND_TYPE_DOUBLE == bond_type)
2355 : : {
2356 : 0 : num_N++;
2357 : 0 : n2 = n1;
2358 : 0 : i2 = i1;
2359 [ # # ]: 0 : if (ion_el_group( at[n1].el_number ) == EL_NUMBER_O)
2360 : : {
2361 : 0 : num_O++;
2362 : : }
2363 : : }
2364 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2365 [ # # ]: 0 : 1 == nNoMetalNumBonds( at, n1 ) &&
2366 [ # # ]: 0 : 1 == nNoMetalBondsValence( at, n1 ) &&
2367 : 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O)
2368 : : {
2369 [ # # ]: 0 : if (0 == at[n1].charge)
2370 : : {
2371 : 0 : num_OH++;
2372 : 0 : n3 = n1;
2373 : 0 : i3 = i1; /* djb-rwth: ignoring LLVM warning: variable used */
2374 : : }
2375 : : else
2376 : : {
2377 : 0 : num_OM++;
2378 : : }
2379 : : }
2380 : : else
2381 : : {
2382 : 0 : num_other++;
2383 : : /* djb-rwth: removing redundant code */
2384 : 0 : i4 = i1;
2385 : : }
2386 : : } /* for (i1 = */
2387 : :
2388 [ # # # # : 0 : if (1 == num_N && 1 == num_O && 1 == num_OH + num_OM)
# # ]
2389 : : {
2390 [ # # ]: 0 : if (1 == num_other)
2391 : : {
2392 : : /* type 1: fix the single bond S-X */
2393 : 0 : iedge = pBNS->vert[i].iedge[i4];
2394 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2395 : 0 : num_changes++;
2396 : : }
2397 : : }
2398 [ # # # # : 0 : else if (1 == num_N && !num_OH && !num_OM)
# # ]
2399 : : {
2400 : 0 : int bFound = 0; /* flag */
2401 : 0 : int bDoNotFixAnyBond = 0; /* flag */
2402 : : /* Avoid case N=S-NH or N=S-N(-); N = N, P, As, Sb */
2403 [ # # ]: 0 : if (ion_el_group( at[n2].el_number ) == EL_NUMBER_N)
2404 : : {
2405 : 0 : U_CHAR el_number = at[n2].el_number;
2406 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2407 : : {
2408 : 0 : n1 = (int) a->neighbor[i1];
2409 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2410 [ # # ]: 0 : if (BOND_TYPE_SINGLE == bond_type &&
2411 [ # # # # ]: 0 : ( NUMH( at, n1 ) || -1 == at[n1].charge ) &&
2412 [ # # ]: 0 : el_number == at[n1].el_number)
2413 : : {
2414 : 0 : i3 = i1; /* djb-rwth: ignoring LLVM warning: variable used */
2415 : 0 : n3 = n1;
2416 : 0 : bFound++;
2417 : : }
2418 : : }
2419 : : }
2420 : : /* Exception: check if Z==X and they belong to the same ring system */
2421 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2422 : : {
2423 [ # # ]: 0 : if (i1 != i2)
2424 : : {
2425 : 0 : n1 = (int) a->neighbor[i1];
2426 [ # # ]: 0 : if (at[n2].el_number == at[n1].el_number &&
2427 [ # # ]: 0 : at[n2].nRingSystem == at[n1].nRingSystem)
2428 : : {
2429 : 0 : bDoNotFixAnyBond++;
2430 : : }
2431 : : }
2432 : : }
2433 [ # # ]: 0 : if (bDoNotFixAnyBond)
2434 : : {
2435 : : ; /* do nothing */
2436 : : }
2437 [ # # ]: 0 : else if (bFound)
2438 : : {
2439 [ # # # # ]: 0 : if (1 == bFound &&
2440 : 0 : 0 <= ( i4 = nNoMetalOtherNeighIndex2( at, i, n2, n3 ) ))
2441 : : {
2442 : : /* fix bond i4 */
2443 : 0 : iedge = pBNS->vert[i].iedge[i4];
2444 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2445 : 0 : num_changes++;
2446 : : }
2447 : : }
2448 : : else
2449 : : {
2450 : : /* fix the double bond >S=X */
2451 : 0 : iedge = pBNS->vert[i].iedge[i2];
2452 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2453 : 0 : num_changes++;
2454 : : /* -- test later --
2455 : : if ( 2 == nNoMetalNumBonds( at, n2 ) &&
2456 : : 0 <= ( i3 = nNoMetalOtherNeighIndex( at, n2, i ) ) ) {
2457 : : iedge = pBNS->vert[n2].iedge[i3];
2458 : : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2459 : : num_changes ++;
2460 : : }
2461 : : -------------------*/
2462 : : }
2463 : : }
2464 : : }
2465 : :
2466 [ + + + - ]: 810 : else if (!a->charge && !a->radical &&
2467 [ + + + - ]: 761 : 4 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2468 : 2 : 0 == num_of_H( at, i ) &&
2469 [ + - ]: 2 : 4 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2470 [ + - + - : 4 : a->el_number != EL_NUMBER_O && ion_el_group( a->el_number ) == EL_NUMBER_O &&
+ - ]
2471 : 2 : 4 == nNoMetalNumBonds( at, i ))
2472 : 2 : {
2473 : : /* Found S(VI), no H, two double bonds or one triple bond */
2474 : : /* O
2475 : : ||
2476 : : in O=S--Y- (X, Y -- non-terminal) fix single bonds S-X, S-Y (type 1)
2477 : : \
2478 : : X--
2479 : :
2480 : : O
2481 : : ||
2482 : : in O=S--O(-) (X -- non-terminal) fix single bond S-X (type 2)
2483 : : \
2484 : : X--
2485 : :
2486 : : O
2487 : : ||
2488 : : in O=S--OH (X -- non-terminal) fix single bond S-X (type 3)
2489 : : \
2490 : : X--
2491 : :
2492 : : */
2493 : : int iN[4]; /* indexes of non-terminal neighbors connected by a single bond */
2494 : 2 : num_N = 0; /* number of non-metal neighbors connected by a double bond */
2495 : 2 : num_OH = 0; /* number of neighbors OH connected by a single bond */
2496 : 2 : num_OM = 0; /* number of non-terminal neighbors connected by a single bond */
2497 : 2 : num_O = 0; /* number of neighbors =O connected by a double bond */
2498 : 2 : num_X = 0; /* number of terminal atom X != O connected by a single bond */
2499 : 2 : num_other = 0;
2500 [ + + ]: 10 : for (i1 = 0; i1 < a->valence; i1++)
2501 : : {
2502 : 8 : n1 = (int) a->neighbor[i1];
2503 [ - + ]: 8 : if (is_el_a_metal( at[n1].el_number ))
2504 : : {
2505 : 0 : continue;
2506 : : }
2507 : 8 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2508 [ + + ]: 8 : if (BOND_TYPE_DOUBLE == bond_type)
2509 : : {
2510 : 4 : num_N++;
2511 [ - + ]: 4 : if (( 0 == at[n1].charge
2512 : : #if ( S_VI_O_PLUS_METAL_FIX_BOND == 1 )
2513 [ # # # # ]: 0 : || (1 == at[n1].charge && 2 == at[n1].valence) /* djb-rwth: addressing LLVM warning */
2514 : : #endif
2515 : 4 : ) &&
2516 [ + - + - ]: 8 : 0 == at[n1].radical &&
2517 [ + - ]: 8 : 0 == num_of_H( at, n1 ) &&
2518 [ + - ]: 8 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2519 : 4 : 1 == nNoMetalNumBonds( at, n1 ))
2520 : : {
2521 : 4 : num_O++;
2522 : : }
2523 : : }
2524 [ + - + - ]: 8 : else if (BOND_TYPE_SINGLE == bond_type &&
2525 [ + - ]: 8 : 1 == nNoMetalNumBonds( at, n1 ) &&
2526 [ + - ]: 8 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2527 : 4 : 1 >= num_of_H( at, n1 ) &&
2528 [ - + - - ]: 4 : 1 == ( ( 0 == at[n1].charge ) && 1 == num_of_H( at, n1 ) )
2529 [ + - + - : 4 : + ( ( -1 == at[n1].charge ) && 0 == num_of_H( at, n1 ) ))
+ - ]
2530 : : {
2531 : 4 : num_OH++; /* -OH or -O(-) */
2532 : : }
2533 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2534 : 0 : 1 < nNoMetalNumBonds( at, n1 ))
2535 : : {
2536 : 0 : iN[num_OM++] = i1; /* non-terminal neighbor connected by a single bond */
2537 : : }
2538 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2539 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2540 : : {
2541 : 0 : num_X++; /* other terminal neighbor connected by a single bond */
2542 : : }
2543 : : else
2544 : : {
2545 : 0 : num_other++;
2546 : : }
2547 : : }
2548 [ + - + - : 2 : if (num_N == num_O && 2 == num_O && 2 == num_OH + num_OM + num_X && 0 == num_other)
+ - + - ]
2549 : : {
2550 [ - + ]: 2 : for (i2 = 0; i2 < num_OM; i2++)
2551 : : {
2552 : 0 : i1 = iN[i2];
2553 : : /* fix bond i1 */
2554 : 0 : iedge = pBNS->vert[i].iedge[i1];
2555 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2556 : 0 : num_changes++;
2557 : : }
2558 : : }
2559 : : }
2560 : :
2561 [ + + + - ]: 808 : else if (!a->charge && !a->radical &&
2562 [ - + - - ]: 757 : 6 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2563 : 0 : 0 == num_of_H( at, i ) &&
2564 [ # # ]: 0 : 6 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2565 [ # # # # : 0 : a->el_number != EL_NUMBER_O && ion_el_group( a->el_number ) == EL_NUMBER_O &&
# # ]
2566 : 0 : 5 == nNoMetalNumBonds( at, i ))
2567 : : {
2568 : : /* Found S(VIII), no H, three double bonds or two triple bond */
2569 : : /*
2570 : :
2571 : : O
2572 : : ||
2573 : : in O=S--Y-- (X, Y -- non-terminal) fix single bond S-X, S-Y (type 4)
2574 : : //\
2575 : : O X--
2576 : :
2577 : : note: this structure is a mistakenly drawn structure
2578 : :
2579 : : O O
2580 : : || ||
2581 : : O=S--O--Y-- or O=S--Y--
2582 : : \ \
2583 : : X-- O--X--
2584 : :
2585 : :
2586 : : */
2587 : : int iN[5]; /* indexes of non-terminal neighbors connected by a single bond */
2588 : 0 : num_N = 0; /* number of non-metal neighbors connected by a double bond */
2589 : 0 : num_OH = 0; /* number of neighbors OH connected by a single bond */
2590 : 0 : num_OM = 0; /* number of non-terminal neighbors connected by a single bond */
2591 : 0 : num_O = 0; /* number of neighbors =O connected by a double bond */
2592 : 0 : num_X = 0; /* number of terminal atom X != O connected by a single bond */
2593 : 0 : num_other = 0;
2594 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2595 : : {
2596 : 0 : n1 = (int) a->neighbor[i1];
2597 [ # # ]: 0 : if (is_el_a_metal( at[n1].el_number ))
2598 : : {
2599 : 0 : continue;
2600 : : }
2601 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2602 [ # # ]: 0 : if (BOND_TYPE_DOUBLE == bond_type)
2603 : : {
2604 : 0 : num_N++;
2605 [ # # ]: 0 : if (( 0 == at[n1].charge
2606 : : #if ( S_VI_O_PLUS_METAL_FIX_BOND == 1 )
2607 [ # # # # ]: 0 : || (1 == at[n1].charge && 2 == at[n1].valence) /* djb-rwth: addressing LLVM warning */
2608 : : #endif
2609 : : )
2610 [ # # # # ]: 0 : && 0 == at[n1].radical &&
2611 [ # # ]: 0 : 0 == num_of_H( at, n1 ) &&
2612 [ # # ]: 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2613 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2614 : : {
2615 : 0 : num_O++;
2616 : : }
2617 : : }
2618 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2619 [ # # ]: 0 : 1 == nNoMetalNumBonds( at, n1 ) &&
2620 [ # # ]: 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2621 : 0 : 1 >= num_of_H( at, n1 ) &&
2622 [ # # # # ]: 0 : 1 == ( ( 0 == at[n1].charge ) && 1 == num_of_H( at, n1 ) )
2623 [ # # # # : 0 : + ( ( -1 == at[n1].charge ) && 0 == num_of_H( at, n1 ) ))
# # ]
2624 : : {
2625 : 0 : num_OH++; /* -OH or -O(-) */
2626 : : }
2627 : : else
2628 : : {
2629 [ # # # # ]: 0 : if (BOND_TYPE_SINGLE == bond_type &&
2630 : 0 : 1 < nNoMetalNumBonds( at, n1 ))
2631 : : {
2632 : :
2633 : 0 : iN[num_OM++] = i1; /* non-terminal neighbor connected by a single bond */
2634 : : }
2635 : : else
2636 : : {
2637 [ # # # # ]: 0 : if (BOND_TYPE_SINGLE == bond_type && 1 == nNoMetalNumBonds( at, n1 ))
2638 : : {
2639 : :
2640 : 0 : num_X++; /* other terminal neighbor connected by a single bond */
2641 : : }
2642 : : else
2643 : : {
2644 : 0 : num_other++;
2645 : : }
2646 : : }
2647 : : }
2648 : : }
2649 [ # # # # : 0 : if (num_N == num_O && 3 == num_O && 2 == num_OH + num_OM + num_X && 0 == num_other)
# # # # ]
2650 : : {
2651 [ # # ]: 0 : for (i2 = 0; i2 < num_OM; i2++)
2652 : : {
2653 : 0 : i1 = iN[i2];
2654 : : /* fix bond i1 */
2655 : 0 : iedge = pBNS->vert[i].iedge[i1];
2656 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2657 : 0 : num_changes++;
2658 : : }
2659 : : }
2660 : : }
2661 : :
2662 : : } /* for (i = */
2663 : :
2664 : 161 : return num_changes;
2665 : : }
2666 : :
2667 : :
2668 : : /****************************************************************************/
2669 : 0 : int fix_explicitly_indicated_bonds( int nebend,
2670 : : int *ebend,
2671 : : BN_STRUCT *pBNS,
2672 : : inp_ATOM *at,
2673 : : int num_atoms )
2674 : : {
2675 : 0 : int i, num_changes = 0;
2676 : : inp_ATOM *a;
2677 : 0 : int j, ia1, ia2, i1 = -1, i2 = -1, index = -1, neigh;
2678 : : BNS_IEDGE iedge;
2679 : 0 : S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;
2680 : 0 : pBNS->edge_forbidden_mask |= edge_forbidden_mask;
2681 : :
2682 [ # # # # ]: 0 : if (nebend < 1 || !ebend)
2683 : : {
2684 : 0 : return 0;
2685 : : }
2686 : :
2687 [ # # ]: 0 : for (j = 0; j < nebend; j += 2)
2688 : : {
2689 : :
2690 : 0 : ia1 = ebend[2 * j];
2691 : 0 : ia2 = ebend[2 * j + 1];
2692 : :
2693 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
2694 : : {
2695 [ # # ]: 0 : if (at[i].orig_at_number == ia1)
2696 : : {
2697 : 0 : i1 = i;
2698 : : }
2699 [ # # ]: 0 : else if (at[i].orig_at_number == ia2)
2700 : : {
2701 : 0 : i2 = i;
2702 : : }
2703 [ # # # # ]: 0 : if (i1 > 0 && i2 > 0)
2704 : : {
2705 : 0 : break;
2706 : : }
2707 : : }
2708 : :
2709 [ # # # # ]: 0 : if (i1 < 0 || i2 < 0)
2710 : : {
2711 : 0 : return 0;
2712 : : }
2713 : :
2714 [ # # ]: 0 : if (i2 < i1)
2715 : : {
2716 : 0 : int tmp = i1; i1 = i2; i2 = tmp;
2717 : : }
2718 : :
2719 : 0 : a = at + i1;
2720 [ # # ]: 0 : for (i = 0; i < a->valence; i++)
2721 : : {
2722 : 0 : neigh = (int) a->neighbor[i];
2723 [ # # ]: 0 : if (neigh == i2)
2724 : : {
2725 : 0 : index = i; break;
2726 : : }
2727 : : }
2728 [ # # ]: 0 : if (index > -1)
2729 : : {
2730 : 0 : iedge = pBNS->vert[i].iedge[index];
2731 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2732 : 0 : num_changes++;
2733 : : }
2734 : : }
2735 : :
2736 : 0 : return num_changes;
2737 : : }
2738 : :
2739 : :
2740 : :
2741 : :
2742 : : #define ALL_NONMETAL_Z 0
2743 : :
2744 : :
2745 : : /****************************************************************************/
2746 : 2485 : int is_Z_atom( U_CHAR el_number )
2747 : : {
2748 [ + + ]: 2485 : switch ( el_number )
2749 : : {
2750 : 2266 : case EL_NUMBER_C: /* fallthrough */
2751 : : case EL_NUMBER_N:
2752 : : case EL_NUMBER_P:
2753 : : case EL_NUMBER_AS:
2754 : : case EL_NUMBER_SB:
2755 : : case EL_NUMBER_S:
2756 : : case EL_NUMBER_SE:
2757 : : case EL_NUMBER_TE:
2758 : : case EL_NUMBER_CL:
2759 : : case EL_NUMBER_BR:
2760 : : case EL_NUMBER_I:
2761 : : #if ( ALL_NONMETAL_Z == 1 )
2762 : : case EL_NUMBER_B:
2763 : : case EL_NUMBER_O:
2764 : : case EL_NUMBER_SI:
2765 : : case EL_NUMBER_GE:
2766 : : case EL_NUMBER_F:
2767 : : case EL_NUMBER_AT:
2768 : : #endif
2769 : 2266 : return 1;
2770 : 219 : default:
2771 : 219 : return 0;
2772 : : }
2773 : : }
2774 : :
2775 : :
2776 : : /****************************************************************************
2777 : : Detect O==Z--X, O=O,S,Se,Te
2778 : : ****************************************************************************/
2779 : 20 : int IsZOX( inp_ATOM *atom, int at_x, int ord )
2780 : : {
2781 : 20 : inp_ATOM *at_Z = atom + atom[at_x].neighbor[ord];
2782 : :
2783 : : int i, neigh, num_O;
2784 : :
2785 [ + + ]: 100 : for (i = 0, num_O = 0; i < at_Z->valence; i++)
2786 : : {
2787 : 80 : neigh = at_Z->neighbor[i];
2788 [ + + ]: 80 : if (neigh == at_x)
2789 : : {
2790 : 20 : continue;
2791 : : }
2792 [ + - ]: 60 : if (atom[neigh].valence == 1 &&
2793 [ + + ]: 60 : atom[neigh].chem_bonds_valence == 2 &&
2794 [ + - ]: 40 : atom[neigh].charge == 0 &&
2795 [ + - ]: 40 : atom[neigh].radical == 0 &&
2796 [ - + ]: 40 : ( atom[neigh].el_number == EL_NUMBER_O ||
2797 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_S ||
2798 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_SE ||
2799 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_TE ))
2800 : : {
2801 : 40 : num_O++;
2802 : : }
2803 : : }
2804 : :
2805 : 20 : return num_O;
2806 : : }
2807 : :
2808 : : #if ( FIX_RENUM_BUG_FOR_CASE_OF_ACIDIC_OH_AT_P_PLUS == 1 )
2809 : : void update_some_attype_totals(int nAtTypeTotals[], int mask, int delta, S_CHAR at_charge);
2810 : : /****************************************************************************/
2811 : 0 : void update_some_attype_totals(int nAtTypeTotals[], int mask, int delta, S_CHAR at_charge)
2812 : : {
2813 : : int i;
2814 : : int32_t bit; /* djb-rwth: fixing coverity ID #499534 */
2815 [ # # ]: 0 : if (nAtTypeTotals)
2816 : : {
2817 [ # # # # ]: 0 : if (mask && !(mask & (ATBIT_Errors)))
2818 : : {
2819 [ # # ]: 0 : for (i = 0, bit = 1; i < ATTOT_ARRAY_LEN; i++, bit <<= 1)
2820 : : {
2821 [ # # ]: 0 : if (bit & mask)
2822 : : {
2823 : 0 : nAtTypeTotals[i] += delta;
2824 : : }
2825 : : }
2826 : : }
2827 : : /* Count charges */
2828 [ # # ]: 0 : if (at_charge)
2829 : : {
2830 : 0 : nAtTypeTotals[ATTOT_TOT_CHARGE] += delta * at_charge;
2831 : 0 : nAtTypeTotals[ATTOT_NUM_CHARGES] += delta;
2832 : : }
2833 : : }
2834 : 0 : return;
2835 : : }
2836 : : #endif
2837 : : /****************************************************************************/
2838 : 1492 : int GetAtomChargeType( inp_ATOM *atom,
2839 : : int at_no,
2840 : : int nAtTypeTotals[],
2841 : : int *pMask,
2842 : : int bSubtract )
2843 : : {
2844 : :
2845 : 1492 : inp_ATOM *at = atom + at_no;
2846 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2847 [ + + ]: 1492 : int i, neigh, mask, type, num_z, num_m, num_o, delta = bSubtract > 0 ? -1 : 1; /* 0 or -2 => add, 1 or 2 => subtract */
2848 : : int32_t bit; /* djb-rwth: fixing coverity ID #499579 */
2849 [ + + + - ]: 1492 : int bNoAdjIon = ( bSubtract == 0 || bSubtract == 1 );
2850 : : #else
2851 : : int i, neigh, mask, bit, type, num_z, num_m, num_o, delta = bSubtract ? -1 : 1;
2852 : : #endif
2853 : 1492 : int bUnsatNHasTerminalO = 0;
2854 : :
2855 : 1492 : type = ATT_NONE;
2856 : 1492 : mask = 0;
2857 : :
2858 [ - + - - ]: 1492 : if (at->radical && at->radical != RADICAL_SINGLET)
2859 : : {
2860 : 0 : goto exit_function;
2861 : : }
2862 : :
2863 [ + + ]: 1492 : if (is_el_a_metal( at->el_number ))
2864 : : {
2865 : 56 : goto exit_function;
2866 : : }
2867 [ + + - + ]: 1436 : if (at->charge < -1 || at->charge > 1)
2868 : : {
2869 : 4 : goto exit_function;
2870 : : }
2871 : :
2872 [ + + - + : 1432 : if (!at->valence && at->charge == 1 && !at->num_H && !at->radical && at->el_number == EL_NUMBER_H)
- - - - -
- ]
2873 : : {
2874 : : /* a proton H+ (#1) */
2875 : 0 : type = ATT_PROTON;
2876 : 0 : mask = ATBIT_Proton;
2877 : 0 : goto count_mask_bits;
2878 : : }
2879 : :
2880 [ + + + + ]: 1432 : if ( !at->valence && at->charge == -1 &&
2881 [ + + + - ]: 28 : !at->num_H && !at->radical &&
2882 [ - + - - ]: 12 : ( at->el_number == EL_NUMBER_F || at->el_number == EL_NUMBER_CL ||
2883 [ # # # # ]: 0 : at->el_number == EL_NUMBER_BR || at->el_number == EL_NUMBER_I )
2884 : : )
2885 : : {
2886 : : /* a halogen anion Hal- (#2) */
2887 : 12 : type = ATT_HalAnion;
2888 : 12 : mask = ATBIT_HalAnion;
2889 : 12 : goto count_mask_bits;
2890 : : }
2891 : : #if ( HAL_ACID_H_XCHG == 1 )
2892 : : /* halogen/chalcogen acid */
2893 [ + + + + : 1420 : if ((!at->valence && at->charge == 0 && 1 == at->num_H && !at->radical &&
+ + + - ]
2894 [ + + ]: 16 : ( at->el_number == EL_NUMBER_F ||
2895 [ + + ]: 8 : at->el_number == EL_NUMBER_CL ||
2896 [ + + ]: 6 : at->el_number == EL_NUMBER_BR ||
2897 [ + + ]: 4 : at->el_number == EL_NUMBER_I )) ||
2898 [ + + + + : 1406 : (!at->valence && at->charge == 0 && 2 == at->num_H && !at->radical &&
+ + + - ]
2899 [ + + ]: 16 : ( at->el_number == EL_NUMBER_O ||
2900 [ + + ]: 6 : at->el_number == EL_NUMBER_S ||
2901 [ + + ]: 4 : at->el_number == EL_NUMBER_SE ||
2902 [ + - ]: 2 : at->el_number == EL_NUMBER_TE )) /* djb-rwth: addressing LLVM warning */
2903 : : )
2904 : : {
2905 : : /* a halogen/chalcogen acid (#3) */
2906 : 30 : type = ATT_HalAcid;
2907 : 30 : mask = ATBIT_HalAcid;
2908 : 30 : goto count_mask_bits;
2909 : : }
2910 : : #endif
2911 : :
2912 [ + + ]: 1390 : if (detect_unusual_el_valence( at->el_number, at->charge, at->radical,
2913 : 1390 : at->chem_bonds_valence, at->num_H, at->valence ))
2914 : : {
2915 : 8 : goto exit_function; /* unusual valence state */
2916 : : }
2917 : :
2918 : : /* Check neighbors */
2919 [ + + ]: 3867 : for (i = 0, num_z = 0, num_m = 0, num_o = 0; i < at->valence; i++)
2920 : : {
2921 : 2489 : neigh = at->neighbor[i];
2922 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2923 [ + - - + ]: 2489 : if (atom[neigh].charge < -1 || atom[neigh].charge > 1)
2924 : : {
2925 : 0 : goto exit_function; /* neighboring charge */
2926 : : }
2927 [ + + - + ]: 2489 : if (atom[neigh].charge && at->charge)
2928 : : {
2929 [ # # ]: 0 : if (bNoAdjIon)
2930 : : {
2931 : : #if ( FIX_RENUM_BUG_FOR_CASE_OF_ACIDIC_OH_AT_P_PLUS == 1 )
2932 : 0 : goto count_mask_bits;
2933 : : /*update_some_attype_totals(nAtTypeTotals, mask, delta, at->charge);*/
2934 : : #endif
2935 : : goto exit_function; /* neighboring charge */
2936 : : }
2937 : 0 : type = ATT_NONE;
2938 : 0 : mask = 0;
2939 : 0 : goto count_mask_bits;
2940 : : }
2941 : : #else
2942 : : if (atom[neigh].charge < -1 || atom[neigh].charge > 1 || atom[neigh].charge && at->charge)
2943 : : {
2944 : : goto exit_function; /* neighboring charge */
2945 : : }
2946 : : #endif
2947 [ + + ]: 2489 : if (detect_unusual_el_valence( atom[neigh].el_number, atom[neigh].charge, atom[neigh].radical,
2948 : 2489 : atom[neigh].chem_bonds_valence, atom[neigh].num_H,
2949 : 2489 : atom[neigh].valence ))
2950 : : {
2951 : : /* neighbor in unusual valence state */
2952 : 4 : goto exit_function;
2953 : : }
2954 [ + + ]: 2485 : if (is_Z_atom( atom[neigh].el_number ))
2955 : : {
2956 : 2266 : num_z++;
2957 : : }
2958 [ + + ]: 2485 : if (is_el_a_metal( atom[neigh].el_number ))
2959 : : {
2960 : 25 : num_m++;
2961 : : }
2962 : 2485 : num_o += ( atom[neigh].el_number == EL_NUMBER_O );
2963 [ + + - + : 2485 : if (at->el_number == EL_NUMBER_N && at->valence == 2 && !at->charge &&
- - ]
2964 : : /*at->valence < at->chem_bonds_valence &&*/
2965 [ # # # # ]: 0 : atom[neigh].valence == 1 && atom[neigh].chem_bonds_valence == 2 &&
2966 [ # # ]: 0 : ( atom[neigh].el_number == EL_NUMBER_O ||
2967 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_S ||
2968 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_SE ||
2969 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_TE ))
2970 : : {
2971 : 0 : bUnsatNHasTerminalO++;
2972 : : }
2973 : : } /* eof check neighbors */
2974 : :
2975 : : /* O, S, Se, Te */
2976 [ + + ]: 1378 : if ( at->el_number == EL_NUMBER_O ||
2977 [ + + ]: 1119 : at->el_number == EL_NUMBER_S ||
2978 [ + - ]: 1117 : at->el_number == EL_NUMBER_SE ||
2979 [ - + ]: 1117 : at->el_number == EL_NUMBER_TE )
2980 : : {
2981 [ - + ]: 261 : if (at->charge == 1)
2982 : : {
2983 [ # # ]: 0 : if (at->num_H)
2984 : : {
2985 : : /* #4 */
2986 : 0 : type = ATT_O_PLUS;
2987 : 0 : mask |= ATBIT_OH_Plus;
2988 : : }
2989 : : else
2990 : : {
2991 : : /* #5 */
2992 : 0 : type = ATT_O_PLUS;
2993 : 0 : mask |= ATBIT_O_Plus;
2994 : : }
2995 : : }
2996 : : else
2997 : : {
2998 : : /* at->charge != 1 */
2999 [ + + ]: 261 : if (at->valence > 1)
3000 : : {
3001 : 12 : goto exit_function; /* not a terminal atom #C1 */
3002 : : }
3003 : : else
3004 : : {
3005 [ + + + + : 249 : if (at->valence && !( num_z || num_o ))
+ - ]
3006 : : {
3007 [ + - ]: 1 : if (num_m == at->valence)
3008 : : {
3009 : 1 : goto exit_function; /* #C2 */
3010 : : }
3011 : 0 : goto count_mask_bits; /* #C3 count charges, no donor or acceptor found */
3012 : : }
3013 : : else
3014 : : {
3015 : : /* Here at->neigh[0] is one of: O, or Z={C, N, P, As, Sb, S, Se, Te, Cl, Br, I} */
3016 [ + + ]: 248 : if (at->valence)
3017 : : {
3018 : 232 : neigh = at->neighbor[0]; /* Z or O only */
3019 [ + - + + ]: 232 : if (!atom[neigh].charge && atom[neigh].el_number == EL_NUMBER_C &&
3020 [ + + ]: 208 : atom[neigh].chem_bonds_valence > atom[neigh].valence)
3021 : : {
3022 : : /* =C-OH, #C-OH, =C-O(-), #C-O(-), -C=O, =C=O; O = O, S, Se, Te */
3023 : 68 : type = ATT_ACIDIC_CO;
3024 [ + + ]: 68 : if (at->num_H == 1)
3025 : : {
3026 : 18 : mask |= ( ATBIT_COH ); /* #6: =C-OH, #C-OH; O=O,S,Se,Te */
3027 : : /*nAtTypeTotals[ATTOT_NUM_COH] ++;*/
3028 : : }
3029 : : else
3030 : : {
3031 [ + + ]: 50 : if (at->charge == -1)
3032 : : {
3033 : 40 : mask |= ( ATBIT_CO_Minus ); /* #7: =C-O(-), #C-O(-); O=O,S,Se,Te */
3034 : : /*nAtTypeTotals[ATTOT_NUM_CO_Minus] ++;*/
3035 : : }
3036 : : else
3037 : : {
3038 [ + - + - ]: 10 : if (!at->num_H && !at->charge)
3039 : : {
3040 : 10 : mask |= ( ATBIT_CO ); /* #8 -C=O, =C=O; O=O,S,Se,Te */
3041 : : /*nAtTypeTotals[ATTOT_NUM_CO] ++;*/
3042 : : }
3043 : : else
3044 : : {
3045 : 0 : mask |= ( ATBIT_Errors );
3046 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3047 : : }
3048 : : }
3049 : : }
3050 : : }
3051 : : else
3052 : : {
3053 [ + - ]: 164 : if (!atom[neigh].charge &&
3054 [ + - ]: 164 : ( atom[neigh].el_number == EL_NUMBER_O ||
3055 [ + + ]: 164 : atom[neigh].el_number == EL_NUMBER_S ||
3056 [ + - ]: 140 : atom[neigh].el_number == EL_NUMBER_SE ||
3057 [ - + ]: 140 : atom[neigh].el_number == EL_NUMBER_TE ) &&
3058 [ - + ]: 24 : atom[neigh].chem_bonds_valence == atom[neigh].valence)
3059 : : {
3060 : : /* -O-OH, -O-O(-); O = O, S, Se, Te */
3061 : 0 : type = ATT_OO;
3062 [ # # ]: 0 : if (at->num_H == 1)
3063 : : {
3064 : 0 : mask |= ( ATBIT_OOH ); /* #9 -O-OH */
3065 : : /*nAtTypeTotals[ATTOT_NUM_OOH] ++;*/
3066 : : }
3067 : : else
3068 : : {
3069 [ # # ]: 0 : if (at->charge == -1)
3070 : : {
3071 : 0 : mask |= ( ATBIT_OO_Minus ); /* #10 -O-O(-) */
3072 : : /*nAtTypeTotals[ATTOT_NUM_OO_Minus] ++;*/
3073 : : }
3074 : : else
3075 : : {
3076 : 0 : mask |= ( ATBIT_Errors );
3077 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3078 : : }
3079 : : }
3080 : : }
3081 : : else
3082 : : {
3083 [ + - ]: 164 : if (!atom[neigh].charge &&
3084 [ + + ]: 164 : atom[neigh].chem_bonds_valence == atom[neigh].valence &&
3085 [ + - ]: 140 : atom[neigh].el_number == EL_NUMBER_C &&
3086 [ - + ]: 140 : at->el_number != EL_NUMBER_O)
3087 : : {
3088 : : /* >C-S(-), >C-SH; S = S, Se, Te */
3089 : 0 : type = ATT_ACIDIC_S;
3090 [ # # ]: 0 : if (at->num_H == 1)
3091 : : {
3092 : 0 : mask |= ( ATBIT_CSH ); /* #11: >C-SH, >CH-SH, -CH2-SH; S = S, Se, Te */
3093 : : /*nAtTypeTotals[ATTOT_NUM_CSH] ++;*/
3094 : : }
3095 : : else
3096 : : {
3097 [ # # ]: 0 : if (at->charge == -1)
3098 : : {
3099 : 0 : mask |= ( ATBIT_CS_Minus ); /* #12: >C-S(-), >CH-S(-), -CH2-S(-); S = S, Se, Te */
3100 : : /*nAtTypeTotals[ATTOT_NUM_CS_Minus] ++;*/
3101 : : }
3102 : : else
3103 : : {
3104 : 0 : mask |= ( ATBIT_Errors );
3105 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3106 : : }
3107 : : }
3108 : : }
3109 : : else
3110 : : {
3111 [ - + ]: 164 : if (atom[neigh].el_number == EL_NUMBER_N &&
3112 [ # # ]: 0 : atom[neigh].valence == 2 &&
3113 [ # # # # : 0 : ( !atom[neigh].num_H || (atom[neigh].num_H == 1 && atom[neigh].charge == 1) )) /* djb-rwth: addressing LLVM warning */
# # ]
3114 : : {
3115 : : /* N or N(-) or NH(+) neighbor */
3116 : 0 : type = ATT_NO; /* single bond only */
3117 [ # # ]: 0 : if (at->num_H == 1)
3118 : : {
3119 : 0 : mask |= ( ATBIT_NOH ); /* #13: =N-OH, =NH(+)-OH, #N(+)-OH, -N(-)-OH; O = O, S, Se, Te */
3120 : : /*nAtTypeTotals[ATTOT_NUM_NOH] ++;*/
3121 : : }
3122 : : else
3123 : : {
3124 [ # # ]: 0 : if (at->charge == -1)
3125 : : {
3126 : 0 : mask |= ( ATBIT_NO_Minus ); /* #14: =N-O(-); O = O, S, Se, Te */
3127 : : /*nAtTypeTotals[ATTOT_NUM_NO_Minus] ++;*/
3128 : : }
3129 : : else
3130 : : {
3131 [ # # # # ]: 0 : if (atom[neigh].charge == 1 || atom[neigh].charge == 0)
3132 : : {
3133 : 0 : mask |= ( ATBIT_NO ); /* #15: =N(+)=O, -NH(+)=O -N=O */
3134 : : /*nAtTypeTotals[ATTOT_NUM_NO] ++;*/
3135 : : }
3136 : : else
3137 : : {
3138 : 0 : mask |= ( ATBIT_Errors );
3139 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3140 : : }
3141 : : }
3142 : : }
3143 : : }
3144 : : else
3145 : : {
3146 [ - + ]: 164 : if (atom[neigh].el_number == EL_NUMBER_N)
3147 : : {
3148 : 0 : type = ATT_N_O; /* #16: single bond only */
3149 [ # # ]: 0 : if (at->num_H == 1)
3150 : : {
3151 : 0 : mask |= ( ATBIT_N_OH ); /* #16: -NH-OH, >N-OH or >N(+)<OH; O = O, S, Se, Te */
3152 : : /*nAtTypeTotals[ATTOT_NUM_NOH] ++;*/
3153 : : }
3154 : : else
3155 : : {
3156 [ # # ]: 0 : if (at->charge == -1)
3157 : : {
3158 : 0 : mask |= ( ATBIT_N_O_Minus ); /* #17: -NH-O(-), >N-O(-); O = O, S, Se, Te */
3159 : : /*nAtTypeTotals[ATTOT_NUM_NO_Minus] ++;*/
3160 : : }
3161 : : else
3162 : : {
3163 [ # # ]: 0 : if (atom[neigh].charge == 1)
3164 : : {
3165 : 0 : mask |= ( ATBIT_N_O ); /* #18: >N(+)=O */
3166 : : /*nAtTypeTotals[ATTOT_NUM_NO] ++;*/
3167 : : }
3168 : : else
3169 : : {
3170 : 0 : mask |= ( ATBIT_Errors );
3171 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3172 : : }
3173 : : }
3174 : : }
3175 : : }
3176 : : else
3177 : : {
3178 [ + + ]: 164 : if ( atom[neigh].el_number != EL_NUMBER_C &&
3179 [ + - + - ]: 48 : atom[neigh].el_number != EL_NUMBER_O &&
3180 : 24 : !is_el_a_metal( atom[neigh].el_number ) &&
3181 [ + - ]: 24 : atom[neigh].chem_bonds_valence > atom[neigh].valence)
3182 : : {
3183 : : /* =Z-OH, #Z-OH, =Z-O(-), #Z-O(-), -Z=O, =Z=O;
3184 : : =Z(+)-OH, #Z(+)-OH, =Z-O(-), #Z-O(-), -Z(+)=O, =Z(+)=O; O = O, S, Se, Te */
3185 : : /* neigh = Z\{N,C} = P, As, Sb, S, Se, Te, Cl, Br, I */
3186 [ + + + - ]: 24 : if (at->chem_bonds_valence == 1 && IsZOX( atom, at_no, 0 ))
3187 : : {
3188 : 20 : type = ATT_ZOO;
3189 [ + + ]: 20 : if (at->num_H == 1)
3190 : : {
3191 : 4 : mask |= ( ATBIT_ZOOH ); /* 18: O=Z-OH; O=O,S,Se,Te; Z may have charge */
3192 : : /*nAtTypeTotals[ATTOT_NUM_ZOOH] ++;*/
3193 : : }
3194 : : else
3195 : : {
3196 [ + - ]: 16 : if (at->charge == -1)
3197 : : {
3198 : 16 : mask |= ( ATBIT_ZOO_Minus ); /* 19: O=Z-O(-); O = O, S, Se, Te */
3199 : : /*nAtTypeTotals[ATTOT_NUM_ZOO_Minus] ++;*/
3200 : : }
3201 : : else
3202 : : {
3203 : 0 : mask |= ( ATBIT_Errors );
3204 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3205 : : }
3206 : : }
3207 : : }
3208 : : else
3209 : : {
3210 : 4 : type = ATT_OTHER_ZO;
3211 [ - + ]: 4 : if (at->num_H == 1)
3212 : : {
3213 : 0 : mask |= ( ATBIT_ZOH ); /* 20: =Z-OH, #Z-OH; O=O,S,Se,Te; Z may have charge */
3214 : : /*nAtTypeTotals[ATTOT_NUM_ZOH] ++;*/
3215 : : }
3216 : : else
3217 : : {
3218 [ - + ]: 4 : if (at->charge == -1)
3219 : : {
3220 : 0 : mask |= ( ATBIT_ZO_Minus ); /* 21: =Z-O(-), #Z-O(-); O = O, S, Se, Te */
3221 : : /*nAtTypeTotals[ATTOT_NUM_ZO_Minus] ++;*/
3222 : : }
3223 : : else
3224 : : {
3225 [ + - ]: 4 : if (at->num_H == 0)
3226 : : {
3227 : 4 : mask |= ( ATBIT_ZO ); /* 22: -Z=O, =Z=O; O=O,S,Se,Te; Z may have charge */
3228 : : /*nAtTypeTotals[ATTOT_NUM_ZO] ++;*/
3229 : : }
3230 : : else
3231 : : {
3232 : 0 : mask |= ( ATBIT_Errors );
3233 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3234 : : }
3235 : : }
3236 : : }
3237 : : }
3238 : : }
3239 : : else
3240 : : {
3241 [ + + + - ]: 140 : if (at->charge == -1 && !is_el_a_metal( atom[neigh].el_number ))
3242 : : {
3243 : : /* >Z-O(-); O=O,S,Se,Te */
3244 : 14 : type = ATT_OTHER_NEG_O;
3245 : 14 : mask |= ( ATBIT_O_Minus ); /* 23: -Z-O(-); O=O,S,Se,Te */
3246 : : /*nAtTypeTotals[ATTOT_NUM_ZO_Minus] ++;*/
3247 : : }
3248 : : }
3249 : : }
3250 : : }
3251 : : }
3252 : : }
3253 : : }
3254 : : }
3255 : :
3256 : : else
3257 : : {
3258 [ + - + - ]: 16 : if (at->charge == -1 && at->num_H == 1)
3259 : : {
3260 : 16 : type = ATT_OH_MINUS;
3261 : 16 : mask |= ( ATBIT_O_Minus ); /* 25: HO(-); O=O,S,Se,Te */
3262 : : }
3263 : : }
3264 : : }
3265 : : }
3266 : : }
3267 : : }
3268 : :
3269 : : else
3270 : : {
3271 : : /* P, N, neutral valence = 3 (not 5) */
3272 [ + + ]: 1117 : if (( at->el_number == EL_NUMBER_N ||
3273 [ + + ]: 1081 : at->el_number == EL_NUMBER_P ) &&
3274 [ - + - + ]: 38 : 0 <= at->valence && at->valence <= 3 &&
3275 [ - + ]: 38 : at->chem_bonds_valence + at->num_H == 3 + at->charge)
3276 : : {
3277 [ + + - + ]: 38 : if (at->valence && !( num_z /*|| num_o == at->valence*/ ))
3278 : : {
3279 [ # # ]: 0 : if (num_m == at->valence)
3280 : : {
3281 : 0 : goto exit_function;
3282 : : }
3283 : 0 : goto count_mask_bits; /* N(III), N(-)(II), N(+)(IV) and same P that have only oxygen neighbors are ignored here */
3284 : : }
3285 [ + + ]: 38 : type = ( at->el_number == EL_NUMBER_N ) ? ATT_ATOM_N : ATT_ATOM_P;
3286 [ - + - - ]: 38 : switch (at->charge)
3287 : : {
3288 : 0 : case -1:
3289 [ # # ]: 0 : if (at->el_number == EL_NUMBER_N)
3290 : : {
3291 : 0 : mask |= ( ATBIT_N_Minus ); /* 26: -NH(-), =N(-), >N(-) */
3292 [ # # ]: 0 : if (at->num_H)
3293 : : {
3294 : 0 : mask |= ( ATBIT_NP_H ); /* 27: -NH(-) */
3295 : : }
3296 : : #if ( FIX_NP_MINUS_BUG == 1 )
3297 : : else
3298 : : {
3299 [ # # # # : 0 : if (at->valence == 1 && at->chem_bonds_valence >= 2 && ( at->bond_type[0] & BOND_MARK_ALL ))
# # ]
3300 : : {
3301 : 0 : type |= ATT_NP_MINUS_V23; /* =N(-) created by normalization 2010-03-11 DT */
3302 : : }
3303 : : }
3304 : : #endif
3305 : : }
3306 : : /*nAtTypeTotals[ATTOT_NUM_N_Minus] += (at->el_number == EL_NUMBER_N);*/
3307 : 0 : break;
3308 : 38 : case 0:
3309 [ + - ]: 38 : if (at->num_H)
3310 : : {
3311 : 38 : mask |= ( ATBIT_NP_H ); /* 28: -NH2, =NH, >NH */
3312 : : /*nAtTypeTotals[ATTOT_NUM_NP_H] ++;*/
3313 : : }
3314 : : else
3315 : : {
3316 [ # # ]: 0 : if (bUnsatNHasTerminalO == 1)
3317 : : {
3318 : 0 : mask |= ( ATBIT_ON ); /* 29: -N=O,-N=OH(+) only, not =N-OH */
3319 : : }
3320 : : else
3321 : : {
3322 : 0 : mask |= ( ATBIT_NP ); /* 30: -P=O,-P=OH(+), >N- =N- (incl. =N-OH) , #N */
3323 : : /*nAtTypeTotals[ATTOT_NUM_NP] ++;*/
3324 : : }
3325 : : }
3326 : 38 : break; /* ignore neutral N or P */
3327 : 0 : case 1:
3328 [ # # ]: 0 : if (at->num_H)
3329 : : {
3330 : 0 : mask |= ( ATBIT_NP_Proton ); /* 31: NH4(+), -NH3(+), =NH2(+), >NH2(+), =NH(+)-, >NH(+)-, #NH(+) */
3331 : : /*nAtTypeTotals[ATTOT_NUM_NP_Proton] ++;*/
3332 : : }
3333 : : else
3334 : : {
3335 [ # # ]: 0 : if (at->chem_bonds_valence > at->valence)
3336 : : {
3337 : 0 : mask |= ( ATBIT_NP_Plus ); /* =N(+)=, #N(+)-, =N(+)< */
3338 : : /*nAtTypeTotals[ATTOT_NUM_NP_Plus] ++;*/
3339 : : }
3340 : : else
3341 : : {
3342 : 0 : type = 0; /* 32: ignore onium cations >N(+)< */
3343 : : }
3344 : : }
3345 : 0 : break;
3346 : 0 : default:
3347 : 0 : mask |= ( 1 << ATTOT_NUM_Errors );
3348 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3349 : 0 : break;
3350 : : }
3351 : : }
3352 : : }
3353 : :
3354 : 1079 : count_mask_bits:
3355 [ + + ]: 1407 : if (nAtTypeTotals)
3356 : : {
3357 [ + + + - ]: 770 : if (mask && !( mask & ( ATBIT_Errors ) ))
3358 : : {
3359 [ + + ]: 3876 : for (i = 0, bit = 1; i < ATTOT_ARRAY_LEN; i++, bit <<= 1)
3360 : : {
3361 [ + + ]: 3762 : if (bit & mask)
3362 : : {
3363 : 114 : nAtTypeTotals[i] += delta;
3364 : : }
3365 : : }
3366 : : }
3367 : :
3368 : : /* Count charges */
3369 [ + + ]: 770 : if (at->charge)
3370 : : {
3371 : 46 : nAtTypeTotals[ATTOT_TOT_CHARGE] += delta * at->charge;
3372 : 46 : nAtTypeTotals[ATTOT_NUM_CHARGES] += delta;
3373 : : }
3374 : : }
3375 : :
3376 [ - + ]: 1407 : if (pMask)
3377 : : {
3378 : 1407 : *pMask = mask;
3379 : : }
3380 : :
3381 : 0 : exit_function:
3382 [ - + ]: 1492 : if (mask & ( ATBIT_Errors ))
3383 : : {
3384 : 0 : type = 0;
3385 [ # # ]: 0 : if (nAtTypeTotals)
3386 : : {
3387 : 0 : nAtTypeTotals[ATTOT_NUM_Errors] += 1;
3388 : : }
3389 : : }
3390 : :
3391 : :
3392 : 1492 : return type;
3393 : : }
3394 : :
3395 : :
3396 : : /****************************************************************************/
3397 : 0 : int SimpleRemoveHplusNPO( inp_ATOM *at,
3398 : : int num_atoms,
3399 : : int nAtTypeTotals[],
3400 : : T_GROUP_INFO *t_group_info )
3401 : : {
3402 : : int i, mask, type, num_removed;
3403 [ # # ]: 0 : for (i = 0, num_removed = 0; i < num_atoms; i++)
3404 : : {
3405 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3406 [ # # ]: 0 : if (( PR_SIMPLE_TYP & ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ) ) &&
3407 [ # # ]: 0 : ( PR_SIMPLE_MSK & mask ))
3408 : : {
3409 : : #if ( bRELEASE_VERSION == 0 )
3410 : : if (at[i].charge != 1 || at[i].num_H == 0)
3411 : : {
3412 : : return -1; /* program error */
3413 : : }
3414 : : #endif
3415 : 0 : type = GetAtomChargeType(at, i, nAtTypeTotals, &mask, 1); /* subtract at[i] */ /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3416 : 0 : at[i].charge = 0;
3417 : 0 : AddOrRemoveExplOrImplH( -1, at, num_atoms, (AT_NUMB) i, t_group_info );
3418 : : /*at[i].num_H --;*/
3419 : 0 : num_removed++;
3420 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
3421 : 0 : type = GetAtomChargeType(at, i, nAtTypeTotals, &mask, 0); /* add changed at[i] */ /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3422 : : #else
3423 : : type = GetAtomChargeType(at, i, nAtTypeTotals, &mask, 1); /* bug: subtract instead of add */ /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3424 : : #endif
3425 : : /*
3426 : : if ( nAtTypeTotals ) {
3427 : : nAtTypeTotals[ATTOT_NUM_NP_Proton] --;
3428 : : if ( at[i].num_H ) {
3429 : : nAtTypeTotals[ATTOT_NUM_NP_H] ++;
3430 : : } else {
3431 : : nAtTypeTotals[ATTOT_NUM_NP] ++;
3432 : : }
3433 : : nAtTypeTotals[ATTOT_TOT_CHARGE] --;
3434 : : nAtTypeTotals[ATTOT_NUM_CHARGES] --;
3435 : : }
3436 : : */
3437 : : }
3438 : : }
3439 : :
3440 : 0 : return num_removed;
3441 : : }
3442 : :
3443 : :
3444 : : /****************************************************************************/
3445 : 0 : int bIsAtomTypeHard( inp_ATOM *at,
3446 : : int endpoint,
3447 : : int nType,
3448 : : int nMask,
3449 : : int nCharge )
3450 : : {
3451 : : int mask;
3452 [ # # # # ]: 0 : if (( nType & GetAtomChargeType( at, endpoint, NULL, &mask, 0 ) ) && ( mask & nMask )
3453 : : #if ( OPPOSITE_CHARGE_IN_CGROUP == 0 )
3454 : : && ( at[endpoint].charge == nCharge || !at[endpoint].charge )
3455 : : #endif
3456 : : )
3457 : : {
3458 : 0 : return 1;
3459 : : }
3460 : :
3461 : 0 : return 0;
3462 : : }
3463 : :
3464 : :
3465 : : /****************************************************************************/
3466 : 0 : int bIsHDonorAccAtomType( inp_ATOM *at, int endpoint, int *cSubType )
3467 : : {
3468 [ # # ]: 0 : if (bIsAtomTypeHard( at, endpoint, PR_HARD_TYP_H, PR_HARD_MSK_H, 0 ))
3469 : : {
3470 : : /* Obtain donor/acceptor info */
3471 : 0 : int neutral_valence = at[endpoint].chem_bonds_valence + at[endpoint].num_H - at[endpoint].charge;
3472 [ # # # # ]: 0 : if (neutral_valence != 2 /* O, S, Se, Te */ &&
3473 : : neutral_valence != 3 /* N, P */)
3474 : : {
3475 : 0 : return -1; /* wrong endpoint neutral valence */
3476 : : }
3477 : : else
3478 : : {
3479 : 0 : int edge_flow = at[endpoint].num_H;
3480 : 0 : int num_bonds = at[endpoint].valence;
3481 : 0 : int edge_cap = neutral_valence - num_bonds; /* does not allow to reduce -NH3(+) to #N or -OH(+)- to -O- */
3482 : 0 : edge_flow = inchi_min( edge_flow, edge_cap );
3483 : : /* what this means: */
3484 [ # # ]: 0 : if (edge_cap)
3485 : : {
3486 [ # # ]: 0 : if (edge_cap > edge_flow)
3487 : : {
3488 : 0 : *cSubType |= SALT_ACCEPTOR;
3489 : : }
3490 [ # # ]: 0 : if (edge_flow)
3491 : : {
3492 : 0 : *cSubType |= SALT_DONOR_H;
3493 : : }
3494 : 0 : return 4;
3495 : : }
3496 : : }
3497 : : }
3498 : :
3499 : 0 : return -1;
3500 : : }
3501 : :
3502 : :
3503 : : /****************************************************************************/
3504 : 0 : int bIsNegAtomType( inp_ATOM *at, int endpoint, int *cSubType )
3505 : : {
3506 : 0 : int sub_type = 0;
3507 [ # # ]: 0 : if (bIsAtomTypeHard( at, endpoint, PR_HARD_TYP_NEG, PR_HARD_MSK_NEG, -1 ))
3508 : : {
3509 : : /* Obtain donor/acceptor info */
3510 : 0 : int neutral_valence = at[endpoint].chem_bonds_valence + at[endpoint].num_H - at[endpoint].charge;
3511 [ # # # # ]: 0 : if (neutral_valence != 2 /* O, S, Se, Te */ &&
3512 : : neutral_valence != 3 /* N, P */)
3513 : : {
3514 : 0 : return -1; /* wrong endpoint neutral valence */
3515 : : }
3516 : : else
3517 : : {
3518 : 0 : int edge_flow = ( at[endpoint].charge == -1 );
3519 : 0 : int num_bonds = at[endpoint].valence;
3520 : 0 : int edge_cap = neutral_valence - num_bonds - at[endpoint].num_H; /* does not allow to reduce -NH3(+) to #N or -OH(+)- to -O- */
3521 : 0 : edge_flow = inchi_min( edge_flow, edge_cap );
3522 : : /* what this means: */
3523 [ # # ]: 0 : if (edge_cap)
3524 : : {
3525 [ # # ]: 0 : if (edge_cap > edge_flow)
3526 : : {
3527 : 0 : sub_type |= SALT_ACCEPTOR;
3528 : : }
3529 [ # # ]: 0 : if (edge_flow)
3530 : : {
3531 : 0 : sub_type |= SALT_DONOR_Neg;
3532 : : }
3533 [ # # ]: 0 : if (sub_type)
3534 : : {
3535 : 0 : *cSubType |= sub_type;
3536 : 0 : return 4;
3537 : : }
3538 : : }
3539 : : }
3540 : : }
3541 : :
3542 : 0 : return -1;
3543 : : }
3544 : :
3545 : :
3546 : : /****************************************************************************/
3547 : 0 : int bIsHardRemHCandidate( inp_ATOM *at, int i, int *cSubType )
3548 : : {
3549 : : int ret1, ret2, ret;
3550 : 0 : int sub_type = 0;
3551 : 0 : ret1 = bIsHDonorAccAtomType( at, i, &sub_type );
3552 : 0 : ret2 = bIsNegAtomType( at, i, &sub_type );
3553 : 0 : ret = inchi_max( ret1, ret2 );
3554 [ # # # # ]: 0 : if (ret > 0 && sub_type)
3555 : : {
3556 : 0 : *cSubType |= sub_type;
3557 : 0 : return ret;
3558 : : }
3559 : 0 : return -1;
3560 : : }
3561 : :
3562 : :
3563 : : /****************************************************************************/
3564 : 12 : int CreateCGroupInBnStruct( inp_ATOM *at,
3565 : : int num_atoms,
3566 : : BN_STRUCT *pBNS,
3567 : : int nType,
3568 : : int nMask,
3569 : : int nCharge )
3570 : : {
3571 : 12 : int k, c_point, cg, centerpoint, fictpoint, type, ret = 0;
3572 : 12 : int num_cg = 1;
3573 : 12 : int num_edges = pBNS->num_edges;
3574 : 12 : int num_vertices = pBNS->num_vertices; /* new c-group bns-ID */
3575 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing charge c-group */
3576 : : BNS_VERTEX *vertex_cpoint;
3577 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric c_point */
3578 : : int mask, num_CPoints;
3579 : :
3580 : : /* Debug: check overflow */
3581 [ - + ]: 12 : if (num_vertices + num_cg >= pBNS->max_vertices)
3582 : : {
3583 : 0 : return BNS_VERT_EDGE_OVFL;
3584 : : }
3585 : :
3586 : : /* Count new c-group edges */
3587 [ + + ]: 54 : for (c_point = 0, num_CPoints = 0; c_point < num_atoms; c_point++)
3588 : : {
3589 [ - + - - ]: 42 : if (( nType & GetAtomChargeType( at, c_point, NULL, &mask, 0 ) ) && ( mask & nMask )
3590 : : #if ( OPPOSITE_CHARGE_IN_CGROUP == 0 )
3591 : : && ( at[c_point].charge == nCharge || !at[c_point].charge )
3592 : : #endif
3593 : : )
3594 : : {
3595 : 0 : num_CPoints++;
3596 : : }
3597 : : }
3598 : :
3599 [ + - ]: 12 : if (!num_CPoints)
3600 : : {
3601 : 12 : return 0;
3602 : : }
3603 : :
3604 : : /* Clear the new vertex */
3605 : 0 : memset( pBNS->vert + num_vertices, 0, 1 * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3606 : :
3607 : : /* *old* Make sure the last t-group has the largest t-group ID:
3608 : : this is necessary to correctly add new edges and vertices for testing augmenting paths
3609 : : */
3610 : :
3611 : : /**************************************/
3612 : : /* initialize new fictitious vertex */
3613 : : /* representing c-point group */
3614 : : /**************************************/
3615 : :
3616 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
3617 : :
3618 [ # # ]: 0 : for (cg = 0; cg < num_cg; cg++, ver_ficpont_prev = vert_ficpoint)
3619 : : {
3620 : : /*
3621 : : vert_ficpoint-1 is the last vertex;
3622 : : vert_ficpoint is the being added vertex
3623 : : Note: nGroupNumber are not contiguous
3624 : : */
3625 : 0 : vert_ficpoint = pBNS->vert + num_vertices + cg;
3626 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
3627 : 0 : vert_ficpoint->max_adj_edges = num_CPoints + BNS_ADD_EDGES;
3628 : 0 : vert_ficpoint->num_adj_edges = 0;
3629 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
3630 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
3631 : 0 : vert_ficpoint->type = BNS_VERT_TYPE_C_GROUP | ( ( nCharge < 0 ) ? BNS_VERT_TYPE_C_NEGATIVE : 0 );
3632 : : }
3633 : :
3634 : : /************************************************/
3635 : : /* Connect c-points to the fictitious vertices */
3636 : : /* representing c-point groups; set caps, flows */
3637 : : /************************************************/
3638 : 0 : cg = 1;
3639 [ # # ]: 0 : for (c_point = 0; c_point < num_atoms; c_point++)
3640 : : {
3641 [ # # # # ]: 0 : if (( nType & ( type = GetAtomChargeType( at, c_point, NULL, &mask, 0 ) ) ) && ( mask & nMask )
3642 : : #if ( OPPOSITE_CHARGE_IN_CGROUP == 0 )
3643 : : && ( at[c_point].charge == nCharge || !at[c_point].charge )
3644 : : #endif
3645 : : )
3646 : : {
3647 : : ;
3648 : : }
3649 : : else
3650 : : {
3651 : 0 : continue;
3652 : : }
3653 : :
3654 : 0 : fictpoint = cg + num_vertices - 1; /* c-group vertex index */
3655 : 0 : vert_ficpoint = pBNS->vert + fictpoint; /* c-group vertex */
3656 : 0 : vertex_cpoint = pBNS->vert + c_point; /* c_point vertex */
3657 : :
3658 : : /* Debug: check overflow */
3659 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
3660 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
3661 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
3662 [ # # ]: 0 : vertex_cpoint->num_adj_edges >= vertex_cpoint->max_adj_edges)
3663 : : {
3664 : : /* djb-rwth: removing redundant code */
3665 : : break;
3666 : : }
3667 : 0 : vertex_cpoint->type |= BNS_VERT_TYPE_C_POINT;
3668 [ # # # # ]: 0 : if (( KNOWN_ACIDIC_TYPE & type ) && nCharge < 0)
3669 : : {
3670 : 0 : vertex_cpoint->type |= pBNS->type_TACN;
3671 : : }
3672 : :
3673 : : #if ( FIX_CPOINT_BOND_CAP != 1 ) /* { */
3674 : : /* Set capacity = 1 to the edges from the c_point to the centerpoint(s) */
3675 : : /* if their current capacity is zero */
3676 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
3677 : : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
3678 : : {
3679 : : int iedge = vertex_cpoint->iedge[k];
3680 : : if (!pBNS->edge[iedge].cap)
3681 : : {
3682 : : /* single bond, possibly between c_point and centerpoint */
3683 : : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
3684 : : if (centerpoint < pBNS->num_atoms &&
3685 : : pBNS->vert[centerpoint].st_edge.cap >= 1)
3686 : : {
3687 : : int bond_type = ( at[c_point].bond_type[k] & BOND_TYPE_MASK );
3688 : : if (bond_type == BOND_TAUTOM ||
3689 : : bond_type == BOND_ALTERN ||
3690 : : bond_type == BOND_SINGLE)
3691 : : {
3692 : : pBNS->edge[iedge].cap = 1;
3693 : : }
3694 : : }
3695 : : }
3696 : : }
3697 : : #endif /* } FIX_CPOINT_BOND_CAP */
3698 : :
3699 : : /* Create a new edge connecting c_point to the new fictitious c-group vertex vert_ficpoint */
3700 : 0 : edge = pBNS->edge + num_edges;
3701 : 0 : edge->cap = 1;
3702 : 0 : edge->flow = 0;
3703 : 0 : edge->pass = 0;
3704 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
3705 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask; /* remove previous temporary ban */
3706 : : #endif
3707 : :
3708 : : /* nCharge = +1: mark edge to c-point having no (+)-moveable charge with flow=1 */
3709 : : /* nCharge = -1: mark edge to c-point having -1 moveable charge with flow=1 */
3710 : :
3711 [ # # # # : 0 : if ((nCharge == 1 && at[c_point].charge != 1) || (nCharge == -1 && at[c_point].charge == -1)) /* djb-rwth: addressing LLVM warning */
# # # # ]
3712 : : /*if ( !CHARGED_CPOINT(at,c_point) )*/
3713 : : {
3714 : : /* Increment new edge flow, update st_edges of the adjacent vertices */
3715 : 0 : edge->flow++;
3716 : : /* Increment c-group vertex st-flow & cap */
3717 : 0 : vert_ficpoint->st_edge.flow++;
3718 : 0 : vert_ficpoint->st_edge.cap++;
3719 : : /* Increment c-point vertex st-flow & cap */
3720 : 0 : vertex_cpoint->st_edge.flow++;
3721 : 0 : vertex_cpoint->st_edge.cap++;
3722 : : }
3723 : :
3724 : : #if ( FIX_CPOINT_BOND_CAP == 1 ) /* { */
3725 : : /* Set capacity = 1 to the edges from the c_point to the centerpoint(s) */
3726 : : /* if their current capacity is zero */
3727 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
3728 [ # # ]: 0 : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
3729 : : {
3730 : 0 : int iedge = vertex_cpoint->iedge[k];
3731 : 0 : VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
3732 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
3733 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
3734 : : {
3735 : : /* Single bond, possibly between c_point and centerpoint */
3736 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
3737 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
3738 : : {
3739 : 0 : nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
3740 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
3741 : 0 : pBNS->edge[iedge].cap = nNewCap;
3742 : : }
3743 : : }
3744 : : #if ( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
3745 : : else
3746 : : {
3747 : : if (centerpoint < pBNS->num_atoms &&
3748 : : edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP)
3749 : : {
3750 : : pBNS->edge[iedge].cap++;
3751 : : }
3752 : : }
3753 : : #endif
3754 : : }
3755 : : #endif /* } FIX_CPOINT_BOND_CAP */
3756 : :
3757 : : /* Connect edge to c_point and fictpoint and increment the counters of neighbors and edges */
3758 : 0 : edge->neighbor1 = c_point; /* the smallest out of v1=endopoint and v2=num_vertices */
3759 : 0 : edge->neighbor12 = c_point ^ fictpoint; /* v1 ^ v2 */
3760 : 0 : vertex_cpoint->iedge[vertex_cpoint->num_adj_edges] = num_edges;
3761 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
3762 : 0 : edge->neigh_ord[0] = vertex_cpoint->num_adj_edges++;
3763 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
3764 : 0 : edge->cap0 = edge->cap;
3765 : 0 : edge->flow0 = edge->flow;
3766 : : }
3767 : :
3768 : 0 : ret = pBNS->num_vertices; /* new c-group atom number */
3769 : 0 : pBNS->num_edges = num_edges;
3770 : 0 : pBNS->num_vertices += num_cg;
3771 : 0 : pBNS->num_c_groups += num_cg;
3772 : :
3773 : 0 : return ret;
3774 : : }
3775 : :
3776 : :
3777 : : /****************************************************************************/
3778 : 4 : int CreateTGroupInBnStruct( inp_ATOM *at,
3779 : : int num_atoms,
3780 : : BN_STRUCT *pBNS,
3781 : : int nType,
3782 : : int nMask )
3783 : : {
3784 : 4 : int ret = 0;
3785 : : /* ret = ReInitBnStruct( pBNS ); */
3786 : : int k, endpoint, tg, centerpoint, fictpoint;
3787 : 4 : int num_tg = 1;
3788 : 4 : int num_edges = pBNS->num_edges;
3789 : 4 : int num_vertices = pBNS->num_vertices;
3790 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing t-group */
3791 : : BNS_VERTEX *vert_endpoint;
3792 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
3793 : : int mask, num_endpoints, neutral_valence, edge_flow, edge_cap, num_bonds;
3794 : :
3795 : : /* Debug: check overflow */
3796 [ - + ]: 4 : if (num_vertices + num_tg >= pBNS->max_vertices)
3797 : : {
3798 : 0 : return BNS_VERT_EDGE_OVFL;
3799 : : }
3800 : :
3801 : : /* Count new t-group edges */
3802 [ + + ]: 18 : for (endpoint = 0, num_endpoints = 0; endpoint < num_atoms; endpoint++)
3803 : : {
3804 [ - + - - ]: 14 : if (( nType & GetAtomChargeType( at, endpoint, NULL, &mask, 0 ) ) && ( mask & nMask )
3805 : : )
3806 : : {
3807 : 0 : num_endpoints++;
3808 : : }
3809 : : }
3810 : :
3811 [ + - ]: 4 : if (!num_endpoints)
3812 : : {
3813 : 4 : return 0;
3814 : : }
3815 : :
3816 : : /* Since t-group IDs may be not contiguous, clear all vertices that will be added.
3817 : : all-zeroes-vertex will be ignored by the BNS
3818 : : */
3819 : 0 : memset( pBNS->vert + num_vertices, 0, num_tg * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3820 : :
3821 : : /* *old* Make sure the last t-group has the largest t-group ID:
3822 : : this is necessary to correctly add new edges and vertices for testing augmenting paths
3823 : : */
3824 : :
3825 : : /**************************************/
3826 : : /* Initialize new fictitious vertex */
3827 : : /* representing t-point group */
3828 : : /**************************************/
3829 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
3830 : :
3831 [ # # ]: 0 : for (tg = 0; tg < num_tg; tg++, ver_ficpont_prev = vert_ficpoint)
3832 : : {
3833 : : /*
3834 : : vert_ficpoint-1 is the last vertex;
3835 : : vert_ficpoint is the vertex that is being added
3836 : : Note: nGroupNumber are not contiguous
3837 : : */
3838 : 0 : vert_ficpoint = pBNS->vert + num_vertices + tg;
3839 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
3840 : 0 : vert_ficpoint->max_adj_edges = num_endpoints + BNS_ADD_EDGES + BNS_ADD_SUPER_TGROUP;
3841 : 0 : vert_ficpoint->num_adj_edges = 0;
3842 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
3843 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
3844 : 0 : vert_ficpoint->type |= BNS_VERT_TYPE_TGROUP;
3845 : : }
3846 : :
3847 : 0 : tg = 1;
3848 [ # # ]: 0 : for (endpoint = 0; endpoint < num_atoms; endpoint++)
3849 : : {
3850 [ # # # # ]: 0 : if (( nType & GetAtomChargeType( at, endpoint, NULL, &mask, 0 ) ) && ( mask & nMask ))
3851 : : {
3852 : : ;
3853 : : }
3854 : : else
3855 : : {
3856 : 0 : continue;
3857 : : }
3858 : 0 : fictpoint = tg + num_vertices - 1;
3859 : 0 : vert_ficpoint = pBNS->vert + fictpoint;
3860 : 0 : vert_endpoint = pBNS->vert + endpoint;
3861 : : /* Debug: check overflow */
3862 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
3863 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
3864 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
3865 [ # # ]: 0 : vert_endpoint->num_adj_edges >= vert_endpoint->max_adj_edges)
3866 : : {
3867 : : /* djb-rwth: removing redundant code */
3868 : : break;
3869 : : }
3870 : :
3871 : : /* Obtain donor/acceptor info */
3872 : 0 : neutral_valence = at[endpoint].chem_bonds_valence + at[endpoint].num_H - at[endpoint].charge;
3873 [ # # # # ]: 0 : if (neutral_valence != 2 /* O, S, Se, Te */ &&
3874 : : neutral_valence != 3 /* N, P */)
3875 : : {
3876 : : /* djb-rwth: removing redundant code */
3877 : 0 : break;
3878 : : }
3879 : 0 : edge_flow = at[endpoint].num_H;
3880 : 0 : num_bonds = at[endpoint].valence;
3881 : 0 : edge_cap = neutral_valence - num_bonds; /* does not allow to reduce -NH3(+) to #N or -OH(+)- to -O- */
3882 : :
3883 [ # # # # ]: 0 : if (3 == neutral_valence /* N or P */ && 1 < num_bonds)
3884 : : {
3885 : 0 : edge_cap++; /* allow -NH2(+)- => -N=, >NH(+)- => >N- */
3886 : : }
3887 : 0 : edge_flow = inchi_min( edge_flow, edge_cap );
3888 : : /*
3889 : : if ( !nGetEndpointInfo( at, endpoint, &eif ) ) {
3890 : : ret = BNS_BOND_ERR;
3891 : : break;
3892 : : }
3893 : : */
3894 : 0 : vert_endpoint->type |= BNS_VERT_TYPE_ENDPOINT;
3895 : :
3896 : : /* Create a new edge connecting endpoint to the new fictitious t-group vertex vert_ficpoint */
3897 : 0 : edge = pBNS->edge + num_edges;
3898 : 0 : edge->cap = edge_cap;
3899 : 0 : edge->flow = edge_flow;
3900 : 0 : edge->pass = 0;
3901 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
3902 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask;
3903 : : #endif
3904 : :
3905 : : /* Adjust st_flow and st_cap of the adjacent vertices */
3906 : : /* Adjust t-group vertex st-flow & cap */
3907 : 0 : vert_ficpoint->st_edge.flow += edge->flow;
3908 : 0 : vert_ficpoint->st_edge.cap += edge->flow;
3909 : : /* adjust endpoint vertex st-flow & cap */
3910 : 0 : vert_endpoint->st_edge.flow += edge->flow;
3911 : 0 : vert_endpoint->st_edge.cap += edge->flow;
3912 : :
3913 : : /* Adjust edge cap & flow according to the number of H and number of bonds */
3914 [ # # ]: 0 : for (k = 0; k < vert_endpoint->num_adj_edges; k++)
3915 : : {
3916 : 0 : int iedge = vert_endpoint->iedge[k];
3917 : 0 : VertexFlow nNewCap = vert_endpoint->st_edge.cap;
3918 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
3919 : : {
3920 : : /* single bond, possibly between endpoint and centerpoint */
3921 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ endpoint );
3922 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
3923 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
3924 : : {
3925 : 0 : nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
3926 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
3927 : 0 : pBNS->edge[iedge].cap = nNewCap;
3928 : : }
3929 : : }
3930 : : }
3931 : :
3932 : : /* Connect edge to endpoint and fictpoint and increment the counters of neighbors and edges */
3933 : 0 : edge->neighbor1 = endpoint; /* the smallest out of v1=endopoint and v2=num_vertices */
3934 : 0 : edge->neighbor12 = endpoint ^ fictpoint; /* v1 ^ v2 */
3935 : 0 : vert_endpoint->iedge[vert_endpoint->num_adj_edges] = num_edges;
3936 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
3937 : 0 : edge->neigh_ord[0] = vert_endpoint->num_adj_edges++;
3938 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
3939 : 0 : edge->cap0 = edge->cap;
3940 : 0 : edge->flow0 = edge->flow;
3941 : : }
3942 : :
3943 : 0 : ret = pBNS->num_vertices; /* new t-group atom number */
3944 : 0 : pBNS->num_edges = num_edges;
3945 : 0 : pBNS->num_vertices += num_tg;
3946 : 0 : pBNS->num_t_groups += num_tg;
3947 : :
3948 : 0 : return ret;
3949 : : }
3950 : :
3951 : :
3952 : : /****************************************************************************/
3953 : 0 : int RemoveLastGroupFromBnStruct( inp_ATOM *at,
3954 : : int num_atoms,
3955 : : int tg,
3956 : : BN_STRUCT *pBNS )
3957 : : {
3958 : 0 : int ret = 0;
3959 : : /* ret = ReInitBnStruct( pBNS ); */
3960 : : int k, endpoint, /*centerpoint, fictpoint,*/ iedge;
3961 : 0 : int num_edges = pBNS->num_edges;
3962 : 0 : int num_vertices = pBNS->num_vertices;
3963 : : BNS_VERTEX *vert_ficpoint /*, *ver_ficpont_prev*/; /* fictitious vertex describing t-group */
3964 : : BNS_VERTEX *vert_endpoint;
3965 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
3966 : : /*int mask, num_endpoints, neutral_valence, edge_flow, edge_cap, num_bonds;*/
3967 : 0 : int is_t_group = 0, is_c_group = 0;
3968 : :
3969 : : /* Debug: check overflow */
3970 [ # # ]: 0 : if (pBNS->num_added_atoms + pBNS->num_c_groups + pBNS->num_t_groups + num_atoms >= pBNS->max_vertices)
3971 : : {
3972 : 0 : return BNS_VERT_EDGE_OVFL;
3973 : : }
3974 : :
3975 [ # # ]: 0 : if (tg + 1 != num_vertices)
3976 : : {
3977 : 0 : return BNS_VERT_EDGE_OVFL;
3978 : : }
3979 : :
3980 : 0 : vert_ficpoint = pBNS->vert + tg;
3981 : :
3982 [ # # ]: 0 : if (vert_ficpoint->type & BNS_VERT_TYPE_TGROUP)
3983 : : {
3984 : 0 : is_t_group = 1;
3985 : : }
3986 [ # # ]: 0 : if (vert_ficpoint->type & BNS_VERT_TYPE_C_GROUP)
3987 : : {
3988 : 0 : is_c_group = 1;
3989 [ # # ]: 0 : if (vert_ficpoint->type & BNS_VERT_TYPE_C_NEGATIVE)
3990 : : {
3991 : 0 : is_c_group = 2;
3992 : : }
3993 : : }
3994 : :
3995 [ # # ]: 0 : for (k = vert_ficpoint->num_adj_edges - 1; 0 <= k; k--)
3996 : : {
3997 : 0 : iedge = vert_ficpoint->iedge[k];
3998 [ # # ]: 0 : if (iedge + 1 != num_edges)
3999 : : {
4000 : 0 : return BNS_VERT_EDGE_OVFL;
4001 : : }
4002 : 0 : edge = pBNS->edge + iedge;
4003 : 0 : endpoint = edge->neighbor12 ^ tg;
4004 : 0 : vert_endpoint = pBNS->vert + endpoint;
4005 : : /* adjust st_flow, st_cap */
4006 : 0 : vert_endpoint->st_edge.cap0 =
4007 : 0 : vert_endpoint->st_edge.cap -= edge->flow;
4008 : 0 : vert_endpoint->st_edge.flow0 =
4009 : 0 : vert_endpoint->st_edge.flow -= edge->flow;
4010 [ # # # # ]: 0 : if (pBNS->type_TACN && ( vert_endpoint->type & pBNS->type_TACN ) == pBNS->type_TACN)
4011 : : {
4012 : 0 : vert_endpoint->type ^= pBNS->type_TACN;
4013 : : }
4014 [ # # ]: 0 : if (is_t_group)
4015 : : {
4016 : 0 : vert_endpoint->type ^= ( vert_ficpoint->type & BNS_VERT_TYPE_ENDPOINT );
4017 : : }
4018 [ # # ]: 0 : if (is_c_group)
4019 : : {
4020 : 0 : vert_endpoint->type ^= ( vert_ficpoint->type & BNS_VERT_TYPE_C_POINT );
4021 : : }
4022 : : /* Remove edge */
4023 [ # # ]: 0 : if (edge->neigh_ord[0] + 1 != vert_endpoint->num_adj_edges)
4024 : : {
4025 : 0 : return BNS_VERT_EDGE_OVFL;
4026 : : }
4027 : 0 : vert_endpoint->num_adj_edges--;
4028 : 0 : memset( edge, 0, sizeof( *edge ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4029 : 0 : num_edges--;
4030 [ # # # # ]: 0 : if (1 == is_t_group && endpoint < num_atoms)
4031 : : {
4032 : 0 : at->endpoint = 0;
4033 : : }
4034 [ # # # # ]: 0 : if (1 == is_c_group && endpoint < num_atoms)
4035 : : {
4036 : 0 : at->c_point = 0;
4037 : : }
4038 : : }
4039 : 0 : memset( vert_ficpoint, 0, sizeof( *vert_ficpoint ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4040 : 0 : num_vertices--;
4041 : :
4042 : 0 : pBNS->num_edges = num_edges;
4043 : 0 : pBNS->num_vertices = num_vertices;
4044 [ # # ]: 0 : if (is_t_group)
4045 : : {
4046 : 0 : pBNS->num_t_groups--;
4047 : : }
4048 [ # # ]: 0 : if (is_c_group)
4049 : : {
4050 : 0 : pBNS->num_c_groups--;
4051 : : }
4052 : :
4053 : 0 : return ret;
4054 : : }
4055 : :
4056 : :
4057 : :
4058 : : /****************************************************************************/
4059 : 14 : int SetInitCapFlowToCurrent( BN_STRUCT *pBNS )
4060 : : {
4061 : : int i, j;
4062 : 14 : BNS_EDGE *pEdge = NULL;
4063 [ + + ]: 65 : for (i = 0; i < pBNS->num_vertices; i++)
4064 : : {
4065 : 51 : pBNS->vert[i].st_edge.flow0 = pBNS->vert[i].st_edge.flow;
4066 : 51 : pBNS->vert[i].st_edge.cap0 = pBNS->vert[i].st_edge.cap;
4067 [ + + ]: 125 : for (j = 0; j < pBNS->vert[i].num_adj_edges; j++)
4068 : : {
4069 : 74 : pEdge = pBNS->edge + pBNS->vert[i].iedge[j];
4070 : 74 : pEdge->cap0 = pEdge->cap;
4071 : 74 : pEdge->flow0 = pEdge->flow;
4072 : : }
4073 : : }
4074 : :
4075 : 14 : return 0;
4076 : : }
4077 : :
4078 : :
4079 : : int ArTypMask[] =
4080 : : {
4081 : : AR_SIMPLE_TYP1,
4082 : : AR_SIMPLE_MSK1,
4083 : : AR_SIMPLE_TYP2,
4084 : : AR_SIMPLE_MSK2,
4085 : : AR_SIMPLE_TYP3,
4086 : : AR_SIMPLE_MSK3,
4087 : : 0,
4088 : : 0
4089 : : };
4090 : :
4091 : :
4092 : :
4093 : : /****************************************************************************/
4094 : 0 : int SimpleRemoveAcidicProtons( inp_ATOM *at,
4095 : : int num_atoms,
4096 : : BN_AATG *pAATG,
4097 : : int num2remove )
4098 : : {
4099 : 0 : int i, j, max_j = -1, mask, type, num_removed;
4100 : : int num[AR_SIMPLE_STEPS + 1], num_tot;
4101 : :
4102 [ # # ]: 0 : for (j = 0; ArTypMask[2 * j]; j++)
4103 : : {
4104 : 0 : num[max_j = j] = 0;
4105 : : }
4106 : :
4107 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
4108 : : {
4109 [ # # # # : 0 : if (!at[i].charge && at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
# # ]
4110 : : {
4111 [ # # ]: 0 : for (j = 0; j <= max_j; j++)
4112 : : {
4113 [ # # # # : 0 : if (( type & ArTypMask[2 * j] ) && ( mask && ArTypMask[2 * j + 1] ))
# # ]
4114 : : {
4115 : 0 : num[j] ++;
4116 : 0 : break;
4117 : : }
4118 : : }
4119 : : }
4120 : : }
4121 [ # # ]: 0 : for (j = 0, num_tot = 0; j <= max_j; j++)
4122 : : {
4123 [ # # ]: 0 : if (( num_tot += num[j] ) >= num2remove)
4124 : : {
4125 : 0 : max_j = j;
4126 : 0 : break;
4127 : : }
4128 : : }
4129 [ # # ]: 0 : if (!num_tot)
4130 : : {
4131 : 0 : return 0;
4132 : : }
4133 [ # # # # ]: 0 : for (i = 0, num_removed = 0; i < num_atoms && num_removed < num2remove; i++)
4134 : : {
4135 [ # # # # : 0 : if (!at[i].charge && at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
# # ]
4136 : : {
4137 [ # # ]: 0 : for (j = 0; j <= max_j; j++)
4138 : : {
4139 [ # # # # : 0 : if (num[j] && ( type & ArTypMask[2 * j] ) && ( mask && ArTypMask[2 * j + 1] ))
# # # # ]
4140 : : {
4141 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4142 : 0 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 1); /* subtract at[i] */
4143 : 0 : num[j] --;
4144 : 0 : at[i].charge--;
4145 : 0 : AddOrRemoveExplOrImplH( -1, at, num_atoms, (AT_NUMB) i, pAATG->t_group_info );
4146 : : /*at[i].num_H --;*/
4147 : 0 : num_removed++;
4148 : 0 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 0); /* add changed at[i] */ /* ! THIS CHANGES pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] */
4149 : 0 : break;
4150 : : }
4151 : : }
4152 : : }
4153 : : }
4154 : :
4155 : : /*
4156 : : pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] -= num_removed;
4157 : : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] += num_removed;
4158 : : */
4159 : :
4160 : 0 : return num_removed;
4161 : : }
4162 : :
4163 : :
4164 : : /****************************************************************************/
4165 : 774 : int bHasAcidicHydrogen( inp_ATOM *at, int i )
4166 : : {
4167 : 774 : int bFound = 0, j, type, mask;
4168 [ + + + + : 774 : if (!at[i].charge && at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
+ + ]
4169 : : {
4170 [ + + ]: 53 : for (j = 0; ArTypMask[2 * j]; j++)
4171 : : {
4172 [ + + + - ]: 34 : if (( type & ArTypMask[2 * j] ) && ( mask & ArTypMask[2 * j + 1] ))
4173 : : {
4174 : 15 : bFound++;
4175 : 15 : break;
4176 : : }
4177 : : }
4178 : : }
4179 : :
4180 : 774 : return bFound;
4181 : : }
4182 : :
4183 : :
4184 : : /****************************************************************************/
4185 : 0 : int bHasOtherExchangableH( inp_ATOM *at, int i )
4186 : : {
4187 : 0 : int bFound = 0, type, mask;
4188 [ # # # # ]: 0 : if (at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4189 : : {
4190 [ # # # # ]: 0 : if (( type & ATT_ATOM_N ) && ( mask & ATBIT_NP_H ))
4191 : : {
4192 : 0 : bFound++;
4193 : : }
4194 : : }
4195 : :
4196 : 0 : return bFound;
4197 : : }
4198 : :
4199 : :
4200 : : int AaTypMask[] =
4201 : : {
4202 : : AA_SIMPLE_TYP1,
4203 : : AA_SIMPLE_MSK1,
4204 : : #if ( FIX_NP_MINUS_BUG == 1 )
4205 : : AA_SIMPLE_TYP4,
4206 : : AA_SIMPLE_MSK4, /* should not follow 0,0 pair */
4207 : : #endif
4208 : : AA_SIMPLE_TYP2,
4209 : : AA_SIMPLE_MSK2,
4210 : : AA_SIMPLE_TYP3,
4211 : : AA_SIMPLE_MSK3,
4212 : : 0,
4213 : : 0
4214 : : };
4215 : :
4216 : :
4217 : : /****************************************************************************/
4218 : 18 : int SimpleAddAcidicProtons( inp_ATOM *at,
4219 : : int num_atoms,
4220 : : BN_AATG *pAATG,
4221 : : int num2add )
4222 : : {
4223 : 18 : int i, j, max_j = -1, mask, type, num_added;
4224 : : int num[AR_SIMPLE_STEPS + 1], num_tot;
4225 : :
4226 [ + + ]: 54 : for (j = 0; AaTypMask[2 * j]; j++)
4227 : : {
4228 : 36 : num[max_j = j] = 0;
4229 : : }
4230 : :
4231 [ + + ]: 83 : for (i = 0; i < num_atoms; i++)
4232 : : {
4233 [ + + + + ]: 65 : if (at[i].charge == -1 && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4234 : : {
4235 [ + + ]: 27 : for (j = 0; j <= max_j; j++)
4236 : : {
4237 [ + + + - : 25 : if (( type & AaTypMask[2 * j] ) && ( mask && AaTypMask[2 * j + 1] ))
+ - ]
4238 : : {
4239 : 21 : num[j] ++;
4240 : 21 : break;
4241 : : }
4242 : : }
4243 : : }
4244 : : }
4245 [ + + ]: 26 : for (j = 0, num_tot = 0; j <= max_j; j++)
4246 : : {
4247 [ + + ]: 22 : if (( num_tot += num[j] ) >= num2add)
4248 : : {
4249 : 14 : max_j = j;
4250 : 14 : break;
4251 : : }
4252 : : }
4253 [ + + ]: 18 : if (!num_tot)
4254 : : {
4255 : 4 : return 0;
4256 : : }
4257 [ + + + + ]: 60 : for (i = 0, num_added = 0; i < num_atoms && num_added < num2add; i++)
4258 : : {
4259 [ + + + - ]: 46 : if (at[i].charge == -1 && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4260 : : {
4261 [ + - ]: 21 : for (j = 0; j <= max_j; j++)
4262 : : {
4263 [ + - + - : 21 : if (num[j] && ( type & AaTypMask[2 * j] ) && ( mask && AaTypMask[2 * j + 1] ))
+ - + - ]
4264 : : {
4265 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4266 : 21 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 1); /* subtract at[i] */
4267 : 21 : num[j] --;
4268 : 21 : at[i].charge++;
4269 : 21 : AddOrRemoveExplOrImplH( 1, at, num_atoms, (AT_NUMB) i, pAATG->t_group_info );
4270 : : /*at[i].num_H ++;*/
4271 : 21 : num_added++;
4272 : 21 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 0); /* add changed at[i] */
4273 : 21 : break;
4274 : : }
4275 : : }
4276 : : }
4277 : : }
4278 : :
4279 : : /*
4280 : : pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] += num_added;
4281 : : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] -= num_added;
4282 : : */
4283 : :
4284 : 14 : return num_added;
4285 : : }
4286 : :
4287 : :
4288 : : /****************************************************************************/
4289 : 759 : int bHasAcidicMinus( inp_ATOM *at, int i )
4290 : : {
4291 : 759 : int bFound = 0, j, type, mask;
4292 [ + + + + ]: 759 : if (at[i].charge == -1 && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4293 : : {
4294 [ + + ]: 6 : for (j = 0; AaTypMask[2 * j]; j++)
4295 : : {
4296 [ - + - - ]: 4 : if (( type & AaTypMask[2 * j] ) && ( mask & AaTypMask[2 * j + 1] ))
4297 : : {
4298 : 0 : bFound++;
4299 : 0 : break;
4300 : : }
4301 : : }
4302 : : }
4303 : :
4304 : 759 : return bFound;
4305 : : }
4306 : :
4307 : :
4308 : : /****************************************************************************
4309 : : HardRemoveAcidicProtons( ... )
4310 : :
4311 : : Create 2 tautomeric groups:
4312 : : (1) for O on -C=O,
4313 : : (2) for the rest of the atoms.
4314 : : Pull H from (2) to (1); remove later
4315 : : ****************************************************************************/
4316 : 0 : int HardRemoveAcidicProtons( CANON_GLOBALS *pCG,
4317 : : inp_ATOM *at,
4318 : : int num_atoms,
4319 : : BN_AATG *pAATG,
4320 : : int num2remove,
4321 : : int *nNumCanceledCharges,
4322 : : BN_STRUCT *pBNS,
4323 : : BN_DATA *pBD )
4324 : : {
4325 : 0 : int cg_Plus = 0;
4326 : 0 : int cg_Minus = 0;
4327 : 0 : int tg_H_Other = 0;
4328 : 0 : int tg_H_Acid = 0;
4329 : :
4330 : 0 : int ret = 0, ret2;
4331 : 0 : int nDelta, nNumMoved2AcidH = 0, nNumNeutralized = 0, nPrevNumCharges; /* djb-rwth: removing redundant variables */
4332 : :
4333 : : int nPosCharges, nPosCharges2;
4334 : : int nNegCharges, nNegCharges2;
4335 : : /*
4336 : : int nNumNP_H, nNumNP_H2;
4337 : : int nNumOS_H, nNumOS_H2;
4338 : : */
4339 : :
4340 : 0 : nPosCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4341 : 0 : nNegCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4342 : : /*
4343 : : nNumNP_H = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4344 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4345 : : nNumOS_H = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4346 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4347 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4348 : : */
4349 : :
4350 : : /* Prevent free exchange H <-> (-) */
4351 : 0 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4352 : 0 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4353 : 0 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4354 : :
4355 : : /* Create (+) charge group */
4356 : 0 : cg_Plus = CreateCGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_POS, AR_HARD_MSK_POS, 1 );
4357 : :
4358 : : /* create (-) charge group */
4359 : : /*
4360 : : if ( nAtTypeTotals[ATTOT_NUM_CO_Minus] +
4361 : : nAtTypeTotals[ATTOT_NUM_CS_Minus] +
4362 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] +
4363 : : nAtTypeTotals[ATTOT_NUM_N_Minus] )
4364 : : */
4365 : :
4366 : 0 : cg_Minus = CreateCGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_NEG, AR_HARD_MSK_NEG, -1 );
4367 : :
4368 : 0 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4369 : 0 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4370 : 0 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4371 : :
4372 : : /* Create tautomeric group for non-acidic or negatively charged acidic O */
4373 : 0 : tg_H_Other = CreateTGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_HN, AR_HARD_MSK_HN );
4374 : :
4375 : : /* Create tautomeric group for possibly acidic O */
4376 : 0 : tg_H_Acid = CreateTGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_HA, AR_HARD_MSK_HA );
4377 [ # # # # ]: 0 : if (tg_H_Other >= num_atoms && tg_H_Acid >= num_atoms)
4378 : : {
4379 : : /* Find alt path to remove one proton */
4380 : : do
4381 : : {
4382 : : /* Remove a proton */
4383 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4384 : : /* djb-rwth: addressing coverity ID #499503 -- tg_H_Other negative values handled properly */
4385 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4386 : : at, num_atoms,
4387 : : tg_H_Other /*nVertDoubleBond*/,
4388 : : tg_H_Acid /*nVertSingleBond*/,
4389 : : ALT_PATH_MODE_REM_PROTON );
4390 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4391 : : {
4392 : 0 : return ret;
4393 : : }
4394 [ # # ]: 0 : if (ret & 1)
4395 : : {
4396 : 0 : nDelta = ( ret & ~3 ) >> 2;
4397 : : /* djb-rwth: removing redundant code */
4398 : : if (nDelta)
4399 : : {
4400 : : /* Radical pair has disappeared */
4401 : : ; /* goto quick_exit;*/
4402 : : }
4403 : 0 : nNumMoved2AcidH++;
4404 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + 1)
4405 : : {
4406 : 0 : nNumNeutralized += ( nPrevNumCharges - ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - 1 ) ) / 2;
4407 : : }
4408 : : }
4409 [ # # # # ]: 0 : } while (( ret & 1 ) && nNumMoved2AcidH < num2remove);
4410 : :
4411 : : /* Neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O */
4412 [ # # # # : 0 : if (( nNumMoved2AcidH /*|| bCancelChargesAlways*/ ) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
# # ]
4413 [ # # ]: 0 : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4414 : : {
4415 : : do
4416 : : {
4417 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4418 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4419 : : at, num_atoms,
4420 : : cg_Minus /*nVertDoubleBond*/,
4421 : : cg_Plus /*nVertSingleBond*/,
4422 : : ALT_PATH_MODE_REM_PROTON );
4423 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4424 : : {
4425 : 0 : return ret;
4426 : : }
4427 [ # # ]: 0 : if (ret & 1)
4428 : : {
4429 : 0 : nDelta = ( ret & ~3 ) >> 2;
4430 : : /* djb-rwth: removing redundant code */
4431 : : if (nDelta)
4432 : : {
4433 : : /* Radical pair has disappeared */
4434 : : ; /* goto quick_exit;*/
4435 : : }
4436 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4437 : : {
4438 : 0 : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4439 : : }
4440 : : }
4441 [ # # ]: 0 : } while (ret & 1);
4442 : : }
4443 : : }
4444 : :
4445 : 0 : ret = 0;
4446 [ # # ]: 0 : if (tg_H_Acid >= num_atoms)
4447 : : {
4448 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H_Acid, pBNS );
4449 [ # # # # ]: 0 : if (!ret && ret2)
4450 : : {
4451 : 0 : ret = ret2;
4452 : : }
4453 : : }
4454 [ # # ]: 0 : if (tg_H_Other >= num_atoms)
4455 : : {
4456 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H_Other, pBNS );
4457 [ # # # # ]: 0 : if (!ret && ret2)
4458 : : {
4459 : 0 : ret = ret2;
4460 : : }
4461 : : }
4462 [ # # ]: 0 : if (cg_Minus >= num_atoms)
4463 : : {
4464 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus, pBNS );
4465 [ # # # # ]: 0 : if (!ret && ret2)
4466 : : {
4467 : 0 : ret = ret2;
4468 : : }
4469 : : }
4470 [ # # ]: 0 : if (cg_Plus >= num_atoms)
4471 : : {
4472 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Plus, pBNS );
4473 [ # # # # ]: 0 : if (!ret && ret2)
4474 : : {
4475 : 0 : ret = ret2;
4476 : : }
4477 : : }
4478 : :
4479 : 0 : pBNS->type_CN = 0;
4480 : 0 : pBNS->type_T = 0;
4481 : 0 : pBNS->type_TACN = 0;
4482 : :
4483 [ # # ]: 0 : if (ret)
4484 : : {
4485 : 0 : return ret;
4486 : : }
4487 : :
4488 [ # # ]: 0 : if (pAATG->nAtTypeTotals[ATTOT_NUM_CO_Minus] + pAATG->nAtTypeTotals[ATTOT_NUM_ZO_Minus] &&
4489 : 0 : pAATG->nAtTypeTotals[ATTOT_NUM_N_Minus])
4490 : : {
4491 : : }
4492 : :
4493 : 0 : nPosCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4494 : 0 : nNegCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4495 : : /*
4496 : : nNumNP_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4497 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4498 : : nNumOS_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4499 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4500 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4501 : : */
4502 [ # # ]: 0 : if (( nPosCharges - nNegCharges ) - ( nPosCharges2 - nNegCharges2 ) != 0)
4503 : : {
4504 : 0 : return BNS_PROGRAM_ERR;
4505 : : }
4506 : :
4507 [ # # ]: 0 : if (nNumCanceledCharges)
4508 : : {
4509 : : #if ( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
4510 : : *nNumCanceledCharges += 2 * nNumNeutralized;
4511 : : #else
4512 : 0 : *nNumCanceledCharges = 2 * nNumNeutralized;
4513 : : #endif
4514 : : }
4515 : :
4516 : 0 : return nNumMoved2AcidH;
4517 : : }
4518 : :
4519 : :
4520 : : /****************************************************************************/
4521 : 4 : int HardAddAcidicProtons( CANON_GLOBALS *pCG,
4522 : : inp_ATOM *at,
4523 : : int num_atoms,
4524 : : BN_AATG *pAATG,
4525 : : int num2add,
4526 : : int *nNumCanceledCharges,
4527 : : BN_STRUCT *pBNS,
4528 : : BN_DATA *pBD )
4529 : : {
4530 : 4 : int cg_Plus = 0;
4531 : 4 : int cg_Minus_CO = 0;
4532 : 4 : int cg_Minus_Other = 0;
4533 : 4 : int tg_H = 0;
4534 : :
4535 : 4 : int ret = 0, ret2;
4536 : 4 : int nDelta, nNumChanges = 0, nNumMoved2AcidMinus = 0, nNumNeutralized = 0, nPrevNumCharges; /* djb-rwth: removing redundant variables */
4537 : :
4538 : : int nPosCharges, nPosCharges2;
4539 : : int nNegCharges, nNegCharges2;
4540 : : /*
4541 : : int nNumNP_H, nNumNP_H2;
4542 : : int nNumOS_H, nNumOS_H2;
4543 : : */
4544 : 4 : nPosCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4545 : 4 : nNegCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4546 : : /*
4547 : : nNumNP_H = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4548 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4549 : : nNumOS_H = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4550 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4551 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4552 : : */
4553 : :
4554 : : /* Prevent free exchange H <-> (-) */
4555 : 4 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4556 : 4 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4557 : 4 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4558 : :
4559 : : /* Create (+) charge group */
4560 : 4 : cg_Plus = CreateCGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_POS, AA_HARD_MSK_POS, 1 );
4561 : :
4562 : : /* Create (-) charge group */
4563 : : /*
4564 : : if ( nAtTypeTotals[ATTOT_NUM_CO_Minus] +
4565 : : nAtTypeTotals[ATTOT_NUM_CS_Minus] +
4566 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] +
4567 : : nAtTypeTotals[ATTOT_NUM_N_Minus] )
4568 : : */
4569 : 4 : cg_Minus_CO = CreateCGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_CO, AA_HARD_MSK_CO, -1 );
4570 : :
4571 : 4 : cg_Minus_Other = CreateCGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_NEG, AA_HARD_MSK_NEG, -1 );
4572 : :
4573 : 4 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4574 : 4 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4575 : 4 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4576 : :
4577 : : /* Create tautomeric group for all H */
4578 : 4 : tg_H = CreateTGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_H, AA_HARD_MSK_H );
4579 : :
4580 [ - + - - ]: 4 : if (cg_Minus_Other >= num_atoms && cg_Minus_CO >= num_atoms)
4581 : : {
4582 : : /* Find alt path to remove one proton */
4583 : : do
4584 : : {
4585 : : /* Add a proton */
4586 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4587 : : /* djb-rwth: addressing coverity ID #499474 -- cg_Minus_CO negative values handled properly */
4588 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4589 : : at, num_atoms,
4590 : : cg_Minus_Other /*nVertDoubleBond*/,
4591 : : cg_Minus_CO /*nVertSingleBond*/,
4592 : : ALT_PATH_MODE_REM_PROTON );
4593 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4594 : : {
4595 : 0 : return ret;
4596 : : }
4597 [ # # ]: 0 : if (ret & 1)
4598 : : {
4599 : 0 : nDelta = ( ret & ~3 ) >> 2;
4600 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4601 : : if (nDelta)
4602 : : {
4603 : : /* Radical pair has disappeared */
4604 : : ; /* goto quick_exit;*/
4605 : : }
4606 : 0 : nNumMoved2AcidMinus++;
4607 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + 1)
4608 : : {
4609 : 0 : nNumNeutralized += ( nPrevNumCharges - ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - 1 ) ) / 2;
4610 : : }
4611 : : }
4612 [ # # # # ]: 0 : } while (( ret & 1 ) && nNumMoved2AcidMinus < num2add);
4613 : :
4614 : : /* Neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O */
4615 [ # # # # ]: 0 : if (( nNumMoved2AcidMinus /*|| bCancelChargesAlways*/ ) &&
4616 [ # # ]: 0 : cg_Minus_Other >= num_atoms && cg_Plus >= num_atoms &&
4617 [ # # ]: 0 : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4618 : : {
4619 : : do
4620 : : {
4621 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4622 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4623 : : at, num_atoms,
4624 : : cg_Minus_Other /*nVertDoubleBond*/,
4625 : : cg_Plus /*nVertSingleBond*/,
4626 : : ALT_PATH_MODE_REM_PROTON );
4627 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4628 : : {
4629 : 0 : return ret;
4630 : : }
4631 [ # # ]: 0 : if (ret & 1)
4632 : : {
4633 : 0 : nDelta = ( ret & ~3 ) >> 2;
4634 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4635 : : if (nDelta)
4636 : : {
4637 : : /* Radical pair has disappeared */
4638 : : ; /* goto quick_exit;*/
4639 : : }
4640 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4641 : : {
4642 : 0 : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4643 : : }
4644 : : }
4645 [ # # ]: 0 : } while (ret & 1);
4646 : : }
4647 : : }
4648 : :
4649 : 4 : ret = 0;
4650 [ - + ]: 4 : if (tg_H >= num_atoms)
4651 : : {
4652 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H, pBNS );
4653 [ # # # # ]: 0 : if (!ret && ret2)
4654 : : {
4655 : 0 : ret = ret2;
4656 : : }
4657 : : }
4658 [ - + ]: 4 : if (cg_Minus_Other >= num_atoms)
4659 : : {
4660 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus_Other, pBNS );
4661 [ # # # # ]: 0 : if (!ret && ret2)
4662 : : {
4663 : 0 : ret = ret2;
4664 : : }
4665 : : }
4666 [ - + ]: 4 : if (cg_Minus_CO >= num_atoms)
4667 : : {
4668 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus_CO, pBNS );
4669 [ # # # # ]: 0 : if (!ret && ret2)
4670 : : {
4671 : 0 : ret = ret2;
4672 : : }
4673 : : }
4674 [ - + ]: 4 : if (cg_Plus >= num_atoms)
4675 : : {
4676 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Plus, pBNS );
4677 [ # # # # ]: 0 : if (!ret && ret2)
4678 : : {
4679 : 0 : ret = ret2;
4680 : : }
4681 : : }
4682 : :
4683 : 4 : pBNS->type_CN = 0;
4684 : 4 : pBNS->type_T = 0;
4685 : 4 : pBNS->type_TACN = 0;
4686 : :
4687 [ - + ]: 4 : if (ret)
4688 : : {
4689 : 0 : return ret;
4690 : : }
4691 : :
4692 [ - + ]: 4 : if (pAATG->nAtTypeTotals[ATTOT_NUM_CO_Minus] + pAATG->nAtTypeTotals[ATTOT_NUM_ZO_Minus] &&
4693 : 0 : pAATG->nAtTypeTotals[ATTOT_NUM_N_Minus])
4694 : : {
4695 : : }
4696 : :
4697 : 4 : nPosCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4698 : 4 : nNegCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4699 : : /*
4700 : : nNumNP_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4701 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4702 : : nNumOS_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4703 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4704 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4705 : : */
4706 : :
4707 [ - + ]: 4 : if (( nPosCharges - nNegCharges ) - ( nPosCharges2 - nNegCharges2 ) != 0)
4708 : : {
4709 : 0 : return BNS_PROGRAM_ERR;
4710 : : }
4711 : :
4712 [ + - ]: 4 : if (nNumCanceledCharges)
4713 : : {
4714 : : #if ( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
4715 : : *nNumCanceledCharges += 2 * nNumNeutralized;
4716 : : #else
4717 : 4 : *nNumCanceledCharges = 2 * nNumNeutralized;
4718 : : #endif
4719 : : }
4720 : :
4721 : 4 : return nNumMoved2AcidMinus;
4722 : : }
4723 : :
4724 : :
4725 : : /****************************************************************************
4726 : : HardRemoveHplusNP( ... )
4727 : :
4728 : : Examples include removal of H from tautomeric O
4729 : : that belongs to the same t-group as N:
4730 : :
4731 : : >N(+)=-N=-OH =(taut.) =>
4732 : : >N(+)=-NH-=O =(+charge move) =>
4733 : : >N-=NH(+)-=O => >N-=N-=O + H(+)
4734 : : ****************************************************************************/
4735 : 0 : int HardRemoveHplusNP( CANON_GLOBALS *pCG,
4736 : : inp_ATOM *at,
4737 : : int num_atoms,
4738 : : int bCancelChargesAlways,
4739 : : int *nNumCanceledCharges,
4740 : : BN_AATG *pAATG,
4741 : : BN_STRUCT *pBNS,
4742 : : BN_DATA *pBD )
4743 : : {
4744 : :
4745 : 0 : int cg_Plus = 0;
4746 : 0 : int cg_Minus = 0;
4747 : 0 : int tg_H = 0;
4748 : : #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
4749 : : int cg_PlusP = 0;
4750 : : #endif
4751 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4752 : : int nPrevRemovedProtons, nCurrRemovedProtons;
4753 : : #endif
4754 : 0 : int ret = 0, ret2;
4755 : 0 : int nDelta, nNumChanges = 0, nNumRemovedProtons = 0, nNumNeutralized = 0, nPrevNumCharges; /* djb-rwth: ignoring LLVM warning: variable used */
4756 : :
4757 : : int nPosCharges, nPosCharges2;
4758 : : int nNegCharges, nNegCharges2;
4759 : : /*
4760 : : int nNumNP_H, nNumNP_H2;
4761 : : int nNumOS_H, nNumOS_H2;
4762 : : */
4763 : :
4764 : 0 : nPosCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4765 : 0 : nNegCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4766 : : /*
4767 : : nNumNP_H = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4768 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4769 : : nNumOS_H = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4770 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4771 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4772 : : */
4773 : :
4774 : : /* Prevent free exchange H <-> (-) */
4775 : 0 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4776 : 0 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4777 : 0 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4778 : :
4779 : : /* Create (+) charge group */
4780 : 0 : cg_Plus = CreateCGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_POS, PR_HARD_MSK_POS, 1 );
4781 : :
4782 : : /* Create (-) charge group */
4783 : : /*
4784 : : if ( nAtTypeTotals[ATTOT_NUM_CO_Minus] +
4785 : : nAtTypeTotals[ATTOT_NUM_CS_Minus] +
4786 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] +
4787 : : nAtTypeTotals[ATTOT_NUM_N_Minus] )
4788 : : */
4789 : : #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
4790 : : cg_PlusP = CreateCGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_POSP, PR_HARD_MSK_POS, 1 );
4791 : : #endif
4792 : 0 : cg_Minus = CreateCGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_NEG, PR_HARD_MSK_NEG, -1 );
4793 : :
4794 : : /* Create single tautomeric group */
4795 : 0 : tg_H = CreateTGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_H, PR_HARD_MSK_H );
4796 : :
4797 [ # # # # ]: 0 : if (tg_H >= num_atoms && cg_Plus >= num_atoms)
4798 : : {
4799 : :
4800 : : #if ( FIX_N_MINUS_NORN_BUG == 1 )
4801 : : /* neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O; >N(+)=-NH(-) => >N-=NH */
4802 : : if (( nNumRemovedProtons || bCancelChargesAlways ) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
4803 : : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4804 : : {
4805 : : do
4806 : : {
4807 : : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4808 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4809 : : nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4810 : : #endif
4811 : : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG, at, num_atoms,
4812 : : cg_Minus /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
4813 : : if (IS_BNS_ERROR( ret ))
4814 : : {
4815 : : return ret;
4816 : : }
4817 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4818 : : nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4819 : : if (nCurrRemovedProtons != nPrevRemovedProtons)
4820 : : {
4821 : : return BNS_RADICAL_ERR;
4822 : : }
4823 : : #endif
4824 : : if (ret & 1)
4825 : : {
4826 : : nDelta = ( ret & ~3 ) >> 2;
4827 : : nNumChanges += ( 0 != ( ret & 2 ) );
4828 : : if (nDelta)
4829 : : {
4830 : : /* radical pair has disappeared */
4831 : : ; /* goto quick_exit;*/
4832 : : }
4833 : : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4834 : : {
4835 : : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4836 : : }
4837 : : }
4838 : : } while (ret & 1);
4839 : : }
4840 : : #endif
4841 : :
4842 : : /* Find alt path to remove one proton */
4843 : : do
4844 : : {
4845 : : /* Remove a proton */
4846 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4847 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4848 : 0 : nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4849 : : #endif
4850 : : /* djb-rwth: addressing coverity ID #499572 -- tg_H negative values handled properly */
4851 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG, at, num_atoms,
4852 : : tg_H /*nVertDoubleBond*/,
4853 : : cg_Plus /*nVertSingleBond*/,
4854 : : ALT_PATH_MODE_REM_PROTON );
4855 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4856 : : {
4857 : 0 : return ret;
4858 : : }
4859 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4860 : 0 : nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4861 [ # # ]: 0 : if (nCurrRemovedProtons != nPrevRemovedProtons + ( ret & 1 ))
4862 : : {
4863 : 0 : return BNS_RADICAL_ERR;
4864 : : }
4865 : : #endif
4866 [ # # ]: 0 : if (ret & 1)
4867 : : {
4868 : 0 : nDelta = ( ret & ~3 ) >> 2;
4869 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4870 : : if (nDelta)
4871 : : {
4872 : : /* radical pair has disappeared */
4873 : : ; /* goto quick_exit;*/
4874 : : }
4875 : 0 : nNumRemovedProtons++;
4876 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + 1)
4877 : : {
4878 : 0 : nNumNeutralized += ( nPrevNumCharges - ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - 1 ) ) / 2;
4879 : : }
4880 : : }
4881 [ # # ]: 0 : } while (ret & 1);
4882 : :
4883 : : /* Neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O */
4884 [ # # # # : 0 : if (( nNumRemovedProtons || bCancelChargesAlways ) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
# # # # ]
4885 [ # # ]: 0 : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4886 : : {
4887 : : do
4888 : : {
4889 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4890 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4891 : 0 : nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4892 : : #endif
4893 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG, at, num_atoms,
4894 : : cg_Minus /*nVertDoubleBond*/,
4895 : : cg_Plus /*nVertSingleBond*/,
4896 : : ALT_PATH_MODE_REM_PROTON );
4897 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4898 : : {
4899 : 0 : return ret;
4900 : : }
4901 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4902 : 0 : nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4903 [ # # ]: 0 : if (nCurrRemovedProtons != nPrevRemovedProtons)
4904 : : {
4905 : 0 : return BNS_RADICAL_ERR;
4906 : : }
4907 : : #endif
4908 [ # # ]: 0 : if (ret & 1)
4909 : : {
4910 : 0 : nDelta = ( ret & ~3 ) >> 2;
4911 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4912 : : if (nDelta)
4913 : : {
4914 : : /* Radical pair has disappeared */
4915 : : ; /* goto quick_exit;*/
4916 : : }
4917 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4918 : : {
4919 : 0 : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4920 : : }
4921 : : }
4922 [ # # ]: 0 : } while (ret & 1);
4923 : : }
4924 : : }
4925 : :
4926 : 0 : ret = 0;
4927 [ # # ]: 0 : if (tg_H >= num_atoms)
4928 : : {
4929 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H, pBNS );
4930 [ # # # # ]: 0 : if (!ret && ret2)
4931 : : {
4932 : 0 : ret = ret2;
4933 : : }
4934 : : }
4935 [ # # ]: 0 : if (cg_Minus >= num_atoms)
4936 : : {
4937 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus, pBNS );
4938 [ # # # # ]: 0 : if (!ret && ret2)
4939 : : {
4940 : 0 : ret = ret2;
4941 : : }
4942 : : }
4943 : : #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
4944 : : if (cg_PlusP >= num_atoms)
4945 : : {
4946 : : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_PlusP, pBNS );
4947 : : if (!ret && ret2)
4948 : : {
4949 : : ret = ret2;
4950 : : }
4951 : : }
4952 : : #endif
4953 [ # # ]: 0 : if (cg_Plus >= num_atoms)
4954 : : {
4955 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Plus, pBNS );
4956 [ # # # # ]: 0 : if (!ret && ret2)
4957 : : {
4958 : 0 : ret = ret2;
4959 : : }
4960 : : }
4961 : :
4962 : 0 : pBNS->type_CN = 0;
4963 : 0 : pBNS->type_T = 0;
4964 : 0 : pBNS->type_TACN = 0;
4965 : :
4966 [ # # ]: 0 : if (ret)
4967 : : {
4968 : 0 : return ret;
4969 : : }
4970 : :
4971 [ # # ]: 0 : if (pAATG->nAtTypeTotals[ATTOT_NUM_CO_Minus] + pAATG->nAtTypeTotals[ATTOT_NUM_ZO_Minus] &&
4972 : 0 : pAATG->nAtTypeTotals[ATTOT_NUM_N_Minus])
4973 : : {
4974 : : }
4975 : :
4976 : 0 : nPosCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4977 : 0 : nNegCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4978 : : /*
4979 : : nNumNP_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4980 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4981 : : nNumOS_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4982 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4983 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4984 : : */
4985 : :
4986 [ # # ]: 0 : if (( nPosCharges - nNegCharges ) - ( nPosCharges2 - nNegCharges2 ) != nNumRemovedProtons)
4987 : : {
4988 : 0 : return BNS_PROGRAM_ERR;
4989 : : }
4990 : :
4991 [ # # ]: 0 : if (nNumCanceledCharges)
4992 : : {
4993 : : #if ( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
4994 : : *nNumCanceledCharges += 2 * nNumNeutralized;
4995 : : #else
4996 : 0 : *nNumCanceledCharges = 2 * nNumNeutralized;
4997 : : #endif
4998 : : }
4999 : :
5000 : 0 : return nNumRemovedProtons;
5001 : : }
5002 : :
5003 : :
5004 : : /****************************************************************************/
5005 : 161 : int mark_at_type( inp_ATOM *atom, int num_atoms, int nAtTypeTotals[] )
5006 : : {
5007 : : int i, max_num_ions, mask, type;
5008 : : /*int max_protons, max_O_Minus, num_H = 0, num_CO=0;*/
5009 : :
5010 [ + - ]: 161 : if (nAtTypeTotals)
5011 : : {
5012 : 161 : memset( nAtTypeTotals, 0, ATTOT_ARRAY_LEN * sizeof( nAtTypeTotals[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5013 : : }
5014 : :
5015 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
5016 : : {
5017 : 810 : type = GetAtomChargeType( atom, i, nAtTypeTotals, &mask, 0 );
5018 : 810 : atom[i].at_type = type;
5019 : : /*
5020 : : num_H += ((type & PR_HARD_TYP_H) && (mask & ATBIT_MSK_H));
5021 : : num_CO += ((type & AR_HARD_TYP_HA) && (mask & AR_HARD_MSK_HA));
5022 : : */
5023 : : }
5024 : :
5025 [ + - ]: 161 : if (nAtTypeTotals)
5026 : : {
5027 : : /*
5028 : : max_protons = nAtTypeTotals[ATTOT_NUM_NP_Proton] +
5029 : : inchi_min(num_H, nAtTypeTotals[ATTOT_NUM_NP_Plus]);
5030 : : max_O_Minus = nAtTypeTotals[ATTOT_NUM_CO_Minus] + nAtTypeTotals[ATTOT_NUM_CS_Minus] +
5031 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] + nAtTypeTotals[ATTOT_NUM_OO_Minus] +
5032 : : nAtTypeTotals[ATTOT_NUM_ZOO_Minus] + nAtTypeTotals[ATTOT_NUM_NO_Minus] +
5033 : : nAtTypeTotals[ATTOT_NUM_O_Minus] +nAtTypeTotals[ATTOT_NUM_N_Minus];
5034 : : ;
5035 : : max_num_ions = max_protons + max_O_Minus + nAtTypeTotals[ATTOT_NUM_CHARGES];
5036 : : */
5037 : 161 : max_num_ions = nAtTypeTotals[ATTOT_NUM_CHARGES];
5038 : : }
5039 : : else
5040 : : {
5041 : 0 : max_num_ions = 0;
5042 : : }
5043 : :
5044 : 161 : return max_num_ions;
5045 : : }
5046 : :
5047 : :
5048 : : /****************************************************************************/
5049 : 18 : int RemoveNPProtonsAndAcidCharges( CANON_GLOBALS *pCG,
5050 : : inp_ATOM *at,
5051 : : int num_atoms,
5052 : : BN_AATG *pAATG,
5053 : : BN_STRUCT *pBNS,
5054 : : BN_DATA *pBD )
5055 : : {
5056 : :
5057 : : /* Prepare data structure */
5058 : : int num;
5059 : 18 : int nNumCanceledCharges = 0;
5060 : : /* djb-rwth: removing redundant variables */
5061 : 18 : T_GROUP_INFO *t_group_info = pAATG->t_group_info;
5062 : 18 : int ret = 0, bError = 0;
5063 : :
5064 : 54 : int bAllowHardRemove = ( t_group_info->bTautFlags & TG_FLAG_TEST_TAUT__SALTS ) &&
5065 [ + - ]: 18 : ( t_group_info->bTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) &&
5066 [ + - + - ]: 54 : ( t_group_info->bTautFlags & TG_FLAG_MOVE_POS_CHARGES ) &&
5067 [ + - ]: 18 : ( t_group_info->bTautFlags & TG_FLAG_HARD_ADD_REM_PROTONS );
5068 : :
5069 [ - + - - ]: 18 : if (pAATG->nMarkedAtom && num_atoms < pAATG->nAllocLen)
5070 : : {
5071 [ # # ]: 0 : inchi_free( pAATG->nMarkedAtom );
5072 [ # # # # ]: 0 : qzfree( pAATG->nEndPoint );
5073 : 0 : memset( pAATG, 0, sizeof( *pAATG ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5074 : : }
5075 : :
5076 [ + - + - ]: 18 : if (!pAATG->nMarkedAtom && ( pAATG->nMarkedAtom = (S_CHAR *) inchi_malloc( num_atoms * sizeof( pAATG->nMarkedAtom[0] ) ) ))
5077 : : {
5078 : 18 : pAATG->nAllocLen = num_atoms;
5079 : 18 : pAATG->nNumFound = 0;
5080 : : }
5081 : :
5082 : : /* o TECHMAN-5.1. Remove protons from charged heteroatoms */
5083 : :
5084 : : /* (TECHMAN-5.1a) Simple remove of protons from N, P, and O,S,Se,Te */
5085 [ - + ]: 18 : if ((num = pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton] + pAATG->nAtTypeTotals[ATTOT_NUM_OH_Plus])) /* djb-rwth: addressing LLVM warning */
5086 : : {
5087 : 0 : ret = SimpleRemoveHplusNPO( at, num_atoms, pAATG->nAtTypeTotals, t_group_info );
5088 [ # # ]: 0 : if (ret != num)
5089 : : {
5090 : 0 : bError = BNS_PROGRAM_ERR;
5091 : 0 : goto exit_function;
5092 : : }
5093 : : /*t_group_info->nNumRemovedProtons += ret;*/
5094 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_NPO_SIMPLE_REMOVED : 0;
5095 : : }
5096 : :
5097 [ - + - - ]: 18 : if (( num = pAATG->nAtTypeTotals[ATTOT_NUM_NP_Plus] ) && bAllowHardRemove) /* djb-rwth: ignoring LLVM warning: variable used */
5098 : : {
5099 : : /* [TECHMAN-5.1b] Hard removing more protons from cationic N; charges may be canceled */
5100 : 0 : ret = HardRemoveHplusNP( pCG, at, num_atoms, 1, &nNumCanceledCharges, pAATG, pBNS, pBD );
5101 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5102 : : {
5103 : 0 : bError = ret;
5104 : 0 : goto exit_function;
5105 : : }
5106 : : /* djb-rwth: removing redundant code */
5107 : : /*t_group_info->nNumRemovedProtons += ret;*/
5108 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_NP_HARD_REMOVED : 0;
5109 : : }
5110 : :
5111 [ - + ]: 18 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] > 0)
5112 : : {
5113 : : /* o TECHMAN-5.2. Remove protons from neutral heteroatoms */
5114 : :
5115 : : /* (TECHMAN-5.2a) Simple removal */
5116 : 0 : ret = SimpleRemoveAcidicProtons( at, num_atoms, pAATG, pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] );
5117 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5118 : : {
5119 : 0 : bError = ret;
5120 : 0 : goto exit_function;
5121 : : }
5122 : :
5123 : : /*t_group_info->nNumRemovedProtons += ret;*/
5124 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_AC_SIMPLE_REMOVED : 0;
5125 : :
5126 : :
5127 [ # # # # ]: 0 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] > 0 && bAllowHardRemove)
5128 : : {
5129 : : /* (TECHMAN-5.2b) Hard removal */
5130 : 0 : ret = HardRemoveAcidicProtons(pCG, at, num_atoms, pAATG, pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE], &nNumCanceledCharges, pBNS, pBD);
5131 [ # # # # ]: 0 : if (IS_BNS_ERROR(ret))
5132 : : {
5133 : 0 : bError = ret;
5134 : 0 : goto exit_function;
5135 : : }
5136 [ # # ]: 0 : if (ret > 0)
5137 : : {
5138 : 0 : int ret2 = SimpleRemoveAcidicProtons(at, num_atoms, pAATG, ret);
5139 [ # # ]: 0 : if (ret2 != ret)
5140 : : {
5141 : 0 : bError = BNS_PROGRAM_ERR;
5142 : 0 : goto exit_function;
5143 : : }
5144 : : /*t_group_info->nNumRemovedProtons += ret;*/
5145 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= (ret > 0) ? FLAG_PROTON_AC_HARD_REMOVED : 0;
5146 : : /* djb-rwth: removing redundant code */
5147 : : }
5148 : : }
5149 : :
5150 : :
5151 : : }
5152 : : else
5153 : : {
5154 [ + - ]: 18 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] < 0)
5155 : : {
5156 : 18 : ret = SimpleAddAcidicProtons( at, num_atoms, pAATG, -pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] );
5157 [ + - - + ]: 18 : if (IS_BNS_ERROR( ret ))
5158 : : {
5159 : 0 : bError = ret;
5160 : 0 : goto exit_function;
5161 : : }
5162 : : /*t_group_info->nNumRemovedProtons -= ret;*/
5163 : : /*
5164 : : CHECK_TACN == 1 prohibits replacing (-) on N with H unless H can be moved to N
5165 : : along an alternating path from another heteroatom (t-group will be detected).
5166 : : */
5167 [ + + ]: 18 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_AC_SIMPLE_ADDED : 0;
5168 [ + + + - ]: 18 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] < 0 && bAllowHardRemove)
5169 : : {
5170 : 4 : ret = HardAddAcidicProtons( pCG, at, num_atoms, pAATG, -pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE], &nNumCanceledCharges, pBNS, pBD );
5171 [ + - - + ]: 4 : if (IS_BNS_ERROR( ret ))
5172 : : {
5173 : 0 : bError = ret;
5174 : 0 : goto exit_function;
5175 : : }
5176 [ - + ]: 4 : if (ret > 0)
5177 : : {
5178 : 0 : int ret2 = SimpleAddAcidicProtons( at, num_atoms, pAATG, ret );
5179 [ # # ]: 0 : if (ret2 != ret)
5180 : : {
5181 : 0 : bError = BNS_PROGRAM_ERR;
5182 : 0 : goto exit_function;
5183 : : }
5184 : : /*t_group_info->nNumRemovedProtons -= ret;*/
5185 : 0 : t_group_info->tni.bNormalizationFlags |= FLAG_PROTON_AC_HARD_ADDED; /* djb-rwth: fixing coverity ID #499527 */
5186 : : /* djb-rwth: removing redundant code */
5187 : : }
5188 : : }
5189 : : }
5190 : : }
5191 : :
5192 [ - + ]: 18 : t_group_info->tni.bNormalizationFlags |= nNumCanceledCharges ? FLAG_PROTON_CHARGE_CANCEL : 0;
5193 : :
5194 : 18 : exit_function:
5195 [ - + ]: 18 : if (bError)
5196 : : {
5197 [ # # # # ]: 0 : ret = IS_BNS_ERROR( bError ) ? bError : BNS_PROGRAM_ERR;
5198 : : }
5199 : :
5200 : 18 : return ret;
5201 : : }
5202 : :
5203 : :
5204 : : /****************************************************************************
5205 : : Main normalization procedure
5206 : : ****************************************************************************/
5207 : 161 : int mark_alt_bonds_and_taut_groups( struct tagINCHI_CLOCK *ic,
5208 : : struct tagCANON_GLOBALS *pCG,
5209 : : inp_ATOM *at,
5210 : : inp_ATOM *at_fixed_bonds_out,
5211 : : int num_atoms,
5212 : : struct tagInchiTime *ulTimeOutTime,
5213 : : T_GROUP_INFO *t_group_info,
5214 : : INCHI_MODE *inpbTautFlags,
5215 : : INCHI_MODE *inpbTautFlagsDone,
5216 : : int nebend,
5217 : : int *ebend )
5218 : :
5219 : :
5220 : : {
5221 : 161 : BN_STRUCT *pBNS = NULL;
5222 : 161 : BN_DATA *pBD = NULL;
5223 : : int bError, nChanges, taut_found, salt_found, salt_pass, salt_step, ret, ret2, num, num_changed_bonds; /* djb-rwth: removing redundant variables */
5224 : 161 : int max_altp = BN_MAX_ALTP;
5225 : 161 : int bChangeFlow = ( BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS );
5226 : : BNS_FLOW_CHANGES fcd[BNS_MAX_NUM_FLOW_CHANGES + 1];
5227 : : C_GROUP_INFO CGroupInfo;
5228 : 161 : C_GROUP_INFO *c_group_info = &CGroupInfo;
5229 : : S_GROUP_INFO SGroupInfo;
5230 : 161 : S_GROUP_INFO *s_group_info = &SGroupInfo;
5231 [ + - ]: 161 : INCHI_MODE *pbTautFlags = t_group_info ? &t_group_info->bTautFlags : inpbTautFlags;
5232 [ + - ]: 161 : INCHI_MODE *pbTautFlagsDone = t_group_info ? &t_group_info->bTautFlagsDone : inpbTautFlagsDone;
5233 : :
5234 : : int nAtTypeTotals[ATTOT_ARRAY_LEN];
5235 : : int nNumOrigTotAtoms;
5236 : :
5237 : : BN_AATG aatg;
5238 : 161 : BN_AATG *pAATG = &aatg;
5239 : :
5240 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5241 : 161 : int i, n_arom_radicals = 0, *stored_radicals = NULL;
5242 : : #endif
5243 : : int at_prot; /* moved from below 2024-09-01 DT */
5244 : :
5245 : 161 : nChanges = 0;
5246 : 161 : bError = 0;
5247 : :
5248 : 161 : memset( c_group_info, 0, sizeof( *c_group_info ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5249 : 161 : memset( s_group_info, 0, sizeof( *s_group_info ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5250 : 161 : memset( pAATG, 0, sizeof( *pAATG ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5251 : :
5252 : : /*(@nnuk : Nauman Ullah Khan) :: Variable for checking (De)protonation status */
5253 : : LOG_NO_ARGS("\n############# Initial state before (De)Protonation (L5373:ichi_bns.c) ###############\n");
5254 [ + + ]: 971 : for (at_prot = 0; at_prot < num_atoms; at_prot++)
5255 : : {
5256 : : LOG_MULT_ARGS("Atom %d: Element: %s, Num_H: %d, Charge: %hhd, Radical: %d\n", at_prot, at[at_prot].elname, at[at_prot].num_H, at[at_prot].charge, at[at_prot].radical);
5257 : : }
5258 : : LOG_NO_ARGS("\n#####################################################################################\n");
5259 : :
5260 : :
5261 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5262 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
5263 : : {
5264 [ - + - - ]: 810 : if (( at[i].radical == RADICAL_DOUBLET ) && ( at[i].valence == 2 ) &&
5265 [ # # # # ]: 0 : ( at[i].bond_type[0] == BOND_ALTERN ) && ( at[i].bond_type[1] == BOND_ALTERN ))
5266 : : {
5267 : 0 : n_arom_radicals++;
5268 [ # # ]: 0 : if (!stored_radicals)
5269 : : {
5270 : 0 : stored_radicals = (int *) inchi_calloc( num_atoms, sizeof( int ) );
5271 : : /* 2011-08-05 explicit cast added due to Evan Bolton */
5272 [ # # ]: 0 : if (!stored_radicals)
5273 : : {
5274 : 0 : bError = BNS_OUT_OF_RAM;
5275 : 0 : goto exit_function;
5276 : : }
5277 : 0 : stored_radicals[i] = RADICAL_DOUBLET;
5278 : 0 : at[i].radical = 0;
5279 : 0 : at[i].num_H++;
5280 : : }
5281 : : }
5282 : : }
5283 : :
5284 : : #endif
5285 : :
5286 [ + - + + ]: 161 : if (( *pbTautFlags & TG_FLAG_MOVE_POS_CHARGES ) && num_atoms > 1)
5287 : : {
5288 : : /* Charge groups memory allocation */
5289 : 77 : c_group_info->c_group = (C_GROUP *) inchi_calloc( num_atoms / 2, sizeof( c_group_info->c_group[0] ) );
5290 : 77 : c_group_info->c_candidate = (C_CANDIDATE*) inchi_calloc( num_atoms, sizeof( c_group_info->c_candidate[0] ) );
5291 [ + - + - ]: 77 : if (c_group_info->c_group && c_group_info->c_candidate)
5292 : : {
5293 : 77 : c_group_info->max_num_c_groups = num_atoms / 2;
5294 : 77 : c_group_info->max_num_candidates = num_atoms;
5295 : : }
5296 : : else
5297 : : {
5298 : 0 : bError = BNS_OUT_OF_RAM; /* error: out of RAM */
5299 : : /*printf("BNS_OUT_OF_RAM-1: num_at=%d, c_gr=%lx c_can=%lx\n", num_atoms, c_group_info->c_group, c_group_info->c_candidate);*/
5300 : 0 : goto exit_function;
5301 : : }
5302 : : }
5303 : :
5304 [ + - ]: 161 : if (*pbTautFlags & TG_FLAG_TEST_TAUT__SALTS)
5305 : : {
5306 [ + - ]: 161 : if (t_group_info)
5307 : : {
5308 : : /* Salt groups memory allocation */
5309 : 161 : s_group_info->s_candidate =
5310 : 161 : (S_CANDIDATE*) inchi_calloc( num_atoms,
5311 : : sizeof( s_group_info->s_candidate[0] ) );
5312 [ + - ]: 161 : if (s_group_info->s_candidate)
5313 : : {
5314 : 161 : s_group_info->max_num_candidates = num_atoms;
5315 : : }
5316 : : else
5317 : : {
5318 : 0 : bError = BNS_OUT_OF_RAM; /* error: out of RAM */
5319 : : /*printf("BNS_OUT_OF_RAM-2\n");*/
5320 : 0 : goto exit_function;
5321 : : }
5322 : : }
5323 : : }
5324 : :
5325 [ + - ]: 161 : if (t_group_info)
5326 : : {
5327 [ - + ]: 161 : if (t_group_info->tGroupNumber)
5328 : : {
5329 [ # # ]: 0 : inchi_free( t_group_info->tGroupNumber );
5330 : : }
5331 : 161 : t_group_info->tGroupNumber = (AT_NUMB *) inchi_calloc( 2 * (long long)num_atoms + 1, sizeof( t_group_info->tGroupNumber[0] ) ); /* djb-rwth: cast operator added */
5332 [ - + ]: 161 : if (!t_group_info->tGroupNumber)
5333 : : {
5334 : : /*printf("BNS_OUT_OF_RAM-9\n");*/
5335 : 0 : bError = BNS_OUT_OF_RAM; /* error: out of RAM */
5336 : 0 : goto exit_function;
5337 : : }
5338 : 161 : num = t_group_info->tni.nNumRemovedExplicitH;
5339 : 161 : memset( &t_group_info->tni, 0, sizeof( t_group_info->tni ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5340 : 161 : t_group_info->tni.nNumRemovedExplicitH = num;
5341 : : }
5342 : :
5343 : : /*
5344 : : again:
5345 : : */
5346 : :
5347 : : /* Allocate Balanced Network Data Strucures; replace Alternating bonds with Single */
5348 [ + - ]: 161 : if (( pBNS = AllocateAndInitBnStruct( at, num_atoms,
5349 : : BNS_ADD_ATOMS, BNS_ADD_EDGES,
5350 : : max_altp, &num_changed_bonds ) )
5351 [ + - ]: 161 : &&
5352 : 161 : ( pBD = AllocateAndInitBnData( pBNS->max_vertices ) ))
5353 : : {
5354 : :
5355 : :
5356 : 161 : pBNS->pbTautFlags = pbTautFlags; /* carry through all functions */
5357 : 161 : pBNS->pbTautFlagsDone = pbTautFlagsDone; /* carry through all functions */
5358 : :
5359 : 161 : pBNS->ulTimeOutTime = ulTimeOutTime; /* v. 1.05 */
5360 : 161 : pBNS->ic = ic; /* v. 1.05 */
5361 : :
5362 : : #if ( BNS_PROTECT_FROM_TAUT == 1 )
5363 : : /* Protect bonds to acetyl and nitro */
5364 : 161 : SetForbiddenEdges( pBNS, at, num_atoms, BNS_EDGE_FORBIDDEN_MASK, nebend, ebend );
5365 : : #endif
5366 : :
5367 : : /* Set bonds in case of input "aromatic" bonds or multiple radicals */
5368 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5369 [ - + ]: 161 : if (n_arom_radicals)
5370 : : {
5371 : 0 : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5372 [ # # ]: 0 : if (stored_radicals)
5373 : : {
5374 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
5375 : : {
5376 [ # # ]: 0 : if (stored_radicals[i])
5377 : : {
5378 : 0 : at[i].radical = stored_radicals[i];
5379 : 0 : at[i].num_H--;
5380 : : }
5381 : : }
5382 : : }
5383 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5384 : : {
5385 : 0 : bError = ret;
5386 : 0 : goto exit_function;
5387 : : }
5388 : : }
5389 : : #endif
5390 : :
5391 : 161 : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5392 : :
5393 : : /* (here pair(s) of radicals could have disappeared from the atoms) */
5394 [ + - - + ]: 161 : if (IS_BNS_ERROR( ret ))
5395 : : {
5396 : 0 : bError = ret;
5397 : 0 : goto exit_function;
5398 : : }
5399 : 161 : pBNS->tot_st_flow += 2 * ret;
5400 : :
5401 : : /*return 0;*/ /* debug */
5402 : : /* djb-rwth: removing redundant code */
5403 : :
5404 [ - + ]: 161 : if (pBNS->tot_st_cap > pBNS->tot_st_flow)
5405 : : {
5406 : : /* has radical */
5407 : 0 : bChangeFlow |= BNS_EF_SET_NOSTEREO;
5408 : : }
5409 : :
5410 : : /********************************************************************
5411 : : * Remove protons from NH(+), but not PH(+)
5412 : : * Add protons to COO(-) etc.
5413 : : * or remove protons from COOH etc to make the organic part neutral
5414 : : * Note: for now (-) from N(-) can be only canceled or moved to -C=O
5415 : : ********************************************************************/
5416 [ + - + - ]: 161 : if (( *pbTautFlags & TG_FLAG_VARIABLE_PROTONS ) &&
5417 [ + + ]: 161 : t_group_info &&
5418 : 161 : mark_at_type( at, num_atoms, nAtTypeTotals ) &&
5419 [ + - ]: 18 : nAtTypeTotals[ATTOT_NUM_CHARGES])
5420 : : {
5421 : : /*
5422 : : the structure is simple to neutralize if it yields exactly
5423 : : num[H(+)] = num[N,P H(+)]
5424 : : num[N,S,O(-)] = num[=C-O(-)] + num[C-S(-)] + num[N(-)] + num[other O(-), S(-)]
5425 : :
5426 : : and n(p) = num[H(+)] - num[N,S,O(-)] (no protons, no negative N,O,S condition)
5427 : :
5428 : : Additional check is needed if:
5429 : : min{num[N,PH], num[N,P(+), not onium]} > 0
5430 : : => possibility to yield more H(+)
5431 : :
5432 : : min_charge = orig_charge(P,N,O,S) - n(p) - n(OH,SH)
5433 : : max_charge = orig_charge(P,N,O,S) - n(p) + n(O,S,N(-))
5434 : : */
5435 : :
5436 : 18 : nNumOrigTotAtoms = t_group_info->tni.nNumRemovedExplicitH + num_atoms;
5437 : 18 : pAATG->nAtTypeTotals = nAtTypeTotals;
5438 : 18 : pAATG->t_group_info = t_group_info;
5439 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5440 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5441 : : #endif
5442 : :
5443 : : /***********************************************************/
5444 : : /* */
5445 : : /* ( D E ) P R O T O N A T I O N */
5446 : : /* */
5447 : : /***********************************************************/
5448 : :
5449 : 18 : ret = RemoveNPProtonsAndAcidCharges( pCG, at, num_atoms, pAATG, pBNS, pBD );
5450 : :
5451 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5452 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5453 : : #endif
5454 [ + - - + ]: 18 : if (IS_BNS_ERROR( ret ))
5455 : : {
5456 : 0 : bError = ret;
5457 : 0 : goto exit_function;
5458 : : }
5459 : :
5460 [ + + ]: 18 : if (t_group_info->tni.bNormalizationFlags)
5461 : : {
5462 : 14 : SetInitCapFlowToCurrent( pBNS );
5463 [ + - ]: 14 : if (at_fixed_bonds_out)
5464 : : {
5465 : : /* Copy modified initial tautomeric structure for displaying
5466 : : Warning: implicit H counts in at_fixed_bonds_out include explicit Hs */
5467 : :
5468 : 14 : memcpy(at_fixed_bonds_out, at, nNumOrigTotAtoms * sizeof(at_fixed_bonds_out[0]));
5469 : :
5470 : : /* -- will be done in FillOutInputInfAtom() --
5471 : : RemoveExcessiveImplicitH( num_atoms, t_group_info->tni.nNumRemovedExplicitH, at_fixed_bonds_out );
5472 : : */
5473 : : }
5474 : : }
5475 : : }
5476 : :
5477 : : /****************** Initial bonds normalization ***************/
5478 : :
5479 [ + - ]: 161 : if (*pbTautFlags & TG_FLAG_MOVE_POS_CHARGES)
5480 : : {
5481 : : /******************* Find moveable positive charges **********************/
5482 : : do
5483 : : {
5484 : : /* Cycling while ret>0 added 2004-06-04 */
5485 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5486 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5487 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5488 : : #endif
5489 : 161 : ret = MarkChargeGroups( pCG, at, num_atoms,
5490 : : c_group_info, t_group_info,
5491 : : pBNS, pBD );
5492 : :
5493 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5494 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5495 : : #endif
5496 [ + - - + ]: 161 : if (IS_BNS_ERROR( ret ))
5497 : : {
5498 : 0 : bError = ret;
5499 : 0 : goto exit_function;
5500 : : }
5501 [ - + ]: 161 : if (ret)
5502 : : {
5503 : 0 : nChanges += ret;
5504 : 0 : ret2 = AddCGroups2BnStruct( pCG, pBNS, at, num_atoms, c_group_info );
5505 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
5506 : : {
5507 : 0 : bError = ret2;
5508 : 0 : goto exit_function;
5509 : : }
5510 : 0 : *pbTautFlagsDone |= TG_FLAG_MOVE_POS_CHARGES_DONE;
5511 : : }
5512 [ - + ]: 161 : } while (ret > 0);
5513 : :
5514 : :
5515 : : #if ( BNS_RAD_SEARCH == 1 )
5516 : : #else
5517 : : /* moveable charges may allow to cancel radicals -- check it */
5518 : : if (pBNS->tot_st_cap > pBNS->tot_st_flow)
5519 : : {
5520 : : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5521 : : if (IS_BNS_ERROR( ret ))
5522 : : {
5523 : : bError = ret;
5524 : : goto exit_function;
5525 : : }
5526 : : if (ret > 0)
5527 : : {
5528 : : /*
5529 : : pBNS->tot_st_flow += 2*ret;
5530 : : ret = ReInitBnStruct( pBNS, at, num_atoms, 1 );
5531 : : if ( IS_BNS_ERROR( ret ) ) {
5532 : : bError = ret;
5533 : : goto exit_function;
5534 : : }
5535 : : */
5536 : : bError = BNS_RADICAL_ERR;
5537 : : goto exit_function;
5538 : : }
5539 : : }
5540 : : #endif
5541 : : }
5542 : :
5543 : : /************************************************************************/
5544 : : /******** Test bonds for bond tautomerism **************/
5545 : : /******** replace moveable bonds with "alternating" bonds **************/
5546 : : /************************************************************************/
5547 : 161 : ret = BnsTestAndMarkAltBonds( pBNS, pBD, at, num_atoms, fcd, bChangeFlow, 0 );
5548 : :
5549 [ + - - + ]: 161 : if (IS_BNS_ERROR( ret ))
5550 : : {
5551 : 0 : bError = ret;
5552 : 0 : goto exit_function;
5553 : : }
5554 : : /* djb-rwth: removing redundant code */
5555 : :
5556 : : /*********************** End of initial bonds normalization *************/
5557 : :
5558 : : /* djb-rwth: removing redundant code */
5559 : :
5560 : : /* Check for tautomerism */
5561 : : /* find new tautomer groups */
5562 : 161 : salt_pass = 0;
5563 : 161 : salt_step = 0;
5564 : 161 : salt_found = 0;
5565 : :
5566 : : /*************************************************************/
5567 : : /* */
5568 : : /* M A I N C Y C L E B E G I N */
5569 : : /* */
5570 : : /*************************************************************/
5571 : :
5572 : : do
5573 : : {
5574 : : /* djb-rwth: removing redundant code */
5575 : 161 : nChanges = 0;
5576 : : /* djb-rwth: removing redundant code */
5577 : :
5578 : : /**************** Regular bond/H/(-)/positive charges tautomerism cycle begin **************/
5579 : : do
5580 : : {
5581 : : /* djb-rwth: removing redundant code */
5582 : 168 : for (taut_found = 0;
5583 [ + + ]: 175 : 0 < ( ret = MarkTautomerGroups( pCG, at, num_atoms,
5584 : : t_group_info, c_group_info,
5585 : : pBNS, pBD ) );
5586 : 7 : taut_found++)
5587 : : {
5588 : : ;
5589 : : }
5590 [ - + ]: 168 : if (ret < 0)
5591 : : {
5592 : 0 : bError = ret;
5593 : : }
5594 [ + + + - ]: 168 : if (taut_found && !salt_pass)
5595 : : {
5596 : 7 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT__ATOMS_DONE;
5597 : : }
5598 : :
5599 [ + + - + ]: 168 : if (taut_found || salt_found)
5600 : : {
5601 : : /****************** repeat bonds normalization ***************/
5602 : 7 : ret = ReInitBnStructAddGroups( pCG, pBNS, at, num_atoms,
5603 : : t_group_info, c_group_info );
5604 [ + - - + ]: 7 : if (IS_BNS_ERROR( ret ))
5605 : : {
5606 : 0 : bError = ret;
5607 : 0 : goto exit_function;
5608 : : }
5609 : : #if ( BNS_RAD_SEARCH == 1 )
5610 : : #else
5611 : : /* discovered moveable charges and H-atoms may allow to cancel radicals */
5612 : : if (pBNS->tot_st_cap > pBNS->tot_st_flow)
5613 : : {
5614 : : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5615 : : if (IS_BNS_ERROR( ret ))
5616 : : {
5617 : : bError = ret;
5618 : : goto exit_function;
5619 : : }
5620 : : if (ret > 0)
5621 : : {
5622 : : /*
5623 : : pBNS->tot_st_flow += 2*ret;
5624 : : ret = ReInitBnStruct( pBNS, at, num_atoms, 1 );
5625 : : if ( IS_BNS_ERROR( ret ) ) {
5626 : : bError = ret;
5627 : : goto exit_function;
5628 : : }
5629 : : */
5630 : : bError = BNS_RADICAL_ERR;
5631 : : goto exit_function;
5632 : : }
5633 : : }
5634 : : #endif
5635 : : /****************** Update bonds normalization ***************/
5636 [ + - ]: 7 : if (*pbTautFlags & TG_FLAG_MOVE_POS_CHARGES)
5637 : : {
5638 : : /******************* Find moveable charges ***************/
5639 : : do
5640 : : {
5641 : : /* Cycling while ret>0 added 2004-06-04 */
5642 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5643 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5644 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5645 : : #endif
5646 : :
5647 : 7 : ret = MarkChargeGroups( pCG, at, num_atoms,
5648 : : c_group_info, t_group_info,
5649 : : pBNS, pBD );
5650 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5651 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5652 : : #endif
5653 [ + - - + ]: 7 : if (IS_BNS_ERROR( ret ))
5654 : : {
5655 : 0 : bError = ret;
5656 : 0 : goto exit_function;
5657 : : }
5658 : 7 : nChanges += ret;
5659 [ - + ]: 7 : if (ret > 0)
5660 : : {
5661 : 0 : ret2 = ReInitBnStructAddGroups( pCG, pBNS,
5662 : : at, num_atoms,
5663 : : t_group_info,
5664 : : c_group_info );
5665 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
5666 : : {
5667 : 0 : bError = ret2;
5668 : 0 : goto exit_function;
5669 : : }
5670 : 0 : *pbTautFlagsDone |= TG_FLAG_MOVE_POS_CHARGES_DONE;
5671 : : }
5672 [ - + ]: 7 : } while (ret > 0);
5673 : : }
5674 : :
5675 : : /************************************************************************/
5676 : : /******** Find moveable bonds: **************/
5677 : : /******** test bonds for bond tautomerism **************/
5678 : : /******** replace moveable bonds with "alternating" bonds **************/
5679 : : /************************************************************************/
5680 : 7 : ret = BnsTestAndMarkAltBonds( pBNS, pBD, at, num_atoms, fcd, bChangeFlow, 0 );
5681 [ + - - + ]: 7 : if (IS_BNS_ERROR( ret ))
5682 : : {
5683 : 0 : bError = ret;
5684 : 0 : goto exit_function;
5685 : : }
5686 : 7 : nChanges += ret;
5687 : : /****************** End of update bonds normalization ***************/
5688 : :
5689 : : }
5690 : 168 : salt_found = 0;
5691 [ + + + - ]: 168 : } while (taut_found && !bError);
5692 : :
5693 : :
5694 : : /**************** Regular bond/H/(-)/positive charges tautomerism cycle end **************/
5695 : :
5696 [ - + ]: 161 : if (bError)
5697 : : {
5698 : 0 : break;
5699 : : }
5700 : :
5701 : :
5702 : : /******************* 'Salt' tautomerism permitted *************************/
5703 [ + - ]: 161 : if (*pbTautFlags & TG_FLAG_TEST_TAUT__SALTS)
5704 : : {
5705 : :
5706 [ + - ]: 161 : if (*pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS)
5707 : : {
5708 : : /*********** Requested one or more "salt" attachement migrartion test ********/
5709 [ + + - + : 161 : if (!nChanges && salt_pass && salt_step)
- - ]
5710 : : {
5711 : 0 : break; /* done */
5712 : : }
5713 [ + - ]: 161 : if (!salt_step)
5714 : : {
5715 : : /* Salt step 0: process one attachment migrartion */
5716 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5717 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5718 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5719 : : #endif
5720 : 161 : salt_found = MarkSaltChargeGroups( pCG, at, num_atoms,
5721 : : s_group_info,
5722 : : t_group_info,
5723 : : c_group_info,
5724 : : pBNS, pBD );
5725 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5726 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5727 : : #endif
5728 [ - + ]: 161 : if (salt_found < 0)
5729 : : {
5730 : 0 : bError = salt_found;
5731 : 0 : break;
5732 : : }
5733 : : else
5734 : : {
5735 [ - + ]: 161 : if (salt_found > 0)
5736 : : {
5737 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT__SALTS_DONE;
5738 : : }
5739 : : }
5740 : 161 : salt_step = !salt_found;
5741 : : /* if new 'salt' atoms have been found then repeat regular taut. search
5742 : : * MarkTautomerGroups() and do not perform salt step 1
5743 : : * if new 'salt' atoms have NOT been found then switch to salt step 1
5744 : : * and never repeat salt step 0 for the current structure
5745 : : */
5746 : : }
5747 : :
5748 [ + - ]: 161 : if (salt_step /*||
5749 : : (t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT)*/)
5750 : : {
5751 : : /* Salt step 1: process more than one attachment migration */
5752 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5753 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5754 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5755 : : #endif
5756 : 161 : salt_found = MarkSaltChargeGroups2( pCG, at, num_atoms,
5757 : : s_group_info,
5758 : : t_group_info,
5759 : : c_group_info,
5760 : : pBNS, pBD );
5761 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5762 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5763 : : #endif
5764 [ - + ]: 161 : if (salt_found < 0)
5765 : : {
5766 : 0 : bError = salt_found;
5767 : 0 : break;
5768 : : }
5769 : : else
5770 : : {
5771 [ + - - + ]: 161 : if (salt_found == 1 || salt_found == 5)
5772 : : {
5773 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT2_SALTS_DONE;
5774 [ # # ]: 0 : if (salt_found == 5)
5775 : : {
5776 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT3_SALTS_DONE;
5777 : : }
5778 : : /* salt_found == 2 => only negative charges involved */
5779 : : }
5780 : : }
5781 : : }
5782 : :
5783 : 161 : salt_pass++;
5784 : : }
5785 : : else
5786 : : {
5787 : : /* !( *pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) */
5788 : : /*************** Requested only one attachement migration test **********/
5789 [ # # # # ]: 0 : if (!nChanges && salt_pass)
5790 : : {
5791 : : /* One attachment migration */
5792 : 0 : break;
5793 : : }
5794 : : /* Salt step 0: process one attachment migration */
5795 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5796 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5797 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5798 : : #endif
5799 : 0 : salt_found = MarkSaltChargeGroups( pCG, at, num_atoms,
5800 : : s_group_info,
5801 : : t_group_info,
5802 : : c_group_info,
5803 : : pBNS, pBD );
5804 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5805 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5806 : : #endif
5807 [ # # ]: 0 : if (salt_found < 0)
5808 : : {
5809 : 0 : bError = salt_found;
5810 : 0 : break;
5811 : : }
5812 : : else
5813 : : {
5814 [ # # ]: 0 : if (salt_found > 0)
5815 : : {
5816 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT__SALTS_DONE;
5817 : : }
5818 : : }
5819 : 0 : salt_pass++;
5820 : : } /* ( *pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) */
5821 : : } /* ( *pbTautFlags & TG_FLAG_TEST_TAUT__SALTS ) */
5822 [ - + - - ]: 161 : } while (salt_found && !bError);
5823 : :
5824 : : /*************************************************************/
5825 : : /* */
5826 : : /* M A I N C Y C L E E N D */
5827 : : /* */
5828 : : /*************************************************************/
5829 : :
5830 : :
5831 [ + - ]: 161 : if (*pbTautFlags & TG_FLAG_MERGE_TAUT_SALTS)
5832 : : {
5833 [ + - + - ]: 161 : if (!bError && s_group_info /*&& s_group_info->num_candidates > 0*/)
5834 : : {
5835 : 161 : ret = MergeSaltTautGroups( pCG, at, num_atoms, s_group_info,
5836 : : t_group_info, c_group_info, pBNS );
5837 [ - + ]: 161 : if (ret < 0)
5838 : : {
5839 : 0 : bError = ret;
5840 : : }
5841 : : else
5842 : : {
5843 [ - + ]: 161 : if (ret > 0)
5844 : : {
5845 : 0 : *pbTautFlagsDone |= TG_FLAG_MERGE_TAUT_SALTS_DONE;
5846 : : }
5847 : : }
5848 : : }
5849 : : }
5850 : :
5851 [ + - + - ]: 161 : if (!bError && t_group_info &&
5852 [ + - ]: 161 : ( t_group_info->bTautFlags & TG_FLAG_VARIABLE_PROTONS ) &&
5853 [ - + ]: 161 : ( t_group_info->bTautFlagsDone & ( TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE | TG_FLAG_FOUND_ISOTOPIC_H_DONE ) ))
5854 : : {
5855 : 0 : ret = MakeIsotopicHGroup( at, num_atoms, s_group_info, t_group_info );
5856 [ # # ]: 0 : if (ret < 0)
5857 : : {
5858 : 0 : bError = ret;
5859 : : }
5860 : : }
5861 : :
5862 : : /* Success */
5863 : :
5864 : 161 : remove_alt_bond_marks( at, num_atoms );
5865 : :
5866 : : /************************************************
5867 : : * Temporarily ignore all non-alternating bonds
5868 : : * and mark non-ring alt bonds non-stereogenic
5869 : : ************************************************/
5870 : :
5871 : 161 : ReInitBnStructForAltBns( pBNS, at, num_atoms, 0 );
5872 : 161 : MarkRingSystemsAltBns( pBNS, 0 );
5873 : 161 : MarkNonStereoAltBns( pBNS, at, num_atoms, 0 );
5874 : : #if ( FIX_EITHER_DB_AS_NONSTEREO == 1 )
5875 : : /* second time unknown ("Either") alternating bonds are treated as non-stereogenic */
5876 : : /* stereobonds bonds that lost stereo get "Either" stereo_type */
5877 : : ReInitBnStructForAltBns( pBNS, at, num_atoms, 1 );
5878 : : MarkRingSystemsAltBns( pBNS, 1 );
5879 : : MarkNonStereoAltBns( pBNS, at, num_atoms, 1 );
5880 : : #endif
5881 : : }
5882 : : else
5883 : : {
5884 : 0 : bError = BNS_OUT_OF_RAM;
5885 : : /*printf("BNS_OUT_OF_RAM-3\n");*/
5886 : : }
5887 : :
5888 : : /*(@nnuk : Nauman Ullah Khan) */
5889 : : LOG_NO_ARGS("\n################# Modified state after (De)Protonation (L6014:ichi_bns.c) ################\n");
5890 [ + + ]: 971 : for (at_prot = 0; at_prot < num_atoms; at_prot++)
5891 : : {
5892 : : LOG_MULT_ARGS("Atom %d: Element: %s, Num_H: %d, Charge: %hhd, Radical: %d\n", at_prot, at[at_prot].elname, at[at_prot].num_H, at[at_prot].charge, at[at_prot].radical);
5893 : : }
5894 : : LOG_NO_ARGS("\n##########################################################################################\n");
5895 : :
5896 : 161 : exit_function:
5897 : :
5898 : : /* djb-rwth: ignoring LLVM warning: variables used to store functions return values */
5899 : 161 : pBNS = DeAllocateBnStruct(pBNS);
5900 : 161 : pBD = DeAllocateBnData(pBD);
5901 : : /*#if ( MOVE_CHARGES == 1 )*/
5902 [ + - ]: 161 : if (c_group_info)
5903 : : {
5904 [ + + ]: 161 : if (c_group_info->c_group)
5905 : : {
5906 [ + - ]: 77 : inchi_free( c_group_info->c_group );
5907 : : }
5908 [ + + ]: 161 : if (c_group_info->c_candidate)
5909 : : {
5910 [ + - ]: 77 : inchi_free( c_group_info->c_candidate );
5911 : : }
5912 : : }
5913 : : /*#endif*/
5914 [ + - + - ]: 161 : if (s_group_info && s_group_info->s_candidate)
5915 : : {
5916 [ + - ]: 161 : inchi_free( s_group_info->s_candidate );
5917 : : }
5918 [ + - + + ]: 161 : if (pAATG && pAATG->nMarkedAtom)
5919 : : {
5920 [ + - ]: 18 : inchi_free( pAATG->nMarkedAtom );
5921 [ - + - - ]: 18 : qzfree( pAATG->nEndPoint );
5922 : : /*qzfree( pAATG->nAtTypeTotals );*/ /* nAtTypeTotals is a stack array */
5923 : : }
5924 [ + - + - ]: 161 : if (t_group_info && t_group_info->tGroupNumber)
5925 : : {
5926 [ + - ]: 161 : inchi_free( t_group_info->tGroupNumber );
5927 : 161 : t_group_info->tGroupNumber = NULL;
5928 : : }
5929 : :
5930 [ + - + + : 161 : if (!bError && num_atoms == 1 && at[0].at_type == ATT_PROTON && t_group_info && !t_group_info->tni.nNumRemovedExplicitH)
- + - - -
- ]
5931 : : {
5932 : : /* remove single isolated proton */
5933 : 0 : t_group_info->tni.nNumRemovedProtons = 1;
5934 : 0 : t_group_info->tni.bNormalizationFlags |= FLAG_PROTON_SINGLE_REMOVED;
5935 [ # # ]: 0 : if (at[0].iso_atw_diff)
5936 : : {
5937 : : #if ( FIX_CURE53_ISSUE_NULL_DEREFERENCE_MAKE_A_COPY_OF_T_GROUP_INFO==1 || defined(FIX_IMPOSSIBLE_H_ISOTOPE_BUG) )
5938 [ # # ]: 0 : if (0 < at[0].iso_atw_diff &&
5939 [ # # ]: 0 : at[0].iso_atw_diff <= NUM_H_ISOTOPES)
5940 : : {
5941 : 0 : t_group_info->tni.nNumRemovedProtonsIsotopic[at[0].iso_atw_diff - 1] ++;
5942 : : }
5943 : : #else
5944 : : t_group_info->tni.nNumRemovedProtonsIsotopic[at[0].iso_atw_diff - 1] ++;
5945 : : #endif
5946 : : }
5947 [ # # ]: 0 : if (at_fixed_bonds_out)
5948 : : {
5949 : 0 : memcpy(at_fixed_bonds_out, at, num_atoms * sizeof(at_fixed_bonds_out[0]));
5950 : : }
5951 : : /*num_atoms --;*/
5952 : : }
5953 : :
5954 : :
5955 : : /*
5956 : : Additional currently unused info:
5957 : :
5958 : : nOrigDelta > 0: original structure has been changed
5959 : : due to fiund augmenting path(s)
5960 : : nChanges > 0: either alt. bonds or taut. groups have been found
5961 : : */
5962 : :
5963 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5964 [ - + ]: 161 : if (stored_radicals)
5965 : : {
5966 [ # # ]: 0 : inchi_free( stored_radicals );
5967 : : }
5968 : : #endif
5969 : :
5970 [ - + ]: 161 : return bError ? bError : num_atoms; /* ret = 0 => success, any other => error */
5971 : : }
5972 : :
5973 : :
5974 : : /****************************************************************************/
5975 : 694 : int nMaxFlow2Check( BN_STRUCT *pBNS, int iedge )
5976 : : {
5977 : 694 : BNS_EDGE *pEdge = pBNS->edge + iedge;
5978 : 694 : int nMaxFlow = ( pEdge->cap & EDGE_FLOW_MASK ); /* edge cap */
5979 : :
5980 [ - + ]: 694 : if (nMaxFlow > MAX_BOND_EDGE_CAP)
5981 : : {
5982 : 0 : nMaxFlow = MAX_BOND_EDGE_CAP;
5983 : : }
5984 : 694 : return nMaxFlow;
5985 : : }
5986 : :
5987 : :
5988 : : /****************************************************************************/
5989 : 694 : int nCurFlow2Check( BN_STRUCT *pBNS, int iedge )
5990 : : {
5991 : 694 : BNS_EDGE *pEdge = pBNS->edge + iedge;
5992 : 694 : int nCurFlow = ( pEdge->flow & EDGE_FLOW_MASK ); /* edge flow */
5993 : 694 : return nCurFlow;
5994 : : }
5995 : :
5996 : :
5997 : : /****************************************************************************/
5998 : 694 : int nMinFlow2Check( BN_STRUCT *pBNS, int iedge )
5999 : : {
6000 : 694 : BNS_EDGE *pEdge = pBNS->edge + iedge;
6001 : 694 : Vertex v1 = pEdge->neighbor1;
6002 : 694 : Vertex v2 = v1 ^ pEdge->neighbor12;
6003 : 694 : int f12 = ( pEdge->flow & EDGE_FLOW_MASK );
6004 : : int rescap1, rescap2, rescap12, i, iedge_i;
6005 : :
6006 [ + + ]: 694 : if (f12 > 0)
6007 : : {
6008 [ + + ]: 196 : for (i = 0, rescap1 = 0; i < pBNS->vert[v1].num_adj_edges; i++)
6009 : : {
6010 : 140 : iedge_i = pBNS->vert[v1].iedge[i];
6011 [ + + ]: 140 : if (iedge_i == iedge)
6012 : : {
6013 : 56 : continue;
6014 : : }
6015 : 84 : rescap1 += ( pBNS->edge[iedge_i].cap & EDGE_FLOW_MASK ) - ( pBNS->edge[iedge_i].flow & EDGE_FLOW_MASK );
6016 : : }
6017 [ + + ]: 189 : for (i = 0, rescap2 = 0; i < pBNS->vert[v2].num_adj_edges; i++)
6018 : : {
6019 : 133 : iedge_i = pBNS->vert[v2].iedge[i];
6020 [ + + ]: 133 : if (iedge_i == iedge)
6021 : : {
6022 : 56 : continue;
6023 : : }
6024 : 77 : rescap2 += ( pBNS->edge[iedge_i].cap & EDGE_FLOW_MASK ) - ( pBNS->edge[iedge_i].flow & EDGE_FLOW_MASK );
6025 : : }
6026 : 56 : rescap12 = inchi_min( rescap1, rescap2 );
6027 : 56 : rescap12 = inchi_min( rescap12, f12 );
6028 : 56 : return f12 - rescap12;
6029 : : }
6030 : :
6031 : 638 : return 0;
6032 : : }
6033 : :
6034 : :
6035 : : /****************************************************************************/
6036 : 38 : int bSetBondsAfterCheckOneBond( BN_STRUCT *pBNS,
6037 : : BNS_FLOW_CHANGES *fcd,
6038 : : int nTestFlow,
6039 : : inp_ATOM *at,
6040 : : int num_atoms,
6041 : : int bChangeFlow0 )
6042 : : {
6043 : 38 : int ifcd, iedge, new_flow, ret_val, nChanges = 0, bError = 0;
6044 : : int bChangeFlow;
6045 : : Vertex v1, v2;
6046 : : int ineigh1, ineigh2;
6047 : : BNS_EDGE *pEdge;
6048 : :
6049 : 38 : bChangeFlow0 &= ~BNS_EF_CHNG_RSTR; /* do not change pEdge flow in SetBondType */
6050 [ + + ]: 38 : if (!bChangeFlow0)
6051 : : {
6052 : 16 : return 0;
6053 : : }
6054 : :
6055 : 22 : bChangeFlow = ( bChangeFlow0 & ~BNS_EF_SET_NOSTEREO );
6056 : :
6057 : : /* Find the next to the last changed */
6058 [ - + ]: 22 : if (bChangeFlow0 & BNS_EF_SET_NOSTEREO)
6059 : : {
6060 [ # # ]: 0 : for (ifcd = 0; NO_VERTEX != ( iedge = fcd[ifcd].iedge ); ifcd++) /* djb-rwth: ignoring LLVM warning: variable used */
6061 : : {
6062 : 0 : iedge = fcd[ifcd].iedge;
6063 : 0 : pEdge = pBNS->edge + iedge;
6064 [ # # ]: 0 : if (!pEdge->pass)
6065 : : {
6066 : 0 : continue;
6067 : : }
6068 : :
6069 [ # # # # ]: 0 : if (!ifcd && nTestFlow >= 0)
6070 : : {
6071 : 0 : new_flow = nTestFlow;
6072 : : }
6073 : : else
6074 : : {
6075 : 0 : new_flow = (int) pEdge->flow;
6076 : : }
6077 : :
6078 : 0 : v1 = pEdge->neighbor1;
6079 : 0 : v2 = pEdge->neighbor12 ^ v1;
6080 [ # # # # : 0 : if (v1 < num_atoms && v2 < num_atoms && new_flow != pEdge->flow0)
# # ]
6081 : : {
6082 : 0 : if (( pBNS->vert[v1].st_edge.cap0 == pBNS->vert[v1].st_edge.flow0 ) !=
6083 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.cap == pBNS->vert[v1].st_edge.flow ) ||
6084 : 0 : ( pBNS->vert[v2].st_edge.cap0 == pBNS->vert[v2].st_edge.flow0 ) !=
6085 [ # # ]: 0 : ( pBNS->vert[v2].st_edge.cap == pBNS->vert[v2].st_edge.flow ))
6086 : : {
6087 : 0 : bChangeFlow |= BNS_EF_SET_NOSTEREO;
6088 : 0 : nChanges |= BNS_EF_SET_NOSTEREO;
6089 : : }
6090 : : }
6091 : : }
6092 : : }
6093 : : else
6094 : : {
6095 [ + + ]: 66 : for (ifcd = 0; NO_VERTEX != ( iedge = fcd[ifcd].iedge ); ifcd++) /* djb-rwth: ignoring LLVM warning: variable used */
6096 : : {
6097 : : ;
6098 : : }
6099 : : }
6100 : :
6101 : : /* restore in reversed order to correctly handle vertex changed more than once */
6102 [ + + ]: 66 : for (ifcd -= 1; 0 <= ifcd; ifcd--)
6103 : : {
6104 : :
6105 : 44 : iedge = fcd[ifcd].iedge;
6106 : 44 : pEdge = pBNS->edge + iedge;
6107 [ - + ]: 44 : if (!pEdge->pass)
6108 : : {
6109 : 0 : continue;
6110 : : }
6111 : :
6112 [ + + + - ]: 44 : if (!ifcd && nTestFlow >= 0)
6113 : : {
6114 : 22 : new_flow = nTestFlow;
6115 : : }
6116 : : else
6117 : : {
6118 : 22 : new_flow = (int) pEdge->flow;
6119 : : }
6120 : :
6121 : 44 : v1 = pEdge->neighbor1;
6122 : 44 : v2 = pEdge->neighbor12 ^ v1;
6123 [ + - + + : 44 : if (v1 < num_atoms && v2 < num_atoms && bChangeFlow && new_flow != pEdge->flow0)
+ - + - ]
6124 : : {
6125 : 37 : ineigh1 = pEdge->neigh_ord[0];
6126 : 37 : ineigh2 = pEdge->neigh_ord[1];
6127 : 37 : ret_val = SetAtomBondType( pEdge, &at[v1].bond_type[ineigh1], &at[v2].bond_type[ineigh2], new_flow - pEdge->flow0, bChangeFlow );
6128 [ + - + - ]: 37 : if (!IS_BNS_ERROR( ret_val ))
6129 : : {
6130 : 37 : nChanges |= ( ret_val > 0 );
6131 : : }
6132 : : else
6133 : : {
6134 : 0 : bError = ret_val;
6135 : : }
6136 : : }
6137 : 44 : pEdge->pass = 0;
6138 : : }
6139 : :
6140 [ - + ]: 22 : return bError ? bError : nChanges;
6141 : : }
6142 : :
6143 : :
6144 : : /****************************************************************************/
6145 : 49 : int bRestoreFlowAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd )
6146 : : {
6147 : : int ifcd, iedge;
6148 : : Vertex v1, v2;
6149 : : BNS_EDGE *pEdge;
6150 : :
6151 : : /* Find the next to the last changed */
6152 [ + + ]: 122 : for (ifcd = 0; NO_VERTEX != ( iedge = fcd[ifcd].iedge ); ifcd++) /* djb-rwth: ignoring LLVM warning: variable used */
6153 : : {
6154 : : ;
6155 : : }
6156 : :
6157 : : /* Restore in reversed order to correctly handle vertex changed more than once */
6158 [ + + ]: 122 : for (ifcd -= 1; 0 <= ifcd; ifcd--)
6159 : : {
6160 : : /* Restore edge flow & cap */
6161 : 73 : iedge = fcd[ifcd].iedge;
6162 : 73 : pEdge = pBNS->edge + iedge;
6163 : 73 : pEdge->flow = fcd[ifcd].flow;
6164 : 73 : pEdge->cap = fcd[ifcd].cap;
6165 : 73 : pEdge->pass = 0;
6166 : :
6167 : : /* Restore st-flow, cap */
6168 [ + - ]: 73 : if (NO_VERTEX != ( v1 = fcd[ifcd].v1 ))
6169 : : {
6170 : 73 : pBNS->vert[v1].st_edge.flow = fcd[ifcd].flow_st1;
6171 : 73 : pBNS->vert[v1].st_edge.cap = fcd[ifcd].cap_st1;
6172 : 73 : pBNS->vert[v1].st_edge.pass = 0;
6173 : : }
6174 [ + + ]: 73 : if (NO_VERTEX != ( v2 = fcd[ifcd].v2 ))
6175 : : {
6176 : 33 : pBNS->vert[v2].st_edge.flow = fcd[ifcd].flow_st2;
6177 : 33 : pBNS->vert[v2].st_edge.cap = fcd[ifcd].cap_st2;
6178 : 33 : pBNS->vert[v2].st_edge.pass = 0;
6179 : : }
6180 : : }
6181 : :
6182 : 49 : return 0;
6183 : : }
6184 : :
6185 : :
6186 : : /****************************************************************************/
6187 : 33 : int bSetFlowToCheckOneBond( BN_STRUCT *pBNS,
6188 : : int iedge,
6189 : : int flow,
6190 : : BNS_FLOW_CHANGES *fcd )
6191 : : {
6192 : 33 : BNS_EDGE *pEdge = pBNS->edge + iedge;
6193 : 33 : int f12 = ( pEdge->flow & EDGE_FLOW_MASK ); /* the original flow */
6194 : 33 : int ifcd = 0;
6195 : 33 : int nDots = 0;
6196 : : int i, iedge_i;
6197 : :
6198 : 33 : fcd[ifcd].iedge = NO_VERTEX;
6199 : :
6200 [ + + ]: 33 : if (f12 < flow)
6201 : : {
6202 : : /* Increase edge flow: Grab flow from the neighbors and delete it: set flow12=cap12 = 0 */
6203 : : /************************************************************************************/
6204 : : /* For example, simulate a new fixed double bond in place of a single bond and */
6205 : : /* creates ONE or NONE (in case of a radical on adjacent atom) augmenting paths and */
6206 : : /* makes it impossible for the BNS to set same flow as it originally was */
6207 : : /************************************************************************************/
6208 : 20 : Vertex v1 = pEdge->neighbor1;
6209 : 20 : Vertex v2 = v1 ^ pEdge->neighbor12;
6210 : : Vertex v_i; /* neighbor of v1 or v2 */
6211 : : BNS_EDGE *pEdge_i;
6212 : : int delta1, delta2, f, st_edge_rescap;
6213 : :
6214 [ + - ]: 20 : if (( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow ||
6215 [ - + ]: 20 : ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow)
6216 : : {
6217 : 0 : return BNS_CANT_SET_BOND;
6218 : : }
6219 [ + - ]: 20 : if (( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12 ||
6220 [ - + ]: 20 : ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12)
6221 : : {
6222 : 0 : return BNS_CAP_FLOW_ERR;
6223 : : }
6224 : :
6225 : 20 : fcd[ifcd].iedge = iedge;
6226 : 20 : fcd[ifcd].flow = pEdge->flow;
6227 : 20 : fcd[ifcd].cap = pEdge->cap;
6228 : :
6229 : 20 : fcd[ifcd].v1 = v1;
6230 : 20 : fcd[ifcd].flow_st1 = pBNS->vert[v1].st_edge.flow;
6231 : 20 : fcd[ifcd].cap_st1 = pBNS->vert[v1].st_edge.cap;
6232 : :
6233 : 20 : fcd[ifcd].v2 = v2;
6234 : 20 : fcd[ifcd].flow_st2 = pBNS->vert[v2].st_edge.flow;
6235 : 20 : fcd[ifcd].cap_st2 = pBNS->vert[v2].st_edge.cap;
6236 : :
6237 : 20 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6238 : 20 : pEdge->pass |= 64;
6239 : :
6240 : 20 : delta1 = delta2 = flow - f12;
6241 : :
6242 [ - + ]: 20 : if (f12 > 0)
6243 : : {
6244 : : /* Remove old edge flow from the flow and cap of the adjacent vertices' st-edges */
6245 : 0 : pBNS->vert[v1].st_edge.cap = ( ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) - f12 ) | ( pBNS->vert[v1].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6246 : 0 : pBNS->vert[v2].st_edge.cap = ( ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) - f12 ) | ( pBNS->vert[v2].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6247 : 0 : pBNS->vert[v1].st_edge.flow = ( ( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) - f12 ) | ( pBNS->vert[v1].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6248 : 0 : pBNS->vert[v2].st_edge.flow = ( ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) - f12 ) | ( pBNS->vert[v2].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6249 : : /* Delete current edge flow and capacity */
6250 : 0 : pEdge->flow = ( pEdge->flow & ~EDGE_FLOW_MASK );
6251 : : }
6252 : 20 : pEdge->cap = ( pEdge->cap & ~EDGE_FLOW_MASK );
6253 : :
6254 : : /* Grab the adjacent vertex1 radical (st_edge_rescap) if it exists */
6255 : 20 : st_edge_rescap = ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) - ( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK );
6256 [ - + - - ]: 20 : while (st_edge_rescap && delta1)
6257 : : {
6258 : 0 : st_edge_rescap--; /* grab the radical */
6259 : 0 : delta1--;
6260 : 0 : pBNS->vert[v1].st_edge.cap = ( ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v1].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6261 : 0 : nDots--;
6262 : : }
6263 : :
6264 : : /* Grab the adjacent vertex2 radical (st_edge_rescap) if it exists */
6265 : 20 : st_edge_rescap = ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) - ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK );
6266 [ - + - - ]: 20 : while (st_edge_rescap && delta2)
6267 : : {
6268 : 0 : st_edge_rescap--; /* grab the radical */
6269 : 0 : delta2--;
6270 : 0 : pBNS->vert[v2].st_edge.cap = ( ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v2].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6271 : 0 : nDots--;
6272 : : }
6273 : :
6274 : : /* Grab flows from v1 neighbors */
6275 [ + + + - ]: 54 : for (i = 0; delta1 && i < pBNS->vert[v1].num_adj_edges; i++)
6276 : : {
6277 : 34 : iedge_i = pBNS->vert[v1].iedge[i];
6278 [ + + ]: 34 : if (iedge_i == iedge)
6279 : : {
6280 : 9 : continue;
6281 : : }
6282 : 25 : pEdge_i = pBNS->edge + iedge_i;
6283 [ - + ]: 25 : if (IS_FORBIDDEN( pEdge_i->forbidden, pBNS ))
6284 : : {
6285 : 0 : continue;
6286 : : }
6287 : 25 : f = ( pEdge_i->flow & EDGE_FLOW_MASK );
6288 [ + + ]: 25 : if (f)
6289 : : {
6290 : 20 : v_i = pEdge_i->neighbor12 ^ v1;
6291 : :
6292 : 20 : fcd[ifcd].iedge = iedge_i;
6293 : 20 : fcd[ifcd].flow = pEdge_i->flow;
6294 : 20 : fcd[ifcd].cap = pEdge_i->cap;
6295 : :
6296 : 20 : fcd[ifcd].v1 = v_i;
6297 : 20 : fcd[ifcd].flow_st1 = pBNS->vert[v_i].st_edge.flow;
6298 : 20 : fcd[ifcd].cap_st1 = pBNS->vert[v_i].st_edge.cap;
6299 : :
6300 : 20 : fcd[ifcd].v2 = NO_VERTEX;
6301 : 20 : fcd[ifcd].flow_st2 = 0;
6302 : 20 : fcd[ifcd].cap_st2 = 0;
6303 : :
6304 : 20 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6305 : 20 : pEdge_i->pass |= 64;
6306 : :
6307 [ + + + - ]: 40 : while (f && delta1)
6308 : : {
6309 : 20 : f--;
6310 : 20 : delta1--;
6311 : 20 : pEdge_i->flow = ( ( pEdge_i->flow & EDGE_FLOW_MASK ) - 1 ) | ( pEdge_i->flow & ~EDGE_FLOW_MASK );
6312 : 20 : pBNS->vert[v_i].st_edge.flow = ( ( pBNS->vert[v_i].st_edge.flow & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v_i].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6313 : : /* next 2 lines added 01-22-2002 */
6314 : 20 : pBNS->vert[v1].st_edge.cap = ( ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v1].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6315 : 20 : pBNS->vert[v1].st_edge.flow = ( ( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v1].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6316 : :
6317 : 20 : nDots++;
6318 : : }
6319 : : }
6320 : : }
6321 : :
6322 : : /* Grab flows from v2 neighbors */
6323 [ + + + - ]: 69 : for (i = 0; delta2 && i < pBNS->vert[v2].num_adj_edges; i++)
6324 : : {
6325 : 49 : iedge_i = pBNS->vert[v2].iedge[i];
6326 [ + + ]: 49 : if (iedge_i == iedge)
6327 : : {
6328 : 20 : continue;
6329 : : }
6330 : 29 : pEdge_i = pBNS->edge + iedge_i;
6331 [ + + ]: 29 : if (IS_FORBIDDEN( pEdge_i->forbidden, pBNS ))
6332 : : {
6333 : 1 : continue;
6334 : : }
6335 : 28 : f = ( pEdge_i->flow & EDGE_FLOW_MASK );
6336 [ + + ]: 28 : if (f)
6337 : : {
6338 : 20 : v_i = pEdge_i->neighbor12 ^ v2;
6339 : :
6340 : 20 : fcd[ifcd].iedge = iedge_i;
6341 : 20 : fcd[ifcd].flow = pEdge_i->flow;
6342 : 20 : fcd[ifcd].cap = pEdge_i->cap;
6343 : :
6344 : 20 : fcd[ifcd].v1 = v_i;
6345 : 20 : fcd[ifcd].flow_st1 = pBNS->vert[v_i].st_edge.flow;
6346 : 20 : fcd[ifcd].cap_st1 = pBNS->vert[v_i].st_edge.cap;
6347 : :
6348 : 20 : fcd[ifcd].v2 = NO_VERTEX;
6349 : 20 : fcd[ifcd].flow_st2 = 0;
6350 : 20 : fcd[ifcd].cap_st2 = 0;
6351 : :
6352 : 20 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6353 : 20 : pEdge_i->pass |= 64;
6354 : :
6355 [ + + + - ]: 40 : while (f && delta2)
6356 : : {
6357 : 20 : f--;
6358 : 20 : delta2--;
6359 : 20 : pEdge_i->flow = ( ( pEdge_i->flow & EDGE_FLOW_MASK ) - 1 ) | ( pEdge_i->flow & ~EDGE_FLOW_MASK );
6360 : 20 : pBNS->vert[v_i].st_edge.flow = ( ( pBNS->vert[v_i].st_edge.flow & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v_i].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6361 : : /* next 2 lines added 01-22-2002 */
6362 : 20 : pBNS->vert[v2].st_edge.cap = ( ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v2].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6363 : 20 : pBNS->vert[v2].st_edge.flow = ( ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) - 1 ) | ( pBNS->vert[v2].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6364 : :
6365 : 20 : nDots++;
6366 : : }
6367 : : }
6368 : : }
6369 [ + - - + ]: 20 : if (delta1 || delta2)
6370 : : {
6371 : 0 : return BNS_CANT_SET_BOND;
6372 : : }
6373 : : }
6374 : :
6375 [ + + ]: 33 : if (f12 >= flow)
6376 : : {
6377 : : /* Decrease edge flow: Redirect flow to the neighbors and delete it on the edge: set flow12=cap12 = 0 */
6378 : : /* f12==flow fixes flow through the edge so that BNS cannot change it */
6379 : : /**********************************************************************************************/
6380 : : /* For example, simulate a removal of a double bond and create ONE or NONE augmenting path */
6381 : : /* Make it impossible for BNS to set same flow as it originally was */
6382 : : /**********************************************************************************************/
6383 : 13 : Vertex v1 = pEdge->neighbor1;
6384 : 13 : Vertex v2 = ( v1 ^ pEdge->neighbor12 );
6385 : : int delta;
6386 : : /* if NOT (st-cap >= st-flow >= f12 >= flow) then error in the BN structure */
6387 [ + - ]: 13 : if (( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12 ||
6388 [ + - ]: 13 : ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12 ||
6389 [ + - ]: 13 : ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow ||
6390 [ - + ]: 13 : ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow)
6391 : : {
6392 : 0 : return BNS_CAP_FLOW_ERR;
6393 : : }
6394 : 13 : fcd[ifcd].iedge = iedge;
6395 : 13 : fcd[ifcd].flow = pEdge->flow;
6396 : 13 : fcd[ifcd].cap = pEdge->cap;
6397 : :
6398 : 13 : fcd[ifcd].v1 = v1;
6399 : 13 : fcd[ifcd].flow_st1 = pBNS->vert[v1].st_edge.flow;
6400 : 13 : fcd[ifcd].cap_st1 = pBNS->vert[v1].st_edge.cap;
6401 : :
6402 : 13 : fcd[ifcd].v2 = v2;
6403 : 13 : fcd[ifcd].flow_st2 = pBNS->vert[v2].st_edge.flow;
6404 : 13 : fcd[ifcd].cap_st2 = pBNS->vert[v2].st_edge.cap;
6405 : :
6406 : 13 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6407 : 13 : pEdge->pass |= 64;
6408 : :
6409 : 13 : delta = f12 - flow;
6410 : :
6411 : : /* Remove current edge flow from st-edges */
6412 : : /* -- seem to be a bug --
6413 : : pBNS->vert[v1].st_edge.flow = ((pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK)-delta) | (pBNS->vert[v1].st_edge.flow & ~EDGE_FLOW_ST_MASK);
6414 : : pBNS->vert[v2].st_edge.flow = ((pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK)-delta) | (pBNS->vert[v2].st_edge.flow & ~EDGE_FLOW_ST_MASK);
6415 : : */
6416 : :
6417 : : /* Replacement to the above 2 lines 01-16-2002 */
6418 : : /* Remove old edge flow from the flow of the adjacent vertices' st-edges */
6419 : :
6420 : 13 : pBNS->vert[v1].st_edge.flow = ( ( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) - f12 ) | ( pBNS->vert[v1].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6421 : 13 : pBNS->vert[v2].st_edge.flow = ( ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) - f12 ) | ( pBNS->vert[v2].st_edge.flow & ~EDGE_FLOW_ST_MASK );
6422 : :
6423 : : /* Sdded 01-16-2002: reduce st-cap if new flow > 0 */
6424 : : /* Remove new edge flow from the cap of the adjacent vertices' st-edges */
6425 : 13 : pBNS->vert[v1].st_edge.cap = ( ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) - flow ) | ( pBNS->vert[v1].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6426 : 13 : pBNS->vert[v2].st_edge.cap = ( ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) - flow ) | ( pBNS->vert[v2].st_edge.cap & ~EDGE_FLOW_ST_MASK );
6427 : :
6428 : : /* delete current edge flow and capacity */
6429 : 13 : pEdge->flow = ( pEdge->flow & ~EDGE_FLOW_MASK );
6430 : 13 : pEdge->cap = ( pEdge->cap & ~EDGE_FLOW_MASK );
6431 : 13 : nDots = 2 * delta;
6432 : : }
6433 : :
6434 : 33 : return nDots;
6435 : : }
6436 : :
6437 : :
6438 : : /****************************************************************************
6439 : : bAddNewVertex( ... )
6440 : :
6441 : : Connect new (fictitious, temporary) vertex to nVertDoubleBond by a new edge
6442 : : Add radical (set st-cap=1) to the new vertex, set cap=1 to the new edge
6443 : : Add radical (set st-cap=1) to nVertSingleBond
6444 : : Find augmenting path connecting new vertex to nVertSingleBond
6445 : : This corresponds to moving H-atom from nVertSingleBond to nVertDoubleBond
6446 : : ****************************************************************************/
6447 : 16 : int bAddNewVertex( BN_STRUCT *pBNS,
6448 : : int nVertDoubleBond,
6449 : : int nCap,
6450 : : int nFlow,
6451 : : int nMaxAdjEdges,
6452 : : int *nDots )
6453 : : {
6454 : 16 : Vertex vlast = pBNS->num_vertices - 1;
6455 : 16 : Vertex vnew = pBNS->num_vertices;
6456 : 16 : Vertex v2 = nVertDoubleBond;
6457 : 16 : BNS_VERTEX *pVert2 = pBNS->vert + v2; /* pointer to an old vertex */
6458 : 16 : BNS_VERTEX *pNewVert = pBNS->vert + vnew; /* pointer to a new vertex */
6459 : :
6460 : 16 : EdgeIndex iedge = pBNS->num_edges;
6461 : 16 : BNS_EDGE *pEdge = pBNS->edge + iedge; /* pointer to a new edge */
6462 : :
6463 [ + - - + ]: 16 : if (iedge >= pBNS->max_edges || vnew >= pBNS->max_vertices)
6464 : : {
6465 : 0 : return BNS_VERT_EDGE_OVFL; /* edges or vertices overflow */
6466 : : }
6467 [ - + ]: 16 : if (( pBNS->vert[vlast].iedge - pBNS->iedge ) + pBNS->vert[vlast].max_adj_edges + nMaxAdjEdges >= pBNS->max_iedges)
6468 : : {
6469 : 0 : return BNS_VERT_EDGE_OVFL; /* iedges overflow */
6470 : : }
6471 [ + - - + ]: 16 : if (pVert2->num_adj_edges >= pVert2->max_adj_edges || nMaxAdjEdges <= 0)
6472 : : {
6473 : 0 : return BNS_VERT_EDGE_OVFL; /* neighbors overflow */
6474 : : }
6475 : :
6476 : : /* Fill out the new edge, set its cap and flow, connect */
6477 : : /* memset( pEdge, 0, sizeof(*pEdge) ); */
6478 : 16 : pEdge->cap = pEdge->cap0 = nCap;
6479 : 16 : pEdge->flow = pEdge->flow0 = nFlow;
6480 : 16 : pEdge->pass = 0;
6481 : 16 : pEdge->neighbor1 = v2;
6482 : 16 : pEdge->neighbor12 = v2 ^ vnew;
6483 : 16 : pEdge->forbidden = 0;
6484 : :
6485 : : /* Fill out the new vertex */
6486 : : /* memset( pNewVert, 0, sizeof(*pNewVert) ); */
6487 : 16 : pNewVert->max_adj_edges = nMaxAdjEdges;
6488 : 16 : pNewVert->num_adj_edges = 0;
6489 : 16 : pNewVert->st_edge.cap0 = pNewVert->st_edge.cap = nCap;
6490 : 16 : pNewVert->st_edge.flow0 = pNewVert->st_edge.flow = nFlow;
6491 : 16 : pNewVert->st_edge.pass = 0; /* add initialization; added 2006-03-25 */
6492 : 16 : pNewVert->iedge = pBNS->vert[vlast].iedge + pBNS->vert[vlast].max_adj_edges;
6493 : 16 : pNewVert->type = BNS_VERT_TYPE_TEMP;
6494 : 16 : *nDots += nCap - nFlow;
6495 : :
6496 : 16 : pEdge->neigh_ord[v2 > vnew] = pVert2->num_adj_edges;
6497 : 16 : pEdge->neigh_ord[v2 < vnew] = pNewVert->num_adj_edges;
6498 : :
6499 : : /* Connect new edge to v2 */
6500 : 16 : pVert2->iedge[pVert2->num_adj_edges++] = iedge;
6501 : : /* Connect new edge to vnew */
6502 : 16 : pNewVert->iedge[pNewVert->num_adj_edges++] = iedge;
6503 : :
6504 : : /* Fix v2 flow and cap */
6505 : 16 : *nDots -= (int) pVert2->st_edge.cap - (int) pVert2->st_edge.flow;
6506 : 16 : pVert2->st_edge.flow += nFlow;
6507 [ - + ]: 16 : if (pVert2->st_edge.cap < pVert2->st_edge.flow)
6508 : : {
6509 : 0 : pVert2->st_edge.cap = pVert2->st_edge.flow;
6510 : : }
6511 : 16 : *nDots += (int) pVert2->st_edge.cap - (int) pVert2->st_edge.flow;
6512 : :
6513 : 16 : pBNS->num_edges++;
6514 : 16 : pBNS->num_vertices++;
6515 : :
6516 : 16 : return vnew;
6517 : : }
6518 : :
6519 : :
6520 : : /****************************************************************************/
6521 : 0 : int AddNewEdge( BNS_VERTEX *p1,
6522 : : BNS_VERTEX *p2,
6523 : : BN_STRUCT *pBNS,
6524 : : int nEdgeCap,
6525 : : int nEdgeFlow )
6526 : : {
6527 : 0 : int ip1 = (int) ( p1 - pBNS->vert );
6528 : 0 : int ip2 = (int) ( p2 - pBNS->vert );
6529 : 0 : int ie = pBNS->num_edges;
6530 : 0 : BNS_EDGE *e = pBNS->edge + ie;
6531 : :
6532 : : /* Debug: check bounds */
6533 [ # # # # ]: 0 : if (ip1 >= pBNS->max_vertices || ip1 < 0 ||
6534 [ # # # # ]: 0 : ip2 >= pBNS->max_vertices || ip2 < 0 ||
6535 [ # # # # ]: 0 : ie >= pBNS->max_edges || ie < 0 ||
6536 [ # # ]: 0 : ( p1->iedge - pBNS->iedge ) < 0 ||
6537 [ # # ]: 0 : ( p1->iedge - pBNS->iedge ) + p1->max_adj_edges > pBNS->max_iedges ||
6538 [ # # ]: 0 : ( p2->iedge - pBNS->iedge ) < 0 ||
6539 [ # # ]: 0 : ( p2->iedge - pBNS->iedge ) + p2->max_adj_edges > pBNS->max_iedges ||
6540 [ # # ]: 0 : p1->num_adj_edges >= p1->max_adj_edges ||
6541 [ # # ]: 0 : p2->num_adj_edges >= p2->max_adj_edges)
6542 : : {
6543 : 0 : return BNS_VERT_EDGE_OVFL;
6544 : : }
6545 : :
6546 : : /* Clear the edge */
6547 : 0 : memset( e, 0, sizeof( *e ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6548 : :
6549 : : /* Connect */
6550 : 0 : e->neighbor1 = inchi_min( ip1, ip2 );
6551 : 0 : e->neighbor12 = ip1 ^ ip2;
6552 : 0 : p1->iedge[p1->num_adj_edges] = ie;
6553 : 0 : p2->iedge[p2->num_adj_edges] = ie;
6554 : 0 : e->neigh_ord[ip1 > ip2] = p1->num_adj_edges++;
6555 : 0 : e->neigh_ord[ip1 < ip2] = p2->num_adj_edges++;
6556 : 0 : e->cap = e->cap0 = nEdgeCap;
6557 : 0 : e->flow = e->flow0 = nEdgeFlow;
6558 : 0 : p1->st_edge.flow += nEdgeFlow;
6559 : 0 : p2->st_edge.flow += nEdgeFlow;
6560 [ # # ]: 0 : if (p1->st_edge.cap < p1->st_edge.flow)
6561 : : {
6562 : 0 : p1->st_edge.cap = p1->st_edge.flow;
6563 : : }
6564 [ # # ]: 0 : if (p2->st_edge.cap < p2->st_edge.flow)
6565 : : {
6566 : 0 : p2->st_edge.cap = p2->st_edge.flow;
6567 : : }
6568 : 0 : pBNS->num_edges++;
6569 : :
6570 : 0 : return ie;
6571 : : }
6572 : :
6573 : :
6574 : : /****************************************************************************/
6575 : 64 : BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type )
6576 : : {
6577 [ + - ]: 64 : if (v1 < pBNS->num_atoms)
6578 : : {
6579 : : Vertex v2;
6580 : : BNS_EDGE *pEdge1;
6581 : 64 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6582 : 64 : int i = pVert1->num_adj_edges - 1;
6583 : :
6584 [ + + ]: 128 : while (0 <= i)
6585 : : {
6586 : 64 : pEdge1 = pBNS->edge + pVert1->iedge[i];
6587 : 64 : v2 = pEdge1->neighbor12 ^ v1;
6588 [ - + ]: 64 : if (pBNS->vert[v2].type == type)
6589 : : {
6590 [ # # ]: 0 : return IS_FORBIDDEN( pEdge1->forbidden, pBNS ) ? NO_VERTEX : pVert1->iedge[i];
6591 : : }
6592 : 64 : i--;
6593 : : }
6594 : 64 : return NO_VERTEX; /* not found t-group */
6595 : : }
6596 : : else
6597 : : {
6598 [ # # ]: 0 : if (v1 < pBNS->num_vertices)
6599 : : {
6600 : 0 : return NO_VERTEX;
6601 : : }
6602 : : }
6603 : :
6604 : 0 : return BNS_VERT_EDGE_OVFL;
6605 : : }
6606 : :
6607 : :
6608 : : /****************************************************************************/
6609 : 0 : Vertex GetGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type )
6610 : : {
6611 [ # # ]: 0 : if (v1 < pBNS->num_atoms)
6612 : : {
6613 : : Vertex v2;
6614 : : BNS_EDGE *pEdge1;
6615 : 0 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6616 : 0 : int i = pVert1->num_adj_edges - 1;
6617 : :
6618 : : AT_NUMB type2;
6619 : :
6620 [ # # ]: 0 : if (type == BNS_VERT_TYPE_ENDPOINT)
6621 : : {
6622 : 0 : type2 = BNS_VERT_TYPE_TGROUP;
6623 : : }
6624 : : else
6625 : : {
6626 [ # # ]: 0 : if (type == BNS_VERT_TYPE_C_POINT)
6627 : : {
6628 : 0 : type2 = BNS_VERT_TYPE_C_GROUP;
6629 : : }
6630 : : else
6631 : : {
6632 : 0 : type2 = 0;
6633 : : }
6634 : : }
6635 : :
6636 [ # # ]: 0 : if (( pVert1->type & type ) == type)
6637 : : {
6638 [ # # ]: 0 : while (0 <= i)
6639 : : {
6640 : 0 : pEdge1 = pBNS->edge + pVert1->iedge[i];
6641 : 0 : v2 = pEdge1->neighbor12 ^ v1;
6642 [ # # ]: 0 : if (pBNS->vert[v2].type == type2)
6643 : : {
6644 [ # # ]: 0 : if (IS_FORBIDDEN( pEdge1->forbidden, pBNS ))
6645 : : {
6646 : 0 : return NO_VERTEX;
6647 : : }
6648 : 0 : return v2;
6649 : : }
6650 : 0 : i--;
6651 : : }
6652 : : }
6653 : 0 : return BNS_BOND_ERR; /* not found t-group */
6654 : : }
6655 : : else
6656 : : {
6657 [ # # ]: 0 : if (v1 < pBNS->num_vertices)
6658 : : {
6659 : 0 : return NO_VERTEX;
6660 : : }
6661 : : }
6662 : :
6663 : 0 : return BNS_VERT_EDGE_OVFL;
6664 : : }
6665 : :
6666 : :
6667 : : /****************************************************************************/
6668 : 16 : int bAddStCapToAVertex( BN_STRUCT *pBNS,
6669 : : Vertex v1,
6670 : : Vertex v2,
6671 : : VertexFlow *nOldCapVertSingleBond,
6672 : : int *nDots,
6673 : : int bAdjacentDonors )
6674 : : {
6675 : 16 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6676 : : BNS_VERTEX *pVert;
6677 : : BNS_EDGE *pEdge;
6678 : : Vertex v;
6679 : : int i, n;
6680 : : VertexFlow nNewCap;
6681 : :
6682 : : /* Change v1: increment its st-cap */
6683 : 16 : n = 0;
6684 : 16 : nOldCapVertSingleBond[n++] = pVert1->st_edge.cap;
6685 : : /*if ( pVert1->st_edge.cap == pVert1->st_edge.flow ) {*/
6686 : 16 : pVert1->st_edge.cap++;
6687 : 16 : *nDots += 1;
6688 : :
6689 : : /*}*/
6690 : : /* increment caps of adjacent edges if
6691 : : (1) the neighbor has st-cap != 0 and
6692 : : (2) (edge cap==0) OR (nSumEdgeCap < pVert1->st_edge.cap && pVert->st_edge.flow > pVert1->st_edge.cap)
6693 : : */
6694 [ + - ]: 16 : if (!( pVert1->type & BNS_VERT_TYPE_ANY_GROUP ))
6695 : : {
6696 : : /*
6697 : : AT_NUMB nSumEdgeCap = 0;
6698 : : for ( i = 0; i < pVert1->num_adj_edges; i ++ ) {
6699 : : pEdge = pBNS->edge + pVert1->iedge[i];
6700 : : nSumEdgeCap += pEdge->cap;
6701 : : }
6702 : : */
6703 : : /* do not increment caps of t-group or c-group edges */
6704 [ + + ]: 32 : for (i = 0; i < pVert1->num_adj_edges; i++)
6705 : : {
6706 : 16 : pEdge = pBNS->edge + pVert1->iedge[i];
6707 : 16 : nOldCapVertSingleBond[n++] = pEdge->cap; /* save edge cap */
6708 : 16 : v = pEdge->neighbor12 ^ v1;
6709 [ - + - - ]: 16 : if (v == v2 && !bAdjacentDonors)
6710 : : {
6711 : 0 : continue;
6712 : : }
6713 : 16 : pVert = pBNS->vert + v;
6714 [ - + ]: 16 : if (pVert->type & BNS_VERT_TYPE_ANY_GROUP)
6715 : 0 : continue;
6716 : 16 : nNewCap = inchi_min( pVert->st_edge.cap, pVert1->st_edge.cap );
6717 : 16 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
6718 : 16 : pEdge->cap = nNewCap; /* change edge cap */
6719 : : /*
6720 : : if ( pVert->st_edge.cap > 0 && !pEdge->cap ) {
6721 : : pEdge->cap ++;
6722 : : } else
6723 : : if ( pVert->st_edge.flow > pVert1->st_edge.cap &&
6724 : : pEdge->cap < MAX_BOND_EDGE_CAP &&
6725 : : nSumEdgeCap < pVert1->st_edge.cap ) {
6726 : : pEdge->cap ++;
6727 : : }
6728 : : */
6729 : : }
6730 : : }
6731 : :
6732 : 16 : return n; /* number of elements in nOldCapVertSingleBond[*] */
6733 : : }
6734 : :
6735 : :
6736 : : #define BNS_CHK_ALTP_NO_ALTPATH 0
6737 : : #define BNS_CHK_ALTP_SAME_TGROUP 1
6738 : : #define BNS_CHK_ALTP_SAME_VERTEX 2
6739 : : #define BNS_CHK_ALTP_SET_SUCCESS 4
6740 : :
6741 : :
6742 : : /****************************************************************************/
6743 : 16 : int bSetBnsToCheckAltPath( BN_STRUCT *pBNS,
6744 : : int nVertDoubleBond,
6745 : : int nVertSingleBond,
6746 : : AT_NUMB type,
6747 : : int path_type,
6748 : : ALT_PATH_CHANGES *apc,
6749 : : BNS_FLOW_CHANGES *fcd,
6750 : : int *nDots )
6751 : : {
6752 : :
6753 [ - + - - ]: 16 : if (!pBNS->vert[nVertDoubleBond].st_edge.flow &&
6754 : :
6755 [ # # # # ]: 0 : !( path_type == ALT_PATH_MODE_REM2H_CHG ||
6756 [ # # ]: 0 : path_type == ALT_PATH_MODE_ADD2H_CHG ||
6757 : : path_type == ALT_PATH_MODE_REM2H_TST ||
6758 : : path_type == ALT_PATH_MODE_ADD2H_TST )
6759 : : )
6760 : : {
6761 : 0 : return BNS_CHK_ALTP_NO_ALTPATH;
6762 : : }
6763 : : else
6764 : : {
6765 : : Vertex vNew;
6766 : 16 : Vertex v1 = nVertSingleBond;
6767 : 16 : Vertex v2 = nVertDoubleBond;
6768 : :
6769 : 16 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6770 : 16 : BNS_VERTEX *pVert2 = pBNS->vert + v2;
6771 : 16 : int n, bAdjacentDonors = 0;
6772 : 16 : int ifcd = 0;
6773 : :
6774 : 16 : Vertex t1 = NO_VERTEX;
6775 : 16 : Vertex t2 = NO_VERTEX;
6776 : : int iapc;
6777 : :
6778 : : /*#if ( TEST_REMOVE_S_ATOMS == 1 )*/ /* && ALT_PATH_MODE_4_SALT == path_type */
6779 [ + - - + ]: 16 : if (( *pBNS->pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) &&
6780 [ # # ]: 0 : ALT_PATH_MODE_4_SALT2 == path_type &&
6781 : : ( BNS_VERT_TYPE_ENDPOINT & type ))
6782 : : {
6783 : : /*
6784 : : ---------------------------------------------------------
6785 : : \ action | DB action (v2) | SB action (v1) |
6786 : : vertex \ | accept H @ vertex | donate H @ vertex |
6787 : : type \ | nVertDoubleBond | nVertSingleBond |
6788 : : ----------------+-------------------+-------------------+
6789 : : -ZH (v1) | error | -ZH(.) |
6790 : : (cap>0 on edge | | increment |
6791 : : except v1-v2) | | st-cap on Z |
6792 : : ----------------+-------------------+-------------------+
6793 : : =Z (v2) | =Z-(.) | error |
6794 : : (st-flow>0) | add fict vertex | |
6795 : : | with st-cap=1 | |
6796 : : ----------------+-------------------+-------------------+
6797 : : endpoint | T(.) | T-(.) |
6798 : : of t-group | increment | add fict vertex |
6799 : : represented | st-cap on T | with st-cap=1 |
6800 : : by fictitious | | |
6801 : : vertex T | | |
6802 : : ---------------------------------------------------------
6803 : : */
6804 : :
6805 : : int bSet_v1; /* indicator: v1 has been set */
6806 : : int bSet_v2; /* indicator: v2 has been set */
6807 : : int i;
6808 : :
6809 : 0 : Vertex v1t = NO_VERTEX;
6810 : 0 : Vertex v2t = NO_VERTEX;
6811 : : Vertex v1Act, v2Act;
6812 : : Vertex v;
6813 : :
6814 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6815 : 0 : fcd[ifcd].iedge = NO_VERTEX;
6816 : 0 : *nDots = 0;
6817 : :
6818 [ # # ]: 0 : if (v1 == v2)
6819 : : {
6820 : 0 : return BNS_CHK_ALTP_SAME_VERTEX;
6821 : : }
6822 : :
6823 : : /* Check whether v1 has neighbors adjacent to multiple bonds */
6824 [ # # ]: 0 : for (i = 0, n = 0; i < pVert1->num_adj_edges; i++)
6825 : : {
6826 : 0 : v = ( pBNS->edge + pVert1->iedge[i] )->neighbor12 ^ v1; /* v is adjacent to v1 */
6827 [ # # ]: 0 : if (v == v2)
6828 : : {
6829 : 0 : continue; /* ignore connection to v2 */
6830 : : }
6831 : 0 : n += ( pBNS->vert[v].st_edge.cap > 0 );
6832 : : }
6833 [ # # ]: 0 : if (!n)
6834 : : {
6835 : 0 : return BNS_CHK_ALTP_NO_ALTPATH; /* the vertex cannot have flow */
6836 : : }
6837 : :
6838 : 0 : v1Act = v1;
6839 : 0 : v2Act = v2;
6840 : :
6841 : : /* find t-group that contains v1 */
6842 [ # # ]: 0 : if (( pVert1->type & type ) == type)
6843 : : {
6844 : 0 : v1t = GetGroupVertex( pBNS, v1, type );
6845 [ # # # # ]: 0 : if (IS_BNS_ERROR( v1t ))
6846 : : {
6847 : 0 : return v1t;
6848 : : }
6849 [ # # ]: 0 : if (v1t != NO_VERTEX)
6850 : : {
6851 : 0 : v1Act = v1t;
6852 : : }
6853 : : }
6854 : : /* Find t-group that contains v2 */
6855 [ # # ]: 0 : if (( pVert2->type & type ) == type)
6856 : : {
6857 : 0 : v2t = GetGroupVertex( pBNS, v2, type );
6858 [ # # # # ]: 0 : if (IS_BNS_ERROR( v2t ))
6859 : : {
6860 : 0 : return v2t;
6861 : : }
6862 [ # # ]: 0 : if (v2t != NO_VERTEX)
6863 : : {
6864 : 0 : v2Act = v2t;
6865 : : }
6866 : : }
6867 [ # # # # ]: 0 : if (v1t != NO_VERTEX && v1t == v2t)
6868 : : {
6869 : 0 : return BNS_CHK_ALTP_SAME_TGROUP;
6870 : : }
6871 : :
6872 : 0 : bSet_v1 = bSet_v2 = 0;
6873 : : /* create new edges adjacent to v1t or v2 */
6874 : 0 : iapc = 0;
6875 [ # # ]: 0 : if (v1t != NO_VERTEX)
6876 : : {
6877 : : /* Create new edge and vertex, connect to v1t */
6878 : 0 : vNew = bAddNewVertex( pBNS, v1t, 1, 0, 1, nDots );
6879 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
6880 : : {
6881 : 0 : return vNew;
6882 : : }
6883 : 0 : apc->vNewVertex[iapc] = vNew;
6884 : 0 : apc->bSetNew[iapc] = 1;
6885 : 0 : bSet_v1 = 1;
6886 : 0 : iapc++;
6887 : : }
6888 [ # # ]: 0 : if (v2t == NO_VERTEX)
6889 : : {
6890 : : /* Create new edge and vertex, connect to v2 */
6891 : 0 : vNew = bAddNewVertex( pBNS, v2, 1, 0, 1, nDots );
6892 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
6893 : : {
6894 : 0 : return vNew;
6895 : : }
6896 : 0 : apc->vNewVertex[iapc] = vNew;
6897 : 0 : apc->bSetNew[iapc] = 1;
6898 : 0 : bSet_v2 = 1;
6899 : 0 : iapc++;
6900 : : }
6901 : :
6902 : : /* Add st-cap to v1 and/or v2t */
6903 : 0 : iapc = 0;
6904 [ # # ]: 0 : if (!bSet_v1)
6905 : : {
6906 : : /* Add st-cap to v1 */
6907 [ # # ]: 0 : if (v1t != NO_VERTEX) /* djb-rwth: addressing coverity ID #499551 -- condition properly written */
6908 : : {
6909 : 0 : return BNS_BOND_ERR;
6910 : : }
6911 : 0 : n = bAddStCapToAVertex( pBNS, v1, v2Act, apc->nOldCapsVert[iapc], nDots, 0 );
6912 : 0 : apc->bSetOldCapsVert[iapc] = n;
6913 : 0 : apc->vOldVert[iapc] = v1;
6914 : 0 : iapc++;
6915 : : }
6916 [ # # ]: 0 : if (!bSet_v2)
6917 : : {
6918 : : /* Add st-cap to v2t */
6919 [ # # ]: 0 : if (v2t == NO_VERTEX)
6920 : : {
6921 : 0 : return BNS_BOND_ERR;
6922 : : }
6923 : 0 : n = bAddStCapToAVertex( pBNS, v2t, v1Act, apc->nOldCapsVert[iapc], nDots, 0 );
6924 : 0 : apc->bSetOldCapsVert[iapc] = n;
6925 : 0 : apc->vOldVert[iapc] = v2t;
6926 : 0 : iapc++;
6927 : : }
6928 [ # # # # ]: 0 : if (*nDots < 0 || *nDots % 2)
6929 : : {
6930 : 0 : return BNS_SET_ALTP_ERR;
6931 : : }
6932 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
6933 : : }
6934 : :
6935 : : /* ( *pBNS->pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) */
6936 : :
6937 : : /*#endif*/
6938 : :
6939 : : /* ( TEST_REMOVE_S_ATOMS == 1 && ALT_PATH_MODE_4_SALT == path_type ) */
6940 : :
6941 [ + - + - ]: 16 : if (path_type == ALT_PATH_MODE_REM2H_CHG ||
6942 [ + - ]: 16 : path_type == ALT_PATH_MODE_ADD2H_CHG ||
6943 [ - + ]: 16 : path_type == ALT_PATH_MODE_REM2H_TST ||
6944 : : path_type == ALT_PATH_MODE_ADD2H_TST)
6945 : : {
6946 : : /* added 2004-03-18 */
6947 : :
6948 [ # # # # ]: 0 : int bDonors = ( path_type == ALT_PATH_MODE_REM2H_CHG ) || ( path_type == ALT_PATH_MODE_REM2H_TST );
6949 : :
6950 : : int bSet_v1; /* indicator: v1 has been set */
6951 : : int bSet_v2; /* indicator: v2 has been set */
6952 : 0 : int i, cap = 1;
6953 : 0 : Vertex v1t = NO_VERTEX;
6954 : 0 : Vertex v2t = NO_VERTEX;
6955 : : Vertex v1Act, v2Act;
6956 : : Vertex v;
6957 : :
6958 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6959 : 0 : fcd[ifcd].iedge = NO_VERTEX;
6960 : 0 : *nDots = 0;
6961 : : /*
6962 : : if ( v1 == v2 ) {
6963 : : return BNS_CHK_ALTP_SAME_VERTEX;
6964 : : }
6965 : : */
6966 : :
6967 : : /* Check whether v1 and v2 have proper neighbors */
6968 [ # # ]: 0 : for (i = 0, n = bAdjacentDonors = 0; i < pVert1->num_adj_edges; i++)
6969 : : {
6970 : 0 : v = ( pBNS->edge + pVert1->iedge[i] )->neighbor12 ^ v1; /* v is adjacent to v1 */
6971 : : /* do not ignore connection to v2
6972 : : if ( v == v2 )
6973 : : continue;
6974 : : */
6975 : 0 : n += bDonors ? ( pBNS->vert[v].st_edge.cap > 0 )
6976 [ # # ]: 0 : : ( ( pBNS->edge + pVert1->iedge[i] )->flow > 0 );
6977 [ # # # # : 0 : bAdjacentDonors += bDonors ? ( v == v2 ) && ( ( pBNS->edge + pVert1->iedge[i] )->flow < MAX_BOND_EDGE_CAP ) : 0;
# # ]
6978 : : /* two donors connected by a single or double bond */
6979 : : }
6980 : :
6981 [ # # # # ]: 0 : if (!n && !bAdjacentDonors)
6982 : : {
6983 : 0 : return BNS_CHK_ALTP_NO_ALTPATH; /* the vertex cannot have flow */
6984 : : }
6985 [ # # ]: 0 : for (i = 0, n = bAdjacentDonors = 0; i < pVert2->num_adj_edges; i++)
6986 : : {
6987 : 0 : v = ( pBNS->edge + pVert2->iedge[i] )->neighbor12 ^ v2; /* v is adjacent to v2 */
6988 : : /* do not ignore connection to v1
6989 : : if ( v == v1 )
6990 : : continue;
6991 : : */
6992 [ # # ]: 0 : n += bDonors ? ( pBNS->vert[v].st_edge.cap > 0 ) : ( ( pBNS->edge + pVert2->iedge[i] )->flow > 0 );
6993 [ # # # # : 0 : bAdjacentDonors += bDonors ? ( v == v1 ) && ( ( pBNS->edge + pVert2->iedge[i] )->flow < MAX_BOND_EDGE_CAP ) : 0;
# # ]
6994 : : /* two donors connected by a single or double bond */
6995 : : }
6996 : :
6997 [ # # # # ]: 0 : if (!n && !bAdjacentDonors)
6998 : : {
6999 : 0 : return BNS_CHK_ALTP_NO_ALTPATH; /* the vertex cannot have flow */
7000 : : }
7001 : :
7002 : 0 : v1Act = v1;
7003 : 0 : v2Act = v2;
7004 : :
7005 : : /* Find t-group that contains v1 */
7006 [ # # ]: 0 : if (( pVert1->type & type ) == type)
7007 : : {
7008 : 0 : v1t = GetGroupVertex( pBNS, v1, type );
7009 [ # # ]: 0 : if (BNS_BOND_ERR == v1t)
7010 : : {
7011 : 0 : v1t = NO_VERTEX;
7012 : : }
7013 : : else
7014 : : {
7015 [ # # # # ]: 0 : if (IS_BNS_ERROR( v1t ))
7016 : : {
7017 : 0 : return v1t;
7018 : : }
7019 : : else
7020 : : {
7021 [ # # ]: 0 : if (v1t != NO_VERTEX)
7022 : : {
7023 : 0 : v1Act = v1t;
7024 : : }
7025 : : }
7026 : : }
7027 : : }
7028 : :
7029 : : /* Find t-group that contains v2 */
7030 [ # # ]: 0 : if (( pVert2->type & type ) == type)
7031 : : {
7032 : 0 : v2t = GetGroupVertex( pBNS, v2, type );
7033 [ # # ]: 0 : if (BNS_BOND_ERR == v2t)
7034 : : {
7035 : 0 : v2t = NO_VERTEX;
7036 : : }
7037 : : else
7038 : : {
7039 [ # # # # ]: 0 : if (IS_BNS_ERROR( v2t ))
7040 : : {
7041 : 0 : return v2t;
7042 : : }
7043 : : else
7044 : : {
7045 [ # # ]: 0 : if (v2t != NO_VERTEX)
7046 : : {
7047 : 0 : v2Act = v2t;
7048 : : }
7049 : : }
7050 : : }
7051 : : }
7052 : :
7053 [ # # # # ]: 0 : if (v1t != NO_VERTEX && v1t == v2t)
7054 : : {
7055 : 0 : cap = 2; /* same t-group */
7056 : : }
7057 : :
7058 : : /* bAddNewVertex: (bDonors != 0) == (vit != NO_VERTEX), i=1,2 */
7059 : 0 : bSet_v1 = bSet_v2 = 0;
7060 : : /* create new edges adjacent to v1t or v2 */
7061 : 0 : iapc = 0;
7062 [ # # ]: 0 : if (( bDonors != 0 ) == ( v1t != NO_VERTEX ))
7063 : : {
7064 : : /* Create new edge and vertex, connect to v1Act */
7065 : 0 : vNew = bAddNewVertex( pBNS, v1Act, cap, 0, 1, nDots );
7066 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7067 : : {
7068 : 0 : return vNew;
7069 : : }
7070 : 0 : apc->vNewVertex[iapc] = vNew;
7071 : 0 : apc->bSetNew[iapc] = 1;
7072 : 0 : bSet_v1 = 1;
7073 : 0 : iapc++;
7074 : : }
7075 [ # # # # ]: 0 : if (( bDonors != 0 ) == ( v2t != NO_VERTEX ) && cap == 1)
7076 : : {
7077 : : /* Create new edge and vertex, connect to v2Act; do not do it if cap==2 */
7078 : 0 : vNew = bAddNewVertex( pBNS, v2Act, cap, 0, 1, nDots );
7079 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7080 : : {
7081 : 0 : return vNew;
7082 : : }
7083 : 0 : apc->vNewVertex[iapc] = vNew;
7084 : 0 : apc->bSetNew[iapc] = 1;
7085 : 0 : bSet_v2 = 1;
7086 : 0 : iapc++;
7087 : : }
7088 : : else
7089 : : {
7090 [ # # ]: 0 : if (( bDonors != 0 ) == ( v2t != NO_VERTEX ))
7091 : : {
7092 : 0 : bSet_v2 = 1;
7093 : : }
7094 : : }
7095 : :
7096 : : /* Add st-cap to v1 and/or v2t */
7097 : 0 : iapc = 0;
7098 : : /* If cap=2 then just increment st_cap 2 times */
7099 [ # # ]: 0 : if (!bSet_v1)
7100 : : {
7101 : : /* Add st-cap to v1 */
7102 [ # # ]: 0 : if (( bDonors != 0 ) == ( v1t != NO_VERTEX ))
7103 : : {
7104 : 0 : return BNS_BOND_ERR;
7105 : : }
7106 : 0 : n = bAddStCapToAVertex( pBNS, v1Act, v2Act, apc->nOldCapsVert[iapc], nDots, bAdjacentDonors );
7107 : 0 : apc->bSetOldCapsVert[iapc] = n;
7108 : 0 : apc->vOldVert[iapc] = v1Act;
7109 : 0 : iapc++;
7110 : : }
7111 [ # # ]: 0 : if (!bSet_v2)
7112 : : {
7113 : : /* Add st-cap to v2t */
7114 [ # # ]: 0 : if (( bDonors != 0 ) == ( v2t != NO_VERTEX ))
7115 : : {
7116 : 0 : return BNS_BOND_ERR;
7117 : : }
7118 : 0 : n = bAddStCapToAVertex( pBNS, v2Act, v1Act, apc->nOldCapsVert[iapc], nDots, bAdjacentDonors );
7119 : 0 : apc->bSetOldCapsVert[iapc] = n;
7120 : 0 : apc->vOldVert[iapc] = v2Act;
7121 : 0 : iapc++;
7122 : : }
7123 [ # # # # ]: 0 : if (*nDots < 0 || *nDots % 2)
7124 : : {
7125 : 0 : return BNS_SET_ALTP_ERR;
7126 : : }
7127 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
7128 : : }
7129 : :
7130 [ - + ]: 16 : if (path_type == ALT_PATH_MODE_REM_PROTON)
7131 : : {
7132 : : /* added 2004-03-05 */
7133 [ # # # # ]: 0 : if (v1 >= 0 && v2 >= 0 &&
7134 [ # # ]: 0 : ( pVert1->type & BNS_VERT_TYPE_ANY_GROUP ) &&
7135 [ # # ]: 0 : ( pVert2->type & BNS_VERT_TYPE_ANY_GROUP ))
7136 : : {
7137 : : /* Create new edge and vertex, connect to v2 */
7138 [ # # ]: 0 : if (( pBNS->vert[v1].type & BNS_VERT_TYPE_C_GROUP ) &&
7139 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.flow == 2 * pBNS->vert[v1].num_adj_edges ))
7140 : : {
7141 : : /* so far in a charge group max edge flow = 1 2004-03-08 */
7142 : 0 : return BNS_CHK_ALTP_NO_ALTPATH;
7143 : : }
7144 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7145 : 0 : fcd[ifcd].iedge = NO_VERTEX;
7146 : 0 : *nDots = 0;
7147 : 0 : iapc = 0;
7148 : :
7149 : 0 : vNew = bAddNewVertex( pBNS, v2, 1, 0, 1, nDots );
7150 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7151 : : {
7152 : 0 : return vNew;
7153 : : }
7154 : 0 : apc->vNewVertex[iapc] = vNew;
7155 : 0 : apc->bSetNew[iapc] = 1;
7156 : : /*iapc ++;*/
7157 : : /* add st-cap (dot) to v1 */
7158 : 0 : n = bAddStCapToAVertex( pBNS, v1, v2, apc->nOldCapsVert[iapc], nDots, 0 );
7159 : 0 : apc->bSetOldCapsVert[iapc] = n;
7160 : 0 : apc->vOldVert[iapc] = v1;
7161 : 0 : iapc++;
7162 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
7163 : : }
7164 : : }
7165 : :
7166 : : #if ( NEUTRALIZE_ENDPOINTS == 1 ) /* { */
7167 : :
7168 : 16 : *nDots = 0;
7169 : 16 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7170 : 16 : fcd[ifcd].iedge = NO_VERTEX;
7171 : :
7172 [ + - ]: 16 : if (type & BNS_VERT_TYPE_ENDPOINT)
7173 : : {
7174 : : BNS_IEDGE iedge;
7175 : : AT_NUMB type2;
7176 : : int ret2;
7177 : : /* prohibit charge movement */
7178 : 16 : type2 = BNS_VERT_TYPE_C_GROUP;
7179 : 16 : iedge = GetEdgeToGroupVertex( pBNS, v1, type2 );
7180 [ - + ]: 16 : if (iedge != NO_VERTEX)
7181 : : {
7182 : : /* Set flow=1 on an edge to a c-group vertex to make sure
7183 : : there is no positive charge when moving tautomeric H-atoms */
7184 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 1, fcd + ifcd );
7185 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7186 : : {
7187 : 0 : return ret2;
7188 : : }
7189 : 0 : *nDots += ret2;
7190 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7191 : : {
7192 : 0 : ifcd++;
7193 : : }
7194 : : }
7195 : :
7196 : 16 : iedge = GetEdgeToGroupVertex( pBNS, v2, type2 );
7197 : :
7198 [ - + ]: 16 : if (iedge != NO_VERTEX)
7199 : : {
7200 : : /* Set flow=1 on an edge to a c-group vertex to make sure
7201 : : there is no positive charge when moving tautomeric H-atoms */
7202 : :
7203 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 1, fcd + ifcd );
7204 : :
7205 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7206 : : {
7207 : 0 : return ret2;
7208 : : }
7209 : 0 : *nDots += ret2;
7210 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7211 : : {
7212 : 0 : ifcd++;
7213 : : }
7214 : : }
7215 : :
7216 : : /* Set hydrogen counts */
7217 : 16 : type2 = BNS_VERT_TYPE_TGROUP;
7218 : 16 : iedge = GetEdgeToGroupVertex( pBNS, v1, type2 );
7219 [ - + ]: 16 : if (iedge != NO_VERTEX)
7220 : : {
7221 : : /* Set flow=1 on an edge to a t-group vertex to make sure there is
7222 : : a moveable hydrogen atom or (-) on v1 when moving tautomeric H-atoms */
7223 : : #if ( FIX_H_CHECKING_TAUT == 1 )
7224 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 1, fcd + ifcd );
7225 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7226 : : {
7227 : 0 : return ret2;
7228 : : }
7229 : 0 : *nDots += ret2;
7230 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7231 : : {
7232 : 0 : ifcd++;
7233 : : }
7234 : : #else
7235 : : t1 = pBNS->edge[iedge].neighbor12 ^ v1;
7236 : : #endif
7237 : : }
7238 : :
7239 : 16 : iedge = GetEdgeToGroupVertex( pBNS, v2, type2 );
7240 [ - + ]: 16 : if (iedge != NO_VERTEX)
7241 : : {
7242 : : /* Set flow=0 on an edge to a t-group vertex to make sure there is
7243 : : no moveable hydrogen atom or (-) on v2 when moving tautomeric H-atoms */
7244 : : #if ( FIX_H_CHECKING_TAUT == 1 )
7245 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 0, fcd + ifcd );
7246 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7247 : : {
7248 : 0 : return ret2;
7249 : : }
7250 : 0 : *nDots += ret2;
7251 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7252 : : {
7253 : 0 : ifcd++;
7254 : : }
7255 : : #else
7256 : : t2 = pBNS->edge[iedge].neighbor12 ^ v2;
7257 : : #endif
7258 : : }
7259 : :
7260 : : #if ( FIX_H_CHECKING_TAUT == 1 )
7261 : : #else
7262 : : if (t1 == t2 && t1 != NO_VERTEX)
7263 : : {
7264 : : return BNS_CHK_ALTP_SAME_TGROUP;
7265 : : }
7266 : : #endif
7267 : :
7268 : 16 : iapc = 0;
7269 : : /* Create new edge and vertex with cap=1 at v2 and/or t1 */
7270 [ - + ]: 16 : if (t1 != NO_VERTEX)
7271 : : {
7272 : : /* Create new edge and vertex, connect to t1 */
7273 : 0 : vNew = bAddNewVertex( pBNS, t1, 1/*cap*/, 0/*flow*/, 1/*max_adj_edges*/, nDots ); /* djb-rwth: addressing coverity ID #499581 -- condition works as expected for t1 == -2 */
7274 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7275 : : {
7276 : 0 : return vNew;
7277 : : }
7278 : 0 : apc->vNewVertex[iapc] = vNew;
7279 : 0 : apc->bSetNew[iapc] = 1;
7280 : 0 : iapc++;
7281 : : }
7282 [ + - ]: 16 : if (t2 == NO_VERTEX)
7283 : : {
7284 : : /* Create new edge and vertex, connect to v2 */
7285 : 16 : vNew = bAddNewVertex( pBNS, v2, 1/*cap*/, 0/*flow*/, 1/*max_adj_edges*/, nDots );
7286 [ + - - + ]: 16 : if (IS_BNS_ERROR( vNew ))
7287 : : {
7288 : 0 : return vNew;
7289 : : }
7290 : 16 : apc->vNewVertex[iapc] = vNew;
7291 : 16 : apc->bSetNew[iapc] = 1;
7292 : 16 : iapc++;
7293 : : }
7294 : :
7295 : : /* Add st-cap to v1 and/or v2t */
7296 : 16 : iapc = 0;
7297 [ + - ]: 16 : if (t1 == NO_VERTEX)
7298 : : {
7299 : : /* Add st-cap to v1 */
7300 [ + - ]: 16 : n = bAddStCapToAVertex(pBNS, v1, (Vertex)(t2 == NO_VERTEX ? v2 : t2), apc->nOldCapsVert[iapc], nDots, 0); /* djb-rwth: addressing coverity ID #499501 -- condition works as expected for t2 == -2 */
7301 : 16 : apc->bSetOldCapsVert[iapc] = n;
7302 : 16 : apc->vOldVert[iapc] = v1;
7303 : 16 : iapc++;
7304 : : }
7305 [ - + ]: 16 : if (t2 != NO_VERTEX)
7306 : : {
7307 : : /* Add st-cap to t2 */
7308 [ # # ]: 0 : n = bAddStCapToAVertex( pBNS, t2, (Vertex) ( t1 == NO_VERTEX ? v1 : t1 ), apc->nOldCapsVert[iapc], nDots, 0 );
7309 : 0 : apc->bSetOldCapsVert[iapc] = n;
7310 : 0 : apc->vOldVert[iapc] = t2;
7311 : 0 : iapc++;
7312 : : }
7313 : : }
7314 : : else
7315 : : {
7316 : : /* Create new edge and vertex, connect to v2 */
7317 : 0 : vNew = bAddNewVertex( pBNS, v2, 1 /* cap*/, 0 /* flow */, 1 /* max_adj_edges */, nDots );
7318 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7319 : : {
7320 : 0 : return vNew;
7321 : : }
7322 : 0 : apc->vNewVertex[0] = vNew;
7323 : 0 : apc->bSetNew[0] = 1;
7324 : :
7325 : : /* add st-cap to v1 */
7326 : 0 : n = bAddStCapToAVertex( pBNS, v1, v2, apc->nOldCapsVert[0], nDots, 0 );
7327 : 0 : apc->bSetOldCapsVert[0] = n;
7328 : 0 : apc->vOldVert[0] = v1;
7329 : : }
7330 : : #else /* } NEUTRALIZE_ENDPOINTS == 0 {*/
7331 : :
7332 : : *nDots = 0;
7333 : : memset( apc, 0, sizeof( *apc ) );
7334 : : fcd[ifcd].iedge = NO_VERTEX;
7335 : :
7336 : : /* Create new edge and vertex, connect to v2 */
7337 : : vNew = bAddNewVertex( pBNS, v2, 1 /* cap*/, 0 /* flow */, 1 /* max_adj_edges */, nDots, 0 );
7338 : : if (IS_BNS_ERROR( vNew ))
7339 : : {
7340 : : return vNew;
7341 : : }
7342 : : apc->vNewVertex[0] = vNew;
7343 : : apc->bSetNew[0] = 1;
7344 : :
7345 : : /* Add st-cap to v1 */
7346 : : n = bAddStCapToAVertex( pBNS, v1, v2, apc->nOldCapsVert[0], nDots );
7347 : : apc->bSetOldCapsVert[0] = n;
7348 : : apc->vOldVert[0] = v1;
7349 : : #endif /* } NEUTRALIZE_ENDPOINTS */
7350 : :
7351 [ + - - + ]: 16 : if (*nDots < 0 || *nDots % 2)
7352 : : {
7353 : 0 : return BNS_SET_ALTP_ERR;
7354 : : }
7355 : 16 : return BNS_CHK_ALTP_SET_SUCCESS;
7356 : : }
7357 : :
7358 : : /*return BNS_CHK_ALTP_NO_ALTPATH;*/
7359 : : }
7360 : :
7361 : :
7362 : : /****************************************************************************/
7363 : 16 : int bRestoreBnsAfterCheckAltPath( BN_STRUCT *pBNS,
7364 : : ALT_PATH_CHANGES *apc,
7365 : : int bChangeFlow )
7366 : : /* int nVertDoubleBond, int nVertSingleBond, int nNewVertex, AT_NUMB *nOldCapVertSingleBond */
7367 : : {
7368 : : BNS_EDGE *pEdge;
7369 : : Vertex vNew;
7370 : : Vertex vOld;
7371 : : BNS_VERTEX *pOldVert;
7372 : : BNS_VERTEX *pNewVert;
7373 : : int i, j, n; /* djb-rwth: removing redundant variables */
7374 : :
7375 : : /* djb-rwth: removing redundant code */
7376 : :
7377 [ - + ]: 16 : if (bChangeFlow & BNS_EF_UPD_H_CHARGE)
7378 : : {
7379 : : /* Remove new temp. vertices and edges connectong them to the structure */
7380 [ # # ]: 0 : for (i = sizeof( apc->bSetNew ) / sizeof( apc->bSetNew[0] ) - 1; 0 <= i; i--)
7381 : : {
7382 [ # # ]: 0 : if (apc->bSetNew[i])
7383 : : {
7384 : 0 : vNew = apc->vNewVertex[i];
7385 : 0 : pNewVert = pBNS->vert + vNew;
7386 [ # # ]: 0 : for (j = 0; j < pNewVert->num_adj_edges; j++)
7387 : : {
7388 : 0 : pEdge = pBNS->edge + pNewVert->iedge[j];
7389 : 0 : vOld = pEdge->neighbor12 ^ vNew;
7390 : 0 : pOldVert = pBNS->vert + vOld;
7391 : 0 : pOldVert->st_edge.flow -= pEdge->flow;
7392 : 0 : pOldVert->st_edge.cap -= pEdge->flow;
7393 : : /* disconnect new edge from pOldVert */
7394 : 0 : pOldVert->iedge[--pOldVert->num_adj_edges] = 0;
7395 : : /* clear the new edge */
7396 : 0 : memset( pEdge, 0, sizeof( *pEdge ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7397 : : /* and decrement the total number of edges */
7398 : 0 : pBNS->num_edges--;
7399 : : }
7400 : : /* Clear the new vertex */
7401 : 0 : memset( pNewVert, 0, sizeof( *pNewVert ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7402 : : /* and decrement the total number of vertices
7403 : : (new vertice ids are contiguous) */
7404 : 0 : pBNS->num_vertices--;
7405 : : /* djb-rwth: removing redundant code */
7406 : : }
7407 : : }
7408 : :
7409 : : /* Restore changed caps of old vertices */
7410 : 0 : for (i = sizeof( apc->bSetOldCapsVert ) / sizeof( apc->bSetOldCapsVert[0] ) - 1;
7411 [ # # ]: 0 : 0 <= i;
7412 : 0 : i--)
7413 : : {
7414 [ # # ]: 0 : if ((n = apc->bSetOldCapsVert[i])) /* djb-rwth: addressing LLVM warning */
7415 : : {
7416 : 0 : pOldVert = pBNS->vert + apc->vOldVert[i];
7417 [ # # ]: 0 : if (pOldVert->st_edge.flow <= apc->nOldCapsVert[i][0])
7418 : : {
7419 : 0 : pOldVert->st_edge.cap = apc->nOldCapsVert[i][0];
7420 : 0 : n--;
7421 : : /* djb-rwth: removing redundant code */
7422 [ # # # # ]: 0 : for (j = 0; j < n && j < pOldVert->num_adj_edges; j++)
7423 : : {
7424 : 0 : pEdge = pBNS->edge + pOldVert->iedge[j];
7425 : 0 : pEdge->cap = apc->nOldCapsVert[i][j + 1];
7426 : : }
7427 : : }
7428 : : }
7429 : : }
7430 : : }
7431 : : else
7432 : : {
7433 : : /* Restore changed caps of old vertices */
7434 [ + + ]: 48 : for (i = sizeof( apc->bSetOldCapsVert ) / sizeof( apc->bSetOldCapsVert[0] ) - 1; 0 <= i; i--)
7435 : : {
7436 [ + + ]: 32 : if ((n = apc->bSetOldCapsVert[i])) /* djb-rwth: addressing LLVM warning */
7437 : : {
7438 : 16 : pOldVert = pBNS->vert + apc->vOldVert[i];
7439 : 16 : pOldVert->st_edge.cap = apc->nOldCapsVert[i][0];
7440 : 16 : n--;
7441 : : /* djb-rwth: removing redundant code */
7442 [ + + + - ]: 32 : for (j = 0; j < n && j < pOldVert->num_adj_edges; j++)
7443 : : {
7444 : 16 : pEdge = pBNS->edge + pOldVert->iedge[j];
7445 : 16 : pEdge->cap = apc->nOldCapsVert[i][j + 1];
7446 : : }
7447 : : }
7448 : : }
7449 : :
7450 : : /* Remove new temp. vertices and edges connectong them to the structure */
7451 [ + + ]: 48 : for (i = sizeof( apc->bSetNew ) / sizeof( apc->bSetNew[0] ) - 1; 0 <= i; i--)
7452 : : {
7453 [ + + ]: 32 : if (apc->bSetNew[i])
7454 : : {
7455 : 16 : vNew = apc->vNewVertex[i];
7456 : 16 : pNewVert = pBNS->vert + vNew;
7457 [ + + ]: 32 : for (j = 0; j < pNewVert->num_adj_edges; j++)
7458 : : {
7459 : 16 : pEdge = pBNS->edge + pNewVert->iedge[j];
7460 : 16 : vOld = pEdge->neighbor12 ^ vNew;
7461 : 16 : pOldVert = pBNS->vert + vOld;
7462 : : /* disconnect new edge from pOldVert */
7463 : 16 : pOldVert->iedge[--pOldVert->num_adj_edges] = 0;
7464 : : /* clear the new edge */
7465 : 16 : memset( pEdge, 0, sizeof( *pEdge ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7466 : : /* and decrement the total number of edges */
7467 : 16 : pBNS->num_edges--;
7468 : : }
7469 : : /* Clear the new vertex */
7470 : 16 : memset( pNewVert, 0, sizeof( *pNewVert ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7471 : : /* and decrement the total number of vertices (new vertice ids are contiguous */
7472 : 16 : pBNS->num_vertices--;
7473 : : /* djb-rwth: removing redundant code */
7474 : : }
7475 : : }
7476 : : }
7477 : :
7478 : 16 : return 0;
7479 : : }
7480 : :
7481 : :
7482 : : /****************************************************************************/
7483 : 18 : int bExistsAnyAltPath( CANON_GLOBALS *pCG,
7484 : : BN_STRUCT *pBNS,
7485 : : BN_DATA *pBD,
7486 : : inp_ATOM *at,
7487 : : int num_atoms,
7488 : : int nVert2,
7489 : : int nVert1,
7490 : : int path_type )
7491 : : {
7492 : : int nRet1, nRet2;
7493 : :
7494 : 18 : nRet1 = bExistsAltPath( pCG, pBNS, pBD, NULL, at, num_atoms, nVert2, nVert1, path_type );
7495 : :
7496 [ + + ]: 18 : if (nRet1 > 0)
7497 : : {
7498 : 10 : return nRet1;
7499 : : }
7500 : :
7501 : 8 : nRet2 = bExistsAltPath( pCG, pBNS, pBD, NULL, at, num_atoms, nVert1, nVert2, path_type );
7502 : :
7503 [ + + ]: 8 : if (nRet2 > 0)
7504 : : {
7505 : 6 : return nRet2;
7506 : : }
7507 [ + - - + ]: 2 : if (IS_BNS_ERROR( nRet1 ))
7508 : : {
7509 : 0 : return nRet1;
7510 : : }
7511 [ + - - + ]: 2 : if (IS_BNS_ERROR( nRet2 ))
7512 : : {
7513 : 0 : return nRet2;
7514 : : }
7515 : :
7516 : 2 : return 0;
7517 : : }
7518 : :
7519 : :
7520 : : #define ALT_PATH_TAUTOM 1
7521 : : #define ALT_PATH_CHARGE 2
7522 : : #define ALT_PATH_4_SALT 3
7523 : :
7524 : :
7525 : : /****************************************************************************/
7526 : 0 : int bIsBnsEndpoint( BN_STRUCT *pBNS, int v )
7527 : : {
7528 : : int i, vt;
7529 : : BNS_VERTEX *pVert; /* vertices */
7530 : : BNS_EDGE *pEdge; /* edges */
7531 : :
7532 [ # # # # : 0 : if (0 <= v && v < pBNS->num_atoms && ( pVert = pBNS->vert + v ) && ( pVert->type & BNS_VERT_TYPE_ENDPOINT ))
# # # # ]
7533 : : {
7534 [ # # ]: 0 : for (i = pVert->num_adj_edges - 1; 0 <= i; i--)
7535 : : {
7536 : 0 : pEdge = pBNS->edge + pVert->iedge[i];
7537 : 0 : vt = pEdge->neighbor12 ^ v;
7538 [ # # ]: 0 : if (pBNS->vert[vt].type & BNS_VERT_TYPE_TGROUP)
7539 : : {
7540 : 0 : return !IS_FORBIDDEN( pEdge->forbidden, pBNS );
7541 : : }
7542 : : }
7543 : : }
7544 : :
7545 : 0 : return 0;
7546 : : }
7547 : :
7548 : :
7549 : : #if ( BNS_RAD_SEARCH == 1 )
7550 : :
7551 : :
7552 : : /****************************************************************************/
7553 : 0 : int bRadChangesAtomType( BN_STRUCT *pBNS,
7554 : : BN_DATA *pBD,
7555 : : Vertex v,
7556 : : Vertex v_1,
7557 : : Vertex v_2 )
7558 : : {
7559 : :
7560 : : EdgeIndex iuv;
7561 : : Vertex v_O, v_ChgOrH;
7562 : :
7563 : : /* The previous atom along the path: should be a terminal atom */
7564 [ # # ]: 0 : if (v_1 == NO_VERTEX)
7565 : : {
7566 : 0 : v_1 = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv );
7567 : : }
7568 : 0 : v_O = v_1 / 2 - 1;
7569 : :
7570 [ # # # # ]: 0 : if (v_O < 0 || v_O >= pBNS->num_atoms)
7571 : : {
7572 : 0 : return 0;
7573 : : }
7574 : :
7575 : : /* Make sure v_O is a terminal atom: its second neighbor is not an atom */
7576 [ # # ]: 0 : if (pBNS->vert[pBNS->edge[pBNS->vert[v_O].iedge[1]].neighbor12 ^ v_O].type & BNS_VERT_TYPE_ATOM)
7577 : : {
7578 : 0 : return 0;
7579 : : }
7580 : :
7581 : : /* The next to previous vertex vertex along the path: should be a Charge or Taut group vertex */
7582 [ # # ]: 0 : if (v_2 == NO_VERTEX)
7583 : : {
7584 : 0 : v_2 = GetPrevVertex( pBNS, v_1, pBD->SwitchEdge, &iuv );
7585 : : }
7586 : :
7587 : 0 : v_ChgOrH = v_2 / 2 - 1;
7588 [ # # ]: 0 : if (v_ChgOrH < pBNS->num_atoms)
7589 : : {
7590 : 0 : return 0;
7591 : : }
7592 : :
7593 : : /* Make sure v_ChgOrH is a charge or taut_group */
7594 [ # # ]: 0 : if (pBNS->vert[v_ChgOrH].type & ( BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP ))
7595 : : {
7596 : 0 : return 1;
7597 : : }
7598 : :
7599 : 0 : return 0;
7600 : : }
7601 : :
7602 : :
7603 : : /****************************************************************************/
7604 : 0 : int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u )
7605 : : {
7606 : : EdgeIndex iuv;
7607 : : int i, num_found;
7608 : : Vertex v, w;
7609 : : Vertex u_last, v2;
7610 [ # # # ]: 0 : switch (pBD->bRadSrchMode)
7611 : : {
7612 : 0 : case RAD_SRCH_NORM:
7613 : : /* Go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
7614 : : /* we need only vertices where a radical may be moved, therefore exclude u%2=1 (odd) vertices */
7615 : : /* atom number = u/2-1; u = 0 or 1 is 's' or 't' vertices, respectively, they are not atoms */
7616 : 0 : num_found = 0;
7617 [ # # # # : 0 : while (u > Vertex_t && ( u % 2 || u / 2 > pBNS->num_atoms ))
# # ]
7618 : : {
7619 : 0 : u = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
7620 : : }
7621 : 0 : w = u / 2 - 1; /* Check whether u is a radical endpoint */
7622 [ # # # # ]: 0 : if (Vertex_t < u && w < pBNS->num_atoms &&
7623 [ # # ]: 0 : pBNS->vert[w].st_edge.cap == ( pBNS->vert[w].st_edge.flow & EDGE_FLOW_ST_MASK ))
7624 : : {
7625 : : /* u is an atom; it is not a radical atom */
7626 : : /* now search for the starting radical atom by following the path back from u */
7627 : 0 : v = u_last = u;
7628 [ # # ]: 0 : while (v > Vertex_t)
7629 : : {
7630 : 0 : u = v;
7631 : 0 : v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv ); /* Radical endpoint */
7632 : : }
7633 : : /* Check whether u is a radical atom */
7634 [ # # # # ]: 0 : if (!( u % 2 ) && Vertex_t < u &&
7635 [ # # ]: 0 : ( u = u / 2 - 1 ) < pBNS->num_atoms &&
7636 [ # # ]: 0 : pBNS->vert[u].st_edge.cap > ( pBNS->vert[u].st_edge.flow & EDGE_FLOW_ST_MASK ))
7637 : : {
7638 : : /* at pBNS->vert[u] we have found the radical that originated the path */
7639 : : /* pBD->RadEndpoints[2k] is the radical, pBD->RadEndpoints[2k+1] is the farthest atom */
7640 : : /* to which the radical may be moved (farthest reachable atom) */
7641 : :
7642 : : /* add *all* atoms that may receive radical from u_rad */
7643 : : /* exception: at2 in: ==(+/-/H)---at1==at2(possible rad endpoint) if pBNS->type_TACN */
7644 [ # # ]: 0 : for (v = u_last; v > Vertex_t; v = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv ))
7645 : : {
7646 [ # # # # ]: 0 : if (!( v % 2 ) && ( v2 = v / 2 - 1 ) < pBNS->num_atoms &&
7647 [ # # ]: 0 : pBNS->vert[v2].st_edge.cap == ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ))
7648 : : {
7649 : : /* Check exception */
7650 [ # # # # ]: 0 : if (pBNS->type_TACN &&
7651 : 0 : bRadChangesAtomType( pBNS, pBD, v, NO_VERTEX, NO_VERTEX ))
7652 : : {
7653 : 0 : continue;
7654 : : }
7655 : : /* Add */
7656 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i += 2)
7657 : : {
7658 : : /* Check whether this pair, (u,w), has already been saved */
7659 [ # # ]: 0 : if (u == pBD->RadEndpoints[i] &&
7660 [ # # ]: 0 : v2 == pBD->RadEndpoints[i + 1])
7661 : : {
7662 : 0 : break;
7663 : : }
7664 : : }
7665 [ # # ]: 0 : if (i >= pBD->nNumRadEndpoints)
7666 : : {
7667 : : /* Add new (u,w) pair */
7668 [ # # ]: 0 : if (pBD->nNumRadEndpoints + 2 <= pBD->max_num_vertices)
7669 : : {
7670 : : /* add */
7671 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = u; /* radical */
7672 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = v2; /* endpoint */
7673 : 0 : num_found++;
7674 : : /*return 1;*/ /* registered */
7675 : : }
7676 : : else
7677 : : {
7678 : 0 : return BNS_VERT_EDGE_OVFL;
7679 : : }
7680 : : }
7681 : : }
7682 : : }
7683 [ # # ]: 0 : if (num_found)
7684 : : {
7685 : 0 : return 1;
7686 : : }
7687 : : }
7688 : : }
7689 : 0 : break;
7690 : :
7691 : 0 : case RAD_SRCH_FROM_FICT:
7692 : : /* Find the nearest atom accessible from a fictitious vertex */
7693 : : /* go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
7694 : :
7695 : 0 : v = u;
7696 : 0 : w = NO_VERTEX; /* the nearest atom -- radical-endpoint */
7697 : 0 : u = NO_VERTEX; /* fictitious vertex carrying a radical */
7698 : :
7699 [ # # ]: 0 : while (v > Vertex_t)
7700 : : {
7701 : 0 : u = v;
7702 [ # # # # ]: 0 : if (!( v % 2 ) && v / 2 <= pBNS->num_atoms &&
7703 [ # # ]: 0 : pBNS->vert[v / 2 - 1].st_edge.cap - pBNS->vert[v / 2 - 1].st_edge.flow < 2)
7704 : : {
7705 : 0 : w = v; /* vertex w is atom that may be singlet or doublet but not triplet */
7706 : : }
7707 : 0 : v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
7708 : : }
7709 : 0 : v = u / 2 - 1; /* vertex u may be the radical from which the path originated; w is the nearest atom */
7710 [ # # # # : 0 : if (w == NO_VERTEX || u == NO_VERTEX || w % 2 || u == w || v < pBNS->num_atoms ||
# # # # #
# ]
7711 [ # # ]: 0 : pBNS->vert[v].st_edge.cap == pBNS->vert[v].st_edge.flow ||
7712 [ # # ]: 0 : ( w = w / 2 - 1 ) >= pBNS->num_atoms)
7713 : : {
7714 : : break; /* reject */
7715 : : }
7716 : 0 : u = v;
7717 : : /* At pBNS->vert[u] we have found the radical that originated the path, w is the nearest atom */
7718 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i += 2)
7719 : : {
7720 [ # # ]: 0 : if (u == pBD->RadEndpoints[i] &&
7721 [ # # ]: 0 : w == pBD->RadEndpoints[i + 1])
7722 : : {
7723 : 0 : break; /* this pair has already been stored */
7724 : : }
7725 : : }
7726 [ # # ]: 0 : if (i >= pBD->nNumRadEndpoints)
7727 : : {
7728 : : /* A new pair has been found */
7729 [ # # ]: 0 : if (pBD->nNumRadEndpoints + 2 <= pBD->max_num_vertices)
7730 : : {
7731 : : /* Add */
7732 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = u; /* radical */
7733 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = w; /* endpoint */
7734 : 0 : return 1; /* registered */
7735 : : }
7736 : : else
7737 : : {
7738 : 0 : return BNS_VERT_EDGE_OVFL;
7739 : : }
7740 : : }
7741 : 0 : break;
7742 : : }
7743 : :
7744 : 0 : return 0; /* rejected */
7745 : : }
7746 : :
7747 : :
7748 : : /****************************************************************************/
7749 : 0 : int cmp_rad_endpoints( const void *a1, const void *a2 )
7750 : : {
7751 : : /* Vertex radical_vertex, radical_endpoint */
7752 : 0 : const Vertex *p1 = (const Vertex *) a1;
7753 : 0 : const Vertex *p2 = (const Vertex *) a2;
7754 : :
7755 [ # # ]: 0 : if (p1[0] < p2[0])
7756 : : {
7757 : 0 : return -1;
7758 : : }
7759 [ # # ]: 0 : if (p1[0] > p2[0])
7760 : : {
7761 : 0 : return 1;
7762 : : }
7763 [ # # ]: 0 : if (p1[1] < p2[1])
7764 : : {
7765 : 0 : return -1;
7766 : : }
7767 [ # # ]: 0 : if (p1[1] > p2[1])
7768 : : {
7769 : 0 : return 1;
7770 : : }
7771 : :
7772 : 0 : return 0;
7773 : : }
7774 : :
7775 : :
7776 : : /****************************************************************************/
7777 : 16 : int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
7778 : : {
7779 : : BNS_EDGE *e;
7780 : : EdgeIndex ie;
7781 : : BNS_VERTEX *p1, *p2;
7782 : : Vertex v1, v2;
7783 : : int i, delta, rad;
7784 : :
7785 [ - + ]: 16 : for (i = pBD->nNumRadEdges - 1; 0 <= i; i--)
7786 : : {
7787 : 0 : ie = pBD->RadEdges[i];
7788 [ # # # # ]: 0 : if (ie < 0 || ie >= pBNS->num_edges)
7789 : : {
7790 : 0 : goto error_exit;
7791 : : }
7792 : 0 : e = pBNS->edge + ie;
7793 : 0 : v1 = e->neighbor1;
7794 : 0 : v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
7795 [ # # # # ]: 0 : if (ie + 1 != pBNS->num_edges ||
7796 [ # # # # ]: 0 : v1 < 0 || v1 >= pBNS->num_vertices ||
7797 [ # # ]: 0 : v2 < 0 || v2 >= pBNS->num_vertices)
7798 : : {
7799 : 0 : goto error_exit;
7800 : : }
7801 : 0 : p1 = pBNS->vert + v1;
7802 : 0 : p2 = pBNS->vert + v2;
7803 : :
7804 [ # # ]: 0 : if (p2->iedge[p2->num_adj_edges - 1] != ie ||
7805 [ # # ]: 0 : p1->iedge[p1->num_adj_edges - 1] != ie)
7806 : : {
7807 : 0 : goto error_exit;
7808 : : }
7809 : :
7810 : 0 : p2->num_adj_edges--;
7811 : 0 : p1->num_adj_edges--;
7812 : 0 : p2->iedge[p2->num_adj_edges] = 0;
7813 : 0 : p1->iedge[p1->num_adj_edges] = 0;
7814 : 0 : p2->st_edge.flow -= e->flow;
7815 : 0 : p1->st_edge.flow -= e->flow;
7816 : :
7817 [ # # # # ]: 0 : if (!p2->num_adj_edges && v2 >= pBNS->num_atoms)
7818 : : {
7819 [ # # ]: 0 : if (v2 + 1 != pBNS->num_vertices)
7820 : : {
7821 : 0 : goto error_exit;
7822 : : }
7823 : 0 : memset( p2, 0, sizeof( *p2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7824 : 0 : pBNS->num_vertices--;
7825 : : }
7826 : :
7827 [ # # # # ]: 0 : if (!p1->num_adj_edges && v1 >= pBNS->num_atoms)
7828 : : {
7829 [ # # ]: 0 : if (v1 + 1 != pBNS->num_vertices)
7830 : : {
7831 : 0 : goto error_exit;
7832 : : }
7833 : 0 : memset( p1, 0, sizeof( *p1 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7834 : 0 : pBNS->num_vertices--;
7835 : : }
7836 : :
7837 [ # # # # ]: 0 : if (at && v1 < pBNS->num_atoms)
7838 : : {
7839 : 0 : delta = p1->st_edge.cap - p1->st_edge.flow;
7840 : 0 : rad = at[v1].radical;
7841 [ # # # ]: 0 : switch (delta)
7842 : : {
7843 : 0 : case 0:
7844 [ # # ]: 0 : if (rad == RADICAL_DOUBLET)
7845 : : {
7846 : 0 : rad = 0;
7847 : : }
7848 : 0 : break;
7849 : 0 : case 1:
7850 [ # # ]: 0 : if (rad != RADICAL_DOUBLET)
7851 : : {
7852 : 0 : rad = RADICAL_DOUBLET;
7853 : : }
7854 : : }
7855 : 0 : at[v1].radical = rad;
7856 : : }
7857 : 0 : memset( e, 0, sizeof( *e ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7858 : 0 : pBNS->num_edges--;
7859 : : }
7860 : 16 : pBD->nNumRadEdges = 0;
7861 : 16 : pBD->nNumRadicals = 0;
7862 : 16 : pBD->bRadSrchMode = RAD_SRCH_NORM;
7863 : 16 : return 0;
7864 : :
7865 : 0 : error_exit:
7866 : :
7867 : 0 : return BNS_PROGRAM_ERR;
7868 : : }
7869 : :
7870 : :
7871 : : /****************************************************************************/
7872 : 0 : int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
7873 : : {
7874 : : BNS_EDGE *e;
7875 : : EdgeIndex ie;
7876 : : BNS_VERTEX *p1, *p2;
7877 : : Vertex v1, v2;
7878 : : int i, delta, rad;
7879 : : int p1_num_adj_edges, p2_num_adj_edges;
7880 : :
7881 [ # # ]: 0 : for (i = pBD->nNumRadEdges - 1; 0 <= i; i--)
7882 : : {
7883 : 0 : ie = pBD->RadEdges[i];
7884 [ # # # # ]: 0 : if (ie < 0 || ie >= pBNS->num_edges)
7885 : : {
7886 : 0 : goto error_exit;
7887 : : }
7888 : 0 : e = pBNS->edge + ie;
7889 : 0 : v1 = e->neighbor1; /* atom */
7890 : 0 : v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
7891 [ # # # # ]: 0 : if (v1 < 0 || v1 >= pBNS->num_atoms ||
7892 [ # # # # ]: 0 : v2 < pBNS->num_atoms || v2 >= pBNS->num_vertices)
7893 : : {
7894 : 0 : goto error_exit;
7895 : : }
7896 : 0 : p1 = pBNS->vert + v1;
7897 : 0 : p2 = pBNS->vert + v2;
7898 : :
7899 : 0 : p1_num_adj_edges = e->neigh_ord[0];
7900 : 0 : p2_num_adj_edges = e->neigh_ord[1];
7901 : :
7902 [ # # ]: 0 : if (p2->iedge[p2_num_adj_edges] != ie ||
7903 [ # # ]: 0 : p1->iedge[p1_num_adj_edges] != ie)
7904 : : {
7905 : 0 : goto error_exit;
7906 : : }
7907 : :
7908 [ # # # # ]: 0 : if (at && v1 < pBNS->num_atoms)
7909 : : {
7910 : 0 : delta = p1->st_edge.cap - p1->st_edge.flow + e->flow;
7911 : 0 : rad = at[v1].radical;
7912 [ # # # ]: 0 : switch (delta)
7913 : : {
7914 : 0 : case 0:
7915 [ # # ]: 0 : if (rad == RADICAL_DOUBLET)
7916 : 0 : rad = 0;
7917 : 0 : break;
7918 : 0 : case 1:
7919 [ # # ]: 0 : if (rad != RADICAL_DOUBLET)
7920 : 0 : rad = RADICAL_DOUBLET;
7921 : : }
7922 : 0 : at[v1].radical = rad;
7923 : : }
7924 : : }
7925 : 0 : return 0;
7926 : :
7927 : 0 : error_exit:
7928 : :
7929 : 0 : return BNS_PROGRAM_ERR;
7930 : : }
7931 : :
7932 : :
7933 : : /****************************************************************************/
7934 : 0 : int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
7935 : : {
7936 : : int ret, i, j, k, delta; /* djb-rwth: removing redundant variables */
7937 : : BNS_VERTEX *pRad, *pEndp;
7938 : : Vertex wRad, vRad, vEndp, nNumRadicals;
7939 : 0 : int nDots = 0 /* added initialization, 2006-03 */, nNumEdges;
7940 : :
7941 [ # # ]: 0 : if (pBNS->tot_st_cap <= pBNS->tot_st_flow)
7942 : : {
7943 : 0 : return 0;
7944 : : }
7945 : :
7946 : 0 : pBD->nNumRadEndpoints = 0;
7947 : 0 : pBD->nNumRadEdges = 0;
7948 : 0 : pBD->bRadSrchMode = bRadSrchMode;
7949 : 0 : pBNS->alt_path = pBNS->altp[0];
7950 : 0 : pBNS->bChangeFlow = 0;
7951 : 0 : ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH );
7952 : 0 : ReInitBnData( pBD );
7953 : 0 : ReInitBnStructAltPaths( pBNS );
7954 [ # # # # ]: 0 : if (!ret && pBD->nNumRadEndpoints >= 2)
7955 : : {
7956 : : /* Sort by radical locations */
7957 : 0 : qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints / 2, 2 * sizeof( pBD->RadEndpoints[0] ), cmp_rad_endpoints );
7958 : : /* djb-rwth: removing redundant code */
7959 : 0 : nNumRadicals = 0;
7960 : :
7961 : : /* Create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1 */
7962 : : /* connecting the new vertices radical vertices */
7963 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
7964 : : {
7965 : 0 : wRad = pBD->RadEndpoints[i];
7966 : 0 : pRad = pBNS->vert + wRad;
7967 : 0 : delta = pRad->st_edge.cap - ( pRad->st_edge.flow & EDGE_FLOW_ST_MASK );
7968 [ # # ]: 0 : if (delta <= 0)
7969 : : {
7970 : 0 : delta = 1;
7971 : : }
7972 : 0 : nNumEdges = 0;
7973 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j]; j += 2)
7974 : : {
7975 : 0 : nNumEdges++;
7976 : : }
7977 : : /* Add new aux vertex to the radical atom/vertex */
7978 : 0 : vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges + 1, &nDots );
7979 [ # # # # ]: 0 : if (IS_BNS_ERROR( vRad ))
7980 : : {
7981 : 0 : ret = vRad;
7982 : 0 : goto error_exit;
7983 : : }
7984 : 0 : pRad = pBNS->vert + vRad;
7985 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = pRad->iedge[pRad->num_adj_edges - 1];
7986 : : /* Replace references to vertex wRad with vRad */
7987 [ # # ]: 0 : for (k = i, nNumEdges = 0; k < j; k += 2) /* djb-rwth: ignoring LLVM warning: variable used */
7988 : : {
7989 : 0 : pBD->RadEndpoints[k] = vRad;
7990 : : }
7991 : 0 : nNumRadicals++;
7992 : : }
7993 : : /* All vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
7994 : : /* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
7995 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
7996 : : {
7997 : 0 : vRad = pBD->RadEndpoints[i];
7998 : 0 : pRad = pBNS->vert + vRad;
7999 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j]; j += 2)
8000 : : {
8001 : : /* Connect vew vertex pRad to radical endpoints */
8002 : 0 : vEndp = pBD->RadEndpoints[j + 1];
8003 : 0 : pEndp = pBNS->vert + vEndp;
8004 : 0 : ret = AddNewEdge( pRad, pEndp, pBNS, 1, 0 );
8005 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8006 : : {
8007 : 0 : goto error_exit;
8008 : : }
8009 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = ret;
8010 : : }
8011 : : }
8012 : 0 : pBD->nNumRadicals = nNumRadicals;
8013 : 0 : return nNumRadicals; /* done */
8014 : : }
8015 : :
8016 : 0 : return 0; /* nothing to do */
8017 : :
8018 : 0 : error_exit:
8019 : 0 : RemoveRadEndpoints( pBNS, pBD, NULL );
8020 : :
8021 : 0 : return ret;
8022 : : }
8023 : :
8024 : :
8025 : : #define MAX_NUM_RAD 256
8026 : :
8027 : :
8028 : : /****************************************************************************/
8029 : 16 : int SetRadEndpoints2( CANON_GLOBALS *pCG,
8030 : : BN_STRUCT *pBNS,
8031 : : BN_DATA *pBD,
8032 : : BRS_MODE bRadSrchMode )
8033 : : {
8034 : 16 : int ret = 0, i, j, k, n, delta = 1; /* djb-rwth: removing redundant variables */
8035 : : BNS_VERTEX *pRad, *pEndp;
8036 : : Vertex wRad, vRad, vEndp, nNumRadicals;
8037 : : Vertex vRadList[MAX_NUM_RAD], vRadEqul[MAX_NUM_RAD];
8038 : 16 : int nNumRad = 0;
8039 : : int edge_flow;
8040 : 16 : int nDots = 0 /* added initialization, 2006-03 */, nNumEdges;
8041 : : NodeSet VertSet;
8042 : :
8043 [ + - ]: 16 : if (pBNS->tot_st_cap <= pBNS->tot_st_flow)
8044 : : {
8045 : 16 : return 0;
8046 : : }
8047 : :
8048 : : /* Find all radicals: their vertices have st_cap-st_flow=delta */
8049 : : /* save radical atom numbers in vRadList[] and remove radical by making st_cap=st_flow */
8050 [ # # ]: 0 : for (i = 0; i < pBNS->num_atoms; i++)
8051 : : {
8052 [ # # ]: 0 : if (pBNS->vert[i].st_edge.cap - delta == ( pBNS->vert[i].st_edge.flow & EDGE_FLOW_ST_MASK ))
8053 : : {
8054 [ # # ]: 0 : if (nNumRad < MAX_NUM_RAD)
8055 : : {
8056 : 0 : pBNS->vert[i].st_edge.cap -= delta;
8057 : 0 : pBNS->tot_st_cap -= delta;
8058 : 0 : vRadList[nNumRad] = i; /* radical position; i > j <=> vRadList[i] > vRadList[j] */
8059 : 0 : vRadEqul[nNumRad] = nNumRad; /* the smallest radical atom that has reachable
8060 : : * atoms in common with this radical atom
8061 : : * always keep vRadEqul[nNumRad] <= nNumRad */
8062 : 0 : nNumRad++;
8063 : : }
8064 : : }
8065 : : }
8066 : :
8067 [ # # ]: 0 : if (pBNS->tot_st_cap - pBNS->tot_st_flow > nNumRad)
8068 : : {
8069 : 0 : return BNS_CAP_FLOW_ERR; /* extra st_cap on non-atoms or program error */
8070 : : }
8071 : :
8072 : 0 : memset( &VertSet, 0, sizeof( VertSet ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8073 : :
8074 : : /* Find reachable atoms by enabling each radical separately */
8075 [ # # ]: 0 : for (j = 0; j < nNumRad; j++)
8076 : : {
8077 : 0 : i = vRadList[j];
8078 : 0 : pBD->nNumRadEndpoints = 0;
8079 : 0 : pBD->nNumRadEdges = 0;
8080 : 0 : pBD->bRadSrchMode = bRadSrchMode;
8081 : 0 : pBNS->alt_path = pBNS->altp[0];
8082 : 0 : pBNS->bChangeFlow = 0;
8083 : 0 : pBNS->vert[i].st_edge.cap += delta; /* enable single radical */
8084 : 0 : pBNS->tot_st_cap += delta;
8085 : 0 : ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH ); /* find reachable atoms */
8086 : 0 : ReInitBnData( pBD );
8087 : 0 : ReInitBnStructAltPaths( pBNS );
8088 : 0 : pBD->bRadSrchMode = RAD_SRCH_NORM;
8089 : 0 : pBNS->vert[i].st_edge.cap -= delta; /* disable single radical */
8090 : 0 : pBNS->tot_st_cap -= delta;
8091 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8092 : : {
8093 : 0 : goto error_exit;
8094 : : }
8095 : : else
8096 : : {
8097 [ # # ]: 0 : if (ret)
8098 : : {
8099 : 0 : ret = BNS_RADICAL_ERR; /* found augmenting path: should not happen since only one radical was enabled */
8100 : 0 : goto error_exit;
8101 : : }
8102 : : }
8103 [ # # # # ]: 0 : if (!ret && pBD->nNumRadEndpoints >= 2)
8104 : : {
8105 : : /* Sort by: primary_key=radical locations, secondary_key=radical endoint */
8106 : :
8107 : 0 : qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints / 2, 2 * sizeof( pBD->RadEndpoints[0] ), cmp_rad_endpoints );
8108 : :
8109 [ # # # # ]: 0 : if (pBD->RadEndpoints[0] != i || pBD->RadEndpoints[pBD->nNumRadEndpoints - 2] != i)
8110 : : {
8111 : 0 : ret = BNS_RADICAL_ERR; /* more than one radical vertex */
8112 : 0 : goto error_exit;
8113 : : }
8114 [ # # ]: 0 : if (nNumRad > 1)
8115 : : {
8116 : : /* If more than one radical then save reachable atoms in bitmaps to allow */
8117 : : /* faster finding whether same atoms are reachable by two or more radicals */
8118 : : /* Later merge such sets */
8119 [ # # ]: 0 : if (NULL == VertSet.bitword)
8120 : : {
8121 : 0 : SetBitCreate( pCG );
8122 [ # # ]: 0 : if (!NodeSetCreate( pCG, &VertSet, pBNS->num_atoms, nNumRad ))
8123 : : {
8124 : 0 : ret = BNS_OUT_OF_RAM; /* out of RAM */
8125 : 0 : goto error_exit;
8126 : : }
8127 : : }
8128 : :
8129 : 0 : NodeSetFromRadEndpoints( pCG, &VertSet, j, pBD->RadEndpoints, pBD->nNumRadEndpoints );
8130 : :
8131 : : /* Do not allow any radical center be treated as a reachable atom: */
8132 : :
8133 : 0 : RemoveFromNodeSet( pCG, &VertSet, j, vRadList, nNumRad );
8134 : : }
8135 : : }
8136 : : }
8137 : :
8138 : : /* Restore radical st_cap so that st_cap-st_flow=delta */
8139 [ # # ]: 0 : for (j = 0; j < nNumRad; j++)
8140 : : {
8141 : 0 : i = vRadList[j];
8142 : 0 : pBNS->vert[i].st_edge.cap += delta;
8143 : 0 : pBNS->tot_st_cap += delta;
8144 : : }
8145 : :
8146 : : /* Merge lists that have common radical endpoints */
8147 : : /* defect: if vertex sets i and j do not intersect they will be compared 2 times */
8148 : : /* total up to nNumRad*(nNumRad-1)/2 calls to DoNodeSetsIntersect() */
8149 [ # # ]: 0 : if (nNumRad > 1)
8150 : : {
8151 [ # # ]: 0 : for (i = 0; i < nNumRad; i++)
8152 : : {
8153 [ # # ]: 0 : if (vRadEqul[i] != i)
8154 : : {
8155 : 0 : continue;
8156 : : }
8157 : : do
8158 : : {
8159 : 0 : n = 0;
8160 [ # # ]: 0 : for (j = i + 1; j < nNumRad; j++)
8161 : : {
8162 [ # # ]: 0 : if (vRadEqul[j] != j)
8163 : : {
8164 : 0 : continue;
8165 : : }
8166 [ # # ]: 0 : if (DoNodeSetsIntersect( &VertSet, i, j ))
8167 : : {
8168 : 0 : AddNodeSet2ToNodeSet1( &VertSet, i, j );
8169 : 0 : vRadEqul[j] = i; /* Set j was copied to set i; i < j */
8170 : 0 : n++;
8171 : : }
8172 : : }
8173 [ # # ]: 0 : } while (n);
8174 : : }
8175 : : /* Fill out pBD->RadEndpoints[] */
8176 [ # # ]: 0 : for (i = 0, n = 0; i < nNumRad; i++)
8177 : : {
8178 [ # # ]: 0 : if (i == vRadEqul[i])
8179 : : {
8180 [ # # ]: 0 : if (!IsNodeSetEmpty( &VertSet, i ))
8181 : : {
8182 : : /* Store equivalent radicals */
8183 [ # # ]: 0 : for (j = i + 1; j < nNumRad; j++)
8184 : : {
8185 [ # # ]: 0 : if (i == vRadEqul[j])
8186 : : {
8187 : 0 : pBD->RadEndpoints[n++] = vRadList[i];
8188 : 0 : pBD->RadEndpoints[n++] = -vRadList[j] - 2; /* equivalent radical, alvays not zero */
8189 : : }
8190 : : }
8191 : : /* Store endpoints */
8192 : 0 : n = AddNodesToRadEndpoints( pCG, &VertSet, i, pBD->RadEndpoints, vRadList[i], n, pBD->max_len_Pu_Pv );
8193 [ # # ]: 0 : if (n < 0)
8194 : : {
8195 : 0 : ret = BNS_RADICAL_ERR; /* pBD->RadEndpoints overflow */
8196 : 0 : goto error_exit;
8197 : : }
8198 : : }
8199 : : else
8200 : : {
8201 : 0 : pBD->RadEndpoints[n++] = vRadList[i];
8202 : 0 : pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
8203 : : }
8204 : : }
8205 : : }
8206 : 0 : pBD->nNumRadEndpoints = n;
8207 : 0 : NodeSetFree( pCG, &VertSet );
8208 : : }
8209 : : else
8210 : : {
8211 [ # # # # ]: 0 : if (nNumRad == 1 && !pBD->nNumRadEndpoints)
8212 : : {
8213 : : /* 2006-07-30: a single radical; no possible endpoint found */
8214 [ # # ]: 0 : for (i = 0, n = 0; i < nNumRad; i++)
8215 : : {
8216 : 0 : pBD->RadEndpoints[n++] = vRadList[i];
8217 : 0 : pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
8218 : : }
8219 : 0 : pBD->nNumRadEndpoints = n;
8220 : : }
8221 : : }
8222 : :
8223 [ # # # # ]: 0 : if (!ret && pBD->nNumRadEndpoints >= 2)
8224 : : {
8225 : : /* Already sorted by radical locations */
8226 : : /* djb-rwth: removing redundant code */
8227 : 0 : nNumRadicals = 0;
8228 : : /**************************************************************************
8229 : : * Create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1
8230 : : * connecting the new vertices radical vertices
8231 : : *
8232 : : *
8233 : : * Original structure: atom A is a radical center A==B--C*--D==E
8234 : : * A*--B==C--D==E atoms C and E are reachable: A==B--C===D--E*
8235 : : *
8236 : : * Resultant temporary structure:
8237 : : * A---B==C--D==E
8238 : : * || / /
8239 : : * || / / The additional new vertex (*) and its
8240 : : * || / / 3 edges replace the radical with alternating
8241 : : * || / / circuits that allow same bond changes
8242 : : * || / / as moving the radical to atoms C or E.
8243 : : * ||// "Double bonds" here have edge cap=1, flow=1
8244 : : * (*) "Single bonds" have edge cap=1, flow=0
8245 : : *
8246 : : * The "equivalent radical centers" (which have at least one reachable atom
8247 : : * in common) are connected to (*) with "double bonds" (edge cap=1, flow=1).
8248 : : * Reachable non-radical atoms are connected by edges with cap=1, flow=0
8249 : : * After running BNS to find alt.path a "double bond" from (*) may move
8250 : : * to another atom thus muving the radical.
8251 : : *
8252 : : * Number of additional (*) vertices = number of sets of
8253 : : * "equivalent radical centers".
8254 : : * Each such a set may include one or more radical centers.
8255 : : *
8256 : : * The radicals will be re-created in RemoveRadEndpoints()
8257 : : ***************************************************************************/
8258 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
8259 : : {
8260 : 0 : wRad = pBD->RadEndpoints[i];
8261 : 0 : pRad = pBNS->vert + wRad;
8262 : 0 : delta = pRad->st_edge.cap - ( pRad->st_edge.flow & EDGE_FLOW_ST_MASK );
8263 [ # # ]: 0 : if (delta <= 0)
8264 : : {
8265 : 0 : delta = 1;
8266 : : }
8267 : 0 : nNumEdges = 0;
8268 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j]; j += 2)
8269 : : {
8270 : 0 : nNumEdges += ( pBD->RadEndpoints[j + 1] != -1 ); /* immobile radicals have one edge only */
8271 : : }
8272 : : /* Add new aux vertex to the radical atom/vertex making st_cap-st_flow=0 */
8273 : : /* in case of immobile radical there will be no additional eddges since nNumEdges=0 */
8274 : 0 : vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges + 1, &nDots );
8275 [ # # # # ]: 0 : if (IS_BNS_ERROR( vRad ))
8276 : : {
8277 : 0 : ret = vRad;
8278 : 0 : goto error_exit;
8279 : : }
8280 : 0 : pRad = pBNS->vert + vRad;
8281 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = pRad->iedge[pRad->num_adj_edges - 1];
8282 : : /* replace references to vertex wRad with vRad */
8283 [ # # ]: 0 : for (k = i, nNumEdges = 0; k < j; k += 2) /* djb-rwth: ignoring LLVM warning: variable used */
8284 : : {
8285 : 0 : pBD->RadEndpoints[k] = vRad;
8286 : : }
8287 : 0 : nNumRadicals++;
8288 : : }
8289 : : /* All vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
8290 : : /* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
8291 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
8292 : : {
8293 : 0 : vRad = pBD->RadEndpoints[i];
8294 : 0 : pRad = pBNS->vert + vRad;
8295 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j]; j += 2)
8296 : : {
8297 : : /* connect vew vertex pRad to radical endpoints */
8298 : 0 : vEndp = pBD->RadEndpoints[j + 1];
8299 [ # # ]: 0 : if (vEndp == -1)
8300 : 0 : continue;
8301 [ # # ]: 0 : if (vEndp < 0)
8302 : : {
8303 : 0 : edge_flow = 1;
8304 : 0 : vEndp = -vEndp - 2; /* equivalent radical centers */
8305 : : }
8306 : : else
8307 : : {
8308 : 0 : edge_flow = 0;
8309 : : }
8310 : 0 : pEndp = pBNS->vert + vEndp;
8311 : 0 : ret = AddNewEdge( pRad, pEndp, pBNS, 1, edge_flow );
8312 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8313 : : {
8314 : 0 : goto error_exit;
8315 : : }
8316 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = ret;
8317 : : }
8318 : : }
8319 : 0 : pBD->nNumRadicals = nNumRadicals;
8320 : 0 : return nNumRadicals; /* done */
8321 : : }
8322 : 0 : return 0; /* nothing to do */
8323 : :
8324 : 0 : error_exit:
8325 : 0 : RemoveRadEndpoints( pBNS, pBD, NULL );
8326 : 0 : NodeSetFree( pCG, &VertSet );
8327 : :
8328 : 0 : return ret;
8329 : : }
8330 : :
8331 : :
8332 : : #else
8333 : : /****************************************************************************/
8334 : : int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
8335 : : {
8336 : : return 0;
8337 : : }
8338 : : int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
8339 : : {
8340 : : return 0;
8341 : : }
8342 : : int SetRadEndpoints2( CANON_GLOBALS *pCG, BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
8343 : : {
8344 : : return 0;
8345 : : }
8346 : : #endif
8347 : :
8348 : :
8349 : : /****************************************************************************
8350 : : bExistsAltPath( ... )
8351 : :
8352 : : Return value ret bits if not IS_BNS_ERROR(ret):
8353 : :
8354 : : ret & 1 => Success
8355 : : ret & 2 => Bonds changed to Alt
8356 : : (ret & ~3) >> 2 => nDelta: number of removed dots
8357 : : ****************************************************************************/
8358 : 26 : int bExistsAltPath( CANON_GLOBALS *pCG,
8359 : : BN_STRUCT *pBNS,
8360 : : BN_DATA *pBD,
8361 : : BN_AATG *pAATG,
8362 : : inp_ATOM *at,
8363 : : int num_atoms,
8364 : : int nVertDoubleBond,
8365 : : int nVertSingleBond,
8366 : : int path_type )
8367 : : {
8368 : : ALT_PATH_CHANGES apc;
8369 : 26 : int ret, ret_val, bError, bSuccess, bChangeFlow = 0, nDots, nDelta, bDoMarkChangedBonds = 1;
8370 : 26 : int bAdjustRadicals = 0;
8371 : : AT_NUMB type;
8372 : : BNS_FLOW_CHANGES fcd[4 * BNS_MAX_NUM_FLOW_CHANGES + 1];
8373 : : ENDPOINT_INFO eif;
8374 : : #if ( KETO_ENOL_TAUT == 1 )
8375 : : ENDPOINT_INFO eif2;
8376 : : #endif
8377 : :
8378 : : /* Initialize */
8379 [ + - - - : 26 : switch (path_type)
- - - - -
- - - - -
- - ]
8380 : : {
8381 : 26 : case ALT_PATH_MODE_TAUTOM:
8382 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8383 : 26 : type = BNS_VERT_TYPE_ENDPOINT;
8384 : 26 : bChangeFlow = BNS_EF_CHNG_RSTR;
8385 [ + - + - ]: 52 : if (!at[nVertSingleBond].endpoint &&
8386 [ + + ]: 52 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ))
8387 : : {
8388 : 8 : return 0;
8389 : : }
8390 [ + - + - ]: 36 : if (!at[nVertDoubleBond].endpoint &&
8391 [ + + ]: 36 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ))
8392 : : {
8393 : 2 : return 0;
8394 : : }
8395 : 16 : break;
8396 : :
8397 : : #if ( TAUT_PT_22_00 == 1 )
8398 : 0 : case ALT_PATH_MODE_TAUTOM_PT_22_00:
8399 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8400 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8401 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8402 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8403 [ # # ]: 0 : (!nGetEndpointInfo_PT_22_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8404 : 0 : return 0;
8405 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8406 [ # # ]: 0 : (!nGetEndpointInfo_PT_22_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8407 : 0 : return 0;
8408 : 0 : break;
8409 : : #endif
8410 : :
8411 : : #if ( TAUT_PT_16_00 == 1 )
8412 : 0 : case ALT_PATH_MODE_TAUTOM_PT_16_00:
8413 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8414 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8415 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8416 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8417 [ # # ]: 0 : (!nGetEndpointInfo_PT_16_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8418 : 0 : return 0;
8419 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8420 [ # # ]: 0 : (!nGetEndpointInfo_PT_16_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8421 : 0 : return 0;
8422 : 0 : break;
8423 : : #endif
8424 : :
8425 : : #if ( TAUT_PT_06_00 == 1 )
8426 : 0 : case ALT_PATH_MODE_TAUTOM_PT_06_00:
8427 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8428 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8429 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8430 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8431 [ # # ]: 0 : (!nGetEndpointInfo_PT_06_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8432 : 0 : return 0;
8433 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8434 [ # # ]: 0 : (!nGetEndpointInfo_PT_06_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8435 : 0 : return 0;
8436 : 0 : break;
8437 : : #endif
8438 : :
8439 : : #if ( TAUT_PT_39_00 == 1 )
8440 : 0 : case ALT_PATH_MODE_TAUTOM_PT_39_00:
8441 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8442 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8443 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8444 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8445 [ # # ]: 0 : (!nGetEndpointInfo_PT_39_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8446 : 0 : return 0;
8447 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8448 [ # # ]: 0 : (!nGetEndpointInfo_PT_39_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8449 : 0 : return 0;
8450 : 0 : break;
8451 : : #endif
8452 : :
8453 : : #if ( TAUT_PT_13_00 == 1 )
8454 : 0 : case ALT_PATH_MODE_TAUTOM_PT_13_00:
8455 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8456 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8457 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8458 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8459 [ # # ]: 0 : (!nGetEndpointInfo_PT_13_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8460 : 0 : return 0;
8461 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8462 [ # # ]: 0 : (!nGetEndpointInfo_PT_13_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8463 : 0 : return 0;
8464 : 0 : break;
8465 : : #endif
8466 : :
8467 : : #if ( TAUT_PT_18_00 == 1 )
8468 : 0 : case ALT_PATH_MODE_TAUTOM_PT_18_00:
8469 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8470 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8471 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8472 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8473 [ # # ]: 0 : (!nGetEndpointInfo_PT_18_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8474 : 0 : return 0;
8475 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8476 [ # # ]: 0 : (!nGetEndpointInfo_PT_18_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8477 : 0 : return 0;
8478 : 0 : break;
8479 : : #endif
8480 : :
8481 : :
8482 : : #if ( KETO_ENOL_TAUT == 1 )
8483 : 0 : case ALT_PATH_MODE_TAUTOM_KET:
8484 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8485 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8486 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8487 : :
8488 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8489 [ # # ]: 0 : ( !nGetEndpointInfo_KET( at, nVertSingleBond, &eif ) || !eif.cDonor ))
8490 : : {
8491 : 0 : return 0;
8492 : : }
8493 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8494 [ # # ]: 0 : ( !nGetEndpointInfo_KET( at, nVertDoubleBond, &eif2 ) || !eif2.cAcceptor ))
8495 : : {
8496 : 0 : return 0;
8497 : : }
8498 : : /*
8499 : : if ( eif.cKetoEnolCode + eif2.cKetoEnolCode != 3 )
8500 : : return 0;
8501 : : */
8502 : 0 : break;
8503 : :
8504 : : #endif
8505 : 0 : case ALT_PATH_MODE_CHARGE:
8506 : : /* Find alt path allowing to move (+). Purpose: establish "charge groups",
8507 : : mark alt. bonds due to (+) charge movement */
8508 : 0 : type = BNS_VERT_TYPE_C_POINT;
8509 : 0 : bChangeFlow = ( BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS );
8510 : 0 : break;
8511 : :
8512 : 0 : case ALT_PATH_MODE_4_SALT:
8513 : : case ALT_PATH_MODE_4_SALT2:
8514 : : /* Find alt paths allowing to move (-) and H between "acidic oxygen atoms".
8515 : : Purpose: mark alt bonds due to this "long range" tautomerism. */
8516 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8517 : 0 : bChangeFlow = ( BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS );
8518 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
8519 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ))
8520 : : {
8521 : 0 : return 0;
8522 : : }
8523 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertDoubleBond].endpoint*/ &&
8524 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ))
8525 : : {
8526 : 0 : return 0;
8527 : : }
8528 : 0 : memset( &apc, 0, sizeof( apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8529 : 0 : break;
8530 : :
8531 : 0 : case ALT_PATH_MODE_REM2H_CHG:
8532 : 0 : bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
8533 : 0 : case ALT_PATH_MODE_REM2H_TST:
8534 : 0 : bChangeFlow |= BNS_EF_CHNG_RSTR;
8535 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8536 : : /* Allow non-tautomeric donors or any tautomeric atom */
8537 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertSingleBond ) /* not linked to a t-group or the edge forbidden */ &&
8538 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor )) /* not a donor */
8539 : : {
8540 : 0 : return 0;
8541 : : }
8542 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* not connected to a t-group */ &&
8543 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cDonor ))
8544 : : {
8545 : 0 : return 0;
8546 : : }
8547 : 0 : memset( &apc, 0, sizeof( apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8548 : 0 : break;
8549 : :
8550 : 0 : case ALT_PATH_MODE_ADD2H_CHG:
8551 : 0 : bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
8552 : 0 : case ALT_PATH_MODE_ADD2H_TST:
8553 : 0 : bChangeFlow |= BNS_EF_CHNG_RSTR;
8554 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8555 : : /* Allow non-tautomeric acceptors or any tautomeric atom */
8556 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
8557 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cAcceptor ))
8558 : : {
8559 : 0 : return 0;
8560 : : }
8561 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertSingleBond].endpoint*/ &&
8562 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ))
8563 : : {
8564 : 0 : return 0;
8565 : : }
8566 : 0 : break;
8567 : :
8568 : 0 : case ALT_PATH_MODE_REM_PROTON:
8569 : : /* alt path is between the t-group (nVertDoubleBond) and
8570 : : the (+)-charge group (nVertSingleBond) */
8571 : 0 : type = 0;
8572 : : /*bDoMarkChangedBonds = 0;*/
8573 : 0 : bChangeFlow = ( BNS_EF_SAVE_ALL | BNS_EF_UPD_H_CHARGE ) | BNS_EF_ALTR_NS; /* added BNS_EF_ALTR_NS: set non-stereo altern non-ring bonds 2004-07-02*/
8574 : 0 : break;
8575 : 0 : default:
8576 : 0 : type = 0;
8577 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8578 : 0 : break;
8579 : : }
8580 : :
8581 : 16 : bError = 0;
8582 : 16 : bSuccess = 0;
8583 : 16 : nDelta = 0;
8584 : :
8585 : 16 : ret = SetRadEndpoints2( pCG, pBNS, pBD, RAD_SRCH_NORM );
8586 [ + - - + ]: 16 : if (IS_BNS_ERROR( ret ))
8587 : : {
8588 : 0 : return ret;
8589 : : }
8590 : :
8591 : : /* Set BNS to check alt path */
8592 : 16 : ret = bSetBnsToCheckAltPath( pBNS, nVertDoubleBond, nVertSingleBond, type, path_type, &apc, fcd, &nDots );
8593 [ - - - + : 16 : switch (ret)
- - ]
8594 : : {
8595 : 0 : case BNS_CHK_ALTP_NO_ALTPATH:
8596 : 0 : ret = RemoveRadEndpoints( pBNS, pBD, NULL );
8597 : 0 : return ret;
8598 : 0 : case BNS_CHK_ALTP_SAME_TGROUP:
8599 : 0 : bSuccess = 1;
8600 : 0 : goto reinit_BNS;
8601 : 0 : case BNS_CHK_ALTP_SAME_VERTEX:
8602 : 0 : ret = RemoveRadEndpoints( pBNS, pBD, NULL );
8603 [ # # ]: 0 : return ret ? ret : 1; /* very strange ... set a breakpoint here */
8604 : 16 : case BNS_CHK_ALTP_SET_SUCCESS:
8605 : 16 : break; /* actually check the existence of the altpath */
8606 : 0 : case BNS_CANT_SET_BOND:
8607 : 0 : goto reinit_BNS;
8608 : 0 : default:
8609 : 0 : ret_val = RemoveRadEndpoints( pBNS, pBD, NULL ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
8610 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8611 : : {
8612 : 0 : return ret;
8613 : : }
8614 : 0 : return BNS_PROGRAM_ERR;
8615 : : }
8616 : :
8617 [ - + - - ]: 16 : bAdjustRadicals = ( ( bChangeFlow & BNS_EF_UPD_RAD_ORI ) && !( bChangeFlow & BNS_EF_RSTR_FLOW ) );
8618 : :
8619 : : /*****************************************************************
8620 : : * nDots = 2 for ALT_PATH_CHARGE (checking moveable positive charges)
8621 : : * Now nDots for ALT_PATH_TAUTOM or ALT_PATH_4_SALT can be greater
8622 : : * because some of the bonds are effectively removed and dots
8623 : : * (vertex st-caps) may be added
8624 : : * -- to make sure there is no (+) charge on a tautomeric endpoint
8625 : : * -- to fix positions of moveable tautomeric attachements
8626 : : * (H and (-)-charges) at the ends of an alt path
8627 : : */
8628 : :
8629 : : /* Run BNS */
8630 : :
8631 : 16 : ret = RunBalancedNetworkSearch( pBNS, pBD, bChangeFlow );
8632 : :
8633 [ + - - + ]: 16 : if (IS_BNS_ERROR( ret ))
8634 : : {
8635 : 0 : bError = ret;
8636 : : }
8637 [ - + ]: 16 : else if (ret > 0)
8638 : : {
8639 [ + - ]: 16 : if (2 * ret >= nDots)
8640 : : {
8641 : 16 : nDelta = 2 * ret - nDots; /* non-zero means augmentation created another alt. path -- between radicals */
8642 [ - + - - ]: 16 : if (pAATG && pAATG->nMarkedAtom)
8643 : : {
8644 [ # # # # ]: 0 : if (pAATG->nAtTypeTotals && ( bChangeFlow & BNS_EF_UPD_H_CHARGE ))
8645 : : {
8646 : 0 : memset( pAATG->nMarkedAtom, 0, num_atoms * sizeof( pAATG->nMarkedAtom[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8647 : : /* Mark atoms that have charge or H changed, check their input types (that is, before changes),
8648 : : and subtract their input charge/H from nAtTypeTotals */
8649 : 0 : SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom, NULL, 1 );
8650 : : /* ZChange charges and/or H, update t_group_info, do not check types or change nAtTypeTotals */
8651 : : /* Atom types will be checked and nAtTypeTotals will be changed in
8652 : : AddChangedAtHChargeBNS() later */
8653 : 0 : SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, NULL, NULL, pAATG->t_group_info, 0 );
8654 : : }
8655 : : else
8656 : : {
8657 [ # # ]: 0 : if (!pAATG->nAtTypeTotals)
8658 : : {
8659 : 0 : bDoMarkChangedBonds = MarkAtomsAtTautGroups( pBNS, num_atoms, pAATG, nVertSingleBond, nVertDoubleBond );
8660 [ # # ]: 0 : if (bDoMarkChangedBonds < 0)
8661 : : {
8662 : 0 : bError = bDoMarkChangedBonds;
8663 : 0 : bDoMarkChangedBonds = 0;
8664 : : }
8665 : : }
8666 : : }
8667 : : }
8668 [ + - ]: 16 : if (bDoMarkChangedBonds)
8669 : : {
8670 : : /* Mark bonds that were changed to configure bond testing */
8671 : 16 : ret_val = bSetBondsAfterCheckOneBond( pBNS, fcd, -1, at, num_atoms, bChangeFlow );
8672 [ + - - + ]: 16 : if (IS_BNS_ERROR( ret_val ))
8673 : : {
8674 : 0 : bError = ret_val;
8675 : : }
8676 : : /*ret = SetBondsRestoreBnStructFlow( pBNS, at, num_atoms, bChangeFlow );*/
8677 : : /* mark all other changed bonds */
8678 : 16 : ret = SetBondsFromBnStructFlow( pBNS, at, num_atoms, bChangeFlow );
8679 [ + - - + ]: 16 : if (IS_BNS_ERROR( ret ))
8680 : : {
8681 : 0 : bError = ret;
8682 : : }
8683 : : else
8684 : : {
8685 [ + - + - ]: 16 : if (!( ret & 1 ) && !( ret_val & 1 ))
8686 : : {
8687 : 16 : bSuccess = 1;
8688 : : }
8689 : : else
8690 : : {
8691 [ # # # # ]: 0 : if ((( ( ret & 1 ) || ( ret_val & 1 ) ) &&
8692 [ # # # # ]: 0 : ( bChangeFlow & BNS_EF_ALTR_BONDS )) || ( bChangeFlow & BNS_EF_UPD_H_CHARGE )) /* djb-rwth: addressing LLVM warning */
8693 : : {
8694 : : /* Some bonds have been changed to alternating */
8695 : 0 : bSuccess = 3;
8696 : : }
8697 : : else
8698 : : {
8699 : 0 : bError = BNS_BOND_ERR;
8700 : : }
8701 : : }
8702 : : }
8703 [ + - - + : 16 : if (!bError && pAATG && pAATG->nMarkedAtom && ( bChangeFlow & BNS_EF_UPD_H_CHARGE ))
- - - - ]
8704 : : {
8705 : : /* Update radicals to avoid errors in atom type check in AddChangedAtHChargeBNS() */
8706 [ # # ]: 0 : if (bAdjustRadicals)
8707 : : {
8708 : 0 : ret_val = RestoreRadicalsOnly( pBNS, pBD, at );
8709 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret_val ))
8710 : : {
8711 : 0 : bError = ret_val;
8712 : : }
8713 : : }
8714 : : /* Check atom types of marked atoms and add charge/H changes to nAtTypeTotals */
8715 : : /* Changing atoms were marked in the 1st call to SubtractOrChangeAtHChargeBNS(..., 1) above */
8716 : 0 : AddChangedAtHChargeBNS( at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom );
8717 [ # # ]: 0 : if (bChangeFlow & BNS_EF_CHNG_FLOW)
8718 : : {
8719 : : /* Eliminate ambiguities in already changed flow:
8720 : : replace (+)--N==(-) with (+)==N--(-) (both represent neutral N) */
8721 : 0 : EliminatePlusMinusChargeAmbiguity( pBNS, num_atoms );
8722 : : }
8723 : : }
8724 : : }
8725 : : }
8726 : :
8727 : 16 : ret = RestoreBnStructFlow( pBNS, bChangeFlow & BNS_EF_CHNG_RSTR );
8728 : :
8729 [ - + + - ]: 16 : if (IS_BNS_ERROR( ret ))
8730 : : {
8731 : 0 : bError = ret;
8732 : : }
8733 : : }
8734 : :
8735 : 16 : reinit_BNS:
8736 : :
8737 : : /* --- Reinitialize to repeat the calculations --- */
8738 : 16 : bRestoreBnsAfterCheckAltPath( pBNS, &apc, bChangeFlow & BNS_EF_UPD_H_CHARGE );
8739 : 16 : bRestoreFlowAfterCheckOneBond( pBNS, fcd );
8740 [ - + ]: 16 : ret_val = RemoveRadEndpoints( pBNS, pBD, bAdjustRadicals ? at : NULL );
8741 : 16 : ReInitBnStructAltPaths( pBNS );
8742 : :
8743 [ + - + - ]: 16 : return bError ? bError : ret_val ? ret_val : ( bSuccess + 4 * nDelta );
8744 : : }
8745 : :
8746 : :
8747 : : /****************************************************************************/
8748 : 161 : BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at,
8749 : : int num_atoms,
8750 : : int nMaxAddAtoms,
8751 : : int nMaxAddEdges,
8752 : : int max_altp,
8753 : : int *pNum_changed_bonds )
8754 : : {
8755 : 161 : BN_STRUCT *pBNS = NULL;
8756 : : BNS_VERTEX *vert;
8757 : :
8758 : 161 : int neigh, num_changed_bonds = 0;
8759 : : U_CHAR bond_type, bond_mark;
8760 : :
8761 : : int i, j, k, n_edges, num_bonds, num_edges, f1, f2, edge_cap, edge_flow, st_flow; /* djb-rwth: removing redundant variables */
8762 : : int tot_st_cap, tot_st_flow;
8763 : : int max_tg, max_edges, max_vertices, len_alt_path, max_iedges, num_altp;
8764 : : #if ( BNS_RAD_SEARCH == 1 )
8765 : 161 : int num_rad = 0;
8766 : :
8767 : 161 : nMaxAddEdges += 1;
8768 : : #endif
8769 : : #if ( FIX_NUM_TG == 1 )
8770 : : max_tg = inchi_max( num_atoms / 2, 5 );
8771 : : #else
8772 : 161 : max_tg = num_atoms;
8773 : : #endif
8774 : 161 : num_changed_bonds = 0;
8775 : :
8776 [ + + ]: 971 : for (i = 0, num_bonds = 0; i < num_atoms; i++)
8777 : : {
8778 : : /*(@nnuk : Nauman Ullah Khan) */
8779 : : LOG_NO_ARGS("\n################# (L8916:ichi_bns.c) ###################\n");
8780 : : LOG_MULT_ARGS("Number of changed bonds (Start): %d\n", num_changed_bonds);
8781 : : LOG_NO_ARGS("\n########################################################\n");
8782 : :
8783 : 810 : num_bonds += at[i].valence;
8784 : : #if ( BNS_RAD_SEARCH == 1 )
8785 : 810 : num_rad += ( at[i].radical == RADICAL_DOUBLET );
8786 : : #endif
8787 : : }
8788 : : /* Each atom has enough edges to belong to a tautomeric group + nMaxAddEdges */
8789 : : /* number of atoms is large enough to accommodate max. possible number of t-groups + nMaxAddAtoms */
8790 : : /* max_altp cannot be larger than BN_MAX_ALTP = 16 */
8791 : 161 : num_edges = ( num_bonds /= 2 );
8792 : : /* +1 for a super-tautomeric group */
8793 : 161 : max_vertices = num_atoms + nMaxAddAtoms + max_tg + 1;
8794 : : /* +max_tg for edges between t-groups and super-tautomeric group */
8795 : 161 : max_edges = num_edges + ( nMaxAddEdges + NUM_KINDS_OF_GROUPS )*max_vertices + max_tg;
8796 : : #if ( BNS_RAD_SEARCH == 1 )
8797 [ - + ]: 161 : if (num_rad)
8798 : : {
8799 : 0 : max_vertices *= 2;
8800 : 0 : max_edges *= 2;
8801 : : }
8802 : : #endif
8803 : 161 : max_iedges = 2 * max_edges;
8804 : 161 : len_alt_path = max_vertices + iALTP_HDR_LEN + 1; /* may overflow if an edge is traversed in 2 directions */
8805 : :
8806 [ + - ]: 161 : if (!( pBNS = (BN_STRUCT *) inchi_calloc( 1, sizeof( BN_STRUCT ) ) ) ||
8807 [ + - ]: 161 : !( pBNS->edge = (BNS_EDGE *) inchi_calloc( max_edges, sizeof( BNS_EDGE ) ) ) ||
8808 [ + - ]: 161 : !( pBNS->vert = (BNS_VERTEX *) inchi_calloc( max_vertices, sizeof( BNS_VERTEX ) ) ) ||
8809 [ - + ]: 161 : !( pBNS->iedge = (BNS_IEDGE *) inchi_calloc( max_iedges, sizeof( BNS_IEDGE ) ) ))
8810 : : {
8811 : 0 : return DeAllocateBnStruct( pBNS );
8812 : : }
8813 : : /* Alt path init */
8814 [ + + + - ]: 2737 : for (num_altp = 0; num_altp < max_altp && num_altp < BN_MAX_ALTP; num_altp++)
8815 : : {
8816 [ - + ]: 2576 : if (!( pBNS->altp[num_altp] = (BNS_ALT_PATH*) inchi_calloc( len_alt_path, sizeof( BNS_ALT_PATH ) ) ))
8817 : : {
8818 : 0 : return DeAllocateBnStruct( pBNS );
8819 : : }
8820 : 2576 : ALTP_ALLOCATED_LEN( pBNS->altp[num_altp] ) = len_alt_path;
8821 : 2576 : pBNS->len_alt_path = len_alt_path; /* ??? duplication ??? */
8822 : : /* re-init */
8823 : 2576 : ALTP_DELTA( pBNS->altp[num_altp] ) = 0;
8824 : 2576 : ALTP_START_ATOM( pBNS->altp[num_altp] ) = NO_VERTEX;
8825 : 2576 : ALTP_END_ATOM( pBNS->altp[num_altp] ) = NO_VERTEX;
8826 : 2576 : ALTP_PATH_LEN( pBNS->altp[num_altp] ) = 0;
8827 : : }
8828 : 161 : pBNS->alt_path = NULL;
8829 : 161 : pBNS->num_altp = 0;
8830 : 161 : pBNS->max_altp = num_altp;
8831 : :
8832 : : /* Fill vertices (no connectivity) */
8833 : 161 : pBNS->vert[0].iedge = pBNS->iedge;
8834 [ + + ]: 971 : for (i = 0; i < num_atoms; i++)
8835 : : {
8836 : 810 : k = pBNS->vert[i].max_adj_edges = at[i].valence + ( nMaxAddEdges + NUM_KINDS_OF_GROUPS );
8837 : 810 : pBNS->vert[i + 1].iedge = pBNS->vert[i].iedge + k;
8838 : : }
8839 : 161 : pBNS->num_atoms = num_atoms; /* number of real atoms */
8840 : 161 : pBNS->num_added_atoms = 0;
8841 : 161 : pBNS->num_t_groups = 0; /* number of added t-groups */
8842 : 161 : pBNS->num_c_groups = 0;
8843 : 161 : pBNS->nMaxAddAtoms = nMaxAddAtoms;
8844 : 161 : pBNS->nMaxAddEdges = nMaxAddEdges;
8845 : :
8846 : 161 : pBNS->num_vertices = num_atoms; /* current number of vertices, a sum of
8847 : : pBNS->num_atoms
8848 : : pBNS->num_t_groups
8849 : : pBNS->num_added_atoms */
8850 : 161 : pBNS->max_vertices = max_vertices;
8851 : :
8852 : :
8853 : 161 : pBNS->num_bonds = num_bonds; /* number of real edges (bonds) */
8854 : 161 : pBNS->max_edges = max_edges;
8855 : 161 : pBNS->max_iedges = max_iedges;
8856 : :
8857 : : /*
8858 : : To remove t-groups and added atoms:
8859 : : In atoms i = 0..pBNS->num_atoms-1
8860 : : pBNS->vert[i].num_adj_edges = pBNS->vert[i].max_adj_edges - pBNS->nMaxAddEdges - NUM_KINDS_OF_GROUPS;
8861 : : pBNS->num_vertices = pBNS->num_atoms;
8862 : : pBNS->num_edges = pBNS->num_bonds;
8863 : : pBNS->num_added_atoms = 0;
8864 : : pBNS->num_t_groups = 0;
8865 : : pBNS->num_added_edges = 0;
8866 : :
8867 : : ALTP_DELTA(pBNS->alt_path) = 0;
8868 : : ALTP_START_ATOM(pBNS->alt_path) = NO_VERTEX;
8869 : : ALTP_END_ATOM(pBNS->alt_path) = NO_VERTEX;
8870 : : ALTP_PATH_LEN(pBNS->alt_path) = 0;
8871 : : */
8872 : :
8873 : : /* Fill edges and connectivity */
8874 : 161 : tot_st_cap = tot_st_flow = 0;
8875 [ + + ]: 971 : for (i = 0, n_edges = 0; i < num_atoms; i++)
8876 : : {
8877 : 810 : vert = &pBNS->vert[i];
8878 : : /* djb-rwth: removing redundant code */
8879 : 810 : st_flow = 0;
8880 : : /* djb-rwth: removing redundant code */
8881 [ + + ]: 2160 : for (j = 0; j < at[i].valence; j++)
8882 : : {
8883 : 1350 : neigh = at[i].neighbor[j];
8884 : : /* find this bond at the neighbor */
8885 [ + - ]: 2237 : for (k = 0; k < at[neigh].valence; k++)
8886 : : {
8887 [ + + ]: 2237 : if (at[neigh].neighbor[k] == i)
8888 : : {
8889 : 1350 : break;
8890 : : }
8891 : : }
8892 : 1350 : bond_type = ( at[i].bond_type[j] & BOND_TYPE_MASK );
8893 : 1350 : bond_mark = ( at[i].bond_type[j] & ~BOND_TYPE_MASK );
8894 [ + + - + : 1350 : if (bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE &&
- - ]
8895 : : bond_type != BOND_TRIPLE /*&& bond_type != BOND_ALTERN*/)
8896 : : {
8897 : : /* Make Unknown or Alternating bonds single */
8898 : 0 : bond_type = 1;
8899 : 0 : at[i].bond_type[j] = bond_mark | bond_type;
8900 : 0 : num_changed_bonds++;
8901 : : }
8902 [ + + ]: 1350 : if (neigh > i)
8903 : : {
8904 : : /* This is the first time we encounter this bond */
8905 [ + + + + : 675 : f1 = MAX_AT_FLOW( at[i] );
- + ]
8906 [ + + + + : 675 : f2 = MAX_AT_FLOW( at[neigh] );
- + ]
8907 : 675 : edge_flow = bond_type - 1;
8908 [ - + ]: 675 : if (edge_flow > MAX_BOND_EDGE_CAP)
8909 : : {
8910 : : /* djb-rwth: removing redundant code */
8911 : 0 : edge_flow = 0; /* BNS will determine flows (that is, bonds) */
8912 : 0 : edge_cap = AROM_BOND_EDGE_CAP;
8913 : : }
8914 : : else
8915 : : {
8916 : : #if ( 0 && KETO_ENOL_TAUT == 1 ) /* ????? */
8917 : : edge_cap = inchi_max( f1, f2 );
8918 : : #else
8919 : 675 : edge_cap = inchi_min( f1, f2 );
8920 : : #endif
8921 : 675 : edge_cap = inchi_min( edge_cap, MAX_BOND_EDGE_CAP ); /* max capacity = 2 means up to triple bond */
8922 : : }
8923 : :
8924 : 675 : pBNS->edge[n_edges].neighbor1 = (AT_NUMB) i;
8925 : 675 : pBNS->edge[n_edges].neighbor12 = (AT_NUMB) ( i ^ neigh );
8926 : 675 : pBNS->edge[n_edges].flow = pBNS->edge[n_edges].flow0 = edge_flow;
8927 : 675 : pBNS->edge[n_edges].cap = pBNS->edge[n_edges].cap0 = edge_cap;
8928 : 675 : pBNS->edge[n_edges].neigh_ord[0] = j;
8929 : 675 : pBNS->edge[n_edges].neigh_ord[1] = k;
8930 : 675 : pBNS->edge[n_edges].pass = 0;
8931 : 675 : pBNS->edge[n_edges].forbidden = 0;
8932 : :
8933 : 675 : vert->iedge[j] = pBNS->vert[neigh].iedge[k] = n_edges++;
8934 : : }
8935 : : else
8936 : : {
8937 : : /* This is the second time we encounter this bond. It was stored at */
8938 : 675 : int iedge = pBNS->vert[neigh].iedge[k];
8939 : 675 : edge_cap = pBNS->edge[iedge].cap; /* djb-rwth: ignoring LLVM warning: variable used */
8940 : 675 : edge_flow = pBNS->edge[iedge].flow;
8941 : : }
8942 : 1350 : st_flow += edge_flow;
8943 : : /* djb-rwth: removing redundant code */
8944 : : }
8945 : 810 : vert->num_adj_edges = j;
8946 : 810 : vert->st_edge.cap =
8947 [ + + + + : 810 : vert->st_edge.cap0 = MAX_AT_FLOW( at[i] );
- + ]
8948 : 810 : vert->st_edge.flow =
8949 : 810 : vert->st_edge.flow0 = st_flow;
8950 : 810 : vert->type = BNS_VERT_TYPE_ATOM;
8951 : 810 : tot_st_cap += vert->st_edge.cap;
8952 : 810 : tot_st_flow += vert->st_edge.flow;
8953 : : }
8954 : 161 : *pNum_changed_bonds = num_changed_bonds / 2;
8955 : :
8956 : 161 : pBNS->num_edges = n_edges; /* number of edges */
8957 : 161 : pBNS->num_added_edges = 0;
8958 : :
8959 : : /*(@nnuk : Nauman Ullah Khan) */
8960 : : LOG_NO_ARGS("\n################# (L9108:ichi_bns.c) ################\n");
8961 [ + + ]: 971 : for (i = 0, num_bonds = 0; i < num_atoms; i++) {
8962 : :
8963 : : LOG_MULT_ARGS("Element : %s, Number of changed bonds (End): %d\n", at[i].elname, *pNum_changed_bonds);
8964 : : }
8965 : : LOG_NO_ARGS("\n#####################################################\n");
8966 : :
8967 : 161 : pBNS->tot_st_cap = tot_st_cap;
8968 : 161 : pBNS->tot_st_flow = tot_st_flow;
8969 : :
8970 : 161 : return pBNS;
8971 : : }
8972 : :
8973 : :
8974 : : /****************************************************************************/
8975 : 161 : BN_STRUCT* DeAllocateBnStruct( BN_STRUCT *pBNS )
8976 : : {
8977 : : int i;
8978 [ + - ]: 161 : if (pBNS)
8979 : : {
8980 [ + - ]: 161 : if (pBNS->edge)
8981 : : {
8982 [ + - ]: 161 : inchi_free( pBNS->edge );
8983 : : }
8984 [ + + + - ]: 2737 : for (i = 0; i < pBNS->max_altp && i < BN_MAX_ALTP; i++)
8985 : : {
8986 [ + - ]: 2576 : if (pBNS->altp[i])
8987 : : {
8988 [ + - ]: 2576 : inchi_free( pBNS->altp[i] );
8989 : : }
8990 : : }
8991 [ + - ]: 161 : if (pBNS->vert)
8992 : : {
8993 [ + - ]: 161 : if (pBNS->vert[0].iedge)
8994 : : {
8995 [ + - ]: 161 : inchi_free( pBNS->vert[0].iedge );
8996 : : }
8997 [ + - ]: 161 : inchi_free( pBNS->vert );
8998 : : }
8999 [ + - ]: 161 : inchi_free( pBNS );
9000 : : }
9001 : :
9002 : 161 : return NULL;
9003 : : }
9004 : :
9005 : :
9006 : : /****************************************************************************/
9007 : 390 : int ReInitBnStructAltPaths( BN_STRUCT *pBNS )
9008 : : {
9009 : : int i;
9010 [ + + + - ]: 6630 : for (i = 0; i < pBNS->max_altp && i < BN_MAX_ALTP; i++)
9011 : : {
9012 [ + - ]: 6240 : if (pBNS->altp[i])
9013 : : {
9014 : 6240 : ALTP_DELTA( pBNS->altp[i] ) = 0;
9015 : 6240 : ALTP_PATH_LEN( pBNS->altp[i] ) = 0;
9016 : 6240 : ALTP_START_ATOM( pBNS->altp[i] ) = NO_VERTEX;
9017 : 6240 : ALTP_END_ATOM( pBNS->altp[i] ) = NO_VERTEX;
9018 : : }
9019 : : }
9020 : 390 : pBNS->alt_path = NULL;
9021 : 390 : pBNS->num_altp = 0;
9022 : 390 : return i;
9023 : : }
9024 : :
9025 : :
9026 : : /****************************************************************************/
9027 : 7 : int ReInitBnStructAddGroups( CANON_GLOBALS *pCG,
9028 : : BN_STRUCT *pBNS,
9029 : : inp_ATOM *at,
9030 : : int num_atoms,
9031 : : T_GROUP_INFO *tgi,
9032 : : C_GROUP_INFO *cgi )
9033 : : {
9034 : : int ret;
9035 : : /* strip all t-groups and c-groups */
9036 : 7 : ret = ReInitBnStruct( pBNS, at, num_atoms, 0 );
9037 [ - + ]: 7 : if (ret)
9038 : : {
9039 : 0 : ret = BNS_REINIT_ERR;
9040 : 0 : goto exit_function;
9041 : : }
9042 : : /*#if ( MOVE_CHARGES == 1 )*/
9043 [ + - ]: 7 : if (*pBNS->pbTautFlags & TG_FLAG_MOVE_POS_CHARGES)
9044 : : {
9045 : : /* Add c-groups */
9046 : 7 : ret = AddCGroups2BnStruct( pCG, pBNS, at, num_atoms, cgi );
9047 [ + - - + ]: 7 : if (IS_BNS_ERROR( ret ))
9048 : : {
9049 : 0 : goto exit_function;
9050 : : }
9051 : : }
9052 : : /*#endif*/
9053 : : /* Add t-groups */
9054 : 7 : ret = AddTGroups2BnStruct( pCG, pBNS, at, num_atoms, tgi );
9055 [ - + + - ]: 7 : if (IS_BNS_ERROR( ret ))
9056 : : {
9057 : 0 : goto exit_function;
9058 : : }
9059 : :
9060 : 7 : exit_function:
9061 : :
9062 : 7 : return ret;
9063 : : }
9064 : :
9065 : :
9066 : : /****************************************************************************/
9067 : 180 : int ReInitBnStruct( BN_STRUCT *pBNS,
9068 : : inp_ATOM *at,
9069 : : int num_at,
9070 : : int bRemoveGroupsFromAtoms )
9071 : : {
9072 : : int i, vfict, kfict, iedgefict, endpoint, centerpoint, iedge, k;
9073 : 180 : int ret = 0;
9074 [ + - ]: 180 : if (pBNS)
9075 : : {
9076 [ + - + - ]: 180 : if (pBNS->vert && pBNS->edge)
9077 : : {
9078 : : /* Debug */
9079 [ + + ]: 1040 : for (k = 0, i = 0; k < pBNS->num_edges; k++)
9080 : : {
9081 [ - + ]: 860 : if (pBNS->edge[k].pass)
9082 : : {
9083 : 0 : i++;
9084 : : }
9085 : : }
9086 : 180 : ret += i * 100;
9087 : : /* Restore flow and cap on edges to vertices connected to fictitious atoms */
9088 [ + + ]: 211 : for (vfict = pBNS->num_atoms; vfict < pBNS->num_vertices; vfict++)
9089 : : {
9090 [ + + ]: 101 : for (kfict = 0; kfict < pBNS->vert[vfict].num_adj_edges; kfict++)
9091 : : {
9092 : 70 : iedgefict = pBNS->vert[vfict].iedge[kfict]; /* fictitious edge to the endpoint */
9093 : 70 : endpoint = pBNS->edge[iedgefict].neighbor12 ^ vfict; /* the endpoint */
9094 : : /* To simlify restore cap and flow in ALL edges to the endpoint */
9095 [ - + - - ]: 70 : if (bRemoveGroupsFromAtoms && endpoint < num_at)
9096 : : {
9097 : 0 : at[endpoint].c_point = 0;
9098 : 0 : at[endpoint].endpoint = 0;
9099 : : }
9100 [ + + ]: 210 : for (k = 0; k < pBNS->vert[endpoint].num_adj_edges; k++)
9101 : : {
9102 : 140 : iedge = pBNS->vert[endpoint].iedge[k]; /* edge to endpoint */
9103 : 140 : centerpoint = pBNS->edge[iedge].neighbor12 ^ endpoint;
9104 : 140 : pBNS->edge[iedge].cap = pBNS->edge[iedge].cap0;
9105 : 140 : pBNS->edge[iedge].flow = pBNS->edge[iedge].flow0;
9106 : 140 : pBNS->edge[iedge].pass = 0;
9107 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
9108 : 140 : pBNS->edge[iedge].forbidden &= pBNS->edge_forbidden_mask;
9109 : : #endif
9110 : 140 : pBNS->vert[centerpoint].st_edge.cap = pBNS->vert[centerpoint].st_edge.cap0;
9111 : 140 : pBNS->vert[centerpoint].st_edge.flow = pBNS->vert[centerpoint].st_edge.flow0;
9112 : : }
9113 : 70 : pBNS->vert[endpoint].st_edge.cap = pBNS->vert[endpoint].st_edge.cap0;
9114 : 70 : pBNS->vert[endpoint].st_edge.flow = pBNS->vert[endpoint].st_edge.flow0;
9115 : 70 : pBNS->vert[endpoint].type &= BNS_VERT_TYPE_ATOM;
9116 : : }
9117 : : }
9118 : : /* Reset number of neighbors */
9119 [ + + ]: 180 : if (pBNS->num_edges > pBNS->num_bonds)
9120 : : {
9121 [ + + ]: 153 : for (i = 0; i < pBNS->num_atoms; i++)
9122 : : {
9123 : 134 : pBNS->vert[i].num_adj_edges =
9124 : 134 : pBNS->vert[i].max_adj_edges - pBNS->nMaxAddEdges - NUM_KINDS_OF_GROUPS;
9125 : : }
9126 : : }
9127 : : }
9128 : : else
9129 : : {
9130 : 0 : ret += 2;
9131 : : }
9132 [ - + ]: 180 : if (!pBNS->edge)
9133 : : {
9134 : 0 : ret += 4;
9135 : : }
9136 [ - + ]: 180 : if (!pBNS->iedge)
9137 : : {
9138 : 0 : ret += 8;
9139 : : }
9140 : :
9141 : 180 : ReInitBnStructAltPaths( pBNS );
9142 : :
9143 : 180 : pBNS->num_vertices = pBNS->num_atoms;
9144 : 180 : pBNS->num_edges = pBNS->num_bonds;
9145 : 180 : pBNS->num_added_atoms = 0;
9146 : 180 : pBNS->num_t_groups = 0;
9147 : 180 : pBNS->num_c_groups = 0;
9148 : 180 : pBNS->num_added_edges = 0;
9149 : : }
9150 : : else
9151 : : {
9152 : 0 : ret += 1;
9153 : : }
9154 : :
9155 : 180 : return ret;
9156 : : }
9157 : :
9158 : :
9159 : : /****************************************************************************/
9160 : 0 : int CompTGroupNumber( const void *tg1, const void *tg2, void *p )
9161 : : {
9162 : 0 : return (int) ( (const T_GROUP *) tg1 )->nGroupNumber - (int) ( (const T_GROUP *) tg2 )->nGroupNumber;
9163 : : }
9164 : :
9165 : :
9166 : : /****************************************************************************/
9167 : 0 : int CompCGroupNumber( const void *cg1, const void *cg2, void *p )
9168 : : {
9169 : 0 : return (int) ( (const C_GROUP *) cg1 )->nGroupNumber - (int) ( (const C_GROUP *) cg2 )->nGroupNumber;
9170 : : }
9171 : :
9172 : :
9173 : : /****************************************************************************/
9174 : 19 : int AddTGroups2BnStruct( CANON_GLOBALS *pCG,
9175 : : BN_STRUCT *pBNS,
9176 : : inp_ATOM *at,
9177 : : int num_atoms,
9178 : : T_GROUP_INFO *tgi )
9179 : : {
9180 : 19 : int ret = 0;
9181 : : /* ret = ReInitBnStruct( pBNS ); */
9182 [ + - + - : 19 : if (tgi && tgi->num_t_groups && tgi->t_group)
+ - ]
9183 : : {
9184 : : int i, k, endpoint, centerpoint, fictpoint;
9185 : 19 : int num_tg = tgi->num_t_groups;
9186 : 19 : int num_edges = pBNS->num_edges;
9187 : 19 : int num_vertices = pBNS->num_vertices;
9188 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing t-group */
9189 : : BNS_VERTEX *vert_endpoint;
9190 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
9191 : 19 : int nMaxTGroupNumber = 0;
9192 : : ENDPOINT_INFO eif;
9193 : :
9194 : : /* Debug: check overflow */
9195 [ - + ]: 19 : if (num_vertices + num_tg >= pBNS->max_vertices)
9196 : : {
9197 : 0 : return BNS_VERT_EDGE_OVFL;
9198 : : }
9199 : : /* Find the largest t-group ID */
9200 [ + + ]: 50 : for (i = 0; i < num_tg; i++)
9201 : : {
9202 [ + - ]: 31 : if (tgi->t_group[i].nGroupNumber > nMaxTGroupNumber)
9203 : : {
9204 : 31 : nMaxTGroupNumber = tgi->t_group[i].nGroupNumber;
9205 : : }
9206 : : }
9207 : : /* Since t-group IDs may be not contiguous, clear all vertices that will be added.
9208 : : all-zeroes-vertex will be ignored by the BNS
9209 : : */
9210 : 19 : memset( pBNS->vert + num_vertices, 0, nMaxTGroupNumber * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
9211 : : /* Make sure the last t-group has the largest t-group ID:
9212 : : this is necessary to correctly add new edges
9213 : : and vertices for testing augmenting paths */
9214 : : #if ( bRELEASE_VERSION != 1 )
9215 : : insertions_sort( pCG, tgi->t_group, num_tg, sizeof( tgi->t_group[0] ), CompTGroupNumber );
9216 : : for (i = 1; i < num_tg; i++)
9217 : : {
9218 : : if (1 != tgi->t_group[i].nGroupNumber - tgi->t_group[i - 1].nGroupNumber)
9219 : : {
9220 : : return BNS_BOND_ERR;
9221 : : }
9222 : : }
9223 : : #else
9224 [ - + ]: 19 : if (nMaxTGroupNumber != tgi->t_group[num_tg - 1].nGroupNumber)
9225 : : {
9226 : 0 : insertions_sort( pCG, tgi->t_group, num_tg, sizeof( tgi->t_group[0] ), CompTGroupNumber );
9227 : : }
9228 : : #endif
9229 : : /* Initialize new fictitious vertices */
9230 : 19 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
9231 : :
9232 [ + + ]: 50 : for (i = 0; i < num_tg; i++, ver_ficpont_prev = vert_ficpoint)
9233 : : {
9234 : : /*
9235 : : vert_ficpoint-1 is the last vertex;
9236 : : vert_ficpoint is the vertex that is being added
9237 : : Note: nGroupNumber are not contiguous
9238 : : */
9239 : 31 : vert_ficpoint = pBNS->vert + num_vertices + tgi->t_group[i].nGroupNumber - 1;
9240 : 31 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
9241 : 31 : vert_ficpoint->max_adj_edges = tgi->t_group[i].nNumEndpoints + BNS_ADD_EDGES + BNS_ADD_SUPER_TGROUP;
9242 : 31 : vert_ficpoint->num_adj_edges = 0;
9243 : 31 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
9244 : 31 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
9245 : 31 : vert_ficpoint->type = BNS_VERT_TYPE_TGROUP;
9246 : : }
9247 : :
9248 [ + + ]: 153 : for (endpoint = 0; endpoint < num_atoms; endpoint++)
9249 : : {
9250 [ + + ]: 134 : if (!at[endpoint].endpoint)
9251 : : {
9252 : 64 : continue;
9253 : : }
9254 : 70 : fictpoint = at[endpoint].endpoint + num_vertices - 1;
9255 : 70 : vert_ficpoint = pBNS->vert + fictpoint;
9256 : 70 : vert_endpoint = pBNS->vert + endpoint;
9257 : : /* Debug: check overflow */
9258 [ + - ]: 70 : if (fictpoint >= pBNS->max_vertices ||
9259 [ + - ]: 70 : num_edges >= pBNS->max_edges ||
9260 [ + - ]: 70 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
9261 [ - + ]: 70 : vert_endpoint->num_adj_edges >= vert_endpoint->max_adj_edges)
9262 : : {
9263 : 0 : ret = BNS_VERT_EDGE_OVFL;
9264 : 0 : break;
9265 : : }
9266 : : /* Obtain donor/acceptor info */
9267 [ - + ]: 70 : if (!nGetEndpointInfo(at, endpoint, &eif)
9268 : : #if ( TAUT_PT_22_00 == 1 )
9269 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_22_00) && nGetEndpointInfo_PT_22_00(at, endpoint, &eif))
9270 : : #endif
9271 : : #if ( TAUT_PT_16_00 == 1 )
9272 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_16_00) && nGetEndpointInfo_PT_16_00(at, endpoint, &eif))
9273 : : #endif
9274 : : #if ( TAUT_PT_06_00 == 1 )
9275 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_06_00) && nGetEndpointInfo_PT_06_00(at, endpoint, &eif))
9276 : : #endif
9277 : : #if ( TAUT_PT_39_00 == 1 )
9278 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_39_00) && nGetEndpointInfo_PT_39_00(at, endpoint, &eif))
9279 : : #endif
9280 : : #if ( TAUT_PT_13_00 == 1 )
9281 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_13_00) && nGetEndpointInfo_PT_13_00(at, endpoint, &eif))
9282 : : #endif
9283 : : #if ( TAUT_PT_18_00 == 1 )
9284 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_18_00) && nGetEndpointInfo_PT_18_00(at, endpoint, &eif))
9285 : : #endif
9286 : : ) {
9287 : : #if ( KETO_ENOL_TAUT == 1 )
9288 [ # # # # ]: 0 : if (!( ( tgi->bTautFlags & TG_FLAG_KETO_ENOL_TAUT ) &&
9289 : 0 : nGetEndpointInfo_KET( at, endpoint, &eif ) ))
9290 : : #endif
9291 : : {
9292 : 0 : ret = BNS_BOND_ERR;
9293 : 0 : break;
9294 : : }
9295 : : }
9296 : :
9297 : 70 : vert_endpoint->type |= BNS_VERT_TYPE_ENDPOINT;
9298 : :
9299 : : /* Set capacity = 1 to the edges from the endpoint to the centerpoint(s) */
9300 [ + + ]: 140 : for (k = 0; k < vert_endpoint->num_adj_edges; k++)
9301 : : {
9302 : 70 : int iedge = vert_endpoint->iedge[k];
9303 [ + + ]: 70 : if (!pBNS->edge[iedge].cap)
9304 : : {
9305 : : /* Single bond, possibly between endpoint and centerpoint */
9306 : 35 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ endpoint );
9307 [ + - ]: 35 : if (centerpoint < pBNS->num_atoms &&
9308 [ + - ]: 35 : pBNS->vert[centerpoint].st_edge.cap >= 1)
9309 : : {
9310 : 35 : int bond_type = ( at[endpoint].bond_type[k] & BOND_TYPE_MASK );
9311 [ + + + - ]: 35 : if (bond_type == BOND_TAUTOM ||
9312 [ + - ]: 14 : bond_type == BOND_ALTERN ||
9313 [ + - ]: 14 : bond_type == BOND_ALT12NS ||
9314 : : bond_type == BOND_SINGLE)
9315 : : {
9316 : 35 : pBNS->edge[iedge].cap = 1;
9317 : : }
9318 : : }
9319 : : }
9320 : : }
9321 : :
9322 : : /* Create a new edge connecting endpoint to the new fictitious t-group vertex vert_ficpoint */
9323 : 70 : edge = pBNS->edge + num_edges;
9324 : 70 : edge->cap = 1;
9325 : 70 : edge->flow = 0;
9326 : 70 : edge->pass = 0;
9327 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
9328 : 70 : edge->forbidden &= pBNS->edge_forbidden_mask;
9329 : : #endif
9330 : : /* Later include case when the charge change allows the endpoint to become tautomeric */
9331 : : /* mark endoint having moveable H atom with flow=1 */
9332 : :
9333 : : /* -- old "no charges" version -- */
9334 : : /* if (at[endpoint].chem_bonds_valence == at[endpoint].valence) */
9335 : : /* -- the following line takes charges into account -- */
9336 [ + + ]: 70 : if (eif.cDonor) /* means the endpoint has an H-atom to donate */
9337 : : {
9338 : : /* increment edge flow */
9339 : 35 : edge->flow++;
9340 : : /* increment one vertex st-flow & cap */
9341 : 35 : vert_ficpoint->st_edge.flow++;
9342 : 35 : vert_ficpoint->st_edge.cap++;
9343 : : /* increment another vertex st-flow & cap */
9344 : 35 : vert_endpoint->st_edge.flow++;
9345 : 35 : vert_endpoint->st_edge.cap++;
9346 : : }
9347 : : /* Connect edge to endpoint and fictpoint and increment the counters of neighbors and edges */
9348 : 70 : edge->neighbor1 = endpoint; /* the smallest out of v1=endopoint and v2=num_vertices */
9349 : 70 : edge->neighbor12 = endpoint ^ fictpoint; /* v1 ^ v2 */
9350 : 70 : vert_endpoint->iedge[vert_endpoint->num_adj_edges] = num_edges;
9351 : 70 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
9352 : 70 : edge->neigh_ord[0] = vert_endpoint->num_adj_edges++;
9353 : 70 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
9354 : 70 : edge->cap0 = edge->cap;
9355 : 70 : edge->flow0 = edge->flow;
9356 : : }
9357 : :
9358 : 19 : pBNS->num_edges = num_edges;
9359 : 19 : pBNS->num_vertices += nMaxTGroupNumber;
9360 : 19 : pBNS->num_t_groups = num_tg;
9361 : : }
9362 : :
9363 : 19 : return ret;
9364 : : }
9365 : :
9366 : :
9367 : : /*#if ( MOVE_CHARGES == 1 )*/ /* { */
9368 : :
9369 : :
9370 : : /****************************************************************************/
9371 : 19 : int AddCGroups2BnStruct( CANON_GLOBALS *pCG,
9372 : : BN_STRUCT *pBNS,
9373 : : inp_ATOM *at,
9374 : : int num_atoms,
9375 : : C_GROUP_INFO *cgi )
9376 : : {
9377 : 19 : int ret = 0;
9378 : : /* ret = ReInitBnStruct( pBNS ); */
9379 [ + - - + : 19 : if (cgi && cgi->num_c_groups && cgi->c_group)
- - ]
9380 : : {
9381 : : int i, k, c_point, centerpoint, fictpoint;
9382 : 0 : int num_cg = cgi->num_c_groups;
9383 : 0 : int num_edges = pBNS->num_edges;
9384 : 0 : int num_vertices = pBNS->num_vertices;
9385 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing charge c-group */
9386 : : BNS_VERTEX *vertex_cpoint;
9387 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric c_point */
9388 : 0 : int nMaxCGroupNumber = 0;
9389 : :
9390 : : /* Debug: check overflow */
9391 [ # # ]: 0 : if (num_vertices + num_cg >= pBNS->max_vertices)
9392 : : {
9393 : 0 : return BNS_VERT_EDGE_OVFL;
9394 : : }
9395 : : /* Find the largest t-group ID */
9396 [ # # ]: 0 : for (i = 0; i < num_cg; i++)
9397 : : {
9398 [ # # ]: 0 : if (cgi->c_group[i].nGroupNumber > nMaxCGroupNumber)
9399 : : {
9400 : 0 : nMaxCGroupNumber = cgi->c_group[i].nGroupNumber;
9401 : : }
9402 : : }
9403 : : /* Since t-group IDs may be not contiguous, clear all vertices that will be added.
9404 : : all-zeroes-vertex will be ignored by the BNS
9405 : : */
9406 : 0 : memset( pBNS->vert + num_vertices, 0, nMaxCGroupNumber * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
9407 : : /* Make sure the last t-group has the largest t-group ID:
9408 : : this is necessary to correctly add new edges and vertices for testing augmenting paths
9409 : : */
9410 : : #if ( bRELEASE_VERSION != 1 )
9411 : : insertions_sort( cgi->c_group, num_cg, sizeof( cgi->c_group[0] ), CompCGroupNumber );
9412 : : for (i = 1; i < num_cg; i++)
9413 : : {
9414 : : if (1 != cgi->c_group[i].nGroupNumber - cgi->c_group[i - 1].nGroupNumber)
9415 : : {
9416 : : return BNS_BOND_ERR;
9417 : : }
9418 : : }
9419 : : #else
9420 [ # # ]: 0 : if (nMaxCGroupNumber != cgi->c_group[num_cg - 1].nGroupNumber)
9421 : : {
9422 : 0 : insertions_sort( pCG, cgi->c_group, num_cg,
9423 : : sizeof( cgi->c_group[0] ),
9424 : : CompCGroupNumber );
9425 : : }
9426 : : #endif
9427 : : /**************************************/
9428 : : /* initialize new fictitious vertices */
9429 : : /* representing c-point groups */
9430 : : /**************************************/
9431 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
9432 : :
9433 [ # # ]: 0 : for (i = 0; i < num_cg; i++, ver_ficpont_prev = vert_ficpoint)
9434 : : {
9435 : : /*
9436 : : vert_ficpoint-1 is the last vertex;
9437 : : vert_ficpoint is the being added vertex
9438 : : Note: nGroupNumber are not contiguous
9439 : : */
9440 : 0 : vert_ficpoint = pBNS->vert + num_vertices + cgi->c_group[i].nGroupNumber - 1;
9441 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
9442 : 0 : vert_ficpoint->max_adj_edges = cgi->c_group[i].num_CPoints + BNS_ADD_EDGES;
9443 : 0 : vert_ficpoint->num_adj_edges = 0;
9444 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
9445 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
9446 : 0 : vert_ficpoint->type = BNS_VERT_TYPE_C_GROUP;
9447 : : }
9448 : :
9449 : : /************************************************/
9450 : : /* Connect c-points to the fictitious vertices */
9451 : : /* representing c-point groups; set caps, flows */
9452 : : /************************************************/
9453 [ # # ]: 0 : for (c_point = 0; c_point < num_atoms; c_point++)
9454 : : {
9455 [ # # ]: 0 : if (!at[c_point].c_point)
9456 : : {
9457 : 0 : continue;
9458 : : }
9459 : 0 : fictpoint = at[c_point].c_point + num_vertices - 1; /* c-group vertex index */
9460 : 0 : vert_ficpoint = pBNS->vert + fictpoint; /* c-group vertex */
9461 : 0 : vertex_cpoint = pBNS->vert + c_point; /* c_point vertex */
9462 : : /* Debug: check overflow */
9463 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
9464 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
9465 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
9466 [ # # ]: 0 : vertex_cpoint->num_adj_edges >= vertex_cpoint->max_adj_edges)
9467 : : {
9468 : 0 : ret = BNS_VERT_EDGE_OVFL;
9469 : 0 : break;
9470 : : }
9471 : 0 : vertex_cpoint->type |= BNS_VERT_TYPE_C_POINT;
9472 : : #if ( FIX_CPOINT_BOND_CAP != 1 ) /* { */
9473 : : /* set capacity = 1 to the edges from the c_point to the centerpoint(s) */
9474 : : /* if their current capacity is zero */
9475 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
9476 : : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
9477 : : {
9478 : : int iedge = vertex_cpoint->iedge[k];
9479 : : if (!pBNS->edge[iedge].cap)
9480 : : {
9481 : : /* single bond, possibly between c_point and centerpoint */
9482 : : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
9483 : : if (centerpoint < pBNS->num_atoms &&
9484 : : pBNS->vert[centerpoint].st_edge.cap >= 1)
9485 : : {
9486 : : int bond_type = ( at[c_point].bond_type[k] & BOND_TYPE_MASK );
9487 : : if (bond_type == BOND_TAUTOM ||
9488 : : bond_type == BOND_ALTERN ||
9489 : : bond_type == BOND_SINGLE)
9490 : : {
9491 : : pBNS->edge[iedge].cap = 1;
9492 : : }
9493 : : }
9494 : : }
9495 : : }
9496 : : #endif /* } FIX_CPOINT_BOND_CAP */
9497 : :
9498 : : /* Create a new edge connecting c_point to the new fictitious c-group vertex vert_ficpoint */
9499 : 0 : edge = pBNS->edge + num_edges;
9500 : 0 : edge->cap = 1;
9501 : 0 : edge->flow = 0;
9502 : 0 : edge->pass = 0;
9503 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
9504 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask;
9505 : : #endif
9506 : : /* Mark edge to c-point having NO moveable charge with flow=1 */
9507 [ # # ]: 0 : if (!CHARGED_CPOINT( at, c_point ))
9508 : : {
9509 : : /* Increment edge flow */
9510 : 0 : edge->flow++;
9511 : : /* Increment c-group vertex st-flow & cap */
9512 : 0 : vert_ficpoint->st_edge.flow++;
9513 : 0 : vert_ficpoint->st_edge.cap++;
9514 : : /* Increment c-point vertex st-flow & cap */
9515 : 0 : vertex_cpoint->st_edge.flow++;
9516 : 0 : vertex_cpoint->st_edge.cap++;
9517 : : }
9518 : :
9519 : : #if ( FIX_CPOINT_BOND_CAP == 1 ) /* { */
9520 : :
9521 : : /* Set capacity = 1 to the edges from the c_point to the centerpoint(s) */
9522 : : /* if their current capacity is zero */
9523 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
9524 [ # # ]: 0 : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
9525 : : {
9526 : 0 : int iedge = vertex_cpoint->iedge[k];
9527 : 0 : VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
9528 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
9529 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
9530 : : {
9531 : : /* Single bond, possibly between c_point and centerpoint */
9532 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
9533 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
9534 : : {
9535 : 0 : nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
9536 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
9537 : 0 : pBNS->edge[iedge].cap = nNewCap;
9538 : : }
9539 : : #if ( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
9540 : : else
9541 : : if (centerpoint < pBNS->num_atoms &&
9542 : : edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP)
9543 : : {
9544 : : pBNS->edge[iedge].cap++;
9545 : : }
9546 : : #endif
9547 : : }
9548 : : }
9549 : : #endif /* } FIX_CPOINT_BOND_CAP */
9550 : :
9551 : : /* Connect edge to c_point and fictpoint and increment the counters of neighbors and edges */
9552 : 0 : edge->neighbor1 = c_point; /* the smallest out of v1=endopoint and v2=num_vertices */
9553 : 0 : edge->neighbor12 = c_point ^ fictpoint; /* v1 ^ v2 */
9554 : 0 : vertex_cpoint->iedge[vertex_cpoint->num_adj_edges] = num_edges;
9555 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
9556 : 0 : edge->neigh_ord[0] = vertex_cpoint->num_adj_edges++;
9557 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
9558 : 0 : edge->cap0 = edge->cap;
9559 : 0 : edge->flow0 = edge->flow;
9560 : : }
9561 : :
9562 : 0 : pBNS->num_edges = num_edges;
9563 : 0 : pBNS->num_vertices += nMaxCGroupNumber;
9564 : 0 : pBNS->num_c_groups = num_cg;
9565 : : }
9566 : :
9567 : 19 : return ret;
9568 : : }
9569 : : /*#endif*/ /* } MOVE_CHARGES == 1 */
9570 : :
9571 : :
9572 : :
9573 : : /****************************************************************************/
9574 : 161 : void ClearAllBnDataVertices( Vertex *v, Vertex value, int size )
9575 : : {
9576 : : int i;
9577 [ + + ]: 4689 : for (i = 0; i < size; i++)
9578 : : {
9579 : 4528 : v[i] = value;
9580 : : }
9581 : 161 : }
9582 : :
9583 : :
9584 : : /****************************************************************************/
9585 : 161 : void ClearAllBnDataEdges( Edge *e, Vertex value, int size )
9586 : : {
9587 : : int i;
9588 [ + + ]: 4689 : for (i = 0; i < size; i++)
9589 : : {
9590 : 4528 : e[i][0] = value;
9591 : : }
9592 : 161 : }
9593 : :
9594 : :
9595 : : /****************************************************************************/
9596 : 161 : BN_DATA *DeAllocateBnData( BN_DATA *pBD )
9597 : : {
9598 [ + - ]: 161 : if (pBD)
9599 : : {
9600 [ + - ]: 161 : if (pBD->BasePtr)
9601 : : {
9602 [ + - ]: 161 : inchi_free( pBD->BasePtr );
9603 : : }
9604 [ + - ]: 161 : if (pBD->SwitchEdge)
9605 : : {
9606 [ + - ]: 161 : inchi_free( pBD->SwitchEdge );
9607 : : }
9608 [ + - ]: 161 : if (pBD->Tree)
9609 : : {
9610 [ + - ]: 161 : inchi_free( pBD->Tree );
9611 : : }
9612 [ + - ]: 161 : if (pBD->ScanQ)
9613 : : {
9614 [ + - ]: 161 : inchi_free( pBD->ScanQ );
9615 : : }
9616 [ + - ]: 161 : if (pBD->Pu)
9617 : : {
9618 [ + - ]: 161 : inchi_free( pBD->Pu );
9619 : : }
9620 [ + - ]: 161 : if (pBD->Pv)
9621 : : {
9622 [ + - ]: 161 : inchi_free( pBD->Pv );
9623 : : }
9624 : : #if ( BNS_RAD_SEARCH == 1 )
9625 [ + - ]: 161 : if (pBD->RadEndpoints)
9626 : : {
9627 [ + - ]: 161 : inchi_free( pBD->RadEndpoints );
9628 : : }
9629 [ + - ]: 161 : if (pBD->RadEdges)
9630 : : {
9631 [ + - ]: 161 : inchi_free( pBD->RadEdges );
9632 : : }
9633 : : #endif
9634 [ + - ]: 161 : inchi_free( pBD );
9635 : : }
9636 : :
9637 : 161 : return NULL;
9638 : : }
9639 : :
9640 : :
9641 : : /****************************************************************************/
9642 : 161 : BN_DATA *AllocateAndInitBnData( int max_num_vertices )
9643 : : {
9644 : 161 : BN_DATA *pBD = NULL;
9645 : : int max_len_Pu_Pv;
9646 : 161 : max_num_vertices = 2 * max_num_vertices + 2;
9647 : 161 : max_len_Pu_Pv = max_num_vertices / 2 + 1;
9648 : 161 : max_len_Pu_Pv += max_len_Pu_Pv % 2; /* even length */
9649 [ + - ]: 161 : if (!( pBD = (BN_DATA *) inchi_calloc( 1, sizeof( BN_DATA ) ) ) ||
9650 [ + - ]: 161 : !( pBD->BasePtr = (Vertex *) inchi_calloc( max_num_vertices, sizeof( Vertex ) ) ) ||
9651 [ + - ]: 161 : !( pBD->SwitchEdge = (Edge *) inchi_calloc( max_num_vertices, sizeof( Edge ) ) ) ||
9652 [ + - ]: 161 : !( pBD->Tree = (S_CHAR *) inchi_calloc( max_num_vertices, sizeof( S_CHAR ) ) ) ||
9653 [ + - ]: 161 : !( pBD->ScanQ = (Vertex *) inchi_calloc( max_num_vertices, sizeof( Vertex ) ) ) ||
9654 [ + - ]: 161 : !( pBD->Pu = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof( Vertex ) ) ) ||
9655 : : #if ( BNS_RAD_SEARCH == 1 )
9656 [ + - ]: 161 : !( pBD->RadEndpoints = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof( Vertex ) ) ) ||
9657 [ + - ]: 161 : !( pBD->RadEdges = (EdgeIndex*) inchi_calloc( max_len_Pu_Pv, sizeof( EdgeIndex ) ) ) ||
9658 : : #endif
9659 [ - + ]: 161 : !( pBD->Pv = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof( Vertex ) ) )
9660 : : )
9661 : : {
9662 : 0 : pBD = DeAllocateBnData( pBD );
9663 : : }
9664 : : else
9665 : : {
9666 : : /* Initialize data */
9667 : 161 : ClearAllBnDataEdges( pBD->SwitchEdge, NO_VERTEX, max_num_vertices );
9668 : 161 : ClearAllBnDataVertices( pBD->BasePtr, NO_VERTEX, max_num_vertices );
9669 : 161 : memset( pBD->Tree, TREE_NOT_IN_M, max_num_vertices ); /* djb-rwth: memset_s C11/Annex K variant? */
9670 : 161 : pBD->QSize = -1;
9671 : 161 : pBD->max_len_Pu_Pv = max_len_Pu_Pv;
9672 : 161 : pBD->max_num_vertices = max_num_vertices;
9673 : : #if ( BNS_RAD_SEARCH == 1 )
9674 : 161 : pBD->nNumRadEndpoints = 0;
9675 : : #endif
9676 : : }
9677 : :
9678 : 161 : return pBD;
9679 : : }
9680 : :
9681 : :
9682 : : /****************************************************************************/
9683 : 248 : int ReInitBnData( BN_DATA *pBD )
9684 : : {
9685 : 248 : int i, ret = 0;
9686 : : Vertex u, v;
9687 [ + - ]: 248 : if (pBD)
9688 : : {
9689 [ - + ]: 248 : if (!pBD->ScanQ)
9690 : : {
9691 : 0 : ret += 2;
9692 : : }
9693 [ - + ]: 248 : if (!pBD->BasePtr)
9694 : : {
9695 : 0 : ret += 4;
9696 : : }
9697 [ - + ]: 248 : if (!pBD->SwitchEdge)
9698 : : {
9699 : 0 : ret += 8;
9700 : : }
9701 [ - + ]: 248 : if (!pBD->Tree)
9702 : : {
9703 : 0 : ret += 16;
9704 : : }
9705 [ + - ]: 248 : if (!ret)
9706 : : {
9707 [ + + ]: 941 : for (i = 0; i <= pBD->QSize; i++)
9708 : : {
9709 : 693 : u = pBD->ScanQ[i];
9710 : 693 : v = prim( u );
9711 : 693 : pBD->BasePtr[u] =
9712 : 693 : pBD->BasePtr[v] =
9713 : 693 : pBD->SwitchEdge_Vert1( u ) =
9714 : 693 : pBD->SwitchEdge_Vert1( v ) = NO_VERTEX;
9715 : 693 : pBD->Tree[u] =
9716 : 693 : pBD->Tree[v] = TREE_NOT_IN_M;
9717 : : }
9718 : : }
9719 : 248 : pBD->QSize = -1;
9720 [ - + ]: 248 : if (!pBD->Pu)
9721 : : {
9722 : 0 : ret += 32;
9723 : : }
9724 [ - + ]: 248 : if (!pBD->Pv)
9725 : : {
9726 : 0 : ret += 64;
9727 : : }
9728 : : }
9729 : : else
9730 : : {
9731 : 0 : ret += 1;
9732 : : }
9733 : :
9734 : 248 : return ret;
9735 : : }
9736 : :
9737 : :
9738 : : /****************************************************************************/
9739 : 456 : int GetVertexDegree( BN_STRUCT* pBNS, Vertex v )
9740 : : {
9741 : 456 : int i = v / 2 - 1;
9742 [ + + ]: 456 : if (i >= 0)
9743 : : {
9744 [ + + ]: 208 : if (pBNS->vert[i].st_edge.cap > 0)
9745 : : {
9746 : 186 : return pBNS->vert[i].num_adj_edges + 1; /* add 1 neighbor for s or t */
9747 : : }
9748 : : else
9749 : : {
9750 : 22 : return 0; /* since the edge s-v has zero capacity, we ignore vertex v */
9751 : : }
9752 : : }
9753 : : else
9754 : : {
9755 : 248 : return pBNS->num_vertices;
9756 : : }
9757 : : }
9758 : :
9759 : :
9760 : : /****************************************************************************/
9761 : 536 : Vertex Get2ndEdgeVertex( BN_STRUCT* pBNS, Edge uv )
9762 : : {
9763 : : /*
9764 : : Vertex ret;
9765 : : */
9766 [ + + ]: 536 : if (uv[1] >= 0)
9767 : : {
9768 : : /* -- debug --
9769 : : if ( uv[1] > pBNS->num_edges || uv[0] > 2*pBNS->num_vertices+3 ) {
9770 : : int stop = 1;
9771 : : }
9772 : : ret = ((uv[0]-2) ^ (2*pBNS->edge[uv[1]].neighbor12+1)) + 2;
9773 : : if ( ret > 2*pBNS->num_vertices+3 ) {
9774 : : int stop = 1;
9775 : : }
9776 : : return ret;
9777 : : -- end debug -- */
9778 : :
9779 : 293 : return ( ( uv[0] - 2 ) ^ ( 2 * pBNS->edge[uv[1]].neighbor12 + 1 ) ) + 2;
9780 : :
9781 : : /*short u = uv[0]-FIRST_INDX; */
9782 : : /*short t = 2*(((u / 2 - 1) ^ pBNS->edge[uv[1]].neighbor12) + 1) + ((u+1) & 1) + FIRST_INDX; */
9783 : : /*return t; */
9784 : : }
9785 : :
9786 [ + - ]: 243 : if (uv[0] <= 1)
9787 : : {
9788 : 243 : return -( 1 + uv[1] ); /* vertex1 is s or t, return x or y */
9789 : : }
9790 : : else
9791 : : {
9792 : 0 : return uv[0] % 2; /* vertex1 is x or y, return s or t; never happens? -- NSC 3737, 7634,... */
9793 : : }
9794 : :
9795 : : }
9796 : :
9797 : :
9798 : : /****************************************************************************/
9799 : 2755 : Vertex GetVertexNeighbor( BN_STRUCT* pBNS,
9800 : : Vertex v,
9801 : : int neigh,
9802 : : EdgeIndex *iedge )
9803 : : {
9804 : : /* neigh = 0 => the neighbor is s or t except case when v is s or t. */
9805 : : /* v= FIRST_INDX or FIRST_INDX+1: v is s or t respectively */
9806 : : int i, neighbor;
9807 [ + + ]: 2755 : if (( i = v - 2 ) >= 0)
9808 : : {
9809 : : /* Neighbor of x or y */
9810 [ + + ]: 589 : if (neigh)
9811 : : {
9812 : 403 : neigh--;
9813 : : /* x or y */
9814 : 403 : *iedge = pBNS->vert[i / 2].iedge[neigh];
9815 [ + + + + ]: 403 : if (!( pBNS->edge[*iedge].cap & EDGE_FLOW_MASK ) || IS_FORBIDDEN( pBNS->edge[*iedge].forbidden, pBNS ))
9816 : : {
9817 : 90 : return NO_VERTEX;
9818 : : }
9819 : 313 : neighbor = ( i ^ ( 2 * pBNS->edge[*iedge].neighbor12 + 1 ) ) + 2; /* parity opposite to v parity */
9820 : : }
9821 : : else
9822 : : {
9823 : : /* neighbor of x or y is s or t */
9824 : 186 : neighbor = ( v & 1 ); /* s or t, same parity as v */
9825 : 186 : *iedge = -( neighbor + 1 );
9826 : : }
9827 : : }
9828 : : else
9829 : : {
9830 : : /* neighbor of s or t: x or y, same parity as v */
9831 [ + + ]: 2166 : if (!( pBNS->vert[neigh].st_edge.cap & EDGE_FLOW_ST_MASK ))
9832 : : {
9833 : 1071 : return NO_VERTEX;
9834 : : }
9835 : 1095 : neighbor = 2 * neigh + 2 + ( v & 1 ); /* parity same as the parity of v */
9836 : 1095 : *iedge = -( neighbor + 1 );
9837 : : }
9838 : :
9839 : 1594 : return neighbor;
9840 : : }
9841 : :
9842 : :
9843 : : /****************************************************************************/
9844 : 1778 : int GetEdgePointer( BN_STRUCT* pBNS,
9845 : : Vertex u,
9846 : : Vertex v,
9847 : : EdgeIndex iuv,
9848 : : BNS_EDGE **uv,
9849 : : S_CHAR *s_or_t )
9850 : : {
9851 : 1778 : int i = u / 2 - 1;
9852 : 1778 : int j = v / 2 - 1;
9853 : 1778 : int bBackward = BNS_WRONG_PARMS;
9854 : 1778 : *uv = NULL;
9855 [ + + ]: 1778 : if (i >= 0)
9856 : : {
9857 : : /* u is an atom */
9858 [ + + ]: 531 : if (j >= 0)
9859 : : {
9860 : : /* v is an atom */
9861 [ + - ]: 436 : if (( u + v ) % 2)
9862 : : {
9863 : 436 : *uv = pBNS->edge + iuv;
9864 : 436 : bBackward = ( u & 1 );
9865 : 436 : *s_or_t = 0;
9866 : : }
9867 : : }
9868 : : else
9869 : : {
9870 : : /* v is s or t */
9871 [ + - + - ]: 95 : if (v >= 0 && !( ( u + v ) % 2 ))
9872 : : {
9873 : 95 : *uv = (BNS_EDGE*) &pBNS->vert[i].st_edge;
9874 : 95 : bBackward = !( v & 1 );
9875 : 95 : *s_or_t = v + 3; /* 3=> v=s, 4=> v=t */
9876 : : }
9877 : : }
9878 : : }
9879 : : else
9880 : : {
9881 [ + - ]: 1247 : if (j >= 0)
9882 : : {
9883 : : /* u is s or t */
9884 [ + - + - ]: 1247 : if (u >= 0 && !( ( u + v ) % 2 ))
9885 : : {
9886 : : /* v is an atom */
9887 : 1247 : *uv = (BNS_EDGE*) &pBNS->vert[j].st_edge;
9888 : 1247 : bBackward = ( u & 1 );
9889 : 1247 : *s_or_t = u + 1; /* 1=> u=s, 2=> u=t */
9890 : : }
9891 : : }
9892 : : }
9893 : :
9894 : 1778 : return bBackward;
9895 : : }
9896 : :
9897 : :
9898 : : /****************************************************************************/
9899 : 180 : int AugmentEdge( BN_STRUCT* pBNS,
9900 : : Vertex u,
9901 : : Vertex v,
9902 : : EdgeIndex iuv,
9903 : : int delta,
9904 : : S_CHAR bReverse,
9905 : : int bChangeFlow )
9906 : : {
9907 : 180 : int f, flow, ret = 0;
9908 : :
9909 : : BNS_ST_EDGE *pst_edge;
9910 : : BNS_EDGE *pedge;
9911 : : S_CHAR s_or_t;
9912 : 180 : int bBackward = GetEdgePointer( pBNS, u, v, iuv, &pedge, &s_or_t );
9913 [ + - + - ]: 180 : if (!IS_BNS_ERROR( bBackward ))
9914 : : {
9915 [ + + ]: 180 : if (bBackward)
9916 : : {
9917 : 33 : delta = -delta;
9918 : : }
9919 : :
9920 [ + + ]: 180 : if (s_or_t)
9921 : : {
9922 : 76 : pst_edge = (BNS_ST_EDGE *) pedge;
9923 : 76 : flow = pst_edge->flow;
9924 : 76 : f = ( flow & EDGE_FLOW_ST_MASK ) + delta; /* new flow */
9925 [ - + ]: 76 : if (!delta)
9926 : : {
9927 : : /*((BNS_ST_EDGE *)pedge)->flow = pst_edge->flow & ~EDGE_FLOW_ST_PATH;*/
9928 : 0 : pst_edge->flow = pst_edge->flow & ~EDGE_FLOW_ST_PATH;
9929 : : }
9930 : : else
9931 : : {
9932 : 76 : int cap = pst_edge->cap;
9933 [ + - - + ]: 76 : if (f < 0 || f > cap)
9934 : : {
9935 : 0 : ret = BNS_WRONG_PARMS;
9936 : : }
9937 : : else
9938 : : {
9939 [ - + ]: 76 : if (!( bChangeFlow & BNS_EF_CHNG_FLOW ))
9940 : : {
9941 : 0 : f -= delta; /* do not actually change the flow, only find the augmenting path */
9942 : : }
9943 : : else
9944 : : {
9945 [ + - ]: 76 : if (delta)
9946 : : {
9947 : : /*((BNS_ST_EDGE *)pedge)->pass ++;*/
9948 : 76 : pst_edge->pass++;
9949 : : }
9950 : : }
9951 : 76 : flow = ( flow & ~( EDGE_FLOW_ST_PATH | EDGE_FLOW_ST_MASK ) ) + f;
9952 : : /*((BNS_ST_EDGE *)pedge)->flow = flow;*/
9953 : 76 : pst_edge->flow = flow;
9954 : : /*((BNS_ST_EDGE *)pedge)->delta += delta; */
9955 [ + + ]: 76 : if (bReverse)
9956 : : {
9957 : : /* u <- v; Note: in case of bReverse s_or_t has actually been determined
9958 : : for the u' <- v' pair; therefore s and t should be switched
9959 : : in order to correctly determine the 1st or the last atom
9960 : : on the augmenting path.
9961 : : */
9962 [ + - - - : 38 : switch (s_or_t)
- ]
9963 : : {
9964 : 38 : case 1: /* u = t: t<-v, v is the last vertex */
9965 : 38 : ALTP_END_ATOM( pBNS->alt_path ) = v / 2 - 1;
9966 : 38 : break;
9967 : 0 : case 2: /* u = s: s<-v, error */
9968 : 0 : ret = BNS_WRONG_PARMS;
9969 : 0 : break;
9970 : 0 : case 3: /* v = t: u<-t, error */
9971 : 0 : ret = BNS_WRONG_PARMS;
9972 : 0 : break;
9973 : 0 : case 4: /* v = s: u<-s, u is the first vertex */
9974 : 0 : ALTP_START_ATOM( pBNS->alt_path ) = u / 2 - 1;
9975 : 0 : ALTP_DELTA( pBNS->alt_path ) = delta;
9976 : 0 : break;
9977 : 0 : default:
9978 : 0 : ret = BNS_WRONG_PARMS;
9979 : 0 : break;
9980 : : }
9981 : : }
9982 : : else
9983 : : {
9984 : : /* u -> v */
9985 [ + - - - : 38 : switch (s_or_t)
- ]
9986 : : {
9987 : 38 : case 1: /* u = s: s->v, v is the first vertex */
9988 : 38 : ALTP_START_ATOM( pBNS->alt_path ) = v / 2 - 1;
9989 : 38 : ALTP_DELTA( pBNS->alt_path ) = delta;
9990 : 38 : break;
9991 : 0 : case 2: /* u = t: t->v, error */
9992 : 0 : ret = BNS_WRONG_PARMS;
9993 : 0 : break;
9994 : 0 : case 3: /* v = s: u->s, error */
9995 : 0 : ret = BNS_WRONG_PARMS;
9996 : 0 : break;
9997 : 0 : case 4: /* v = t: u->t, u is the last vertex */
9998 : 0 : ALTP_END_ATOM( pBNS->alt_path ) = u / 2 - 1;
9999 : 0 : break;
10000 : 0 : default:
10001 : 0 : ret = BNS_WRONG_PARMS;
10002 : 0 : break;
10003 : : }
10004 : : }
10005 : : }
10006 : : }
10007 : : }
10008 : : else
10009 : : {
10010 : 104 : f = ( pedge->flow & EDGE_FLOW_MASK ) + delta;
10011 [ - + ]: 104 : if (!delta)
10012 : : {
10013 : 0 : pedge->flow &= ~EDGE_FLOW_PATH;
10014 : : }
10015 : : else
10016 : : {
10017 [ + - - + ]: 104 : if (f < 0 || f > pedge->cap)
10018 : : {
10019 : 0 : ret = BNS_WRONG_PARMS;
10020 : : }
10021 : : else
10022 : : {
10023 : 104 : AT_NUMB iu = u / 2 - 1;
10024 : 104 : AT_NUMB iv = v / 2 - 1;
10025 : : int indx;
10026 [ - + ]: 104 : if (!( bChangeFlow & BNS_EF_CHNG_FLOW ))
10027 : : {
10028 : 0 : f -= delta; /* do not actually change the flow, only find the augmenting path */
10029 : : }
10030 : : else
10031 : : {
10032 [ + - ]: 104 : if (delta)
10033 : : {
10034 : 104 : pedge->pass++;
10035 : : }
10036 : : }
10037 : 104 : pedge->flow = ( pedge->flow & ~( EDGE_FLOW_PATH | EDGE_FLOW_MASK ) ) | f;
10038 [ + - ]: 104 : if (ALTP_MAY_ADD( pBNS->alt_path ))
10039 : : {
10040 : : /* bReverse? u <- v : u -> v */
10041 [ + + ]: 104 : indx = bReverse ? ( pedge->neighbor1 == iv ) : ( pedge->neighbor1 == iu );
10042 : 104 : ALTP_CUR_THIS_ATOM_NEIGHBOR( pBNS->alt_path ) = pedge->neigh_ord[1 - indx];
10043 : 104 : ALTP_CUR_NEXT_ATOM_NEIGHBOR( pBNS->alt_path ) = pedge->neigh_ord[indx];
10044 : 104 : ALTP_NEXT( pBNS->alt_path );
10045 : : }
10046 : : else
10047 : : {
10048 : 0 : ALTP_OVERFLOW( pBNS->alt_path ) = 1;
10049 : 0 : ret = BNS_ALTPATH_OVFL;
10050 : : }
10051 : : }
10052 : : }
10053 : : }
10054 [ - + ]: 180 : return ret ? ret : f;
10055 : : }
10056 : :
10057 : 0 : return bBackward;
10058 : : }
10059 : :
10060 : :
10061 : : /****************************************************************************
10062 : : rescap_mark( ... )
10063 : :
10064 : : Find residual capacity and mark the edge
10065 : : as belonging to the augmenting path
10066 : : ****************************************************************************/
10067 : 180 : int rescap_mark( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
10068 : : {
10069 : : BNS_ST_EDGE *pst_edge;
10070 : : BNS_EDGE *pedge;
10071 : :
10072 : : int f, flow;
10073 : : S_CHAR s_or_t;
10074 : 180 : int bBackward = GetEdgePointer( pBNS, u, v, iuv, &pedge, &s_or_t );
10075 : :
10076 [ + - + - ]: 180 : if (!IS_BNS_ERROR( bBackward ))
10077 : : {
10078 [ + + ]: 180 : if (s_or_t)
10079 : : {
10080 : 76 : pst_edge = (BNS_ST_EDGE *) pedge;
10081 : 76 : flow = pst_edge->flow;
10082 : 76 : f = ( flow & EDGE_FLOW_ST_MASK );
10083 [ + - ]: 76 : if (!bBackward)
10084 : : {
10085 : 76 : f = (int) pst_edge->cap - f;
10086 : : }
10087 [ - + ]: 76 : if (flow & EDGE_FLOW_ST_PATH)
10088 : : {
10089 : 0 : pBNS->bNotASimplePath++;
10090 : 0 : f /= 2; /* this is the second time we pass the same edge: reduce flow by a factor of 2 */
10091 : : }
10092 : : else
10093 : : {
10094 : 76 : pst_edge->flow |= EDGE_FLOW_ST_PATH; /* mark the edge */
10095 : : }
10096 : : }
10097 : : else
10098 : : {
10099 : 104 : flow = pedge->flow;
10100 : 104 : f = flow & EDGE_FLOW_MASK;
10101 [ + + ]: 104 : if (!bBackward)
10102 : : {
10103 : 71 : f = (int) pedge->cap - f;
10104 : : }
10105 [ - + ]: 104 : if (flow & EDGE_FLOW_PATH)
10106 : : {
10107 : 0 : f /= 2; /* this is the second time we pass the same edge: reduce flow by a factor of 2 */
10108 : 0 : pBNS->bNotASimplePath++;
10109 : : }
10110 : : else
10111 : : {
10112 : 104 : pedge->flow |= EDGE_FLOW_PATH; /* mark the edge */
10113 : : }
10114 : : }
10115 : 180 : return f;
10116 : : }
10117 : :
10118 : 0 : return bBackward;
10119 : : }
10120 : :
10121 : :
10122 : : /****************************************************************************
10123 : : GetPrevVertex( ... )
10124 : :
10125 : : Get previous vertex in the searched path
10126 : : z is SwitchEdge_Vert2(y) != y. Go backward from z to y
10127 : : ****************************************************************************/
10128 : 0 : Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv )
10129 : : {
10130 : : Vertex w, z, x2, y2; /* djb-rwth: removing redundant variables */
10131 : : EdgeIndex iwy;
10132 : :
10133 : 0 : w = SwitchEdge_Vert1( y );
10134 : 0 : z = SwitchEdge_Vert2( y );
10135 : 0 : iwy = SwitchEdge_IEdge( y );
10136 [ # # ]: 0 : if (z == y)
10137 : : {
10138 : 0 : *iuv = iwy;
10139 : 0 : return w;
10140 : : }
10141 : 0 : x2 = prim( y );
10142 : 0 : y2 = prim( z );
10143 : : /* djb-rwth: removing redundant code */
10144 [ # # ]: 0 : while (y2 != NO_VERTEX)
10145 : : {
10146 : 0 : w = SwitchEdge_Vert1( y2 );
10147 : 0 : z = SwitchEdge_Vert2( y2 );
10148 : 0 : iwy = SwitchEdge_IEdge( y2 );
10149 [ # # ]: 0 : if (w == x2)
10150 : : {
10151 : 0 : *iuv = iwy;
10152 : : /*return z; */
10153 [ # # ]: 0 : return ( y + z ) % 2 ? z : prim( z );
10154 : : }
10155 : : /* djb-rwth: removing redundant code */
10156 : : /*
10157 : : #ifdef _DEBUG
10158 : : if ( n ) {
10159 : : int stop = 1;
10160 : : }
10161 : : #endif
10162 : : */
10163 [ # # ]: 0 : if (w == y2)
10164 : : {
10165 : 0 : return NO_VERTEX;
10166 : : }
10167 : 0 : y2 = w;
10168 : : }
10169 : :
10170 : 0 : return y2;
10171 : : }
10172 : :
10173 : :
10174 : :
10175 : : #define CHECK_TACN 1
10176 : :
10177 : :
10178 : : /****************************************************************************
10179 : : The purpose is to avoid paths
10180 : :
10181 : : (H-group)[u]---atom[v]---((-)-cgroup)[w],
10182 : :
10183 : : where atom[v] is not acidic and (-) and H are not interchangeable without
10184 : : explicit bond tautomerism.
10185 : :
10186 : : It is important that acidic atoms are only O,S,Se,Te and should have
10187 : : only one chemical bond. Only because of this an early rejection of
10188 : : the vertex v (before it gets on SCANQ) is possible.
10189 : :
10190 : : CHECK_TACN == 1 prohibits replacing (-) on N with H unless H can be moved to N
10191 : : along an alternating path from another heteroatom (t-group will be detected).
10192 : : ****************************************************************************/
10193 : :
10194 : :
10195 : : #if ( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
10196 : :
10197 : :
10198 : : /****************************************************************************/
10199 : : int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
10200 : : {
10201 : : #define TYPE_T 1 /* t-group [also called H-group] */
10202 : : #define TYPE_CN 2 /* (-)c-group */
10203 : : int i, degree, ret, u_is_taut = 0, w_is_taut, num_allowed = 0, num_found_groups = 0;
10204 : : Vertex w;
10205 : : EdgeIndex ivw;
10206 : : if (!pBNS->type_TACN || u <= 1 || v <= 1 ||
10207 : : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10208 : : {
10209 : : return 0; /* add/remove H(+) is allowed for acidic atoms */
10210 : : }
10211 : : if (!pBNS->type_T || !pBNS->type_CN)
10212 : : {
10213 : : return 0; /* should not happen */
10214 : : }
10215 : : u_is_taut = ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10216 : : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10217 : : if (u_is_taut)
10218 : : {
10219 : : /* u is either t-group vertex or (-) c-group */
10220 : : degree = GetVertexDegree( pBNS, v );
10221 : : for (i = 0; i < degree; i++)
10222 : : {
10223 : : /* v = vert[u].neighbor[i]; */
10224 : : w = GetVertexNeighbor( pBNS, v, i, &ivw );
10225 : : if (w == NO_VERTEX || w <= 1)
10226 : : {
10227 : : continue; /* the atom has only single bonds or it is s or t, ignore it */
10228 : : }
10229 : : if (w != u && ( ret = rescap( pBNS, v, w, ivw ) ) > 0)
10230 : : {
10231 : : num_allowed++;
10232 : : w_is_taut = ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN :
10233 : : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T : 0;
10234 : : if (( u_is_taut | w_is_taut ) == ( TYPE_T | TYPE_CN ))
10235 : : {
10236 : : num_found_groups++;
10237 : : }
10238 : : }
10239 : : }
10240 : : if (num_found_groups && num_allowed == 1)
10241 : : {
10242 : : return 1; /* reject */
10243 : : }
10244 : : }
10245 : :
10246 : : return 0;
10247 : : #undef TYPE_T
10248 : : #undef TYPE_CN
10249 : : }
10250 : :
10251 : :
10252 : : #else /* } FIX_TACN_POSSIBLE_BUG { */
10253 : :
10254 : :
10255 : : /****************************************************************************/
10256 : 0 : int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
10257 : : {
10258 : 0 : int i, degree, ret, u_is_taut = 0, num_allowed = 0, num_found_groups = 0;
10259 : : Vertex w;
10260 : : EdgeIndex ivw;
10261 [ # # # # : 0 : if (!pBNS->type_TACN || u <= 1 || v <= 1 ||
# # ]
10262 [ # # ]: 0 : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10263 : : {
10264 : 0 : return 0; /* add/remove H(+) is allowed for acidic atoms */
10265 : : }
10266 [ # # # # ]: 0 : if (!pBNS->type_T || !pBNS->type_CN)
10267 : : {
10268 : 0 : return 0; /* should not happen */
10269 : : }
10270 [ # # ]: 0 : if (( u_is_taut = ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ||
10271 [ # # ]: 0 : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ))
10272 : : {
10273 : : /* u is either t-group vertex or (-) c-group */
10274 : 0 : degree = GetVertexDegree( pBNS, v );
10275 [ # # ]: 0 : for (i = 0; i < degree; i++)
10276 : : {
10277 : : /* v = vert[u].neighbor[i]; */
10278 : 0 : w = GetVertexNeighbor( pBNS, v, i, &ivw );
10279 [ # # # # ]: 0 : if (w == NO_VERTEX || w <= 1)
10280 : : {
10281 : 0 : continue; /* the atom has only single bonds or it is s or t, ignore it */
10282 : : }
10283 [ # # # # ]: 0 : if (w != u && ( ret = rescap( pBNS, v, w, ivw ) ) > 0) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
10284 : : {
10285 : 0 : num_allowed++;
10286 [ # # # # ]: 0 : if (( u_is_taut ? ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) :
10287 : 0 : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ))
10288 : : {
10289 : 0 : num_found_groups++;
10290 : : }
10291 : : }
10292 : : }
10293 [ # # # # ]: 0 : if (num_found_groups && num_allowed == 1)
10294 : : {
10295 : 0 : return 1; /* reject */
10296 : : }
10297 : : }
10298 : :
10299 : 0 : return 0;
10300 : : }
10301 : :
10302 : :
10303 : :
10304 : : #endif /* } FIX_TACN_POSSIBLE_BUG */
10305 : :
10306 : :
10307 : :
10308 : : /****************************************************************************
10309 : : The purpose is to avoid paths
10310 : : (H-group)[u]---atom[v]---((-)-cgroup)[w],
10311 : :
10312 : : where atom[v] is not acidic and (-) and H are not interchangeable without
10313 : : explicit bond tautomerism.
10314 : :
10315 : : It is important that acidic atoms are only O,S,Se,Te and should have
10316 : : only one chemical bond. Only because of this an early rejection of
10317 : : the vertex v (before it gets on SCANQ) is possible.
10318 : : ****************************************************************************/
10319 : :
10320 : :
10321 : : #if ( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
10322 : :
10323 : :
10324 : : /****************************************************************************/
10325 : : int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS,
10326 : : Vertex v,
10327 : : Vertex w,
10328 : : Edge *SwitchEdge )
10329 : : {
10330 : : #define TYPE_T 1 /* t-group [also called H-group] */
10331 : : #define TYPE_CN 2 /* (-)c-group */
10332 : : int u_is_taut = 0, w_is_taut = 0;
10333 : : Vertex u;
10334 : : EdgeIndex iuv;
10335 : : if (v <= 1 || w <= 1)
10336 : : return 0;
10337 : : #if ( CHECK_TACN == 1 )
10338 : : if (!pBNS->type_TACN ||
10339 : : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10340 : : {
10341 : : return 0;
10342 : : }
10343 : : if (!pBNS->type_T || !pBNS->type_CN)
10344 : : {
10345 : : return 0; /* should not happen */
10346 : : }
10347 : : #endif
10348 : : u = GetPrevVertex( pBNS, v, SwitchEdge, &iuv );
10349 : : /*
10350 : : u = SwitchEdge_Vert1(v);
10351 : : iuv = SwitchEdge_IEdge(v);
10352 : : */
10353 : : if (u == NO_VERTEX || iuv < 0)
10354 : : return 0; /* should not happen */
10355 : : /* check edge adjacency */
10356 : : if (pBNS->edge[iuv].neighbor1 != ( u / 2 - 1 ) && pBNS->edge[iuv].neighbor1 != v / 2 - 1 ||
10357 : : ( pBNS->edge[iuv].neighbor12 ^ ( u / 2 - 1 ) ) != ( v / 2 - 1 ))
10358 : : {
10359 : : return 0; /* !!! should not happen !!! */
10360 : : }
10361 : :
10362 : : #if ( CHECK_TACN == 1 )
10363 : : u_is_taut = ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10364 : : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10365 : : w_is_taut = ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10366 : : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10367 : : if (( u_is_taut | w_is_taut ) == ( TYPE_T | TYPE_CN ))
10368 : : {
10369 : : /* rescap must have already been checked */
10370 : : return 1;
10371 : : }
10372 : : #endif
10373 : :
10374 : : return 0;
10375 : : #undef TYPE_T
10376 : : #undef TYPE_CN
10377 : : }
10378 : :
10379 : :
10380 : : #else /* } FIX_TACN_POSSIBLE_BUG { */
10381 : :
10382 : :
10383 : : /****************************************************************************/
10384 : 0 : int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS,
10385 : : Vertex v,
10386 : : Vertex w,
10387 : : Edge *SwitchEdge )
10388 : : {
10389 : 0 : int u_is_taut = 0, w_is_taut = 0;
10390 : : Vertex u;
10391 : : EdgeIndex iuv;
10392 [ # # # # ]: 0 : if (v <= 1 || w <= 1)
10393 : 0 : return 0;
10394 : : #if ( CHECK_TACN == 1 )
10395 [ # # ]: 0 : if (!pBNS->type_TACN ||
10396 [ # # ]: 0 : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10397 : : {
10398 : 0 : return 0;
10399 : : }
10400 [ # # # # ]: 0 : if (!pBNS->type_T || !pBNS->type_CN)
10401 : : {
10402 : 0 : return 0; /* should not happen */
10403 : : }
10404 : : #endif
10405 : 0 : u = GetPrevVertex( pBNS, v, SwitchEdge, &iuv );
10406 : : /*
10407 : : u = SwitchEdge_Vert1(v);
10408 : : iuv = SwitchEdge_IEdge(v);
10409 : : */
10410 [ # # # # ]: 0 : if (u == NO_VERTEX || iuv < 0)
10411 : : {
10412 : 0 : return 0; /* should not happen */
10413 : : }
10414 : : /* check edge adjacency */
10415 [ # # # # ]: 0 : if ((pBNS->edge[iuv].neighbor1 != ( u / 2 - 1 ) && pBNS->edge[iuv].neighbor1 != v / 2 - 1) ||
10416 [ # # ]: 0 : (( pBNS->edge[iuv].neighbor12 ^ ( u / 2 - 1 ) ) != ( v / 2 - 1 ))) /* djb-rwth: addressing LLVM warning */
10417 : : {
10418 : 0 : return 0; /* !!! should not happen !!! */
10419 : : }
10420 : :
10421 : : #if ( CHECK_TACN == 1 )
10422 [ # # ]: 0 : if (( ( u_is_taut = ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ||
10423 [ # # ]: 0 : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ) &&
10424 [ # # ]: 0 : ( ( w_is_taut = ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ||
10425 [ # # ]: 0 : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ) &&
10426 [ # # ]: 0 : u_is_taut + w_is_taut == 1)
10427 : : {
10428 : : /* rescap must have already been checked */
10429 : 0 : return 1;
10430 : : }
10431 : : #endif
10432 : :
10433 : 0 : return 0;
10434 : : }
10435 : : #endif /* } FIX_TACN_POSSIBLE_BUG { */
10436 : :
10437 : :
10438 : :
10439 : : #if ( FIX_KEEP_H_ON_NH_ANION == 1 )
10440 : :
10441 : :
10442 : : /****************************************************************************
10443 : : bIsRemovedHfromNHaion( ... )
10444 : :
10445 : : Detect an attempt to remove H from -NH(-) to make =N(-);
10446 : : all taut atoma except N are 'acidic'
10447 : : ****************************************************************************/
10448 : : int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v )
10449 : : {
10450 : : int i, u2, v2, vat2;
10451 : : Vertex vtg, vat;
10452 : : BNS_VERTEX *pvAT, *pvCN;
10453 : : BNS_EDGE *pEdge;
10454 : : if (!pBNS->type_TACN || u <= 1 || v <= 1 ||
10455 : : u % 2 || !( v % 2 ) /* the edge flow may only increase */)
10456 : : {
10457 : : return 0;
10458 : : }
10459 : : if (( pBNS->vert[u2 = u / 2 - 1].type & pBNS->type_TACN ) ||
10460 : : ( pBNS->vert[v2 = v / 2 - 1].type & pBNS->type_TACN ))
10461 : : {
10462 : : return 0; /* add/remove H is allowed for acidic atoms */
10463 : : }
10464 : : if (!pBNS->type_T || !pBNS->type_CN)
10465 : : {
10466 : : return 0; /* should not happen */
10467 : : }
10468 : : /* find which of u, v vertices is N and which is t-group */
10469 : : if (( ( pBNS->vert[u2].type & pBNS->type_T ) == pBNS->type_T ) && v2 < pBNS->num_atoms)
10470 : : {
10471 : : vtg = u;
10472 : : vat = v;
10473 : : }
10474 : : else
10475 : : {
10476 : : if (( ( pBNS->vert[v2].type & pBNS->type_T ) == pBNS->type_T ) && u2 < pBNS->num_atoms)
10477 : : {
10478 : : vtg = v;
10479 : : vat = u;
10480 : : }
10481 : : else
10482 : : {
10483 : : return 0;
10484 : : }
10485 : : }
10486 : :
10487 : : vat2 = vat / 2 - 1;
10488 : : pvAT = pBNS->vert + vat2; /* atom */
10489 : : for (i = pvAT->num_adj_edges - 1; 0 <= i; i--)
10490 : : {
10491 : : pEdge = pBNS->edge + pvAT->iedge[i];
10492 : : pvCN = pBNS->vert + ( pEdge->neighbor12 ^ vat2 );
10493 : : if (( ( pvCN->type & pBNS->type_CN ) == pBNS->type_CN ) && pEdge->flow > 0)
10494 : : {
10495 : : return 1; /* detected */
10496 : : }
10497 : : }
10498 : :
10499 : : return 0;
10500 : : }
10501 : : #endif
10502 : :
10503 : :
10504 : : #if ( FIX_AVOID_ADP == 1 )
10505 : :
10506 : : /****************************************************************************
10507 : : bIsAggressiveDeprotonation( ... )
10508 : :
10509 : : Detect (tg)-N=A-A=A-A=N-(tg)
10510 : : u v w
10511 : : k = 5 4 3 2 1 0 1 2
10512 : : ^
10513 : : odd number means ADP
10514 : : ****************************************************************************/
10515 : : int bIsAggressiveDeprotonation( BN_STRUCT* pBNS,
10516 : : Vertex v,
10517 : : Vertex w,
10518 : : Edge *SwitchEdge )
10519 : : {
10520 : : #define TYPE_T 1 /* t-group [also called H-group] */
10521 : : #define TYPE_CN 2 /* (-)c-group */
10522 : : #define TYPE_AT 4
10523 : : int k, v2, u2, w2, u2_next, type0, type1, type2, type;
10524 : : Vertex u, u_next;
10525 : : EdgeIndex iuv;
10526 : :
10527 : : if (v <= 1 || w <= 1)
10528 : : {
10529 : : return 0;
10530 : : }
10531 : :
10532 : : if (!pBNS->type_TACN || !pBNS->type_T || !pBNS->type_CN)
10533 : : {
10534 : : return 0; /* should not happen */
10535 : : }
10536 : :
10537 : : v2 = v / 2 - 1;
10538 : : w2 = w / 2 - 1;
10539 : : if (v2 >= pBNS->num_atoms || w2 < pBNS->num_atoms)
10540 : : {
10541 : : goto cross_edge;
10542 : : }
10543 : :
10544 : : if (!( ( pBNS->vert[w2].type & pBNS->type_T ) == pBNS->type_T ) &&
10545 : : !( ( pBNS->vert[w2].type & pBNS->type_CN ) == pBNS->type_CN ))
10546 : : {
10547 : : goto cross_edge;
10548 : : }
10549 : :
10550 : : /* v ia an atom, w is a t-group, v != w' */
10551 : : for (k = 0, u = v; 1 < ( u_next = u, u = GetPrevVertex( pBNS, u, SwitchEdge, &iuv ) ); k++)
10552 : : {
10553 : : u2 = u / 2 - 1;
10554 : : if (u2 >= pBNS->num_atoms)
10555 : : {
10556 : : /* Moving backward along the alt path we have found a vertex
10557 : : that is not an atom. Possibly it is a t- or (-)c-group */
10558 : : if (!( k % 2 ))
10559 : : {
10560 : : return 0; /* even vertex -- always okay */
10561 : : }
10562 : : if (!( ( pBNS->vert[u2].type & pBNS->type_T ) == pBNS->type_T ) &&
10563 : : !( ( pBNS->vert[u2].type & pBNS->type_CN ) == pBNS->type_CN ))
10564 : : {
10565 : : /* not a t- or (-)c-group */
10566 : : return 0;
10567 : : }
10568 : : u2_next = u_next / 2 - 1;
10569 : : if (!( pBNS->vert[v2].type & pBNS->type_TACN ) &&
10570 : : !( pBNS->vert[u2_next].type & pBNS->type_TACN ))
10571 : : {
10572 : : /* none of the atoms at the ends are N */
10573 : : return 0;
10574 : : }
10575 : : return 1;
10576 : : }
10577 : : }
10578 : :
10579 : : return 0;
10580 : :
10581 : : cross_edge:
10582 : :
10583 : : /*****************************************************************************
10584 : : * v and w (v=w') are same vertex reached with opposite "phases".
10585 : : * w cannot be (t) because this would have been detected earlier -- ???
10586 : : * (t)-A=A-A=A-A=A-(t)
10587 : : * v
10588 : : * 3 2 1 0 1 2 3 4
10589 : : * kv kw
10590 : : * (kv + kw)%2 == 1 <==> aggressive deprotonation
10591 : : *****************************************************************************/
10592 : :
10593 : : if (v == prim( w ))
10594 : : {
10595 : : type0 = 0;
10596 : : if (v2 >= pBNS->num_atoms)
10597 : : {
10598 : : type0 = ( ( pBNS->vert[v2].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10599 : : ( ( pBNS->vert[v2].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10600 : : }
10601 : : }
10602 : :
10603 : : return 0;
10604 : : }
10605 : : #endif
10606 : :
10607 : :
10608 : : /****************************************************************************/
10609 : 1418 : int rescap( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
10610 : : {
10611 : : BNS_ST_EDGE *pst_edge;
10612 : : BNS_EDGE *pedge;
10613 : :
10614 : : int f;
10615 : : S_CHAR s_or_t;
10616 : 1418 : int bBackward = GetEdgePointer( pBNS, u, v, iuv, &pedge, &s_or_t );
10617 : :
10618 [ + - + - ]: 1418 : if (!IS_BNS_ERROR( bBackward ))
10619 : : {
10620 : :
10621 [ + + ]: 1418 : if (s_or_t)
10622 : : {
10623 : 1190 : pst_edge = (BNS_ST_EDGE *) pedge;
10624 : 1190 : f = ( pst_edge->flow & EDGE_FLOW_ST_MASK );
10625 [ + + ]: 1190 : if (!bBackward)
10626 : : {
10627 : 1158 : f = (int) pst_edge->cap - f;
10628 : : }
10629 : : }
10630 : : else
10631 : : {
10632 : 228 : f = ( pedge->flow & EDGE_FLOW_MASK );
10633 [ + + ]: 228 : if (!bBackward)
10634 : : {
10635 : 153 : f = (int) pedge->cap - f;
10636 : : }
10637 : : }
10638 : 1418 : return f;
10639 : : }
10640 : :
10641 : 0 : return bBackward; /* error */
10642 : : }
10643 : :
10644 : :
10645 : : /****************************************************************************
10646 : : W.Kocay, D.Stone,
10647 : : "An Algorithm for Balanced Flows",
10648 : : The Journal of Combinatorial Mathematics and Combinatorial Computing,
10649 : : vol. 19 (1995) pp. 3-31
10650 : :
10651 : : W.Kocay, D.Stone,
10652 : : "Balanced network flows",
10653 : : Bulletin of the Institute of Combinatorics and its Applications,
10654 : : vol. 7 (1993), pp. 17--32
10655 : :
10656 : : N = a balanced network (bipartite directed graph) of:
10657 : : n=2*V+2 vertices (incl. s (source) and t (target);
10658 : : each other vertex i is included 2 times:
10659 : : set X (x[i]) of V vertices (v) and a set Y (y[j]) of
10660 : : V complementary vertices (v') so that x[i]' = y[i], x[i]''=x[i], and
10661 : : m=2*E+2*V edges (each original undirected edge i-j is represented as
10662 : : 2 directed edges: x[i]->y[j] and x[j]->y[i]; plus
10663 : : V edges s->x[i] and V edges y[j]->t)
10664 : : v' = a complement vertex to v
10665 : : v'u' = (uv)' = a complement edge to uv
10666 : : rescap(uv) = cap(uv)-f(uv) if uv is a forward edge
10667 : : = f(uv) if uv is a backward edge
10668 : : (i) 0 <= f(uv) <= cap(uv)
10669 : : (ii) f+(u) = f-(u) for all u in X, Y where f+(u) is a total flow out of u,
10670 : : and f-(u) is a total flow into u
10671 : : (iii) f(uv) = f((uv)') (balanced flow condition)
10672 : :
10673 : : S = a set of all s-searchable vertices
10674 : : S- = all other vertices
10675 : : if t in S, then N contains a valid augmenting path P, so that flow can be
10676 : : augmented on both P and P'
10677 : : if t not in S, then let K=[S,S-], the set of all edges directed from S to S-.
10678 : : K is an edge-cut that has a special structure.
10679 : : Let
10680 : : A = {x[i], y[i] |x[i] not in S, y[i] in S}
10681 : : B = {x[i], y[i] |x[i] in S, y[i] not in S}
10682 : : C = {x[i], y[i] |x[i] in S, y[i] in S}
10683 : : D = {x[i], y[i] |x[i] not in S, y[i] not in S}
10684 : : N[C] = subgraph of N induced by C;
10685 : : it consists of of a number of connected components C[i]
10686 : : K[i] = those edges of K with one endpoint in C[i].
10687 : :
10688 : : If t is in S- then
10689 : :
10690 : : i) Each C[i] = C[i]'
10691 : : ii) There are no edges between C and D
10692 : : iii) Each K[i] has odd capacity, it is called a balanced edge-cut.
10693 : :
10694 : : balcap(K) = cap(K) - odd(K), where odd(K) is the number of connected components in N[C].
10695 : : Name "odd(K)" is because each cap(K[i]) is odd.
10696 : :
10697 : : Max-Balanced-Flow-Min-Balanced-Cut Theorem:
10698 : :
10699 : : Let f be a balanced flow in N, and let K be any balanced edge-cut.
10700 : : The value of a maximum balanced flow equals the capacity of a minimum
10701 : : edge-cut, that is, val(f) = balcap(K) when f is maximum and K is minimum.
10702 : :
10703 : : ****************************************************************************/
10704 : :
10705 : :
10706 : : /*******************************************************/
10707 : : /* */
10708 : : /* VERTEX NUMBERING */
10709 : : /* */
10710 : : /* Total number of atoms = n */
10711 : : /* Total number of vertices = 2*n+2 */
10712 : : /*******************************************************/
10713 : : /* */
10714 : : /* atom numbering starts from 0: */
10715 : : /* */
10716 : : /* atoms s t x0 y0 x1 y1 ... xi yi ...xn yn */
10717 : : /* vertices 0 1 2 3 4 5 ... 2i-2 2i-1 ...2n-2 2n-1 */
10718 : : /* */
10719 : : /* atom = vertex/2-1; if negative then s or t */
10720 : : /* */
10721 : : /* vertex = (atom + 1) * 2 + i; i=0 for x, i=1 for y */
10722 : : /* */
10723 : : /*******************************************************/
10724 : :
10725 : : /*********************************************************************************/
10726 : : /* v' variable is called prim(v) for now */
10727 : : /*********************************************************************************/
10728 : :
10729 : : /*
10730 : : BalancedNetworkSearch( ... )
10731 : :
10732 : : N has source s, target t, the mirror network M is constructed.
10733 : : The tree T contains a valid sv-path for each v in T. Simultaneously, the complementary
10734 : : tree T' is built as indicated in comments. The trees T and T' must have no edges or
10735 : : vertices in common. Initially T will be built as in breadth-first-search, and T' will
10736 : : be the complementary tree, it will contain the complementary valid v't-path.
10737 : :
10738 : : NB: this procedure is _not_ recursive
10739 : :
10740 : : */
10741 : :
10742 : :
10743 : : /****************************************************************************/
10744 : 248 : int BalancedNetworkSearch( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
10745 : :
10746 : : {
10747 : 248 : Vertex *BasePtr = pBD->BasePtr;
10748 : 248 : Edge *SwitchEdge = pBD->SwitchEdge;
10749 : 248 : S_CHAR *Tree = pBD->Tree;
10750 : 248 : Vertex *ScanQ = pBD->ScanQ;
10751 : 248 : int QSize = pBD->QSize;
10752 : 248 : Vertex *Pu = pBD->Pu;
10753 : 248 : Vertex *Pv = pBD->Pv;
10754 : 248 : int max_len_Pu_Pv = pBD->max_len_Pu_Pv;
10755 : :
10756 : : /* added to translate into C */
10757 : 248 : int i, k, degree, delta, ret = 0;
10758 : : Vertex u, b_u, v, b_v, w;
10759 : : EdgeIndex iuv;
10760 : : #if ( BNS_RAD_SEARCH == 1 )
10761 [ - + - - ]: 248 : int n, bRadSearch = ( BNS_EF_RAD_SRCH & bChangeFlow ) && pBD->RadEndpoints;
10762 : 248 : BRS_MODE bRadSrchMode = RAD_SRCH_NORM;
10763 : 248 : int bRadSearchPrelim = 0;
10764 [ - + ]: 248 : if (bRadSearch)
10765 : : {
10766 : 0 : pBD->nNumRadEndpoints = 0;
10767 : 0 : bRadSrchMode = pBD->bRadSrchMode;
10768 [ # # # # ]: 0 : bRadSearchPrelim = pBNS->type_TACN && bRadSrchMode == RAD_SRCH_NORM;
10769 : : }
10770 : : #endif
10771 : :
10772 : : /* -- Always --
10773 : : Vertex_s = FIRST_INDX;
10774 : : Vertex_t = Vertex_s+1;
10775 : : */
10776 : 248 : QSize = k = 0; /* put s on ScanQ = set S */
10777 : 248 : ScanQ[QSize] = Vertex_s;
10778 : 248 : BasePtr[Vertex_t] = Vertex_s;
10779 : 248 : BasePtr[Vertex_s] = BLOSSOM_BASE; /* create initial blossom C(Vertex_s) with base s */
10780 : 248 : Tree[Vertex_s] = TREE_IN_1;
10781 : :
10782 : : do
10783 : : {
10784 : 456 : u = ScanQ[k]; /* select u from the head of ScanQ */
10785 : : /* since u is on the queue, it has a blossom C(U) with base b_u */
10786 : 456 : b_u = FindBase( u, BasePtr );
10787 : 456 : degree = GetVertexDegree( pBNS, u );
10788 : : #if ( BNS_RAD_SEARCH == 1 )
10789 : 456 : n = 0;
10790 : : #endif
10791 [ + + ]: 3173 : for (i = 0; i < degree; i++)
10792 : : {
10793 : : /* v = vert[u].neighbor[i]; */
10794 : 2755 : v = GetVertexNeighbor( pBNS, u, i, &iuv );
10795 [ + + ]: 2755 : if (v == NO_VERTEX)
10796 : : {
10797 : 1161 : continue; /* the atom has only single bonds, ignore it */
10798 : : }
10799 : : #if ( BNS_RAD_SEARCH == 1 )
10800 [ + + - + : 1594 : if (!k && bRadSrchMode == RAD_SRCH_FROM_FICT && v / 2 <= pBNS->num_atoms)
- - ]
10801 : : {
10802 : 0 : continue; /* start from fict. vertices only */
10803 : : }
10804 [ - + - - ]: 1594 : if (bRadSearchPrelim && v / 2 > pBNS->num_atoms)
10805 : : {
10806 : 0 : continue; /* during initial add/remove H allow radical movement only through real atoms */
10807 : : }
10808 : : #endif
10809 : 1594 : if ( /* PrevPt[u] != v ** avoid edges of T */
10810 [ + + - + ]: 1594 : ( SwitchEdge_Vert1( u ) != v || SwitchEdge_Vert2( u ) != u ) /* avoid edges of T */
10811 [ + + ]: 1418 : && ( ret = rescap( pBNS, u, v, iuv ) ) > 0)
10812 : : {
10813 : : /* Special treatment to prevent H<->(-) replacement on non-acidic atoms */
10814 : : /*----------------------------------------------------------------------*/
10815 [ - + ]: 345 : if (pBNS->type_TACN)
10816 : : {
10817 [ # # ]: 0 : if (bIgnoreVertexNonTACN_atom( pBNS, u, v ))
10818 : : {
10819 : 0 : continue;
10820 : : }
10821 [ # # ]: 0 : if (bIgnoreVertexNonTACN_group( pBNS, u, v, SwitchEdge ))
10822 : : {
10823 : 0 : continue;
10824 : : }
10825 : : #if ( FIX_KEEP_H_ON_NH_ANION == 1 )
10826 : : if (bIsRemovedHfromNHaion( pBNS, u, v ))
10827 : : {
10828 : : continue;
10829 : : }
10830 : : #endif
10831 : : #if ( FIX_AVOID_ADP == 1 )
10832 : : if (bIsAggressiveDeprotonation( pBNS, u, v, SwitchEdge ))
10833 : : {
10834 : : continue;
10835 : : }
10836 : : #endif
10837 : : }
10838 : : /*----------------------------------------------------------------------*/
10839 : 345 : b_v = FindBase( v, BasePtr ); /* Notation: b_x is a base of x */
10840 : :
10841 [ + + ]: 345 : if (b_v == NO_VERTEX)
10842 : : {
10843 : : /* Originally 0 instead of NO_VERTEX */
10844 : :
10845 : : /* Important note: following "A. Note of Implementing the Algorithm" from the
10846 : : article by Kocay and Stone, all references to PrevPt[a] have been
10847 : : replaced with SwitchEdge[a][0]=SwitchEdge_Vert1(a); to be on a safe side
10848 : : the check whether (SwitchEdge_Vert2(a)==a) has been added.
10849 : : */
10850 : :
10851 : : /* v is not yet in T or T' -- add it to T and M */
10852 : : /*PrevPt[v] = u; ** this effectively adds v to T and v' to T' */
10853 : :
10854 : 265 : QSize++;
10855 : 265 : ScanQ[QSize] = v;
10856 [ + - ]: 265 : TREE_MARK( v, TREE_IN_1 ); /* mark v s-reachable (in T) */
10857 [ + - ]: 265 : TREE_MARK( prim( v ), TREE_IN_2 ); /* mark v' in T' */
10858 : :
10859 : : /* Switch Edges: If u in T then Pu (a valid su-path) can be constructed
10860 : : by successfully executing u=PrevPt[u] until u=s.
10861 : : For vertices in T' the situation is different.
10862 : : Suppose uv and v'u' are added to a mirror network M creating a blossom:
10863 : :
10864 : : s T (Note: in the code v' is prim(v),
10865 : : T / \ u' is prim(u), etc.)
10866 : : / ...
10867 : : w=x1
10868 : : / \ u in T, v in T'
10869 : : u=y2 v'=y3
10870 : : \ / <--- two added edges uv and (uv)'=v'u'
10871 : : -------- X ------------intersection of the edges ------------------------
10872 : : / \ <--- (the edges intersection in the picture is shown as X)
10873 : : u'=x2 v=x3 u' it T', v' in T
10874 : : \ /
10875 : : T' w'=y1
10876 : : \ ...
10877 : : \ /
10878 : : t T'
10879 : :
10880 : : Vertices v and u' now become s-reachable;
10881 : : The valid paths to v and u' must use the edges uv and v'u' respectively.
10882 : :
10883 : : For each vertex z in S we define a switch-edge that allows a valid sz-path
10884 : : to be constructed, SwitchEdge[v]=uv and SwitchEdge[u']=v'u'. (We don't
10885 : : know the direction of the edge uv, it may be (u,v) or (v,u). In either case,
10886 : : the complementary edge is indicated by v'u').
10887 : :
10888 : : Vertex w' also becomes s-reachable when uv is added to M, and a valid sw'-path
10889 : : must use one of uv and v'u'. Therefore we choose one of them, say uv (see below
10890 : : the rule of choosing the switch-edge), and define SwitchEdge[w'] = uv.
10891 : :
10892 : : When the addition of an edge uv to M causes a vertex z to become s-reachable
10893 : : (where z was previously non-reachable), z is placed on the ScanQ, that is, into S.
10894 : : The edge uv is said to be a switch-edge for z.
10895 : :
10896 : : Rule: We choose the the order of the vertices uv to be such that the valid sz-path
10897 : : consists of a valid su-path, followed by edge uv, followed by a valid vz-path.
10898 : :
10899 : : For vertices z in T we can take SwitchEdge[z]=yz where y=PrevPt[z] since
10900 : : it is the edge yz that allows z to be s-reachable.
10901 : : For vertices z not in S we take SwitchEdge[z]=NONE.
10902 : :
10903 : : */
10904 : :
10905 : : /* v is not yet in T or T' -- add it to T and M */
10906 : 265 : SwitchEdge_Vert1( v ) = u; /* this effectively adds uv and v'u' to M */
10907 : 265 : SwitchEdge_IEdge( v ) = iuv;
10908 : :
10909 : 265 : BasePtr[prim( v )] = v;
10910 : 265 : BasePtr[v] = BLOSSOM_BASE; /* create a trivial blossom C(v) with base v */
10911 : : #if ( BNS_RAD_SEARCH == 1 )
10912 : 265 : n++;
10913 : : #endif
10914 : : }
10915 : :
10916 [ + + ]: 80 : else if (TREE_IS_S_REACHABLE( prim( v ) ) /*Is_s_Reachable(prim(v)*/
10917 : : /* if v' is reachable, an st-path is given by P(u)-uv-P'(v') */
10918 : : /*&& PrevPt[prim(u)] != prim(v) ** avoid edges of T' */
10919 [ - + - - ]: 38 : && ( SwitchEdge_Vert1( prim( u ) ) != prim( v ) || SwitchEdge_Vert2( prim( u ) ) != prim( u ) ) /* avoid edges of T' */
10920 [ + - ]: 38 : && b_u != b_v
10921 [ - + - - ]: 38 : && !( pBNS->type_TACN && bIgnoreVertexNonTACN_group( pBNS, prim( v ), u, SwitchEdge ) )
10922 : : #if ( FIX_KEEP_H_ON_NH_ANION == 1 )
10923 : : && !( pBNS->type_TACN && bIsRemovedHfromNHaion( pBNS, prim( v ), u ) )
10924 : : #endif
10925 : : )
10926 : : {
10927 : : #if ( BNS_RAD_SEARCH == 1 )
10928 : 38 : n++;
10929 : : #endif
10930 : : /* There is now a valid sv-path via u avoiding b_v (unless v==b_v)
10931 : : => u, v, u', and v' now all become part of the same connected component of M[C] */
10932 : :
10933 : : /* djb-rwth: addressing coverity ID #499578 -- negative values of b_u handled properly */
10934 : 38 : w = MakeBlossom( pBNS, ScanQ, &QSize, Pu, Pv, max_len_Pu_Pv, SwitchEdge, BasePtr, u, v, iuv, b_u, b_v, Tree );
10935 : : /* this constructed the new blossom and returned its base */
10936 : :
10937 [ + - - + ]: 38 : if (IS_BNS_ERROR( w ))
10938 : : {
10939 : 0 : pBD->QSize = QSize;
10940 : 0 : return w; /* error */
10941 : : }
10942 : :
10943 : 38 : b_u = w; /* the new base of C(u) */
10944 [ + - ]: 38 : if (prim( w ) == Vertex_t)
10945 : : {
10946 : : /* t is now s-reachable, a valid augmenting path P exists in M */
10947 : 38 : delta = FindPathCap( pBNS, SwitchEdge, Vertex_s, Vertex_t, 10000 ); /* compute the residual capacity of P + P' */
10948 [ + - - + ]: 38 : if (IS_BNS_ERROR( delta ))
10949 : : {
10950 : 0 : pBD->QSize = QSize;
10951 : 0 : return delta; /* error */
10952 : : }
10953 : : #if ( ALLOW_ONLY_SIMPLE_ALT_PATH == 1 )
10954 : : if (pBNS->bNotASimplePath || abs( delta ) > 1)
10955 : : {
10956 : : delta = 0;
10957 : : }
10958 : : #endif
10959 [ + - ]: 38 : if (delta)
10960 : : {
10961 : 38 : pBNS->bChangeFlow |= ( bChangeFlow & BNS_EF_CHNG_FLOW );
10962 : : }
10963 : 38 : ret = PullFlow( pBNS, SwitchEdge, Vertex_s, Vertex_t, delta, 0, bChangeFlow ); /* augment on a pair of valid st-paths */
10964 : 38 : pBD->QSize = QSize;
10965 : : return
10966 [ + - - + ]: 38 : ( IS_BNS_ERROR( ret ) ? ret : delta );
10967 : : }
10968 : : }
10969 : : }
10970 : :
10971 [ + - - + ]: 1249 : else if (IS_BNS_ERROR( ret ))
10972 : : {
10973 : 0 : pBD->QSize = QSize;
10974 : 0 : return ret; /* error */
10975 : : }
10976 : : }
10977 : :
10978 : : #if ( BNS_RAD_SEARCH == 1 )
10979 [ - + - - ]: 418 : if (bRadSearch && !n)
10980 : : {
10981 : : /* The BNS stopped at u */
10982 : 0 : n = RegisterRadEndpoint( pBNS, pBD, u );
10983 [ # # # # ]: 0 : if (IS_BNS_ERROR( n ))
10984 : : {
10985 : 0 : pBD->QSize = QSize;
10986 : 0 : return n;
10987 : : }
10988 : : }
10989 : : #endif
10990 : :
10991 : 418 : k++; /* advance ScanQ */
10992 [ + + ]: 418 : } while (k <= QSize);
10993 : :
10994 : :
10995 : : /* if this point is reached, no valid augmenting path exists, ScanQ contains
10996 : : the set S of all s-reachable vertices and K=[S,S-] is a minimum balanced edge-cut */
10997 : : /* ClearFlowMarks( vert, num_vert); */
10998 : :
10999 : 210 : pBD->QSize = QSize;
11000 : :
11001 : 210 : return 0;
11002 : : }
11003 : :
11004 : :
11005 : : /*
11006 : : Blossoms.
11007 : :
11008 : : The vertices of a mirror network M consist T U T'. Intersection T ^ T' is empty.
11009 : :
11010 : : The edges of M consist of switch-edges and their complements because edges
11011 : : are added in complementary pairs, one of which is always a switch-edge.
11012 : :
11013 : : The base of every blossom is in T.
11014 : : Let C(i) be a blossom with base b_i. Since C(i)=C(i)', C(i) contains vertices of T and T'.
11015 : : Since every valid sv-path to v in C(i) contains b_i, b_i is the first s-reachable vertex of C(i).
11016 : :
11017 : : Suppose the mirror network M contains a valid sz-path P(z) to all vertices z in ScanQ.
11018 : : Every vertex of P(z) is s-reachable therefore its vertices are all in blossoms or
11019 : : trivial blossoms.
11020 : :
11021 : : Let z be an s-reachable vertex and P(z) be a valid path in M.
11022 : : Then every valid sz-path in M contains exactly the same sequence of blossom bases as P(z).
11023 : :
11024 : : */
11025 : :
11026 : :
11027 : :
11028 : : /***********************************************************************
11029 : : BasePtr[u] = -2 NO_VERTEX u is not a blossom
11030 : : -1 BLOSSOM_BASE u is the base of its blossom
11031 : : v a vertex closer to the base
11032 : : ************************************************************************/
11033 : 981 : Vertex FindBase( Vertex u, Vertex *BasePtr )
11034 : : {
11035 [ + + ]: 981 : if (BasePtr[u] == NO_VERTEX)
11036 : : {
11037 : 265 : return NO_VERTEX;
11038 : : }
11039 [ + + ]: 716 : else if (BasePtr[u] == BLOSSOM_BASE)
11040 : : {
11041 : 678 : return u;
11042 : : }
11043 : : else
11044 : : {
11045 : : Vertex b;
11046 : 38 : b = FindBase( BasePtr[u], BasePtr );
11047 : 38 : BasePtr[u] = b; /* path compression */
11048 : 38 : return b;
11049 : : }
11050 : :
11051 : : }
11052 : :
11053 : :
11054 : : /****************************************************************************
11055 : : Returns index of the last path element and the path
11056 : : ****************************************************************************/
11057 : 76 : int FindPathToVertex_s( Vertex x,
11058 : : Edge *SwitchEdge,
11059 : : Vertex *BasePtr,
11060 : : Vertex *Path,
11061 : : int MaxPathLen )
11062 : : {
11063 : : /* x is the base of a blossom, construct a valid Path of blossom bases to s */
11064 : 76 : int i = 0;
11065 : 76 : Path[i] = x;
11066 [ + + ]: 218 : while (x != Vertex_s)
11067 : : {
11068 : 142 : x = FindBase( SwitchEdge_Vert1( x ), BasePtr );
11069 [ + - ]: 142 : if (++i < MaxPathLen)
11070 : : {
11071 : 142 : Path[i] = x;
11072 : : }
11073 : : else
11074 : : {
11075 : 0 : return BNS_WRONG_PARMS;
11076 : : }
11077 : : }
11078 : :
11079 : 76 : return i;
11080 : : }
11081 : :
11082 : :
11083 : :
11084 : : /****************************************************************************
11085 : : Make a blossom
11086 : : ****************************************************************************/
11087 : 38 : Vertex MakeBlossom( BN_STRUCT* pBNS,
11088 : : Vertex *ScanQ,
11089 : : int *pQSize,
11090 : : Vertex *Pu,
11091 : : Vertex *Pv,
11092 : : int max_len_Pu_Pv,
11093 : : Edge *SwitchEdge,
11094 : : Vertex *BasePtr,
11095 : : Vertex u,
11096 : : Vertex v,
11097 : : EdgeIndex iuv,
11098 : : Vertex b_u,
11099 : : Vertex b_v,
11100 : : S_CHAR *Tree )
11101 : : {
11102 : : /* In order to find the base of the new blossom, the paths
11103 : : P(u) and P(v') are constructed and compared in order to
11104 : : find the last blossom base they have in common which
11105 : : is reachable on a valid path.
11106 : :
11107 : : Edge uv connects two blossoms, their bases are b_u and b_v.
11108 : : */
11109 : : Vertex w, z;
11110 : : int len_Pu, len_Pv;
11111 : : int i, j, k;
11112 : : EdgeIndex izw;
11113 : :
11114 : 38 : len_Pu = FindPathToVertex_s( b_u, SwitchEdge, BasePtr, Pu, max_len_Pu_Pv );
11115 [ + - - + ]: 38 : if (IS_BNS_ERROR( len_Pu ))
11116 : : {
11117 : 0 : return len_Pu;
11118 : : }
11119 : 38 : len_Pv = FindPathToVertex_s( b_v, SwitchEdge, BasePtr, Pv, max_len_Pu_Pv );
11120 [ + - - + ]: 38 : if (IS_BNS_ERROR( len_Pv ))
11121 : : {
11122 : 0 : return len_Pv;
11123 : : }
11124 : 38 : i = len_Pu;
11125 : 38 : j = len_Pv;
11126 : : /* Initially Pu[i] and Pv[j] both equal to s, but their first elements are different */
11127 : : /* Find the last blossom base common to Pu and Pv */
11128 [ + - + - : 76 : while (i >= 0 && j >= 0 && Pu[i] == Pv[j])
+ + ]
11129 : : {
11130 : : /* Was (Pu[i]==Pv[j] && i>=0 && j>=0) => tested Pu[-1], Pv[-1] <- pointed by W.Ihlenfeldt 08-26-2004*/
11131 : 38 : i--;
11132 : 38 : j--;
11133 : : }
11134 : 38 : i++;
11135 : 38 : w = Pu[i]; /* w is the last common vertex */
11136 : 38 : z = SwitchEdge_Vert1( w );
11137 : 38 : izw = SwitchEdge_IEdge( w );
11138 : : /* now extend the blossom if rescap(zw) >= 2 */
11139 [ - + - - ]: 38 : while (w != Vertex_s && rescap( pBNS, z, w, izw ) >= 2)
11140 : : {
11141 : 0 : i++;
11142 : 0 : w = Pu[i];
11143 : 0 : z = SwitchEdge_Vert1( w );
11144 : 0 : izw = SwitchEdge_IEdge( w );
11145 : : }
11146 : : /* w is the base of the new blossom */
11147 : : /* first follow the path Pu from w to b_u */
11148 [ + + ]: 109 : for (k = i - 1; k >= 0; k--)
11149 : : {
11150 : 71 : z = Pu[k]; /* z is the base of the blossom */
11151 : 71 : BasePtr[z] = w;
11152 : 71 : BasePtr[prim( z )] = w; /* w is the new base of the blossom */
11153 : : /* z and z' may already be part of a blossom that is being
11154 : : swallowed into a larger blossom.
11155 : : We don't want to change the switch edge in that case.
11156 : : */
11157 : :
11158 [ + - ]: 71 : if (!TREE_IS_ON_SCANQ( prim( z ) ) /*!IsInScanQ(prim(z)) */)
11159 : : {
11160 : 71 : SwitchEdge_Vert1( prim( z ) ) = prim( v ); /* set the switch edge of z' */
11161 : : /* SwitchEdge[prim(z)][1] = prim(u); */
11162 : 71 : SwitchEdge_IEdge( prim( z ) ) = iuv;
11163 : 71 : ( *pQSize )++;
11164 : 71 : ScanQ[*pQSize] = prim( z ); /* add z' to ScanQ */
11165 [ + - ]: 71 : TREE_MARK( prim( z ), TREE_IN_2BLOSS ); /* mark z' s-reachable */
11166 : : }
11167 : : }
11168 : : /* Now follow the path Pv */
11169 [ + + ]: 109 : for (k = j; k >= 0; k--) /* djb-rwth: converting for loop into while loop to avoid LLVM warning */
11170 : : {
11171 : 71 : z = Pv[k]; /* z is the base of the blossom */
11172 : 71 : BasePtr[z] = w;
11173 : 71 : BasePtr[prim( z )] = w; /* w is the new base of the blossom */
11174 : : /* z and z' may already be part of a blossom that is being
11175 : : swallowed into a larger blossom.
11176 : : We don't want to change the switch edge in that case.
11177 : : */
11178 : :
11179 [ + - ]: 71 : if (!TREE_IS_ON_SCANQ( prim( z ) ) /*!IsInScanQ(prim(z)) */)
11180 : : {
11181 : 71 : SwitchEdge_Vert1( prim( z ) ) = u; /* set the switch edge of z' */
11182 : : /* SwitchEdge[prim(z)][1] = v; */
11183 : 71 : SwitchEdge_IEdge( prim( z ) ) = iuv;
11184 : 71 : ( *pQSize )++;
11185 : 71 : ScanQ[*pQSize] = prim( z ); /* add z' to ScanQ */
11186 [ + - ]: 71 : TREE_MARK( prim( z ), TREE_IN_2BLOSS ); /* mark z' s-reachable */
11187 : : }
11188 : : }
11189 : :
11190 [ + - ]: 38 : if (!TREE_IS_ON_SCANQ( prim( w ) ) /* !IsInScanQ(prim(w))*/)
11191 : : { /* add w' to the blossom */
11192 : 38 : SwitchEdge_Vert1( prim( w ) ) = u; /* set the switch edge of w' */
11193 : : /* SwitchEdge[prim(w)][1] = v; */
11194 : 38 : SwitchEdge_IEdge( prim( w ) ) = iuv;
11195 : 38 : ( *pQSize )++;
11196 : 38 : ScanQ[*pQSize] = prim( w ); /* add w' to ScanQ */
11197 [ + - ]: 38 : TREE_MARK( prim( w ), TREE_IN_2BLOSS ); /* mark w' s-reachable */
11198 : : }
11199 : :
11200 : 38 : return w;
11201 : : }
11202 : :
11203 : :
11204 : : /****************************************************************************
11205 : : When t is found to be s-reachable, a valid st-path P is known to exist.
11206 : : Its complementary path P' is also valid. Once the residual capacity
11207 : : delta(P) is known, the flow is augmented by calling PullFlow(s,t,delta).
11208 : : It constructs the path P by using the switch-edges.
11209 : : Let uv=SwitchEdge[t].
11210 : : Then P is given by a valid su-path, followed by the edge uv, followed by
11211 : : a valid vt-path.
11212 : : PullFlow is a recursive procedure that constructs the path and its complement.
11213 : :
11214 : : Let wz=SwitchEdge[y]. PullFlow(x, y, delta) uses the xw- and zy-portions of P
11215 : : (see below). Since it must also augment on P' simultaneously, the zy-portion
11216 : : is replaced by the y'z'-portion.
11217 : :
11218 : : x y'
11219 : : | | P: x--w--z--y
11220 : : P | | P' P': y'-z'-w'-x'
11221 : : | o
11222 : : o \
11223 : : / w' z \
11224 : : / o----\ /----o /
11225 : : \ / \ / \ /
11226 : : \/ X \/
11227 : : /\ / \ /\
11228 : : / \ w / \ z' / \
11229 : : \ o---- ----o / Using a switch-edge wz and w'z'
11230 : : \ / to construct P and P'
11231 : : o o
11232 : : | |
11233 : : | |
11234 : : x' y
11235 : :
11236 : :
11237 : : ****************************************************************************/
11238 : :
11239 : :
11240 : :
11241 : : /* PullFlow( ... )
11242 : :
11243 : : Augment the flow by delta on all edges on a path P
11244 : : between x and y in the order of the path;
11245 : : AugmentEdge( pBNS, w, z, iwz, delta, 0 ) means the path is in w->z direction
11246 : : AugmentEdge( pBNS, w, z, iwz, delta, 1 ) means the path is in w<-z direction
11247 : :
11248 : : Unlike PullFlow in the paper by Kocay & Stone, here the augmentation
11249 : : starts at "s", proceeds sequentially through the path end terminates at "t".
11250 : : Since we do not really need the complement path, PullFlow ignores it.
11251 : : */
11252 : :
11253 : :
11254 : : /****************************************************************************/
11255 : 180 : int PullFlow( BN_STRUCT *pBNS,
11256 : : Edge *SwitchEdge,
11257 : : Vertex x,
11258 : : Vertex y,
11259 : : int delta,
11260 : : S_CHAR bReverse,
11261 : : int bChangeFlow )
11262 : : {
11263 : : Vertex w, z;
11264 : : EdgeIndex iwz;
11265 : 180 : int ret = 0;
11266 : :
11267 : 180 : w = SwitchEdge_Vert1( y );
11268 : 180 : z = SwitchEdge_Vert2( y );
11269 : 180 : iwz = SwitchEdge_IEdge( y );
11270 [ + + ]: 180 : if (bReverse)
11271 : : {
11272 : : /* P consists of a path from x to w, then wz, then a path from z to y. */
11273 : : /* z may equal y, in which case z is just PrevPt[y] */
11274 [ - + ]: 71 : if (z != y)
11275 : : {
11276 : 0 : ret = PullFlow( pBNS, SwitchEdge, prim( y ), prim( z ), delta, (S_CHAR) ( 1 - bReverse ), bChangeFlow ); /* augment between z and y */
11277 : : }
11278 [ + - + - ]: 71 : if (!IS_BNS_ERROR( ret ))
11279 : : {
11280 : 71 : ret = AugmentEdge( pBNS, w, z, iwz, delta, bReverse, bChangeFlow );
11281 : : }
11282 : : /* Do not augment the complementary path: AugmentEdge( prim(z), prim(w), vert, delta); */
11283 : : /* w may equal x, in which case there is no need to call PullFlow(x, w) */
11284 [ + + + - : 71 : if (w != x && !IS_BNS_ERROR( ret ))
+ - ]
11285 : : {
11286 : 33 : ret = PullFlow( pBNS, SwitchEdge, x, w, delta, bReverse, bChangeFlow ); /* augment between x and w */
11287 : : }
11288 : : }
11289 : : else
11290 : : {
11291 : : /* P consists of a path from x to w, then wz, then a path from z to y. */
11292 : : /* w may equal x, in which case there is no need to call PullFlow(x, w) */
11293 [ + + + - : 109 : if (w != x && !IS_BNS_ERROR( ret ))
+ - ]
11294 : : {
11295 : 71 : ret = PullFlow( pBNS, SwitchEdge, x, w, delta, bReverse, bChangeFlow ); /* augment between x and w */
11296 : : }
11297 [ + - + - ]: 109 : if (!IS_BNS_ERROR( ret ))
11298 : : {
11299 : 109 : ret = AugmentEdge( pBNS, w, z, iwz, delta, bReverse, bChangeFlow );
11300 : : }
11301 : : /* z may equal y, in which case z is just PrevPt[y] */
11302 [ + + + - : 109 : if (z != y && !IS_BNS_ERROR( ret ))
+ - ]
11303 : : {
11304 : 38 : ret = PullFlow( pBNS, SwitchEdge, prim( y ), prim( z ), delta, (S_CHAR) ( 1 - bReverse ), bChangeFlow ); /* augment between z and y */
11305 : : }
11306 : : }
11307 : :
11308 : 180 : return ret;
11309 : : }
11310 : :
11311 : :
11312 : : /****************************************************************************
11313 : : Before augmenting on the two paths, it is necessary to find delta(P).
11314 : : This can be done by following the paths and computing the minimum
11315 : : residual capacity of all edges on P. An edge on both P and P' counts
11316 : : for only half of its actual residual capacity, since augmentng on P by
11317 : : delta will simutaneously reduce its capacity on P' by delta.
11318 : : The path P can only be followed by using the switch-edges, as in PullFlow(...).
11319 : : FindPathCap( x, y, delta ) is a recursive procedure that finds the residual
11320 : : capacity on the portion of P between x and y. delta is the minimum capacity
11321 : : found so far along the path.
11322 : : ****************************************************************************/
11323 : :
11324 : :
11325 : : /****************************************************************************
11326 : : Find the minimum residual capacity of all edges
11327 : : between x and y in a valid st-path P.
11328 : : delta is the minimum found so far
11329 : : the vertices occur in order s,...,x,...,y,...,t along P
11330 : : the vertices occur in order s,...,y',...,x',...,t along P'
11331 : : ****************************************************************************/
11332 : 180 : int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta )
11333 : : {
11334 : :
11335 : : Vertex w, z, iwz;
11336 : : int cap, delta2;
11337 : :
11338 : : /* static int level;
11339 : : if ( level ++ > 50 )
11340 : : {
11341 : : #ifdef _DEBUG
11342 : : int stop = 1;
11343 : : #else
11344 : : ;
11345 : : #endif
11346 : : }
11347 : : */
11348 : :
11349 : 180 : w = SwitchEdge_Vert1( y );
11350 : 180 : z = SwitchEdge_Vert2( y ); /* wz is on the path P */
11351 : 180 : iwz = SwitchEdge_IEdge( y ); /* edge index */
11352 : :
11353 : : /* Rescap_mark() detects edges passed 2 times and reduces rescap */
11354 : 180 : cap = rescap_mark( pBNS, w, z, iwz );
11355 : :
11356 [ + - - + ]: 180 : if (IS_BNS_ERROR( cap ))
11357 : : {
11358 : : /* level --; */
11359 : 0 : return cap;
11360 : : }
11361 [ + + ]: 180 : if (cap < delta)
11362 : : {
11363 : 38 : delta = cap;
11364 : : }
11365 : : /* P consists of a path from x to w, then wz, then a path from z to y */
11366 [ + + ]: 180 : if (w != x)
11367 : : {
11368 : 104 : delta2 = FindPathCap( pBNS, SwitchEdge, x, w, delta );
11369 : 104 : delta = inchi_min( delta2, delta );
11370 : : }
11371 [ + + ]: 180 : if (z != y)
11372 : : {
11373 : 38 : delta2 = FindPathCap( pBNS, SwitchEdge, prim( y ), prim( z ), delta );
11374 : 38 : delta = inchi_min( delta2, delta );
11375 : : }
11376 : : /* level --; */
11377 : :
11378 : 180 : return delta;
11379 : : }
11380 : :
11381 : :
11382 : : /*
11383 : : BT = bond types
11384 : : */
11385 : :
11386 : :
11387 : : #define BT_ALTERN_BOND 1 /* 1-2, possibly stereo */
11388 : : #define BT_OTHER_ALTERN_BOND 2 /* 1-3, 2-3, 1-2-3 alternating non-stereo non-taut bonds */
11389 : :
11390 : : #define BT_ALTERN_NS_BOND 4
11391 : :
11392 : : #define BT_TAUTOM_BOND 8
11393 : :
11394 : : #define BT_ALTERN_UNKN_BOND 16
11395 : :
11396 : : #define BT_IGNORE_BOND 0
11397 : :
11398 : : #define BT_NONSTEREO_MASK (BT_TAUTOM_BOND|BT_ALTERN_NS_BOND)
11399 : :
11400 : : #define BT_ALT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND)
11401 : :
11402 : : #define BT_NONTAUT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND|BT_ALTERN_NS_BOND)
11403 : :
11404 : : /* BNS members redefinitions for finding non-stereo bonds */
11405 : : /* BNS_EDGE */
11406 : : #define nBlockNumberAltBns flow /* internal variable of the DFS traversal: mark traversed bonds */
11407 : : #define nNumAtInBlockAltBns cap
11408 : : #define nBondTypeInpAltBns pass /* 0=>cannot be stereo at all, 1=>alt or taut non-stereo, 2=>can be stereo */
11409 : : #define nBondNonStereoAltBns cap /* 1=>found to be non-stereogenic although BondTypeInp=2; 0=>as in BondTypeInp */
11410 : :
11411 : : #if ( BNS_MARK_ONLY_BLOCKS == 1 ) /* { */
11412 : : /* BNS_VERTEX */
11413 : : #define bCutVertexAltBns st_edge.cap0 /* cut-vertex flag */
11414 : : #define nRingSystemAltBns st_edge.cap /* ordering number of a ring system */
11415 : : #define nNumAtInRingSystemAltBns st_edge.flow0 /* number of vertices in a ring system */
11416 : : #define nBlockSystemAltBns st_edge.flow /* result of the DFS traversal: even cirquit must be within one block */
11417 : :
11418 : : #endif /* } */
11419 : :
11420 : : #define valenceAltBns num_adj_edges
11421 : :
11422 : :
11423 : : /****************************************************************************/
11424 : 161 : int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo )
11425 : 774 : {
11426 : 161 : AT_NUMB *nStackAtom = NULL;
11427 : : int nTopStackAtom;
11428 : 161 : AT_NUMB *nRingStack = NULL;
11429 : : int nTopRingStack; /* was AT_NUMB */
11430 : 161 : AT_NUMB *nBondStack = NULL;
11431 : : int nTopBondStack;
11432 : 161 : AT_NUMB *nDfsNumber = NULL;
11433 : 161 : AT_NUMB *nLowNumber = NULL;
11434 : 161 : S_CHAR *cNeighNumb = NULL;
11435 : : AT_NUMB nDfs;
11436 : : AT_NUMB nNumAtInRingSystem;
11437 : : int i, j, u, w, start, nNumRingSystems; /* djb-rwth: removing redundant variables */
11438 : 161 : BNS_VERTEX *at = pBNS->vert;
11439 : 161 : BNS_EDGE *bond = pBNS->edge;
11440 : 161 : int num_atoms = pBNS->num_atoms;
11441 : 161 : int num_edges = pBNS->num_bonds;
11442 : :
11443 : : /* Allocate arrays */
11444 : 161 : nStackAtom = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nStackAtom[0] ) );
11445 : 161 : nRingStack = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nRingStack[0] ) );
11446 : 161 : nDfsNumber = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nDfsNumber[0] ) );
11447 : 161 : nLowNumber = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nLowNumber[0] ) );
11448 [ + + ]: 161 : nBondStack = num_edges ? ( (AT_NUMB *) inchi_malloc( num_edges * sizeof( nBondStack[0] ) ) ) : (AT_NUMB *) ( NULL ); /* special case: no bonds 2006-03 */
11449 : 161 : cNeighNumb = (S_CHAR *) inchi_malloc( num_atoms * sizeof( cNeighNumb[0] ) );
11450 : :
11451 : : /* Check allocation */
11452 [ + - + - : 161 : if (!nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || (!nBondStack && num_edges) || !cNeighNumb
+ - + - +
+ + - -
+ ]
11453 : : ) /* djb-rwth: addressing LLVM warning */
11454 : : {
11455 : 0 : nNumRingSystems = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
11456 : 0 : goto exit_function;
11457 : : }
11458 : :
11459 : : /********************************************
11460 : : *
11461 : : * Find Cut-vertices & Blocks
11462 : : *
11463 : : * 1\ /5 has 3 blocks (maximal subgraphs that
11464 : : * Example: | >3--4< | are nonseparable by deleting a single vertex):
11465 : : * 2/ \6 (1,2,3, has 3 bonds), (3,4, has 1 bond), and (4,5,6, has 3 bonds)
11466 : : *
11467 : : * Cut-vertices or articulation points are
11468 : : * intersections of the blocks: points 3 and 4.
11469 : : ********************************************/
11470 : :
11471 : : /********************************************************
11472 : :
11473 : : RingSystemAlt are atoms connected by alternating bonds
11474 : : (as must be indicated in bIsAltBond()):
11475 : :
11476 : : BOND_ALTERN
11477 : : BOND_ALT_123
11478 : : BOND_ALT_13
11479 : : BOND_ALT_23
11480 : :
11481 : : Since other bonds may be present, we possibly need
11482 : : to restart to move to another component
11483 : : *********************************************************/
11484 : :
11485 : 161 : nNumRingSystems = 0;
11486 : 161 : memset( nDfsNumber, 0, num_atoms * sizeof( nDfsNumber[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
11487 : :
11488 [ + + ]: 971 : for (start = 0; start < num_atoms; start++)
11489 : : {
11490 [ + + ]: 810 : if (nDfsNumber[start])
11491 : : {
11492 : 30 : continue;
11493 : : }
11494 [ + + ]: 2042 : for (i = 0; i < at[start].valenceAltBns; i++)
11495 : : {
11496 [ + + ]: 1268 : if (bond[at[start].iedge[i]].nBondTypeInpAltBns & BT_ALTERN_BOND)
11497 : 6 : goto found_alt;
11498 : : }
11499 : 774 : continue;
11500 : :
11501 : 6 : found_alt:
11502 : :
11503 : : /* Initiation */
11504 : 6 : u = start; /* start atom */
11505 : 6 : nDfs = 0;
11506 : 6 : nTopStackAtom = -1;
11507 : 6 : nTopRingStack = -1;
11508 : 6 : nTopBondStack = -1;
11509 : 6 : memset( cNeighNumb, 0, num_atoms * sizeof( cNeighNumb[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
11510 : : /* Push the start atom on the stack */
11511 : 6 : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11512 : 6 : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11513 : 6 : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11514 : :
11515 : : /* djb-rwth: removing redundant code */
11516 : :
11517 : : do
11518 : : {
11519 : : /* advance */
11520 : : /*while ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
11521 : : /* replaced due to missing sequence point */
11522 [ + + ]: 128 : while (i = (int) nStackAtom[nTopStackAtom], j = (int) cNeighNumb[i], (int) at[i].valenceAltBns > j)
11523 : : {
11524 : 92 : cNeighNumb[i] ++;
11525 [ + + ]: 92 : if (!( bond[w = at[i].iedge[j]].nBondTypeInpAltBns & BT_ALT_BOND_MASK ))
11526 : : {
11527 : 20 : continue;
11528 : : }
11529 : 72 : u = (int) ( bond[at[i].iedge[j]].neighbor12 ^ i );
11530 [ + + + - ]: 72 : if (!nDfsNumber[u] && nBondStack) /* djb-rwth: fixing a NULL pointer dereference */
11531 : : {
11532 : : /* tree edge, 1st visit -- advance */
11533 : 30 : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11534 : 30 : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11535 : 30 : nBondStack[++nTopBondStack] = (AT_NUMB) w;
11536 : 30 : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11537 : : /* djb-rwth: removing redundant code */
11538 : : }
11539 : : else
11540 : : {
11541 [ + + + + ]: 42 : if (!nTopStackAtom || u != (int) nStackAtom[nTopStackAtom - 1])
11542 : : { /* may comment out ? */
11543 : : /* back edge: u is not a predecessor of i */
11544 [ + + + - ]: 12 : if ((nDfsNumber[u] < nDfsNumber[i]) && nBondStack) /* djb-rwth: fixing a NULL pointer dereference */
11545 : : {
11546 : : /* Back edge, 1st visit: u is ancestor of i. Save and compare */
11547 : 6 : nBondStack[++nTopBondStack] = (AT_NUMB) w;
11548 [ + - ]: 6 : if (nLowNumber[i] > nDfsNumber[u])
11549 : : {
11550 : 6 : nLowNumber[i] = nDfsNumber[u];
11551 : : }
11552 : : }
11553 : : }
11554 : : }
11555 : : }
11556 : 36 : cNeighNumb[i] = 0;
11557 : :
11558 : : /* Back up */
11559 [ + + ]: 36 : if (i != start)
11560 : : {
11561 : 30 : u = (int) nStackAtom[nTopStackAtom - 1]; /* predecessor of i */
11562 [ + + ]: 30 : if (nLowNumber[i] >= nDfsNumber[u])
11563 : : {
11564 : : /* Output the block; the block was entered through its first bond u->i */
11565 : 6 : nNumRingSystems++;
11566 : : /*at[u].nBlockSystemAltBns = nNumRingSystems;*/ /* mark the atom */
11567 : 6 : nNumAtInRingSystem = 1;
11568 : : /*
11569 : : if ( u != start || nNumStartChildren > 1 ) {
11570 : : at[u].bCutVertexAltBns += 1; // mark cut-vertex (articulation point)
11571 : : }
11572 : : */
11573 [ + - ]: 30 : while (nTopRingStack >= 0)
11574 : : {
11575 : 30 : j = nRingStack[nTopRingStack--];
11576 : : /*at[j].nBlockSystemAltBns = nNumRingSystems;*/ /* mark the atom */
11577 : 30 : nNumAtInRingSystem++;
11578 [ + + ]: 30 : if (i == j)
11579 : : {
11580 : 6 : break;
11581 : : }
11582 : : }
11583 [ + - ]: 36 : while (nTopBondStack >= 0)
11584 : : {
11585 : 36 : w = nBondStack[nTopBondStack--];
11586 : 36 : bond[w].nBlockNumberAltBns = nNumRingSystems; /* mark the bond */
11587 : 36 : bond[w].nNumAtInBlockAltBns = nNumAtInRingSystem;
11588 [ + + + - ]: 36 : if ((i == bond[w].neighbor1 && u == ( i ^ bond[w].neighbor12 )) ||
11589 [ + + + + ]: 36 : (u == bond[w].neighbor1 && i == ( u ^ bond[w].neighbor12 ))) /* djb-rwth: addressing LLVM warning */
11590 : : {
11591 : : break;
11592 : : }
11593 : : }
11594 : : }
11595 : : else
11596 : : {
11597 [ + - ]: 24 : if (nLowNumber[u] > nLowNumber[i])
11598 : : {
11599 : : /* inherit */
11600 : 24 : nLowNumber[u] = nLowNumber[i];
11601 : : }
11602 : : }
11603 : : }
11604 [ + + ]: 36 : } while (--nTopStackAtom >= 0);
11605 : : }
11606 : :
11607 : : #if ( BNS_MARK_ONLY_BLOCKS != 1 ) /* { */
11608 : :
11609 : : /********************************************
11610 : : *
11611 : : * Find Ring Systems
11612 : : * Including chain atoms X: A-X-B, where the bonds (of any kind) are bridges.
11613 : : *
11614 : : ********************************************/
11615 : :
11616 : : /* Initiation */
11617 : : nNumRingSystems = 0;
11618 : : for (start = 0; start < num_atoms; start++)
11619 : : {
11620 : : if (at[start].nRingSystemAltBns)
11621 : : {
11622 : : continue;
11623 : : }
11624 : : for (i = 0; i < at[start].valenceAltBns; i++)
11625 : : {
11626 : : if (bond[at[start].iedge[i]].nBondTypeInpAltBns & BT_ALT_BOND_MASK)
11627 : : {
11628 : : goto found_alt2;
11629 : : }
11630 : : }
11631 : : continue;
11632 : :
11633 : : found_alt2:
11634 : : u = start; /* start atom */
11635 : : nDfs = 0;
11636 : : nTopStackAtom = -1;
11637 : : nTopRingStack = -1;
11638 : : memset( nDfsNumber, 0, num_atoms * sizeof( nDfsNumber[0] ) );
11639 : : memset( cNeighNumb, 0, num_atoms * sizeof( cNeighNumb[0] ) );
11640 : : /* push the start atom on the stack */
11641 : : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11642 : : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11643 : : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11644 : :
11645 : : do
11646 : : {
11647 : : /* advance */
11648 : : advance_ring:
11649 : : /*if ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
11650 : : /* replaced due to missing sequence point */
11651 : : if (i = (int) nStackAtom[nTopStackAtom], j = (int) cNeighNumb[i], (int) at[i].valenceAltBns > j)
11652 : : {
11653 : : cNeighNumb[i] ++;
11654 : : if (!( bond[at[i].iedge[j]].nBondTypeInpAltBns & BT_ALTERN_BOND ))
11655 : : {
11656 : : goto advance_ring;
11657 : : }
11658 : : u = (int) ( bond[at[i].iedge[j]].neighbor12 ^ i );
11659 : : if (!nDfsNumber[u])
11660 : : {
11661 : : /* tree edge, 1st visit -- advance */
11662 : : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11663 : : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11664 : : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11665 : : }
11666 : : else
11667 : : {
11668 : : if (!nTopStackAtom || u != (int) nStackAtom[nTopStackAtom - 1])
11669 : : {
11670 : : /* back edge: u is not a predecessor of i */
11671 : : if (nDfsNumber[u] < nDfsNumber[i])
11672 : : {
11673 : : /* Back edge, 1st visit: u is ancestor of i. Compare */
11674 : : if (nLowNumber[i] > nDfsNumber[u])
11675 : : {
11676 : : nLowNumber[i] = nDfsNumber[u];
11677 : : }
11678 : : }
11679 : : }
11680 : : }
11681 : : goto advance_ring;
11682 : : }
11683 : : else
11684 : : {
11685 : : cNeighNumb[i] = 0;
11686 : : }
11687 : :
11688 : : /* Back up */
11689 : : if (nDfsNumber[i] == nLowNumber[i])
11690 : : {
11691 : : /* Found a ring system */
11692 : : nNumRingSystems++;
11693 : :
11694 : : /* Unwind nRingStack[] down to i */
11695 : :
11696 : : /* Count atoms in a ring system */
11697 : : for (nNumAtInRingSystem = 0, j = nTopRingStack; 0 <= j; j--)
11698 : : {
11699 : : nNumAtInRingSystem++;
11700 : : if (i == (int) nRingStack[j])
11701 : : {
11702 : : break;
11703 : : }
11704 : : }
11705 : : while (nTopRingStack >= 0)
11706 : : {
11707 : : j = (int) nRingStack[nTopRingStack--];
11708 : : at[j].nRingSystemAltBns = (AT_NUMB) nNumRingSystems; /* ring system id */
11709 : : at[j].nNumAtInRingSystemAltBns = nNumAtInRingSystem;
11710 : : if (i == j)
11711 : : {
11712 : : /* Reached atom on the top of nStackAtom[] stack */
11713 : : break;
11714 : : }
11715 : : }
11716 : : }
11717 : : else
11718 : : {
11719 : : if (nTopStackAtom > 0)
11720 : : {
11721 : : j = (int) nStackAtom[nTopStackAtom - 1];
11722 : : /* inherit nLowNumber */
11723 : : if (nLowNumber[j] > nLowNumber[i])
11724 : : {
11725 : : nLowNumber[j] = nLowNumber[i];
11726 : : }
11727 : : }
11728 : : }
11729 : : } while (--nTopStackAtom >= 0);
11730 : : }
11731 : :
11732 : : #endif /* } BNS_MARK_ONLY_BLOCKS != 1 */
11733 : :
11734 : 161 : exit_function:
11735 [ + - ]: 161 : if (nStackAtom)
11736 : : {
11737 [ + - ]: 161 : inchi_free( nStackAtom );
11738 : : }
11739 [ + - ]: 161 : if (nRingStack)
11740 : : {
11741 [ + - ]: 161 : inchi_free( nRingStack );
11742 : : }
11743 [ + - ]: 161 : if (nDfsNumber)
11744 : : {
11745 [ + - ]: 161 : inchi_free( nDfsNumber );
11746 : : }
11747 [ + - ]: 161 : if (nLowNumber)
11748 : : {
11749 [ + - ]: 161 : inchi_free( nLowNumber );
11750 : : }
11751 [ + + ]: 161 : if (nBondStack)
11752 : : {
11753 [ + - ]: 77 : inchi_free( nBondStack );
11754 : : }
11755 [ + - ]: 161 : if (cNeighNumb)
11756 : : {
11757 [ + - ]: 161 : inchi_free( cNeighNumb );
11758 : : }
11759 : :
11760 : 161 : return nNumRingSystems;
11761 : : }
11762 : :
11763 : :
11764 : : /****************************************************************************/
11765 : 161 : int ReInitBnStructForAltBns( BN_STRUCT *pBNS,
11766 : : inp_ATOM *at,
11767 : : int num_atoms,
11768 : : int bUnknAltAsNoStereo )
11769 : : {
11770 : : Vertex v, v2;
11771 : : int ret, bond_type, num_to_test, j;
11772 : : BNS_EDGE *pBond;
11773 : : BNS_VERTEX *pAtom;
11774 : :
11775 : : /* Strip all t-groups and c-groups */
11776 : 161 : num_to_test = 0;
11777 [ - + ]: 161 : if (bUnknAltAsNoStereo)
11778 : : {
11779 [ # # ]: 0 : for (j = 0; j < pBNS->num_edges; j++)
11780 : : {
11781 : 0 : pBNS->edge[j].pass = 0;
11782 : : }
11783 : : }
11784 : :
11785 : 161 : ret = ReInitBnStruct( pBNS, at, num_atoms, 0 );
11786 : :
11787 [ + - + - : 161 : if (ret || pBNS->num_atoms != num_atoms || pBNS->num_vertices != num_atoms || pBNS->num_bonds != pBNS->num_edges)
+ - - + ]
11788 : : {
11789 : 0 : ret = BNS_REINIT_ERR;
11790 : 0 : goto exit_function;
11791 : : }
11792 : :
11793 : : /* Eliminate bonds and fix st-caps */
11794 [ + + ]: 971 : for (v = 0; v < num_atoms; v++)
11795 : : {
11796 : 810 : pAtom = pBNS->vert + v;
11797 [ + + ]: 2160 : for (j = 0; j < pAtom->valenceAltBns; j++)
11798 : : {
11799 : 1350 : pBond = pBNS->edge + pAtom->iedge[j];
11800 [ + + ]: 1350 : if (pBond->neighbor1 == v)
11801 : : {
11802 : 675 : bond_type = ( at[v].bond_type[j] & BOND_TYPE_MASK );
11803 : 675 : v2 = pBond->neighbor12 ^ v;
11804 [ + + + + ]: 675 : if (at[v].endpoint || at[v2].endpoint)
11805 : : {
11806 : 28 : bond_type = 0; /* any bond to an endpoint considered non-stereogenic */
11807 : : }
11808 : : #if ( FIX_EITHER_DB_AS_NONSTEREO == 1 )
11809 : : if (bUnknAltAsNoStereo)
11810 : : {
11811 : : if (bond_type == BOND_ALTERN && at[v].bond_stereo[j] == STEREO_DBLE_EITHER)
11812 : : {
11813 : : bond_type = 0; /* treat unknown (Either) ALT bond as non-stereo */
11814 : : }
11815 : : }
11816 : : #endif
11817 [ + - - - : 675 : switch (bond_type)
+ - ]
11818 : : {
11819 : :
11820 : 36 : case BOND_ALTERN:
11821 : 36 : pBond->nBondTypeInpAltBns = BT_ALTERN_BOND;
11822 : 36 : num_to_test++;
11823 : 36 : break;
11824 : :
11825 : 0 : case BOND_ALT_123:
11826 : : case BOND_ALT_13:
11827 : : case BOND_ALT_23:
11828 : 0 : pBond->nBondTypeInpAltBns = BT_OTHER_ALTERN_BOND;
11829 : 0 : break;
11830 : :
11831 : 0 : case BOND_TAUTOM:
11832 : 0 : pBond->nBondTypeInpAltBns = BT_TAUTOM_BOND;
11833 : 0 : break;
11834 : :
11835 : 0 : case BOND_ALT12NS:
11836 : 0 : pBond->nBondTypeInpAltBns = BT_ALTERN_NS_BOND;
11837 : 0 : break;
11838 : :
11839 : 639 : case 0:
11840 : : case BOND_SINGLE:
11841 : : case BOND_DOUBLE:
11842 : : case BOND_TRIPLE:
11843 : 639 : pBond->nBondTypeInpAltBns = BT_IGNORE_BOND;
11844 : 639 : break;
11845 : :
11846 : 0 : default:
11847 : 0 : pBond->nBondTypeInpAltBns = BT_IGNORE_BOND;
11848 : 0 : break;
11849 : : }
11850 : 675 : pBond->nBondNonStereoAltBns = 0; /* djb-rwth: addressing GCC warning -- operations on pBond->cap might be undefined */
11851 : 675 : pBond->nBlockNumberAltBns = 0;
11852 : 675 : pBond->nNumAtInBlockAltBns = 0;
11853 : :
11854 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
11855 : 675 : pBond->forbidden &= pBNS->edge_forbidden_mask;
11856 : : #endif
11857 : : }
11858 : : }
11859 : 810 : pAtom->bCutVertexAltBns =
11860 : 810 : pAtom->nRingSystemAltBns =
11861 : 810 : pAtom->nNumAtInRingSystemAltBns =
11862 : 810 : pAtom->nBlockSystemAltBns = 0;
11863 : : }
11864 : :
11865 : 161 : return num_to_test;
11866 : :
11867 : 0 : exit_function:
11868 : :
11869 : 0 : return ret;
11870 : : }
11871 : :
11872 : :
11873 : : /****************************************************************************/
11874 : 161 : int MarkNonStereoAltBns( BN_STRUCT *pBNS,
11875 : : inp_ATOM *at,
11876 : : int num_atoms,
11877 : : int bUnknAltAsNoStereo )
11878 : : {
11879 : 161 : int num_bonds = pBNS->num_bonds;
11880 : : int ret;
11881 : : int ibond, ib1, ib2;
11882 : : BNS_EDGE *pBond;
11883 : : Vertex iat1, iat2;
11884 : :
11885 : 161 : ret = 0;
11886 : :
11887 [ + - + - : 161 : if (pBNS->num_atoms != num_atoms || pBNS->num_vertices != num_atoms || pBNS->num_bonds != pBNS->num_edges)
- + ]
11888 : : {
11889 : 0 : ret = BNS_REINIT_ERR;
11890 : 0 : goto exit_function;
11891 : : }
11892 [ - + ]: 161 : if (bUnknAltAsNoStereo)
11893 : : {
11894 [ # # ]: 0 : for (ibond = 0; ibond < num_bonds; ibond++)
11895 : : {
11896 : 0 : pBond = pBNS->edge + ibond;
11897 [ # # # # ]: 0 : if (pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND)
11898 : : {
11899 : 0 : continue;
11900 : : }
11901 : 0 : iat1 = pBond->neighbor1;
11902 : 0 : iat2 = pBond->neighbor12 ^ iat1;
11903 : 0 : ib1 = pBond->neigh_ord[0];
11904 : 0 : ib2 = pBond->neigh_ord[1];
11905 : 0 : if ( /* alt bond non-adjacent to a taut. endpoint: */
11906 [ # # ]: 0 : ( pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
11907 [ # # ]: 0 : pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
11908 : : /* alt bond adjacent to a taut. endpoint: */
11909 [ # # ]: 0 : ( pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
11910 [ # # ]: 0 : ( at[iat1].bond_type[ib1] & BOND_TYPE_MASK ) == BOND_ALTERN )
11911 : : )
11912 : : {
11913 [ # # ]: 0 : if (( at[iat1].bond_type[ib1] & BOND_TYPE_MASK ) == BOND_ALTERN)
11914 : : {
11915 : : /* bond_type = BOND_ALT12NS; */
11916 : 0 : at[iat1].bond_stereo[ib1] =
11917 : 0 : at[iat2].bond_stereo[ib2] = STEREO_DBLE_EITHER;
11918 : 0 : ret++;
11919 : : }
11920 : : }
11921 : : }
11922 : : }
11923 : : else
11924 : : {
11925 [ + + ]: 836 : for (ibond = 0; ibond < num_bonds; ibond++)
11926 : : {
11927 : 675 : pBond = pBNS->edge + ibond;
11928 [ + + - + ]: 675 : if (pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND)
11929 : : {
11930 : 0 : continue;
11931 : : }
11932 : 675 : iat1 = pBond->neighbor1;
11933 : 675 : iat2 = pBond->neighbor12 ^ iat1;
11934 : 675 : ib1 = pBond->neigh_ord[0];
11935 : 675 : ib2 = pBond->neigh_ord[1];
11936 : 675 : if ( /* alt bond non-adjacent to a taut. endpoint: */
11937 [ + + ]: 675 : ( pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
11938 [ + - ]: 36 : pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
11939 : : /* alt bond adjacent to a taut. endpoint: */
11940 [ + + ]: 675 : ( pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
11941 [ - + ]: 639 : ( at[iat1].bond_type[ib1] & BOND_TYPE_MASK ) == BOND_ALTERN )
11942 : : )
11943 : : {
11944 : 0 : at[iat1].bond_type[ib1] =
11945 : 0 : at[iat2].bond_type[ib2] = BOND_ALT12NS;
11946 : 0 : ret++;
11947 : : }
11948 : : }
11949 : : }
11950 : :
11951 : 161 : exit_function:
11952 : :
11953 : 161 : return ret;
11954 : : }
11955 : :
11956 : :
11957 : : #if ( READ_INCHI_STRING == 1 )
11958 : : /*****************************************************************************/
11959 : : #ifndef RI_ERR_ALLOC
11960 : : /* from ichirvrs.h */
11961 : : #define RI_ERR_ALLOC (-1)
11962 : : #define RI_ERR_SYNTAX (-2)
11963 : : #define RI_ERR_PROGR (-3)
11964 : : #endif
11965 : :
11966 : :
11967 : : /****************************************************************************
11968 : : Check if atom bonded to charged atom
11969 : : ****************************************************************************/
11970 : 0 : int bHasChargedNeighbor( inp_ATOM *at, int iat )
11971 : : {
11972 : : int i;
11973 [ # # ]: 0 : for (i = 0; i < at[iat].valence; i++)
11974 : : {
11975 [ # # ]: 0 : if (at[(int) at[iat].neighbor[i]].charge)
11976 : : {
11977 : 0 : return 1;
11978 : : }
11979 : : }
11980 : :
11981 : 0 : return 0;
11982 : : }
11983 : :
11984 : :
11985 : : /****************************************************************************
11986 : : Add or remove protons
11987 : :
11988 : : *num_protons_to_add = nToBeRemovedByNormFromRevrs
11989 : :
11990 : : nToBeRemovedByNormFromRevrs > 0: less protons should be allowed to be
11991 : : added by the Normalization of the Reconstructed Structure
11992 : : nToBeRemovedByNormFromRevrs < 0: prepare more H(+) to be removed by
11993 : : the InChI Normalization of the Reconstructed Structure
11994 : :
11995 : : OrigStruct -> NormOrig + n(orig)*H(+)
11996 : : RevrStruct -> NormRevr + n(revr)*H(+)
11997 : : nToBeRemovedByNormFromRevrs = n(orig) - n(revr) [each may be negative]
11998 : :
11999 : : n(orig) > n(revr) or nToBeRemovedByNormFromRevrs > 0 means:
12000 : : -----------------------------------------------------------
12001 : : - Too many protons were added by the Normalization to the Reconstructed Structure
12002 : : (a) n(revr) < 0 => protons were added while they should not have been added;
12003 : : Solution: "neutralize" (-) charged proton acceptors by moving charges to other atoms
12004 : : on the condition ADP cannot add in another way;
12005 : : (b) n(orig) > n(revr) => 0 => too few protons were removed
12006 : : Solution: (the easiest) attach H(+) to =O or -N< or -N=
12007 : : Solution: move (+) from N or OH to an atom adjacent to (-) charge or to
12008 : : an atom that is not N.
12009 : :
12010 : : n(orig) < n(revr) or nToBeRemovedByNormFromRevrs < 0 means:
12011 : : -----------------------------------------------------------
12012 : : - Too few protons were added by the Normalization to the Reconstructed Stucture
12013 : : (a) n(orig) < 0 => protons were not added while they should have been added;
12014 : : Solution: move (-) to O by replacing =O with -O(-)
12015 : : (b) 0 <= n(orig) < n(revr) => too many protons were removed
12016 : :
12017 : : Note: it is critically important to takr into account cumbersome Normalization
12018 : : Total Charge: if it is >= 0 then no H(+) may be removed from -OH or by ADP
12019 : : However, if N(+) is present then ADP will always try to remove a proton
12020 : : ****************************************************************************/
12021 : 0 : int AddRemoveProtonsRestr( inp_ATOM *at,
12022 : : int num_atoms,
12023 : : int *num_protons_to_add,
12024 : : int nNumProtAddedByRestr,
12025 : : INCHI_MODE bNormalizationFlags,
12026 : : int num_tg,
12027 : : int nChargeRevrs,
12028 : : int nChargeInChI )
12029 : : {
12030 : 0 : int i, j, ret = 0;
12031 : : int nAtTypeTotals[ATTOT_ARRAY_LEN];
12032 : 0 : int num_prot = *num_protons_to_add;
12033 : 0 : int type, mask, bSuccess, nTotCharge, nNumSuccess = 0;
12034 : 0 : int max_j_Aa = -1, max_j_Ar = -1;
12035 : :
12036 : : /* for the reference:
12037 : :
12038 : : #define FLAG_NORM_CONSIDER_TAUT ( FLAG_PROTON_NPO_SIMPLE_REMOVED | \
12039 : : FLAG_PROTON_NP_HARD_REMOVED | \
12040 : : FLAG_PROTON_AC_SIMPLE_ADDED | \
12041 : : FLAG_PROTON_AC_SIMPLE_REMOVED | \
12042 : : FLAG_PROTON_AC_HARD_REMOVED | \
12043 : : FLAG_PROTON_AC_HARD_ADDED | \
12044 : : FLAG_PROTON_SINGLE_REMOVED | \
12045 : : FLAG_PROTON_CHARGE_CANCEL )
12046 : :
12047 : : #define FLAG_FORCE_SALT_TAUT ( FLAG_PROTON_NP_HARD_REMOVED | \
12048 : : FLAG_PROTON_AC_HARD_REMOVED | \
12049 : : FLAG_PROTON_AC_HARD_ADDED )
12050 : :
12051 : : */
12052 : :
12053 : : /* if ChargeRevrs > nChargeInChI then we should prevent proton addition or facilitate proton removal
12054 : : a typical case is (=) on N or O instead of C(-)
12055 : :
12056 : : if ChargeRevrs < nChargeInChI then we should prevent proton removal or facilitate proton addition
12057 : : */
12058 : :
12059 : 0 : mark_at_type( at, num_atoms, nAtTypeTotals );
12060 [ # # ]: 0 : for (i = nTotCharge = 0; i < num_atoms; i++)
12061 : : {
12062 : 0 : nTotCharge += at[i].charge;
12063 : : }
12064 : : /* Size for SimpleAddAcidicProtons() */
12065 [ # # ]: 0 : for (max_j_Aa = 0; AaTypMask[2 * max_j_Aa]; max_j_Aa++)
12066 : : {
12067 : : ;
12068 : : }
12069 : : /* Size for SimpleRemoveAcidicProtons */
12070 [ # # ]: 0 : for (max_j_Ar = 0; ArTypMask[2 * max_j_Ar]; max_j_Ar++)
12071 : : {
12072 : : ;
12073 : : }
12074 [ # # # # ]: 0 : if (num_prot < 0 && nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr <= 0)
12075 : : {
12076 : : /* Remove proton(s) */
12077 : : /* use test from SimpleAddAcidicProtons() to test whether removal of H(+) from =C-OH, etc. is correct */
12078 [ # # # # ]: 0 : for (i = 0; i < num_atoms && num_prot; i++)
12079 : : {
12080 : : /* Choose an atom */
12081 [ # # # # : 0 : if (at[i].sb_parity[0] || at[i].p_parity || at[i].charge ||
# # ]
12082 [ # # # # : 0 : !at[i].num_H || at[i].radical || bHasChargedNeighbor( at, i ))
# # ]
12083 : : {
12084 : 0 : continue;
12085 : : }
12086 : : /* try to remove a proton and check whether InChI would add it back */
12087 : 0 : at[i].charge--;
12088 : 0 : at[i].num_H--;
12089 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12090 : 0 : at[i].charge++;
12091 : 0 : at[i].num_H++;
12092 : :
12093 [ # # ]: 0 : if (type)
12094 : : {
12095 [ # # ]: 0 : for (bSuccess = 0, j = 0; j < max_j_Aa; j++)
12096 : : {
12097 [ # # # # : 0 : if ((bSuccess = ( type & AaTypMask[2 * j] ) && ( mask && AaTypMask[2 * j + 1] ))) /* djb-rwth: addressing LLVM warning */
# # # # ]
12098 : : {
12099 : 0 : break; /* the proton may be added to this atom */
12100 : : }
12101 : : }
12102 [ # # ]: 0 : if (bSuccess)
12103 : : {
12104 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12105 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12106 : 0 : at[i].charge--;
12107 : 0 : at[i].num_H--;
12108 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12109 : 0 : num_prot++; /* success */
12110 : 0 : nNumSuccess++;
12111 : : }
12112 : : }
12113 : : }
12114 : : }
12115 : :
12116 [ # # # # : 0 : if (num_prot < 0 && num_tg && nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr <= 0)
# # ]
12117 : : {
12118 : : /* Alternative proton removal: O=C-NH => (-)O-C=N, O and N are taut. endpoints */
12119 : : int endp2, centp, k, i0, k0;
12120 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
12121 : : {
12122 : : /* Choose an atom */
12123 [ # # # # : 0 : if (!at[i].endpoint || at[i].sb_parity[0] || at[i].p_parity ||
# # ]
12124 [ # # # # : 0 : at[i].radical || at[i].charge || bHasChargedNeighbor( at, i ))
# # ]
12125 : : {
12126 : 0 : continue;
12127 : : }
12128 : : /* Looking for tautomeric =O */
12129 [ # # # # : 0 : if (1 != at[i].valence || BOND_TYPE_DOUBLE != at[i].bond_type[0] || at[i].num_H ||
# # # # ]
12130 : 0 : 2 != get_endpoint_valence( at[i].el_number ))
12131 : : {
12132 : 0 : continue;
12133 : : }
12134 : 0 : centp = at[i].neighbor[0];
12135 [ # # # # : 0 : if (at[centp].sb_parity[0] || at[centp].p_parity || !is_centerpoint_elem( at[centp].el_number ))
# # ]
12136 : : {
12137 : 0 : continue;
12138 : : }
12139 : : /* Found a possible centerpoint, looking for -NH endpoint */
12140 [ # # ]: 0 : for (k = 0; k < at[centp].valence; k++)
12141 : : {
12142 [ # # ]: 0 : if (at[centp].bond_type[k] != BOND_TYPE_SINGLE)
12143 : : {
12144 : 0 : continue;
12145 : : }
12146 : 0 : endp2 = at[centp].neighbor[k];
12147 [ # # ]: 0 : if (at[endp2].endpoint != at[i].endpoint ||
12148 [ # # # # ]: 0 : !at[endp2].num_H || at[endp2].charge ||
12149 [ # # # # ]: 0 : at[endp2].sb_parity[0] || at[endp2].p_parity ||
12150 [ # # ]: 0 : at[endp2].valence != at[endp2].chem_bonds_valence ||
12151 [ # # # # ]: 0 : 3 != at[endp2].chem_bonds_valence + at[endp2].num_H ||
12152 : 0 : 3 != get_endpoint_valence( at[endp2].el_number ))
12153 : : {
12154 : 0 : continue;
12155 : : }
12156 : : /* Find bonds in reciprocal ajacency lists */
12157 [ # # # # ]: 0 : for (i0 = 0; i0 < at[centp].valence && i != at[centp].neighbor[i0]; i0++)
12158 : : {
12159 : : ;
12160 : : }
12161 [ # # # # ]: 0 : for (k0 = 0; k0 < at[endp2].valence && centp != at[endp2].neighbor[k0]; k0++)
12162 : : {
12163 : : ;
12164 : : }
12165 [ # # # # ]: 0 : if (i0 == at[centp].valence || k0 == at[endp2].valence)
12166 : : {
12167 : 0 : return RI_ERR_PROGR;
12168 : : }
12169 : : /* -NH has been found */
12170 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12171 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12172 : 0 : type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 1 ); /* subtract at[endp2] */
12173 : :
12174 : 0 : at[i].bond_type[0] --;
12175 : 0 : at[centp].bond_type[i0] --;
12176 : 0 : at[i].chem_bonds_valence--;
12177 : 0 : at[i].charge--;
12178 : :
12179 : 0 : at[endp2].bond_type[k0] ++;
12180 : 0 : at[centp].bond_type[k] ++;
12181 : 0 : at[endp2].chem_bonds_valence++;
12182 : 0 : at[endp2].num_H--;
12183 : :
12184 : 0 : num_prot++;
12185 : 0 : nNumSuccess++;
12186 : :
12187 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12188 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add at[i] */
12189 : 0 : type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 0 ); /* add at[endp2] */
12190 : : }
12191 : : }
12192 : : }
12193 : :
12194 [ # # ]: 0 : if (num_prot > 0)
12195 : : {
12196 : : /* Add protons */
12197 : : /* 1. Use test from SimpleRemoveAcidicProtons() to test whether addition of H(+) to =C-O(-), etc. is correct */
12198 [ # # # # : 0 : for (i = 0; i < num_atoms && num_prot && nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr >= 0; i++)
# # ]
12199 : : {
12200 : : /* Choose an atom */
12201 [ # # # # : 0 : if (at[i].sb_parity[0] || at[i].p_parity || at[i].num_H ||
# # ]
12202 [ # # # # : 0 : at[i].charge != -1 || at[i].radical || bHasChargedNeighbor( at, i ))
# # ]
12203 : : {
12204 : 0 : continue;
12205 : : }
12206 : : /* Try to add a proton and check whether InChI would remove it back */
12207 : 0 : at[i].charge++;
12208 : 0 : at[i].num_H++;
12209 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12210 : 0 : at[i].charge--;
12211 : 0 : at[i].num_H--;
12212 [ # # ]: 0 : if (type)
12213 : : {
12214 [ # # ]: 0 : for (bSuccess = 0, j = 0; j < max_j_Ar; j++)
12215 : : {
12216 [ # # # # : 0 : if ((bSuccess = ( type & ArTypMask[2 * j] ) && ( mask && ArTypMask[2 * j + 1] ))) /* djb-rwth: addressing LLVM warning */
# # # # ]
12217 : : {
12218 : 0 : break;
12219 : : }
12220 : : }
12221 [ # # ]: 0 : if (bSuccess)
12222 : : {
12223 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12224 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12225 : 0 : at[i].charge++;
12226 : 0 : at[i].num_H++;
12227 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12228 : 0 : num_prot--; /* success */
12229 : 0 : nNumSuccess++;
12230 : : }
12231 : : }
12232 : : }
12233 : : /* 2. Use test from SimpleRemoveHplusNPO() */
12234 [ # # # # ]: 0 : for (i = 0; i < num_atoms && num_prot; i++)
12235 : : {
12236 : : /* Choose an atom */
12237 [ # # # # ]: 0 : if (at[i].sb_parity[0] || at[i].p_parity ||
12238 [ # # # # : 0 : at[i].charge || at[i].radical || bHasChargedNeighbor( at, i ))
# # ]
12239 : : {
12240 : 0 : continue;
12241 : : }
12242 : : /* Try to add a proton and check whether InChI would remove it back */
12243 : 0 : at[i].num_H++;
12244 : 0 : at[i].charge++;
12245 [ # # ]: 0 : bSuccess = ( PR_SIMPLE_TYP & ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ) ) &&
12246 [ # # ]: 0 : ( PR_SIMPLE_MSK & mask ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12247 : 0 : at[i].num_H--; /* failed */
12248 : 0 : at[i].charge--;
12249 [ # # ]: 0 : if (bSuccess)
12250 : : {
12251 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12252 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12253 : 0 : at[i].num_H++;
12254 : 0 : at[i].charge++;
12255 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12256 : 0 : num_prot--; /* succeeded */
12257 : 0 : nNumSuccess++;
12258 : : }
12259 : : }
12260 : : }
12261 : :
12262 [ # # # # : 0 : if (num_prot < 0 && ( bNormalizationFlags & FLAG_PROTON_AC_HARD_ADDED ) && 1 == num_tg &&
# # ]
12263 [ # # ]: 0 : nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr <= 0)
12264 : : {
12265 : : /* Try to remove protons from tautomeric N (specific ADP must be present) */
12266 : 0 : int nNumAcceptors_DB_O = 0, nNumDonors_SB_NH = 0, num_max, num_success;
12267 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
12268 : : {
12269 : : /* Choose an atom */
12270 [ # # # # ]: 0 : if (!at[i].endpoint || at[i].radical ||
12271 [ # # # # : 0 : at[i].sb_parity[0] || at[i].p_parity || bHasChargedNeighbor( at, i ))
# # ]
12272 : : {
12273 : 0 : continue;
12274 : : }
12275 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12276 [ # # # # ]: 0 : if (( type & AA_HARD_TYP_CO ) && ( mask & AA_HARD_MSK_CO ))
12277 : : {
12278 : 0 : nNumAcceptors_DB_O++;
12279 : : }
12280 : : else
12281 : : {
12282 [ # # # # : 0 : if (( type == ATT_ATOM_N ) && ( mask == ATBIT_NP_H ) && !at[i].charge &&
# # ]
12283 [ # # ]: 0 : at[i].valence == at[i].chem_bonds_valence)
12284 : : {
12285 : 0 : nNumDonors_SB_NH++;
12286 : : }
12287 : : }
12288 : : }
12289 : 0 : num_max = inchi_min( nNumAcceptors_DB_O, nNumDonors_SB_NH );
12290 [ # # # # : 0 : for (i = 0, num_success = 0; i < num_atoms && num_success < num_max && num_prot < 0; i++)
# # ]
12291 : : {
12292 : : /* Choose an atom */
12293 [ # # # # : 0 : if (!at[i].endpoint || at[i].radical || at[i].sb_parity[0] ||
# # ]
12294 [ # # # # ]: 0 : at[i].p_parity || bHasChargedNeighbor( at, i ))
12295 : : {
12296 : 0 : continue;
12297 : : }
12298 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12299 [ # # # # : 0 : if (( type == ATT_ATOM_N ) && ( mask == ATBIT_NP_H ) && !at[i].charge &&
# # ]
12300 [ # # ]: 0 : at[i].valence == at[i].chem_bonds_valence)
12301 : : {
12302 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12303 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12304 : 0 : at[i].num_H--;
12305 : 0 : at[i].charge--;
12306 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12307 : 0 : num_prot++;
12308 : 0 : num_success++;
12309 : 0 : nNumSuccess++;
12310 : : }
12311 : : }
12312 : : }
12313 : :
12314 : : /*exit_function:*/
12315 : :
12316 : 0 : *num_protons_to_add = num_prot;
12317 : :
12318 [ # # ]: 0 : return ret < 0 ? ret : nNumSuccess;
12319 : : }
12320 : :
12321 : :
12322 : : /****************************************************************************
12323 : : Add or remove isotopic protons
12324 : : ****************************************************************************/
12325 : 0 : int AddRemoveIsoProtonsRestr( inp_ATOM *at,
12326 : : int num_atoms,
12327 : : NUM_H num_protons_to_add[],
12328 : : int num_tg )
12329 : : {
12330 : 0 : int i, j, k, n, ret = 0;
12331 : 0 : int nNumSuccess = 0, min_at, max_at, num_H, num_iso_H, num_expl_H, num_expl_iso_H; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
12332 : : int iCurIso; /* 0=> 1H, 1=> D, 2=> T */
12333 : : int iCurMode, iCurMode1, iCurMode2; /* 0=> Not Endpoints, 1=> Endpoints */
12334 : :
12335 : : /* Distribute isotopes from heaviest to lightest; pick up atoms in order 1. Not endpoints; 2. Endpoints */
12336 : 0 : iCurMode1 = 0;
12337 : 0 : iCurMode2 = num_tg ? 1 : 0;
12338 [ # # ]: 0 : for (iCurMode = iCurMode1; iCurMode <= iCurMode2; iCurMode++)
12339 : : {
12340 [ # # ]: 0 : for (iCurIso = 2; 0 <= iCurIso; iCurIso--)
12341 : : {
12342 : : /* check for isotopic H to add */
12343 [ # # ]: 0 : if (!num_protons_to_add[iCurIso])
12344 : : {
12345 : 0 : continue;
12346 : : }
12347 [ # # ]: 0 : if (0 > num_protons_to_add[iCurIso])
12348 : : {
12349 : 0 : ret = RI_ERR_PROGR;
12350 : 0 : goto exit_function;
12351 : : }
12352 : :
12353 : : /* Limits for atom scanning */
12354 : 0 : min_at = 0;
12355 : 0 : max_at = num_atoms;
12356 : :
12357 : : /* Cycle withio the limits */
12358 [ # # # # ]: 0 : for (i = min_at; i < max_at && 0 < num_protons_to_add[iCurIso]; i++)
12359 : : {
12360 : : /* Pick an atom */
12361 [ # # ]: 0 : if (iCurMode)
12362 : : {
12363 [ # # ]: 0 : if (at[i].endpoint)
12364 : : {
12365 : 0 : j = i; /* atom number */
12366 : : }
12367 : : else
12368 : : {
12369 : 0 : continue;
12370 : : }
12371 : : }
12372 : : else
12373 : : {
12374 [ # # # # ]: 0 : if (!at[i].endpoint && 1 == bHeteroAtomMayHaveXchgIsoH( at, i ))
12375 : : { /* atom number */
12376 : 0 : j = i;
12377 : : }
12378 : : else
12379 : : {
12380 [ # # # # ]: 0 : if (at[i].el_number == EL_NUMBER_H && at[i].charge == 1 &&
12381 [ # # # # : 0 : !at[i].valence && !at[i].radical && !at[i].iso_atw_diff)
# # ]
12382 : : {
12383 : : /* proton, not isotopic; make it isotopic */
12384 : 0 : at[i].iso_atw_diff = 1 + iCurIso;
12385 : 0 : num_protons_to_add[iCurIso] --;
12386 : 0 : nNumSuccess++;
12387 : 0 : continue;
12388 : : }
12389 : : else
12390 : : {
12391 : 0 : continue;
12392 : : }
12393 : : }
12394 : : }
12395 : :
12396 : : /* j is the atom number */
12397 : : /* count implicit H */
12398 : 0 : num_H = at[j].num_H;
12399 : 0 : num_iso_H = NUM_ISO_H(at, j); /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
12400 : :
12401 [ # # # # ]: 0 : while (num_H > 0 && num_protons_to_add[iCurIso] > 0)
12402 : : {
12403 : : /* Substitute one implicit H with an isotopic atom H */
12404 : 0 : at[j].num_iso_H[iCurIso] ++;
12405 : 0 : at[j].num_H--;
12406 : 0 : num_protons_to_add[iCurIso] --;
12407 : 0 : num_H--;
12408 : 0 : num_iso_H++;
12409 : 0 : nNumSuccess++;
12410 : : }
12411 : : /* Count explicit H */
12412 : 0 : num_expl_H = num_expl_iso_H = 0;
12413 [ # # # # ]: 0 : for (k = 0; k < at[j].valence && num_atoms <= ( n = at[j].neighbor[k] ); k++)
12414 : : {
12415 : 0 : num_expl_H += ( 0 == at[n].iso_atw_diff );
12416 : 0 : num_expl_iso_H += ( 0 != at[n].iso_atw_diff );
12417 : : }
12418 [ # # # # ]: 0 : while (num_expl_H > 0 && num_protons_to_add[iCurIso] > 0)
12419 : : {
12420 : : /* Substitute one explicit H with an isotopic atom H */
12421 : 0 : n = at[j].neighbor[num_expl_H];
12422 [ # # ]: 0 : if (at[n].iso_atw_diff)
12423 : : {
12424 : 0 : ret = RI_ERR_PROGR;
12425 : 0 : goto exit_function;
12426 : : }
12427 : 0 : at[n].iso_atw_diff = 1 + iCurIso;
12428 : 0 : num_expl_H--;
12429 : 0 : num_expl_iso_H++;
12430 : 0 : num_protons_to_add[iCurIso] --;
12431 : 0 : nNumSuccess++;
12432 : : }
12433 : : }
12434 : : }
12435 : : }
12436 : :
12437 : 0 : exit_function:
12438 : :
12439 [ # # ]: 0 : return ret < 0 ? ret : nNumSuccess;
12440 : : }
12441 : :
12442 : : #endif
|