Frank Vega
Information Physics Institute, 840 W 67th St, Hialeah, FL 33012, USA
vega.frank@gmail.com
Problem Statement
Given an undirected graph
, an edge dominating set is a subset of edges
such that every edge in
is either in
or shares at least one endpoint with an edge in
. Formally, for every edge
, either
, or there exists an edge
such that
and
are adjacent (i.e., they share a common vertex). The goal of the Edge Dominating Set Problem is to find an edge dominating set
of minimum size. This problem is NP-hard, and the find_edge_dominating
algorithm provides an approximate solution by transforming the problem into a dominating set problem on a line graph.
- Input: An undirected graph , represented as a NetworkX graph.
- Output: A subset such that every edge in is either in or adjacent to an edge in , with as small as possible.
Algorithm Overview: find_edge_dominating
The find_edge_dominating(graph)
algorithm computes an approximate minimum edge dominating set by transforming the edge dominating set problem into a dominating set problem on the line graph of each connected component of the input graph.
Consider the algorithm implemented in Python:
import networkx as nx
import baldor.algorithm as alg
def find_edge_dominating(graph):
"""
Compute an approximate minimum edge dominating set set for an undirected graph by transforming it into a chordal graph.
Args:
graph (nx.Graph): A NetworkX Graph object representing the input graph.
Returns:
set: A set of vertex indices representing the minimum edge dominating set set.
Returns an empty set if the graph is empty or has no edges.
"""
# Check if the input graph is a valid undirected NetworkX Graph; raises an error if not.
if not isinstance(graph, nx.Graph):
raise ValueError("Input must be an undirected NetworkX Graph.")
# Handle edge cases: return an empty set if the graph has no nodes or no edges, as no edge dominating set is needed.
if graph.number_of_nodes() == 0 or graph.number_of_edges() == 0:
return set()
# Remove all self-loop edges since they cannot be part of an edge dominating set.
graph.remove_edges_from(list(nx.selfloop_edges(graph)))
# Remove isolated nodes from the graph to process the remaining components, as they do not contribute to an edge dominating set.
graph.remove_nodes_from(list(nx.isolates(graph)))
# After removing isolated nodes, if the graph is empty, return an empty set (no edge dominating set needed).
if graph.number_of_nodes() == 0:
return set()
# Initialize an empty set to store the approximate edge dominating set.
approximate_edge_dominating = set()
# Iterate over each connected component of the graph to compute the edge dominating set independently.
for component in nx.connected_components(graph):
# Extract the subgraph corresponding to the current connected component.
subgraph = graph.subgraph(component)
# Handle small components: if the subgraph has 2 or fewer edges, select one edge to dominate all edges in the component.
if subgraph.number_of_edges() <= 2:
# Add the first edge from the subgraph to the edge dominating set and move to the next component.
approximate_edge_dominating.add(next(iter(set(subgraph.edges()))))
continue
# Transform the subgraph into a line graph, where nodes represent edges of the subgraph, and edges represent adjacency between edges.
line_graph = nx.line_graph(subgraph)
# Use Baldor's 2-approximation algorithm to find a dominating set in the line graph.
# This dominating set corresponds to an edge dominating set in the original graph via the transformation.
edge_dominating = alg.find_dominating_set(line_graph)
# Add the edges from the dominating set (representing edges in the original subgraph) to the approximate edge dominating set.
approximate_edge_dominating.update(edge_dominating)
# Return the computed approximate edge dominating set set.
return approximate_edge_dominating
Here's the step-by-step breakdown:
-
Input Validation and Preprocessing:
- Validates that the input is an undirected NetworkX graph.
- Returns an empty set if the graph has no nodes or edges (no edge dominating set needed).
- Removes self-loops (as they cannot be part of an edge dominating set) and isolated nodes (as they do not contribute to edge domination).
-
Component-wise Processing:
- Decomposes the graph into its connected components.
- For each connected component:
- Extracts the subgraph corresponding to the component.
- If the subgraph has 2 or fewer edges, selects one edge to dominate all edges in the component.
- Otherwise, proceeds with the transformation to a line graph.
-
Transformation to Line Graph:
- Constructs the line graph of the subgraph, where:
- Each node in represents an edge in the subgraph.
- Two nodes in are connected if their corresponding edges in the subgraph share a common vertex.
- In , a dominating set corresponds to an edge dominating set in the original subgraph: selecting a node in (an edge in the subgraph) ensures that all adjacent nodes (adjacent edges) are dominated.
-
Dominating Set Computation:
- Uses
alg.find_dominating_set
(Baldor's 2-approximation algorithm) to compute a dominating set in . Thealg.find_dominating_set
algorithm is detailed in the article Bipartite-Based 2-Approximation for Dominating Sets in General Graphs. - The resulting dominating set in is a set of edges in the original subgraph that forms an edge dominating set for that component.
- Uses
-
Aggregation:
- Combines the edge dominating sets from all components into the final approximate edge dominating set .
- Returns .
Running Time Analysis
Let (number of vertices) and (number of edges) in the input graph .
-
Preprocessing:
- Input validation, self-loop removal, and isolated node removal: using NetworkX operations.
-
Component Decomposition:
- Finding connected components: using a depth-first search (DFS) or breadth-first search (BFS) in NetworkX.
-
Per Component:
- Subgraph Extraction: , where and are the number of vertices and edges in the component. Across all components, this sums to .
- Small Components ( ): Selecting one edge takes , negligible cost.
- Line Graph Construction:
- Vertices in : .
- Edges in : Each edge in the subgraph corresponds to a vertex in , and two vertices in are adjacent if their corresponding edges share a vertex. For a vertex of degree , its incident edges form a clique of size in , contributing edges. Total edges in : , which is . For sparse graphs ( ), this is typically , but in dense graphs, it can be .
- Construction time: , summing to over all components.
- Dominating Set Computation:
-
alg.find_dominating_set
has a runtime of , where (vertices in ) and (edges in ). - Per component: .
- Across all components: .
-
Total Runtime:
- Combining all steps: .
- For sparse graphs ( , degrees are small), , so the runtime simplifies to .
- For dense graphs ( ), , making the runtime .
Approximation Factor
- Transformation Property: An edge dominating set in corresponds to a dominating set in . If is a dominating set in , the corresponding set of edges in is an edge dominating set.
-
Baldor's Dominating Set Approximation:
alg.find_dominating_set
guarantees a 2-approximation for the dominating set problem in . For a deep dive into this algorithm, check out the article Bipartite-Based 2-Approximation for Dominating Sets in General Graphs, which provides a thorough explanation. - Edge Dominating Set Approximation: Since the transformation preserves the approximation ratio, the edge dominating set computed has an approximation ratio of 2. That is, the size of the edge dominating set , where is the optimal edge dominating set.
-
Potential Improvement: As noted in the conclusion, if
alg.find_dominating_set
achieves an approximation ratio in practice, the edge dominating set approximation ratio also reduces to , often making the solution closer to optimal.
Why This Algorithm is Better for Sparse Graphs
The find_edge_dominating
algorithm is particularly efficient for sparse graphs (
) due to the following reasons:
-
Line Graph Size:
- In a sparse graph, the degrees are small (e.g., constant or ). Thus, the number of edges in the line graph , given by , is . For example, if (a constant), then , and since , this is .
- In contrast, for dense graphs ( ), degrees are , so , leading to a much larger line graph with edges, significantly increasing the runtime.
-
Dominating Set Computation:
- The runtime of
alg.find_dominating_set
on is . For sparse graphs, , and , so this becomes , which is manageable. - In dense graphs, , making the runtime , which is much slower.
- The runtime of
-
Overall Runtime:
- For sparse graphs, the total runtime simplifies to , which is nearly linear in the size of the graph, making the algorithm efficient.
- For dense graphs, the runtime becomes , which is impractical for large graphs.
-
Practical Performance:
- Sparse graphs (e.g., social networks, road networks) are common in real-world applications. The algorithm's near-linear runtime in such cases makes it practical for large-scale problems, while its approximation ratio of 2 (or better if ) ensures good solution quality.
Thus, the algorithm's design, particularly the line graph transformation and the use of alg.find_dominating_set
, makes it well-suited for sparse graphs, where the computational overhead of constructing and processing the line graph remains low, and the overall runtime scales efficiently. This implementation is publicly accessible through the Python Package Index (PyPI): https://pypi.org/project/loynaz/.