99import numpy
1010from scipy .optimize import linear_sum_assignment
1111
12- from rdkit import Chem , DataStructs
13- from rdkit .Chem import AllChem , rdmolops
14- from rdkit .Chem .Fingerprints import FingerprintMols
12+ from rdkit import Chem
13+ from rdkit .Chem import rdmolops
1514
16- _BK_ = {
15+ _bondTypeCodes = {
1716 Chem .rdchem .BondType .SINGLE : 1 ,
1817 Chem .rdchem .BondType .DOUBLE : 2 ,
1918 Chem .rdchem .BondType .TRIPLE : 3 ,
2019 Chem .rdchem .BondType .AROMATIC : 4
2120}
2221_BONDSYMBOL_ = {1 : '-' , 2 : '=' , 3 : '#' , 4 : ':' }
2322
24- #_nAT_ = 217 # 108*2+1
25- _nAT_ = 223 # Gobbi code actually uses the first prime higher than 217, not 217 itself
26- _nBT_ = 5
23+ #_atomHashModulus = 217 # 108*2+1
24+ _atomHashModulus = 223 # Gobbi code actually uses the first prime higher than 217, not 217 itself
25+ _bondHashModulus = 5
2726
2827#def FindAllPathsOfLengthN_Gobbi(mol, length, rootedAtAtom=-1, uniquepaths=True):
2928# return FindAllPathsOfLengthMToN(mol, length, length, rootedAtAtom=rootedAtAtom, uniquepaths=uniquepaths)
@@ -61,12 +60,12 @@ def _FindAllPathsOfLengthMToN_Gobbi(atom, path, minlength, maxlength, visited, p
6160 if len (path ) >= minlength and len (path ) <= maxlength :
6261 paths .append (tuple (path ))
6362 if len (path ) < maxlength :
64- a1 = bond .GetBeginAtom ()
65- a2 = bond .GetEndAtom ()
66- if a1 .GetIdx () == atom .GetIdx ():
67- nextatom = a2
63+ beginAtom = bond .GetBeginAtom ()
64+ endAtom = bond .GetEndAtom ()
65+ if beginAtom .GetIdx () == atom .GetIdx ():
66+ nextatom = endAtom
6867 else :
69- nextatom = a1
68+ nextatom = beginAtom
7069 nextatomidx = nextatom .GetIdx ()
7170 if nextatomidx not in visited :
7271 visited .add (nextatomidx )
@@ -79,7 +78,7 @@ def getpathintegers(m1, uptolength=7):
7978 '''returns a list of integers describing the paths for molecule m1. This uses numpy 16 bit unsigned integers to reproduce the data in the Gobbi paper. The returned list is sorted'''
8079 bondtypelookup = {}
8180 for b in m1 .GetBonds ():
82- bondtypelookup [b .GetIdx ()] = _BK_ [b .GetBondType ()], b .GetBeginAtom (), b .GetEndAtom ()
81+ bondtypelookup [b .GetIdx ()] = _bondTypeCodes [b .GetBondType ()], b .GetBeginAtom (), b .GetEndAtom ()
8382 pathintegers = {}
8483 for a in m1 .GetAtoms ():
8584 idx = a .GetIdx ()
@@ -88,40 +87,32 @@ def getpathintegers(m1, uptolength=7):
8887 # for path in rdmolops.FindAllPathsOfLengthN(m1, pathlength, rootedAtAtom=idx):
8988 for ipath , path in enumerate (
9089 FindAllPathsOfLengthMToN_Gobbi (m1 , 1 , uptolength , rootedAtAtom = idx , uniquepaths = False )):
91- strpath = []
9290 currentidx = idx
9391 res = []
9492 for ip , p in enumerate (path ):
95- bk , a1 , a2 = bondtypelookup [p ]
96- strpath .append (_BONDSYMBOL_ [bk ])
97- if a1 .GetIdx () == currentidx :
98- a = a2
93+ bondTypeCode , beginAtom , endAtom = bondtypelookup [p ]
94+ if beginAtom .GetIdx () == currentidx :
95+ a = endAtom
9996 else :
100- a = a1
101- ak = a .GetAtomicNum ()
97+ a = beginAtom
98+ neighborAtomCode = a .GetAtomicNum ()
10299 if a .GetIsAromatic ():
103- ak += 108
100+ neighborAtomCode += 108
104101#trying to get the same behaviour as the Gobbi test code - it looks like a circular path includes the bond, but not the closure atom - this fix works
105102 if a .GetIdx () == idx :
106- ak = None
107- if ak is not None :
108- astr = a .GetSymbol ()
109- if a .GetIsAromatic ():
110- strpath .append (astr .lower ())
111- else :
112- strpath .append (astr )
113- res .append ((bk , ak ))
103+ neighborAtomCode = None
104+ res .append ((bondTypeCode , neighborAtomCode ))
114105 currentidx = a .GetIdx ()
115106 pathuniqueint = numpy .ushort (0 ) # work with 16 bit unsigned integers and ignore overflow...
116- for ires , (bi , ai ) in enumerate (res ):
107+ for ires , (bondValue , atomValue ) in enumerate (res ):
117108 #use 16 bit unsigned integer arithmetic to reproduce the Gobbi ints
118- # pathuniqueint = ((pathuniqueint+bi)*_nAT_+ai)*_nBT_
119- val1 = pathuniqueint + numpy .ushort (bi )
120- val2 = val1 * numpy .ushort (_nAT_ )
109+ # pathuniqueint = ((pathuniqueint+bondValue)*_atomHashModulus+atomValue)*_bondHashModulus
110+ val1 = pathuniqueint + numpy .ushort (bondValue )
111+ val2 = val1 * numpy .ushort (_atomHashModulus )
121112 #trying to get the same behaviour as the Gobbi test code - it looks like a circular path includes the bond, but not the closure atom - this fix works
122- if ai is not None :
123- val3 = val2 + numpy .ushort (ai )
124- val4 = val3 * numpy .ushort (_nBT_ )
113+ if atomValue is not None :
114+ val3 = val2 + numpy .ushort (atomValue )
115+ val4 = val3 * numpy .ushort (_bondHashModulus )
125116 else :
126117 val4 = val2
127118 pathuniqueint = val4
@@ -140,14 +131,14 @@ def getcommon(l1, ll1, l2, ll2):
140131 ix1 = 0
141132 ix2 = 0
142133 while (ix1 < ll1 ) and (ix2 < ll2 ):
143- a1 = l1 [ix1 ]
144- a2 = l2 [ix2 ]
145- #a1 is < or > more often that ==
146- if a1 < a2 :
134+ beginAtom = l1 [ix1 ]
135+ endAtom = l2 [ix2 ]
136+ #beginAtom is < or > more often that ==
137+ if beginAtom < endAtom :
147138 ix1 += 1
148- elif a1 > a2 :
139+ elif beginAtom > endAtom :
149140 ix2 += 1
150- else : # a1 == a2 :
141+ else : # beginAtom == endAtom :
151142 ncommon += 1
152143 ix1 += 1
153144 ix2 += 1
@@ -206,19 +197,20 @@ def getsimab(mappings, simmatrixdict):
206197def getsimmatrix (m1 , m1pathintegers , m2 , m2pathintegers ):
207198 '''generate a matrix of atom atom similarities. See Figure 4'''
208199
209- aidata = [((ai .GetAtomicNum (), ai .GetIsAromatic ()), ai .GetIdx ()) for ai in m1 .GetAtoms ()]
200+ aidata = [((atomValue .GetAtomicNum (), atomValue .GetIsAromatic ()), atomValue .GetIdx ())
201+ for atomValue in m1 .GetAtoms ()]
210202 bjdata = [((bj .GetAtomicNum (), bj .GetIsAromatic ()), bj .GetIdx ()) for bj in m2 .GetAtoms ()]
211203
212204 simmatrixarray = numpy .zeros ((len (aidata ), len (bjdata )))
213205
214- for ai , (aitype , aiidx ) in enumerate (aidata ):
206+ for atomValue , (aitype , aiidx ) in enumerate (aidata ):
215207 aipaths = m1pathintegers [aiidx ]
216208 naipaths = len (aipaths )
217209 for bj , (bjtype , bjidx ) in enumerate (bjdata ):
218210 if aitype == bjtype :
219211 bjpaths = m2pathintegers [bjidx ]
220212 nbjpaths = len (bjpaths )
221- simmatrixarray [ai ][bj ] = getsimaibj (aipaths , bjpaths , naipaths , nbjpaths )
213+ simmatrixarray [atomValue ][bj ] = getsimaibj (aipaths , bjpaths , naipaths , nbjpaths )
222214 return simmatrixarray
223215
224216
0 commit comments