예제 #1
0
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_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_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)
예제 #6
0
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_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))
예제 #8
0
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)))
예제 #9
0
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)
예제 #11
0
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)
예제 #12
0
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)
예제 #13
0
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)
예제 #14
0
    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)
예제 #15
0
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
예제 #17
0
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
예제 #18
0
def part2(graph):
    subgraphs = list(nx.k_edge_subgraphs(graph, 1))
    return len(subgraphs)