def pathSearch(self, n1, n2=None, edgecb=None, tocb=None): ''' Search for the shortest path from one node to another with the option to filter based on edges using edgecb. edgecb should be a function: def myedgecb(graph, eid, n1, n2, depth) which returns True if it's OK to traverse this node in the search. Additionally, n2 may be None and the caller may specify tocb with a function such as: def mytocb(graph, nid) which must return True on finding the target node Returns a list of edge ids... ''' if n2 is None and tocb is None: raise Exception('You must use either n2 or tocb!') root = vg_pathcore.newPathNode(nid=n1, eid=None) todo = [ (root, 0), ] # FIXME make this a deque so it can be FIFO while len(todo): pnode, depth = todo.pop() # popleft() ppnode, pkids, pprops = pnode nid = pprops.get('nid') for edge in self.getRefsFromByNid(nid): eid, srcid, dstid, eprops = edge if vg_pathcore.isPathLoop(pnode, 'nid', dstid): continue # Check if the callback is present and likes us... if edgecb is not None: if not edgecb(self, edge, depth): continue # Are we the match? match = False if dstid == n2: match = True if tocb and tocb(self, dstid): match = True if match: m = vg_pathcore.newPathNode(pnode, nid=dstid, eid=eid) path = vg_pathcore.getPathToNode(m) ret = [] for ppnode, pkids, pprops in path: eid = pprops.get('eid') if eid is not None: ret.append(eid) yield ret # Add the next set of choices to evaluate. branch = vg_pathcore.newPathNode(pnode, nid=dstid, eid=eid) todo.append((branch, depth + 1))
def getCodePaths(vw, fromva, tova, trim=True): """ Return a list of paths, where each path is a list of code blocks from fromva to tova. Usage: getCodePaths(vw, <fromva>, <tova>) -> [ [frblock, ..., toblock], ...] NOTE: "trim" causes an optimization which may not reveal *all* the paths, but is much faster to run. It will never return no paths when there are some, but may not return all of them... (based on path overlap) """ done = {} res = [] frcb = vw.getCodeBlock(fromva) tocb = vw.getCodeBlock(tova) if frcb == None: raise viv_exc.InvalidLocation(fromva) if tocb == None: raise viv_exc.InvalidLocation(tova) frva = frcb[0] # For compare speed root = vg_path.newPathNode(cb=tocb, cbva=tocb[0]) todo = [ root, ] done[tova] = tocb cbcache = {} while len(todo): path = todo.pop() cbva = vg_path.getNodeProp(path, 'cbva') codeblocks = cbcache.get(cbva) if codeblocks == None: codeblocks = getCodeFlow(vw, cbva) cbcache[cbva] = codeblocks for cblock in codeblocks: bva, bsize, bfva = cblock # Don't follow loops... if vg_path.isPathLoop(path, 'cbva', bva): continue # If we have been here before and it's *not* the answer, # skip out... if trim and done.get(bva) != None: continue done[bva] = cblock newpath = vg_path.newPathNode(parent=path, cb=cblock, cbva=bva) # If this one is a match, we don't need to # track past it. Also, put it in the results list # so we don't have to do it later.... if bva == frva: res.append(newpath) else: todo.append(newpath) # Now... if we have some results, lets build the block list. ret = [] for cpath in res: fullpath = vg_path.getPathToNode(cpath) # We actually do it by inbound references, so reverse the result! fullpath.reverse() ret.append([vg_path.getNodeProp(path, 'cb') for path in fullpath]) return ret
def pathSearch(self, n1, n2=None, edgecb=None, tocb=None): ''' Search for the shortest path from one node to another with the option to filter based on edges using edgecb. edgecb should be a function: def myedgecb(graph, eid, n1, n2, depth) which returns True if it's OK to traverse this node in the search. Additionally, n2 may be None and the caller may specify tocb with a function such as: def mytocb(graph, nid) which must return True on finding the target node Returns a list of edge ids... ''' if n2 == None and tocb == None: raise Exception('You must use either n2 or tocb!') root = vg_pathcore.newPathNode(nid=n1, eid=None) todo = [(root, 0),] # FIXME make this a deque so it can be FIFO while len(todo): pnode,depth = todo.pop() # popleft() ppnode, pkids, pprops = pnode nid = pprops.get('nid') for edge in self.getRefsFromByNid(nid): eid, srcid, dstid, eprops = edge if vg_pathcore.isPathLoop(pnode, 'nid', dstid): continue # Check if the callback is present and likes us... if edgecb != None: if not edgecb(self, edge, depth): continue # Are we the match? match = False if dstid == n2: match = True if tocb and tocb(self, dstid): match = True if match: m = vg_pathcore.newPathNode(pnode, nid=dstid, eid=eid) path = vg_pathcore.getPathToNode(m) ret = [] for ppnode, pkids, pprops in path: eid = pprops.get('eid') if eid != None: ret.append(eid) yield ret # Add the next set of choices to evaluate. branch = vg_pathcore.newPathNode(pnode, nid=dstid, eid=eid) todo.append((branch, depth+1))
def getCodePaths(vw, fromva, tova, trim=True): """ Return a list of paths, where each path is a list of code blocks from fromva to tova. Usage: getCodePaths(vw, <fromva>, <tova>) -> [ [frblock, ..., toblock], ...] NOTE: "trim" causes an optimization which may not reveal *all* the paths, but is much faster to run. It will never return no paths when there are some, but may not return all of them... (based on path overlap) """ done = {} res = [] frcb = vw.getCodeBlock(fromva) tocb = vw.getCodeBlock(tova) if frcb == None: raise viv_exc.InvalidLocation(fromva) if tocb == None: raise viv_exc.InvalidLocation(tova) frva = frcb[0] # For compare speed root = vg_path.newPathNode(cb=tocb, cbva=tocb[0]) todo = [root, ] done[tova] = tocb cbcache = {} while len(todo): path = todo.pop() cbva = vg_path.getNodeProp(path, 'cbva') codeblocks = cbcache.get(cbva) if codeblocks == None: codeblocks = getCodeFlow(vw, cbva) cbcache[cbva] = codeblocks for cblock in codeblocks: bva,bsize,bfva = cblock # Don't follow loops... if vg_path.isPathLoop(path, 'cbva', bva): continue # If we have been here before and it's *not* the answer, # skip out... if trim and done.get(bva) != None: continue done[bva] = cblock newpath = vg_path.newPathNode(parent=path, cb=cblock, cbva=bva) # If this one is a match, we don't need to # track past it. Also, put it in the results list # so we don't have to do it later.... if bva == frva: res.append(newpath) else: todo.append(newpath) # Now... if we have some results, lets build the block list. ret = [] for cpath in res: fullpath = vg_path.getPathToNode(cpath) # We actually do it by inbound references, so reverse the result! fullpath.reverse() ret.append([vg_path.getNodeProp(path, 'cb') for path in fullpath]) return ret