rino 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. data/Rakefile +1 -1
  2. data/ext/extconf.rb +1 -24
  3. data/ext/libinchi.so +0 -0
  4. data/ext/src/aux2atom.h +120 -39
  5. data/ext/src/comdef.h +3 -3
  6. data/ext/src/dispstru.c +2547 -0
  7. data/ext/src/dispstru.h +73 -0
  8. data/ext/src/extr_ct.h +5 -2
  9. data/ext/src/ichi.h +27 -11
  10. data/ext/src/ichi_bns.c +1800 -254
  11. data/ext/src/ichi_bns.h +205 -4
  12. data/ext/src/ichican2.c +197 -86
  13. data/ext/src/ichicano.c +8 -13
  14. data/ext/src/ichicano.h +2 -2
  15. data/ext/src/ichicans.c +11 -6
  16. data/ext/src/ichicant.h +2 -2
  17. data/ext/src/ichicomn.h +2 -2
  18. data/ext/src/ichicomp.h +19 -4
  19. data/ext/src/ichidrp.h +9 -5
  20. data/ext/src/ichierr.h +5 -3
  21. data/ext/src/ichiisot.c +2 -2
  22. data/ext/src/ichimain.c +461 -0
  23. data/ext/src/ichimain.h +23 -15
  24. data/ext/src/ichimak2.c +6 -6
  25. data/ext/src/ichimake.c +843 -42
  26. data/ext/src/ichimake.h +4 -2
  27. data/ext/src/ichimap1.c +5 -5
  28. data/ext/src/ichimap2.c +2 -2
  29. data/ext/src/ichimap4.c +34 -21
  30. data/ext/src/ichinorm.c +11 -5
  31. data/ext/src/ichinorm.h +3 -2
  32. data/ext/src/ichiparm.c +2 -2
  33. data/ext/src/ichiparm.h +232 -30
  34. data/ext/src/ichiprt1.c +35 -11
  35. data/ext/src/ichiprt2.c +78 -7
  36. data/ext/src/ichiprt3.c +300 -120
  37. data/ext/src/ichiqueu.c +17 -2
  38. data/ext/src/ichiread.c +6932 -0
  39. data/ext/src/ichiring.c +3 -2
  40. data/ext/src/ichiring.h +2 -2
  41. data/ext/src/ichirvr1.c +4891 -0
  42. data/ext/src/ichirvr2.c +6344 -0
  43. data/ext/src/ichirvr3.c +5499 -0
  44. data/ext/src/ichirvr4.c +3177 -0
  45. data/ext/src/ichirvr5.c +1166 -0
  46. data/ext/src/ichirvr6.c +1287 -0
  47. data/ext/src/ichirvr7.c +2319 -0
  48. data/ext/src/ichirvrs.h +882 -0
  49. data/ext/src/ichisize.h +2 -2
  50. data/ext/src/ichisort.c +5 -5
  51. data/ext/src/ichister.c +281 -86
  52. data/ext/src/ichister.h +9 -3
  53. data/ext/src/ichitaut.c +208 -9
  54. data/ext/src/ichitaut.h +13 -11
  55. data/ext/src/ichitime.h +16 -2
  56. data/ext/src/inchicmp.h +107 -0
  57. data/ext/src/inpdef.h +6 -3
  58. data/ext/src/libinchi_wrap.c +912 -0
  59. data/ext/src/lreadmol.h +34 -31
  60. data/ext/src/mode.h +244 -7
  61. data/ext/src/mol2atom.c +1060 -0
  62. data/ext/src/mol2atom.h +31 -0
  63. data/ext/src/readinch.c +239 -0
  64. data/ext/src/readmol.c +28 -0
  65. data/ext/src/{e_readmol.h → readmol.h} +7 -9
  66. data/ext/src/runichi.c +251 -177
  67. data/ext/src/strutil.c +444 -238
  68. data/ext/src/strutil.h +150 -11
  69. data/ext/src/util.c +176 -118
  70. data/ext/src/util.h +15 -3
  71. data/lib/rino.rb +71 -3
  72. data/test/test.rb +33 -4
  73. metadata +22 -34
  74. data/ext/ruby_inchi_main.so +0 -0
  75. data/ext/src/e_0dstereo.c +0 -3014
  76. data/ext/src/e_0dstereo.h +0 -31
  77. data/ext/src/e_comdef.h +0 -57
  78. data/ext/src/e_ctl_data.h +0 -147
  79. data/ext/src/e_ichi_io.c +0 -498
  80. data/ext/src/e_ichi_io.h +0 -40
  81. data/ext/src/e_ichi_parms.c +0 -37
  82. data/ext/src/e_ichi_parms.h +0 -41
  83. data/ext/src/e_ichicomp.h +0 -50
  84. data/ext/src/e_ichierr.h +0 -40
  85. data/ext/src/e_ichimain.c +0 -593
  86. data/ext/src/e_ichisize.h +0 -43
  87. data/ext/src/e_inchi_atom.c +0 -75
  88. data/ext/src/e_inchi_atom.h +0 -33
  89. data/ext/src/e_inpdef.h +0 -41
  90. data/ext/src/e_mode.h +0 -706
  91. data/ext/src/e_mol2atom.c +0 -649
  92. data/ext/src/e_readinch.c +0 -58
  93. data/ext/src/e_readmol.c +0 -54
  94. data/ext/src/e_readstru.c +0 -251
  95. data/ext/src/e_readstru.h +0 -33
  96. data/ext/src/e_util.c +0 -284
  97. data/ext/src/e_util.h +0 -61
  98. data/ext/src/ichilnct.c +0 -286
  99. data/ext/src/inchi_api.h +0 -670
  100. data/ext/src/inchi_dll.c +0 -1480
  101. data/ext/src/inchi_dll.h +0 -34
  102. data/ext/src/inchi_dll_main.c +0 -23
  103. data/ext/src/inchi_dll_main.h +0 -31
  104. data/ext/src/ruby_inchi_main.c +0 -558
@@ -0,0 +1,73 @@
1
+ /*
2
+ * International Union of Pure and Applied Chemistry (IUPAC)
3
+ * International Chemical Identifier (InChI)
4
+ * Version 1
5
+ * Software version 1.01
6
+ * July 21, 2006
7
+ * Developed at NIST
8
+ */
9
+
10
+ #ifndef __DISP_STRU_H__
11
+ #define __DISP_STRU_H__
12
+ #include <windows.h>
13
+
14
+ /* local types */
15
+ /*****************************************************/
16
+ typedef struct tagInternalDrawParms {
17
+ double xmin, xmax, ymin, ymax;
18
+ int max_label_width_char;
19
+ int max_left_label_width_pix;
20
+ int max_right_label_width_pix;
21
+ int bInit;
22
+ } INT_DRAW_PARMS; /* internal: saved for redisplaying one structure */
23
+
24
+
25
+ /*****************************************************
26
+ * Window data
27
+ */
28
+ typedef struct tagWindowData {
29
+
30
+ inp_ATOM *at0; /* [MAX_ATOMS]; */
31
+ inp_ATOM *at1; /* [MAX_ATOMS]; */
32
+ INF_ATOM_DATA inf_at_data;
33
+ /*inf_ATOM *inf_at;*/ /* [MAX_ATOMS]; */
34
+ int num_at;
35
+ int bOrigAtom;
36
+ int bHighlight;
37
+ int bEsc;
38
+ int bUserIntervened;
39
+ UINT nTimerId;
40
+
41
+ unsigned long ulDisplTime;
42
+ int nFontSize;
43
+ RECT rc; /* window rectangle size for saving */
44
+ INT_DRAW_PARMS idp; /* structure geom. parameters for redrawing */
45
+ TBL_DRAW_PARMS tdp; /* table data for displaying */
46
+ char *szTitle; /* for INCHI_LIB printing */
47
+
48
+ /* component equivalence info */
49
+ AT_NUMB *nEquLabels; /* num_at elements or NULL */
50
+ AT_NUMB nNumEquSets; /* number of equivalent sets or 0 */
51
+ AT_NUMB nCurEquLabel; /* in range 0..nNumEquSets; 0=>do not display equivalent components */
52
+
53
+ AT_NUMB nNewEquLabel; /* non-zero only if DISPLAY_EQU_COMPONENTS==1 */
54
+
55
+ } MY_WINDOW_DATA;
56
+
57
+ #ifndef INCHI_ALL_CPP
58
+ #ifdef __cplusplus
59
+ extern "C" {
60
+ #endif
61
+ #endif
62
+
63
+ void FreeWinData( MY_WINDOW_DATA* pWinData );
64
+ int CreateInputStructPicture( HDC hDC, MY_WINDOW_DATA *pWinData, RECT *rc, int bPrint, AT_NUMB nNewEquLabel );
65
+
66
+ #ifndef INCHI_ALL_CPP
67
+ #ifdef __cplusplus
68
+ }
69
+ #endif
70
+ #endif
71
+
72
+
73
+ #endif
@@ -2,8 +2,8 @@
2
2
  * International Union of Pure and Applied Chemistry (IUPAC)
3
3
  * International Chemical Identifier (InChI)
4
4
  * Version 1
5
- * Software version 1.00
6
- * April 13, 2005
5
+ * Software version 1.01
6
+ * July 21, 2006
7
7
  * Developed at NIST
8
8
  */
9
9
 
@@ -175,6 +175,9 @@ typedef struct tagAtom {
175
175
  #define BOND_MARK_ALT12NS 0x50 /* 1 or 2, non-stereo */
176
176
  #define BOND_MARK_MASK 0x70
177
177
 
178
+ #define ACTUAL_ORDER(PBNS, IAT,IBOND, BTYPE) ( ((PBNS) && (PBNS)->edge && (PBNS)->vert &&\
179
+ ((BTYPE)==BOND_ALT_123 || (BTYPE)==BOND_ALT_13 || (BTYPE)==BOND_ALT_23))? (PBNS)->edge[(PBNS)->vert[IAT].iedge[IBOND]].flow+BOND_TYPE_SINGLE:(BTYPE))
180
+
178
181
 
179
182
  #define BITS_PARITY 0x07 /* mask to retrieve half-bond parity */
180
183
  #define MASK_CUMULENE_LEN 0x38 /* mask to retrieve (cumulene chain length - 1)*MULT_STEREOBOND */
@@ -2,8 +2,8 @@
2
2
  * International Union of Pure and Applied Chemistry (IUPAC)
3
3
  * International Chemical Identifier (InChI)
4
4
  * Version 1
5
- * Software version 1.00
6
- * April 13, 2005
5
+ * Software version 1.01
6
+ * July 21, 2006
7
7
  * Developed at NIST
8
8
  */
9
9
 
@@ -12,8 +12,8 @@
12
12
 
13
13
  #include "comdef.h"
14
14
 
15
- #define REQ_MODE_BASIC 0x000001 /* B */
16
- #define REQ_MODE_TAUT 0x000002 /* T */
15
+ #define REQ_MODE_BASIC 0x000001 /* B include Fixed-H layer */
16
+ #define REQ_MODE_TAUT 0x000002 /* T include Mobile-H layer */
17
17
  #define REQ_MODE_ISO 0x000004 /* I */
18
18
  #define REQ_MODE_NON_ISO 0x000008 /* NI */
19
19
  #define REQ_MODE_STEREO 0x000010 /* S */
@@ -45,7 +45,7 @@
45
45
  /****************** chemical identifier member definitions *************/
46
46
  typedef struct tagINChI_IsotopicAtom {
47
47
  AT_NUMB nAtomNumber; /* Canonical atom number */
48
- NUM_H nIsoDifference; /* 0=non-isotopic; 1=only most abundant */
48
+ NUM_H nIsoDifference; /* 0=non-isotopic; 1=rounded avg. atomic mass */
49
49
  NUM_H nNum_H; /* number of 1H isotopic atoms attached */
50
50
  NUM_H nNum_D; /* number of 2H isotopic atoms attached */
51
51
  NUM_H nNum_T; /* number of 3H isotopic atoms attached */
@@ -98,6 +98,15 @@ typedef struct tagINChI_Stereo { /* [N] = allocated length */
98
98
  #define INCHI_OUT_XML_TEXT_COMMENTS 0x0100 /* output xml text annotation */
99
99
  #define INCHI_OUT_WINCHI_WINDOW 0x0200 /* output into wINChI text window */
100
100
  #define INCHI_OUT_TABBED_OUTPUT 0x0400 /* tab-delimited (only for plain text) */
101
+ #define INCHI_OUT_SDFILE_ATOMS_DT 0x0800 /* SDfile output H isotopes as D and T */
102
+ #define INCHI_OUT_SDFILE_SPLIT 0x1000 /* Split SDfile into components */
103
+
104
+ #define INCHI_OUT_PRINT_OPTIONS (INCHI_OUT_EMBED_REC | \
105
+ INCHI_OUT_XML | \
106
+ INCHI_OUT_PLAIN_TEXT | \
107
+ INCHI_OUT_PLAIN_TEXT_COMMENTS | \
108
+ INCHI_OUT_XML_TEXT_COMMENTS)
109
+
101
110
 
102
111
  /*******REQ_MODE_SB_IGN_ALL_UU*************** chemical identifier definition *****************/
103
112
  typedef struct tagINChI { /* [N] = allocated length */
@@ -131,6 +140,7 @@ typedef struct tagINChI { /* [N] = allocated length */
131
140
  int nNumberOfIsotopicAtoms;
132
141
  INChI_IsotopicAtom *IsotopicAtom; /* [nNumberOfIsotopicAtoms] */
133
142
  int nNumberOfIsotopicTGroups;
143
+ /* in reversing InChI keeps a pointer to stolen from AuxInfo coordinates */
134
144
  INChI_IsotopicTGroup *IsotopicTGroup; /* [nNumberOfIsotopicAtoms] */
135
145
  /* ---- stereo layer */
136
146
  INChI_Stereo *Stereo;
@@ -144,7 +154,9 @@ typedef struct tagINChI { /* [N] = allocated length */
144
154
  #if( bRELEASE_VERSION == 0 )
145
155
  int bExtract;
146
156
  #endif
147
-
157
+ #if( READ_INCHI_STRING == 1 )
158
+ int nLink; /* negative: ignore InChI; positive: index of (Reconnected component) + 1 linked to it */
159
+ #endif
148
160
  } INChI;
149
161
 
150
162
  typedef INChI *PINChI2[TAUT_NUM];
@@ -185,11 +197,12 @@ typedef struct tagINChI_Aux { /* [N] = allocated length */
185
197
  MOL_COORD *szOrigCoord;
186
198
  NUM_H nNumRemovedProtons;
187
199
  NUM_H nNumRemovedIsotopicH[NUM_H_ISOTOPES]; /* isotopic H that may be exchanged and considered
188
- randomly distributed, including removed protons */
200
+ randomly distributed, including removed protons;
201
+ order: 0=>1H, 1=>D, 2=>T */
189
202
  int bDeleted;
190
- INCHI_MODE bTautFlags;
191
- INCHI_MODE bTautFlagsDone;
192
- INCHI_MODE bNormalizationFlags;
203
+ INCHI_MODE bTautFlags; /* t_group_info->bTautFlags */
204
+ INCHI_MODE bTautFlagsDone; /* t_group_info->bTautFlagsDone */
205
+ INCHI_MODE bNormalizationFlags; /* t_group_info->tni.bNormalizationFlags */
193
206
  int nCanonFlags;
194
207
  } INChI_Aux;
195
208
 
@@ -199,7 +212,10 @@ typedef INChI_Aux *PINChI_Aux2[TAUT_NUM];
199
212
  typedef struct tagINChIforSort {
200
213
  INChI *pINChI[TAUT_NUM];
201
214
  INChI_Aux *pINChI_Aux[TAUT_NUM];
202
- int ord_number; /* for stable sort */
215
+ short ord_number; /* for stable sort */
216
+ short n1; /* points to the original; used in structure reconstruction only */
217
+ short n2; /* points to the original; used in structure reconstruction only */
218
+ short n3; /* points to the original; used in structure reconstruction only */
203
219
  }INCHI_SORT;
204
220
 
205
221
 
@@ -2,8 +2,8 @@
2
2
  * International Union of Pure and Applied Chemistry (IUPAC)
3
3
  * International Chemical Identifier (InChI)
4
4
  * Version 1
5
- * Software version 1.00
6
- * April 13, 2005
5
+ * Software version 1.01
6
+ * July 21, 2006
7
7
  * Developed at NIST
8
8
  */
9
9
 
@@ -28,8 +28,6 @@
28
28
 
29
29
  #define BNS_MARK_ONLY_BLOCKS 1 /* 1 => find only blocks, do not search for ring systems */
30
30
  #define ALLOW_ONLY_SIMPLE_ALT_PATH 0 /* 0 => allow alt. path to contain same bond 2 times (in opposite directions) */
31
- #define MAX_BOND_EDGE_CAP 2 /* triple bond */
32
- #define AROM_BOND_EDGE_CAP 1
33
31
 
34
32
  #define CHECK_TG_ALT_PATH 0 /* 1=> when chacking alt path of a tautomeric atom modify
35
33
  t-group, not the atom */
@@ -37,9 +35,7 @@
37
35
 
38
36
  #define FIX_CPOINT_BOND_CAP 1 /* 1=> fix bug in case of double bond from neutral cpoint */
39
37
 
40
- #define ADD_CAPACITY_RADICAL 1 /* add capacity to radical */
41
-
42
- #define RESET_EDGE_FORBIDDEN_MASK 1 /* 1: previous; 0: do not apply "dge->forbidden &= pBNS->edge_forbidden_mask" */
38
+ #define RESET_EDGE_FORBIDDEN_MASK 1 /* 1: previous; 0: do not apply "edge->forbidden &= pBNS->edge_forbidden_mask" */
43
39
  #if ( RESET_EDGE_FORBIDDEN_MASK == 1 )
44
40
  #define IS_FORBIDDEN(EDGE_FORBIDDEN, PBNS) (EDGE_FORBIDDEN)
45
41
  #else
@@ -219,23 +215,6 @@ typedef struct tagProtonRemovalMaskAndType {
219
215
  #define AA_HARD_MSK_H (ATBIT_MSK_NP | ATBIT_MSK_OS)
220
216
  #define AA_HARD_TYP_H (ATTYP_N | ATTYP_OS)
221
217
 
222
- /*********************************************************************************/
223
- #if( ADD_CAPACITY_RADICAL == 1 ) /* { */
224
- /* -- do not treat triplets as moving dots -- 2004-02-18 --
225
- #define MAX_AT_FLOW(X) (((X).chem_bonds_valence - (X).valence)+\
226
- ((is_centerpoint_elem((X).el_number)||get_endpoint_valence((X).el_number))?\
227
- (((X).radical==RADICAL_DOUBLET)+2*((X).radical==RADICAL_TRIPLET)):0))
228
- */
229
- #define MAX_AT_FLOW(X) (((X).chem_bonds_valence - (X).valence)+\
230
- ((is_centerpoint_elem((X).el_number)||get_endpoint_valence((X).el_number))?\
231
- (((X).radical==RADICAL_DOUBLET)/*+2*((X).radical==RADICAL_TRIPLET)*/):0))
232
-
233
-
234
- #else /* } ADD_CAPACITY_RADICAL { */
235
-
236
- #define MAX_AT_FLOW(X) (((X).chem_bonds_valence - (X).valence)
237
-
238
- #endif /* } ADD_CAPACITY_RADICAL */
239
218
 
240
219
  /*********************************************************************************/
241
220
 
@@ -247,9 +226,6 @@ typedef struct tagProtonRemovalMaskAndType {
247
226
  #define FIRST_INDX 1
248
227
  */
249
228
 
250
- #define NO_VERTEX -2
251
- #define BLOSSOM_BASE -1
252
-
253
229
 
254
230
  #define TREE_NOT_IN_M 0 /* not in T or T' */
255
231
  #define TREE_IN_2 1 /* in T' and not s-reachable */
@@ -261,83 +237,6 @@ typedef struct tagProtonRemovalMaskAndType {
261
237
  /* #define TREE_IS_ON_SCANQ(X) (Tree[X] != TREE_NOT_IN_M) */
262
238
  #define TREE_MARK(X, MARK) do{ if( Tree[X] < MARK ) Tree[X]=MARK; }while(0)
263
239
 
264
-
265
- #define BNS_ADD_ATOMS 2 /* max. number of fictitious atoms to add (except t-gtoups) */
266
- #define BNS_ADD_EDGES 1 /* max. number of edges to add to each atom (except edges to a t-group or c-group) */
267
- #define BNS_ADD_SUPER_TGROUP 1 /* reserve one more edge for a t-group to connect to a single super-t-group */
268
- #define NUM_KINDS_OF_GROUPS 2 /* 1 accounts for t-group kind, one more 1 accounts for c-group kind */
269
-
270
- #define BNS_VERT_TYPE_ATOM 0x0001
271
- #define BNS_VERT_TYPE_ENDPOINT 0x0002
272
- #define BNS_VERT_TYPE_TGROUP 0x0004
273
- #define BNS_VERT_TYPE_C_POINT 0x0008
274
- #define BNS_VERT_TYPE_C_GROUP 0x0010
275
- #define BNS_VERT_TYPE_SUPER_TGROUP 0x0020
276
- #define BNS_VERT_TYPE_TEMP 0x0040
277
- #define BNS_VERT_TYPE_C_NEGATIVE 0x0080 /* attribute, should be used with BNS_VERT_TYPE_C_GROUP */
278
- #define BNS_VERT_TYPE_ACID 0x0100 /* only for this type are allowed paths: t_group-atom-c_group_neg (path_TACN) */
279
- #define BNS_VERT_TYPE_ANY_GROUP (BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP | BNS_VERT_TYPE_SUPER_TGROUP)
280
-
281
- /*********************************************************************************
282
- bChangeFlow:
283
- 1 => change flow inside the BNS search
284
- 3 => change flow inside the BNS search and undo the flow change in the BNS structure here
285
- 4 => change bonds in the structure according to the flow
286
- 8 => make altern. bonds in the structure
287
-
288
- Note: (bChangeFlow & 1) == 1 is needed for multiple runs
289
- **********************************************************************************/
290
-
291
- /* "EF" = "Edge Flow" */
292
- #define BNS_EF_CHNG_FLOW 1 /* change Balanced Network (BN) flow inside the BNS search */
293
- #define BNS_EF_RSTR_FLOW 2 /* undo BN flow changes after BNS */
294
- #define BNS_EF_CHNG_RSTR (BNS_EF_CHNG_FLOW | BNS_EF_RSTR_FLOW)
295
- #define BNS_EF_CHNG_BONDS 4 /* change bonds in the structure according to the BN flow */
296
- #define BNS_EF_ALTR_BONDS 8 /* make altern. bonds in the structure if the flow has changed */
297
- #define BNS_EF_UPD_RAD_ORI 16 /* update BN flow0 & Atom radical values:
298
- flow0 := flow, radical:=st_cap - st_flow */
299
- #define BNS_EF_SET_NOSTEREO 32 /* in combination with BNS_EF_ALTR_BONDS only:
300
- ALT12 bond cannot be stereogenic */
301
- #define BNS_EF_UPD_H_CHARGE 64 /* update charges and H-counts according to change flow to c- and t-group vertices */
302
-
303
- #define BNS_EF_SAVE_ALL (BNS_EF_CHNG_FLOW | BNS_EF_CHNG_BONDS | BNS_EF_UPD_RAD_ORI)
304
- #define BNS_EF_ALTR_NS (BNS_EF_ALTR_BONDS | BNS_EF_SET_NOSTEREO)
305
-
306
- /* edge to s or t */
307
- #define EDGE_FLOW_ST_MASK 0x3fff /* mask for flow */
308
- #define EDGE_FLOW_ST_PATH 0x4000 /* mark: the edge belongs to the augmenting path */
309
- /* edges between other vertices */
310
- #define EDGE_FLOW_MASK 0x3f /* mask for flow */
311
- #define EDGE_FLOW_PATH 0x40 /* mark: the edge belongs to the augmenting path */
312
-
313
-
314
- typedef enum tagAltPathConst {
315
- iALTP_MAX_LEN, /* 0 */
316
- iALTP_FLOW, /* 1 */
317
- iALTP_PATH_LEN, /* 2 */
318
- iALTP_START_ATOM, /* 3 */
319
- iALTP_END_ATOM, /* 4 */
320
- iALTP_NEIGHBOR, /* 5 */
321
- iALTP_HDR_LEN = iALTP_NEIGHBOR
322
- } ALT_CONST;
323
-
324
- #define ALTP_PATH_LEN(altp) (altp)[iALTP_PATH_LEN].number /* number of bonds = number of atoms-1*/
325
- #define ALTP_END_ATOM(altp) (altp)[iALTP_END_ATOM].number
326
- #define ALTP_START_ATOM(altp) (altp)[iALTP_START_ATOM].number
327
- #define ALTP_THIS_ATOM_NEIGHBOR(altp,X) (altp)[iALTP_NEIGHBOR+(X)].ineigh[0] /* 0 <= X < path_len */
328
- #define ALTP_NEXT_ATOM_NEIGHBOR(altp,X) (altp)[iALTP_NEIGHBOR+(X)].ineigh[1]
329
- #define ALTP_CUR_THIS_ATOM_NEIGHBOR(altp) (altp)[iALTP_NEIGHBOR+ALTP_PATH_LEN(altp)].ineigh[0] /* 0 <= X < path_len */
330
- #define ALTP_CUR_NEXT_ATOM_NEIGHBOR(altp) (altp)[iALTP_NEIGHBOR+ALTP_PATH_LEN(altp)].ineigh[1]
331
- #define ALTP_NEXT(altp) (++ALTP_PATH_LEN(altp))
332
- #define ALTP_PREV(altp) (--ALTP_PATH_LEN(altp))
333
- #define ALTP_MAY_ADD(altp) (iALTP_NEIGHBOR + (altp)[iALTP_PATH_LEN].number < (altp)[iALTP_MAX_LEN].number)
334
- #define ALTP_ALLOCATED_LEN(altp) (altp)[iALTP_MAX_LEN].number
335
- #define ALTP_DELTA(altp) (altp)[iALTP_FLOW].flow[0]
336
- #define ALTP_OVERFLOW(altp) (altp)[iALTP_FLOW].flow[1]
337
-
338
- #define Vertex_s 0
339
- #define Vertex_t 1
340
-
341
240
  /**********************************************************************************
342
241
  * store changes done to check whether an alternating path exists
343
242
  * (see bSetBnsToCheckAltPath, bRestoreBnsAfterCheckAltPath)
@@ -357,20 +256,8 @@ typedef struct tagAltPathChanges {
357
256
 
358
257
  /* local functions */
359
258
 
360
- BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtoms, int nMaxAddEdges, int max_altp, int *num_changed_bonds );
361
- BN_STRUCT* DeAllocateBnStruct( BN_STRUCT *pBNS );
362
- int ReInitBnStructAltPaths( BN_STRUCT *pBNS );
363
- /*
364
- int ReInitBnStructAddGroups( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, T_GROUP_INFO *tgi, C_GROUP_INFO *cgi );
365
- */
366
- int ReInitBnStructForMoveableAltBondTest( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
367
-
368
- void ClearAllBnDataVertices( Vertex *v, Vertex value, int size );
369
- void ClearAllBnDataEdges( Edge *e, Vertex value, int size );
370
- BN_DATA *DeAllocateBnData( BN_DATA *pBD );
371
- BN_DATA *AllocateAndInitBnData( int max_num_vertices );
372
- int ReInitBnData( BN_DATA *pBD );
373
-
259
+ int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at );
260
+ int bRadChangesAtomType( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex v, Vertex v_1, Vertex v_2 );
374
261
  int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms );
375
262
  int SetAtomRadAndChemValFromVertexCapFlow( BN_STRUCT *pBNS, inp_ATOM *atom, int v1 );
376
263
  int bNeedToTestTheFlow( int bond_type, int nTestFlow, int bTestForNonStereoBond );
@@ -383,9 +270,9 @@ int CompTGroupNumber( const void *tg1, const void *tg2 );
383
270
  int CompCGroupNumber( const void *cg1, const void *cg2 );
384
271
 
385
272
  /* Rings, Blocks, Non-stereo bonds */
386
- int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
387
- int MarkRingSystemsAltBns( BN_STRUCT* pBNS );
388
- int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
273
+ int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
274
+ int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo );
275
+ int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo );
389
276
 
390
277
  /* called from BalancedNetworkSearch */
391
278
 
@@ -406,10 +293,6 @@ Vertex MakeBlossom( BN_STRUCT* pBNS, Vertex *ScanQ, int *pQSize,
406
293
  int PullFlow( BN_STRUCT *pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta, S_CHAR bReverse, int bChangeFlow );
407
294
  int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delta );
408
295
 
409
- /* main function: find augmenting path */
410
- int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow );
411
-
412
- int RunBalancedNetworkSearch( BN_STRUCT *pBNS, BN_DATA *pBD, int bChangeFlow );
413
296
 
