def __find_mst(graph): graph = -1 * graph graph = np.transpose(graph) G = nx.DiGraph(graph) try: MSA = nx.minimum_spanning_arborescence(G) except nx.exception.NetworkXException: # If a node with no head exists, hack it into a node with uniform dist: ng = np.array(graph - 0.0001) MSA = nx.minimum_spanning_arborescence(nx.DiGraph(ng)) return nx.adjacency_matrix(MSA).todense().transpose() * (-1)
def __find_mst(graph): graph = -1*graph graph = np.transpose(graph) G = nx.DiGraph(graph) try: MSA = nx.minimum_spanning_arborescence(G) except nx.exception.NetworkXException: # If a node with no head exists, hack it into a node with uniform dist: ng = np.array(graph - 0.0001) MSA = nx.minimum_spanning_arborescence(nx.DiGraph(ng)) return nx.adjacency_matrix(MSA).todense().transpose()*(-1)
def draw_mst(user_id, source=()): if user_id not in graphs: return "У вас еще нет графа" if not weighted[user_id]: return "У вас невзвешенный граф" if isinstance(graphs[user_id], nx.DiGraph): if len(source) != 1: return "Вы ввели некорректные данные. Обратитесь к команде help" source = source[0] graphs[user_id].add_node('Extra_node_for_algo') graphs[user_id].add_edge('Extra_node_for_algo', source, weight=-1) t = nx.minimum_spanning_arborescence(graphs[user_id], attr='weight') t.remove_node('Extra_node_for_algo') graphs[user_id].remove_node('Extra_node_for_algo') else: t = nx.minimum_spanning_tree(graphs[user_id]) edges = "" for edge in t.edges: edges += "{} {} {}\n".format(edge[0], edge[1], t[edge[0]][edge[1]]['weight']) pos = nx.spring_layout(t) nx.draw(t, pos) nx.draw_networkx_labels(t, pos) weights = nx.get_edge_attributes(t, 'weight') nx.draw_networkx_edge_labels(t, pos, edge_labels=weights) plt.savefig('temp.png', dpi=300) plt.close() return "OK"
def treeConverter(self): # getting root root = [ n for n in self.Graph.nodes() if len(list(self.Graph.predecessors(n))) == 0 ][0] self.root = root is_treee = nx.is_tree(self.Graph) is_arb = nx.is_arborescence(self.Graph) if not is_arb: logging.info( "Arborescence is not possible due to in-bound and out-bound edges. Therefore converting to tree using BFS." ) self.DAG2Tree() else: logging.info("Converting dag to tree") arb_graph = nx.minimum_spanning_arborescence(self.Graph) if nx.is_tree(arb_graph): logging.info( "Converted to tree! But some information is lost...") nx.write_edgelist(arb_graph, self.edgelist_file) self.removeParantheses(self.edgelist_file) nx.write_graphml(arb_graph, self.gml_file) self.Graph = arb_graph
def vecMat2tree(word_mat, indKeys, treeType='TRmsa', treeThresh=20, simType='cos', focusRank=3): ''' description: - given embeddings matrix, treeType and simType, builds and returns networkx tree object params: - word_mat: embeddings matrix (VOCABxNDIMS) - indKeys: index to word mapping (dict) - treeType: - 'msa': maximum spanning arboroscence - 'Rmsa': rank minimum spanning arboroscence - 'TRmsa': transpose rank minimum spanning arboroscence - 'FRmsa': flipped rank minimum spanning arboroscence (see flipMatrix() for more info) - treeThresh: (relevant) edge weight threshold for adjacency matrix - simType: - 'cos': cosine similarity - 'xor': xor similarity (weights must be discretized) focusRank: pivot for flipped Rmsa (only applicable if treeType == 'FRmsa') returns: - tree: networkx graph object ''' argMax = False sim_mat, temp_mat = None, None if simType == 'cos': sim_mat = cos_similarity(word_mat) elif simType == 'xor': sim_mat = xor_similarity(word_mat) elif simType == 'kl': sim_mat = kl_similarity(word_mat) if treeType == 'msa': argMax = True # maximize similarity edge weight in arboroscence temp_mat = sim_mat.copy() elif treeType == 'Rmsa': rank_mat = rankMatrix(sim_mat) temp_mat = rank_mat.copy() elif treeType == 'TRmsa': rank_mat = rankMatrix(sim_mat) temp_mat = rank_mat.T.copy() elif treeType == 'FRmsa': rank_mat = rankMatrix(sim_mat) flipped_rank_mat = flipMatrix(rank_mat, focusRank=focusRank) temp_mat = flipped_rank_mat.copy() adj_mat = buildAdjMat(temp_mat, thresh=20, mode='abs', reverse=(not argMax)) g = nx.convert_matrix.from_numpy_array(adj_mat, create_using=nx.DiGraph) tree = nx.minimum_spanning_arborescence(g) tree = nx.relabel_nodes(tree, indKeys) return tree
def MinimumArborescence(G): B = nx.minimum_spanning_arborescence(G, attr="inv_lcprob") for edge in B.edges(): if edge in G.edges(): for key in G.edges()[edge]: B.edges()[edge][key] = G.edges()[edge][key] for node in B.nodes(): if node in G.nodes(): for key in G.nodes()[node]: B.nodes()[node][key] = G.nodes()[node][key] return B
def compute_k_edge_disjoint_aborescenes(self, k, bridge_dict): k_ada = [] mdg = nx.MultiDiGraph(self.network_configuration.graph) for node_id in self.network_configuration.graph: node_type = self.network_configuration.get_node_type(node_id) # Remove all host nodes if node_type == "host": mdg.remove_node(node_id) dst_br_preds = list(mdg.predecessors(bridge_dict["bridge_name"])) dst_br_succs = list(mdg.successors(bridge_dict["bridge_name"])) # Remove the predecessor edges to dst_br, to make it the "root" for pred in dst_br_preds: mdg.remove_edge(pred, bridge_dict["bridge_name"]) # Initially, remove all successors edges of dst_br as well for succ in dst_br_succs: mdg.remove_edge(bridge_dict["bridge_name"], succ) for i in range(k): # Assume there are always k edges as the successor of the dst_br, kill all but one for j in range(k): if i == j: mdg.add_edge(bridge_dict["bridge_name"], dst_br_succs[j]) else: if mdg.has_edge(bridge_dict["bridge_name"], dst_br_succs[j]): mdg.remove_edge(bridge_dict["bridge_name"], dst_br_succs[j]) # Compute and store one msa = nx.minimum_spanning_arborescence(mdg) k_ada.append(msa) # If there are predecessors of dst_br now, we could not find k msa, so break if len(list(msa.predecessors(bridge_dict["bridge_name"]))) > 0: print "Could not find k msa." break # Remove its arcs from mdg for arc in msa.edges(): mdg.remove_edge(arc[0], arc[1]) return k_ada
def graph_minimum_spanning_arborescence(output_directory, is_trial, graphs, adjacency_matrices, widget, properties_dict): output_directory = os.path.join(output_directory, 'MaximumSpanningArborescence') if not os.path.exists(output_directory): os.makedirs(output_directory) log_file = os.path.join(output_directory, 'MaximumSpanningArborescence.txt') msa_list = [] for window, graph in enumerate(graphs): msa_graph = nx.minimum_spanning_arborescence(graph) msa_list.append(msa_graph.edges()) count = 0 weight = 0 for edge in msa_graph.edges(): node_index_1 = 0 node_index_2 = 0 for key in list(CHANNELS_DICT.keys()): if CHANNELS_DICT[key] == edge[0]: node_index_1 = key break for key in list(CHANNELS_DICT.keys()): if CHANNELS_DICT[key] == edge[1]: node_index_2 = key break weight += adjacency_matrices[window][node_index_1][node_index_2] count += 1 if not is_trial: log(f'Window {window}', file=log_file) log(f'\t Weight: {weight}', file=log_file) log(f'\t Weight average: {weight / (count * 1.0)}', file=log_file) if not is_trial: properties_dict[window][MSA_WEIGHT] = weight else: properties_dict[MSA_WEIGHT] = weight with open(os.path.join(output_directory, 'MSAList.bin'), 'wb+') as f: pickle.dump(msa_list, f)
def compute_k_edge_disjoint_aborescenes(self, dst_sw): k_eda = [] mdg = self.get_mdg() dst_sw_preds = sorted(list(mdg.predecessors(dst_sw.node_id))) dst_sw_succs = sorted(list(mdg.successors(dst_sw.node_id))) # Remove the predecessor edges to dst_sw, to make it the "root" for pred in dst_sw_preds: mdg.remove_edge(pred, dst_sw.node_id) # Initially, remove all successors edges of dst_sw as well for succ in dst_sw_succs: mdg.remove_edge(dst_sw.node_id, succ) for i in range(self.params["k"]): # Assume there are always k edges as the successor of the dst_sw for j in range(self.params["k"]): if i == j: mdg.add_edge(dst_sw.node_id, dst_sw_succs[j], weight=1) else: if mdg.has_edge(dst_sw.node_id, dst_sw_succs[j]): mdg.remove_edge(dst_sw.node_id, dst_sw_succs[j]) # Compute and store one msa = nx.minimum_spanning_arborescence(mdg) k_eda.append(msa) # If there are predecessors of dst_sw now, we could not find k msa, so break if len(list(msa.predecessors(dst_sw.node_id))) > 0: print "Could not find k msa." break # Remove its arcs from mdg to ensure that these arcs are not part of any future msa for arc in msa.edges(): mdg.remove_edge(arc[0], arc[1]) if arc[0] != dst_sw.node_id and arc[1] != dst_sw.node_id: if mdg.has_edge(arc[1], arc[0]): prev_weight = mdg[arc[1]][arc[0]][0]['weight'] mdg.remove_edge(arc[1], arc[0]) mdg.add_edge(arc[1], arc[0], weight=prev_weight+100) return k_eda
def steiner_tree_region_mst(g, root, infection_times, source, terminals, return_closure=False, debug=False): regions = connect_adjacent_infections(g, terminals, infection_times) gc, eweight, orginal_edge_info = build_region_closure( g, root, regions, infection_times, terminals) root = gc.num_vertices() - 1 # last node is root gx = gt2nx(gc, root, list(map(int, gc.vertices())), edge_attrs={'weight': eweight}) try: nx_tree = nx.minimum_spanning_arborescence(gx, 'weight') except nx.NetworkXException: # cannot find any MST return None # now we reconstruct the super node tree to the original tree orig_edges = [] for i, j in nx_tree.edges(): einfo = orginal_edge_info[(i, j)] u, v = einfo['original_edge'] pred = einfo['pred'] c = u while c != v and pred[c] != -1: orig_edges.append((c, pred[c])) c = pred[c] efilt = g.new_edge_property('bool') efilt.a = False all_edges = [e for r in regions.values() for e in r['edges']] all_edges += orig_edges steiner_tree = edges2graph(g, all_edges) ret = steiner_tree if return_closure: region_graph = edges2graph( g, [e for r in regions.values() for e in r['edges']]) ret = (ret, gc, region_graph) return ret
def compute_k_edge_disjoint_aborescenes(self, k, dst_sw): k_eda = [] mdg = self.network_graph.get_mdg() dst_sw_preds = list(mdg.predecessors(dst_sw.node_id)) dst_sw_succs = list(mdg.successors(dst_sw.node_id)) # Remove the predecessor edges to dst_sw, to make it the "root" for pred in dst_sw_preds: mdg.remove_edge(pred, dst_sw.node_id) # Initially, remove all successors edges of dst_sw as well for succ in dst_sw_succs: mdg.remove_edge(dst_sw.node_id, succ) for i in range(k): # Assume there are always k edges as the successor of the dst_sw, kill all but one for j in range(k): if i == j: mdg.add_edge(dst_sw.node_id, dst_sw_succs[j]) else: if mdg.has_edge(dst_sw.node_id, dst_sw_succs[j]): mdg.remove_edge(dst_sw.node_id, dst_sw_succs[j]) # Compute and store one msa = nx.minimum_spanning_arborescence(mdg) k_eda.append(msa) # If there are predecessors of dst_sw now, we could not find k msa, so break if len(list(msa.predecessors(dst_sw.node_id))) > 0: print "Could not find k msa." break # Remove its arcs from mdg for arc in msa.edges(): mdg.remove_edge(arc[0], arc[1]) return k_eda
def _minimum_rooted_branching(D, root): """Computes minimum rooted branching (aka rooted arborescence) Before the branching can be computed, the directed graph must be rooted by removing the predecessors of root. A branching / arborescence of rooted graph G is a subgraph that contains a directed path from the root to every other vertex. It is the directed analog of the minimum spanning tree problem. References ---------- [1] Khuller, Samir (2002) Advanced Algorithms Lecture 24 Notes. https://www.cs.umd.edu/class/spring2011/cmsc651/lec07.pdf """ rooted = D.copy() # root the graph by removing all predecessors to `root`. rooted.remove_edges_from([(u, root) for u in D.predecessors(root)]) # Then compute the branching / arborescence. A = nx.minimum_spanning_arborescence(rooted) return A
def mst(user_id, source=()): if user_id not in graphs: return "У вас еще нет графа" if not weighted[user_id]: return "У вас невзвешенный граф" if isinstance(graphs[user_id], nx.DiGraph): if len(source) != 1: return "Вы ввели некорректные данные. Обратитесь к команде help" source = source[0] graphs[user_id].add_node('Extra_node_for_algo') graphs[user_id].add_edge('Extra_node_for_algo', source, weight=-1) t = nx.minimum_spanning_arborescence(graphs[user_id], attr='weight') t.remove_node('Extra_node_for_algo') graphs[user_id].remove_node('Extra_node_for_algo') else: t = nx.minimum_spanning_tree(graphs[user_id]) edges = "" for edge in t.edges: edges += "{} {} {}\n".format(edge[0], edge[1], t[edge[0]][edge[1]]['weight']) return edges
def _minimum_rooted_branching(D, root): """Helper function to compute a minimum rooted branching (aka rooted arborescence) Before the branching can be computed, the directed graph must be rooted by removing the predecessors of root. A branching / arborescence of rooted graph G is a subgraph that contains a directed path from the root to every other vertex. It is the directed analog of the minimum spanning tree problem. References ---------- [1] Khuller, Samir (2002) Advanced Algorithms Lecture 24 Notes. https://www.cs.umd.edu/class/spring2011/cmsc651/lec07.pdf """ rooted = D.copy() # root the graph by removing all predecessors to `root`. rooted.remove_edges_from([(u, root) for u in D.predecessors(root)]) # Then compute the branching / arborescence. A = nx.minimum_spanning_arborescence(rooted) return A
def steiner_tree_region_mst(g, root, infection_times, source, terminals, return_closure=False, debug=False): regions = connect_adjacent_infections(g, terminals, infection_times) gc, eweight, orginal_edge_info = build_region_closure( g, root, regions, infection_times, terminals) root = gc.num_vertices() - 1 # last node is root gx = gt2nx(gc, root, list(map(int, gc.vertices())), edge_attrs={'weight': eweight}) try: nx_tree = nx.minimum_spanning_arborescence(gx, 'weight') except nx.NetworkXException: # cannot find any MST return None # now we reconstruct the super node tree to the original tree orig_edges = [] for i, j in nx_tree.edges(): einfo = orginal_edge_info[(i, j)] u, v = einfo['original_edge'] pred = einfo['pred'] c = u while c != v and pred[c] != -1: orig_edges.append((c, pred[c])) c = pred[c] efilt = g.new_edge_property('bool') efilt.a = False all_edges = [e for r in regions.values() for e in r['edges']] all_edges += orig_edges steiner_tree = edges2graph(g, all_edges) ret = steiner_tree if return_closure: region_graph = edges2graph(g, [e for r in regions.values() for e in r['edges']]) ret = (ret, gc, region_graph) return ret
def steiner_tree_mst(g, root, infection_times, source, terminals, closure_builder=build_closure, strictly_smaller=True, return_closure=False, k=-1, debug=False, verbose=True): gc, eweight, r2pred = closure_builder(g, root, terminals, infection_times, strictly_smaller=strictly_smaller, k=k, debug=debug, verbose=verbose) # get the minimum spanning arborescence # graph_tool does not provide minimum_spanning_arborescence if verbose: print('getting mst') gx = gt2nx(gc, root, terminals, edge_attrs={'weight': eweight}) try: nx_tree = nx.minimum_spanning_arborescence(gx, 'weight') except nx.exception.NetworkXException: if debug: print('fail to find mst') if return_closure: return None, gc, None else: return None if verbose: print('returning tree') mst_tree = Graph(directed=True) for _ in range(g.num_vertices()): mst_tree.add_vertex() for u, v in nx_tree.edges(): mst_tree.add_edge(u, v) if verbose: print('extract edges from original graph') # extract the edges from the original graph # sort observations by time # and also topological order topological_index = {} for i, e in enumerate(bfs_iterator(mst_tree, source=root)): topological_index[int(e.target())] = i sorted_obs = sorted( set(terminals) - {root}, key=lambda o: (infection_times[o], topological_index[o])) tree_nodes = {root} tree_edges = set() # print('root', root) for u in sorted_obs: if u in tree_nodes: if debug: print('{} covered already'.format(u)) continue # print(u) v, u = map(int, next(mst_tree.vertex(u).in_edges())) # v is ancestor tree_nodes.add(v) late_nodes = [n for n in terminals if infection_times[n] > infection_times[u]] vis = init_visitor(g, u) # from child to any tree node, including v cpbfs_search(g, source=u, terminals=list(tree_nodes), forbidden_nodes=late_nodes, visitor=vis, count_threshold=1) # dist, pred = shortest_distance(g, source=u, pred_map=True) node_set = {v for v, d in vis.dist.items() if d > 0} reachable_tree_nodes = node_set.intersection(tree_nodes) ancestor = min(reachable_tree_nodes, key=vis.dist.__getitem__) edges = extract_edges_from_pred(g, u, ancestor, vis.pred) edges = {(j, i) for i, j in edges} # need to reverse it if debug: print('tree_nodes', tree_nodes) print('connecting {} to {}'.format(v, u)) print('using ancestor {}'.format(ancestor)) print('adding edges {}'.format(edges)) tree_nodes |= {u for e in edges for u in e} tree_edges |= edges t = Graph(directed=True) for _ in range(g.num_vertices()): t.add_vertex() for u, v in tree_edges: t.add_edge(t.vertex(u), t.vertex(v)) tree_nodes = {u for e in tree_edges for u in e} vfilt = t.new_vertex_property('bool') vfilt.a = False for v in tree_nodes: vfilt[t.vertex(v)] = True t.set_vertex_filter(vfilt) if return_closure: return t, gc, mst_tree else: return t
def _asymmetric(dist, weight, **params): def get_shortcut(dist, weight, cutoff=20): if dist.shape[0] < 3000: cutoff = 1 elif dist.shape[0] < 10000: cutoff = 5 elif dist.shape[0] < 30000: cutoff = 10 link = np.array(np.where(dist < (cutoff + 1))) link = link.T[weight[link[0]] < weight[link[1]]].T link = np.vstack( [link, dist[tuple(link.tolist())] + weight[link[0]]]) link = link.T[np.lexsort(link)] return link[np.unique(link.T[1], return_index=True)[1]].astype(int) try: presence = np.arange(weight.shape[0]) shortcuts = get_shortcut(dist, weight) for (s, t, d) in shortcuts: dist[s, dist[s] > dist[t]] = dist[t, dist[s] > dist[t]] presence[shortcuts.T[1]] = -1 dist = dist.T[presence >= 0].T[presence >= 0] presence = presence[presence >= 0] weight2 = weight[presence] dist = np.round(dist, 0) + weight2.reshape([weight2.size, -1]) np.fill_diagonal(dist, 0.0) dist_file = params['tempfix'] + '.dist.list' with open(dist_file, 'w') as fout: for d in dist: fout.write('{0}\n'.format('\t'.join([ '{0:.5f}'.format(dd) for dd in (d + (1. - 0.000005)) ]))) del dist, d mstree = Popen([params['edmonds_' + platform.system()], dist_file], stdout=PIPE).communicate()[0] os.unlink(dist_file) if isinstance(mstree, bytes): mstree = mstree.decode('utf8') mstree = np.array( [br.strip().split() for br in mstree.strip().split('\n')], dtype=float).astype(int) assert mstree.size > 0 mstree.T[2] -= 1 mstree.T[:2] = presence[mstree.T[:2]] return mstree.tolist() + shortcuts.tolist() except: try: os.unlink(dist_file) except: pass dist = np.load(params['dist_file']) dist = np.round(dist, 0) + weight.reshape([weight.size, -1]) np.fill_diagonal(dist, 0.0) presence = np.arange(weight.shape[0]) shortcuts = get_shortcut(dist, weight) for (s, t, d) in shortcuts: dist[s, dist[s] > dist[t]] = dist[t, dist[s] > dist[t]] presence[t] = -1 dist = dist.T[presence >= 0].T[presence >= 0] presence = presence[presence >= 0] g = nx.DiGraph(dist) ms = nx.minimum_spanning_arborescence(g) return [[presence[d[0]], presence[d[1]], int(d[2]['weight'])] for d in ms.edges(data=True)] + shortcuts.tolist()
# msa = nx.relabel_nodes(msa,ind_keys) # dot = to_pydot(msa) # write_dot(msa,"Tmsa.dot") # print(rank_mat) # TRMSA or RMSA # temp_mat = rank_mat.copy() # RMSA temp_mat = np.transpose(rank_mat.copy()) # TRMSA # 'seed' is the MAXIMUM edge rank allowed in the msa adj_mat = am.build(temp_mat, seed=20, mode='absolute', reverse=True) # Remove transpose for Rmsa g = nx.convert_matrix.from_numpy_array(adj_mat, create_using=nx.DiGraph) print("Graph made") Rmsa = nx.minimum_spanning_arborescence(g) Rmsa = nx.relabel_nodes(Rmsa, ind_keys) dot = to_pydot(Rmsa) write_dot(Rmsa, "TRmsa_nouns.dot") # The CSV Bit # import csv # Saving the edgelist as csv ; For Poincare implementation # csv_columns = ['id1','id2','weight'] # dict_data = list() # for u in Rmsa: # for v in Rmsa[u]: # dict_data.append({'id1':u, 'id2':v, 'weight':1}) # csv_file = "TRmsa_nouns.csv" # try: # with open(csv_file, 'w') as csvfile: # writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
def demo_TRmsa(fpath='/home/kvaditya/GitHubRepos/wiki-news-300d-nouns.txt', pipeline='short'): ''' description: - demo function to generate TRmsa tree from given embedding file params: - fapth: path to embedding file - pipeline: - 'short': implement using prebuilt main functions - 'long': implement using utility functions *NOTE: both methods furnish same results returns: None ''' if pipeline == 'short': # using prebuilt main functions print('building demo TRmsa using short pipeline') vecMat, indKeys, wordKeys = vecFile2vecMat(fpath, norm=True, disc=False) tree = vecMat2tree(vecMat, indKeys, treeType='TRmsa', treeThresh=20, simType='cos') saveTreeDot(tree, fpath='demo_TRmsa.dot') dot2png(dotPath='demo_TRmsa.dot') print('process complete') elif pipeline == 'long': # using utility functions print('building demo TRmsa using long pipeline') if not path.exists(embFile): print('error: path does not exist') return None if not path.isfile(embFile): print('error: path not a file') return None else: # step_1) loading embeddings and generating embedding matrix & index-word mappings for the matrix emb = load_embedding(embFile, VOCAB=100, typ='w2v') indKeys, wordKeys, word_mat = buildWordMat(emb) word_mat = normalize(word_mat, axis=0) # word_mat = discretize(word_mat, axis=0) # uncomment to enable discretization #step_2) building similarity matrix sim_mat = cos_similarity(word_mat) #step_3) building rank similarity matrix renk_mat = rankMatrix(sim_mat) # step_4) building the adjacency matrix, followed by generating the graph temp_mat = np.transpose(rank_mat) # TRmsa adj_mat = buildAdjMat(temp_mat, thresh=20, mode='abs', reverse=True) g = nx.convert_matrix.from_numpy_array(adj_mat, create_using=nx.DiGraph) # step_5) generating the minimum spanning arboroscence of the graph tree = nx.minimum_spanning_arborescence(g) tree = nx.relabel_nodes(tree, indKeys) # step_6) saving tree to dot file dot = to_pydot(tree) dotPath = 'TRmsa.dot' write_dot(tree, 'TRmsa.dot') # step_7) converting dot file to png cmd = 'dot -Tpng ' + dotPath process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) output, error = process.communicate() pngPath = dotPath.rstrip('.dot') + '.png' with open(pngPath, 'wb') as outfile: outfile.write(output) outfile.close() print('file saved as', pngPath) print('process complete')
def minimum_spanning_arborescence(self, graph, weight="weight", algorithm="prim"): """ Compute the minimum spanning arborescence graph """ return nx.minimum_spanning_arborescence(graph, attr=weight)
def create_mbs(self, body_dict=None, joint_dict=None): self.__bodies = {0: bodymodels.create(0, 'zero')} self.__joints = {} self.__msa = None #Minimum spanning arborescence self.__predecessors = {0: None} self.__successors = {0: []} self.__ancestors = {0: []} self.__descendants = {0: []} #Add all bodies if body_dict is not None: for key, val in body_dict.items(): geom, geom_par = val.popitem() #geom_par is a dict abody = bodymodels.create(key, geom, **geom_par) self.__bodies[key] = abody self.__num_bodies = len(self.__bodies) - 1 for k in self.bid_iter(): self.__successors[k] = [] self.__ancestors[k] = [] self.__descendants[k] = [] #Add all joints if joint_dict is not None: #Add pf and sf for root joint. Also ensure that there is exactly #one root joint. nrj = 0 for joint in joint_dict.values(): if joint['joint_type'] == 'root': joint['pf'] = 0 joint['sf'] = 1 nrj += 1 # assert nrj == 1 #Construct the model digraph model_digraph = nx.DiGraph() for key, val in joint_dict.items(): model_digraph.add_edge(val['pf'], val['sf'], {'key_in_joint_dict': key}) self.__num_joints = model_digraph.number_of_edges() #Construct the minimum spanning arborescence if nx.is_arborescence(model_digraph): self.__msa = model_digraph.copy() else: self.__msa = nx.minimum_spanning_arborescence(model_digraph) self.__num_tree_joints = self.__msa.number_of_edges() if self.__draw_graph: self.export_digraph(model_digraph, 'model_digraph.eps') self.export_digraph(self.__msa, 'msa.eps') for edge in self.__msa.edges_iter(): u, v = edge #Copy the joint attributes from model_digraph to self.__msa self.__msa[u][v]['key_in_joint_dict'] = model_digraph[u][v][ 'key_in_joint_dict'] self.__predecessors[v] = u self.__successors[u].append(v) #Fill in the ancestors and descendants lists for k in self.bid_iter(): predecessor = self.__predecessors[k] self.__ancestors[k].append(predecessor) self.__ancestors[k].extend(self.__ancestors[predecessor]) while predecessor is not None: self.__descendants[predecessor].append(k) predecessor = self.__predecessors[predecessor] for k in self.bid_iter(): pk = self.__predecessors[k] key_in_joint_dict = self.__msa[pk][k]['key_in_joint_dict'] joint_par = joint_dict[key_in_joint_dict] joint_type = joint_par.pop('joint_type') joint_par['category'] = 'tree' joint_par['pf'] = weakref.proxy(self.__bodies[pk]) joint_par['sf'] = weakref.proxy(self.__bodies[k]) self.__joints[k] = jointmodels.create(joint_type, **joint_par) #Remove the msa edges from model_digraph model_digraph.remove_edges_from(self.__msa.edges()) self.__num_loop_joints = model_digraph.number_of_edges() #Create the loop joints after renumbering ljid = self.__num_tree_joints for edge in model_digraph.edges_iter(): ljid += 1 u, v = edge key_in_joint_dict = model_digraph[u][v]['key_in_joint_dict'] joint_par = joint_dict[key_in_joint_dict] joint_type = joint_par.pop('joint_type') joint_par['category'] = 'loop' joint_par['pf'] = weakref.proxy(self.__bodies[u]) joint_par['sf'] = weakref.proxy(self.__bodies[v]) self.__joints[ljid] = jointmodels.create( joint_type, **joint_par) assert len(self.__bodies) == self.__num_tree_joints + 1 #Loop over the tree joints to find the total number of generalized #coordinates and generalized speeds. self.__num_gencoord = 0 self.__num_genspeed = 0 self.__gsloc = {} for jid in self.tree_jid_iter(): joint = self.__joints[jid] ngc = joint.num_gencoord ngs = joint.num_genspeed if ngs != 0: self.__gsloc[jid] = (self.__num_genspeed, self.__num_genspeed + ngs) self.__num_gencoord += ngc self.__num_genspeed += ngs self.__gencoord = np.zeros((self.__num_gencoord, )) self.__gencoord_dot = np.zeros((self.__num_gencoord, )) self.__genspeed = np.zeros((self.__num_genspeed, )) #Allocate space for the partial matrix self.__partial_mat = np.zeros( (6 * self.__num_bodies, self.__num_genspeed)) #Loop over the loop joints to find the total number of constraints. self.__num_constraints = 0 self.__cloc = {} for jid in self.loop_jid_iter(): joint = self.__joints[jid] nc = joint.num_constraints self.__cloc[jid] = (self.__num_constraints, self.__num_constraints + nc) self.__num_constraints += nc #Allocate space for the constraint matrix self.__constraint_mat = np.zeros( (self.__num_constraints, self.__num_genspeed)) #Allocate space for the evaluated constraints self.__plc = np.zeros((self.__num_constraints, )) #Position level self.__vlc = np.zeros((self.__num_constraints, )) #Velocity level # Print statements for debugging # print(self.__predecessors) # print(self.__successors) # print(self.__ancestors) # print(self.__descendants) # for jid in self.jid_iter(): # joint = self.__joints[jid] # print(jid, joint.connects) # print('num_constraints', self.__num_constraints) # # Root joint state if self.__rooted: self.__pullback = False else: self.__joints[1].uproot()
def minimum_spanning_arborescence(self): b = nx.minimum_spanning_arborescence(self.G) return nx.to_numpy_matrix(b, nodelist=list(range(len(self.G.nodes()))))
def steiner_tree_mst(g, root, infection_times, source, terminals, closure_builder=build_closure, strictly_smaller=True, return_closure=False, k=-1, debug=False, verbose=True): gc, eweight, r2pred = closure_builder(g, root, terminals, infection_times, strictly_smaller=strictly_smaller, k=k, debug=debug, verbose=verbose) # get the minimum spanning arborescence # graph_tool does not provide minimum_spanning_arborescence if verbose: print('getting mst') gx = gt2nx(gc, root, terminals, edge_attrs={'weight': eweight}) try: nx_tree = nx.minimum_spanning_arborescence(gx, 'weight') except nx.exception.NetworkXException: if debug: print('fail to find mst') if return_closure: return None, gc, None else: return None if verbose: print('returning tree') mst_tree = Graph(directed=True) for _ in range(g.num_vertices()): mst_tree.add_vertex() for u, v in nx_tree.edges(): mst_tree.add_edge(u, v) if verbose: print('extract edges from original graph') # extract the edges from the original graph # sort observations by time # and also topological order topological_index = {} for i, e in enumerate(bfs_iterator(mst_tree, source=root)): topological_index[int(e.target())] = i sorted_obs = sorted(set(terminals) - {root}, key=lambda o: (infection_times[o], topological_index[o])) tree_nodes = {root} tree_edges = set() # print('root', root) for u in sorted_obs: if u in tree_nodes: if debug: print('{} covered already'.format(u)) continue # print(u) v, u = map(int, next(mst_tree.vertex(u).in_edges())) # v is ancestor tree_nodes.add(v) late_nodes = [ n for n in terminals if infection_times[n] > infection_times[u] ] vis = init_visitor(g, u) # from child to any tree node, including v cpbfs_search(g, source=u, terminals=list(tree_nodes), forbidden_nodes=late_nodes, visitor=vis, count_threshold=1) # dist, pred = shortest_distance(g, source=u, pred_map=True) node_set = {v for v, d in vis.dist.items() if d > 0} reachable_tree_nodes = node_set.intersection(tree_nodes) ancestor = min(reachable_tree_nodes, key=vis.dist.__getitem__) edges = extract_edges_from_pred(g, u, ancestor, vis.pred) edges = {(j, i) for i, j in edges} # need to reverse it if debug: print('tree_nodes', tree_nodes) print('connecting {} to {}'.format(v, u)) print('using ancestor {}'.format(ancestor)) print('adding edges {}'.format(edges)) tree_nodes |= {u for e in edges for u in e} tree_edges |= edges t = Graph(directed=True) for _ in range(g.num_vertices()): t.add_vertex() for u, v in tree_edges: t.add_edge(t.vertex(u), t.vertex(v)) tree_nodes = {u for e in tree_edges for u in e} vfilt = t.new_vertex_property('bool') vfilt.a = False for v in tree_nodes: vfilt[t.vertex(v)] = True t.set_vertex_filter(vfilt) if return_closure: return t, gc, mst_tree else: return t