def get_scc(path): (v_len, edges) = loadCNFFormula(path) implication_graph = nx.DiGraph() nodes = [i for i in range(1, v_len + 1)] + [-i for i in range(1, v_len + 1)] implication_graph.add_nodes_from(nodes) for x, y in edges: implication_graph.add_edge(-x, y) implication_graph.add_edge(-y, x) scc_gen = strongly_connected_components(implication_graph) scc = {} i = 0 for s in scc_gen: new_set = set() for node in s: new_set.add(node) scc[i] = new_set i += 1 return scc, implication_graph
def _analyze(rules: List[Rule]) -> List[List[Rule]]: # build rule dependency graph occ: Dict[Atom, Set[RuleIndex]] = {} dep_graph = DiGraph() for u, rule in enumerate(rules): dep_graph.add_node(u) for lit in rule.body: occ.setdefault(abs(lit), set()).add(u) for u, rule in enumerate(rules): atm, = rule.head for v in occ.get(atm, []): dep_graph.add_edge(u, v) sccs = list(strongly_connected_components(dep_graph)) # build scc dependency graph # (this part only exists because the networkx library does not document the # order of components; in principle, the tarjan algorithm guarentees a # topological order) scc_rule: Dict[RuleIndex, RuleIndex] = {} scc_graph = DiGraph() for i, scc in enumerate(sccs): scc_graph.add_node(i) for u in scc: scc_rule[u] = i for i, scc in enumerate(sccs): for u in scc: for v in dep_graph[u]: j = scc_rule[u] if i != j: scc_graph.add_edge(i, j) return [[rules[j] for j in sccs[i]] for i in topological_sort(scc_graph)]
def get_cycle_vars(graph, varmeta): # examine the graph to see if we have any cycles that we need to # deal with cycle_vars = [] # make a copy of the graph since we don't want to modify it g = graph.subgraph(graph.nodes_iter()) sizes = [] while not is_directed_acyclic_graph(g): if not sizes: # get total data sizes for subsystem connections for u,v,data in g.edges_iter(data=True): sz = 0 for node in data['varconns']: sz += varmeta[node].get('size', 0) data['conn_size'] = sz sizes.append((sz, (u,v))) sizes = sorted(sizes) strong = list(strongly_connected_components(g))[0] if len(strong) == 1: break # find the connection with the smallest data xfer for sz, (src, dest) in sizes: if src in strong and dest in strong: cycle_vars.extend(g[src][dest]['varconns']) g.remove_edge(src, dest) sizes.remove((sz, (src, dest))) break return cycle_vars
def component_colormap(graph): """ Colormap by strong compoments """ # automatically color by components # a list of colors in hexadecimal Red/Gree/Blue notation colors = [ ORANGE, SPRING_GREEN, GOLD, TEAL, PURPLE, NAVY, SIENNA, CRIMSON, BLUE, ] # find the strongly connected components components = component.strongly_connected_components(graph) # make sure we have as many colors as components if len(colors) < len(components): util.warn('there are more components than colors!') # create the colormap colormap = {} for color, comp in zip(colors, components): for node in comp: colormap[node] = color return colormap
def compress_graph(self): """ 出力サイズが同じ頂点を縮約したグラフを作る """ g_for_scc = self.g.copy() for v in self.g.nodes: # vからの入力があるnodeとvのoutput_sizeは同じ if self.is_concat_node(v): if self.allow_param_in_concat: v_edges = list(self.g_inv.edges([v])) for (_, s), (__, t) in zip(v_edges[:-1], v_edges[1:]): g_for_scc.add_edge(s, t) g_for_scc.add_edge(t, s) else: for _, u in self.g_inv.edges([v]): g_for_scc.add_edge(v, u) scc_idx = [0] * (self.max_node_idx + 1) scc = strongly_connected_components(g_for_scc) for idx, nodes in enumerate(scc): for v in nodes: scc_idx[v] = idx g_compressed = nx.DiGraph() for v in self.g.nodes: g_compressed.add_node(scc_idx[v]) for s, t in self.g.edges: rs = scc_idx[s] rt = scc_idx[t] if rs != rt: g_compressed.add_edge(rs, rt) return scc_idx, g_compressed
def connect(self, srcpath, destpath): """Add an edge to our Component graph from *srccompname* to *destcompname*. """ graph = self._graph srccompname, srcvarname, destcompname, destvarname = \ _cvt_names_to_graph(srcpath, destpath) if srccompname == '@xin' and destcompname != '@bin': # this is an auto-passthrough input so we need 2 links if '@bin' not in graph['@xin']: link = _Link('@xin', '@bin') graph.add_edge('@xin', '@bin', link=link) else: link = graph['@xin']['@bin']['link'] link.connect(srcvarname, '.'.join([destcompname, destvarname])) if destcompname not in graph['@bin']: link = _Link('@bin', destcompname) graph.add_edge('@bin', destcompname, link=link) else: link = graph['@bin'][destcompname]['link'] link.connect('.'.join([destcompname, destvarname]), destvarname) elif destcompname == '@xout' and srccompname != '@bout': # this is an auto-passthrough output so we need 2 links if '@xout' not in graph['@bout']: link = _Link('@bout', '@xout') graph.add_edge('@bout', '@xout', link=link) else: link = graph['@bout']['@xout']['link'] link.connect('.'.join([srccompname, srcvarname]), destvarname) if srccompname not in graph or '@bout' not in graph[srccompname]: link = _Link(srccompname, '@bout') graph.add_edge(srccompname, '@bout', link=link) else: link = graph[srccompname]['@bout']['link'] link.connect(srcvarname, '.'.join([srccompname, srcvarname])) else: try: link = graph[srccompname][destcompname]['link'] except KeyError: link = _Link(srccompname, destcompname) graph.add_edge(srccompname, destcompname, link=link) if is_directed_acyclic_graph(graph): link.connect(srcvarname, destvarname) else: # cycle found # do a little extra work here to give more info to the user # in the error message strongly_connected = strongly_connected_components(graph) if len(link) == 0: graph.remove_edge(srccompname, destcompname) for strcon in strongly_connected: if len(strcon) > 1: raise RuntimeError( 'circular dependency (%s) would be created by connecting %s to %s' % (str(strcon), '.'.join([srccompname, srcvarname]), '.'.join([destcompname, destvarname]))) self._allsrcs[destpath] = srcpath
def get_reduced_graph(self): if self._reduced_graph is None: parent_graph = self.parent.get_reduced_graph() # copy parent graph g = parent_graph.subgraph(parent_graph.nodes_iter()) nodes = set([c.name for c in self.workflow]) g.collapse_subdrivers(nodes, self.workflow.subdrivers()) nodes.add(self.name) g = g.full_subgraph(nodes) nodes.remove(self.name) # create fake edges to/from the driver and each of its # components so we can get everything that's relevant # by getting all nodes that are strongly connected to the # driver in the graph. to_add = [] for name in nodes: if not g.has_edge(self.name, name): to_add.append((self.name, name)) if not g.has_edge(name, self.name): to_add.append((name, self.name)) g.add_edges_from(to_add) comps = [] for comps in strongly_connected_components(g): if self.name in comps: break g.remove_edges_from(to_add) self._reduced_graph = g.subgraph(comps) return self._reduced_graph
def get_reduced_graph(self): if self._reduced_graph is None: parent_graph = self.parent._reduced_graph # copy parent graph g = parent_graph.subgraph(parent_graph.nodes_iter()) nodes = set([c.name for c in self.workflow]) g.collapse_subdrivers(nodes, self.workflow.subdrivers()) nodes.add(self.name) g = g.full_subgraph(nodes) nodes.remove(self.name) # create fake edges to/from the driver and each of its # components so we can get everything that's relevant # by getting all nodes that are strongly connected to the # driver in the graph. to_add = [] for name in nodes: if not g.has_edge(self.name, name): to_add.append((self.name, name)) if not g.has_edge(name, self.name): to_add.append((name, self.name)) g.add_edges_from(to_add) comps = [] for comps in strongly_connected_components(g): if self.name in comps: break g.remove_edges_from(to_add) self._reduced_graph = g.subgraph(comps) return self._reduced_graph
def get_loops(self): lvlmap = self.get_level_map() result = [] for i in xrange(len(lvlmap) - 1, -1, -1): irreducible = False for n in lvlmap[i]: for e in self.in_edges(n): if not self.has_edge(*e): continue if self.is_cj_edge(e) and self.is_sp_back_edge(e): irreducible = True elif self.is_bj_edge(e): cs = self.reach_under(e[1]) | set([n]) ret = self.collapse_set(n, cs) ret.entries.add(n) result.append(ret) if irreducible: j = chain(*(lvlmap[i] for i in xrange(i, len(lvlmap)))) for scc in strongly_connected_components(self.subgraph(j)): if len(scc) > 1: e = [e for e in scc if self.node[e]['level'] == i] ret = self.collapse_set(min(scc), scc) ret.entries = set(e) ret.reducible = False result.append(ret) return result
def check_config(self): """Check for cyclc graph.""" graph = self._get_collapsed_graph() if not is_directed_acyclic_graph(graph): # do a little extra work here to give more info to the user # in the error message strcon = strongly_connected_components(graph) self.scope.raise_exception('circular dependency found between' ' the following: %s' % str(strcon[0]), RuntimeError)
def check_config(self): """Check for cyclc graph.""" graph = self._get_collapsed_graph() if not is_directed_acyclic_graph(graph): # do a little extra work here to give more info to the user # in the error message strcon = strongly_connected_components(graph) self.scope.raise_exception( 'circular dependency found between' ' the following: %s' % str(strcon[0]), RuntimeError)
def _get_topsort(self): if self._topsort is None: graph = self._get_collapsed_graph() try: self._topsort = nx.topological_sort(graph) except nx.NetworkXUnfeasible: # do a little extra work here to give more info to the user in the error message strcon = strongly_connected_components(graph) self.scope.raise_exception('circular dependency found between the following: %s' % str(strcon[0]), RuntimeError) return self._topsort
def test_scc(): vertex_count = 8 edges_count = 14 tests_count = 5 for _ in range(tests_count): ntx_graph = gnm_random_graph(vertex_count, edges_count, directed=True) my_graph = networkx_to_my(ntx_graph, vertex_count) scc_networkx = list(strongly_connected_components(ntx_graph)) scc_my = calc_scc(my_graph) res = compare_scc(scc_my, scc_networkx) assert res
def has_loop(edges, threshold=2): """check if a list of edges representing a directed graph contains a loop args: edges: list of edge sets representing a directed graph i.e. [(1, 2), (2, 1)] threshold: min number of nodes contained in loop returns: bool """ g = networkx.DiGraph() g.add_edges_from(edges) return any(len(comp) >= threshold for comp in strongly_connected_components(g))
def problem_graph2(): ntx = DiGraph() edges = [(0, 6), (1, 2), (1, 0), (2, 6), (2, 1), (2, 3), (3, 4), (4, 1), (4, 2), (5, 0), (5, 2), (7, 4), (7, 6), (7, 2)] data = [[] for _ in range(8)] for edge in edges: ntx.add_edge(*edge) data[edge[0]].append(edge[1]) my_graph = Graph(1) my_graph._data = data my_graph._size = 8 scc_networkx = list(strongly_connected_components(ntx)) scc_my = calc_scc(my_graph) assert compare_scc(scc_my, scc_networkx)
def _get_topsort(self): """ Return a sorted list of components in the workflow. """ if self._topsort is None: self._severed_edges = set() graph = nx.DiGraph(self._get_collapsed_graph()) cyclic = True while cyclic: try: self._topsort = nx.topological_sort(graph) cyclic = False except nx.NetworkXUnfeasible: strong = strongly_connected_components(graph) # We may have multiple loops. We only deal with one at # a time because multiple loops create some non-unique # paths. strong = strong[0] # Break one edge of the loop. # For now, just break the first edge. # TODO: smarter ways to choose edge to break. graph.remove_edge(strong[-1], strong[0]) # Keep a list of the edges we break, so that a solver # can use them as its independents/dependents. depgraph = self.scope._depgraph edge_set = set( depgraph.get_directional_interior_edges( strong[-1], strong[0])) self._severed_edges.update(edge_set) if self._severed_edges: self._var_graph = self.scope._depgraph.copy() self._var_graph.remove_edges_from(self._severed_edges) return self._topsort
def _get_topsort(self): """ Return a sorted list of components in the workflow. """ if self._topsort is None: self._severed_edges = set() graph = nx.DiGraph(self._get_collapsed_graph()) cyclic = True while cyclic: try: self._topsort = nx.topological_sort(graph) cyclic = False except nx.NetworkXUnfeasible: strong = strongly_connected_components(graph) # We may have multiple loops. We only deal with one at # a time because multiple loops create some non-unique # paths. strong = strong[0] # Break one edge of the loop. # For now, just break the first edge. # TODO: smarter ways to choose edge to break. graph.remove_edge(strong[-1], strong[0]) # Keep a list of the edges we break, so that a solver # can use them as its independents/dependents. depgraph = self.scope._depgraph edge_set = set(depgraph.get_directional_interior_edges(strong[-1], strong[0])) self._severed_edges.update(edge_set) if self._severed_edges: self._var_graph = self.scope._depgraph.copy() self._var_graph.remove_edges_from(self._severed_edges) return self._topsort
def any2CNF(name: str) -> Optional[Dict[int, bool]]: G = toNxGraph(name) SCC = strongly_connected_components(G) # returns generator SCCList = [] mapVtoComp = {} t = 0 for S in SCC: SCCList.append(S) for v in S: if -v in S: # print("in ", t, " both ", v, " and ", -v, " are present") return None mapVtoComp[v] = t t += 1 H = nx.DiGraph( ) # graf w którym wierzchołkami są silnie spójne składowe (dokladnie ich ind w SCCList H.add_nodes_from([x for x in range(0, t)]) # print(mapVtoComp) for ind, S in enumerate(SCCList): for v in S: for u in G.adj[v].keys(): if mapVtoComp[u] != mapVtoComp[v]: H.add_edge(mapVtoComp[v], mapVtoComp[u]) topSort = topological_sort(H) vBoolValues = {} for x in topSort: # print(x, " ", SCCList[x]) for v in SCCList[x]: if v not in vBoolValues.keys(): vBoolValues[v] = False vBoolValues[-v] = True return vBoolValues
def check_config(self, strict=False): """Make sure the problem is set up right.""" super(FixedPointIterator, self).check_config(strict=strict) # We need to figure our severed edges before querying. eqcons = self.get_constraints().values() n_dep = len(eqcons) n_indep = len(self.get_parameters()) if n_dep != n_indep: msg = "The number of input parameters must equal the number of" \ " output constraint equations in FixedPointIterator." self.raise_exception(msg, RuntimeError) # Check to make sure we don't have a null problem. if n_dep == 0: cgraph = self.parent._depgraph.component_graph().subgraph([c.name for c in self.workflow]) strong = list(strongly_connected_components(cgraph)) if not ((strong and len(strong[0]) > 1) or self._get_param_constraint_pairs()): msg = "FixedPointIterator requires a cyclic workflow, or a " \ "parameter/constraint pair." self.raise_exception(msg, RuntimeError) # Check the eq constraints to make sure they look ok. for eqcon in eqcons: if eqcon.rhs.text == '0' or eqcon.lhs.text == '0': msg = "Please specify constraints in the form 'A=B'" msg += ': %s = %s' % (eqcon.lhs.text, eqcon.rhs.text) self.raise_exception(msg, RuntimeError) if len(eqcon.get_referenced_varpaths()) > 2: msg = "Please specify constraints in the form 'A=B'" msg += ': %s = %s' % (eqcon.lhs.text, eqcon.rhs.text) self.raise_exception(msg, RuntimeError)
from dimacs import * import networkx as nx from networkx.algorithms.components import strongly_connected_components from networkx.algorithms.dag import topological_sort #Budowa grafu implikacji def graph(G,F): for x,y in F: if not G.has_edge(-x,y): G.add_edge(-x,y) if not G.has_edge(-y,x): G.add_edge(-y,x) G = nx.DiGraph() (V,F) = loadCNFFormula("simple_sat") print(F) graph(G,F) print(G.nodes) print(G.edges) O = topological_sort(G) SCC = strongly_connected_components(G)
def zad3(): G, V = load_formula('sat/sat100_200') SCC = strongly_connected_components(G) print(check_if_fulfillable(SCC)) SCC_G = create_components_graph(G, SCC) sorted_SCC_G = topological_sort(SCC_G)
def compute_itersets(self, cgraph): """Return a list of all components required to run a full iteration of this driver. """ self._full_iter_set = set() comps = [ getattr(self.parent, n) for n in self.workflow._explicit_names ] subdrivers = [c for c in comps if has_interface(c, IDriver)] subnames = [s.name for s in subdrivers] allcomps = [ getattr(self.parent, n) for n in cgraph if not n == self.name ] alldrivers = [c.name for c in allcomps if has_interface(c, IDriver)] # make our own copy of the graph to play with cgraph = cgraph.subgraph( [n for n in cgraph if n not in alldrivers or n in subnames]) myset = set(self.workflow._explicit_names + self.list_pseudocomps()) # First, have all of our subdrivers (recursively) determine # their iteration sets, because we need those to determine # our full set. subcomps = set() for comp in subdrivers: cgcopy = cgraph.subgraph(cgraph.nodes_iter()) comp.compute_itersets(cgcopy) subcomps.update(comp._full_iter_set) # create fake edges to/from the driver and each of its # components so we can get everything that's relevant # by getting all nodes that are strongly connected to the # driver in the graph. for drv in subdrivers: for name in drv._full_iter_set: cgraph.add_edge(drv.name, name) cgraph.add_edge(name, drv.name) # add predecessors to my pseudocomps if they aren't # already in the itersets of my subdrivers for pcomp in self.list_pseudocomps(): for pred in cgraph.predecessors(pcomp): if pred not in subcomps: myset.add(pred) # now create fake edges from us to all of the comps # that we know about in our iterset for name in myset: cgraph.add_edge(self.name, name) cgraph.add_edge(name, self.name) # collapse our explicit subdrivers self._iter_set = self.workflow._explicit_names self._collapse_subdrivers(cgraph) comps = [] for comps in strongly_connected_components(cgraph): if self.name in comps: break self._iter_set = set(comps) self._iter_set.remove(self.name) # the following fixes a test failure when using DOEdriver with # an empty workflow. This adds any comps that own DOEdriver # parameters to the DOEdriver's iteration set. conns = self.get_expr_depends() self._iter_set.update( [u for u, v in conns if u != self.name and u not in subcomps]) self._iter_set.update( [v for u, v in conns if v != self.name and v not in subcomps]) old_iter = self._iter_set.copy() # remove any drivers that were not explicitly specified in our worklow self._iter_set = set([ c for c in self._iter_set if c not in alldrivers or c in subnames ]) diff = old_iter - self._iter_set if diff: self._logger.warning( "Driver '%s' had the following subdrivers removed" " from its workflow because they were not explicity" " added: %s" % (self.name, list(diff))) self._full_iter_set.update(self._iter_set) self._full_iter_set.update(subcomps)
def graph_strongly_connected_components(output_directory, is_trial, graphs, widget, properties_dict): output_directory = os.path.join(output_directory, 'StronglyConnectedComponents') if not os.path.exists(output_directory): os.makedirs(output_directory) log_file = os.path.join(output_directory, 'StronglyConnectedComponents.txt') largest_components = [] for window, graph in enumerate(graphs): components = strongly_connected_components(graph) if is_trial: log('Strongly connected components: ', file=log_file, widget=None) else: log(f'Strongly Connected Components for window {window}:', file=log_file, widget=None) components = [component for component in components] components = sorted(components, key=lambda x: len(x)) largest_components.append(components[-1]) longest_component_length = len(components[-1]) components_greater_than_one = 0 for component in components: if len(component) > 1: components_greater_than_one += 1 component_regions = [] for node in component: node_index = 0 for key in list(CHANNELS_DICT.keys()): if CHANNELS_DICT[key] == node: node_index = key break region_index = 0 for index, region in enumerate(CHANNELS_PLACEMENT): if node_index in region: region_index = index break component_regions.append( CHANNELS_PLACEMENT_LABEL[region_index].replace('\n', '_')) if is_trial: log(f'\t Length {len(component)} : {component}', file=log_file, widget=None) log(f'\t Length {len(component_regions)} : {component_regions}', file=log_file, widget=None) else: log(f'\t Length {len(component)} : {component}', file=log_file, widget=None) log(f'\t Length {len(component_regions)} : {component_regions}', file=log_file, widget=None) if not is_trial: properties_dict[window][ STRONGLY_CONNECTED_COMPONENTS] = components_greater_than_one properties_dict[window][ LONGEST_COMPONET_LENGTH] = longest_component_length else: properties_dict[ STRONGLY_CONNECTED_COMPONENTS] = components_greater_than_one properties_dict[LONGEST_COMPONET_LENGTH] = longest_component_length with open(os.path.join(output_directory, 'LargeComponent.bin'), 'wb+') as f: pickle.dump(largest_components, f) components_intersection = largest_components[0] for index in range(1, len(largest_components)): aux = [] for node in components_intersection: if node in largest_components[index]: aux.append(node) components_intersection = aux log(f'Largest component intersection; {len(components_intersection)} nodes: ', file=log_file, widget=None) for node in components_intersection: log(f'\tNode {node}', file=log_file, widget=None) concatenated_largest_component = [] for component in largest_components: concatenated_largest_component.extend(component) freq_dict = {} for key in list(CHANNELS_DICT.keys()): node = CHANNELS_DICT[key] freq_dict[node] = concatenated_largest_component.count(node) / ( len(largest_components)) sorted_keys = sorted(freq_dict, key=lambda x: freq_dict[x], reverse=True) log(f'Largest component frequencies: ', file=log_file, widget=None) for key in sorted_keys: log(f'\t{key} : {freq_dict[key]}', file=log_file, widget=None)
with open('graph-components.txt') as f: lines = f.readlines() edgeList = [line.strip().split() for line in lines] G = nx.DiGraph() G.add_edges_from(edgeList) figure(figsize=(14, 6)) ax = plt.subplot(1, 3, 1) ax.title.set_text("Input graph ") nx.draw_networkx(G) weak_components = weakly_connected_components(G) strong_components = strongly_connected_components(G) W = [G.subgraph(c).copy() for c in weakly_connected_components(G)] S = [G.subgraph(c).copy() for c in strongly_connected_components(G)] weak_component = max(W, key=len) strong_component = max(S, key=len) ax = plt.subplot(1, 3, 2) ax.title.set_text("Weakly Connected Components ") pos = nx.spring_layout(weak_component) nx.draw_networkx(weak_component) ax = plt.subplot(1, 3, 3) ax.title.set_text("Strongly Connected Components ") pos = nx.spring_layout(strong_component)
def compute_itersets(self, cgraph): """Return a list of all components required to run a full iteration of this driver. """ self._full_iter_set = set() comps = [getattr(self.parent, n) for n in self.workflow._explicit_names] subdrivers = [c for c in comps if has_interface(c, IDriver)] subnames = [s.name for s in subdrivers] allcomps = [getattr(self.parent, n) for n in cgraph if not n == self.name] alldrivers = [c.name for c in allcomps if has_interface(c, IDriver)] # make our own copy of the graph to play with cgraph = cgraph.subgraph([n for n in cgraph if n not in alldrivers or n in subnames]) myset = set(self.workflow._explicit_names + self.list_pseudocomps()) # First, have all of our subdrivers (recursively) determine # their iteration sets, because we need those to determine # our full set. subcomps = set() for comp in subdrivers: cgcopy = cgraph.subgraph(cgraph.nodes_iter()) comp.compute_itersets(cgcopy) subcomps.update(comp._full_iter_set) # create fake edges to/from the driver and each of its # components so we can get everything that's relevant # by getting all nodes that are strongly connected to the # driver in the graph. for drv in subdrivers: for name in drv._full_iter_set: cgraph.add_edge(drv.name, name) cgraph.add_edge(name, drv.name) # add predecessors to my pseudocomps if they aren't # already in the itersets of my subdrivers for pcomp in self.list_pseudocomps(): for pred in cgraph.predecessors(pcomp): if pred not in subcomps: myset.add(pred) # now create fake edges from us to all of the comps # that we know about in our iterset for name in myset: cgraph.add_edge(self.name, name) cgraph.add_edge(name, self.name) # collapse our explicit subdrivers self._iter_set = self.workflow._explicit_names self._collapse_subdrivers(cgraph) comps = [] for comps in strongly_connected_components(cgraph): if self.name in comps: break self._iter_set = set(comps) self._iter_set.remove(self.name) # the following fixes a test failure when using DOEdriver with # an empty workflow. This adds any comps that own DOEdriver # parameters to the DOEdriver's iteration set. conns = self.get_expr_depends() self._iter_set.update([u for u,v in conns if u != self.name and u not in subcomps]) self._iter_set.update([v for u,v in conns if v != self.name and v not in subcomps]) old_iter = self._iter_set.copy() # remove any drivers that were not explicitly specified in our worklow self._iter_set = set([c for c in self._iter_set if c not in alldrivers or c in subnames]) diff = old_iter - self._iter_set if diff: self._logger.warning("Driver '%s' had the following subdrivers removed" " from its workflow because they were not explicity" " added: %s" % (self.name, list(diff))) self._full_iter_set.update(self._iter_set) self._full_iter_set.update(subcomps)