414
297
  /*
415
298
  int SetBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, int delta, int bChangeFlow );
@@ -432,8 +315,7 @@ int bSetBondsAfterCheckOneBond( BN_STRUCT *pBNS, BNS_FLOW_CHANGES *fcd, int nTes
432
315
  int BnsTestAndMarkAltBonds( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms, BNS_FLOW_CHANGES *fcd, int bChangeFlow, int nBondTypeToTest );
433
316
  int bIsAltBond( int bond_type );
434
317
  /* fix bonds */
435
- int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
436
- int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
318
+ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int edge_forbidden_mask );
437
319
  int TempFix_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
438
320
  int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms );
439
321
 
@@ -444,6 +326,7 @@ int bRestoreBnsAfterCheckAltPath( BN_STRUCT *pBNS, ALT_PATH_CHANGES *apc, int bC
444
326
  Vertex GetGroupVertex(BN_STRUCT *pBNS, Vertex v1, AT_NUMB type);
445
327
  BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type);
446
328
  int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, int nMaxAdjEdges, int *nDots );
329
+ int AddNewEdge( BNS_VERTEX *p1, BNS_VERTEX *p2, BN_STRUCT *pBNS, int nEdgeCap, int nEdgeFlow );
447
330
  int bAddStCapToAVertex( BN_STRUCT *pBNS, Vertex v1, Vertex v2, VertexFlow *nOldCapVertSingleBond, int *nDots, int bAdjacentDonors );
448
331
 
449
332
  static void remove_alt_bond_marks(inp_ATOM *at, int num_atoms);
@@ -479,11 +362,20 @@ int RemoveNPProtonsAndAcidCharges( inp_ATOM *at, int num_atoms, BN_AATG *pAATG,
479
362
  Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv );
480
363
  int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v );
481
364
  int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
365
+ int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v );
366
+ int bIsAggressiveDeprotonation( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge );
482
367
 
483
368
  int bIsAtomTypeHard( inp_ATOM *at, int endpoint, int nType, int nMask, int nCharge );
484
369
  int bIsHDonorAccAtomType( inp_ATOM *at, int endpoint, int *cSubType );
485
370
  int bIsNegAtomType( inp_ATOM *at, int i, int *cSubType );
486
371
 
372
+ #if ( BNS_RAD_SEARCH == 1 )
373
+ int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u);
374
+ int cmp_rad_endpoints( const void *a1, const void *a2 );
375
+ int cmp_endpoints_rad( const void *a1, const void *a2 );
376
+ #endif
377
+
378
+ int bHasChargedNeighbor( inp_ATOM *at, int iat );
487
379
  /*********************************************************************************/
488
380
 
489
381
  /**** prim(v) is v' *****/
@@ -502,7 +394,6 @@ int bIsNegAtomType( inp_ATOM *at, int i, int *cSubType );
502
394
  /* returns value > 0 if a bond has been changed */
503
395
  int RestoreEdgeFlow( BNS_EDGE *edge, int delta, int bChangeFlow )
504
396
  {
505
-
506
397
  /*flow1 = edge->flow;*/ /* output from BNS */
507
398
  switch ( bChangeFlow & BNS_EF_CHNG_RSTR ) {
508
399
  case 0: /* the flow has not been permitted to change inside the BNS */
@@ -550,6 +441,8 @@ int SetAtomBondType( BNS_EDGE *edge, U_CHAR *bond_type12, U_CHAR *bond_type21, i
550
441
  flow2 = edge->flow; /* output from BNS, the changed (new) value */
551
442
  flow1 = edge->flow0; /* the original flow (old) value before the BNS */
552
443
  break;
444
+ default:
445
+ return 0; /* added 2006-03-21 */
553
446
  }
554
447
 
555
448
  if ( (bChangeFlow & BNS_EF_CHNG_BONDS) && (bChangeFlow & BNS_EF_ALTR_NS) !=BNS_EF_ALTR_NS ) {
@@ -745,7 +638,12 @@ int AddChangedAtHChargeBNS( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], S_
745
638
  for ( i = 0, num = 0; i < num_atoms; i ++ ) {
746
639
  if ( mark[i] ) {
747
640
  mark[i] = 0;
641
+ #if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
642
+ /* add ignoring adjacent charges */
643
+ at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, -2 );
644
+ #else
748
645
  at[i].at_type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 );
646
+ #endif
749
647
  num ++;
750
648
  }
751
649
  }
@@ -1014,7 +912,11 @@ int SubtractOrChangeAtHChargeBNS( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms,
1014
912
  if ( bSubtract ) {
1015
913
  if ( !mark[v1] ) {
1016
914
  /* first time the atom has been encountered: subtract */
915
+ #if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
916
+ type = GetAtomChargeType( at, v1, nAtTypeTotals, &mask, 2 );
917
+ #else
1017
918
  type = GetAtomChargeType( at, v1, nAtTypeTotals, &mask, 1 );
919
+ #endif
1018
920
  ret ++; /* number of changed atoms */
1019
921
  mark[v1] ++;
1020
922
  }
@@ -1410,14 +1312,68 @@ int bNeedToTestTheFlow( int bond_type, int nTestFlow, int bTestForNonStereoBond
1410
1312
  }
1411
1313
  return 1;
1412
1314
  }
1413
-
1315
+ /***********************************************************************************/
1316
+ int nBondsValenceInpAt( const inp_ATOM *at, int *nNumAltBonds, int *nNumWrongBonds )
1317
+ {
1318
+ int j, bond_type, nBondsValence = 0, nAltBonds = 0, nNumWrong = 0;
1319
+ for ( j = 0; j < at->valence; j ++ ) {
1320
+ bond_type = at->bond_type[j] & BOND_TYPE_MASK;
1321
+ switch( bond_type ) {
1322
+ case 0: /* for structure from InChI reconstruction */
1323
+ case BOND_SINGLE:
1324
+ case BOND_DOUBLE:
1325
+ case BOND_TRIPLE:
1326
+ nBondsValence += bond_type;
1327
+ break;
1328
+ case BOND_ALTERN:
1329
+ nAltBonds ++;
1330
+ break;
1331
+ default:
1332
+ nNumWrong ++;
1333
+ }
1334
+ }
1335
+ switch ( nAltBonds ) {
1336
+ case 0:
1337
+ break;
1338
+ case 1:
1339
+ nBondsValence += 1; /* 1 or greater than 3 is wrong */
1340
+ nNumWrong ++;
1341
+ break;
1342
+ default:
1343
+ nBondsValence += nAltBonds+1;
1344
+ break;
1345
+ }
1346
+ if ( nNumAltBonds ) *nNumAltBonds = nAltBonds;
1347
+ if ( nNumWrongBonds ) *nNumWrongBonds = nNumWrong;
1348
+ return nBondsValence;
1349
+ }
1414
1350
  /***************************************************************************************/
1415
1351
  /* if radical or has aromatic bonds then augment to the lowest "multiplicity" */
1416
1352
  int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_atoms )
1417
1353
  {
1418
- int bError, nOrigDelta, ret, num_removed;
1419
- bError = 0;
1420
- nOrigDelta = 0;
1354
+ int bError=0, nOrigDelta=0, ret, num_removed;
1355
+
1356
+ #if( CHECK_AROMBOND2ALT == 1 )
1357
+ char *pcValMinusBondsVal = NULL;
1358
+ int i, nValMinusBondsVal, nAltBonds, bIgnore;
1359
+
1360
+ /* find valence excess (it may only be due to aromatic bonds) */
1361
+ for ( i = 0; i < num_atoms; i ++ ) {
1362
+ nValMinusBondsVal = (int)at[i].chem_bonds_valence - nBondsValenceInpAt( at+i, &nAltBonds, &bIgnore );
1363
+ bIgnore += (nAltBonds > 3);
1364
+ if ( !bIgnore && nValMinusBondsVal > 0 ) {
1365
+ if ( !pcValMinusBondsVal &&
1366
+ !(pcValMinusBondsVal = (char *)inchi_calloc(num_atoms, sizeof(pcValMinusBondsVal[0])))) {
1367
+ bError = BNS_OUT_OF_RAM;
1368
+ goto exit_function;
1369
+ }
1370
+ /* mark atoms that have extra unsatisfied valence due to aromatic bonds */
1371
+ pcValMinusBondsVal[i] = nValMinusBondsVal + (at[i].radical == RADICAL_DOUBLET);
1372
+ }
1373
+ }
1374
+ #endif /* CHECK_AROMBOND2ALT */
1375
+
1376
+ /* match bonds to valences */
1421
1377
  do {
1422
1378
  num_removed = 0;
1423
1379
  ret = RunBalancedNetworkSearch( pBNS, pBD, BNS_EF_CHNG_FLOW );
@@ -1440,6 +1396,27 @@ int BnsAdjustFlowBondsRad( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at, int num_
1440
1396
  ReInitBnStructAltPaths( pBNS );
1441
1397
  }
1442
1398
  } while ( num_removed && num_removed == pBNS->max_altp && !bError );
1399
+
1400
+ #if( CHECK_AROMBOND2ALT == 1 )
1401
+ /* check whether aromatic bonds have been replaces with alternating bonds */
1402
+ if ( !bError && pcValMinusBondsVal ) {
1403
+ for ( i = 0; i < num_atoms; i ++ ) {
1404
+ if ( !pcValMinusBondsVal[i] )
1405
+ continue;
1406
+ nValMinusBondsVal = (int)at[i].chem_bonds_valence - nBondsValenceInpAt( at+i, &nAltBonds, &bIgnore );
1407
+ if ( bIgnore ||
1408
+ 1 != (int)pcValMinusBondsVal[i] - (nValMinusBondsVal + (at[i].radical == RADICAL_DOUBLET)) ) {
1409
+ /* radical excess has not been reduced */
1410
+ bError = BNS_ALTBOND_ERR;
1411
+ break;
1412
+ }
1413
+ }
1414
+ }
1415
+
1416
+ exit_function:
1417
+ if ( pcValMinusBondsVal ) inchi_free( pcValMinusBondsVal );
1418
+ #endif /* CHECK_AROMBOND2ALT */
1419
+
1443
1420
  return bError? bError : nOrigDelta;
1444
1421
  }
1445
1422
 
@@ -1551,7 +1528,7 @@ static void remove_alt_bond_marks(inp_ATOM *at, int num_atoms)
1551
1528
  }
1552
1529
  }
1553
1530
  /***************************************************************************************/
1554
- int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1531
+ int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int forbidden_mask )
1555
1532
  {
1556
1533
  static U_CHAR el_number_O;
1557
1534
  static U_CHAR el_number_C;
@@ -1559,9 +1536,10 @@ int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1559
1536
 
1560
1537
  int i, j, neigh, num_found;
1561
1538
  BNS_IEDGE iedge;
1562
- S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;
1539
+ /*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
1540
+ S_CHAR edge_forbidden_mask = forbidden_mask;
1563
1541
 
1564
- pBNS->edge_forbidden_mask |= edge_forbidden_mask;
1542
+ pBNS->edge_forbidden_mask |= forbidden_mask;
1565
1543
 
1566
1544
  if ( !el_number_C ) {
1567
1545
  el_number_O = (U_CHAR)get_periodic_table_number( "O" );
@@ -1623,7 +1601,7 @@ int SetForbiddenEdges( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1623
1601
  }
1624
1602
  }
1625
1603
  #if ( REMOVE_ION_PAIRS_FIX_BONDS == 1 )
1626
- num_found += fix_special_bonds( pBNS, at, num_atoms );
1604
+ num_found += fix_special_bonds( pBNS, at, num_atoms, edge_forbidden_mask );
1627
1605
  #endif
1628
1606
  #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
1629
1607
  num_found += TempFix_NH_NH_Bonds( pBNS, at, num_atoms );
@@ -1696,12 +1674,16 @@ int CorrectFixing_NH_NH_Bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1696
1674
  #endif
1697
1675
  /************************************************************************/
1698
1676
  /* fixes bonds set by remove_ion_pairs() in strutil.c */
1699
- int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1677
+ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int forbidden_mask )
1700
1678
  {
1701
1679
  int num_changes = 0;
1702
1680
 
1703
1681
  /* 0 1 2 3 4 5 6 7 8 9 8 9 */
1682
+ #if( FIX_REM_ION_PAIRS_Si_BUG == 1 )
1683
+ static const char el[] = "N;P;As;Sb;O;S;Se;Te;C;Si;"; /* 8 elements + C, Si */
1684
+ #else
1704
1685
  static const char el[] = "N;P;As;Sb;O;S;Se;Te;C;Si"; /* 8 elements + C, Si */
1686
+ #endif
1705
1687
  static char en[12]; /* same number: 8 elements */
1706
1688
  static int ne=0; /* will be 8 and 10 */
1707
1689
 
@@ -1722,7 +1704,8 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1722
1704
  int j[3], m[3], num_O, k_O, num_N, num_OH, num_OM, num_X, num_other, k_N;
1723
1705
 
1724
1706
  BNS_IEDGE iedge;
1725
- S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;
1707
+ /*S_CHAR edge_forbidden_mask = BNS_EDGE_FORBIDDEN_MASK;*/
1708
+ S_CHAR edge_forbidden_mask = forbidden_mask;
1726
1709
 
1727
1710
  pBNS->edge_forbidden_mask |= edge_forbidden_mask;
1728
1711
 
@@ -1735,7 +1718,8 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1735
1718
  elname[len] = '\0';
1736
1719
  en[ne++] = get_periodic_table_number( elname );
1737
1720
  }
1738
- en[ne] = '\0';
1721
+ en[ne] = '\0';
1722
+ en[ne+1] = '\0';
1739
1723
  }
