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.
- chython/__init__.py +31 -0
- chython/_functions.py +69 -0
- chython/algorithms/__init__.py +18 -0
- chython/algorithms/_isomorphism.cp312-win_amd64.pyd +0 -0
- chython/algorithms/_isomorphism.pyx +189 -0
- chython/algorithms/aromatics/__init__.py +27 -0
- chython/algorithms/aromatics/_rules.py +124 -0
- chython/algorithms/aromatics/kekule.py +530 -0
- chython/algorithms/aromatics/test/__init__.py +18 -0
- chython/algorithms/aromatics/test/test_kekule.py +160 -0
- chython/algorithms/aromatics/test/test_thiele.py +263 -0
- chython/algorithms/aromatics/thiele.py +226 -0
- chython/algorithms/calculate2d/__init__.py +23 -0
- chython/algorithms/calculate2d/clean2d.js +1 -0
- chython/algorithms/calculate2d/molecule.py +149 -0
- chython/algorithms/calculate2d/reaction.py +80 -0
- chython/algorithms/depict.py +523 -0
- chython/algorithms/fingerprints/__init__.py +48 -0
- chython/algorithms/fingerprints/linear.py +208 -0
- chython/algorithms/fingerprints/morgan.py +137 -0
- chython/algorithms/fingerprints/test/__init__.py +18 -0
- chython/algorithms/fingerprints/test/test_linear.py +127 -0
- chython/algorithms/fingerprints/test/test_morgan.py +79 -0
- chython/algorithms/isomorphism.py +667 -0
- chython/algorithms/mapping/__init__.py +28 -0
- chython/algorithms/mapping/_groups.py +94 -0
- chython/algorithms/mapping/_reactions.py +72 -0
- chython/algorithms/mapping/attention.py +216 -0
- chython/algorithms/mapping/fixmapper.py +84 -0
- chython/algorithms/mapping/groups.py +137 -0
- chython/algorithms/mcs.py +202 -0
- chython/algorithms/morgan.py +82 -0
- chython/algorithms/rings.py +551 -0
- chython/algorithms/smiles.py +556 -0
- chython/algorithms/standardize/__init__.py +30 -0
- chython/algorithms/standardize/_charged.py +115 -0
- chython/algorithms/standardize/_groups.py +926 -0
- chython/algorithms/standardize/_metal_organics.py +189 -0
- chython/algorithms/standardize/_reagents.py +44 -0
- chython/algorithms/standardize/_salts.py +68 -0
- chython/algorithms/standardize/molecule.py +479 -0
- chython/algorithms/standardize/reaction.py +429 -0
- chython/algorithms/standardize/resonance.py +196 -0
- chython/algorithms/standardize/salts.py +128 -0
- chython/algorithms/standardize/saturation.py +378 -0
- chython/algorithms/standardize/test/__init__.py +18 -0
- chython/algorithms/standardize/test/test_groups.py +118 -0
- chython/algorithms/stereo.py +1222 -0
- chython/algorithms/tautomers/__init__.py +171 -0
- chython/algorithms/tautomers/_acid.py +59 -0
- chython/algorithms/tautomers/_base.py +116 -0
- chython/algorithms/tautomers/_keto_enol.py +107 -0
- chython/algorithms/tautomers/acid_base.py +214 -0
- chython/algorithms/tautomers/heteroarenes.py +108 -0
- chython/algorithms/tautomers/keto_enol.py +148 -0
- chython/algorithms/tautomers/test/__init__.py +18 -0
- chython/algorithms/tautomers/test/test_tautomers.py +80 -0
- chython/algorithms/test/__init__.py +18 -0
- chython/algorithms/test/test_isomorphism.py +58 -0
- chython/algorithms/test/test_smiles.py +76 -0
- chython/algorithms/x3dom.py +355 -0
- chython/containers/__init__.py +43 -0
- chython/containers/_pack_v2.cp312-win_amd64.pyd +0 -0
- chython/containers/_pack_v2.pyx +271 -0
- chython/containers/_unpack_v0v2.cp312-win_amd64.pyd +0 -0
- chython/containers/_unpack_v0v2.pyx +300 -0
- chython/containers/bonds.py +255 -0
- chython/containers/cgr.py +115 -0
- chython/containers/graph.py +200 -0
- chython/containers/molecule.py +695 -0
- chython/containers/query.py +66 -0
- chython/containers/reaction.py +324 -0
- chython/exceptions.py +114 -0
- chython/files/MRVrw.py +523 -0
- chython/files/PDBrw.py +257 -0
- chython/files/RDFrw.py +298 -0
- chython/files/SDFrw.py +221 -0
- chython/files/__init__.py +29 -0
- chython/files/_convert.py +207 -0
- chython/files/_mapping.py +117 -0
- chython/files/_xyz.cp312-win_amd64.pyd +0 -0
- chython/files/_xyz.pyx +74 -0
- chython/files/daylight/__init__.py +24 -0
- chython/files/daylight/parser.py +157 -0
- chython/files/daylight/smarts.py +107 -0
- chython/files/daylight/smiles.py +245 -0
- chython/files/daylight/test/__init__.py +18 -0
- chython/files/daylight/test/test_daylight_smarts.py +289 -0
- chython/files/daylight/test/test_daylight_smiles.py +101 -0
- chython/files/daylight/test/test_parser.py +118 -0
- chython/files/daylight/test/test_tokenize.py +77 -0
- chython/files/daylight/tokenize.py +376 -0
- chython/files/libinchi/__init__.py +22 -0
- chython/files/libinchi/libinchi.dll +0 -0
- chython/files/libinchi/wrapper.py +555 -0
- chython/files/mdl/__init__.py +25 -0
- chython/files/mdl/emol.py +209 -0
- chython/files/mdl/erxn.py +67 -0
- chython/files/mdl/mol.py +144 -0
- chython/files/mdl/read.py +225 -0
- chython/files/mdl/rxn.py +67 -0
- chython/files/mdl/stereo.py +63 -0
- chython/files/mdl/write.py +165 -0
- chython/files/xyz.py +78 -0
- chython/periodictable/__init__.py +69 -0
- chython/periodictable/base/__init__.py +25 -0
- chython/periodictable/base/dynamic.py +149 -0
- chython/periodictable/base/element.py +452 -0
- chython/periodictable/base/groups.py +90 -0
- chython/periodictable/base/periods.py +46 -0
- chython/periodictable/base/query.py +473 -0
- chython/periodictable/base/vector.py +119 -0
- chython/periodictable/groupI.py +252 -0
- chython/periodictable/groupII.py +223 -0
- chython/periodictable/groupIII.py +1154 -0
- chython/periodictable/groupIV.py +210 -0
- chython/periodictable/groupIX.py +196 -0
- chython/periodictable/groupV.py +192 -0
- chython/periodictable/groupVI.py +183 -0
- chython/periodictable/groupVII.py +162 -0
- chython/periodictable/groupVIII.py +161 -0
- chython/periodictable/groupX.py +166 -0
- chython/periodictable/groupXI.py +164 -0
- chython/periodictable/groupXII.py +158 -0
- chython/periodictable/groupXIII.py +239 -0
- chython/periodictable/groupXIV.py +262 -0
- chython/periodictable/groupXV.py +276 -0
- chython/periodictable/groupXVI.py +457 -0
- chython/periodictable/groupXVII.py +324 -0
- chython/periodictable/groupXVIII.py +260 -0
- chython/reactor/__init__.py +24 -0
- chython/reactor/base.py +212 -0
- chython/reactor/deprotection.py +565 -0
- chython/reactor/groups.py +128 -0
- chython/reactor/reactions/__init__.py +157 -0
- chython/reactor/reactions/_amidation.py +58 -0
- chython/reactor/reactions/_amine_isocyanate.py +52 -0
- chython/reactor/reactions/_buchwald_hartwig.py +50 -0
- chython/reactor/reactions/_esterification.py +49 -0
- chython/reactor/reactions/_macmillan.py +43 -0
- chython/reactor/reactions/_reductive_amination.py +50 -0
- chython/reactor/reactions/_sonogashira.py +49 -0
- chython/reactor/reactions/_sulfonamidation.py +52 -0
- chython/reactor/reactions/_suzuki_miyaura.py +88 -0
- chython/reactor/reactions/ufe.py +99 -0
- chython/reactor/reactor.py +170 -0
- chython/reactor/retro/__init__.py +77 -0
- chython/reactor/retro/_amidation.py +39 -0
- chython/reactor/retro/_aryl_amination.py +32 -0
- chython/reactor/retro/_mitsunobu.py +49 -0
- chython/reactor/retro/_sonogashira.py +49 -0
- chython/reactor/retro/_suzuki_miyaura.py +54 -0
- chython/reactor/scaffold.py +122 -0
- chython/reactor/test/__init__.py +18 -0
- chython/reactor/test/test_deprotection.py +57 -0
- chython/reactor/test/test_reactor.py +40 -0
- chython/reactor/test/test_scaffold.py +57 -0
- chython/reactor/test/test_transformer.py +40 -0
- chython/reactor/transformer.py +62 -0
- chython/utils/__init__.py +57 -0
- chython/utils/free_wilson.py +114 -0
- chython/utils/grid.py +130 -0
- chython/utils/rdkit.py +165 -0
- chython/utils/retro.py +139 -0
- chython/utils/svg.py +57 -0
- chython/utils/test/__init__.py +18 -0
- chython/utils/test/test_rdkit.py +71 -0
- chython-2.4.dist-info/LICENSE +165 -0
- chython-2.4.dist-info/METADATA +101 -0
- chython-2.4.dist-info/RECORD +171 -0
- 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
|
+
#
|
|
Binary file
|
|
@@ -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']
|