def isolate(expanded_manifest, subset): section = subset["section"] name = subset["name"] uid = f"{section}|{name}" m = create_minimal_manifest(expanded_manifest) G = convert_to_graph(expanded_manifest, nx.DiGraph()) node = G.nodes.get(uid) data = deepcopy(node) del data["section"] del data["item_name"] m[node.get("section")][node.get("item_name")] = data if subset.get("include_dependencies", False): click.echo("Including dependencies") for dependency in nx.edge_dfs(G, uid, orientation="original"): link, dependency_name, direction = dependency node = G.nodes.get(dependency_name) data = deepcopy(node) del data["section"] del data["item_name"] m[node.get("section")][node.get("item_name")] = data if subset.get("include_reverse_dependencies", False): click.echo("Including reverse dependencies") for dependency in nx.edge_dfs(G, uid, orientation="reverse"): dependency_name, link, direction = dependency node = G.nodes.get(dependency_name) data = deepcopy(node) del data["section"] del data["item_name"] m[node.get("section")][node.get("item_name")] = data return m
def sort_instructions(instructions): '''Finds the correct execution order for the given instructions. :param instructions: List of conditional relations for instruction steps pairs. :type instructions: list(tuple(int)) ''' # compute dependency tree G = nx.DiGraph() G.add_edges_from(instructions) dependencies, deps_copy = {}, {} for node in G: values = list(nx.edge_dfs(G, node, orientation='reverse')) dependencies[node] = set([t[0] for t in values]) deps_copy[node] = set([t[0] for t in values]) # step order computation order = '' while len(dependencies) > 0: next_node = sorted(dependencies.keys(), key=lambda x: (len(dependencies[x]), x))[0] for n, children in dependencies.items(): children.discard(next_node) del dependencies[next_node] order += next_node return deps_copy, order
def adjust_edge_perturb_radii(frcs, graph, perturb_factor=2): """ Returns a new graph where the 'perturb_radius' has been adjusted to account for rounding errors. See train_image for parameters and returns. 调整perturb_radius边的权重, 由于舍入误差 为什么要这样调整而不在添加边的时候直接进行四舍五入? 为什么下一次迭代要算上上一次的误差? 如果没有这个调整效果会差多少? """ graph = graph.copy() total_rounding_error = 0 # 直到源结点遍历完所有它能到达的边才停止, n1 n2为每一访问的边的两端的节点 for n1, n2 in nx.edge_dfs(graph): desired_radius = distance.euclidean(frcs[n1, 1:], frcs[n2, 1:]) / perturb_factor upper = int(np.ceil(desired_radius)) lower = int(np.floor(desired_radius)) round_up_error = total_rounding_error + upper - desired_radius round_down_error = total_rounding_error + lower - desired_radius if abs(round_up_error) < abs(round_down_error): graph.edge[n1][n2]['perturb_radius'] = upper total_rounding_error = round_up_error else: graph.edge[n1][n2]['perturb_radius'] = lower total_rounding_error = round_down_error return graph
def _build(G, target=None, full=False, outs=False): import networkx as nx from dvc.repo.graph import get_pipeline, get_pipelines if target: H = get_pipeline(get_pipelines(G), target) if not full: descendants = nx.descendants(G, target) descendants.add(target) H.remove_nodes_from(set(G.nodes()) - descendants) else: H = G if outs: G = nx.DiGraph() for stage in H.nodes: G.add_nodes_from(stage.outs) for from_stage, to_stage in nx.edge_dfs(H): G.add_edges_from([(from_out, to_out) for from_out in from_stage.outs for to_out in to_stage.outs]) H = G def _relabel(node): from dvc.stage import Stage return node.addressing if isinstance(node, Stage) else str(node) return nx.relabel_nodes(H, _relabel, copy=False)
def upstream_edge_info(wg, n): upstream_edges = list(nx.edge_dfs(wg, n, orientation='reverse')) # print(upstream_edges) up_switch_dict = {} e_file = gv.filepaths["edges"] for u in upstream_edges: # edge info: p = u[0].lstrip() q = u[1].lstrip() edge_of_path_name_1 = p + "_to_" + event_intensity(n) edge_of_path_name_2 = q + "_to_" + p edge_search_result_1 = db._edge_search(edge_of_path_name_1) edge_search_result_2 = db._edge_search(edge_of_path_name_2) try: with open(e_file, 'r') as f: csvr = csv.reader(f) csvr = list(csvr) for row in csvr: if row[0].lstrip() == edge_of_path_name_1 or row[0].lstrip( ) == edge_of_path_name_2: if edge_search_result_1 != 0 or edge_search_result_2 != 0: if row[1].lstrip() == "switch": # print("[i] Upstream Switch: {}, Status: {}, Availability: {}".format(row[0], row[4], # row[13])) up_switch_dict[row[0]] = row[4] if row[1].lstrip() == "transformer": pass # print( # " [i] Upstream Transformer: {}, Status: {}, Availability: {}".format(row[0], row[4], # row[13])) except: print("[x] Error in up-stream edge search.") return up_switch_dict
def amplify_network(self, epochs=5, alpha=1.): local_g = self.graph.copy() influence_epochs = {} for epoch in range(epochs): for node, influence in local_g.nodes(data='influence'): if epoch == 0: influence_epochs[node] = [] influence_epochs[node].append(influence) egde_traversal = list(nx.edge_dfs(local_g)) influence = nx.get_node_attributes(local_g, 'influence') weight_absolute = nx.get_edge_attributes(local_g, 'weight_absolute') for _, (from_node, to_node, _) in enumerate(egde_traversal): if influence[to_node] == 0: computed_influence = 0 else: computed_influence = influence[to_node] + ( influence[from_node] * (alpha * weight_absolute[(from_node, to_node, 0)])) if int(copysign(1, influence[to_node])) == 1: computed_influence = computed_influence if computed_influence > 0 else 0 elif computed_influence > 0: computed_influence = computed_influence if computed_influence < 0 else 0 influence[to_node] = computed_influence nx.set_node_attributes(local_g, influence, 'influence') return epochs, {'influence_epochs': influence_epochs}
def _build_graph(self, target, commands, outs): import networkx from dvc.stage import Stage from dvc.repo.graph import get_pipeline target_stage = Stage.load(self.repo, target) G = get_pipeline(self.repo.pipelines, target_stage) nodes = set() for stage in networkx.dfs_preorder_nodes(G, target_stage): if commands: if stage.cmd is None: continue nodes.add(stage.cmd) elif outs: for out in stage.outs: nodes.add(str(out)) else: nodes.add(stage.relpath) edges = [] for from_stage, to_stage in networkx.edge_dfs(G, target_stage): if commands: if to_stage.cmd is None: continue edges.append((from_stage.cmd, to_stage.cmd)) elif outs: for from_out in from_stage.outs: for to_out in to_stage.outs: edges.append((str(from_out), str(to_out))) else: edges.append((from_stage.relpath, to_stage.relpath)) return list(nodes), edges, networkx.is_tree(G)
def reachable_subgraph(self): """Return a new StmtGraph that only contains the nodes reachable from Entry. """ sub_graph = StmtGraph() sub_graph.graph.add_edges_from(nx.edge_dfs(self.graph, Entry)) return sub_graph
def depends_on(self, *, include_filters=True, recursive=False, include_fakes=True): def gen_actions(include_filters=include_filters, include_fakes=include_fakes): task_strings = self.declaration_line.split(":", 1)[1].split() task_name_index_tuples = [ (self.bashfile.find_chunk(task_name=s), s) for s in task_strings ] for i, task_string in task_name_index_tuples: if task_string.startswith("@"): if include_filters: yield TaskFilter(task_string, bashfile=self.bashfile) elif i is None: if include_fakes: yield FakeTaskScript(task_string, bashfile=self.bashfile) else: # Otherwise, create the task. yield TaskScript(chunk_index=i, bashfile=self.bashfile) actions = [t for t in gen_actions()] if recursive: graph = {} actions = [] edge_view = networkx.edge_dfs( self.bashfile.graph, self, orientation="original" ) for parent, child, _ in edge_view: if parent not in graph: graph[parent] = [child] else: if child not in graph[parent]: graph[parent].append(child) for task in graph: for action in graph[task]: for dep_action in graph.get(action, []): actions.append(dep_action) actions.append(action) # Remove filters, if requested to do so. if not include_filters: _actions = [] for action in actions: if not isinstance(action, TaskFilter): _actions.append(action) actions = _actions # Remove duplicates from the list. _actions = [] for action in actions: if action not in _actions: _actions.append(action) actions = _actions return actions
def createWaysDict(self): """ Begin with startNode and traverse the graph, collecting the nodes of each way. When a new way is encountered, start a new list of nodes. When a new intersection is encountered, pass the list of ways to the getWay function for processing. Input: graph, startNode Output: dictionary used for creating VISSIM links """ waysDict = {} ways = [] nodes = [] prevAttr = None currAttr = None for fromN, toN in nx.edge_dfs(self.G): currAttr = self.G.edge[fromN][toN] if currAttr['highway'] not in self.roadTypes: continue if self.isIntersection(fromN): ways.append(nodes) waysDict.update(self.getWay(ways)) ways = [] nodes = [] elif self.isNewWay(fromN, toN, prevAttr): ways.append(nodes) nodes = [] nodes.append(fromN) nodes.append(toN) prevAttr = currAttr if self.isExterior(toN): ways.append(nodes) self.getWay(ways) ways.append(nodes) waysDict.update(self.getWay(ways)) return waysDict
def _find_iterative_props(self): r""" Find and return properties that need to be iterated while running the algorithm Parameters ---------- propnames : string or list of strings The propnames of the properties that are variable throughout the algorithm. """ import networkx as nx phase = self.project.phases(self.settings['phase']) physics = self.project.find_physics(phase=phase) geometries = self.project.geometries().values() # Combine dependency graphs of phase and all physics/geometries dg = phase.models.dependency_graph(deep=True) for g in geometries: dg = nx.compose(dg, g.models.dependency_graph(deep=True)) for p in physics: dg = nx.compose(dg, p.models.dependency_graph(deep=True)) base_props = [self.settings["quantity"]] + self.settings["variable_props"] if base_props is None: return [] # Find all props downstream that rely on "quantity" (if at all) dg = nx.DiGraph(nx.edge_dfs(dg, source=base_props)) if len(dg.nodes) == 0: return [] dg.remove_nodes_from(base_props) return list(nx.dag.lexicographical_topological_sort(dg))
def compute_arcs_in_order(self): self.finalArcs = {k: [] for k in self.K} self.remainingFuel = {t: 0 for t in self.T} for i in self.sol: if self.sol[i] >= 0.9 and i[0] == 'x': x, y, k = i.split(',') x = x.replace("x[", "") k = k.replace("]", "") for q in range(math.ceil(self.sol[i])): self.finalArcs[k].append((x, y)) if self.sol[i] >= 0.9 and i[0] == 'r': x, y = i.split('[') y = y.replace("]", "") self.remainingFuel[y] = self.sol[i] # Create a grpah for each robot G = {k: nx.MultiDiGraph() for k in self.K} # Add all nodes in the graph for each robot for k in self.K: G[k].add_nodes_from(self.N) G[k].add_edges_from(self.finalArcs[k]) #print("Nodes in G["+k+"]: ", G[k].nodes(data=True)) #print("Edges in G["+k+"]: ", G[k].edges(data=True)) # Now compute the paths in the above graphs self.arcsInOrder = {k: [] for k in self.K} tempArcsInOrder = {k: [] for k in self.K} for k in self.K: tempArcsInOrder[k] = list(nx.edge_dfs(G[k], source=self.S[0])) for arc in tempArcsInOrder[k]: newArc = tuple((arc[0], arc[1])) self.arcsInOrder[k].append(newArc)
def _build_graph(self, target, commands=False, outs=False): import networkx from dvc import dvcfile from dvc.repo.graph import get_pipeline from dvc.utils import parse_target path, name = parse_target(target) target_stage = dvcfile.Dvcfile(self.repo, path).stages[name] G = get_pipeline(self.repo.pipelines, target_stage) nodes = set() for stage in networkx.dfs_preorder_nodes(G, target_stage): if commands: if stage.cmd is None: continue nodes.add(stage.cmd) elif not outs: nodes.add(stage.addressing) edges = [] for from_stage, to_stage in networkx.edge_dfs(G, target_stage): if commands: if to_stage.cmd is None: continue edges.append((from_stage.cmd, to_stage.cmd)) elif not outs: edges.append((from_stage.addressing, to_stage.addressing)) if outs: nodes, edges = self._build_output_graph(G, target_stage) return list(nodes), edges, networkx.is_tree(G)
def dependency_extraction(sentence, stop_words_list=None): edges=[] for token in sentence: for child in token.children: edges.append(('{0} {1}'.format(token.lemma_, token.i),'{0} {1}'.format(child.lemma_, child.i))) graph=nx.DiGraph(edges) final,roots=[],[] for num in range(2, 5): for sub_nodes in itertools.combinations(graph.nodes(), num): subg = graph.subgraph(sub_nodes) if nx.is_tree(subg): d = dict(subg.in_degree(subg.nodes())) tmp_root,two_parents,stopwords=[],False,False for i,j in d.items(): if j==0: tmp_root.append(i) if j>1: two_parents == True if i.split(' ')[0] in stop_words_list: stopwords=True if not two_parents and len(tmp_root)==1 and not stopwords: final.append(subg) roots.append(tmp_root[0]) features=[] for i in range(len(roots)): features.append(tree_to_string(list(nx.edge_dfs(final[i])), roots[i])) return features
def get_operation(self, graph_connector): passed = [] failed = [] for u, v in edge_dfs(graph_connector): origin_attributes = graph_connector.nodes(data=True)[u] opposite_vertices = None if origin_attributes in self.vertices_under_resource_types: opposite_vertices = self.vertices_under_connected_resources_types elif origin_attributes in self.vertices_under_connected_resources_types: opposite_vertices = self.vertices_under_resource_types if not opposite_vertices: continue destination_attributes = graph_connector.nodes(data=True)[v] if destination_attributes in opposite_vertices: if origin_attributes in self.excluded_vertices or destination_attributes in self.excluded_vertices: failed.extend([origin_attributes, destination_attributes]) else: passed.extend([origin_attributes, destination_attributes]) continue destination_block_type = destination_attributes.get(CustomAttributes.BLOCK_TYPE) if destination_block_type == BlockType.OUTPUT.value: try: output_edges = graph_connector.edges(v, data=True) _, output_destination, _ = next(iter(output_edges)) output_destination = graph_connector.nodes(data=True)[output_destination] output_destination_type = output_destination.get(CustomAttributes.RESOURCE_TYPE) if self.is_associated_edge(origin_attributes.get(CustomAttributes.RESOURCE_TYPE), output_destination_type): passed.extend([origin_attributes, output_destination]) except StopIteration: continue failed.extend([v for v in self.vertices_under_resource_types + self.vertices_under_connected_resources_types if v not in passed]) return passed, failed
def make_graph_nodes_consistent(self, seed_kmer_strings=None): """ Take a Cortex graph and make all nodes have kmer_strings that are consistent with each other. If a seed kmer string is provided, then start with that seed kmer. """ if self.graph.is_consistent(): return self if seed_kmer_strings is None: seed_kmer_strings = [] graph = CortexDiGraph(self.graph) new_graph = ConsistentCortexDiGraph(graph=self.graph.graph) seeds = SeedKmerStringIterator.from_all_kmer_strings_and_seeds(self.graph.nodes(), seed_kmer_strings) for seed, lexlo_seed in seeds: new_graph.add_node(seed, kmer=self.graph.node[lexlo_seed]) seeds.remove(lexlo_seed) for source, sink, key, direction in nx.edge_dfs(graph, lexlo_seed, 'ignore'): if direction == 'forward': rc_after_ref_kmer = True ref, target = source, sink elif direction == 'reverse': ref, target = sink, source rc_after_ref_kmer = False else: raise Exception("unknown direction: {}".format(direction)) if ref not in new_graph.node: ref = revcomp(ref) rc_after_ref_kmer = not rc_after_ref_kmer matched_target, _ = revcomp_target_to_match_ref(target, ref, rc_after_ref_kmer) new_graph.add_node(matched_target, kmer=graph.node[matched_target]) seeds.remove(lexlo(matched_target)) self.graph = new_graph return self
def resiliency(analysis='nodal'): """ This function helps compute the resiliency metric of the network of a node, or a network :param kwargs: :return: """ # 0. what's the event? event = gv.event # 1. get the graphs g1 = gv.graph_collection[0] g2 = gv.graph_collection[1] nodes = g2.nodes() edges = g2.edges() # 2. for which node and edge are you doing the analysis? wg = nx.DiGraph() # wg: working graph wg.add_edges_from(edges) for n in nodes: # Finding Downstream Edges print("Downstream Edges of %s -->" % n) downstream_edges = list(nx.dfs_edges(wg, n)) resiliency_downstream(g2, downstream_edges, event) # Finding Upstream Edges print("Upstream Edges of %s -->" % n) upstream_edges = list(nx.edge_dfs(wg, n, orientation='reverse')) resiliency_upstream(g2, upstream_edges, event)
def transitive_closure(G, reflexive=False): """Returns transitive closure of a directed graph The transitive closure of G = (V,E) is a graph G+ = (V,E+) such that for all v, w in V there is an edge (v, w) in E+ if and only if there is a path from v to w in G. Handling of paths from v to v has some flexibility within this definition. A reflexive transitive closure creates a self-loop for the path from v to v of length 0. The usual transitive closure creates a self-loop only if a cycle exists (a path from v to v with length > 0). We also allow an option for no self-loops. Parameters ---------- G : NetworkX DiGraph A directed graph reflexive : Bool or None, optional (default: False) Determines when cycles create self-loops in the Transitive Closure. If True, trivial cycles (length 0) create self-loops. The result is a reflexive tranistive closure of G. If False (the default) non-trivial cycles create self-loops. If None, self-loops are not created. Returns ------- NetworkX DiGraph The transitive closure of `G` Raises ------ NetworkXNotImplemented If `G` is not directed References ---------- .. [1] http://www.ics.uci.edu/~eppstein/PADS/PartialOrder.py TODO this function applies to all directed graphs and is probably misplaced here in dag.py """ if reflexive is None: TC = G.copy() for v in G: edges = ((v, u) for u in nx.dfs_preorder_nodes(G, v) if v != u) TC.add_edges_from(edges) return TC if reflexive is True: TC = G.copy() for v in G: edges = ((v, u) for u in nx.dfs_preorder_nodes(G, v)) TC.add_edges_from(edges) return TC # reflexive is False TC = G.copy() for v in G: edges = ((v, w) for u, w in nx.edge_dfs(G, v)) TC.add_edges_from(edges) return TC
def getStartNodes(self): """ Get a list of nodes that do not overlap when traversed. """ edgeNodes = self.getExteriorNodes() for node in edgeNodes: for prev, n in nx.edge_dfs(self.G, source=node): if n in edgeNodes: edgeNodes.remove(n) return edgeNodes
def createIntersectionDict(self): """ Use depth-first search to map intersection nodes and lane widths. Input: graph, startNode Output: dictionary mapping of intersection nodes """ intersections = {} for fromN, toN in nx.edge_dfs(self.G): if self.isIntersection(toN): intersections[toN] = self.getIntersection(toN) return intersections
def remove_backward_edges(di_graph, root_id=entity): dac = nx.DiGraph() dac.add_nodes_from(di_graph.nodes(data=True)) for (n1, n2) in list(nx.edge_dfs(di_graph, root_id)): if (n1 in nx.descendants(dac, n2) or n1 == n2): di_graph.remove_edge(n1, n2) #dac.add_edge(n1, n2, value=di_graph[n1][n2]["value"]) return di_graph
def descendants(self, parent): """ Returns descendants (children and children of children, etc.) of `parent` """ try: edges = list( nx.edge_dfs(self._graph, parent, orientation="reverse")) except nx.exception.NetworkXError: edges = [] return [edge[0] for edge in edges]
def getPath(G, source=None): # G: the graph of which the edge is a Relation(targetTable.name, sourceTable.name) # return the execution path, list of tuple<str, str> # source is a list of node name(str) from where dfs starts. if(source == None): source = findGraphHead(G) else: if(source != findGraphHead(G)): raise ValueError("The input head is not the same as the real head of Graph. " "head is the node which has no parent. ") return reversEdgeList(list(nx.edge_dfs(G, source=[source], orientation='original')))
def assign_inverts(G, data_key='ELEVATIONI'): """ Assign invert values for each node in the graph, G by walking up the network and accumulating elevation based on sewer slope and length """ G1 = G.copy() topo_sorted_nodes = nx.topological_sort(G1, reverse=True) terminal_nodes = [n for n,d in G1.out_degree_iter() if d == 0] #Assign starting El for tn in terminal_nodes: #set the terminal node invert by measuring the delta between #it and then nearest upstream node having elevation data G1.node[tn]['invert'] = 0 #find tn position in the topologically sorted nodes i = topo_sorted_nodes.index(tn) while G1.node[tn]['invert'] == 0: delta = 0 #loop through sorted nodes, starting at the tn position for n in topo_sorted_nodes[i:]: #depth first search to nearest node with trusted elevation data for u,v,direction in nx.edge_dfs(G1, n, 'reverse'): delta += elevation_change(G1, u, v) if 'invert_trusted' in G1.node[u]: G1.node[tn]['invert'] = G1.node[u]['invert_trusted'] - delta break if G1.node[tn]['invert'] != 0: break for n in topo_sorted_nodes: for p in G1.predecessors(n): el_0 = G1.node[n]['invert'] el_2 = el_0 + elevation_change(G1,p,n) #fill invert values where nodes already have trusted invert vals if G1.node[n].get('invert_trusted', 0) != 0: el_0 = G1.node[n]['invert_trusted'] G.node[n]['invert'] = el_0 if G1.node[p].get('invert_trusted', 0) != 0: el_2 = G1.node[p]['invert_trusted'] G1.node[p]['invert'] = el_2 return G1
def calc_voltages_PU(graph): """Calculates the trueVoltagePU for each node on the network, starting from the "service" node then running down the digraph edges out to the load nodes using an oriented depth-first created tree of the graph structure. The segment_vdrop_PU function is used to calculate the per unit voltage drop along each edge, set edge per unit currents, and to assign the trueVoltagePU to each node. """ serviceNode = graph.get_service_node() #Oriented tree structure of digraph starting at serviceNode graphStructure = nx.edge_dfs(graph, source=serviceNode) #Calculate voltages starting at source and working towards loads for i in graphStructure: segment_vdrop_PU(graph, i[0], i[1])
def find_ordering(labels, order_type, root_node): edges = [] added_edges = [] for label in labels: x, name, y = label.split('.') i = -1 if (x, y) in added_edges: i = added_edges.index((x, y)) elif (y, x) in added_edges: i = added_edges.index((y, x)) if i != -1: edges[i][2]['name'].append(name) else: edges.append((x, y, {'name': [name]})) added_edges.append((x, y)) G = nx.Graph() G.add_edges_from(edges) if root_node == 'none': degrees = nx.degree_centrality(G) root_node = max(degrees, key=degrees.get) if order_type == 'bfs': new_labels = nx.edge_bfs(G, root_node) if order_type == 'dfs': new_labels = nx.edge_dfs(G, root_node) names = nx.get_edge_attributes(G, 'name') ordered_labels = [] for label in new_labels: x, y = label if label in names: edge_names = names[label] else: edge_names = names[(y, x)] for name in edge_names: new_label = '.'.join([x, name, y]) if new_label in labels: ordered_labels.append(new_label) else: new_label = '.'.join([y, name, x]) ordered_labels.append(new_label) return ordered_labels
def right_vector(G): node_to_index = {n: i for i, n in enumerate(G.nodes())} M = np.zeros((G.size(), G.order()), int) for i, e in enumerate(G.edges(data='weight')): M[i][node_to_index[e[0]]] = 1 w = e[2] dfs = list(nx.edge_dfs(G, e)) L = [f for f in dfs if G.get_edge_data(*f)['weight'] > w] if L != []: M[i][node_to_index[L[0][0]]] = -1 else: M[i][node_to_index[dfs[-1][1]]] = -1 return M
def solve_out_tips(graph, ending_nodes): """ Removes unecessary ending nodes in a graph :Parameters: graph : (nx.Digraph) ending_nodes : list of nodes Returns: graph : (nx.Digraph) """ # Paths identification paths = {} common_nodes = [] for end in ending_nodes: # Find node with several predecessors common_node = -1 full_path = nx.edge_dfs(graph, end, orientation='reverse') path = [] for edge in full_path: if path == []: path.append(edge[0]) path.append(edge[1]) if len(list(graph.successors(edge[0]))) > 1: common_node = edge[0] if common_node not in common_nodes: common_nodes.append(common_node) break paths[end] = (path, common_node, int(path_average_weight(graph, path))) # Select best paths for node in common_nodes: if node == -1: break sub_paths = { i: paths[i] for i in paths.keys() if common_node == paths[i][1] } path = [] weights = [] lengths = [] for d_key in sub_paths: path.append(sub_paths[d_key][0]) weights.append(sub_paths[d_key][2]) lengths.append(len(sub_paths[d_key][0]) - 1) # Update graph graph = select_best_path(graph, path, weights, lengths, delete_sink_node=True) return graph
def count_orbits(orbits): '''Finds the number of direct and indirect orbits from the given list of orbits. :param orbits: List of orbit pairs in the form (object at the center of the orbit, revolving object). :type orbits: list(tuple(str)) :return: Orbits count. :rtype: int ''' G = nx.DiGraph() G.add_edges_from(orbits) return G, sum( [len(list(nx.edge_dfs(G, node, orientation='reverse'))) for node in G])
def connected_subgraph(G, H, start_node, matched_nodes): h_dfs = list(nx.edge_dfs(H, start_node)) for start in matched_nodes: h_map = dict.fromkeys(H.nodes(), 0) h_map[h_dfs[0][0]] = 1 g_map = {start: h_dfs[0][0]} g_un = set(G.edges()) i = 0 g_stack = [] last_node = h_dfs[0][0] while i < len(h_dfs): if last_node != h_dfs[i][0]: for node in g_map: if g_map[node] == h_dfs[i][0]: start = node edge = next_edge(G, H, start, h_dfs[i], g_un, g_map, h_map) if edge != False: try: g_un.remove(edge) except: g_un.remove((edge[1], edge[0])) start = edge[1] g_stack.append(edge) #print(edge) i += 1 else: i -= 1 if i != -1: last_edge = g_stack.pop() start = last_edge[0] h_map[g_map[last_edge[0]]] -= 1 res_edge = [] for res_i in range(len(g_stack) - 1, -1, -1): if g_stack[res_i][0] == start: res_edge.append(g_stack.pop()) g_un.update(res_edge) for res in res_edge: h_map[g_map[res[0]]] -= 1 if i == -1: #print('No Match') break if i == len(h_dfs): #print("Match_Found") #print(g_stack) #print(g_map) return g_map #print(g_map," ",g_stack) return False
def adjust_edge_perturb_radii(frcs, graph, perturb_factor=2): """Returns a new graph where the 'perturb_radius' has been adjusted to account for rounding errors. See train_image for parameters and returns. """ graph = graph.copy() total_rounding_error = 0 for n1, n2 in nx.edge_dfs(graph): desired_radius = distance.euclidean(frcs[n1, 1:], frcs[n2, 1:]) / perturb_factor upper = int(np.ceil(desired_radius)) lower = int(np.floor(desired_radius)) round_up_error = total_rounding_error + upper - desired_radius round_down_error = total_rounding_error + lower - desired_radius if abs(round_up_error) < abs(round_down_error): graph.edge[n1][n2]['perturb_radius'] = upper total_rounding_error = round_up_error else: graph.edge[n1][n2]['perturb_radius'] = lower total_rounding_error = round_down_error return graph
def find_cycle(G, source=None, orientation=None): """Returns a cycle found via depth-first traversal. The cycle is a list of edges indicating the cyclic path. Orientation of directed edges is controlled by `orientation`. Parameters ---------- G : graph A directed/undirected graph/multigraph. source : node, list of nodes The node from which the traversal begins. If None, then a source is chosen arbitrarily and repeatedly until all edges from each node in the graph are searched. orientation : None | 'original' | 'reverse' | 'ignore' (default: None) For directed graphs and directed multigraphs, edge traversals need not respect the original orientation of the edges. When set to 'reverse' every edge is traversed in the reverse direction. When set to 'ignore', every edge is treated as undirected. When set to 'original', every edge is treated as directed. In all three cases, the yielded edge tuples add a last entry to indicate the direction in which that edge was traversed. If orientation is None, the yielded edge has no direction indicated. The direction is respected, but not reported. Returns ------- edges : directed edges A list of directed edges indicating the path taken for the loop. If no cycle is found, then an exception is raised. For graphs, an edge is of the form `(u, v)` where `u` and `v` are the tail and head of the edge as determined by the traversal. For multigraphs, an edge is of the form `(u, v, key)`, where `key` is the key of the edge. When the graph is directed, then `u` and `v` are always in the order of the actual directed edge. If orientation is not None then the edge tuple is extended to include the direction of traversal ('forward' or 'reverse') on that edge. Raises ------ NetworkXNoCycle If no cycle was found. Examples -------- In this example, we construct a DAG and find, in the first call, that there are no directed cycles, and so an exception is raised. In the second call, we ignore edge orientations and find that there is an undirected cycle. Note that the second call finds a directed cycle while effectively traversing an undirected graph, and so, we found an "undirected cycle". This means that this DAG structure does not form a directed tree (which is also known as a polytree). >>> import networkx as nx >>> G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) >>> try: ... nx.find_cycle(G, orientation='original') ... except: ... pass ... >>> list(nx.find_cycle(G, orientation='ignore')) [(0, 1, 'forward'), (1, 2, 'forward'), (0, 2, 'reverse')] """ if not G.is_directed() or orientation in (None, 'original'): def tailhead(edge): return edge[:2] elif orientation == 'reverse': def tailhead(edge): return edge[1], edge[0] elif orientation == 'ignore': def tailhead(edge): if edge[-1] == 'reverse': return edge[1], edge[0] return edge[:2] explored = set() cycle = [] final_node = None for start_node in G.nbunch_iter(source): if start_node in explored: # No loop is possible. continue edges = [] # All nodes seen in this iteration of edge_dfs seen = {start_node} # Nodes in active path. active_nodes = {start_node} previous_head = None for edge in nx.edge_dfs(G, start_node, orientation): # Determine if this edge is a continuation of the active path. tail, head = tailhead(edge) if head in explored: # Then we've already explored it. No loop is possible. continue if previous_head is not None and tail != previous_head: # This edge results from backtracking. # Pop until we get a node whose head equals the current tail. # So for example, we might have: # (0, 1), (1, 2), (2, 3), (1, 4) # which must become: # (0, 1), (1, 4) while True: try: popped_edge = edges.pop() except IndexError: edges = [] active_nodes = {tail} break else: popped_head = tailhead(popped_edge)[1] active_nodes.remove(popped_head) if edges: last_head = tailhead(edges[-1])[1] if tail == last_head: break edges.append(edge) if head in active_nodes: # We have a loop! cycle.extend(edges) final_node = head break else: seen.add(head) active_nodes.add(head) previous_head = head if cycle: break else: explored.update(seen) else: assert(len(cycle) == 0) raise nx.exception.NetworkXNoCycle('No cycle found.') # We now have a list of edges which ends on a cycle. # So we need to remove from the beginning edges that are not relevant. for i, edge in enumerate(cycle): tail, head = tailhead(edge) if tail == final_node: break return cycle[i:]