Package rdkit :: Package Chem :: Package FeatMaps :: Module FeatMapUtils
[hide private]
[frames] | no frames]

Source Code for Module rdkit.Chem.FeatMaps.FeatMapUtils

  1  ## Automatically adapted for numpy.oldnumeric Jun 27, 2008 by -c 
  2   
  3  # $Id: FeatMapUtils.py 997 2009-02-25 06:12:43Z glandrum $ 
  4  # 
  5  # Copyright (C) 2006 Greg Landrum 
  6  # 
  7  #   @@ All Rights Reserved  @@ 
  8  # 
  9  from rdkit import Geometry 
 10  import numpy.oldnumeric as Numeric 
 11  from rdkit.Chem.FeatMaps import FeatMaps 
 12  from rdkit.Chem.FeatMaps.FeatMapPoint import FeatMapPoint 
 13  import math,copy 
 14   
15 -class MergeMethod(object):
16 WeightedAverage=0 17 """ Put the new point at the weighted average position of the two 18 fused points 19 """ 20 21 Average=1 22 """ Put the new point at the un-weighted average position of the two 23 fused points 24 """ 25 26 UseLarger=2 27 """ Put the new point at the position of the larger (by weight) 28 of the two points 29 """
30
31 -class MergeMetric(object):
32 NoMerge=0 33 """ Do not merge points """ 34 35 Distance=1 36 """ merge two points if they come within a threshold distance """ 37 38 Overlap=2 39 """ merge two points if their percent overlap exceeds a threshold """
40
41 -class DirMergeMode(object):
42 NoMerge=0 43 """ Do not merge directions (i.e. keep all direction vectors) """ 44 45 Sum=1 46 """ Sum direction vectors """
47
48 -def __copyAll(res,fm1,fm2):
49 """ no user-serviceable parts inside """ 50 for feat in fm1.getFeatures(): 51 res.addFeatPoint(copy.deepcopy(feat)) 52 for feat in fm2.getFeatures(): 53 res.addFeatPoint(copy.deepcopy(feat))
54 55
56 -def GetFeatFeatDistMatrix(fm,mergeMetric,mergeTol,dirMergeMode,compatFunc):
57 """ 58 59 NOTE that mergeTol is a max value for merging when using distance-based 60 merging and a min value when using score-based merging. 61 62 """ 63 dists = [[1e8]*fm.GetNumFeatures() for x in range(fm.GetNumFeatures())] 64 if mergeMetric==MergeMetric.NoMerge: 65 return dists 66 elif mergeMetric==MergeMetric.Distance: 67 mergeTol2 = mergeTol*mergeTol 68 for i in range(fm.GetNumFeatures()): 69 ptI = fm.GetFeature(i) 70 for j in range(i+1,fm.GetNumFeatures()): 71 ptJ = fm.GetFeature(j) 72 if compatFunc(ptI,ptJ): 73 dist2 = ptI.GetDist2(ptJ) 74 if dist2<mergeTol2: 75 dists[i][j]=dist2 76 dists[j][i]=dist2 77 elif mergeMetric==MergeMetric.Overlap: 78 for i in range(fm.GetNumFeatures()): 79 ptI = fm.GetFeature(i) 80 for j in range(i+1,fm.GetNumFeatures()): 81 ptJ = fm.GetFeature(j) 82 if compatFunc(ptI,ptJ): 83 score = fm.GetFeatFeatScore(ptI,ptJ,typeMatch=False) 84 score *= -1*ptJ.weight 85 if score<mergeTol: 86 dists[i][j]=score 87 dists[j][i]=score 88 else: 89 raise ValueError,'unrecognized mergeMetric' 90 91 return dists
92
93 -def familiesMatch(f1,f2):
94 return f1.GetFamily()==f2.GetFamily()
95
96 -def feq(v1,v2,tol=1e-4):
97 return abs(v1-v2)<tol
98
99 -def MergeFeatPoints(fm,mergeMetric=MergeMetric.NoMerge,mergeTol=1.5, 100 dirMergeMode=DirMergeMode.NoMerge, 101 mergeMethod=MergeMethod.WeightedAverage, 102 compatFunc=familiesMatch):
103 """ 104 105 NOTE that mergeTol is a max value for merging when using distance-based 106 merging and a min value when using score-based merging. 107 108 returns whether or not any points were actually merged 109 110 """ 111 res=False 112 if mergeMetric==MergeMetric.NoMerge: 113 return res 114 dists = GetFeatFeatDistMatrix(fm,mergeMetric,mergeTol,dirMergeMode,compatFunc) 115 distOrders = [None]*len(dists) 116 for i in range(len(dists)): 117 distV = dists[i] 118 distOrders[i] = [] 119 for j,dist in enumerate(distV): 120 if dist<mergeTol: 121 distOrders[i].append((dist,j)) 122 distOrders[i].sort() 123 124 #print 'distOrders:' 125 #print distOrders 126 127 # we now know the "distances" and have rank-ordered list of 128 # each point's neighbors. Work with that. 129 130 # progressively merge nearest neighbors until there 131 # are no more points left to merge 132 featsInPlay=range(fm.GetNumFeatures()) 133 featsToRemove = [] 134 #print '--------------------------------' 135 while featsInPlay: 136 # find two features who are mutual nearest neighbors: 137 fipCopy=featsInPlay[:] 138 for fi in fipCopy: 139 #print '>>>',fi,fipCopy,featsInPlay 140 #print '\t',distOrders[fi] 141 mergeThem=False 142 if not distOrders[fi]: 143 featsInPlay.remove(fi) 144 continue 145 dist,nbr = distOrders[fi][0] 146 if nbr not in featsInPlay: 147 continue 148 if distOrders[nbr][0][1]==fi: 149 #print 'direct:',fi,nbr 150 mergeThem=True 151 else: 152 # it may be that there are several points at about the same distance, 153 # check for that now 154 if(feq(distOrders[nbr][0][0],dist)): 155 for distJ,nbrJ in distOrders[nbr][1:]: 156 if feq(dist,distJ): 157 if nbrJ==fi: 158 #print 'indirect: ',fi,nbr 159 mergeThem=True 160 break 161 else: 162 break 163 #print ' bottom:',mergeThem 164 if mergeThem: break 165 if mergeThem: 166 res=True 167 featI = fm.GetFeature(fi) 168 nbrFeat = fm.GetFeature(nbr) 169 170 if mergeMethod==MergeMethod.WeightedAverage: 171 newPos = featI.GetPos()*featI.weight+nbrFeat.GetPos()*nbrFeat.weight 172 newPos /= (featI.weight+nbrFeat.weight) 173 newWeight = (featI.weight+nbrFeat.weight)/2 174 elif mergeMethod==MergeMethod.Average: 175 newPos = featI.GetPos()+nbrFeat.GetPos() 176 newPos /= 2 177 newWeight = (featI.weight+nbrFeat.weight)/2 178 elif mergeMethod==MergeMethod.UseLarger: 179 if featI.weight>nbrFeat.weight: 180 newPos=featI.GetPos() 181 newWeight = featI.weight 182 else: 183 newPos=nbrFeat.GetPos() 184 newWeight = nbrFeat.weight 185 else: 186 raise ValueError,"bad mergeMethod" 187 188 featI.SetPos(newPos) 189 featI.weight = newWeight 190 191 # nbr and fi are no longer valid targets: 192 #print 'nbr done:',nbr,featsToRemove,featsInPlay 193 featsToRemove.append(nbr) 194 featsInPlay.remove(fi) 195 featsInPlay.remove(nbr) 196 for nbrList in distOrders: 197 try: 198 nbrList.remove(fi) 199 except ValueError: 200 pass 201 try: 202 nbrList.remove(nbr) 203 except ValueError: 204 pass 205 else: 206 #print ">>>> Nothing found, abort" 207 break 208 featsToRemove.sort() 209 for i,fIdx in enumerate(featsToRemove): 210 fm.DropFeature(fIdx-i) 211 return res
212
213 -def CombineFeatMaps(fm1,fm2,mergeMetric=MergeMetric.NoMerge,mergeTol=1.5, 214 dirMergeMode=DirMergeMode.NoMerge):
215 """ 216 the parameters will be taken from fm1 217 """ 218 res = FeatMaps.FeatMap(params=fm1.params) 219 220 __copyAll(res,fm1,fm2) 221 if mergeMetric!=MergeMetric.NoMerge: 222 MergeFeatPoints(res,mergeMetric=mergeMetric,mergeTol=mergeTol) 223 return res
224 225 #------------------------------------ 226 # 227 # doctest boilerplate 228 #
229 -def _test():
230 import doctest,sys 231 return doctest.testmod(sys.modules["__main__"])
232 233 if __name__ == '__main__': 234 import sys 235 failed,tried = _test() 236 sys.exit(failed) 237