chython 2.4__cp312-cp312-win_amd64.whl

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 (171) hide show
  1. chython/__init__.py +31 -0
  2. chython/_functions.py +69 -0
  3. chython/algorithms/__init__.py +18 -0
  4. chython/algorithms/_isomorphism.cp312-win_amd64.pyd +0 -0
  5. chython/algorithms/_isomorphism.pyx +189 -0
  6. chython/algorithms/aromatics/__init__.py +27 -0
  7. chython/algorithms/aromatics/_rules.py +124 -0
  8. chython/algorithms/aromatics/kekule.py +530 -0
  9. chython/algorithms/aromatics/test/__init__.py +18 -0
  10. chython/algorithms/aromatics/test/test_kekule.py +160 -0
  11. chython/algorithms/aromatics/test/test_thiele.py +263 -0
  12. chython/algorithms/aromatics/thiele.py +226 -0
  13. chython/algorithms/calculate2d/__init__.py +23 -0
  14. chython/algorithms/calculate2d/clean2d.js +1 -0
  15. chython/algorithms/calculate2d/molecule.py +149 -0
  16. chython/algorithms/calculate2d/reaction.py +80 -0
  17. chython/algorithms/depict.py +523 -0
  18. chython/algorithms/fingerprints/__init__.py +48 -0
  19. chython/algorithms/fingerprints/linear.py +208 -0
  20. chython/algorithms/fingerprints/morgan.py +137 -0
  21. chython/algorithms/fingerprints/test/__init__.py +18 -0
  22. chython/algorithms/fingerprints/test/test_linear.py +127 -0
  23. chython/algorithms/fingerprints/test/test_morgan.py +79 -0
  24. chython/algorithms/isomorphism.py +667 -0
  25. chython/algorithms/mapping/__init__.py +28 -0
  26. chython/algorithms/mapping/_groups.py +94 -0
  27. chython/algorithms/mapping/_reactions.py +72 -0
  28. chython/algorithms/mapping/attention.py +216 -0
  29. chython/algorithms/mapping/fixmapper.py +84 -0
  30. chython/algorithms/mapping/groups.py +137 -0
  31. chython/algorithms/mcs.py +202 -0
  32. chython/algorithms/morgan.py +82 -0
  33. chython/algorithms/rings.py +551 -0
  34. chython/algorithms/smiles.py +556 -0
  35. chython/algorithms/standardize/__init__.py +30 -0
  36. chython/algorithms/standardize/_charged.py +115 -0
  37. chython/algorithms/standardize/_groups.py +926 -0
  38. chython/algorithms/standardize/_metal_organics.py +189 -0
  39. chython/algorithms/standardize/_reagents.py +44 -0
  40. chython/algorithms/standardize/_salts.py +68 -0
  41. chython/algorithms/standardize/molecule.py +479 -0
  42. chython/algorithms/standardize/reaction.py +429 -0
  43. chython/algorithms/standardize/resonance.py +196 -0
  44. chython/algorithms/standardize/salts.py +128 -0
  45. chython/algorithms/standardize/saturation.py +378 -0
  46. chython/algorithms/standardize/test/__init__.py +18 -0
  47. chython/algorithms/standardize/test/test_groups.py +118 -0
  48. chython/algorithms/stereo.py +1222 -0
  49. chython/algorithms/tautomers/__init__.py +171 -0
  50. chython/algorithms/tautomers/_acid.py +59 -0
  51. chython/algorithms/tautomers/_base.py +116 -0
  52. chython/algorithms/tautomers/_keto_enol.py +107 -0
  53. chython/algorithms/tautomers/acid_base.py +214 -0
  54. chython/algorithms/tautomers/heteroarenes.py +108 -0
  55. chython/algorithms/tautomers/keto_enol.py +148 -0
  56. chython/algorithms/tautomers/test/__init__.py +18 -0
  57. chython/algorithms/tautomers/test/test_tautomers.py +80 -0
  58. chython/algorithms/test/__init__.py +18 -0
  59. chython/algorithms/test/test_isomorphism.py +58 -0
  60. chython/algorithms/test/test_smiles.py +76 -0
  61. chython/algorithms/x3dom.py +355 -0
  62. chython/containers/__init__.py +43 -0
  63. chython/containers/_pack_v2.cp312-win_amd64.pyd +0 -0
  64. chython/containers/_pack_v2.pyx +271 -0
  65. chython/containers/_unpack_v0v2.cp312-win_amd64.pyd +0 -0
  66. chython/containers/_unpack_v0v2.pyx +300 -0
  67. chython/containers/bonds.py +255 -0
  68. chython/containers/cgr.py +115 -0
  69. chython/containers/graph.py +200 -0
  70. chython/containers/molecule.py +695 -0
  71. chython/containers/query.py +66 -0
  72. chython/containers/reaction.py +324 -0
  73. chython/exceptions.py +114 -0
  74. chython/files/MRVrw.py +523 -0
  75. chython/files/PDBrw.py +257 -0
  76. chython/files/RDFrw.py +298 -0
  77. chython/files/SDFrw.py +221 -0
  78. chython/files/__init__.py +29 -0
  79. chython/files/_convert.py +207 -0
  80. chython/files/_mapping.py +117 -0
  81. chython/files/_xyz.cp312-win_amd64.pyd +0 -0
  82. chython/files/_xyz.pyx +74 -0
  83. chython/files/daylight/__init__.py +24 -0
  84. chython/files/daylight/parser.py +157 -0
  85. chython/files/daylight/smarts.py +107 -0
  86. chython/files/daylight/smiles.py +245 -0
  87. chython/files/daylight/test/__init__.py +18 -0
  88. chython/files/daylight/test/test_daylight_smarts.py +289 -0
  89. chython/files/daylight/test/test_daylight_smiles.py +101 -0
  90. chython/files/daylight/test/test_parser.py +118 -0
  91. chython/files/daylight/test/test_tokenize.py +77 -0
  92. chython/files/daylight/tokenize.py +376 -0
  93. chython/files/libinchi/__init__.py +22 -0
  94. chython/files/libinchi/libinchi.dll +0 -0
  95. chython/files/libinchi/wrapper.py +555 -0
  96. chython/files/mdl/__init__.py +25 -0
  97. chython/files/mdl/emol.py +209 -0
  98. chython/files/mdl/erxn.py +67 -0
  99. chython/files/mdl/mol.py +144 -0
  100. chython/files/mdl/read.py +225 -0
  101. chython/files/mdl/rxn.py +67 -0
  102. chython/files/mdl/stereo.py +63 -0
  103. chython/files/mdl/write.py +165 -0
  104. chython/files/xyz.py +78 -0
  105. chython/periodictable/__init__.py +69 -0
  106. chython/periodictable/base/__init__.py +25 -0
  107. chython/periodictable/base/dynamic.py +149 -0
  108. chython/periodictable/base/element.py +452 -0
  109. chython/periodictable/base/groups.py +90 -0
  110. chython/periodictable/base/periods.py +46 -0
  111. chython/periodictable/base/query.py +473 -0
  112. chython/periodictable/base/vector.py +119 -0
  113. chython/periodictable/groupI.py +252 -0
  114. chython/periodictable/groupII.py +223 -0
  115. chython/periodictable/groupIII.py +1154 -0
  116. chython/periodictable/groupIV.py +210 -0
  117. chython/periodictable/groupIX.py +196 -0
  118. chython/periodictable/groupV.py +192 -0
  119. chython/periodictable/groupVI.py +183 -0
  120. chython/periodictable/groupVII.py +162 -0
  121. chython/periodictable/groupVIII.py +161 -0
  122. chython/periodictable/groupX.py +166 -0
  123. chython/periodictable/groupXI.py +164 -0
  124. chython/periodictable/groupXII.py +158 -0
  125. chython/periodictable/groupXIII.py +239 -0
  126. chython/periodictable/groupXIV.py +262 -0
  127. chython/periodictable/groupXV.py +276 -0
  128. chython/periodictable/groupXVI.py +457 -0
  129. chython/periodictable/groupXVII.py +324 -0
  130. chython/periodictable/groupXVIII.py +260 -0
  131. chython/reactor/__init__.py +24 -0
  132. chython/reactor/base.py +212 -0
  133. chython/reactor/deprotection.py +565 -0
  134. chython/reactor/groups.py +128 -0
  135. chython/reactor/reactions/__init__.py +157 -0
  136. chython/reactor/reactions/_amidation.py +58 -0
  137. chython/reactor/reactions/_amine_isocyanate.py +52 -0
  138. chython/reactor/reactions/_buchwald_hartwig.py +50 -0
  139. chython/reactor/reactions/_esterification.py +49 -0
  140. chython/reactor/reactions/_macmillan.py +43 -0
  141. chython/reactor/reactions/_reductive_amination.py +50 -0
  142. chython/reactor/reactions/_sonogashira.py +49 -0
  143. chython/reactor/reactions/_sulfonamidation.py +52 -0
  144. chython/reactor/reactions/_suzuki_miyaura.py +88 -0
  145. chython/reactor/reactions/ufe.py +99 -0
  146. chython/reactor/reactor.py +170 -0
  147. chython/reactor/retro/__init__.py +77 -0
  148. chython/reactor/retro/_amidation.py +39 -0
  149. chython/reactor/retro/_aryl_amination.py +32 -0
  150. chython/reactor/retro/_mitsunobu.py +49 -0
  151. chython/reactor/retro/_sonogashira.py +49 -0
  152. chython/reactor/retro/_suzuki_miyaura.py +54 -0
  153. chython/reactor/scaffold.py +122 -0
  154. chython/reactor/test/__init__.py +18 -0
  155. chython/reactor/test/test_deprotection.py +57 -0
  156. chython/reactor/test/test_reactor.py +40 -0
  157. chython/reactor/test/test_scaffold.py +57 -0
  158. chython/reactor/test/test_transformer.py +40 -0
  159. chython/reactor/transformer.py +62 -0
  160. chython/utils/__init__.py +57 -0
  161. chython/utils/free_wilson.py +114 -0
  162. chython/utils/grid.py +130 -0
  163. chython/utils/rdkit.py +165 -0
  164. chython/utils/retro.py +139 -0
  165. chython/utils/svg.py +57 -0
  166. chython/utils/test/__init__.py +18 -0
  167. chython/utils/test/test_rdkit.py +71 -0
  168. chython-2.4.dist-info/LICENSE +165 -0
  169. chython-2.4.dist-info/METADATA +101 -0
  170. chython-2.4.dist-info/RECORD +171 -0
  171. chython-2.4.dist-info/WHEEL +4 -0