1740
1724
  for ( i = 0, a = at; i < num_atoms; i ++, a++ ) {
1741
1725
  if ( !a->charge && !a->radical &&
@@ -1747,15 +1731,25 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1747
1731
  if ( 2 == nNoMetalNumBonds(at, i) ) {
1748
1732
  /* #N= */
1749
1733
  /* fix bonds: double and triple: =N# so that bonds cannot be changed by the normalization */
1734
+ #if( FIX_N_V_METAL_BONDS_GPF == 1 )
1735
+ if ( 0 > (i1 = nNoMetalNeighIndex( at, i )) ||
1736
+ 0 > (i2 = nNoMetalOtherNeighIndex( at, i,
1737
+ n1 = a->neighbor[i1]/* non-metal neighbor #1 */ ) ) ) {
1738
+ /*num_err ++; */ /* do not count would-be original InChI v.1 buffer overflow GPF */
1739
+ continue; /* v1 bug: 2 bonds to metal yield i1 < 0 and/or i2 < 0 => bounds violation */
1740
+ }
1741
+ #else
1750
1742
  i1 = nNoMetalNeighIndex( at, i );
1751
1743
  n1 = a->neighbor[i1]; /* non-metal neighbor #1 */
1752
1744
  i2 = nNoMetalOtherNeighIndex( at, i, n1 );
1745
+ #endif
1753
1746
  n2 = a->neighbor[i2]; /* non-metal neighbor #2 */
1754
1747
  /* forbid all edges to non-metals */
1755
1748
  iedge = pBNS->vert[i].iedge[i1];
1756
1749
  pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
1757
1750
  iedge = pBNS->vert[i].iedge[i2];
1758
1751
  pBNS->edge[iedge].forbidden |= edge_forbidden_mask; /* fix bond to neighbor #1 */
1752
+ num_changes ++; /* added 11-15-2005 */
1759
1753
  /* i n3 */
1760
1754
  /* forbid single bond edge beyond the neighboring =N- as in #N=N- */
1761
1755
  if ( (at[i].bond_type[i1] & BOND_TYPE_MASK) == BOND_TYPE_DOUBLE ) {
@@ -1823,7 +1817,7 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1823
1817
  } else
1824
1818
  if ( 4 == nNoMetalNumBonds(at, i) ) {
1825
1819
  /* | */
1826
- /* found -N= */
1820
+ /* found -N=N- */
1827
1821
  /* | */
1828
1822
  /* locate non-metal neighbor connected by a double bond;
1829
1823
  * if it is =N- then fix the double bond and the single bond beyond the neighbor
@@ -1852,7 +1846,6 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
1852
1846
  iedge = pBNS->vert[i].iedge[i2];
1853
1847
  pBNS->edge[iedge].forbidden |= edge_forbidden_mask;
1854
1848
  num_changes ++;
1855
- num_changes ++;
1856
1849
  }
1857
1850
  }
1858
1851
  } else
@@ -2152,8 +2145,6 @@ int fix_special_bonds( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
2152
2145
  }
2153
2146
  }
2154
2147
  }
2155
-
2156
-
2157
2148
  return num_changes;
2158
2149
  }
2159
2150
 
@@ -2267,7 +2258,12 @@ int GetAtomChargeType( inp_ATOM *atom, int at_no, int nAtTypeTotals[], int *pMas
2267
2258
  static U_CHAR el_number_I = 0;
2268
2259
 
2269
2260
  inp_ATOM *at = atom + at_no;
2261
+ #if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2262
+ int i, neigh, mask, bit, type, num_z, num_m, num_o, delta = bSubtract > 0 ? -1 : 1; /* 0 or -2 => add, 1 or 2 => subtract */
2263
+ int bNoAdjIon = (bSubtract==0 || bSubtract==1);
2264
+ #else
2270
2265
  int i, neigh, mask, bit, type, num_z, num_m, num_o, delta = bSubtract? -1 : 1;
2266
+ #endif
2271
2267
  int bUnsatNHasTerminalO = 0;
2272
2268
  if ( !el_number_C ) {
2273
2269
  el_number_C = (U_CHAR)get_periodic_table_number( "C" );
@@ -2339,9 +2335,23 @@ int GetAtomChargeType( inp_ATOM *atom, int at_no, int nAtTypeTotals[], int *pMas
2339
2335
  /* check neighbors */
2340
2336
  for ( i = 0, num_z = 0, num_m = 0, num_o = 0; i < at->valence; i ++ ) {
2341
2337
  neigh = at->neighbor[i];
2338
+ #if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2339
+ if ( atom[neigh].charge < -1 || atom[neigh].charge > 1 ) {
2340
+ goto exit_function; /* neighboring charge */
2341
+ }
2342
+ if ( atom[neigh].charge && at->charge ) {
2343
+ if ( bNoAdjIon ) {
2344
+ goto exit_function; /* neighboring charge */
2345
+ }
2346
+ type = ATT_NONE;
2347
+ mask = 0;
2348
+ goto count_mask_bits;
2349
+ }
2350
+ #else
2342
2351
  if ( atom[neigh].charge < -1 || atom[neigh].charge > 1 || atom[neigh].charge && at->charge ) {
2343
2352
  goto exit_function; /* neighboring charge */
2344
2353
  }
2354
+ #endif
2345
2355
  if ( detect_unusual_el_valence( atom[neigh].el_number, atom[neigh].charge, atom[neigh].radical,
2346
2356
  atom[neigh].chem_bonds_valence, atom[neigh].num_H,
2347
2357
  atom[neigh].valence ) ) {
@@ -2634,7 +2644,11 @@ int SimpleRemoveHplusNPO( inp_ATOM *at, int num_atoms, int nAtTypeTotals[], T_GR
2634
2644
  AddOrRemoveExplOrImplH( -1, at, num_atoms, (AT_NUMB)i, t_group_info );
2635
2645
  /*at[i].num_H --;*/
2636
2646
  num_removed ++;
2637
- type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* add changed at[i] */
2647
+ #if( FIX_NORM_BUG_ADD_ION_PAIR == 1 )
2648
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
2649
+ #else
2650
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* bug: subtract instead of add */
2651
+ #endif
2638
2652
  /*
2639
2653
  if ( nAtTypeTotals ) {
2640
2654
  nAtTypeTotals[ATTOT_NUM_NP_Proton] --;
@@ -2876,9 +2890,9 @@ int CreateCGroupInBnStruct( inp_ATOM *at, int num_atoms,
2876
2890
  for ( k = 0; k < vertex_cpoint->num_adj_edges; k ++ ) {
2877
2891
  int iedge = vertex_cpoint->iedge[k];
2878
2892
  VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
2893
+ centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
2879
2894
  if ( !pBNS->edge[iedge].cap ) {
2880
2895
  /* single bond, possibly between c_point and centerpoint */
2881
- centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
2882
2896
  if ( centerpoint < pBNS->num_atoms &&
2883
2897
  pBNS->vert[centerpoint].st_edge.cap >= 1 ) {
2884
2898
  nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
@@ -2886,6 +2900,13 @@ int CreateCGroupInBnStruct( inp_ATOM *at, int num_atoms,
2886
2900
  pBNS->edge[iedge].cap = nNewCap;
2887
2901
  }
2888
2902
  }
2903
+ #if( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
2904
+ else
2905
+ if ( centerpoint < pBNS->num_atoms &&
2906
+ edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP ) {
2907
+ pBNS->edge[iedge].cap ++;
2908
+ }
2909
+ #endif
2889
2910
  }
2890
2911
  #endif /* } FIX_CPOINT_BOND_CAP */
2891
2912
  /* connect edge to c_point and fictpoint and increment the counters of neighbors and edges */
@@ -3451,7 +3472,11 @@ int HardRemoveAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int nu
3451
3472
  }
3452
3473
 
3453
3474
  if ( nNumCanceledCharges ) {
3475
+ #if( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
3476
+ *nNumCanceledCharges += 2*nNumNeutralized;
3477
+ #else
3454
3478
  *nNumCanceledCharges = 2*nNumNeutralized;
3479
+ #endif
3455
3480
  }
3456
3481
 
3457
3482
  return nNumMoved2AcidH;
@@ -3604,7 +3629,11 @@ int HardAddAcidicProtons( inp_ATOM *at, int num_atoms, BN_AATG *pAATG, int num2a
3604
3629
  }
3605
3630
 
3606
3631
  if ( nNumCanceledCharges ) {
3632
+ #if( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
3633
+ *nNumCanceledCharges += 2*nNumNeutralized;
3634
+ #else
3607
3635
  *nNumCanceledCharges = 2*nNumNeutralized;
3636
+ #endif
3608
3637
  }
3609
3638
 
3610
3639
  return nNumMoved2AcidMinus;
@@ -3622,6 +3651,9 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
3622
3651
  int tg_H = 0;
3623
3652
  #if ( MOVE_PPLUS_TO_REMOVE_PROTONS == 1 )
3624
3653
  int cg_PlusP = 0;
3654
+ #endif
3655
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3656
+ int nPrevRemovedProtons, nCurrRemovedProtons;
3625
3657
  #endif
3626
3658
  int ret = 0, ret2;
3627
3659
  int nDelta, nNumChanges = 0, nNumRemovedProtons = 0, nNumNeutralized = 0, nPrevNumCharges;
@@ -3664,15 +3696,59 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
3664
3696
  tg_H = CreateTGroupInBnStruct( at, num_atoms, pBNS, PR_HARD_TYP_H, PR_HARD_MSK_H );
3665
3697
 
3666
3698
  if ( tg_H >= num_atoms && cg_Plus >= num_atoms ) {
3699
+
3700
+ #if( FIX_N_MINUS_NORN_BUG == 1 )
3701
+ /* neutralize: remove ion pairs like >N(+)=-O(-) => >N-=O; >N(+)=-NH(-) => >N-=NH */
3702
+ if ( (nNumRemovedProtons || bCancelChargesAlways) && cg_Minus >= num_atoms && cg_Plus >= num_atoms &&
3703
+ pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs(pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE]) ) {
3704
+ do {
3705
+ nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
3706
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3707
+ nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
3708
+ #endif
3709
+ ret = bExistsAltPath( pBNS, pBD, pAATG, at, num_atoms,
3710
+ cg_Minus /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
3711
+ if ( IS_BNS_ERROR( ret ) ) {
3712
+ return ret;
3713
+ }
3714
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3715
+ nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
3716
+ if ( nCurrRemovedProtons != nPrevRemovedProtons ) {
3717
+ return BNS_RADICAL_ERR;
3718
+ }
3719
+ #endif
3720
+ if ( ret & 1 ) {
3721
+ nDelta = (ret & ~3) >> 2;
3722
+ nNumChanges += (0 != (ret & 2));
3723
+ if ( nDelta ) {
3724
+ /* radical pair has disappeared */
3725
+ ; /* goto quick_exit;*/
3726
+ }
3727
+ if ( nPrevNumCharges > pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] ) {
3728
+ nNumNeutralized += (nPrevNumCharges - pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES])/2;
3729
+ }
3730
+ }
3731
+ } while ( ret & 1 );
3732
+ }
3733
+ #endif
3667
3734
  /* find alt path to remove one proton */
3668
3735
  do {
3669
3736
  /* remove a proton */
3670
3737
  nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
3738
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3739
+ nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
3740
+ #endif
3671
3741
  ret = bExistsAltPath( pBNS, pBD, pAATG, at, num_atoms,
3672
3742
  tg_H /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
3673
3743
  if ( IS_BNS_ERROR( ret ) ) {
3674
3744
  return ret;
3675
3745
  }
3746
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3747
+ nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
3748
+ if ( nCurrRemovedProtons != nPrevRemovedProtons + (ret & 1) ) {
3749
+ return BNS_RADICAL_ERR;
3750
+ }
3751
+ #endif
3676
3752
  if ( ret & 1 ) {
3677
3753
  nDelta = (ret & ~3) >> 2;
3678
3754
  nNumChanges += (0 != (ret & 2));
@@ -3693,11 +3769,20 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
3693
3769
  pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES] > abs(pAATG->nAtTypeTotals[ATTOT_TOT_CHARGE]) ) {
3694
3770
  do {
3695
3771
  nPrevNumCharges = pAATG->nAtTypeTotals[ATTOT_NUM_CHARGES];
3772
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3773
+ nPrevRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
3774
+ #endif
3696
3775
  ret = bExistsAltPath( pBNS, pBD, pAATG, at, num_atoms,
3697
3776
  cg_Minus /*nVertDoubleBond*/, cg_Plus /*nVertSingleBond*/, ALT_PATH_MODE_REM_PROTON );
3698
3777
  if ( IS_BNS_ERROR( ret ) ) {
3699
3778
  return ret;
3700
3779
  }
3780
+ #if ( FIX_REM_PROTON_COUNT_BUG == 1 )
3781
+ nCurrRemovedProtons = pAATG->t_group_info->tni.nNumRemovedProtons;
3782
+ if ( nCurrRemovedProtons != nPrevRemovedProtons ) {
3783
+ return BNS_RADICAL_ERR;
3784
+ }
3785
+ #endif
3701
3786
  if ( ret & 1 ) {
3702
3787
  nDelta = (ret & ~3) >> 2;
3703
3788
  nNumChanges += (0 != (ret & 2));
@@ -3761,7 +3846,11 @@ int HardRemoveHplusNP( inp_ATOM *at, int num_atoms, int bCancelChargesAlways, in
3761
3846
  }
3762
3847
 
3763
3848
  if ( nNumCanceledCharges ) {
3849
+ #if( FIX_CANCEL_CHARGE_COUNT_BUG == 1 )
3850
+ *nNumCanceledCharges += 2*nNumNeutralized;
3851
+ #else
3764
3852
  *nNumCanceledCharges = 2*nNumNeutralized;
3853
+ #endif
3765
3854
  }
3766
3855
 
3767
3856
  return nNumRemovedProtons;
@@ -3986,7 +4075,7 @@ int mark_alt_bonds_and_taut_groups ( inp_ATOM *at, inp_ATOM *at_fixed_bonds_out,
3986
4075
  /*
3987
4076
  again:
3988
4077
  */
3989
- /* allocate Balanced Network Data Strucures */
4078
+ /* allocate Balanced Network Data Strucures; replace Alternating bonds with Single */
3990
4079
  if ( (pBNS = AllocateAndInitBnStruct( at, num_atoms, BNS_ADD_ATOMS, BNS_ADD_EDGES, max_altp, &num_changed_bonds )) &&
3991
4080
  (pBD = AllocateAndInitBnData( pBNS->max_vertices )) ) {
3992
4081
 
@@ -3995,7 +4084,7 @@ again:
3995
4084
 
3996
4085
  #if( BNS_PROTECT_FROM_TAUT == 1 )
3997
4086
  /* protect bonds to acetyl and nitro */
3998
- SetForbiddenEdges( pBNS, at, num_atoms );
4087
+ SetForbiddenEdges( pBNS, at, num_atoms, BNS_EDGE_FORBIDDEN_MASK );
3999
4088
  #endif
4000
4089
  /* set bonds in case of input "aromatic" bonds or multiple radicals */
4001
4090
  ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
@@ -4042,6 +4131,11 @@ again:
4042
4131
  #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
4043
4132
  pBNS->edge_forbidden_mask |= BNS_EDGE_FORBIDDEN_TEMP;
4044
4133
  #endif
4134
+ /***********************************************************/
4135
+ /* */
4136
+ /* ( D E ) P R O T O N A T I O N */
4137
+ /* */
4138
+ /***********************************************************/
4045
4139
  ret = RemoveNPProtonsAndAcidCharges( at, num_atoms, pAATG, pBNS, pBD );
4046
4140
  #if ( RESET_EDGE_FORBIDDEN_MASK == 0 )
4047
4141
  pBNS->edge_forbidden_mask &= ~BNS_EDGE_FORBIDDEN_TEMP;
@@ -4088,6 +4182,8 @@ again:
4088
4182
  *pbTautFlagsDone |= TG_FLAG_MOVE_POS_CHARGES_DONE;
4089
4183
  }
4090
4184
  } while ( ret > 0 );
4185
+ #if( BNS_RAD_SEARCH == 1 )
4186
+ #else
4091
4187
  /* moveable charges may allow to cancel radicals -- check it */
4092
4188
  if ( pBNS->tot_st_cap > pBNS->tot_st_flow ) {
4093
4189
  ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
@@ -4108,6 +4204,7 @@ again:
4108
4204
  goto exit_function;
4109
4205
  }
4110
4206
  }
4207
+ #endif
4111
4208
  }
4112
4209
  /************************************************************************/
4113
4210
  /******** test bonds for bond tautomerism **************/
@@ -4156,6 +4253,8 @@ again:
4156
4253
  bError = ret;
4157
4254
  goto exit_function;
4158
4255
  }
4256
+ #if( BNS_RAD_SEARCH == 1 )
4257
+ #else
4159
4258
  /* discovered moveable charges and H-atoms may allow to cancel radicals */
4160
4259
  if ( pBNS->tot_st_cap > pBNS->tot_st_flow ) {
4161
4260
  ret = BnsAdjustFlowBondsRad( pBNS, pBD, at, num_atoms );
@@ -4176,7 +4275,7 @@ again:
4176
4275
  goto exit_function;
4177
4276
  }
4178
4277
  }
4179
-
4278
+ #endif
4180
4279
  /****************** update bonds normalization ***************/
4181
4280
  if ( *pbTautFlags & TG_FLAG_MOVE_POS_CHARGES ) {
4182
4281
  /******************* find moveable charges ***************/
@@ -4346,9 +4445,16 @@ again:
4346
4445
  * and mark non-ring alt bonds non-stereogenic
4347
4446
  ************************************************/
4348
4447
 
4349
- ReInitBnStructForAltBns( pBNS, at, num_atoms );
4350
- MarkRingSystemsAltBns( pBNS );
4351
- MarkNonStereoAltBns( pBNS, at, num_atoms );
4448
+ ReInitBnStructForAltBns( pBNS, at, num_atoms, 0 );
4449
+ MarkRingSystemsAltBns( pBNS, 0 );
4450
+ MarkNonStereoAltBns( pBNS, at, num_atoms, 0 );
4451
+ #if( FIX_EITHER_DB_AS_NONSTEREO == 1 )
4452
+ /* second time unknown ("Either") alternating bonds are treated as non-stereogenic */
4453
+ /* stereobonds bonds that lost stereo get "Either" stereo_type */
4454
+ ReInitBnStructForAltBns( pBNS, at, num_atoms, 1 );
4455
+ MarkRingSystemsAltBns( pBNS, 1 );
4456
+ MarkNonStereoAltBns( pBNS, at, num_atoms, 1 );
4457
+ #endif
4352
4458
  } else {
4353
4459
  bError = BNS_OUT_OF_RAM;
4354
4460
  /*printf("BNS_OUT_OF_RAM-3\n");*/
@@ -4812,7 +4918,9 @@ int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, in
4812
4918
  if ( (pBNS->vert[vlast].iedge - pBNS->iedge) + pBNS->vert[vlast].max_adj_edges + nMaxAdjEdges >= pBNS->max_iedges ) {
4813
4919
  return BNS_VERT_EDGE_OVFL; /* iedges overflow */
4814
4920
  }
4815
-
4921
+ if ( pVert2->num_adj_edges >= pVert2->max_adj_edges || nMaxAdjEdges <= 0 ) {
4922
+ return BNS_VERT_EDGE_OVFL; /* neighbors overflow */
4923
+ }
4816
4924
  /* fill out the new edge, set its cap and flow, connect */
4817
4925
  /* memset( pEdge, 0, sizeof(*pEdge) ); */
4818
4926
  pEdge->cap = pEdge->cap0 = nCap;
@@ -4827,12 +4935,13 @@ int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, in
4827
4935
  pNewVert->num_adj_edges = 0;
4828
4936
  pNewVert->st_edge.cap0 = pNewVert->st_edge.cap = nCap;
4829
4937
  pNewVert->st_edge.flow0 = pNewVert->st_edge.flow = nFlow;
4938
+ pNewVert->st_edge.pass = 0; /* add initialization; added 2006-03-25 */
4830
4939
  pNewVert->iedge = pBNS->vert[vlast].iedge + pBNS->vert[vlast].max_adj_edges;
4831
4940
  pNewVert->type = BNS_VERT_TYPE_TEMP;
4832
4941
  *nDots += nCap - nFlow;
4833
4942
 
4834
- pEdge->neigh_ord[0] = pVert2->num_adj_edges;
4835
- pEdge->neigh_ord[1] = pNewVert->num_adj_edges;
4943
+ pEdge->neigh_ord[v2>vnew] = pVert2->num_adj_edges;
4944
+ pEdge->neigh_ord[v2<vnew] = pNewVert->num_adj_edges;
4836
4945
 
4837
4946
  /* connect new edge to v2 */
4838
4947
  pVert2->iedge[pVert2->num_adj_edges ++] = iedge;
@@ -4852,6 +4961,48 @@ int bAddNewVertex( BN_STRUCT *pBNS, int nVertDoubleBond, int nCap, int nFlow, in
4852
4961
 
4853
4962
  return vnew;
4854
4963
  }
4964
+
4965
+ /*****************************************************************************************************/
4966
+ int AddNewEdge( BNS_VERTEX *p1, BNS_VERTEX *p2, BN_STRUCT *pBNS, int nEdgeCap, int nEdgeFlow )
4967
+ {
4968
+ int ip1 = p1 - pBNS->vert;
4969
+ int ip2 = p2 - pBNS->vert;
4970
+ int ie = pBNS->num_edges;
4971
+ BNS_EDGE *e = pBNS->edge + ie;
4972
+ /* debug: check bounds */
4973
+ if ( ip1 >= pBNS->max_vertices || ip1 < 0 ||
4974
+ ip2 >= pBNS->max_vertices || ip2 < 0 ||
4975
+ ie >= pBNS->max_edges || ie < 0 ||
4976
+ (p1->iedge - pBNS->iedge) < 0 ||
4977
+ (p1->iedge - pBNS->iedge) + p1->max_adj_edges > pBNS->max_iedges ||
4978
+ (p2->iedge - pBNS->iedge) < 0 ||
4979
+ (p2->iedge - pBNS->iedge) + p2->max_adj_edges > pBNS->max_iedges ||
4980
+ p1->num_adj_edges >= p1->max_adj_edges ||
4981
+ p2->num_adj_edges >= p2->max_adj_edges ) {
4982
+ return BNS_VERT_EDGE_OVFL;
4983
+ }
4984
+ /* clear the edge */
4985
+ memset( e, 0, sizeof(*e) );
4986
+ /* connect */
4987
+ e->neighbor1 = inchi_min( ip1, ip2 );
4988
+ e->neighbor12 = ip1 ^ ip2;
4989
+ p1->iedge[p1->num_adj_edges] = ie;
4990
+ p2->iedge[p2->num_adj_edges] = ie;
4991
+ e->neigh_ord[ip1 > ip2] = p1->num_adj_edges ++;
4992
+ e->neigh_ord[ip1 < ip2] = p2->num_adj_edges ++;
4993
+ e->cap = e->cap0 = nEdgeCap;
4994
+ e->flow = e->flow0 = nEdgeFlow;
4995
+ p1->st_edge.flow += nEdgeFlow;
4996
+ p2->st_edge.flow += nEdgeFlow;
4997
+ if ( p1->st_edge.cap < p1->st_edge.flow ) {
4998
+ p1->st_edge.cap = p1->st_edge.flow;
4999
+ }
5000
+ if ( p2->st_edge.cap < p2->st_edge.flow ) {
5001
+ p2->st_edge.cap = p2->st_edge.flow;
5002
+ }
5003
+ pBNS->num_edges ++;
5004
+ return ie;
5005
+ }
4855
5006
  /**********************************************************************************/
4856
5007
  BNS_IEDGE GetEdgeToGroupVertex( BN_STRUCT *pBNS, Vertex v1, AT_NUMB type)
4857
5008
  {
@@ -5630,60 +5781,684 @@ int bIsBnsEndpoint( BN_STRUCT *pBNS, int v )
5630
5781
  return 0;
5631
5782
  }
5632
5783
  /**********************************************************************************/
5633
- /* Return value ret bits if not IS_BNS_ERROR(ret):
5634
-
5635
- ret & 1 => Success
5636
- ret & 2 => Bonds changed to Alt
5637
- (ret & ~3) >> 2 => nDelta: number of removed dots
5638
- */
5639
- int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at, int num_atoms,
5640
- int nVertDoubleBond, int nVertSingleBond, int path_type )
5784
+ #if ( BNS_RAD_SEARCH == 1 )
5785
+ /**********************************************************************************/
5786
+ int bRadChangesAtomType( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex v, Vertex v_1, Vertex v_2 )
5641
5787
  {
5642
- ALT_PATH_CHANGES apc;
5643
- int ret, ret_val, bError, bSuccess, bChangeFlow=0, nDots, nDelta, bDoMarkChangedBonds = 1;
5644
- AT_NUMB type;
5645
- BNS_FLOW_CHANGES fcd[4*BNS_MAX_NUM_FLOW_CHANGES+1];
5646
- ENDPOINT_INFO eif;
5647
-
5648
- /* initialize */
5649
- switch( path_type ) {
5650
- case ALT_PATH_MODE_TAUTOM:
5651
- /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
5652
- type = BNS_VERT_TYPE_ENDPOINT;
5653
- bChangeFlow = BNS_EF_CHNG_RSTR;
5654
- if ( !at[nVertSingleBond].endpoint &&
5655
- (!nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ) )
5656
- return 0;
5657
- if ( !at[nVertDoubleBond].endpoint &&
5658
- (!nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ) )
5659
- return 0;
5788
+
5789
+ EdgeIndex iuv;
5790
+ Vertex v_O, v_ChgOrH;
5791
+ /* the previous atom along the path: should be a terminal atom */
5792
+ if ( v_1 == NO_VERTEX ) {
5793
+ v_1 = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv );
5794
+ }
5795
+ v_O = v_1 / 2 - 1;
5796
+ if ( v_O < 0 || v_O >= pBNS->num_atoms ) {
5797
+ return 0;
5798
+ }
5799
+ /* make sure v_O is a terminal atom: its second neighbor is not an atom */
5800
+ if ( pBNS->vert[pBNS->edge[pBNS->vert[v_O].iedge[1]].neighbor12 ^ v_O].type & BNS_VERT_TYPE_ATOM ) {
5801
+ return 0;
5802
+ }
5803
+ /* the next to previous vertex vertex along the path: should be a Charge or Taut group vertex */
5804
+ if ( v_2 == NO_VERTEX ) {
5805
+ v_2 = GetPrevVertex( pBNS, v_1, pBD->SwitchEdge, &iuv );
5806
+ }
5807
+ v_ChgOrH = v_2 / 2 - 1;
5808
+ if ( v_ChgOrH < pBNS->num_atoms ) {
5809
+ return 0;
5810
+ }
5811
+ /* make sure v_ChgOrH is a charge or taut_group */
5812
+ if ( pBNS->vert[v_ChgOrH].type & (BNS_VERT_TYPE_TGROUP | BNS_VERT_TYPE_C_GROUP) )
5813
+ return 1;
5814
+ return 0;
5815
+ }
5816
+ /**********************************************************************************/
5817
+ int RegisterRadEndpoint( BN_STRUCT *pBNS, BN_DATA *pBD, Vertex u)
5818
+ {
5819
+ EdgeIndex iuv;
5820
+ int i, num_found;
5821
+ Vertex v, w;
5822
+ Vertex u_last, v2;
5823
+ switch( pBD->bRadSrchMode ) {
5824
+ case RAD_SRCH_NORM:
5825
+ /* go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
5826
+ /* we need only vertices where a radical may be moved, therefore exclude u%2=1 (odd) vertices */
5827
+ /* atom number = u/2-1; u = 0 or 1 is 's' or 't' vertices, respectively, they are not atoms */
5828
+ num_found = 0;
5829
+ while ( u > Vertex_t && (u % 2 || u/2 > pBNS->num_atoms ) ) {
5830
+ u = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
5831
+ }
5832
+ w = u/2 - 1; /* Check whether u is a radical endpoint */
5833
+ if ( Vertex_t < u && w < pBNS->num_atoms &&
5834
+ pBNS->vert[w].st_edge.cap == (pBNS->vert[w].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
5835
+ /* u is an atom; it is not a radical atom */
5836
+ /* now search for the starting radical atom by following the path back from u */
5837
+ v = u_last = u;
5838
+ while( v > Vertex_t ) {
5839
+ u = v;
5840
+ v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv ); /* Radical endpoint */
5841
+ }
5842
+ /* check whether u is a radical atom */
5843
+ if ( !(u%2) && Vertex_t < u &&
5844
+ (u = u/2 - 1) < pBNS->num_atoms &&
5845
+ pBNS->vert[u].st_edge.cap > (pBNS->vert[u].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
5846
+ /* at pBNS->vert[u] we have found the radical that originated the path */
5847
+ /* pBD->RadEndpoints[2k] is the radical, pBD->RadEndpoints[2k+1] is the farthest atom */
5848
+ /* to which the radical may be moved (farthest reachable atom) */
5849
+
5850
+ /* add *all* atoms that may receive radical from u_rad */
5851
+ /* exception: at2 in: ==(+/-/H)---at1==at2(possible rad endpoint) if pBNS->type_TACN */
5852
+
5853
+ for ( v = u_last; v > Vertex_t; v = GetPrevVertex( pBNS, v, pBD->SwitchEdge, &iuv ) ) {
5854
+ if ( !(v%2) && (v2 = v/2 - 1) < pBNS->num_atoms &&
5855
+ pBNS->vert[v2].st_edge.cap == (pBNS->vert[v2].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
5856
+ /* check exception */
5857
+ if ( pBNS->type_TACN &&
5858
+ bRadChangesAtomType( pBNS, pBD, v, NO_VERTEX, NO_VERTEX ) ) {
5859
+ continue;
5860
+ }
5861
+ /* add */
5862
+ for ( i = 0; i < pBD->nNumRadEndpoints; i += 2 ) {
5863
+ /* check whether this pair, (u,w), has already been saved */
5864
+ if ( u == pBD->RadEndpoints[i] &&
5865
+ v2 == pBD->RadEndpoints[i+1] ) {
5866
+ break;
5867
+ }
5868
+ }
5869
+ if ( i >= pBD->nNumRadEndpoints ) {
5870
+ /* add new (u,w) pair */
5871
+ if ( pBD->nNumRadEndpoints+2 <= pBD->max_num_vertices ) {
5872
+ /* add */
5873
+ pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = u; /* radical */
5874
+ pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = v2; /* endpoint */
5875
+ num_found ++;
5876
+ /*return 1;*/ /* registered */
5877
+ } else {
5878
+ return BNS_VERT_EDGE_OVFL;
5879
+ }
5880
+ }
5881
+ }
5882
+ }
5883
+ if ( num_found ) {
5884
+ return 1;
5885
+ }
5886
+ }
5887
+ }
5660
5888
  break;
5661
5889
 
5662
- case ALT_PATH_MODE_CHARGE:
5663
- /* Find alt path allowing to move (+). Purpose: establish "charge groups",
5664
- mark alt. bonds due to (+) charge movement */
5665
- type = BNS_VERT_TYPE_C_POINT;
5666
- bChangeFlow = (BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS);
5890
+ case RAD_SRCH_FROM_FICT:
5891
+ /* find nearest atom accessible from a fictitious vertex */
5892
+ /* go backwards along alt path and stop at the 1st found atom (not a fictitious vertex) */
5893
+ v = u;
5894
+ w = NO_VERTEX; /* the nearest atom -- radical-endpoint */
5895
+ u = NO_VERTEX; /* fictitious vertex carrying a radical */
5896
+ while ( v > Vertex_t ) {
5897
+ u = v;
5898
+ if ( !(v % 2) && v/2 <= pBNS->num_atoms &&
5899
+ pBNS->vert[v/2-1].st_edge.cap - pBNS->vert[v/2-1].st_edge.flow < 2 ) {
5900
+ w = v; /* vertex w is atom that may be singlet or doublet but not triplet */
5901
+ }
5902
+ v = GetPrevVertex( pBNS, u, pBD->SwitchEdge, &iuv );
5903
+ }
5904
+ v = u/2 - 1; /* vertex u may be the radical from which the path originated; w is the nearest atom */
5905
+ if ( w == NO_VERTEX || u == NO_VERTEX || w % 2 || u == w || v < pBNS->num_atoms ||
5906
+ pBNS->vert[v].st_edge.cap == pBNS->vert[v].st_edge.flow ||
5907
+ (w = w/2 - 1) >= pBNS->num_atoms ) {
5908
+ break; /* reject */
5909
+ }
5910
+ u = v;
5911
+ /* at pBNS->vert[u] we have found the radical that originated the path, w is the nearest atom */
5912
+ for ( i = 0; i < pBD->nNumRadEndpoints; i += 2 ) {
5913
+ if ( u == pBD->RadEndpoints[i] &&
5914
+ w == pBD->RadEndpoints[i+1] ) {
5915
+ break; /* this pair has already been stored */
5916
+ }
5917
+ }
5918
+ if ( i >= pBD->nNumRadEndpoints ) {
5919
+ /* a new pair has been found */
5920
+ if ( pBD->nNumRadEndpoints+2 <= pBD->max_num_vertices ) {
5921
+ /* add */
5922
+ pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = u; /* radical */
5923
+ pBD->RadEndpoints[pBD->nNumRadEndpoints ++] = w; /* endpoint */
5924
+ return 1; /* registered */
5925
+ } else {
5926
+ return BNS_VERT_EDGE_OVFL;
5927
+ }
5928
+ }
5667
5929
  break;
5930
+ }
5668
5931
 
5669
- case ALT_PATH_MODE_4_SALT:
5670
- case ALT_PATH_MODE_4_SALT2:
5671
- /* Find alt paths allowing to move (-) and H between "acidic oxygen atoms".
5672
- Purpose: mark alt bonds due to this "long range" tautomerism. */
5673
- type = BNS_VERT_TYPE_ENDPOINT;
5674
- bChangeFlow = (BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS);
5675
- if ( !bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
5676
- (!nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ) )
5677
- return 0;
5678
- if ( !bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertDoubleBond].endpoint*/ &&
5679
- (!nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ) )
5680
- return 0;
5681
- memset( &apc, 0, sizeof(apc) );
5682
- break;
5932
+ return 0; /* rejected */
5933
+ }
5934
+ /**********************************************************************************/
5935
+ int cmp_rad_endpoints( const void *a1, const void *a2 )
5936
+ {
5937
+ /* Vertex radical_vertex, radical_endpoint */
5938
+ const Vertex *p1 = (const Vertex *)a1;
5939
+ const Vertex *p2 = (const Vertex *)a2;
5940
+ if ( p1[0] < p2[0] )
5941
+ return -1;
5942
+ if ( p1[0] > p2[0] )
5943
+ return 1;
5944
+ if ( p1[1] < p2[1] )
5945
+ return -1;
5946
+ if ( p1[1] > p2[1] )
5947
+ return 1;
5948
+ return 0;
5949
+ }
5950
+ /**********************************************************************************/
5951
+ int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
5952
+ {
5953
+ BNS_EDGE *e;
5954
+ EdgeIndex ie;
5955
+ BNS_VERTEX *p1, *p2;
5956
+ Vertex v1, v2;
5957
+ int i, delta, rad;
5958
+ for ( i = pBD->nNumRadEdges-1; 0 <= i; i -- ) {
5959
+ ie = pBD->RadEdges[i];
5960
+ if ( ie < 0 || ie >= pBNS->num_edges ) {
5961
+ goto error_exit;
5962
+ }
5963
+ e = pBNS->edge + ie;
5964
+ v1 = e->neighbor1;
5965
+ v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
5966
+ if ( ie + 1 != pBNS->num_edges ||
5967
+ v1 < 0 || v1 >= pBNS->num_vertices ||
5968
+ v2 < 0 || v2 >= pBNS->num_vertices ) {
5969
+ goto error_exit;
5970
+ }
5971
+ p1 = pBNS->vert + v1;
5972
+ p2 = pBNS->vert + v2;
5973
+
5974
+ if ( p2->iedge[p2->num_adj_edges-1] != ie ||
5975
+ p1->iedge[p1->num_adj_edges-1] != ie ) {
5976
+ goto error_exit;
5977
+ }
5978
+ p2->num_adj_edges --;
5979
+ p1->num_adj_edges --;
5980
+ p2->iedge[p2->num_adj_edges] = 0;
5981
+ p1->iedge[p1->num_adj_edges] = 0;
5982
+ p2->st_edge.flow -= e->flow;
5983
+ p1->st_edge.flow -= e->flow;
5984
+
5985
+ if ( !p2->num_adj_edges && v2 >= pBNS->num_atoms ) {
5986
+ if ( v2+1 != pBNS->num_vertices ) {
5987
+ goto error_exit;
5988
+ }
5989
+ memset( p2, 0, sizeof(*p2) );
5990
+ pBNS->num_vertices --;
5991
+ }
5992
+ if ( !p1->num_adj_edges && v1 >= pBNS->num_atoms ) {
5993
+ if ( v1+1 != pBNS->num_vertices ) {
5994
+ goto error_exit;
5995
+ }
5996
+ memset( p1, 0, sizeof(*p1) );
5997
+ pBNS->num_vertices --;
5998
+ }
5999
+ if ( at && v1 < pBNS->num_atoms ) {
6000
+ delta = p1->st_edge.cap - p1->st_edge.flow;
6001
+ rad = at[v1].radical;
6002
+ switch( delta ) {
6003
+ case 0:
6004
+ if ( rad == RADICAL_DOUBLET )
6005
+ rad = 0;
6006
+ break;
6007
+ case 1:
6008
+ if ( rad != RADICAL_DOUBLET )
6009
+ rad = RADICAL_DOUBLET;
6010
+ }
6011
+ at[v1].radical = rad;
6012
+ }
6013
+ memset( e, 0, sizeof(*e) );
6014
+ pBNS->num_edges --;
6015
+ }
6016
+ pBD->nNumRadEdges = 0;
6017
+ pBD->nNumRadicals = 0;
6018
+ pBD->bRadSrchMode = RAD_SRCH_NORM;
6019
+ return 0;
6020
+ error_exit:
6021
+ return BNS_PROGRAM_ERR;
6022
+ }
6023
+ /**********************************************************************************/
6024
+ int RestoreRadicalsOnly( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
6025
+ {
6026
+ BNS_EDGE *e;
6027
+ EdgeIndex ie;
6028
+ BNS_VERTEX *p1, *p2;
6029
+ Vertex v1, v2;
6030
+ int i, delta, rad;
6031
+ int p1_num_adj_edges, p2_num_adj_edges;
6032
+
6033
+ for ( i = pBD->nNumRadEdges-1; 0 <= i; i -- ) {
6034
+ ie = pBD->RadEdges[i];
6035
+ if ( ie < 0 || ie >= pBNS->num_edges ) {
6036
+ goto error_exit;
6037
+ }
6038
+ e = pBNS->edge + ie;
6039
+ v1 = e->neighbor1; /* atom */
6040
+ v2 = e->neighbor12 ^ v1; /* v2 > v1 <=> v2 was added later */
6041
+ if ( v1 < 0 || v1 >= pBNS->num_atoms ||
6042
+ v2 < pBNS->num_atoms || v2 >= pBNS->num_vertices ) {
6043
+ goto error_exit;
6044
+ }
6045
+ p1 = pBNS->vert + v1;
6046
+ p2 = pBNS->vert + v2;
6047
+
6048
+ p1_num_adj_edges = e->neigh_ord[0];
6049
+ p2_num_adj_edges = e->neigh_ord[1];
6050
+
6051
+ if ( p2->iedge[p2_num_adj_edges] != ie ||
6052
+ p1->iedge[p1_num_adj_edges] != ie ) {
6053
+ goto error_exit;
6054
+ }
6055
+
6056
+ if ( at && v1 < pBNS->num_atoms ) {
6057
+ delta = p1->st_edge.cap - p1->st_edge.flow + e->flow;
6058
+ rad = at[v1].radical;
6059
+ switch( delta ) {
6060
+ case 0:
6061
+ if ( rad == RADICAL_DOUBLET )
6062
+ rad = 0;
6063
+ break;
6064
+ case 1:
6065
+ if ( rad != RADICAL_DOUBLET )
6066
+ rad = RADICAL_DOUBLET;
6067
+ }
6068
+ at[v1].radical = rad;
6069
+ }
6070
+ }
6071
+ return 0;
6072
+ error_exit:
6073
+ return BNS_PROGRAM_ERR;
6074
+ }
6075
+ /**********************************************************************************/
6076
+ int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
6077
+ {
6078
+ int ret, i, j, k, num_new_edges, delta;
6079
+ BNS_VERTEX *pRad, *pEndp;
6080
+ Vertex wRad, vRad, vEndp, nNumRadicals;
6081
+ int nDots=0 /* added initialization, 2006-03 */, nNumEdges;
6082
+ if ( pBNS->tot_st_cap <= pBNS->tot_st_flow ) {
6083
+ return 0;
6084
+ }
6085
+ pBD->nNumRadEndpoints = 0;
6086
+ pBD->nNumRadEdges = 0;
6087
+ pBD->bRadSrchMode = bRadSrchMode;
6088
+ pBNS->alt_path = pBNS->altp[0];
6089
+ pBNS->bChangeFlow = 0;
6090
+ ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH );
6091
+ ReInitBnData( pBD );
6092
+ ReInitBnStructAltPaths( pBNS );
6093
+ if ( !ret && pBD->nNumRadEndpoints >= 2 ) {
6094
+ /* sort by radical locations */
6095
+ qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints/2, 2*sizeof(pBD->RadEndpoints[0]), cmp_rad_endpoints );
6096
+ num_new_edges = 0;
6097
+ nNumRadicals = 0;
6098
+ /* create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1 */
6099
+ /* connecting the new vertices radical vertices */
6100
+ for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
6101
+ wRad = pBD->RadEndpoints[i];
6102
+ pRad = pBNS->vert + wRad;
6103
+ delta = pRad->st_edge.cap - (pRad->st_edge.flow & EDGE_FLOW_ST_MASK);
6104
+ if ( delta <= 0 ) {
6105
+ delta = 1;
6106
+ }
6107
+ nNumEdges = 0;
6108
+ for ( j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j] ; j += 2 ) {
6109
+ nNumEdges ++;
6110
+ }
6111
+ /* add new aux vertex to the radical atom/vertex */
6112
+ vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges+1, &nDots );
6113
+ if ( IS_BNS_ERROR( vRad ) ) {
6114
+ ret = vRad;
6115
+ goto error_exit;
6116
+ }
6117
+ pRad = pBNS->vert + vRad;
6118
+ pBD->RadEdges[pBD->nNumRadEdges ++] = pRad->iedge[pRad->num_adj_edges-1];
6119
+ /* replace references to vertex wRad with vRad */
6120
+ for ( k = i, nNumEdges = 0; k < j; k += 2 ) {
6121
+ pBD->RadEndpoints[k] = vRad;
6122
+ }
6123
+ nNumRadicals ++;
6124
+ }
6125
+ /* all vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
6126
+ /* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
6127
+ for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
6128
+ vRad = pBD->RadEndpoints[i];
6129
+ pRad = pBNS->vert + vRad;
6130
+ for ( j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j] ; j += 2 ) {
6131
+ /* connect vew vertex pRad to radical endpoints */
6132
+ vEndp = pBD->RadEndpoints[j+1];
6133
+ pEndp = pBNS->vert + vEndp;
6134
+ ret = AddNewEdge( pRad, pEndp, pBNS, 1, 0 );
6135
+ if ( IS_BNS_ERROR( ret ) ) {
6136
+ goto error_exit;
6137
+ }
6138
+ pBD->RadEdges[pBD->nNumRadEdges ++] = ret;
6139
+ }
6140
+ }
6141
+ pBD->nNumRadicals = nNumRadicals;
6142
+ return nNumRadicals; /* done */
6143
+ }
6144
+ return 0; /* nothing to do */
5683
6145
 
5684
- case ALT_PATH_MODE_REM2H_CHG:
5685
- bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
5686
- case ALT_PATH_MODE_REM2H_TST:
6146
+ error_exit:
6147
+ RemoveRadEndpoints( pBNS, pBD, NULL );
6148
+ return ret;
6149
+
6150
+ }
6151
+ /**********************************************************************************/
6152
+ #define MAX_NUM_RAD 256
6153
+ /***************************************************************************/
6154
+ int SetRadEndpoints2( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
6155
+ {
6156
+ int ret = 0, i, j, k, n, num_new_edges, delta = 1;
6157
+ BNS_VERTEX *pRad, *pEndp;
6158
+ Vertex wRad, vRad, vEndp, nNumRadicals;
6159
+ Vertex vRadList[MAX_NUM_RAD], vRadEqul[MAX_NUM_RAD];
6160
+ int nNumRad = 0;
6161
+ int edge_flow;
6162
+ int nDots=0 /* added initialization, 2006-03 */, nNumEdges;
6163
+ NodeSet VertSet;
6164
+ if ( pBNS->tot_st_cap <= pBNS->tot_st_flow ) {
6165
+ return 0;
6166
+ }
6167
+ /* find all radicals: their vertices have st_cap-st_flow=delta */
6168
+ /* save radical atom numbers in vRadList[] and remove radical by making st_cap=st_flow */
6169
+ for ( i = 0; i < pBNS->num_atoms; i ++ ) {
6170
+ if ( pBNS->vert[i].st_edge.cap - delta == (pBNS->vert[i].st_edge.flow & EDGE_FLOW_ST_MASK) ) {
6171
+ if ( nNumRad < MAX_NUM_RAD ) {
6172
+ pBNS->vert[i].st_edge.cap -= delta;
6173
+ pBNS->tot_st_cap -= delta;
6174
+ vRadList[nNumRad] = i; /* radical position; i > j <=> vRadList[i] > vRadList[j] */
6175
+ vRadEqul[nNumRad] = nNumRad; /* the smallest radical atom that has reachable
6176
+ * atoms in common with this radical atom
6177
+ * always keep vRadEqul[nNumRad] <= nNumRad */
6178
+ nNumRad ++;
6179
+ }
6180
+ }
6181
+ }
6182
+ if ( pBNS->tot_st_cap - pBNS->tot_st_flow > nNumRad ) {
6183
+ return BNS_CAP_FLOW_ERR; /* extra st_cap on non-atoms or program error */
6184
+ }
6185
+ memset( &VertSet, 0, sizeof(VertSet) );
6186
+ /* find reachable atoms by enabling each radical separately */
6187
+ for ( j = 0; j < nNumRad; j ++ ) {
6188
+ i = vRadList[j];
6189
+ pBD->nNumRadEndpoints = 0;
6190
+ pBD->nNumRadEdges = 0;
6191
+ pBD->bRadSrchMode = bRadSrchMode;
6192
+ pBNS->alt_path = pBNS->altp[0];
6193
+ pBNS->bChangeFlow = 0;
6194
+ pBNS->vert[i].st_edge.cap += delta; /* enable single radical */
6195
+ pBNS->tot_st_cap += delta;
6196
+ ret = BalancedNetworkSearch( pBNS, pBD, BNS_EF_RAD_SRCH ); /* find reachable atoms */
6197
+ ReInitBnData( pBD );
6198
+ ReInitBnStructAltPaths( pBNS );
6199
+ pBD->bRadSrchMode = RAD_SRCH_NORM;
6200
+ pBNS->vert[i].st_edge.cap -= delta; /* disable single radical */
6201
+ pBNS->tot_st_cap -= delta;
6202
+ if ( IS_BNS_ERROR( ret ) ) {
6203
+ goto error_exit;
6204
+ } else
6205
+ if ( ret ) {
6206
+ ret = BNS_RADICAL_ERR; /* found augmenting path: should not happen since only one radical was enabled */
6207
+ goto error_exit;
6208
+ }
6209
+ if ( !ret && pBD->nNumRadEndpoints >= 2 ) {
6210
+ /* sort by: primary_key=radical locations, secondary_key=radical endoint */
6211
+ qsort( pBD->RadEndpoints, pBD->nNumRadEndpoints/2, 2*sizeof(pBD->RadEndpoints[0]), cmp_rad_endpoints );
6212
+ if ( pBD->RadEndpoints[0] != i || pBD->RadEndpoints[pBD->nNumRadEndpoints-2] != i ) {
6213
+ ret = BNS_RADICAL_ERR; /* more than one radical vertex */
6214
+ goto error_exit;
6215
+ }
6216
+ if ( nNumRad > 1 ) {
6217
+ /* if more than one radical then save reachable atoms in bitmaps to allow */
6218
+ /* faster finding whether same atoms are reachable by two or more radicals */
6219
+ /* Later merge such sets */
6220
+ if ( NULL == VertSet.bitword ) {
6221
+ SetBitCreate( );
6222
+ if ( !NodeSetCreate( &VertSet, pBNS->num_atoms, nNumRad ) ) {
6223
+ ret = BNS_OUT_OF_RAM; /* out of RAM */
6224
+ goto error_exit;
6225
+ }
6226
+ }
6227
+ NodeSetFromRadEndpoints( &VertSet, j, pBD->RadEndpoints, pBD->nNumRadEndpoints);
6228
+ /* do not allow any radical center be treated as a reachable atom: */
6229
+ RemoveFromNodeSet( &VertSet, j, vRadList, nNumRad );
6230
+ }
6231
+ }
6232
+ }
6233
+ /* restore radical st_cap so that st_cap-st_flow=delta */
6234
+ for ( j = 0; j < nNumRad; j ++ ) {
6235
+ i = vRadList[j];
6236
+ pBNS->vert[i].st_edge.cap += delta;
6237
+ pBNS->tot_st_cap += delta;
6238
+ }
6239
+ /* merge lists that have common radical endpoints */
6240
+ /* defect: if vertex sets i and j do not intersect they will be compared 2 times */
6241
+ /* total up to nNumRad*(nNumRad-1)/2 calls to DoNodeSetsIntersect() */
6242
+ if ( nNumRad > 1 ) {
6243
+ for ( i = 0; i < nNumRad; i ++ ) {
6244
+ if ( vRadEqul[i] != i )
6245
+ continue;
6246
+ do {
6247
+ n = 0;
6248
+ for ( j = i+1; j < nNumRad; j ++ ) {
6249
+ if ( vRadEqul[j] != j )
6250
+ continue;
6251
+ if ( DoNodeSetsIntersect( &VertSet, i, j) ) {
6252
+ AddNodeSet2ToNodeSet1( &VertSet, i, j);
6253
+ vRadEqul[j] = i; /* Set j was copied to set i; i < j */
6254
+ n ++;
6255
+ }
6256
+ }
6257
+ } while( n );
6258
+ }
6259
+ /* fill out pBD->RadEndpoints[] */
6260
+ for ( i = 0, n = 0; i < nNumRad; i ++ ) {
6261
+ if ( i == vRadEqul[i] ) {
6262
+ if ( !IsNodeSetEmpty( &VertSet, i) ) {
6263
+ /* store equivalent radicals */
6264
+ for ( j = i+1; j < nNumRad; j ++ ) {
6265
+ if (i == vRadEqul[j] ) {
6266
+ pBD->RadEndpoints[n++] = vRadList[i];
6267
+ pBD->RadEndpoints[n++] = -vRadList[j]-2; /* equivalent radical, alvays not zero */
6268
+ }
6269
+ }
6270
+ /* store endpoints */
6271
+ n = AddNodesToRadEndpoints( &VertSet, i, pBD->RadEndpoints, vRadList[i], n, pBD->max_len_Pu_Pv );
6272
+ if ( n < 0 ) {
6273
+ ret = BNS_RADICAL_ERR; /* pBD->RadEndpoints overflow */
6274
+ goto error_exit;
6275
+ }
6276
+ } else {
6277
+ pBD->RadEndpoints[n++] = vRadList[i];
6278
+ pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
6279
+ }
6280
+ }
6281
+ }
6282
+ pBD->nNumRadEndpoints = n;
6283
+ NodeSetFree( &VertSet );
6284
+ } else
6285
+ if ( nNumRad == 1 && !pBD->nNumRadEndpoints ) {
6286
+ /* 2006-07-30: a single radical; no possible endpoint found */
6287
+ for ( i = 0, n = 0; i < nNumRad; i ++ ) {
6288
+ pBD->RadEndpoints[n++] = vRadList[i];
6289
+ pBD->RadEndpoints[n++] = -1; /* immobile radical, only one edge to add */
6290
+ }
6291
+ pBD->nNumRadEndpoints = n;
6292
+ }
6293
+
6294
+ if ( !ret && pBD->nNumRadEndpoints >= 2 ) {
6295
+ /* already sorted by radical locations */
6296
+ num_new_edges = 0;
6297
+ nNumRadicals = 0;
6298
+ /**************************************************************************
6299
+ * create new vertices (type=BNS_VERT_TYPE_TEMP) and edges with flow=cap=1
6300
+ * connecting the new vertices radical vertices
6301
+ *
6302
+ *
6303
+ * Original structure: atom A is a radical center A==B--C*--D==E
6304
+ * A*--B==C--D==E atoms C and E are reachable: A==B--C===D--E*
6305
+ *
6306
+ * Resultant temporary structure:
6307
+ * A---B==C--D==E
6308
+ * || / /
6309
+ * || / / The additional new vertex (*) and its
6310
+ * || / / 3 edges replace the radical with alternating
6311
+ * || / / circuits that allow same bond changes
6312
+ * || / / as moving the radical to atoms C or E.
6313
+ * ||// "Double bonds" here have edge cap=1, flow=1
6314
+ * (*) "Single bonds" have edge cap=1, flow=0
6315
+ *
6316
+ * The "equivalent radical centers" (which have at least one reachable atom
6317
+ * in common) are connected to (*) with "double bonds" (edge cap=1, flow=1).
6318
+ * Reachable non-radical atoms are connected by edges with cap=1, flow=0
6319
+ * After running BNS to find alt.path a "double bond" from (*) may move
6320
+ * to another atom thus muving the radical.
6321
+ *
6322
+ * Number of additional (*) vertices = number of sets of
6323
+ * "equivalent radical centers".
6324
+ * Each such a set may include one or more radical centers.
6325
+ *
6326
+ * The radicals will be re-created in RemoveRadEndpoints()
6327
+ ***************************************************************************/
6328
+ for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
6329
+ wRad = pBD->RadEndpoints[i];
6330
+ pRad = pBNS->vert + wRad;
6331
+ delta = pRad->st_edge.cap - (pRad->st_edge.flow & EDGE_FLOW_ST_MASK);
6332
+ if ( delta <= 0 ) {
6333
+ delta = 1;
6334
+ }
6335
+ nNumEdges = 0;
6336
+ for ( j = i; j < pBD->nNumRadEndpoints && wRad == pBD->RadEndpoints[j] ; j += 2 ) {
6337
+ nNumEdges += (pBD->RadEndpoints[j+1] != -1); /* immobile radicals have one edge only */
6338
+ }
6339
+ /* add new aux vertex to the radical atom/vertex making st_cap-st_flow=0 */
6340
+ /* in case of immobile radical there will be no additional eddges since nNumEdges=0 */
6341
+ vRad = bAddNewVertex( pBNS, wRad, delta, delta, nNumEdges+1, &nDots );
6342
+ if ( IS_BNS_ERROR( vRad ) ) {
6343
+ ret = vRad;
6344
+ goto error_exit;
6345
+ }
6346
+ pRad = pBNS->vert + vRad;
6347
+ pBD->RadEdges[pBD->nNumRadEdges ++] = pRad->iedge[pRad->num_adj_edges-1];
6348
+ /* replace references to vertex wRad with vRad */
6349
+ for ( k = i, nNumEdges = 0; k < j; k += 2 ) {
6350
+ pBD->RadEndpoints[k] = vRad;
6351
+ }
6352
+ nNumRadicals ++;
6353
+ }
6354
+ /* all vRad vertex indices should be in the range vFirstNewVertex...vFirstNewVertex+nNumRadicals-1 */
6355
+ /* connect new vertices to the radical endpoints thus replacing radicals with even-length alternating cycles */
6356
+ for ( i = 0; i < pBD->nNumRadEndpoints; i = j ) {
6357
+ vRad = pBD->RadEndpoints[i];
6358
+ pRad = pBNS->vert + vRad;
6359
+ for ( j = i; j < pBD->nNumRadEndpoints && vRad == pBD->RadEndpoints[j] ; j += 2 ) {
6360
+ /* connect vew vertex pRad to radical endpoints */
6361
+ vEndp = pBD->RadEndpoints[j+1];
6362
+ if ( vEndp == -1 )
6363
+ continue;
6364
+ if ( vEndp < 0 ) {
6365
+ edge_flow = 1;
6366
+ vEndp = -vEndp - 2; /* equivalent radical centers */
6367
+ } else {
6368
+ edge_flow = 0;
6369
+ }
6370
+ pEndp = pBNS->vert + vEndp;
6371
+ ret = AddNewEdge( pRad, pEndp, pBNS, 1, edge_flow );
6372
+ if ( IS_BNS_ERROR( ret ) ) {
6373
+ goto error_exit;
6374
+ }
6375
+ pBD->RadEdges[pBD->nNumRadEdges ++] = ret;
6376
+ }
6377
+ }
6378
+ pBD->nNumRadicals = nNumRadicals;
6379
+ return nNumRadicals; /* done */
6380
+ }
6381
+ return 0; /* nothing to do */
6382
+
6383
+ error_exit:
6384
+ RemoveRadEndpoints( pBNS, pBD, NULL );
6385
+ NodeSetFree( &VertSet );
6386
+ return ret;
6387
+
6388
+ }
6389
+
6390
+
6391
+ #else
6392
+ /**********************************************************************************/
6393
+ int SetRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
6394
+ {
6395
+ return 0;
6396
+ }
6397
+ int RemoveRadEndpoints( BN_STRUCT *pBNS, BN_DATA *pBD, inp_ATOM *at )
6398
+ {
6399
+ return 0;
6400
+ }
6401
+ int SetRadEndpoints2( BN_STRUCT *pBNS, BN_DATA *pBD, BRS_MODE bRadSrchMode )
6402
+ {
6403
+ return 0;
6404
+ }
6405
+ #endif
6406
+ /**********************************************************************************/
6407
+ /* Return value ret bits if not IS_BNS_ERROR(ret):
6408
+
6409
+ ret & 1 => Success
6410
+ ret & 2 => Bonds changed to Alt
6411
+ (ret & ~3) >> 2 => nDelta: number of removed dots
6412
+ */
6413
+ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at, int num_atoms,
6414
+ int nVertDoubleBond, int nVertSingleBond, int path_type )
6415
+ {
6416
+ ALT_PATH_CHANGES apc;
6417
+ int ret, ret_val, bError, bSuccess, bChangeFlow=0, nDots, nDelta, bDoMarkChangedBonds = 1;
6418
+ int bAdjustRadicals = 0;
6419
+ AT_NUMB type;
6420
+ BNS_FLOW_CHANGES fcd[4*BNS_MAX_NUM_FLOW_CHANGES+1];
6421
+ ENDPOINT_INFO eif;
6422
+
6423
+ /* initialize */
6424
+ switch( path_type ) {
6425
+ case ALT_PATH_MODE_TAUTOM:
6426
+ /* Check for alt path allowing to move H and (-). Purpose: confirm possible tautomerism */
6427
+ type = BNS_VERT_TYPE_ENDPOINT;
6428
+ bChangeFlow = BNS_EF_CHNG_RSTR;
6429
+ if ( !at[nVertSingleBond].endpoint &&
6430
+ (!nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ) )
6431
+ return 0;
6432
+ if ( !at[nVertDoubleBond].endpoint &&
6433
+ (!nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ) )
6434
+ return 0;
6435
+ break;
6436
+
6437
+ case ALT_PATH_MODE_CHARGE:
6438
+ /* Find alt path allowing to move (+). Purpose: establish "charge groups",
6439
+ mark alt. bonds due to (+) charge movement */
6440
+ type = BNS_VERT_TYPE_C_POINT;
6441
+ bChangeFlow = (BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS);
6442
+ break;
6443
+
6444
+ case ALT_PATH_MODE_4_SALT:
6445
+ case ALT_PATH_MODE_4_SALT2:
6446
+ /* Find alt paths allowing to move (-) and H between "acidic oxygen atoms".
6447
+ Purpose: mark alt bonds due to this "long range" tautomerism. */
6448
+ type = BNS_VERT_TYPE_ENDPOINT;
6449
+ bChangeFlow = (BNS_EF_CHNG_RSTR | BNS_EF_ALTR_BONDS);
6450
+ if ( !bIsBnsEndpoint( pBNS, nVertSingleBond ) /* !at[nVertSingleBond].endpoint*/ &&
6451
+ (!nGetEndpointInfo( at, nVertSingleBond, &eif ) || !eif.cDonor ) )
6452
+ return 0;
6453
+ if ( !bIsBnsEndpoint( pBNS, nVertDoubleBond ) /* !at[nVertDoubleBond].endpoint*/ &&
6454
+ (!nGetEndpointInfo( at, nVertDoubleBond, &eif ) || !eif.cAcceptor ) )
6455
+ return 0;
6456
+ memset( &apc, 0, sizeof(apc) );
6457
+ break;
6458
+
6459
+ case ALT_PATH_MODE_REM2H_CHG:
6460
+ bChangeFlow |= BNS_EF_ALTR_BONDS; /* fall through */
6461
+ case ALT_PATH_MODE_REM2H_TST:
5687
6462
  bChangeFlow |= BNS_EF_CHNG_RSTR;
5688
6463
  type = BNS_VERT_TYPE_ENDPOINT;
5689
6464
  /* allow non-tautomeric donors or any tautomeric atom */
@@ -5727,27 +6502,37 @@ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at,
5727
6502
  bSuccess = 0;
5728
6503
  nDelta = 0;
5729
6504
 
6505
+ ret = SetRadEndpoints2( pBNS, pBD, RAD_SRCH_NORM );
6506
+ if ( IS_BNS_ERROR( ret ) ) {
6507
+ return ret;
6508
+ }
6509
+
5730
6510
  /* set BNS to check alt path */
5731
6511
  ret = bSetBnsToCheckAltPath( pBNS, nVertDoubleBond, nVertSingleBond, type, path_type, &apc, fcd, &nDots );
5732
6512
  switch( ret ) {
5733
6513
  case BNS_CHK_ALTP_NO_ALTPATH:
5734
- return 0;
6514
+ ret = RemoveRadEndpoints( pBNS, pBD, NULL );
6515
+ return ret;
5735
6516
  case BNS_CHK_ALTP_SAME_TGROUP:
5736
6517
  bSuccess = 1;
5737
6518
  goto reinit_BNS;
5738
6519
  case BNS_CHK_ALTP_SAME_VERTEX:
5739
- return 1; /* very strange ... set a breakpoint here */
6520
+ ret = RemoveRadEndpoints( pBNS, pBD, NULL );
6521
+ return ret? ret : 1; /* very strange ... set a breakpoint here */
5740
6522
  case BNS_CHK_ALTP_SET_SUCCESS:
5741
6523
  break; /* actually check the existence of the altpath */
5742
6524
  case BNS_CANT_SET_BOND:
5743
6525
  goto reinit_BNS;
5744
6526
  default:
6527
+ ret_val = RemoveRadEndpoints( pBNS, pBD, NULL );
5745
6528
  if ( IS_BNS_ERROR( ret ) ) {
5746
6529
  return ret;
5747
6530
  }
5748
6531
  return BNS_PROGRAM_ERR;
5749
6532
  }
5750
6533
 
6534
+ bAdjustRadicals = ( (bChangeFlow & BNS_EF_UPD_RAD_ORI) && !(bChangeFlow & BNS_EF_RSTR_FLOW) );
6535
+
5751
6536
  /*****************************************************************
5752
6537
  * nDots = 2 for ALT_PATH_CHARGE (checking moveable positive charges)
5753
6538
  * Now nDots for ALT_PATH_TAUTOM or ALT_PATH_4_SALT can be greater
@@ -5769,9 +6554,12 @@ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at,
5769
6554
  if ( pAATG && pAATG->nMarkedAtom ) {
5770
6555
  if ( pAATG->nAtTypeTotals && (bChangeFlow & BNS_EF_UPD_H_CHARGE) ) {
5771
6556
  memset( pAATG->nMarkedAtom, 0, num_atoms*sizeof(pAATG->nMarkedAtom[0]) );
5772
- /* subtract */
6557
+ /* mark atoms that have charge or H changed, check their input types (that is, before changes),
6558
+ and subtract their input charge/H from nAtTypeTotals */
5773
6559
  SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom, NULL, 1 );
5774
- /* change */
6560
+ /* ZChange charges and/or H, update t_group_info, do not check types or change nAtTypeTotals */
6561
+ /* Atom types will be checked and nAtTypeTotals will be changed in
6562
+ AddChangedAtHChargeBNS() later */
5775
6563
  SubtractOrChangeAtHChargeBNS( pBNS, at, num_atoms, NULL, NULL, pAATG->t_group_info, 0 );
5776
6564
  } else
