def testAddEmptyGraph(self): gr1 = graph.digraph() gr1.generate(25, 100) gr1c = copy.copy(gr1) gr2 = graph.digraph() gr1.add_graph(gr2) self.assertTrue(gr1.nodes() == gr1c.nodes()) self.assertTrue(gr1.edges() == gr1c.edges())
def testAddGraph(self): gr1 = graph.digraph() gr1.generate(25, 100) gr2 = graph.digraph() gr2.generate(40, 200) gr1.add_graph(gr2) for each in gr2.nodes(): self.assertTrue(each in gr1) for each in gr2.edges(): self.assertTrue(each in gr1.edges())
def resolveIncludes(self, includeTree=graph.digraph()): console.debug("including %s" % ( self._fname.decode('utf-8') if self._fname else "<unknown>",)) config = self._data jobsmap = self.getJobsMap({}) if self._fname: # we stem from a file if self._fname not in includeTree: includeTree.add_node(self._fname) # only for the top-level config - others will be inserted by the parent if 'include' in config: for i in range(len(config['include'])): incspec = config['include'][i] # need this indirection so that later macro expansions in config['inlcude'] take effect # analyse value of ['include'][key] if isinstance(incspec, types.StringTypes): fname = incspec elif isinstance(incspec, types.DictType): fname = incspec['path'] else: raise RuntimeError, "Unknown include spec: %s" % repr(incspec) fname = fname.encode('utf-8') fapath = self.absPath(fname) # calculate path relative to config file # cycle check includeTree.add_node(fapath) # add the child if self._fname: # add edge to child, but not if we are a memory-config, # since we don't create nodes for those. includeTree.add_edge(self._fname, fapath) cycle_nodes = includeTree.find_cycle() if cycle_nodes: raise RuntimeError("Detected circular inclusion of config files: %r" % cycle_nodes) # see if we use a namespace prefix for the imported jobs if isinstance(incspec, types.DictType) and 'as' in incspec: namespace = incspec['as'] else: namespace = "" econfig = Config(self._console, fapath.decode('utf-8')) econfig.resolveIncludes(includeTree) # recursive include # check include/import if 'import' in incspec: importList = incspec['import'] else: importList = None # check include/block if 'block' in incspec: blockList = incspec['block'] else: blockList = None # check include/bypass-export-list if 'bypass-export-list' in incspec: bypassExports = incspec['bypass-export-list'] else: bypassExports = False self._integrateExternalConfig(econfig, namespace, importList, blockList, bypassExports) self._includedConfigs.append(econfig) # save external config for later reference
def testDigraph(self): def has_parent(node, list): for each in list: if gr.has_edge(each, node): return True return ts == [] gr = graph.digraph() gr.add_nodes([0, 1, 2, 3, 4, 5, 6, 7, 8]) gr.add_edge(0, 1) gr.add_edge(0, 2) gr.add_edge(1, 3) gr.add_edge(1, 4) gr.add_edge(2, 5) gr.add_edge(2, 6) gr.add_edge(3, 7) gr.add_edge(8, 0) gr.add_edge(7, 5) gr.add_edge(3, 0) gr.add_edge(4, 3) gr.add_edge(2, 7) gr.add_edge(6, 0) ts = gr.topological_sorting() while ts: x = ts.pop() assert has_parent(x, ts)
def sortClassesTopological(self, classList, variants, buildType=''): # create graph object gr = graph.digraph() # add classes as nodes gr.add_nodes(classList) # for each load dependency add a directed edge for classId in classList: deps, _ = self._classesObj[classId].getCombinedDeps(variants, self._jobconf) for dep in deps["load"]: depClassId = dep.name if depClassId in classList: gr.add_edge(depClassId, classId) # cycle check? cycle_nodes = gr.find_cycle() if cycle_nodes: #raise RuntimeError("Detected circular dependencies between nodes: %r" % cycle_nodes) pass classList = gr.topological_sorting() return classList
def test_makeCut(self): # blah? # start with a non-directed graph. g = pygraph.graph() # add some nodes g.add_nodes(range(1,11)) # add some edges for each in range(1,10): g.add_edge(each,each+1) # make a single cut gcut1 = makeCut([1,2],g) # should be two less edges because both (1,2) and (2,1) should have been removed. self.assertTrue(len(gcut1.edges()) == len(g.edges())-2) gcut2 = makeCut(([1,2],[3,4]),g) self.assertTrue(len(gcut2.edges()) == len(g.edges())-4) gcut3 = makeCut(([1,2],[3,4],[4,5]),g) self.assertTrue(len(gcut3.edges()) == len(g.edges())-6) # directed graph test g2 = pygraph.digraph() # add some nodes g2.add_nodes(range(1,11)) # add some edges for each in range(1,10): g2.add_edge(each,each+1) # make a single cut g2cut1 = makeCut([1,2],g2) self.assertTrue(len(g2cut1.edges()) == len(g2.edges())-1) # make two cuts g2cut2 = makeCut(([1,2],[2,3]),g2) self.assertTrue(len(g2cut2.edges()) == len(g2.edges())-2)
def separateGraphs(g): # given a graph g with non-connected components, return each component separately. # there's countGraphs(g) number of graphs to find in g. graphs = [] #dict = pygraph.accessibility.connected_components(g) #len(list(frozenset(dict.values()))) thedict = pygraph.accessibility.connected_components(g) # there's len(frozenset(thedict.keys())) number of graphs to be returned. for each in list(frozenset(thedict.values())): if type(g) == type(pygraph.graph): g2 = pygraph.graph() if type(g) == type(pygraph.digraph): g2 = pygraph.digraph() else: print "ERROR: unknown graph type.\n" return for node in thedict.keys(): if thedict[node] == each: g2.add_node(node) # also, add the edges corresponding to this node in this component for edge in g.edges(): if edge[0] == node or edge[1] == node: g2.add_edge(edge[0],edge[1]) graphs.append(g2) return graphs
def testNoCycleDigraph2(self): G = graph.digraph() G.add_nodes([1,2,3]) G.add_edge(1,2) G.add_edge(1,3) G.add_edge(2,3) assert G.find_cycle() == []
def _sortPackagesTopological(self, packages): # packages : [Package] import graph # create graph object gr = graph.digraph() # add classes as nodes gr.add_nodes(packages) # for each load dependency add a directed edge for package in packages: for dep in package.packageDeps: gr.add_edge(package, dep) # cycle check? cycle_nodes = gr.find_cycle() if cycle_nodes: raise RuntimeError( "Detected circular dependencies between packages: %r" % cycle_nodes) packageList = gr.topological_sorting() return packageList
def sortClassesTopological(self, includeWithDeps, variants): # create graph object gr = graph.digraph() # add classes as nodes gr.add_nodes(includeWithDeps) # for each load dependency add a directed edge for classId in includeWithDeps: deps, _ = self.getCombinedDeps(classId, variants) for depClassId in deps["load"]: if depClassId in includeWithDeps: gr.add_edge(depClassId, classId) # cycle check? cycle_nodes = gr.find_cycle() if cycle_nodes: raise RuntimeError( "Detected circular dependencies between nodes: %r" % cycle_nodes) classList = gr.topological_sorting() return classList
def testReadDigraphDot(self): dot = ['digraph graphname {', '1;', '2;', '3;', '4;', '5;', '1 -> 2;', '4 -> 5;', '1 -> 5;', '2 -> 3;', '2 -> 4;', '3 -> 5;', '}', ''] dot = "\n".join(dot) gr = graph.digraph() gr.read(dot, 'dot') self._check_nodes(gr, dot) self._check_arrows(gr, dot)
def testGraphComplete(self): gr = graph.digraph() gr.add_nodes(xrange(10)) gr.complete() for i in xrange(10): for j in range(10): self.assertTrue((i, j) in gr.edges() or i == j)
def testSanityDigraph(self): G = graph.digraph() G.generate(100, 500) st, lo = G.breadth_first_search() for each in G: if (st[each] != None): assert lo.index(each) > lo.index(st[each])
def saveTree(self, filename): ''' Saves the image of AST built with the current node as a root node. @param filename: filename to which to save. 'png' extension will be appended. ''' import graph import gv gr = graph.digraph() queue = [self] i = 0 h = {} while len(queue): n = queue.pop() h[n] = i gr.add_node(i, [('label', n.value)]) if n.children is not None: queue.extend(n.children) i += 1 queue = [self] while len(queue): n = queue.pop() if n.children is not None: for c in n.children: gr.add_edge(h[n], h[c]) queue.append(c) dot = gr.write(fmt='dot') gvv = gv.readstring(dot) gv.layout(gvv, 'dot') gv.render(gvv, 'png', str(filename) + '.png')
def test_cutsets(self): # this is the big one. # total number of f-cutsets in a given graph = (len(g.nodes())-1) # start with a non-directed graph g = pygraph.graph() # add some nodes. g.add_nodes(range(1,11)) # add some edges for each in range(1,10): g.add_edge(each,each+1) # find all cutsets that divide the graph into 2 graphs. # the third parameter is set to the max number of cuts to return # in this case, we know that there are at most 9 cuts, # (because of the 9 edges) gsets = cutsets(g,2,len(g.edges())/2) self.assertTrue(len(gsets)==len(g.edges())/2) # this only holds for pygraph.graph (not pygraph.digraph) self.assertTrue(len(gsets)==len(g.nodes())-1) # directed graph test. g2 = pygraph.digraph() g2.add_nodes(range(1,11)) for each in range(1,10): g2.add_edge(each,each+1) self.assertTrue(countGraphs(makeCut([1,2],g2)) == 2) g2sets = cutsets(g2,2) self.assertTrue(len(g2sets)==len(g.nodes())-1)
def fastGraph(g): dg = graph.digraph() for v in g: dg.add_node(v) for v in g: for w in g[v]: dg.add_edge(v, w) return dg
def testRandomGraph(self): gr = graph.digraph() gr.generate(100, 500) self.assertEqual(gr.nodes(),range(100)) self.assertEqual(len(gr.edges()), 500) for each, other in gr.edges(): self.assertTrue(each in gr) self.assertTrue(other in gr)
def testSanityDigraph(self): G = graph.digraph() G.generate(100, 500) st, pre, post = G.depth_first_search() for each in G: if (st[each] != None): assert pre.index(each) > pre.index(st[each]) assert post.index(each) < post.index(st[each])
def testGraphInverse(self): gr = graph.digraph() gr.generate(50, 300) inv = gr.inverse() for each in gr.edges(): self.assertTrue(each not in inv.edges()) for each in inv.edges(): self.assertTrue(each not in gr.edges())
def test_countGraphs_digraph(self): g = pygraph.digraph() g.add_nodes(range(1,11)) for each in range(1,10): g.add_edge(each,each+1) self.assertTrue(countGraphs(g)==1) g1cut1 = makeCut([1,2],g) self.assertTrue(countGraphs(g1cut1)==2)
def testNodeRemoval(self): gr = graph.digraph() gr.generate(10, 90) gr.del_node(0) self.assertTrue(0 not in gr) for each, other in gr.edges(): self.assertTrue(each in gr) self.assertTrue(other in gr)
def testNoCycleDigraph(self): G = graph.digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge(1, 2) G.add_edge(2, 3) G.add_edge(2, 4) G.add_edge(4, 5) G.add_edge(3, 5) assert G.find_cycle() == []
def resolveIncludes(self, includeTree=graph.digraph()): console.debug("including %s" % (self._fname or "<unknown>",)) config = self._data jobsmap = self.getJobsMap({}) if self._fname: # we stem from a file if self._fname not in includeTree: includeTree.add_node(self._fname) # only for the top-level config - others will be inserted by the parent if 'include' in config: for i in range(len(config['include'])): incspec = config['include'][i] # need this indirection so that later macro expansions in config['inlcude'] take effect # analyse value of ['include'][key] if isinstance(incspec, types.StringTypes): fname = incspec elif isinstance(incspec, types.DictType): fname = incspec['path'] else: raise RuntimeError, "Unknown include spec: %s" % repr(incspec) fname = fname.encode('utf-8') fapath = self.absPath(fname) # calculate path relative to config file # cycle check includeTree.add_node(fapath) # add the child includeTree.add_edge(self._fname, fapath) # add edge to child cycle_nodes = includeTree.find_cycle() if cycle_nodes: raise RuntimeError("Detected circular inclusion of config files: %r" % cycle_nodes) # see if we use a namespace prefix for the imported jobs if isinstance(incspec, types.DictType) and 'as' in incspec: namespace = incspec['as'] else: namespace = "" econfig = Config(self._console, fapath.decode('utf-8')) econfig.resolveIncludes(includeTree) # recursive include # check include/import if 'import' in incspec: importList = incspec['import'] else: importList = None # check include/block if 'block' in incspec: blockList = incspec['block'] else: blockList = None # check include/bypass-export-list if 'bypass-export-list' in incspec: bypassExports = incspec['bypass-export-list'] else: bypassExports = False self._integrateExternalConfig(econfig, namespace, importList, blockList, bypassExports) self._includedConfigs.append(econfig) # save external config for later reference
def testMisleadingDigraph(self): G = graph.digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge(1, 2) G.add_edge(2, 3) G.add_edge(2, 4) G.add_edge(4, 5) G.add_edge(3, 5) G.add_edge(3, 1) assert G.find_cycle() == [1, 2, 3]
def testSmallCycleDigraph(self): G = graph.digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge(1, 2) G.add_edge(2, 3) G.add_edge(2, 4) G.add_edge(4, 5) G.add_edge(2, 1) # Cycle: 1-2 assert G.find_cycle() == [1,2]
def savePythonGraph(self, filename): ''' Saves CFG as a png image by means of graphviz. @param filename: CFG will be saved to "filename.png" ''' try: import graph import gv except ImportError: print '# Err: no modules for drawing graphs found... try:' print '#> sudo apt-get install python-setuptools ' \ '# needed for the next line' print '#> sudo easy_install python-graph '\ '# This actually installs the thing' print '#> sudo apt-get install libgv-python ' \ '# for graphviz in python support' print '#> sudo apt-get install python-pydot # for pydot' return None pattern1 = re.compile(r'\n') pattern2 = re.compile(r'\"') gr = graph.digraph() for n in self.nodes: if self.nodes[n].code != '': if self.nodes[n].condition is not None: txt = re.sub(pattern1, r'\\l', self.nodes[n].code + \ '\n\n' + str(self.nodes[n].condition)) txt = re.sub(pattern2, r'\\"', txt) gr.add_node(n, [('label', '"' + txt + '"')]) #print '1:::' #print txt else: txt = re.sub(pattern1, r'\\l', self.nodes[n].code) txt = re.sub(pattern2, r'\\"', txt) gr.add_node(n, [('label', '"' + txt + '"')]) #print '2:::' #print txt else: txt = re.sub(pattern1, r'\\l', str(self.nodes[n].condition)) txt = re.sub(pattern2, r'\\"', txt) gr.add_node(n, [('label', '"' + txt + '"')]) if not self.nodes[n].conditional: gr.add_node_attribute(n, ('shape', 'box')) for n in self.nodes: for e in self.nodes[n].outgoing: gr.add_edge(n, e.toNode, label=e.type) dot = gr.write(fmt='dot') #print '>>>>>' #print dot #print '<<<<<' gvv = gv.readstring(dot) gv.layout(gvv, 'dot') gv.render(gvv, 'png', str(filename) + '.png')
def testWriteDigraphDot(self): gr = graph.digraph() gr.add_nodes([1, 2, 3, 4, 5]) gr.add_edge(1, 2) gr.add_edge(2, 3) gr.add_edge(2, 4) gr.add_edge(4, 5) gr.add_edge(1, 5) gr.add_edge(3, 5) dot = gr.write('dot') self._check_nodes(gr, dot) self._check_arrows(gr, dot)
def testDigraph(self): G = graph.digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge(1, 2) G.add_edge(2, 3) G.add_edge(2, 4) G.add_edge(4, 5) G.add_edge(1, 5) G.add_edge(3, 5) st, lo = G.breadth_first_search() assert st == {1: None, 2: 1, 3: 2, 4: 2, 5: 1} assert lo == [1, 2, 5, 3, 4]
def testDigraphDFS(self): G = graph.digraph() G.add_nodes([1, 2, 3, 4, 5, 6]) G.add_edge(1, 2) G.add_edge(1, 3) G.add_edge(2, 4) G.add_edge(4, 3) G.add_edge(5, 1) G.add_edge(3, 5) G.add_edge(5, 6) st, pre, post = G.depth_first_search(1, filter=filters.find(5)) assert st == {1: None, 2: 1, 3: 4, 4: 2, 5: 3}
def testDigraph(self): G = graph.digraph() G.add_nodes([1, 2, 3, 4, 5]) G.add_edge(1, 2) G.add_edge(2, 3) G.add_edge(2, 4) G.add_edge(4, 5) G.add_edge(1, 5) G.add_edge(3, 5) st, pre, post = G.depth_first_search() assert st == {1: None, 2: 1, 3: 2, 4: 2, 5: 3} assert pre == [1, 2, 3, 5, 4] assert post == [5, 3, 4, 2, 1]
def createPrinterGraph(gr, depsLogConf): # create a helper graph for output format, mode = getFormatMode(depsLogConf) searchRoot = depsLogConf.get('dot/root') # get the root node for the spanning tree searchRadius = depsLogConf.get('dot/radius', None) if searchRadius: filter = graph.filters.radius(searchRadius) else: filter = graph.filters.null() st, op = gr.breadth_first_search(root=searchRoot, filter=filter) # get the spanning tree gr1 = graph.digraph() st_nodes = set(st.keys() + st.values()) addNodes(gr1, st_nodes) addEdges(gr, gr1, st, st_nodes, mode) return gr1
def _load_tag(self): """ Loads a level. All active objects are updated, missing objects are created. """ ## Build a graph with all relationships betwen objects, then do a topological sort di = graph.digraph() for av in self.versionned_objects.all(): avatar = av.history_model ## Add the node to the graph if not di.has_node(avatar.essence.id): ## It may have been created before through a relationship di.add_node(avatar.essence.id) ## Add edges towards linked objects for field in avatar._meta.fields + avatar._meta.many_to_many: # Check this field is an historised relationship if field.__class__.__name__ != 'ManyToManyField' and field.__class__.__name__ != 'ForeignKey': continue try: if not field.history_field: continue except AttributeError: continue # Extract target essences if field.__class__.__name__ == 'ManyToManyField': target_essences = getattr(avatar, field.name).all() if field.__class__.__name__ == 'ForeignKey': target_essences = [getattr(avatar, field.name),] if target_essences[0] == None: target_essences = [] # Add edges for essence in target_essences: ## Add the target node to the graph if it doesn't already exist if not di.has_node(essence.id): di.add_node(essence.id) ## Add the edge di.add_edge(essence.id, avatar.essence.id) id_list = di.topological_sorting() ## Restore the objects in the computed order for essence_id in id_list: avatar = self.versionned_objects.get(essence__id = essence_id).history_model _revert_to(avatar)
def load_automaton(filename): """ Read a automaton described as a labelled transition system and build the equivalent graph. @type filename: string @param filename: Name of the file containing the LTS-described automaton. @rtype: graph @return: Automaton's graph. """ gr = graph.digraph() infile = file(filename,'r') line = infile.readline() final = [] while (line): line = line.replace("\n",'').split(' ') datatype = line[0] data = line[1:] if (datatype == 'Q'): # States for each in data: gr.add_node(each) if (datatype == 'A'): # Alphabet pass if (datatype == 'F'): # Final states final = final + data if (datatype == 's'): # Initial state gr.add_node('.',attrs=[('shape','point')]) gr.add_edge('.',data[0]) if (datatype == 't'): # Transitions if (gr.has_edge(data[1], data[2])): gr.set_edge_label(data[1], data[2], \ gr.get_edge_label(data[1], data[2]) + ', ' + data[0]) else: gr.add_edge(data[1], data[2], label=data[0]) line = infile.readline() for node in gr: if (node in final and node != '.'): gr.add_node_attribute(node, ('shape','doublecircle')) elif (node != '.'): gr.add_node_attribute(node, ('shape','circle')) return gr, final
def createPrinterGraph(gr, depsLogConf): # create a helper graph for output format, mode = getFormatMode(depsLogConf) searchRoot = depsLogConf.get( 'dot/root') # get the root node for the spanning tree searchRadius = depsLogConf.get('dot/radius', None) if searchRadius: filter = graph.filters.radius(searchRadius) else: filter = graph.filters.null() st, op = gr.breadth_first_search( root=searchRoot, filter=filter) # get the spanning tree gr1 = graph.digraph() st_nodes = set(st.keys() + st.values()) addNodes(gr1, st_nodes) addEdges(gr, gr1, st, st_nodes, mode) return gr1
def test_combinations(self): # combinations() actually exists in python 2.6 as itertools.combinations() # very simple test. simpleTest = [1,2,3,4,5] simplecom = combinations(simpleTest,1) simplecom = list(simplecom) self.assertTrue(len(simplecom) == len(simpleTest)) #stillsimplecom = list(combinations(simpleTest,2)) # make a directed graph g = pygraph.digraph() # add some nodes g.add_nodes(range(1,11)) # add some edges for each in range(1,10): g.add_edge(each,each+1) # get the combinations com = combinations(g.edges(),3) # don't want a generator com = list(com) # don't want dupes. com2 = frozenset(copy.copy(com)) self.assertTrue(com!=com2)
def depsToDotFile(classDepsIter, depsLogConf): def getNodeAttribs(classId, useCompiledSize=False, optimize=[]): # return color according to size attribs = [] color = fontsize = None sizes = { # (big-threshold, medium-threshold) 'compiled': (8000, 2000), 'source': (20000, 5000) } compOptions = CompileOptions() compOptions.optimize = optimize compOptions.variantset = variants compOptions.format = True # guess it's most likely if classId in script.classesAll: if useCompiledSize: fsize = script.classesAll[classId].getCompiledSize( compOptions, featuremap=script._featureMap) mode = 'compiled' else: fsize = script.classesAll[classId].size mode = 'source' if fsize > sizes[mode][0]: color = "red" fontsize = 15 elif fsize > sizes[mode][1]: color = "green" fontsize = 13 else: color = "blue" fontsize = 10 if fontsize: attribs.append(("fontsize", fontsize)) if color: attribs.append(("color", color)) return attribs def addEdges(gr, gr1, st, st_nodes, mode): # rather gr.add_spanning_tree(st), go through individual edges for coloring for v in st.iteritems(): if None in v: # drop edges with a None node continue v2, v1 = v if gr.has_edge(v1, v2): gr1.add_edge(v1, v2, attrs=gr.get_edge_attributes(v1, v2)) else: gr1.add_edge( v1, v2, ) if not mode or not mode == "span-tree-only": # add additional dependencies for v1 in st_nodes: # that are not covered by the span tree for v2 in st_nodes: if None in (v1, v2): continue if gr.has_edge(v1, v2): gr1.add_edge(v1, v2, attrs=gr.get_edge_attributes(v1, v2)) return def addNodes(gr, st_nodes): # rather gr.add_nodes(st), go through indiviudal nodes for coloring useCompiledSize = depsLogConf.get("dot/compiled-class-size", True) optimize = jobconf.get("compile-options/code/optimize", []) for cid in st_nodes: if cid == None: # None is introduced in st continue attribs = getNodeAttribs(cid, useCompiledSize, optimize) gr.add_node(cid, attrs=attribs) return def writeDotFile(gr1, depsLogConf): file = depsLogConf.get('dot/file', "deps.dot") dot = gr1.write(fmt='dotwt') console.info("Writing dependency graph to file: %s" % file) filetool.save(file, dot) return def getFormatMode(depsLogConf): format = mode = None mode = depsLogConf.get('dot/span-tree-only', None) if mode: mode = "span-tree-only" return format, mode def createPrinterGraph(gr, depsLogConf): # create a helper graph for output format, mode = getFormatMode(depsLogConf) searchRoot = depsLogConf.get( 'dot/root') # get the root node for the spanning tree searchRadius = depsLogConf.get('dot/radius', None) if searchRadius: filter = graph.filters.radius(searchRadius) else: filter = graph.filters.null() st, op = gr.breadth_first_search( root=searchRoot, filter=filter) # get the spanning tree gr1 = graph.digraph() st_nodes = set(st.keys() + st.values()) addNodes(gr1, st_nodes) addEdges(gr, gr1, st, st_nodes, mode) return gr1 # -- Main (depsToDotFile) ------------------------------------------ phase = depsLogConf.get('phase', None) gr = graph.digraph() #graphAddNodes(gr, script.classes) graphAddEdges(classDepsIter, gr, phase) gr1 = createPrinterGraph(gr, depsLogConf) writeDotFile(gr1, depsLogConf) return