chython/__init__.py ADDED
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2014-2024 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # Copyright 2014-2019 Timur Madzhidov tmadzhidov@gmail.com features and API discussion
5
+ # Copyright 2014-2019 Alexandre Varnek <varnek@unistra.fr> base idea of CGR approach
6
+ # This file is part of chython.
7
+ #
8
+ # chython is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU Lesser General Public License as published by
10
+ # the Free Software Foundation; either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public License
19
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
20
+ #
21
+ from .algorithms.depict import depict_settings
22
+ from .containers import *
23
+ from .files import *
24
+ from .reactor import *
25
+ from .utils import *
26
+
27
+
28
+ torch_device = 'cpu' # AAM model device. Change before first `reset_mapping` call!
29
+
30
+
31
+ __all__ = []
chython/_functions.py ADDED
@@ -0,0 +1,69 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2020, 2021 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # This file is part of chython.
5
+ #
6
+ # chython is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+ from itertools import product
20
+
21
+
22
+ # lazy itertools.product with diagonal combination precedence
23
+ def lazy_product(*args):
24
+ if len(args) == 1:
25
+ for x in args[0]:
26
+ yield x,
27
+ elif not args:
28
+ yield ()
29
+ else:
30
+ gens = [iter(x) for x in args]
31
+ empty = [False] * len(args)
32
+ pools = [[] for _ in range(len(args))]
33
+ indices = set()
34
+
35
+ reached = 0
36
+ while True:
37
+ out = []
38
+ ind = []
39
+ for n, (p, g, e) in enumerate(zip(pools, gens, empty)):
40
+ if e:
41
+ out.append(p[-1])
42
+ else:
43
+ try:
44
+ x = next(g)
45
+ except StopIteration:
46
+ if not p: # one of gens empty
47
+ return
48
+ reached += 1
49
+ if reached == len(args):
50
+ break
51
+ out.append(p[-1])
52
+ empty[n] = True
53
+ else:
54
+ p.append(x)
55
+ out.append(x)
56
+ ind.append(len(p) - 1)
57
+ else:
58
+ yield tuple(out)
59
+ indices.add(tuple(ind))
60
+ continue
61
+ break
62
+
63
+ for ind in product(*(range(len(p)) for p in pools)):
64
+ if ind in indices:
65
+ continue
66
+ yield tuple(p[x] for x, p in zip(ind, pools))
67
+
68
+
69
+ __all__ = ['lazy_product']
@@ -0,0 +1,18 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2017-2021 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # This file is part of chython.
5
+ #
6
+ # chython is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
18
+ #
@@ -0,0 +1,189 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2021-2025 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # Copyright 2021 Aleksandr Sizov <murkyrussian@gmail.com>
5
+ # This file is part of chython.
6
+ #
7
+ # chython is free software; you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation; either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+ cimport cython
21
+ from cpython.mem cimport PyMem_Malloc, PyMem_Free
22
+ from libc.string cimport memset
23
+
24
+ cdef extern from "Python.h":
25
+ dict _PyDict_NewPresized(Py_ssize_t minused)
26
+
27
+ cdef packed struct atom_t:
28
+ unsigned long long bits1
29
+ unsigned long long bits2
30
+ unsigned long long bits3
31
+ unsigned long long bits4
32
+ unsigned int from_
33
+ unsigned int to_
34
+ unsigned int mapping
35
+
36
+ cdef packed struct bond_t:
37
+ unsigned long long bond
38
+ unsigned int index
39
+
40
+ cdef packed struct molecule_t:
41
+ unsigned int atoms_count
42
+ atom_t *atoms
43
+ bond_t *bonds
44
+
45
+ cdef packed struct q_atom_t:
46
+ unsigned long long mask1
47
+ unsigned long long mask2
48
+ unsigned long long mask3
49
+ unsigned long long mask4
50
+ unsigned int back
51
+ unsigned int closure
52
+ unsigned int from_
53
+ unsigned int to_
54
+ unsigned int mapping
55
+
56
+ cdef packed struct query_t:
57
+ unsigned int atoms_count
58
+ q_atom_t *atoms
59
+ bond_t *bonds
60
+
61
+
62
+ @cython.boundscheck(False)
63
+ @cython.wraparound(False)
64
+ def get_mapping(const unsigned char[::1] q_buffer not None, const unsigned char[::1] m_buffer not None,
65
+ const unsigned int[::1] scope not None):
66
+ # expected less than 2^16 atoms in structure.
67
+ cdef unsigned int stack = 0, path_size = 0, depth, front, q_decrement
68
+ cdef unsigned int n, m, i, j, closures_counter
69
+ cdef unsigned long long c_bond
70
+ cdef dict mapping
71
+ cdef query_t query
72
+ cdef molecule_t molecule
73
+ cdef q_atom_t q_atom
74
+ cdef atom_t n_atom, m_atom
75
+ cdef bond_t i_bond, j_bond
76
+
77
+ query.atoms_count = (<unsigned int*> &q_buffer[0])[0]
78
+ query.atoms = <q_atom_t*> (&q_buffer[0] + 4)
79
+ query.bonds = <bond_t*> (&query.atoms[0] + query.atoms_count)
80
+ q_decrement = query.atoms_count - 1
81
+
82
+ molecule.atoms_count = (<unsigned int*> &m_buffer[0])[0]
83
+ molecule.atoms = <atom_t*> (&m_buffer[0] + 4)
84
+ molecule.bonds = <bond_t*> (&molecule.atoms[0] + molecule.atoms_count)
85
+
86
+ cdef unsigned int *path = <unsigned int *> PyMem_Malloc(q_decrement * sizeof(unsigned int))
87
+ cdef unsigned int *stack_index = <unsigned int *> PyMem_Malloc(2 * molecule.atoms_count * sizeof(unsigned int))
88
+ cdef unsigned int *stack_depth = <unsigned int *> PyMem_Malloc(2 * molecule.atoms_count * sizeof(unsigned int))
89
+ cdef bint *matched = <bint *> PyMem_Malloc(molecule.atoms_count * sizeof(bint))
90
+ cdef unsigned long long *closures = <unsigned long long *> PyMem_Malloc(molecule.atoms_count * sizeof(unsigned long long))
91
+
92
+ if not path or not stack_index or not stack_depth or not matched or not closures:
93
+ raise MemoryError()
94
+
95
+ memset(matched, 0, molecule.atoms_count * sizeof(bint))
96
+ memset(closures, 0, molecule.atoms_count * sizeof(unsigned long long))
97
+
98
+ q_atom = query.atoms[0]
99
+ for n in range(molecule.atoms_count):
100
+ n_atom = molecule.atoms[n]
101
+ if (scope[n] and
102
+ q_atom.mask1 & n_atom.bits1 and # bits1 doesn't contain bond bits.
103
+ q_atom.mask2 & n_atom.bits2 == n_atom.bits2 and
104
+ q_atom.mask3 & n_atom.bits3 == n_atom.bits3 and
105
+ q_atom.mask4 & n_atom.bits4):
106
+
107
+ stack_index[stack] = n
108
+ stack_depth[stack] = 0
109
+ stack += 1
110
+
111
+ try:
112
+ while stack:
113
+ stack -= 1
114
+ depth = stack_depth[stack]
115
+ n = stack_index[stack]
116
+
117
+ if depth == q_decrement:
118
+ mapping = _PyDict_NewPresized(query.atoms_count)
119
+ for i in range(depth):
120
+ mapping[query.atoms[i].mapping] = molecule.atoms[path[i]].mapping
121
+ mapping[query.atoms[depth].mapping] = molecule.atoms[n].mapping
122
+ yield mapping
123
+ else:
124
+ if path_size != depth: # dead end reached
125
+ for i in range(depth, path_size):
126
+ matched[path[i]] = False # mark unmatched
127
+ path_size = depth
128
+
129
+ matched[n] = True
130
+ path[path_size] = n
131
+ path_size += 1
132
+
133
+ front = depth + 1
134
+ # load next query atom
135
+ q_atom = query.atoms[front]
136
+ if q_atom.back != depth: # branch
137
+ n = path[q_atom.back]
138
+
139
+ n_atom = molecule.atoms[n]
140
+ for i in range(n_atom.from_, n_atom.to_):
141
+ i_bond = molecule.bonds[i]
142
+ m = i_bond.index
143
+ m_atom = molecule.atoms[m]
144
+ if (scope[m] and not matched[m] and
145
+ q_atom.mask1 & i_bond.bond == i_bond.bond and # bond order, in ring mark and atom bit should match.
146
+ q_atom.mask2 & m_atom.bits2 == m_atom.bits2 and
147
+ q_atom.mask3 & m_atom.bits3 == m_atom.bits3 and
148
+ q_atom.mask4 & m_atom.bits4):
149
+
150
+ if q_atom.closure: # candidate atom should have same closures.
151
+ closures_counter = 0
152
+ # make a map of closures for o_n atom
153
+ # an index is a neighbor atom and a value is a bond between o_n and the neighbor
154
+ for j in range(m_atom.from_, m_atom.to_):
155
+ j_bond = molecule.bonds[j]
156
+ if j_bond.index != n and matched[j_bond.index]:
157
+ closures[j_bond.index] = j_bond.bond
158
+ closures_counter += 1
159
+
160
+ if closures_counter == q_atom.closure:
161
+ for j in range(q_atom.from_, q_atom.to_):
162
+ j_bond = query.bonds[j]
163
+ c_bond = closures[path[j_bond.index]]
164
+ if not c_bond or j_bond.bond & c_bond != c_bond: # compare order and ring bits
165
+ break
166
+ else:
167
+ stack_index[stack] = m
168
+ stack_depth[stack] = front
169
+ stack += 1
170
+
171
+ # fill an array with nulls
172
+ for j in range(m_atom.from_, m_atom.to_):
173
+ j_bond = molecule.bonds[j]
174
+ closures[j_bond.index] = 0
175
+ else: # candidate atom should not have closures.
176
+ for j in range(m_atom.from_, m_atom.to_):
177
+ j_bond = molecule.bonds[j]
178
+ if j_bond.index != n and matched[j_bond.index]:
179
+ break # found closure
180
+ else:
181
+ stack_index[stack] = m
182
+ stack_depth[stack] = front
183
+ stack += 1
184
+ finally:
185
+ PyMem_Free(path)
186
+ PyMem_Free(matched)
187
+ PyMem_Free(stack_index)
188
+ PyMem_Free(stack_depth)
189
+ PyMem_Free(closures)
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2018-2021 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # This file is part of chython.
5
+ #
6
+ # chython is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+ from .kekule import *
20
+ from .thiele import *
21
+
22
+
23
+ class Aromatize(Thiele, Kekule):
24
+ __slots__ = ()
25
+
26
+
27
+ __all__ = ['Aromatize']
@@ -0,0 +1,124 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright 2021-2024 Ramil Nugmanov <nougmanoff@protonmail.com>
4
+ # This file is part of chython.
5
+ #
6
+ # chython is free software; you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation; either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program; if not, see <https://www.gnu.org/licenses/>.
18
+ #
19
+ from lazy_object_proxy import Proxy
20
+
21
+
22
+ def _rules():
23
+ from ... import smarts
24
+
25
+ rules = []
26
+
27
+ # Aromatic N-Oxide
28
+ #
29
+ # : N : >> : [N+] :
30
+ # \\ \
31
+ # O [O-]
32
+ #
33
+ q = smarts('[N;a;D3:1]=[O;D1:2]')
34
+ atom_fix = {1: 1, 2: -1}
35
+ bonds_fix = ((1, 2, 1),)
36
+ # query, atom fix, bond fix, allow multimatch
37
+ rules.append((q, atom_fix, bonds_fix, False))
38
+
39
+ # Aromatic N-Nitride?
40
+ #
41
+ # : N : >> : [N+] :
42
+ # \\ \
43
+ # N [N-]
44
+ #
45
+ q = smarts('[N;a;D3:1]=[N;D1,D2;z2:2]')
46
+ atom_fix = {1: 1, 2: -1}
47
+ bonds_fix = ((1, 2, 1),)
48
+ rules.append((q, atom_fix, bonds_fix, False))
49
+
50
+ #
51
+ # : [S+] : >> : S :
52
+ # | \\
53
+ # [O-] O
54
+ #
55
+ q = smarts('[S;a;D3;+:1]-[O;D1;-:2]')
56
+ atom_fix = {1: 0, 2: 0}
57
+ bonds_fix = ((1, 2, 2),)
58
+ rules.append((q, atom_fix, bonds_fix, False))
59
+
60
+ #
61
+ # [O-]-N:C:C:[N+]=O
62
+ #
63
+ q = smarts('[N;a;D3;+:1](=[O;D1:2]):[C:3]:[C:4]:[N;D3:5]-[O;D1;-:6]')
64
+ atom_fix = {5: 1, 2: -1}
65
+ bonds_fix = ((1, 2, 1),)
66
+ rules.append((q, atom_fix, bonds_fix, False))
67
+
68
+ #
69
+ # N : A : N - ?
70
+ # : :
71
+ # C # C
72
+ q = smarts('[N;a;D2,D3;r5:3]:1:[C;D2;r5:1]#[C;D2;r5:2]:[N;D2;r5:5]:[C,N;r5:4]:1')
73
+ atom_fix = {}
74
+ bonds_fix = ((1, 2, 4),)
75
+ rules.append((q, atom_fix, bonds_fix, False))
76
+
77
+ #
78
+ # C:[N+]:[C-]
79
+ # \\
80
+ # O
81
+ #
82
+ q = smarts('[N;a;D3;+:1](=[O;D1:2])(:[C;D2,D3;-:3]):[C;D2,D3:4]')
83
+ atom_fix = {2: -1, 3: 0}
84
+ bonds_fix = ((1, 2, 1),)
85
+ rules.append((q, atom_fix, bonds_fix, False))
86
+
87
+ #
88
+ # O=[N+] : C
89
+ # : :
90
+ # O : N : C
91
+ q = smarts('[N;a;D3;r5;+:1]:1(=[O;D1:2]):[O;D2;r5:3]:[N;D2,D3;r5:4]:[C;D2,D3;r5:5]:[C;D2,D3;r5:6]:1')
92
+ atom_fix = {}
93
+ bonds_fix = ((1, 3, 1), (1, 6, 1), (3, 4, 1), (4, 5, 1), (5, 6, 2))
94
+ rules.append((q, atom_fix, bonds_fix, False))
95
+
96
+ # bad complex representation
97
+ # : :
98
+ # N - [M] >> N ... [M]
99
+ # : :
100
+ q = smarts('[N;a;D3:1]-[M:2]')
101
+ atom_fix = {}
102
+ bonds_fix = ((1, 2, 8),)
103
+ rules.append((q, atom_fix, bonds_fix, True))
104
+ return rules
105
+
106
+
107
+ def _freaks():
108
+ from ... import smarts
109
+
110
+ rules = []
111
+
112
+ q = smarts('[N,O,S;D2;r5;z1]1[A;r5]=,:[A;r5][A;r5]:[A;r5]1')
113
+ rules.append(q)
114
+
115
+ q = smarts('[N;D3;r5;z1]1[A;r5]=,:[A;r5][A;r5]:[A;r5]1')
116
+ rules.append(q)
117
+ return rules
118
+
119
+
120
+ rules = Proxy(_rules)
121
+ freak_rules = Proxy(_freaks)
122
+
123
+
124
+ __all__ = ['rules', 'freak_rules']