def local_clustering_binary_undirected(g, nodes=None): ''' Returns the undirected local clustering coefficient of some `nodes`. If `g` is directed, then it is converted to a simple undirected graph (no parallel edges). Parameters ---------- g : :class:`~nngt.Graph` Graph to analyze. nodes : list, optional (default: all nodes) The list of nodes for which the clustering will be returned Returns ------- lc : :class:`numpy.ndarray` The list of clustering coefficients, on per node. References ---------- .. [gt-local-clustering] :gtdoc:`clustering.locall_clustering` ''' # use undirected graph view, filter parallel edges u = GraphView(g.graph, directed=False) u = GraphView(u, efilt=label_parallel_edges(u).fa == 0) # compute clustering lc = gtc.local_clustering(u, weight=None, undirected=None).a if nodes is None: return lc return lc[nodes]
def min_steiner_tree(g, obs_nodes, debug=False, verbose=False): if g.num_vertices() == len(obs_nodes): print('it\'s a minimum spanning tree problem') gc, eweight, r2pred = build_closure(g, obs_nodes, debug=debug, verbose=verbose) # print('gc', gc) tree_map = min_spanning_tree(gc, eweight, root=None) tree = GraphView(gc, directed=False, efilt=tree_map) tree_edges = set() # print('tree', tree) for e in tree.edges(): u, v = map(int, e) recovered_edges = extract_edges_from_pred(u, v, r2pred[u]) assert recovered_edges, 'empty!' for i, j in recovered_edges: tree_edges.add(((i, j))) tree_nodes = list(set(itertools.chain(*tree_edges))) vfilt = g.new_vertex_property('bool') vfilt.set_value(False) for n in tree_nodes: vfilt[n] = True efilt = g.new_edge_property('bool') for i, j in tree_edges: efilt[g.edge(i, j)] = 1 return GraphView(g, efilt=efilt, vfilt=vfilt)
def ratio_of_typed_subjects(D, edge_labels=np.empty(0), stats=dict(), print_stats=False): """ (1) number of all different typed subjects (2) ratio of typed subjects """ if edge_labels is None or edge_labels.size == 0: edge_labels = np.array([D.ep.c0[p] for p in D.get_edges()]) # ae98476863dc6ec5 = http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf_type = hash('ae98476863dc6ec5') S_C_G = GraphView(D, efilt=edge_labels == rdf_type) S_C_G = np.unique(S_C_G.get_edges()[:, 0]) if print_stats: print("number of different typed subjects S^{C}_G: %s" % S_C_G.size) S_G = GraphView(D, vfilt=D.get_out_degrees(D.get_vertices())) if print_stats: print("ratio of typed subjects r_T(G): %s" % (float(S_C_G.size) / S_G.num_vertices())) stats['typed_subjects'], stats['ratio_of_typed_subjects'] = S_C_G.size, ( float(S_C_G.size) / S_G.num_vertices()) return S_C_G
def solve(g): if g.num_vertices() == 0: W0 = self.pg.new_vertex_property("bool") W1 = self.pg.new_vertex_property("bool") return {0: W0, 1: W1} else: p = self.maxparity(g) i = p % 2 U = self.vertices_with_priority(g, p) A = self.attractor(U, i) # get i attractor of U in g WW = solve(GraphView(g, vfilt=self.complement(A))) #if WW[1-i].ma.all(): ## does not work gg = GraphView(g, vfilt=WW[1 - i]) # just to check emptiness if gg.num_vertices() == 0: res = {} res[i] = self.maskplus(g, WW[i], A) res[1 - i] = WW[1 - i] return res else: B = self.attractor(WW[1 - i], 1 - i) gg = GraphView(g, vfilt=self.complement(B)) WW = solve(gg) res = {} res[i] = WW[i] res[1 - i] = self.maskplus(g, WW[1 - i], B) return res
def min_steiner_tree(g, obs_nodes, p=None, return_type='tree', debug=False, verbose=False): assert len(obs_nodes) > 0, 'no terminals' if g.num_vertices() == len(obs_nodes): print('it\'s a minimum spanning tree problem') gc, eweight, r2pred = build_closure(g, obs_nodes, p=p, debug=debug, verbose=verbose) # print('gc', gc) tree_map = min_spanning_tree(gc, eweight, root=None) tree = GraphView(gc, directed=False, efilt=tree_map) tree_edges = set() for e in tree.edges(): u, v = map(int, e) recovered_edges = extract_edges_from_pred(u, v, r2pred[u]) assert recovered_edges, 'empty!' for i, j in recovered_edges: tree_edges.add((i, j)) tree_nodes = list(set(itertools.chain(*tree_edges))) if return_type == 'nodes': return tree_nodes elif return_type == 'edges': return list(map(edge2tuple, tree_edges)) elif return_type == 'tree': vfilt = g.new_vertex_property('bool') vfilt.set_value(False) for n in tree_nodes: vfilt[n] = True efilt = g.new_edge_property('bool') for i, j in tree_edges: efilt[g.edge(i, j)] = 1 subg = GraphView(g, efilt=efilt, vfilt=vfilt, directed=False) if p is not None: weights = subg.new_edge_property('float') for e in subg.edges(): weights[e] = p[e] else: weights = None # remove cycles tree_map = min_spanning_tree(subg, weights, root=None) t = GraphView(g, directed=False, vfilt=vfilt, efilt=tree_map) return t
def test_fill_missing_time(): """simple chain graph test """ g = Graph(directed=False) g.add_vertex(4) g.add_edge_list([(0, 1), (1, 2), (2, 3)]) t = GraphView(g, directed=True) efilt = t.new_edge_property('bool') efilt.a = True efilt[t.edge(2, 3)] = False t.set_edge_filter(efilt) vfilt = t.new_vertex_property('bool') vfilt.a = True vfilt[3] = False t.set_vertex_filter(vfilt) root = 0 obs_nodes = {0, 2} infection_times = [0, 1.5, 3, -1] pt = fill_missing_time(g, t, root, obs_nodes, infection_times, debug=False) for i in range(4): assert pt[i] == infection_times[i]
def new_function(eptm, *args, **kwargs): from .epithelium import Epithelium from graph_tool import Graph, GraphView local_graph = Graph(GraphView(eptm.graph, vfilt=eptm.is_local_vert, efilt=eptm.is_local_edge), prune=True) local_eptm = Epithelium(paramtree=eptm.paramtree, graph=local_graph) # if local_eptm.at_boundary.fa.sum() > 0: # local_eptm.rotate(np.pi) # local_eptm.current_angle = np.pi # print('rotated') out = meth(local_eptm, *args, **kwargs) # if not -1e-8 < local_eptm.current_angle < 1e-8: # local_eptm.rotate(-local_eptm.current_angle) # local_eptm.current_angle = 0. # print( 'rotated back') eptm.graph.set_vertex_filter(eptm.is_local_vert) eptm.graph.set_edge_filter(eptm.is_local_edge) for key, val in local_eptm.graph.vertex_properties.items(): eptm.graph.vertex_properties[key].fa = val.a for key, val in local_eptm.graph.edge_properties.items(): eptm.graph.edge_properties[key].fa = val.a eptm.graph.set_vertex_filter(None) eptm.graph.set_edge_filter(None) eptm.reset_topology() return out
def save(self, file_name, fmt="auto"): """ overload Graph.save to make output dotfiles pretty. This is entirely cosmetic. """ u = self # add some properties to prettify dot output if fmt is "dot" or fmt is "auto" and file_name.endswith(".dot"): u = GraphView(self) # add shape property according to vertex owners shape = u.new_vertex_property("string") for v in u.vertices(): if u.vp.owner[v] == 1: shape[v] = "box" else: shape[v] = "diamond" u.vp.shape = shape # add label property according to priorities #u.vertex_properties['label'] = u.vertex_properties['priority'] label = u.new_vertex_property("string") for v in u.vertices(): prio = u.vertex_properties['priority'][v] name = u.vertex_index[v] label[v] = "%d (%d)" % (name, prio) u.vp.label = label Graph.save(u, file_name, fmt)
def egonets(graph, direction): egonets = dict() for node in graph.vertices(): mask = graph.new_vertex_property("bool") for u in node.out_neighbours(): mask[u] = True mask[node] = True label_node = graph.vertex_properties["name"][node] egonets[label_node] = GraphView(graph, vfilt=mask) return egonets
def egoNetwork(inGraph, node): ''' Compute the ego-network subgraph of the -inGraph- where the ego is the -node-. Precondition: inGraph is undirected ''' neighbors = [int(n) for n in node.out_neighbours()] neighborhood = inGraph.new_vertex_property("bool") neighborhood.a[neighbors] = 1 neighborhood.a[int(node)] = 1 return GraphView(inGraph, vfilt=neighborhood)
def produce_answer(entry, g, prune): qc_fltr = g.new_vertex_property("bool") qc_fltr = make_filter(g, entry.qc, qc_fltr) qg = GraphView(g, qc_fltr) qg = Graph(qg, prune=prune) best_score = 0.0 answer = -1 for i, ac in enumerate(entry.ac): ac_fltr = g.new_vertex_property("bool") ac_fltr = None #make_filter(g, ac, ac_fltr) ag = GraphView(g, ac_fltr) ag = Graph(ag, prune=prune) score = reason_over_paths(qg, ag) if score > best_score: best_score = score answer = i del ac_fltr del qc_fltr return answer
def observe_cascade(c, source, q, method='uniform', tree=None, source_includable=False): """ given a cascade `c` and `source`, return a list of observed nodes according to probability `q` """ all_infection = np.nonzero(c != -1)[0] if not source_includable: all_infection = list(set(all_infection) - {source}) num_obs = int(math.ceil(len(all_infection) * q)) if num_obs < 2: num_obs = 2 if method == 'uniform': return np.random.permutation(all_infection)[:num_obs] elif method == 'late': return np.argsort(c)[-num_obs:] elif method == 'leaves': assert tree is not None, 'to get the leaves, the cascade tree is required' # extract_steiner_tree(tree, ) nodes_in_order = reverse_bfs(tree) return nodes_in_order[:num_obs] elif method == 'bfs-head': assert tree is not None, 'the cascade tree is required' vis = BFSNodeCollector() bfs_search(GraphView(tree, directed=False), source, vis) sampling_weights_by_order vis.nodes_in_order return vis.nodes_in_order[:num_obs] # head elif method == 'bfs-tail': assert tree is not None, 'the cascade tree is required' vis = BFSNodeCollector() bfs_search(GraphView(tree, directed=False), source, vis) return vis.nodes_in_order[-num_obs:] # tail else: raise ValueError('unknown method {}'.format(method))
def global_clustering_binary_undirected(g): ''' Returns the undirected global clustering coefficient. This corresponds to the ratio of undirected triangles to the number of undirected triads. Parameters ---------- g : :class:`~nngt.Graph` Graph to analyze. References ---------- .. [gt-global-clustering] :gtdoc:`clustering.global_clustering` ''' # use undirected graph view, filter parallel edges u = GraphView(g.graph, directed=False) u = GraphView(u, efilt=label_parallel_edges(u).fa == 0) return gtc.global_clustering(u, weight=None)[0]
def draw_community(gml_fn, output, layout_name=None, layout_kwargs=dict(), **draw_kwargs): g = load_graph(gml_fn) # Sampel of graph g # g = GraphView(g, vfilt=lambda v: g.vertex_index[v]%2==0) g.vp['wdeg'] = g.degree_property_map('total', weight=g.ep['weight']) # g = GraphView(g, vfilt=lambda v: g.vp['wdeg'][v]>0) # label for hub account only in each community g.vp['clabel'] = g.new_vertex_property("string", val="") for c in np.nditer(np.unique(g.vp['community'].a)): cg = GraphView(g, vfilt=(g.vp['community'].a == c)) v_hub = find_vertex(cg, cg.vp['wdeg'], cg.vp['wdeg'].fa.max())[0] cg.vp['clabel'][v_hub] = cg.vp['screenname'][v_hub] v_size = prop_to_size( g.vp['wdeg'], mi=MIN_V_SIZE, ma=MAX_V_SIZE, log=V_SIZE_LOG, power=V_SIZE_POWER) e_width = prop_to_size( g.ep['weight'], mi=MIN_E_WIDTH, ma=MAX_E_WIDTH, log=E_WIDTH_LOG, power=E_WIDTH_POWER) if layout_name is not None: try: pos = globals()[layout_name](g, **layout_kwargs) except KeyError as e: logger.critical('No such layout function found!') raise graph_draw( g, pos, output=output, vprops=dict( fill_color=g.vp['community'], # color='grey', size=v_size, pen_width=0.01, text=g.vp['clabel'], text_position='centered', font_size=8,), eprops=dict( pen_width=e_width, end_marker="arrow",), **draw_kwargs)
def is_tree(tree): # is tree? l, _ = label_components(GraphView(tree, directed=False)) if not np.all(np.array(l.a) == 0): print('not connected') print(np.array(l.a)) return False if tree.num_edges() != (tree.num_vertices() - 1): print('n. edges != n. nodes - 1') return False return True
def get(self, args): from depth_first_searcher import dfs_search_with_limit root = int(args["root"]) limit = int(args["limit"]) vertices = dfs_search_with_limit(graph, graph.vertex(root), limit) v_filter = graph.new_vertex_property('bool') for v in vertices: v_filter[v] = True subgraph = GraphView(graph, v_filter) from graph_tool.stats import remove_parallel_edges remove_parallel_edges(subgraph) subgraph = self.set_properties(subgraph) from graph_json_builder import create_json_graph return create_json_graph(subgraph)
def fs_digraph_using_basic_properties(D, stats, options={'features': []}): """""" # at least one of these features needed to continue if len([ f for f in ['degree', 'parallel_edges', 'fill'] if f in options['features'] ]) == 0: return # feature: order num_vertices = D.num_vertices() log.debug('done order') # feature: size num_edges = D.num_edges() log.debug('done size') stats['n'] = num_vertices stats['m'] = num_edges # feature: mean_degree if 'degree' in options['features']: stats['mean_degree'] = float(2 * num_edges) / num_vertices log.debug('done mean_degree') # feature: fill_overall if 'fill' in options['features']: stats['fill_overall'] = float(num_edges) / (num_vertices * num_vertices) log.debug('done fill_overall') if 'parallel_edges' in options['features'] or 'fill' in options['features']: eprop = label_parallel_edges(D, mark_only=True) PE = GraphView(D, efilt=eprop) num_edges_PE = PE.num_edges() stats['m_unique'] = num_edges - num_edges_PE # feature: parallel_edges if 'parallel_edges' in options['features']: stats['parallel_edges'] = num_edges_PE log.debug('done parallel_edges') # feature: fill if 'fill' in options['features']: stats['fill'] = float(num_edges - num_edges_PE) / (num_vertices * num_vertices) log.debug('done fill')
def is_tree(t): # to undirected t = GraphView(t, directed=False) # num nodes = num edges+1 if t.num_vertices() != (t.num_edges() + 1): return False # all nodes have degree > 0 vs = list(map(int, t.vertices())) degs = t.degree_property_map('out').a[vs] if np.all(degs > 0) == 0: return False return True
def sample_graph_by_p(g, p): """ for IC model graph_tool version of sampling a graph mask the edge according to probability p and return the masked graph g: the graph p: float or np.array """ if isinstance(p, PropertyMap): p = p.a flags = (np.random.random(p.shape) <= p) p = g.new_edge_property('bool') p.set_2d_array(flags) return GraphView(g, efilt=p)
def remove_filters(g): """ remove all filters and add filter with all entries on so that we won't get null vertex_filter or edge_filter """ efilt = g.new_edge_property('bool') efilt.a = True vfilt = g.new_vertex_property('bool') vfilt.a = True # print('making GraphView started') gv = GraphView(g, efilt=efilt, vfilt=vfilt, directed=g.is_directed()) # print('making GraphView done') return gv
def remove_redundant_edges_from_tree(g, tree, r, terminals): """given a set of edges, a root, and terminals to cover, return a new tree with redundant edges removed""" efilt = g.new_edge_property('bool') for u, v in tree: efilt[g.edge(u, v)] = True tree = GraphView(g, efilt=efilt) # remove redundant edges min_tree_efilt = g.new_edge_property('bool') min_tree_efilt.set_2d_array(np.zeros(g.num_edges())) for o in terminals: if o != r: tree.vertex(r) tree.vertex(o) _, edge_list = shortest_path(tree, source=tree.vertex(r), target=tree.vertex(o)) assert len(edge_list) > 0, 'unable to reach {} from {}'.format( o, r) for e in edge_list: min_tree_efilt[e] = True min_tree = GraphView(g, efilt=min_tree_efilt) return min_tree
def filter_graph_by_edges(g, edges): """returns GraphView """ efilt = g.new_edge_property('bool') efilt.set_value(False) for i, j in edges: efilt[g.edge(i, j)] = True vfilt = g.new_vertex_property('bool') vfilt.set_value(False) for e in edges: for u in e: vfilt[u] = True return GraphView(g, efilt=efilt, vfilt=vfilt)
def get_subgraph(self, vertices, genes=False): r''' Return the subgraph of self induced by the given vertices. Args: vertices: a set of vertex IDs (or a set of genes) genes: a boolean with value `True` if `vertices` is a set of genes and `False` if it is a set of vertex IDs. Returns: :math:`\Delta_{\text{vertices}}(G)` ''' if genes: vertices = self.verts_id(vertices) filt = self.G.new_vertex_property('bool') filt.a[vertices] = True return GraphView(self.G, vfilt=filt)
def f_pseudo_diameter( D, stats, options={ 'features': [] } ): """""" LC = label_largest_component(D) LCD = GraphView( D, vfilt=LC ) if 'diameter' in options['features']: if LCD.num_vertices() == 0 or LCD.num_vertices() == 1: # if largest component does practically not exist, use the whole graph dist, ends = pseudo_diameter(D) else: dist, ends = pseudo_diameter(LCD) stats['pseudo_diameter']=dist # D may be used in both cases stats['pseudo_diameter_src_vertex']=D.vertex_properties['name'][ends[0]] stats['pseudo_diameter_trg_vertex']=D.vertex_properties['name'][ends[1]] log.debug( 'done pseudo_diameter' )
def get_steiner_tree(g, root, obs_nodes, debug=False, verbose=False): gc, eweight, r2pred = build_closure(g, obs_nodes, debug=debug, verbose=verbose) tree_map = min_spanning_tree(gc, eweight, root=None) tree = GraphView(gc, directed=False, efilt=tree_map) tree_edges = set() for e in tree.edges(): u, v = map(int, e) for i, j in extract_edges_from_pred(g, u, v, r2pred[u]): tree_edges.add((j, i)) # a bit involved... und_tree = edges_to_directed_tree(g, root, tree_edges) return build_minimum_tree(g, root, obs_nodes, extract_edges(und_tree))
def is_arborescence(tree): # is tree? l, _ = label_components(GraphView(tree, directed=False)) if not np.all(np.array(l.a) == 0): print('not connected') print(np.array(l.a)) return False in_degs = np.array([v.in_degree() for v in tree.vertices()]) if in_degs.max() > 1: print('in_degree.max() > 1') return False if np.sum(in_degs == 1) != (tree.num_vertices() - 1): print('should be: only root has no parent') return False roots = get_roots(tree) assert len(roots) == 1, '>1 roots' return True
def number_of_classes(D, edge_labels=np.empty(0), stats=dict(), print_stats=False): """counts the number of different classes""" if edge_labels is None or edge_labels.size == 0: edge_labels = np.array([D.ep.c0[p] for p in D.get_edges()]) # ae98476863dc6ec5 = http://www.w3.org/1999/02/22-rdf-syntax-ns#type rdf_type = hash('ae98476863dc6ec5') C_G = GraphView(D, efilt=edge_labels == rdf_type) C_G = np.unique(C_G.get_edges()[:, 1]) if print_stats: print("number of different classes C_G: %s" % C_G.size) stats['distinct_classes'] = C_G.size return C_G
def is_order_respected(tree, root, obs_nodes, infection_times): tree = GraphView(tree) obs_set = set(obs_nodes) vfilt = tree.new_vertex_property('bool') vfilt.a = True tree.set_vertex_filter(vfilt) leaves = [o for o in obs_nodes if tree.vertex(o).out_degree() == 0] vis = init_visitor(tree, root) pbfs_search(tree, root, terminals=leaves, visitor=vis, count_threshold=-1) for l in leaves: edges = extract_edges_from_pred(tree, root, l, vis.pred) edges = edges[::-1] path = list(edges[0]) + [u for _, u in edges[1:]] useful_nodes_on_path = [v for v in path if v in obs_set] for i in range(len(useful_nodes_on_path)-1): u, v = useful_nodes_on_path[i: i+2] if infection_times[u] > infection_times[v]: return False return True
def extract_tree(g, source, pred, terminals=None): """return a tree from source to terminals based on `pred`""" edges = set() if terminals: visited = set() for t in sorted(terminals): c = t while c != source and c not in visited: visited.add(c) if pred[c] != -1: edges.add((pred[c], c)) c = pred[c] else: break else: for c, p in enumerate(pred.a): if p != -1: edges.add((c, p)) efilt = g.new_edge_property('bool') for u, v in edges: efilt[g.edge(g.vertex(u), g.vertex(v))] = 1 return GraphView(g, efilt=efilt)
def repeated_predicate_lists(D, edge_labels=np.empty(0), stats=dict(), print_stats=False, return_collected=True): """""" if edge_labels is None or edge_labels.size == 0: edge_labels = [D.ep.c0[p] for p in D.get_edges()] # filter those vertices v | out-degree(v) > 0 S = GraphView(D, vfilt=D.get_out_degrees(D.get_vertices())) # .. is defined as the ratio of repeated predicate lists from the total lists in the graph G df = pd.DataFrame(data=list(zip(D.get_edges()[:, 0], edge_labels)), index=np.arange(0, D.get_edges().shape[0]), columns=np.arange(0, D.get_edges().shape[1])) df = df.groupby(0)[1].apply(tuple).apply(hash).to_frame().reset_index() if return_collected: df = df.groupby(1).count()[0] if print_stats: print("(Eq.17) ratio of repeated predicate lists r_L(G): %f" % (1 - (df.size / S.num_vertices()))) print( "(Eq.18/19) predicate list degree deg_{PL}(G). max: %f, mean: %f" % (df.max(), df.mean())) stats['repeated_predicate_lists'] = 1 - (df.size / S.num_vertices()) stats['max_predicate_list_degree'], stats[ 'mean_predicate_list_degree'] = df.max(), df.mean() return df