def test_triangles(): paths = [ (11, 12, 13, 11), # first 3-clique (21, 22, 23, 21), # second 3-clique (11, 21), # connected by an edge ] G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) # subgraph and ccs are the same in all cases here assert_equal( fset(nx.k_edge_components(G, k=1)), fset(nx.k_edge_subgraphs(G, k=1)) ) assert_equal( fset(nx.k_edge_components(G, k=2)), fset(nx.k_edge_subgraphs(G, k=2)) ) assert_equal( fset(nx.k_edge_components(G, k=3)), fset(nx.k_edge_subgraphs(G, k=3)) ) _check_edge_connectivity(G)
def test_five_clique(): # Make a graph that can be disconnected less than 4 edges, but no node has # degree less than 4. G = nx.disjoint_union(nx.complete_graph(5), nx.complete_graph(5)) paths = [ # add aux-connections (1, 100, 6), (2, 100, 7), (3, 200, 8), (4, 200, 100), ] G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) assert min(dict(nx.degree(G)).values()) == 4 # For k=3 they are the same assert fset(nx.k_edge_components(G, k=3)) == fset(nx.k_edge_subgraphs(G, k=3)) # For k=4 they are the different # the aux nodes are in the same CC as clique 1 but no the same subgraph assert fset(nx.k_edge_components(G, k=4)) != fset( nx.k_edge_subgraphs(G, k=4)) # For k=5 they are not the same assert fset(nx.k_edge_components(G, k=5)) != fset( nx.k_edge_subgraphs(G, k=5)) # For k=6 they are the same assert fset(nx.k_edge_components(G, k=6)) == fset(nx.k_edge_subgraphs(G, k=6)) _check_edge_connectivity(G)
def test_local_subgraph_difference_directed(): dipaths = [ (1, 2, 3, 4, 1), (1, 3, 1), ] G = nx.DiGraph(it.chain(*[pairwise(path) for path in dipaths])) assert_equal( fset(nx.k_edge_components(G, k=1)), fset(nx.k_edge_subgraphs(G, k=1)) ) # Unlike undirected graphs, when k=2, for directed graphs there is a case # where the k-edge-ccs are not the same as the k-edge-subgraphs. # (in directed graphs ccs and subgraphs are the same when k=2) assert_not_equal( fset(nx.k_edge_components(G, k=2)), fset(nx.k_edge_subgraphs(G, k=2)) ) assert_equal( fset(nx.k_edge_components(G, k=3)), fset(nx.k_edge_subgraphs(G, k=3)) ) _check_edge_connectivity(G)
def test_undirected_aux_graph(): # Graph similar to the one in # http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 a, b, c, d, e, f, g, h, i = 'abcdefghi' paths = [(a, d, b, f, c), (a, e, b), (a, e, b, c, g, b, a), (c, b), (f, g, f), (h, i)] G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) aux_graph = EdgeComponentAuxGraph.construct(G) components_1 = fset(aux_graph.k_edge_subgraphs(k=1)) target_1 = fset([{a, b, c, d, e, f, g}, {h, i}]) assert_equal(target_1, components_1) # Check that the undirected case for k=1 agrees with CCs alt_1 = fset(nx.k_edge_subgraphs(G, k=1)) assert_equal(alt_1, components_1) components_2 = fset(aux_graph.k_edge_subgraphs(k=2)) target_2 = fset([{a, b, c, d, e, f, g}, {h}, {i}]) assert_equal(target_2, components_2) # Check that the undirected case for k=2 agrees with bridge components alt_2 = fset(nx.k_edge_subgraphs(G, k=2)) assert_equal(alt_2, components_2) components_3 = fset(aux_graph.k_edge_subgraphs(k=3)) target_3 = fset([{a}, {b, c, f, g}, {d}, {e}, {h}, {i}]) assert_equal(target_3, components_3) components_4 = fset(aux_graph.k_edge_subgraphs(k=4)) target_4 = fset([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) assert_equal(target_4, components_4) _check_edge_connectivity(G)
def test_empty_input(): G = nx.Graph() assert [] == list(nx.k_edge_components(G, k=5)) assert [] == list(nx.k_edge_subgraphs(G, k=5)) G = nx.DiGraph() assert [] == list(nx.k_edge_components(G, k=5)) assert [] == list(nx.k_edge_subgraphs(G, k=5))
def test_empty_input(): G = nx.Graph() assert_equal([], list(nx.k_edge_components(G, k=5))) assert_equal([], list(nx.k_edge_subgraphs(G, k=5))) G = nx.DiGraph() assert_equal([], list(nx.k_edge_components(G, k=5))) assert_equal([], list(nx.k_edge_subgraphs(G, k=5)))
def combine_connected_subclusters(mcl_subclusters, mcl_groups_to_combine): """ Creates a graph to identify all connected subclusters with each other and returns the nested array of clusters with their respective subclusters. """ mcl_cluster_connection_graph = nx.Graph() mcl_cluster_connection_graph.add_edges_from(mcl_groups_to_combine) connected_subclusters = [] for new_cluster in nx.k_edge_subgraphs(mcl_cluster_connection_graph, k=1): connected_subclusters.append( [mcl_subclusters[a]["mcl_subcluster"] for a in new_cluster]) assert len(list(nx.k_edge_subgraphs( mcl_cluster_connection_graph, k=1))) == len(connected_subclusters), "Combining went wrong" return connected_subclusters
def test_four_clique(): paths = [ (11, 12, 13, 14, 11, 13, 14, 12), # first 4-clique (21, 22, 23, 24, 21, 23, 24, 22), # second 4-clique # paths connecting the 4 cliques such that they are # 3-connected in G, but not in the subgraph. # Case where the nodes bridging them do not have degree less than 3. (100, 13), (12, 100, 22), (13, 200, 23), (14, 300, 24), ] G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) # The subgraphs and ccs are different for k=3 local_ccs = fset(nx.k_edge_components(G, k=3)) subgraphs = fset(nx.k_edge_subgraphs(G, k=3)) assert local_ccs != subgraphs # The cliques ares in the same cc clique1 = frozenset(paths[0]) clique2 = frozenset(paths[1]) assert clique1.union(clique2).union({100}) in local_ccs # but different subgraphs assert clique1 in subgraphs assert clique2 in subgraphs assert G.degree(100) == 3 _check_edge_connectivity(G)
def test_four_clique(): paths = [ (11, 12, 13, 14, 11, 13, 14, 12), # first 4-clique (21, 22, 23, 24, 21, 23, 24, 22), # second 4-clique # paths connecting the 4 cliques such that they are # 3-connected in G, but not in the subgraph. # Case where the nodes bridging them do not have degree less than 3. (100, 13), (12, 100, 22), (13, 200, 23), (14, 300, 24), ] G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) # The subgraphs and ccs are different for k=3 local_ccs = fset(nx.k_edge_components(G, k=3)) subgraphs = fset(nx.k_edge_subgraphs(G, k=3)) assert_not_equal(local_ccs, subgraphs) # The cliques ares in the same cc clique1 = frozenset(paths[0]) clique2 = frozenset(paths[1]) assert_in(clique1.union(clique2).union({100}), local_ccs) # but different subgraphs assert_in(clique1, subgraphs) assert_in(clique2, subgraphs) assert_equal(G.degree(100), 3) _check_edge_connectivity(G)
def test_undirected_aux_graph(): # Graph similar to the one in # http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 a, b, c, d, e, f, g, h, i = 'abcdefghi' paths = [ (a, d, b, f, c), (a, e, b), (a, e, b, c, g, b, a), (c, b), (f, g, f), (h, i) ] G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) aux_graph = EdgeComponentAuxGraph.construct(G) components_1 = fset(aux_graph.k_edge_subgraphs(k=1)) target_1 = fset([{a, b, c, d, e, f, g}, {h, i}]) assert_equal(target_1, components_1) # Check that the undirected case for k=1 agrees with CCs alt_1 = fset(nx.k_edge_subgraphs(G, k=1)) assert_equal(alt_1, components_1) components_2 = fset(aux_graph.k_edge_subgraphs(k=2)) target_2 = fset([{a, b, c, d, e, f, g}, {h}, {i}]) assert_equal(target_2, components_2) # Check that the undirected case for k=2 agrees with bridge components alt_2 = fset(nx.k_edge_subgraphs(G, k=2)) assert_equal(alt_2, components_2) components_3 = fset(aux_graph.k_edge_subgraphs(k=3)) target_3 = fset([{a}, {b, c, f, g}, {d}, {e}, {h}, {i}]) assert_equal(target_3, components_3) components_4 = fset(aux_graph.k_edge_subgraphs(k=4)) target_4 = fset([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) assert_equal(target_4, components_4) _check_edge_connectivity(G)
def test_five_clique(): # Make a graph that can be disconnected less than 4 edges, but no node has # degree less than 4. G = nx.disjoint_union(nx.complete_graph(5), nx.complete_graph(5)) paths = [ # add aux-connections (1, 100, 6), (2, 100, 7), (3, 200, 8), (4, 200, 100), ] G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) assert_equal(min(dict(nx.degree(G)).values()), 4) # For k=3 they are the same assert_equal( fset(nx.k_edge_components(G, k=3)), fset(nx.k_edge_subgraphs(G, k=3)) ) # For k=4 they are the different # the aux nodes are in the same CC as clique 1 but no the same subgraph assert_not_equal( fset(nx.k_edge_components(G, k=4)), fset(nx.k_edge_subgraphs(G, k=4)) ) # For k=5 they are not the same assert_not_equal( fset(nx.k_edge_components(G, k=5)), fset(nx.k_edge_subgraphs(G, k=5)) ) # For k=6 they are the same assert_equal( fset(nx.k_edge_components(G, k=6)), fset(nx.k_edge_subgraphs(G, k=6)) ) _check_edge_connectivity(G)
def clusterDetection(self, customParams): """ Group the variants based on a given threshold; to do so, edges with a weight above the threshold are deleted from the given graph respresenting the optimal mappings :param customParams: custom parameter object containing the threshold the algorithm should use :return: list of subgraphs where each subgraph represents a cluster of variants """ horizontalTreshold = customParams.getHorizontalThreshold() #filteredEdges = [(u, v) for (u, v, d) in self.__G.edges(data=True) if (d['weight'] > horizontalTreshold and d['weight'] != -1)] filteredEdges = [ (u, v) for (u, v, d) in self.__G.edges(data=True) if (d['weight'] > horizontalTreshold and d['weight'] != -1 or d['weight'] == -42) ] self.__G.remove_edges_from(filteredEdges) return [ nx.Graph(self.__G.subgraph(c)) for c in nx.k_edge_subgraphs(self.__G, k=1) ] #or also use nx.connected_components(G)
def part2(grid): graph = nx.Graph() # Build graph for x in range(128): for y in range(128): if grid[x][y]: graph.add_node((x, y)) # Iterate over graph and add edges between adjacent nodes for x in range(128): for y in range(128): if not graph.has_node((x, y)): continue up = (x, y - 1) down = (x, y + 1) left = (x - 1, y) right = (x + 1, y) if graph.has_node(up): graph.add_edge((x, y), up) if graph.has_node(down): graph.add_edge((x, y), down) if graph.has_node(left): graph.add_edge((x, y), left) if graph.has_node(right): graph.add_edge((x, y), right) # Find the islands subgraphs = list(nx.k_edge_subgraphs(graph, 1)) return len(subgraphs)
def partial_k_edge_augmentation(G, k, avail, weight=None): """Finds augmentation that k-edge-connects as much of the graph as possible. When a k-edge-augmentation is not possible, we can still try to find a small set of edges that partially k-edge-connects as much of the graph as possible. All possible edges are generated between remaining parts. This minimizes the number of k-edge-connected subgraphs in the resulting graph and maxmizes the edge connectivity between those subgraphs. Parameters ---------- G : NetworkX graph An undirected graph. k : integer Desired edge connectivity avail : dict or a set of 2 or 3 tuples For more details, see :func:`k_edge_augmentation`. weight : string key to use to find weights if ``avail`` is a set of 3-tuples. For more details, see :func:`k_edge_augmentation`. Yields ------ edge : tuple Edges in the partial augmentation of G. These edges k-edge-connect any part of G where it is possible, and maximally connects the remaining parts. In other words, all edges from avail are generated except for those within subgraphs that have already become k-edge-connected. Notes ----- Construct H that augments G with all edges in avail. Find the k-edge-subgraphs of H. For each k-edge-subgraph, if the number of nodes is more than k, then find the k-edge-augmentation of that graph and add it to the solution. Then add all edges in avail between k-edge subgraphs to the solution. See Also -------- :func:`k_edge_augmentation` Example ------- >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) >>> G.add_node(8) >>> avail = [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5), (1, 8)] >>> sorted(partial_k_edge_augmentation(G, k=2, avail=avail)) [(1, 5), (1, 8)] """ def _edges_between_disjoint(H, only1, only2): """ finds edges between disjoint nodes """ only1_adj = {u: set(H.adj[u]) for u in only1} for u, neighbs in only1_adj.items(): # Find the neighbors of u in only1 that are also in only2 neighbs12 = neighbs.intersection(only2) for v in neighbs12: yield (u, v) avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) # Find which parts of the graph can be k-edge-connected H = G.copy() H.add_edges_from(((u, v, { 'weight': w, 'generator': (u, v) }) for (u, v), w in zip(avail, avail_w))) k_edge_subgraphs = list(nx.k_edge_subgraphs(H, k=k)) # Generate edges to k-edge-connect internal subgraphs for nodes in k_edge_subgraphs: if len(nodes) > 1: # Get the k-edge-connected subgraph C = H.subgraph(nodes).copy() # Find the internal edges that were available sub_avail = { d['generator']: d['weight'] for (u, v, d) in C.edges(data=True) if 'generator' in d } # Remove potential augmenting edges C.remove_edges_from(sub_avail.keys()) # Find a subset of these edges that makes the compoment # k-edge-connected and ignore the rest for edge in nx.k_edge_augmentation(C, k=k, avail=sub_avail): yield edge # Generate all edges between CCs that could not be k-edge-connected for cc1, cc2 in it.combinations(k_edge_subgraphs, 2): for (u, v) in _edges_between_disjoint(H, cc1, cc2): d = H.get_edge_data(u, v) edge = d.get('generator', None) if edge is not None: yield edge
def partial_k_edge_augmentation(G, k, avail, weight=None): """Finds augmentation that k-edge-connects as much of the graph as possible. When a k-edge-augmentation is not possible, we can still try to find a small set of edges that partially k-edge-connects as much of the graph as possible. All possible edges are generated between remaining parts. This minimizes the number of k-edge-connected subgraphs in the resulting graph and maxmizes the edge connectivity between those subgraphs. Parameters ---------- G : NetworkX graph An undirected graph. k : integer Desired edge connectivity avail : dict or a set of 2 or 3 tuples For more details, see :func:`k_edge_augmentation`. weight : string key to use to find weights if ``avail`` is a set of 3-tuples. For more details, see :func:`k_edge_augmentation`. Yields ------ edge : tuple Edges in the partial augmentation of G. These edges k-edge-connect any part of G where it is possible, and maximally connects the remaining parts. In other words, all edges from avail are generated except for those within subgraphs that have already become k-edge-connected. Notes ----- Construct H that augments G with all edges in avail. Find the k-edge-subgraphs of H. For each k-edge-subgraph, if the number of nodes is more than k, then find the k-edge-augmentation of that graph and add it to the solution. Then add all edges in avail between k-edge subgraphs to the solution. See Also -------- :func:`k_edge_augmentation` Example ------- >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) >>> G.add_node(8) >>> avail = [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5), (1, 8)] >>> sorted(partial_k_edge_augmentation(G, k=2, avail=avail)) [(1, 5), (1, 8)] """ def _edges_between_disjoint(H, only1, only2): """ finds edges between disjoint nodes """ only1_adj = {u: set(H.adj[u]) for u in only1} for u, neighbs in only1_adj.items(): # Find the neighbors of u in only1 that are also in only2 neighbs12 = neighbs.intersection(only2) for v in neighbs12: yield (u, v) avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) # Find which parts of the graph can be k-edge-connected H = G.copy() H.add_edges_from( ((u, v, {'weight': w, 'generator': (u, v)}) for (u, v), w in zip(avail, avail_w))) k_edge_subgraphs = list(nx.k_edge_subgraphs(H, k=k)) # Generate edges to k-edge-connect internal subgraphs for nodes in k_edge_subgraphs: if len(nodes) > 1: # Get the k-edge-connected subgraph C = H.subgraph(nodes).copy() # Find the internal edges that were available sub_avail = { d['generator']: d['weight'] for (u, v, d) in C.edges(data=True) if 'generator' in d } # Remove potential augmenting edges C.remove_edges_from(sub_avail.keys()) # Find a subset of these edges that makes the compoment # k-edge-connected and ignore the rest for edge in nx.k_edge_augmentation(C, k=k, avail=sub_avail): yield edge # Generate all edges between CCs that could not be k-edge-connected for cc1, cc2 in it.combinations(k_edge_subgraphs, 2): for (u, v) in _edges_between_disjoint(H, cc1, cc2): d = H.get_edge_data(u, v) edge = d.get('generator', None) if edge is not None: yield edge
def part2(graph): subgraphs = list(nx.k_edge_subgraphs(graph, 1)) return len(subgraphs)