Branch data Line data Source code
1 : : /*
2 : : * International Chemical Identifier (InChI)
3 : : * Version 1
4 : : * Software version 1.07
5 : : * April 30, 2024
6 : : *
7 : : * MIT License
8 : : *
9 : : * Copyright (c) 2024 IUPAC and InChI Trust
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
12 : : * of this software and associated documentation files (the "Software"), to deal
13 : : * in the Software without restriction, including without limitation the rights
14 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 : : * copies of the Software, and to permit persons to whom the Software is
16 : : * furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice shall be included in all
19 : : * copies or substantial portions of the Software.
20 : : *
21 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 : : * SOFTWARE.
28 : : *
29 : : * The InChI library and programs are free software developed under the
30 : : * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
31 : : * Originally developed at NIST.
32 : : * Modifications and additions by IUPAC and the InChI Trust.
33 : : * Some portions of code were developed/changed by external contributors
34 : : * (either contractor or volunteer) which are listed in the file
35 : : * 'External-contributors' included in this distribution.
36 : : *
37 : : * info@inchi-trust.org
38 : : *
39 : : */
40 : :
41 : :
42 : : /*
43 : : Balanced Network Search
44 : :
45 : : Normalization related procedures
46 : : */
47 : :
48 : : #include <stdlib.h>
49 : : #include <string.h>
50 : : #include <stdint.h>
51 : :
52 : : #include "mode.h"
53 : : #include "ichitime.h"
54 : : #include "ichicant.h"
55 : : #include "ichierr.h"
56 : : #include "ichitaut.h"
57 : : #include "ichinorm.h"
58 : : #include "util.h"
59 : : #include "ichister.h"
60 : : #include "ichi_bns.h"
61 : :
62 : : #include "bcf_s.h"
63 : :
64 : : #include <string.h>
65 : : #include "logging.h" /*(@nnuk : Nauman Ullah Khan) :: Needed for logging functionality*/
66 : :
67 : : #define BNS_MARK_ONLY_BLOCKS 1 /* 1 => find only blocks, do not search for ring systems */
68 : : #define ALLOW_ONLY_SIMPLE_ALT_PATH 0 /* 0 => allow alt. path to contain same bond 2 times (in opposite directions) */
69 : : #define CHECK_TG_ALT_PATH 0 /* 1=> when chacking alt path of a tautomeric atom modify
70 : : t-group, not the atom */
71 : : /* 0=> old mode */
72 : :
73 : : #define FIX_CPOINT_BOND_CAP 1 /* 1=> fix bug in case of double bond from neutral cpoint */
74 : : #define RESET_EDGE_FORBIDDEN_MASK 1 /* 1: previous; 0: do not apply "edge->forbidden &= pBNS->edge_forbidden_mask" */
75 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
76 : : #define IS_FORBIDDEN(EDGE_FORBIDDEN, PBNS) (EDGE_FORBIDDEN)
77 : : #else
78 : : #define IS_FORBIDDEN(EDGE_FORBIDDEN, PBNS) (EDGE_FORBIDDEN & PBNS->edge_forbidden_mask)
79 : : #endif
80 : :
81 : :
82 : : typedef enum tagAtTypeTotals
83 : : {
84 : : /* counts do not include:
85 : : charged atom adjacent to another charged atom
86 : : atom in an unusual valence state or adjacent to an atom in an unusual valence state
87 : : radicals different from singlet
88 : : */
89 : : /*ATTOT_NUM_Plus. */ /* number of positive charges, +1, is (ATTOT_NUM_CHARGES + ATTOT_TOT_CHARGE)/2 */
90 : : /*ATTOT_NUM_Minus.*/ /* number of negative charges, -1, is (ATTOT_NUM_CHARGES - ATTOT_TOT_CHARGE)/2 */
91 : : ATTOT_NUM_NP_Plus, /* 0 no H: =N(+)=, #N(+)-, =N(+)<, does not include onium cations >P(+)<, >N(+)< */
92 : : ATTOT_NUM_NP_Proton, /* 1 H(+): -NH3(+), =NH2(+), >NH2(+), =NH(+)-, >NH(+)-, #NH(+), N=N,P */
93 : : ATTOT_NUM_NP_H, /* 2 H: -NH2, =NH, >NH -NH(-) */
94 : : ATTOT_NUM_N_Minus, /* 3 (-): -NH(-), >N(-), =N(-) */
95 : : ATTOT_NUM_NP, /* 4 no H: >N- =N-, #N */
96 : : ATTOT_NUM_ON, /* 5 -N=O: do not allow -N=O => -NH-OH during H(+) add/removal */
97 : : ATTOT_NUM_COH, /* 6 =C-OH, #C-OH; O=O,S,Se,Te */
98 : : ATTOT_NUM_CSH, /* 7 -C-SH, -C-SeH -C-TeH */
99 : : ATTOT_NUM_ZOH, /* 8 =Z-OH, #Z-OH; O=O,S,Se,Te; Z may have charge, Z != C */
100 : : ATTOT_NUM_OOH, /* 9 -O-OH, O=O,S,Se,Te */
101 : : ATTOT_NUM_ZOOH, /* 10 O=Z-OH, O=O,S,Se,Te */
102 : : ATTOT_NUM_NOH, /* 11 =N-OH, -N(-)-OH */
103 : : ATTOT_NUM_N_OH, /* 12 >N-OH, -NH-OH, >NH(+)-OH, -N(-)-OH */
104 : : ATTOT_NUM_CO, /* 13 -C=O, =C=O; O=O,S,Se,Te */
105 : : ATTOT_NUM_ZO, /* 14 -Z=O, =Z=O; O=O,S,Se,Te; Z may have charge */
106 : : ATTOT_NUM_NO, /* 15 -N=O, =N(+)=O */
107 : : ATTOT_NUM_N_O, /* 16 >N(+)=O, =N(+)=O */
108 : : ATTOT_NUM_CO_Minus, /* 17 =C-O(-), #C-O(-); O=O,S,Se,Te */
109 : : ATTOT_NUM_CS_Minus, /* 18 -C-S(-); S = S, Se, Te */
110 : : ATTOT_NUM_ZO_Minus, /* 19 =Z-O(-), #Z-O(-); O = O, S, Se, Te */
111 : : ATTOT_NUM_OO_Minus, /* 20 -O-O(-), O=O,S,Se,Te */
112 : : ATTOT_NUM_ZOO_Minus, /* 21 O=Z-O(-), O=O,S,Se,Te */
113 : : ATTOT_NUM_NO_Minus, /* 22 >N-O(-), -NH-O(-) */
114 : : ATTOT_NUM_N_O_Minus, /* 23 -NH-O(-), >N-O(-); O = O, S, Se, Te */
115 : : ATTOT_NUM_O_Minus, /* 24 -Z-O(-); O=O,S,Se,Te */
116 : : ATTOT_NUM_OH_Plus, /* 25 any OH(+) */
117 : : ATTOT_NUM_O_Plus, /* 26 any O(+) without H */
118 : : ATTOT_NUM_Proton, /* 27 proton */
119 : : ATTOT_NUM_HalAnion, /* 28 Halogen anion */
120 : : ATTOT_NUM_HalAcid, /* 29 Halogen acid */
121 : : ATTOT_NUM_Errors, /* 30 for debugging */
122 : : ATTOT_TOT_CHARGE, /* 31 total of positive and negative single charges, +1 and -1 */
123 : : ATTOT_NUM_CHARGES, /* 32 number of positive and negative single charges, +1 and -1 */
124 : : ATTOT_ARRAY_LEN /* 33 array length */
125 : : } AT_TYPE_TOTALS;
126 : :
127 : : #define ATBIT_NP_Plus (1 << ATTOT_NUM_NP_Plus)
128 : : #define ATBIT_NP_Proton (1 << ATTOT_NUM_NP_Proton)
129 : : #define ATBIT_NP_H (1 << ATTOT_NUM_NP_H)
130 : : #define ATBIT_N_Minus (1 << ATTOT_NUM_N_Minus)
131 : : #define ATBIT_NP (1 << ATTOT_NUM_NP)
132 : : #define ATBIT_ON (1 << ATTOT_NUM_ON)
133 : : #define ATBIT_COH (1 << ATTOT_NUM_COH)
134 : : #define ATBIT_CSH (1 << ATTOT_NUM_CSH)
135 : : #define ATBIT_ZOH (1 << ATTOT_NUM_ZOH)
136 : : #define ATBIT_OOH (1 << ATTOT_NUM_OOH)
137 : : #define ATBIT_ZOOH (1 << ATTOT_NUM_ZOOH)
138 : : #define ATBIT_NOH (1 << ATTOT_NUM_NOH)
139 : : #define ATBIT_N_OH (1 << ATTOT_NUM_N_OH)
140 : : #define ATBIT_CO (1 << ATTOT_NUM_CO)
141 : : #define ATBIT_ZO (1 << ATTOT_NUM_ZO)
142 : : #define ATBIT_NO (1 << ATTOT_NUM_NO)
143 : : #define ATBIT_N_O (1 << ATTOT_NUM_N_O)
144 : : #define ATBIT_CO_Minus (1 << ATTOT_NUM_CO_Minus)
145 : : #define ATBIT_CS_Minus (1 << ATTOT_NUM_CS_Minus)
146 : : #define ATBIT_ZO_Minus (1 << ATTOT_NUM_ZO_Minus)
147 : : #define ATBIT_OO_Minus (1 << ATTOT_NUM_OO_Minus)
148 : : #define ATBIT_ZOO_Minus (1 << ATTOT_NUM_ZOO_Minus)
149 : : #define ATBIT_NO_Minus (1 << ATTOT_NUM_NO_Minus)
150 : : #define ATBIT_N_O_Minus (1 << ATTOT_NUM_N_O_Minus)
151 : : #define ATBIT_O_Minus (1 << ATTOT_NUM_O_Minus)
152 : : #define ATBIT_OH_Plus (1 << ATTOT_NUM_OH_Plus)
153 : : #define ATBIT_O_Plus (1 << ATTOT_NUM_O_Plus)
154 : : #define ATBIT_Proton (1 << ATTOT_NUM_Proton)
155 : : #define ATBIT_HalAnion (1 << ATTOT_NUM_HalAnion)
156 : : #define ATBIT_HalAcid (1 << ATTOT_NUM_HalAcid)
157 : :
158 : :
159 : : #define ATBIT_Errors (1 << ATTOT_NUM_Errors)
160 : :
161 : : typedef struct tagProtonRemovalMaskAndType
162 : : {
163 : : int typePos; /* atoms accessible to positive charges */
164 : : int maskPos;
165 : : int typeNeg; /* atoms accessible to negative charges */
166 : : int maskNeg;
167 : : int typeH; /* atoms accessible to hydrogen atoms */
168 : : int maskH;
169 : : } PRMAT;
170 : :
171 : : #define PR_SIMPLE_MSK (ATBIT_NP_Proton | ATBIT_OH_Plus)
172 : : #define PR_SIMPLE_TYP (ATT_ATOM_N | ATT_ATOM_P | ATT_O_PLUS)
173 : :
174 : : #define ATBIT_MSK_NP (ATBIT_NP_Plus | ATBIT_NP_Proton | ATBIT_NP_H | ATBIT_N_Minus | ATBIT_NP)
175 : : #define KNOWN_ACIDIC_TYPE (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO)
176 : : #define ATBIT_MSK_OS (ATBIT_COH | ATBIT_CSH | ATBIT_ZOH | ATBIT_OOH | ATBIT_ZOOH | ATBIT_NOH | ATBIT_N_OH |\
177 : : ATBIT_CO | ATBIT_ZO | ATBIT_NO | ATBIT_N_O |\
178 : : ATBIT_CO_Minus | ATBIT_CS_Minus | ATBIT_ZO_Minus | ATBIT_OO_Minus |\
179 : : ATBIT_ZOO_Minus | ATBIT_NO_Minus | ATBIT_N_O_Minus /*| ATBIT_O_Minus*/ )
180 : : #define ATBIT_MSK_H (ATBIT_NP_Proton | ATBIT_NP_H | ATBIT_COH | ATBIT_CSH | ATBIT_ZOH | ATBIT_OOH |\
181 : : ATBIT_ZOOH | ATBIT_NOH | ATBIT_N_OH)
182 : :
183 : : #define ATTYP_OS (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO /*| ATT_OTHER_NEG_O*/ | ATT_OTHER_ZO)
184 : : #define ATTYP_NP (ATT_ATOM_N | ATT_ATOM_P)
185 : : #define ATTYP_N (ATT_ATOM_N)
186 : : #define ATTYP_P (ATT_ATOM_P)
187 : :
188 : : /************* simple proton removal from acids **************************/
189 : : #define AR_ANY_OH 0 /* 1 => create unknown to be acidic anions */
190 : : #define AR_SIMPLE_STEPS 3
191 : : /* acidic groups for proton removal, step 1 */
192 : : #define AR_SIMPLE_MSK1 (ATBIT_COH | ATBIT_CSH | ATBIT_OOH | ATBIT_ZOOH | ATBIT_NOH | ATBIT_HalAcid)
193 : : #define AR_SIMPLE_TYP1 (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO | ATT_HalAcid)
194 : : /* acidic groups for proton removal, step 2 */
195 : : #define AR_SIMPLE_MSK2 (AR_ANY_OH? (ATBIT_N_OH) :0)
196 : : #define AR_SIMPLE_TYP2 (AR_ANY_OH? (ATT_N_O) :0)
197 : : /* acidic groups for proton removal, step 3 */
198 : : #define AR_SIMPLE_MSK3 (AR_ANY_OH? (ATBIT_ZOH) :0)
199 : : #define AR_SIMPLE_TYP3 (AR_ANY_OH? (ATT_OTHER_ZO):0)
200 : :
201 : : /************* simple proton addition to acids **************************/
202 : : #define AA_ANY_O_Minus 0 /* 1 => neutralize unknown to be acidic anions */
203 : : #define AA_SIMPLE_STEPS 3
204 : : /* acidic groups for proton addition, step 1 */
205 : : #define AA_SIMPLE_MSK1 (ATBIT_CO_Minus | ATBIT_CS_Minus | ATBIT_OO_Minus | ATBIT_ZOO_Minus | ATBIT_NO_Minus | ATBIT_O_Minus | ATBIT_HalAnion)
206 : : #define AA_SIMPLE_TYP1 (ATT_ACIDIC_CO | ATT_ACIDIC_S | ATT_OO | ATT_ZOO | ATT_NO | ATT_OH_MINUS | ATT_HalAnion )
207 : : /* acidic groups for proton addition, step 2 */
208 : : #define AA_SIMPLE_MSK2 (AA_ANY_O_Minus? (ATBIT_N_O_Minus) :0)
209 : : #define AA_SIMPLE_TYP2 (AA_ANY_O_Minus? (ATT_N_O) :0)
210 : : /* acidic groups for proton addition, step 3 */
211 : : #define AA_SIMPLE_MSK3 (AA_ANY_O_Minus? (ATBIT_ZO_Minus | ATBIT_O_Minus):0)
212 : : #define AA_SIMPLE_TYP3 (AA_ANY_O_Minus? (ATT_OTHER_ZO) :0)
213 : :
214 : : #if ( FIX_NP_MINUS_BUG == 1 )
215 : : /* allow to add H(+) to =N(-) which previously was #N */
216 : : #undef AA_SIMPLE_STEPS
217 : : #define AA_SIMPLE_STEPS 4
218 : : #define AA_SIMPLE_MSK4 ATBIT_N_Minus
219 : : #define AA_SIMPLE_TYP4 ATT_NP_MINUS_V23
220 : : #endif
221 : :
222 : : /************* hard proton removal from NP **************************/
223 : : /* (+) charge group for proton removal: mask & type */
224 : : #define PR_HARD_MSK_POS ATBIT_MSK_NP
225 : : #define PR_HARD_TYP_POS ATTYP_N
226 : : #define PR_HARD_TYP_POSP ATTYP_P
227 : : /* (-) charge group for proton removal */
228 : : #define PR_HARD_MSK_NEG (ATBIT_MSK_NP | ATBIT_MSK_OS)
229 : : #define PR_HARD_TYP_NEG (ATTYP_N | ATTYP_OS)
230 : : /* H-group for proton removal */
231 : : #define PR_HARD_MSK_H (ATBIT_MSK_NP | ATBIT_MSK_OS)
232 : : #define PR_HARD_TYP_H (ATTYP_N | ATTYP_OS)
233 : :
234 : : /************* hard proton removal from acids **************************/
235 : : /* (+) charge group for proton removal: mask & type */
236 : : #define AR_HARD_MSK_POS ATBIT_MSK_NP
237 : : #define AR_HARD_TYP_POS ATTYP_N
238 : : /* (-) charge group for proton removal */
239 : : #define AR_HARD_MSK_NEG (ATBIT_MSK_NP | ATBIT_MSK_OS)
240 : : #define AR_HARD_TYP_NEG (ATTYP_N | ATTYP_OS)
241 : : /* H-group acid for proton removal */
242 : : #define AR_HARD_MSK_HA (ATBIT_CO | ATBIT_NO )
243 : : #define AR_HARD_TYP_HA (ATT_ACIDIC_CO | ATT_NO)
244 : : /* H-group non-acid for proton removal */
245 : : #define AR_HARD_MSK_HN ((ATBIT_MSK_NP | ATBIT_MSK_OS) & ~AR_HARD_MSK_HA)
246 : : #define AR_HARD_TYP_HN ((ATTYP_N | ATTYP_OS) /*& ~AR_HARD_TYP_HA*/)
247 : :
248 : : /************* hard proton addition to acids **************************/
249 : : /* (+) charge group for proton removal: mask & type */
250 : : #define AA_HARD_MSK_POS ATBIT_MSK_NP
251 : : #define AA_HARD_TYP_POS ATTYP_N
252 : : /* (-) charge group for negative charge removal */
253 : : #define AA_HARD_MSK_NEG ((ATBIT_MSK_NP | ATBIT_MSK_OS) & ~(ATBIT_CO | ATBIT_NO ))
254 : : #define AA_HARD_TYP_NEG (ATTYP_N | ATTYP_OS)
255 : : /* (-) charge group to accept negative charges */
256 : : #define AA_HARD_MSK_CO (ATBIT_CO | ATBIT_NO )
257 : : #define AA_HARD_TYP_CO (ATT_ACIDIC_CO | ATT_NO)
258 : : /* H-group non-acid for proton removal */
259 : : #define AA_HARD_MSK_H (ATBIT_MSK_NP | ATBIT_MSK_OS)
260 : : #define AA_HARD_TYP_H (ATTYP_N | ATTYP_OS)
261 : :
262 : :
263 : : /*****************************************************************************/
264 : : #define BNS_MAX_NUM_FLOW_CHANGES (1+2*MAX_BOND_EDGE_CAP)
265 : :
266 : : /* -- opiginal Pascal values --
267 : : #define NO_VERTEX 0
268 : : #define BLOSSOM_BASE -1
269 : : #define FIRST_INDX 1
270 : : */
271 : :
272 : : #define TREE_NOT_IN_M 0 /* not in T or T' */
273 : : #define TREE_IN_2 1 /* in T' and not s-reachable */
274 : : #define TREE_IN_2BLOSS 2 /* in T' and in a blossom, is s-reachable */
275 : : #define TREE_IN_1 3 /* in T and is s-reachable */
276 : :
277 : : #define TREE_IS_S_REACHABLE(X) (Tree[X] >= TREE_IN_2BLOSS)
278 : : #define TREE_IS_ON_SCANQ TREE_IS_S_REACHABLE
279 : : /* #define TREE_IS_ON_SCANQ(X) (Tree[X] != TREE_NOT_IN_M) */
280 : : #define TREE_MARK(X, MARK) do{ if( Tree[X] < MARK ) Tree[X]=MARK; }while(0)
281 : :
282 : :
283 : : /*****************************************************************************
284 : : * store changes done to check whether an alternating path exists
285 : : * (see bSetBnsToCheckAltPath, bRestoreBnsAfterCheckAltPath)
286 : : ******************************************************************************/
287 : : typedef struct tagAltPathChanges
288 : : {
289 : : /* caps changed in up to 2 vertices */
290 : : VertexFlow nOldCapsVert[2][MAXVAL + 1];
291 : : Vertex vOldVert[2];
292 : : S_CHAR bSetOldCapsVert[2]; /* number of caps to restore, including st-cap */
293 : : /* save ids of the newly created temporary vertices */
294 : : Vertex vNewVertex[2];
295 : : S_CHAR bSetNew[2]; /* indicators whether to remove vertices */
296 : : } ALT_PATH_CHANGES;
297 : :
298 : :
299 : :
300 : : /*****************************************************************************/
301 : :
302 : :
303 : : /* Local functions */
304 : :
305 : : int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at );
306 : : int bRadChangesAtomType( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex v, Vertex v_1, Vertex v_2 );
307 : : int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms );
308 : : int SetAtomRadAndChemValFromVertexCapFlow( BN_STRUCT *pBNS, inp_ATOM *atom, int v1 );
309 : : int bNeedToTestTheFlow( int bond_type, int nTestFlow, int bTestForNonStereoBond );
310 : : int RestoreEdgeFlow( BNS_EDGE *edge, int delta, int bChangeFlow );
311 : : int SetAtomBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, int delta, int bChangeFlow );
312 : : int RestoreBnStructFlow( BN_STRUCT *pBNS, int bChangeFlow );
313 : : int CompTGroupNumber( const void *tg1, const void *tg2, void *p );
314 : : int CompCGroupNumber( const void *cg1, const void *cg2, void *p );
315 : :
316 : : /* Rings, Blocks, Non-stereo bonds */
317 : : int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
318 : : int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo );
319 : : int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
320 : :
321 : : /* Called from BalancedNetworkSearch */
322 : : int GetVertexDegree( BN_STRUCT* pBNS, Vertex v );
323 : : /* Vertex Get2ndNeighbor1( BN_STRUCT* pBNS, Vertex u, EdgeIndex iedge ); not used */
324 : : Vertex Get2ndEdgeVertex( BN_STRUCT* pBNS, Edge uv );
325 : : Vertex GetVertexNeighbor( BN_STRUCT* pBNS, Vertex v, int neigh, EdgeIndex *iedge );
326 : : int GetEdgePointer( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv, BNS_EDGE **uv, S_CHAR *s_or_t );
327 : : int AugmentEdge( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv, int delta, S_CHAR bReverse, int bChangeFlow );
328 : : int rescap_mark( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv );
329 : : int rescap( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv );
330 : : Vertex FindBase( Vertex u, Vertex *BasePtr );
331 : : int FindPathToVertex_s( Vertex x, Edge *SwitchEdge, Vertex *BasePtr, Vertex *Path, int MaxPathLen );
332 : : Vertex MakeBlossom( BN_STRUCT* pBNS, Vertex *ScanQ, int *pQSize,
333 : : Vertex *Pu, Vertex *Pv, int max_len_Pu_Pv,
334 : : Edge *SwitchEdge, Vertex *BasePtr,
335 : : Vertex u, Vertex v, EdgeIndex iuv, Vertex b_u, Vertex b_v, S_CHAR *Tree );
336 : : int PullFlow( BN_STRUCT *pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta, S_CHAR bReverse, int bChangeFlow );
337 : : int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta );
338 : :
339 : : /*
340 : : int SetBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, int delta, int bChangeFlow );
341 : : int SetBondsRestoreBnStructFlow( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bChangeFlow );
342 : : */
343 : : int SetBondsFromBnStructFlow( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bChangeFlow0 );
344 : : int MarkAtomsAtTautGroups( BN_STRUCT *pBNS, int num_atoms, BN_AATG *pAATG, int nEnd1, int nEnd2 );
345 : :
346 : : int nMinFlow2Check( BN_STRUCT *pBNS, int iedge );
347 : : int nMaxFlow2Check( BN_STRUCT *pBNS, int iedge );
348 : : int nCurFlow2Check( BN_STRUCT *pBNS, int iedge );
349 : :
350 : : /* Bonds testing */
351 : : /*
352 : : int bRestoreFlowToCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd, int nTestFlow, inp_ATOM *at, int num_atoms, int bChangeFlow );
353 : : */
354 : : int bSetFlowToCheckOneBond( BN_STRUCT *pBNS, int iedge, int flow, BNS_FLOW_CHANGES *fcd );
355 : : int bRestoreFlowAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd );
356 : : int bSetBondsAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd, int nTestFlow, inp_ATOM *at, int num_atoms, int bChangeFlow );
357 : : int BnsTestAndMarkAltBonds( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms, BNS_FLOW_CHANGES *fcd, int bChangeFlow, int nBondTypeToTest );
358 : : /*
359 : : int bIsAltBond(int bond_type); -- djb-rwth: function definition not found
360 : : */
361 : :
362 : : /* Fix bonds */
363 : : int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int edge_forbidden_mask );
364 : : int TempFix_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
365 : : int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
366 : : int fix_explicitly_indicated_bonds( int nebend, int *ebend, BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
367 : :
368 : : /* Alt path testing */
369 : : int bSetBnsToCheckAltPath( BN_STRUCT *pBNS, int nVertDoubleBond, int nVertSingleBond, AT_NUMB type,
370 : : int path_type, ALT_PATH_CHANGES *apc, BNS_FLOW_CHANGES *fcd, int *nDots );
371 : : int bRestoreBnsAfterCheckAltPath( BN_STRUCT *pBNS, ALT_PATH_CHANGES *apc, int bChangeFlow );
372 : : Vertex GetGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type );
373 : : BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type );
374 : : int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, int nMaxAdjEdges, int *nDots );
375 : : int AddNewEdge( BNS_VERTEX *p1, BNS_VERTEX *p2, BN_STRUCT *pBNS, int nEdgeCap, int nEdgeFlow );
376 : : int bAddStCapToAVertex( BN_STRUCT *pBNS, Vertex v1, Vertex v2, VertexFlow *nOldCapVertSingleBond, int *nDots, int bAdjacentDonors );
377 : :
378 : : static void remove_alt_bond_marks( inp_ATOM *at, int num_atoms );
379 : : int bIsBnsEndpoint( BN_STRUCT *pBNS, int v );
380 : :
381 : : /* Protons removal, charge neutralization */
382 : : /* int is_acidic_CO(inp_ATOM* atom, int at_no); */ /* djb-rwth: function definition not found*/
383 : : int mark_at_type( inp_ATOM *atom, int num_atoms, int nAtTypeTotals[] );
384 : : int GetAtomChargeType( inp_ATOM *atom, int at_no, int nAtTypeTotals[], int *pMask, int bSubtract );
385 : : int AddChangedAtHChargeBNS( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], S_CHAR *mark );
386 : : int EliminatePlusMinusChargeAmbiguity( BN_STRUCT *pBNS, int num_atoms );
387 : : int AddOrRemoveExplOrImplH( int nDelta, inp_ATOM *at, int num_atoms, AT_NUMB at_no, T_GROUP_INFO *t_group_info );
388 : : int SubtractOrChangeAtHChargeBNS( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms,
389 : : int nAtTypeTotals[], S_CHAR *mark, T_GROUP_INFO *t_group_info, int bSubtract );
390 : : int is_Z_atom( U_CHAR el_number );
391 : : int IsZOX( inp_ATOM *atom, int at_x, int ord );
392 : : int SimpleRemoveHplusNPO( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], T_GROUP_INFO *t_group_info );
393 : : int CreateCGroupInBnStruct( inp_ATOM *at, int num_atoms,
394 : : BN_STRUCT *pBNS, int nType, int nMask, int nCharge );
395 : : int CreateTGroupInBnStruct( inp_ATOM *at, int num_atoms,
396 : : BN_STRUCT *pBNS, int nType, int nMask );
397 : : int RemoveLastGroupFromBnStruct( inp_ATOM *at, int num_atoms, int tg, BN_STRUCT *pBNS );
398 : : int SetInitCapFlowToCurrent( BN_STRUCT *pBNS );
399 : : int SimpleRemoveAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2remove );
400 : : int SimpleAddAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2add );
401 : : int HardRemoveAcidicProtons( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2remove,
402 : : int *nNumCanceledCharges, BN_STRUCT *pBNS, BN_DATA *pBD );
403 : : int HardAddAcidicProtons( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2add,
404 : : int *nNumCanceledCharges, BN_STRUCT *pBNS, BN_DATA *pBD );
405 : : int HardRemoveHplusNP( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, int bCancelChargesAlways, int *nNumCanceledCharges,
406 : : BN_AATG *pAATG, BN_STRUCT *pBNS, BN_DATA *pBD );
407 : : int RemoveNPProtonsAndAcidCharges( struct tagCANON_GLOBALS *pCG, inp_ATOM *at, int num_atoms, BN_AATG *pAATG, BN_STRUCT *pBNS, BN_DATA *pBD );
408 : : Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv );
409 : : int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v );
410 : : int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
411 : : int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v );
412 : : int bIsAggressiveDeprotonation( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
413 : :
414 : : int bIsAtomTypeHard( inp_ATOM *at, int endpoint, int nType, int nMask, int nCharge );
415 : : int bIsHDonorAccAtomType( inp_ATOM *at, int endpoint, int *cSubType );
416 : : int bIsNegAtomType( inp_ATOM *at, int i, int *cSubType );
417 : :
418 : : #if ( BNS_RAD_SEARCH == 1 )
419 : : int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u );
420 : : int cmp_rad_endpoints( const void *a1, const void *a2 );
421 : : int cmp_endpoints_rad( const void *a1, const void *a2 );
422 : : #endif
423 : :
424 : : int bHasChargedNeighbor( inp_ATOM *at, int iat );
425 : : /*****************************************************************************/
426 : : /**** prim(v) is v' *****/
427 : : #define prim(v) (Vertex)((v)^1)
428 : :
429 : : /*****************************************************************************/
430 : : #define SwitchEdge_Vert1(u) SwitchEdge[u][0]
431 : : #define SwitchEdge_Vert2(u) Get2ndEdgeVertex( pBNS, SwitchEdge[u] )
432 : : #define SwitchEdge_IEdge(u) SwitchEdge[u][1]
433 : : /*****************************************************************************/
434 : :
435 : :
436 : :
437 : :
438 : :
439 : : /****************************************************************************
440 : : Returns value > 0 if a bond has been changed
441 : : ****************************************************************************/
442 : 6 : int RestoreEdgeFlow( BNS_EDGE *edge, int delta, int bChangeFlow )
443 : : {
444 : : /*flow1 = edge->flow;*/ /* output from BNS */
445 [ - - + - : 6 : switch (bChangeFlow & BNS_EF_CHNG_RSTR)
- ]
446 : : {
447 : 0 : case 0:
448 : : /* the flow has not been permitted to change inside the BNS */
449 : : /* nothing to do */
450 : : /*flow1 = edge->flow;*/ /* output from BNS, the original flow value */
451 : : /*flow2 = flow1 + delta;*/ /* the flow would be changed to this value by the BNS if permitted */
452 : 0 : break;
453 : 0 : case BNS_EF_CHNG_FLOW:
454 : : /* the flow has been changed by the BNS; update flow0 */
455 : : /*flow2 = edge->flow;*/ /* output from BNS, the changed value */
456 : : /*flow1 = flow2 - delta;*/ /* the original flow value before the BNS */
457 : 0 : edge->flow0 = edge->flow; /* SAVE NEW EDGE FLOW AS THE INITIAL FLOW FROM CHEM. BONDS */
458 : 0 : break;
459 : 6 : case BNS_EF_CHNG_RSTR:
460 : : /* the flow has been changed by the BNS; requested to change it back */
461 : : /*flow2 = edge->flow;*/ /* output from BNS, the changed value */
462 : : /*flow1 = flow2 - delta;*/ /* the original flow value before the BNS */
463 : 6 : edge->flow = edge->flow - delta; /* CHANGE EDGE FLOW BACK (RESTORE) */
464 : 6 : break;
465 : 0 : case BNS_EF_RSTR_FLOW:
466 : : /* the flow has not been permitted to change inside the BNS */
467 : : /* nothing to do */
468 : : /*flow1 = edge->flow;*/ /* output from BNS, the original flow value */
469 : : /*flow2 = flow1 + delta;*/ /* the flow would be changed to this value by the BNS if permitted */
470 : 0 : break;
471 : : }
472 : :
473 : 6 : return 0;
474 : : }
475 : :
476 : :
477 : : /****************************************************************************
478 : : Returns value > 0 if a bond has been changed; do not change flow
479 : : ****************************************************************************/
480 : 12 : int SetAtomBondType( BNS_EDGE *edge,
481 : : U_CHAR *bond_type12,
482 : : U_CHAR *bond_type21,
483 : : int delta,
484 : : int bChangeFlow )
485 : : {
486 : 12 : int flow1, flow2, tmp, ret = 0;
487 : 12 : int bond_mark = 0, bond_type, new_bond_type; /* djb-rwth: addressing LLVM warning */
488 : :
489 [ + - - + ]: 12 : if (!edge->pass || !bond_type21)
490 : : {
491 : 0 : return 0;
492 : : }
493 : :
494 [ + + - ]: 12 : switch (bChangeFlow & BNS_EF_CHNG_RSTR)
495 : : {
496 : 6 : case 0: /* the flow has not been permitted to change inside the BNS: simulated in case of check one bond */
497 : : case BNS_EF_RSTR_FLOW: /* the flow has not been permitted to change inside the BNS: obsolete mode, unexpected bChangeFlow */
498 : 6 : flow1 = edge->flow0; /* output from BNS, the original (old) flow value */
499 : 6 : flow2 = flow1 + delta; /* the flow would be changed to this value by the BNS if permitted */
500 : 6 : break;
501 : 6 : case BNS_EF_CHNG_FLOW: /* the flow has been changed by the BNS */
502 : : case BNS_EF_CHNG_RSTR: /* the flow has been changed by the BNS; requested to change it back */
503 : 6 : flow2 = edge->flow; /* output from BNS, the changed (new) value */
504 : 6 : flow1 = edge->flow0; /* the original flow (old) value before the BNS */
505 : 6 : break;
506 : 0 : default:
507 : 0 : return 0; /* added 2006-03-21 */
508 : : }
509 : :
510 [ - + - - ]: 12 : if (( bChangeFlow & BNS_EF_CHNG_BONDS ) && ( bChangeFlow & BNS_EF_ALTR_NS ) != BNS_EF_ALTR_NS)
511 : : {
512 : : /* Set new bond types according to the new flow values */
513 : 0 : new_bond_type = flow2 + BOND_SINGLE;
514 [ # # ]: 0 : if (*bond_type12 != new_bond_type)
515 : : {
516 : 0 : *bond_type12 = *bond_type21 = new_bond_type;
517 : 0 : ret++;
518 : : }
519 : : }
520 : : else
521 : : {
522 [ - + ]: 12 : if (bChangeFlow & BNS_EF_ALTR_BONDS)
523 : : {
524 [ - + ]: 12 : if (flow1 == flow2)
525 : : {
526 : 0 : goto exit_function;
527 : : }
528 : : /* Update alternating bond information */
529 [ + + ]: 12 : if (flow1 > flow2)
530 : : {
531 : : /* Make sure flow2 > flow1 */
532 : 6 : tmp = flow1;
533 : 6 : flow1 = flow2;
534 : 6 : flow2 = tmp;
535 : : }
536 : : /* djb-rwth: removing redundant code */
537 [ + - - ]: 12 : switch (bond_type = ( *bond_type12 & BOND_TYPE_MASK ))
538 : : {
539 : 12 : case BOND_SINGLE:
540 : : case BOND_DOUBLE:
541 : : case BOND_TRIPLE:
542 : : /* assume that the input bond type fits either flow1 or flow2 */
543 [ + - + - ]: 12 : if (flow1 == 0 && flow2 == 1)
544 : : {
545 [ - + ]: 12 : if (bChangeFlow & BNS_EF_SET_NOSTEREO)
546 : : {
547 : 0 : bond_mark = BOND_MARK_ALT12NS;
548 : 0 : bond_type = BOND_ALT12NS;
549 : : }
550 : : else
551 : : {
552 : 12 : bond_mark = BOND_MARK_ALT12;
553 : 12 : bond_type = BOND_ALTERN;
554 : : }
555 : : }
556 : : else
557 : : {
558 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 2)
559 : : {
560 : 0 : bond_mark = BOND_MARK_ALT13;
561 : 0 : bond_type = BOND_ALT_13;
562 : : }
563 : : else
564 : : {
565 [ # # # # ]: 0 : if (flow1 == 1 && flow2 == 2)
566 : : {
567 : 0 : bond_mark = BOND_MARK_ALT23;
568 : 0 : bond_type = BOND_ALT_23;
569 : : }
570 : : else
571 : : {
572 : 0 : return BNS_BOND_ERR; /* error */
573 : : }
574 : : }
575 : : }
576 : 12 : break;
577 : 0 : case BOND_TAUTOM:
578 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 1)
579 : : {
580 : 0 : bond_mark = BOND_MARK_ALT12NS;
581 : : }
582 : : else
583 [ # # # # ]: 0 : if (flow1 == 1 && flow2 == 2) {
584 : 0 : bond_mark = BOND_MARK_ALT23;
585 : : }
586 : : else {
587 : 0 : return BNS_BOND_ERR; /* error */
588 : : }
589 : 0 : break;
590 : 0 : default:
591 : 0 : new_bond_type = bond_type;
592 : 0 : bond_mark = ( *bond_type12 & BOND_MARK_MASK );
593 [ # # # # : 0 : switch (bond_mark)
# # # ]
594 : : {
595 : 0 : case BOND_MARK_ALT12:
596 [ # # # # : 0 : if (( bChangeFlow & BNS_EF_SET_NOSTEREO ) && flow1 == 0 && flow2 == 1)
# # ]
597 : : {
598 : 0 : bond_mark = BOND_MARK_ALT12NS;
599 : 0 : new_bond_type = BOND_ALT12NS;
600 : 0 : break;
601 : : }
602 : : case BOND_MARK_ALT12NS:
603 [ # # # # ]: 0 : if (flow1 == 2 || flow2 == 2)
604 : : {
605 : 0 : bond_mark = BOND_MARK_ALT123;
606 : 0 : new_bond_type = BOND_ALT_123;
607 : : }
608 : 0 : break;
609 : 0 : case BOND_MARK_ALT13:
610 [ # # # # ]: 0 : if (flow1 == 1 || flow2 == 1)
611 : : {
612 : 0 : bond_mark = BOND_MARK_ALT123;
613 : 0 : new_bond_type = BOND_ALT_123;
614 : : }
615 : 0 : break;
616 : 0 : case BOND_MARK_ALT23:
617 [ # # # # ]: 0 : if (flow1 == 0 || flow2 == 0)
618 : : {
619 : 0 : bond_mark = BOND_MARK_ALT123;
620 : 0 : new_bond_type = BOND_ALT_123;
621 : : }
622 : 0 : break;
623 : 0 : case BOND_MARK_ALT123:
624 : 0 : break;
625 : :
626 : 0 : case 0: /* special case: second alt bond testing */
627 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 1)
628 : : {
629 : 0 : bond_mark = BOND_MARK_ALT12;
630 : : }
631 : : else
632 : : {
633 [ # # # # ]: 0 : if (flow1 == 0 && flow2 == 2)
634 : : {
635 : 0 : bond_mark = BOND_MARK_ALT13;
636 : : }
637 : : else
638 : : {
639 [ # # # # ]: 0 : if (flow1 == 1 && flow2 == 2)
640 : : {
641 : 0 : bond_mark = BOND_MARK_ALT23;
642 : : }
643 : : else
644 : : {
645 : 0 : return BNS_BOND_ERR; /* error */
646 : : }
647 : : }
648 : : }
649 : 0 : break;
650 : :
651 : 0 : default:
652 : 0 : return BNS_BOND_ERR; /* error */
653 : : }
654 : :
655 [ # # # ]: 0 : switch (bond_type)
656 : : {
657 : 0 : case BOND_TAUTOM:
658 : 0 : break;
659 : 0 : case BOND_ALTERN:
660 : : case BOND_ALT12NS:
661 : : case BOND_ALT_123:
662 : : case BOND_ALT_13:
663 : : case BOND_ALT_23:
664 : 0 : bond_type = new_bond_type;
665 : 0 : break;
666 : 0 : default:
667 : 0 : return BNS_BOND_ERR; /* error */
668 : : }
669 : : }
670 : :
671 : 12 : new_bond_type = bond_type | bond_mark;
672 [ - + ]: 12 : if (new_bond_type != *bond_type12)
673 : : {
674 : 12 : *bond_type12 = *bond_type21 = new_bond_type;
675 : 12 : ret++;
676 : : }
677 : : }
678 : : }
679 : :
680 : 0 : exit_function:
681 : :
682 : 12 : return ret;
683 : : }
684 : :
685 : :
686 : : /****************************************************************************
687 : : Run BalancedNetworkSearch( ... ) until no aug pass is found
688 : : ****************************************************************************/
689 : 74 : int RunBalancedNetworkSearch( BN_STRUCT *pBNS, BN_DATA *pBD, int bChangeFlow )
690 : : {
691 : 74 : int pass, delta = 0, nSumDelta;
692 : :
693 : 74 : nSumDelta = 0;
694 [ + - ]: 76 : for (pass = 0; pass < pBNS->max_altp; pass++)
695 : : {
696 : 76 : pBNS->alt_path = pBNS->altp[pass];
697 : 76 : pBNS->bChangeFlow = 0;
698 : 76 : delta = BalancedNetworkSearch( pBNS, pBD, bChangeFlow );
699 : 76 : ReInitBnData( pBD );
700 [ + + ]: 76 : if (0 < delta)
701 : : {
702 : 2 : pBNS->num_altp++;
703 : 2 : nSumDelta += abs( delta );
704 : : }
705 : : else
706 : : {
707 : 74 : break;
708 : : }
709 : : }
710 : :
711 [ + - - + ]: 74 : if (IS_BNS_ERROR( delta ))
712 : : {
713 : 0 : return delta;
714 : : }
715 : :
716 [ - + ]: 74 : if (bInchiTimeIsOver( pBNS->ic, pBNS->ulTimeOutTime ))
717 : : {
718 : 0 : return BNS_TIMEOUT;
719 : : }
720 : :
721 : 74 : return nSumDelta; /* number of eliminated pairs of "dots" */
722 : : }
723 : :
724 : :
725 : : /****************************************************************************/
726 : 0 : int SetAtomRadAndChemValFromVertexCapFlow( BN_STRUCT *pBNS,
727 : : inp_ATOM *atom,
728 : : int v1 )
729 : : {
730 : 0 : BNS_VERTEX *vert = pBNS->vert + v1;
731 : 0 : inp_ATOM *at = atom + v1;
732 : : S_CHAR cValue;
733 : 0 : int nChanges = 0;
734 : :
735 : : /* Set only on the 1st pass */
736 [ # # ]: 0 : if (!vert->st_edge.pass)
737 : : {
738 : 0 : return 0;
739 : : }
740 : :
741 : : /* Adjust chem_bonds_valence */
742 : 0 : cValue = at->chem_bonds_valence - at->valence;
743 [ # # # # ]: 0 : if (cValue >= 0 && cValue != vert->st_edge.flow)
744 : : {
745 : 0 : at->chem_bonds_valence = at->valence + vert->st_edge.flow;
746 : 0 : nChanges++;
747 : : }
748 : :
749 : : /* Adjist radical */
750 [ # # # # ]: 0 : switch (vert->st_edge.cap - vert->st_edge.flow)
751 : : {
752 : 0 : case 0:
753 : 0 : cValue = 0;
754 : 0 : break;
755 : 0 : case 1:
756 : 0 : cValue = RADICAL_DOUBLET;
757 : 0 : break;
758 : 0 : case 2:
759 : 0 : cValue = RADICAL_TRIPLET;
760 : 0 : break;
761 : 0 : default:
762 : 0 : return BNS_BOND_ERR;
763 : : }
764 [ # # ]: 0 : if (cValue != at->radical)
765 : : {
766 : 0 : at->radical = cValue;
767 : 0 : nChanges++;
768 : : }
769 : :
770 : 0 : return nChanges;
771 : : }
772 : :
773 : :
774 : : /****************************************************************************/
775 : 0 : int AddChangedAtHChargeBNS( inp_ATOM *at,
776 : : int num_atoms,
777 : : int nAtTypeTotals[],
778 : : S_CHAR *mark )
779 : : {
780 : : int i, mask, num;
781 [ # # ]: 0 : for (i = 0, num = 0; i < num_atoms; i++)
782 : : {
783 [ # # ]: 0 : if (mark[i])
784 : : {
785 : 0 : mark[i] = 0;
786 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
787 : : /* add ignoring adjacent charges */
788 : 0 : at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, -2 );
789 : : #else
790 : : at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 );
791 : : #endif
792 : 0 : num++;
793 : : }
794 : : }
795 : :
796 : 0 : return num;
797 : : }
798 : :
799 : :
800 : : /****************************************************************************
801 : : Eliminate neutral representation ambiguity:
802 : :
803 : : replace (+)--N==(-) with (+)==N--(-)
804 : :
805 : : here (+) is positive charge group,
806 : : (-) is negative charge group, N is N or P
807 : : This reduces possibility of creating ion pair -OH => -O(+) + H(+)
808 : : instead of removing H(+) from N or P
809 : :
810 : : !Call this function after alt path was found and new flows have been set.
811 : : ****************************************************************************/
812 : 0 : int EliminatePlusMinusChargeAmbiguity( BN_STRUCT *pBNS, int num_atoms )
813 : : {
814 : : int pass, i, v0, v1, v2, ineigh1, /*ineigh0,*/ /*ineigh2,*/
815 : 0 : vLast, n, delta, ret, err = 0;
816 : : int nFound, k;
817 : : BNS_EDGE *edge;
818 : :
819 [ # # ]: 0 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
820 : : {
821 : :
822 : 0 : pBNS->alt_path = pBNS->altp[pass];
823 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
824 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
825 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
826 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
827 : 0 : v0 = v2 = NO_VERTEX; /* negative number */
828 : :
829 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2 /*, ineigh0 = ineigh1*/)
830 : : {
831 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
832 : : /*ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i);*/ /* v2->v1 neighbor */
833 : 0 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
834 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
835 : : t-groups, c-groups or other fictitious edges/vertices
836 : : */
837 : 0 : v2 = edge->neighbor12 ^ v1;
838 [ # # # # ]: 0 : if (v1 < num_atoms &&
839 [ # # # # ]: 0 : ( (v0 >= num_atoms && ( pBNS->vert[v0].type & BNS_VERT_TYPE_C_GROUP )) ||
840 [ # # ]: 0 : (v2 >= num_atoms && ( pBNS->vert[v2].type & BNS_VERT_TYPE_C_GROUP ) ))) /* djb-rwth: addressing LLVM warning */
841 : : {
842 : 0 : int cgPos = 0, cgNeg = 0;
843 : 0 : int neighPos = -1, neighNeg = -1;
844 : : BNS_EDGE *edgePos, *edgeNeg;
845 : 0 : nFound = 0;
846 [ # # # # : 0 : for (k = pBNS->vert[v1].num_adj_edges - 1; k >= 0 && ( neighPos < 0 || neighNeg < 0 ); k--)
# # ]
847 : : {
848 : 0 : BNS_EDGE *next_edge = pBNS->edge + pBNS->vert[v1].iedge[k];
849 : 0 : int v = next_edge->neighbor12 ^ v1;
850 [ # # ]: 0 : if (pBNS->vert[v].type & BNS_VERT_TYPE_C_GROUP)
851 : : {
852 [ # # ]: 0 : if (pBNS->vert[v].type & BNS_VERT_TYPE_C_NEGATIVE)
853 : : {
854 : 0 : cgNeg = v;
855 : 0 : neighNeg = k;
856 : 0 : nFound++;
857 : : }
858 : : else
859 : : {
860 : 0 : cgPos = v;
861 : 0 : neighPos = k;
862 : 0 : nFound++;
863 : : }
864 : : }
865 : : }
866 [ # # # # : 0 : if (2 == nFound && neighPos >= 0 && neighNeg >= 0)
# # ]
867 : : {
868 : : /* both c-groups have been found */
869 : 0 : edgePos = pBNS->edge + pBNS->vert[v1].iedge[neighPos];
870 : 0 : edgeNeg = pBNS->edge + pBNS->vert[v1].iedge[neighNeg];
871 [ # # ]: 0 : if (edgePos->flow < edgeNeg->flow)
872 : : {
873 : : /* ambiguity found; replace (+cg)--N==(-cg) with (+cg)==N--(-cg) */
874 : 0 : int dflow = edgeNeg->flow - edgePos->flow;
875 : :
876 : 0 : edgePos->flow += dflow;
877 : 0 : pBNS->vert[cgPos].st_edge.cap += dflow;
878 : 0 : pBNS->vert[cgPos].st_edge.flow += dflow;
879 : :
880 : 0 : edgeNeg->flow -= dflow;
881 : 0 : pBNS->vert[cgNeg].st_edge.cap -= dflow;
882 : 0 : pBNS->vert[cgNeg].st_edge.flow -= dflow;
883 : 0 : ret++;
884 : : }
885 : : }
886 : : }
887 : : }
888 : :
889 [ # # ]: 0 : if (v2 != vLast)
890 : : {
891 : 0 : err = BNS_PROGRAM_ERR;
892 : : }
893 : : }
894 : :
895 [ # # ]: 0 : return err ? err : ret;
896 : : }
897 : :
898 : :
899 : : /****************************************************************************
900 : : Add or remove ixplicit or implicit hydrogens
901 : : ****************************************************************************/
902 : 3 : int AddOrRemoveExplOrImplH( int nDelta,
903 : : inp_ATOM *at,
904 : : int num_atoms,
905 : : AT_NUMB at_no,
906 : : T_GROUP_INFO *t_group_info )
907 : : {
908 : : int i, iso, tot_num_iso_H,
909 : : num_H, /* number of H before the removal, including explicit H */
910 : : nNum2Remove, /* number of H to remove */
911 : : nNumRemovedExplicitH; /* djb-rwth: removing redundant variables */
912 : : S_CHAR num_iso_H[NUM_H_ISOTOPES];
913 : : inp_ATOM *at_H;
914 : :
915 [ - + ]: 3 : if (!nDelta)
916 : : {
917 : 0 : return 0;
918 : : }
919 : : /* add */
920 [ + - ]: 3 : if (nDelta > 0)
921 : : {
922 : 3 : at[at_no].num_H += nDelta;
923 : 3 : t_group_info->tni.nNumRemovedProtons--;
924 : 3 : return nDelta;
925 : : }
926 : : /* remove */
927 : 0 : nNum2Remove = -nDelta;
928 : 0 : nNumRemovedExplicitH = t_group_info->tni.nNumRemovedExplicitH; /* number of explicit H saved separately in
929 : : at[num_atoms+i], i=0..nNumRemovedExplicitH-1 */
930 : 0 : tot_num_iso_H = NUM_ISO_H( at, at_no );
931 : 0 : num_H = at[at_no].num_H;
932 : : /*
933 : : tot_num_iso_H = NUM_ISO_H(at,at_no);
934 : : num_H = at[at_no].num_H;
935 : : nNumAtomExplicitH = 0;
936 : : nNumRemovedExplicitH = t_group_info->tni.nNumRemovedExplicitH;
937 : : tot_num_explicit_iso_H = 0;
938 : : */
939 : :
940 : 0 : at_H = at + num_atoms;
941 : 0 : memcpy(num_iso_H, at[at_no].num_iso_H, sizeof(num_iso_H));
942 : : /* Remove all explicit H, otherwise a false stereo can occur.
943 : : Example: remove H(+) from the following substructure:
944 : :
945 : : H H
946 : : A / A /
947 : : >X==N(+) produces false stereogenic bond: >X==N
948 : : B \ B
949 : : H
950 : :
951 : : To avoid this effect all explicit H atoms must be removed
952 : : */
953 : :
954 : : /* djb-rwth: removing redundant code */
955 [ # # ]: 0 : for (i = 0; i < nNumRemovedExplicitH; )
956 : : {
957 [ # # ]: 0 : if (at_H[i].neighbor[0] == at_no)
958 : : {
959 : 0 : int m, k, orig_no = at_H[i].orig_at_number;
960 : 0 : nNumRemovedExplicitH--;
961 : : /* djb-rwth: removing redundant code */
962 [ # # ]: 0 : if (nNumRemovedExplicitH > i)
963 : : {
964 : 0 : inp_ATOM at_i = at_H[i];
965 : 0 : memmove(at_H + i, at_H + i + 1, sizeof(at_H[0]) * ((long long)nNumRemovedExplicitH - i)); /* djb-rwth: cast operator added */
966 : 0 : at_H[nNumRemovedExplicitH] = at_i; /* save removed H (for debugging purposes?) */
967 : : }
968 : : /* Adjust 0D parities */
969 [ # # ]: 0 : if (at[at_no].sb_parity[0])
970 : : {
971 [ # # # # ]: 0 : for (m = 0; m < MAX_NUM_STEREO_BONDS && at[at_no].sb_parity[m]; m++)
972 : : {
973 [ # # ]: 0 : if (at[at_no].sn_orig_at_num[m] == orig_no)
974 : : {
975 [ # # ]: 0 : if (at[at_no].valence >= MIN_NUM_STEREO_BOND_NEIGH)
976 : : {
977 : 0 : at[at_no].sn_ord[m] = k = ( at[at_no].sb_ord[m] == 0 );
978 : 0 : at[at_no].sn_orig_at_num[m] = at[(int) at[at_no].neighbor[k]].orig_at_number;
979 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[at_no].sb_parity[m] ))
980 : : {
981 : 0 : at[at_no].sb_parity[m] = 3 - at[at_no].sb_parity[m];
982 : : }
983 : : }
984 : : else
985 : : {
986 : 0 : at[at_no].sn_ord[m] = -99; /* no sb neighbor exists anymore */
987 : 0 : at[at_no].sn_orig_at_num[m] = 0;
988 [ # # # # ]: 0 : if (ATOM_PARITY_WELL_DEF( at[at_no].sb_parity[m] ))
989 : : {
990 : : int pnxt_atom, pinxt2cur, pinxt_sb_parity_ord;
991 [ # # ]: 0 : if (0 < get_opposite_sb_atom( at, at_no, at[at_no].sb_ord[m],
992 : : &pnxt_atom, &pinxt2cur, &pinxt_sb_parity_ord ))
993 : : {
994 : 0 : at[at_no].sb_parity[m] =
995 : 0 : at[pnxt_atom].sb_parity[pinxt_sb_parity_ord] = AB_PARITY_UNDF;
996 : : }
997 : : }
998 : : }
999 : : }
1000 : : }
1001 : : }
1002 : : /* do not increment i here: we have shifted next at_H[] element
1003 : : to the ith position and decremented nNumRemovedExplicitH */
1004 : : }
1005 : : else
1006 : : {
1007 : 0 : i++;
1008 : : }
1009 : : }
1010 : :
1011 [ # # # # ]: 0 : for (iso = -1; iso < NUM_H_ISOTOPES && 0 < nNum2Remove; iso++)
1012 : : {
1013 : : /* Each pass removes up to one H */
1014 [ # # ]: 0 : if (iso < 0)
1015 : : {
1016 : : /* Try to remove non-isotopic */
1017 [ # # # # ]: 0 : while (tot_num_iso_H < num_H && 0 < nNum2Remove)
1018 : : {
1019 : : /* Non-isotopic H exists */
1020 : 0 : num_H--;
1021 : 0 : t_group_info->tni.nNumRemovedProtons++;
1022 : 0 : nNum2Remove--;
1023 : : }
1024 : : }
1025 : : else
1026 : : {
1027 : : /* Remove isotopic */
1028 [ # # # # : 0 : while (num_iso_H[iso] && num_H && 0 < nNum2Remove)
# # ]
1029 : : {
1030 : : /* Isotopic H exists */
1031 : 0 : num_H--;
1032 : 0 : num_iso_H[iso] --;
1033 : 0 : t_group_info->tni.nNumRemovedProtonsIsotopic[iso] ++;
1034 : 0 : t_group_info->tni.nNumRemovedProtons++;
1035 : 0 : nNum2Remove--;
1036 : : }
1037 : : }
1038 : : }
1039 : : #if ( bRELEASE_VERSION != 1 )
1040 : : if (nNum2Remove)
1041 : : {
1042 : : int stop = 1; /* <BRKPT> Program error */
1043 : : }
1044 : : #endif
1045 [ # # ]: 0 : if (nDelta + nNum2Remove < 0)
1046 : : {
1047 : 0 : at[at_no].num_H = num_H;
1048 : 0 : memcpy(at[at_no].num_iso_H, num_iso_H, sizeof(at[0].num_iso_H));
1049 : 0 : t_group_info->tni.nNumRemovedExplicitH = nNumRemovedExplicitH;
1050 : : }
1051 : :
1052 : 0 : return nDelta + nNum2Remove;
1053 : : }
1054 : :
1055 : :
1056 : : /****************************************************************************/
1057 : 0 : int SubtractOrChangeAtHChargeBNS( BN_STRUCT *pBNS,
1058 : : inp_ATOM *at,
1059 : : int num_atoms,
1060 : : int nAtTypeTotals[],
1061 : : S_CHAR *mark,
1062 : : T_GROUP_INFO *t_group_info,
1063 : : int bSubtract )
1064 : : {
1065 : 0 : int pass, i, v0, v1, v2, ineigh1, /*ineigh2,*/ vLast, n, delta, ret, err = 0;
1066 : : BNS_EDGE *edge;
1067 : : int nDeltaH, nDeltaCharge;
1068 : : int mask, type; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1069 : :
1070 [ # # ]: 0 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
1071 : : {
1072 : :
1073 : 0 : pBNS->alt_path = pBNS->altp[pass];
1074 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1075 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
1076 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
1077 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1078 : 0 : v0 = v2 = NO_VERTEX;
1079 : :
1080 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2)
1081 : : {
1082 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1083 : : /*ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i);*/ /* v2->v1 neighbor */
1084 : 0 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1085 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
1086 : : t-groups, c-groups or other fictitious edges/vertices
1087 : : */
1088 : 0 : v2 = edge->neighbor12 ^ v1;
1089 [ # # # # : 0 : if (v1 < num_atoms && ( v0 >= num_atoms || v2 >= num_atoms ))
# # ]
1090 : : {
1091 : 0 : nDeltaH = nDeltaCharge = 0;
1092 [ # # ]: 0 : if (v0 >= num_atoms)
1093 : : {
1094 : : /* delta(v0-v1) = -delta(v1-v2) along the alternating path */
1095 [ # # ]: 0 : if (pBNS->vert[v0].type & BNS_VERT_TYPE_TGROUP)
1096 : : {
1097 : 0 : nDeltaH -= delta;
1098 : : }
1099 : : else
1100 : : {
1101 [ # # ]: 0 : if (pBNS->vert[v0].type & BNS_VERT_TYPE_C_GROUP)
1102 : : {
1103 : 0 : nDeltaCharge += delta;
1104 : : }
1105 : : }
1106 : : }
1107 [ # # ]: 0 : if (v2 >= num_atoms)
1108 : : {
1109 [ # # ]: 0 : if (pBNS->vert[v2].type & BNS_VERT_TYPE_TGROUP)
1110 : : {
1111 : 0 : nDeltaH += delta;
1112 : : }
1113 : : else
1114 : : {
1115 [ # # ]: 0 : if (pBNS->vert[v2].type & BNS_VERT_TYPE_C_GROUP)
1116 : : {
1117 : 0 : nDeltaCharge -= delta;
1118 : : }
1119 : : }
1120 : : }
1121 [ # # # # ]: 0 : if (nDeltaH || nDeltaCharge)
1122 : : {
1123 [ # # ]: 0 : if (bSubtract)
1124 : : {
1125 [ # # ]: 0 : if (!mark[v1])
1126 : : {
1127 : : /* first time the atom has been encountered: subtract */
1128 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
1129 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
1130 : 0 : type = GetAtomChargeType(at, v1, nAtTypeTotals, &mask, 2);
1131 : : #else
1132 : : type = GetAtomChargeType(at, v1, nAtTypeTotals, &mask, 1);
1133 : : #endif
1134 : 0 : ret++; /* number of changed atoms */
1135 : 0 : mark[v1] ++;
1136 : : }
1137 : : }
1138 : : else
1139 : : {
1140 : : /* Change */
1141 : 0 : at[v1].charge += nDeltaCharge;
1142 [ # # ]: 0 : if (nDeltaH)
1143 : : {
1144 : 0 : AddOrRemoveExplOrImplH( nDeltaH, at, num_atoms, (AT_NUMB) v1, t_group_info );
1145 : : }
1146 : 0 : ret++; /* number of changed atoms */
1147 : : }
1148 : : }
1149 : : }
1150 : : }
1151 : :
1152 [ # # ]: 0 : if (v2 != vLast)
1153 : : {
1154 : 0 : err = BNS_PROGRAM_ERR;
1155 : : }
1156 : : }
1157 : :
1158 [ # # ]: 0 : return err ? err : ret;
1159 : : }
1160 : :
1161 : :
1162 : : /****************************************************************************
1163 : : Set Bonds From BnS Struct Flow
1164 : : ****************************************************************************/
1165 : 2 : int SetBondsFromBnStructFlow( BN_STRUCT *pBNS,
1166 : : inp_ATOM *at,
1167 : : int num_atoms,
1168 : : int bChangeFlow0 )
1169 : : {
1170 : 2 : int pass, i, v0, v1, v2, ineigh1, ineigh2, vLast, n, delta, ret, ret_val, err = 0;
1171 : : BNS_EDGE *edge;
1172 : : int bChangeFlowAdd; /* djb-rwth: removing redundant variables */
1173 : 2 : int bChangeFlow = ( bChangeFlow0 & ~BNS_EF_SET_NOSTEREO );
1174 : : /*
1175 : : bCheckMovingRad = (bChangeFlow & BNS_EF_ALTR_NS) == BNS_EF_ALTR_NS &&
1176 : : pBNS->tot_st_cap > pBNS->tot_st_flow;
1177 : : */
1178 [ + + ]: 4 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
1179 : : {
1180 : 2 : pBNS->alt_path = pBNS->altp[pass];
1181 : 2 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1182 : 2 : n = ALTP_PATH_LEN( pBNS->alt_path );
1183 : 2 : delta = ALTP_DELTA( pBNS->alt_path );
1184 : 2 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1185 [ - + ]: 2 : if (( bChangeFlow0 & BNS_EF_SET_NOSTEREO ) &&
1186 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.cap0 > pBNS->vert[v1].st_edge.flow0 ||
1187 [ # # ]: 0 : pBNS->vert[vLast].st_edge.cap0 > pBNS->vert[vLast].st_edge.flow0 ))
1188 : : {
1189 : : /* djb-rwth: removing redundant code */
1190 : 0 : bChangeFlowAdd = BNS_EF_SET_NOSTEREO;
1191 : 0 : ret |= 2;
1192 : : }
1193 : : else
1194 : : {
1195 : 2 : bChangeFlowAdd = 0;
1196 : : }
1197 : : /* start vertex */
1198 [ - + ]: 2 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1199 : : {
1200 : : /* Restore s-v1 edge flow to the BNS this pass input value */
1201 : : ; /*pBNS->vert[v1].st_edge.flow -= delta;*/
1202 : : }
1203 : : else
1204 : : {
1205 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1206 : : {
1207 [ # # ]: 0 : if (v1 < num_atoms)
1208 : : {
1209 : : /* Will produce wrong result if called for v1 next time? */
1210 : 0 : ret_val = SetAtomRadAndChemValFromVertexCapFlow( pBNS, at, v1 );
1211 [ # # ]: 0 : if (ret_val < 0)
1212 : : {
1213 : 0 : err = BNS_PROGRAM_ERR;
1214 : : }
1215 : : else
1216 : : {
1217 : 0 : ret |= ( ret_val > 0 );
1218 : : }
1219 : : }
1220 : : /*pBNS->vert[v1].st_edge.flow0 = pBNS->vert[v1].st_edge.flow;*/
1221 : : }
1222 : : }
1223 : :
1224 : 2 : pBNS->vert[v1].st_edge.pass = 0;
1225 : :
1226 : 2 : v0 = v2 = NO_VERTEX;
1227 [ + + ]: 8 : for (i = 0; i < n; i++, delta = -delta, v0 = v1, v1 = v2)
1228 : : {
1229 : 6 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1230 : 6 : ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v2->v1 neighbor */
1231 : 6 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1232 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
1233 : : t-groups, c-groups or other fictitious edges/vertices
1234 : : */
1235 : :
1236 : 6 : v2 = edge->neighbor12 ^ v1;
1237 : :
1238 : : /* change at->chem_bonds_valence 2004-03-08 */
1239 [ - + - - ]: 6 : if (( bChangeFlow & BNS_EF_CHNG_BONDS ) && v1 < num_atoms)
1240 : : {
1241 [ # # # # ]: 0 : if (v0 >= num_atoms && v2 < num_atoms)
1242 : : {
1243 : 0 : at[v1].chem_bonds_valence += delta; /* change in v1-v2 bond order */
1244 : : }
1245 : : else
1246 : : {
1247 [ # # # # : 0 : if (v0 < num_atoms && v2 >= num_atoms && v0 != NO_VERTEX)
# # ]
1248 : : {
1249 : 0 : at[v1].chem_bonds_valence -= delta; /* change in v0-v1 bond order */
1250 : : }
1251 : : }
1252 : : }
1253 : :
1254 [ - + ]: 6 : if (!edge->pass)
1255 : : {
1256 : 0 : continue;
1257 : : }
1258 : :
1259 [ + - + - : 6 : if (v1 < num_atoms && ineigh1 < at[v1].valence &&
+ - ]
1260 [ + - ]: 6 : v2 < num_atoms && ineigh2 < at[v2].valence)
1261 : : {
1262 [ - + ]: 6 : if (( bChangeFlow0 & BNS_EF_ALTR_NS ) == BNS_EF_ALTR_NS &&
1263 [ # # ]: 0 : ( bChangeFlow0 & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1264 : : {
1265 : : /* 2004-07-02 special mode: save new ring bonds and mark as non-stereo non-ring bonds */
1266 [ # # ]: 0 : if (at[v1].nRingSystem != at[v2].nRingSystem)
1267 : : {
1268 : : /* Non-ring bond (bridge) */
1269 : 0 : bChangeFlowAdd = BNS_EF_ALTR_NS;
1270 : : }
1271 : : else
1272 : : {
1273 : : /* Ring bond */
1274 : 0 : bChangeFlowAdd = 0;
1275 : : }
1276 : : }
1277 : : /* Change bonds on the first pass only: in this case all flow correspond to the BNS output */
1278 : 6 : ret_val = SetAtomBondType( edge, &at[v1].bond_type[ineigh1], &at[v2].bond_type[ineigh2], delta, bChangeFlow | bChangeFlowAdd );
1279 [ - + ]: 6 : if (ret_val < 0)
1280 : : {
1281 : 0 : err = BNS_PROGRAM_ERR;
1282 : : }
1283 : : else
1284 : : {
1285 : 6 : ret |= ( ret_val > 0 );
1286 : : }
1287 : : }
1288 : 6 : edge->pass = 0;
1289 : : }
1290 : :
1291 [ - + ]: 2 : if (v2 != vLast)
1292 : : {
1293 : 0 : err = BNS_PROGRAM_ERR;
1294 : : }
1295 : : else
1296 : : {
1297 [ - + ]: 2 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1298 : : {
1299 : : /* Restore v2-t edge flow to the BNS this pass input value */
1300 : : /* "+=" instead of "-=" explanation: delta must have same sign as at the last edge */
1301 : : ; /*pBNS->vert[v2].st_edge.flow += delta; */
1302 : : }
1303 : : else
1304 : : {
1305 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1306 : : {
1307 [ # # ]: 0 : if (v2 < num_atoms)
1308 : : {
1309 : 0 : ret_val = SetAtomRadAndChemValFromVertexCapFlow( pBNS, at, v2 );
1310 [ # # ]: 0 : if (ret_val < 0)
1311 : : {
1312 : 0 : err = BNS_PROGRAM_ERR;
1313 : : }
1314 : : else
1315 : : {
1316 : 0 : ret |= ( ret_val > 0 );
1317 : : }
1318 : : }
1319 : : /*pBNS->vert[v2].st_edge.flow0 = pBNS->vert[v2].st_edge.flow;*/
1320 : : }
1321 : : }
1322 : : }
1323 : 2 : pBNS->vert[v2].st_edge.pass = 0;
1324 : : }
1325 : :
1326 [ - + ]: 2 : return err ? err : ret;
1327 : : }
1328 : :
1329 : :
1330 : : /****************************************************************************/
1331 : 0 : int MarkAtomsAtTautGroups( BN_STRUCT *pBNS,
1332 : : int num_atoms,
1333 : : BN_AATG *pAATG,
1334 : : int nEnd1,
1335 : : int nEnd2 )
1336 : : {
1337 : 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 */
1338 : : BNS_EDGE *edge;
1339 : : S_CHAR cDelta[MAX_ALT_AATG_ARRAY_LEN];
1340 : : AT_NUMB nVertex[MAX_ALT_AATG_ARRAY_LEN];
1341 : 0 : int nLenDelta = 0, last_i, nNumFound;
1342 : :
1343 [ # # ]: 0 : for (pass = pBNS->num_altp - 1; 0 <= pass; pass--)
1344 : : {
1345 : 0 : pBNS->alt_path = pBNS->altp[pass];
1346 : 0 : vFirst =
1347 : 0 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1348 : 0 : n = ALTP_PATH_LEN( pBNS->alt_path );
1349 : 0 : delta = ALTP_DELTA( pBNS->alt_path );
1350 : 0 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1351 : 0 : v2 = NO_VERTEX;
1352 : 0 : pAATG->nNumFound = 0; /* initialize */
1353 : :
1354 [ # # # # ]: 0 : if (nEnd1 != vFirst && nEnd1 != vLast)
1355 : : {
1356 : 0 : nEnd1 = -1; /* really not the end */
1357 : : }
1358 [ # # # # ]: 0 : if (nEnd2 != vFirst && nEnd2 != vLast)
1359 : : {
1360 : 0 : nEnd2 = -1; /* really not the end */
1361 : : }
1362 : :
1363 [ # # ]: 0 : for (i = 0; i < n; i++, delta = -delta, v1 = v2)
1364 : : {
1365 : 0 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1366 : 0 : ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i); /* v2->v1 neighbor */ /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1367 : 0 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1368 : : /* follow the BN Structure, not the inp_ATOM, to take care of swithching to
1369 : : t-groups, c-groups or other fictitious edges/vertices
1370 : : */
1371 : 0 : v2 = edge->neighbor12 ^ v1;
1372 : : /*
1373 : : if ( v1 < num_atoms && v2 < num_atoms ) {
1374 : : continue;
1375 : : }
1376 : : */
1377 : : /* BNS increased edge flow by delta */
1378 [ # # ]: 0 : if (v1 >= num_atoms &&
1379 [ # # # # : 0 : ( ( pBNS->vert[v1].type & BNS_VERT_TYPE_TGROUP ) || ( pBNS->vert[v1].type & BNS_VERT_TYPE_TEMP ) ) &&
# # ]
1380 [ # # # # ]: 0 : 0 <= v2 && v2 < num_atoms && ( pBNS->vert[v2].type & BNS_VERT_TYPE_ATOM ))
1381 : : {
1382 : : /*
1383 : : if ( !(pAATG->nMarkedAtom[v2] & AATG_MARK_IN_PATH) ) {
1384 : : pAATG->nMarkedAtom[v2] |= AATG_MARK_IN_PATH;
1385 : : pAATG->nNumFound ++;
1386 : : }
1387 : : */
1388 : :
1389 : : /* BNS increased bond order in v1(t-group)-v2(atom) by delta: added delta attachments */
1390 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1391 : : {
1392 : 0 : cDelta[nLenDelta] = delta;
1393 : 0 : nVertex[nLenDelta] = v2;
1394 : 0 : nLenDelta++;
1395 : : }
1396 : : }
1397 : : else
1398 : : {
1399 [ # # ]: 0 : if (v2 >= num_atoms &&
1400 [ # # # # : 0 : ( ( pBNS->vert[v2].type & BNS_VERT_TYPE_TGROUP ) || ( pBNS->vert[v2].type & BNS_VERT_TYPE_TEMP ) ) &&
# # ]
1401 [ # # # # ]: 0 : 0 <= v1 && v1 < num_atoms && ( pBNS->vert[v1].type & BNS_VERT_TYPE_ATOM ))
1402 : : {
1403 : : /*
1404 : : if ( !(pAATG->nMarkedAtom[v1] & AATG_MARK_IN_PATH) ) {
1405 : : pAATG->nMarkedAtom[v1] |= AATG_MARK_IN_PATH;
1406 : : pAATG->nNumFound ++;
1407 : : }
1408 : : */
1409 : :
1410 : : /* BNS increased bond order in v1(atom)-v2(t-group) by delta: added delta attachments */
1411 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1412 : : {
1413 : 0 : cDelta[nLenDelta] = delta;
1414 : 0 : nVertex[nLenDelta] = v1;
1415 : 0 : nLenDelta++;
1416 : : }
1417 : : }
1418 : : else
1419 : : {
1420 : : /* Special case when the testing 'dot' was placed on an atom (should be nEnd1 only) */
1421 [ # # # # : 0 : if ((0 <= v1 && v1 == nEnd1) || (v1 == nEnd2 && 0 <= v2 && v2 < num_atoms)) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
1422 : : {
1423 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1424 : : {
1425 : 0 : cDelta[nLenDelta] = -delta;
1426 : 0 : nVertex[nLenDelta] = v1;
1427 : 0 : nLenDelta++;
1428 : : }
1429 : : }
1430 : : else
1431 : : {
1432 [ # # # # : 0 : if ((0 <= v2 && v2 == nEnd1) || (v2 == nEnd2 && 0 <= v1 && v1 < num_atoms)) /* djb-rwth: addressing LLVM warning */
# # # # #
# ]
1433 : : {
1434 [ # # ]: 0 : if (nLenDelta < MAX_ALT_AATG_ARRAY_LEN)
1435 : : {
1436 : 0 : cDelta[nLenDelta] = -delta;
1437 : 0 : nVertex[nLenDelta] = v2;
1438 : 0 : nLenDelta++;
1439 : : }
1440 : : }
1441 : : }
1442 : : }
1443 : : }
1444 : : }
1445 : :
1446 [ # # ]: 0 : if (v2 != vLast)
1447 : : {
1448 : 0 : err = BNS_PROGRAM_ERR;
1449 : : }
1450 : : else
1451 : : {
1452 : 0 : last_i = -1;
1453 : 0 : nNumFound = 0;
1454 : : /* first run */
1455 [ # # ]: 0 : for (i = 1, j = 0; i < nLenDelta; j = i++)
1456 : : {
1457 : : /* Ignore sequences (-1,+1) and (+1,-1) in cDelta[] because they */
1458 : : /* describe ordinary aug. paths of moving a single attachment */
1459 : : /* we are looking for aug. paths describing movement of 2 or more */
1460 [ # # # # ]: 0 : if ((cDelta[j] > 0 && cDelta[i] > 0) ||
1461 [ # # # # ]: 0 : (cDelta[j] < 0 && cDelta[i] < 0)) /* djb-rwth: addressing LLVM warning */
1462 : : {
1463 [ # # ]: 0 : if (j == last_i)
1464 : : {
1465 : : /* Three attachments moved */
1466 : 0 : return 0;
1467 : : }
1468 : 0 : v1 = nVertex[j];
1469 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v1] & AATG_MARK_IN_PATH ))
1470 : : {
1471 : 0 : nNumFound++;
1472 : : }
1473 : 0 : v2 = nVertex[i];
1474 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v2] & AATG_MARK_IN_PATH ))
1475 : : {
1476 : 0 : nNumFound++;
1477 : : }
1478 : 0 : last_i = i;
1479 : : }
1480 : : }
1481 [ # # ]: 0 : if (!nNumFound)
1482 : : {
1483 : 0 : return 0;
1484 : : }
1485 [ # # ]: 0 : if (nNumFound > 4)
1486 : : {
1487 : 0 : return 0;
1488 : : }
1489 [ # # ]: 0 : if (nNumFound < 4)
1490 : : {
1491 : 0 : return 0;
1492 : : }
1493 : :
1494 : : /* Second run */
1495 [ # # ]: 0 : for (i = 1, j = 0; i < nLenDelta; j = i++)
1496 : : {
1497 : : /* Ignore sequences (-1,+1) and (+1,-1) in cDelta[] because they */
1498 : : /* describe ordinary aug. paths of moving a single attachment */
1499 : : /* we are looking for aug. paths describing movement of 2 or more */
1500 [ # # # # ]: 0 : if ((cDelta[j] > 0 && cDelta[i] > 0) ||
1501 [ # # # # ]: 0 : (cDelta[j] < 0 && cDelta[i] < 0)) /* djb-rwth: addressing LLVM warning */
1502 : : {
1503 : 0 : v1 = nVertex[i - 1];
1504 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v1] & AATG_MARK_IN_PATH ))
1505 : : {
1506 : 0 : pAATG->nMarkedAtom[v1] |= AATG_MARK_IN_PATH;
1507 : 0 : pAATG->nNumFound++;
1508 : : }
1509 : 0 : v2 = nVertex[i];
1510 [ # # ]: 0 : if (!( pAATG->nMarkedAtom[v2] & AATG_MARK_IN_PATH ))
1511 : : {
1512 : 0 : pAATG->nMarkedAtom[v2] |= AATG_MARK_IN_PATH;
1513 : 0 : pAATG->nNumFound++;
1514 : : }
1515 : : }
1516 : : }
1517 : : }
1518 : : }
1519 : :
1520 [ # # ]: 0 : return err ? err : pAATG->nNumFound;
1521 : : }
1522 : :
1523 : :
1524 : : /****************************************************************************/
1525 : 2 : int RestoreBnStructFlow( BN_STRUCT *pBNS, int bChangeFlow )
1526 : : {
1527 : 2 : int pass, i, v1, v2, ineigh1, ineigh2, vLast, n, delta, ret, err = 0; /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1528 : : BNS_EDGE *edge;
1529 : :
1530 [ + + ]: 4 : for (pass = pBNS->num_altp - 1, ret = 0; 0 <= pass; pass--)
1531 : : {
1532 : 2 : pBNS->alt_path = pBNS->altp[pass];
1533 : 2 : v1 = ALTP_START_ATOM( pBNS->alt_path );
1534 : 2 : n = ALTP_PATH_LEN( pBNS->alt_path );
1535 : 2 : delta = ALTP_DELTA( pBNS->alt_path );
1536 : 2 : vLast = ALTP_END_ATOM( pBNS->alt_path );
1537 : 2 : v2 = NO_VERTEX;
1538 : : /* starting vertex */
1539 [ + - ]: 2 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1540 : : {
1541 : 2 : pBNS->vert[v1].st_edge.flow -= delta; /* restore s-v1 edge flow to the BNS input value */
1542 : : }
1543 : : else
1544 : : {
1545 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1546 : : {
1547 : 0 : pBNS->vert[v1].st_edge.flow0 = pBNS->vert[v1].st_edge.flow;
1548 : : }
1549 : : }
1550 : :
1551 : : /* Augmenting path edges */
1552 [ + + ]: 8 : for (i = 0; i < n; i++, delta = -delta, v1 = v2)
1553 : : {
1554 : 6 : ineigh1 = ALTP_THIS_ATOM_NEIGHBOR( pBNS->alt_path, i ); /* v1->v2 neighbor */
1555 : 6 : ineigh2 = ALTP_NEXT_ATOM_NEIGHBOR(pBNS->alt_path, i); /* v2->v1 neighbor */ /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
1556 : 6 : edge = pBNS->edge + pBNS->vert[v1].iedge[ineigh1];
1557 : 6 : v2 = edge->neighbor12 ^ v1;
1558 : 6 : RestoreEdgeFlow( edge, delta, bChangeFlow );
1559 : 6 : edge->pass = 0;
1560 : : }
1561 : :
1562 : : /* Ending vertex */
1563 [ - + ]: 2 : if (v2 != vLast)
1564 : : {
1565 : 0 : err = BNS_PROGRAM_ERR;
1566 : : }
1567 : : else
1568 : : {
1569 [ + - ]: 2 : if (( bChangeFlow & BNS_EF_CHNG_RSTR ) == BNS_EF_CHNG_RSTR)
1570 : : {
1571 : : /* Restore v2-t edge flow to the original value */
1572 : : /* "+=" instead of "-=" explanation: delta must have same sign as at the last edge */
1573 : 2 : pBNS->vert[v2].st_edge.flow += delta;
1574 : : }
1575 : : else
1576 : : {
1577 [ # # ]: 0 : if (( bChangeFlow & BNS_EF_SAVE_ALL ) == BNS_EF_SAVE_ALL)
1578 : : {
1579 : 0 : pBNS->vert[v2].st_edge.flow0 = pBNS->vert[v2].st_edge.flow;
1580 : : }
1581 : : }
1582 : : }
1583 : : }
1584 : :
1585 [ - + ]: 2 : return err ? err : ret;
1586 : : }
1587 : :
1588 : :
1589 : : /****************************************************************************/
1590 : 15 : int bNeedToTestTheFlow( int bond_type,
1591 : : int nTestFlow,
1592 : : int bTestForNonStereoBond )
1593 : : {
1594 : 15 : int nBondType = ( BOND_TYPE_MASK & bond_type );
1595 : 15 : int nBondAttrib = ( BOND_MARK_MASK & bond_type );
1596 : :
1597 [ - + ]: 15 : if (bTestForNonStereoBond)
1598 : : {
1599 [ # # # # : 0 : if (nBondAttrib || nBondType == BOND_ALTERN || nBondType == BOND_ALT12NS)
# # ]
1600 : : {
1601 [ # # # # ]: 0 : switch (nTestFlow)
1602 : : {
1603 : 0 : case 0: /* single: can be 1 (single)? */
1604 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT12NS ||
1605 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1606 : : nBondAttrib == BOND_MARK_ALT13)
1607 : : {
1608 : 0 : return 0; /* yes, already checked */
1609 : : }
1610 : 0 : break;
1611 : :
1612 : 0 : case 1: /* double: can be 2 (double)? */
1613 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT12NS ||
1614 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1615 : : nBondAttrib == BOND_MARK_ALT23)
1616 : : {
1617 : 0 : return 0; /* yes, already checked */
1618 : : }
1619 : 0 : break;
1620 : 0 : case 2: /* triple: can be 3 (triple)? */
1621 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT13 ||
1622 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1623 : : nBondAttrib == BOND_MARK_ALT23)
1624 : : {
1625 : 0 : return 0; /* yes, already checked */
1626 : : }
1627 : 0 : break;
1628 : : }
1629 : : }
1630 : : }
1631 : : else
1632 : : {
1633 [ + + + - : 15 : if (nBondAttrib || nBondType == BOND_ALTERN || nBondType == BOND_ALT12NS)
- + ]
1634 : : {
1635 [ + + - - ]: 10 : switch (nTestFlow)
1636 : : {
1637 : 6 : case 0: /* single: can be 1 (single)? */
1638 [ - + - - ]: 6 : if (nBondAttrib == BOND_MARK_ALT12 ||
1639 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT12NS ||
1640 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1641 : : nBondAttrib == BOND_MARK_ALT13)
1642 : : {
1643 : 6 : return 0;
1644 : : }
1645 : 0 : break;
1646 : :
1647 : 4 : case 1: /* double: can be 2 (double)? */
1648 [ - + - - ]: 4 : if (nBondAttrib == BOND_MARK_ALT12 ||
1649 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT12NS ||
1650 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1651 : : nBondAttrib == BOND_MARK_ALT23)
1652 : : {
1653 : 4 : return 0; /* yes */
1654 : : }
1655 : 0 : break;
1656 : 0 : case 2: /* triple: can be 3 (triple)? */
1657 [ # # # # ]: 0 : if (nBondAttrib == BOND_MARK_ALT13 ||
1658 [ # # ]: 0 : nBondAttrib == BOND_MARK_ALT123 ||
1659 : : nBondAttrib == BOND_MARK_ALT23)
1660 : : {
1661 : 0 : return 0;
1662 : : }
1663 : 0 : break;
1664 : : }
1665 : : }
1666 : : }
1667 : :
1668 : 5 : return 1;
1669 : : }
1670 : :
1671 : :
1672 : : /****************************************************************************/
1673 : 1801 : int nBondsValenceInpAt( const inp_ATOM *at,
1674 : : int *nNumAltBonds,
1675 : : int *nNumWrongBonds )
1676 : : {
1677 : 1801 : int j, bond_type, nBondsValence = 0, nAltBonds = 0, nNumWrong = 0;
1678 [ + + ]: 5163 : for (j = 0; j < at->valence; j++)
1679 : : {
1680 : 3362 : bond_type = at->bond_type[j] & BOND_TYPE_MASK;
1681 [ + - + ]: 3362 : switch (bond_type)
1682 : : {
1683 : 3322 : case 0: /* for structure from InChI reconstruction */
1684 : : case BOND_SINGLE:
1685 : : case BOND_DOUBLE:
1686 : : case BOND_TRIPLE:
1687 : 3322 : nBondsValence += bond_type;
1688 : 3322 : break;
1689 : 0 : case BOND_ALTERN:
1690 : 0 : nAltBonds++;
1691 : 0 : break;
1692 : 40 : default:
1693 : 40 : nNumWrong++;
1694 : : }
1695 : : }
1696 [ + - - ]: 1801 : switch (nAltBonds)
1697 : : {
1698 : 1801 : case 0:
1699 : 1801 : break;
1700 : 0 : case 1:
1701 : 0 : nBondsValence += 1; /* 1 or greater than 3 is wrong */
1702 : 0 : nNumWrong++;
1703 : 0 : break;
1704 : 0 : default:
1705 : 0 : nBondsValence += nAltBonds + 1;
1706 : 0 : break;
1707 : : }
1708 [ + + ]: 1801 : if (nNumAltBonds)
1709 : : {
1710 : 619 : *nNumAltBonds = nAltBonds;
1711 : : }
1712 [ + + ]: 1801 : if (nNumWrongBonds)
1713 : : {
1714 : 619 : *nNumWrongBonds = nNumWrong;
1715 : : }
1716 : :
1717 : 1801 : return nBondsValence;
1718 : : }
1719 : :
1720 : :
1721 : : /****************************************************************************
1722 : : If radical or has aromatic bonds,
1723 : : then augment to the lowest "multiplicity"
1724 : : ****************************************************************************/
1725 : 69 : int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS,
1726 : : BN_DATA *pBD,
1727 : : inp_ATOM *at,
1728 : : int num_atoms )
1729 : : {
1730 : 69 : int bError = 0, nOrigDelta = 0, ret, num_removed;
1731 : :
1732 : : #if( CHECK_AROMBOND2ALT == 1 )
1733 : 69 : int *pcValMinusBondsVal = NULL;
1734 : : int i, nValMinusBondsVal, nAltBonds, bIgnore, valen, is_rad, excess;
1735 : :
1736 : : /* Find valence excess (it may only be due to aromatic bonds) */
1737 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
1738 : : {
1739 : 619 : valen = nBondsValenceInpAt( at + i, &nAltBonds, &bIgnore );
1740 : 619 : nValMinusBondsVal = (int) at[i].chem_bonds_valence - valen;
1741 : 619 : bIgnore += ( nAltBonds > 3 );
1742 [ + - - + ]: 619 : if (!bIgnore && nValMinusBondsVal > 0)
1743 : : {
1744 [ # # ]: 0 : if (!pcValMinusBondsVal &&
1745 [ # # ]: 0 : !( pcValMinusBondsVal = (int *) inchi_calloc( num_atoms, sizeof( pcValMinusBondsVal[0] ) ) ))
1746 : : {
1747 : 0 : bError = BNS_OUT_OF_RAM;
1748 : 0 : goto exit_function;
1749 : : }
1750 : : /* Mark atoms that have extra unsatisfied valence due to aromatic bonds */
1751 : 0 : is_rad = ( at[i].radical == RADICAL_DOUBLET );
1752 : 0 : excess = nValMinusBondsVal + is_rad;
1753 : 0 : pcValMinusBondsVal[i] = excess;
1754 : : }
1755 : : }
1756 : : #endif /* CHECK_AROMBOND2ALT */
1757 : :
1758 : : /* Match bonds to valences */
1759 : : do
1760 : : {
1761 : 69 : num_removed = 0;
1762 : 69 : ret = RunBalancedNetworkSearch( pBNS, pBD, BNS_EF_CHNG_FLOW );
1763 [ + - - + ]: 69 : if (IS_BNS_ERROR( ret ))
1764 : : {
1765 : 0 : bError = ret;
1766 : : }
1767 : : else
1768 : : {
1769 : 69 : nOrigDelta += ret;
1770 : 69 : num_removed = pBNS->num_altp; /* number of augmenting paths */
1771 [ - + ]: 69 : if (ret > 0)
1772 : : {
1773 : : /* save new bonds in at[] and flows in pBNS and at[] */
1774 : 0 : ret = SetBondsFromBnStructFlow( pBNS, at, num_atoms, BNS_EF_SAVE_ALL ); /* must include 1: 5=(4|1) */
1775 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
1776 : : {
1777 : 0 : bError = ret;
1778 : : }
1779 : 0 : ret = RestoreBnStructFlow( pBNS, BNS_EF_SAVE_ALL ); /* must include 1: 5=(4|1) */
1780 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
1781 : : {
1782 : 0 : bError = ret;
1783 : : }
1784 : : }
1785 : 69 : ReInitBnStructAltPaths( pBNS );
1786 : : }
1787 [ - + - - : 69 : } while (num_removed && num_removed == pBNS->max_altp && !bError);
- - ]
1788 : :
1789 : : #if( CHECK_AROMBOND2ALT == 1 )
1790 : : /* Check whether aromatic bonds have been replaced with alternating bonds */
1791 [ - + + - ]: 69 : if (!bError && pcValMinusBondsVal)
1792 : : {
1793 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
1794 : : {
1795 [ # # ]: 0 : if (!pcValMinusBondsVal[i])
1796 : : {
1797 : 0 : continue;
1798 : : }
1799 : 0 : valen = nBondsValenceInpAt( at + i, &nAltBonds, &bIgnore );
1800 : 0 : nValMinusBondsVal = (int) at[i].chem_bonds_valence - valen;
1801 : 0 : is_rad = ( at[i].radical == RADICAL_DOUBLET );
1802 : 0 : excess = nValMinusBondsVal + is_rad;
1803 [ # # ]: 0 : if (bIgnore ||
1804 [ # # ]: 0 : ( pcValMinusBondsVal[i] - excess ) != 1)
1805 : : {
1806 : : /* radical excess has not been reduced */
1807 : 0 : bError = BNS_ALTBOND_ERR;
1808 : 0 : break;
1809 : : }
1810 : : }
1811 : : }
1812 : :
1813 : 69 : exit_function:
1814 [ - + ]: 69 : if (pcValMinusBondsVal)
1815 : : {
1816 [ # # ]: 0 : inchi_free( pcValMinusBondsVal );
1817 : : }
1818 : : #endif /* CHECK_AROMBOND2ALT */
1819 : :
1820 [ - + ]: 69 : return bError ? bError : nOrigDelta;
1821 : : }
1822 : :
1823 : :
1824 : : /****************************************************************************/
1825 : 69 : int BnsTestAndMarkAltBonds( BN_STRUCT *pBNS,
1826 : : BN_DATA *pBD,
1827 : : inp_ATOM *at,
1828 : : int num_atoms,
1829 : : BNS_FLOW_CHANGES *fcd,
1830 : : int bChangeFlow,
1831 : : int nBondTypeToTest )
1832 : : {
1833 : : int ret, iat, ineigh, neigh;
1834 : : int nMinFlow, nMaxFlow, nTestFlow, nCurFlow;
1835 : : int iedge, bError, nDots, nChanges, bTestForNonStereoBond; /* djb-rwth: removing redundant variables */
1836 : :
1837 : : /* Normalize bonds and find tautomeric groups */
1838 : 69 : bError = 0;
1839 : 69 : nChanges = 0;
1840 : 69 : bTestForNonStereoBond = pBNS->tot_st_cap > pBNS->tot_st_flow;
1841 : :
1842 [ + + + - ]: 688 : for (iat = 0; iat < num_atoms && !bError; iat++)
1843 : : {
1844 [ + + + - ]: 1753 : for (ineigh = 0; ineigh < at[iat].valence && !bError; ineigh++)
1845 : : {
1846 : 1134 : neigh = at[iat].neighbor[ineigh];
1847 [ + + ]: 1134 : if (neigh < iat)
1848 : : {
1849 : 567 : continue; /* we have already tested the bond */
1850 : : }
1851 : 567 : iedge = pBNS->vert[iat].iedge[ineigh];
1852 [ - + ]: 567 : if (IS_FORBIDDEN( pBNS->edge[iedge].forbidden, pBNS ))
1853 : : {
1854 : 0 : continue;
1855 : : }
1856 [ - + - - ]: 567 : if (nBondTypeToTest && ( at[iat].bond_type[ineigh] & BOND_TYPE_MASK ) != nBondTypeToTest)
1857 : : {
1858 : 0 : continue;
1859 : : }
1860 : 567 : nMinFlow = nMinFlow2Check( pBNS, iedge );
1861 : 567 : nMaxFlow = nMaxFlow2Check( pBNS, iedge );
1862 : 567 : nCurFlow = nCurFlow2Check( pBNS, iedge );
1863 [ + + ]: 567 : if (nMinFlow == nMaxFlow)
1864 : : {
1865 [ + + - + ]: 552 : if (nMaxFlow && bTestForNonStereoBond)
1866 : : {
1867 : 0 : nTestFlow = nMaxFlow - (int) ( pBNS->tot_st_cap - pBNS->tot_st_flow ); /* temporary use of nTestFlow */
1868 : 0 : nMinFlow = inchi_max( 0, nTestFlow );
1869 : : }
1870 : : else
1871 : : {
1872 : 552 : continue;
1873 : : }
1874 : : }
1875 [ + + + - ]: 45 : for (nTestFlow = nMinFlow; nTestFlow <= nMaxFlow && !bError; nTestFlow++)
1876 : : {
1877 [ + + ]: 30 : if (nTestFlow == nCurFlow)
1878 : : {
1879 : 15 : continue;
1880 : : }
1881 [ + + ]: 15 : if (!bNeedToTestTheFlow( at[iat].bond_type[ineigh], nTestFlow, bTestForNonStereoBond ))
1882 : : {
1883 : 10 : continue;
1884 : : }
1885 : : /* djb-rwth: removing redundant code */
1886 : 5 : nDots = bSetFlowToCheckOneBond( pBNS, iedge, nTestFlow, fcd );
1887 : :
1888 [ + - - + ]: 5 : if (IS_BNS_ERROR( nDots ))
1889 : : {
1890 [ # # ]: 0 : if (nDots == BNS_CANT_SET_BOND)
1891 : : {
1892 : 0 : ret = bRestoreFlowAfterCheckOneBond( pBNS, fcd );
1893 [ # # # # ]: 0 : if (!IS_BNS_ERROR( ret ))
1894 : : {
1895 : 0 : continue;
1896 : : }
1897 : : }
1898 : 0 : bError = nDots;
1899 : : }
1900 : : else
1901 : : {
1902 [ + - ]: 5 : if (nDots > 0)
1903 : : {
1904 : 5 : ret = RunBalancedNetworkSearch( pBNS, pBD, bChangeFlow );
1905 [ + - - + ]: 5 : if (IS_BNS_ERROR( ret ))
1906 : : {
1907 : 0 : bError = ret;
1908 : : }
1909 : : else
1910 : : {
1911 [ + + ]: 5 : if (ret > 0)
1912 : : {
1913 [ + - ]: 2 : if (2 * ret == nDots)
1914 : : {
1915 : 2 : ret = bSetBondsAfterCheckOneBond( pBNS, fcd, nTestFlow, at, num_atoms, bChangeFlow );
1916 [ + - - + ]: 2 : if (IS_BNS_ERROR( ret ))
1917 : : {
1918 : 0 : bError = ret;
1919 : : }
1920 : : else
1921 : : {
1922 : 2 : nChanges += ( ret & 1 );
1923 : 2 : ret = SetBondsFromBnStructFlow( pBNS, at, num_atoms, bChangeFlow );
1924 [ + - - + ]: 2 : if (IS_BNS_ERROR( ret ))
1925 : : {
1926 : 0 : bError = ret;
1927 : : }
1928 : : else
1929 : : {
1930 [ + - ]: 2 : if (ret >= 0)
1931 : : {
1932 : 2 : nChanges += ( ret & 1 );
1933 : : /* djb-rwth: removing redundant code */
1934 : : }
1935 : : else
1936 : : {
1937 : 0 : bError = ret;
1938 : : }
1939 : : }
1940 : : }
1941 : : }
1942 : : /* typically 2*ret < nDots; 2*ret > nDots should not happen. Check later */
1943 : 2 : ret = RestoreBnStructFlow( pBNS, bChangeFlow & BNS_EF_CHNG_RSTR );
1944 [ + - - + ]: 2 : if (IS_BNS_ERROR( ret ))
1945 : : {
1946 : 0 : bError = ret;
1947 : : }
1948 : : }
1949 : : }
1950 : : /* --- Reinitialize to repeat the calculations --- */
1951 : 5 : ReInitBnStructAltPaths( pBNS );
1952 : : }
1953 : :
1954 : : else
1955 : : {
1956 [ # # ]: 0 : if (nDots == 0)
1957 : : {
1958 : 0 : ret = bSetBondsAfterCheckOneBond( pBNS, fcd, nTestFlow, at, num_atoms, bChangeFlow );
1959 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
1960 : : {
1961 : 0 : bError = ret;
1962 : : }
1963 : : else
1964 : : {
1965 : 0 : nChanges += ( ret & 1 );
1966 : : }
1967 : : }
1968 : : }
1969 : : }
1970 : :
1971 : 5 : ret = bRestoreFlowAfterCheckOneBond( pBNS, fcd );
1972 : :
1973 [ + - - + ]: 5 : if (IS_BNS_ERROR( ret ))
1974 : : {
1975 : 0 : bError = ret;
1976 : : }
1977 : :
1978 : : } /* for (nTestFlow = */
1979 : : } /* for (ineigh = */
1980 : : } /* for (iat = */
1981 : :
1982 [ - + ]: 69 : return bError ? bError : nChanges;
1983 : : }
1984 : :
1985 : :
1986 : : /****************************************************************************/
1987 : 69 : static void remove_alt_bond_marks( inp_ATOM *at, int num_atoms )
1988 : : {
1989 : : int i, j, val;
1990 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
1991 : : {
1992 [ + + ]: 1753 : for (val = at[i].valence, j = 0; j < val; j++)
1993 : : {
1994 : 1134 : at[i].bond_type[j] &= BOND_TYPE_MASK;
1995 : : }
1996 : : }
1997 : :
1998 : 69 : }
1999 : :
2000 : :
2001 : : /****************************************************************************/
2002 : 69 : int SetForbiddenEdges( BN_STRUCT *pBNS,
2003 : : inp_ATOM *at,
2004 : : int num_atoms,
2005 : : int forbidden_mask,
2006 : : int nebend,
2007 : : int *ebend )
2008 : : {
2009 : :
2010 : :
2011 : : int i, j, neigh, num_found;
2012 : : BNS_IEDGE iedge;
2013 : : /*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
2014 : 69 : S_CHAR edge_forbidden_mask = forbidden_mask;
2015 : :
2016 : 69 : pBNS->edge_forbidden_mask |= forbidden_mask;
2017 : :
2018 : 69 : num_found = 0;
2019 : :
2020 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
2021 : : {
2022 : : /* acetyl */
2023 [ + + + + ]: 619 : if (at[i].el_number == EL_NUMBER_C && 3 == at[i].valence &&
2024 [ + + ]: 205 : 4 == at[i].chem_bonds_valence)
2025 : 6 : {
2026 : 6 : int num_O = 0;
2027 : 6 : int bond_to_O_val = 0;
2028 : 6 : int forbidden_bond_pos = -1;
2029 : 6 : int forbidden_bond_val = -1;
2030 [ + + ]: 24 : for (j = 0; j < at[i].valence; j++)
2031 : : {
2032 : 18 : neigh = at[i].neighbor[j];
2033 [ - + ]: 18 : if (at[neigh].el_number == EL_NUMBER_O &&
2034 [ # # ]: 0 : at[neigh].valence == 1)
2035 : : {
2036 : 0 : num_O++;
2037 : 0 : bond_to_O_val += ( at[i].bond_type[j] & BOND_TYPE_MASK );
2038 : : }
2039 : : else
2040 : : {
2041 : 18 : forbidden_bond_pos = j;
2042 : 18 : forbidden_bond_val = ( at[i].bond_type[j] & BOND_TYPE_MASK );
2043 : : }
2044 : : }
2045 [ - + - - : 6 : if (2 == num_O && 3 == bond_to_O_val && 1 == forbidden_bond_val)
- - ]
2046 : : {
2047 : 0 : iedge = pBNS->vert[i].iedge[forbidden_bond_pos];
2048 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2049 : 0 : num_found++;
2050 : : }
2051 : : }
2052 : : else
2053 : : {
2054 : : /* nitro */
2055 [ + + - + ]: 613 : if (at[i].el_number == EL_NUMBER_N && 3 == at[i].valence &&
2056 [ # # # # ]: 0 : ( 4 == at[i].chem_bonds_valence || 5 == at[i].chem_bonds_valence ))
2057 : : {
2058 : 0 : int num_O = 0;
2059 : 0 : int bond_to_O_val = 0;
2060 : 0 : int forbidden_bond_pos = -1;
2061 : 0 : int forbidden_bond_val = -1;
2062 [ # # ]: 0 : for (j = 0; j < at[i].valence; j++)
2063 : : {
2064 : 0 : neigh = at[i].neighbor[j];
2065 [ # # ]: 0 : if (at[neigh].el_number == EL_NUMBER_O &&
2066 [ # # ]: 0 : at[neigh].valence == 1)
2067 : : {
2068 : 0 : num_O++;
2069 : 0 : bond_to_O_val += ( at[i].bond_type[j] & BOND_TYPE_MASK );
2070 : : }
2071 : : else
2072 : : {
2073 : 0 : forbidden_bond_pos = j;
2074 : 0 : forbidden_bond_val = ( at[i].bond_type[j] & BOND_TYPE_MASK );
2075 : : }
2076 : : }
2077 [ # # # # : 0 : if (2 == num_O && ( 3 == bond_to_O_val || 4 == bond_to_O_val ) && 1 == forbidden_bond_val)
# # # # ]
2078 : : {
2079 : 0 : iedge = pBNS->vert[i].iedge[forbidden_bond_pos];
2080 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2081 : 0 : num_found++;
2082 : : }
2083 : : }
2084 : : }
2085 : : }
2086 : :
2087 : : #ifdef FIX_SRU_CYCLIZING_PS_BONDS_IN_BNS
2088 : : if (nebend > 1)
2089 : : num_found += fix_explicitly_indicated_bonds( nebend, ebend, pBNS, at, num_atoms );
2090 : : #endif
2091 : :
2092 : : #if ( REMOVE_ION_PAIRS_FIX_BONDS == 1 )
2093 : 69 : num_found += fix_special_bonds( pBNS, at, num_atoms, edge_forbidden_mask );
2094 : : #endif
2095 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
2096 : : num_found += TempFix_NH_NH_Bonds( pBNS, at, num_atoms );
2097 : : #endif
2098 : :
2099 : 69 : return num_found;
2100 : : }
2101 : :
2102 : :
2103 : :
2104 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
2105 : :
2106 : :
2107 : : /****************************************************************************/
2108 : : int TempFix_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 : : for (i = 0, num_found = 0; i < num_atoms; i++)
2114 : : {
2115 : : /* -NH-NH- or -NH-NH3 */
2116 : : if (at[i].el_number == EL_NUMBER_N && at[i].valence < 3 && at[i].num_H &&
2117 : : 3 == at[i].chem_bonds_valence + at[i].num_H &&
2118 : : at[i].chem_bonds_valence == at[i].valence &&
2119 : : !at[i].charge && !at[i].radical)
2120 : : {
2121 : : for (j = 0; j < at[i].valence; j++)
2122 : : {
2123 : : neigh = at[i].neighbor[j];
2124 : : if (neigh < i &&
2125 : : at[neigh].el_number == EL_NUMBER_N && at[neigh].valence < 3 && at[neigh].num_H &&
2126 : : 3 == at[neigh].chem_bonds_valence + at[neigh].num_H &&
2127 : : at[neigh].chem_bonds_valence == at[neigh].valence &&
2128 : : !at[neigh].charge && !at[neigh].radical)
2129 : : {
2130 : : iedge = pBNS->vert[i].iedge[j];
2131 : : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2132 : : num_found++;
2133 : : }
2134 : : }
2135 : : }
2136 : : }
2137 : :
2138 : : return num_found;
2139 : : }
2140 : :
2141 : :
2142 : : /****************************************************************************/
2143 : : int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
2144 : : {
2145 : : int i, j, neigh, num_found;
2146 : : BNS_IEDGE iedge;
2147 : : S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_TEMP;
2148 : :
2149 : : for (i = 0, num_found = 0; i < num_atoms; i++)
2150 : : {
2151 : : /* -NH-NH- or -NH-NH3 */
2152 : : if (at[i].el_number == EL_NUMBER_N && at[i].valence < 3)
2153 : : {
2154 : : for (j = 0; j < at[i].valence; j++)
2155 : : {
2156 : : neigh = at[i].neighbor[j];
2157 : : if (neigh < i &&
2158 : : at[neigh].el_number == EL_NUMBER_N && at[neigh].valence < 3)
2159 : : {
2160 : : if (BOND_TYPE_SINGLE != ( at[i].bond_type[j] & BOND_TYPE_MASK ))
2161 : : {
2162 : : iedge = pBNS->vert[i].iedge[j];
2163 : : if (pBNS->edge[iedge].forbidden & edge_forbidden_mask)
2164 : : {
2165 : : pBNS->edge[iedge].forbidden &= ~edge_forbidden_mask;
2166 : : num_found++;
2167 : : }
2168 : : }
2169 : : }
2170 : : }
2171 : : }
2172 : : }
2173 : :
2174 : : return num_found;
2175 : : }
2176 : : #endif
2177 : :
2178 : : /****************************************************************************
2179 : : Fixes bonds which were set by remove_ion_pairs( ... )
2180 : : ****************************************************************************/
2181 : 69 : int fix_special_bonds( BN_STRUCT *pBNS,
2182 : : inp_ATOM *at,
2183 : : int num_atoms,
2184 : : int forbidden_mask )
2185 : : {
2186 : 69 : int num_changes = 0;
2187 : :
2188 : : #define MAX_NEIGH 6
2189 : :
2190 : : int i, k, n1, n2, n3, i1, i2, i3, i4, bond_type; /* djb-rwth: removing redundant variables */
2191 : : inp_ATOM *a;
2192 : : int j[3], m[3], num_O, k_O, num_N, num_OH, num_OM, num_X, num_other, k_N;
2193 : :
2194 : : BNS_IEDGE iedge;
2195 : : /*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
2196 : 69 : S_CHAR edge_forbidden_mask = forbidden_mask;
2197 : :
2198 : 69 : pBNS->edge_forbidden_mask |= edge_forbidden_mask;
2199 : :
2200 [ + + ]: 688 : for (i = 0, a = at; i < num_atoms; i++, a++)
2201 : : {
2202 : :
2203 [ + + + - ]: 619 : if (!a->charge && !a->radical &&
2204 [ + + + - ]: 614 : 2 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2205 : 2 : 0 == num_of_H( at, i ) &&
2206 [ + + - + ]: 3 : 2 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2207 : 1 : ion_el_group( at[i].el_number ) == EL_NUMBER_N )
2208 : : {
2209 : : /* Found N(V), no H */
2210 [ # # ]: 0 : if (2 == nNoMetalNumBonds( at, i ))
2211 : : {
2212 : : /* #N= */
2213 : : /* fix bonds: double and triple: =N# so that bonds cannot be changed by the normalization */
2214 : : #if ( FIX_N_V_METAL_BONDS_GPF == 1 )
2215 [ # # # # ]: 0 : if (0 > ( i1 = nNoMetalNeighIndex( at, i ) ) ||
2216 : 0 : 0 > ( i2 = nNoMetalOtherNeighIndex( at, i, n1 = a->neighbor[i1]/* non-metal neighbor #1 */ ) ))
2217 : : {
2218 : : /*num_err ++; */ /* do not count would-be original InChI v.1 buffer overflow GPF */
2219 : 0 : continue; /* v1 bug: 2 bonds to metal yield i1 < 0 and/or i2 < 0 => bounds violation */
2220 : : }
2221 : : #else
2222 : : i1 = nNoMetalNeighIndex( at, i );
2223 : : n1 = a->neighbor[i1]; /* non-metal neighbor #1 */
2224 : : i2 = nNoMetalOtherNeighIndex( at, i, n1 );
2225 : : #endif
2226 : 0 : n2 = a->neighbor[i2]; /* non-metal neighbor #2 */
2227 : : /* forbid all edges to non-metals */
2228 : 0 : iedge = pBNS->vert[i].iedge[i1];
2229 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
2230 : 0 : iedge = pBNS->vert[i].iedge[i2];
2231 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
2232 : 0 : num_changes++; /* added 11-15-2005 */
2233 : : /* i n3 */
2234 : : /* forbid single bond edge beyond the neighboring =N- as in #N=N- */
2235 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2236 [ # # ]: 0 : if (( at[i].bond_type[i1] & BOND_TYPE_MASK ) == BOND_TYPE_DOUBLE)
2237 : : {
2238 : 0 : i3 = i1; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2239 : 0 : n3 = n1;
2240 : : }
2241 : : else
2242 : : {
2243 : 0 : i3 = i2; /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
2244 : 0 : n3 = n2;
2245 : : }
2246 [ # # # # : 0 : if (0 == NUMH( at, n3 ) && 2 == nNoMetalNumBonds( at, n3 ) &&
# # ]
2247 [ # # ]: 0 : 3 == nNoMetalBondsValence( at, n3 ) &&
2248 [ # # ]: 0 : ion_el_group( at[n3].el_number ) == EL_NUMBER_N &&
2249 : 0 : 0 <= ( k = nNoMetalOtherNeighIndex( at, n3, i ) ))
2250 : : {
2251 : : /* found =N- ; forbid the edge*/
2252 : 0 : iedge = pBNS->vert[n3].iedge[k];
2253 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2254 : 0 : num_changes++;
2255 : : }
2256 : : }
2257 [ # # ]: 0 : else if (3 == nNoMetalNumBonds( at, i ) &&
2258 : : /* | */
2259 : : /* found =N= */
2260 : : /* locate all non-metal neighbors */
2261 [ # # ]: 0 : 0 <= ( j[0] = nNoMetalNeighIndex( at, i ) ) &&
2262 [ # # ]: 0 : 0 <= ( j[1] = nNoMetalOtherNeighIndex( at, i, m[0] = a->neighbor[j[0]] ) ) &&
2263 [ # # ]: 0 : 0 <= ( j[2] = nNoMetalOtherNeighIndex2( at, i, m[0], m[1] = a->neighbor[j[1]] ) ))
2264 : : {
2265 : : /* Count specific neighbors: N(V)=N, N(V)-N N(V)=O, and N(V)-N */
2266 : :
2267 : : /* if there is a single neighbor connected by a double bond, namely
2268 : : N(V)=N and/or N(V)=O, then fix the bond(s).
2269 : : If N(V)=O was fixed then do not fix another bond */
2270 : 0 : m[2] = a->neighbor[j[2]];
2271 : 0 : num_O = num_N = 0;
2272 [ # # ]: 0 : for (k = 0; k < 3; k++)
2273 : : {
2274 : 0 : n1 = m[k];
2275 : 0 : i1 = j[k]; /* djb-rwth: ignoring LLVM warning: variable used */
2276 [ # # ]: 0 : if (ion_el_group( at[n1].el_number ) == EL_NUMBER_N)
2277 : : {
2278 : 0 : k_N = k;
2279 : 0 : num_N++;
2280 : : }
2281 [ # # # # ]: 0 : else if (ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2282 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2283 : : {
2284 : 0 : k_O = k;
2285 : 0 : num_O++;
2286 : : }
2287 : : }
2288 : 0 : num_other = 0;
2289 [ # # ]: 0 : if (1 == num_O &&
2290 [ # # ]: 0 : 0 == at[n1 = m[k_O]].charge &&
2291 [ # # ]: 0 : 0 == at[n1].radical &&
2292 [ # # ]: 0 : BOND_TYPE_DOUBLE == ( at[i].bond_type[i1 = j[k_O]] & BOND_TYPE_MASK )
2293 : : )
2294 : : {
2295 : : /* Fix bond to neighbor =O */
2296 : 0 : iedge = pBNS->vert[i].iedge[i1];
2297 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2298 : 0 : num_changes++;
2299 : 0 : num_other++; /* indicator: double to a terminal O has been fixed */
2300 : : }
2301 [ # # # # ]: 0 : if (!num_other &&
2302 [ # # ]: 0 : num_O <= 1 &&
2303 : 0 : 1 == num_N &&
2304 [ # # ]: 0 : 0 == at[n1 = m[k_N]].charge &&
2305 [ # # ]: 0 : 0 == at[n1].radical &&
2306 [ # # ]: 0 : BOND_TYPE_DOUBLE == ( at[i].bond_type[i1 = j[k_N]] & BOND_TYPE_MASK ))
2307 : : {
2308 : : /* Fix bond to neighbor =N */
2309 : 0 : iedge = pBNS->vert[i].iedge[i1];
2310 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2311 : 0 : num_changes++;
2312 : : }
2313 : : }
2314 [ # # ]: 0 : else if (4 == nNoMetalNumBonds( at, i ))
2315 : : {
2316 : : /* | */
2317 : : /* found -N=N- */
2318 : : /* | */
2319 : : /* locate non-metal neighbor connected by a double bond;
2320 : : * if it is =N- then fix the double bond and the single bond beyond the neighbor
2321 : : */
2322 : 0 : num_N = 0;
2323 : 0 : num_other = 0; /* djb-rwth: ignoring LLVM warning: variable used */
2324 [ # # ]: 0 : for (i1 = 0; i1 < at[i].valence; i1++)
2325 : : {
2326 [ # # # # ]: 0 : if (BOND_TYPE_DOUBLE == ( at[i].bond_type[i1] & BOND_TYPE_MASK ) &&
2327 [ # # ]: 0 : !is_el_a_metal( at[n1 = (int) at[i].neighbor[i1]].el_number ) &&
2328 : 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_N)
2329 : : {
2330 : 0 : num_N++;
2331 : 0 : n2 = n1;
2332 : 0 : i2 = i1;
2333 : : }
2334 : : }
2335 [ # # # # : 0 : if (1 == num_N && 0 == NUMH( at, n2 ) &&
# # ]
2336 [ # # ]: 0 : 2 == nNoMetalNumBonds( at, n2 ) &&
2337 [ # # ]: 0 : 3 == nNoMetalBondsValence( at, n2 ) &&
2338 : 0 : 0 <= ( i3 = nNoMetalOtherNeighIndex( at, n2, i ) ) &&
2339 [ # # ]: 0 : BOND_TYPE_SINGLE == ( at[n2].bond_type[i3] & BOND_TYPE_MASK ))
2340 : : {
2341 : : /* fix the single bond beyond the N(V) neighbor N(V)=N- */
2342 : 0 : iedge = pBNS->vert[n2].iedge[i3];
2343 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2344 : 0 : num_changes++;
2345 : : /* fix the double bond */
2346 : 0 : iedge = pBNS->vert[i].iedge[i2];
2347 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2348 : 0 : num_changes++;
2349 : : }
2350 : : }
2351 : : }
2352 : :
2353 [ + + + - ]: 619 : else if (!a->charge && !a->radical &&
2354 [ + + + - ]: 614 : 2 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2355 : 2 : 0 == num_of_H( at, i ) &&
2356 [ + + ]: 2 : 2 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2357 [ + - - + : 1 : a->el_number != EL_NUMBER_O && ion_el_group( a->el_number ) == EL_NUMBER_O &&
- - ]
2358 : 0 : 3 == nNoMetalNumBonds( at, i ))
2359 : : {
2360 : : /* Found S(IV), no H, one double bond, total 3 bonds */
2361 : : /* OH
2362 : : /
2363 : : in O=S (X != O) fix single bond O-X (type 1)
2364 : : \
2365 : : X
2366 : :
2367 : : X
2368 : : /
2369 : : in Z=S (X, Y != OH) fix double bond Z=S (type 2)
2370 : : \
2371 : : Y
2372 : : */
2373 : 0 : num_N = 0; /* number of non-metal neighbors connected by a double bond */
2374 : 0 : num_OH = 0; /* number of neighbors OH connected by a single bond */
2375 : 0 : num_OM = 0; /* number of charged neighbors O connected by a single bond */
2376 : 0 : num_O = 0; /* number of neighbors =O connected by a double bond */
2377 : 0 : num_other = 0;
2378 : :
2379 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2380 : : {
2381 : 0 : n1 = (int) a->neighbor[i1];
2382 [ # # ]: 0 : if (is_el_a_metal( at[n1].el_number ))
2383 : : {
2384 : 0 : continue;
2385 : : }
2386 : :
2387 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2388 : :
2389 [ # # ]: 0 : if (BOND_TYPE_DOUBLE == bond_type)
2390 : : {
2391 : 0 : num_N++;
2392 : 0 : n2 = n1;
2393 : 0 : i2 = i1;
2394 [ # # ]: 0 : if (ion_el_group( at[n1].el_number ) == EL_NUMBER_O)
2395 : : {
2396 : 0 : num_O++;
2397 : : }
2398 : : }
2399 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2400 [ # # ]: 0 : 1 == nNoMetalNumBonds( at, n1 ) &&
2401 [ # # ]: 0 : 1 == nNoMetalBondsValence( at, n1 ) &&
2402 : 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O)
2403 : : {
2404 [ # # ]: 0 : if (0 == at[n1].charge)
2405 : : {
2406 : 0 : num_OH++;
2407 : 0 : n3 = n1;
2408 : 0 : i3 = i1; /* djb-rwth: ignoring LLVM warning: variable used */
2409 : : }
2410 : : else
2411 : : {
2412 : 0 : num_OM++;
2413 : : }
2414 : : }
2415 : : else
2416 : : {
2417 : 0 : num_other++;
2418 : : /* djb-rwth: removing redundant code */
2419 : 0 : i4 = i1;
2420 : : }
2421 : : } /* for (i1 = */
2422 : :
2423 [ # # # # : 0 : if (1 == num_N && 1 == num_O && 1 == num_OH + num_OM)
# # ]
2424 : : {
2425 [ # # ]: 0 : if (1 == num_other)
2426 : : {
2427 : : /* type 1: fix the single bond S-X */
2428 : 0 : iedge = pBNS->vert[i].iedge[i4];
2429 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2430 : 0 : num_changes++;
2431 : : }
2432 : : }
2433 [ # # # # : 0 : else if (1 == num_N && !num_OH && !num_OM)
# # ]
2434 : : {
2435 : 0 : int bFound = 0; /* flag */
2436 : 0 : int bDoNotFixAnyBond = 0; /* flag */
2437 : : /* Avoid case N=S-NH or N=S-N(-); N = N, P, As, Sb */
2438 [ # # ]: 0 : if (ion_el_group( at[n2].el_number ) == EL_NUMBER_N)
2439 : : {
2440 : 0 : U_CHAR el_number = at[n2].el_number;
2441 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2442 : : {
2443 : 0 : n1 = (int) a->neighbor[i1];
2444 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2445 [ # # ]: 0 : if (BOND_TYPE_SINGLE == bond_type &&
2446 [ # # # # ]: 0 : ( NUMH( at, n1 ) || -1 == at[n1].charge ) &&
2447 [ # # ]: 0 : el_number == at[n1].el_number)
2448 : : {
2449 : 0 : i3 = i1; /* djb-rwth: ignoring LLVM warning: variable used */
2450 : 0 : n3 = n1;
2451 : 0 : bFound++;
2452 : : }
2453 : : }
2454 : : }
2455 : : /* Exception: check if Z==X and they belong to the same ring system */
2456 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2457 : : {
2458 [ # # ]: 0 : if (i1 != i2)
2459 : : {
2460 : 0 : n1 = (int) a->neighbor[i1];
2461 [ # # ]: 0 : if (at[n2].el_number == at[n1].el_number &&
2462 [ # # ]: 0 : at[n2].nRingSystem == at[n1].nRingSystem)
2463 : : {
2464 : 0 : bDoNotFixAnyBond++;
2465 : : }
2466 : : }
2467 : : }
2468 [ # # ]: 0 : if (bDoNotFixAnyBond)
2469 : : {
2470 : : ; /* do nothing */
2471 : : }
2472 [ # # ]: 0 : else if (bFound)
2473 : : {
2474 [ # # # # ]: 0 : if (1 == bFound &&
2475 : 0 : 0 <= ( i4 = nNoMetalOtherNeighIndex2( at, i, n2, n3 ) ))
2476 : : {
2477 : : /* fix bond i4 */
2478 : 0 : iedge = pBNS->vert[i].iedge[i4];
2479 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2480 : 0 : num_changes++;
2481 : : }
2482 : : }
2483 : : else
2484 : : {
2485 : : /* fix the double bond >S=X */
2486 : 0 : iedge = pBNS->vert[i].iedge[i2];
2487 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2488 : 0 : num_changes++;
2489 : : /* -- test later --
2490 : : if ( 2 == nNoMetalNumBonds( at, n2 ) &&
2491 : : 0 <= ( i3 = nNoMetalOtherNeighIndex( at, n2, i ) ) ) {
2492 : : iedge = pBNS->vert[n2].iedge[i3];
2493 : : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2494 : : num_changes ++;
2495 : : }
2496 : : -------------------*/
2497 : : }
2498 : : }
2499 : : }
2500 : :
2501 [ + + + - ]: 619 : else if (!a->charge && !a->radical &&
2502 [ - + - - ]: 612 : 4 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2503 : 0 : 0 == num_of_H( at, i ) &&
2504 [ # # ]: 0 : 4 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2505 [ # # # # : 0 : a->el_number != EL_NUMBER_O && ion_el_group( a->el_number ) == EL_NUMBER_O &&
# # ]
2506 : 0 : 4 == nNoMetalNumBonds( at, i ))
2507 : 0 : {
2508 : : /* Found S(VI), no H, two double bonds or one triple bond */
2509 : : /* O
2510 : : ||
2511 : : in O=S--Y- (X, Y -- non-terminal) fix single bonds S-X, S-Y (type 1)
2512 : : \
2513 : : X--
2514 : :
2515 : : O
2516 : : ||
2517 : : in O=S--O(-) (X -- non-terminal) fix single bond S-X (type 2)
2518 : : \
2519 : : X--
2520 : :
2521 : : O
2522 : : ||
2523 : : in O=S--OH (X -- non-terminal) fix single bond S-X (type 3)
2524 : : \
2525 : : X--
2526 : :
2527 : : */
2528 : : int iN[4]; /* indexes of non-terminal neighbors connected by a single bond */
2529 : 0 : num_N = 0; /* number of non-metal neighbors connected by a double bond */
2530 : 0 : num_OH = 0; /* number of neighbors OH connected by a single bond */
2531 : 0 : num_OM = 0; /* number of non-terminal neighbors connected by a single bond */
2532 : 0 : num_O = 0; /* number of neighbors =O connected by a double bond */
2533 : 0 : num_X = 0; /* number of terminal atom X != O connected by a single bond */
2534 : 0 : num_other = 0;
2535 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2536 : : {
2537 : 0 : n1 = (int) a->neighbor[i1];
2538 [ # # ]: 0 : if (is_el_a_metal( at[n1].el_number ))
2539 : : {
2540 : 0 : continue;
2541 : : }
2542 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2543 [ # # ]: 0 : if (BOND_TYPE_DOUBLE == bond_type)
2544 : : {
2545 : 0 : num_N++;
2546 [ # # ]: 0 : if (( 0 == at[n1].charge
2547 : : #if ( S_VI_O_PLUS_METAL_FIX_BOND == 1 )
2548 [ # # # # ]: 0 : || (1 == at[n1].charge && 2 == at[n1].valence) /* djb-rwth: addressing LLVM warning */
2549 : : #endif
2550 : 0 : ) &&
2551 [ # # # # ]: 0 : 0 == at[n1].radical &&
2552 [ # # ]: 0 : 0 == num_of_H( at, n1 ) &&
2553 [ # # ]: 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2554 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2555 : : {
2556 : 0 : num_O++;
2557 : : }
2558 : : }
2559 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2560 [ # # ]: 0 : 1 == nNoMetalNumBonds( at, n1 ) &&
2561 [ # # ]: 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2562 : 0 : 1 >= num_of_H( at, n1 ) &&
2563 [ # # # # ]: 0 : 1 == ( ( 0 == at[n1].charge ) && 1 == num_of_H( at, n1 ) )
2564 [ # # # # : 0 : + ( ( -1 == at[n1].charge ) && 0 == num_of_H( at, n1 ) ))
# # ]
2565 : : {
2566 : 0 : num_OH++; /* -OH or -O(-) */
2567 : : }
2568 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2569 : 0 : 1 < nNoMetalNumBonds( at, n1 ))
2570 : : {
2571 : 0 : iN[num_OM++] = i1; /* non-terminal neighbor connected by a single bond */
2572 : : }
2573 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2574 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2575 : : {
2576 : 0 : num_X++; /* other terminal neighbor connected by a single bond */
2577 : : }
2578 : : else
2579 : : {
2580 : 0 : num_other++;
2581 : : }
2582 : : }
2583 [ # # # # : 0 : if (num_N == num_O && 2 == num_O && 2 == num_OH + num_OM + num_X && 0 == num_other)
# # # # ]
2584 : : {
2585 [ # # ]: 0 : for (i2 = 0; i2 < num_OM; i2++)
2586 : : {
2587 : 0 : i1 = iN[i2];
2588 : : /* fix bond i1 */
2589 : 0 : iedge = pBNS->vert[i].iedge[i1];
2590 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2591 : 0 : num_changes++;
2592 : : }
2593 : : }
2594 : : }
2595 : :
2596 [ + + + - ]: 619 : else if (!a->charge && !a->radical &&
2597 [ - + - - ]: 612 : 6 <= a->chem_bonds_valence + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2598 : 0 : 0 == num_of_H( at, i ) &&
2599 [ # # ]: 0 : 6 == nNoMetalBondsValence( at, i ) + NUMH( a, 0 ) - get_el_valence( a->el_number, 0, 0 ) &&
2600 [ # # # # : 0 : a->el_number != EL_NUMBER_O && ion_el_group( a->el_number ) == EL_NUMBER_O &&
# # ]
2601 : 0 : 5 == nNoMetalNumBonds( at, i ))
2602 : : {
2603 : : /* Found S(VIII), no H, three double bonds or two triple bond */
2604 : : /*
2605 : :
2606 : : O
2607 : : ||
2608 : : in O=S--Y-- (X, Y -- non-terminal) fix single bond S-X, S-Y (type 4)
2609 : : //\
2610 : : O X--
2611 : :
2612 : : note: this structure is a mistakenly drawn structure
2613 : :
2614 : : O O
2615 : : || ||
2616 : : O=S--O--Y-- or O=S--Y--
2617 : : \ \
2618 : : X-- O--X--
2619 : :
2620 : :
2621 : : */
2622 : : int iN[5]; /* indexes of non-terminal neighbors connected by a single bond */
2623 : 0 : num_N = 0; /* number of non-metal neighbors connected by a double bond */
2624 : 0 : num_OH = 0; /* number of neighbors OH connected by a single bond */
2625 : 0 : num_OM = 0; /* number of non-terminal neighbors connected by a single bond */
2626 : 0 : num_O = 0; /* number of neighbors =O connected by a double bond */
2627 : 0 : num_X = 0; /* number of terminal atom X != O connected by a single bond */
2628 : 0 : num_other = 0;
2629 [ # # ]: 0 : for (i1 = 0; i1 < a->valence; i1++)
2630 : : {
2631 : 0 : n1 = (int) a->neighbor[i1];
2632 [ # # ]: 0 : if (is_el_a_metal( at[n1].el_number ))
2633 : : {
2634 : 0 : continue;
2635 : : }
2636 : 0 : bond_type = ( a->bond_type[i1] & BOND_TYPE_MASK );
2637 [ # # ]: 0 : if (BOND_TYPE_DOUBLE == bond_type)
2638 : : {
2639 : 0 : num_N++;
2640 [ # # ]: 0 : if (( 0 == at[n1].charge
2641 : : #if ( S_VI_O_PLUS_METAL_FIX_BOND == 1 )
2642 [ # # # # ]: 0 : || (1 == at[n1].charge && 2 == at[n1].valence) /* djb-rwth: addressing LLVM warning */
2643 : : #endif
2644 : : )
2645 [ # # # # ]: 0 : && 0 == at[n1].radical &&
2646 [ # # ]: 0 : 0 == num_of_H( at, n1 ) &&
2647 [ # # ]: 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2648 : 0 : 1 == nNoMetalNumBonds( at, n1 ))
2649 : : {
2650 : 0 : num_O++;
2651 : : }
2652 : : }
2653 [ # # # # ]: 0 : else if (BOND_TYPE_SINGLE == bond_type &&
2654 [ # # ]: 0 : 1 == nNoMetalNumBonds( at, n1 ) &&
2655 [ # # ]: 0 : ion_el_group( at[n1].el_number ) == EL_NUMBER_O &&
2656 : 0 : 1 >= num_of_H( at, n1 ) &&
2657 [ # # # # ]: 0 : 1 == ( ( 0 == at[n1].charge ) && 1 == num_of_H( at, n1 ) )
2658 [ # # # # : 0 : + ( ( -1 == at[n1].charge ) && 0 == num_of_H( at, n1 ) ))
# # ]
2659 : : {
2660 : 0 : num_OH++; /* -OH or -O(-) */
2661 : : }
2662 : : else
2663 : : {
2664 [ # # # # ]: 0 : if (BOND_TYPE_SINGLE == bond_type &&
2665 : 0 : 1 < nNoMetalNumBonds( at, n1 ))
2666 : : {
2667 : :
2668 : 0 : iN[num_OM++] = i1; /* non-terminal neighbor connected by a single bond */
2669 : : }
2670 : : else
2671 : : {
2672 [ # # # # ]: 0 : if (BOND_TYPE_SINGLE == bond_type && 1 == nNoMetalNumBonds( at, n1 ))
2673 : : {
2674 : :
2675 : 0 : num_X++; /* other terminal neighbor connected by a single bond */
2676 : : }
2677 : : else
2678 : : {
2679 : 0 : num_other++;
2680 : : }
2681 : : }
2682 : : }
2683 : : }
2684 [ # # # # : 0 : if (num_N == num_O && 3 == num_O && 2 == num_OH + num_OM + num_X && 0 == num_other)
# # # # ]
2685 : : {
2686 [ # # ]: 0 : for (i2 = 0; i2 < num_OM; i2++)
2687 : : {
2688 : 0 : i1 = iN[i2];
2689 : : /* fix bond i1 */
2690 : 0 : iedge = pBNS->vert[i].iedge[i1];
2691 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2692 : 0 : num_changes++;
2693 : : }
2694 : : }
2695 : : }
2696 : :
2697 : : } /* for (i = */
2698 : :
2699 : 69 : return num_changes;
2700 : : }
2701 : :
2702 : :
2703 : : /****************************************************************************/
2704 : 0 : int fix_explicitly_indicated_bonds( int nebend,
2705 : : int *ebend,
2706 : : BN_STRUCT *pBNS,
2707 : : inp_ATOM *at,
2708 : : int num_atoms )
2709 : : {
2710 : 0 : int i, num_changes = 0;
2711 : : inp_ATOM *a;
2712 : 0 : int j, ia1, ia2, i1 = -1, i2 = -1, index = -1, neigh;
2713 : : BNS_IEDGE iedge;
2714 : 0 : S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;
2715 : 0 : pBNS->edge_forbidden_mask |= edge_forbidden_mask;
2716 : :
2717 [ # # # # ]: 0 : if (nebend < 1 || !ebend)
2718 : : {
2719 : 0 : return 0;
2720 : : }
2721 : :
2722 [ # # ]: 0 : for (j = 0; j < nebend; j += 2)
2723 : : {
2724 : :
2725 : 0 : ia1 = ebend[2 * j];
2726 : 0 : ia2 = ebend[2 * j + 1];
2727 : :
2728 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
2729 : : {
2730 [ # # ]: 0 : if (at[i].orig_at_number == ia1)
2731 : : {
2732 : 0 : i1 = i;
2733 : : }
2734 [ # # ]: 0 : else if (at[i].orig_at_number == ia2)
2735 : : {
2736 : 0 : i2 = i;
2737 : : }
2738 [ # # # # ]: 0 : if (i1 > 0 && i2 > 0)
2739 : : {
2740 : 0 : break;
2741 : : }
2742 : : }
2743 : :
2744 [ # # # # ]: 0 : if (i1 < 0 || i2 < 0)
2745 : : {
2746 : 0 : return 0;
2747 : : }
2748 : :
2749 [ # # ]: 0 : if (i2 < i1)
2750 : : {
2751 : 0 : int tmp = i1; i1 = i2; i2 = tmp;
2752 : : }
2753 : :
2754 : 0 : a = at + i1;
2755 [ # # ]: 0 : for (i = 0; i < a->valence; i++)
2756 : : {
2757 : 0 : neigh = (int) a->neighbor[i];
2758 [ # # ]: 0 : if (neigh == i2)
2759 : : {
2760 : 0 : index = i; break;
2761 : : }
2762 : : }
2763 [ # # ]: 0 : if (index > -1)
2764 : : {
2765 : 0 : iedge = pBNS->vert[i].iedge[index];
2766 : 0 : pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
2767 : 0 : num_changes++;
2768 : : }
2769 : : }
2770 : :
2771 : 0 : return num_changes;
2772 : : }
2773 : :
2774 : :
2775 : :
2776 : :
2777 : : #define ALL_NONMETAL_Z 0
2778 : :
2779 : :
2780 : : /****************************************************************************/
2781 : 2173 : int is_Z_atom( U_CHAR el_number )
2782 : : {
2783 [ + + ]: 2173 : switch ( el_number )
2784 : : {
2785 : 2032 : case EL_NUMBER_C: /* fallthrough */
2786 : : case EL_NUMBER_N:
2787 : : case EL_NUMBER_P:
2788 : : case EL_NUMBER_AS:
2789 : : case EL_NUMBER_SB:
2790 : : case EL_NUMBER_S:
2791 : : case EL_NUMBER_SE:
2792 : : case EL_NUMBER_TE:
2793 : : case EL_NUMBER_CL:
2794 : : case EL_NUMBER_BR:
2795 : : case EL_NUMBER_I:
2796 : : #if ( ALL_NONMETAL_Z == 1 )
2797 : : case EL_NUMBER_B:
2798 : : case EL_NUMBER_O:
2799 : : case EL_NUMBER_SI:
2800 : : case EL_NUMBER_GE:
2801 : : case EL_NUMBER_F:
2802 : : case EL_NUMBER_AT:
2803 : : #endif
2804 : 2032 : return 1;
2805 : 141 : default:
2806 : 141 : return 0;
2807 : : }
2808 : : }
2809 : :
2810 : :
2811 : : /****************************************************************************
2812 : : Detect O==Z--X, O=O,S,Se,Te
2813 : : ****************************************************************************/
2814 : 0 : int IsZOX( inp_ATOM *atom, int at_x, int ord )
2815 : : {
2816 : 0 : inp_ATOM *at_Z = atom + atom[at_x].neighbor[ord];
2817 : :
2818 : : int i, neigh, num_O;
2819 : :
2820 [ # # ]: 0 : for (i = 0, num_O = 0; i < at_Z->valence; i++)
2821 : : {
2822 : 0 : neigh = at_Z->neighbor[i];
2823 [ # # ]: 0 : if (neigh == at_x)
2824 : : {
2825 : 0 : continue;
2826 : : }
2827 [ # # ]: 0 : if (atom[neigh].valence == 1 &&
2828 [ # # ]: 0 : atom[neigh].chem_bonds_valence == 2 &&
2829 [ # # ]: 0 : atom[neigh].charge == 0 &&
2830 [ # # ]: 0 : atom[neigh].radical == 0 &&
2831 [ # # ]: 0 : ( atom[neigh].el_number == EL_NUMBER_O ||
2832 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_S ||
2833 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_SE ||
2834 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_TE ))
2835 : : {
2836 : 0 : num_O++;
2837 : : }
2838 : : }
2839 : :
2840 : 0 : return num_O;
2841 : : }
2842 : :
2843 : : #if ( FIX_RENUM_BUG_FOR_CASE_OF_ACIDIC_OH_AT_P_PLUS == 1 )
2844 : : void update_some_attype_totals(int nAtTypeTotals[], int mask, int delta, S_CHAR at_charge);
2845 : : /****************************************************************************/
2846 : 0 : void update_some_attype_totals(int nAtTypeTotals[], int mask, int delta, S_CHAR at_charge)
2847 : : {
2848 : : int i;
2849 : : int32_t bit; /* djb-rwth: fixing coverity ID #499534 */
2850 [ # # ]: 0 : if (nAtTypeTotals)
2851 : : {
2852 [ # # # # ]: 0 : if (mask && !(mask & (ATBIT_Errors)))
2853 : : {
2854 [ # # ]: 0 : for (i = 0, bit = 1; i < ATTOT_ARRAY_LEN; i++, bit <<= 1)
2855 : : {
2856 [ # # ]: 0 : if (bit & mask)
2857 : : {
2858 : 0 : nAtTypeTotals[i] += delta;
2859 : : }
2860 : : }
2861 : : }
2862 : : /* Count charges */
2863 [ # # ]: 0 : if (at_charge)
2864 : : {
2865 : 0 : nAtTypeTotals[ATTOT_TOT_CHARGE] += delta * at_charge;
2866 : 0 : nAtTypeTotals[ATTOT_NUM_CHARGES] += delta;
2867 : : }
2868 : : }
2869 : 0 : return;
2870 : : }
2871 : : #endif
2872 : : /****************************************************************************/
2873 : 1165 : int GetAtomChargeType( inp_ATOM *atom,
2874 : : int at_no,
2875 : : int nAtTypeTotals[],
2876 : : int *pMask,
2877 : : int bSubtract )
2878 : : {
2879 : :
2880 : 1165 : inp_ATOM *at = atom + at_no;
2881 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2882 [ + + ]: 1165 : int i, neigh, mask, type, num_z, num_m, num_o, delta = bSubtract > 0 ? -1 : 1; /* 0 or -2 => add, 1 or 2 => subtract */
2883 : : int32_t bit; /* djb-rwth: fixing coverity ID #499579 */
2884 [ + + + - ]: 1165 : int bNoAdjIon = ( bSubtract == 0 || bSubtract == 1 );
2885 : : #else
2886 : : int i, neigh, mask, bit, type, num_z, num_m, num_o, delta = bSubtract ? -1 : 1;
2887 : : #endif
2888 : 1165 : int bUnsatNHasTerminalO = 0;
2889 : :
2890 : 1165 : type = ATT_NONE;
2891 : 1165 : mask = 0;
2892 : :
2893 [ - + - - ]: 1165 : if (at->radical && at->radical != RADICAL_SINGLET)
2894 : : {
2895 : 0 : goto exit_function;
2896 : : }
2897 : :
2898 [ + + ]: 1165 : if (is_el_a_metal( at->el_number ))
2899 : : {
2900 : 8 : goto exit_function;
2901 : : }
2902 [ + - - + ]: 1157 : if (at->charge < -1 || at->charge > 1)
2903 : : {
2904 : 0 : goto exit_function;
2905 : : }
2906 : :
2907 [ + + - + : 1157 : if (!at->valence && at->charge == 1 && !at->num_H && !at->radical && at->el_number == EL_NUMBER_H)
- - - - -
- ]
2908 : : {
2909 : : /* a proton H+ (#1) */
2910 : 0 : type = ATT_PROTON;
2911 : 0 : mask = ATBIT_Proton;
2912 : 0 : goto count_mask_bits;
2913 : : }
2914 : :
2915 [ + + + + ]: 1157 : if ( !at->valence && at->charge == -1 &&
2916 [ + - + - ]: 12 : !at->num_H && !at->radical &&
2917 [ - + - - ]: 12 : ( at->el_number == EL_NUMBER_F || at->el_number == EL_NUMBER_CL ||
2918 [ # # # # ]: 0 : at->el_number == EL_NUMBER_BR || at->el_number == EL_NUMBER_I )
2919 : : )
2920 : : {
2921 : : /* a halogen anion Hal- (#2) */
2922 : 12 : type = ATT_HalAnion;
2923 : 12 : mask = ATBIT_HalAnion;
2924 : 12 : goto count_mask_bits;
2925 : : }
2926 : : #if ( HAL_ACID_H_XCHG == 1 )
2927 : : /* halogen/chalcogen acid */
2928 [ + + + - : 1145 : if ((!at->valence && at->charge == 0 && 1 == at->num_H && !at->radical &&
+ - + - ]
2929 [ - + ]: 6 : ( at->el_number == EL_NUMBER_F ||
2930 [ # # ]: 0 : at->el_number == EL_NUMBER_CL ||
2931 [ # # ]: 0 : at->el_number == EL_NUMBER_BR ||
2932 [ # # ]: 0 : at->el_number == EL_NUMBER_I )) ||
2933 [ - + - - : 1139 : (!at->valence && at->charge == 0 && 2 == at->num_H && !at->radical &&
- - - - ]
2934 [ # # ]: 0 : ( at->el_number == EL_NUMBER_O ||
2935 [ # # ]: 0 : at->el_number == EL_NUMBER_S ||
2936 [ # # ]: 0 : at->el_number == EL_NUMBER_SE ||
2937 [ # # ]: 0 : at->el_number == EL_NUMBER_TE )) /* djb-rwth: addressing LLVM warning */
2938 : : )
2939 : : {
2940 : : /* a halogen/chalcogen acid (#3) */
2941 : 6 : type = ATT_HalAcid;
2942 : 6 : mask = ATBIT_HalAcid;
2943 : 6 : goto count_mask_bits;
2944 : : }
2945 : : #endif
2946 : :
2947 [ + + ]: 1139 : if (detect_unusual_el_valence( at->el_number, at->charge, at->radical,
2948 : 1139 : at->chem_bonds_valence, at->num_H, at->valence ))
2949 : : {
2950 : 4 : goto exit_function; /* unusual valence state */
2951 : : }
2952 : :
2953 : : /* Check neighbors */
2954 [ + + ]: 3308 : for (i = 0, num_z = 0, num_m = 0, num_o = 0; i < at->valence; i++)
2955 : : {
2956 : 2173 : neigh = at->neighbor[i];
2957 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2958 [ + - - + ]: 2173 : if (atom[neigh].charge < -1 || atom[neigh].charge > 1)
2959 : : {
2960 : 0 : goto exit_function; /* neighboring charge */
2961 : : }
2962 [ + + - + ]: 2173 : if (atom[neigh].charge && at->charge)
2963 : : {
2964 [ # # ]: 0 : if (bNoAdjIon)
2965 : : {
2966 : : #if ( FIX_RENUM_BUG_FOR_CASE_OF_ACIDIC_OH_AT_P_PLUS == 1 )
2967 : 0 : goto count_mask_bits;
2968 : : /*update_some_attype_totals(nAtTypeTotals, mask, delta, at->charge);*/
2969 : : #endif
2970 : : goto exit_function; /* neighboring charge */
2971 : : }
2972 : 0 : type = ATT_NONE;
2973 : 0 : mask = 0;
2974 : 0 : goto count_mask_bits;
2975 : : }
2976 : : #else
2977 : : if (atom[neigh].charge < -1 || atom[neigh].charge > 1 || atom[neigh].charge && at->charge)
2978 : : {
2979 : : goto exit_function; /* neighboring charge */
2980 : : }
2981 : : #endif
2982 [ - + ]: 2173 : if (detect_unusual_el_valence( atom[neigh].el_number, atom[neigh].charge, atom[neigh].radical,
2983 : 2173 : atom[neigh].chem_bonds_valence, atom[neigh].num_H,
2984 : 2173 : atom[neigh].valence ))
2985 : : {
2986 : : /* neighbor in unusual valence state */
2987 : 0 : goto exit_function;
2988 : : }
2989 [ + + ]: 2173 : if (is_Z_atom( atom[neigh].el_number ))
2990 : : {
2991 : 2032 : num_z++;
2992 : : }
2993 [ + + ]: 2173 : if (is_el_a_metal( atom[neigh].el_number ))
2994 : : {
2995 : 19 : num_m++;
2996 : : }
2997 : 2173 : num_o += ( atom[neigh].el_number == EL_NUMBER_O );
2998 [ + + - + : 2173 : if (at->el_number == EL_NUMBER_N && at->valence == 2 && !at->charge &&
- - ]
2999 : : /*at->valence < at->chem_bonds_valence &&*/
3000 [ # # # # ]: 0 : atom[neigh].valence == 1 && atom[neigh].chem_bonds_valence == 2 &&
3001 [ # # ]: 0 : ( atom[neigh].el_number == EL_NUMBER_O ||
3002 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_S ||
3003 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_SE ||
3004 [ # # ]: 0 : atom[neigh].el_number == EL_NUMBER_TE ))
3005 : : {
3006 : 0 : bUnsatNHasTerminalO++;
3007 : : }
3008 : : } /* eof check neighbors */
3009 : :
3010 : : /* O, S, Se, Te */
3011 [ + + ]: 1135 : if ( at->el_number == EL_NUMBER_O ||
3012 [ + - ]: 1012 : at->el_number == EL_NUMBER_S ||
3013 [ + - ]: 1012 : at->el_number == EL_NUMBER_SE ||
3014 [ - + ]: 1012 : at->el_number == EL_NUMBER_TE )
3015 : : {
3016 [ - + ]: 123 : if (at->charge == 1)
3017 : : {
3018 [ # # ]: 0 : if (at->num_H)
3019 : : {
3020 : : /* #4 */
3021 : 0 : type = ATT_O_PLUS;
3022 : 0 : mask |= ATBIT_OH_Plus;
3023 : : }
3024 : : else
3025 : : {
3026 : : /* #5 */
3027 : 0 : type = ATT_O_PLUS;
3028 : 0 : mask |= ATBIT_O_Plus;
3029 : : }
3030 : : }
3031 : : else
3032 : : {
3033 : : /* at->charge != 1 */
3034 [ - + ]: 123 : if (at->valence > 1)
3035 : : {
3036 : 0 : goto exit_function; /* not a terminal atom #C1 */
3037 : : }
3038 : : else
3039 : : {
3040 [ + - + + : 123 : if (at->valence && !( num_z || num_o ))
+ - ]
3041 : : {
3042 [ + - ]: 1 : if (num_m == at->valence)
3043 : : {
3044 : 1 : goto exit_function; /* #C2 */
3045 : : }
3046 : 0 : goto count_mask_bits; /* #C3 count charges, no donor or acceptor found */
3047 : : }
3048 : : else
3049 : : {
3050 : : /* Here at->neigh[0] is one of: O, or Z={C, N, P, As, Sb, S, Se, Te, Cl, Br, I} */
3051 [ + - ]: 122 : if (at->valence)
3052 : : {
3053 : 122 : neigh = at->neighbor[0]; /* Z or O only */
3054 [ + - + - ]: 122 : if (!atom[neigh].charge && atom[neigh].el_number == EL_NUMBER_C &&
3055 [ - + ]: 122 : atom[neigh].chem_bonds_valence > atom[neigh].valence)
3056 : : {
3057 : : /* =C-OH, #C-OH, =C-O(-), #C-O(-), -C=O, =C=O; O = O, S, Se, Te */
3058 : 0 : type = ATT_ACIDIC_CO;
3059 [ # # ]: 0 : if (at->num_H == 1)
3060 : : {
3061 : 0 : mask |= ( ATBIT_COH ); /* #6: =C-OH, #C-OH; O=O,S,Se,Te */
3062 : : /*nAtTypeTotals[ATTOT_NUM_COH] ++;*/
3063 : : }
3064 : : else
3065 : : {
3066 [ # # ]: 0 : if (at->charge == -1)
3067 : : {
3068 : 0 : mask |= ( ATBIT_CO_Minus ); /* #7: =C-O(-), #C-O(-); O=O,S,Se,Te */
3069 : : /*nAtTypeTotals[ATTOT_NUM_CO_Minus] ++;*/
3070 : : }
3071 : : else
3072 : : {
3073 [ # # # # ]: 0 : if (!at->num_H && !at->charge)
3074 : : {
3075 : 0 : mask |= ( ATBIT_CO ); /* #8 -C=O, =C=O; O=O,S,Se,Te */
3076 : : /*nAtTypeTotals[ATTOT_NUM_CO] ++;*/
3077 : : }
3078 : : else
3079 : : {
3080 : 0 : mask |= ( ATBIT_Errors );
3081 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3082 : : }
3083 : : }
3084 : : }
3085 : : }
3086 : : else
3087 : : {
3088 [ + - ]: 122 : if (!atom[neigh].charge &&
3089 [ + - ]: 122 : ( atom[neigh].el_number == EL_NUMBER_O ||
3090 [ + - ]: 122 : atom[neigh].el_number == EL_NUMBER_S ||
3091 [ + - ]: 122 : atom[neigh].el_number == EL_NUMBER_SE ||
3092 [ - + ]: 122 : atom[neigh].el_number == EL_NUMBER_TE ) &&
3093 [ # # ]: 0 : atom[neigh].chem_bonds_valence == atom[neigh].valence)
3094 : : {
3095 : : /* -O-OH, -O-O(-); O = O, S, Se, Te */
3096 : 0 : type = ATT_OO;
3097 [ # # ]: 0 : if (at->num_H == 1)
3098 : : {
3099 : 0 : mask |= ( ATBIT_OOH ); /* #9 -O-OH */
3100 : : /*nAtTypeTotals[ATTOT_NUM_OOH] ++;*/
3101 : : }
3102 : : else
3103 : : {
3104 [ # # ]: 0 : if (at->charge == -1)
3105 : : {
3106 : 0 : mask |= ( ATBIT_OO_Minus ); /* #10 -O-O(-) */
3107 : : /*nAtTypeTotals[ATTOT_NUM_OO_Minus] ++;*/
3108 : : }
3109 : : else
3110 : : {
3111 : 0 : mask |= ( ATBIT_Errors );
3112 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3113 : : }
3114 : : }
3115 : : }
3116 : : else
3117 : : {
3118 [ + - ]: 122 : if (!atom[neigh].charge &&
3119 [ + - ]: 122 : atom[neigh].chem_bonds_valence == atom[neigh].valence &&
3120 [ + - ]: 122 : atom[neigh].el_number == EL_NUMBER_C &&
3121 [ - + ]: 122 : at->el_number != EL_NUMBER_O)
3122 : : {
3123 : : /* >C-S(-), >C-SH; S = S, Se, Te */
3124 : 0 : type = ATT_ACIDIC_S;
3125 [ # # ]: 0 : if (at->num_H == 1)
3126 : : {
3127 : 0 : mask |= ( ATBIT_CSH ); /* #11: >C-SH, >CH-SH, -CH2-SH; S = S, Se, Te */
3128 : : /*nAtTypeTotals[ATTOT_NUM_CSH] ++;*/
3129 : : }
3130 : : else
3131 : : {
3132 [ # # ]: 0 : if (at->charge == -1)
3133 : : {
3134 : 0 : mask |= ( ATBIT_CS_Minus ); /* #12: >C-S(-), >CH-S(-), -CH2-S(-); S = S, Se, Te */
3135 : : /*nAtTypeTotals[ATTOT_NUM_CS_Minus] ++;*/
3136 : : }
3137 : : else
3138 : : {
3139 : 0 : mask |= ( ATBIT_Errors );
3140 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3141 : : }
3142 : : }
3143 : : }
3144 : : else
3145 : : {
3146 [ - + ]: 122 : if (atom[neigh].el_number == EL_NUMBER_N &&
3147 [ # # ]: 0 : atom[neigh].valence == 2 &&
3148 [ # # # # : 0 : ( !atom[neigh].num_H || (atom[neigh].num_H == 1 && atom[neigh].charge == 1) )) /* djb-rwth: addressing LLVM warning */
# # ]
3149 : : {
3150 : : /* N or N(-) or NH(+) neighbor */
3151 : 0 : type = ATT_NO; /* single bond only */
3152 [ # # ]: 0 : if (at->num_H == 1)
3153 : : {
3154 : 0 : mask |= ( ATBIT_NOH ); /* #13: =N-OH, =NH(+)-OH, #N(+)-OH, -N(-)-OH; O = O, S, Se, Te */
3155 : : /*nAtTypeTotals[ATTOT_NUM_NOH] ++;*/
3156 : : }
3157 : : else
3158 : : {
3159 [ # # ]: 0 : if (at->charge == -1)
3160 : : {
3161 : 0 : mask |= ( ATBIT_NO_Minus ); /* #14: =N-O(-); O = O, S, Se, Te */
3162 : : /*nAtTypeTotals[ATTOT_NUM_NO_Minus] ++;*/
3163 : : }
3164 : : else
3165 : : {
3166 [ # # # # ]: 0 : if (atom[neigh].charge == 1 || atom[neigh].charge == 0)
3167 : : {
3168 : 0 : mask |= ( ATBIT_NO ); /* #15: =N(+)=O, -NH(+)=O -N=O */
3169 : : /*nAtTypeTotals[ATTOT_NUM_NO] ++;*/
3170 : : }
3171 : : else
3172 : : {
3173 : 0 : mask |= ( ATBIT_Errors );
3174 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3175 : : }
3176 : : }
3177 : : }
3178 : : }
3179 : : else
3180 : : {
3181 [ - + ]: 122 : if (atom[neigh].el_number == EL_NUMBER_N)
3182 : : {
3183 : 0 : type = ATT_N_O; /* #16: single bond only */
3184 [ # # ]: 0 : if (at->num_H == 1)
3185 : : {
3186 : 0 : mask |= ( ATBIT_N_OH ); /* #16: -NH-OH, >N-OH or >N(+)<OH; O = O, S, Se, Te */
3187 : : /*nAtTypeTotals[ATTOT_NUM_NOH] ++;*/
3188 : : }
3189 : : else
3190 : : {
3191 [ # # ]: 0 : if (at->charge == -1)
3192 : : {
3193 : 0 : mask |= ( ATBIT_N_O_Minus ); /* #17: -NH-O(-), >N-O(-); O = O, S, Se, Te */
3194 : : /*nAtTypeTotals[ATTOT_NUM_NO_Minus] ++;*/
3195 : : }
3196 : : else
3197 : : {
3198 [ # # ]: 0 : if (atom[neigh].charge == 1)
3199 : : {
3200 : 0 : mask |= ( ATBIT_N_O ); /* #18: >N(+)=O */
3201 : : /*nAtTypeTotals[ATTOT_NUM_NO] ++;*/
3202 : : }
3203 : : else
3204 : : {
3205 : 0 : mask |= ( ATBIT_Errors );
3206 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3207 : : }
3208 : : }
3209 : : }
3210 : : }
3211 : : else
3212 : : {
3213 [ - + ]: 122 : if ( atom[neigh].el_number != EL_NUMBER_C &&
3214 [ # # # # ]: 0 : atom[neigh].el_number != EL_NUMBER_O &&
3215 : 0 : !is_el_a_metal( atom[neigh].el_number ) &&
3216 [ # # ]: 0 : atom[neigh].chem_bonds_valence > atom[neigh].valence)
3217 : : {
3218 : : /* =Z-OH, #Z-OH, =Z-O(-), #Z-O(-), -Z=O, =Z=O;
3219 : : =Z(+)-OH, #Z(+)-OH, =Z-O(-), #Z-O(-), -Z(+)=O, =Z(+)=O; O = O, S, Se, Te */
3220 : : /* neigh = Z\{N,C} = P, As, Sb, S, Se, Te, Cl, Br, I */
3221 [ # # # # ]: 0 : if (at->chem_bonds_valence == 1 && IsZOX( atom, at_no, 0 ))
3222 : : {
3223 : 0 : type = ATT_ZOO;
3224 [ # # ]: 0 : if (at->num_H == 1)
3225 : : {
3226 : 0 : mask |= ( ATBIT_ZOOH ); /* 18: O=Z-OH; O=O,S,Se,Te; Z may have charge */
3227 : : /*nAtTypeTotals[ATTOT_NUM_ZOOH] ++;*/
3228 : : }
3229 : : else
3230 : : {
3231 [ # # ]: 0 : if (at->charge == -1)
3232 : : {
3233 : 0 : mask |= ( ATBIT_ZOO_Minus ); /* 19: O=Z-O(-); O = O, S, Se, Te */
3234 : : /*nAtTypeTotals[ATTOT_NUM_ZOO_Minus] ++;*/
3235 : : }
3236 : : else
3237 : : {
3238 : 0 : mask |= ( ATBIT_Errors );
3239 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3240 : : }
3241 : : }
3242 : : }
3243 : : else
3244 : : {
3245 : 0 : type = ATT_OTHER_ZO;
3246 [ # # ]: 0 : if (at->num_H == 1)
3247 : : {
3248 : 0 : mask |= ( ATBIT_ZOH ); /* 20: =Z-OH, #Z-OH; O=O,S,Se,Te; Z may have charge */
3249 : : /*nAtTypeTotals[ATTOT_NUM_ZOH] ++;*/
3250 : : }
3251 : : else
3252 : : {
3253 [ # # ]: 0 : if (at->charge == -1)
3254 : : {
3255 : 0 : mask |= ( ATBIT_ZO_Minus ); /* 21: =Z-O(-), #Z-O(-); O = O, S, Se, Te */
3256 : : /*nAtTypeTotals[ATTOT_NUM_ZO_Minus] ++;*/
3257 : : }
3258 : : else
3259 : : {
3260 [ # # ]: 0 : if (at->num_H == 0)
3261 : : {
3262 : 0 : mask |= ( ATBIT_ZO ); /* 22: -Z=O, =Z=O; O=O,S,Se,Te; Z may have charge */
3263 : : /*nAtTypeTotals[ATTOT_NUM_ZO] ++;*/
3264 : : }
3265 : : else
3266 : : {
3267 : 0 : mask |= ( ATBIT_Errors );
3268 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3269 : : }
3270 : : }
3271 : : }
3272 : : }
3273 : : }
3274 : : else
3275 : : {
3276 [ - + - - ]: 122 : if (at->charge == -1 && !is_el_a_metal( atom[neigh].el_number ))
3277 : : {
3278 : : /* >Z-O(-); O=O,S,Se,Te */
3279 : 0 : type = ATT_OTHER_NEG_O;
3280 : 0 : mask |= ( ATBIT_O_Minus ); /* 23: -Z-O(-); O=O,S,Se,Te */
3281 : : /*nAtTypeTotals[ATTOT_NUM_ZO_Minus] ++;*/
3282 : : }
3283 : : }
3284 : : }
3285 : : }
3286 : : }
3287 : : }
3288 : : }
3289 : : }
3290 : :
3291 : : else
3292 : : {
3293 [ # # # # ]: 0 : if (at->charge == -1 && at->num_H == 1)
3294 : : {
3295 : 0 : type = ATT_OH_MINUS;
3296 : 0 : mask |= ( ATBIT_O_Minus ); /* 25: HO(-); O=O,S,Se,Te */
3297 : : }
3298 : : }
3299 : : }
3300 : : }
3301 : : }
3302 : : }
3303 : :
3304 : : else
3305 : : {
3306 : : /* P, N, neutral valence = 3 (not 5) */
3307 [ + + ]: 1012 : if (( at->el_number == EL_NUMBER_N ||
3308 [ + - ]: 978 : at->el_number == EL_NUMBER_P ) &&
3309 [ - + - + ]: 34 : 0 <= at->valence && at->valence <= 3 &&
3310 [ - + ]: 34 : at->chem_bonds_valence + at->num_H == 3 + at->charge)
3311 : : {
3312 [ + - - + ]: 34 : if (at->valence && !( num_z /*|| num_o == at->valence*/ ))
3313 : : {
3314 [ # # ]: 0 : if (num_m == at->valence)
3315 : : {
3316 : 0 : goto exit_function;
3317 : : }
3318 : 0 : goto count_mask_bits; /* N(III), N(-)(II), N(+)(IV) and same P that have only oxygen neighbors are ignored here */
3319 : : }
3320 [ + - ]: 34 : type = ( at->el_number == EL_NUMBER_N ) ? ATT_ATOM_N : ATT_ATOM_P;
3321 [ - + - - ]: 34 : switch (at->charge)
3322 : : {
3323 : 0 : case -1:
3324 [ # # ]: 0 : if (at->el_number == EL_NUMBER_N)
3325 : : {
3326 : 0 : mask |= ( ATBIT_N_Minus ); /* 26: -NH(-), =N(-), >N(-) */
3327 [ # # ]: 0 : if (at->num_H)
3328 : : {
3329 : 0 : mask |= ( ATBIT_NP_H ); /* 27: -NH(-) */
3330 : : }
3331 : : #if ( FIX_NP_MINUS_BUG == 1 )
3332 : : else
3333 : : {
3334 [ # # # # : 0 : if (at->valence == 1 && at->chem_bonds_valence >= 2 && ( at->bond_type[0] & BOND_MARK_ALL ))
# # ]
3335 : : {
3336 : 0 : type |= ATT_NP_MINUS_V23; /* =N(-) created by normalization 2010-03-11 DT */
3337 : : }
3338 : : }
3339 : : #endif
3340 : : }
3341 : : /*nAtTypeTotals[ATTOT_NUM_N_Minus] += (at->el_number == EL_NUMBER_N);*/
3342 : 0 : break;
3343 : 34 : case 0:
3344 [ + - ]: 34 : if (at->num_H)
3345 : : {
3346 : 34 : mask |= ( ATBIT_NP_H ); /* 28: -NH2, =NH, >NH */
3347 : : /*nAtTypeTotals[ATTOT_NUM_NP_H] ++;*/
3348 : : }
3349 : : else
3350 : : {
3351 [ # # ]: 0 : if (bUnsatNHasTerminalO == 1)
3352 : : {
3353 : 0 : mask |= ( ATBIT_ON ); /* 29: -N=O,-N=OH(+) only, not =N-OH */
3354 : : }
3355 : : else
3356 : : {
3357 : 0 : mask |= ( ATBIT_NP ); /* 30: -P=O,-P=OH(+), >N- =N- (incl. =N-OH) , #N */
3358 : : /*nAtTypeTotals[ATTOT_NUM_NP] ++;*/
3359 : : }
3360 : : }
3361 : 34 : break; /* ignore neutral N or P */
3362 : 0 : case 1:
3363 [ # # ]: 0 : if (at->num_H)
3364 : : {
3365 : 0 : mask |= ( ATBIT_NP_Proton ); /* 31: NH4(+), -NH3(+), =NH2(+), >NH2(+), =NH(+)-, >NH(+)-, #NH(+) */
3366 : : /*nAtTypeTotals[ATTOT_NUM_NP_Proton] ++;*/
3367 : : }
3368 : : else
3369 : : {
3370 [ # # ]: 0 : if (at->chem_bonds_valence > at->valence)
3371 : : {
3372 : 0 : mask |= ( ATBIT_NP_Plus ); /* =N(+)=, #N(+)-, =N(+)< */
3373 : : /*nAtTypeTotals[ATTOT_NUM_NP_Plus] ++;*/
3374 : : }
3375 : : else
3376 : : {
3377 : 0 : type = 0; /* 32: ignore onium cations >N(+)< */
3378 : : }
3379 : : }
3380 : 0 : break;
3381 : 0 : default:
3382 : 0 : mask |= ( 1 << ATTOT_NUM_Errors );
3383 : : /*nAtTypeTotals[ATTOT_NUM_Errors] ++;*/
3384 : 0 : break;
3385 : : }
3386 : : }
3387 : : }
3388 : :
3389 : 978 : count_mask_bits:
3390 [ + + ]: 1152 : if (nAtTypeTotals)
3391 : : {
3392 [ + + + - ]: 615 : if (mask && !( mask & ( ATBIT_Errors ) ))
3393 : : {
3394 [ + + ]: 884 : for (i = 0, bit = 1; i < ATTOT_ARRAY_LEN; i++, bit <<= 1)
3395 : : {
3396 [ + + ]: 858 : if (bit & mask)
3397 : : {
3398 : 26 : nAtTypeTotals[i] += delta;
3399 : : }
3400 : : }
3401 : : }
3402 : :
3403 : : /* Count charges */
3404 [ + + ]: 615 : if (at->charge)
3405 : : {
3406 : 8 : nAtTypeTotals[ATTOT_TOT_CHARGE] += delta * at->charge;
3407 : 8 : nAtTypeTotals[ATTOT_NUM_CHARGES] += delta;
3408 : : }
3409 : : }
3410 : :
3411 [ - + ]: 1152 : if (pMask)
3412 : : {
3413 : 1152 : *pMask = mask;
3414 : : }
3415 : :
3416 : 0 : exit_function:
3417 [ - + ]: 1165 : if (mask & ( ATBIT_Errors ))
3418 : : {
3419 : 0 : type = 0;
3420 [ # # ]: 0 : if (nAtTypeTotals)
3421 : : {
3422 : 0 : nAtTypeTotals[ATTOT_NUM_Errors] += 1;
3423 : : }
3424 : : }
3425 : :
3426 : :
3427 : 1165 : return type;
3428 : : }
3429 : :
3430 : :
3431 : : /****************************************************************************/
3432 : 0 : int SimpleRemoveHplusNPO( inp_ATOM *at,
3433 : : int num_atoms,
3434 : : int nAtTypeTotals[],
3435 : : T_GROUP_INFO *t_group_info )
3436 : : {
3437 : : int i, mask, type, num_removed;
3438 [ # # ]: 0 : for (i = 0, num_removed = 0; i < num_atoms; i++)
3439 : : {
3440 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3441 [ # # ]: 0 : if (( PR_SIMPLE_TYP & ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ) ) &&
3442 [ # # ]: 0 : ( PR_SIMPLE_MSK & mask ))
3443 : : {
3444 : : #if ( bRELEASE_VERSION == 0 )
3445 : : if (at[i].charge != 1 || at[i].num_H == 0)
3446 : : {
3447 : : return -1; /* program error */
3448 : : }
3449 : : #endif
3450 : 0 : type = GetAtomChargeType(at, i, nAtTypeTotals, &mask, 1); /* subtract at[i] */ /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3451 : 0 : at[i].charge = 0;
3452 : 0 : AddOrRemoveExplOrImplH( -1, at, num_atoms, (AT_NUMB) i, t_group_info );
3453 : : /*at[i].num_H --;*/
3454 : 0 : num_removed++;
3455 : : #if ( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
3456 : 0 : type = GetAtomChargeType(at, i, nAtTypeTotals, &mask, 0); /* add changed at[i] */ /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3457 : : #else
3458 : : type = GetAtomChargeType(at, i, nAtTypeTotals, &mask, 1); /* bug: subtract instead of add */ /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
3459 : : #endif
3460 : : /*
3461 : : if ( nAtTypeTotals ) {
3462 : : nAtTypeTotals[ATTOT_NUM_NP_Proton] --;
3463 : : if ( at[i].num_H ) {
3464 : : nAtTypeTotals[ATTOT_NUM_NP_H] ++;
3465 : : } else {
3466 : : nAtTypeTotals[ATTOT_NUM_NP] ++;
3467 : : }
3468 : : nAtTypeTotals[ATTOT_TOT_CHARGE] --;
3469 : : nAtTypeTotals[ATTOT_NUM_CHARGES] --;
3470 : : }
3471 : : */
3472 : : }
3473 : : }
3474 : :
3475 : 0 : return num_removed;
3476 : : }
3477 : :
3478 : :
3479 : : /****************************************************************************/
3480 : 0 : int bIsAtomTypeHard( inp_ATOM *at,
3481 : : int endpoint,
3482 : : int nType,
3483 : : int nMask,
3484 : : int nCharge )
3485 : : {
3486 : : int mask;
3487 [ # # # # ]: 0 : if (( nType & GetAtomChargeType( at, endpoint, NULL, &mask, 0 ) ) && ( mask & nMask )
3488 : : #if ( OPPOSITE_CHARGE_IN_CGROUP == 0 )
3489 : : && ( at[endpoint].charge == nCharge || !at[endpoint].charge )
3490 : : #endif
3491 : : )
3492 : : {
3493 : 0 : return 1;
3494 : : }
3495 : :
3496 : 0 : return 0;
3497 : : }
3498 : :
3499 : :
3500 : : /****************************************************************************/
3501 : 0 : int bIsHDonorAccAtomType( inp_ATOM *at, int endpoint, int *cSubType )
3502 : : {
3503 [ # # ]: 0 : if (bIsAtomTypeHard( at, endpoint, PR_HARD_TYP_H, PR_HARD_MSK_H, 0 ))
3504 : : {
3505 : : /* Obtain donor/acceptor info */
3506 : 0 : int neutral_valence = at[endpoint].chem_bonds_valence + at[endpoint].num_H - at[endpoint].charge;
3507 [ # # # # ]: 0 : if (neutral_valence != 2 /* O, S, Se, Te */ &&
3508 : : neutral_valence != 3 /* N, P */)
3509 : : {
3510 : 0 : return -1; /* wrong endpoint neutral valence */
3511 : : }
3512 : : else
3513 : : {
3514 : 0 : int edge_flow = at[endpoint].num_H;
3515 : 0 : int num_bonds = at[endpoint].valence;
3516 : 0 : int edge_cap = neutral_valence - num_bonds; /* does not allow to reduce -NH3(+) to #N or -OH(+)- to -O- */
3517 : 0 : edge_flow = inchi_min( edge_flow, edge_cap );
3518 : : /* what this means: */
3519 [ # # ]: 0 : if (edge_cap)
3520 : : {
3521 [ # # ]: 0 : if (edge_cap > edge_flow)
3522 : : {
3523 : 0 : *cSubType |= SALT_ACCEPTOR;
3524 : : }
3525 [ # # ]: 0 : if (edge_flow)
3526 : : {
3527 : 0 : *cSubType |= SALT_DONOR_H;
3528 : : }
3529 : 0 : return 4;
3530 : : }
3531 : : }
3532 : : }
3533 : :
3534 : 0 : return -1;
3535 : : }
3536 : :
3537 : :
3538 : : /****************************************************************************/
3539 : 0 : int bIsNegAtomType( inp_ATOM *at, int endpoint, int *cSubType )
3540 : : {
3541 : 0 : int sub_type = 0;
3542 [ # # ]: 0 : if (bIsAtomTypeHard( at, endpoint, PR_HARD_TYP_NEG, PR_HARD_MSK_NEG, -1 ))
3543 : : {
3544 : : /* Obtain donor/acceptor info */
3545 : 0 : int neutral_valence = at[endpoint].chem_bonds_valence + at[endpoint].num_H - at[endpoint].charge;
3546 [ # # # # ]: 0 : if (neutral_valence != 2 /* O, S, Se, Te */ &&
3547 : : neutral_valence != 3 /* N, P */)
3548 : : {
3549 : 0 : return -1; /* wrong endpoint neutral valence */
3550 : : }
3551 : : else
3552 : : {
3553 : 0 : int edge_flow = ( at[endpoint].charge == -1 );
3554 : 0 : int num_bonds = at[endpoint].valence;
3555 : 0 : int edge_cap = neutral_valence - num_bonds - at[endpoint].num_H; /* does not allow to reduce -NH3(+) to #N or -OH(+)- to -O- */
3556 : 0 : edge_flow = inchi_min( edge_flow, edge_cap );
3557 : : /* what this means: */
3558 [ # # ]: 0 : if (edge_cap)
3559 : : {
3560 [ # # ]: 0 : if (edge_cap > edge_flow)
3561 : : {
3562 : 0 : sub_type |= SALT_ACCEPTOR;
3563 : : }
3564 [ # # ]: 0 : if (edge_flow)
3565 : : {
3566 : 0 : sub_type |= SALT_DONOR_Neg;
3567 : : }
3568 [ # # ]: 0 : if (sub_type)
3569 : : {
3570 : 0 : *cSubType |= sub_type;
3571 : 0 : return 4;
3572 : : }
3573 : : }
3574 : : }
3575 : : }
3576 : :
3577 : 0 : return -1;
3578 : : }
3579 : :
3580 : :
3581 : : /****************************************************************************/
3582 : 0 : int bIsHardRemHCandidate( inp_ATOM *at, int i, int *cSubType )
3583 : : {
3584 : : int ret1, ret2, ret;
3585 : 0 : int sub_type = 0;
3586 : 0 : ret1 = bIsHDonorAccAtomType( at, i, &sub_type );
3587 : 0 : ret2 = bIsNegAtomType( at, i, &sub_type );
3588 : 0 : ret = inchi_max( ret1, ret2 );
3589 [ # # # # ]: 0 : if (ret > 0 && sub_type)
3590 : : {
3591 : 0 : *cSubType |= sub_type;
3592 : 0 : return ret;
3593 : : }
3594 : 0 : return -1;
3595 : : }
3596 : :
3597 : :
3598 : : /****************************************************************************/
3599 : 6 : int CreateCGroupInBnStruct( inp_ATOM *at,
3600 : : int num_atoms,
3601 : : BN_STRUCT *pBNS,
3602 : : int nType,
3603 : : int nMask,
3604 : : int nCharge )
3605 : : {
3606 : 6 : int k, c_point, cg, centerpoint, fictpoint, type, ret = 0;
3607 : 6 : int num_cg = 1;
3608 : 6 : int num_edges = pBNS->num_edges;
3609 : 6 : int num_vertices = pBNS->num_vertices; /* new c-group bns-ID */
3610 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing charge c-group */
3611 : : BNS_VERTEX *vertex_cpoint;
3612 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric c_point */
3613 : : int mask, num_CPoints;
3614 : :
3615 : : /* Debug: check overflow */
3616 [ - + ]: 6 : if (num_vertices + num_cg >= pBNS->max_vertices)
3617 : : {
3618 : 0 : return BNS_VERT_EDGE_OVFL;
3619 : : }
3620 : :
3621 : : /* Count new c-group edges */
3622 [ + + ]: 36 : for (c_point = 0, num_CPoints = 0; c_point < num_atoms; c_point++)
3623 : : {
3624 [ - + - - ]: 30 : if (( nType & GetAtomChargeType( at, c_point, NULL, &mask, 0 ) ) && ( mask & nMask )
3625 : : #if ( OPPOSITE_CHARGE_IN_CGROUP == 0 )
3626 : : && ( at[c_point].charge == nCharge || !at[c_point].charge )
3627 : : #endif
3628 : : )
3629 : : {
3630 : 0 : num_CPoints++;
3631 : : }
3632 : : }
3633 : :
3634 [ + - ]: 6 : if (!num_CPoints)
3635 : : {
3636 : 6 : return 0;
3637 : : }
3638 : :
3639 : : /* Clear the new vertex */
3640 : 0 : memset( pBNS->vert + num_vertices, 0, 1 * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3641 : :
3642 : : /* *old* Make sure the last t-group has the largest t-group ID:
3643 : : this is necessary to correctly add new edges and vertices for testing augmenting paths
3644 : : */
3645 : :
3646 : : /**************************************/
3647 : : /* initialize new fictitious vertex */
3648 : : /* representing c-point group */
3649 : : /**************************************/
3650 : :
3651 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
3652 : :
3653 [ # # ]: 0 : for (cg = 0; cg < num_cg; cg++, ver_ficpont_prev = vert_ficpoint)
3654 : : {
3655 : : /*
3656 : : vert_ficpoint-1 is the last vertex;
3657 : : vert_ficpoint is the being added vertex
3658 : : Note: nGroupNumber are not contiguous
3659 : : */
3660 : 0 : vert_ficpoint = pBNS->vert + num_vertices + cg;
3661 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
3662 : 0 : vert_ficpoint->max_adj_edges = num_CPoints + BNS_ADD_EDGES;
3663 : 0 : vert_ficpoint->num_adj_edges = 0;
3664 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
3665 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
3666 : 0 : vert_ficpoint->type = BNS_VERT_TYPE_C_GROUP | ( ( nCharge < 0 ) ? BNS_VERT_TYPE_C_NEGATIVE : 0 );
3667 : : }
3668 : :
3669 : : /************************************************/
3670 : : /* Connect c-points to the fictitious vertices */
3671 : : /* representing c-point groups; set caps, flows */
3672 : : /************************************************/
3673 : 0 : cg = 1;
3674 [ # # ]: 0 : for (c_point = 0; c_point < num_atoms; c_point++)
3675 : : {
3676 [ # # # # ]: 0 : if (( nType & ( type = GetAtomChargeType( at, c_point, NULL, &mask, 0 ) ) ) && ( mask & nMask )
3677 : : #if ( OPPOSITE_CHARGE_IN_CGROUP == 0 )
3678 : : && ( at[c_point].charge == nCharge || !at[c_point].charge )
3679 : : #endif
3680 : : )
3681 : : {
3682 : : ;
3683 : : }
3684 : : else
3685 : : {
3686 : 0 : continue;
3687 : : }
3688 : :
3689 : 0 : fictpoint = cg + num_vertices - 1; /* c-group vertex index */
3690 : 0 : vert_ficpoint = pBNS->vert + fictpoint; /* c-group vertex */
3691 : 0 : vertex_cpoint = pBNS->vert + c_point; /* c_point vertex */
3692 : :
3693 : : /* Debug: check overflow */
3694 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
3695 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
3696 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
3697 [ # # ]: 0 : vertex_cpoint->num_adj_edges >= vertex_cpoint->max_adj_edges)
3698 : : {
3699 : : /* djb-rwth: removing redundant code */
3700 : : break;
3701 : : }
3702 : 0 : vertex_cpoint->type |= BNS_VERT_TYPE_C_POINT;
3703 [ # # # # ]: 0 : if (( KNOWN_ACIDIC_TYPE & type ) && nCharge < 0)
3704 : : {
3705 : 0 : vertex_cpoint->type |= pBNS->type_TACN;
3706 : : }
3707 : :
3708 : : #if ( FIX_CPOINT_BOND_CAP != 1 ) /* { */
3709 : : /* Set capacity = 1 to the edges from the c_point to the centerpoint(s) */
3710 : : /* if their current capacity is zero */
3711 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
3712 : : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
3713 : : {
3714 : : int iedge = vertex_cpoint->iedge[k];
3715 : : if (!pBNS->edge[iedge].cap)
3716 : : {
3717 : : /* single bond, possibly between c_point and centerpoint */
3718 : : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
3719 : : if (centerpoint < pBNS->num_atoms &&
3720 : : pBNS->vert[centerpoint].st_edge.cap >= 1)
3721 : : {
3722 : : int bond_type = ( at[c_point].bond_type[k] & BOND_TYPE_MASK );
3723 : : if (bond_type == BOND_TAUTOM ||
3724 : : bond_type == BOND_ALTERN ||
3725 : : bond_type == BOND_SINGLE)
3726 : : {
3727 : : pBNS->edge[iedge].cap = 1;
3728 : : }
3729 : : }
3730 : : }
3731 : : }
3732 : : #endif /* } FIX_CPOINT_BOND_CAP */
3733 : :
3734 : : /* Create a new edge connecting c_point to the new fictitious c-group vertex vert_ficpoint */
3735 : 0 : edge = pBNS->edge + num_edges;
3736 : 0 : edge->cap = 1;
3737 : 0 : edge->flow = 0;
3738 : 0 : edge->pass = 0;
3739 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
3740 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask; /* remove previous temporary ban */
3741 : : #endif
3742 : :
3743 : : /* nCharge = +1: mark edge to c-point having no (+)-moveable charge with flow=1 */
3744 : : /* nCharge = -1: mark edge to c-point having -1 moveable charge with flow=1 */
3745 : :
3746 [ # # # # : 0 : if ((nCharge == 1 && at[c_point].charge != 1) || (nCharge == -1 && at[c_point].charge == -1)) /* djb-rwth: addressing LLVM warning */
# # # # ]
3747 : : /*if ( !CHARGED_CPOINT(at,c_point) )*/
3748 : : {
3749 : : /* Increment new edge flow, update st_edges of the adjacent vertices */
3750 : 0 : edge->flow++;
3751 : : /* Increment c-group vertex st-flow & cap */
3752 : 0 : vert_ficpoint->st_edge.flow++;
3753 : 0 : vert_ficpoint->st_edge.cap++;
3754 : : /* Increment c-point vertex st-flow & cap */
3755 : 0 : vertex_cpoint->st_edge.flow++;
3756 : 0 : vertex_cpoint->st_edge.cap++;
3757 : : }
3758 : :
3759 : : #if ( FIX_CPOINT_BOND_CAP == 1 ) /* { */
3760 : : /* Set capacity = 1 to the edges from the c_point to the centerpoint(s) */
3761 : : /* if their current capacity is zero */
3762 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
3763 [ # # ]: 0 : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
3764 : : {
3765 : 0 : int iedge = vertex_cpoint->iedge[k];
3766 : 0 : VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
3767 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
3768 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
3769 : : {
3770 : : /* Single bond, possibly between c_point and centerpoint */
3771 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
3772 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
3773 : : {
3774 : 0 : nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
3775 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
3776 : 0 : pBNS->edge[iedge].cap = nNewCap;
3777 : : }
3778 : : }
3779 : : #if ( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
3780 : : else
3781 : : {
3782 : : if (centerpoint < pBNS->num_atoms &&
3783 : : edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP)
3784 : : {
3785 : : pBNS->edge[iedge].cap++;
3786 : : }
3787 : : }
3788 : : #endif
3789 : : }
3790 : : #endif /* } FIX_CPOINT_BOND_CAP */
3791 : :
3792 : : /* Connect edge to c_point and fictpoint and increment the counters of neighbors and edges */
3793 : 0 : edge->neighbor1 = c_point; /* the smallest out of v1=endopoint and v2=num_vertices */
3794 : 0 : edge->neighbor12 = c_point ^ fictpoint; /* v1 ^ v2 */
3795 : 0 : vertex_cpoint->iedge[vertex_cpoint->num_adj_edges] = num_edges;
3796 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
3797 : 0 : edge->neigh_ord[0] = vertex_cpoint->num_adj_edges++;
3798 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
3799 : 0 : edge->cap0 = edge->cap;
3800 : 0 : edge->flow0 = edge->flow;
3801 : : }
3802 : :
3803 : 0 : ret = pBNS->num_vertices; /* new c-group atom number */
3804 : 0 : pBNS->num_edges = num_edges;
3805 : 0 : pBNS->num_vertices += num_cg;
3806 : 0 : pBNS->num_c_groups += num_cg;
3807 : :
3808 : 0 : return ret;
3809 : : }
3810 : :
3811 : :
3812 : : /****************************************************************************/
3813 : 2 : int CreateTGroupInBnStruct( inp_ATOM *at,
3814 : : int num_atoms,
3815 : : BN_STRUCT *pBNS,
3816 : : int nType,
3817 : : int nMask )
3818 : : {
3819 : 2 : int ret = 0;
3820 : : /* ret = ReInitBnStruct( pBNS ); */
3821 : : int k, endpoint, tg, centerpoint, fictpoint;
3822 : 2 : int num_tg = 1;
3823 : 2 : int num_edges = pBNS->num_edges;
3824 : 2 : int num_vertices = pBNS->num_vertices;
3825 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing t-group */
3826 : : BNS_VERTEX *vert_endpoint;
3827 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
3828 : : int mask, num_endpoints, neutral_valence, edge_flow, edge_cap, num_bonds;
3829 : :
3830 : : /* Debug: check overflow */
3831 [ - + ]: 2 : if (num_vertices + num_tg >= pBNS->max_vertices)
3832 : : {
3833 : 0 : return BNS_VERT_EDGE_OVFL;
3834 : : }
3835 : :
3836 : : /* Count new t-group edges */
3837 [ + + ]: 12 : for (endpoint = 0, num_endpoints = 0; endpoint < num_atoms; endpoint++)
3838 : : {
3839 [ - + - - ]: 10 : if (( nType & GetAtomChargeType( at, endpoint, NULL, &mask, 0 ) ) && ( mask & nMask )
3840 : : )
3841 : : {
3842 : 0 : num_endpoints++;
3843 : : }
3844 : : }
3845 : :
3846 [ + - ]: 2 : if (!num_endpoints)
3847 : : {
3848 : 2 : return 0;
3849 : : }
3850 : :
3851 : : /* Since t-group IDs may be not contiguous, clear all vertices that will be added.
3852 : : all-zeroes-vertex will be ignored by the BNS
3853 : : */
3854 : 0 : memset( pBNS->vert + num_vertices, 0, num_tg * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
3855 : :
3856 : : /* *old* Make sure the last t-group has the largest t-group ID:
3857 : : this is necessary to correctly add new edges and vertices for testing augmenting paths
3858 : : */
3859 : :
3860 : : /**************************************/
3861 : : /* Initialize new fictitious vertex */
3862 : : /* representing t-point group */
3863 : : /**************************************/
3864 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
3865 : :
3866 [ # # ]: 0 : for (tg = 0; tg < num_tg; tg++, ver_ficpont_prev = vert_ficpoint)
3867 : : {
3868 : : /*
3869 : : vert_ficpoint-1 is the last vertex;
3870 : : vert_ficpoint is the vertex that is being added
3871 : : Note: nGroupNumber are not contiguous
3872 : : */
3873 : 0 : vert_ficpoint = pBNS->vert + num_vertices + tg;
3874 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
3875 : 0 : vert_ficpoint->max_adj_edges = num_endpoints + BNS_ADD_EDGES + BNS_ADD_SUPER_TGROUP;
3876 : 0 : vert_ficpoint->num_adj_edges = 0;
3877 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
3878 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
3879 : 0 : vert_ficpoint->type |= BNS_VERT_TYPE_TGROUP;
3880 : : }
3881 : :
3882 : 0 : tg = 1;
3883 [ # # ]: 0 : for (endpoint = 0; endpoint < num_atoms; endpoint++)
3884 : : {
3885 [ # # # # ]: 0 : if (( nType & GetAtomChargeType( at, endpoint, NULL, &mask, 0 ) ) && ( mask & nMask ))
3886 : : {
3887 : : ;
3888 : : }
3889 : : else
3890 : : {
3891 : 0 : continue;
3892 : : }
3893 : 0 : fictpoint = tg + num_vertices - 1;
3894 : 0 : vert_ficpoint = pBNS->vert + fictpoint;
3895 : 0 : vert_endpoint = pBNS->vert + endpoint;
3896 : : /* Debug: check overflow */
3897 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
3898 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
3899 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
3900 [ # # ]: 0 : vert_endpoint->num_adj_edges >= vert_endpoint->max_adj_edges)
3901 : : {
3902 : : /* djb-rwth: removing redundant code */
3903 : : break;
3904 : : }
3905 : :
3906 : : /* Obtain donor/acceptor info */
3907 : 0 : neutral_valence = at[endpoint].chem_bonds_valence + at[endpoint].num_H - at[endpoint].charge;
3908 [ # # # # ]: 0 : if (neutral_valence != 2 /* O, S, Se, Te */ &&
3909 : : neutral_valence != 3 /* N, P */)
3910 : : {
3911 : : /* djb-rwth: removing redundant code */
3912 : 0 : break;
3913 : : }
3914 : 0 : edge_flow = at[endpoint].num_H;
3915 : 0 : num_bonds = at[endpoint].valence;
3916 : 0 : edge_cap = neutral_valence - num_bonds; /* does not allow to reduce -NH3(+) to #N or -OH(+)- to -O- */
3917 : :
3918 [ # # # # ]: 0 : if (3 == neutral_valence /* N or P */ && 1 < num_bonds)
3919 : : {
3920 : 0 : edge_cap++; /* allow -NH2(+)- => -N=, >NH(+)- => >N- */
3921 : : }
3922 : 0 : edge_flow = inchi_min( edge_flow, edge_cap );
3923 : : /*
3924 : : if ( !nGetEndpointInfo( at, endpoint, &eif ) ) {
3925 : : ret = BNS_BOND_ERR;
3926 : : break;
3927 : : }
3928 : : */
3929 : 0 : vert_endpoint->type |= BNS_VERT_TYPE_ENDPOINT;
3930 : :
3931 : : /* Create a new edge connecting endpoint to the new fictitious t-group vertex vert_ficpoint */
3932 : 0 : edge = pBNS->edge + num_edges;
3933 : 0 : edge->cap = edge_cap;
3934 : 0 : edge->flow = edge_flow;
3935 : 0 : edge->pass = 0;
3936 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
3937 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask;
3938 : : #endif
3939 : :
3940 : : /* Adjust st_flow and st_cap of the adjacent vertices */
3941 : : /* Adjust t-group vertex st-flow & cap */
3942 : 0 : vert_ficpoint->st_edge.flow += edge->flow;
3943 : 0 : vert_ficpoint->st_edge.cap += edge->flow;
3944 : : /* adjust endpoint vertex st-flow & cap */
3945 : 0 : vert_endpoint->st_edge.flow += edge->flow;
3946 : 0 : vert_endpoint->st_edge.cap += edge->flow;
3947 : :
3948 : : /* Adjust edge cap & flow according to the number of H and number of bonds */
3949 [ # # ]: 0 : for (k = 0; k < vert_endpoint->num_adj_edges; k++)
3950 : : {
3951 : 0 : int iedge = vert_endpoint->iedge[k];
3952 : 0 : VertexFlow nNewCap = vert_endpoint->st_edge.cap;
3953 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
3954 : : {
3955 : : /* single bond, possibly between endpoint and centerpoint */
3956 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ endpoint );
3957 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
3958 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
3959 : : {
3960 : 0 : nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
3961 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
3962 : 0 : pBNS->edge[iedge].cap = nNewCap;
3963 : : }
3964 : : }
3965 : : }
3966 : :
3967 : : /* Connect edge to endpoint and fictpoint and increment the counters of neighbors and edges */
3968 : 0 : edge->neighbor1 = endpoint; /* the smallest out of v1=endopoint and v2=num_vertices */
3969 : 0 : edge->neighbor12 = endpoint ^ fictpoint; /* v1 ^ v2 */
3970 : 0 : vert_endpoint->iedge[vert_endpoint->num_adj_edges] = num_edges;
3971 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
3972 : 0 : edge->neigh_ord[0] = vert_endpoint->num_adj_edges++;
3973 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
3974 : 0 : edge->cap0 = edge->cap;
3975 : 0 : edge->flow0 = edge->flow;
3976 : : }
3977 : :
3978 : 0 : ret = pBNS->num_vertices; /* new t-group atom number */
3979 : 0 : pBNS->num_edges = num_edges;
3980 : 0 : pBNS->num_vertices += num_tg;
3981 : 0 : pBNS->num_t_groups += num_tg;
3982 : :
3983 : 0 : return ret;
3984 : : }
3985 : :
3986 : :
3987 : : /****************************************************************************/
3988 : 0 : int RemoveLastGroupFromBnStruct( inp_ATOM *at,
3989 : : int num_atoms,
3990 : : int tg,
3991 : : BN_STRUCT *pBNS )
3992 : : {
3993 : 0 : int ret = 0;
3994 : : /* ret = ReInitBnStruct( pBNS ); */
3995 : : int k, endpoint, /*centerpoint, fictpoint,*/ iedge;
3996 : 0 : int num_edges = pBNS->num_edges;
3997 : 0 : int num_vertices = pBNS->num_vertices;
3998 : : BNS_VERTEX *vert_ficpoint /*, *ver_ficpont_prev*/; /* fictitious vertex describing t-group */
3999 : : BNS_VERTEX *vert_endpoint;
4000 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
4001 : : /*int mask, num_endpoints, neutral_valence, edge_flow, edge_cap, num_bonds;*/
4002 : 0 : int is_t_group = 0, is_c_group = 0;
4003 : :
4004 : : /* Debug: check overflow */
4005 [ # # ]: 0 : if (pBNS->num_added_atoms + pBNS->num_c_groups + pBNS->num_t_groups + num_atoms >= pBNS->max_vertices)
4006 : : {
4007 : 0 : return BNS_VERT_EDGE_OVFL;
4008 : : }
4009 : :
4010 [ # # ]: 0 : if (tg + 1 != num_vertices)
4011 : : {
4012 : 0 : return BNS_VERT_EDGE_OVFL;
4013 : : }
4014 : :
4015 : 0 : vert_ficpoint = pBNS->vert + tg;
4016 : :
4017 [ # # ]: 0 : if (vert_ficpoint->type & BNS_VERT_TYPE_TGROUP)
4018 : : {
4019 : 0 : is_t_group = 1;
4020 : : }
4021 [ # # ]: 0 : if (vert_ficpoint->type & BNS_VERT_TYPE_C_GROUP)
4022 : : {
4023 : 0 : is_c_group = 1;
4024 [ # # ]: 0 : if (vert_ficpoint->type & BNS_VERT_TYPE_C_NEGATIVE)
4025 : : {
4026 : 0 : is_c_group = 2;
4027 : : }
4028 : : }
4029 : :
4030 [ # # ]: 0 : for (k = vert_ficpoint->num_adj_edges - 1; 0 <= k; k--)
4031 : : {
4032 : 0 : iedge = vert_ficpoint->iedge[k];
4033 [ # # ]: 0 : if (iedge + 1 != num_edges)
4034 : : {
4035 : 0 : return BNS_VERT_EDGE_OVFL;
4036 : : }
4037 : 0 : edge = pBNS->edge + iedge;
4038 : 0 : endpoint = edge->neighbor12 ^ tg;
4039 : 0 : vert_endpoint = pBNS->vert + endpoint;
4040 : : /* adjust st_flow, st_cap */
4041 : 0 : vert_endpoint->st_edge.cap0 =
4042 : 0 : vert_endpoint->st_edge.cap -= edge->flow;
4043 : 0 : vert_endpoint->st_edge.flow0 =
4044 : 0 : vert_endpoint->st_edge.flow -= edge->flow;
4045 [ # # # # ]: 0 : if (pBNS->type_TACN && ( vert_endpoint->type & pBNS->type_TACN ) == pBNS->type_TACN)
4046 : : {
4047 : 0 : vert_endpoint->type ^= pBNS->type_TACN;
4048 : : }
4049 [ # # ]: 0 : if (is_t_group)
4050 : : {
4051 : 0 : vert_endpoint->type ^= ( vert_ficpoint->type & BNS_VERT_TYPE_ENDPOINT );
4052 : : }
4053 [ # # ]: 0 : if (is_c_group)
4054 : : {
4055 : 0 : vert_endpoint->type ^= ( vert_ficpoint->type & BNS_VERT_TYPE_C_POINT );
4056 : : }
4057 : : /* Remove edge */
4058 [ # # ]: 0 : if (edge->neigh_ord[0] + 1 != vert_endpoint->num_adj_edges)
4059 : : {
4060 : 0 : return BNS_VERT_EDGE_OVFL;
4061 : : }
4062 : 0 : vert_endpoint->num_adj_edges--;
4063 : 0 : memset( edge, 0, sizeof( *edge ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4064 : 0 : num_edges--;
4065 [ # # # # ]: 0 : if (1 == is_t_group && endpoint < num_atoms)
4066 : : {
4067 : 0 : at->endpoint = 0;
4068 : : }
4069 [ # # # # ]: 0 : if (1 == is_c_group && endpoint < num_atoms)
4070 : : {
4071 : 0 : at->c_point = 0;
4072 : : }
4073 : : }
4074 : 0 : memset( vert_ficpoint, 0, sizeof( *vert_ficpoint ) ); /* djb-rwth: memset_s C11/Annex K variant? */
4075 : 0 : num_vertices--;
4076 : :
4077 : 0 : pBNS->num_edges = num_edges;
4078 : 0 : pBNS->num_vertices = num_vertices;
4079 [ # # ]: 0 : if (is_t_group)
4080 : : {
4081 : 0 : pBNS->num_t_groups--;
4082 : : }
4083 [ # # ]: 0 : if (is_c_group)
4084 : : {
4085 : 0 : pBNS->num_c_groups--;
4086 : : }
4087 : :
4088 : 0 : return ret;
4089 : : }
4090 : :
4091 : :
4092 : :
4093 : : /****************************************************************************/
4094 : 3 : int SetInitCapFlowToCurrent( BN_STRUCT *pBNS )
4095 : : {
4096 : : int i, j;
4097 : 3 : BNS_EDGE *pEdge = NULL;
4098 [ + + ]: 6 : for (i = 0; i < pBNS->num_vertices; i++)
4099 : : {
4100 : 3 : pBNS->vert[i].st_edge.flow0 = pBNS->vert[i].st_edge.flow;
4101 : 3 : pBNS->vert[i].st_edge.cap0 = pBNS->vert[i].st_edge.cap;
4102 [ - + ]: 3 : for (j = 0; j < pBNS->vert[i].num_adj_edges; j++)
4103 : : {
4104 : 0 : pEdge = pBNS->edge + pBNS->vert[i].iedge[j];
4105 : 0 : pEdge->cap0 = pEdge->cap;
4106 : 0 : pEdge->flow0 = pEdge->flow;
4107 : : }
4108 : : }
4109 : :
4110 : 3 : return 0;
4111 : : }
4112 : :
4113 : :
4114 : : int ArTypMask[] =
4115 : : {
4116 : : AR_SIMPLE_TYP1,
4117 : : AR_SIMPLE_MSK1,
4118 : : AR_SIMPLE_TYP2,
4119 : : AR_SIMPLE_MSK2,
4120 : : AR_SIMPLE_TYP3,
4121 : : AR_SIMPLE_MSK3,
4122 : : 0,
4123 : : 0
4124 : : };
4125 : :
4126 : :
4127 : :
4128 : : /****************************************************************************/
4129 : 0 : int SimpleRemoveAcidicProtons( inp_ATOM *at,
4130 : : int num_atoms,
4131 : : BN_AATG *pAATG,
4132 : : int num2remove )
4133 : : {
4134 : 0 : int i, j, max_j = -1, mask, type, num_removed;
4135 : : int num[AR_SIMPLE_STEPS + 1], num_tot;
4136 : :
4137 [ # # ]: 0 : for (j = 0; ArTypMask[2 * j]; j++)
4138 : : {
4139 : 0 : num[max_j = j] = 0;
4140 : : }
4141 : :
4142 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
4143 : : {
4144 [ # # # # : 0 : if (!at[i].charge && at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
# # ]
4145 : : {
4146 [ # # ]: 0 : for (j = 0; j <= max_j; j++)
4147 : : {
4148 [ # # # # : 0 : if (( type & ArTypMask[2 * j] ) && ( mask && ArTypMask[2 * j + 1] ))
# # ]
4149 : : {
4150 : 0 : num[j] ++;
4151 : 0 : break;
4152 : : }
4153 : : }
4154 : : }
4155 : : }
4156 [ # # ]: 0 : for (j = 0, num_tot = 0; j <= max_j; j++)
4157 : : {
4158 [ # # ]: 0 : if (( num_tot += num[j] ) >= num2remove)
4159 : : {
4160 : 0 : max_j = j;
4161 : 0 : break;
4162 : : }
4163 : : }
4164 [ # # ]: 0 : if (!num_tot)
4165 : : {
4166 : 0 : return 0;
4167 : : }
4168 [ # # # # ]: 0 : for (i = 0, num_removed = 0; i < num_atoms && num_removed < num2remove; i++)
4169 : : {
4170 [ # # # # : 0 : if (!at[i].charge && at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
# # ]
4171 : : {
4172 [ # # ]: 0 : for (j = 0; j <= max_j; j++)
4173 : : {
4174 [ # # # # : 0 : if (num[j] && ( type & ArTypMask[2 * j] ) && ( mask && ArTypMask[2 * j + 1] ))
# # # # ]
4175 : : {
4176 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4177 : 0 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 1); /* subtract at[i] */
4178 : 0 : num[j] --;
4179 : 0 : at[i].charge--;
4180 : 0 : AddOrRemoveExplOrImplH( -1, at, num_atoms, (AT_NUMB) i, pAATG->t_group_info );
4181 : : /*at[i].num_H --;*/
4182 : 0 : num_removed++;
4183 : 0 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 0); /* add changed at[i] */ /* ! THIS CHANGES pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] */
4184 : 0 : break;
4185 : : }
4186 : : }
4187 : : }
4188 : : }
4189 : :
4190 : : /*
4191 : : pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] -= num_removed;
4192 : : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] += num_removed;
4193 : : */
4194 : :
4195 : 0 : return num_removed;
4196 : : }
4197 : :
4198 : :
4199 : : /****************************************************************************/
4200 : 619 : int bHasAcidicHydrogen( inp_ATOM *at, int i )
4201 : : {
4202 : 619 : int bFound = 0, j, type, mask;
4203 [ + + + + : 619 : if (!at[i].charge && at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
+ + ]
4204 : : {
4205 [ + + ]: 37 : for (j = 0; ArTypMask[2 * j]; j++)
4206 : : {
4207 [ + + + - ]: 20 : if (( type & ArTypMask[2 * j] ) && ( mask & ArTypMask[2 * j + 1] ))
4208 : : {
4209 : 3 : bFound++;
4210 : 3 : break;
4211 : : }
4212 : : }
4213 : : }
4214 : :
4215 : 619 : return bFound;
4216 : : }
4217 : :
4218 : :
4219 : : /****************************************************************************/
4220 : 0 : int bHasOtherExchangableH( inp_ATOM *at, int i )
4221 : : {
4222 : 0 : int bFound = 0, type, mask;
4223 [ # # # # ]: 0 : if (at[i].num_H && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4224 : : {
4225 [ # # # # ]: 0 : if (( type & ATT_ATOM_N ) && ( mask & ATBIT_NP_H ))
4226 : : {
4227 : 0 : bFound++;
4228 : : }
4229 : : }
4230 : :
4231 : 0 : return bFound;
4232 : : }
4233 : :
4234 : :
4235 : : int AaTypMask[] =
4236 : : {
4237 : : AA_SIMPLE_TYP1,
4238 : : AA_SIMPLE_MSK1,
4239 : : #if ( FIX_NP_MINUS_BUG == 1 )
4240 : : AA_SIMPLE_TYP4,
4241 : : AA_SIMPLE_MSK4, /* should not follow 0,0 pair */
4242 : : #endif
4243 : : AA_SIMPLE_TYP2,
4244 : : AA_SIMPLE_MSK2,
4245 : : AA_SIMPLE_TYP3,
4246 : : AA_SIMPLE_MSK3,
4247 : : 0,
4248 : : 0
4249 : : };
4250 : :
4251 : :
4252 : : /****************************************************************************/
4253 : 5 : int SimpleAddAcidicProtons( inp_ATOM *at,
4254 : : int num_atoms,
4255 : : BN_AATG *pAATG,
4256 : : int num2add )
4257 : : {
4258 : 5 : int i, j, max_j = -1, mask, type, num_added;
4259 : : int num[AR_SIMPLE_STEPS + 1], num_tot;
4260 : :
4261 [ + + ]: 15 : for (j = 0; AaTypMask[2 * j]; j++)
4262 : : {
4263 : 10 : num[max_j = j] = 0;
4264 : : }
4265 : :
4266 [ + + ]: 18 : for (i = 0; i < num_atoms; i++)
4267 : : {
4268 [ + + + + ]: 13 : if (at[i].charge == -1 && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4269 : : {
4270 [ + - ]: 3 : for (j = 0; j <= max_j; j++)
4271 : : {
4272 [ + - + - : 3 : if (( type & AaTypMask[2 * j] ) && ( mask && AaTypMask[2 * j + 1] ))
+ - ]
4273 : : {
4274 : 3 : num[j] ++;
4275 : 3 : break;
4276 : : }
4277 : : }
4278 : : }
4279 : : }
4280 [ + + ]: 9 : for (j = 0, num_tot = 0; j <= max_j; j++)
4281 : : {
4282 [ + + ]: 7 : if (( num_tot += num[j] ) >= num2add)
4283 : : {
4284 : 3 : max_j = j;
4285 : 3 : break;
4286 : : }
4287 : : }
4288 [ + + ]: 5 : if (!num_tot)
4289 : : {
4290 : 2 : return 0;
4291 : : }
4292 [ + + + - ]: 6 : for (i = 0, num_added = 0; i < num_atoms && num_added < num2add; i++)
4293 : : {
4294 [ + - + - ]: 3 : if (at[i].charge == -1 && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4295 : : {
4296 [ + - ]: 3 : for (j = 0; j <= max_j; j++)
4297 : : {
4298 [ + - + - : 3 : if (num[j] && ( type & AaTypMask[2 * j] ) && ( mask && AaTypMask[2 * j + 1] ))
+ - + - ]
4299 : : {
4300 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
4301 : 3 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 1); /* subtract at[i] */
4302 : 3 : num[j] --;
4303 : 3 : at[i].charge++;
4304 : 3 : AddOrRemoveExplOrImplH( 1, at, num_atoms, (AT_NUMB) i, pAATG->t_group_info );
4305 : : /*at[i].num_H ++;*/
4306 : 3 : num_added++;
4307 : 3 : type = GetAtomChargeType(at, i, pAATG->nAtTypeTotals, &mask, 0); /* add changed at[i] */
4308 : 3 : break;
4309 : : }
4310 : : }
4311 : : }
4312 : : }
4313 : :
4314 : : /*
4315 : : pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] += num_added;
4316 : : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] -= num_added;
4317 : : */
4318 : :
4319 : 3 : return num_added;
4320 : : }
4321 : :
4322 : :
4323 : : /****************************************************************************/
4324 : 616 : int bHasAcidicMinus( inp_ATOM *at, int i )
4325 : : {
4326 : 616 : int bFound = 0, j, type, mask;
4327 [ + + - + ]: 616 : if (at[i].charge == -1 && ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ))
4328 : : {
4329 [ # # ]: 0 : for (j = 0; AaTypMask[2 * j]; j++)
4330 : : {
4331 [ # # # # ]: 0 : if (( type & AaTypMask[2 * j] ) && ( mask & AaTypMask[2 * j + 1] ))
4332 : : {
4333 : 0 : bFound++;
4334 : 0 : break;
4335 : : }
4336 : : }
4337 : : }
4338 : :
4339 : 616 : return bFound;
4340 : : }
4341 : :
4342 : :
4343 : : /****************************************************************************
4344 : : HardRemoveAcidicProtons( ... )
4345 : :
4346 : : Create 2 tautomeric groups:
4347 : : (1) for O on -C=O,
4348 : : (2) for the rest of the atoms.
4349 : : Pull H from (2) to (1); remove later
4350 : : ****************************************************************************/
4351 : 0 : int HardRemoveAcidicProtons( CANON_GLOBALS *pCG,
4352 : : inp_ATOM *at,
4353 : : int num_atoms,
4354 : : BN_AATG *pAATG,
4355 : : int num2remove,
4356 : : int *nNumCanceledCharges,
4357 : : BN_STRUCT *pBNS,
4358 : : BN_DATA *pBD )
4359 : : {
4360 : 0 : int cg_Plus = 0;
4361 : 0 : int cg_Minus = 0;
4362 : 0 : int tg_H_Other = 0;
4363 : 0 : int tg_H_Acid = 0;
4364 : :
4365 : 0 : int ret = 0, ret2;
4366 : 0 : int nDelta, nNumMoved2AcidH = 0, nNumNeutralized = 0, nPrevNumCharges; /* djb-rwth: removing redundant variables */
4367 : :
4368 : : int nPosCharges, nPosCharges2;
4369 : : int nNegCharges, nNegCharges2;
4370 : : /*
4371 : : int nNumNP_H, nNumNP_H2;
4372 : : int nNumOS_H, nNumOS_H2;
4373 : : */
4374 : :
4375 : 0 : nPosCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4376 : 0 : nNegCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4377 : : /*
4378 : : nNumNP_H = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4379 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4380 : : nNumOS_H = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4381 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4382 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4383 : : */
4384 : :
4385 : : /* Prevent free exchange H <-> (-) */
4386 : 0 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4387 : 0 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4388 : 0 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4389 : :
4390 : : /* Create (+) charge group */
4391 : 0 : cg_Plus = CreateCGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_POS, AR_HARD_MSK_POS, 1 );
4392 : :
4393 : : /* create (-) charge group */
4394 : : /*
4395 : : if ( nAtTypeTotals[ATTOT_NUM_CO_Minus] +
4396 : : nAtTypeTotals[ATTOT_NUM_CS_Minus] +
4397 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] +
4398 : : nAtTypeTotals[ATTOT_NUM_N_Minus] )
4399 : : */
4400 : :
4401 : 0 : cg_Minus = CreateCGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_NEG, AR_HARD_MSK_NEG, -1 );
4402 : :
4403 : 0 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4404 : 0 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4405 : 0 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4406 : :
4407 : : /* Create tautomeric group for non-acidic or negatively charged acidic O */
4408 : 0 : tg_H_Other = CreateTGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_HN, AR_HARD_MSK_HN );
4409 : :
4410 : : /* Create tautomeric group for possibly acidic O */
4411 : 0 : tg_H_Acid = CreateTGroupInBnStruct( at, num_atoms, pBNS, AR_HARD_TYP_HA, AR_HARD_MSK_HA );
4412 [ # # # # ]: 0 : if (tg_H_Other >= num_atoms && tg_H_Acid >= num_atoms)
4413 : : {
4414 : : /* Find alt path to remove one proton */
4415 : : do
4416 : : {
4417 : : /* Remove a proton */
4418 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4419 : : /* djb-rwth: addressing coverity ID #499503 -- tg_H_Other negative values handled properly */
4420 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4421 : : at, num_atoms,
4422 : : tg_H_Other /*nVertDoubleBond*/,
4423 : : tg_H_Acid /*nVertSingleBond*/,
4424 : : ALT_PATH_MODE_REM_PROTON );
4425 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4426 : : {
4427 : 0 : return ret;
4428 : : }
4429 [ # # ]: 0 : if (ret & 1)
4430 : : {
4431 : 0 : nDelta = ( ret & ~3 ) >> 2;
4432 : : /* djb-rwth: removing redundant code */
4433 : : if (nDelta)
4434 : : {
4435 : : /* Radical pair has disappeared */
4436 : : ; /* goto quick_exit;*/
4437 : : }
4438 : 0 : nNumMoved2AcidH++;
4439 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + 1)
4440 : : {
4441 : 0 : nNumNeutralized += ( nPrevNumCharges - ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - 1 ) ) / 2;
4442 : : }
4443 : : }
4444 [ # # # # ]: 0 : } while (( ret & 1 ) && nNumMoved2AcidH < num2remove);
4445 : :
4446 : : /* Neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O */
4447 [ # # # # : 0 : if (( nNumMoved2AcidH /*|| bCancelChargesAlways*/ ) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
# # ]
4448 [ # # ]: 0 : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4449 : : {
4450 : : do
4451 : : {
4452 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4453 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4454 : : at, num_atoms,
4455 : : cg_Minus /*nVertDoubleBond*/,
4456 : : cg_Plus /*nVertSingleBond*/,
4457 : : ALT_PATH_MODE_REM_PROTON );
4458 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4459 : : {
4460 : 0 : return ret;
4461 : : }
4462 [ # # ]: 0 : if (ret & 1)
4463 : : {
4464 : 0 : nDelta = ( ret & ~3 ) >> 2;
4465 : : /* djb-rwth: removing redundant code */
4466 : : if (nDelta)
4467 : : {
4468 : : /* Radical pair has disappeared */
4469 : : ; /* goto quick_exit;*/
4470 : : }
4471 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4472 : : {
4473 : 0 : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4474 : : }
4475 : : }
4476 [ # # ]: 0 : } while (ret & 1);
4477 : : }
4478 : : }
4479 : :
4480 : 0 : ret = 0;
4481 [ # # ]: 0 : if (tg_H_Acid >= num_atoms)
4482 : : {
4483 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H_Acid, pBNS );
4484 [ # # # # ]: 0 : if (!ret && ret2)
4485 : : {
4486 : 0 : ret = ret2;
4487 : : }
4488 : : }
4489 [ # # ]: 0 : if (tg_H_Other >= num_atoms)
4490 : : {
4491 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H_Other, pBNS );
4492 [ # # # # ]: 0 : if (!ret && ret2)
4493 : : {
4494 : 0 : ret = ret2;
4495 : : }
4496 : : }
4497 [ # # ]: 0 : if (cg_Minus >= num_atoms)
4498 : : {
4499 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus, pBNS );
4500 [ # # # # ]: 0 : if (!ret && ret2)
4501 : : {
4502 : 0 : ret = ret2;
4503 : : }
4504 : : }
4505 [ # # ]: 0 : if (cg_Plus >= num_atoms)
4506 : : {
4507 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Plus, pBNS );
4508 [ # # # # ]: 0 : if (!ret && ret2)
4509 : : {
4510 : 0 : ret = ret2;
4511 : : }
4512 : : }
4513 : :
4514 : 0 : pBNS->type_CN = 0;
4515 : 0 : pBNS->type_T = 0;
4516 : 0 : pBNS->type_TACN = 0;
4517 : :
4518 [ # # ]: 0 : if (ret)
4519 : : {
4520 : 0 : return ret;
4521 : : }
4522 : :
4523 [ # # ]: 0 : if (pAATG->nAtTypeTotals[ATTOT_NUM_CO_Minus] + pAATG->nAtTypeTotals[ATTOT_NUM_ZO_Minus] &&
4524 : 0 : pAATG->nAtTypeTotals[ATTOT_NUM_N_Minus])
4525 : : {
4526 : : }
4527 : :
4528 : 0 : nPosCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4529 : 0 : nNegCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4530 : : /*
4531 : : nNumNP_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4532 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4533 : : nNumOS_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4534 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4535 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4536 : : */
4537 [ # # ]: 0 : if (( nPosCharges - nNegCharges ) - ( nPosCharges2 - nNegCharges2 ) != 0)
4538 : : {
4539 : 0 : return BNS_PROGRAM_ERR;
4540 : : }
4541 : :
4542 [ # # ]: 0 : if (nNumCanceledCharges)
4543 : : {
4544 : : #if ( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
4545 : : *nNumCanceledCharges += 2 * nNumNeutralized;
4546 : : #else
4547 : 0 : *nNumCanceledCharges = 2 * nNumNeutralized;
4548 : : #endif
4549 : : }
4550 : :
4551 : 0 : return nNumMoved2AcidH;
4552 : : }
4553 : :
4554 : :
4555 : : /****************************************************************************/
4556 : 2 : int HardAddAcidicProtons( CANON_GLOBALS *pCG,
4557 : : inp_ATOM *at,
4558 : : int num_atoms,
4559 : : BN_AATG *pAATG,
4560 : : int num2add,
4561 : : int *nNumCanceledCharges,
4562 : : BN_STRUCT *pBNS,
4563 : : BN_DATA *pBD )
4564 : : {
4565 : 2 : int cg_Plus = 0;
4566 : 2 : int cg_Minus_CO = 0;
4567 : 2 : int cg_Minus_Other = 0;
4568 : 2 : int tg_H = 0;
4569 : :
4570 : 2 : int ret = 0, ret2;
4571 : 2 : int nDelta, nNumChanges = 0, nNumMoved2AcidMinus = 0, nNumNeutralized = 0, nPrevNumCharges; /* djb-rwth: removing redundant variables */
4572 : :
4573 : : int nPosCharges, nPosCharges2;
4574 : : int nNegCharges, nNegCharges2;
4575 : : /*
4576 : : int nNumNP_H, nNumNP_H2;
4577 : : int nNumOS_H, nNumOS_H2;
4578 : : */
4579 : 2 : nPosCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4580 : 2 : nNegCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4581 : : /*
4582 : : nNumNP_H = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4583 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4584 : : nNumOS_H = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4585 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4586 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4587 : : */
4588 : :
4589 : : /* Prevent free exchange H <-> (-) */
4590 : 2 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4591 : 2 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4592 : 2 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4593 : :
4594 : : /* Create (+) charge group */
4595 : 2 : cg_Plus = CreateCGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_POS, AA_HARD_MSK_POS, 1 );
4596 : :
4597 : : /* Create (-) charge group */
4598 : : /*
4599 : : if ( nAtTypeTotals[ATTOT_NUM_CO_Minus] +
4600 : : nAtTypeTotals[ATTOT_NUM_CS_Minus] +
4601 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] +
4602 : : nAtTypeTotals[ATTOT_NUM_N_Minus] )
4603 : : */
4604 : 2 : cg_Minus_CO = CreateCGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_CO, AA_HARD_MSK_CO, -1 );
4605 : :
4606 : 2 : cg_Minus_Other = CreateCGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_NEG, AA_HARD_MSK_NEG, -1 );
4607 : :
4608 : 2 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4609 : 2 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4610 : 2 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4611 : :
4612 : : /* Create tautomeric group for all H */
4613 : 2 : tg_H = CreateTGroupInBnStruct( at, num_atoms, pBNS, AA_HARD_TYP_H, AA_HARD_MSK_H );
4614 : :
4615 [ - + - - ]: 2 : if (cg_Minus_Other >= num_atoms && cg_Minus_CO >= num_atoms)
4616 : : {
4617 : : /* Find alt path to remove one proton */
4618 : : do
4619 : : {
4620 : : /* Add a proton */
4621 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4622 : : /* djb-rwth: addressing coverity ID #499474 -- cg_Minus_CO negative values handled properly */
4623 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4624 : : at, num_atoms,
4625 : : cg_Minus_Other /*nVertDoubleBond*/,
4626 : : cg_Minus_CO /*nVertSingleBond*/,
4627 : : ALT_PATH_MODE_REM_PROTON );
4628 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4629 : : {
4630 : 0 : return ret;
4631 : : }
4632 [ # # ]: 0 : if (ret & 1)
4633 : : {
4634 : 0 : nDelta = ( ret & ~3 ) >> 2;
4635 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4636 : : if (nDelta)
4637 : : {
4638 : : /* Radical pair has disappeared */
4639 : : ; /* goto quick_exit;*/
4640 : : }
4641 : 0 : nNumMoved2AcidMinus++;
4642 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + 1)
4643 : : {
4644 : 0 : nNumNeutralized += ( nPrevNumCharges - ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - 1 ) ) / 2;
4645 : : }
4646 : : }
4647 [ # # # # ]: 0 : } while (( ret & 1 ) && nNumMoved2AcidMinus < num2add);
4648 : :
4649 : : /* Neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O */
4650 [ # # # # ]: 0 : if (( nNumMoved2AcidMinus /*|| bCancelChargesAlways*/ ) &&
4651 [ # # ]: 0 : cg_Minus_Other >= num_atoms && cg_Plus >= num_atoms &&
4652 [ # # ]: 0 : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4653 : : {
4654 : : do
4655 : : {
4656 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4657 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG,
4658 : : at, num_atoms,
4659 : : cg_Minus_Other /*nVertDoubleBond*/,
4660 : : cg_Plus /*nVertSingleBond*/,
4661 : : ALT_PATH_MODE_REM_PROTON );
4662 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4663 : : {
4664 : 0 : return ret;
4665 : : }
4666 [ # # ]: 0 : if (ret & 1)
4667 : : {
4668 : 0 : nDelta = ( ret & ~3 ) >> 2;
4669 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4670 : : if (nDelta)
4671 : : {
4672 : : /* Radical pair has disappeared */
4673 : : ; /* goto quick_exit;*/
4674 : : }
4675 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4676 : : {
4677 : 0 : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4678 : : }
4679 : : }
4680 [ # # ]: 0 : } while (ret & 1);
4681 : : }
4682 : : }
4683 : :
4684 : 2 : ret = 0;
4685 [ - + ]: 2 : if (tg_H >= num_atoms)
4686 : : {
4687 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H, pBNS );
4688 [ # # # # ]: 0 : if (!ret && ret2)
4689 : : {
4690 : 0 : ret = ret2;
4691 : : }
4692 : : }
4693 [ - + ]: 2 : if (cg_Minus_Other >= num_atoms)
4694 : : {
4695 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus_Other, pBNS );
4696 [ # # # # ]: 0 : if (!ret && ret2)
4697 : : {
4698 : 0 : ret = ret2;
4699 : : }
4700 : : }
4701 [ - + ]: 2 : if (cg_Minus_CO >= num_atoms)
4702 : : {
4703 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus_CO, pBNS );
4704 [ # # # # ]: 0 : if (!ret && ret2)
4705 : : {
4706 : 0 : ret = ret2;
4707 : : }
4708 : : }
4709 [ - + ]: 2 : if (cg_Plus >= num_atoms)
4710 : : {
4711 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Plus, pBNS );
4712 [ # # # # ]: 0 : if (!ret && ret2)
4713 : : {
4714 : 0 : ret = ret2;
4715 : : }
4716 : : }
4717 : :
4718 : 2 : pBNS->type_CN = 0;
4719 : 2 : pBNS->type_T = 0;
4720 : 2 : pBNS->type_TACN = 0;
4721 : :
4722 [ - + ]: 2 : if (ret)
4723 : : {
4724 : 0 : return ret;
4725 : : }
4726 : :
4727 [ - + ]: 2 : if (pAATG->nAtTypeTotals[ATTOT_NUM_CO_Minus] + pAATG->nAtTypeTotals[ATTOT_NUM_ZO_Minus] &&
4728 : 0 : pAATG->nAtTypeTotals[ATTOT_NUM_N_Minus])
4729 : : {
4730 : : }
4731 : :
4732 : 2 : nPosCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4733 : 2 : nNegCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4734 : : /*
4735 : : nNumNP_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4736 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4737 : : nNumOS_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4738 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4739 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4740 : : */
4741 : :
4742 [ - + ]: 2 : if (( nPosCharges - nNegCharges ) - ( nPosCharges2 - nNegCharges2 ) != 0)
4743 : : {
4744 : 0 : return BNS_PROGRAM_ERR;
4745 : : }
4746 : :
4747 [ + - ]: 2 : if (nNumCanceledCharges)
4748 : : {
4749 : : #if ( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
4750 : : *nNumCanceledCharges += 2 * nNumNeutralized;
4751 : : #else
4752 : 2 : *nNumCanceledCharges = 2 * nNumNeutralized;
4753 : : #endif
4754 : : }
4755 : :
4756 : 2 : return nNumMoved2AcidMinus;
4757 : : }
4758 : :
4759 : :
4760 : : /****************************************************************************
4761 : : HardRemoveHplusNP( ... )
4762 : :
4763 : : Examples include removal of H from tautomeric O
4764 : : that belongs to the same t-group as N:
4765 : :
4766 : : >N(+)=-N=-OH =(taut.) =>
4767 : : >N(+)=-NH-=O =(+charge move) =>
4768 : : >N-=NH(+)-=O => >N-=N-=O + H(+)
4769 : : ****************************************************************************/
4770 : 0 : int HardRemoveHplusNP( CANON_GLOBALS *pCG,
4771 : : inp_ATOM *at,
4772 : : int num_atoms,
4773 : : int bCancelChargesAlways,
4774 : : int *nNumCanceledCharges,
4775 : : BN_AATG *pAATG,
4776 : : BN_STRUCT *pBNS,
4777 : : BN_DATA *pBD )
4778 : : {
4779 : :
4780 : 0 : int cg_Plus = 0;
4781 : 0 : int cg_Minus = 0;
4782 : 0 : int tg_H = 0;
4783 : : #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
4784 : : int cg_PlusP = 0;
4785 : : #endif
4786 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4787 : : int nPrevRemovedProtons, nCurrRemovedProtons;
4788 : : #endif
4789 : 0 : int ret = 0, ret2;
4790 : 0 : int nDelta, nNumChanges = 0, nNumRemovedProtons = 0, nNumNeutralized = 0, nPrevNumCharges; /* djb-rwth: ignoring LLVM warning: variable used */
4791 : :
4792 : : int nPosCharges, nPosCharges2;
4793 : : int nNegCharges, nNegCharges2;
4794 : : /*
4795 : : int nNumNP_H, nNumNP_H2;
4796 : : int nNumOS_H, nNumOS_H2;
4797 : : */
4798 : :
4799 : 0 : nPosCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4800 : 0 : nNegCharges = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
4801 : : /*
4802 : : nNumNP_H = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
4803 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
4804 : : nNumOS_H = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
4805 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
4806 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
4807 : : */
4808 : :
4809 : : /* Prevent free exchange H <-> (-) */
4810 : 0 : pBNS->type_CN = ( BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_C_NEGATIVE );
4811 : 0 : pBNS->type_T = BNS_VERT_TYPE_TGROUP;
4812 : 0 : pBNS->type_TACN = BNS_VERT_TYPE_ACID;
4813 : :
4814 : : /* Create (+) charge group */
4815 : 0 : cg_Plus = CreateCGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_POS, PR_HARD_MSK_POS, 1 );
4816 : :
4817 : : /* Create (-) charge group */
4818 : : /*
4819 : : if ( nAtTypeTotals[ATTOT_NUM_CO_Minus] +
4820 : : nAtTypeTotals[ATTOT_NUM_CS_Minus] +
4821 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] +
4822 : : nAtTypeTotals[ATTOT_NUM_N_Minus] )
4823 : : */
4824 : : #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
4825 : : cg_PlusP = CreateCGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_POSP, PR_HARD_MSK_POS, 1 );
4826 : : #endif
4827 : 0 : cg_Minus = CreateCGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_NEG, PR_HARD_MSK_NEG, -1 );
4828 : :
4829 : : /* Create single tautomeric group */
4830 : 0 : tg_H = CreateTGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_H, PR_HARD_MSK_H );
4831 : :
4832 [ # # # # ]: 0 : if (tg_H >= num_atoms && cg_Plus >= num_atoms)
4833 : : {
4834 : :
4835 : : #if ( FIX_N_MINUS_NORN_BUG == 1 )
4836 : : /* neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O; >N(+)=-NH(-) => >N-=NH */
4837 : : if (( nNumRemovedProtons || bCancelChargesAlways ) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
4838 : : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4839 : : {
4840 : : do
4841 : : {
4842 : : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4843 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4844 : : nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4845 : : #endif
4846 : : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG, at, num_atoms,
4847 : : cg_Minus /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
4848 : : if (IS_BNS_ERROR( ret ))
4849 : : {
4850 : : return ret;
4851 : : }
4852 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4853 : : nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4854 : : if (nCurrRemovedProtons != nPrevRemovedProtons)
4855 : : {
4856 : : return BNS_RADICAL_ERR;
4857 : : }
4858 : : #endif
4859 : : if (ret & 1)
4860 : : {
4861 : : nDelta = ( ret & ~3 ) >> 2;
4862 : : nNumChanges += ( 0 != ( ret & 2 ) );
4863 : : if (nDelta)
4864 : : {
4865 : : /* radical pair has disappeared */
4866 : : ; /* goto quick_exit;*/
4867 : : }
4868 : : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4869 : : {
4870 : : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4871 : : }
4872 : : }
4873 : : } while (ret & 1);
4874 : : }
4875 : : #endif
4876 : :
4877 : : /* Find alt path to remove one proton */
4878 : : do
4879 : : {
4880 : : /* Remove a proton */
4881 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4882 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4883 : 0 : nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4884 : : #endif
4885 : : /* djb-rwth: addressing coverity ID #499572 -- tg_H negative values handled properly */
4886 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG, at, num_atoms,
4887 : : tg_H /*nVertDoubleBond*/,
4888 : : cg_Plus /*nVertSingleBond*/,
4889 : : ALT_PATH_MODE_REM_PROTON );
4890 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4891 : : {
4892 : 0 : return ret;
4893 : : }
4894 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4895 : 0 : nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4896 [ # # ]: 0 : if (nCurrRemovedProtons != nPrevRemovedProtons + ( ret & 1 ))
4897 : : {
4898 : 0 : return BNS_RADICAL_ERR;
4899 : : }
4900 : : #endif
4901 [ # # ]: 0 : if (ret & 1)
4902 : : {
4903 : 0 : nDelta = ( ret & ~3 ) >> 2;
4904 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4905 : : if (nDelta)
4906 : : {
4907 : : /* radical pair has disappeared */
4908 : : ; /* goto quick_exit;*/
4909 : : }
4910 : 0 : nNumRemovedProtons++;
4911 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + 1)
4912 : : {
4913 : 0 : nNumNeutralized += ( nPrevNumCharges - ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - 1 ) ) / 2;
4914 : : }
4915 : : }
4916 [ # # ]: 0 : } while (ret & 1);
4917 : :
4918 : : /* Neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O */
4919 [ # # # # : 0 : if (( nNumRemovedProtons || bCancelChargesAlways ) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
# # # # ]
4920 [ # # ]: 0 : pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs( pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ))
4921 : : {
4922 : : do
4923 : : {
4924 : 0 : nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
4925 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4926 : 0 : nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4927 : : #endif
4928 : 0 : ret = bExistsAltPath( pCG, pBNS, pBD, pAATG, at, num_atoms,
4929 : : cg_Minus /*nVertDoubleBond*/,
4930 : : cg_Plus /*nVertSingleBond*/,
4931 : : ALT_PATH_MODE_REM_PROTON );
4932 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
4933 : : {
4934 : 0 : return ret;
4935 : : }
4936 : : #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
4937 : 0 : nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
4938 [ # # ]: 0 : if (nCurrRemovedProtons != nPrevRemovedProtons)
4939 : : {
4940 : 0 : return BNS_RADICAL_ERR;
4941 : : }
4942 : : #endif
4943 [ # # ]: 0 : if (ret & 1)
4944 : : {
4945 : 0 : nDelta = ( ret & ~3 ) >> 2;
4946 : 0 : nNumChanges += (0 != (ret & 2)); /* djb-rwth: ignoring LLVM warning: variable used */
4947 : : if (nDelta)
4948 : : {
4949 : : /* Radical pair has disappeared */
4950 : : ; /* goto quick_exit;*/
4951 : : }
4952 [ # # ]: 0 : if (nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])
4953 : : {
4954 : 0 : nNumNeutralized += ( nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) / 2;
4955 : : }
4956 : : }
4957 [ # # ]: 0 : } while (ret & 1);
4958 : : }
4959 : : }
4960 : :
4961 : 0 : ret = 0;
4962 [ # # ]: 0 : if (tg_H >= num_atoms)
4963 : : {
4964 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, tg_H, pBNS );
4965 [ # # # # ]: 0 : if (!ret && ret2)
4966 : : {
4967 : 0 : ret = ret2;
4968 : : }
4969 : : }
4970 [ # # ]: 0 : if (cg_Minus >= num_atoms)
4971 : : {
4972 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Minus, pBNS );
4973 [ # # # # ]: 0 : if (!ret && ret2)
4974 : : {
4975 : 0 : ret = ret2;
4976 : : }
4977 : : }
4978 : : #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
4979 : : if (cg_PlusP >= num_atoms)
4980 : : {
4981 : : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_PlusP, pBNS );
4982 : : if (!ret && ret2)
4983 : : {
4984 : : ret = ret2;
4985 : : }
4986 : : }
4987 : : #endif
4988 [ # # ]: 0 : if (cg_Plus >= num_atoms)
4989 : : {
4990 : 0 : ret2 = RemoveLastGroupFromBnStruct( at, num_atoms, cg_Plus, pBNS );
4991 [ # # # # ]: 0 : if (!ret && ret2)
4992 : : {
4993 : 0 : ret = ret2;
4994 : : }
4995 : : }
4996 : :
4997 : 0 : pBNS->type_CN = 0;
4998 : 0 : pBNS->type_T = 0;
4999 : 0 : pBNS->type_TACN = 0;
5000 : :
5001 [ # # ]: 0 : if (ret)
5002 : : {
5003 : 0 : return ret;
5004 : : }
5005 : :
5006 [ # # ]: 0 : if (pAATG->nAtTypeTotals[ATTOT_NUM_CO_Minus] + pAATG->nAtTypeTotals[ATTOT_NUM_ZO_Minus] &&
5007 : 0 : pAATG->nAtTypeTotals[ATTOT_NUM_N_Minus])
5008 : : {
5009 : : }
5010 : :
5011 : 0 : nPosCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] + pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
5012 : 0 : nNegCharges2 = ( pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] - pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] ) / 2;
5013 : : /*
5014 : : nNumNP_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_NP_H] +
5015 : : pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton];
5016 : : nNumOS_H2 = pAATG->nAtTypeTotals[ATTOT_NUM_COH] +
5017 : : pAATG->nAtTypeTotals[ATTOT_NUM_CSH] +
5018 : : pAATG->nAtTypeTotals[ATTOT_NUM_ZOH];
5019 : : */
5020 : :
5021 [ # # ]: 0 : if (( nPosCharges - nNegCharges ) - ( nPosCharges2 - nNegCharges2 ) != nNumRemovedProtons)
5022 : : {
5023 : 0 : return BNS_PROGRAM_ERR;
5024 : : }
5025 : :
5026 [ # # ]: 0 : if (nNumCanceledCharges)
5027 : : {
5028 : : #if ( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
5029 : : *nNumCanceledCharges += 2 * nNumNeutralized;
5030 : : #else
5031 : 0 : *nNumCanceledCharges = 2 * nNumNeutralized;
5032 : : #endif
5033 : : }
5034 : :
5035 : 0 : return nNumRemovedProtons;
5036 : : }
5037 : :
5038 : :
5039 : : /****************************************************************************/
5040 : 69 : int mark_at_type( inp_ATOM *atom, int num_atoms, int nAtTypeTotals[] )
5041 : : {
5042 : : int i, max_num_ions, mask, type;
5043 : : /*int max_protons, max_O_Minus, num_H = 0, num_CO=0;*/
5044 : :
5045 [ + - ]: 69 : if (nAtTypeTotals)
5046 : : {
5047 : 69 : memset( nAtTypeTotals, 0, ATTOT_ARRAY_LEN * sizeof( nAtTypeTotals[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5048 : : }
5049 : :
5050 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
5051 : : {
5052 : 619 : type = GetAtomChargeType( atom, i, nAtTypeTotals, &mask, 0 );
5053 : 619 : atom[i].at_type = type;
5054 : : /*
5055 : : num_H += ((type & PR_HARD_TYP_H) && (mask & ATBIT_MSK_H));
5056 : : num_CO += ((type & AR_HARD_TYP_HA) && (mask & AR_HARD_MSK_HA));
5057 : : */
5058 : : }
5059 : :
5060 [ + - ]: 69 : if (nAtTypeTotals)
5061 : : {
5062 : : /*
5063 : : max_protons = nAtTypeTotals[ATTOT_NUM_NP_Proton] +
5064 : : inchi_min(num_H, nAtTypeTotals[ATTOT_NUM_NP_Plus]);
5065 : : max_O_Minus = nAtTypeTotals[ATTOT_NUM_CO_Minus] + nAtTypeTotals[ATTOT_NUM_CS_Minus] +
5066 : : nAtTypeTotals[ATTOT_NUM_ZO_Minus] + nAtTypeTotals[ATTOT_NUM_OO_Minus] +
5067 : : nAtTypeTotals[ATTOT_NUM_ZOO_Minus] + nAtTypeTotals[ATTOT_NUM_NO_Minus] +
5068 : : nAtTypeTotals[ATTOT_NUM_O_Minus] +nAtTypeTotals[ATTOT_NUM_N_Minus];
5069 : : ;
5070 : : max_num_ions = max_protons + max_O_Minus + nAtTypeTotals[ATTOT_NUM_CHARGES];
5071 : : */
5072 : 69 : max_num_ions = nAtTypeTotals[ATTOT_NUM_CHARGES];
5073 : : }
5074 : : else
5075 : : {
5076 : 0 : max_num_ions = 0;
5077 : : }
5078 : :
5079 : 69 : return max_num_ions;
5080 : : }
5081 : :
5082 : :
5083 : : /****************************************************************************/
5084 : 5 : int RemoveNPProtonsAndAcidCharges( CANON_GLOBALS *pCG,
5085 : : inp_ATOM *at,
5086 : : int num_atoms,
5087 : : BN_AATG *pAATG,
5088 : : BN_STRUCT *pBNS,
5089 : : BN_DATA *pBD )
5090 : : {
5091 : :
5092 : : /* Prepare data structure */
5093 : : int num;
5094 : 5 : int nNumCanceledCharges = 0;
5095 : : /* djb-rwth: removing redundant variables */
5096 : 5 : T_GROUP_INFO *t_group_info = pAATG->t_group_info;
5097 : 5 : int ret = 0, bError = 0;
5098 : :
5099 : 15 : int bAllowHardRemove = ( t_group_info->bTautFlags & TG_FLAG_TEST_TAUT__SALTS ) &&
5100 [ + - ]: 5 : ( t_group_info->bTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) &&
5101 [ + - + - ]: 15 : ( t_group_info->bTautFlags & TG_FLAG_MOVE_POS_CHARGES ) &&
5102 [ + - ]: 5 : ( t_group_info->bTautFlags & TG_FLAG_HARD_ADD_REM_PROTONS );
5103 : :
5104 [ - + - - ]: 5 : if (pAATG->nMarkedAtom && num_atoms < pAATG->nAllocLen)
5105 : : {
5106 [ # # ]: 0 : inchi_free( pAATG->nMarkedAtom );
5107 [ # # # # ]: 0 : qzfree( pAATG->nEndPoint );
5108 : 0 : memset( pAATG, 0, sizeof( *pAATG ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5109 : : }
5110 : :
5111 [ + - + - ]: 5 : if (!pAATG->nMarkedAtom && ( pAATG->nMarkedAtom = (S_CHAR *) inchi_malloc( num_atoms * sizeof( pAATG->nMarkedAtom[0] ) ) ))
5112 : : {
5113 : 5 : pAATG->nAllocLen = num_atoms;
5114 : 5 : pAATG->nNumFound = 0;
5115 : : }
5116 : :
5117 : : /* o TECHMAN-5.1. Remove protons from charged heteroatoms */
5118 : :
5119 : : /* (TECHMAN-5.1a) Simple remove of protons from N, P, and O,S,Se,Te */
5120 [ - + ]: 5 : if ((num = pAATG->nAtTypeTotals[ATTOT_NUM_NP_Proton] + pAATG->nAtTypeTotals[ATTOT_NUM_OH_Plus])) /* djb-rwth: addressing LLVM warning */
5121 : : {
5122 : 0 : ret = SimpleRemoveHplusNPO( at, num_atoms, pAATG->nAtTypeTotals, t_group_info );
5123 [ # # ]: 0 : if (ret != num)
5124 : : {
5125 : 0 : bError = BNS_PROGRAM_ERR;
5126 : 0 : goto exit_function;
5127 : : }
5128 : : /*t_group_info->nNumRemovedProtons += ret;*/
5129 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_NPO_SIMPLE_REMOVED : 0;
5130 : : }
5131 : :
5132 [ - + - - ]: 5 : if (( num = pAATG->nAtTypeTotals[ATTOT_NUM_NP_Plus] ) && bAllowHardRemove) /* djb-rwth: ignoring LLVM warning: variable used */
5133 : : {
5134 : : /* [TECHMAN-5.1b] Hard removing more protons from cationic N; charges may be canceled */
5135 : 0 : ret = HardRemoveHplusNP( pCG, at, num_atoms, 1, &nNumCanceledCharges, pAATG, pBNS, pBD );
5136 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5137 : : {
5138 : 0 : bError = ret;
5139 : 0 : goto exit_function;
5140 : : }
5141 : : /* djb-rwth: removing redundant code */
5142 : : /*t_group_info->nNumRemovedProtons += ret;*/
5143 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_NP_HARD_REMOVED : 0;
5144 : : }
5145 : :
5146 [ - + ]: 5 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] > 0)
5147 : : {
5148 : : /* o TECHMAN-5.2. Remove protons from neutral heteroatoms */
5149 : :
5150 : : /* (TECHMAN-5.2a) Simple removal */
5151 : 0 : ret = SimpleRemoveAcidicProtons( at, num_atoms, pAATG, pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] );
5152 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5153 : : {
5154 : 0 : bError = ret;
5155 : 0 : goto exit_function;
5156 : : }
5157 : :
5158 : : /*t_group_info->nNumRemovedProtons += ret;*/
5159 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_AC_SIMPLE_REMOVED : 0;
5160 : :
5161 : :
5162 [ # # # # ]: 0 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] > 0 && bAllowHardRemove)
5163 : : {
5164 : : /* (TECHMAN-5.2b) Hard removal */
5165 : 0 : ret = HardRemoveAcidicProtons(pCG, at, num_atoms, pAATG, pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE], &nNumCanceledCharges, pBNS, pBD);
5166 [ # # # # ]: 0 : if (IS_BNS_ERROR(ret))
5167 : : {
5168 : 0 : bError = ret;
5169 : 0 : goto exit_function;
5170 : : }
5171 [ # # ]: 0 : if (ret > 0)
5172 : : {
5173 : 0 : int ret2 = SimpleRemoveAcidicProtons(at, num_atoms, pAATG, ret);
5174 [ # # ]: 0 : if (ret2 != ret)
5175 : : {
5176 : 0 : bError = BNS_PROGRAM_ERR;
5177 : 0 : goto exit_function;
5178 : : }
5179 : : /*t_group_info->nNumRemovedProtons += ret;*/
5180 [ # # ]: 0 : t_group_info->tni.bNormalizationFlags |= (ret > 0) ? FLAG_PROTON_AC_HARD_REMOVED : 0;
5181 : : /* djb-rwth: removing redundant code */
5182 : : }
5183 : : }
5184 : :
5185 : :
5186 : : }
5187 : : else
5188 : : {
5189 [ + - ]: 5 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] < 0)
5190 : : {
5191 : 5 : ret = SimpleAddAcidicProtons( at, num_atoms, pAATG, -pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] );
5192 [ + - - + ]: 5 : if (IS_BNS_ERROR( ret ))
5193 : : {
5194 : 0 : bError = ret;
5195 : 0 : goto exit_function;
5196 : : }
5197 : : /*t_group_info->nNumRemovedProtons -= ret;*/
5198 : : /*
5199 : : CHECK_TACN == 1 prohibits replacing (-) on N with H unless H can be moved to N
5200 : : along an alternating path from another heteroatom (t-group will be detected).
5201 : : */
5202 [ + + ]: 5 : t_group_info->tni.bNormalizationFlags |= ( ret > 0 ) ? FLAG_PROTON_AC_SIMPLE_ADDED : 0;
5203 [ + + + - ]: 5 : if (pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE] < 0 && bAllowHardRemove)
5204 : : {
5205 : 2 : ret = HardAddAcidicProtons( pCG, at, num_atoms, pAATG, -pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE], &nNumCanceledCharges, pBNS, pBD );
5206 [ + - - + ]: 2 : if (IS_BNS_ERROR( ret ))
5207 : : {
5208 : 0 : bError = ret;
5209 : 0 : goto exit_function;
5210 : : }
5211 [ - + ]: 2 : if (ret > 0)
5212 : : {
5213 : 0 : int ret2 = SimpleAddAcidicProtons( at, num_atoms, pAATG, ret );
5214 [ # # ]: 0 : if (ret2 != ret)
5215 : : {
5216 : 0 : bError = BNS_PROGRAM_ERR;
5217 : 0 : goto exit_function;
5218 : : }
5219 : : /*t_group_info->nNumRemovedProtons -= ret;*/
5220 : 0 : t_group_info->tni.bNormalizationFlags |= FLAG_PROTON_AC_HARD_ADDED; /* djb-rwth: fixing coverity ID #499527 */
5221 : : /* djb-rwth: removing redundant code */
5222 : : }
5223 : : }
5224 : : }
5225 : : }
5226 : :
5227 [ - + ]: 5 : t_group_info->tni.bNormalizationFlags |= nNumCanceledCharges ? FLAG_PROTON_CHARGE_CANCEL : 0;
5228 : :
5229 : 5 : exit_function:
5230 [ - + ]: 5 : if (bError)
5231 : : {
5232 [ # # # # ]: 0 : ret = IS_BNS_ERROR( bError ) ? bError : BNS_PROGRAM_ERR;
5233 : : }
5234 : :
5235 : 5 : return ret;
5236 : : }
5237 : :
5238 : :
5239 : : /****************************************************************************
5240 : : Main normalization procedure
5241 : : ****************************************************************************/
5242 : 69 : int mark_alt_bonds_and_taut_groups( struct tagINCHI_CLOCK *ic,
5243 : : struct tagCANON_GLOBALS *pCG,
5244 : : inp_ATOM *at,
5245 : : inp_ATOM *at_fixed_bonds_out,
5246 : : int num_atoms,
5247 : : struct tagInchiTime *ulTimeOutTime,
5248 : : T_GROUP_INFO *t_group_info,
5249 : : INCHI_MODE *inpbTautFlags,
5250 : : INCHI_MODE *inpbTautFlagsDone,
5251 : : int nebend,
5252 : : int *ebend )
5253 : :
5254 : :
5255 : : {
5256 : 69 : BN_STRUCT *pBNS = NULL;
5257 : 69 : BN_DATA *pBD = NULL;
5258 : : int bError, nChanges, taut_found, salt_found, salt_pass, salt_step, ret, ret2, num, num_changed_bonds; /* djb-rwth: removing redundant variables */
5259 : 69 : int max_altp = BN_MAX_ALTP;
5260 : 69 : int bChangeFlow = ( BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS );
5261 : : BNS_FLOW_CHANGES fcd[BNS_MAX_NUM_FLOW_CHANGES + 1];
5262 : : C_GROUP_INFO CGroupInfo;
5263 : 69 : C_GROUP_INFO *c_group_info = &CGroupInfo;
5264 : : S_GROUP_INFO SGroupInfo;
5265 : 69 : S_GROUP_INFO *s_group_info = &SGroupInfo;
5266 [ + - ]: 69 : INCHI_MODE *pbTautFlags = t_group_info ? &t_group_info->bTautFlags : inpbTautFlags;
5267 [ + - ]: 69 : INCHI_MODE *pbTautFlagsDone = t_group_info ? &t_group_info->bTautFlagsDone : inpbTautFlagsDone;
5268 : :
5269 : : int nAtTypeTotals[ATTOT_ARRAY_LEN];
5270 : : int nNumOrigTotAtoms;
5271 : :
5272 : : BN_AATG aatg;
5273 : 69 : BN_AATG *pAATG = &aatg;
5274 : :
5275 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5276 : 69 : int i, n_arom_radicals = 0, *stored_radicals = NULL;
5277 : : #endif
5278 : : int at_prot; /* moved from below 2024-09-01 DT */
5279 : :
5280 : 69 : nChanges = 0;
5281 : 69 : bError = 0;
5282 : :
5283 : 69 : memset( c_group_info, 0, sizeof( *c_group_info ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5284 : 69 : memset( s_group_info, 0, sizeof( *s_group_info ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5285 : 69 : memset( pAATG, 0, sizeof( *pAATG ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5286 : :
5287 : : /*(@nnuk : Nauman Ullah Khan) :: Variable for checking (De)protonation status */
5288 : : LOG_NO_ARGS("\n############# Initial state before (De)Protonation (L5373:ichi_bns.c) ###############\n");
5289 [ + + ]: 688 : for (at_prot = 0; at_prot < num_atoms; at_prot++)
5290 : : {
5291 : : 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);
5292 : : }
5293 : : LOG_NO_ARGS("\n#####################################################################################\n");
5294 : :
5295 : :
5296 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5297 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
5298 : : {
5299 [ - + - - ]: 619 : if (( at[i].radical == RADICAL_DOUBLET ) && ( at[i].valence == 2 ) &&
5300 [ # # # # ]: 0 : ( at[i].bond_type[0] == BOND_ALTERN ) && ( at[i].bond_type[1] == BOND_ALTERN ))
5301 : : {
5302 : 0 : n_arom_radicals++;
5303 [ # # ]: 0 : if (!stored_radicals)
5304 : : {
5305 : 0 : stored_radicals = (int *) inchi_calloc( num_atoms, sizeof( int ) );
5306 : : /* 2011-08-05 explicit cast added due to Evan Bolton */
5307 [ # # ]: 0 : if (!stored_radicals)
5308 : : {
5309 : 0 : bError = BNS_OUT_OF_RAM;
5310 : 0 : goto exit_function;
5311 : : }
5312 : 0 : stored_radicals[i] = RADICAL_DOUBLET;
5313 : 0 : at[i].radical = 0;
5314 : 0 : at[i].num_H++;
5315 : : }
5316 : : }
5317 : : }
5318 : :
5319 : : #endif
5320 : :
5321 [ + - + + ]: 69 : if (( *pbTautFlags & TG_FLAG_MOVE_POS_CHARGES ) && num_atoms > 1)
5322 : : {
5323 : : /* Charge groups memory allocation */
5324 : 64 : c_group_info->c_group = (C_GROUP *) inchi_calloc( num_atoms / 2, sizeof( c_group_info->c_group[0] ) );
5325 : 64 : c_group_info->c_candidate = (C_CANDIDATE*) inchi_calloc( num_atoms, sizeof( c_group_info->c_candidate[0] ) );
5326 [ + - + - ]: 64 : if (c_group_info->c_group && c_group_info->c_candidate)
5327 : : {
5328 : 64 : c_group_info->max_num_c_groups = num_atoms / 2;
5329 : 64 : c_group_info->max_num_candidates = num_atoms;
5330 : : }
5331 : : else
5332 : : {
5333 : 0 : bError = BNS_OUT_OF_RAM; /* error: out of RAM */
5334 : : /*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);*/
5335 : 0 : goto exit_function;
5336 : : }
5337 : : }
5338 : :
5339 [ + - ]: 69 : if (*pbTautFlags & TG_FLAG_TEST_TAUT__SALTS)
5340 : : {
5341 [ + - ]: 69 : if (t_group_info)
5342 : : {
5343 : : /* Salt groups memory allocation */
5344 : 69 : s_group_info->s_candidate =
5345 : 69 : (S_CANDIDATE*) inchi_calloc( num_atoms,
5346 : : sizeof( s_group_info->s_candidate[0] ) );
5347 [ + - ]: 69 : if (s_group_info->s_candidate)
5348 : : {
5349 : 69 : s_group_info->max_num_candidates = num_atoms;
5350 : : }
5351 : : else
5352 : : {
5353 : 0 : bError = BNS_OUT_OF_RAM; /* error: out of RAM */
5354 : : /*printf("BNS_OUT_OF_RAM-2\n");*/
5355 : 0 : goto exit_function;
5356 : : }
5357 : : }
5358 : : }
5359 : :
5360 [ + - ]: 69 : if (t_group_info)
5361 : : {
5362 [ - + ]: 69 : if (t_group_info->tGroupNumber)
5363 : : {
5364 [ # # ]: 0 : inchi_free( t_group_info->tGroupNumber );
5365 : : }
5366 : 69 : 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 */
5367 [ - + ]: 69 : if (!t_group_info->tGroupNumber)
5368 : : {
5369 : : /*printf("BNS_OUT_OF_RAM-9\n");*/
5370 : 0 : bError = BNS_OUT_OF_RAM; /* error: out of RAM */
5371 : 0 : goto exit_function;
5372 : : }
5373 : 69 : num = t_group_info->tni.nNumRemovedExplicitH;
5374 : 69 : memset( &t_group_info->tni, 0, sizeof( t_group_info->tni ) ); /* djb-rwth: memset_s C11/Annex K variant? */
5375 : 69 : t_group_info->tni.nNumRemovedExplicitH = num;
5376 : : }
5377 : :
5378 : : /*
5379 : : again:
5380 : : */
5381 : :
5382 : : /* Allocate Balanced Network Data Strucures; replace Alternating bonds with Single */
5383 [ + - ]: 69 : if (( pBNS = AllocateAndInitBnStruct( at, num_atoms,
5384 : : BNS_ADD_ATOMS, BNS_ADD_EDGES,
5385 : : max_altp, &num_changed_bonds ) )
5386 [ + - ]: 69 : &&
5387 : 69 : ( pBD = AllocateAndInitBnData( pBNS->max_vertices ) ))
5388 : : {
5389 : :
5390 : :
5391 : 69 : pBNS->pbTautFlags = pbTautFlags; /* carry through all functions */
5392 : 69 : pBNS->pbTautFlagsDone = pbTautFlagsDone; /* carry through all functions */
5393 : :
5394 : 69 : pBNS->ulTimeOutTime = ulTimeOutTime; /* v. 1.05 */
5395 : 69 : pBNS->ic = ic; /* v. 1.05 */
5396 : :
5397 : : #if ( BNS_PROTECT_FROM_TAUT == 1 )
5398 : : /* Protect bonds to acetyl and nitro */
5399 : 69 : SetForbiddenEdges( pBNS, at, num_atoms, BNS_EDGE_FORBIDDEN_MASK, nebend, ebend );
5400 : : #endif
5401 : :
5402 : : /* Set bonds in case of input "aromatic" bonds or multiple radicals */
5403 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5404 [ - + ]: 69 : if (n_arom_radicals)
5405 : : {
5406 : 0 : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5407 [ # # ]: 0 : if (stored_radicals)
5408 : : {
5409 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
5410 : : {
5411 [ # # ]: 0 : if (stored_radicals[i])
5412 : : {
5413 : 0 : at[i].radical = stored_radicals[i];
5414 : 0 : at[i].num_H--;
5415 : : }
5416 : : }
5417 : : }
5418 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5419 : : {
5420 : 0 : bError = ret;
5421 : 0 : goto exit_function;
5422 : : }
5423 : : }
5424 : : #endif
5425 : :
5426 : 69 : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5427 : :
5428 : : /* (here pair(s) of radicals could have disappeared from the atoms) */
5429 [ + - - + ]: 69 : if (IS_BNS_ERROR( ret ))
5430 : : {
5431 : 0 : bError = ret;
5432 : 0 : goto exit_function;
5433 : : }
5434 : 69 : pBNS->tot_st_flow += 2 * ret;
5435 : :
5436 : : /*return 0;*/ /* debug */
5437 : : /* djb-rwth: removing redundant code */
5438 : :
5439 [ - + ]: 69 : if (pBNS->tot_st_cap > pBNS->tot_st_flow)
5440 : : {
5441 : : /* has radical */
5442 : 0 : bChangeFlow |= BNS_EF_SET_NOSTEREO;
5443 : : }
5444 : :
5445 : : /********************************************************************
5446 : : * Remove protons from NH(+), but not PH(+)
5447 : : * Add protons to COO(-) etc.
5448 : : * or remove protons from COOH etc to make the organic part neutral
5449 : : * Note: for now (-) from N(-) can be only canceled or moved to -C=O
5450 : : ********************************************************************/
5451 [ + - + - ]: 69 : if (( *pbTautFlags & TG_FLAG_VARIABLE_PROTONS ) &&
5452 [ + + ]: 69 : t_group_info &&
5453 : 69 : mark_at_type( at, num_atoms, nAtTypeTotals ) &&
5454 [ + - ]: 5 : nAtTypeTotals[ATTOT_NUM_CHARGES])
5455 : : {
5456 : : /*
5457 : : the structure is simple to neutralize if it yields exactly
5458 : : num[H(+)] = num[N,P H(+)]
5459 : : num[N,S,O(-)] = num[=C-O(-)] + num[C-S(-)] + num[N(-)] + num[other O(-), S(-)]
5460 : :
5461 : : and n(p) = num[H(+)] - num[N,S,O(-)] (no protons, no negative N,O,S condition)
5462 : :
5463 : : Additional check is needed if:
5464 : : min{num[N,PH], num[N,P(+), not onium]} > 0
5465 : : => possibility to yield more H(+)
5466 : :
5467 : : min_charge = orig_charge(P,N,O,S) - n(p) - n(OH,SH)
5468 : : max_charge = orig_charge(P,N,O,S) - n(p) + n(O,S,N(-))
5469 : : */
5470 : :
5471 : 5 : nNumOrigTotAtoms = t_group_info->tni.nNumRemovedExplicitH + num_atoms;
5472 : 5 : pAATG->nAtTypeTotals = nAtTypeTotals;
5473 : 5 : pAATG->t_group_info = t_group_info;
5474 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5475 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5476 : : #endif
5477 : :
5478 : : /***********************************************************/
5479 : : /* */
5480 : : /* ( D E ) P R O T O N A T I O N */
5481 : : /* */
5482 : : /***********************************************************/
5483 : :
5484 : 5 : ret = RemoveNPProtonsAndAcidCharges( pCG, at, num_atoms, pAATG, pBNS, pBD );
5485 : :
5486 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5487 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5488 : : #endif
5489 [ + - - + ]: 5 : if (IS_BNS_ERROR( ret ))
5490 : : {
5491 : 0 : bError = ret;
5492 : 0 : goto exit_function;
5493 : : }
5494 : :
5495 [ + + ]: 5 : if (t_group_info->tni.bNormalizationFlags)
5496 : : {
5497 : 3 : SetInitCapFlowToCurrent( pBNS );
5498 [ + - ]: 3 : if (at_fixed_bonds_out)
5499 : : {
5500 : : /* Copy modified initial tautomeric structure for displaying
5501 : : Warning: implicit H counts in at_fixed_bonds_out include explicit Hs */
5502 : :
5503 : 3 : memcpy(at_fixed_bonds_out, at, nNumOrigTotAtoms * sizeof(at_fixed_bonds_out[0]));
5504 : :
5505 : : /* -- will be done in FillOutInputInfAtom() --
5506 : : RemoveExcessiveImplicitH( num_atoms, t_group_info->tni.nNumRemovedExplicitH, at_fixed_bonds_out );
5507 : : */
5508 : : }
5509 : : }
5510 : : }
5511 : :
5512 : : /****************** Initial bonds normalization ***************/
5513 : :
5514 [ + - ]: 69 : if (*pbTautFlags & TG_FLAG_MOVE_POS_CHARGES)
5515 : : {
5516 : : /******************* Find moveable positive charges **********************/
5517 : : do
5518 : : {
5519 : : /* Cycling while ret>0 added 2004-06-04 */
5520 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5521 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5522 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5523 : : #endif
5524 : 69 : ret = MarkChargeGroups( pCG, at, num_atoms,
5525 : : c_group_info, t_group_info,
5526 : : pBNS, pBD );
5527 : :
5528 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5529 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5530 : : #endif
5531 [ + - - + ]: 69 : if (IS_BNS_ERROR( ret ))
5532 : : {
5533 : 0 : bError = ret;
5534 : 0 : goto exit_function;
5535 : : }
5536 [ - + ]: 69 : if (ret)
5537 : : {
5538 : 0 : nChanges += ret;
5539 : 0 : ret2 = AddCGroups2BnStruct( pCG, pBNS, at, num_atoms, c_group_info );
5540 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
5541 : : {
5542 : 0 : bError = ret2;
5543 : 0 : goto exit_function;
5544 : : }
5545 : 0 : *pbTautFlagsDone |= TG_FLAG_MOVE_POS_CHARGES_DONE;
5546 : : }
5547 [ - + ]: 69 : } while (ret > 0);
5548 : :
5549 : :
5550 : : #if ( BNS_RAD_SEARCH == 1 )
5551 : : #else
5552 : : /* moveable charges may allow to cancel radicals -- check it */
5553 : : if (pBNS->tot_st_cap > pBNS->tot_st_flow)
5554 : : {
5555 : : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5556 : : if (IS_BNS_ERROR( ret ))
5557 : : {
5558 : : bError = ret;
5559 : : goto exit_function;
5560 : : }
5561 : : if (ret > 0)
5562 : : {
5563 : : /*
5564 : : pBNS->tot_st_flow += 2*ret;
5565 : : ret = ReInitBnStruct( pBNS, at, num_atoms, 1 );
5566 : : if ( IS_BNS_ERROR( ret ) ) {
5567 : : bError = ret;
5568 : : goto exit_function;
5569 : : }
5570 : : */
5571 : : bError = BNS_RADICAL_ERR;
5572 : : goto exit_function;
5573 : : }
5574 : : }
5575 : : #endif
5576 : : }
5577 : :
5578 : : /************************************************************************/
5579 : : /******** Test bonds for bond tautomerism **************/
5580 : : /******** replace moveable bonds with "alternating" bonds **************/
5581 : : /************************************************************************/
5582 : 69 : ret = BnsTestAndMarkAltBonds( pBNS, pBD, at, num_atoms, fcd, bChangeFlow, 0 );
5583 : :
5584 [ + - - + ]: 69 : if (IS_BNS_ERROR( ret ))
5585 : : {
5586 : 0 : bError = ret;
5587 : 0 : goto exit_function;
5588 : : }
5589 : : /* djb-rwth: removing redundant code */
5590 : :
5591 : : /*********************** End of initial bonds normalization *************/
5592 : :
5593 : : /* djb-rwth: removing redundant code */
5594 : :
5595 : : /* Check for tautomerism */
5596 : : /* find new tautomer groups */
5597 : 69 : salt_pass = 0;
5598 : 69 : salt_step = 0;
5599 : 69 : salt_found = 0;
5600 : :
5601 : : /*************************************************************/
5602 : : /* */
5603 : : /* M A I N C Y C L E B E G I N */
5604 : : /* */
5605 : : /*************************************************************/
5606 : :
5607 : : do
5608 : : {
5609 : : /* djb-rwth: removing redundant code */
5610 : 69 : nChanges = 0;
5611 : : /* djb-rwth: removing redundant code */
5612 : :
5613 : : /**************** Regular bond/H/(-)/positive charges tautomerism cycle begin **************/
5614 : : do
5615 : : {
5616 : : /* djb-rwth: removing redundant code */
5617 : 69 : for (taut_found = 0;
5618 [ - + ]: 69 : 0 < ( ret = MarkTautomerGroups( pCG, at, num_atoms,
5619 : : t_group_info, c_group_info,
5620 : : pBNS, pBD ) );
5621 : 0 : taut_found++)
5622 : : {
5623 : : ;
5624 : : }
5625 [ - + ]: 69 : if (ret < 0)
5626 : : {
5627 : 0 : bError = ret;
5628 : : }
5629 [ - + - - ]: 69 : if (taut_found && !salt_pass)
5630 : : {
5631 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT__ATOMS_DONE;
5632 : : }
5633 : :
5634 [ + - - + ]: 69 : if (taut_found || salt_found)
5635 : : {
5636 : : /****************** repeat bonds normalization ***************/
5637 : 0 : ret = ReInitBnStructAddGroups( pCG, pBNS, at, num_atoms,
5638 : : t_group_info, c_group_info );
5639 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5640 : : {
5641 : 0 : bError = ret;
5642 : 0 : goto exit_function;
5643 : : }
5644 : : #if ( BNS_RAD_SEARCH == 1 )
5645 : : #else
5646 : : /* discovered moveable charges and H-atoms may allow to cancel radicals */
5647 : : if (pBNS->tot_st_cap > pBNS->tot_st_flow)
5648 : : {
5649 : : ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
5650 : : if (IS_BNS_ERROR( ret ))
5651 : : {
5652 : : bError = ret;
5653 : : goto exit_function;
5654 : : }
5655 : : if (ret > 0)
5656 : : {
5657 : : /*
5658 : : pBNS->tot_st_flow += 2*ret;
5659 : : ret = ReInitBnStruct( pBNS, at, num_atoms, 1 );
5660 : : if ( IS_BNS_ERROR( ret ) ) {
5661 : : bError = ret;
5662 : : goto exit_function;
5663 : : }
5664 : : */
5665 : : bError = BNS_RADICAL_ERR;
5666 : : goto exit_function;
5667 : : }
5668 : : }
5669 : : #endif
5670 : : /****************** Update bonds normalization ***************/
5671 [ # # ]: 0 : if (*pbTautFlags & TG_FLAG_MOVE_POS_CHARGES)
5672 : : {
5673 : : /******************* Find moveable charges ***************/
5674 : : do
5675 : : {
5676 : : /* Cycling while ret>0 added 2004-06-04 */
5677 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5678 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5679 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5680 : : #endif
5681 : :
5682 : 0 : ret = MarkChargeGroups( pCG, at, num_atoms,
5683 : : c_group_info, t_group_info,
5684 : : pBNS, pBD );
5685 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5686 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5687 : : #endif
5688 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5689 : : {
5690 : 0 : bError = ret;
5691 : 0 : goto exit_function;
5692 : : }
5693 : 0 : nChanges += ret;
5694 [ # # ]: 0 : if (ret > 0)
5695 : : {
5696 : 0 : ret2 = ReInitBnStructAddGroups( pCG, pBNS,
5697 : : at, num_atoms,
5698 : : t_group_info,
5699 : : c_group_info );
5700 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
5701 : : {
5702 : 0 : bError = ret2;
5703 : 0 : goto exit_function;
5704 : : }
5705 : 0 : *pbTautFlagsDone |= TG_FLAG_MOVE_POS_CHARGES_DONE;
5706 : : }
5707 [ # # ]: 0 : } while (ret > 0);
5708 : : }
5709 : :
5710 : : /************************************************************************/
5711 : : /******** Find moveable bonds: **************/
5712 : : /******** test bonds for bond tautomerism **************/
5713 : : /******** replace moveable bonds with "alternating" bonds **************/
5714 : : /************************************************************************/
5715 : 0 : ret = BnsTestAndMarkAltBonds( pBNS, pBD, at, num_atoms, fcd, bChangeFlow, 0 );
5716 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
5717 : : {
5718 : 0 : bError = ret;
5719 : 0 : goto exit_function;
5720 : : }
5721 : 0 : nChanges += ret;
5722 : : /****************** End of update bonds normalization ***************/
5723 : :
5724 : : }
5725 : 69 : salt_found = 0;
5726 [ - + - - ]: 69 : } while (taut_found && !bError);
5727 : :
5728 : :
5729 : : /**************** Regular bond/H/(-)/positive charges tautomerism cycle end **************/
5730 : :
5731 [ - + ]: 69 : if (bError)
5732 : : {
5733 : 0 : break;
5734 : : }
5735 : :
5736 : :
5737 : : /******************* 'Salt' tautomerism permitted *************************/
5738 [ + - ]: 69 : if (*pbTautFlags & TG_FLAG_TEST_TAUT__SALTS)
5739 : : {
5740 : :
5741 [ + - ]: 69 : if (*pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS)
5742 : : {
5743 : : /*********** Requested one or more "salt" attachement migrartion test ********/
5744 [ + - - + : 69 : if (!nChanges && salt_pass && salt_step)
- - ]
5745 : : {
5746 : 0 : break; /* done */
5747 : : }
5748 [ + - ]: 69 : if (!salt_step)
5749 : : {
5750 : : /* Salt step 0: process one attachment migrartion */
5751 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5752 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5753 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5754 : : #endif
5755 : 69 : salt_found = MarkSaltChargeGroups( pCG, at, num_atoms,
5756 : : s_group_info,
5757 : : t_group_info,
5758 : : c_group_info,
5759 : : pBNS, pBD );
5760 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5761 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5762 : : #endif
5763 [ - + ]: 69 : if (salt_found < 0)
5764 : : {
5765 : 0 : bError = salt_found;
5766 : 0 : break;
5767 : : }
5768 : : else
5769 : : {
5770 [ - + ]: 69 : if (salt_found > 0)
5771 : : {
5772 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT__SALTS_DONE;
5773 : : }
5774 : : }
5775 : 69 : salt_step = !salt_found;
5776 : : /* if new 'salt' atoms have been found then repeat regular taut. search
5777 : : * MarkTautomerGroups() and do not perform salt step 1
5778 : : * if new 'salt' atoms have NOT been found then switch to salt step 1
5779 : : * and never repeat salt step 0 for the current structure
5780 : : */
5781 : : }
5782 : :
5783 [ + - ]: 69 : if (salt_step /*||
5784 : : (t_group_info->tni.bNormalizationFlags & FLAG_NORM_CONSIDER_TAUT)*/)
5785 : : {
5786 : : /* Salt step 1: process more than one attachment migration */
5787 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5788 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5789 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5790 : : #endif
5791 : 69 : salt_found = MarkSaltChargeGroups2( pCG, at, num_atoms,
5792 : : s_group_info,
5793 : : t_group_info,
5794 : : c_group_info,
5795 : : pBNS, pBD );
5796 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5797 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5798 : : #endif
5799 [ - + ]: 69 : if (salt_found < 0)
5800 : : {
5801 : 0 : bError = salt_found;
5802 : 0 : break;
5803 : : }
5804 : : else
5805 : : {
5806 [ + - - + ]: 69 : if (salt_found == 1 || salt_found == 5)
5807 : : {
5808 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT2_SALTS_DONE;
5809 [ # # ]: 0 : if (salt_found == 5)
5810 : : {
5811 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT3_SALTS_DONE;
5812 : : }
5813 : : /* salt_found == 2 => only negative charges involved */
5814 : : }
5815 : : }
5816 : : }
5817 : :
5818 : 69 : salt_pass++;
5819 : : }
5820 : : else
5821 : : {
5822 : : /* !( *pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) */
5823 : : /*************** Requested only one attachement migration test **********/
5824 [ # # # # ]: 0 : if (!nChanges && salt_pass)
5825 : : {
5826 : : /* One attachment migration */
5827 : 0 : break;
5828 : : }
5829 : : /* Salt step 0: process one attachment migration */
5830 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5831 : : pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
5832 : : CorrectFixing_NH_NH_Bonds( pBNS, at, num_atoms );
5833 : : #endif
5834 : 0 : salt_found = MarkSaltChargeGroups( pCG, at, num_atoms,
5835 : : s_group_info,
5836 : : t_group_info,
5837 : : c_group_info,
5838 : : pBNS, pBD );
5839 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
5840 : : pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
5841 : : #endif
5842 [ # # ]: 0 : if (salt_found < 0)
5843 : : {
5844 : 0 : bError = salt_found;
5845 : 0 : break;
5846 : : }
5847 : : else
5848 : : {
5849 [ # # ]: 0 : if (salt_found > 0)
5850 : : {
5851 : 0 : *pbTautFlagsDone |= TG_FLAG_TEST_TAUT__SALTS_DONE;
5852 : : }
5853 : : }
5854 : 0 : salt_pass++;
5855 : : } /* ( *pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) */
5856 : : } /* ( *pbTautFlags & TG_FLAG_TEST_TAUT__SALTS ) */
5857 [ - + - - ]: 69 : } while (salt_found && !bError);
5858 : :
5859 : : /*************************************************************/
5860 : : /* */
5861 : : /* M A I N C Y C L E E N D */
5862 : : /* */
5863 : : /*************************************************************/
5864 : :
5865 : :
5866 [ + - ]: 69 : if (*pbTautFlags & TG_FLAG_MERGE_TAUT_SALTS)
5867 : : {
5868 [ + - + - ]: 69 : if (!bError && s_group_info /*&& s_group_info->num_candidates > 0*/)
5869 : : {
5870 : 69 : ret = MergeSaltTautGroups( pCG, at, num_atoms, s_group_info,
5871 : : t_group_info, c_group_info, pBNS );
5872 [ - + ]: 69 : if (ret < 0)
5873 : : {
5874 : 0 : bError = ret;
5875 : : }
5876 : : else
5877 : : {
5878 [ - + ]: 69 : if (ret > 0)
5879 : : {
5880 : 0 : *pbTautFlagsDone |= TG_FLAG_MERGE_TAUT_SALTS_DONE;
5881 : : }
5882 : : }
5883 : : }
5884 : : }
5885 : :
5886 [ + - + - ]: 69 : if (!bError && t_group_info &&
5887 [ + - ]: 69 : ( t_group_info->bTautFlags & TG_FLAG_VARIABLE_PROTONS ) &&
5888 [ - + ]: 69 : ( t_group_info->bTautFlagsDone & ( TG_FLAG_FOUND_ISOTOPIC_ATOM_DONE | TG_FLAG_FOUND_ISOTOPIC_H_DONE ) ))
5889 : : {
5890 : 0 : ret = MakeIsotopicHGroup( at, num_atoms, s_group_info, t_group_info );
5891 [ # # ]: 0 : if (ret < 0)
5892 : : {
5893 : 0 : bError = ret;
5894 : : }
5895 : : }
5896 : :
5897 : : /* Success */
5898 : :
5899 : 69 : remove_alt_bond_marks( at, num_atoms );
5900 : :
5901 : : /************************************************
5902 : : * Temporarily ignore all non-alternating bonds
5903 : : * and mark non-ring alt bonds non-stereogenic
5904 : : ************************************************/
5905 : :
5906 : 69 : ReInitBnStructForAltBns( pBNS, at, num_atoms, 0 );
5907 : 69 : MarkRingSystemsAltBns( pBNS, 0 );
5908 : 69 : MarkNonStereoAltBns( pBNS, at, num_atoms, 0 );
5909 : : #if ( FIX_EITHER_DB_AS_NONSTEREO == 1 )
5910 : : /* second time unknown ("Either") alternating bonds are treated as non-stereogenic */
5911 : : /* stereobonds bonds that lost stereo get "Either" stereo_type */
5912 : : ReInitBnStructForAltBns( pBNS, at, num_atoms, 1 );
5913 : : MarkRingSystemsAltBns( pBNS, 1 );
5914 : : MarkNonStereoAltBns( pBNS, at, num_atoms, 1 );
5915 : : #endif
5916 : : }
5917 : : else
5918 : : {
5919 : 0 : bError = BNS_OUT_OF_RAM;
5920 : : /*printf("BNS_OUT_OF_RAM-3\n");*/
5921 : : }
5922 : :
5923 : : /*(@nnuk : Nauman Ullah Khan) */
5924 : : LOG_NO_ARGS("\n################# Modified state after (De)Protonation (L6014:ichi_bns.c) ################\n");
5925 [ + + ]: 688 : for (at_prot = 0; at_prot < num_atoms; at_prot++)
5926 : : {
5927 : : 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);
5928 : : }
5929 : : LOG_NO_ARGS("\n##########################################################################################\n");
5930 : :
5931 : 69 : exit_function:
5932 : :
5933 : : /* djb-rwth: ignoring LLVM warning: variables used to store functions return values */
5934 : 69 : pBNS = DeAllocateBnStruct(pBNS);
5935 : 69 : pBD = DeAllocateBnData(pBD);
5936 : : /*#if ( MOVE_CHARGES == 1 )*/
5937 [ + - ]: 69 : if (c_group_info)
5938 : : {
5939 [ + + ]: 69 : if (c_group_info->c_group)
5940 : : {
5941 [ + - ]: 64 : inchi_free( c_group_info->c_group );
5942 : : }
5943 [ + + ]: 69 : if (c_group_info->c_candidate)
5944 : : {
5945 [ + - ]: 64 : inchi_free( c_group_info->c_candidate );
5946 : : }
5947 : : }
5948 : : /*#endif*/
5949 [ + - + - ]: 69 : if (s_group_info && s_group_info->s_candidate)
5950 : : {
5951 [ + - ]: 69 : inchi_free( s_group_info->s_candidate );
5952 : : }
5953 [ + - + + ]: 69 : if (pAATG && pAATG->nMarkedAtom)
5954 : : {
5955 [ + - ]: 5 : inchi_free( pAATG->nMarkedAtom );
5956 [ - + - - ]: 5 : qzfree( pAATG->nEndPoint );
5957 : : /*qzfree( pAATG->nAtTypeTotals );*/ /* nAtTypeTotals is a stack array */
5958 : : }
5959 [ + - + - ]: 69 : if (t_group_info && t_group_info->tGroupNumber)
5960 : : {
5961 [ + - ]: 69 : inchi_free( t_group_info->tGroupNumber );
5962 : 69 : t_group_info->tGroupNumber = NULL;
5963 : : }
5964 : :
5965 [ + - + + : 69 : if (!bError && num_atoms == 1 && at[0].at_type == ATT_PROTON && t_group_info && !t_group_info->tni.nNumRemovedExplicitH)
- + - - -
- ]
5966 : : {
5967 : : /* remove single isolated proton */
5968 : 0 : t_group_info->tni.nNumRemovedProtons = 1;
5969 : 0 : t_group_info->tni.bNormalizationFlags |= FLAG_PROTON_SINGLE_REMOVED;
5970 [ # # ]: 0 : if (at[0].iso_atw_diff)
5971 : : {
5972 : : #if ( FIX_CURE53_ISSUE_NULL_DEREFERENCE_MAKE_A_COPY_OF_T_GROUP_INFO==1 || defined(FIX_IMPOSSIBLE_H_ISOTOPE_BUG) )
5973 [ # # ]: 0 : if (at[0].iso_atw_diff <= NUM_H_ISOTOPES)
5974 : : {
5975 : : /* djb-rwth: possible false positive oss-fuzz issue #39064660 */
5976 : 0 : t_group_info->tni.nNumRemovedProtonsIsotopic[at[0].iso_atw_diff - 1] ++;
5977 : : }
5978 : : #else
5979 : : t_group_info->tni.nNumRemovedProtonsIsotopic[at[0].iso_atw_diff - 1] ++;
5980 : : #endif
5981 : : }
5982 [ # # ]: 0 : if (at_fixed_bonds_out)
5983 : : {
5984 : 0 : memcpy(at_fixed_bonds_out, at, num_atoms * sizeof(at_fixed_bonds_out[0]));
5985 : : }
5986 : : /*num_atoms --;*/
5987 : : }
5988 : :
5989 : :
5990 : : /*
5991 : : Additional currently unused info:
5992 : :
5993 : : nOrigDelta > 0: original structure has been changed
5994 : : due to fiund augmenting path(s)
5995 : : nChanges > 0: either alt. bonds or taut. groups have been found
5996 : : */
5997 : :
5998 : : #ifdef FIX_AROM_RADICAL /* Added 2011-05-09 IPl */
5999 [ - + ]: 69 : if (stored_radicals)
6000 : : {
6001 [ # # ]: 0 : inchi_free( stored_radicals );
6002 : : }
6003 : : #endif
6004 : :
6005 [ - + ]: 69 : return bError ? bError : num_atoms; /* ret = 0 => success, any other => error */
6006 : : }
6007 : :
6008 : :
6009 : : /****************************************************************************/
6010 : 567 : int nMaxFlow2Check( BN_STRUCT *pBNS, int iedge )
6011 : : {
6012 : 567 : BNS_EDGE *pEdge = pBNS->edge + iedge;
6013 : 567 : int nMaxFlow = ( pEdge->cap & EDGE_FLOW_MASK ); /* edge cap */
6014 : :
6015 [ - + ]: 567 : if (nMaxFlow > MAX_BOND_EDGE_CAP)
6016 : : {
6017 : 0 : nMaxFlow = MAX_BOND_EDGE_CAP;
6018 : : }
6019 : 567 : return nMaxFlow;
6020 : : }
6021 : :
6022 : :
6023 : : /****************************************************************************/
6024 : 567 : int nCurFlow2Check( BN_STRUCT *pBNS, int iedge )
6025 : : {
6026 : 567 : BNS_EDGE *pEdge = pBNS->edge + iedge;
6027 : 567 : int nCurFlow = ( pEdge->flow & EDGE_FLOW_MASK ); /* edge flow */
6028 : 567 : return nCurFlow;
6029 : : }
6030 : :
6031 : :
6032 : : /****************************************************************************/
6033 : 567 : int nMinFlow2Check( BN_STRUCT *pBNS, int iedge )
6034 : : {
6035 : 567 : BNS_EDGE *pEdge = pBNS->edge + iedge;
6036 : 567 : Vertex v1 = pEdge->neighbor1;
6037 : 567 : Vertex v2 = v1 ^ pEdge->neighbor12;
6038 : 567 : int f12 = ( pEdge->flow & EDGE_FLOW_MASK );
6039 : : int rescap1, rescap2, rescap12, i, iedge_i;
6040 : :
6041 [ + + ]: 567 : if (f12 > 0)
6042 : : {
6043 [ + + ]: 42 : for (i = 0, rescap1 = 0; i < pBNS->vert[v1].num_adj_edges; i++)
6044 : : {
6045 : 30 : iedge_i = pBNS->vert[v1].iedge[i];
6046 [ + + ]: 30 : if (iedge_i == iedge)
6047 : : {
6048 : 12 : continue;
6049 : : }
6050 : 18 : rescap1 += ( pBNS->edge[iedge_i].cap & EDGE_FLOW_MASK ) - ( pBNS->edge[iedge_i].flow & EDGE_FLOW_MASK );
6051 : : }
6052 [ + + ]: 37 : for (i = 0, rescap2 = 0; i < pBNS->vert[v2].num_adj_edges; i++)
6053 : : {
6054 : 25 : iedge_i = pBNS->vert[v2].iedge[i];
6055 [ + + ]: 25 : if (iedge_i == iedge)
6056 : : {
6057 : 12 : continue;
6058 : : }
6059 : 13 : rescap2 += ( pBNS->edge[iedge_i].cap & EDGE_FLOW_MASK ) - ( pBNS->edge[iedge_i].flow & EDGE_FLOW_MASK );
6060 : : }
6061 : 12 : rescap12 = inchi_min( rescap1, rescap2 );
6062 : 12 : rescap12 = inchi_min( rescap12, f12 );
6063 : 12 : return f12 - rescap12;
6064 : : }
6065 : :
6066 : 555 : return 0;
6067 : : }
6068 : :
6069 : :
6070 : : /****************************************************************************/
6071 : 2 : int bSetBondsAfterCheckOneBond( BN_STRUCT *pBNS,
6072 : : BNS_FLOW_CHANGES *fcd,
6073 : : int nTestFlow,
6074 : : inp_ATOM *at,
6075 : : int num_atoms,
6076 : : int bChangeFlow0 )
6077 : : {
6078 : 2 : int ifcd, iedge, new_flow, ret_val, nChanges = 0, bError = 0;
6079 : : int bChangeFlow;
6080 : : Vertex v1, v2;
6081 : : int ineigh1, ineigh2;
6082 : : BNS_EDGE *pEdge;
6083 : :
6084 : 2 : bChangeFlow0 &= ~BNS_EF_CHNG_RSTR; /* do not change pEdge flow in SetBondType */
6085 [ - + ]: 2 : if (!bChangeFlow0)
6086 : : {
6087 : 0 : return 0;
6088 : : }
6089 : :
6090 : 2 : bChangeFlow = ( bChangeFlow0 & ~BNS_EF_SET_NOSTEREO );
6091 : :
6092 : : /* Find the next to the last changed */
6093 [ - + ]: 2 : if (bChangeFlow0 & BNS_EF_SET_NOSTEREO)
6094 : : {
6095 [ # # ]: 0 : for (ifcd = 0; NO_VERTEX != ( iedge = fcd[ifcd].iedge ); ifcd++) /* djb-rwth: ignoring LLVM warning: variable used */
6096 : : {
6097 : 0 : iedge = fcd[ifcd].iedge;
6098 : 0 : pEdge = pBNS->edge + iedge;
6099 [ # # ]: 0 : if (!pEdge->pass)
6100 : : {
6101 : 0 : continue;
6102 : : }
6103 : :
6104 [ # # # # ]: 0 : if (!ifcd && nTestFlow >= 0)
6105 : : {
6106 : 0 : new_flow = nTestFlow;
6107 : : }
6108 : : else
6109 : : {
6110 : 0 : new_flow = (int) pEdge->flow;
6111 : : }
6112 : :
6113 : 0 : v1 = pEdge->neighbor1;
6114 : 0 : v2 = pEdge->neighbor12 ^ v1;
6115 [ # # # # : 0 : if (v1 < num_atoms && v2 < num_atoms && new_flow != pEdge->flow0)
# # ]
6116 : : {
6117 : 0 : if (( pBNS->vert[v1].st_edge.cap0 == pBNS->vert[v1].st_edge.flow0 ) !=
6118 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.cap == pBNS->vert[v1].st_edge.flow ) ||
6119 : 0 : ( pBNS->vert[v2].st_edge.cap0 == pBNS->vert[v2].st_edge.flow0 ) !=
6120 [ # # ]: 0 : ( pBNS->vert[v2].st_edge.cap == pBNS->vert[v2].st_edge.flow ))
6121 : : {
6122 : 0 : bChangeFlow |= BNS_EF_SET_NOSTEREO;
6123 : 0 : nChanges |= BNS_EF_SET_NOSTEREO;
6124 : : }
6125 : : }
6126 : : }
6127 : : }
6128 : : else
6129 : : {
6130 [ + + ]: 8 : for (ifcd = 0; NO_VERTEX != ( iedge = fcd[ifcd].iedge ); ifcd++) /* djb-rwth: ignoring LLVM warning: variable used */
6131 : : {
6132 : : ;
6133 : : }
6134 : : }
6135 : :
6136 : : /* restore in reversed order to correctly handle vertex changed more than once */
6137 [ + + ]: 8 : for (ifcd -= 1; 0 <= ifcd; ifcd--)
6138 : : {
6139 : :
6140 : 6 : iedge = fcd[ifcd].iedge;
6141 : 6 : pEdge = pBNS->edge + iedge;
6142 [ - + ]: 6 : if (!pEdge->pass)
6143 : : {
6144 : 0 : continue;
6145 : : }
6146 : :
6147 [ + + + - ]: 6 : if (!ifcd && nTestFlow >= 0)
6148 : : {
6149 : 2 : new_flow = nTestFlow;
6150 : : }
6151 : : else
6152 : : {
6153 : 4 : new_flow = (int) pEdge->flow;
6154 : : }
6155 : :
6156 : 6 : v1 = pEdge->neighbor1;
6157 : 6 : v2 = pEdge->neighbor12 ^ v1;
6158 [ + - + - : 6 : if (v1 < num_atoms && v2 < num_atoms && bChangeFlow && new_flow != pEdge->flow0)
+ - + - ]
6159 : : {
6160 : 6 : ineigh1 = pEdge->neigh_ord[0];
6161 : 6 : ineigh2 = pEdge->neigh_ord[1];
6162 : 6 : ret_val = SetAtomBondType( pEdge, &at[v1].bond_type[ineigh1], &at[v2].bond_type[ineigh2], new_flow - pEdge->flow0, bChangeFlow );
6163 [ + - + - ]: 6 : if (!IS_BNS_ERROR( ret_val ))
6164 : : {
6165 : 6 : nChanges |= ( ret_val > 0 );
6166 : : }
6167 : : else
6168 : : {
6169 : 0 : bError = ret_val;
6170 : : }
6171 : : }
6172 : 6 : pEdge->pass = 0;
6173 : : }
6174 : :
6175 [ - + ]: 2 : return bError ? bError : nChanges;
6176 : : }
6177 : :
6178 : :
6179 : : /****************************************************************************/
6180 : 5 : int bRestoreFlowAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd )
6181 : : {
6182 : : int ifcd, iedge;
6183 : : Vertex v1, v2;
6184 : : BNS_EDGE *pEdge;
6185 : :
6186 : : /* Find the next to the last changed */
6187 [ + + ]: 20 : for (ifcd = 0; NO_VERTEX != ( iedge = fcd[ifcd].iedge ); ifcd++) /* djb-rwth: ignoring LLVM warning: variable used */
6188 : : {
6189 : : ;
6190 : : }
6191 : :
6192 : : /* Restore in reversed order to correctly handle vertex changed more than once */
6193 [ + + ]: 20 : for (ifcd -= 1; 0 <= ifcd; ifcd--)
6194 : : {
6195 : : /* Restore edge flow & cap */
6196 : 15 : iedge = fcd[ifcd].iedge;
6197 : 15 : pEdge = pBNS->edge + iedge;
6198 : 15 : pEdge->flow = fcd[ifcd].flow;
6199 : 15 : pEdge->cap = fcd[ifcd].cap;
6200 : 15 : pEdge->pass = 0;
6201 : :
6202 : : /* Restore st-flow, cap */
6203 [ + - ]: 15 : if (NO_VERTEX != ( v1 = fcd[ifcd].v1 ))
6204 : : {
6205 : 15 : pBNS->vert[v1].st_edge.flow = fcd[ifcd].flow_st1;
6206 : 15 : pBNS->vert[v1].st_edge.cap = fcd[ifcd].cap_st1;
6207 : 15 : pBNS->vert[v1].st_edge.pass = 0;
6208 : : }
6209 [ + + ]: 15 : if (NO_VERTEX != ( v2 = fcd[ifcd].v2 ))
6210 : : {
6211 : 5 : pBNS->vert[v2].st_edge.flow = fcd[ifcd].flow_st2;
6212 : 5 : pBNS->vert[v2].st_edge.cap = fcd[ifcd].cap_st2;
6213 : 5 : pBNS->vert[v2].st_edge.pass = 0;
6214 : : }
6215 : : }
6216 : :
6217 : 5 : return 0;
6218 : : }
6219 : :
6220 : :
6221 : : /****************************************************************************/
6222 : 5 : int bSetFlowToCheckOneBond( BN_STRUCT *pBNS,
6223 : : int iedge,
6224 : : int flow,
6225 : : BNS_FLOW_CHANGES *fcd )
6226 : : {
6227 : 5 : BNS_EDGE *pEdge = pBNS->edge + iedge;
6228 : 5 : int f12 = ( pEdge->flow & EDGE_FLOW_MASK ); /* the original flow */
6229 : 5 : int ifcd = 0;
6230 : 5 : int nDots = 0;
6231 : : int i, iedge_i;
6232 : :
6233 : 5 : fcd[ifcd].iedge = NO_VERTEX;
6234 : :
6235 [ + - ]: 5 : if (f12 < flow)
6236 : : {
6237 : : /* Increase edge flow: Grab flow from the neighbors and delete it: set flow12=cap12 = 0 */
6238 : : /************************************************************************************/
6239 : : /* For example, simulate a new fixed double bond in place of a single bond and */
6240 : : /* creates ONE or NONE (in case of a radical on adjacent atom) augmenting paths and */
6241 : : /* makes it impossible for the BNS to set same flow as it originally was */
6242 : : /************************************************************************************/
6243 : 5 : Vertex v1 = pEdge->neighbor1;
6244 : 5 : Vertex v2 = v1 ^ pEdge->neighbor12;
6245 : : Vertex v_i; /* neighbor of v1 or v2 */
6246 : : BNS_EDGE *pEdge_i;
6247 : : int delta1, delta2, f, st_edge_rescap;
6248 : :
6249 [ + - ]: 5 : if (( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow ||
6250 [ - + ]: 5 : ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow)
6251 : : {
6252 : 0 : return BNS_CANT_SET_BOND;
6253 : : }
6254 [ + - ]: 5 : if (( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12 ||
6255 [ - + ]: 5 : ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12)
6256 : : {
6257 : 0 : return BNS_CAP_FLOW_ERR;
6258 : : }
6259 : :
6260 : 5 : fcd[ifcd].iedge = iedge;
6261 : 5 : fcd[ifcd].flow = pEdge->flow;
6262 : 5 : fcd[ifcd].cap = pEdge->cap;
6263 : :
6264 : 5 : fcd[ifcd].v1 = v1;
6265 : 5 : fcd[ifcd].flow_st1 = pBNS->vert[v1].st_edge.flow;
6266 : 5 : fcd[ifcd].cap_st1 = pBNS->vert[v1].st_edge.cap;
6267 : :
6268 : 5 : fcd[ifcd].v2 = v2;
6269 : 5 : fcd[ifcd].flow_st2 = pBNS->vert[v2].st_edge.flow;
6270 : 5 : fcd[ifcd].cap_st2 = pBNS->vert[v2].st_edge.cap;
6271 : :
6272 : 5 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6273 : 5 : pEdge->pass |= 64;
6274 : :
6275 : 5 : delta1 = delta2 = flow - f12;
6276 : :
6277 [ - + ]: 5 : if (f12 > 0)
6278 : : {
6279 : : /* Remove old edge flow from the flow and cap of the adjacent vertices' st-edges */
6280 : 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 );
6281 : 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 );
6282 : 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 );
6283 : 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 );
6284 : : /* Delete current edge flow and capacity */
6285 : 0 : pEdge->flow = ( pEdge->flow & ~EDGE_FLOW_MASK );
6286 : : }
6287 : 5 : pEdge->cap = ( pEdge->cap & ~EDGE_FLOW_MASK );
6288 : :
6289 : : /* Grab the adjacent vertex1 radical (st_edge_rescap) if it exists */
6290 : 5 : st_edge_rescap = ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) - ( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK );
6291 [ - + - - ]: 5 : while (st_edge_rescap && delta1)
6292 : : {
6293 : 0 : st_edge_rescap--; /* grab the radical */
6294 : 0 : delta1--;
6295 : 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 );
6296 : 0 : nDots--;
6297 : : }
6298 : :
6299 : : /* Grab the adjacent vertex2 radical (st_edge_rescap) if it exists */
6300 : 5 : st_edge_rescap = ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) - ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK );
6301 [ - + - - ]: 5 : while (st_edge_rescap && delta2)
6302 : : {
6303 : 0 : st_edge_rescap--; /* grab the radical */
6304 : 0 : delta2--;
6305 : 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 );
6306 : 0 : nDots--;
6307 : : }
6308 : :
6309 : : /* Grab flows from v1 neighbors */
6310 [ + + + - ]: 12 : for (i = 0; delta1 && i < pBNS->vert[v1].num_adj_edges; i++)
6311 : : {
6312 : 7 : iedge_i = pBNS->vert[v1].iedge[i];
6313 [ + + ]: 7 : if (iedge_i == iedge)
6314 : : {
6315 : 2 : continue;
6316 : : }
6317 : 5 : pEdge_i = pBNS->edge + iedge_i;
6318 [ - + ]: 5 : if (IS_FORBIDDEN( pEdge_i->forbidden, pBNS ))
6319 : : {
6320 : 0 : continue;
6321 : : }
6322 : 5 : f = ( pEdge_i->flow & EDGE_FLOW_MASK );
6323 [ + - ]: 5 : if (f)
6324 : : {
6325 : 5 : v_i = pEdge_i->neighbor12 ^ v1;
6326 : :
6327 : 5 : fcd[ifcd].iedge = iedge_i;
6328 : 5 : fcd[ifcd].flow = pEdge_i->flow;
6329 : 5 : fcd[ifcd].cap = pEdge_i->cap;
6330 : :
6331 : 5 : fcd[ifcd].v1 = v_i;
6332 : 5 : fcd[ifcd].flow_st1 = pBNS->vert[v_i].st_edge.flow;
6333 : 5 : fcd[ifcd].cap_st1 = pBNS->vert[v_i].st_edge.cap;
6334 : :
6335 : 5 : fcd[ifcd].v2 = NO_VERTEX;
6336 : 5 : fcd[ifcd].flow_st2 = 0;
6337 : 5 : fcd[ifcd].cap_st2 = 0;
6338 : :
6339 : 5 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6340 : 5 : pEdge_i->pass |= 64;
6341 : :
6342 [ + + + - ]: 10 : while (f && delta1)
6343 : : {
6344 : 5 : f--;
6345 : 5 : delta1--;
6346 : 5 : pEdge_i->flow = ( ( pEdge_i->flow & EDGE_FLOW_MASK ) - 1 ) | ( pEdge_i->flow & ~EDGE_FLOW_MASK );
6347 : 5 : 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 );
6348 : : /* next 2 lines added 01-22-2002 */
6349 : 5 : 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 );
6350 : 5 : 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 );
6351 : :
6352 : 5 : nDots++;
6353 : : }
6354 : : }
6355 : : }
6356 : :
6357 : : /* Grab flows from v2 neighbors */
6358 [ + + + - ]: 17 : for (i = 0; delta2 && i < pBNS->vert[v2].num_adj_edges; i++)
6359 : : {
6360 : 12 : iedge_i = pBNS->vert[v2].iedge[i];
6361 [ + + ]: 12 : if (iedge_i == iedge)
6362 : : {
6363 : 5 : continue;
6364 : : }
6365 : 7 : pEdge_i = pBNS->edge + iedge_i;
6366 [ - + ]: 7 : if (IS_FORBIDDEN( pEdge_i->forbidden, pBNS ))
6367 : : {
6368 : 0 : continue;
6369 : : }
6370 : 7 : f = ( pEdge_i->flow & EDGE_FLOW_MASK );
6371 [ + + ]: 7 : if (f)
6372 : : {
6373 : 5 : v_i = pEdge_i->neighbor12 ^ v2;
6374 : :
6375 : 5 : fcd[ifcd].iedge = iedge_i;
6376 : 5 : fcd[ifcd].flow = pEdge_i->flow;
6377 : 5 : fcd[ifcd].cap = pEdge_i->cap;
6378 : :
6379 : 5 : fcd[ifcd].v1 = v_i;
6380 : 5 : fcd[ifcd].flow_st1 = pBNS->vert[v_i].st_edge.flow;
6381 : 5 : fcd[ifcd].cap_st1 = pBNS->vert[v_i].st_edge.cap;
6382 : :
6383 : 5 : fcd[ifcd].v2 = NO_VERTEX;
6384 : 5 : fcd[ifcd].flow_st2 = 0;
6385 : 5 : fcd[ifcd].cap_st2 = 0;
6386 : :
6387 : 5 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6388 : 5 : pEdge_i->pass |= 64;
6389 : :
6390 [ + + + - ]: 10 : while (f && delta2)
6391 : : {
6392 : 5 : f--;
6393 : 5 : delta2--;
6394 : 5 : pEdge_i->flow = ( ( pEdge_i->flow & EDGE_FLOW_MASK ) - 1 ) | ( pEdge_i->flow & ~EDGE_FLOW_MASK );
6395 : 5 : 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 );
6396 : : /* next 2 lines added 01-22-2002 */
6397 : 5 : 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 );
6398 : 5 : 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 );
6399 : :
6400 : 5 : nDots++;
6401 : : }
6402 : : }
6403 : : }
6404 [ + - - + ]: 5 : if (delta1 || delta2)
6405 : : {
6406 : 0 : return BNS_CANT_SET_BOND;
6407 : : }
6408 : : }
6409 : :
6410 [ - + ]: 5 : if (f12 >= flow)
6411 : : {
6412 : : /* Decrease edge flow: Redirect flow to the neighbors and delete it on the edge: set flow12=cap12 = 0 */
6413 : : /* f12==flow fixes flow through the edge so that BNS cannot change it */
6414 : : /**********************************************************************************************/
6415 : : /* For example, simulate a removal of a double bond and create ONE or NONE augmenting path */
6416 : : /* Make it impossible for BNS to set same flow as it originally was */
6417 : : /**********************************************************************************************/
6418 : 0 : Vertex v1 = pEdge->neighbor1;
6419 : 0 : Vertex v2 = ( v1 ^ pEdge->neighbor12 );
6420 : : int delta;
6421 : : /* if NOT (st-cap >= st-flow >= f12 >= flow) then error in the BN structure */
6422 [ # # ]: 0 : if (( pBNS->vert[v1].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12 ||
6423 [ # # ]: 0 : ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ) < f12 ||
6424 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow ||
6425 [ # # ]: 0 : ( pBNS->vert[v2].st_edge.cap & EDGE_FLOW_ST_MASK ) < flow)
6426 : : {
6427 : 0 : return BNS_CAP_FLOW_ERR;
6428 : : }
6429 : 0 : fcd[ifcd].iedge = iedge;
6430 : 0 : fcd[ifcd].flow = pEdge->flow;
6431 : 0 : fcd[ifcd].cap = pEdge->cap;
6432 : :
6433 : 0 : fcd[ifcd].v1 = v1;
6434 : 0 : fcd[ifcd].flow_st1 = pBNS->vert[v1].st_edge.flow;
6435 : 0 : fcd[ifcd].cap_st1 = pBNS->vert[v1].st_edge.cap;
6436 : :
6437 : 0 : fcd[ifcd].v2 = v2;
6438 : 0 : fcd[ifcd].flow_st2 = pBNS->vert[v2].st_edge.flow;
6439 : 0 : fcd[ifcd].cap_st2 = pBNS->vert[v2].st_edge.cap;
6440 : :
6441 : 0 : fcd[++ifcd].iedge = NO_VERTEX; /* mark the end of the fcd[] data */
6442 : 0 : pEdge->pass |= 64;
6443 : :
6444 : 0 : delta = f12 - flow;
6445 : :
6446 : : /* Remove current edge flow from st-edges */
6447 : : /* -- seem to be a bug --
6448 : : 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);
6449 : : 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);
6450 : : */
6451 : :
6452 : : /* Replacement to the above 2 lines 01-16-2002 */
6453 : : /* Remove old edge flow from the flow of the adjacent vertices' st-edges */
6454 : :
6455 : 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 );
6456 : 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 );
6457 : :
6458 : : /* Sdded 01-16-2002: reduce st-cap if new flow > 0 */
6459 : : /* Remove new edge flow from the cap of the adjacent vertices' st-edges */
6460 : 0 : 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 );
6461 : 0 : 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 );
6462 : :
6463 : : /* delete current edge flow and capacity */
6464 : 0 : pEdge->flow = ( pEdge->flow & ~EDGE_FLOW_MASK );
6465 : 0 : pEdge->cap = ( pEdge->cap & ~EDGE_FLOW_MASK );
6466 : 0 : nDots = 2 * delta;
6467 : : }
6468 : :
6469 : 5 : return nDots;
6470 : : }
6471 : :
6472 : :
6473 : : /****************************************************************************
6474 : : bAddNewVertex( ... )
6475 : :
6476 : : Connect new (fictitious, temporary) vertex to nVertDoubleBond by a new edge
6477 : : Add radical (set st-cap=1) to the new vertex, set cap=1 to the new edge
6478 : : Add radical (set st-cap=1) to nVertSingleBond
6479 : : Find augmenting path connecting new vertex to nVertSingleBond
6480 : : This corresponds to moving H-atom from nVertSingleBond to nVertDoubleBond
6481 : : ****************************************************************************/
6482 : 0 : int bAddNewVertex( BN_STRUCT *pBNS,
6483 : : int nVertDoubleBond,
6484 : : int nCap,
6485 : : int nFlow,
6486 : : int nMaxAdjEdges,
6487 : : int *nDots )
6488 : : {
6489 : 0 : Vertex vlast = pBNS->num_vertices - 1;
6490 : 0 : Vertex vnew = pBNS->num_vertices;
6491 : 0 : Vertex v2 = nVertDoubleBond;
6492 : 0 : BNS_VERTEX *pVert2 = pBNS->vert + v2; /* pointer to an old vertex */
6493 : 0 : BNS_VERTEX *pNewVert = pBNS->vert + vnew; /* pointer to a new vertex */
6494 : :
6495 : 0 : EdgeIndex iedge = pBNS->num_edges;
6496 : 0 : BNS_EDGE *pEdge = pBNS->edge + iedge; /* pointer to a new edge */
6497 : :
6498 [ # # # # ]: 0 : if (iedge >= pBNS->max_edges || vnew >= pBNS->max_vertices)
6499 : : {
6500 : 0 : return BNS_VERT_EDGE_OVFL; /* edges or vertices overflow */
6501 : : }
6502 [ # # ]: 0 : if (( pBNS->vert[vlast].iedge - pBNS->iedge ) + pBNS->vert[vlast].max_adj_edges + nMaxAdjEdges >= pBNS->max_iedges)
6503 : : {
6504 : 0 : return BNS_VERT_EDGE_OVFL; /* iedges overflow */
6505 : : }
6506 [ # # # # ]: 0 : if (pVert2->num_adj_edges >= pVert2->max_adj_edges || nMaxAdjEdges <= 0)
6507 : : {
6508 : 0 : return BNS_VERT_EDGE_OVFL; /* neighbors overflow */
6509 : : }
6510 : :
6511 : : /* Fill out the new edge, set its cap and flow, connect */
6512 : : /* memset( pEdge, 0, sizeof(*pEdge) ); */
6513 : 0 : pEdge->cap = pEdge->cap0 = nCap;
6514 : 0 : pEdge->flow = pEdge->flow0 = nFlow;
6515 : 0 : pEdge->pass = 0;
6516 : 0 : pEdge->neighbor1 = v2;
6517 : 0 : pEdge->neighbor12 = v2 ^ vnew;
6518 : 0 : pEdge->forbidden = 0;
6519 : :
6520 : : /* Fill out the new vertex */
6521 : : /* memset( pNewVert, 0, sizeof(*pNewVert) ); */
6522 : 0 : pNewVert->max_adj_edges = nMaxAdjEdges;
6523 : 0 : pNewVert->num_adj_edges = 0;
6524 : 0 : pNewVert->st_edge.cap0 = pNewVert->st_edge.cap = nCap;
6525 : 0 : pNewVert->st_edge.flow0 = pNewVert->st_edge.flow = nFlow;
6526 : 0 : pNewVert->st_edge.pass = 0; /* add initialization; added 2006-03-25 */
6527 : 0 : pNewVert->iedge = pBNS->vert[vlast].iedge + pBNS->vert[vlast].max_adj_edges;
6528 : 0 : pNewVert->type = BNS_VERT_TYPE_TEMP;
6529 : 0 : *nDots += nCap - nFlow;
6530 : :
6531 : 0 : pEdge->neigh_ord[v2 > vnew] = pVert2->num_adj_edges;
6532 : 0 : pEdge->neigh_ord[v2 < vnew] = pNewVert->num_adj_edges;
6533 : :
6534 : : /* Connect new edge to v2 */
6535 : 0 : pVert2->iedge[pVert2->num_adj_edges++] = iedge;
6536 : : /* Connect new edge to vnew */
6537 : 0 : pNewVert->iedge[pNewVert->num_adj_edges++] = iedge;
6538 : :
6539 : : /* Fix v2 flow and cap */
6540 : 0 : *nDots -= (int) pVert2->st_edge.cap - (int) pVert2->st_edge.flow;
6541 : 0 : pVert2->st_edge.flow += nFlow;
6542 [ # # ]: 0 : if (pVert2->st_edge.cap < pVert2->st_edge.flow)
6543 : : {
6544 : 0 : pVert2->st_edge.cap = pVert2->st_edge.flow;
6545 : : }
6546 : 0 : *nDots += (int) pVert2->st_edge.cap - (int) pVert2->st_edge.flow;
6547 : :
6548 : 0 : pBNS->num_edges++;
6549 : 0 : pBNS->num_vertices++;
6550 : :
6551 : 0 : return vnew;
6552 : : }
6553 : :
6554 : :
6555 : : /****************************************************************************/
6556 : 0 : int AddNewEdge( BNS_VERTEX *p1,
6557 : : BNS_VERTEX *p2,
6558 : : BN_STRUCT *pBNS,
6559 : : int nEdgeCap,
6560 : : int nEdgeFlow )
6561 : : {
6562 : 0 : int ip1 = (int) ( p1 - pBNS->vert );
6563 : 0 : int ip2 = (int) ( p2 - pBNS->vert );
6564 : 0 : int ie = pBNS->num_edges;
6565 : 0 : BNS_EDGE *e = pBNS->edge + ie;
6566 : :
6567 : : /* Debug: check bounds */
6568 [ # # # # ]: 0 : if (ip1 >= pBNS->max_vertices || ip1 < 0 ||
6569 [ # # # # ]: 0 : ip2 >= pBNS->max_vertices || ip2 < 0 ||
6570 [ # # # # ]: 0 : ie >= pBNS->max_edges || ie < 0 ||
6571 [ # # ]: 0 : ( p1->iedge - pBNS->iedge ) < 0 ||
6572 [ # # ]: 0 : ( p1->iedge - pBNS->iedge ) + p1->max_adj_edges > pBNS->max_iedges ||
6573 [ # # ]: 0 : ( p2->iedge - pBNS->iedge ) < 0 ||
6574 [ # # ]: 0 : ( p2->iedge - pBNS->iedge ) + p2->max_adj_edges > pBNS->max_iedges ||
6575 [ # # ]: 0 : p1->num_adj_edges >= p1->max_adj_edges ||
6576 [ # # ]: 0 : p2->num_adj_edges >= p2->max_adj_edges)
6577 : : {
6578 : 0 : return BNS_VERT_EDGE_OVFL;
6579 : : }
6580 : :
6581 : : /* Clear the edge */
6582 : 0 : memset( e, 0, sizeof( *e ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6583 : :
6584 : : /* Connect */
6585 : 0 : e->neighbor1 = inchi_min( ip1, ip2 );
6586 : 0 : e->neighbor12 = ip1 ^ ip2;
6587 : 0 : p1->iedge[p1->num_adj_edges] = ie;
6588 : 0 : p2->iedge[p2->num_adj_edges] = ie;
6589 : 0 : e->neigh_ord[ip1 > ip2] = p1->num_adj_edges++;
6590 : 0 : e->neigh_ord[ip1 < ip2] = p2->num_adj_edges++;
6591 : 0 : e->cap = e->cap0 = nEdgeCap;
6592 : 0 : e->flow = e->flow0 = nEdgeFlow;
6593 : 0 : p1->st_edge.flow += nEdgeFlow;
6594 : 0 : p2->st_edge.flow += nEdgeFlow;
6595 [ # # ]: 0 : if (p1->st_edge.cap < p1->st_edge.flow)
6596 : : {
6597 : 0 : p1->st_edge.cap = p1->st_edge.flow;
6598 : : }
6599 [ # # ]: 0 : if (p2->st_edge.cap < p2->st_edge.flow)
6600 : : {
6601 : 0 : p2->st_edge.cap = p2->st_edge.flow;
6602 : : }
6603 : 0 : pBNS->num_edges++;
6604 : :
6605 : 0 : return ie;
6606 : : }
6607 : :
6608 : :
6609 : : /****************************************************************************/
6610 : 0 : BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type )
6611 : : {
6612 [ # # ]: 0 : if (v1 < pBNS->num_atoms)
6613 : : {
6614 : : Vertex v2;
6615 : : BNS_EDGE *pEdge1;
6616 : 0 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6617 : 0 : int i = pVert1->num_adj_edges - 1;
6618 : :
6619 [ # # ]: 0 : while (0 <= i)
6620 : : {
6621 : 0 : pEdge1 = pBNS->edge + pVert1->iedge[i];
6622 : 0 : v2 = pEdge1->neighbor12 ^ v1;
6623 [ # # ]: 0 : if (pBNS->vert[v2].type == type)
6624 : : {
6625 [ # # ]: 0 : return IS_FORBIDDEN( pEdge1->forbidden, pBNS ) ? NO_VERTEX : pVert1->iedge[i];
6626 : : }
6627 : 0 : i--;
6628 : : }
6629 : 0 : return NO_VERTEX; /* not found t-group */
6630 : : }
6631 : : else
6632 : : {
6633 [ # # ]: 0 : if (v1 < pBNS->num_vertices)
6634 : : {
6635 : 0 : return NO_VERTEX;
6636 : : }
6637 : : }
6638 : :
6639 : 0 : return BNS_VERT_EDGE_OVFL;
6640 : : }
6641 : :
6642 : :
6643 : : /****************************************************************************/
6644 : 0 : Vertex GetGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type )
6645 : : {
6646 [ # # ]: 0 : if (v1 < pBNS->num_atoms)
6647 : : {
6648 : : Vertex v2;
6649 : : BNS_EDGE *pEdge1;
6650 : 0 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6651 : 0 : int i = pVert1->num_adj_edges - 1;
6652 : :
6653 : : AT_NUMB type2;
6654 : :
6655 [ # # ]: 0 : if (type == BNS_VERT_TYPE_ENDPOINT)
6656 : : {
6657 : 0 : type2 = BNS_VERT_TYPE_TGROUP;
6658 : : }
6659 : : else
6660 : : {
6661 [ # # ]: 0 : if (type == BNS_VERT_TYPE_C_POINT)
6662 : : {
6663 : 0 : type2 = BNS_VERT_TYPE_C_GROUP;
6664 : : }
6665 : : else
6666 : : {
6667 : 0 : type2 = 0;
6668 : : }
6669 : : }
6670 : :
6671 [ # # ]: 0 : if (( pVert1->type & type ) == type)
6672 : : {
6673 [ # # ]: 0 : while (0 <= i)
6674 : : {
6675 : 0 : pEdge1 = pBNS->edge + pVert1->iedge[i];
6676 : 0 : v2 = pEdge1->neighbor12 ^ v1;
6677 [ # # ]: 0 : if (pBNS->vert[v2].type == type2)
6678 : : {
6679 [ # # ]: 0 : if (IS_FORBIDDEN( pEdge1->forbidden, pBNS ))
6680 : : {
6681 : 0 : return NO_VERTEX;
6682 : : }
6683 : 0 : return v2;
6684 : : }
6685 : 0 : i--;
6686 : : }
6687 : : }
6688 : 0 : return BNS_BOND_ERR; /* not found t-group */
6689 : : }
6690 : : else
6691 : : {
6692 [ # # ]: 0 : if (v1 < pBNS->num_vertices)
6693 : : {
6694 : 0 : return NO_VERTEX;
6695 : : }
6696 : : }
6697 : :
6698 : 0 : return BNS_VERT_EDGE_OVFL;
6699 : : }
6700 : :
6701 : :
6702 : : /****************************************************************************/
6703 : 0 : int bAddStCapToAVertex( BN_STRUCT *pBNS,
6704 : : Vertex v1,
6705 : : Vertex v2,
6706 : : VertexFlow *nOldCapVertSingleBond,
6707 : : int *nDots,
6708 : : int bAdjacentDonors )
6709 : : {
6710 : 0 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6711 : : BNS_VERTEX *pVert;
6712 : : BNS_EDGE *pEdge;
6713 : : Vertex v;
6714 : : int i, n;
6715 : : VertexFlow nNewCap;
6716 : :
6717 : : /* Change v1: increment its st-cap */
6718 : 0 : n = 0;
6719 : 0 : nOldCapVertSingleBond[n++] = pVert1->st_edge.cap;
6720 : : /*if ( pVert1->st_edge.cap == pVert1->st_edge.flow ) {*/
6721 : 0 : pVert1->st_edge.cap++;
6722 : 0 : *nDots += 1;
6723 : :
6724 : : /*}*/
6725 : : /* increment caps of adjacent edges if
6726 : : (1) the neighbor has st-cap != 0 and
6727 : : (2) (edge cap==0) OR (nSumEdgeCap < pVert1->st_edge.cap && pVert->st_edge.flow > pVert1->st_edge.cap)
6728 : : */
6729 [ # # ]: 0 : if (!( pVert1->type & BNS_VERT_TYPE_ANY_GROUP ))
6730 : : {
6731 : : /*
6732 : : AT_NUMB nSumEdgeCap = 0;
6733 : : for ( i = 0; i < pVert1->num_adj_edges; i ++ ) {
6734 : : pEdge = pBNS->edge + pVert1->iedge[i];
6735 : : nSumEdgeCap += pEdge->cap;
6736 : : }
6737 : : */
6738 : : /* do not increment caps of t-group or c-group edges */
6739 [ # # ]: 0 : for (i = 0; i < pVert1->num_adj_edges; i++)
6740 : : {
6741 : 0 : pEdge = pBNS->edge + pVert1->iedge[i];
6742 : 0 : nOldCapVertSingleBond[n++] = pEdge->cap; /* save edge cap */
6743 : 0 : v = pEdge->neighbor12 ^ v1;
6744 [ # # # # ]: 0 : if (v == v2 && !bAdjacentDonors)
6745 : : {
6746 : 0 : continue;
6747 : : }
6748 : 0 : pVert = pBNS->vert + v;
6749 [ # # ]: 0 : if (pVert->type & BNS_VERT_TYPE_ANY_GROUP)
6750 : 0 : continue;
6751 : 0 : nNewCap = inchi_min( pVert->st_edge.cap, pVert1->st_edge.cap );
6752 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
6753 : 0 : pEdge->cap = nNewCap; /* change edge cap */
6754 : : /*
6755 : : if ( pVert->st_edge.cap > 0 && !pEdge->cap ) {
6756 : : pEdge->cap ++;
6757 : : } else
6758 : : if ( pVert->st_edge.flow > pVert1->st_edge.cap &&
6759 : : pEdge->cap < MAX_BOND_EDGE_CAP &&
6760 : : nSumEdgeCap < pVert1->st_edge.cap ) {
6761 : : pEdge->cap ++;
6762 : : }
6763 : : */
6764 : : }
6765 : : }
6766 : :
6767 : 0 : return n; /* number of elements in nOldCapVertSingleBond[*] */
6768 : : }
6769 : :
6770 : :
6771 : : #define BNS_CHK_ALTP_NO_ALTPATH 0
6772 : : #define BNS_CHK_ALTP_SAME_TGROUP 1
6773 : : #define BNS_CHK_ALTP_SAME_VERTEX 2
6774 : : #define BNS_CHK_ALTP_SET_SUCCESS 4
6775 : :
6776 : :
6777 : : /****************************************************************************/
6778 : 0 : int bSetBnsToCheckAltPath( BN_STRUCT *pBNS,
6779 : : int nVertDoubleBond,
6780 : : int nVertSingleBond,
6781 : : AT_NUMB type,
6782 : : int path_type,
6783 : : ALT_PATH_CHANGES *apc,
6784 : : BNS_FLOW_CHANGES *fcd,
6785 : : int *nDots )
6786 : : {
6787 : :
6788 [ # # # # ]: 0 : if (!pBNS->vert[nVertDoubleBond].st_edge.flow &&
6789 : :
6790 [ # # # # ]: 0 : !( path_type == ALT_PATH_MODE_REM2H_CHG ||
6791 [ # # ]: 0 : path_type == ALT_PATH_MODE_ADD2H_CHG ||
6792 : : path_type == ALT_PATH_MODE_REM2H_TST ||
6793 : : path_type == ALT_PATH_MODE_ADD2H_TST )
6794 : : )
6795 : : {
6796 : 0 : return BNS_CHK_ALTP_NO_ALTPATH;
6797 : : }
6798 : : else
6799 : : {
6800 : : Vertex vNew;
6801 : 0 : Vertex v1 = nVertSingleBond;
6802 : 0 : Vertex v2 = nVertDoubleBond;
6803 : :
6804 : 0 : BNS_VERTEX *pVert1 = pBNS->vert + v1;
6805 : 0 : BNS_VERTEX *pVert2 = pBNS->vert + v2;
6806 : 0 : int n, bAdjacentDonors = 0;
6807 : 0 : int ifcd = 0;
6808 : :
6809 : 0 : Vertex t1 = NO_VERTEX;
6810 : 0 : Vertex t2 = NO_VERTEX;
6811 : : int iapc;
6812 : :
6813 : : /*#if ( TEST_REMOVE_S_ATOMS == 1 )*/ /* && ALT_PATH_MODE_4_SALT == path_type */
6814 [ # # # # ]: 0 : if (( *pBNS->pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) &&
6815 [ # # ]: 0 : ALT_PATH_MODE_4_SALT2 == path_type &&
6816 : : ( BNS_VERT_TYPE_ENDPOINT & type ))
6817 : : {
6818 : : /*
6819 : : ---------------------------------------------------------
6820 : : \ action | DB action (v2) | SB action (v1) |
6821 : : vertex \ | accept H @ vertex | donate H @ vertex |
6822 : : type \ | nVertDoubleBond | nVertSingleBond |
6823 : : ----------------+-------------------+-------------------+
6824 : : -ZH (v1) | error | -ZH(.) |
6825 : : (cap>0 on edge | | increment |
6826 : : except v1-v2) | | st-cap on Z |
6827 : : ----------------+-------------------+-------------------+
6828 : : =Z (v2) | =Z-(.) | error |
6829 : : (st-flow>0) | add fict vertex | |
6830 : : | with st-cap=1 | |
6831 : : ----------------+-------------------+-------------------+
6832 : : endpoint | T(.) | T-(.) |
6833 : : of t-group | increment | add fict vertex |
6834 : : represented | st-cap on T | with st-cap=1 |
6835 : : by fictitious | | |
6836 : : vertex T | | |
6837 : : ---------------------------------------------------------
6838 : : */
6839 : :
6840 : : int bSet_v1; /* indicator: v1 has been set */
6841 : : int bSet_v2; /* indicator: v2 has been set */
6842 : : int i;
6843 : :
6844 : 0 : Vertex v1t = NO_VERTEX;
6845 : 0 : Vertex v2t = NO_VERTEX;
6846 : : Vertex v1Act, v2Act;
6847 : : Vertex v;
6848 : :
6849 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6850 : 0 : fcd[ifcd].iedge = NO_VERTEX;
6851 : 0 : *nDots = 0;
6852 : :
6853 [ # # ]: 0 : if (v1 == v2)
6854 : : {
6855 : 0 : return BNS_CHK_ALTP_SAME_VERTEX;
6856 : : }
6857 : :
6858 : : /* Check whether v1 has neighbors adjacent to multiple bonds */
6859 [ # # ]: 0 : for (i = 0, n = 0; i < pVert1->num_adj_edges; i++)
6860 : : {
6861 : 0 : v = ( pBNS->edge + pVert1->iedge[i] )->neighbor12 ^ v1; /* v is adjacent to v1 */
6862 [ # # ]: 0 : if (v == v2)
6863 : : {
6864 : 0 : continue; /* ignore connection to v2 */
6865 : : }
6866 : 0 : n += ( pBNS->vert[v].st_edge.cap > 0 );
6867 : : }
6868 [ # # ]: 0 : if (!n)
6869 : : {
6870 : 0 : return BNS_CHK_ALTP_NO_ALTPATH; /* the vertex cannot have flow */
6871 : : }
6872 : :
6873 : 0 : v1Act = v1;
6874 : 0 : v2Act = v2;
6875 : :
6876 : : /* find t-group that contains v1 */
6877 [ # # ]: 0 : if (( pVert1->type & type ) == type)
6878 : : {
6879 : 0 : v1t = GetGroupVertex( pBNS, v1, type );
6880 [ # # # # ]: 0 : if (IS_BNS_ERROR( v1t ))
6881 : : {
6882 : 0 : return v1t;
6883 : : }
6884 [ # # ]: 0 : if (v1t != NO_VERTEX)
6885 : : {
6886 : 0 : v1Act = v1t;
6887 : : }
6888 : : }
6889 : : /* Find t-group that contains v2 */
6890 [ # # ]: 0 : if (( pVert2->type & type ) == type)
6891 : : {
6892 : 0 : v2t = GetGroupVertex( pBNS, v2, type );
6893 [ # # # # ]: 0 : if (IS_BNS_ERROR( v2t ))
6894 : : {
6895 : 0 : return v2t;
6896 : : }
6897 [ # # ]: 0 : if (v2t != NO_VERTEX)
6898 : : {
6899 : 0 : v2Act = v2t;
6900 : : }
6901 : : }
6902 [ # # # # ]: 0 : if (v1t != NO_VERTEX && v1t == v2t)
6903 : : {
6904 : 0 : return BNS_CHK_ALTP_SAME_TGROUP;
6905 : : }
6906 : :
6907 : 0 : bSet_v1 = bSet_v2 = 0;
6908 : : /* create new edges adjacent to v1t or v2 */
6909 : 0 : iapc = 0;
6910 [ # # ]: 0 : if (v1t != NO_VERTEX)
6911 : : {
6912 : : /* Create new edge and vertex, connect to v1t */
6913 : 0 : vNew = bAddNewVertex( pBNS, v1t, 1, 0, 1, nDots );
6914 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
6915 : : {
6916 : 0 : return vNew;
6917 : : }
6918 : 0 : apc->vNewVertex[iapc] = vNew;
6919 : 0 : apc->bSetNew[iapc] = 1;
6920 : 0 : bSet_v1 = 1;
6921 : 0 : iapc++;
6922 : : }
6923 [ # # ]: 0 : if (v2t == NO_VERTEX)
6924 : : {
6925 : : /* Create new edge and vertex, connect to v2 */
6926 : 0 : vNew = bAddNewVertex( pBNS, v2, 1, 0, 1, nDots );
6927 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
6928 : : {
6929 : 0 : return vNew;
6930 : : }
6931 : 0 : apc->vNewVertex[iapc] = vNew;
6932 : 0 : apc->bSetNew[iapc] = 1;
6933 : 0 : bSet_v2 = 1;
6934 : 0 : iapc++;
6935 : : }
6936 : :
6937 : : /* Add st-cap to v1 and/or v2t */
6938 : 0 : iapc = 0;
6939 [ # # ]: 0 : if (!bSet_v1)
6940 : : {
6941 : : /* Add st-cap to v1 */
6942 [ # # ]: 0 : if (v1t != NO_VERTEX) /* djb-rwth: addressing coverity ID #499551 -- condition properly written */
6943 : : {
6944 : 0 : return BNS_BOND_ERR;
6945 : : }
6946 : 0 : n = bAddStCapToAVertex( pBNS, v1, v2Act, apc->nOldCapsVert[iapc], nDots, 0 );
6947 : 0 : apc->bSetOldCapsVert[iapc] = n;
6948 : 0 : apc->vOldVert[iapc] = v1;
6949 : 0 : iapc++;
6950 : : }
6951 [ # # ]: 0 : if (!bSet_v2)
6952 : : {
6953 : : /* Add st-cap to v2t */
6954 [ # # ]: 0 : if (v2t == NO_VERTEX)
6955 : : {
6956 : 0 : return BNS_BOND_ERR;
6957 : : }
6958 : 0 : n = bAddStCapToAVertex( pBNS, v2t, v1Act, apc->nOldCapsVert[iapc], nDots, 0 );
6959 : 0 : apc->bSetOldCapsVert[iapc] = n;
6960 : 0 : apc->vOldVert[iapc] = v2t;
6961 : 0 : iapc++;
6962 : : }
6963 [ # # # # ]: 0 : if (*nDots < 0 || *nDots % 2)
6964 : : {
6965 : 0 : return BNS_SET_ALTP_ERR;
6966 : : }
6967 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
6968 : : }
6969 : :
6970 : : /* ( *pBNS->pbTautFlags & TG_FLAG_TEST_TAUT2_SALTS ) */
6971 : :
6972 : : /*#endif*/
6973 : :
6974 : : /* ( TEST_REMOVE_S_ATOMS == 1 && ALT_PATH_MODE_4_SALT == path_type ) */
6975 : :
6976 [ # # # # ]: 0 : if (path_type == ALT_PATH_MODE_REM2H_CHG ||
6977 [ # # ]: 0 : path_type == ALT_PATH_MODE_ADD2H_CHG ||
6978 [ # # ]: 0 : path_type == ALT_PATH_MODE_REM2H_TST ||
6979 : : path_type == ALT_PATH_MODE_ADD2H_TST)
6980 : : {
6981 : : /* added 2004-03-18 */
6982 : :
6983 [ # # # # ]: 0 : int bDonors = ( path_type == ALT_PATH_MODE_REM2H_CHG ) || ( path_type == ALT_PATH_MODE_REM2H_TST );
6984 : :
6985 : : int bSet_v1; /* indicator: v1 has been set */
6986 : : int bSet_v2; /* indicator: v2 has been set */
6987 : 0 : int i, cap = 1;
6988 : 0 : Vertex v1t = NO_VERTEX;
6989 : 0 : Vertex v2t = NO_VERTEX;
6990 : : Vertex v1Act, v2Act;
6991 : : Vertex v;
6992 : :
6993 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
6994 : 0 : fcd[ifcd].iedge = NO_VERTEX;
6995 : 0 : *nDots = 0;
6996 : : /*
6997 : : if ( v1 == v2 ) {
6998 : : return BNS_CHK_ALTP_SAME_VERTEX;
6999 : : }
7000 : : */
7001 : :
7002 : : /* Check whether v1 and v2 have proper neighbors */
7003 [ # # ]: 0 : for (i = 0, n = bAdjacentDonors = 0; i < pVert1->num_adj_edges; i++)
7004 : : {
7005 : 0 : v = ( pBNS->edge + pVert1->iedge[i] )->neighbor12 ^ v1; /* v is adjacent to v1 */
7006 : : /* do not ignore connection to v2
7007 : : if ( v == v2 )
7008 : : continue;
7009 : : */
7010 : 0 : n += bDonors ? ( pBNS->vert[v].st_edge.cap > 0 )
7011 [ # # ]: 0 : : ( ( pBNS->edge + pVert1->iedge[i] )->flow > 0 );
7012 [ # # # # : 0 : bAdjacentDonors += bDonors ? ( v == v2 ) && ( ( pBNS->edge + pVert1->iedge[i] )->flow < MAX_BOND_EDGE_CAP ) : 0;
# # ]
7013 : : /* two donors connected by a single or double bond */
7014 : : }
7015 : :
7016 [ # # # # ]: 0 : if (!n && !bAdjacentDonors)
7017 : : {
7018 : 0 : return BNS_CHK_ALTP_NO_ALTPATH; /* the vertex cannot have flow */
7019 : : }
7020 [ # # ]: 0 : for (i = 0, n = bAdjacentDonors = 0; i < pVert2->num_adj_edges; i++)
7021 : : {
7022 : 0 : v = ( pBNS->edge + pVert2->iedge[i] )->neighbor12 ^ v2; /* v is adjacent to v2 */
7023 : : /* do not ignore connection to v1
7024 : : if ( v == v1 )
7025 : : continue;
7026 : : */
7027 [ # # ]: 0 : n += bDonors ? ( pBNS->vert[v].st_edge.cap > 0 ) : ( ( pBNS->edge + pVert2->iedge[i] )->flow > 0 );
7028 [ # # # # : 0 : bAdjacentDonors += bDonors ? ( v == v1 ) && ( ( pBNS->edge + pVert2->iedge[i] )->flow < MAX_BOND_EDGE_CAP ) : 0;
# # ]
7029 : : /* two donors connected by a single or double bond */
7030 : : }
7031 : :
7032 [ # # # # ]: 0 : if (!n && !bAdjacentDonors)
7033 : : {
7034 : 0 : return BNS_CHK_ALTP_NO_ALTPATH; /* the vertex cannot have flow */
7035 : : }
7036 : :
7037 : 0 : v1Act = v1;
7038 : 0 : v2Act = v2;
7039 : :
7040 : : /* Find t-group that contains v1 */
7041 [ # # ]: 0 : if (( pVert1->type & type ) == type)
7042 : : {
7043 : 0 : v1t = GetGroupVertex( pBNS, v1, type );
7044 [ # # ]: 0 : if (BNS_BOND_ERR == v1t)
7045 : : {
7046 : 0 : v1t = NO_VERTEX;
7047 : : }
7048 : : else
7049 : : {
7050 [ # # # # ]: 0 : if (IS_BNS_ERROR( v1t ))
7051 : : {
7052 : 0 : return v1t;
7053 : : }
7054 : : else
7055 : : {
7056 [ # # ]: 0 : if (v1t != NO_VERTEX)
7057 : : {
7058 : 0 : v1Act = v1t;
7059 : : }
7060 : : }
7061 : : }
7062 : : }
7063 : :
7064 : : /* Find t-group that contains v2 */
7065 [ # # ]: 0 : if (( pVert2->type & type ) == type)
7066 : : {
7067 : 0 : v2t = GetGroupVertex( pBNS, v2, type );
7068 [ # # ]: 0 : if (BNS_BOND_ERR == v2t)
7069 : : {
7070 : 0 : v2t = NO_VERTEX;
7071 : : }
7072 : : else
7073 : : {
7074 [ # # # # ]: 0 : if (IS_BNS_ERROR( v2t ))
7075 : : {
7076 : 0 : return v2t;
7077 : : }
7078 : : else
7079 : : {
7080 [ # # ]: 0 : if (v2t != NO_VERTEX)
7081 : : {
7082 : 0 : v2Act = v2t;
7083 : : }
7084 : : }
7085 : : }
7086 : : }
7087 : :
7088 [ # # # # ]: 0 : if (v1t != NO_VERTEX && v1t == v2t)
7089 : : {
7090 : 0 : cap = 2; /* same t-group */
7091 : : }
7092 : :
7093 : : /* bAddNewVertex: (bDonors != 0) == (vit != NO_VERTEX), i=1,2 */
7094 : 0 : bSet_v1 = bSet_v2 = 0;
7095 : : /* create new edges adjacent to v1t or v2 */
7096 : 0 : iapc = 0;
7097 [ # # ]: 0 : if (( bDonors != 0 ) == ( v1t != NO_VERTEX ))
7098 : : {
7099 : : /* Create new edge and vertex, connect to v1Act */
7100 : 0 : vNew = bAddNewVertex( pBNS, v1Act, cap, 0, 1, nDots );
7101 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7102 : : {
7103 : 0 : return vNew;
7104 : : }
7105 : 0 : apc->vNewVertex[iapc] = vNew;
7106 : 0 : apc->bSetNew[iapc] = 1;
7107 : 0 : bSet_v1 = 1;
7108 : 0 : iapc++;
7109 : : }
7110 [ # # # # ]: 0 : if (( bDonors != 0 ) == ( v2t != NO_VERTEX ) && cap == 1)
7111 : : {
7112 : : /* Create new edge and vertex, connect to v2Act; do not do it if cap==2 */
7113 : 0 : vNew = bAddNewVertex( pBNS, v2Act, cap, 0, 1, nDots );
7114 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7115 : : {
7116 : 0 : return vNew;
7117 : : }
7118 : 0 : apc->vNewVertex[iapc] = vNew;
7119 : 0 : apc->bSetNew[iapc] = 1;
7120 : 0 : bSet_v2 = 1;
7121 : 0 : iapc++;
7122 : : }
7123 : : else
7124 : : {
7125 [ # # ]: 0 : if (( bDonors != 0 ) == ( v2t != NO_VERTEX ))
7126 : : {
7127 : 0 : bSet_v2 = 1;
7128 : : }
7129 : : }
7130 : :
7131 : : /* Add st-cap to v1 and/or v2t */
7132 : 0 : iapc = 0;
7133 : : /* If cap=2 then just increment st_cap 2 times */
7134 [ # # ]: 0 : if (!bSet_v1)
7135 : : {
7136 : : /* Add st-cap to v1 */
7137 [ # # ]: 0 : if (( bDonors != 0 ) == ( v1t != NO_VERTEX ))
7138 : : {
7139 : 0 : return BNS_BOND_ERR;
7140 : : }
7141 : 0 : n = bAddStCapToAVertex( pBNS, v1Act, v2Act, apc->nOldCapsVert[iapc], nDots, bAdjacentDonors );
7142 : 0 : apc->bSetOldCapsVert[iapc] = n;
7143 : 0 : apc->vOldVert[iapc] = v1Act;
7144 : 0 : iapc++;
7145 : : }
7146 [ # # ]: 0 : if (!bSet_v2)
7147 : : {
7148 : : /* Add st-cap to v2t */
7149 [ # # ]: 0 : if (( bDonors != 0 ) == ( v2t != NO_VERTEX ))
7150 : : {
7151 : 0 : return BNS_BOND_ERR;
7152 : : }
7153 : 0 : n = bAddStCapToAVertex( pBNS, v2Act, v1Act, apc->nOldCapsVert[iapc], nDots, bAdjacentDonors );
7154 : 0 : apc->bSetOldCapsVert[iapc] = n;
7155 : 0 : apc->vOldVert[iapc] = v2Act;
7156 : 0 : iapc++;
7157 : : }
7158 [ # # # # ]: 0 : if (*nDots < 0 || *nDots % 2)
7159 : : {
7160 : 0 : return BNS_SET_ALTP_ERR;
7161 : : }
7162 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
7163 : : }
7164 : :
7165 [ # # ]: 0 : if (path_type == ALT_PATH_MODE_REM_PROTON)
7166 : : {
7167 : : /* added 2004-03-05 */
7168 [ # # # # ]: 0 : if (v1 >= 0 && v2 >= 0 &&
7169 [ # # ]: 0 : ( pVert1->type & BNS_VERT_TYPE_ANY_GROUP ) &&
7170 [ # # ]: 0 : ( pVert2->type & BNS_VERT_TYPE_ANY_GROUP ))
7171 : : {
7172 : : /* Create new edge and vertex, connect to v2 */
7173 [ # # ]: 0 : if (( pBNS->vert[v1].type & BNS_VERT_TYPE_C_GROUP ) &&
7174 [ # # ]: 0 : ( pBNS->vert[v1].st_edge.flow == 2 * pBNS->vert[v1].num_adj_edges ))
7175 : : {
7176 : : /* so far in a charge group max edge flow = 1 2004-03-08 */
7177 : 0 : return BNS_CHK_ALTP_NO_ALTPATH;
7178 : : }
7179 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7180 : 0 : fcd[ifcd].iedge = NO_VERTEX;
7181 : 0 : *nDots = 0;
7182 : 0 : iapc = 0;
7183 : :
7184 : 0 : vNew = bAddNewVertex( pBNS, v2, 1, 0, 1, nDots );
7185 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7186 : : {
7187 : 0 : return vNew;
7188 : : }
7189 : 0 : apc->vNewVertex[iapc] = vNew;
7190 : 0 : apc->bSetNew[iapc] = 1;
7191 : : /*iapc ++;*/
7192 : : /* add st-cap (dot) to v1 */
7193 : 0 : n = bAddStCapToAVertex( pBNS, v1, v2, apc->nOldCapsVert[iapc], nDots, 0 );
7194 : 0 : apc->bSetOldCapsVert[iapc] = n;
7195 : 0 : apc->vOldVert[iapc] = v1;
7196 : 0 : iapc++;
7197 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
7198 : : }
7199 : : }
7200 : :
7201 : : #if ( NEUTRALIZE_ENDPOINTS == 1 ) /* { */
7202 : :
7203 : 0 : *nDots = 0;
7204 : 0 : memset( apc, 0, sizeof( *apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7205 : 0 : fcd[ifcd].iedge = NO_VERTEX;
7206 : :
7207 [ # # ]: 0 : if (type & BNS_VERT_TYPE_ENDPOINT)
7208 : : {
7209 : : BNS_IEDGE iedge;
7210 : : AT_NUMB type2;
7211 : : int ret2;
7212 : : /* prohibit charge movement */
7213 : 0 : type2 = BNS_VERT_TYPE_C_GROUP;
7214 : 0 : iedge = GetEdgeToGroupVertex( pBNS, v1, type2 );
7215 [ # # ]: 0 : if (iedge != NO_VERTEX)
7216 : : {
7217 : : /* Set flow=1 on an edge to a c-group vertex to make sure
7218 : : there is no positive charge when moving tautomeric H-atoms */
7219 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 1, fcd + ifcd );
7220 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7221 : : {
7222 : 0 : return ret2;
7223 : : }
7224 : 0 : *nDots += ret2;
7225 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7226 : : {
7227 : 0 : ifcd++;
7228 : : }
7229 : : }
7230 : :
7231 : 0 : iedge = GetEdgeToGroupVertex( pBNS, v2, type2 );
7232 : :
7233 [ # # ]: 0 : if (iedge != NO_VERTEX)
7234 : : {
7235 : : /* Set flow=1 on an edge to a c-group vertex to make sure
7236 : : there is no positive charge when moving tautomeric H-atoms */
7237 : :
7238 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 1, fcd + ifcd );
7239 : :
7240 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7241 : : {
7242 : 0 : return ret2;
7243 : : }
7244 : 0 : *nDots += ret2;
7245 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7246 : : {
7247 : 0 : ifcd++;
7248 : : }
7249 : : }
7250 : :
7251 : : /* Set hydrogen counts */
7252 : 0 : type2 = BNS_VERT_TYPE_TGROUP;
7253 : 0 : iedge = GetEdgeToGroupVertex( pBNS, v1, type2 );
7254 [ # # ]: 0 : if (iedge != NO_VERTEX)
7255 : : {
7256 : : /* Set flow=1 on an edge to a t-group vertex to make sure there is
7257 : : a moveable hydrogen atom or (-) on v1 when moving tautomeric H-atoms */
7258 : : #if ( FIX_H_CHECKING_TAUT == 1 )
7259 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 1, fcd + ifcd );
7260 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7261 : : {
7262 : 0 : return ret2;
7263 : : }
7264 : 0 : *nDots += ret2;
7265 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7266 : : {
7267 : 0 : ifcd++;
7268 : : }
7269 : : #else
7270 : : t1 = pBNS->edge[iedge].neighbor12 ^ v1;
7271 : : #endif
7272 : : }
7273 : :
7274 : 0 : iedge = GetEdgeToGroupVertex( pBNS, v2, type2 );
7275 [ # # ]: 0 : if (iedge != NO_VERTEX)
7276 : : {
7277 : : /* Set flow=0 on an edge to a t-group vertex to make sure there is
7278 : : no moveable hydrogen atom or (-) on v2 when moving tautomeric H-atoms */
7279 : : #if ( FIX_H_CHECKING_TAUT == 1 )
7280 : 0 : ret2 = bSetFlowToCheckOneBond( pBNS, iedge, 0, fcd + ifcd );
7281 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret2 ))
7282 : : {
7283 : 0 : return ret2;
7284 : : }
7285 : 0 : *nDots += ret2;
7286 [ # # ]: 0 : while (fcd[ifcd].iedge != NO_VERTEX)
7287 : : {
7288 : 0 : ifcd++;
7289 : : }
7290 : : #else
7291 : : t2 = pBNS->edge[iedge].neighbor12 ^ v2;
7292 : : #endif
7293 : : }
7294 : :
7295 : : #if ( FIX_H_CHECKING_TAUT == 1 )
7296 : : #else
7297 : : if (t1 == t2 && t1 != NO_VERTEX)
7298 : : {
7299 : : return BNS_CHK_ALTP_SAME_TGROUP;
7300 : : }
7301 : : #endif
7302 : :
7303 : 0 : iapc = 0;
7304 : : /* Create new edge and vertex with cap=1 at v2 and/or t1 */
7305 [ # # ]: 0 : if (t1 != NO_VERTEX)
7306 : : {
7307 : : /* Create new edge and vertex, connect to t1 */
7308 : 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 */
7309 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7310 : : {
7311 : 0 : return vNew;
7312 : : }
7313 : 0 : apc->vNewVertex[iapc] = vNew;
7314 : 0 : apc->bSetNew[iapc] = 1;
7315 : 0 : iapc++;
7316 : : }
7317 [ # # ]: 0 : if (t2 == NO_VERTEX)
7318 : : {
7319 : : /* Create new edge and vertex, connect to v2 */
7320 : 0 : vNew = bAddNewVertex( pBNS, v2, 1/*cap*/, 0/*flow*/, 1/*max_adj_edges*/, nDots );
7321 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7322 : : {
7323 : 0 : return vNew;
7324 : : }
7325 : 0 : apc->vNewVertex[iapc] = vNew;
7326 : 0 : apc->bSetNew[iapc] = 1;
7327 : 0 : iapc++;
7328 : : }
7329 : :
7330 : : /* Add st-cap to v1 and/or v2t */
7331 : 0 : iapc = 0;
7332 [ # # ]: 0 : if (t1 == NO_VERTEX)
7333 : : {
7334 : : /* Add st-cap to v1 */
7335 [ # # ]: 0 : 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 */
7336 : 0 : apc->bSetOldCapsVert[iapc] = n;
7337 : 0 : apc->vOldVert[iapc] = v1;
7338 : 0 : iapc++;
7339 : : }
7340 [ # # ]: 0 : if (t2 != NO_VERTEX)
7341 : : {
7342 : : /* Add st-cap to t2 */
7343 [ # # ]: 0 : n = bAddStCapToAVertex( pBNS, t2, (Vertex) ( t1 == NO_VERTEX ? v1 : t1 ), apc->nOldCapsVert[iapc], nDots, 0 );
7344 : 0 : apc->bSetOldCapsVert[iapc] = n;
7345 : 0 : apc->vOldVert[iapc] = t2;
7346 : 0 : iapc++;
7347 : : }
7348 : : }
7349 : : else
7350 : : {
7351 : : /* Create new edge and vertex, connect to v2 */
7352 : 0 : vNew = bAddNewVertex( pBNS, v2, 1 /* cap*/, 0 /* flow */, 1 /* max_adj_edges */, nDots );
7353 [ # # # # ]: 0 : if (IS_BNS_ERROR( vNew ))
7354 : : {
7355 : 0 : return vNew;
7356 : : }
7357 : 0 : apc->vNewVertex[0] = vNew;
7358 : 0 : apc->bSetNew[0] = 1;
7359 : :
7360 : : /* add st-cap to v1 */
7361 : 0 : n = bAddStCapToAVertex( pBNS, v1, v2, apc->nOldCapsVert[0], nDots, 0 );
7362 : 0 : apc->bSetOldCapsVert[0] = n;
7363 : 0 : apc->vOldVert[0] = v1;
7364 : : }
7365 : : #else /* } NEUTRALIZE_ENDPOINTS == 0 {*/
7366 : :
7367 : : *nDots = 0;
7368 : : memset( apc, 0, sizeof( *apc ) );
7369 : : fcd[ifcd].iedge = NO_VERTEX;
7370 : :
7371 : : /* Create new edge and vertex, connect to v2 */
7372 : : vNew = bAddNewVertex( pBNS, v2, 1 /* cap*/, 0 /* flow */, 1 /* max_adj_edges */, nDots, 0 );
7373 : : if (IS_BNS_ERROR( vNew ))
7374 : : {
7375 : : return vNew;
7376 : : }
7377 : : apc->vNewVertex[0] = vNew;
7378 : : apc->bSetNew[0] = 1;
7379 : :
7380 : : /* Add st-cap to v1 */
7381 : : n = bAddStCapToAVertex( pBNS, v1, v2, apc->nOldCapsVert[0], nDots );
7382 : : apc->bSetOldCapsVert[0] = n;
7383 : : apc->vOldVert[0] = v1;
7384 : : #endif /* } NEUTRALIZE_ENDPOINTS */
7385 : :
7386 [ # # # # ]: 0 : if (*nDots < 0 || *nDots % 2)
7387 : : {
7388 : 0 : return BNS_SET_ALTP_ERR;
7389 : : }
7390 : 0 : return BNS_CHK_ALTP_SET_SUCCESS;
7391 : : }
7392 : :
7393 : : /*return BNS_CHK_ALTP_NO_ALTPATH;*/
7394 : : }
7395 : :
7396 : :
7397 : : /****************************************************************************/
7398 : 0 : int bRestoreBnsAfterCheckAltPath( BN_STRUCT *pBNS,
7399 : : ALT_PATH_CHANGES *apc,
7400 : : int bChangeFlow )
7401 : : /* int nVertDoubleBond, int nVertSingleBond, int nNewVertex, AT_NUMB *nOldCapVertSingleBond */
7402 : : {
7403 : : BNS_EDGE *pEdge;
7404 : : Vertex vNew;
7405 : : Vertex vOld;
7406 : : BNS_VERTEX *pOldVert;
7407 : : BNS_VERTEX *pNewVert;
7408 : : int i, j, n; /* djb-rwth: removing redundant variables */
7409 : :
7410 : : /* djb-rwth: removing redundant code */
7411 : :
7412 [ # # ]: 0 : if (bChangeFlow & BNS_EF_UPD_H_CHARGE)
7413 : : {
7414 : : /* Remove new temp. vertices and edges connectong them to the structure */
7415 [ # # ]: 0 : for (i = sizeof( apc->bSetNew ) / sizeof( apc->bSetNew[0] ) - 1; 0 <= i; i--)
7416 : : {
7417 [ # # ]: 0 : if (apc->bSetNew[i])
7418 : : {
7419 : 0 : vNew = apc->vNewVertex[i];
7420 : 0 : pNewVert = pBNS->vert + vNew;
7421 [ # # ]: 0 : for (j = 0; j < pNewVert->num_adj_edges; j++)
7422 : : {
7423 : 0 : pEdge = pBNS->edge + pNewVert->iedge[j];
7424 : 0 : vOld = pEdge->neighbor12 ^ vNew;
7425 : 0 : pOldVert = pBNS->vert + vOld;
7426 : 0 : pOldVert->st_edge.flow -= pEdge->flow;
7427 : 0 : pOldVert->st_edge.cap -= pEdge->flow;
7428 : : /* disconnect new edge from pOldVert */
7429 : 0 : pOldVert->iedge[--pOldVert->num_adj_edges] = 0;
7430 : : /* clear the new edge */
7431 : 0 : memset( pEdge, 0, sizeof( *pEdge ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7432 : : /* and decrement the total number of edges */
7433 : 0 : pBNS->num_edges--;
7434 : : }
7435 : : /* Clear the new vertex */
7436 : 0 : memset( pNewVert, 0, sizeof( *pNewVert ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7437 : : /* and decrement the total number of vertices
7438 : : (new vertice ids are contiguous) */
7439 : 0 : pBNS->num_vertices--;
7440 : : /* djb-rwth: removing redundant code */
7441 : : }
7442 : : }
7443 : :
7444 : : /* Restore changed caps of old vertices */
7445 : 0 : for (i = sizeof( apc->bSetOldCapsVert ) / sizeof( apc->bSetOldCapsVert[0] ) - 1;
7446 [ # # ]: 0 : 0 <= i;
7447 : 0 : i--)
7448 : : {
7449 [ # # ]: 0 : if ((n = apc->bSetOldCapsVert[i])) /* djb-rwth: addressing LLVM warning */
7450 : : {
7451 : 0 : pOldVert = pBNS->vert + apc->vOldVert[i];
7452 [ # # ]: 0 : if (pOldVert->st_edge.flow <= apc->nOldCapsVert[i][0])
7453 : : {
7454 : 0 : pOldVert->st_edge.cap = apc->nOldCapsVert[i][0];
7455 : 0 : n--;
7456 : : /* djb-rwth: removing redundant code */
7457 [ # # # # ]: 0 : for (j = 0; j < n && j < pOldVert->num_adj_edges; j++)
7458 : : {
7459 : 0 : pEdge = pBNS->edge + pOldVert->iedge[j];
7460 : 0 : pEdge->cap = apc->nOldCapsVert[i][j + 1];
7461 : : }
7462 : : }
7463 : : }
7464 : : }
7465 : : }
7466 : : else
7467 : : {
7468 : : /* Restore changed caps of old vertices */
7469 [ # # ]: 0 : for (i = sizeof( apc->bSetOldCapsVert ) / sizeof( apc->bSetOldCapsVert[0] ) - 1; 0 <= i; i--)
7470 : : {
7471 [ # # ]: 0 : if ((n = apc->bSetOldCapsVert[i])) /* djb-rwth: addressing LLVM warning */
7472 : : {
7473 : 0 : pOldVert = pBNS->vert + apc->vOldVert[i];
7474 : 0 : pOldVert->st_edge.cap = apc->nOldCapsVert[i][0];
7475 : 0 : n--;
7476 : : /* djb-rwth: removing redundant code */
7477 [ # # # # ]: 0 : for (j = 0; j < n && j < pOldVert->num_adj_edges; j++)
7478 : : {
7479 : 0 : pEdge = pBNS->edge + pOldVert->iedge[j];
7480 : 0 : pEdge->cap = apc->nOldCapsVert[i][j + 1];
7481 : : }
7482 : : }
7483 : : }
7484 : :
7485 : : /* Remove new temp. vertices and edges connectong them to the structure */
7486 [ # # ]: 0 : for (i = sizeof( apc->bSetNew ) / sizeof( apc->bSetNew[0] ) - 1; 0 <= i; i--)
7487 : : {
7488 [ # # ]: 0 : if (apc->bSetNew[i])
7489 : : {
7490 : 0 : vNew = apc->vNewVertex[i];
7491 : 0 : pNewVert = pBNS->vert + vNew;
7492 [ # # ]: 0 : for (j = 0; j < pNewVert->num_adj_edges; j++)
7493 : : {
7494 : 0 : pEdge = pBNS->edge + pNewVert->iedge[j];
7495 : 0 : vOld = pEdge->neighbor12 ^ vNew;
7496 : 0 : pOldVert = pBNS->vert + vOld;
7497 : : /* disconnect new edge from pOldVert */
7498 : 0 : pOldVert->iedge[--pOldVert->num_adj_edges] = 0;
7499 : : /* clear the new edge */
7500 : 0 : memset( pEdge, 0, sizeof( *pEdge ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7501 : : /* and decrement the total number of edges */
7502 : 0 : pBNS->num_edges--;
7503 : : }
7504 : : /* Clear the new vertex */
7505 : 0 : memset( pNewVert, 0, sizeof( *pNewVert ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7506 : : /* and decrement the total number of vertices (new vertice ids are contiguous */
7507 : 0 : pBNS->num_vertices--;
7508 : : /* djb-rwth: removing redundant code */
7509 : : }
7510 : : }
7511 : : }
7512 : :
7513 : 0 : return 0;
7514 : : }
7515 : :
7516 : :
7517 : : /****************************************************************************/
7518 : 0 : int bExistsAnyAltPath( CANON_GLOBALS *pCG,
7519 : : BN_STRUCT *pBNS,
7520 : : BN_DATA *pBD,
7521 : : inp_ATOM *at,
7522 : : int num_atoms,
7523 : : int nVert2,
7524 : : int nVert1,
7525 : : int path_type )
7526 : : {
7527 : : int nRet1, nRet2;
7528 : :
7529 : 0 : nRet1 = bExistsAltPath( pCG, pBNS, pBD, NULL, at, num_atoms, nVert2, nVert1, path_type );
7530 : :
7531 [ # # ]: 0 : if (nRet1 > 0)
7532 : : {
7533 : 0 : return nRet1;
7534 : : }
7535 : :
7536 : 0 : nRet2 = bExistsAltPath( pCG, pBNS, pBD, NULL, at, num_atoms, nVert1, nVert2, path_type );
7537 : :
7538 [ # # ]: 0 : if (nRet2 > 0)
7539 : : {
7540 : 0 : return nRet2;
7541 : : }
7542 [ # # # # ]: 0 : if (IS_BNS_ERROR( nRet1 ))
7543 : : {
7544 : 0 : return nRet1;
7545 : : }
7546 [ # # # # ]: 0 : if (IS_BNS_ERROR( nRet2 ))
7547 : : {
7548 : 0 : return nRet2;
7549 : : }
7550 : :
7551 : 0 : return 0;
7552 : : }
7553 : :
7554 : :
7555 : : #define ALT_PATH_TAUTOM 1
7556 : : #define ALT_PATH_CHARGE 2
7557 : : #define ALT_PATH_4_SALT 3
7558 : :
7559 : :
7560 : : /****************************************************************************/
7561 : 0 : int bIsBnsEndpoint( BN_STRUCT *pBNS, int v )
7562 : : {
7563 : : int i, vt;
7564 : : BNS_VERTEX *pVert; /* vertices */
7565 : : BNS_EDGE *pEdge; /* edges */
7566 : :
7567 [ # # # # : 0 : if (0 <= v && v < pBNS->num_atoms && ( pVert = pBNS->vert + v ) && ( pVert->type & BNS_VERT_TYPE_ENDPOINT ))
# # # # ]
7568 : : {
7569 [ # # ]: 0 : for (i = pVert->num_adj_edges - 1; 0 <= i; i--)
7570 : : {
7571 : 0 : pEdge = pBNS->edge + pVert->iedge[i];
7572 : 0 : vt = pEdge->neighbor12 ^ v;
7573 [ # # ]: 0 : if (pBNS->vert[vt].type & BNS_VERT_TYPE_TGROUP)
7574 : : {
7575 : 0 : return !IS_FORBIDDEN( pEdge->forbidden, pBNS );
7576 : : }
7577 : : }
7578 : : }
7579 : :
7580 : 0 : return 0;
7581 : : }
7582 : :
7583 : :
7584 : : #if ( BNS_RAD_SEARCH == 1 )
7585 : :
7586 : :
7587 : : /****************************************************************************/
7588 : 0 : int bRadChangesAtomType( BN_STRUCT *pBNS,
7589 : : BN_DATA *pBD,
7590 : : Vertex v,
7591 : : Vertex v_1,
7592 : : Vertex v_2 )
7593 : : {
7594 : :
7595 : : EdgeIndex iuv;
7596 : : Vertex v_O, v_ChgOrH;
7597 : :
7598 : : /* The previous atom along the path: should be a terminal atom */
7599 [ # # ]: 0 : if (v_1 == NO_VERTEX)
7600 : : {
7601 : 0 : v_1 = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv );
7602 : : }
7603 : 0 : v_O = v_1 / 2 - 1;
7604 : :
7605 [ # # # # ]: 0 : if (v_O < 0 || v_O >= pBNS->num_atoms)
7606 : : {
7607 : 0 : return 0;
7608 : : }
7609 : :
7610 : : /* Make sure v_O is a terminal atom: its second neighbor is not an atom */
7611 [ # # ]: 0 : if (pBNS->vert[pBNS->edge[pBNS->vert[v_O].iedge[1]].neighbor12 ^ v_O].type & BNS_VERT_TYPE_ATOM)
7612 : : {
7613 : 0 : return 0;
7614 : : }
7615 : :
7616 : : /* The next to previous vertex vertex along the path: should be a Charge or Taut group vertex */
7617 [ # # ]: 0 : if (v_2 == NO_VERTEX)
7618 : : {
7619 : 0 : v_2 = GetPrevVertex( pBNS, v_1, pBD->SwitchEdge, &iuv );
7620 : : }
7621 : :
7622 : 0 : v_ChgOrH = v_2 / 2 - 1;
7623 [ # # ]: 0 : if (v_ChgOrH < pBNS->num_atoms)
7624 : : {
7625 : 0 : return 0;
7626 : : }
7627 : :
7628 : : /* Make sure v_ChgOrH is a charge or taut_group */
7629 [ # # ]: 0 : if (pBNS->vert[v_ChgOrH].type & ( BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP ))
7630 : : {
7631 : 0 : return 1;
7632 : : }
7633 : :
7634 : 0 : return 0;
7635 : : }
7636 : :
7637 : :
7638 : : /****************************************************************************/
7639 : 0 : int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u )
7640 : : {
7641 : : EdgeIndex iuv;
7642 : : int i, num_found;
7643 : : Vertex v, w;
7644 : : Vertex u_last, v2;
7645 [ # # # ]: 0 : switch (pBD->bRadSrchMode)
7646 : : {
7647 : 0 : case RAD_SRCH_NORM:
7648 : : /* Go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
7649 : : /* we need only vertices where a radical may be moved, therefore exclude u%2=1 (odd) vertices */
7650 : : /* atom number = u/2-1; u = 0 or 1 is 's' or 't' vertices, respectively, they are not atoms */
7651 : 0 : num_found = 0;
7652 [ # # # # : 0 : while (u > Vertex_t && ( u % 2 || u / 2 > pBNS->num_atoms ))
# # ]
7653 : : {
7654 : 0 : u = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
7655 : : }
7656 : 0 : w = u / 2 - 1; /* Check whether u is a radical endpoint */
7657 [ # # # # ]: 0 : if (Vertex_t < u && w < pBNS->num_atoms &&
7658 [ # # ]: 0 : pBNS->vert[w].st_edge.cap == ( pBNS->vert[w].st_edge.flow & EDGE_FLOW_ST_MASK ))
7659 : : {
7660 : : /* u is an atom; it is not a radical atom */
7661 : : /* now search for the starting radical atom by following the path back from u */
7662 : 0 : v = u_last = u;
7663 [ # # ]: 0 : while (v > Vertex_t)
7664 : : {
7665 : 0 : u = v;
7666 : 0 : v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv ); /* Radical endpoint */
7667 : : }
7668 : : /* Check whether u is a radical atom */
7669 [ # # # # ]: 0 : if (!( u % 2 ) && Vertex_t < u &&
7670 [ # # ]: 0 : ( u = u / 2 - 1 ) < pBNS->num_atoms &&
7671 [ # # ]: 0 : pBNS->vert[u].st_edge.cap > ( pBNS->vert[u].st_edge.flow & EDGE_FLOW_ST_MASK ))
7672 : : {
7673 : : /* at pBNS->vert[u] we have found the radical that originated the path */
7674 : : /* pBD->RadEndpoints[2k] is the radical, pBD->RadEndpoints[2k+1] is the farthest atom */
7675 : : /* to which the radical may be moved (farthest reachable atom) */
7676 : :
7677 : : /* add *all* atoms that may receive radical from u_rad */
7678 : : /* exception: at2 in: ==(+/-/H)---at1==at2(possible rad endpoint) if pBNS->type_TACN */
7679 [ # # ]: 0 : for (v = u_last; v > Vertex_t; v = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv ))
7680 : : {
7681 [ # # # # ]: 0 : if (!( v % 2 ) && ( v2 = v / 2 - 1 ) < pBNS->num_atoms &&
7682 [ # # ]: 0 : pBNS->vert[v2].st_edge.cap == ( pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK ))
7683 : : {
7684 : : /* Check exception */
7685 [ # # # # ]: 0 : if (pBNS->type_TACN &&
7686 : 0 : bRadChangesAtomType( pBNS, pBD, v, NO_VERTEX, NO_VERTEX ))
7687 : : {
7688 : 0 : continue;
7689 : : }
7690 : : /* Add */
7691 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i += 2)
7692 : : {
7693 : : /* Check whether this pair, (u,w), has already been saved */
7694 [ # # ]: 0 : if (u == pBD->RadEndpoints[i] &&
7695 [ # # ]: 0 : v2 == pBD->RadEndpoints[i + 1])
7696 : : {
7697 : 0 : break;
7698 : : }
7699 : : }
7700 [ # # ]: 0 : if (i >= pBD->nNumRadEndpoints)
7701 : : {
7702 : : /* Add new (u,w) pair */
7703 [ # # ]: 0 : if (pBD->nNumRadEndpoints + 2 <= pBD->max_num_vertices)
7704 : : {
7705 : : /* add */
7706 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = u; /* radical */
7707 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = v2; /* endpoint */
7708 : 0 : num_found++;
7709 : : /*return 1;*/ /* registered */
7710 : : }
7711 : : else
7712 : : {
7713 : 0 : return BNS_VERT_EDGE_OVFL;
7714 : : }
7715 : : }
7716 : : }
7717 : : }
7718 [ # # ]: 0 : if (num_found)
7719 : : {
7720 : 0 : return 1;
7721 : : }
7722 : : }
7723 : : }
7724 : 0 : break;
7725 : :
7726 : 0 : case RAD_SRCH_FROM_FICT:
7727 : : /* Find the nearest atom accessible from a fictitious vertex */
7728 : : /* go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
7729 : :
7730 : 0 : v = u;
7731 : 0 : w = NO_VERTEX; /* the nearest atom -- radical-endpoint */
7732 : 0 : u = NO_VERTEX; /* fictitious vertex carrying a radical */
7733 : :
7734 [ # # ]: 0 : while (v > Vertex_t)
7735 : : {
7736 : 0 : u = v;
7737 [ # # # # ]: 0 : if (!( v % 2 ) && v / 2 <= pBNS->num_atoms &&
7738 [ # # ]: 0 : pBNS->vert[v / 2 - 1].st_edge.cap - pBNS->vert[v / 2 - 1].st_edge.flow < 2)
7739 : : {
7740 : 0 : w = v; /* vertex w is atom that may be singlet or doublet but not triplet */
7741 : : }
7742 : 0 : v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
7743 : : }
7744 : 0 : v = u / 2 - 1; /* vertex u may be the radical from which the path originated; w is the nearest atom */
7745 [ # # # # : 0 : if (w == NO_VERTEX || u == NO_VERTEX || w % 2 || u == w || v < pBNS->num_atoms ||
# # # # #
# ]
7746 [ # # ]: 0 : pBNS->vert[v].st_edge.cap == pBNS->vert[v].st_edge.flow ||
7747 [ # # ]: 0 : ( w = w / 2 - 1 ) >= pBNS->num_atoms)
7748 : : {
7749 : : break; /* reject */
7750 : : }
7751 : 0 : u = v;
7752 : : /* At pBNS->vert[u] we have found the radical that originated the path, w is the nearest atom */
7753 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i += 2)
7754 : : {
7755 [ # # ]: 0 : if (u == pBD->RadEndpoints[i] &&
7756 [ # # ]: 0 : w == pBD->RadEndpoints[i + 1])
7757 : : {
7758 : 0 : break; /* this pair has already been stored */
7759 : : }
7760 : : }
7761 [ # # ]: 0 : if (i >= pBD->nNumRadEndpoints)
7762 : : {
7763 : : /* A new pair has been found */
7764 [ # # ]: 0 : if (pBD->nNumRadEndpoints + 2 <= pBD->max_num_vertices)
7765 : : {
7766 : : /* Add */
7767 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = u; /* radical */
7768 : 0 : pBD->RadEndpoints[pBD->nNumRadEndpoints++] = w; /* endpoint */
7769 : 0 : return 1; /* registered */
7770 : : }
7771 : : else
7772 : : {
7773 : 0 : return BNS_VERT_EDGE_OVFL;
7774 : : }
7775 : : }
7776 : 0 : break;
7777 : : }
7778 : :
7779 : 0 : return 0; /* rejected */
7780 : : }
7781 : :
7782 : :
7783 : : /****************************************************************************/
7784 : 0 : int cmp_rad_endpoints( const void *a1, const void *a2 )
7785 : : {
7786 : : /* Vertex radical_vertex, radical_endpoint */
7787 : 0 : const Vertex *p1 = (const Vertex *) a1;
7788 : 0 : const Vertex *p2 = (const Vertex *) a2;
7789 : :
7790 [ # # ]: 0 : if (p1[0] < p2[0])
7791 : : {
7792 : 0 : return -1;
7793 : : }
7794 [ # # ]: 0 : if (p1[0] > p2[0])
7795 : : {
7796 : 0 : return 1;
7797 : : }
7798 [ # # ]: 0 : if (p1[1] < p2[1])
7799 : : {
7800 : 0 : return -1;
7801 : : }
7802 [ # # ]: 0 : if (p1[1] > p2[1])
7803 : : {
7804 : 0 : return 1;
7805 : : }
7806 : :
7807 : 0 : return 0;
7808 : : }
7809 : :
7810 : :
7811 : : /****************************************************************************/
7812 : 0 : int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
7813 : : {
7814 : : BNS_EDGE *e;
7815 : : EdgeIndex ie;
7816 : : BNS_VERTEX *p1, *p2;
7817 : : Vertex v1, v2;
7818 : : int i, delta, rad;
7819 : :
7820 [ # # ]: 0 : for (i = pBD->nNumRadEdges - 1; 0 <= i; i--)
7821 : : {
7822 : 0 : ie = pBD->RadEdges[i];
7823 [ # # # # ]: 0 : if (ie < 0 || ie >= pBNS->num_edges)
7824 : : {
7825 : 0 : goto error_exit;
7826 : : }
7827 : 0 : e = pBNS->edge + ie;
7828 : 0 : v1 = e->neighbor1;
7829 : 0 : v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
7830 [ # # # # ]: 0 : if (ie + 1 != pBNS->num_edges ||
7831 [ # # # # ]: 0 : v1 < 0 || v1 >= pBNS->num_vertices ||
7832 [ # # ]: 0 : v2 < 0 || v2 >= pBNS->num_vertices)
7833 : : {
7834 : 0 : goto error_exit;
7835 : : }
7836 : 0 : p1 = pBNS->vert + v1;
7837 : 0 : p2 = pBNS->vert + v2;
7838 : :
7839 [ # # ]: 0 : if (p2->iedge[p2->num_adj_edges - 1] != ie ||
7840 [ # # ]: 0 : p1->iedge[p1->num_adj_edges - 1] != ie)
7841 : : {
7842 : 0 : goto error_exit;
7843 : : }
7844 : :
7845 : 0 : p2->num_adj_edges--;
7846 : 0 : p1->num_adj_edges--;
7847 : 0 : p2->iedge[p2->num_adj_edges] = 0;
7848 : 0 : p1->iedge[p1->num_adj_edges] = 0;
7849 : 0 : p2->st_edge.flow -= e->flow;
7850 : 0 : p1->st_edge.flow -= e->flow;
7851 : :
7852 [ # # # # ]: 0 : if (!p2->num_adj_edges && v2 >= pBNS->num_atoms)
7853 : : {
7854 [ # # ]: 0 : if (v2 + 1 != pBNS->num_vertices)
7855 : : {
7856 : 0 : goto error_exit;
7857 : : }
7858 : 0 : memset( p2, 0, sizeof( *p2 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7859 : 0 : pBNS->num_vertices--;
7860 : : }
7861 : :
7862 [ # # # # ]: 0 : if (!p1->num_adj_edges && v1 >= pBNS->num_atoms)
7863 : : {
7864 [ # # ]: 0 : if (v1 + 1 != pBNS->num_vertices)
7865 : : {
7866 : 0 : goto error_exit;
7867 : : }
7868 : 0 : memset( p1, 0, sizeof( *p1 ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7869 : 0 : pBNS->num_vertices--;
7870 : : }
7871 : :
7872 [ # # # # ]: 0 : if (at && v1 < pBNS->num_atoms)
7873 : : {
7874 : 0 : delta = p1->st_edge.cap - p1->st_edge.flow;
7875 : 0 : rad = at[v1].radical;
7876 [ # # # ]: 0 : switch (delta)
7877 : : {
7878 : 0 : case 0:
7879 [ # # ]: 0 : if (rad == RADICAL_DOUBLET)
7880 : : {
7881 : 0 : rad = 0;
7882 : : }
7883 : 0 : break;
7884 : 0 : case 1:
7885 [ # # ]: 0 : if (rad != RADICAL_DOUBLET)
7886 : : {
7887 : 0 : rad = RADICAL_DOUBLET;
7888 : : }
7889 : : }
7890 : 0 : at[v1].radical = rad;
7891 : : }
7892 : 0 : memset( e, 0, sizeof( *e ) ); /* djb-rwth: memset_s C11/Annex K variant? */
7893 : 0 : pBNS->num_edges--;
7894 : : }
7895 : 0 : pBD->nNumRadEdges = 0;
7896 : 0 : pBD->nNumRadicals = 0;
7897 : 0 : pBD->bRadSrchMode = RAD_SRCH_NORM;
7898 : 0 : return 0;
7899 : :
7900 : 0 : error_exit:
7901 : :
7902 : 0 : return BNS_PROGRAM_ERR;
7903 : : }
7904 : :
7905 : :
7906 : : /****************************************************************************/
7907 : 0 : int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
7908 : : {
7909 : : BNS_EDGE *e;
7910 : : EdgeIndex ie;
7911 : : BNS_VERTEX *p1, *p2;
7912 : : Vertex v1, v2;
7913 : : int i, delta, rad;
7914 : : int p1_num_adj_edges, p2_num_adj_edges;
7915 : :
7916 [ # # ]: 0 : for (i = pBD->nNumRadEdges - 1; 0 <= i; i--)
7917 : : {
7918 : 0 : ie = pBD->RadEdges[i];
7919 [ # # # # ]: 0 : if (ie < 0 || ie >= pBNS->num_edges)
7920 : : {
7921 : 0 : goto error_exit;
7922 : : }
7923 : 0 : e = pBNS->edge + ie;
7924 : 0 : v1 = e->neighbor1; /* atom */
7925 : 0 : v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
7926 [ # # # # ]: 0 : if (v1 < 0 || v1 >= pBNS->num_atoms ||
7927 [ # # # # ]: 0 : v2 < pBNS->num_atoms || v2 >= pBNS->num_vertices)
7928 : : {
7929 : 0 : goto error_exit;
7930 : : }
7931 : 0 : p1 = pBNS->vert + v1;
7932 : 0 : p2 = pBNS->vert + v2;
7933 : :
7934 : 0 : p1_num_adj_edges = e->neigh_ord[0];
7935 : 0 : p2_num_adj_edges = e->neigh_ord[1];
7936 : :
7937 [ # # ]: 0 : if (p2->iedge[p2_num_adj_edges] != ie ||
7938 [ # # ]: 0 : p1->iedge[p1_num_adj_edges] != ie)
7939 : : {
7940 : 0 : goto error_exit;
7941 : : }
7942 : :
7943 [ # # # # ]: 0 : if (at && v1 < pBNS->num_atoms)
7944 : : {
7945 : 0 : delta = p1->st_edge.cap - p1->st_edge.flow + e->flow;
7946 : 0 : rad = at[v1].radical;
7947 [ # # # ]: 0 : switch (delta)
7948 : : {
7949 : 0 : case 0:
7950 [ # # ]: 0 : if (rad == RADICAL_DOUBLET)
7951 : 0 : rad = 0;
7952 : 0 : break;
7953 : 0 : case 1:
7954 [ # # ]: 0 : if (rad != RADICAL_DOUBLET)
7955 : 0 : rad = RADICAL_DOUBLET;
7956 : : }
7957 : 0 : at[v1].radical = rad;
7958 : : }
7959 : : }
7960 : 0 : return 0;
7961 : :
7962 : 0 : error_exit:
7963 : :
7964 : 0 : return BNS_PROGRAM_ERR;
7965 : : }
7966 : :
7967 : :
7968 : : /****************************************************************************/
7969 : 0 : int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
7970 : : {
7971 : : int ret, i, j, k, delta; /* djb-rwth: removing redundant variables */
7972 : : BNS_VERTEX *pRad, *pEndp;
7973 : : Vertex wRad, vRad, vEndp, nNumRadicals;
7974 : 0 : int nDots = 0 /* added initialization, 2006-03 */, nNumEdges;
7975 : :
7976 [ # # ]: 0 : if (pBNS->tot_st_cap <= pBNS->tot_st_flow)
7977 : : {
7978 : 0 : return 0;
7979 : : }
7980 : :
7981 : 0 : pBD->nNumRadEndpoints = 0;
7982 : 0 : pBD->nNumRadEdges = 0;
7983 : 0 : pBD->bRadSrchMode = bRadSrchMode;
7984 : 0 : pBNS->alt_path = pBNS->altp[0];
7985 : 0 : pBNS->bChangeFlow = 0;
7986 : 0 : ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH );
7987 : 0 : ReInitBnData( pBD );
7988 : 0 : ReInitBnStructAltPaths( pBNS );
7989 [ # # # # ]: 0 : if (!ret && pBD->nNumRadEndpoints >= 2)
7990 : : {
7991 : : /* Sort by radical locations */
7992 : 0 : qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints / 2, 2 * sizeof( pBD->RadEndpoints[0] ), cmp_rad_endpoints );
7993 : : /* djb-rwth: removing redundant code */
7994 : 0 : nNumRadicals = 0;
7995 : :
7996 : : /* Create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1 */
7997 : : /* connecting the new vertices radical vertices */
7998 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
7999 : : {
8000 : 0 : wRad = pBD->RadEndpoints[i];
8001 : 0 : pRad = pBNS->vert + wRad;
8002 : 0 : delta = pRad->st_edge.cap - ( pRad->st_edge.flow & EDGE_FLOW_ST_MASK );
8003 [ # # ]: 0 : if (delta <= 0)
8004 : : {
8005 : 0 : delta = 1;
8006 : : }
8007 : 0 : nNumEdges = 0;
8008 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j]; j += 2)
8009 : : {
8010 : 0 : nNumEdges++;
8011 : : }
8012 : : /* Add new aux vertex to the radical atom/vertex */
8013 : 0 : vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges + 1, &nDots );
8014 [ # # # # ]: 0 : if (IS_BNS_ERROR( vRad ))
8015 : : {
8016 : 0 : ret = vRad;
8017 : 0 : goto error_exit;
8018 : : }
8019 : 0 : pRad = pBNS->vert + vRad;
8020 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = pRad->iedge[pRad->num_adj_edges - 1];
8021 : : /* Replace references to vertex wRad with vRad */
8022 [ # # ]: 0 : for (k = i, nNumEdges = 0; k < j; k += 2) /* djb-rwth: ignoring LLVM warning: variable used */
8023 : : {
8024 : 0 : pBD->RadEndpoints[k] = vRad;
8025 : : }
8026 : 0 : nNumRadicals++;
8027 : : }
8028 : : /* All vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
8029 : : /* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
8030 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
8031 : : {
8032 : 0 : vRad = pBD->RadEndpoints[i];
8033 : 0 : pRad = pBNS->vert + vRad;
8034 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j]; j += 2)
8035 : : {
8036 : : /* Connect vew vertex pRad to radical endpoints */
8037 : 0 : vEndp = pBD->RadEndpoints[j + 1];
8038 : 0 : pEndp = pBNS->vert + vEndp;
8039 : 0 : ret = AddNewEdge( pRad, pEndp, pBNS, 1, 0 );
8040 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8041 : : {
8042 : 0 : goto error_exit;
8043 : : }
8044 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = ret;
8045 : : }
8046 : : }
8047 : 0 : pBD->nNumRadicals = nNumRadicals;
8048 : 0 : return nNumRadicals; /* done */
8049 : : }
8050 : :
8051 : 0 : return 0; /* nothing to do */
8052 : :
8053 : 0 : error_exit:
8054 : 0 : RemoveRadEndpoints( pBNS, pBD, NULL );
8055 : :
8056 : 0 : return ret;
8057 : : }
8058 : :
8059 : :
8060 : : #define MAX_NUM_RAD 256
8061 : :
8062 : :
8063 : : /****************************************************************************/
8064 : 0 : int SetRadEndpoints2( CANON_GLOBALS *pCG,
8065 : : BN_STRUCT *pBNS,
8066 : : BN_DATA *pBD,
8067 : : BRS_MODE bRadSrchMode )
8068 : : {
8069 : 0 : int ret = 0, i, j, k, n, delta = 1; /* djb-rwth: removing redundant variables */
8070 : : BNS_VERTEX *pRad, *pEndp;
8071 : : Vertex wRad, vRad, vEndp, nNumRadicals;
8072 : : Vertex vRadList[MAX_NUM_RAD], vRadEqul[MAX_NUM_RAD];
8073 : 0 : int nNumRad = 0;
8074 : : int edge_flow;
8075 : 0 : int nDots = 0 /* added initialization, 2006-03 */, nNumEdges;
8076 : : NodeSet VertSet;
8077 : :
8078 [ # # ]: 0 : if (pBNS->tot_st_cap <= pBNS->tot_st_flow)
8079 : : {
8080 : 0 : return 0;
8081 : : }
8082 : :
8083 : : /* Find all radicals: their vertices have st_cap-st_flow=delta */
8084 : : /* save radical atom numbers in vRadList[] and remove radical by making st_cap=st_flow */
8085 [ # # ]: 0 : for (i = 0; i < pBNS->num_atoms; i++)
8086 : : {
8087 [ # # ]: 0 : if (pBNS->vert[i].st_edge.cap - delta == ( pBNS->vert[i].st_edge.flow & EDGE_FLOW_ST_MASK ))
8088 : : {
8089 [ # # ]: 0 : if (nNumRad < MAX_NUM_RAD)
8090 : : {
8091 : 0 : pBNS->vert[i].st_edge.cap -= delta;
8092 : 0 : pBNS->tot_st_cap -= delta;
8093 : 0 : vRadList[nNumRad] = i; /* radical position; i > j <=> vRadList[i] > vRadList[j] */
8094 : 0 : vRadEqul[nNumRad] = nNumRad; /* the smallest radical atom that has reachable
8095 : : * atoms in common with this radical atom
8096 : : * always keep vRadEqul[nNumRad] <= nNumRad */
8097 : 0 : nNumRad++;
8098 : : }
8099 : : }
8100 : : }
8101 : :
8102 [ # # ]: 0 : if (pBNS->tot_st_cap - pBNS->tot_st_flow > nNumRad)
8103 : : {
8104 : 0 : return BNS_CAP_FLOW_ERR; /* extra st_cap on non-atoms or program error */
8105 : : }
8106 : :
8107 : 0 : memset( &VertSet, 0, sizeof( VertSet ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8108 : :
8109 : : /* Find reachable atoms by enabling each radical separately */
8110 [ # # ]: 0 : for (j = 0; j < nNumRad; j++)
8111 : : {
8112 : 0 : i = vRadList[j];
8113 : 0 : pBD->nNumRadEndpoints = 0;
8114 : 0 : pBD->nNumRadEdges = 0;
8115 : 0 : pBD->bRadSrchMode = bRadSrchMode;
8116 : 0 : pBNS->alt_path = pBNS->altp[0];
8117 : 0 : pBNS->bChangeFlow = 0;
8118 : 0 : pBNS->vert[i].st_edge.cap += delta; /* enable single radical */
8119 : 0 : pBNS->tot_st_cap += delta;
8120 : 0 : ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH ); /* find reachable atoms */
8121 : 0 : ReInitBnData( pBD );
8122 : 0 : ReInitBnStructAltPaths( pBNS );
8123 : 0 : pBD->bRadSrchMode = RAD_SRCH_NORM;
8124 : 0 : pBNS->vert[i].st_edge.cap -= delta; /* disable single radical */
8125 : 0 : pBNS->tot_st_cap -= delta;
8126 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8127 : : {
8128 : 0 : goto error_exit;
8129 : : }
8130 : : else
8131 : : {
8132 [ # # ]: 0 : if (ret)
8133 : : {
8134 : 0 : ret = BNS_RADICAL_ERR; /* found augmenting path: should not happen since only one radical was enabled */
8135 : 0 : goto error_exit;
8136 : : }
8137 : : }
8138 [ # # # # ]: 0 : if (!ret && pBD->nNumRadEndpoints >= 2)
8139 : : {
8140 : : /* Sort by: primary_key=radical locations, secondary_key=radical endoint */
8141 : :
8142 : 0 : qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints / 2, 2 * sizeof( pBD->RadEndpoints[0] ), cmp_rad_endpoints );
8143 : :
8144 [ # # # # ]: 0 : if (pBD->RadEndpoints[0] != i || pBD->RadEndpoints[pBD->nNumRadEndpoints - 2] != i)
8145 : : {
8146 : 0 : ret = BNS_RADICAL_ERR; /* more than one radical vertex */
8147 : 0 : goto error_exit;
8148 : : }
8149 [ # # ]: 0 : if (nNumRad > 1)
8150 : : {
8151 : : /* If more than one radical then save reachable atoms in bitmaps to allow */
8152 : : /* faster finding whether same atoms are reachable by two or more radicals */
8153 : : /* Later merge such sets */
8154 [ # # ]: 0 : if (NULL == VertSet.bitword)
8155 : : {
8156 : 0 : SetBitCreate( pCG );
8157 [ # # ]: 0 : if (!NodeSetCreate( pCG, &VertSet, pBNS->num_atoms, nNumRad ))
8158 : : {
8159 : 0 : ret = BNS_OUT_OF_RAM; /* out of RAM */
8160 : 0 : goto error_exit;
8161 : : }
8162 : : }
8163 : :
8164 : 0 : NodeSetFromRadEndpoints( pCG, &VertSet, j, pBD->RadEndpoints, pBD->nNumRadEndpoints );
8165 : :
8166 : : /* Do not allow any radical center be treated as a reachable atom: */
8167 : :
8168 : 0 : RemoveFromNodeSet( pCG, &VertSet, j, vRadList, nNumRad );
8169 : : }
8170 : : }
8171 : : }
8172 : :
8173 : : /* Restore radical st_cap so that st_cap-st_flow=delta */
8174 [ # # ]: 0 : for (j = 0; j < nNumRad; j++)
8175 : : {
8176 : 0 : i = vRadList[j];
8177 : 0 : pBNS->vert[i].st_edge.cap += delta;
8178 : 0 : pBNS->tot_st_cap += delta;
8179 : : }
8180 : :
8181 : : /* Merge lists that have common radical endpoints */
8182 : : /* defect: if vertex sets i and j do not intersect they will be compared 2 times */
8183 : : /* total up to nNumRad*(nNumRad-1)/2 calls to DoNodeSetsIntersect() */
8184 [ # # ]: 0 : if (nNumRad > 1)
8185 : : {
8186 [ # # ]: 0 : for (i = 0; i < nNumRad; i++)
8187 : : {
8188 [ # # ]: 0 : if (vRadEqul[i] != i)
8189 : : {
8190 : 0 : continue;
8191 : : }
8192 : : do
8193 : : {
8194 : 0 : n = 0;
8195 [ # # ]: 0 : for (j = i + 1; j < nNumRad; j++)
8196 : : {
8197 [ # # ]: 0 : if (vRadEqul[j] != j)
8198 : : {
8199 : 0 : continue;
8200 : : }
8201 [ # # ]: 0 : if (DoNodeSetsIntersect( &VertSet, i, j ))
8202 : : {
8203 : 0 : AddNodeSet2ToNodeSet1( &VertSet, i, j );
8204 : 0 : vRadEqul[j] = i; /* Set j was copied to set i; i < j */
8205 : 0 : n++;
8206 : : }
8207 : : }
8208 [ # # ]: 0 : } while (n);
8209 : : }
8210 : : /* Fill out pBD->RadEndpoints[] */
8211 [ # # ]: 0 : for (i = 0, n = 0; i < nNumRad; i++)
8212 : : {
8213 [ # # ]: 0 : if (i == vRadEqul[i])
8214 : : {
8215 [ # # ]: 0 : if (!IsNodeSetEmpty( &VertSet, i ))
8216 : : {
8217 : : /* Store equivalent radicals */
8218 [ # # ]: 0 : for (j = i + 1; j < nNumRad; j++)
8219 : : {
8220 [ # # ]: 0 : if (i == vRadEqul[j])
8221 : : {
8222 : 0 : pBD->RadEndpoints[n++] = vRadList[i];
8223 : 0 : pBD->RadEndpoints[n++] = -vRadList[j] - 2; /* equivalent radical, alvays not zero */
8224 : : }
8225 : : }
8226 : : /* Store endpoints */
8227 : 0 : n = AddNodesToRadEndpoints( pCG, &VertSet, i, pBD->RadEndpoints, vRadList[i], n, pBD->max_len_Pu_Pv );
8228 [ # # ]: 0 : if (n < 0)
8229 : : {
8230 : 0 : ret = BNS_RADICAL_ERR; /* pBD->RadEndpoints overflow */
8231 : 0 : goto error_exit;
8232 : : }
8233 : : }
8234 : : else
8235 : : {
8236 : 0 : pBD->RadEndpoints[n++] = vRadList[i];
8237 : 0 : pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
8238 : : }
8239 : : }
8240 : : }
8241 : 0 : pBD->nNumRadEndpoints = n;
8242 : 0 : NodeSetFree( pCG, &VertSet );
8243 : : }
8244 : : else
8245 : : {
8246 [ # # # # ]: 0 : if (nNumRad == 1 && !pBD->nNumRadEndpoints)
8247 : : {
8248 : : /* 2006-07-30: a single radical; no possible endpoint found */
8249 [ # # ]: 0 : for (i = 0, n = 0; i < nNumRad; i++)
8250 : : {
8251 : 0 : pBD->RadEndpoints[n++] = vRadList[i];
8252 : 0 : pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
8253 : : }
8254 : 0 : pBD->nNumRadEndpoints = n;
8255 : : }
8256 : : }
8257 : :
8258 [ # # # # ]: 0 : if (!ret && pBD->nNumRadEndpoints >= 2)
8259 : : {
8260 : : /* Already sorted by radical locations */
8261 : : /* djb-rwth: removing redundant code */
8262 : 0 : nNumRadicals = 0;
8263 : : /**************************************************************************
8264 : : * Create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1
8265 : : * connecting the new vertices radical vertices
8266 : : *
8267 : : *
8268 : : * Original structure: atom A is a radical center A==B--C*--D==E
8269 : : * A*--B==C--D==E atoms C and E are reachable: A==B--C===D--E*
8270 : : *
8271 : : * Resultant temporary structure:
8272 : : * A---B==C--D==E
8273 : : * || / /
8274 : : * || / / The additional new vertex (*) and its
8275 : : * || / / 3 edges replace the radical with alternating
8276 : : * || / / circuits that allow same bond changes
8277 : : * || / / as moving the radical to atoms C or E.
8278 : : * ||// "Double bonds" here have edge cap=1, flow=1
8279 : : * (*) "Single bonds" have edge cap=1, flow=0
8280 : : *
8281 : : * The "equivalent radical centers" (which have at least one reachable atom
8282 : : * in common) are connected to (*) with "double bonds" (edge cap=1, flow=1).
8283 : : * Reachable non-radical atoms are connected by edges with cap=1, flow=0
8284 : : * After running BNS to find alt.path a "double bond" from (*) may move
8285 : : * to another atom thus muving the radical.
8286 : : *
8287 : : * Number of additional (*) vertices = number of sets of
8288 : : * "equivalent radical centers".
8289 : : * Each such a set may include one or more radical centers.
8290 : : *
8291 : : * The radicals will be re-created in RemoveRadEndpoints()
8292 : : ***************************************************************************/
8293 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
8294 : : {
8295 : 0 : wRad = pBD->RadEndpoints[i];
8296 : 0 : pRad = pBNS->vert + wRad;
8297 : 0 : delta = pRad->st_edge.cap - ( pRad->st_edge.flow & EDGE_FLOW_ST_MASK );
8298 [ # # ]: 0 : if (delta <= 0)
8299 : : {
8300 : 0 : delta = 1;
8301 : : }
8302 : 0 : nNumEdges = 0;
8303 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j]; j += 2)
8304 : : {
8305 : 0 : nNumEdges += ( pBD->RadEndpoints[j + 1] != -1 ); /* immobile radicals have one edge only */
8306 : : }
8307 : : /* Add new aux vertex to the radical atom/vertex making st_cap-st_flow=0 */
8308 : : /* in case of immobile radical there will be no additional eddges since nNumEdges=0 */
8309 : 0 : vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges + 1, &nDots );
8310 [ # # # # ]: 0 : if (IS_BNS_ERROR( vRad ))
8311 : : {
8312 : 0 : ret = vRad;
8313 : 0 : goto error_exit;
8314 : : }
8315 : 0 : pRad = pBNS->vert + vRad;
8316 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = pRad->iedge[pRad->num_adj_edges - 1];
8317 : : /* replace references to vertex wRad with vRad */
8318 [ # # ]: 0 : for (k = i, nNumEdges = 0; k < j; k += 2) /* djb-rwth: ignoring LLVM warning: variable used */
8319 : : {
8320 : 0 : pBD->RadEndpoints[k] = vRad;
8321 : : }
8322 : 0 : nNumRadicals++;
8323 : : }
8324 : : /* All vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
8325 : : /* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
8326 [ # # ]: 0 : for (i = 0; i < pBD->nNumRadEndpoints; i = j)
8327 : : {
8328 : 0 : vRad = pBD->RadEndpoints[i];
8329 : 0 : pRad = pBNS->vert + vRad;
8330 [ # # # # ]: 0 : for (j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j]; j += 2)
8331 : : {
8332 : : /* connect vew vertex pRad to radical endpoints */
8333 : 0 : vEndp = pBD->RadEndpoints[j + 1];
8334 [ # # ]: 0 : if (vEndp == -1)
8335 : 0 : continue;
8336 [ # # ]: 0 : if (vEndp < 0)
8337 : : {
8338 : 0 : edge_flow = 1;
8339 : 0 : vEndp = -vEndp - 2; /* equivalent radical centers */
8340 : : }
8341 : : else
8342 : : {
8343 : 0 : edge_flow = 0;
8344 : : }
8345 : 0 : pEndp = pBNS->vert + vEndp;
8346 : 0 : ret = AddNewEdge( pRad, pEndp, pBNS, 1, edge_flow );
8347 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8348 : : {
8349 : 0 : goto error_exit;
8350 : : }
8351 : 0 : pBD->RadEdges[pBD->nNumRadEdges++] = ret;
8352 : : }
8353 : : }
8354 : 0 : pBD->nNumRadicals = nNumRadicals;
8355 : 0 : return nNumRadicals; /* done */
8356 : : }
8357 : 0 : return 0; /* nothing to do */
8358 : :
8359 : 0 : error_exit:
8360 : 0 : RemoveRadEndpoints( pBNS, pBD, NULL );
8361 : 0 : NodeSetFree( pCG, &VertSet );
8362 : :
8363 : 0 : return ret;
8364 : : }
8365 : :
8366 : :
8367 : : #else
8368 : : /****************************************************************************/
8369 : : int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
8370 : : {
8371 : : return 0;
8372 : : }
8373 : : int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
8374 : : {
8375 : : return 0;
8376 : : }
8377 : : int SetRadEndpoints2( CANON_GLOBALS *pCG, BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
8378 : : {
8379 : : return 0;
8380 : : }
8381 : : #endif
8382 : :
8383 : :
8384 : : /****************************************************************************
8385 : : bExistsAltPath( ... )
8386 : :
8387 : : Return value ret bits if not IS_BNS_ERROR(ret):
8388 : :
8389 : : ret & 1 => Success
8390 : : ret & 2 => Bonds changed to Alt
8391 : : (ret & ~3) >> 2 => nDelta: number of removed dots
8392 : : ****************************************************************************/
8393 : 0 : int bExistsAltPath( CANON_GLOBALS *pCG,
8394 : : BN_STRUCT *pBNS,
8395 : : BN_DATA *pBD,
8396 : : BN_AATG *pAATG,
8397 : : inp_ATOM *at,
8398 : : int num_atoms,
8399 : : int nVertDoubleBond,
8400 : : int nVertSingleBond,
8401 : : int path_type )
8402 : : {
8403 : : ALT_PATH_CHANGES apc;
8404 : 0 : int ret, ret_val, bError, bSuccess, bChangeFlow = 0, nDots, nDelta, bDoMarkChangedBonds = 1;
8405 : 0 : int bAdjustRadicals = 0;
8406 : : AT_NUMB type;
8407 : : BNS_FLOW_CHANGES fcd[4 * BNS_MAX_NUM_FLOW_CHANGES + 1];
8408 : : ENDPOINT_INFO eif;
8409 : : #if ( KETO_ENOL_TAUT == 1 )
8410 : : ENDPOINT_INFO eif2;
8411 : : #endif
8412 : :
8413 : : /* Initialize */
8414 [ # # # # : 0 : switch (path_type)
# # # # #
# # # # #
# # ]
8415 : : {
8416 : 0 : case ALT_PATH_MODE_TAUTOM:
8417 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8418 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8419 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8420 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8421 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ))
8422 : : {
8423 : 0 : return 0;
8424 : : }
8425 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8426 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ))
8427 : : {
8428 : 0 : return 0;
8429 : : }
8430 : 0 : break;
8431 : :
8432 : : #if ( TAUT_PT_22_00 == 1 )
8433 : 0 : case ALT_PATH_MODE_TAUTOM_PT_22_00:
8434 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8435 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8436 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8437 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8438 [ # # ]: 0 : (!nGetEndpointInfo_PT_22_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8439 : 0 : return 0;
8440 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8441 [ # # ]: 0 : (!nGetEndpointInfo_PT_22_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8442 : 0 : return 0;
8443 : 0 : break;
8444 : : #endif
8445 : :
8446 : : #if ( TAUT_PT_16_00 == 1 )
8447 : 0 : case ALT_PATH_MODE_TAUTOM_PT_16_00:
8448 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8449 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8450 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8451 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8452 [ # # ]: 0 : (!nGetEndpointInfo_PT_16_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8453 : 0 : return 0;
8454 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8455 [ # # ]: 0 : (!nGetEndpointInfo_PT_16_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8456 : 0 : return 0;
8457 : 0 : break;
8458 : : #endif
8459 : :
8460 : : #if ( TAUT_PT_06_00 == 1 )
8461 : 0 : case ALT_PATH_MODE_TAUTOM_PT_06_00:
8462 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8463 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8464 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8465 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8466 [ # # ]: 0 : (!nGetEndpointInfo_PT_06_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8467 : 0 : return 0;
8468 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8469 [ # # ]: 0 : (!nGetEndpointInfo_PT_06_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8470 : 0 : return 0;
8471 : 0 : break;
8472 : : #endif
8473 : :
8474 : : #if ( TAUT_PT_39_00 == 1 )
8475 : 0 : case ALT_PATH_MODE_TAUTOM_PT_39_00:
8476 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8477 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8478 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8479 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8480 [ # # ]: 0 : (!nGetEndpointInfo_PT_39_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8481 : 0 : return 0;
8482 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8483 [ # # ]: 0 : (!nGetEndpointInfo_PT_39_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8484 : 0 : return 0;
8485 : 0 : break;
8486 : : #endif
8487 : :
8488 : : #if ( TAUT_PT_13_00 == 1 )
8489 : 0 : case ALT_PATH_MODE_TAUTOM_PT_13_00:
8490 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8491 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8492 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8493 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8494 [ # # ]: 0 : (!nGetEndpointInfo_PT_13_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8495 : 0 : return 0;
8496 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8497 [ # # ]: 0 : (!nGetEndpointInfo_PT_13_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8498 : 0 : return 0;
8499 : 0 : break;
8500 : : #endif
8501 : :
8502 : : #if ( TAUT_PT_18_00 == 1 )
8503 : 0 : case ALT_PATH_MODE_TAUTOM_PT_18_00:
8504 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8505 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8506 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8507 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8508 [ # # ]: 0 : (!nGetEndpointInfo_PT_18_00(at, nVertSingleBond, &eif) || !eif.cDonor))
8509 : 0 : return 0;
8510 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8511 [ # # ]: 0 : (!nGetEndpointInfo_PT_18_00(at, nVertDoubleBond, &eif) || !eif.cAcceptor))
8512 : 0 : return 0;
8513 : 0 : break;
8514 : : #endif
8515 : :
8516 : :
8517 : : #if ( KETO_ENOL_TAUT == 1 )
8518 : 0 : case ALT_PATH_MODE_TAUTOM_KET:
8519 : : /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
8520 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8521 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8522 : :
8523 [ # # # # ]: 0 : if (!at[nVertSingleBond].endpoint &&
8524 [ # # ]: 0 : ( !nGetEndpointInfo_KET( at, nVertSingleBond, &eif ) || !eif.cDonor ))
8525 : : {
8526 : 0 : return 0;
8527 : : }
8528 [ # # # # ]: 0 : if (!at[nVertDoubleBond].endpoint &&
8529 [ # # ]: 0 : ( !nGetEndpointInfo_KET( at, nVertDoubleBond, &eif2 ) || !eif2.cAcceptor ))
8530 : : {
8531 : 0 : return 0;
8532 : : }
8533 : : /*
8534 : : if ( eif.cKetoEnolCode + eif2.cKetoEnolCode != 3 )
8535 : : return 0;
8536 : : */
8537 : 0 : break;
8538 : :
8539 : : #endif
8540 : 0 : case ALT_PATH_MODE_CHARGE:
8541 : : /* Find alt path allowing to move (+). Purpose: establish "charge groups",
8542 : : mark alt. bonds due to (+) charge movement */
8543 : 0 : type = BNS_VERT_TYPE_C_POINT;
8544 : 0 : bChangeFlow = ( BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS );
8545 : 0 : break;
8546 : :
8547 : 0 : case ALT_PATH_MODE_4_SALT:
8548 : : case ALT_PATH_MODE_4_SALT2:
8549 : : /* Find alt paths allowing to move (-) and H between "acidic oxygen atoms".
8550 : : Purpose: mark alt bonds due to this "long range" tautomerism. */
8551 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8552 : 0 : bChangeFlow = ( BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS );
8553 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
8554 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ))
8555 : : {
8556 : 0 : return 0;
8557 : : }
8558 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertDoubleBond].endpoint*/ &&
8559 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ))
8560 : : {
8561 : 0 : return 0;
8562 : : }
8563 : 0 : memset( &apc, 0, sizeof( apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8564 : 0 : break;
8565 : :
8566 : 0 : case ALT_PATH_MODE_REM2H_CHG:
8567 : 0 : bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
8568 : 0 : case ALT_PATH_MODE_REM2H_TST:
8569 : 0 : bChangeFlow |= BNS_EF_CHNG_RSTR;
8570 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8571 : : /* Allow non-tautomeric donors or any tautomeric atom */
8572 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertSingleBond ) /* not linked to a t-group or the edge forbidden */ &&
8573 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor )) /* not a donor */
8574 : : {
8575 : 0 : return 0;
8576 : : }
8577 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* not connected to a t-group */ &&
8578 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cDonor ))
8579 : : {
8580 : 0 : return 0;
8581 : : }
8582 : 0 : memset( &apc, 0, sizeof( apc ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8583 : 0 : break;
8584 : :
8585 : 0 : case ALT_PATH_MODE_ADD2H_CHG:
8586 : 0 : bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
8587 : 0 : case ALT_PATH_MODE_ADD2H_TST:
8588 : 0 : bChangeFlow |= BNS_EF_CHNG_RSTR;
8589 : 0 : type = BNS_VERT_TYPE_ENDPOINT;
8590 : : /* Allow non-tautomeric acceptors or any tautomeric atom */
8591 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
8592 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cAcceptor ))
8593 : : {
8594 : 0 : return 0;
8595 : : }
8596 [ # # # # ]: 0 : if (!bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertSingleBond].endpoint*/ &&
8597 [ # # ]: 0 : ( !nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ))
8598 : : {
8599 : 0 : return 0;
8600 : : }
8601 : 0 : break;
8602 : :
8603 : 0 : case ALT_PATH_MODE_REM_PROTON:
8604 : : /* alt path is between the t-group (nVertDoubleBond) and
8605 : : the (+)-charge group (nVertSingleBond) */
8606 : 0 : type = 0;
8607 : : /*bDoMarkChangedBonds = 0;*/
8608 : 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*/
8609 : 0 : break;
8610 : 0 : default:
8611 : 0 : type = 0;
8612 : 0 : bChangeFlow = BNS_EF_CHNG_RSTR;
8613 : 0 : break;
8614 : : }
8615 : :
8616 : 0 : bError = 0;
8617 : 0 : bSuccess = 0;
8618 : 0 : nDelta = 0;
8619 : :
8620 : 0 : ret = SetRadEndpoints2( pCG, pBNS, pBD, RAD_SRCH_NORM );
8621 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8622 : : {
8623 : 0 : return ret;
8624 : : }
8625 : :
8626 : : /* Set BNS to check alt path */
8627 : 0 : ret = bSetBnsToCheckAltPath( pBNS, nVertDoubleBond, nVertSingleBond, type, path_type, &apc, fcd, &nDots );
8628 [ # # # # : 0 : switch (ret)
# # ]
8629 : : {
8630 : 0 : case BNS_CHK_ALTP_NO_ALTPATH:
8631 : 0 : ret = RemoveRadEndpoints( pBNS, pBD, NULL );
8632 : 0 : return ret;
8633 : 0 : case BNS_CHK_ALTP_SAME_TGROUP:
8634 : 0 : bSuccess = 1;
8635 : 0 : goto reinit_BNS;
8636 : 0 : case BNS_CHK_ALTP_SAME_VERTEX:
8637 : 0 : ret = RemoveRadEndpoints( pBNS, pBD, NULL );
8638 [ # # ]: 0 : return ret ? ret : 1; /* very strange ... set a breakpoint here */
8639 : 0 : case BNS_CHK_ALTP_SET_SUCCESS:
8640 : 0 : break; /* actually check the existence of the altpath */
8641 : 0 : case BNS_CANT_SET_BOND:
8642 : 0 : goto reinit_BNS;
8643 : 0 : default:
8644 : 0 : ret_val = RemoveRadEndpoints( pBNS, pBD, NULL ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
8645 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8646 : : {
8647 : 0 : return ret;
8648 : : }
8649 : 0 : return BNS_PROGRAM_ERR;
8650 : : }
8651 : :
8652 [ # # # # ]: 0 : bAdjustRadicals = ( ( bChangeFlow & BNS_EF_UPD_RAD_ORI ) && !( bChangeFlow & BNS_EF_RSTR_FLOW ) );
8653 : :
8654 : : /*****************************************************************
8655 : : * nDots = 2 for ALT_PATH_CHARGE (checking moveable positive charges)
8656 : : * Now nDots for ALT_PATH_TAUTOM or ALT_PATH_4_SALT can be greater
8657 : : * because some of the bonds are effectively removed and dots
8658 : : * (vertex st-caps) may be added
8659 : : * -- to make sure there is no (+) charge on a tautomeric endpoint
8660 : : * -- to fix positions of moveable tautomeric attachements
8661 : : * (H and (-)-charges) at the ends of an alt path
8662 : : */
8663 : :
8664 : : /* Run BNS */
8665 : :
8666 : 0 : ret = RunBalancedNetworkSearch( pBNS, pBD, bChangeFlow );
8667 : :
8668 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8669 : : {
8670 : 0 : bError = ret;
8671 : : }
8672 [ # # ]: 0 : else if (ret > 0)
8673 : : {
8674 [ # # ]: 0 : if (2 * ret >= nDots)
8675 : : {
8676 : 0 : nDelta = 2 * ret - nDots; /* non-zero means augmentation created another alt. path -- between radicals */
8677 [ # # # # ]: 0 : if (pAATG && pAATG->nMarkedAtom)
8678 : : {
8679 [ # # # # ]: 0 : if (pAATG->nAtTypeTotals && ( bChangeFlow & BNS_EF_UPD_H_CHARGE ))
8680 : : {
8681 : 0 : memset( pAATG->nMarkedAtom, 0, num_atoms * sizeof( pAATG->nMarkedAtom[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
8682 : : /* Mark atoms that have charge or H changed, check their input types (that is, before changes),
8683 : : and subtract their input charge/H from nAtTypeTotals */
8684 : 0 : SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom, NULL, 1 );
8685 : : /* ZChange charges and/or H, update t_group_info, do not check types or change nAtTypeTotals */
8686 : : /* Atom types will be checked and nAtTypeTotals will be changed in
8687 : : AddChangedAtHChargeBNS() later */
8688 : 0 : SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, NULL, NULL, pAATG->t_group_info, 0 );
8689 : : }
8690 : : else
8691 : : {
8692 [ # # ]: 0 : if (!pAATG->nAtTypeTotals)
8693 : : {
8694 : 0 : bDoMarkChangedBonds = MarkAtomsAtTautGroups( pBNS, num_atoms, pAATG, nVertSingleBond, nVertDoubleBond );
8695 [ # # ]: 0 : if (bDoMarkChangedBonds < 0)
8696 : : {
8697 : 0 : bError = bDoMarkChangedBonds;
8698 : 0 : bDoMarkChangedBonds = 0;
8699 : : }
8700 : : }
8701 : : }
8702 : : }
8703 [ # # ]: 0 : if (bDoMarkChangedBonds)
8704 : : {
8705 : : /* Mark bonds that were changed to configure bond testing */
8706 : 0 : ret_val = bSetBondsAfterCheckOneBond( pBNS, fcd, -1, at, num_atoms, bChangeFlow );
8707 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret_val ))
8708 : : {
8709 : 0 : bError = ret_val;
8710 : : }
8711 : : /*ret = SetBondsRestoreBnStructFlow( pBNS, at, num_atoms, bChangeFlow );*/
8712 : : /* mark all other changed bonds */
8713 : 0 : ret = SetBondsFromBnStructFlow( pBNS, at, num_atoms, bChangeFlow );
8714 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8715 : : {
8716 : 0 : bError = ret;
8717 : : }
8718 : : else
8719 : : {
8720 [ # # # # ]: 0 : if (!( ret & 1 ) && !( ret_val & 1 ))
8721 : : {
8722 : 0 : bSuccess = 1;
8723 : : }
8724 : : else
8725 : : {
8726 [ # # # # ]: 0 : if ((( ( ret & 1 ) || ( ret_val & 1 ) ) &&
8727 [ # # # # ]: 0 : ( bChangeFlow & BNS_EF_ALTR_BONDS )) || ( bChangeFlow & BNS_EF_UPD_H_CHARGE )) /* djb-rwth: addressing LLVM warning */
8728 : : {
8729 : : /* Some bonds have been changed to alternating */
8730 : 0 : bSuccess = 3;
8731 : : }
8732 : : else
8733 : : {
8734 : 0 : bError = BNS_BOND_ERR;
8735 : : }
8736 : : }
8737 : : }
8738 [ # # # # : 0 : if (!bError && pAATG && pAATG->nMarkedAtom && ( bChangeFlow & BNS_EF_UPD_H_CHARGE ))
# # # # ]
8739 : : {
8740 : : /* Update radicals to avoid errors in atom type check in AddChangedAtHChargeBNS() */
8741 [ # # ]: 0 : if (bAdjustRadicals)
8742 : : {
8743 : 0 : ret_val = RestoreRadicalsOnly( pBNS, pBD, at );
8744 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret_val ))
8745 : : {
8746 : 0 : bError = ret_val;
8747 : : }
8748 : : }
8749 : : /* Check atom types of marked atoms and add charge/H changes to nAtTypeTotals */
8750 : : /* Changing atoms were marked in the 1st call to SubtractOrChangeAtHChargeBNS(..., 1) above */
8751 : 0 : AddChangedAtHChargeBNS( at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom );
8752 [ # # ]: 0 : if (bChangeFlow & BNS_EF_CHNG_FLOW)
8753 : : {
8754 : : /* Eliminate ambiguities in already changed flow:
8755 : : replace (+)--N==(-) with (+)==N--(-) (both represent neutral N) */
8756 : 0 : EliminatePlusMinusChargeAmbiguity( pBNS, num_atoms );
8757 : : }
8758 : : }
8759 : : }
8760 : : }
8761 : :
8762 : 0 : ret = RestoreBnStructFlow( pBNS, bChangeFlow & BNS_EF_CHNG_RSTR );
8763 : :
8764 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
8765 : : {
8766 : 0 : bError = ret;
8767 : : }
8768 : : }
8769 : :
8770 : 0 : reinit_BNS:
8771 : :
8772 : : /* --- Reinitialize to repeat the calculations --- */
8773 : 0 : bRestoreBnsAfterCheckAltPath( pBNS, &apc, bChangeFlow & BNS_EF_UPD_H_CHARGE );
8774 : 0 : bRestoreFlowAfterCheckOneBond( pBNS, fcd );
8775 [ # # ]: 0 : ret_val = RemoveRadEndpoints( pBNS, pBD, bAdjustRadicals ? at : NULL );
8776 : 0 : ReInitBnStructAltPaths( pBNS );
8777 : :
8778 [ # # # # ]: 0 : return bError ? bError : ret_val ? ret_val : ( bSuccess + 4 * nDelta );
8779 : : }
8780 : :
8781 : :
8782 : : /****************************************************************************/
8783 : 69 : BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at,
8784 : : int num_atoms,
8785 : : int nMaxAddAtoms,
8786 : : int nMaxAddEdges,
8787 : : int max_altp,
8788 : : int *pNum_changed_bonds )
8789 : : {
8790 : 69 : BN_STRUCT *pBNS = NULL;
8791 : : BNS_VERTEX *vert;
8792 : :
8793 : 69 : int neigh, num_changed_bonds = 0;
8794 : : U_CHAR bond_type, bond_mark;
8795 : :
8796 : : int i, j, k, n_edges, num_bonds, num_edges, f1, f2, edge_cap, edge_flow, st_flow; /* djb-rwth: removing redundant variables */
8797 : : int tot_st_cap, tot_st_flow;
8798 : : int max_tg, max_edges, max_vertices, len_alt_path, max_iedges, num_altp;
8799 : : #if ( BNS_RAD_SEARCH == 1 )
8800 : 69 : int num_rad = 0;
8801 : :
8802 : 69 : nMaxAddEdges += 1;
8803 : : #endif
8804 : : #if ( FIX_NUM_TG == 1 )
8805 : : max_tg = inchi_max( num_atoms / 2, 5 );
8806 : : #else
8807 : 69 : max_tg = num_atoms;
8808 : : #endif
8809 : 69 : num_changed_bonds = 0;
8810 : :
8811 [ + + ]: 688 : for (i = 0, num_bonds = 0; i < num_atoms; i++)
8812 : : {
8813 : : /*(@nnuk : Nauman Ullah Khan) */
8814 : : LOG_NO_ARGS("\n################# (L8916:ichi_bns.c) ###################\n");
8815 : : LOG_MULT_ARGS("Number of changed bonds (Start): %d\n", num_changed_bonds);
8816 : : LOG_NO_ARGS("\n########################################################\n");
8817 : :
8818 : 619 : num_bonds += at[i].valence;
8819 : : #if ( BNS_RAD_SEARCH == 1 )
8820 : 619 : num_rad += ( at[i].radical == RADICAL_DOUBLET );
8821 : : #endif
8822 : : }
8823 : : /* Each atom has enough edges to belong to a tautomeric group + nMaxAddEdges */
8824 : : /* number of atoms is large enough to accommodate max. possible number of t-groups + nMaxAddAtoms */
8825 : : /* max_altp cannot be larger than BN_MAX_ALTP = 16 */
8826 : 69 : num_edges = ( num_bonds /= 2 );
8827 : : /* +1 for a super-tautomeric group */
8828 : 69 : max_vertices = num_atoms + nMaxAddAtoms + max_tg + 1;
8829 : : /* +max_tg for edges between t-groups and super-tautomeric group */
8830 : 69 : max_edges = num_edges + ( nMaxAddEdges + NUM_KINDS_OF_GROUPS )*max_vertices + max_tg;
8831 : : #if ( BNS_RAD_SEARCH == 1 )
8832 [ - + ]: 69 : if (num_rad)
8833 : : {
8834 : 0 : max_vertices *= 2;
8835 : 0 : max_edges *= 2;
8836 : : }
8837 : : #endif
8838 : 69 : max_iedges = 2 * max_edges;
8839 : 69 : len_alt_path = max_vertices + iALTP_HDR_LEN + 1; /* may overflow if an edge is traversed in 2 directions */
8840 : :
8841 [ + - ]: 69 : if (!( pBNS = (BN_STRUCT *) inchi_calloc( 1, sizeof( BN_STRUCT ) ) ) ||
8842 [ + - ]: 69 : !( pBNS->edge = (BNS_EDGE *) inchi_calloc( max_edges, sizeof( BNS_EDGE ) ) ) ||
8843 [ + - ]: 69 : !( pBNS->vert = (BNS_VERTEX *) inchi_calloc( max_vertices, sizeof( BNS_VERTEX ) ) ) ||
8844 [ - + ]: 69 : !( pBNS->iedge = (BNS_IEDGE *) inchi_calloc( max_iedges, sizeof( BNS_IEDGE ) ) ))
8845 : : {
8846 : 0 : return DeAllocateBnStruct( pBNS );
8847 : : }
8848 : : /* Alt path init */
8849 [ + + + - ]: 1173 : for (num_altp = 0; num_altp < max_altp && num_altp < BN_MAX_ALTP; num_altp++)
8850 : : {
8851 [ - + ]: 1104 : if (!( pBNS->altp[num_altp] = (BNS_ALT_PATH*) inchi_calloc( len_alt_path, sizeof( BNS_ALT_PATH ) ) ))
8852 : : {
8853 : 0 : return DeAllocateBnStruct( pBNS );
8854 : : }
8855 : 1104 : ALTP_ALLOCATED_LEN( pBNS->altp[num_altp] ) = len_alt_path;
8856 : 1104 : pBNS->len_alt_path = len_alt_path; /* ??? duplication ??? */
8857 : : /* re-init */
8858 : 1104 : ALTP_DELTA( pBNS->altp[num_altp] ) = 0;
8859 : 1104 : ALTP_START_ATOM( pBNS->altp[num_altp] ) = NO_VERTEX;
8860 : 1104 : ALTP_END_ATOM( pBNS->altp[num_altp] ) = NO_VERTEX;
8861 : 1104 : ALTP_PATH_LEN( pBNS->altp[num_altp] ) = 0;
8862 : : }
8863 : 69 : pBNS->alt_path = NULL;
8864 : 69 : pBNS->num_altp = 0;
8865 : 69 : pBNS->max_altp = num_altp;
8866 : :
8867 : : /* Fill vertices (no connectivity) */
8868 : 69 : pBNS->vert[0].iedge = pBNS->iedge;
8869 [ + + ]: 688 : for (i = 0; i < num_atoms; i++)
8870 : : {
8871 : 619 : k = pBNS->vert[i].max_adj_edges = at[i].valence + ( nMaxAddEdges + NUM_KINDS_OF_GROUPS );
8872 : 619 : pBNS->vert[i + 1].iedge = pBNS->vert[i].iedge + k;
8873 : : }
8874 : 69 : pBNS->num_atoms = num_atoms; /* number of real atoms */
8875 : 69 : pBNS->num_added_atoms = 0;
8876 : 69 : pBNS->num_t_groups = 0; /* number of added t-groups */
8877 : 69 : pBNS->num_c_groups = 0;
8878 : 69 : pBNS->nMaxAddAtoms = nMaxAddAtoms;
8879 : 69 : pBNS->nMaxAddEdges = nMaxAddEdges;
8880 : :
8881 : 69 : pBNS->num_vertices = num_atoms; /* current number of vertices, a sum of
8882 : : pBNS->num_atoms
8883 : : pBNS->num_t_groups
8884 : : pBNS->num_added_atoms */
8885 : 69 : pBNS->max_vertices = max_vertices;
8886 : :
8887 : :
8888 : 69 : pBNS->num_bonds = num_bonds; /* number of real edges (bonds) */
8889 : 69 : pBNS->max_edges = max_edges;
8890 : 69 : pBNS->max_iedges = max_iedges;
8891 : :
8892 : : /*
8893 : : To remove t-groups and added atoms:
8894 : : In atoms i = 0..pBNS->num_atoms-1
8895 : : pBNS->vert[i].num_adj_edges = pBNS->vert[i].max_adj_edges - pBNS->nMaxAddEdges - NUM_KINDS_OF_GROUPS;
8896 : : pBNS->num_vertices = pBNS->num_atoms;
8897 : : pBNS->num_edges = pBNS->num_bonds;
8898 : : pBNS->num_added_atoms = 0;
8899 : : pBNS->num_t_groups = 0;
8900 : : pBNS->num_added_edges = 0;
8901 : :
8902 : : ALTP_DELTA(pBNS->alt_path) = 0;
8903 : : ALTP_START_ATOM(pBNS->alt_path) = NO_VERTEX;
8904 : : ALTP_END_ATOM(pBNS->alt_path) = NO_VERTEX;
8905 : : ALTP_PATH_LEN(pBNS->alt_path) = 0;
8906 : : */
8907 : :
8908 : : /* Fill edges and connectivity */
8909 : 69 : tot_st_cap = tot_st_flow = 0;
8910 [ + + ]: 688 : for (i = 0, n_edges = 0; i < num_atoms; i++)
8911 : : {
8912 : 619 : vert = &pBNS->vert[i];
8913 : : /* djb-rwth: removing redundant code */
8914 : 619 : st_flow = 0;
8915 : : /* djb-rwth: removing redundant code */
8916 [ + + ]: 1753 : for (j = 0; j < at[i].valence; j++)
8917 : : {
8918 : 1134 : neigh = at[i].neighbor[j];
8919 : : /* find this bond at the neighbor */
8920 [ + - ]: 1873 : for (k = 0; k < at[neigh].valence; k++)
8921 : : {
8922 [ + + ]: 1873 : if (at[neigh].neighbor[k] == i)
8923 : : {
8924 : 1134 : break;
8925 : : }
8926 : : }
8927 : 1134 : bond_type = ( at[i].bond_type[j] & BOND_TYPE_MASK );
8928 : 1134 : bond_mark = ( at[i].bond_type[j] & ~BOND_TYPE_MASK );
8929 [ + + + + : 1134 : if (bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE &&
+ - ]
8930 : : bond_type != BOND_TRIPLE /*&& bond_type != BOND_ALTERN*/)
8931 : : {
8932 : : /* Make Unknown or Alternating bonds single */
8933 : 4 : bond_type = 1;
8934 : 4 : at[i].bond_type[j] = bond_mark | bond_type;
8935 : 4 : num_changed_bonds++;
8936 : : }
8937 [ + + ]: 1134 : if (neigh > i)
8938 : : {
8939 : : /* This is the first time we encounter this bond */
8940 [ + + + + : 567 : f1 = MAX_AT_FLOW( at[i] );
- + ]
8941 [ + + + + : 567 : f2 = MAX_AT_FLOW( at[neigh] );
- + ]
8942 : 567 : edge_flow = bond_type - 1;
8943 [ - + ]: 567 : if (edge_flow > MAX_BOND_EDGE_CAP)
8944 : : {
8945 : : /* djb-rwth: removing redundant code */
8946 : 0 : edge_flow = 0; /* BNS will determine flows (that is, bonds) */
8947 : 0 : edge_cap = AROM_BOND_EDGE_CAP;
8948 : : }
8949 : : else
8950 : : {
8951 : : #if ( 0 && KETO_ENOL_TAUT == 1 ) /* ????? */
8952 : : edge_cap = inchi_max( f1, f2 );
8953 : : #else
8954 : 567 : edge_cap = inchi_min( f1, f2 );
8955 : : #endif
8956 : 567 : edge_cap = inchi_min( edge_cap, MAX_BOND_EDGE_CAP ); /* max capacity = 2 means up to triple bond */
8957 : : }
8958 : :
8959 : 567 : pBNS->edge[n_edges].neighbor1 = (AT_NUMB) i;
8960 : 567 : pBNS->edge[n_edges].neighbor12 = (AT_NUMB) ( i ^ neigh );
8961 : 567 : pBNS->edge[n_edges].flow = pBNS->edge[n_edges].flow0 = edge_flow;
8962 : 567 : pBNS->edge[n_edges].cap = pBNS->edge[n_edges].cap0 = edge_cap;
8963 : 567 : pBNS->edge[n_edges].neigh_ord[0] = j;
8964 : 567 : pBNS->edge[n_edges].neigh_ord[1] = k;
8965 : 567 : pBNS->edge[n_edges].pass = 0;
8966 : 567 : pBNS->edge[n_edges].forbidden = 0;
8967 : :
8968 : 567 : vert->iedge[j] = pBNS->vert[neigh].iedge[k] = n_edges++;
8969 : : }
8970 : : else
8971 : : {
8972 : : /* This is the second time we encounter this bond. It was stored at */
8973 : 567 : int iedge = pBNS->vert[neigh].iedge[k];
8974 : 567 : edge_cap = pBNS->edge[iedge].cap; /* djb-rwth: ignoring LLVM warning: variable used */
8975 : 567 : edge_flow = pBNS->edge[iedge].flow;
8976 : : }
8977 : 1134 : st_flow += edge_flow;
8978 : : /* djb-rwth: removing redundant code */
8979 : : }
8980 : 619 : vert->num_adj_edges = j;
8981 : 619 : vert->st_edge.cap =
8982 [ + + + + : 619 : vert->st_edge.cap0 = MAX_AT_FLOW( at[i] );
- + ]
8983 : 619 : vert->st_edge.flow =
8984 : 619 : vert->st_edge.flow0 = st_flow;
8985 : 619 : vert->type = BNS_VERT_TYPE_ATOM;
8986 : 619 : tot_st_cap += vert->st_edge.cap;
8987 : 619 : tot_st_flow += vert->st_edge.flow;
8988 : : }
8989 : 69 : *pNum_changed_bonds = num_changed_bonds / 2;
8990 : :
8991 : 69 : pBNS->num_edges = n_edges; /* number of edges */
8992 : 69 : pBNS->num_added_edges = 0;
8993 : :
8994 : : /*(@nnuk : Nauman Ullah Khan) */
8995 : : LOG_NO_ARGS("\n################# (L9108:ichi_bns.c) ################\n");
8996 [ + + ]: 688 : for (i = 0, num_bonds = 0; i < num_atoms; i++) {
8997 : :
8998 : : LOG_MULT_ARGS("Element : %s, Number of changed bonds (End): %d\n", at[i].elname, *pNum_changed_bonds);
8999 : : }
9000 : : LOG_NO_ARGS("\n#####################################################\n");
9001 : :
9002 : 69 : pBNS->tot_st_cap = tot_st_cap;
9003 : 69 : pBNS->tot_st_flow = tot_st_flow;
9004 : :
9005 : 69 : return pBNS;
9006 : : }
9007 : :
9008 : :
9009 : : /****************************************************************************/
9010 : 69 : BN_STRUCT* DeAllocateBnStruct( BN_STRUCT *pBNS )
9011 : : {
9012 : : int i;
9013 [ + - ]: 69 : if (pBNS)
9014 : : {
9015 [ + - ]: 69 : if (pBNS->edge)
9016 : : {
9017 [ + - ]: 69 : inchi_free( pBNS->edge );
9018 : : }
9019 [ + + + - ]: 1173 : for (i = 0; i < pBNS->max_altp && i < BN_MAX_ALTP; i++)
9020 : : {
9021 [ + - ]: 1104 : if (pBNS->altp[i])
9022 : : {
9023 [ + - ]: 1104 : inchi_free( pBNS->altp[i] );
9024 : : }
9025 : : }
9026 [ + - ]: 69 : if (pBNS->vert)
9027 : : {
9028 [ + - ]: 69 : if (pBNS->vert[0].iedge)
9029 : : {
9030 [ + - ]: 69 : inchi_free( pBNS->vert[0].iedge );
9031 : : }
9032 [ + - ]: 69 : inchi_free( pBNS->vert );
9033 : : }
9034 [ + - ]: 69 : inchi_free( pBNS );
9035 : : }
9036 : :
9037 : 69 : return NULL;
9038 : : }
9039 : :
9040 : :
9041 : : /****************************************************************************/
9042 : 143 : int ReInitBnStructAltPaths( BN_STRUCT *pBNS )
9043 : : {
9044 : : int i;
9045 [ + + + - ]: 2431 : for (i = 0; i < pBNS->max_altp && i < BN_MAX_ALTP; i++)
9046 : : {
9047 [ + - ]: 2288 : if (pBNS->altp[i])
9048 : : {
9049 : 2288 : ALTP_DELTA( pBNS->altp[i] ) = 0;
9050 : 2288 : ALTP_PATH_LEN( pBNS->altp[i] ) = 0;
9051 : 2288 : ALTP_START_ATOM( pBNS->altp[i] ) = NO_VERTEX;
9052 : 2288 : ALTP_END_ATOM( pBNS->altp[i] ) = NO_VERTEX;
9053 : : }
9054 : : }
9055 : 143 : pBNS->alt_path = NULL;
9056 : 143 : pBNS->num_altp = 0;
9057 : 143 : return i;
9058 : : }
9059 : :
9060 : :
9061 : : /****************************************************************************/
9062 : 0 : int ReInitBnStructAddGroups( CANON_GLOBALS *pCG,
9063 : : BN_STRUCT *pBNS,
9064 : : inp_ATOM *at,
9065 : : int num_atoms,
9066 : : T_GROUP_INFO *tgi,
9067 : : C_GROUP_INFO *cgi )
9068 : : {
9069 : : int ret;
9070 : : /* strip all t-groups and c-groups */
9071 : 0 : ret = ReInitBnStruct( pBNS, at, num_atoms, 0 );
9072 [ # # ]: 0 : if (ret)
9073 : : {
9074 : 0 : ret = BNS_REINIT_ERR;
9075 : 0 : goto exit_function;
9076 : : }
9077 : : /*#if ( MOVE_CHARGES == 1 )*/
9078 [ # # ]: 0 : if (*pBNS->pbTautFlags & TG_FLAG_MOVE_POS_CHARGES)
9079 : : {
9080 : : /* Add c-groups */
9081 : 0 : ret = AddCGroups2BnStruct( pCG, pBNS, at, num_atoms, cgi );
9082 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
9083 : : {
9084 : 0 : goto exit_function;
9085 : : }
9086 : : }
9087 : : /*#endif*/
9088 : : /* Add t-groups */
9089 : 0 : ret = AddTGroups2BnStruct( pCG, pBNS, at, num_atoms, tgi );
9090 [ # # # # ]: 0 : if (IS_BNS_ERROR( ret ))
9091 : : {
9092 : 0 : goto exit_function;
9093 : : }
9094 : :
9095 : 0 : exit_function:
9096 : :
9097 : 0 : return ret;
9098 : : }
9099 : :
9100 : :
9101 : : /****************************************************************************/
9102 : 69 : int ReInitBnStruct( BN_STRUCT *pBNS,
9103 : : inp_ATOM *at,
9104 : : int num_at,
9105 : : int bRemoveGroupsFromAtoms )
9106 : : {
9107 : : int i, vfict, kfict, iedgefict, endpoint, centerpoint, iedge, k;
9108 : 69 : int ret = 0;
9109 [ + - ]: 69 : if (pBNS)
9110 : : {
9111 [ + - + - ]: 69 : if (pBNS->vert && pBNS->edge)
9112 : : {
9113 : : /* Debug */
9114 [ + + ]: 636 : for (k = 0, i = 0; k < pBNS->num_edges; k++)
9115 : : {
9116 [ - + ]: 567 : if (pBNS->edge[k].pass)
9117 : : {
9118 : 0 : i++;
9119 : : }
9120 : : }
9121 : 69 : ret += i * 100;
9122 : : /* Restore flow and cap on edges to vertices connected to fictitious atoms */
9123 [ - + ]: 69 : for (vfict = pBNS->num_atoms; vfict < pBNS->num_vertices; vfict++)
9124 : : {
9125 [ # # ]: 0 : for (kfict = 0; kfict < pBNS->vert[vfict].num_adj_edges; kfict++)
9126 : : {
9127 : 0 : iedgefict = pBNS->vert[vfict].iedge[kfict]; /* fictitious edge to the endpoint */
9128 : 0 : endpoint = pBNS->edge[iedgefict].neighbor12 ^ vfict; /* the endpoint */
9129 : : /* To simlify restore cap and flow in ALL edges to the endpoint */
9130 [ # # # # ]: 0 : if (bRemoveGroupsFromAtoms && endpoint < num_at)
9131 : : {
9132 : 0 : at[endpoint].c_point = 0;
9133 : 0 : at[endpoint].endpoint = 0;
9134 : : }
9135 [ # # ]: 0 : for (k = 0; k < pBNS->vert[endpoint].num_adj_edges; k++)
9136 : : {
9137 : 0 : iedge = pBNS->vert[endpoint].iedge[k]; /* edge to endpoint */
9138 : 0 : centerpoint = pBNS->edge[iedge].neighbor12 ^ endpoint;
9139 : 0 : pBNS->edge[iedge].cap = pBNS->edge[iedge].cap0;
9140 : 0 : pBNS->edge[iedge].flow = pBNS->edge[iedge].flow0;
9141 : 0 : pBNS->edge[iedge].pass = 0;
9142 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
9143 : 0 : pBNS->edge[iedge].forbidden &= pBNS->edge_forbidden_mask;
9144 : : #endif
9145 : 0 : pBNS->vert[centerpoint].st_edge.cap = pBNS->vert[centerpoint].st_edge.cap0;
9146 : 0 : pBNS->vert[centerpoint].st_edge.flow = pBNS->vert[centerpoint].st_edge.flow0;
9147 : : }
9148 : 0 : pBNS->vert[endpoint].st_edge.cap = pBNS->vert[endpoint].st_edge.cap0;
9149 : 0 : pBNS->vert[endpoint].st_edge.flow = pBNS->vert[endpoint].st_edge.flow0;
9150 : 0 : pBNS->vert[endpoint].type &= BNS_VERT_TYPE_ATOM;
9151 : : }
9152 : : }
9153 : : /* Reset number of neighbors */
9154 [ - + ]: 69 : if (pBNS->num_edges > pBNS->num_bonds)
9155 : : {
9156 [ # # ]: 0 : for (i = 0; i < pBNS->num_atoms; i++)
9157 : : {
9158 : 0 : pBNS->vert[i].num_adj_edges =
9159 : 0 : pBNS->vert[i].max_adj_edges - pBNS->nMaxAddEdges - NUM_KINDS_OF_GROUPS;
9160 : : }
9161 : : }
9162 : : }
9163 : : else
9164 : : {
9165 : 0 : ret += 2;
9166 : : }
9167 [ - + ]: 69 : if (!pBNS->edge)
9168 : : {
9169 : 0 : ret += 4;
9170 : : }
9171 [ - + ]: 69 : if (!pBNS->iedge)
9172 : : {
9173 : 0 : ret += 8;
9174 : : }
9175 : :
9176 : 69 : ReInitBnStructAltPaths( pBNS );
9177 : :
9178 : 69 : pBNS->num_vertices = pBNS->num_atoms;
9179 : 69 : pBNS->num_edges = pBNS->num_bonds;
9180 : 69 : pBNS->num_added_atoms = 0;
9181 : 69 : pBNS->num_t_groups = 0;
9182 : 69 : pBNS->num_c_groups = 0;
9183 : 69 : pBNS->num_added_edges = 0;
9184 : : }
9185 : : else
9186 : : {
9187 : 0 : ret += 1;
9188 : : }
9189 : :
9190 : 69 : return ret;
9191 : : }
9192 : :
9193 : :
9194 : : /****************************************************************************/
9195 : 0 : int CompTGroupNumber( const void *tg1, const void *tg2, void *p )
9196 : : {
9197 : 0 : return (int) ( (const T_GROUP *) tg1 )->nGroupNumber - (int) ( (const T_GROUP *) tg2 )->nGroupNumber;
9198 : : }
9199 : :
9200 : :
9201 : : /****************************************************************************/
9202 : 0 : int CompCGroupNumber( const void *cg1, const void *cg2, void *p )
9203 : : {
9204 : 0 : return (int) ( (const C_GROUP *) cg1 )->nGroupNumber - (int) ( (const C_GROUP *) cg2 )->nGroupNumber;
9205 : : }
9206 : :
9207 : :
9208 : : /****************************************************************************/
9209 : 0 : int AddTGroups2BnStruct( CANON_GLOBALS *pCG,
9210 : : BN_STRUCT *pBNS,
9211 : : inp_ATOM *at,
9212 : : int num_atoms,
9213 : : T_GROUP_INFO *tgi )
9214 : : {
9215 : 0 : int ret = 0;
9216 : : /* ret = ReInitBnStruct( pBNS ); */
9217 [ # # # # : 0 : if (tgi && tgi->num_t_groups && tgi->t_group)
# # ]
9218 : : {
9219 : : int i, k, endpoint, centerpoint, fictpoint;
9220 : 0 : int num_tg = tgi->num_t_groups;
9221 : 0 : int num_edges = pBNS->num_edges;
9222 : 0 : int num_vertices = pBNS->num_vertices;
9223 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing t-group */
9224 : : BNS_VERTEX *vert_endpoint;
9225 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric endpoint */
9226 : 0 : int nMaxTGroupNumber = 0;
9227 : : ENDPOINT_INFO eif;
9228 : :
9229 : : /* Debug: check overflow */
9230 [ # # ]: 0 : if (num_vertices + num_tg >= pBNS->max_vertices)
9231 : : {
9232 : 0 : return BNS_VERT_EDGE_OVFL;
9233 : : }
9234 : : /* Find the largest t-group ID */
9235 [ # # ]: 0 : for (i = 0; i < num_tg; i++)
9236 : : {
9237 [ # # ]: 0 : if (tgi->t_group[i].nGroupNumber > nMaxTGroupNumber)
9238 : : {
9239 : 0 : nMaxTGroupNumber = tgi->t_group[i].nGroupNumber;
9240 : : }
9241 : : }
9242 : : /* Since t-group IDs may be not contiguous, clear all vertices that will be added.
9243 : : all-zeroes-vertex will be ignored by the BNS
9244 : : */
9245 : 0 : memset( pBNS->vert + num_vertices, 0, nMaxTGroupNumber * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
9246 : : /* Make sure the last t-group has the largest t-group ID:
9247 : : this is necessary to correctly add new edges
9248 : : and vertices for testing augmenting paths */
9249 : : #if ( bRELEASE_VERSION != 1 )
9250 : : insertions_sort( pCG, tgi->t_group, num_tg, sizeof( tgi->t_group[0] ), CompTGroupNumber );
9251 : : for (i = 1; i < num_tg; i++)
9252 : : {
9253 : : if (1 != tgi->t_group[i].nGroupNumber - tgi->t_group[i - 1].nGroupNumber)
9254 : : {
9255 : : return BNS_BOND_ERR;
9256 : : }
9257 : : }
9258 : : #else
9259 [ # # ]: 0 : if (nMaxTGroupNumber != tgi->t_group[num_tg - 1].nGroupNumber)
9260 : : {
9261 : 0 : insertions_sort( pCG, tgi->t_group, num_tg, sizeof( tgi->t_group[0] ), CompTGroupNumber );
9262 : : }
9263 : : #endif
9264 : : /* Initialize new fictitious vertices */
9265 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
9266 : :
9267 [ # # ]: 0 : for (i = 0; i < num_tg; i++, ver_ficpont_prev = vert_ficpoint)
9268 : : {
9269 : : /*
9270 : : vert_ficpoint-1 is the last vertex;
9271 : : vert_ficpoint is the vertex that is being added
9272 : : Note: nGroupNumber are not contiguous
9273 : : */
9274 : 0 : vert_ficpoint = pBNS->vert + num_vertices + tgi->t_group[i].nGroupNumber - 1;
9275 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
9276 : 0 : vert_ficpoint->max_adj_edges = tgi->t_group[i].nNumEndpoints + BNS_ADD_EDGES + BNS_ADD_SUPER_TGROUP;
9277 : 0 : vert_ficpoint->num_adj_edges = 0;
9278 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
9279 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
9280 : 0 : vert_ficpoint->type = BNS_VERT_TYPE_TGROUP;
9281 : : }
9282 : :
9283 [ # # ]: 0 : for (endpoint = 0; endpoint < num_atoms; endpoint++)
9284 : : {
9285 [ # # ]: 0 : if (!at[endpoint].endpoint)
9286 : : {
9287 : 0 : continue;
9288 : : }
9289 : 0 : fictpoint = at[endpoint].endpoint + num_vertices - 1;
9290 : 0 : vert_ficpoint = pBNS->vert + fictpoint;
9291 : 0 : vert_endpoint = pBNS->vert + endpoint;
9292 : : /* Debug: check overflow */
9293 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
9294 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
9295 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
9296 [ # # ]: 0 : vert_endpoint->num_adj_edges >= vert_endpoint->max_adj_edges)
9297 : : {
9298 : 0 : ret = BNS_VERT_EDGE_OVFL;
9299 : 0 : break;
9300 : : }
9301 : : /* Obtain donor/acceptor info */
9302 [ # # ]: 0 : if (!nGetEndpointInfo(at, endpoint, &eif)
9303 : : #if ( TAUT_PT_22_00 == 1 )
9304 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_22_00) && nGetEndpointInfo_PT_22_00(at, endpoint, &eif))
9305 : : #endif
9306 : : #if ( TAUT_PT_16_00 == 1 )
9307 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_16_00) && nGetEndpointInfo_PT_16_00(at, endpoint, &eif))
9308 : : #endif
9309 : : #if ( TAUT_PT_06_00 == 1 )
9310 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_06_00) && nGetEndpointInfo_PT_06_00(at, endpoint, &eif))
9311 : : #endif
9312 : : #if ( TAUT_PT_39_00 == 1 )
9313 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_39_00) && nGetEndpointInfo_PT_39_00(at, endpoint, &eif))
9314 : : #endif
9315 : : #if ( TAUT_PT_13_00 == 1 )
9316 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_13_00) && nGetEndpointInfo_PT_13_00(at, endpoint, &eif))
9317 : : #endif
9318 : : #if ( TAUT_PT_18_00 == 1 )
9319 [ # # # # ]: 0 : && !((tgi->bTautFlags & TG_FLAG_PT_18_00) && nGetEndpointInfo_PT_18_00(at, endpoint, &eif))
9320 : : #endif
9321 : : ) {
9322 : : #if ( KETO_ENOL_TAUT == 1 )
9323 [ # # # # ]: 0 : if (!( ( tgi->bTautFlags & TG_FLAG_KETO_ENOL_TAUT ) &&
9324 : 0 : nGetEndpointInfo_KET( at, endpoint, &eif ) ))
9325 : : #endif
9326 : : {
9327 : 0 : ret = BNS_BOND_ERR;
9328 : 0 : break;
9329 : : }
9330 : : }
9331 : :
9332 : 0 : vert_endpoint->type |= BNS_VERT_TYPE_ENDPOINT;
9333 : :
9334 : : /* Set capacity = 1 to the edges from the endpoint to the centerpoint(s) */
9335 [ # # ]: 0 : for (k = 0; k < vert_endpoint->num_adj_edges; k++)
9336 : : {
9337 : 0 : int iedge = vert_endpoint->iedge[k];
9338 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
9339 : : {
9340 : : /* Single bond, possibly between endpoint and centerpoint */
9341 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ endpoint );
9342 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
9343 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
9344 : : {
9345 : 0 : int bond_type = ( at[endpoint].bond_type[k] & BOND_TYPE_MASK );
9346 [ # # # # ]: 0 : if (bond_type == BOND_TAUTOM ||
9347 [ # # ]: 0 : bond_type == BOND_ALTERN ||
9348 [ # # ]: 0 : bond_type == BOND_ALT12NS ||
9349 : : bond_type == BOND_SINGLE)
9350 : : {
9351 : 0 : pBNS->edge[iedge].cap = 1;
9352 : : }
9353 : : }
9354 : : }
9355 : : }
9356 : :
9357 : : /* Create a new edge connecting endpoint to the new fictitious t-group vertex vert_ficpoint */
9358 : 0 : edge = pBNS->edge + num_edges;
9359 : 0 : edge->cap = 1;
9360 : 0 : edge->flow = 0;
9361 : 0 : edge->pass = 0;
9362 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
9363 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask;
9364 : : #endif
9365 : : /* Later include case when the charge change allows the endpoint to become tautomeric */
9366 : : /* mark endoint having moveable H atom with flow=1 */
9367 : :
9368 : : /* -- old "no charges" version -- */
9369 : : /* if (at[endpoint].chem_bonds_valence == at[endpoint].valence) */
9370 : : /* -- the following line takes charges into account -- */
9371 [ # # ]: 0 : if (eif.cDonor) /* means the endpoint has an H-atom to donate */
9372 : : {
9373 : : /* increment edge flow */
9374 : 0 : edge->flow++;
9375 : : /* increment one vertex st-flow & cap */
9376 : 0 : vert_ficpoint->st_edge.flow++;
9377 : 0 : vert_ficpoint->st_edge.cap++;
9378 : : /* increment another vertex st-flow & cap */
9379 : 0 : vert_endpoint->st_edge.flow++;
9380 : 0 : vert_endpoint->st_edge.cap++;
9381 : : }
9382 : : /* Connect edge to endpoint and fictpoint and increment the counters of neighbors and edges */
9383 : 0 : edge->neighbor1 = endpoint; /* the smallest out of v1=endopoint and v2=num_vertices */
9384 : 0 : edge->neighbor12 = endpoint ^ fictpoint; /* v1 ^ v2 */
9385 : 0 : vert_endpoint->iedge[vert_endpoint->num_adj_edges] = num_edges;
9386 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
9387 : 0 : edge->neigh_ord[0] = vert_endpoint->num_adj_edges++;
9388 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
9389 : 0 : edge->cap0 = edge->cap;
9390 : 0 : edge->flow0 = edge->flow;
9391 : : }
9392 : :
9393 : 0 : pBNS->num_edges = num_edges;
9394 : 0 : pBNS->num_vertices += nMaxTGroupNumber;
9395 : 0 : pBNS->num_t_groups = num_tg;
9396 : : }
9397 : :
9398 : 0 : return ret;
9399 : : }
9400 : :
9401 : :
9402 : : /*#if ( MOVE_CHARGES == 1 )*/ /* { */
9403 : :
9404 : :
9405 : : /****************************************************************************/
9406 : 0 : int AddCGroups2BnStruct( CANON_GLOBALS *pCG,
9407 : : BN_STRUCT *pBNS,
9408 : : inp_ATOM *at,
9409 : : int num_atoms,
9410 : : C_GROUP_INFO *cgi )
9411 : : {
9412 : 0 : int ret = 0;
9413 : : /* ret = ReInitBnStruct( pBNS ); */
9414 [ # # # # : 0 : if (cgi && cgi->num_c_groups && cgi->c_group)
# # ]
9415 : : {
9416 : : int i, k, c_point, centerpoint, fictpoint;
9417 : 0 : int num_cg = cgi->num_c_groups;
9418 : 0 : int num_edges = pBNS->num_edges;
9419 : 0 : int num_vertices = pBNS->num_vertices;
9420 : : BNS_VERTEX *vert_ficpoint, *ver_ficpont_prev; /* fictitious vertex describing charge c-group */
9421 : : BNS_VERTEX *vertex_cpoint;
9422 : : BNS_EDGE *edge; /* edge between that vertex and the tautomeric c_point */
9423 : 0 : int nMaxCGroupNumber = 0;
9424 : :
9425 : : /* Debug: check overflow */
9426 [ # # ]: 0 : if (num_vertices + num_cg >= pBNS->max_vertices)
9427 : : {
9428 : 0 : return BNS_VERT_EDGE_OVFL;
9429 : : }
9430 : : /* Find the largest t-group ID */
9431 [ # # ]: 0 : for (i = 0; i < num_cg; i++)
9432 : : {
9433 [ # # ]: 0 : if (cgi->c_group[i].nGroupNumber > nMaxCGroupNumber)
9434 : : {
9435 : 0 : nMaxCGroupNumber = cgi->c_group[i].nGroupNumber;
9436 : : }
9437 : : }
9438 : : /* Since t-group IDs may be not contiguous, clear all vertices that will be added.
9439 : : all-zeroes-vertex will be ignored by the BNS
9440 : : */
9441 : 0 : memset( pBNS->vert + num_vertices, 0, nMaxCGroupNumber * sizeof( pBNS->vert[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
9442 : : /* Make sure the last t-group has the largest t-group ID:
9443 : : this is necessary to correctly add new edges and vertices for testing augmenting paths
9444 : : */
9445 : : #if ( bRELEASE_VERSION != 1 )
9446 : : insertions_sort( cgi->c_group, num_cg, sizeof( cgi->c_group[0] ), CompCGroupNumber );
9447 : : for (i = 1; i < num_cg; i++)
9448 : : {
9449 : : if (1 != cgi->c_group[i].nGroupNumber - cgi->c_group[i - 1].nGroupNumber)
9450 : : {
9451 : : return BNS_BOND_ERR;
9452 : : }
9453 : : }
9454 : : #else
9455 [ # # ]: 0 : if (nMaxCGroupNumber != cgi->c_group[num_cg - 1].nGroupNumber)
9456 : : {
9457 : 0 : insertions_sort( pCG, cgi->c_group, num_cg,
9458 : : sizeof( cgi->c_group[0] ),
9459 : : CompCGroupNumber );
9460 : : }
9461 : : #endif
9462 : : /**************************************/
9463 : : /* initialize new fictitious vertices */
9464 : : /* representing c-point groups */
9465 : : /**************************************/
9466 : 0 : ver_ficpont_prev = pBNS->vert + num_vertices - 1;
9467 : :
9468 [ # # ]: 0 : for (i = 0; i < num_cg; i++, ver_ficpont_prev = vert_ficpoint)
9469 : : {
9470 : : /*
9471 : : vert_ficpoint-1 is the last vertex;
9472 : : vert_ficpoint is the being added vertex
9473 : : Note: nGroupNumber are not contiguous
9474 : : */
9475 : 0 : vert_ficpoint = pBNS->vert + num_vertices + cgi->c_group[i].nGroupNumber - 1;
9476 : 0 : vert_ficpoint->iedge = ver_ficpont_prev->iedge + ver_ficpont_prev->max_adj_edges;
9477 : 0 : vert_ficpoint->max_adj_edges = cgi->c_group[i].num_CPoints + BNS_ADD_EDGES;
9478 : 0 : vert_ficpoint->num_adj_edges = 0;
9479 : 0 : vert_ficpoint->st_edge.flow = vert_ficpoint->st_edge.flow0 = 0;
9480 : 0 : vert_ficpoint->st_edge.cap = vert_ficpoint->st_edge.cap0 = 0;
9481 : 0 : vert_ficpoint->type = BNS_VERT_TYPE_C_GROUP;
9482 : : }
9483 : :
9484 : : /************************************************/
9485 : : /* Connect c-points to the fictitious vertices */
9486 : : /* representing c-point groups; set caps, flows */
9487 : : /************************************************/
9488 [ # # ]: 0 : for (c_point = 0; c_point < num_atoms; c_point++)
9489 : : {
9490 [ # # ]: 0 : if (!at[c_point].c_point)
9491 : : {
9492 : 0 : continue;
9493 : : }
9494 : 0 : fictpoint = at[c_point].c_point + num_vertices - 1; /* c-group vertex index */
9495 : 0 : vert_ficpoint = pBNS->vert + fictpoint; /* c-group vertex */
9496 : 0 : vertex_cpoint = pBNS->vert + c_point; /* c_point vertex */
9497 : : /* Debug: check overflow */
9498 [ # # ]: 0 : if (fictpoint >= pBNS->max_vertices ||
9499 [ # # ]: 0 : num_edges >= pBNS->max_edges ||
9500 [ # # ]: 0 : vert_ficpoint->num_adj_edges >= vert_ficpoint->max_adj_edges ||
9501 [ # # ]: 0 : vertex_cpoint->num_adj_edges >= vertex_cpoint->max_adj_edges)
9502 : : {
9503 : 0 : ret = BNS_VERT_EDGE_OVFL;
9504 : 0 : break;
9505 : : }
9506 : 0 : vertex_cpoint->type |= BNS_VERT_TYPE_C_POINT;
9507 : : #if ( FIX_CPOINT_BOND_CAP != 1 ) /* { */
9508 : : /* set capacity = 1 to the edges from the c_point to the centerpoint(s) */
9509 : : /* if their current capacity is zero */
9510 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
9511 : : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
9512 : : {
9513 : : int iedge = vertex_cpoint->iedge[k];
9514 : : if (!pBNS->edge[iedge].cap)
9515 : : {
9516 : : /* single bond, possibly between c_point and centerpoint */
9517 : : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
9518 : : if (centerpoint < pBNS->num_atoms &&
9519 : : pBNS->vert[centerpoint].st_edge.cap >= 1)
9520 : : {
9521 : : int bond_type = ( at[c_point].bond_type[k] & BOND_TYPE_MASK );
9522 : : if (bond_type == BOND_TAUTOM ||
9523 : : bond_type == BOND_ALTERN ||
9524 : : bond_type == BOND_SINGLE)
9525 : : {
9526 : : pBNS->edge[iedge].cap = 1;
9527 : : }
9528 : : }
9529 : : }
9530 : : }
9531 : : #endif /* } FIX_CPOINT_BOND_CAP */
9532 : :
9533 : : /* Create a new edge connecting c_point to the new fictitious c-group vertex vert_ficpoint */
9534 : 0 : edge = pBNS->edge + num_edges;
9535 : 0 : edge->cap = 1;
9536 : 0 : edge->flow = 0;
9537 : 0 : edge->pass = 0;
9538 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
9539 : 0 : edge->forbidden &= pBNS->edge_forbidden_mask;
9540 : : #endif
9541 : : /* Mark edge to c-point having NO moveable charge with flow=1 */
9542 [ # # ]: 0 : if (!CHARGED_CPOINT( at, c_point ))
9543 : : {
9544 : : /* Increment edge flow */
9545 : 0 : edge->flow++;
9546 : : /* Increment c-group vertex st-flow & cap */
9547 : 0 : vert_ficpoint->st_edge.flow++;
9548 : 0 : vert_ficpoint->st_edge.cap++;
9549 : : /* Increment c-point vertex st-flow & cap */
9550 : 0 : vertex_cpoint->st_edge.flow++;
9551 : 0 : vertex_cpoint->st_edge.cap++;
9552 : : }
9553 : :
9554 : : #if ( FIX_CPOINT_BOND_CAP == 1 ) /* { */
9555 : :
9556 : : /* Set capacity = 1 to the edges from the c_point to the centerpoint(s) */
9557 : : /* if their current capacity is zero */
9558 : : /* the centerpoint is any adjacent atom that is adjacent to a multiple bond */
9559 [ # # ]: 0 : for (k = 0; k < vertex_cpoint->num_adj_edges; k++)
9560 : : {
9561 : 0 : int iedge = vertex_cpoint->iedge[k];
9562 : 0 : VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
9563 : 0 : centerpoint = ( pBNS->edge[iedge].neighbor12 ^ c_point );
9564 [ # # ]: 0 : if (!pBNS->edge[iedge].cap)
9565 : : {
9566 : : /* Single bond, possibly between c_point and centerpoint */
9567 [ # # ]: 0 : if (centerpoint < pBNS->num_atoms &&
9568 [ # # ]: 0 : pBNS->vert[centerpoint].st_edge.cap >= 1)
9569 : : {
9570 : 0 : nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
9571 : 0 : nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
9572 : 0 : pBNS->edge[iedge].cap = nNewCap;
9573 : : }
9574 : : #if ( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
9575 : : else
9576 : : if (centerpoint < pBNS->num_atoms &&
9577 : : edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP)
9578 : : {
9579 : : pBNS->edge[iedge].cap++;
9580 : : }
9581 : : #endif
9582 : : }
9583 : : }
9584 : : #endif /* } FIX_CPOINT_BOND_CAP */
9585 : :
9586 : : /* Connect edge to c_point and fictpoint and increment the counters of neighbors and edges */
9587 : 0 : edge->neighbor1 = c_point; /* the smallest out of v1=endopoint and v2=num_vertices */
9588 : 0 : edge->neighbor12 = c_point ^ fictpoint; /* v1 ^ v2 */
9589 : 0 : vertex_cpoint->iedge[vertex_cpoint->num_adj_edges] = num_edges;
9590 : 0 : vert_ficpoint->iedge[vert_ficpoint->num_adj_edges] = num_edges++;
9591 : 0 : edge->neigh_ord[0] = vertex_cpoint->num_adj_edges++;
9592 : 0 : edge->neigh_ord[1] = vert_ficpoint->num_adj_edges++;
9593 : 0 : edge->cap0 = edge->cap;
9594 : 0 : edge->flow0 = edge->flow;
9595 : : }
9596 : :
9597 : 0 : pBNS->num_edges = num_edges;
9598 : 0 : pBNS->num_vertices += nMaxCGroupNumber;
9599 : 0 : pBNS->num_c_groups = num_cg;
9600 : : }
9601 : :
9602 : 0 : return ret;
9603 : : }
9604 : : /*#endif*/ /* } MOVE_CHARGES == 1 */
9605 : :
9606 : :
9607 : :
9608 : : /****************************************************************************/
9609 : 69 : void ClearAllBnDataVertices( Vertex *v, Vertex value, int size )
9610 : : {
9611 : : int i;
9612 [ + + ]: 3097 : for (i = 0; i < size; i++)
9613 : : {
9614 : 3028 : v[i] = value;
9615 : : }
9616 : 69 : }
9617 : :
9618 : :
9619 : : /****************************************************************************/
9620 : 69 : void ClearAllBnDataEdges( Edge *e, Vertex value, int size )
9621 : : {
9622 : : int i;
9623 [ + + ]: 3097 : for (i = 0; i < size; i++)
9624 : : {
9625 : 3028 : e[i][0] = value;
9626 : : }
9627 : 69 : }
9628 : :
9629 : :
9630 : : /****************************************************************************/
9631 : 69 : BN_DATA *DeAllocateBnData( BN_DATA *pBD )
9632 : : {
9633 [ + - ]: 69 : if (pBD)
9634 : : {
9635 [ + - ]: 69 : if (pBD->BasePtr)
9636 : : {
9637 [ + - ]: 69 : inchi_free( pBD->BasePtr );
9638 : : }
9639 [ + - ]: 69 : if (pBD->SwitchEdge)
9640 : : {
9641 [ + - ]: 69 : inchi_free( pBD->SwitchEdge );
9642 : : }
9643 [ + - ]: 69 : if (pBD->Tree)
9644 : : {
9645 [ + - ]: 69 : inchi_free( pBD->Tree );
9646 : : }
9647 [ + - ]: 69 : if (pBD->ScanQ)
9648 : : {
9649 [ + - ]: 69 : inchi_free( pBD->ScanQ );
9650 : : }
9651 [ + - ]: 69 : if (pBD->Pu)
9652 : : {
9653 [ + - ]: 69 : inchi_free( pBD->Pu );
9654 : : }
9655 [ + - ]: 69 : if (pBD->Pv)
9656 : : {
9657 [ + - ]: 69 : inchi_free( pBD->Pv );
9658 : : }
9659 : : #if ( BNS_RAD_SEARCH == 1 )
9660 [ + - ]: 69 : if (pBD->RadEndpoints)
9661 : : {
9662 [ + - ]: 69 : inchi_free( pBD->RadEndpoints );
9663 : : }
9664 [ + - ]: 69 : if (pBD->RadEdges)
9665 : : {
9666 [ + - ]: 69 : inchi_free( pBD->RadEdges );
9667 : : }
9668 : : #endif
9669 [ + - ]: 69 : inchi_free( pBD );
9670 : : }
9671 : :
9672 : 69 : return NULL;
9673 : : }
9674 : :
9675 : :
9676 : : /****************************************************************************/
9677 : 69 : BN_DATA *AllocateAndInitBnData( int max_num_vertices )
9678 : : {
9679 : 69 : BN_DATA *pBD = NULL;
9680 : : int max_len_Pu_Pv;
9681 : 69 : max_num_vertices = 2 * max_num_vertices + 2;
9682 : 69 : max_len_Pu_Pv = max_num_vertices / 2 + 1;
9683 : 69 : max_len_Pu_Pv += max_len_Pu_Pv % 2; /* even length */
9684 [ + - ]: 69 : if (!( pBD = (BN_DATA *) inchi_calloc( 1, sizeof( BN_DATA ) ) ) ||
9685 [ + - ]: 69 : !( pBD->BasePtr = (Vertex *) inchi_calloc( max_num_vertices, sizeof( Vertex ) ) ) ||
9686 [ + - ]: 69 : !( pBD->SwitchEdge = (Edge *) inchi_calloc( max_num_vertices, sizeof( Edge ) ) ) ||
9687 [ + - ]: 69 : !( pBD->Tree = (S_CHAR *) inchi_calloc( max_num_vertices, sizeof( S_CHAR ) ) ) ||
9688 [ + - ]: 69 : !( pBD->ScanQ = (Vertex *) inchi_calloc( max_num_vertices, sizeof( Vertex ) ) ) ||
9689 [ + - ]: 69 : !( pBD->Pu = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof( Vertex ) ) ) ||
9690 : : #if ( BNS_RAD_SEARCH == 1 )
9691 [ + - ]: 69 : !( pBD->RadEndpoints = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof( Vertex ) ) ) ||
9692 [ + - ]: 69 : !( pBD->RadEdges = (EdgeIndex*) inchi_calloc( max_len_Pu_Pv, sizeof( EdgeIndex ) ) ) ||
9693 : : #endif
9694 [ - + ]: 69 : !( pBD->Pv = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof( Vertex ) ) )
9695 : : )
9696 : : {
9697 : 0 : pBD = DeAllocateBnData( pBD );
9698 : : }
9699 : : else
9700 : : {
9701 : : /* Initialize data */
9702 : 69 : ClearAllBnDataEdges( pBD->SwitchEdge, NO_VERTEX, max_num_vertices );
9703 : 69 : ClearAllBnDataVertices( pBD->BasePtr, NO_VERTEX, max_num_vertices );
9704 : 69 : memset( pBD->Tree, TREE_NOT_IN_M, max_num_vertices ); /* djb-rwth: memset_s C11/Annex K variant? */
9705 : 69 : pBD->QSize = -1;
9706 : 69 : pBD->max_len_Pu_Pv = max_len_Pu_Pv;
9707 : 69 : pBD->max_num_vertices = max_num_vertices;
9708 : : #if ( BNS_RAD_SEARCH == 1 )
9709 : 69 : pBD->nNumRadEndpoints = 0;
9710 : : #endif
9711 : : }
9712 : :
9713 : 69 : return pBD;
9714 : : }
9715 : :
9716 : :
9717 : : /****************************************************************************/
9718 : 76 : int ReInitBnData( BN_DATA *pBD )
9719 : : {
9720 : 76 : int i, ret = 0;
9721 : : Vertex u, v;
9722 [ + - ]: 76 : if (pBD)
9723 : : {
9724 [ - + ]: 76 : if (!pBD->ScanQ)
9725 : : {
9726 : 0 : ret += 2;
9727 : : }
9728 [ - + ]: 76 : if (!pBD->BasePtr)
9729 : : {
9730 : 0 : ret += 4;
9731 : : }
9732 [ - + ]: 76 : if (!pBD->SwitchEdge)
9733 : : {
9734 : 0 : ret += 8;
9735 : : }
9736 [ - + ]: 76 : if (!pBD->Tree)
9737 : : {
9738 : 0 : ret += 16;
9739 : : }
9740 [ + - ]: 76 : if (!ret)
9741 : : {
9742 [ + + ]: 195 : for (i = 0; i <= pBD->QSize; i++)
9743 : : {
9744 : 119 : u = pBD->ScanQ[i];
9745 : 119 : v = prim( u );
9746 : 119 : pBD->BasePtr[u] =
9747 : 119 : pBD->BasePtr[v] =
9748 : 119 : pBD->SwitchEdge_Vert1( u ) =
9749 : 119 : pBD->SwitchEdge_Vert1( v ) = NO_VERTEX;
9750 : 119 : pBD->Tree[u] =
9751 : 119 : pBD->Tree[v] = TREE_NOT_IN_M;
9752 : : }
9753 : : }
9754 : 76 : pBD->QSize = -1;
9755 [ - + ]: 76 : if (!pBD->Pu)
9756 : : {
9757 : 0 : ret += 32;
9758 : : }
9759 [ - + ]: 76 : if (!pBD->Pv)
9760 : : {
9761 : 0 : ret += 64;
9762 : : }
9763 : : }
9764 : : else
9765 : : {
9766 : 0 : ret += 1;
9767 : : }
9768 : :
9769 : 76 : return ret;
9770 : : }
9771 : :
9772 : :
9773 : : /****************************************************************************/
9774 : 104 : int GetVertexDegree( BN_STRUCT* pBNS, Vertex v )
9775 : : {
9776 : 104 : int i = v / 2 - 1;
9777 [ + + ]: 104 : if (i >= 0)
9778 : : {
9779 [ + + ]: 28 : if (pBNS->vert[i].st_edge.cap > 0)
9780 : : {
9781 : 20 : return pBNS->vert[i].num_adj_edges + 1; /* add 1 neighbor for s or t */
9782 : : }
9783 : : else
9784 : : {
9785 : 8 : return 0; /* since the edge s-v has zero capacity, we ignore vertex v */
9786 : : }
9787 : : }
9788 : : else
9789 : : {
9790 : 76 : return pBNS->num_vertices;
9791 : : }
9792 : : }
9793 : :
9794 : :
9795 : : /****************************************************************************/
9796 : 40 : Vertex Get2ndEdgeVertex( BN_STRUCT* pBNS, Edge uv )
9797 : : {
9798 : : /*
9799 : : Vertex ret;
9800 : : */
9801 [ + + ]: 40 : if (uv[1] >= 0)
9802 : : {
9803 : : /* -- debug --
9804 : : if ( uv[1] > pBNS->num_edges || uv[0] > 2*pBNS->num_vertices+3 ) {
9805 : : int stop = 1;
9806 : : }
9807 : : ret = ((uv[0]-2) ^ (2*pBNS->edge[uv[1]].neighbor12+1)) + 2;
9808 : : if ( ret > 2*pBNS->num_vertices+3 ) {
9809 : : int stop = 1;
9810 : : }
9811 : : return ret;
9812 : : -- end debug -- */
9813 : :
9814 : 22 : return ( ( uv[0] - 2 ) ^ ( 2 * pBNS->edge[uv[1]].neighbor12 + 1 ) ) + 2;
9815 : :
9816 : : /*short u = uv[0]-FIRST_INDX; */
9817 : : /*short t = 2*(((u / 2 - 1) ^ pBNS->edge[uv[1]].neighbor12) + 1) + ((u+1) & 1) + FIRST_INDX; */
9818 : : /*return t; */
9819 : : }
9820 : :
9821 [ + - ]: 18 : if (uv[0] <= 1)
9822 : : {
9823 : 18 : return -( 1 + uv[1] ); /* vertex1 is s or t, return x or y */
9824 : : }
9825 : : else
9826 : : {
9827 : 0 : return uv[0] % 2; /* vertex1 is x or y, return s or t; never happens? -- NSC 3737, 7634,... */
9828 : : }
9829 : :
9830 : : }
9831 : :
9832 : :
9833 : : /****************************************************************************/
9834 : 775 : Vertex GetVertexNeighbor( BN_STRUCT* pBNS,
9835 : : Vertex v,
9836 : : int neigh,
9837 : : EdgeIndex *iedge )
9838 : : {
9839 : : /* neigh = 0 => the neighbor is s or t except case when v is s or t. */
9840 : : /* v= FIRST_INDX or FIRST_INDX+1: v is s or t respectively */
9841 : : int i, neighbor;
9842 [ + + ]: 775 : if (( i = v - 2 ) >= 0)
9843 : : {
9844 : : /* Neighbor of x or y */
9845 [ + + ]: 66 : if (neigh)
9846 : : {
9847 : 46 : neigh--;
9848 : : /* x or y */
9849 : 46 : *iedge = pBNS->vert[i / 2].iedge[neigh];
9850 [ + + - + ]: 46 : if (!( pBNS->edge[*iedge].cap & EDGE_FLOW_MASK ) || IS_FORBIDDEN( pBNS->edge[*iedge].forbidden, pBNS ))
9851 : : {
9852 : 9 : return NO_VERTEX;
9853 : : }
9854 : 37 : neighbor = ( i ^ ( 2 * pBNS->edge[*iedge].neighbor12 + 1 ) ) + 2; /* parity opposite to v parity */
9855 : : }
9856 : : else
9857 : : {
9858 : : /* neighbor of x or y is s or t */
9859 : 20 : neighbor = ( v & 1 ); /* s or t, same parity as v */
9860 : 20 : *iedge = -( neighbor + 1 );
9861 : : }
9862 : : }
9863 : : else
9864 : : {
9865 : : /* neighbor of s or t: x or y, same parity as v */
9866 [ + + ]: 709 : if (!( pBNS->vert[neigh].st_edge.cap & EDGE_FLOW_ST_MASK ))
9867 : : {
9868 : 630 : return NO_VERTEX;
9869 : : }
9870 : 79 : neighbor = 2 * neigh + 2 + ( v & 1 ); /* parity same as the parity of v */
9871 : 79 : *iedge = -( neighbor + 1 );
9872 : : }
9873 : :
9874 : 136 : return neighbor;
9875 : : }
9876 : :
9877 : :
9878 : : /****************************************************************************/
9879 : 136 : int GetEdgePointer( BN_STRUCT* pBNS,
9880 : : Vertex u,
9881 : : Vertex v,
9882 : : EdgeIndex iuv,
9883 : : BNS_EDGE **uv,
9884 : : S_CHAR *s_or_t )
9885 : : {
9886 : 136 : int i = u / 2 - 1;
9887 : 136 : int j = v / 2 - 1;
9888 : 136 : int bBackward = BNS_WRONG_PARMS;
9889 : 136 : *uv = NULL;
9890 [ + + ]: 136 : if (i >= 0)
9891 : : {
9892 : : /* u is an atom */
9893 [ + + ]: 49 : if (j >= 0)
9894 : : {
9895 : : /* v is an atom */
9896 [ + - ]: 39 : if (( u + v ) % 2)
9897 : : {
9898 : 39 : *uv = pBNS->edge + iuv;
9899 : 39 : bBackward = ( u & 1 );
9900 : 39 : *s_or_t = 0;
9901 : : }
9902 : : }
9903 : : else
9904 : : {
9905 : : /* v is s or t */
9906 [ + - + - ]: 10 : if (v >= 0 && !( ( u + v ) % 2 ))
9907 : : {
9908 : 10 : *uv = (BNS_EDGE*) &pBNS->vert[i].st_edge;
9909 : 10 : bBackward = !( v & 1 );
9910 : 10 : *s_or_t = v + 3; /* 3=> v=s, 4=> v=t */
9911 : : }
9912 : : }
9913 : : }
9914 : : else
9915 : : {
9916 [ + - ]: 87 : if (j >= 0)
9917 : : {
9918 : : /* u is s or t */
9919 [ + - + - ]: 87 : if (u >= 0 && !( ( u + v ) % 2 ))
9920 : : {
9921 : : /* v is an atom */
9922 : 87 : *uv = (BNS_EDGE*) &pBNS->vert[j].st_edge;
9923 : 87 : bBackward = ( u & 1 );
9924 : 87 : *s_or_t = u + 1; /* 1=> u=s, 2=> u=t */
9925 : : }
9926 : : }
9927 : : }
9928 : :
9929 : 136 : return bBackward;
9930 : : }
9931 : :
9932 : :
9933 : : /****************************************************************************/
9934 : 10 : int AugmentEdge( BN_STRUCT* pBNS,
9935 : : Vertex u,
9936 : : Vertex v,
9937 : : EdgeIndex iuv,
9938 : : int delta,
9939 : : S_CHAR bReverse,
9940 : : int bChangeFlow )
9941 : : {
9942 : 10 : int f, flow, ret = 0;
9943 : :
9944 : : BNS_ST_EDGE *pst_edge;
9945 : : BNS_EDGE *pedge;
9946 : : S_CHAR s_or_t;
9947 : 10 : int bBackward = GetEdgePointer( pBNS, u, v, iuv, &pedge, &s_or_t );
9948 [ + - + - ]: 10 : if (!IS_BNS_ERROR( bBackward ))
9949 : : {
9950 [ + + ]: 10 : if (bBackward)
9951 : : {
9952 : 2 : delta = -delta;
9953 : : }
9954 : :
9955 [ + + ]: 10 : if (s_or_t)
9956 : : {
9957 : 4 : pst_edge = (BNS_ST_EDGE *) pedge;
9958 : 4 : flow = pst_edge->flow;
9959 : 4 : f = ( flow & EDGE_FLOW_ST_MASK ) + delta; /* new flow */
9960 [ - + ]: 4 : if (!delta)
9961 : : {
9962 : : /*((BNS_ST_EDGE *)pedge)->flow = pst_edge->flow & ~EDGE_FLOW_ST_PATH;*/
9963 : 0 : pst_edge->flow = pst_edge->flow & ~EDGE_FLOW_ST_PATH;
9964 : : }
9965 : : else
9966 : : {
9967 : 4 : int cap = pst_edge->cap;
9968 [ + - - + ]: 4 : if (f < 0 || f > cap)
9969 : : {
9970 : 0 : ret = BNS_WRONG_PARMS;
9971 : : }
9972 : : else
9973 : : {
9974 [ - + ]: 4 : if (!( bChangeFlow & BNS_EF_CHNG_FLOW ))
9975 : : {
9976 : 0 : f -= delta; /* do not actually change the flow, only find the augmenting path */
9977 : : }
9978 : : else
9979 : : {
9980 [ + - ]: 4 : if (delta)
9981 : : {
9982 : : /*((BNS_ST_EDGE *)pedge)->pass ++;*/
9983 : 4 : pst_edge->pass++;
9984 : : }
9985 : : }
9986 : 4 : flow = ( flow & ~( EDGE_FLOW_ST_PATH | EDGE_FLOW_ST_MASK ) ) + f;
9987 : : /*((BNS_ST_EDGE *)pedge)->flow = flow;*/
9988 : 4 : pst_edge->flow = flow;
9989 : : /*((BNS_ST_EDGE *)pedge)->delta += delta; */
9990 [ + + ]: 4 : if (bReverse)
9991 : : {
9992 : : /* u <- v; Note: in case of bReverse s_or_t has actually been determined
9993 : : for the u' <- v' pair; therefore s and t should be switched
9994 : : in order to correctly determine the 1st or the last atom
9995 : : on the augmenting path.
9996 : : */
9997 [ + - - - : 2 : switch (s_or_t)
- ]
9998 : : {
9999 : 2 : case 1: /* u = t: t<-v, v is the last vertex */
10000 : 2 : ALTP_END_ATOM( pBNS->alt_path ) = v / 2 - 1;
10001 : 2 : break;
10002 : 0 : case 2: /* u = s: s<-v, error */
10003 : 0 : ret = BNS_WRONG_PARMS;
10004 : 0 : break;
10005 : 0 : case 3: /* v = t: u<-t, error */
10006 : 0 : ret = BNS_WRONG_PARMS;
10007 : 0 : break;
10008 : 0 : case 4: /* v = s: u<-s, u is the first vertex */
10009 : 0 : ALTP_START_ATOM( pBNS->alt_path ) = u / 2 - 1;
10010 : 0 : ALTP_DELTA( pBNS->alt_path ) = delta;
10011 : 0 : break;
10012 : 0 : default:
10013 : 0 : ret = BNS_WRONG_PARMS;
10014 : 0 : break;
10015 : : }
10016 : : }
10017 : : else
10018 : : {
10019 : : /* u -> v */
10020 [ + - - - : 2 : switch (s_or_t)
- ]
10021 : : {
10022 : 2 : case 1: /* u = s: s->v, v is the first vertex */
10023 : 2 : ALTP_START_ATOM( pBNS->alt_path ) = v / 2 - 1;
10024 : 2 : ALTP_DELTA( pBNS->alt_path ) = delta;
10025 : 2 : break;
10026 : 0 : case 2: /* u = t: t->v, error */
10027 : 0 : ret = BNS_WRONG_PARMS;
10028 : 0 : break;
10029 : 0 : case 3: /* v = s: u->s, error */
10030 : 0 : ret = BNS_WRONG_PARMS;
10031 : 0 : break;
10032 : 0 : case 4: /* v = t: u->t, u is the last vertex */
10033 : 0 : ALTP_END_ATOM( pBNS->alt_path ) = u / 2 - 1;
10034 : 0 : break;
10035 : 0 : default:
10036 : 0 : ret = BNS_WRONG_PARMS;
10037 : 0 : break;
10038 : : }
10039 : : }
10040 : : }
10041 : : }
10042 : : }
10043 : : else
10044 : : {
10045 : 6 : f = ( pedge->flow & EDGE_FLOW_MASK ) + delta;
10046 [ - + ]: 6 : if (!delta)
10047 : : {
10048 : 0 : pedge->flow &= ~EDGE_FLOW_PATH;
10049 : : }
10050 : : else
10051 : : {
10052 [ + - - + ]: 6 : if (f < 0 || f > pedge->cap)
10053 : : {
10054 : 0 : ret = BNS_WRONG_PARMS;
10055 : : }
10056 : : else
10057 : : {
10058 : 6 : AT_NUMB iu = u / 2 - 1;
10059 : 6 : AT_NUMB iv = v / 2 - 1;
10060 : : int indx;
10061 [ - + ]: 6 : if (!( bChangeFlow & BNS_EF_CHNG_FLOW ))
10062 : : {
10063 : 0 : f -= delta; /* do not actually change the flow, only find the augmenting path */
10064 : : }
10065 : : else
10066 : : {
10067 [ + - ]: 6 : if (delta)
10068 : : {
10069 : 6 : pedge->pass++;
10070 : : }
10071 : : }
10072 : 6 : pedge->flow = ( pedge->flow & ~( EDGE_FLOW_PATH | EDGE_FLOW_MASK ) ) | f;
10073 [ + - ]: 6 : if (ALTP_MAY_ADD( pBNS->alt_path ))
10074 : : {
10075 : : /* bReverse? u <- v : u -> v */
10076 [ + + ]: 6 : indx = bReverse ? ( pedge->neighbor1 == iv ) : ( pedge->neighbor1 == iu );
10077 : 6 : ALTP_CUR_THIS_ATOM_NEIGHBOR( pBNS->alt_path ) = pedge->neigh_ord[1 - indx];
10078 : 6 : ALTP_CUR_NEXT_ATOM_NEIGHBOR( pBNS->alt_path ) = pedge->neigh_ord[indx];
10079 : 6 : ALTP_NEXT( pBNS->alt_path );
10080 : : }
10081 : : else
10082 : : {
10083 : 0 : ALTP_OVERFLOW( pBNS->alt_path ) = 1;
10084 : 0 : ret = BNS_ALTPATH_OVFL;
10085 : : }
10086 : : }
10087 : : }
10088 : : }
10089 [ - + ]: 10 : return ret ? ret : f;
10090 : : }
10091 : :
10092 : 0 : return bBackward;
10093 : : }
10094 : :
10095 : :
10096 : : /****************************************************************************
10097 : : rescap_mark( ... )
10098 : :
10099 : : Find residual capacity and mark the edge
10100 : : as belonging to the augmenting path
10101 : : ****************************************************************************/
10102 : 10 : int rescap_mark( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
10103 : : {
10104 : : BNS_ST_EDGE *pst_edge;
10105 : : BNS_EDGE *pedge;
10106 : :
10107 : : int f, flow;
10108 : : S_CHAR s_or_t;
10109 : 10 : int bBackward = GetEdgePointer( pBNS, u, v, iuv, &pedge, &s_or_t );
10110 : :
10111 [ + - + - ]: 10 : if (!IS_BNS_ERROR( bBackward ))
10112 : : {
10113 [ + + ]: 10 : if (s_or_t)
10114 : : {
10115 : 4 : pst_edge = (BNS_ST_EDGE *) pedge;
10116 : 4 : flow = pst_edge->flow;
10117 : 4 : f = ( flow & EDGE_FLOW_ST_MASK );
10118 [ + - ]: 4 : if (!bBackward)
10119 : : {
10120 : 4 : f = (int) pst_edge->cap - f;
10121 : : }
10122 [ - + ]: 4 : if (flow & EDGE_FLOW_ST_PATH)
10123 : : {
10124 : 0 : pBNS->bNotASimplePath++;
10125 : 0 : f /= 2; /* this is the second time we pass the same edge: reduce flow by a factor of 2 */
10126 : : }
10127 : : else
10128 : : {
10129 : 4 : pst_edge->flow |= EDGE_FLOW_ST_PATH; /* mark the edge */
10130 : : }
10131 : : }
10132 : : else
10133 : : {
10134 : 6 : flow = pedge->flow;
10135 : 6 : f = flow & EDGE_FLOW_MASK;
10136 [ + + ]: 6 : if (!bBackward)
10137 : : {
10138 : 4 : f = (int) pedge->cap - f;
10139 : : }
10140 [ - + ]: 6 : if (flow & EDGE_FLOW_PATH)
10141 : : {
10142 : 0 : f /= 2; /* this is the second time we pass the same edge: reduce flow by a factor of 2 */
10143 : 0 : pBNS->bNotASimplePath++;
10144 : : }
10145 : : else
10146 : : {
10147 : 6 : pedge->flow |= EDGE_FLOW_PATH; /* mark the edge */
10148 : : }
10149 : : }
10150 : 10 : return f;
10151 : : }
10152 : :
10153 : 0 : return bBackward;
10154 : : }
10155 : :
10156 : :
10157 : : /****************************************************************************
10158 : : GetPrevVertex( ... )
10159 : :
10160 : : Get previous vertex in the searched path
10161 : : z is SwitchEdge_Vert2(y) != y. Go backward from z to y
10162 : : ****************************************************************************/
10163 : 0 : Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv )
10164 : : {
10165 : : Vertex w, z, x2, y2; /* djb-rwth: removing redundant variables */
10166 : : EdgeIndex iwy;
10167 : :
10168 : 0 : w = SwitchEdge_Vert1( y );
10169 : 0 : z = SwitchEdge_Vert2( y );
10170 : 0 : iwy = SwitchEdge_IEdge( y );
10171 [ # # ]: 0 : if (z == y)
10172 : : {
10173 : 0 : *iuv = iwy;
10174 : 0 : return w;
10175 : : }
10176 : 0 : x2 = prim( y );
10177 : 0 : y2 = prim( z );
10178 : : /* djb-rwth: removing redundant code */
10179 [ # # ]: 0 : while (y2 != NO_VERTEX)
10180 : : {
10181 : 0 : w = SwitchEdge_Vert1( y2 );
10182 : 0 : z = SwitchEdge_Vert2( y2 );
10183 : 0 : iwy = SwitchEdge_IEdge( y2 );
10184 [ # # ]: 0 : if (w == x2)
10185 : : {
10186 : 0 : *iuv = iwy;
10187 : : /*return z; */
10188 [ # # ]: 0 : return ( y + z ) % 2 ? z : prim( z );
10189 : : }
10190 : : /* djb-rwth: removing redundant code */
10191 : : /*
10192 : : #ifdef _DEBUG
10193 : : if ( n ) {
10194 : : int stop = 1;
10195 : : }
10196 : : #endif
10197 : : */
10198 [ # # ]: 0 : if (w == y2)
10199 : : {
10200 : 0 : return NO_VERTEX;
10201 : : }
10202 : 0 : y2 = w;
10203 : : }
10204 : :
10205 : 0 : return y2;
10206 : : }
10207 : :
10208 : :
10209 : :
10210 : : #define CHECK_TACN 1
10211 : :
10212 : :
10213 : : /****************************************************************************
10214 : : The purpose is to avoid paths
10215 : :
10216 : : (H-group)[u]---atom[v]---((-)-cgroup)[w],
10217 : :
10218 : : where atom[v] is not acidic and (-) and H are not interchangeable without
10219 : : explicit bond tautomerism.
10220 : :
10221 : : It is important that acidic atoms are only O,S,Se,Te and should have
10222 : : only one chemical bond. Only because of this an early rejection of
10223 : : the vertex v (before it gets on SCANQ) is possible.
10224 : :
10225 : : CHECK_TACN == 1 prohibits replacing (-) on N with H unless H can be moved to N
10226 : : along an alternating path from another heteroatom (t-group will be detected).
10227 : : ****************************************************************************/
10228 : :
10229 : :
10230 : : #if ( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
10231 : :
10232 : :
10233 : : /****************************************************************************/
10234 : : int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
10235 : : {
10236 : : #define TYPE_T 1 /* t-group [also called H-group] */
10237 : : #define TYPE_CN 2 /* (-)c-group */
10238 : : int i, degree, ret, u_is_taut = 0, w_is_taut, num_allowed = 0, num_found_groups = 0;
10239 : : Vertex w;
10240 : : EdgeIndex ivw;
10241 : : if (!pBNS->type_TACN || u <= 1 || v <= 1 ||
10242 : : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10243 : : {
10244 : : return 0; /* add/remove H(+) is allowed for acidic atoms */
10245 : : }
10246 : : if (!pBNS->type_T || !pBNS->type_CN)
10247 : : {
10248 : : return 0; /* should not happen */
10249 : : }
10250 : : u_is_taut = ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10251 : : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10252 : : if (u_is_taut)
10253 : : {
10254 : : /* u is either t-group vertex or (-) c-group */
10255 : : degree = GetVertexDegree( pBNS, v );
10256 : : for (i = 0; i < degree; i++)
10257 : : {
10258 : : /* v = vert[u].neighbor[i]; */
10259 : : w = GetVertexNeighbor( pBNS, v, i, &ivw );
10260 : : if (w == NO_VERTEX || w <= 1)
10261 : : {
10262 : : continue; /* the atom has only single bonds or it is s or t, ignore it */
10263 : : }
10264 : : if (w != u && ( ret = rescap( pBNS, v, w, ivw ) ) > 0)
10265 : : {
10266 : : num_allowed++;
10267 : : w_is_taut = ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN :
10268 : : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T : 0;
10269 : : if (( u_is_taut | w_is_taut ) == ( TYPE_T | TYPE_CN ))
10270 : : {
10271 : : num_found_groups++;
10272 : : }
10273 : : }
10274 : : }
10275 : : if (num_found_groups && num_allowed == 1)
10276 : : {
10277 : : return 1; /* reject */
10278 : : }
10279 : : }
10280 : :
10281 : : return 0;
10282 : : #undef TYPE_T
10283 : : #undef TYPE_CN
10284 : : }
10285 : :
10286 : :
10287 : : #else /* } FIX_TACN_POSSIBLE_BUG { */
10288 : :
10289 : :
10290 : : /****************************************************************************/
10291 : 0 : int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
10292 : : {
10293 : 0 : int i, degree, ret, u_is_taut = 0, num_allowed = 0, num_found_groups = 0;
10294 : : Vertex w;
10295 : : EdgeIndex ivw;
10296 [ # # # # : 0 : if (!pBNS->type_TACN || u <= 1 || v <= 1 ||
# # ]
10297 [ # # ]: 0 : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10298 : : {
10299 : 0 : return 0; /* add/remove H(+) is allowed for acidic atoms */
10300 : : }
10301 [ # # # # ]: 0 : if (!pBNS->type_T || !pBNS->type_CN)
10302 : : {
10303 : 0 : return 0; /* should not happen */
10304 : : }
10305 [ # # ]: 0 : if (( u_is_taut = ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ||
10306 [ # # ]: 0 : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ))
10307 : : {
10308 : : /* u is either t-group vertex or (-) c-group */
10309 : 0 : degree = GetVertexDegree( pBNS, v );
10310 [ # # ]: 0 : for (i = 0; i < degree; i++)
10311 : : {
10312 : : /* v = vert[u].neighbor[i]; */
10313 : 0 : w = GetVertexNeighbor( pBNS, v, i, &ivw );
10314 [ # # # # ]: 0 : if (w == NO_VERTEX || w <= 1)
10315 : : {
10316 : 0 : continue; /* the atom has only single bonds or it is s or t, ignore it */
10317 : : }
10318 [ # # # # ]: 0 : if (w != u && ( ret = rescap( pBNS, v, w, ivw ) ) > 0) /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
10319 : : {
10320 : 0 : num_allowed++;
10321 [ # # # # ]: 0 : if (( u_is_taut ? ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) :
10322 : 0 : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ))
10323 : : {
10324 : 0 : num_found_groups++;
10325 : : }
10326 : : }
10327 : : }
10328 [ # # # # ]: 0 : if (num_found_groups && num_allowed == 1)
10329 : : {
10330 : 0 : return 1; /* reject */
10331 : : }
10332 : : }
10333 : :
10334 : 0 : return 0;
10335 : : }
10336 : :
10337 : :
10338 : :
10339 : : #endif /* } FIX_TACN_POSSIBLE_BUG */
10340 : :
10341 : :
10342 : :
10343 : : /****************************************************************************
10344 : : The purpose is to avoid paths
10345 : : (H-group)[u]---atom[v]---((-)-cgroup)[w],
10346 : :
10347 : : where atom[v] is not acidic and (-) and H are not interchangeable without
10348 : : explicit bond tautomerism.
10349 : :
10350 : : It is important that acidic atoms are only O,S,Se,Te and should have
10351 : : only one chemical bond. Only because of this an early rejection of
10352 : : the vertex v (before it gets on SCANQ) is possible.
10353 : : ****************************************************************************/
10354 : :
10355 : :
10356 : : #if ( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
10357 : :
10358 : :
10359 : : /****************************************************************************/
10360 : : int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS,
10361 : : Vertex v,
10362 : : Vertex w,
10363 : : Edge *SwitchEdge )
10364 : : {
10365 : : #define TYPE_T 1 /* t-group [also called H-group] */
10366 : : #define TYPE_CN 2 /* (-)c-group */
10367 : : int u_is_taut = 0, w_is_taut = 0;
10368 : : Vertex u;
10369 : : EdgeIndex iuv;
10370 : : if (v <= 1 || w <= 1)
10371 : : return 0;
10372 : : #if ( CHECK_TACN == 1 )
10373 : : if (!pBNS->type_TACN ||
10374 : : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10375 : : {
10376 : : return 0;
10377 : : }
10378 : : if (!pBNS->type_T || !pBNS->type_CN)
10379 : : {
10380 : : return 0; /* should not happen */
10381 : : }
10382 : : #endif
10383 : : u = GetPrevVertex( pBNS, v, SwitchEdge, &iuv );
10384 : : /*
10385 : : u = SwitchEdge_Vert1(v);
10386 : : iuv = SwitchEdge_IEdge(v);
10387 : : */
10388 : : if (u == NO_VERTEX || iuv < 0)
10389 : : return 0; /* should not happen */
10390 : : /* check edge adjacency */
10391 : : if (pBNS->edge[iuv].neighbor1 != ( u / 2 - 1 ) && pBNS->edge[iuv].neighbor1 != v / 2 - 1 ||
10392 : : ( pBNS->edge[iuv].neighbor12 ^ ( u / 2 - 1 ) ) != ( v / 2 - 1 ))
10393 : : {
10394 : : return 0; /* !!! should not happen !!! */
10395 : : }
10396 : :
10397 : : #if ( CHECK_TACN == 1 )
10398 : : u_is_taut = ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10399 : : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10400 : : w_is_taut = ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10401 : : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10402 : : if (( u_is_taut | w_is_taut ) == ( TYPE_T | TYPE_CN ))
10403 : : {
10404 : : /* rescap must have already been checked */
10405 : : return 1;
10406 : : }
10407 : : #endif
10408 : :
10409 : : return 0;
10410 : : #undef TYPE_T
10411 : : #undef TYPE_CN
10412 : : }
10413 : :
10414 : :
10415 : : #else /* } FIX_TACN_POSSIBLE_BUG { */
10416 : :
10417 : :
10418 : : /****************************************************************************/
10419 : 0 : int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS,
10420 : : Vertex v,
10421 : : Vertex w,
10422 : : Edge *SwitchEdge )
10423 : : {
10424 : 0 : int u_is_taut = 0, w_is_taut = 0;
10425 : : Vertex u;
10426 : : EdgeIndex iuv;
10427 [ # # # # ]: 0 : if (v <= 1 || w <= 1)
10428 : 0 : return 0;
10429 : : #if ( CHECK_TACN == 1 )
10430 [ # # ]: 0 : if (!pBNS->type_TACN ||
10431 [ # # ]: 0 : ( pBNS->vert[v / 2 - 1].type & pBNS->type_TACN ))
10432 : : {
10433 : 0 : return 0;
10434 : : }
10435 [ # # # # ]: 0 : if (!pBNS->type_T || !pBNS->type_CN)
10436 : : {
10437 : 0 : return 0; /* should not happen */
10438 : : }
10439 : : #endif
10440 : 0 : u = GetPrevVertex( pBNS, v, SwitchEdge, &iuv );
10441 : : /*
10442 : : u = SwitchEdge_Vert1(v);
10443 : : iuv = SwitchEdge_IEdge(v);
10444 : : */
10445 [ # # # # ]: 0 : if (u == NO_VERTEX || iuv < 0)
10446 : : {
10447 : 0 : return 0; /* should not happen */
10448 : : }
10449 : : /* check edge adjacency */
10450 [ # # # # ]: 0 : if ((pBNS->edge[iuv].neighbor1 != ( u / 2 - 1 ) && pBNS->edge[iuv].neighbor1 != v / 2 - 1) ||
10451 [ # # ]: 0 : (( pBNS->edge[iuv].neighbor12 ^ ( u / 2 - 1 ) ) != ( v / 2 - 1 ))) /* djb-rwth: addressing LLVM warning */
10452 : : {
10453 : 0 : return 0; /* !!! should not happen !!! */
10454 : : }
10455 : :
10456 : : #if ( CHECK_TACN == 1 )
10457 [ # # ]: 0 : if (( ( u_is_taut = ( pBNS->vert[u / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ||
10458 [ # # ]: 0 : ( ( pBNS->vert[u / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ) &&
10459 [ # # ]: 0 : ( ( w_is_taut = ( pBNS->vert[w / 2 - 1].type & pBNS->type_T ) == pBNS->type_T ) ||
10460 [ # # ]: 0 : ( ( pBNS->vert[w / 2 - 1].type & pBNS->type_CN ) == pBNS->type_CN ) ) &&
10461 [ # # ]: 0 : u_is_taut + w_is_taut == 1)
10462 : : {
10463 : : /* rescap must have already been checked */
10464 : 0 : return 1;
10465 : : }
10466 : : #endif
10467 : :
10468 : 0 : return 0;
10469 : : }
10470 : : #endif /* } FIX_TACN_POSSIBLE_BUG { */
10471 : :
10472 : :
10473 : :
10474 : : #if ( FIX_KEEP_H_ON_NH_ANION == 1 )
10475 : :
10476 : :
10477 : : /****************************************************************************
10478 : : bIsRemovedHfromNHaion( ... )
10479 : :
10480 : : Detect an attempt to remove H from -NH(-) to make =N(-);
10481 : : all taut atoma except N are 'acidic'
10482 : : ****************************************************************************/
10483 : : int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v )
10484 : : {
10485 : : int i, u2, v2, vat2;
10486 : : Vertex vtg, vat;
10487 : : BNS_VERTEX *pvAT, *pvCN;
10488 : : BNS_EDGE *pEdge;
10489 : : if (!pBNS->type_TACN || u <= 1 || v <= 1 ||
10490 : : u % 2 || !( v % 2 ) /* the edge flow may only increase */)
10491 : : {
10492 : : return 0;
10493 : : }
10494 : : if (( pBNS->vert[u2 = u / 2 - 1].type & pBNS->type_TACN ) ||
10495 : : ( pBNS->vert[v2 = v / 2 - 1].type & pBNS->type_TACN ))
10496 : : {
10497 : : return 0; /* add/remove H is allowed for acidic atoms */
10498 : : }
10499 : : if (!pBNS->type_T || !pBNS->type_CN)
10500 : : {
10501 : : return 0; /* should not happen */
10502 : : }
10503 : : /* find which of u, v vertices is N and which is t-group */
10504 : : if (( ( pBNS->vert[u2].type & pBNS->type_T ) == pBNS->type_T ) && v2 < pBNS->num_atoms)
10505 : : {
10506 : : vtg = u;
10507 : : vat = v;
10508 : : }
10509 : : else
10510 : : {
10511 : : if (( ( pBNS->vert[v2].type & pBNS->type_T ) == pBNS->type_T ) && u2 < pBNS->num_atoms)
10512 : : {
10513 : : vtg = v;
10514 : : vat = u;
10515 : : }
10516 : : else
10517 : : {
10518 : : return 0;
10519 : : }
10520 : : }
10521 : :
10522 : : vat2 = vat / 2 - 1;
10523 : : pvAT = pBNS->vert + vat2; /* atom */
10524 : : for (i = pvAT->num_adj_edges - 1; 0 <= i; i--)
10525 : : {
10526 : : pEdge = pBNS->edge + pvAT->iedge[i];
10527 : : pvCN = pBNS->vert + ( pEdge->neighbor12 ^ vat2 );
10528 : : if (( ( pvCN->type & pBNS->type_CN ) == pBNS->type_CN ) && pEdge->flow > 0)
10529 : : {
10530 : : return 1; /* detected */
10531 : : }
10532 : : }
10533 : :
10534 : : return 0;
10535 : : }
10536 : : #endif
10537 : :
10538 : :
10539 : : #if ( FIX_AVOID_ADP == 1 )
10540 : :
10541 : : /****************************************************************************
10542 : : bIsAggressiveDeprotonation( ... )
10543 : :
10544 : : Detect (tg)-N=A-A=A-A=N-(tg)
10545 : : u v w
10546 : : k = 5 4 3 2 1 0 1 2
10547 : : ^
10548 : : odd number means ADP
10549 : : ****************************************************************************/
10550 : : int bIsAggressiveDeprotonation( BN_STRUCT* pBNS,
10551 : : Vertex v,
10552 : : Vertex w,
10553 : : Edge *SwitchEdge )
10554 : : {
10555 : : #define TYPE_T 1 /* t-group [also called H-group] */
10556 : : #define TYPE_CN 2 /* (-)c-group */
10557 : : #define TYPE_AT 4
10558 : : int k, v2, u2, w2, u2_next, type0, type1, type2, type;
10559 : : Vertex u, u_next;
10560 : : EdgeIndex iuv;
10561 : :
10562 : : if (v <= 1 || w <= 1)
10563 : : {
10564 : : return 0;
10565 : : }
10566 : :
10567 : : if (!pBNS->type_TACN || !pBNS->type_T || !pBNS->type_CN)
10568 : : {
10569 : : return 0; /* should not happen */
10570 : : }
10571 : :
10572 : : v2 = v / 2 - 1;
10573 : : w2 = w / 2 - 1;
10574 : : if (v2 >= pBNS->num_atoms || w2 < pBNS->num_atoms)
10575 : : {
10576 : : goto cross_edge;
10577 : : }
10578 : :
10579 : : if (!( ( pBNS->vert[w2].type & pBNS->type_T ) == pBNS->type_T ) &&
10580 : : !( ( pBNS->vert[w2].type & pBNS->type_CN ) == pBNS->type_CN ))
10581 : : {
10582 : : goto cross_edge;
10583 : : }
10584 : :
10585 : : /* v ia an atom, w is a t-group, v != w' */
10586 : : for (k = 0, u = v; 1 < ( u_next = u, u = GetPrevVertex( pBNS, u, SwitchEdge, &iuv ) ); k++)
10587 : : {
10588 : : u2 = u / 2 - 1;
10589 : : if (u2 >= pBNS->num_atoms)
10590 : : {
10591 : : /* Moving backward along the alt path we have found a vertex
10592 : : that is not an atom. Possibly it is a t- or (-)c-group */
10593 : : if (!( k % 2 ))
10594 : : {
10595 : : return 0; /* even vertex -- always okay */
10596 : : }
10597 : : if (!( ( pBNS->vert[u2].type & pBNS->type_T ) == pBNS->type_T ) &&
10598 : : !( ( pBNS->vert[u2].type & pBNS->type_CN ) == pBNS->type_CN ))
10599 : : {
10600 : : /* not a t- or (-)c-group */
10601 : : return 0;
10602 : : }
10603 : : u2_next = u_next / 2 - 1;
10604 : : if (!( pBNS->vert[v2].type & pBNS->type_TACN ) &&
10605 : : !( pBNS->vert[u2_next].type & pBNS->type_TACN ))
10606 : : {
10607 : : /* none of the atoms at the ends are N */
10608 : : return 0;
10609 : : }
10610 : : return 1;
10611 : : }
10612 : : }
10613 : :
10614 : : return 0;
10615 : :
10616 : : cross_edge:
10617 : :
10618 : : /*****************************************************************************
10619 : : * v and w (v=w') are same vertex reached with opposite "phases".
10620 : : * w cannot be (t) because this would have been detected earlier -- ???
10621 : : * (t)-A=A-A=A-A=A-(t)
10622 : : * v
10623 : : * 3 2 1 0 1 2 3 4
10624 : : * kv kw
10625 : : * (kv + kw)%2 == 1 <==> aggressive deprotonation
10626 : : *****************************************************************************/
10627 : :
10628 : : if (v == prim( w ))
10629 : : {
10630 : : type0 = 0;
10631 : : if (v2 >= pBNS->num_atoms)
10632 : : {
10633 : : type0 = ( ( pBNS->vert[v2].type & pBNS->type_T ) == pBNS->type_T ) ? TYPE_T :
10634 : : ( ( pBNS->vert[v2].type & pBNS->type_CN ) == pBNS->type_CN ) ? TYPE_CN : 0;
10635 : : }
10636 : : }
10637 : :
10638 : : return 0;
10639 : : }
10640 : : #endif
10641 : :
10642 : :
10643 : : /****************************************************************************/
10644 : 116 : int rescap( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
10645 : : {
10646 : : BNS_ST_EDGE *pst_edge;
10647 : : BNS_EDGE *pedge;
10648 : :
10649 : : int f;
10650 : : S_CHAR s_or_t;
10651 : 116 : int bBackward = GetEdgePointer( pBNS, u, v, iuv, &pedge, &s_or_t );
10652 : :
10653 [ + - + - ]: 116 : if (!IS_BNS_ERROR( bBackward ))
10654 : : {
10655 : :
10656 [ + + ]: 116 : if (s_or_t)
10657 : : {
10658 : 89 : pst_edge = (BNS_ST_EDGE *) pedge;
10659 : 89 : f = ( pst_edge->flow & EDGE_FLOW_ST_MASK );
10660 [ + + ]: 89 : if (!bBackward)
10661 : : {
10662 : 85 : f = (int) pst_edge->cap - f;
10663 : : }
10664 : : }
10665 : : else
10666 : : {
10667 : 27 : f = ( pedge->flow & EDGE_FLOW_MASK );
10668 [ + + ]: 27 : if (!bBackward)
10669 : : {
10670 : 21 : f = (int) pedge->cap - f;
10671 : : }
10672 : : }
10673 : 116 : return f;
10674 : : }
10675 : :
10676 : 0 : return bBackward; /* error */
10677 : : }
10678 : :
10679 : :
10680 : : /****************************************************************************
10681 : : W.Kocay, D.Stone,
10682 : : "An Algorithm for Balanced Flows",
10683 : : The Journal of Combinatorial Mathematics and Combinatorial Computing,
10684 : : vol. 19 (1995) pp. 3-31
10685 : :
10686 : : W.Kocay, D.Stone,
10687 : : "Balanced network flows",
10688 : : Bulletin of the Institute of Combinatorics and its Applications,
10689 : : vol. 7 (1993), pp. 17--32
10690 : :
10691 : : N = a balanced network (bipartite directed graph) of:
10692 : : n=2*V+2 vertices (incl. s (source) and t (target);
10693 : : each other vertex i is included 2 times:
10694 : : set X (x[i]) of V vertices (v) and a set Y (y[j]) of
10695 : : V complementary vertices (v') so that x[i]' = y[i], x[i]''=x[i], and
10696 : : m=2*E+2*V edges (each original undirected edge i-j is represented as
10697 : : 2 directed edges: x[i]->y[j] and x[j]->y[i]; plus
10698 : : V edges s->x[i] and V edges y[j]->t)
10699 : : v' = a complement vertex to v
10700 : : v'u' = (uv)' = a complement edge to uv
10701 : : rescap(uv) = cap(uv)-f(uv) if uv is a forward edge
10702 : : = f(uv) if uv is a backward edge
10703 : : (i) 0 <= f(uv) <= cap(uv)
10704 : : (ii) f+(u) = f-(u) for all u in X, Y where f+(u) is a total flow out of u,
10705 : : and f-(u) is a total flow into u
10706 : : (iii) f(uv) = f((uv)') (balanced flow condition)
10707 : :
10708 : : S = a set of all s-searchable vertices
10709 : : S- = all other vertices
10710 : : if t in S, then N contains a valid augmenting path P, so that flow can be
10711 : : augmented on both P and P'
10712 : : if t not in S, then let K=[S,S-], the set of all edges directed from S to S-.
10713 : : K is an edge-cut that has a special structure.
10714 : : Let
10715 : : A = {x[i], y[i] |x[i] not in S, y[i] in S}
10716 : : B = {x[i], y[i] |x[i] in S, y[i] not in S}
10717 : : C = {x[i], y[i] |x[i] in S, y[i] in S}
10718 : : D = {x[i], y[i] |x[i] not in S, y[i] not in S}
10719 : : N[C] = subgraph of N induced by C;
10720 : : it consists of of a number of connected components C[i]
10721 : : K[i] = those edges of K with one endpoint in C[i].
10722 : :
10723 : : If t is in S- then
10724 : :
10725 : : i) Each C[i] = C[i]'
10726 : : ii) There are no edges between C and D
10727 : : iii) Each K[i] has odd capacity, it is called a balanced edge-cut.
10728 : :
10729 : : balcap(K) = cap(K) - odd(K), where odd(K) is the number of connected components in N[C].
10730 : : Name "odd(K)" is because each cap(K[i]) is odd.
10731 : :
10732 : : Max-Balanced-Flow-Min-Balanced-Cut Theorem:
10733 : :
10734 : : Let f be a balanced flow in N, and let K be any balanced edge-cut.
10735 : : The value of a maximum balanced flow equals the capacity of a minimum
10736 : : edge-cut, that is, val(f) = balcap(K) when f is maximum and K is minimum.
10737 : :
10738 : : ****************************************************************************/
10739 : :
10740 : :
10741 : : /*******************************************************/
10742 : : /* */
10743 : : /* VERTEX NUMBERING */
10744 : : /* */
10745 : : /* Total number of atoms = n */
10746 : : /* Total number of vertices = 2*n+2 */
10747 : : /*******************************************************/
10748 : : /* */
10749 : : /* atom numbering starts from 0: */
10750 : : /* */
10751 : : /* atoms s t x0 y0 x1 y1 ... xi yi ...xn yn */
10752 : : /* vertices 0 1 2 3 4 5 ... 2i-2 2i-1 ...2n-2 2n-1 */
10753 : : /* */
10754 : : /* atom = vertex/2-1; if negative then s or t */
10755 : : /* */
10756 : : /* vertex = (atom + 1) * 2 + i; i=0 for x, i=1 for y */
10757 : : /* */
10758 : : /*******************************************************/
10759 : :
10760 : : /*********************************************************************************/
10761 : : /* v' variable is called prim(v) for now */
10762 : : /*********************************************************************************/
10763 : :
10764 : : /*
10765 : : BalancedNetworkSearch( ... )
10766 : :
10767 : : N has source s, target t, the mirror network M is constructed.
10768 : : The tree T contains a valid sv-path for each v in T. Simultaneously, the complementary
10769 : : tree T' is built as indicated in comments. The trees T and T' must have no edges or
10770 : : vertices in common. Initially T will be built as in breadth-first-search, and T' will
10771 : : be the complementary tree, it will contain the complementary valid v't-path.
10772 : :
10773 : : NB: this procedure is _not_ recursive
10774 : :
10775 : : */
10776 : :
10777 : :
10778 : : /****************************************************************************/
10779 : 76 : int BalancedNetworkSearch( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
10780 : :
10781 : : {
10782 : 76 : Vertex *BasePtr = pBD->BasePtr;
10783 : 76 : Edge *SwitchEdge = pBD->SwitchEdge;
10784 : 76 : S_CHAR *Tree = pBD->Tree;
10785 : 76 : Vertex *ScanQ = pBD->ScanQ;
10786 : 76 : int QSize = pBD->QSize;
10787 : 76 : Vertex *Pu = pBD->Pu;
10788 : 76 : Vertex *Pv = pBD->Pv;
10789 : 76 : int max_len_Pu_Pv = pBD->max_len_Pu_Pv;
10790 : :
10791 : : /* added to translate into C */
10792 : 76 : int i, k, degree, delta, ret = 0;
10793 : : Vertex u, b_u, v, b_v, w;
10794 : : EdgeIndex iuv;
10795 : : #if ( BNS_RAD_SEARCH == 1 )
10796 [ - + - - ]: 76 : int n, bRadSearch = ( BNS_EF_RAD_SRCH & bChangeFlow ) && pBD->RadEndpoints;
10797 : 76 : BRS_MODE bRadSrchMode = RAD_SRCH_NORM;
10798 : 76 : int bRadSearchPrelim = 0;
10799 [ - + ]: 76 : if (bRadSearch)
10800 : : {
10801 : 0 : pBD->nNumRadEndpoints = 0;
10802 : 0 : bRadSrchMode = pBD->bRadSrchMode;
10803 [ # # # # ]: 0 : bRadSearchPrelim = pBNS->type_TACN && bRadSrchMode == RAD_SRCH_NORM;
10804 : : }
10805 : : #endif
10806 : :
10807 : : /* -- Always --
10808 : : Vertex_s = FIRST_INDX;
10809 : : Vertex_t = Vertex_s+1;
10810 : : */
10811 : 76 : QSize = k = 0; /* put s on ScanQ = set S */
10812 : 76 : ScanQ[QSize] = Vertex_s;
10813 : 76 : BasePtr[Vertex_t] = Vertex_s;
10814 : 76 : BasePtr[Vertex_s] = BLOSSOM_BASE; /* create initial blossom C(Vertex_s) with base s */
10815 : 76 : Tree[Vertex_s] = TREE_IN_1;
10816 : :
10817 : : do
10818 : : {
10819 : 104 : u = ScanQ[k]; /* select u from the head of ScanQ */
10820 : : /* since u is on the queue, it has a blossom C(U) with base b_u */
10821 : 104 : b_u = FindBase( u, BasePtr );
10822 : 104 : degree = GetVertexDegree( pBNS, u );
10823 : : #if ( BNS_RAD_SEARCH == 1 )
10824 : 104 : n = 0;
10825 : : #endif
10826 [ + + ]: 877 : for (i = 0; i < degree; i++)
10827 : : {
10828 : : /* v = vert[u].neighbor[i]; */
10829 : 775 : v = GetVertexNeighbor( pBNS, u, i, &iuv );
10830 [ + + ]: 775 : if (v == NO_VERTEX)
10831 : : {
10832 : 639 : continue; /* the atom has only single bonds, ignore it */
10833 : : }
10834 : : #if ( BNS_RAD_SEARCH == 1 )
10835 [ + + - + : 136 : if (!k && bRadSrchMode == RAD_SRCH_FROM_FICT && v / 2 <= pBNS->num_atoms)
- - ]
10836 : : {
10837 : 0 : continue; /* start from fict. vertices only */
10838 : : }
10839 [ - + - - ]: 136 : if (bRadSearchPrelim && v / 2 > pBNS->num_atoms)
10840 : : {
10841 : 0 : continue; /* during initial add/remove H allow radical movement only through real atoms */
10842 : : }
10843 : : #endif
10844 : 136 : if ( /* PrevPt[u] != v ** avoid edges of T */
10845 [ + + - + ]: 136 : ( SwitchEdge_Vert1( u ) != v || SwitchEdge_Vert2( u ) != u ) /* avoid edges of T */
10846 [ + + ]: 116 : && ( ret = rescap( pBNS, u, v, iuv ) ) > 0)
10847 : : {
10848 : : /* Special treatment to prevent H<->(-) replacement on non-acidic atoms */
10849 : : /*----------------------------------------------------------------------*/
10850 [ - + ]: 41 : if (pBNS->type_TACN)
10851 : : {
10852 [ # # ]: 0 : if (bIgnoreVertexNonTACN_atom( pBNS, u, v ))
10853 : : {
10854 : 0 : continue;
10855 : : }
10856 [ # # ]: 0 : if (bIgnoreVertexNonTACN_group( pBNS, u, v, SwitchEdge ))
10857 : : {
10858 : 0 : continue;
10859 : : }
10860 : : #if ( FIX_KEEP_H_ON_NH_ANION == 1 )
10861 : : if (bIsRemovedHfromNHaion( pBNS, u, v ))
10862 : : {
10863 : : continue;
10864 : : }
10865 : : #endif
10866 : : #if ( FIX_AVOID_ADP == 1 )
10867 : : if (bIsAggressiveDeprotonation( pBNS, u, v, SwitchEdge ))
10868 : : {
10869 : : continue;
10870 : : }
10871 : : #endif
10872 : : }
10873 : : /*----------------------------------------------------------------------*/
10874 : 41 : b_v = FindBase( v, BasePtr ); /* Notation: b_x is a base of x */
10875 : :
10876 [ + + ]: 41 : if (b_v == NO_VERTEX)
10877 : : {
10878 : : /* Originally 0 instead of NO_VERTEX */
10879 : :
10880 : : /* Important note: following "A. Note of Implementing the Algorithm" from the
10881 : : article by Kocay and Stone, all references to PrevPt[a] have been
10882 : : replaced with SwitchEdge[a][0]=SwitchEdge_Vert1(a); to be on a safe side
10883 : : the check whether (SwitchEdge_Vert2(a)==a) has been added.
10884 : : */
10885 : :
10886 : : /* v is not yet in T or T' -- add it to T and M */
10887 : : /*PrevPt[v] = u; ** this effectively adds v to T and v' to T' */
10888 : :
10889 : 33 : QSize++;
10890 : 33 : ScanQ[QSize] = v;
10891 [ + - ]: 33 : TREE_MARK( v, TREE_IN_1 ); /* mark v s-reachable (in T) */
10892 [ + - ]: 33 : TREE_MARK( prim( v ), TREE_IN_2 ); /* mark v' in T' */
10893 : :
10894 : : /* Switch Edges: If u in T then Pu (a valid su-path) can be constructed
10895 : : by successfully executing u=PrevPt[u] until u=s.
10896 : : For vertices in T' the situation is different.
10897 : : Suppose uv and v'u' are added to a mirror network M creating a blossom:
10898 : :
10899 : : s T (Note: in the code v' is prim(v),
10900 : : T / \ u' is prim(u), etc.)
10901 : : / ...
10902 : : w=x1
10903 : : / \ u in T, v in T'
10904 : : u=y2 v'=y3
10905 : : \ / <--- two added edges uv and (uv)'=v'u'
10906 : : -------- X ------------intersection of the edges ------------------------
10907 : : / \ <--- (the edges intersection in the picture is shown as X)
10908 : : u'=x2 v=x3 u' it T', v' in T
10909 : : \ /
10910 : : T' w'=y1
10911 : : \ ...
10912 : : \ /
10913 : : t T'
10914 : :
10915 : : Vertices v and u' now become s-reachable;
10916 : : The valid paths to v and u' must use the edges uv and v'u' respectively.
10917 : :
10918 : : For each vertex z in S we define a switch-edge that allows a valid sz-path
10919 : : to be constructed, SwitchEdge[v]=uv and SwitchEdge[u']=v'u'. (We don't
10920 : : know the direction of the edge uv, it may be (u,v) or (v,u). In either case,
10921 : : the complementary edge is indicated by v'u').
10922 : :
10923 : : Vertex w' also becomes s-reachable when uv is added to M, and a valid sw'-path
10924 : : must use one of uv and v'u'. Therefore we choose one of them, say uv (see below
10925 : : the rule of choosing the switch-edge), and define SwitchEdge[w'] = uv.
10926 : :
10927 : : When the addition of an edge uv to M causes a vertex z to become s-reachable
10928 : : (where z was previously non-reachable), z is placed on the ScanQ, that is, into S.
10929 : : The edge uv is said to be a switch-edge for z.
10930 : :
10931 : : Rule: We choose the the order of the vertices uv to be such that the valid sz-path
10932 : : consists of a valid su-path, followed by edge uv, followed by a valid vz-path.
10933 : :
10934 : : For vertices z in T we can take SwitchEdge[z]=yz where y=PrevPt[z] since
10935 : : it is the edge yz that allows z to be s-reachable.
10936 : : For vertices z not in S we take SwitchEdge[z]=NONE.
10937 : :
10938 : : */
10939 : :
10940 : : /* v is not yet in T or T' -- add it to T and M */
10941 : 33 : SwitchEdge_Vert1( v ) = u; /* this effectively adds uv and v'u' to M */
10942 : 33 : SwitchEdge_IEdge( v ) = iuv;
10943 : :
10944 : 33 : BasePtr[prim( v )] = v;
10945 : 33 : BasePtr[v] = BLOSSOM_BASE; /* create a trivial blossom C(v) with base v */
10946 : : #if ( BNS_RAD_SEARCH == 1 )
10947 : 33 : n++;
10948 : : #endif
10949 : : }
10950 : :
10951 [ + + ]: 8 : else if (TREE_IS_S_REACHABLE( prim( v ) ) /*Is_s_Reachable(prim(v)*/
10952 : : /* if v' is reachable, an st-path is given by P(u)-uv-P'(v') */
10953 : : /*&& PrevPt[prim(u)] != prim(v) ** avoid edges of T' */
10954 [ - + - - ]: 2 : && ( SwitchEdge_Vert1( prim( u ) ) != prim( v ) || SwitchEdge_Vert2( prim( u ) ) != prim( u ) ) /* avoid edges of T' */
10955 [ + - ]: 2 : && b_u != b_v
10956 [ - + - - ]: 2 : && !( pBNS->type_TACN && bIgnoreVertexNonTACN_group( pBNS, prim( v ), u, SwitchEdge ) )
10957 : : #if ( FIX_KEEP_H_ON_NH_ANION == 1 )
10958 : : && !( pBNS->type_TACN && bIsRemovedHfromNHaion( pBNS, prim( v ), u ) )
10959 : : #endif
10960 : : )
10961 : : {
10962 : : #if ( BNS_RAD_SEARCH == 1 )
10963 : 2 : n++;
10964 : : #endif
10965 : : /* There is now a valid sv-path via u avoiding b_v (unless v==b_v)
10966 : : => u, v, u', and v' now all become part of the same connected component of M[C] */
10967 : :
10968 : : /* djb-rwth: addressing coverity ID #499578 -- negative values of b_u handled properly */
10969 : 2 : w = MakeBlossom( pBNS, ScanQ, &QSize, Pu, Pv, max_len_Pu_Pv, SwitchEdge, BasePtr, u, v, iuv, b_u, b_v, Tree );
10970 : : /* this constructed the new blossom and returned its base */
10971 : :
10972 [ + - - + ]: 2 : if (IS_BNS_ERROR( w ))
10973 : : {
10974 : 0 : pBD->QSize = QSize;
10975 : 0 : return w; /* error */
10976 : : }
10977 : :
10978 : 2 : b_u = w; /* the new base of C(u) */
10979 [ + - ]: 2 : if (prim( w ) == Vertex_t)
10980 : : {
10981 : : /* t is now s-reachable, a valid augmenting path P exists in M */
10982 : 2 : delta = FindPathCap( pBNS, SwitchEdge, Vertex_s, Vertex_t, 10000 ); /* compute the residual capacity of P + P' */
10983 [ + - - + ]: 2 : if (IS_BNS_ERROR( delta ))
10984 : : {
10985 : 0 : pBD->QSize = QSize;
10986 : 0 : return delta; /* error */
10987 : : }
10988 : : #if ( ALLOW_ONLY_SIMPLE_ALT_PATH == 1 )
10989 : : if (pBNS->bNotASimplePath || abs( delta ) > 1)
10990 : : {
10991 : : delta = 0;
10992 : : }
10993 : : #endif
10994 [ + - ]: 2 : if (delta)
10995 : : {
10996 : 2 : pBNS->bChangeFlow |= ( bChangeFlow & BNS_EF_CHNG_FLOW );
10997 : : }
10998 : 2 : ret = PullFlow( pBNS, SwitchEdge, Vertex_s, Vertex_t, delta, 0, bChangeFlow ); /* augment on a pair of valid st-paths */
10999 : 2 : pBD->QSize = QSize;
11000 : : return
11001 [ + - - + ]: 2 : ( IS_BNS_ERROR( ret ) ? ret : delta );
11002 : : }
11003 : : }
11004 : : }
11005 : :
11006 [ + - - + ]: 95 : else if (IS_BNS_ERROR( ret ))
11007 : : {
11008 : 0 : pBD->QSize = QSize;
11009 : 0 : return ret; /* error */
11010 : : }
11011 : : }
11012 : :
11013 : : #if ( BNS_RAD_SEARCH == 1 )
11014 [ - + - - ]: 102 : if (bRadSearch && !n)
11015 : : {
11016 : : /* The BNS stopped at u */
11017 : 0 : n = RegisterRadEndpoint( pBNS, pBD, u );
11018 [ # # # # ]: 0 : if (IS_BNS_ERROR( n ))
11019 : : {
11020 : 0 : pBD->QSize = QSize;
11021 : 0 : return n;
11022 : : }
11023 : : }
11024 : : #endif
11025 : :
11026 : 102 : k++; /* advance ScanQ */
11027 [ + + ]: 102 : } while (k <= QSize);
11028 : :
11029 : :
11030 : : /* if this point is reached, no valid augmenting path exists, ScanQ contains
11031 : : the set S of all s-reachable vertices and K=[S,S-] is a minimum balanced edge-cut */
11032 : : /* ClearFlowMarks( vert, num_vert); */
11033 : :
11034 : 74 : pBD->QSize = QSize;
11035 : :
11036 : 74 : return 0;
11037 : : }
11038 : :
11039 : :
11040 : : /*
11041 : : Blossoms.
11042 : :
11043 : : The vertices of a mirror network M consist T U T'. Intersection T ^ T' is empty.
11044 : :
11045 : : The edges of M consist of switch-edges and their complements because edges
11046 : : are added in complementary pairs, one of which is always a switch-edge.
11047 : :
11048 : : The base of every blossom is in T.
11049 : : Let C(i) be a blossom with base b_i. Since C(i)=C(i)', C(i) contains vertices of T and T'.
11050 : : Since every valid sv-path to v in C(i) contains b_i, b_i is the first s-reachable vertex of C(i).
11051 : :
11052 : : Suppose the mirror network M contains a valid sz-path P(z) to all vertices z in ScanQ.
11053 : : Every vertex of P(z) is s-reachable therefore its vertices are all in blossoms or
11054 : : trivial blossoms.
11055 : :
11056 : : Let z be an s-reachable vertex and P(z) be a valid path in M.
11057 : : Then every valid sz-path in M contains exactly the same sequence of blossom bases as P(z).
11058 : :
11059 : : */
11060 : :
11061 : :
11062 : :
11063 : : /***********************************************************************
11064 : : BasePtr[u] = -2 NO_VERTEX u is not a blossom
11065 : : -1 BLOSSOM_BASE u is the base of its blossom
11066 : : v a vertex closer to the base
11067 : : ************************************************************************/
11068 : 155 : Vertex FindBase( Vertex u, Vertex *BasePtr )
11069 : : {
11070 [ + + ]: 155 : if (BasePtr[u] == NO_VERTEX)
11071 : : {
11072 : 33 : return NO_VERTEX;
11073 : : }
11074 [ + + ]: 122 : else if (BasePtr[u] == BLOSSOM_BASE)
11075 : : {
11076 : 120 : return u;
11077 : : }
11078 : : else
11079 : : {
11080 : : Vertex b;
11081 : 2 : b = FindBase( BasePtr[u], BasePtr );
11082 : 2 : BasePtr[u] = b; /* path compression */
11083 : 2 : return b;
11084 : : }
11085 : :
11086 : : }
11087 : :
11088 : :
11089 : : /****************************************************************************
11090 : : Returns index of the last path element and the path
11091 : : ****************************************************************************/
11092 : 4 : int FindPathToVertex_s( Vertex x,
11093 : : Edge *SwitchEdge,
11094 : : Vertex *BasePtr,
11095 : : Vertex *Path,
11096 : : int MaxPathLen )
11097 : : {
11098 : : /* x is the base of a blossom, construct a valid Path of blossom bases to s */
11099 : 4 : int i = 0;
11100 : 4 : Path[i] = x;
11101 [ + + ]: 12 : while (x != Vertex_s)
11102 : : {
11103 : 8 : x = FindBase( SwitchEdge_Vert1( x ), BasePtr );
11104 [ + - ]: 8 : if (++i < MaxPathLen)
11105 : : {
11106 : 8 : Path[i] = x;
11107 : : }
11108 : : else
11109 : : {
11110 : 0 : return BNS_WRONG_PARMS;
11111 : : }
11112 : : }
11113 : :
11114 : 4 : return i;
11115 : : }
11116 : :
11117 : :
11118 : :
11119 : : /****************************************************************************
11120 : : Make a blossom
11121 : : ****************************************************************************/
11122 : 2 : Vertex MakeBlossom( BN_STRUCT* pBNS,
11123 : : Vertex *ScanQ,
11124 : : int *pQSize,
11125 : : Vertex *Pu,
11126 : : Vertex *Pv,
11127 : : int max_len_Pu_Pv,
11128 : : Edge *SwitchEdge,
11129 : : Vertex *BasePtr,
11130 : : Vertex u,
11131 : : Vertex v,
11132 : : EdgeIndex iuv,
11133 : : Vertex b_u,
11134 : : Vertex b_v,
11135 : : S_CHAR *Tree )
11136 : : {
11137 : : /* In order to find the base of the new blossom, the paths
11138 : : P(u) and P(v') are constructed and compared in order to
11139 : : find the last blossom base they have in common which
11140 : : is reachable on a valid path.
11141 : :
11142 : : Edge uv connects two blossoms, their bases are b_u and b_v.
11143 : : */
11144 : : Vertex w, z;
11145 : : int len_Pu, len_Pv;
11146 : : int i, j, k;
11147 : : EdgeIndex izw;
11148 : :
11149 : 2 : len_Pu = FindPathToVertex_s( b_u, SwitchEdge, BasePtr, Pu, max_len_Pu_Pv );
11150 [ + - - + ]: 2 : if (IS_BNS_ERROR( len_Pu ))
11151 : : {
11152 : 0 : return len_Pu;
11153 : : }
11154 : 2 : len_Pv = FindPathToVertex_s( b_v, SwitchEdge, BasePtr, Pv, max_len_Pu_Pv );
11155 [ + - - + ]: 2 : if (IS_BNS_ERROR( len_Pv ))
11156 : : {
11157 : 0 : return len_Pv;
11158 : : }
11159 : 2 : i = len_Pu;
11160 : 2 : j = len_Pv;
11161 : : /* Initially Pu[i] and Pv[j] both equal to s, but their first elements are different */
11162 : : /* Find the last blossom base common to Pu and Pv */
11163 [ + - + - : 4 : while (i >= 0 && j >= 0 && Pu[i] == Pv[j])
+ + ]
11164 : : {
11165 : : /* Was (Pu[i]==Pv[j] && i>=0 && j>=0) => tested Pu[-1], Pv[-1] <- pointed by W.Ihlenfeldt 08-26-2004*/
11166 : 2 : i--;
11167 : 2 : j--;
11168 : : }
11169 : 2 : i++;
11170 : 2 : w = Pu[i]; /* w is the last common vertex */
11171 : 2 : z = SwitchEdge_Vert1( w );
11172 : 2 : izw = SwitchEdge_IEdge( w );
11173 : : /* now extend the blossom if rescap(zw) >= 2 */
11174 [ - + - - ]: 2 : while (w != Vertex_s && rescap( pBNS, z, w, izw ) >= 2)
11175 : : {
11176 : 0 : i++;
11177 : 0 : w = Pu[i];
11178 : 0 : z = SwitchEdge_Vert1( w );
11179 : 0 : izw = SwitchEdge_IEdge( w );
11180 : : }
11181 : : /* w is the base of the new blossom */
11182 : : /* first follow the path Pu from w to b_u */
11183 [ + + ]: 6 : for (k = i - 1; k >= 0; k--)
11184 : : {
11185 : 4 : z = Pu[k]; /* z is the base of the blossom */
11186 : 4 : BasePtr[z] = w;
11187 : 4 : BasePtr[prim( z )] = w; /* w is the new base of the blossom */
11188 : : /* z and z' may already be part of a blossom that is being
11189 : : swallowed into a larger blossom.
11190 : : We don't want to change the switch edge in that case.
11191 : : */
11192 : :
11193 [ + - ]: 4 : if (!TREE_IS_ON_SCANQ( prim( z ) ) /*!IsInScanQ(prim(z)) */)
11194 : : {
11195 : 4 : SwitchEdge_Vert1( prim( z ) ) = prim( v ); /* set the switch edge of z' */
11196 : : /* SwitchEdge[prim(z)][1] = prim(u); */
11197 : 4 : SwitchEdge_IEdge( prim( z ) ) = iuv;
11198 : 4 : ( *pQSize )++;
11199 : 4 : ScanQ[*pQSize] = prim( z ); /* add z' to ScanQ */
11200 [ + - ]: 4 : TREE_MARK( prim( z ), TREE_IN_2BLOSS ); /* mark z' s-reachable */
11201 : : }
11202 : : }
11203 : : /* Now follow the path Pv */
11204 [ + + ]: 6 : for (k = j; k >= 0; k--) /* djb-rwth: converting for loop into while loop to avoid LLVM warning */
11205 : : {
11206 : 4 : z = Pv[k]; /* z is the base of the blossom */
11207 : 4 : BasePtr[z] = w;
11208 : 4 : BasePtr[prim( z )] = w; /* w is the new base of the blossom */
11209 : : /* z and z' may already be part of a blossom that is being
11210 : : swallowed into a larger blossom.
11211 : : We don't want to change the switch edge in that case.
11212 : : */
11213 : :
11214 [ + - ]: 4 : if (!TREE_IS_ON_SCANQ( prim( z ) ) /*!IsInScanQ(prim(z)) */)
11215 : : {
11216 : 4 : SwitchEdge_Vert1( prim( z ) ) = u; /* set the switch edge of z' */
11217 : : /* SwitchEdge[prim(z)][1] = v; */
11218 : 4 : SwitchEdge_IEdge( prim( z ) ) = iuv;
11219 : 4 : ( *pQSize )++;
11220 : 4 : ScanQ[*pQSize] = prim( z ); /* add z' to ScanQ */
11221 [ + - ]: 4 : TREE_MARK( prim( z ), TREE_IN_2BLOSS ); /* mark z' s-reachable */
11222 : : }
11223 : : }
11224 : :
11225 [ + - ]: 2 : if (!TREE_IS_ON_SCANQ( prim( w ) ) /* !IsInScanQ(prim(w))*/)
11226 : : { /* add w' to the blossom */
11227 : 2 : SwitchEdge_Vert1( prim( w ) ) = u; /* set the switch edge of w' */
11228 : : /* SwitchEdge[prim(w)][1] = v; */
11229 : 2 : SwitchEdge_IEdge( prim( w ) ) = iuv;
11230 : 2 : ( *pQSize )++;
11231 : 2 : ScanQ[*pQSize] = prim( w ); /* add w' to ScanQ */
11232 [ + - ]: 2 : TREE_MARK( prim( w ), TREE_IN_2BLOSS ); /* mark w' s-reachable */
11233 : : }
11234 : :
11235 : 2 : return w;
11236 : : }
11237 : :
11238 : :
11239 : : /****************************************************************************
11240 : : When t is found to be s-reachable, a valid st-path P is known to exist.
11241 : : Its complementary path P' is also valid. Once the residual capacity
11242 : : delta(P) is known, the flow is augmented by calling PullFlow(s,t,delta).
11243 : : It constructs the path P by using the switch-edges.
11244 : : Let uv=SwitchEdge[t].
11245 : : Then P is given by a valid su-path, followed by the edge uv, followed by
11246 : : a valid vt-path.
11247 : : PullFlow is a recursive procedure that constructs the path and its complement.
11248 : :
11249 : : Let wz=SwitchEdge[y]. PullFlow(x, y, delta) uses the xw- and zy-portions of P
11250 : : (see below). Since it must also augment on P' simultaneously, the zy-portion
11251 : : is replaced by the y'z'-portion.
11252 : :
11253 : : x y'
11254 : : | | P: x--w--z--y
11255 : : P | | P' P': y'-z'-w'-x'
11256 : : | o
11257 : : o \
11258 : : / w' z \
11259 : : / o----\ /----o /
11260 : : \ / \ / \ /
11261 : : \/ X \/
11262 : : /\ / \ /\
11263 : : / \ w / \ z' / \
11264 : : \ o---- ----o / Using a switch-edge wz and w'z'
11265 : : \ / to construct P and P'
11266 : : o o
11267 : : | |
11268 : : | |
11269 : : x' y
11270 : :
11271 : :
11272 : : ****************************************************************************/
11273 : :
11274 : :
11275 : :
11276 : : /* PullFlow( ... )
11277 : :
11278 : : Augment the flow by delta on all edges on a path P
11279 : : between x and y in the order of the path;
11280 : : AugmentEdge( pBNS, w, z, iwz, delta, 0 ) means the path is in w->z direction
11281 : : AugmentEdge( pBNS, w, z, iwz, delta, 1 ) means the path is in w<-z direction
11282 : :
11283 : : Unlike PullFlow in the paper by Kocay & Stone, here the augmentation
11284 : : starts at "s", proceeds sequentially through the path end terminates at "t".
11285 : : Since we do not really need the complement path, PullFlow ignores it.
11286 : : */
11287 : :
11288 : :
11289 : : /****************************************************************************/
11290 : 10 : int PullFlow( BN_STRUCT *pBNS,
11291 : : Edge *SwitchEdge,
11292 : : Vertex x,
11293 : : Vertex y,
11294 : : int delta,
11295 : : S_CHAR bReverse,
11296 : : int bChangeFlow )
11297 : : {
11298 : : Vertex w, z;
11299 : : EdgeIndex iwz;
11300 : 10 : int ret = 0;
11301 : :
11302 : 10 : w = SwitchEdge_Vert1( y );
11303 : 10 : z = SwitchEdge_Vert2( y );
11304 : 10 : iwz = SwitchEdge_IEdge( y );
11305 [ + + ]: 10 : if (bReverse)
11306 : : {
11307 : : /* P consists of a path from x to w, then wz, then a path from z to y. */
11308 : : /* z may equal y, in which case z is just PrevPt[y] */
11309 [ - + ]: 4 : if (z != y)
11310 : : {
11311 : 0 : ret = PullFlow( pBNS, SwitchEdge, prim( y ), prim( z ), delta, (S_CHAR) ( 1 - bReverse ), bChangeFlow ); /* augment between z and y */
11312 : : }
11313 [ + - + - ]: 4 : if (!IS_BNS_ERROR( ret ))
11314 : : {
11315 : 4 : ret = AugmentEdge( pBNS, w, z, iwz, delta, bReverse, bChangeFlow );
11316 : : }
11317 : : /* Do not augment the complementary path: AugmentEdge( prim(z), prim(w), vert, delta); */
11318 : : /* w may equal x, in which case there is no need to call PullFlow(x, w) */
11319 [ + + + - : 4 : if (w != x && !IS_BNS_ERROR( ret ))
+ - ]
11320 : : {
11321 : 2 : ret = PullFlow( pBNS, SwitchEdge, x, w, delta, bReverse, bChangeFlow ); /* augment between x and w */
11322 : : }
11323 : : }
11324 : : else
11325 : : {
11326 : : /* P consists of a path from x to w, then wz, then a path from z to y. */
11327 : : /* w may equal x, in which case there is no need to call PullFlow(x, w) */
11328 [ + + + - : 6 : if (w != x && !IS_BNS_ERROR( ret ))
+ - ]
11329 : : {
11330 : 4 : ret = PullFlow( pBNS, SwitchEdge, x, w, delta, bReverse, bChangeFlow ); /* augment between x and w */
11331 : : }
11332 [ + - + - ]: 6 : if (!IS_BNS_ERROR( ret ))
11333 : : {
11334 : 6 : ret = AugmentEdge( pBNS, w, z, iwz, delta, bReverse, bChangeFlow );
11335 : : }
11336 : : /* z may equal y, in which case z is just PrevPt[y] */
11337 [ + + + - : 6 : if (z != y && !IS_BNS_ERROR( ret ))
+ - ]
11338 : : {
11339 : 2 : ret = PullFlow( pBNS, SwitchEdge, prim( y ), prim( z ), delta, (S_CHAR) ( 1 - bReverse ), bChangeFlow ); /* augment between z and y */
11340 : : }
11341 : : }
11342 : :
11343 : 10 : return ret;
11344 : : }
11345 : :
11346 : :
11347 : : /****************************************************************************
11348 : : Before augmenting on the two paths, it is necessary to find delta(P).
11349 : : This can be done by following the paths and computing the minimum
11350 : : residual capacity of all edges on P. An edge on both P and P' counts
11351 : : for only half of its actual residual capacity, since augmentng on P by
11352 : : delta will simutaneously reduce its capacity on P' by delta.
11353 : : The path P can only be followed by using the switch-edges, as in PullFlow(...).
11354 : : FindPathCap( x, y, delta ) is a recursive procedure that finds the residual
11355 : : capacity on the portion of P between x and y. delta is the minimum capacity
11356 : : found so far along the path.
11357 : : ****************************************************************************/
11358 : :
11359 : :
11360 : : /****************************************************************************
11361 : : Find the minimum residual capacity of all edges
11362 : : between x and y in a valid st-path P.
11363 : : delta is the minimum found so far
11364 : : the vertices occur in order s,...,x,...,y,...,t along P
11365 : : the vertices occur in order s,...,y',...,x',...,t along P'
11366 : : ****************************************************************************/
11367 : 10 : int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta )
11368 : : {
11369 : :
11370 : : Vertex w, z, iwz;
11371 : : int cap, delta2;
11372 : :
11373 : : /* static int level;
11374 : : if ( level ++ > 50 )
11375 : : {
11376 : : #ifdef _DEBUG
11377 : : int stop = 1;
11378 : : #else
11379 : : ;
11380 : : #endif
11381 : : }
11382 : : */
11383 : :
11384 : 10 : w = SwitchEdge_Vert1( y );
11385 : 10 : z = SwitchEdge_Vert2( y ); /* wz is on the path P */
11386 : 10 : iwz = SwitchEdge_IEdge( y ); /* edge index */
11387 : :
11388 : : /* Rescap_mark() detects edges passed 2 times and reduces rescap */
11389 : 10 : cap = rescap_mark( pBNS, w, z, iwz );
11390 : :
11391 [ + - - + ]: 10 : if (IS_BNS_ERROR( cap ))
11392 : : {
11393 : : /* level --; */
11394 : 0 : return cap;
11395 : : }
11396 [ + + ]: 10 : if (cap < delta)
11397 : : {
11398 : 2 : delta = cap;
11399 : : }
11400 : : /* P consists of a path from x to w, then wz, then a path from z to y */
11401 [ + + ]: 10 : if (w != x)
11402 : : {
11403 : 6 : delta2 = FindPathCap( pBNS, SwitchEdge, x, w, delta );
11404 : 6 : delta = inchi_min( delta2, delta );
11405 : : }
11406 [ + + ]: 10 : if (z != y)
11407 : : {
11408 : 2 : delta2 = FindPathCap( pBNS, SwitchEdge, prim( y ), prim( z ), delta );
11409 : 2 : delta = inchi_min( delta2, delta );
11410 : : }
11411 : : /* level --; */
11412 : :
11413 : 10 : return delta;
11414 : : }
11415 : :
11416 : :
11417 : : /*
11418 : : BT = bond types
11419 : : */
11420 : :
11421 : :
11422 : : #define BT_ALTERN_BOND 1 /* 1-2, possibly stereo */
11423 : : #define BT_OTHER_ALTERN_BOND 2 /* 1-3, 2-3, 1-2-3 alternating non-stereo non-taut bonds */
11424 : :
11425 : : #define BT_ALTERN_NS_BOND 4
11426 : :
11427 : : #define BT_TAUTOM_BOND 8
11428 : :
11429 : : #define BT_ALTERN_UNKN_BOND 16
11430 : :
11431 : : #define BT_IGNORE_BOND 0
11432 : :
11433 : : #define BT_NONSTEREO_MASK (BT_TAUTOM_BOND|BT_ALTERN_NS_BOND)
11434 : :
11435 : : #define BT_ALT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND)
11436 : :
11437 : : #define BT_NONTAUT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND|BT_ALTERN_NS_BOND)
11438 : :
11439 : : /* BNS members redefinitions for finding non-stereo bonds */
11440 : : /* BNS_EDGE */
11441 : : #define nBlockNumberAltBns flow /* internal variable of the DFS traversal: mark traversed bonds */
11442 : : #define nNumAtInBlockAltBns cap
11443 : : #define nBondTypeInpAltBns pass /* 0=>cannot be stereo at all, 1=>alt or taut non-stereo, 2=>can be stereo */
11444 : : #define nBondNonStereoAltBns cap /* 1=>found to be non-stereogenic although BondTypeInp=2; 0=>as in BondTypeInp */
11445 : :
11446 : : #if ( BNS_MARK_ONLY_BLOCKS == 1 ) /* { */
11447 : : /* BNS_VERTEX */
11448 : : #define bCutVertexAltBns st_edge.cap0 /* cut-vertex flag */
11449 : : #define nRingSystemAltBns st_edge.cap /* ordering number of a ring system */
11450 : : #define nNumAtInRingSystemAltBns st_edge.flow0 /* number of vertices in a ring system */
11451 : : #define nBlockSystemAltBns st_edge.flow /* result of the DFS traversal: even cirquit must be within one block */
11452 : :
11453 : : #endif /* } */
11454 : :
11455 : : #define valenceAltBns num_adj_edges
11456 : :
11457 : :
11458 : : /****************************************************************************/
11459 : 69 : int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo )
11460 : 607 : {
11461 : 69 : AT_NUMB *nStackAtom = NULL;
11462 : : int nTopStackAtom;
11463 : 69 : AT_NUMB *nRingStack = NULL;
11464 : : int nTopRingStack; /* was AT_NUMB */
11465 : 69 : AT_NUMB *nBondStack = NULL;
11466 : : int nTopBondStack;
11467 : 69 : AT_NUMB *nDfsNumber = NULL;
11468 : 69 : AT_NUMB *nLowNumber = NULL;
11469 : 69 : S_CHAR *cNeighNumb = NULL;
11470 : : AT_NUMB nDfs;
11471 : : AT_NUMB nNumAtInRingSystem;
11472 : : int i, j, u, w, start, nNumRingSystems; /* djb-rwth: removing redundant variables */
11473 : 69 : BNS_VERTEX *at = pBNS->vert;
11474 : 69 : BNS_EDGE *bond = pBNS->edge;
11475 : 69 : int num_atoms = pBNS->num_atoms;
11476 : 69 : int num_edges = pBNS->num_bonds;
11477 : :
11478 : : /* Allocate arrays */
11479 : 69 : nStackAtom = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nStackAtom[0] ) );
11480 : 69 : nRingStack = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nRingStack[0] ) );
11481 : 69 : nDfsNumber = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nDfsNumber[0] ) );
11482 : 69 : nLowNumber = (AT_NUMB *) inchi_malloc( num_atoms * sizeof( nLowNumber[0] ) );
11483 [ + + ]: 69 : nBondStack = num_edges ? ( (AT_NUMB *) inchi_malloc( num_edges * sizeof( nBondStack[0] ) ) ) : (AT_NUMB *) ( NULL ); /* special case: no bonds 2006-03 */
11484 : 69 : cNeighNumb = (S_CHAR *) inchi_malloc( num_atoms * sizeof( cNeighNumb[0] ) );
11485 : :
11486 : : /* Check allocation */
11487 [ + - + - : 69 : if (!nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || (!nBondStack && num_edges) || !cNeighNumb
+ - + - +
+ + - -
+ ]
11488 : : ) /* djb-rwth: addressing LLVM warning */
11489 : : {
11490 : 0 : nNumRingSystems = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
11491 : 0 : goto exit_function;
11492 : : }
11493 : :
11494 : : /********************************************
11495 : : *
11496 : : * Find Cut-vertices & Blocks
11497 : : *
11498 : : * 1\ /5 has 3 blocks (maximal subgraphs that
11499 : : * Example: | >3--4< | are nonseparable by deleting a single vertex):
11500 : : * 2/ \6 (1,2,3, has 3 bonds), (3,4, has 1 bond), and (4,5,6, has 3 bonds)
11501 : : *
11502 : : * Cut-vertices or articulation points are
11503 : : * intersections of the blocks: points 3 and 4.
11504 : : ********************************************/
11505 : :
11506 : : /********************************************************
11507 : :
11508 : : RingSystemAlt are atoms connected by alternating bonds
11509 : : (as must be indicated in bIsAltBond()):
11510 : :
11511 : : BOND_ALTERN
11512 : : BOND_ALT_123
11513 : : BOND_ALT_13
11514 : : BOND_ALT_23
11515 : :
11516 : : Since other bonds may be present, we possibly need
11517 : : to restart to move to another component
11518 : : *********************************************************/
11519 : :
11520 : 69 : nNumRingSystems = 0;
11521 : 69 : memset( nDfsNumber, 0, num_atoms * sizeof( nDfsNumber[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
11522 : :
11523 [ + + ]: 688 : for (start = 0; start < num_atoms; start++)
11524 : : {
11525 [ + + ]: 619 : if (nDfsNumber[start])
11526 : : {
11527 : 10 : continue;
11528 : : }
11529 [ + + ]: 1713 : for (i = 0; i < at[start].valenceAltBns; i++)
11530 : : {
11531 [ + + ]: 1106 : if (bond[at[start].iedge[i]].nBondTypeInpAltBns & BT_ALTERN_BOND)
11532 : 2 : goto found_alt;
11533 : : }
11534 : 607 : continue;
11535 : :
11536 : 2 : found_alt:
11537 : :
11538 : : /* Initiation */
11539 : 2 : u = start; /* start atom */
11540 : 2 : nDfs = 0;
11541 : 2 : nTopStackAtom = -1;
11542 : 2 : nTopRingStack = -1;
11543 : 2 : nTopBondStack = -1;
11544 : 2 : memset( cNeighNumb, 0, num_atoms * sizeof( cNeighNumb[0] ) ); /* djb-rwth: memset_s C11/Annex K variant? */
11545 : : /* Push the start atom on the stack */
11546 : 2 : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11547 : 2 : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11548 : 2 : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11549 : :
11550 : : /* djb-rwth: removing redundant code */
11551 : :
11552 : : do
11553 : : {
11554 : : /* advance */
11555 : : /*while ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
11556 : : /* replaced due to missing sequence point */
11557 [ + + ]: 42 : while (i = (int) nStackAtom[nTopStackAtom], j = (int) cNeighNumb[i], (int) at[i].valenceAltBns > j)
11558 : : {
11559 : 30 : cNeighNumb[i] ++;
11560 [ + + ]: 30 : if (!( bond[w = at[i].iedge[j]].nBondTypeInpAltBns & BT_ALT_BOND_MASK ))
11561 : : {
11562 : 6 : continue;
11563 : : }
11564 : 24 : u = (int) ( bond[at[i].iedge[j]].neighbor12 ^ i );
11565 [ + + + - ]: 24 : if (!nDfsNumber[u] && nBondStack) /* djb-rwth: fixing a NULL pointer dereference */
11566 : : {
11567 : : /* tree edge, 1st visit -- advance */
11568 : 10 : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11569 : 10 : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11570 : 10 : nBondStack[++nTopBondStack] = (AT_NUMB) w;
11571 : 10 : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11572 : : /* djb-rwth: removing redundant code */
11573 : : }
11574 : : else
11575 : : {
11576 [ + + + + ]: 14 : if (!nTopStackAtom || u != (int) nStackAtom[nTopStackAtom - 1])
11577 : : { /* may comment out ? */
11578 : : /* back edge: u is not a predecessor of i */
11579 [ + + + - ]: 4 : if ((nDfsNumber[u] < nDfsNumber[i]) && nBondStack) /* djb-rwth: fixing a NULL pointer dereference */
11580 : : {
11581 : : /* Back edge, 1st visit: u is ancestor of i. Save and compare */
11582 : 2 : nBondStack[++nTopBondStack] = (AT_NUMB) w;
11583 [ + - ]: 2 : if (nLowNumber[i] > nDfsNumber[u])
11584 : : {
11585 : 2 : nLowNumber[i] = nDfsNumber[u];
11586 : : }
11587 : : }
11588 : : }
11589 : : }
11590 : : }
11591 : 12 : cNeighNumb[i] = 0;
11592 : :
11593 : : /* Back up */
11594 [ + + ]: 12 : if (i != start)
11595 : : {
11596 : 10 : u = (int) nStackAtom[nTopStackAtom - 1]; /* predecessor of i */
11597 [ + + ]: 10 : if (nLowNumber[i] >= nDfsNumber[u])
11598 : : {
11599 : : /* Output the block; the block was entered through its first bond u->i */
11600 : 2 : nNumRingSystems++;
11601 : : /*at[u].nBlockSystemAltBns = nNumRingSystems;*/ /* mark the atom */
11602 : 2 : nNumAtInRingSystem = 1;
11603 : : /*
11604 : : if ( u != start || nNumStartChildren > 1 ) {
11605 : : at[u].bCutVertexAltBns += 1; // mark cut-vertex (articulation point)
11606 : : }
11607 : : */
11608 [ + - ]: 10 : while (nTopRingStack >= 0)
11609 : : {
11610 : 10 : j = nRingStack[nTopRingStack--];
11611 : : /*at[j].nBlockSystemAltBns = nNumRingSystems;*/ /* mark the atom */
11612 : 10 : nNumAtInRingSystem++;
11613 [ + + ]: 10 : if (i == j)
11614 : : {
11615 : 2 : break;
11616 : : }
11617 : : }
11618 [ + - ]: 12 : while (nTopBondStack >= 0)
11619 : : {
11620 : 12 : w = nBondStack[nTopBondStack--];
11621 : 12 : bond[w].nBlockNumberAltBns = nNumRingSystems; /* mark the bond */
11622 : 12 : bond[w].nNumAtInBlockAltBns = nNumAtInRingSystem;
11623 [ + + + - ]: 12 : if ((i == bond[w].neighbor1 && u == ( i ^ bond[w].neighbor12 )) ||
11624 [ + + + + ]: 12 : (u == bond[w].neighbor1 && i == ( u ^ bond[w].neighbor12 ))) /* djb-rwth: addressing LLVM warning */
11625 : : {
11626 : : break;
11627 : : }
11628 : : }
11629 : : }
11630 : : else
11631 : : {
11632 [ + - ]: 8 : if (nLowNumber[u] > nLowNumber[i])
11633 : : {
11634 : : /* inherit */
11635 : 8 : nLowNumber[u] = nLowNumber[i];
11636 : : }
11637 : : }
11638 : : }
11639 [ + + ]: 12 : } while (--nTopStackAtom >= 0);
11640 : : }
11641 : :
11642 : : #if ( BNS_MARK_ONLY_BLOCKS != 1 ) /* { */
11643 : :
11644 : : /********************************************
11645 : : *
11646 : : * Find Ring Systems
11647 : : * Including chain atoms X: A-X-B, where the bonds (of any kind) are bridges.
11648 : : *
11649 : : ********************************************/
11650 : :
11651 : : /* Initiation */
11652 : : nNumRingSystems = 0;
11653 : : for (start = 0; start < num_atoms; start++)
11654 : : {
11655 : : if (at[start].nRingSystemAltBns)
11656 : : {
11657 : : continue;
11658 : : }
11659 : : for (i = 0; i < at[start].valenceAltBns; i++)
11660 : : {
11661 : : if (bond[at[start].iedge[i]].nBondTypeInpAltBns & BT_ALT_BOND_MASK)
11662 : : {
11663 : : goto found_alt2;
11664 : : }
11665 : : }
11666 : : continue;
11667 : :
11668 : : found_alt2:
11669 : : u = start; /* start atom */
11670 : : nDfs = 0;
11671 : : nTopStackAtom = -1;
11672 : : nTopRingStack = -1;
11673 : : memset( nDfsNumber, 0, num_atoms * sizeof( nDfsNumber[0] ) );
11674 : : memset( cNeighNumb, 0, num_atoms * sizeof( cNeighNumb[0] ) );
11675 : : /* push the start atom on the stack */
11676 : : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11677 : : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11678 : : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11679 : :
11680 : : do
11681 : : {
11682 : : /* advance */
11683 : : advance_ring:
11684 : : /*if ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
11685 : : /* replaced due to missing sequence point */
11686 : : if (i = (int) nStackAtom[nTopStackAtom], j = (int) cNeighNumb[i], (int) at[i].valenceAltBns > j)
11687 : : {
11688 : : cNeighNumb[i] ++;
11689 : : if (!( bond[at[i].iedge[j]].nBondTypeInpAltBns & BT_ALTERN_BOND ))
11690 : : {
11691 : : goto advance_ring;
11692 : : }
11693 : : u = (int) ( bond[at[i].iedge[j]].neighbor12 ^ i );
11694 : : if (!nDfsNumber[u])
11695 : : {
11696 : : /* tree edge, 1st visit -- advance */
11697 : : nStackAtom[++nTopStackAtom] = (AT_NUMB) u;
11698 : : nRingStack[++nTopRingStack] = (AT_NUMB) u;
11699 : : nLowNumber[u] = nDfsNumber[u] = ++nDfs;
11700 : : }
11701 : : else
11702 : : {
11703 : : if (!nTopStackAtom || u != (int) nStackAtom[nTopStackAtom - 1])
11704 : : {
11705 : : /* back edge: u is not a predecessor of i */
11706 : : if (nDfsNumber[u] < nDfsNumber[i])
11707 : : {
11708 : : /* Back edge, 1st visit: u is ancestor of i. Compare */
11709 : : if (nLowNumber[i] > nDfsNumber[u])
11710 : : {
11711 : : nLowNumber[i] = nDfsNumber[u];
11712 : : }
11713 : : }
11714 : : }
11715 : : }
11716 : : goto advance_ring;
11717 : : }
11718 : : else
11719 : : {
11720 : : cNeighNumb[i] = 0;
11721 : : }
11722 : :
11723 : : /* Back up */
11724 : : if (nDfsNumber[i] == nLowNumber[i])
11725 : : {
11726 : : /* Found a ring system */
11727 : : nNumRingSystems++;
11728 : :
11729 : : /* Unwind nRingStack[] down to i */
11730 : :
11731 : : /* Count atoms in a ring system */
11732 : : for (nNumAtInRingSystem = 0, j = nTopRingStack; 0 <= j; j--)
11733 : : {
11734 : : nNumAtInRingSystem++;
11735 : : if (i == (int) nRingStack[j])
11736 : : {
11737 : : break;
11738 : : }
11739 : : }
11740 : : while (nTopRingStack >= 0)
11741 : : {
11742 : : j = (int) nRingStack[nTopRingStack--];
11743 : : at[j].nRingSystemAltBns = (AT_NUMB) nNumRingSystems; /* ring system id */
11744 : : at[j].nNumAtInRingSystemAltBns = nNumAtInRingSystem;
11745 : : if (i == j)
11746 : : {
11747 : : /* Reached atom on the top of nStackAtom[] stack */
11748 : : break;
11749 : : }
11750 : : }
11751 : : }
11752 : : else
11753 : : {
11754 : : if (nTopStackAtom > 0)
11755 : : {
11756 : : j = (int) nStackAtom[nTopStackAtom - 1];
11757 : : /* inherit nLowNumber */
11758 : : if (nLowNumber[j] > nLowNumber[i])
11759 : : {
11760 : : nLowNumber[j] = nLowNumber[i];
11761 : : }
11762 : : }
11763 : : }
11764 : : } while (--nTopStackAtom >= 0);
11765 : : }
11766 : :
11767 : : #endif /* } BNS_MARK_ONLY_BLOCKS != 1 */
11768 : :
11769 : 69 : exit_function:
11770 [ + - ]: 69 : if (nStackAtom)
11771 : : {
11772 [ + - ]: 69 : inchi_free( nStackAtom );
11773 : : }
11774 [ + - ]: 69 : if (nRingStack)
11775 : : {
11776 [ + - ]: 69 : inchi_free( nRingStack );
11777 : : }
11778 [ + - ]: 69 : if (nDfsNumber)
11779 : : {
11780 [ + - ]: 69 : inchi_free( nDfsNumber );
11781 : : }
11782 [ + - ]: 69 : if (nLowNumber)
11783 : : {
11784 [ + - ]: 69 : inchi_free( nLowNumber );
11785 : : }
11786 [ + + ]: 69 : if (nBondStack)
11787 : : {
11788 [ + - ]: 64 : inchi_free( nBondStack );
11789 : : }
11790 [ + - ]: 69 : if (cNeighNumb)
11791 : : {
11792 [ + - ]: 69 : inchi_free( cNeighNumb );
11793 : : }
11794 : :
11795 : 69 : return nNumRingSystems;
11796 : : }
11797 : :
11798 : :
11799 : : /****************************************************************************/
11800 : 69 : int ReInitBnStructForAltBns( BN_STRUCT *pBNS,
11801 : : inp_ATOM *at,
11802 : : int num_atoms,
11803 : : int bUnknAltAsNoStereo )
11804 : : {
11805 : : Vertex v, v2;
11806 : : int ret, bond_type, num_to_test, j;
11807 : : BNS_EDGE *pBond;
11808 : : BNS_VERTEX *pAtom;
11809 : :
11810 : : /* Strip all t-groups and c-groups */
11811 : 69 : num_to_test = 0;
11812 [ - + ]: 69 : if (bUnknAltAsNoStereo)
11813 : : {
11814 [ # # ]: 0 : for (j = 0; j < pBNS->num_edges; j++)
11815 : : {
11816 : 0 : pBNS->edge[j].pass = 0;
11817 : : }
11818 : : }
11819 : :
11820 : 69 : ret = ReInitBnStruct( pBNS, at, num_atoms, 0 );
11821 : :
11822 [ + - + - : 69 : if (ret || pBNS->num_atoms != num_atoms || pBNS->num_vertices != num_atoms || pBNS->num_bonds != pBNS->num_edges)
+ - - + ]
11823 : : {
11824 : 0 : ret = BNS_REINIT_ERR;
11825 : 0 : goto exit_function;
11826 : : }
11827 : :
11828 : : /* Eliminate bonds and fix st-caps */
11829 [ + + ]: 688 : for (v = 0; v < num_atoms; v++)
11830 : : {
11831 : 619 : pAtom = pBNS->vert + v;
11832 [ + + ]: 1753 : for (j = 0; j < pAtom->valenceAltBns; j++)
11833 : : {
11834 : 1134 : pBond = pBNS->edge + pAtom->iedge[j];
11835 [ + + ]: 1134 : if (pBond->neighbor1 == v)
11836 : : {
11837 : 567 : bond_type = ( at[v].bond_type[j] & BOND_TYPE_MASK );
11838 : 567 : v2 = pBond->neighbor12 ^ v;
11839 [ + - - + ]: 567 : if (at[v].endpoint || at[v2].endpoint)
11840 : : {
11841 : 0 : bond_type = 0; /* any bond to an endpoint considered non-stereogenic */
11842 : : }
11843 : : #if ( FIX_EITHER_DB_AS_NONSTEREO == 1 )
11844 : : if (bUnknAltAsNoStereo)
11845 : : {
11846 : : if (bond_type == BOND_ALTERN && at[v].bond_stereo[j] == STEREO_DBLE_EITHER)
11847 : : {
11848 : : bond_type = 0; /* treat unknown (Either) ALT bond as non-stereo */
11849 : : }
11850 : : }
11851 : : #endif
11852 [ + - - - : 567 : switch (bond_type)
+ - ]
11853 : : {
11854 : :
11855 : 12 : case BOND_ALTERN:
11856 : 12 : pBond->nBondTypeInpAltBns = BT_ALTERN_BOND;
11857 : 12 : num_to_test++;
11858 : 12 : break;
11859 : :
11860 : 0 : case BOND_ALT_123:
11861 : : case BOND_ALT_13:
11862 : : case BOND_ALT_23:
11863 : 0 : pBond->nBondTypeInpAltBns = BT_OTHER_ALTERN_BOND;
11864 : 0 : break;
11865 : :
11866 : 0 : case BOND_TAUTOM:
11867 : 0 : pBond->nBondTypeInpAltBns = BT_TAUTOM_BOND;
11868 : 0 : break;
11869 : :
11870 : 0 : case BOND_ALT12NS:
11871 : 0 : pBond->nBondTypeInpAltBns = BT_ALTERN_NS_BOND;
11872 : 0 : break;
11873 : :
11874 : 555 : case 0:
11875 : : case BOND_SINGLE:
11876 : : case BOND_DOUBLE:
11877 : : case BOND_TRIPLE:
11878 : 555 : pBond->nBondTypeInpAltBns = BT_IGNORE_BOND;
11879 : 555 : break;
11880 : :
11881 : 0 : default:
11882 : 0 : pBond->nBondTypeInpAltBns = BT_IGNORE_BOND;
11883 : 0 : break;
11884 : : }
11885 : 567 : pBond->nBondNonStereoAltBns = 0; /* djb-rwth: addressing GCC warning -- operations on pBond->cap might be undefined */
11886 : 567 : pBond->nBlockNumberAltBns = 0;
11887 : 567 : pBond->nNumAtInBlockAltBns = 0;
11888 : :
11889 : : #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
11890 : 567 : pBond->forbidden &= pBNS->edge_forbidden_mask;
11891 : : #endif
11892 : : }
11893 : : }
11894 : 619 : pAtom->bCutVertexAltBns =
11895 : 619 : pAtom->nRingSystemAltBns =
11896 : 619 : pAtom->nNumAtInRingSystemAltBns =
11897 : 619 : pAtom->nBlockSystemAltBns = 0;
11898 : : }
11899 : :
11900 : 69 : return num_to_test;
11901 : :
11902 : 0 : exit_function:
11903 : :
11904 : 0 : return ret;
11905 : : }
11906 : :
11907 : :
11908 : : /****************************************************************************/
11909 : 69 : int MarkNonStereoAltBns( BN_STRUCT *pBNS,
11910 : : inp_ATOM *at,
11911 : : int num_atoms,
11912 : : int bUnknAltAsNoStereo )
11913 : : {
11914 : 69 : int num_bonds = pBNS->num_bonds;
11915 : : int ret;
11916 : : int ibond, ib1, ib2;
11917 : : BNS_EDGE *pBond;
11918 : : Vertex iat1, iat2;
11919 : :
11920 : 69 : ret = 0;
11921 : :
11922 [ + - + - : 69 : if (pBNS->num_atoms != num_atoms || pBNS->num_vertices != num_atoms || pBNS->num_bonds != pBNS->num_edges)
- + ]
11923 : : {
11924 : 0 : ret = BNS_REINIT_ERR;
11925 : 0 : goto exit_function;
11926 : : }
11927 [ - + ]: 69 : if (bUnknAltAsNoStereo)
11928 : : {
11929 [ # # ]: 0 : for (ibond = 0; ibond < num_bonds; ibond++)
11930 : : {
11931 : 0 : pBond = pBNS->edge + ibond;
11932 [ # # # # ]: 0 : if (pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND)
11933 : : {
11934 : 0 : continue;
11935 : : }
11936 : 0 : iat1 = pBond->neighbor1;
11937 : 0 : iat2 = pBond->neighbor12 ^ iat1;
11938 : 0 : ib1 = pBond->neigh_ord[0];
11939 : 0 : ib2 = pBond->neigh_ord[1];
11940 : 0 : if ( /* alt bond non-adjacent to a taut. endpoint: */
11941 [ # # ]: 0 : ( pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
11942 [ # # ]: 0 : pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
11943 : : /* alt bond adjacent to a taut. endpoint: */
11944 [ # # ]: 0 : ( pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
11945 [ # # ]: 0 : ( at[iat1].bond_type[ib1] & BOND_TYPE_MASK ) == BOND_ALTERN )
11946 : : )
11947 : : {
11948 [ # # ]: 0 : if (( at[iat1].bond_type[ib1] & BOND_TYPE_MASK ) == BOND_ALTERN)
11949 : : {
11950 : : /* bond_type = BOND_ALT12NS; */
11951 : 0 : at[iat1].bond_stereo[ib1] =
11952 : 0 : at[iat2].bond_stereo[ib2] = STEREO_DBLE_EITHER;
11953 : 0 : ret++;
11954 : : }
11955 : : }
11956 : : }
11957 : : }
11958 : : else
11959 : : {
11960 [ + + ]: 636 : for (ibond = 0; ibond < num_bonds; ibond++)
11961 : : {
11962 : 567 : pBond = pBNS->edge + ibond;
11963 [ + + - + ]: 567 : if (pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND)
11964 : : {
11965 : 0 : continue;
11966 : : }
11967 : 567 : iat1 = pBond->neighbor1;
11968 : 567 : iat2 = pBond->neighbor12 ^ iat1;
11969 : 567 : ib1 = pBond->neigh_ord[0];
11970 : 567 : ib2 = pBond->neigh_ord[1];
11971 : 567 : if ( /* alt bond non-adjacent to a taut. endpoint: */
11972 [ + + ]: 567 : ( pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
11973 [ + - ]: 12 : pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
11974 : : /* alt bond adjacent to a taut. endpoint: */
11975 [ + + ]: 567 : ( pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
11976 [ - + ]: 555 : ( at[iat1].bond_type[ib1] & BOND_TYPE_MASK ) == BOND_ALTERN )
11977 : : )
11978 : : {
11979 : 0 : at[iat1].bond_type[ib1] =
11980 : 0 : at[iat2].bond_type[ib2] = BOND_ALT12NS;
11981 : 0 : ret++;
11982 : : }
11983 : : }
11984 : : }
11985 : :
11986 : 69 : exit_function:
11987 : :
11988 : 69 : return ret;
11989 : : }
11990 : :
11991 : :
11992 : : #if ( READ_INCHI_STRING == 1 )
11993 : : /*****************************************************************************/
11994 : : #ifndef RI_ERR_ALLOC
11995 : : /* from ichirvrs.h */
11996 : : #define RI_ERR_ALLOC (-1)
11997 : : #define RI_ERR_SYNTAX (-2)
11998 : : #define RI_ERR_PROGR (-3)
11999 : : #endif
12000 : :
12001 : :
12002 : : /****************************************************************************
12003 : : Check if atom bonded to charged atom
12004 : : ****************************************************************************/
12005 : 0 : int bHasChargedNeighbor( inp_ATOM *at, int iat )
12006 : : {
12007 : : int i;
12008 [ # # ]: 0 : for (i = 0; i < at[iat].valence; i++)
12009 : : {
12010 [ # # ]: 0 : if (at[(int) at[iat].neighbor[i]].charge)
12011 : : {
12012 : 0 : return 1;
12013 : : }
12014 : : }
12015 : :
12016 : 0 : return 0;
12017 : : }
12018 : :
12019 : :
12020 : : /****************************************************************************
12021 : : Add or remove protons
12022 : :
12023 : : *num_protons_to_add = nToBeRemovedByNormFromRevrs
12024 : :
12025 : : nToBeRemovedByNormFromRevrs > 0: less protons should be allowed to be
12026 : : added by the Normalization of the Reconstructed Structure
12027 : : nToBeRemovedByNormFromRevrs < 0: prepare more H(+) to be removed by
12028 : : the InChI Normalization of the Reconstructed Structure
12029 : :
12030 : : OrigStruct -> NormOrig + n(orig)*H(+)
12031 : : RevrStruct -> NormRevr + n(revr)*H(+)
12032 : : nToBeRemovedByNormFromRevrs = n(orig) - n(revr) [each may be negative]
12033 : :
12034 : : n(orig) > n(revr) or nToBeRemovedByNormFromRevrs > 0 means:
12035 : : -----------------------------------------------------------
12036 : : - Too many protons were added by the Normalization to the Reconstructed Structure
12037 : : (a) n(revr) < 0 => protons were added while they should not have been added;
12038 : : Solution: "neutralize" (-) charged proton acceptors by moving charges to other atoms
12039 : : on the condition ADP cannot add in another way;
12040 : : (b) n(orig) > n(revr) => 0 => too few protons were removed
12041 : : Solution: (the easiest) attach H(+) to =O or -N< or -N=
12042 : : Solution: move (+) from N or OH to an atom adjacent to (-) charge or to
12043 : : an atom that is not N.
12044 : :
12045 : : n(orig) < n(revr) or nToBeRemovedByNormFromRevrs < 0 means:
12046 : : -----------------------------------------------------------
12047 : : - Too few protons were added by the Normalization to the Reconstructed Stucture
12048 : : (a) n(orig) < 0 => protons were not added while they should have been added;
12049 : : Solution: move (-) to O by replacing =O with -O(-)
12050 : : (b) 0 <= n(orig) < n(revr) => too many protons were removed
12051 : :
12052 : : Note: it is critically important to takr into account cumbersome Normalization
12053 : : Total Charge: if it is >= 0 then no H(+) may be removed from -OH or by ADP
12054 : : However, if N(+) is present then ADP will always try to remove a proton
12055 : : ****************************************************************************/
12056 : 0 : int AddRemoveProtonsRestr( inp_ATOM *at,
12057 : : int num_atoms,
12058 : : int *num_protons_to_add,
12059 : : int nNumProtAddedByRestr,
12060 : : INCHI_MODE bNormalizationFlags,
12061 : : int num_tg,
12062 : : int nChargeRevrs,
12063 : : int nChargeInChI )
12064 : : {
12065 : 0 : int i, j, ret = 0;
12066 : : int nAtTypeTotals[ATTOT_ARRAY_LEN];
12067 : 0 : int num_prot = *num_protons_to_add;
12068 : 0 : int type, mask, bSuccess, nTotCharge, nNumSuccess = 0;
12069 : 0 : int max_j_Aa = -1, max_j_Ar = -1;
12070 : :
12071 : : /* for the reference:
12072 : :
12073 : : #define FLAG_NORM_CONSIDER_TAUT ( FLAG_PROTON_NPO_SIMPLE_REMOVED | \
12074 : : FLAG_PROTON_NP_HARD_REMOVED | \
12075 : : FLAG_PROTON_AC_SIMPLE_ADDED | \
12076 : : FLAG_PROTON_AC_SIMPLE_REMOVED | \
12077 : : FLAG_PROTON_AC_HARD_REMOVED | \
12078 : : FLAG_PROTON_AC_HARD_ADDED | \
12079 : : FLAG_PROTON_SINGLE_REMOVED | \
12080 : : FLAG_PROTON_CHARGE_CANCEL )
12081 : :
12082 : : #define FLAG_FORCE_SALT_TAUT ( FLAG_PROTON_NP_HARD_REMOVED | \
12083 : : FLAG_PROTON_AC_HARD_REMOVED | \
12084 : : FLAG_PROTON_AC_HARD_ADDED )
12085 : :
12086 : : */
12087 : :
12088 : : /* if ChargeRevrs > nChargeInChI then we should prevent proton addition or facilitate proton removal
12089 : : a typical case is (=) on N or O instead of C(-)
12090 : :
12091 : : if ChargeRevrs < nChargeInChI then we should prevent proton removal or facilitate proton addition
12092 : : */
12093 : :
12094 : 0 : mark_at_type( at, num_atoms, nAtTypeTotals );
12095 [ # # ]: 0 : for (i = nTotCharge = 0; i < num_atoms; i++)
12096 : : {
12097 : 0 : nTotCharge += at[i].charge;
12098 : : }
12099 : : /* Size for SimpleAddAcidicProtons() */
12100 [ # # ]: 0 : for (max_j_Aa = 0; AaTypMask[2 * max_j_Aa]; max_j_Aa++)
12101 : : {
12102 : : ;
12103 : : }
12104 : : /* Size for SimpleRemoveAcidicProtons */
12105 [ # # ]: 0 : for (max_j_Ar = 0; ArTypMask[2 * max_j_Ar]; max_j_Ar++)
12106 : : {
12107 : : ;
12108 : : }
12109 [ # # # # ]: 0 : if (num_prot < 0 && nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr <= 0)
12110 : : {
12111 : : /* Remove proton(s) */
12112 : : /* use test from SimpleAddAcidicProtons() to test whether removal of H(+) from =C-OH, etc. is correct */
12113 [ # # # # ]: 0 : for (i = 0; i < num_atoms && num_prot; i++)
12114 : : {
12115 : : /* Choose an atom */
12116 [ # # # # : 0 : if (at[i].sb_parity[0] || at[i].p_parity || at[i].charge ||
# # ]
12117 [ # # # # : 0 : !at[i].num_H || at[i].radical || bHasChargedNeighbor( at, i ))
# # ]
12118 : : {
12119 : 0 : continue;
12120 : : }
12121 : : /* try to remove a proton and check whether InChI would add it back */
12122 : 0 : at[i].charge--;
12123 : 0 : at[i].num_H--;
12124 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12125 : 0 : at[i].charge++;
12126 : 0 : at[i].num_H++;
12127 : :
12128 [ # # ]: 0 : if (type)
12129 : : {
12130 [ # # ]: 0 : for (bSuccess = 0, j = 0; j < max_j_Aa; j++)
12131 : : {
12132 [ # # # # : 0 : if ((bSuccess = ( type & AaTypMask[2 * j] ) && ( mask && AaTypMask[2 * j + 1] ))) /* djb-rwth: addressing LLVM warning */
# # # # ]
12133 : : {
12134 : 0 : break; /* the proton may be added to this atom */
12135 : : }
12136 : : }
12137 [ # # ]: 0 : if (bSuccess)
12138 : : {
12139 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12140 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12141 : 0 : at[i].charge--;
12142 : 0 : at[i].num_H--;
12143 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12144 : 0 : num_prot++; /* success */
12145 : 0 : nNumSuccess++;
12146 : : }
12147 : : }
12148 : : }
12149 : : }
12150 : :
12151 [ # # # # : 0 : if (num_prot < 0 && num_tg && nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr <= 0)
# # ]
12152 : : {
12153 : : /* Alternative proton removal: O=C-NH => (-)O-C=N, O and N are taut. endpoints */
12154 : : int endp2, centp, k, i0, k0;
12155 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
12156 : : {
12157 : : /* Choose an atom */
12158 [ # # # # : 0 : if (!at[i].endpoint || at[i].sb_parity[0] || at[i].p_parity ||
# # ]
12159 [ # # # # : 0 : at[i].radical || at[i].charge || bHasChargedNeighbor( at, i ))
# # ]
12160 : : {
12161 : 0 : continue;
12162 : : }
12163 : : /* Looking for tautomeric =O */
12164 [ # # # # : 0 : if (1 != at[i].valence || BOND_TYPE_DOUBLE != at[i].bond_type[0] || at[i].num_H ||
# # # # ]
12165 : 0 : 2 != get_endpoint_valence( at[i].el_number ))
12166 : : {
12167 : 0 : continue;
12168 : : }
12169 : 0 : centp = at[i].neighbor[0];
12170 [ # # # # : 0 : if (at[centp].sb_parity[0] || at[centp].p_parity || !is_centerpoint_elem( at[centp].el_number ))
# # ]
12171 : : {
12172 : 0 : continue;
12173 : : }
12174 : : /* Found a possible centerpoint, looking for -NH endpoint */
12175 [ # # ]: 0 : for (k = 0; k < at[centp].valence; k++)
12176 : : {
12177 [ # # ]: 0 : if (at[centp].bond_type[k] != BOND_TYPE_SINGLE)
12178 : : {
12179 : 0 : continue;
12180 : : }
12181 : 0 : endp2 = at[centp].neighbor[k];
12182 [ # # ]: 0 : if (at[endp2].endpoint != at[i].endpoint ||
12183 [ # # # # ]: 0 : !at[endp2].num_H || at[endp2].charge ||
12184 [ # # # # ]: 0 : at[endp2].sb_parity[0] || at[endp2].p_parity ||
12185 [ # # ]: 0 : at[endp2].valence != at[endp2].chem_bonds_valence ||
12186 [ # # # # ]: 0 : 3 != at[endp2].chem_bonds_valence + at[endp2].num_H ||
12187 : 0 : 3 != get_endpoint_valence( at[endp2].el_number ))
12188 : : {
12189 : 0 : continue;
12190 : : }
12191 : : /* Find bonds in reciprocal ajacency lists */
12192 [ # # # # ]: 0 : for (i0 = 0; i0 < at[centp].valence && i != at[centp].neighbor[i0]; i0++)
12193 : : {
12194 : : ;
12195 : : }
12196 [ # # # # ]: 0 : for (k0 = 0; k0 < at[endp2].valence && centp != at[endp2].neighbor[k0]; k0++)
12197 : : {
12198 : : ;
12199 : : }
12200 [ # # # # ]: 0 : if (i0 == at[centp].valence || k0 == at[endp2].valence)
12201 : : {
12202 : 0 : return RI_ERR_PROGR;
12203 : : }
12204 : : /* -NH has been found */
12205 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12206 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12207 : 0 : type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 1 ); /* subtract at[endp2] */
12208 : :
12209 : 0 : at[i].bond_type[0] --;
12210 : 0 : at[centp].bond_type[i0] --;
12211 : 0 : at[i].chem_bonds_valence--;
12212 : 0 : at[i].charge--;
12213 : :
12214 : 0 : at[endp2].bond_type[k0] ++;
12215 : 0 : at[centp].bond_type[k] ++;
12216 : 0 : at[endp2].chem_bonds_valence++;
12217 : 0 : at[endp2].num_H--;
12218 : :
12219 : 0 : num_prot++;
12220 : 0 : nNumSuccess++;
12221 : :
12222 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12223 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add at[i] */
12224 : 0 : type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 0 ); /* add at[endp2] */
12225 : : }
12226 : : }
12227 : : }
12228 : :
12229 [ # # ]: 0 : if (num_prot > 0)
12230 : : {
12231 : : /* Add protons */
12232 : : /* 1. Use test from SimpleRemoveAcidicProtons() to test whether addition of H(+) to =C-O(-), etc. is correct */
12233 [ # # # # : 0 : for (i = 0; i < num_atoms && num_prot && nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr >= 0; i++)
# # ]
12234 : : {
12235 : : /* Choose an atom */
12236 [ # # # # : 0 : if (at[i].sb_parity[0] || at[i].p_parity || at[i].num_H ||
# # ]
12237 [ # # # # : 0 : at[i].charge != -1 || at[i].radical || bHasChargedNeighbor( at, i ))
# # ]
12238 : : {
12239 : 0 : continue;
12240 : : }
12241 : : /* Try to add a proton and check whether InChI would remove it back */
12242 : 0 : at[i].charge++;
12243 : 0 : at[i].num_H++;
12244 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12245 : 0 : at[i].charge--;
12246 : 0 : at[i].num_H--;
12247 [ # # ]: 0 : if (type)
12248 : : {
12249 [ # # ]: 0 : for (bSuccess = 0, j = 0; j < max_j_Ar; j++)
12250 : : {
12251 [ # # # # : 0 : if ((bSuccess = ( type & ArTypMask[2 * j] ) && ( mask && ArTypMask[2 * j + 1] ))) /* djb-rwth: addressing LLVM warning */
# # # # ]
12252 : : {
12253 : 0 : break;
12254 : : }
12255 : : }
12256 [ # # ]: 0 : if (bSuccess)
12257 : : {
12258 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12259 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12260 : 0 : at[i].charge++;
12261 : 0 : at[i].num_H++;
12262 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12263 : 0 : num_prot--; /* success */
12264 : 0 : nNumSuccess++;
12265 : : }
12266 : : }
12267 : : }
12268 : : /* 2. Use test from SimpleRemoveHplusNPO() */
12269 [ # # # # ]: 0 : for (i = 0; i < num_atoms && num_prot; i++)
12270 : : {
12271 : : /* Choose an atom */
12272 [ # # # # ]: 0 : if (at[i].sb_parity[0] || at[i].p_parity ||
12273 [ # # # # : 0 : at[i].charge || at[i].radical || bHasChargedNeighbor( at, i ))
# # ]
12274 : : {
12275 : 0 : continue;
12276 : : }
12277 : : /* Try to add a proton and check whether InChI would remove it back */
12278 : 0 : at[i].num_H++;
12279 : 0 : at[i].charge++;
12280 [ # # ]: 0 : bSuccess = ( PR_SIMPLE_TYP & ( type = GetAtomChargeType( at, i, NULL, &mask, 0 ) ) ) &&
12281 [ # # ]: 0 : ( PR_SIMPLE_MSK & mask ); /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12282 : 0 : at[i].num_H--; /* failed */
12283 : 0 : at[i].charge--;
12284 [ # # ]: 0 : if (bSuccess)
12285 : : {
12286 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12287 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12288 : 0 : at[i].num_H++;
12289 : 0 : at[i].charge++;
12290 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12291 : 0 : num_prot--; /* succeeded */
12292 : 0 : nNumSuccess++;
12293 : : }
12294 : : }
12295 : : }
12296 : :
12297 [ # # # # : 0 : if (num_prot < 0 && ( bNormalizationFlags & FLAG_PROTON_AC_HARD_ADDED ) && 1 == num_tg &&
# # ]
12298 [ # # ]: 0 : nAtTypeTotals[ATTOT_TOT_CHARGE] - nNumProtAddedByRestr <= 0)
12299 : : {
12300 : : /* Try to remove protons from tautomeric N (specific ADP must be present) */
12301 : 0 : int nNumAcceptors_DB_O = 0, nNumDonors_SB_NH = 0, num_max, num_success;
12302 [ # # ]: 0 : for (i = 0; i < num_atoms; i++)
12303 : : {
12304 : : /* Choose an atom */
12305 [ # # # # ]: 0 : if (!at[i].endpoint || at[i].radical ||
12306 [ # # # # : 0 : at[i].sb_parity[0] || at[i].p_parity || bHasChargedNeighbor( at, i ))
# # ]
12307 : : {
12308 : 0 : continue;
12309 : : }
12310 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12311 [ # # # # ]: 0 : if (( type & AA_HARD_TYP_CO ) && ( mask & AA_HARD_MSK_CO ))
12312 : : {
12313 : 0 : nNumAcceptors_DB_O++;
12314 : : }
12315 : : else
12316 : : {
12317 [ # # # # : 0 : if (( type == ATT_ATOM_N ) && ( mask == ATBIT_NP_H ) && !at[i].charge &&
# # ]
12318 [ # # ]: 0 : at[i].valence == at[i].chem_bonds_valence)
12319 : : {
12320 : 0 : nNumDonors_SB_NH++;
12321 : : }
12322 : : }
12323 : : }
12324 : 0 : num_max = inchi_min( nNumAcceptors_DB_O, nNumDonors_SB_NH );
12325 [ # # # # : 0 : for (i = 0, num_success = 0; i < num_atoms && num_success < num_max && num_prot < 0; i++)
# # ]
12326 : : {
12327 : : /* Choose an atom */
12328 [ # # # # : 0 : if (!at[i].endpoint || at[i].radical || at[i].sb_parity[0] ||
# # ]
12329 [ # # # # ]: 0 : at[i].p_parity || bHasChargedNeighbor( at, i ))
12330 : : {
12331 : 0 : continue;
12332 : : }
12333 : 0 : type = GetAtomChargeType( at, i, NULL, &mask, 0 );
12334 [ # # # # : 0 : if (( type == ATT_ATOM_N ) && ( mask == ATBIT_NP_H ) && !at[i].charge &&
# # ]
12335 [ # # ]: 0 : at[i].valence == at[i].chem_bonds_valence)
12336 : : {
12337 : : /* djb-rwth: ignoring LLVM warning: variable used to store function return value */
12338 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
12339 : 0 : at[i].num_H--;
12340 : 0 : at[i].charge--;
12341 : 0 : type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
12342 : 0 : num_prot++;
12343 : 0 : num_success++;
12344 : 0 : nNumSuccess++;
12345 : : }
12346 : : }
12347 : : }
12348 : :
12349 : : /*exit_function:*/
12350 : :
12351 : 0 : *num_protons_to_add = num_prot;
12352 : :
12353 [ # # ]: 0 : return ret < 0 ? ret : nNumSuccess;
12354 : : }
12355 : :
12356 : :
12357 : : /****************************************************************************
12358 : : Add or remove isotopic protons
12359 : : ****************************************************************************/
12360 : 0 : int AddRemoveIsoProtonsRestr( inp_ATOM *at,
12361 : : int num_atoms,
12362 : : NUM_H num_protons_to_add[],
12363 : : int num_tg )
12364 : : {
12365 : 0 : int i, j, k, n, ret = 0;
12366 : 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 */
12367 : : int iCurIso; /* 0=> 1H, 1=> D, 2=> T */
12368 : : int iCurMode, iCurMode1, iCurMode2; /* 0=> Not Endpoints, 1=> Endpoints */
12369 : :
12370 : : /* Distribute isotopes from heaviest to lightest; pick up atoms in order 1. Not endpoints; 2. Endpoints */
12371 : 0 : iCurMode1 = 0;
12372 : 0 : iCurMode2 = num_tg ? 1 : 0;
12373 [ # # ]: 0 : for (iCurMode = iCurMode1; iCurMode <= iCurMode2; iCurMode++)
12374 : : {
12375 [ # # ]: 0 : for (iCurIso = 2; 0 <= iCurIso; iCurIso--)
12376 : : {
12377 : : /* check for isotopic H to add */
12378 [ # # ]: 0 : if (!num_protons_to_add[iCurIso])
12379 : : {
12380 : 0 : continue;
12381 : : }
12382 [ # # ]: 0 : if (0 > num_protons_to_add[iCurIso])
12383 : : {
12384 : 0 : ret = RI_ERR_PROGR;
12385 : 0 : goto exit_function;
12386 : : }
12387 : :
12388 : : /* Limits for atom scanning */
12389 : 0 : min_at = 0;
12390 : 0 : max_at = num_atoms;
12391 : :
12392 : : /* Cycle withio the limits */
12393 [ # # # # ]: 0 : for (i = min_at; i < max_at && 0 < num_protons_to_add[iCurIso]; i++)
12394 : : {
12395 : : /* Pick an atom */
12396 [ # # ]: 0 : if (iCurMode)
12397 : : {
12398 [ # # ]: 0 : if (at[i].endpoint)
12399 : : {
12400 : 0 : j = i; /* atom number */
12401 : : }
12402 : : else
12403 : : {
12404 : 0 : continue;
12405 : : }
12406 : : }
12407 : : else
12408 : : {
12409 [ # # # # ]: 0 : if (!at[i].endpoint && 1 == bHeteroAtomMayHaveXchgIsoH( at, i ))
12410 : : { /* atom number */
12411 : 0 : j = i;
12412 : : }
12413 : : else
12414 : : {
12415 [ # # # # ]: 0 : if (at[i].el_number == EL_NUMBER_H && at[i].charge == 1 &&
12416 [ # # # # : 0 : !at[i].valence && !at[i].radical && !at[i].iso_atw_diff)
# # ]
12417 : : {
12418 : : /* proton, not isotopic; make it isotopic */
12419 : 0 : at[i].iso_atw_diff = 1 + iCurIso;
12420 : 0 : num_protons_to_add[iCurIso] --;
12421 : 0 : nNumSuccess++;
12422 : 0 : continue;
12423 : : }
12424 : : else
12425 : : {
12426 : 0 : continue;
12427 : : }
12428 : : }
12429 : : }
12430 : :
12431 : : /* j is the atom number */
12432 : : /* count implicit H */
12433 : 0 : num_H = at[j].num_H;
12434 : 0 : num_iso_H = NUM_ISO_H(at, j); /* djb-rwth: ignoring LLVM warning: possible presence of global variables */
12435 : :
12436 [ # # # # ]: 0 : while (num_H > 0 && num_protons_to_add[iCurIso] > 0)
12437 : : {
12438 : : /* Substitute one implicit H with an isotopic atom H */
12439 : 0 : at[j].num_iso_H[iCurIso] ++;
12440 : 0 : at[j].num_H--;
12441 : 0 : num_protons_to_add[iCurIso] --;
12442 : 0 : num_H--;
12443 : 0 : num_iso_H++;
12444 : 0 : nNumSuccess++;
12445 : : }
12446 : : /* Count explicit H */
12447 : 0 : num_expl_H = num_expl_iso_H = 0;
12448 [ # # # # ]: 0 : for (k = 0; k < at[j].valence && num_atoms <= ( n = at[j].neighbor[k] ); k++)
12449 : : {
12450 : 0 : num_expl_H += ( 0 == at[n].iso_atw_diff );
12451 : 0 : num_expl_iso_H += ( 0 != at[n].iso_atw_diff );
12452 : : }
12453 [ # # # # ]: 0 : while (num_expl_H > 0 && num_protons_to_add[iCurIso] > 0)
12454 : : {
12455 : : /* Substitute one explicit H with an isotopic atom H */
12456 : 0 : n = at[j].neighbor[num_expl_H];
12457 [ # # ]: 0 : if (at[n].iso_atw_diff)
12458 : : {
12459 : 0 : ret = RI_ERR_PROGR;
12460 : 0 : goto exit_function;
12461 : : }
12462 : 0 : at[n].iso_atw_diff = 1 + iCurIso;
12463 : 0 : num_expl_H--;
12464 : 0 : num_expl_iso_H++;
12465 : 0 : num_protons_to_add[iCurIso] --;
12466 : 0 : nNumSuccess++;
12467 : : }
12468 : : }
12469 : : }
12470 : : }
12471 : :
12472 : 0 : exit_function:
12473 : :
12474 [ # # ]: 0 : return ret < 0 ? ret : nNumSuccess;
12475 : : }
12476 : :
12477 : : #endif
|