| | """Functions related to graph covers.""" |
| |
|
| | from functools import partial |
| | from itertools import chain |
| |
|
| | import networkx as nx |
| | from networkx.utils import arbitrary_element, not_implemented_for |
| |
|
| | __all__ = ["min_edge_cover", "is_edge_cover"] |
| |
|
| |
|
| | @not_implemented_for("directed") |
| | @not_implemented_for("multigraph") |
| | @nx._dispatchable |
| | def min_edge_cover(G, matching_algorithm=None): |
| | """Returns the min cardinality edge cover of the graph as a set of edges. |
| | |
| | A smallest edge cover can be found in polynomial time by finding |
| | a maximum matching and extending it greedily so that all nodes |
| | are covered. This function follows that process. A maximum matching |
| | algorithm can be specified for the first step of the algorithm. |
| | The resulting set may return a set with one 2-tuple for each edge, |
| | (the usual case) or with both 2-tuples `(u, v)` and `(v, u)` for |
| | each edge. The latter is only done when a bipartite matching algorithm |
| | is specified as `matching_algorithm`. |
| | |
| | Parameters |
| | ---------- |
| | G : NetworkX graph |
| | An undirected graph. |
| | |
| | matching_algorithm : function |
| | A function that returns a maximum cardinality matching for `G`. |
| | The function must take one input, the graph `G`, and return |
| | either a set of edges (with only one direction for the pair of nodes) |
| | or a dictionary mapping each node to its mate. If not specified, |
| | :func:`~networkx.algorithms.matching.max_weight_matching` is used. |
| | Common bipartite matching functions include |
| | :func:`~networkx.algorithms.bipartite.matching.hopcroft_karp_matching` |
| | or |
| | :func:`~networkx.algorithms.bipartite.matching.eppstein_matching`. |
| | |
| | Returns |
| | ------- |
| | min_cover : set |
| | |
| | A set of the edges in a minimum edge cover in the form of tuples. |
| | It contains only one of the equivalent 2-tuples `(u, v)` and `(v, u)` |
| | for each edge. If a bipartite method is used to compute the matching, |
| | the returned set contains both the 2-tuples `(u, v)` and `(v, u)` |
| | for each edge of a minimum edge cover. |
| | |
| | Examples |
| | -------- |
| | >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) |
| | >>> sorted(nx.min_edge_cover(G)) |
| | [(2, 1), (3, 0)] |
| | |
| | Notes |
| | ----- |
| | An edge cover of a graph is a set of edges such that every node of |
| | the graph is incident to at least one edge of the set. |
| | The minimum edge cover is an edge covering of smallest cardinality. |
| | |
| | Due to its implementation, the worst-case running time of this algorithm |
| | is bounded by the worst-case running time of the function |
| | ``matching_algorithm``. |
| | |
| | Minimum edge cover for `G` can also be found using the `min_edge_covering` |
| | function in :mod:`networkx.algorithms.bipartite.covering` which is |
| | simply this function with a default matching algorithm of |
| | :func:`~networkx.algorithms.bipartite.matching.hopcraft_karp_matching` |
| | """ |
| | if len(G) == 0: |
| | return set() |
| | if nx.number_of_isolates(G) > 0: |
| | |
| | raise nx.NetworkXException( |
| | "Graph has a node with no edge incident on it, so no edge cover exists." |
| | ) |
| | if matching_algorithm is None: |
| | matching_algorithm = partial(nx.max_weight_matching, maxcardinality=True) |
| | maximum_matching = matching_algorithm(G) |
| | |
| | try: |
| | |
| | min_cover = set(maximum_matching.items()) |
| | bipartite_cover = True |
| | except AttributeError: |
| | min_cover = maximum_matching |
| | bipartite_cover = False |
| | |
| | uncovered_nodes = set(G) - {v for u, v in min_cover} - {u for u, v in min_cover} |
| | for v in uncovered_nodes: |
| | |
| | |
| | |
| | |
| | |
| | |
| | u = arbitrary_element(G[v]) |
| | min_cover.add((u, v)) |
| | if bipartite_cover: |
| | min_cover.add((v, u)) |
| | return min_cover |
| |
|
| |
|
| | @not_implemented_for("directed") |
| | @nx._dispatchable |
| | def is_edge_cover(G, cover): |
| | """Decides whether a set of edges is a valid edge cover of the graph. |
| | |
| | Given a set of edges, whether it is an edge covering can |
| | be decided if we just check whether all nodes of the graph |
| | has an edge from the set, incident on it. |
| | |
| | Parameters |
| | ---------- |
| | G : NetworkX graph |
| | An undirected bipartite graph. |
| | |
| | cover : set |
| | Set of edges to be checked. |
| | |
| | Returns |
| | ------- |
| | bool |
| | Whether the set of edges is a valid edge cover of the graph. |
| | |
| | Examples |
| | -------- |
| | >>> G = nx.Graph([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3)]) |
| | >>> cover = {(2, 1), (3, 0)} |
| | >>> nx.is_edge_cover(G, cover) |
| | True |
| | |
| | Notes |
| | ----- |
| | An edge cover of a graph is a set of edges such that every node of |
| | the graph is incident to at least one edge of the set. |
| | """ |
| | return set(G) <= set(chain.from_iterable(cover)) |
| |
|