5777
6565
  if ( !pAATG->nAtTypeTotals ){
@@ -5805,6 +6593,15 @@ int bExistsAltPath( BN_STRUCT *pBNS, BN_DATA *pBD, BN_AATG *pAATG, inp_ATOM *at,
5805
6593
  bError = BNS_BOND_ERR;
5806
6594
  }
5807
6595
  if ( !bError && pAATG && pAATG->nMarkedAtom && (bChangeFlow & BNS_EF_UPD_H_CHARGE) ) {
6596
+ /* Update radicals to avoid errors in atom type check in AddChangedAtHChargeBNS() */
6597
+ if ( bAdjustRadicals ) {
6598
+ ret_val = RestoreRadicalsOnly( pBNS, pBD, at );
6599
+ if ( IS_BNS_ERROR( ret_val ) ) {
6600
+ bError = ret_val;
6601
+ }
6602
+ }
6603
+ /* Check atom types of marked atoms and add charge/H changes to nAtTypeTotals */
6604
+ /* Changing atoms were marked in the 1st call to SubtractOrChangeAtHChargeBNS(..., 1) above */
5808
6605
  AddChangedAtHChargeBNS( at, num_atoms, pAATG->nAtTypeTotals, pAATG->nMarkedAtom );
5809
6606
  if ( bChangeFlow & BNS_EF_CHNG_FLOW ) {
5810
6607
  /* eliminate ambiguities in already changed flow:
@@ -5823,8 +6620,9 @@ reinit_BNS:
5823
6620
  /* --- reinitialize to repeat the calculations --- */
5824
6621
  bRestoreBnsAfterCheckAltPath( pBNS, &apc, bChangeFlow & BNS_EF_UPD_H_CHARGE );
5825
6622
  bRestoreFlowAfterCheckOneBond( pBNS, fcd );
6623
+ ret_val = RemoveRadEndpoints( pBNS, pBD, bAdjustRadicals? at : NULL );
5826
6624
  ReInitBnStructAltPaths( pBNS );
5827
- return bError? bError : (bSuccess + 4*nDelta);
6625
+ return bError? bError : ret_val? ret_val : (bSuccess + 4*nDelta);
5828
6626
  }
5829
6627
 
5830
6628
 
@@ -5840,12 +6638,23 @@ BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtom
5840
6638
  int i, j, k, n_edges, num_bonds, num_edges, f1, f2, edge_cap, edge_flow, st_cap, st_flow, flag_alt_bond;
5841
6639
  int tot_st_cap, tot_st_flow;
5842
6640
  int max_tg, max_edges, max_vertices, len_alt_path, max_iedges, num_altp;
6641
+ #if( BNS_RAD_SEARCH == 1 )
6642
+ int num_rad = 0;
5843
6643
 
5844
- max_tg = num_atoms / 2;
6644
+ nMaxAddEdges += 1;
6645
+ #endif
6646
+ #if( FIX_NUM_TG == 1 )
6647
+ max_tg = inchi_max( num_atoms / 2, 5);
6648
+ #else
6649
+ max_tg = num_atoms;
6650
+ #endif
5845
6651
  num_changed_bonds = 0;
5846
6652
 
5847
6653
  for ( i = 0, num_bonds = 0; i < num_atoms; i ++ ) {
5848
6654
  num_bonds += at[i].valence;
6655
+ #if( BNS_RAD_SEARCH == 1 )
6656
+ num_rad += (at[i].radical == RADICAL_DOUBLET);
6657
+ #endif
5849
6658
  }
5850
6659
  /* each atom has enough edges to belong to a tautomeric group + nMaxAddEdges */
5851
6660
  /* number of atoms is large enough to accommodate max. possible number of t-groups + nMaxAddAtoms */
@@ -5855,6 +6664,12 @@ BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtom
5855
6664
  max_vertices = num_atoms + nMaxAddAtoms + max_tg + 1;
5856
6665
  /* +max_tg for edges between t-groups and super-tautomeric group */
5857
6666
  max_edges = num_edges + (nMaxAddEdges + NUM_KINDS_OF_GROUPS)*max_vertices + max_tg;
6667
+ #if( BNS_RAD_SEARCH == 1 )
6668
+ if ( num_rad ) {
6669
+ max_vertices *= 2;
6670
+ max_edges *= 2;
6671
+ }
6672
+ #endif
5858
6673
  max_iedges = 2*max_edges;
5859
6674
  len_alt_path = max_vertices+iALTP_HDR_LEN+1; /* may overflow if an edge is traversed in 2 directions */
5860
6675
 
@@ -5942,8 +6757,9 @@ BN_STRUCT* AllocateAndInitBnStruct( inp_ATOM *at, int num_atoms, int nMaxAddAtom
5942
6757
  }
5943
6758
  bond_type = (at[i].bond_type[j] & BOND_TYPE_MASK);
5944
6759
  bond_mark = (at[i].bond_type[j] & ~BOND_TYPE_MASK);
5945
- if ( bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE && bond_type != BOND_TRIPLE ) {
5946
- /* make unknown bonds single */
6760
+ if ( bond_type != BOND_SINGLE && bond_type != BOND_DOUBLE &&
6761
+ bond_type != BOND_TRIPLE /*&& bond_type != BOND_ALTERN*/ ) {
6762
+ /* make Unknown or Alternating bonds single */
5947
6763
  bond_type = 1;
5948
6764
  at[i].bond_type[j] = bond_mark | bond_type;
5949
6765
  num_changed_bonds ++;
@@ -6429,15 +7245,22 @@ int AddCGroups2BnStruct( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, C_GROUP_I
6429
7245
  for ( k = 0; k < vertex_cpoint->num_adj_edges; k ++ ) {
6430
7246
  int iedge = vertex_cpoint->iedge[k];
6431
7247
  VertexFlow nNewCap = vertex_cpoint->st_edge.cap;
7248
+ centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
6432
7249
  if ( !pBNS->edge[iedge].cap ) {
6433
7250
  /* single bond, possibly between c_point and centerpoint */
6434
- centerpoint = (pBNS->edge[iedge].neighbor12 ^ c_point);
6435
7251
  if ( centerpoint < pBNS->num_atoms &&
6436
7252
  pBNS->vert[centerpoint].st_edge.cap >= 1 ) {
6437
7253
  nNewCap = inchi_min( pBNS->vert[centerpoint].st_edge.cap, nNewCap );
6438
7254
  nNewCap = inchi_min( nNewCap, MAX_BOND_EDGE_CAP );
6439
7255
  pBNS->edge[iedge].cap = nNewCap;
6440
7256
  }
7257
+ #if( FIX_CPOINT_BOND_CAP2 == 1 ) /* multiple bond */
7258
+ else
7259
+ if ( centerpoint < pBNS->num_atoms &&
7260
+ edge->flow && pBNS->edge[iedge].cap < MAX_BOND_EDGE_CAP ) {
7261
+ pBNS->edge[iedge].cap ++;
7262
+ }
7263
+ #endif
6441
7264
  }
6442
7265
  }
6443
7266
  #endif /* } FIX_CPOINT_BOND_CAP */
@@ -6495,6 +7318,14 @@ BN_DATA *DeAllocateBnData( BN_DATA *pBD )
6495
7318
  inchi_free( pBD->Pu );
6496
7319
  if ( pBD->Pv )
6497
7320
  inchi_free( pBD->Pv );
7321
+ #if( BNS_RAD_SEARCH == 1 )
7322
+ if ( pBD->RadEndpoints ) {
7323
+ inchi_free( pBD->RadEndpoints );
7324
+ }
7325
+ if ( pBD->RadEdges ) {
7326
+ inchi_free( pBD->RadEdges );
7327
+ }
7328
+ #endif
6498
7329
  inchi_free( pBD );
6499
7330
  }
6500
7331
  return NULL;
@@ -6507,12 +7338,17 @@ BN_DATA *AllocateAndInitBnData( int max_num_vertices )
6507
7338
  int max_len_Pu_Pv;
6508
7339
  max_num_vertices = 2*max_num_vertices+2;
6509
7340
  max_len_Pu_Pv = max_num_vertices/2+1;
7341
+ max_len_Pu_Pv += max_len_Pu_Pv % 2; /* even length */
6510
7342
  if ( !(pBD = (BN_DATA *) inchi_calloc( 1, sizeof(BN_DATA) ) ) ||
6511
7343
  !(pBD->BasePtr = (Vertex *) inchi_calloc( max_num_vertices, sizeof(Vertex) ) ) ||
6512
7344
  !(pBD->SwitchEdge = (Edge *) inchi_calloc( max_num_vertices, sizeof(Edge ) ) ) ||
6513
7345
  !(pBD->Tree = (S_CHAR *) inchi_calloc( max_num_vertices, sizeof(S_CHAR) ) ) ||
6514
7346
  !(pBD->ScanQ = (Vertex *) inchi_calloc( max_num_vertices, sizeof(Vertex) ) ) ||
6515
7347
  !(pBD->Pu = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof(Vertex) ) ) ||
7348
+ #if( BNS_RAD_SEARCH == 1 )
7349
+ !(pBD->RadEndpoints = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof(Vertex) ) ) ||
7350
+ !(pBD->RadEdges = (EdgeIndex*) inchi_calloc( max_len_Pu_Pv, sizeof(EdgeIndex) ) ) ||
7351
+ #endif
6516
7352
  !(pBD->Pv = (Vertex *) inchi_calloc( max_len_Pu_Pv, sizeof(Vertex) ) )
6517
7353
  ) {
6518
7354
  pBD = DeAllocateBnData( pBD );
@@ -6524,6 +7360,9 @@ BN_DATA *AllocateAndInitBnData( int max_num_vertices )
6524
7360
  pBD->QSize = -1;
6525
7361
  pBD->max_len_Pu_Pv = max_len_Pu_Pv;
6526
7362
  pBD->max_num_vertices = max_num_vertices;
7363
+ #if( BNS_RAD_SEARCH == 1 )
7364
+ pBD->nNumRadEndpoints = 0;
7365
+ #endif
6527
7366
  }
6528
7367
  return pBD;
6529
7368
  }
@@ -6846,12 +7685,14 @@ int rescap_mark( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
6846
7685
  return bBackward;
6847
7686
  }
6848
7687
  /********************************************************************************
7688
+ Get previous vertex in the searched path
6849
7689
  z is SwitchEdge_Vert2(y) != y. Go backward from z to y
6850
7690
  *********************************************************************************/
6851
7691
  Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iuv )
