def generate_solution_graphs(prediction, test_graph_edges, test_solution_edges, test_terminals): n_inputs, n_outputs, max_edge_index, edge_to_id, id_to_edge = edge_to_number( ) connected_graphs = 0 disconnected_graphs = 0 disconnected_opt_solutions = 0 rat_arr = [] for j, pred in enumerate(prediction): sorted_ind = np.argsort(pred) #print(pred) #print(sorted_ind) pred = np.round(pred) opt = len(test_solution_edges[j]) G = nx.Graph() for e in test_graph_edges[j]: u, v, w = e G.add_edge(u, v) V = [] for i, val in enumerate(pred): if val == 1: V.append(i) #G.add_edge(*id_to_edge[i]) for terminal in test_terminals[j][0]: if terminal not in V: V.append(terminal) S = G.subgraph(V) #''' is_disconnected = False if not nx.is_connected(S): is_disconnected = True k = len(sorted_ind) - 1 while not nx.is_connected(S): u = sorted_ind[k] if u not in V: V.append(u) S = G.subgraph(V) k -= 1 if is_disconnected: mst = nx.minimum_spanning_edges(S) apprx = len(list(mst)) if opt == apprx: disconnected_opt_solutions += 1 #''' if nx.is_connected(S): connected_graphs += 1 mst = nx.minimum_spanning_edges(S) apprx = len(list(mst)) rat_arr.append(apprx / opt) else: disconnected_graphs += 1 print("No. of connected graphs:", connected_graphs) total_rat = 0 for rat in rat_arr: total_rat += rat avg_rat = total_rat / connected_graphs print("average ratio:", avg_rat) print("No. of disconnected graphs:", disconnected_graphs) print("No. of disconnected graphs become optimal after connecting:", disconnected_opt_solutions)
def test_multigraph_keys(self): """Tests that the minimum spanning edges of a multigraph preserves edge keys. """ G = nx.MultiGraph() G.add_edge(0, 1, key="a", weight=2) G.add_edge(0, 1, key="b", weight=1) mst_edges = nx.minimum_spanning_edges(G, algorithm="kruskal", data=False) assert_equal([(0, 1, "b")], list(mst_edges)) mst_edges = nx.minimum_spanning_edges(G, algorithm="prim", data=False) assert_equal([(0, 1, "b")], list(mst_edges))
def _get_mst(self): # full_graph = Graph.Full(self.n0) # factor = 1e5 # since small weights lead to MST problem # weights = [factor * self.distance[self._s((edge.source,edge.target))] for edge in full_graph.es] # G = full_graph.spanning_tree(weights).as_undirected() # return G.get_edgelist() g = nx.complete_graph(self.n0) factor = 1e5 for u, v in g.edges(): g[u][v]['weight'] = factor * self.distance[self._s((u, v))] nx.minimum_spanning_edges(g) return list(nx.minimum_spanning_edges(g))
def test_multigraph_keys(self): """Tests that the minimum spanning edges of a multigraph preserves edge keys. """ G = nx.MultiGraph() G.add_edge(0, 1, key='a', weight=2) G.add_edge(0, 1, key='b', weight=1) mst_edges = nx.minimum_spanning_edges(G, algorithm='kruskal', data=False) assert_equal([(0, 1, 'b')], list(mst_edges)) mst_edges = nx.minimum_spanning_edges(G, algorithm='prim', data=False) assert_equal([(0, 1, 'b')], list(mst_edges))
def main(): # create complete graph graph = networkx.complete_graph(len(PREMISES) + len(DISTRIBUTION_POINT)) # relabel nodes mapping = {} for i, node in enumerate(PREMISES + DISTRIBUTION_POINT): mapping[i] = node['properties']['name'] graph = networkx.relabel_nodes(graph, mapping) node_lookup = {} for node in PREMISES + DISTRIBUTION_POINT: name = node['properties']['name'] node_lookup[name] = node # set up edges with distance for u, v in graph.edges: u_geom = node_lookup[u]['geometry']['coordinates'] v_geom = node_lookup[v]['geometry']['coordinates'] graph.edges[u, v]['weight'] = distance(u_geom, v_geom) # print complete graph with distances print(list(graph.edges(data=True))) # print mst mst = networkx.minimum_spanning_edges(graph) print(list(mst))
def get_DT(MI_subset): #we use networkx package #create a Graph object G = nx.Graph() G.add_nodes_from(range(len(MI_subset))) edge_list = [] for i in range(len(MI_subset)): for j in range(i+1,len(MI_subset)): #we negate MI, turning into a MST problem edge_list.extend([(i,j,-MI_subset[i][j]),(j,i,-MI_subset[j][i])]) G.add_weighted_edges_from(edge_list) min_span_tree = sorted(list(nx.minimum_spanning_edges(G))) #rearrange the mst s.t. all 1st axis is parents of 2nd axis N = len(min_span_tree) #indicates which nodes are added, hence they are not children indicator = np.zeros((N+1,1)) #add 1 to compensate for N edges and N+1 nodes temp1,temp2,_ = min_span_tree.pop(0) rearranged = [[temp1,temp2]] indicator[[rearranged[0][0],rearranged[0][1]]] = 1 #default parents while min_span_tree: for ins in range(len(min_span_tree)): if indicator[min_span_tree[ins][0]]==1: temp1,temp2,_ = min_span_tree.pop(ins) rearranged.append([temp1,temp2]) indicator[temp2] = 1 break elif indicator[min_span_tree[ins][1]]==1: temp1,temp2,_ = min_span_tree.pop(ins) rearranged.append([temp2,temp1]) indicator[temp1] = 1 break return rearranged
def gstar_with_kruskal_init(X, level_thresholds=None, function=None, threshold_method='percentile'): """Same algorithm as generalized_star_clustering_link but first find 1 kruskal tree and work on what is left. Will output the union of the Krukal tree and the subgraph given by the generalized_star_clustering_link in the form of a json, meant to be uploaded to the force directed graph interface """ graph = array_to_dist_graph(X) tree = nx.minimum_spanning_edges(graph, weight='weight', data=True) graph.remove_edges_from(tree) if function is None: function = default_priority_func if level_thresholds is None: level_thresholds = int( min(MAX_NUM_LEVELS_IN_STAR_CLUS, max(MIN_NUM_LEVELS_IN_STAR_CLUS, sqrt(len(X))))) if isinstance( level_thresholds, int ): # then consider level_thresholds to be the spec of how many levels we want level_thresholds = _choose_level_thresholds_from_complete_graph( graph, level_thresholds, method=threshold_method) subgraph_2 = layered_clustering(graph, level_thresholds, function) subgraph_2.add_edges_from(tree) return json_links_from_graph(subgraph_2, link_distance_attr='weight')
def _get_n_best_paf_graphs( data, metadata, full_graph, n_graphs=10, root=None, which="best", ignore_inds=None, metric="auc", ): if which not in ("best", "worst"): raise ValueError('`which` must be either "best" or "worst"') (within_train, _), (between_train, _) = _calc_within_between_pafs( data, metadata, train_set_only=True, ) # Handle unlabeled bodyparts... existing_edges = set(k for k, v in within_train.items() if v) if ignore_inds is not None: existing_edges = existing_edges.difference(ignore_inds) existing_edges = list(existing_edges) if not any(between_train.values()): # Only 1 animal, let us return the full graph indices only return ([existing_edges], dict(zip(existing_edges, [0] * len(existing_edges)))) scores, _ = zip(*[ _calc_separability(between_train[n], within_train[n], metric=metric) for n in existing_edges ]) # Find minimal skeleton G = nx.Graph() for edge, score in zip(existing_edges, scores): if np.isfinite(score): G.add_edge(*full_graph[edge], weight=score) if which == "best": order = np.asarray(existing_edges)[np.argsort(scores)[::-1]] if root is None: root = [] for edge in nx.maximum_spanning_edges(G, data=False): root.append(full_graph.index(sorted(edge))) else: order = np.asarray(existing_edges)[np.argsort(scores)] if root is None: root = [] for edge in nx.minimum_spanning_edges(G, data=False): root.append(full_graph.index(sorted(edge))) n_edges = len(existing_edges) - len(root) lengths = np.linspace(0, n_edges, min(n_graphs, n_edges + 1), dtype=int)[1:] order = order[np.isin(order, root, invert=True)] paf_inds = [root] for length in lengths: paf_inds.append(root + list(order[:length])) return paf_inds, dict(zip(existing_edges, scores))
def test_nan_weights_order(self): # now try again with a nan edge at the beginning of G.nodes edges = [ (0, 1, 7), (0, 3, 5), (1, 2, 8), (1, 3, 9), (1, 4, 7), (2, 4, 5), (3, 4, 15), (3, 5, 6), (4, 5, 8), (4, 6, 9), (5, 6, 11), ] G = nx.Graph() G.add_weighted_edges_from([(u + 1, v + 1, wt) for u, v, wt in edges]) G.add_edge(0, 7, weight=float("nan")) edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False, ignore_nan=True) actual = sorted((min(u, v), max(u, v)) for u, v in edges) shift = [(u + 1, v + 1) for u, v, d in self.minimum_spanning_edgelist] assert_edges_equal(actual, shift)
def crossover(self, edges1, edges2): g = nx.Graph() g.add_edges_from(edges1) g.add_edges_from(edges2) mst = nx.minimum_spanning_edges(g, 'weight') edge_list = list(mst) self.graph.add_edges_from(edge_list)
def test_isolated_node(self): # now try again with an isolated node edges = [ (0, 1, 7), (0, 3, 5), (1, 2, 8), (1, 3, 9), (1, 4, 7), (2, 4, 5), (3, 4, 15), (3, 5, 6), (4, 5, 8), (4, 6, 9), (5, 6, 11), ] G = nx.Graph() G.add_weighted_edges_from([(u + 1, v + 1, wt) for u, v, wt in edges]) G.add_node(0) edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False, ignore_nan=True) actual = sorted((min(u, v), max(u, v)) for u, v in edges) shift = [(u + 1, v + 1) for u, v, d in self.minimum_spanning_edgelist] assert edges_equal(actual, shift)
def test_nan_weights(self): # Edge weights NaN never appear in the spanning tree. see #2164 G = self.G G.add_edge(0, 12, weight=float('nan')) edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False, ignore_nan=True) actual = sorted((min(u, v), max(u, v)) for u, v in edges) expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] assert_edges_equal(actual, expected) # Now test for raising exception edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False, ignore_nan=False) assert_raises(ValueError, list, edges) # test default for ignore_nan as False edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False) assert_raises(ValueError, list, edges)
def mstClustering(G, service_number): mst = nx.minimum_spanning_edges(G, weight='inverse_weight', data=True) edge_list = list(mst) node_list = list() edge_dict = dict() for each in edge_list: #print each[0], each[1], each[2]['inverse_weight'], each[2]['weight'] class1 = each[0] class2 = each[1] inverse_value = each[2]['inverse_weight'] if (class1, class2) not in edge_dict: edge_dict[(class1, class2)] = inverse_value if class1 not in node_list: node_list.append(class1) if class2 not in node_list: node_list.append(class2) #sort value in reduced order edge_dict = sorted(edge_dict.items(), key=lambda x: x[1], reverse=True) current_service_number = 1 while (current_service_number < service_number): ((c1, c2), w) = edge_dict[0] print('delete edge: ') print(c1, c2, w, '\n') current_service_number += 1 del edge_dict[0] #remove the first key-value of the dict edge_list = list() for each in edge_dict: ((c1, c2), w) = each edge_list.append((c1, c2, 1 / w)) return node_list, edge_list
def plotGraph(g,filename): """ Creates a plot of the graph passed in after transforming the full graph into a minimum spanning tree. The MST of a graph like this has some significance (but also some locally strange paths) and is nice to look add due to the reduced edge density. """ plt.figure(figsize=(15, 10)) np.random.seed(5) mst = nx.minimum_spanning_tree(g, weight='difference') pos = nx.spring_layout(mst, iterations=900, k=.008, weight='difference') mst_edges = list(nx.minimum_spanning_edges(g, weight='difference')) degs = mst.degree() nodesize = [degs[v]*80 for v in mst] nl = mst.nodes() nx.draw_networkx_edges(g, pos, edgelist=mst_edges, alpha=.2) nx.draw_networkx_nodes(g, pos, nodelist = nl, node_size=nodesize, node_color=nodesize) nx.draw_networkx_labels(g, pos, font_color='k', font_size=7) plt.title("Artist Network", fontsize=18) plt.xticks([]) plt.yticks([]) plt.savefig(filename)
def proposed_graph(adj_matrix1): ''' takes an adjacency matrix and generates a new adjacency matrix with a porposal distribution Arguments: adj_matrix1= an adjacency matrix Returns: adj_matrix1= an new mutated adjacency matrix ''' extra,G2=graph_theta(adj_matrix1,r1)#graph and its coordinates node1=randint(0, len(adj_matrix1[0])-1)#random node 1 node2=randint(0, len(adj_matrix1[0])-1)#random node 2 G2_min_span_edges=nx.minimum_spanning_edges(G2)#edge of minimum spanning tree bridges=len(list(G2_min_span_edges))#number of edges in the spanning tree element=(node1, node2)#tuple of two nodes for an edge M=len(adj_matrix1[0])#number of vertices q_i_j=2.0/(M*(M-1.0))#i state probability q_j_i=2.0/(M*(M-1.0)-bridges)#j state probability ratio=float(q_j_i)/float(q_i_j)#calculates the ratio if (node1!=node2 and adj_matrix1[node1][node2]==0):# makes sure the two nodes are not identical and that there is no edge between them adj_matrix1[node1][node1]=1#add an edge elif(node1!=node2 and adj_matrix1[node1][node2]!=0):# if element in G2_min_span_edges: adj_matrix1[node1][node2]=1#if the edge is in MST don't remove else: adj_matrix1[node1][node2]=0#if it is not remove the edge extra1,G3=graph_theta(adj_matrix1,r1) if (nx.is_connected(G3)==False):#makes sure that the graph is connected adj_matrix1[node1][node2]=1 return adj_matrix1
def mask_test_edges(network, node_list=None, databases=None, test_frac=.10, val_frac=.05, seed=0, verbose=False): g = network.G edges_to_remove = g.edges(data=True) if databases: edges_to_remove = [(u, v, d) for u, v, d in g.edges(data=True) if d["database"] in databases] if node_list: edges_to_remove = [(u, v, d) for u, v, d in edges_to_remove if (u in node_list) and (v in node_list)] print("edges_to_remove", len(edges_to_remove)) if verbose else None # Avoid removing edges in the MST temp_graph = nx.Graph(incoming_graph_data=edges_to_remove) mst_edges = nx.minimum_spanning_edges(temp_graph, data=False, ignore_nan=True) edges_to_remove = [(u, v, d) for u, v, d in edges_to_remove if ~((u, v) in mst_edges or (v, u) in mst_edges)] print("edges_to_remove (after MST)", len(edges_to_remove)) if verbose else None np.random.seed(seed) np.random.shuffle(edges_to_remove) test_edges_size = int(len(edges_to_remove) * test_frac) val_edges_size = int(len(edges_to_remove) * val_frac) test_edges = edges_to_remove[0: test_edges_size] val_edges = edges_to_remove[test_edges_size: test_edges_size + val_edges_size] print("test_edges_size", len(test_edges)) if verbose else None print("val_edges_size", len(val_edges)) if verbose else None return test_edges, val_edges
def solve(G): """ Directly calls MST algorithm to link together the nodes of the dominatingSet. Only includes edges that link together two dominating set vertices. Args: G: networkx.Graph Returns: T: networkx.Graph """ temp = nx.Graph() dominatingSet = min_weighted_dominating_set(G, weight="weight") temp.add_nodes_from(dominatingSet) for node in dominatingSet: for node2 in dominatingSet: if G.has_edge(node, node2): temp.add_edge(node, node2) temp[node][node2]['weight'] = G.get_edge_data(node, node2)['weight'] # Get MST of dominating set edges = list( nx.minimum_spanning_edges(temp, algorithm='kruskal', weight='weight', keys=True, data=True, ignore_nan=False)) T = nx.Graph() T.add_nodes_from(dominatingSet) T.add_edges_from(edges) return T
def lower_bound(g, sub_cycle): # The weight of the current path. current_weight = sum([g[sub_cycle[i]][sub_cycle[i + 1]]['weight'] for i in range(len(sub_cycle) - 1)]) # For convenience we create a new graph which only contains vertices not used by g. unused = [v for v in g.nodes() if v not in sub_cycle] h = g.subgraph(unused) # Compute the weight of a minimum spanning tree. t = list(nx.minimum_spanning_edges(h)) mst_weight = sum([h.get_edge_data(e[0], e[1])['weight'] for e in t]) # If the current sub_cycle is "trivial" (i.e., it contains no vertices or all vertices), then our lower bound is # just the sum of the weight of a minimum spanning tree and the current weight. if len(sub_cycle) == 0 or len(sub_cycle) == g.number_of_nodes(): return mst_weight + current_weight # If the current sub_cycle is not trivial, then we can also add the weight of two edges connecting the vertices # from sub_cycle and the remaining part of the graph. # s is the first vertex of the sub_cycle s = sub_cycle[0] # t is the last vertex of the sub_cycle t = sub_cycle[-1] # The minimum weight of an edge connecting a vertex from outside of sub_sycle to s. min_to_s_weight = min([g[v][s]['weight'] for v in g.nodes() if v not in sub_cycle]) # The minimum weight of an edge connecting the vertex t to a vertex from outside of sub_cycle. min_from_t_weight = min([g[t][v]['weight'] for v in g.nodes() if v not in sub_cycle]) # Any cycle which starts with sub_cycle must be of length: # the weight of the edges from sub_cycle + # the minimum weight of an edge connecting sub_cycle and the remaining vertices + # the minimum weight of a spanning tree on the remaining vertices + # the minimum weight of an edge connecting the remaining vertices to sub_cycle. return current_weight + min_from_t_weight + mst_weight + min_to_s_weight
def test_without_data(self): edges = nx.minimum_spanning_edges(self.G, algorithm=self.algo, data=False) # Edges from the spanning edges functions don't come in sorted # orientation, so we need to sort each edge individually. actual = sorted((min(u, v), max(u, v)) for u, v in edges) expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] assert_edges_equal(actual, expected)
def graph_mst(dist, labels, limit): """Обёртка над алгоритмом MST""" from collections import deque; S = nx.Graph(); #исходный граф S.add_nodes_from(labels); R = S.copy(); #результат кластеризации C = nx.Graph(); #читаемый результат dq = deque(dist); len_x = len(labels); for x in range( len_x-1 ): for y in range(x + 1, len_x): S.add_edge( labels[x], labels[y], weight=dq.popleft() ); mst = deque(nx.minimum_spanning_edges(S, data=True)); del S; R.add_edges_from( [edge for edge in mst if( edge[2]['weight'] <= limit)] ); for num, clust in enumerate(nx.connected_components(R)): C.add_node(num, { 'size':len(clust), 'members': clust }); del R; return C;
def coopers_steiner_tree(G, terminal_nodes, weight='weight', verbose=False): ''' Just do pairwise dijkstra distances for the terminal nodes we care about Parameters ---------- G : NetworkX graph terminal_nodes : list A list of terminal nodes for which minimum steiner tree is to be found. ''' H = nx.Graph() for u, v in combinations(terminal_nodes, 2): distance = nx.dijkstra_path_length(G, u, v, weight=weight) path = nx.dijkstra_path(G, u, v, weight=weight) H.add_edge(u, v, distance=distance, path=path) mst_edges = nx.minimum_spanning_edges(H, weight='distance', data=True) # Create an iterator over each edge in each shortest path; repeats are okay #if verbose: print("Begin iterator thing") edges = chain.from_iterable(pairwise(d['path']) for u, v, d in mst_edges) T = G.edge_subgraph(edges) return T
def _min_cycle_basis(comp, weight): cb = [] # We extract the edges not in a spanning tree. We do not really need a # *minimum* spanning tree. That is why we call the next function with # weight=None. Depending on implementation, it may be faster as well spanning_tree_edges = list( nx.minimum_spanning_edges(comp, weight=None, data=False)) edges_excl = [ frozenset(e) for e in comp.edges() if e not in spanning_tree_edges ] N = len(edges_excl) # We maintain a set of vectors orthogonal to sofar found cycles set_orth = [set([edge]) for edge in edges_excl] for k in range(N): # kth cycle is "parallel" to kth vector in set_orth new_cycle = _min_cycle(comp, set_orth[k], weight=weight) cb.append(list(set().union(*new_cycle))) # now update set_orth so that k+1,k+2... th elements are # orthogonal to the newly found cycle, as per [p. 336, 1] base = set_orth[k] set_orth[k + 1:] = [ orth ^ base if len(orth & new_cycle) % 2 else orth for orth in set_orth[k + 1:] ] return cb
def getModifiedSteinerTree(self, graph, steiner_nodes, steiner_edges): biGraph = self.bidirected(graph) M = self.metric_closure(biGraph, weight='weight') H = M.subgraph(steiner_nodes) for edge in steiner_edges: # To-Do check this condition... if edge[0] in H.edges and edge[2] in H.edges: H[edge[0]][edge[2]]['distance'] = -1 mst_edges = nx.minimum_spanning_edges(H, weight='weight', data=True) edges = chain.from_iterable( pairwise(d['path']) for u, v, d in mst_edges) selected_edges = [] for edge in edges: selected_edges += [edge] selected_edges += [(edge[1], edge[0])] tree = graph.edge_subgraph( selected_edges) if selected_edges else graph.subgraph( steiner_nodes) return tree
def iterativeAlgorithm(self): T = nx.Graph() for n in T: T.node[n]=self.node[n].copy() T.graph=self.graph.copy() for u, v, d in nx.minimum_spanning_edges(self, data=True): T.add_edge(u,v,d) yield T
def test_unicode_name(self): """Tests that using a Unicode string can correctly indicate Borůvka's algorithm. """ edges = nx.minimum_spanning_edges(self.G, algorithm="borůvka") # Edges from the spanning edges functions don't come in sorted # orientation, so we need to sort each edge individually. actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) assert edges_equal(actual, self.minimum_spanning_edgelist)
def findmst(roadGraph, node): mst = nx.minimum_spanning_edges(roadGraph) edgeList = list(mst) tnodes = roadGraph.nodes(data=False) shpLayout = dict(zip(tnodes, tnodes)) plt.figure(1, figsize=(12, 12)) nx.draw_networkx_edges(roadGraph, pos=shpLayout, edgelist=edgeList) plt.show() pass
def solve_problem(nodes_cnt): graph = create_graph(nodes_cnt) spanning_tree_edges = list( nx.minimum_spanning_edges(graph, algorithm='prim')) print('Path: ' + str(spanning_tree_edges)) draw_graph(graph, spanning_tree_edges)
def test_nan_weights(self): # Edge weights NaN never appear in the spanning tree. see #2164 G = self.G G.add_edge(0, 12, weight=float('nan')) edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False, ignore_nan=True) actual = sorted((min(u, v), max(u, v)) for u, v in edges) expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] assert_edges_equal(actual, expected) # Now test for raising exception edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False, ignore_nan=False) with pytest.raises(ValueError): list(edges) # test default for ignore_nan as False edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False) with pytest.raises(ValueError): list(edges)
def test_unicode_name(self): """Tests that using a Unicode string can correctly indicate Borůvka's algorithm. """ edges = nx.minimum_spanning_edges(self.G, algorithm=u'borůvka') # Edges from the spanning edges functions don't come in sorted # orientation, so we need to sort each edge individually. actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) assert_edges_equal(actual, self.minimum_spanning_edgelist)
def crossover(self, other): full_child = nx.Graph() full_child.add_edges_from(self.graph) full_child.add_edges_from(other.graph) mst = nx.minimum_spanning_edges(full_child, 'weight') child = nx.Graph() child.add_edges_from(list(mst)) return child
def steiner_tree(G, terminal_nodes, weight="weight"): """Return an approximation to the minimum Steiner tree of a graph. The minimum Steiner tree of `G` w.r.t a set of `terminal_nodes` is a tree within `G` that spans those nodes and has minimum size (sum of edge weights) among all such trees. The minimum Steiner tree can be approximated by computing the minimum spanning tree of the subgraph of the metric closure of *G* induced by the terminal nodes, where the metric closure of *G* is the complete graph in which each edge is weighted by the shortest path distance between the nodes in *G* . This algorithm produces a tree whose weight is within a (2 - (2 / t)) factor of the weight of the optimal Steiner tree where *t* is number of terminal nodes. Parameters ---------- G : NetworkX graph terminal_nodes : list A list of terminal nodes for which minimum steiner tree is to be found. Returns ------- NetworkX graph Approximation to the minimum steiner tree of `G` induced by `terminal_nodes` . Notes ----- For multigraphs, the edge between two nodes with minimum weight is the edge put into the Steiner tree. References ---------- .. [1] Steiner_tree_problem on Wikipedia. https://en.wikipedia.org/wiki/Steiner_tree_problem """ # H is the subgraph induced by terminal_nodes in the metric closure M of G. M = metric_closure(G, weight=weight) H = M.subgraph(terminal_nodes) # Use the 'distance' attribute of each edge provided by M. mst_edges = nx.minimum_spanning_edges(H, weight="distance", data=True) # Create an iterator over each edge in each shortest path; repeats are okay edges = chain.from_iterable(pairwise(d["path"]) for u, v, d in mst_edges) # For multigraph we should add the minimal weight edge keys if G.is_multigraph(): edges = ( (u, v, min(G[u][v], key=lambda k: G[u][v][k][weight])) for u, v in edges ) T = G.edge_subgraph(edges) return T
def euclidean_minimum_spanning_tree(nodes, **kwargs): """ :param nodes: list of (x,y) nodes positions :return: :class:`GeoGraph` with minimum spanning tree between nodes see https://en.wikipedia.org/wiki/Euclidean_minimum_spanning_tree """ g = GeoGraph(None, **kwargs) d = delauney_triangulation(nodes, **kwargs) g.add_edges_from(nx.minimum_spanning_edges(d, weight='length')) return g
def create_islands(graph): # create minimum spanning tree from undirected edges mst_edges = sorted(list(nx.minimum_spanning_edges(graph, data=True))) islands = nx.Graph() for e0, e1, w in mst_edges: ring0 = graph.node[e0]["ring"] ring1 = graph.node[e1]["ring"] local0, local1 = graph.node[e0]["local"], graph.node[e1]["local"] if ring0 != ring1: islands.add_edge(ring0, ring1, weight=w, connection=[e0, e1, local0, local1]) return islands
def euclidean_minimum_spanning_tree(nodes, **kwargs): """ :param nodes: list of (x,y) nodes positions :return: geograph with minimum spanning tree between nodes see https://en.wikipedia.org/wiki/Euclidean_minimum_spanning_tree """ g = GeoGraph(None, **kwargs) d = delauney_triangulation(nodes, **kwargs) for edge in nx.minimum_spanning_edges(d, weight="length"): g.add_edge(*edge) return g
def draw_tours(P): G = get_complete_graph(P) Te = [(u, v) for u, v, w in nx.minimum_spanning_edges(G)] f, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 4)) d_tour = get_double_tree_tour(len(P), Te) c_tour = get_christofides_tour(G, len(P), Te) draw_tour(ax1, P, d_tour, "Double tree: ") draw_tour(ax2, P, c_tour, "Christofides': ")
def reduce_mst(mst1, mst2): logging.debug('Reducing MST') graph = nx.Graph() for node1, node2, distance in mst1: graph.add_edge(node1, node2, weight=distance['weight']) for node1, node2, distance in mst2: graph.add_edge(node1, node2, weight=distance['weight']) return list(nx.minimum_spanning_edges(graph, data=True))
def knnMstWeight(X, K=20): us, vs, ds = getKnnRelation(K, X) knnGraph = nx.Graph() knnGraph.add_weighted_edges_from( zip(us, vs, ds)) # G is undirected, so adding both directions is unneccessary mstEdges = nx.minimum_spanning_edges(knnGraph, algorithm='kruskal') _, _, edgeWeights = zip(*mstEdges) # unzip the list of tuples return np.array([w['weight'] for w in edgeWeights]).sum()
def euclidean_minimum_spanning_tree(nodes,**kwargs): """ :param nodes: list of (x,y) nodes positions :return: :class:`GeoGraph` with minimum spanning tree between nodes see https://en.wikipedia.org/wiki/Euclidean_minimum_spanning_tree """ g=GeoGraph(None,**kwargs) d=delauney_triangulation(nodes,**kwargs) g.add_edges_from(nx.minimum_spanning_edges(d, weight='length')) return g
def calculate_edges_votes(graph, tam, central_markers): """Functions that calculates edges votes and make corresponding graph. :param graph: NetworkX graph that contains all nodes and edges with positions, distance and duration. :type graph: NetworkX graph :param tam: Number that indicates the total number of elements and the names of the nodes :type tam: Integer :param central_markers: One or more locations with latitude/longitude and id values that indicates which points are going to be centrals. It means those points are going to be always in the minimum spanning tree. :type central_markers: list :return: globals.vote_global_graph: global variable containing graph with all nodes and edges with duration, distance and votes as attributes. :rtype: NetworkX graph """ central_markers_id = [] for central_mark in central_markers: central_markers_id.append(str(central_mark['id'])) votes_aux = {} graph_nodes = list(graph.nodes(data='id')) l_max = [] for node in graph_nodes: l_max.append(int(node[0])) tam_aux = max(l_max) + 1 votes = np.zeros((tam_aux, tam_aux)) for i in graph_nodes: if i[0] not in central_markers_id: random_graph = copy.deepcopy(graph) # print('OUT') random_graph.remove_node(i[0]) mst = nx.minimum_spanning_edges(random_graph, weight='weight', data=True) edge_list_min = list(mst) # make a list of the minimum edges for pair in edge_list_min: x = int(pair[0]) y = int(pair[1]) votes[x, y] = votes[x, y] + 1 globals.vote_global_graph.add_edge( pair[0], pair[1], weight=pair[2]['weight'], votes=votes[x, y], duration=pair[2]['duration']) print('Edge Added-> ', pair[0], ' - ', pair[1], ' -> ', pair[2]['duration']) session['max_votes'] = votes.max() session['min_votes'] = votes.min() return globals.vote_global_graph
def create_islands(graph): #create minimum spanning tree from undirected edges mst_edges = sorted(list(nx.minimum_spanning_edges(graph,data=True))) islands = nx.Graph() for e0, e1, w in mst_edges: ring0 = graph.node[e0]['ring'] ring1 = graph.node[e1]['ring'] local0, local1 = graph.node[e0]['local'], graph.node[e1]['local'] if ring0 != ring1: islands.add_edge(ring0, ring1, weight = w, connection = [e0, e1, local0, local1], ) return islands
def main(): # build up a graph filename = '../../florentine_families_graph.gpickle' G = nx.read_gpickle(filename) # Spanning tree mst = nx.minimum_spanning_tree(G) out_file = 'florentine_families_graph_minimum_spanning_tree.png' PlotGraph.plot_graph(G, filename=out_file, colored_edges=mst.edges()) edges = nx.minimum_spanning_edges(G, weight='weight', data=True) list_edges = list(edges) print(list_edges)
def mst_pairs(pairs): """Given all pairwise distances, determine the minimal spanning subset. Convert pairwise distances to an undirected graph, determine the minumum spanning tree, and emit the minimal list of edges to connect all nodes. Input: iterable of (SeqRecord, SeqRecord, distance) Output: iterable of (SeqRecord, SeqRecord) """ G = networkx.Graph() for left, right, score in pairs: G.add_edge(left, right, weight=1.0/score) mst = networkx.minimum_spanning_edges(G, data=False) return list(mst)
def minimum_spanning_tree(G, weight="weight"): """Return a minimum spanning tree or forest of an undirected weighted graph. A minimum spanning tree is a subgraph of the graph (a tree) with the minimum sum of edge weights. If the graph is not connected a spanning forest is constructed. A spanning forest is a union of the spanning trees for each connected component of the graph. Parameters ---------- G : NetworkX Graph weight : string Edge data key to use for weight (default 'weight'). Returns ------- G : NetworkX Graph A minimum spanning tree or forest. Examples -------- >>> G=nx.cycle_graph(4) >>> G.add_edge(0,3,weight=2) # assign weight 2 to edge 0-3 >>> T=nx.minimum_spanning_tree(G) >>> print(sorted(T.edges(data=True))) [(0, 1, {}), (1, 2, {}), (2, 3, {})] Notes ----- Uses Kruskal's algorithm. If the graph edges do not have a weight attribute a default weight of 1 will be used. """ T = nx.Graph(nx.minimum_spanning_edges(G, weight=weight, data=True)) # Add isolated nodes if len(T) != len(G): T.add_nodes_from([n for n, d in G.degree().items() if d == 0]) # Add node and graph attributes as shallow copy for n in T: T.node[n] = G.node[n].copy() T.graph = G.graph.copy() return T
def get_sparsified_MPST_remove_leaves(G, K, directed=False): ''' Sparsify graph using most probable spanning tree. If |MPST| < K, then add most probable edges that are not included. If |MPST| > K, then remove edges that are adjacent to leaves ''' G_edges = G.edges(data=True) if directed: # MPST_edges = branchings.minimum_spanning_arborescence(G, attr='weight').edges(data=True) pass else: MPST_edges = list(nx.minimum_spanning_edges(G,weight='weight',data=True)) edges = [e for e in G_edges if e not in MPST_edges] mp_edges = sorted(edges, key = lambda (u,v,d): exp(1)**(-d["weight"]), reverse = True) if len(MPST_edges) <= K: MPST_edges.extend(mp_edges[:(K - len(MPST_edges))]) else: # remove edges that are adjacent to leaves (keeping connectivity) # if ties remove with lowest probability (keeping probability) #TODO check why in case of directed MPST it doesn't work MPST = nx.Graph(MPST_edges) degrees = dict() leaves = set() for u in MPST: degrees[u] = len(MPST[u]) if degrees[u] == 1: v, d = MPST[u].items()[0] leaves.add((u,v,d["weight"])) for _ in range(len(MPST_edges) - K): u,v,d = min(leaves, key = lambda (u,v,d): exp(1)**(-d)) MPST.remove_edge(u,v) leaves.remove((u,v,d)) v_edges = MPST[v].items() if len(v_edges) == 1: w, t = v_edges[0] leaves.add((v,w,t["weight"])) elif len(v_edges) == 0: leaves.remove((v,u,d)) print len(MPST.edges()), K MPST_edges = MPST.edges(data=True) return MPST_edges
def steiner_tree(G, terminal_nodes, weight='weight'): """ Return an approximation to the minimum Steiner tree of a graph. Parameters ---------- G : NetworkX graph terminal_nodes : list A list of terminal nodes for which minimum steiner tree is to be found. Returns ------- NetworkX graph Approximation to the minimum steiner tree of `G` induced by `terminal_nodes` . Notes ----- Steiner tree can be approximated by computing the minimum spanning tree of the subgraph of the metric closure of the graph induced by the terminal nodes, where the metric closure of *G* is the complete graph in which each edge is weighted by the shortest path distance between the nodes in *G* . This algorithm produces a tree whose weight is within a (2 - (2 / t)) factor of the weight of the optimal Steiner tree where *t* is number of terminal nodes. """ # M is the subgraph of the metric closure induced by the terminal nodes of # G. M = metric_closure(G, weight=weight) # Use the 'distance' attribute of each edge provided by the metric closure # graph. H = M.subgraph(terminal_nodes) mst_edges = nx.minimum_spanning_edges(H, weight='distance', data=True) # Create an iterator over each edge in each shortest path; repeats are okay edges = chain.from_iterable(pairwise(d['path']) for u, v, d in mst_edges) T = G.edge_subgraph(edges) return T
def plotGraph(g,filename): plt.figure(figsize=(15, 10)) np.random.seed(5) mst = nx.minimum_spanning_tree(g, weight='difference') pos = nx.spring_layout(mst, iterations=900, k=.008, weight='difference') mst_edges = list(nx.minimum_spanning_edges(g, weight='difference')) degs = mst.degree() nodesize = [degs[v]*80 for v in mst] nl = mst.nodes() nx.draw_networkx_edges(g, pos, edgelist=mst_edges, alpha=.2) nx.draw_networkx_nodes(g, pos, nodelist = nl, node_size=nodesize, node_color=nodesize) nx.draw_networkx_labels(g, pos, font_color='k', font_size=7) plt.title("Artist Network", fontsize=18) plt.xticks([]) plt.yticks([]) plt.savefig(filename)
def _min_cycle_basis(comp, weight): cb = [] # We extract the edges not in this spanning tree spanning_tree_edges = list( nx.minimum_spanning_edges(comp, weight=None, data=False)) edges_excl = [ frozenset(e) for e in comp.edges() if e not in spanning_tree_edges] N = len(edges_excl) # We maintain a set of vectors orthogonal to sofar found cycles set_orth = [set([edge]) for edge in edges_excl] for k in xrange(N): # kth cycle is "parallel" to kth vector in set_orth new_cycle = _min_cycle(comp, set_orth[k], weight=weight) cb.append(list(set().union(*new_cycle))) # now update set_orth so that k+1,k+2... th elements are # orthogonal to the newly found cycle, as per [p. 336, 1] base = set_orth[k] set_orth[k + 1:] = [orth ^ base if len(orth & new_cycle) % 2\ else orth for orth in set_orth[k + 1:]] return cb
def test_prim_minimum_spanning_edges(self): edgelist = sorted(nx.minimum_spanning_edges(self.G, algorithm="prim")) edgelist = sorted((sorted((u, v))[0], sorted((u, v))[1], d) for u, v, d in edgelist) assert_equal(edgelist, self.minimum_spanning_edgelist)
def minimum_spanning_tree(G,weight='weight'): T=nx.Graph(nx.minimum_spanning_edges(G,weight=weight,data=True)) return T
def main(argv): try: opts, args = getopt.getopt(argv, "hb:f:ds", ["help", "bootstrap=","file="]) except getopt.GetoptError: usage() sys.exit(2) filename = None inputFile = None verbose = False bootstrapFile = None for opt, arg in opts: if opt == "-v": verbose = True elif opt in ("-h", "--help"): usage() sys.exit() elif opt in ("-f", "--file"): inputFile = arg shapefilename = inputFile[0:-4] elif opt in ("-b", "--bootstrap"): bootstrapFile = arg elif opt in ("-s", "--shapefile"): shapefileFlag = arg else: assert False, "unhandled option" if bootstrapFile is not None: try: file = open(bootstrapFile) except IOError: print "can't open ", bootstrapFile, ". I will now exit." sys.exit() bootstrapValues = [] bootstrapError = [] while 1: line = file.readline() if line in ['\n', '\r\n']: break row = line.split() bootstrapValues[row[0]][row[1]] = row[2] bootstrapValues[row[1]][row[0]] = row[2] bootstrapError[row[1]][row[0]] = row[3] bootstrapError[row[0]][row[1]] = row[3] #Set up blank lists for data x,y,id_no,date,target = [], [], [], [], [] nodeX = {} nodeY = {} nodeEasting = {} nodeNorthing = {} nodes = [] graphs = [] nodeSize = {} #read data from csv file and store in lists block = "" count = 0 old_network = 0 G = None graphCount = -1 edgeCount = 0 graphHash = {} row = () ## Read in all of the data from the .vna file Reconstruct the graphs. try: file = open(inputFile) except IOError: print "can't open ", inputFile, ". I will now exit." sys.exit() except TypeError: print "No file specified (use --file=<filename>). I will now exit." sys.exit() megaGraph = nx.Graph() while 1: line=file.readline() #print line if not line: break if "*Node data" in line: block = "nodes" count = 0 elif "*Node properties" in line: block = "properties" count= 0 elif "*Tie data" in line: block = "ties" count = 0 if line in ['\n', '\r\n']: break row =line.split() if row is None: break if count > 1 and block == "nodes": nodename = row[0] nodes.append(row[0]) nodeX[nodename] = float(row[2]) nodeY[nodename] = float(row[3]) nodeEasting[nodename] = float(row[4]) nodeNorthing[nodename] = float(row[5]) nodeSize[nodename] = float(row[1]) if count > 1 and block == "ties": node1 = row[0] node2 = row[1] node1x,node1y = nodeEasting[node1], nodeNorthing[node1] node2x,node2y = nodeEasting[node2], nodeNorthing[node2] node1Size=nodeSize[node1] node2Size=nodeSize[node2] weight = float(row[3]) network = int(row[4]) #print "now on network: ", network, " edge: ", edgeCount, " oldnetwork: ", old_network pvalue = float(row[5]) pError = float(row[6]) meanDistance = float(row[7]) if network > old_network: #print "adding network..." old_network = network graphs.append(nx.Graph()) graphCount += 1 edgeCount = 0 graphs[graphCount].add_node(node1, x = node1x, y = node1y, name=node1, size=node1Size ) graphs[graphCount].add_node(node2, x = node2x, y = node2y, name=node2, size=node2Size ) graphs[graphCount].add_edge(node1,node2, xy1=(node1x, node1y), xy2=(node2x, node2y), weight=weight, meanDistance=meanDistance, pvalue=pvalue,pError=pError,color='black') if bootstrapFile is not None: megaGraph.add_edge(node1,node2, xy1=(node1x,node1y), xy2=(node2x,node2y), weight = bootstrapValues[node1][node2], pvalueError = bootstrapError[node1][node2], meanDistance = meanDistance, pvalue = pvalue, pError = pError, color ='black') edgeCount += 1 count += 1 if shapefileFlag is not None: w = shapefile.Writer(shapefile.POLYLINE) # 3= polylines #print count, " graphs " c=0 #pp.pprint(graphs) for g in graphs: edges = g.edges() for e in edges: node1 = e[0] node2 = e[1] print g[node1][node2] x1 = g[node1][node2]['xy1'][0] y1 = g[node1][node2]['xy1'][1] x2 = g[node2][node1]['xy2'][0] y2 = g[node2][node1]['xy2'][1] #print x1, "-", y1 #print x2, "-", y2 w.poly(parts=[[[x1,y1],[x2,y2]]]) c += 1 w.save(shapefilename) if bootstrapFile is not None: outputFile = inputFile[0,-4]+"-bootstrap.vna" f = open(outputFile, 'w') f.write("*node data\n") f.write("ID X Y") vertices = megaGraph.vertices() for v in vertices: output = v[0]+" "+nodeX[v[0]]+" "+nodeY[v[0]]+"\n" f.write(output) mst=nx.minimum_spanning_edges(megaGraph,data=True) edgelist = list(mst) # make a list of the edges f.write("*tie data\n*from to weight error\n") for edge in edgelist: output = edge[0]+" "+edge[1]+" "+edge[0][1]['weight']+" "+edge[0][1]['pvalueError']+"\n" print edge[0], " - ", edge[1], " ", edge[0][1]['weight']," ", edge[0][1]['pvalueError'],"\n" f.write(output)
for n, nbrs in G.adjacency_iter(): w = 0 for nbr, eattr in nbrs.items(): w += 1 / eattr['weight'] si.append(w) # pos = nx.spring_layout(G, k=1) # positions for all nodes fig, ax = plt.subplots(1) # nodes scaler = 20 nx.draw_networkx_nodes(G, pos, node_size=[x * scaler for x in si]) # edges mst = nx.minimum_spanning_edges(G, data=False) nx.draw_networkx_edges(G, pos, width=1, edgelist=list(mst)) # labels; make them but dont actually draw them labels = {ii: label for ii, label in enumerate(labels)} nx.draw_networkx_labels(G, pos, font_size=10, font_family='sans-serif') plt.axis('off') # plt.savefig("weighted_graph.png") # save as png # legend props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) # ax.text(-0.15, 0.95, textstr, transform=ax.transAxes, # fontsize=14, verticalalignment='top', bbox=props) plt.axis('off')
node_color[row[0][5:-3]]='yellow' sen_Names.append('%s' %row[0][5:-3]) sen_Names = sen_Names[1:] #print sen_Names g = nx.Graph() gn = nx.Graph() g.add_nodes_from(sen_Names) gn.add_nodes_from(sen_Names) for row in xrange(100): for col in xrange(row, 100): if row != col: g.add_edge(sen_Names[row], sen_Names[col], weight=abs(votes[row][col]-1000)) mst = nx.minimum_spanning_edges(g, data = True) edgelist = list(mst) gn.add_edges_from(edgelist) #print sorted(edgelist) labels={} for name in sen_Names: labels[name] = r'%s' %name #print labels positions = nx.spring_layout(gn, k = 0.40) nx.draw_networkx_labels(gn, positions, labels, font_size = 11) nx.draw(gn, positions,node_size = 55, node_color=node_color.values())
for e in weighted_edges: f = e[0] t = e[1] w = e[2] if w > 20: G2.add_edge(f, t, weight=w) nx.write_graphml(G2, 'topic_graph.graphml') # minimum spanning tree T = nx.algorithms.minimum_spanning_tree(G2, weight='weight') nx.write_graphml(T, "spanning_tree.graphml") # spanning edges E = nx.minimum_spanning_edges(G2, weight='weight') nx.write_graphml(T, "spanning_edges.graphml") # code -> topic code_topic = {'0' : 'EU roma külpolitika', '1' : 'Roma önkormányzat', '2' : 'Magyar Gárda, stb.', '3' : 'Lopással kapcsolatos hírek', '4' : 'Roma-nem roma társadalmi prolémák, stb.', '5' : 'Politikai pártok, politikusok', '6' : 'Ingatlanüggyel, lakhatással kapcsolatos problémák, bűntények', '7' : 'Máshonnan átvett tartalmak', '8' : 'Vidéki települések roma-többségi konfliktusai', '9' : 'Egészségügy', '10' : 'Közbiztonság, önvédelem, polgárőrség', '11' : 'Olvasói történetek',
#draw the labels lbls = nx.draw_networkx_labels(votes, pos, alpha=5, font_size=8) #coordinate information is meaningless here, so let's remove it plt.xticks([]) plt.yticks([]) remove_border(left=False, bottom=False) # plt.show() plt.figure(figsize=(15,10)) np.random.seed(5) mst = nx.minimum_spanning_tree(votes, weight='difference') pos = nx.spring_layout(mst, iterations=900, k=.008, weight='difference') mst_edges = list(nx.minimum_spanning_edges(votes, weight='difference')) n1 = votes.nodes() c = [votes.node[n]['color'] for n in n1] nx.draw_networkx_edges(votes, pos, edgelist=mst_edges, alpha=.2) nx.draw_networkx_nodes(votes, pos, nodelist = n1, node_color = c, node_size=60) for p in pos.values(): p[1] += .02 nx.draw_networkx_labels(votes, pos, font_color='k', fonr_size=7) plt.title("MST of Vote Disagreement", fontsize=18) plt.xticks([]) plt.yticks([]) remove_border(left=False, bottom=False)
def compute_mst_networkx(self): """ Calculate the weight of the MST for the given graph using Networkx functions (for comparison).""" return sum([e[2]['weight'] for e in list(nx.minimum_spanning_edges(self.graph, data=True))])
def test_mst_edges(self): edgelist=sorted(nx.minimum_spanning_edges(self.G)) assert_equal(edgelist,self.tree_edgelist)
def test_minimum_edges(self): edges = nx.minimum_spanning_edges(self.G, algorithm=self.algo) # Edges from the spanning edges functions don't come in sorted # orientation, so we need to sort each edge individually. actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) assert_edges_equal(actual, self.minimum_spanning_edgelist)
def test_kruskal_minimum_spanning_edges(self): edgelist = sorted(nx.minimum_spanning_edges(self.G, algorithm="kruskal")) assert_equal(edgelist, self.minimum_spanning_edgelist)
# add a returning edge from the last node to the first node result_cost = tmpNode['dist'] + g.edge[tmpNode['trace'][-1]][tmpNode['trace'][0]]['weight']; break; # deal with all tmpNode's neighbors neighbors = g.nodes(); for visited in tmpNode['trace']: # remove all visited node neighbors.remove(visited); for v in neighbors: # create new state node name = tmpNode['label'] + v; states.add_node(name); states.node[name]['trace'] = tmpNode['trace'] + [v]; states.node[name]['label'] = name; states.node[name]['dist'] = tmpNode['dist'] + g.edge[tmpNode['trace'][-1]][v]['weight']; remain = neighbors[:]; remain.remove(v); mst = nx.minimum_spanning_edges(g.subgraph(remain)); # use weight of mst of remaining nodes as heuristic states.node[name]['heur'] = 0.0; for e in mst: states.node[name]['heur'] += e[2]['weight']; states.node[name]['fact'] = states.node[name]['dist'] + states.node[name]['heur']; # put new state node into heap nodeId.append(name); keys.append(states.node[name]['fact']); # output final result print "Tour: " + ' '.join(result_trace); print "Cost: " + str(result_cost);