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