6852
7692
  {
6853
7693
  Vertex w, z, x2, y2, n;
6854
7694
  EdgeIndex iwy;
7695
+
6855
7696
  w = SwitchEdge_Vert1(y);
6856
7697
  z = SwitchEdge_Vert2(y);
6857
7698
  iwy = SwitchEdge_IEdge(y);
@@ -6868,7 +7709,8 @@ Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iu
6868
7709
  iwy = SwitchEdge_IEdge(y2);
6869
7710
  if ( w == x2 ) {
6870
7711
  *iuv = iwy;
6871
- return z;
7712
+ /*return z; */
7713
+ return (y + z)%2? z : prim(z);
6872
7714
  }
6873
7715
  n ++;
6874
7716
  #ifdef _DEBUG
@@ -6896,6 +7738,51 @@ Vertex GetPrevVertex( BN_STRUCT* pBNS, Vertex y, Edge *SwitchEdge, EdgeIndex *iu
6896
7738
  along an alternating path from another heteroatom (t-group will be detected).
6897
7739
 
6898
7740
  **********************************************************************************/
7741
+ #if( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
7742
+ /*********************************************************************************/
7743
+ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
7744
+ {
7745
+ #define TYPE_T 1 /* t-group [also called H-group] */
7746
+ #define TYPE_CN 2 /* (-)c-group */
7747
+ int i, degree, ret, u_is_taut=0, w_is_taut, num_allowed=0, num_found_groups=0;
7748
+ Vertex w;
7749
+ EdgeIndex ivw;
7750
+ if ( !pBNS->type_TACN || u <= 1 || v <= 1 ||
7751
+ (pBNS->vert[v/2-1].type & pBNS->type_TACN) ) {
7752
+ return 0; /* add/remove H(+) is allowed for acidic atoms */
7753
+ }
7754
+ if ( !pBNS->type_T || !pBNS->type_CN )
7755
+ return 0; /* should not happen */
7756
+ u_is_taut = ((pBNS->vert[u/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
7757
+ ((pBNS->vert[u/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
7758
+ if ( u_is_taut ) {
7759
+ /* u is either t-group vertex or (-) c-group */
7760
+ degree = GetVertexDegree( pBNS, v );
7761
+ for ( i = 0; i < degree; i ++ ) {
7762
+ /* v = vert[u].neighbor[i]; */
7763
+ w = GetVertexNeighbor( pBNS, v, i, &ivw );
7764
+ if ( w == NO_VERTEX || w <= 1 ) {
7765
+ continue; /* the atom has only single bonds or it is s or t, ignore it */
7766
+ }
7767
+ if ( w != u && (ret = rescap(pBNS, v, w, ivw)) > 0 ) {
7768
+ num_allowed ++;
7769
+ w_is_taut = ((pBNS->vert[w/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN :
7770
+ ((pBNS->vert[w/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T : 0;
7771
+ if ( (u_is_taut | w_is_taut) == (TYPE_T | TYPE_CN) ) {
7772
+ num_found_groups ++;
7773
+ }
7774
+ }
7775
+ }
7776
+ if ( num_found_groups && num_allowed == 1 ) {
7777
+ return 1; /* reject */
7778
+ }
7779
+ }
7780
+ return 0;
7781
+ #undef TYPE_T
7782
+ #undef TYPE_CN
7783
+ }
7784
+ #else /* } FIX_TACN_POSSIBLE_BUG { */
7785
+ /*********************************************************************************/
6899
7786
  int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
6900
7787
  {
6901
7788
  int i, degree, ret, u_is_taut=0, num_allowed=0, num_found_groups=0;
@@ -6903,12 +7790,13 @@ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
6903
7790
  EdgeIndex ivw;
6904
7791
  if ( !pBNS->type_TACN || u <= 1 || v <= 1 ||
6905
7792
  (pBNS->vert[v/2-1].type & pBNS->type_TACN) ) {
6906
- return 0;
7793
+ return 0; /* add/remove H(+) is allowed for acidic atoms */
6907
7794
  }
6908
7795
  if ( !pBNS->type_T || !pBNS->type_CN )
6909
7796
  return 0; /* should not happen */
6910
7797
  if ( (u_is_taut = (pBNS->vert[u/2-1].type & pBNS->type_T) == pBNS->type_T) ||
6911
7798
  ( (pBNS->vert[u/2-1].type & pBNS->type_CN) == pBNS->type_CN) ) {
7799
+ /* u is either t-group vertex or (-) c-group */
6912
7800
  degree = GetVertexDegree( pBNS, v );
6913
7801
  for ( i = 0; i < degree; i ++ ) {
6914
7802
  /* v = vert[u].neighbor[i]; */
@@ -6925,12 +7813,13 @@ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
6925
7813
  }
6926
7814
  }
6927
7815
  if ( num_found_groups && num_allowed == 1 ) {
6928
- return 1;
7816
+ return 1; /* reject */
6929
7817
  }
6930
7818
 
6931
7819
  }
6932
7820
  return 0;
6933
7821
  }
7822
+ #endif /* } FIX_TACN_POSSIBLE_BUG */
6934
7823
  /*********************************************************************************
6935
7824
  the purpose is to avoid paths
6936
7825
  (H-group)[u]---atom[v]---((-)-cgroup)[w], where
@@ -6940,6 +7829,55 @@ int bIgnoreVertexNonTACN_atom( BN_STRUCT* pBNS, Vertex u, Vertex v )
6940
7829
  only one chemical bond. Only because of this an early rejection of
6941
7830
  the vertex v (before it gets on SCANQ) is possible.
6942
7831
  **********************************************************************************/
7832
+ #if( FIX_TACN_POSSIBLE_BUG == 1 ) /* { */
7833
+ /*********************************************************************************/
7834
+ int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge )
7835
+ {
7836
+ #define TYPE_T 1 /* t-group [also called H-group] */
7837
+ #define TYPE_CN 2 /* (-)c-group */
7838
+ int u_is_taut=0, w_is_taut=0;
7839
+ Vertex u;
7840
+ EdgeIndex iuv;
7841
+ if ( v <= 1 || w <= 1 )
7842
+ return 0;
7843
+ #if ( CHECK_TACN == 1 )
7844
+ if ( !pBNS->type_TACN ||
7845
+ (pBNS->vert[v/2-1].type & pBNS->type_TACN) ) {
7846
+ return 0;
7847
+ }
7848
+ if ( !pBNS->type_T || !pBNS->type_CN )
7849
+ return 0; /* should not happen */
7850
+ #endif
7851
+ u = GetPrevVertex( pBNS, v, SwitchEdge, &iuv );
7852
+ /*
7853
+ u = SwitchEdge_Vert1(v);
7854
+ iuv = SwitchEdge_IEdge(v);
7855
+ */
7856
+ if ( u == NO_VERTEX || iuv < 0 )
7857
+ return 0; /* should not happen */
7858
+ /* check edge adjacency */
7859
+ if ( pBNS->edge[iuv].neighbor1 != (u/2-1) && pBNS->edge[iuv].neighbor1 != v/2-1 ||
7860
+ (pBNS->edge[iuv].neighbor12 ^ (u/2-1)) != (v/2-1) ) {
7861
+ return 0; /* !!! should not happen !!! */
7862
+ }
7863
+
7864
+ #if ( CHECK_TACN == 1 )
7865
+ u_is_taut = ((pBNS->vert[u/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
7866
+ ((pBNS->vert[u/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
7867
+ w_is_taut = ((pBNS->vert[w/2-1].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
7868
+ ((pBNS->vert[w/2-1].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
7869
+ if ( (u_is_taut | w_is_taut) == (TYPE_T | TYPE_CN ) ) {
7870
+ /* rescap must have already been checked */
7871
+ return 1;
7872
+ }
7873
+ #endif
7874
+
7875
+ return 0;
7876
+ #undef TYPE_T
7877
+ #undef TYPE_CN
7878
+ }
7879
+ #else /* } FIX_TACN_POSSIBLE_BUG { */
7880
+ /*********************************************************************************/
6943
7881
  int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge )
6944
7882
  {
6945
7883
  int u_is_taut=0, w_is_taut=0;
@@ -6981,6 +7919,131 @@ int bIgnoreVertexNonTACN_group( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *Switc
6981
7919
 
6982
7920
  return 0;
6983
7921
  }
7922
+ #endif /* } FIX_TACN_POSSIBLE_BUG { */
7923
+
7924
+ #if( FIX_KEEP_H_ON_NH_ANION == 1 )
7925
+ /*********************************************************************************/
7926
+ /* detect an attempt to remove H from -NH(-) to make =N(-); */
7927
+ /* all taut atoma except N are 'acidic' */
7928
+ /*********************************************************************************/
7929
+ int bIsRemovedHfromNHaion( BN_STRUCT* pBNS, Vertex u, Vertex v )
7930
+ {
7931
+ int i, u2, v2, vat2;
7932
+ Vertex vtg, vat;
7933
+ BNS_VERTEX *pvAT, *pvCN;
7934
+ BNS_EDGE *pEdge;
7935
+ if ( !pBNS->type_TACN || u <= 1 || v <= 1 ||
7936
+ u%2 || !(v%2) /* the edge flow may only increase */ ) {
7937
+ return 0;
7938
+ }
7939
+ if ((pBNS->vert[u2 = u/2-1].type & pBNS->type_TACN) ||
7940
+ (pBNS->vert[v2 = v/2-1].type & pBNS->type_TACN) ) {
7941
+ return 0; /* add/remove H is allowed for acidic atoms */
7942
+ }
7943
+ if ( !pBNS->type_T || !pBNS->type_CN )
7944
+ return 0; /* should not happen */
7945
+ /* find which of u, v vertices is N and which is t-group */
7946
+ if ( ((pBNS->vert[u2].type & pBNS->type_T) == pBNS->type_T ) && v2 < pBNS->num_atoms ) {
7947
+ vtg = u;
7948
+ vat = v;
7949
+ } else
7950
+ if ( ((pBNS->vert[v2].type & pBNS->type_T) == pBNS->type_T ) && u2 < pBNS->num_atoms ) {
7951
+ vtg = v;
7952
+ vat = u;
7953
+ } else {
7954
+ return 0;
7955
+ }
7956
+ vat2 = vat/2-1;
7957
+ pvAT = pBNS->vert + vat2; /* atom */
7958
+ for ( i = pvAT->num_adj_edges-1; 0 <= i; i -- ) {
7959
+ pEdge = pBNS->edge + pvAT->iedge[i];
7960
+ pvCN = pBNS->vert + (pEdge->neighbor12 ^ vat2);
7961
+ if ( ((pvCN->type & pBNS->type_CN) == pBNS->type_CN) && pEdge->flow > 0 ) {
7962
+ return 1; /* detected */
7963
+ }
7964
+ }
7965
+ return 0;
7966
+ }
7967
+ #endif
7968
+ #if ( FIX_AVOID_ADP == 1 )
7969
+ /************************************************************************
7970
+ Detect (tg)-N=A-A=A-A=N-(tg)
7971
+ u v w
7972
+ k = 5 4 3 2 1 0 1 2
7973
+ ^
7974
+ odd number means ADP
7975
+ *************************************************************************/
7976
+ int bIsAggressiveDeprotonation( BN_STRUCT* pBNS, Vertex v, Vertex w, Edge *SwitchEdge )
7977
+ {
7978
+ #define TYPE_T 1 /* t-group [also called H-group] */
7979
+ #define TYPE_CN 2 /* (-)c-group */
7980
+ #define TYPE_AT 4
7981
+ int k, v2, u2, w2, u2_next, type0, type1, type2, type;
7982
+ Vertex u, u_next;
7983
+ EdgeIndex iuv;
7984
+ if ( v <= 1 || w <= 1 )
7985
+ return 0;
7986
+
7987
+ if ( !pBNS->type_TACN || !pBNS->type_T || !pBNS->type_CN )
7988
+ return 0; /* should not happen */
7989
+ v2 = v/2 - 1;
7990
+ w2 = w/2 - 1;
7991
+ if ( v2 >= pBNS->num_atoms || w2 < pBNS->num_atoms )
7992
+ goto cross_edge;
7993
+
7994
+ if ( !((pBNS->vert[w2].type & pBNS->type_T) == pBNS->type_T ) &&
7995
+ !((pBNS->vert[w2].type & pBNS->type_CN) == pBNS->type_CN) )
7996
+ goto cross_edge;
7997
+ /* v ia an atom, w is a t-group, v != w' */
7998
+ for ( k = 0, u = v; 1 < (u_next = u, u = GetPrevVertex( pBNS, u, SwitchEdge, &iuv )); k ++ ) {
7999
+ u2 = u/2 - 1;
8000
+ if ( u2 >= pBNS->num_atoms ) {
8001
+ /* moving backward along the alt path we have found a vertex
8002
+ that is not an atom. Possibly it is a t- or (-)c-group */
8003
+ if ( !( k % 2 ) ) {
8004
+ return 0; /* even vertex -- always okay */
8005
+ }
8006
+ if ( !((pBNS->vert[u2].type & pBNS->type_T) == pBNS->type_T ) &&
8007
+ !((pBNS->vert[u2].type & pBNS->type_CN) == pBNS->type_CN) ) {
8008
+ /* not a t- or (-)c-group */
8009
+ return 0;
8010
+ }
8011
+ u2_next = u_next/2 - 1;
8012
+ if ( !(pBNS->vert[v2 ].type & pBNS->type_TACN) &&
8013
+ !(pBNS->vert[u2_next].type & pBNS->type_TACN) ) {
8014
+ /* none of the atoms at the ends are N */
8015
+ return 0;
8016
+ }
8017
+ return 1;
8018
+ }
8019
+ }
8020
+ return 0;
8021
+ cross_edge:
8022
+ /*****************************************************************************
8023
+ * v and w (v=w') are same vertex reached with opposite "phases".
8024
+ * w cannot be (t) because this would have been detected earlier -- ???
8025
+ * (t)-A=A-A=A-A=A-(t)
8026
+ * v
8027
+ * 3 2 1 0 1 2 3 4
8028
+ * kv kw
8029
+ * (kv + kw)%2 == 1 <==> aggressive deprotonation
8030
+ *****************************************************************************/
8031
+ if ( v == prim(w) ) {
8032
+ type0 = 0;
8033
+ if ( v2 >= pBNS->num_atoms ) {
8034
+ type0 = ((pBNS->vert[v2].type & pBNS->type_T) == pBNS->type_T )? TYPE_T :
8035
+ ((pBNS->vert[v2].type & pBNS->type_CN) == pBNS->type_CN)? TYPE_CN : 0;
8036
+ }
8037
+
8038
+
8039
+
8040
+ }
8041
+
8042
+
8043
+ return 0;
8044
+ }
8045
+ #endif
8046
+
6984
8047
  /*********************************************************************************/
6985
8048
  int rescap( BN_STRUCT* pBNS, Vertex u, Vertex v, EdgeIndex iuv )
6986
8049
  {
@@ -7107,12 +8170,20 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
7107
8170
  Vertex *Pv = pBD->Pv;
7108
8171
  int max_len_Pu_Pv= pBD->max_len_Pu_Pv;
7109
8172
 
7110
-
7111
-
7112
8173
  /* added to translate into C */
7113
8174
  int i, k, degree, delta, ret = 0;
7114
8175
  Vertex u, b_u, v, b_v, w;
7115
8176
  EdgeIndex iuv;
8177
+ #if( BNS_RAD_SEARCH == 1 )
8178
+ int n, bRadSearch = (BNS_EF_RAD_SRCH & bChangeFlow) && pBD->RadEndpoints;
8179
+ BRS_MODE bRadSrchMode = RAD_SRCH_NORM;
8180
+ int bRadSearchPrelim = 0;
8181
+ if ( bRadSearch ) {
8182
+ pBD->nNumRadEndpoints = 0;
8183
+ bRadSrchMode = pBD->bRadSrchMode;
8184
+ bRadSearchPrelim = pBNS->type_TACN && bRadSrchMode == RAD_SRCH_NORM;
8185
+ }
8186
+ #endif
7116
8187
 
7117
8188
  /* -- Always --
7118
8189
  Vertex_s = FIRST_INDX;
@@ -7129,12 +8200,23 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
7129
8200
  /* since u is on the queue, it has a blossom C(U) with base b_u */
7130
8201
  b_u = FindBase( u, BasePtr );
7131
8202
  degree = GetVertexDegree( pBNS, u );
8203
+ #if( BNS_RAD_SEARCH == 1 )
8204
+ n = 0;
8205
+ #endif
7132
8206
  for ( i = 0; i < degree; i ++ ) {
7133
8207
  /* v = vert[u].neighbor[i]; */
7134
8208
  v = GetVertexNeighbor( pBNS, u, i, &iuv );
7135
8209
  if ( v == NO_VERTEX ) {
7136
8210
  continue; /* the atom has only single bonds, ignore it */
7137
8211
  }
8212
+ #if( BNS_RAD_SEARCH == 1 )
8213
+ if ( !k && bRadSrchMode == RAD_SRCH_FROM_FICT && v/2 <= pBNS->num_atoms ) {
8214
+ continue; /* start from fict. vertices only */
8215
+ }
8216
+ if ( bRadSearchPrelim && v/2 > pBNS->num_atoms ) {
8217
+ continue; /* during initial add/remove H allow radical movement only through real atoms */
8218
+ }
8219
+ #endif
7138
8220
  if ( /* PrevPt[u] != v ** avoid edges of T */
7139
8221
  ( SwitchEdge_Vert1(u) != v || SwitchEdge_Vert2(u) != u ) /* avoid edges of T */
7140
8222
  && (ret = rescap(pBNS, u, v, iuv)) > 0 ) {
@@ -7147,6 +8229,17 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
7147
8229
  if ( bIgnoreVertexNonTACN_group( pBNS, u, v, SwitchEdge ) ) {
7148
8230
  continue;
7149
8231
  }
8232
+ #if( FIX_KEEP_H_ON_NH_ANION == 1 )
8233
+ if ( bIsRemovedHfromNHaion( pBNS, u, v ) ) {
8234
+ continue;
8235
+ }
8236
+ #endif
8237
+ #if ( FIX_AVOID_ADP == 1 )
8238
+ if ( bIsAggressiveDeprotonation( pBNS, u, v, SwitchEdge ) ) {
8239
+ continue;
8240
+ }
8241
+ #endif
8242
+
7150
8243
  }
7151
8244
  /*----------------------------------------------------------------------*/
7152
8245
  b_v = FindBase(v, BasePtr); /* Notation: b_x is a base of x */
@@ -7217,14 +8310,23 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
7217
8310
 
7218
8311
  BasePtr[prim(v)] = v;
7219
8312
  BasePtr[v] = BLOSSOM_BASE; /* create a trivial blossom C(v) with base v */
8313
+ #if( BNS_RAD_SEARCH == 1 )
8314
+ n ++;
8315
+ #endif
7220
8316
  } else
7221
8317
  if ( TREE_IS_S_REACHABLE(prim(v)) /*Is_s_Reachable(prim(v)*/
7222
8318
  /* if v' is reachable, an st-path is given by P(u)-uv-P'(v') */
7223
8319
  /*&& PrevPt[prim(u)] != prim(v) ** avoid edges of T' */
7224
8320
  && (SwitchEdge_Vert1(prim(u)) != prim(v) || SwitchEdge_Vert2(prim(u)) != prim(u)) /* avoid edges of T' */
7225
8321
  && b_u != b_v
7226
- && !(pBNS->type_TACN && bIgnoreVertexNonTACN_group( pBNS, prim(v), u, SwitchEdge )) ) {
7227
-
8322
+ && !(pBNS->type_TACN && bIgnoreVertexNonTACN_group( pBNS, prim(v), u, SwitchEdge ))
8323
+ #if( FIX_KEEP_H_ON_NH_ANION == 1 )
8324
+ && !(pBNS->type_TACN && bIsRemovedHfromNHaion( pBNS, prim(v), u ))
8325
+ #endif
8326
+ ) {
8327
+ #if( BNS_RAD_SEARCH == 1 )
8328
+ n ++;
8329
+ #endif
7228
8330
  /* there is now a valid sv-path via u avoiding b_v (unless v==b_v)
7229
8331
  => u, v, u', and v' now all become part of the same connected component of M[C] */
7230
8332
  w = MakeBlossom( pBNS, ScanQ, &QSize, Pu, Pv, max_len_Pu_Pv, SwitchEdge, BasePtr, u, v, iuv, b_u, b_v, Tree );
@@ -7239,9 +8341,8 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
7239
8341
  delta = FindPathCap( pBNS, SwitchEdge, Vertex_s, Vertex_t, 10000 ); /* compute the residual capacity of P + P' */
7240
8342
  if ( IS_BNS_ERROR( delta ) ) {
7241
8343
  pBD->QSize = QSize;
7242
- return delta;
8344
+ return delta; /* error */
7243
8345
  }
7244
-
7245
8346
  #if( ALLOW_ONLY_SIMPLE_ALT_PATH == 1 )
7246
8347
  if ( pBNS->bNotASimplePath || abs(delta) > 1 ) {
7247
8348
  delta = 0;
@@ -7258,11 +8359,19 @@ int BalancedNetworkSearch ( BN_STRUCT* pBNS, BN_DATA *pBD, int bChangeFlow )
7258
8359
  } else
7259
8360
  if ( IS_BNS_ERROR( ret ) ) {
7260
8361
  pBD->QSize = QSize;
7261
- return ret;
8362
+ return ret; /* error */
7262
8363
  }
7263
-
7264
-
7265
8364
  }
8365
+ #if( BNS_RAD_SEARCH == 1 )
8366
+ if ( bRadSearch && !n ) {
8367
+ /* the BNS stopped at u */
8368
+ n = RegisterRadEndpoint( pBNS, pBD, u);
8369
+ if ( IS_BNS_ERROR( n ) ) {
8370
+ pBD->QSize = QSize;
8371
+ return n;
8372
+ }
8373
+ }
8374
+ #endif
7266
8375
  k ++; /* advance ScanQ */
7267
8376
  } while( k <= QSize );
7268
8377
  /* if this point is reached, no valid augmenting path exists, ScanQ contains
@@ -7538,6 +8647,16 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
7538
8647
  */
7539
8648
  Vertex w, z, iwz;
7540
8649
  int cap, delta2;
8650
+ static int level;
8651
+
8652
+ if ( level ++ > 50 ) {
8653
+ #ifdef _DEBUG
8654
+ int stop = 1;
8655
+ #else
8656
+ ;
8657
+ #endif
8658
+ }
8659
+
7541
8660
 
7542
8661
  w = SwitchEdge_Vert1(y);
7543
8662
  z = SwitchEdge_Vert2(y); /* wz is on the path P */
@@ -7547,6 +8666,7 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
7547
8666
  cap = rescap_mark( pBNS, w, z, iwz );
7548
8667
 
7549
8668
  if ( IS_BNS_ERROR( cap ) ) {
8669
+ level --;
7550
8670
  return cap;
7551
8671
  }
7552
8672
  if ( cap < delta ) {
@@ -7561,6 +8681,7 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
7561
8681
  delta2 = FindPathCap( pBNS, SwitchEdge, prim(y), prim(z), delta );
7562
8682
  delta = inchi_min( delta2, delta );
7563
8683
  }
8684
+ level --;
7564
8685
  return delta;
7565
8686
  }
7566
8687
 
@@ -7569,18 +8690,19 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
7569
8690
  #define BT_ALTERN_BOND 1 /* 1-2, possibly stereo */
7570
8691
  #define BT_OTHER_ALTERN_BOND 2 /* 1-3, 2-3, 1-2-3 alternating non-stereo non-taut bonds */
7571
8692
 
7572
- #define BT_ALT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND)
7573
-
7574
8693
  #define BT_ALTERN_NS_BOND 4
7575
8694
 
7576
- #define BT_NONTAUT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND|BT_ALTERN_NS_BOND)
7577
-
7578
8695
  #define BT_TAUTOM_BOND 8
7579
8696
 
8697
+ #define BT_ALTERN_UNKN_BOND 16
8698
+
7580
8699
  #define BT_IGNORE_BOND 0
7581
8700
 
7582
8701
  #define BT_NONSTEREO_MASK (BT_TAUTOM_BOND|BT_ALTERN_NS_BOND)
7583
8702
 
8703
+ #define BT_ALT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND)
8704
+
8705
+ #define BT_NONTAUT_BOND_MASK (BT_ALTERN_BOND|BT_OTHER_ALTERN_BOND|BT_ALTERN_NS_BOND)
7584
8706
 
7585
8707
  /* BNS members redefinitions for finding non-stereo bonds */
7586
8708
  /* BNS_EDGE */
@@ -7603,7 +8725,7 @@ int FindPathCap( BN_STRUCT* pBNS, Edge *SwitchEdge, Vertex x, Vertex y, int delt
7603
8725
 
7604
8726
 
7605
8727
  /********************************************************************************/
7606
- int MarkRingSystemsAltBns( BN_STRUCT* pBNS )
8728
+ int MarkRingSystemsAltBns( BN_STRUCT* pBNS, int bUnknAltAsNoStereo )
7607
8729
  {
7608
8730
  AT_NUMB *nStackAtom = NULL;
7609
8731
  int nTopStackAtom;
@@ -7627,10 +8749,10 @@ int MarkRingSystemsAltBns( BN_STRUCT* pBNS )
7627
8749
  nRingStack = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nRingStack[0]));
7628
8750
  nDfsNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nDfsNumber[0]));
7629
8751
  nLowNumber = (AT_NUMB *)inchi_malloc(num_atoms*sizeof(nLowNumber[0]));
7630
- nBondStack = (AT_NUMB *)inchi_malloc(num_edges*sizeof(nBondStack[0]));
8752
+ nBondStack = (AT_NUMB *)(num_edges? inchi_malloc(num_edges*sizeof(nBondStack[0])):NULL); /* special case: no bonds 2006-03 */
7631
8753
  cNeighNumb = (S_CHAR *)inchi_malloc(num_atoms*sizeof(cNeighNumb[0]));
7632
8754
  /* check allocation */
7633
- if ( !nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || !nBondStack || !cNeighNumb
8755
+ if ( !nStackAtom || !nRingStack || !nDfsNumber || !nLowNumber || !nBondStack && num_edges || !cNeighNumb
7634
8756
  ) {
7635
8757
  nNumRingSystems = CT_OUT_OF_RAM; /* program error */ /* <BRKPT> */
7636
8758
  goto exit_function;
@@ -7693,7 +8815,10 @@ found_alt:
7693
8815
 
7694
8816
  do {
7695
8817
  /* advance */
7696
- while ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) ) {
8818
+ /*while ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
8819
+ /* replaced due to missing sequence point */
8820
+ while ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i], (int)at[i].valenceAltBns > j )
8821
+ {
7697
8822
  cNeighNumb[i] ++;
7698
8823
  if ( !(bond[w=at[i].iedge[j]].nBondTypeInpAltBns & BT_ALT_BOND_MASK) ) {
7699
8824
  continue;
@@ -7797,7 +8922,10 @@ found_alt2:
7797
8922
  do {
7798
8923
  /* advance */
7799
8924
  advance_ring:
7800
- if ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) ) {
8925
+ /*if ( (int)at[i=nStackAtom[nTopStackAtom]].valenceAltBns > (j = (int)cNeighNumb[i]) )*/
8926
+ /* replaced due to missing sequence point */
8927
+ if ( i=(int)nStackAtom[nTopStackAtom], j = (int)cNeighNumb[i], (int)at[i].valenceAltBns > j )
8928
+ {
7801
8929
  cNeighNumb[i] ++;
7802
8930
  if ( !(bond[at[i].iedge[j]].nBondTypeInpAltBns & BT_ALTERN_BOND) ) {
7803
8931
  goto advance_ring;
@@ -7876,7 +9004,7 @@ exit_function:
7876
9004
  }
7877
9005
 
7878
9006
  /*********************************************************************************/
7879
- int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
9007
+ int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo )
7880
9008
  {
7881
9009
  Vertex v, v2;
7882
9010
  int ret, bond_type, num_to_test, j;
@@ -7884,6 +9012,11 @@ int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
7884
9012
  BNS_VERTEX *pAtom;
7885
9013
  /* strip all t-groups and c-groups */
7886
9014
  num_to_test = 0;
9015
+ if ( bUnknAltAsNoStereo ) {
9016
+ for ( j = 0; j < pBNS->num_edges; j ++ ) {
9017
+ pBNS->edge[j].pass = 0;
9018
+ }
9019
+ }
7887
9020
  ret = ReInitBnStruct( pBNS, at, num_atoms, 0 );
7888
9021
  if ( ret || pBNS->num_atoms != num_atoms || pBNS->num_vertices != num_atoms || pBNS->num_bonds != pBNS->num_edges ) {
7889
9022
  ret = BNS_REINIT_ERR;
@@ -7900,6 +9033,13 @@ int ReInitBnStructForAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
7900
9033
  if ( at[v].endpoint || at[v2].endpoint ) {
7901
9034
  bond_type = 0; /* any bond to an endpoint considered non-stereogenic */
7902
9035
  }
9036
+ #if( FIX_EITHER_DB_AS_NONSTEREO == 1 )
9037
+ if ( bUnknAltAsNoStereo ) {
9038
+ if ( bond_type == BOND_ALTERN && at[v].bond_stereo[j] == STEREO_DBLE_EITHER ) {
9039
+ bond_type = 0; /* treat unknown (Either) ALT bond as non-stereo */
9040
+ }
9041
+ }
9042
+ #endif
7903
9043
  switch ( bond_type ) {
7904
9044
 
7905
9045
  case BOND_ALTERN :
@@ -7954,7 +9094,7 @@ exit_function:
7954
9094
  }
7955
9095
 
7956
9096
  /************************************************************************************/
7957
- int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
9097
+ int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms, int bUnknAltAsNoStereo )
7958
9098
  {
7959
9099
  int num_bonds = pBNS->num_bonds;
7960
9100
  int ret;
@@ -7968,27 +9108,53 @@ int MarkNonStereoAltBns( BN_STRUCT *pBNS, inp_ATOM *at, int num_atoms )
7968
9108
  ret = BNS_REINIT_ERR;
7969
9109
  goto exit_function;
7970
9110
  }
7971
-
7972
- for ( ibond=0; ibond < num_bonds; ibond ++ ) {
7973
- pBond = pBNS->edge + ibond;
7974
- if ( pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND ) {
7975
- continue;
9111
+ if ( bUnknAltAsNoStereo ) {
9112
+ for ( ibond=0; ibond < num_bonds; ibond ++ ) {
9113
+ pBond = pBNS->edge + ibond;
9114
+ if ( pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND ) {
9115
+ continue;
9116
+ }
9117
+ iat1 = pBond->neighbor1;
9118
+ iat2 = pBond->neighbor12 ^ iat1;
9119
+ ib1 = pBond->neigh_ord[0];
9120
+ ib2 = pBond->neigh_ord[1];
9121
+ if ( /* alt bond non-adjacent to a taut. endpoint: */
9122
+ (pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
9123
+ pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
9124
+ /* alt bond adjacent to a taut. endpoint: */
9125
+ (pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
9126
+ (at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN )
9127
+ ) {
9128
+ if ( (at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN ) {
9129
+ /* bond_type = BOND_ALT12NS; */
9130
+ at[iat1].bond_stereo[ib1] =
9131
+ at[iat2].bond_stereo[ib2] =STEREO_DBLE_EITHER;
9132
+ ret ++;
9133
+ }
9134
+ }
9135
+ }
9136
+ } else {
9137
+ for ( ibond=0; ibond < num_bonds; ibond ++ ) {
9138
+ pBond = pBNS->edge + ibond;
9139
+ if ( pBond->nBondTypeInpAltBns != BT_ALTERN_BOND && pBond->nBondTypeInpAltBns != BT_IGNORE_BOND ) {
9140
+ continue;
9141
+ }
9142
+ iat1 = pBond->neighbor1;
9143
+ iat2 = pBond->neighbor12 ^ iat1;
9144
+ ib1 = pBond->neigh_ord[0];
9145
+ ib2 = pBond->neigh_ord[1];
9146
+ if ( /* alt bond non-adjacent to a taut. endpoint: */
9147
+ (pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
9148
+ pBond->nNumAtInBlockAltBns <= 3 ) /* non-ring bond */ ||
9149
+ /* alt bond adjacent to a taut. endpoint: */
9150
+ (pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
9151
+ (at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN )
9152
+ ) {
9153
+ at[iat1].bond_type[ib1] =
9154
+ at[iat2].bond_type[ib2] =BOND_ALT12NS;
9155
+ ret ++;
9156
+ }
7976
9157
  }
7977
- iat1 = pBond->neighbor1;
7978
- iat2 = pBond->neighbor12 ^ iat1;
7979
- ib1 = pBond->neigh_ord[0];
7980
- ib2 = pBond->neigh_ord[1];
7981
- if ( /* alt bond non-adjacent to a taut. endpoint: */
7982
- (pBond->nBondTypeInpAltBns == BT_ALTERN_BOND &&
7983
- pBond->nNumAtInBlockAltBns <= 3 ) ||
7984
- /* alt bond adjacent to a taut. endpoint: */
7985
- (pBond->nBondTypeInpAltBns == BT_IGNORE_BOND &&
7986
- (at[iat1].bond_type[ib1] & BOND_TYPE_MASK) == BOND_ALTERN )
7987
- ) {
7988
- at[iat1].bond_type[ib1] =
7989
- at[iat2].bond_type[ib2] =BOND_ALT12NS;
7990
- ret ++;
7991
- }
7992
9158
  }
7993
9159
 
7994
9160
  exit_function:
@@ -7996,4 +9162,384 @@ exit_function:
7996
9162
  return ret;
7997
9163
  }
7998
9164
 
9165
+ #if( READ_INCHI_STRING == 1 )
9166
+ /*****************************************************************/
9167
+ #ifndef RI_ERR_ALLOC
9168
+ /* from ichirvrs.h */
9169
+ #define RI_ERR_ALLOC (-1)
9170
+ #define RI_ERR_SYNTAX (-2)
9171
+ #define RI_ERR_PROGR (-3)
9172
+ #endif
9173
+ /*****************************************************************/
9174
+ int bHasChargedNeighbor( inp_ATOM *at, int iat )
9175
+ {
9176
+ int i;
9177
+ for( i = 0; i < at[iat].valence; i ++ ) {
9178
+ if ( at[(int)at[iat].neighbor[i]].charge )
9179
+ return 1;
9180
+ }
9181
+ return 0;
9182
+ }
9183
+ /***********************************************************************************************
9184
+ *num_protons_to_add = nToBeRemovedByNormFromRevrs
9185
+
9186
+ nToBeRemovedByNormFromRevrs > 0: less protons should be allowed to be
9187
+ added by the Normalization of the Reconstructed Structure
9188
+ nToBeRemovedByNormFromRevrs < 0: prepare more H(+) to be removed by
9189
+ the InChI Normalization of the Reconstructed Structure
9190
+
9191
+ OrigStruct -> NormOrig + n(orig)*H(+)
9192
+ RevrStruct -> NormRevr + n(revr)*H(+)
9193
+ nToBeRemovedByNormFromRevrs = n(orig) - n(revr) [each may be negative]
9194
+
9195
+ n(orig) > n(revr) or nToBeRemovedByNormFromRevrs > 0 means:
9196
+ -----------------------------------------------------------
9197
+ - Too many protons were added by the Normalization to the Reconstructed Structure
9198
+ (a) n(revr) < 0 => protons were added while they should not have been added;
9199
+ Solution: "neutralize" (-) charged proton acceptors by moving charges to other atoms
9200
+ on the condition ADP cannot add in another way;
9201
+ (b) n(orig) > n(revr) => 0 => too few protons were removed
9202
+ Solution: (the easiest) attach H(+) to =O or -N< or -N=
9203
+ Solution: move (+) from N or OH to an atom adjacent to (-) charge or to
9204
+ an atom that is not N.
9205
+
9206
+ n(orig) < n(revr) or nToBeRemovedByNormFromRevrs < 0 means:
9207
+ -----------------------------------------------------------
9208
+ - Too few protons were added by the Normalization to the Reconstructed Stucture
9209
+ (a) n(orig) < 0 => protons were not added while they should have been added;
9210
+ Solution: move (-) to O by replacing =O with -O(-)
9211
+ (b) 0 <= n(orig) < n(revr) => too many protons were removed
9212
+
9213
+ Note: it is critically important to takr into account cumbersome Normalization
9214
+ Total Charge: if it is >= 0 then no H(+) may be removed from -OH or by ADP
9215
+ However, if N(+) is present then ADP will always try to remove a proton
9216
+ *********************************************************************************************/
9217
+ int AddRemoveProtonsRestr( inp_ATOM *at, int num_atoms, int *num_protons_to_add,
9218
+ int nNumProtAddedByRestr, INCHI_MODE bNormalizationFlags,
9219
+ int num_tg, int nChargeRevrs, int nChargeInChI )
9220
+ {
9221
+ int i, j, ret = 0;
9222
+ int nAtTypeTotals[ATTOT_ARRAY_LEN];
9223
+ int num_prot = *num_protons_to_add;
9224
+ int type, mask, bSuccess, nTotCharge, nNumSuccess = 0;
9225
+ int max_j_Aa=-1, max_j_Ar=-1;
9226
+
9227
+ /* for the reference:
9228
+
9229
+ #define FLAG_NORM_CONSIDER_TAUT ( FLAG_PROTON_NPO_SIMPLE_REMOVED | \
9230
+ FLAG_PROTON_NP_HARD_REMOVED | \
9231
+ FLAG_PROTON_AC_SIMPLE_ADDED | \
9232
+ FLAG_PROTON_AC_SIMPLE_REMOVED | \
9233
+ FLAG_PROTON_AC_HARD_REMOVED | \
9234
+ FLAG_PROTON_AC_HARD_ADDED | \
9235
+ FLAG_PROTON_SINGLE_REMOVED | \
9236
+ FLAG_PROTON_CHARGE_CANCEL )
9237
+
9238
+ #define FLAG_FORCE_SALT_TAUT ( FLAG_PROTON_NP_HARD_REMOVED | \
9239
+ FLAG_PROTON_AC_HARD_REMOVED | \
9240
+ FLAG_PROTON_AC_HARD_ADDED )
9241
+
9242
+ */
9243
+ /* if ChargeRevrs > nChargeInChI then we should prevent proton addition or facilitate proton removal
9244
+ a typical case is (=) on N or O instead of C(-)
9245
+
9246
+ if ChargeRevrs < nChargeInChI then we should prevent proton removal or facilitate proton addition
9247
+ */
9248
+
9249
+ mark_at_type( at, num_atoms, nAtTypeTotals );
9250
+ for ( i = nTotCharge = 0; i < num_atoms; i ++ ) {
9251
+ nTotCharge += at[i].charge;
9252
+ }
9253
+ /* size for SimpleAddAcidicProtons() */
9254
+ for ( max_j_Aa = 0; AaTypMask[2*max_j_Aa]; max_j_Aa ++ )
9255
+ ;
9256
+ /* size for SimpleRemoveAcidicProtons */
9257
+ for ( max_j_Ar = 0; ArTypMask[2*max_j_Ar]; max_j_Ar ++ )
9258
+ ;
9259
+ if ( num_prot < 0 && nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr <= 0 ) {
9260
+ /* remove proton(s) */
9261
+ /* use test from SimpleAddAcidicProtons() to test whether removal of H(+) from =C-OH, etc. is correct */
9262
+ for ( i = 0; i < num_atoms && num_prot; i ++ ) {
9263
+ /* choose an atom */
9264
+ if ( at[i].sb_parity[0] || at[i].p_parity || at[i].charge ||
9265
+ !at[i].num_H || at[i].radical || bHasChargedNeighbor( at, i ) ) {
9266
+ continue;
9267
+ }
9268
+ /* try to remove a proton and check whether InChI would add it back */
9269
+ at[i].charge --;
9270
+ at[i].num_H --;
9271
+ type = GetAtomChargeType( at, i, NULL, &mask, 0 );
9272
+ at[i].charge ++;
9273
+ at[i].num_H ++;
9274
+
9275
+ if ( type ) {
9276
+ for ( bSuccess = 0, j = 0; j < max_j_Aa; j ++ ) {
9277
+ if ( bSuccess = (type & AaTypMask[2*j]) && (mask && AaTypMask[2*j+1]) ) {
9278
+ break; /* the proton may be added to this atom */
9279
+ }
9280
+ }
9281
+ if ( bSuccess ) {
9282
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
9283
+ at[i].charge --;
9284
+ at[i].num_H --;
9285
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
9286
+ num_prot ++; /* success */
9287
+ nNumSuccess ++;
9288
+ }
9289
+ }
9290
+ }
9291
+ }
9292
+ if ( num_prot < 0 && num_tg && nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr <= 0 ) {
9293
+ /* alternative proton removal: O=C-NH => (-)O-C=N, O and N are taut. endpoints */
9294
+ int endp2, centp, k, i0, k0;
9295
+ for ( i = 0; i < num_atoms; i ++ ) {
9296
+ /* choose an atom */
9297
+ if ( !at[i].endpoint || at[i].sb_parity[0] || at[i].p_parity ||
9298
+ at[i].radical || at[i].charge || bHasChargedNeighbor( at, i ) ) {
9299
+ continue;
9300
+ }
9301
+ /* looking for tautomeric =O */
9302
+ if ( 1 != at[i].valence || BOND_TYPE_DOUBLE != at[i].bond_type[0] || at[i].num_H ||
9303
+ 2 != get_endpoint_valence( at[i].el_number ) ) {
9304
+ continue;
9305
+ }
9306
+ centp = at[i].neighbor[0];
9307
+ if ( at[centp].sb_parity[0] || at[centp].p_parity || !is_centerpoint_elem( at[centp].el_number ) ) {
9308
+ continue;
9309
+ }
9310
+ /* found a possible centerpoint, looking for -NH endpoint */
9311
+ for ( k = 0; k < at[centp].valence; k ++ ) {
9312
+ if ( at[centp].bond_type[k] != BOND_TYPE_SINGLE ) {
9313
+ continue;
9314
+ }
9315
+ endp2 = at[centp].neighbor[k];
9316
+ if ( at[endp2].endpoint != at[i].endpoint ||
9317
+ !at[endp2].num_H || at[endp2].charge ||
9318
+ at[endp2].sb_parity[0] || at[endp2].p_parity ||
9319
+ at[endp2].valence != at[endp2].chem_bonds_valence ||
9320
+ 3 != at[endp2].chem_bonds_valence + at[endp2].num_H ||
9321
+ 3 != get_endpoint_valence( at[endp2].el_number ) ) {
9322
+ continue;
9323
+ }
9324
+ /* find bonds in reciprocal ajacency lists */
9325
+ for ( i0 = 0; i0 < at[centp].valence && i != at[centp].neighbor[i0]; i0 ++ )
9326
+ ;
9327
+ for ( k0 = 0; k0 < at[endp2].valence && centp != at[endp2].neighbor[k0]; k0 ++ )
9328
+ ;
9329
+ if ( i0 == at[centp].valence || k0 == at[endp2].valence ) {
9330
+ return RI_ERR_PROGR;
9331
+ }
9332
+ /* -NH has been found */
9333
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
9334
+ type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 1 ); /* subtract at[endp2] */
9335
+
9336
+ at[i].bond_type[0] --;
9337
+ at[centp].bond_type[i0] --;
9338
+ at[i].chem_bonds_valence --;
9339
+ at[i].charge --;
9340
+
9341
+ at[endp2].bond_type[k0] ++;
9342
+ at[centp].bond_type[k] ++;
9343
+ at[endp2].chem_bonds_valence ++;
9344
+ at[endp2].num_H --;
9345
+
9346
+ num_prot ++;
9347
+ nNumSuccess ++;
9348
+
9349
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add at[i] */
9350
+ type = GetAtomChargeType( at, endp2, nAtTypeTotals, &mask, 0 ); /* add at[endp2] */
9351
+ }
9352
+ }
9353
+ }
9354
+ if ( num_prot > 0 ) {
9355
+ /* add protons */
9356
+ /* 1. Use test from SimpleRemoveAcidicProtons() to test whether addition of H(+) to =C-O(-), etc. is correct */
9357
+ for ( i = 0; i < num_atoms && num_prot && nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr >= 0; i ++ ) {
9358
+ /* choose an atom */
9359
+ if ( at[i].sb_parity[0] || at[i].p_parity || at[i].num_H ||
9360
+ at[i].charge != -1 || at[i].radical || bHasChargedNeighbor( at, i ) ) {
9361
+ continue;
9362
+ }
9363
+ /* try to add a proton and check whether InChI would remove it back */
9364
+ at[i].charge ++;
9365
+ at[i].num_H ++;
9366
+ type = GetAtomChargeType( at, i, NULL, &mask, 0 );
9367
+ at[i].charge --;
9368
+ at[i].num_H --;
9369
+
9370
+ if ( type ) {
9371
+ for ( bSuccess = 0, j = 0; j < max_j_Ar; j ++ ) {
9372
+ if ( bSuccess = (type & ArTypMask[2*j]) && (mask && ArTypMask[2*j+1]) ) {
9373
+ break;
9374
+ }
9375
+ }
9376
+ if ( bSuccess ) {
9377
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
9378
+ at[i].charge ++;
9379
+ at[i].num_H ++;
9380
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
9381
+ num_prot --; /* success */
9382
+ nNumSuccess ++;
9383
+ }
9384
+ }
9385
+ }
9386
+ /* 2. Use test from SimpleRemoveHplusNPO() */
9387
+ for ( i = 0; i < num_atoms && num_prot; i ++ ) {
9388
+ /* choose an atom */
9389
+ if ( at[i].sb_parity[0] || at[i].p_parity ||
9390
+ at[i].charge || at[i].radical || bHasChargedNeighbor( at, i ) ) {
9391
+ continue;
9392
+ }
9393
+ /* try to add a proton and check whether InChI would remove it back */
9394
+ at[i].num_H ++;
9395
+ at[i].charge ++;
9396
+ bSuccess = (PR_SIMPLE_TYP & (type = GetAtomChargeType( at, i, NULL, &mask, 0 )) ) &&
9397
+ (PR_SIMPLE_MSK & mask );
9398
+ at[i].num_H --; /* failed */
9399
+ at[i].charge --;
9400
+ if ( bSuccess ) {
9401
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
9402
+ at[i].num_H ++;
9403
+ at[i].charge ++;
9404
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
9405
+ num_prot --; /* succeeded */
9406
+ nNumSuccess ++;
9407
+ }
9408
+ }
9409
+ }
9410
+
9411
+ if ( num_prot < 0 && (bNormalizationFlags & FLAG_PROTON_AC_HARD_ADDED) && 1 == num_tg &&
9412
+ nAtTypeTotals[ATTOT_TOT_CHARGE]-nNumProtAddedByRestr <= 0 ) {
9413
+ /* try to remove protons from tautomeric N (specific ADP must be present) */
9414
+ int nNumAcceptors_DB_O=0, nNumDonors_SB_NH=0, num_max, num_success;
9415
+ for ( i = 0; i < num_atoms; i ++ ) {
9416
+ /* choose an atom */
9417
+ if ( !at[i].endpoint || at[i].radical ||
9418
+ at[i].sb_parity[0] || at[i].p_parity || bHasChargedNeighbor( at, i ) ) {
9419
+ continue;
9420
+ }
9421
+ type = GetAtomChargeType( at, i, NULL, &mask, 0 );
9422
+ if ( (type & AA_HARD_TYP_CO) && (mask & AA_HARD_MSK_CO) ) {
9423
+ nNumAcceptors_DB_O ++;
9424
+ } else
9425
+ if ( (type == ATT_ATOM_N ) && (mask == ATBIT_NP_H) && !at[i].charge &&
9426
+ at[i].valence == at[i].chem_bonds_valence ) {
9427
+ nNumDonors_SB_NH ++;
9428
+ }
9429
+ }
9430
+ num_max = inchi_min( nNumAcceptors_DB_O, nNumDonors_SB_NH );
9431
+ for ( i = 0, num_success = 0; i < num_atoms && num_success < num_max && num_prot < 0; i ++ ) {
9432
+ /* choose an atom */
9433
+ if ( !at[i].endpoint|| at[i].radical || at[i].sb_parity[0] ||
9434
+ at[i].p_parity || bHasChargedNeighbor( at, i ) ) {
9435
+ continue;
9436
+ }
9437
+ type = GetAtomChargeType( at, i, NULL, &mask, 0 );
9438
+ if ( (type == ATT_ATOM_N ) && (mask == ATBIT_NP_H) && !at[i].charge &&
9439
+ at[i].valence == at[i].chem_bonds_valence ) {
9440
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 1 ); /* subtract at[i] */
9441
+ at[i].num_H --;
9442
+ at[i].charge --;
9443
+ type = GetAtomChargeType( at, i, nAtTypeTotals, &mask, 0 ); /* add changed at[i] */
9444
+ num_prot ++;
9445
+ num_success ++;
9446
+ nNumSuccess ++;
9447
+ }
9448
+ }
9449
+ }
9450
+ /*exit_function:*/
9451
+ *num_protons_to_add = num_prot;
9452
+ return ret<0? ret : nNumSuccess;
9453
+ }
9454
+ /*****************************************************************/
9455
+ int AddRemoveIsoProtonsRestr( inp_ATOM *at, int num_atoms, NUM_H num_protons_to_add[], int num_tg )
9456
+ {
9457
+ int i, j, k, n, ret = 0;
9458
+ int nNumSuccess = 0, min_at, max_at, num_H, num_iso_H, num_expl_H, num_expl_iso_H;
9459
+ int iCurIso; /* 0=> 1H, 1=> D, 2=> T */
9460
+ int iCurMode, iCurMode1, iCurMode2; /* 0=> Not Endpoints, 1=> Endpoints */
9461
+ static U_CHAR el_number_H = 0;
9462
+
9463
+ /* distribute isotopes from heaviest to lightest; pick up atoms in order 1. Not endpoints; 2. Endpoints */
9464
+ iCurMode1 = 0;
9465
+ iCurMode2 = num_tg ? 1 : 0;
9466
+ if ( !el_number_H ) {
9467
+ el_number_H = (U_CHAR) get_periodic_table_number( "H" );
9468
+ }
9469
+ for ( iCurMode = iCurMode1; iCurMode <= iCurMode2; iCurMode ++ ) {
9470
+ for ( iCurIso = 2; 0 <= iCurIso; iCurIso -- ) {
9471
+ /* check for isotopic H to add */
9472
+ if ( !num_protons_to_add[iCurIso] ) {
9473
+ continue;
9474
+ }
9475
+ if ( 0 > num_protons_to_add[iCurIso] ) {
9476
+ ret = RI_ERR_PROGR;
9477
+ goto exit_function;
9478
+ }
9479
+ /* limits for atom scanning */
9480
+ min_at = 0;
9481
+ max_at = num_atoms;
9482
+ /* cycle withio the limits */
9483
+ for ( i = min_at; i < max_at && 0 < num_protons_to_add[iCurIso]; i ++ ) {
9484
+ /* pick an atom */
9485
+ if ( iCurMode ) {
9486
+ if ( at[i].endpoint )
9487
+ j = i; /* atom number */
9488
+ else
9489
+ continue;
9490
+ } else
9491
+ if ( !at[i].endpoint &&
9492
+ 1 == bHeteroAtomMayHaveXchgIsoH( at, i ) ) { /* atom number */
9493
+ j = i;
9494
+ } else
9495
+ if ( at[i].el_number == el_number_H && at[i].charge == 1 &&
9496
+ !at[i].valence && !at[i].radical && !at[i].iso_atw_diff ) {
9497
+ /* proton, not isotopic; make it isotopic */
9498
+ at[i].iso_atw_diff = 1 + iCurIso;
9499
+ num_protons_to_add[iCurIso] --;
9500
+ nNumSuccess ++;
9501
+ continue;
9502
+ } else {
9503
+ continue;
9504
+ }
9505
+ /* j is the atom number */
9506
+ /* count implicit H */
9507
+ num_H = at[j].num_H;
9508
+ num_iso_H = NUM_ISO_H(at,j);
9509
+ while ( num_H > 0 && num_protons_to_add[iCurIso] > 0 ) {
9510
+ /* substitute one implicit H with an isotopic atom H */
9511
+ at[j].num_iso_H[iCurIso] ++;
9512
+ at[j].num_H --;
9513
+ num_protons_to_add[iCurIso] --;
9514
+ num_H --;
9515
+ num_iso_H ++;
9516
+ nNumSuccess ++;
9517
+ }
9518
+ /* count explicit H */
9519
+ num_expl_H = num_expl_iso_H = 0;
9520
+ for ( k = 0; k < at[j].valence && num_atoms <= (n=at[j].neighbor[k]); k ++ ) {
9521
+ num_expl_H += (0 == at[n].iso_atw_diff);
9522
+ num_expl_iso_H += (0 != at[n].iso_atw_diff);
9523
+ }
9524
+ while ( num_expl_H > 0 && num_protons_to_add[iCurIso] > 0 ) {
9525
+ /* substitute one explicit H with an isotopic atom H */
9526
+ n = at[j].neighbor[num_expl_H];
9527
+ if ( at[n].iso_atw_diff ) {
9528
+ ret = RI_ERR_PROGR;
9529
+ goto exit_function;
9530
+ }
9531
+ at[n].iso_atw_diff = 1 + iCurIso;
9532
+ num_expl_H --;
9533
+ num_expl_iso_H ++;
9534
+ num_protons_to_add[iCurIso] --;
9535
+ nNumSuccess ++;
9536
+ }
9537
+ }
9538
+ }
9539
+ }
9540
+ exit_function:
9541
+ return ret<0? ret : nNumSuccess;
9542
+ }
9543
+
9544
+ #endif
7999
9545