use crate::core::types::{BaseGraph, GraphConstructor, NodeId};
use std::collections::{BinaryHeap, HashMap, HashSet};
pub fn min_weighted_vertex_cover<A, Ty>(graph: &BaseGraph<A, f64, Ty>) -> HashSet<NodeId>
where
Ty: GraphConstructor<A, f64>,
{
let mut adj: HashMap<NodeId, HashSet<NodeId>> = HashMap::new();
let mut deg: HashMap<NodeId, usize> = HashMap::new();
let mut self_loops: HashSet<NodeId> = HashSet::new();
for (u, v, _) in graph.edges() {
if u == v {
if self_loops.insert(u) {
*deg.entry(u).or_insert(0) += 1;
}
continue;
}
if adj.entry(u).or_default().insert(v) {
*deg.entry(u).or_insert(0) += 1;
adj.entry(v).or_default().insert(u);
*deg.entry(v).or_insert(0) += 1;
}
}
let mut heap: BinaryHeap<(usize, NodeId)> = deg.iter().map(|(&u, &d)| (d, u)).collect();
let mut cover: HashSet<NodeId> = HashSet::new();
while let Some((d, u)) = heap.pop() {
if cover.contains(&u) {
continue; }
if deg.get(&u).copied().unwrap_or(0) != d {
continue; }
if d == 0 {
break; }
cover.insert(u);
if let Some(neighbors) = adj.get(&u) {
for &w in neighbors {
if !cover.contains(&w) {
if let Some(dw) = deg.get_mut(&w) {
*dw -= 1;
heap.push((*dw, w));
}
}
}
}
}
cover
}
#[cfg(test)]
mod tests {
use super::min_weighted_vertex_cover;
use crate::core::types::{Graph, NodeId};
use std::collections::HashSet;
fn covers_all_edges(graph: &Graph<i32, f64>, cover: &HashSet<NodeId>) -> bool {
graph
.edges()
.all(|(u, v, _)| cover.contains(&u) || cover.contains(&v))
}
#[test]
fn test_greedy_vertex_cover() {
let mut graph = Graph::<i32, f64>::new();
let n1 = graph.add_node(1);
let n2 = graph.add_node(2);
let n3 = graph.add_node(3);
let n4 = graph.add_node(4);
graph.add_edge(n1, n2, 1.0);
graph.add_edge(n2, n3, 1.0);
graph.add_edge(n3, n4, 1.0);
let cover = min_weighted_vertex_cover(&graph);
assert!(!cover.is_empty());
assert!(cover.len() <= graph.node_count());
assert!(covers_all_edges(&graph, &cover));
}
#[test]
fn test_vertex_cover_empty_graph() {
let graph = Graph::<i32, f64>::new();
let cover = min_weighted_vertex_cover(&graph);
assert!(cover.is_empty());
}
#[test]
fn test_vertex_cover_star_picks_center() {
let mut graph = Graph::<i32, f64>::new();
let center = graph.add_node(0);
let leaves: Vec<_> = (1..=5).map(|i| graph.add_node(i)).collect();
for &leaf in &leaves {
graph.add_edge(center, leaf, 1.0);
}
let cover = min_weighted_vertex_cover(&graph);
assert_eq!(cover, HashSet::from([center]));
}
#[test]
fn test_vertex_cover_complete_graph() {
let mut graph = Graph::<i32, f64>::new();
let nodes: Vec<_> = (0..5).map(|i| graph.add_node(i)).collect();
for i in 0..nodes.len() {
for j in (i + 1)..nodes.len() {
graph.add_edge(nodes[i], nodes[j], 1.0);
}
}
let cover = min_weighted_vertex_cover(&graph);
assert!(covers_all_edges(&graph, &cover));
assert_eq!(cover.len(), nodes.len() - 1);
}
#[test]
fn test_vertex_cover_self_loop_forces_endpoint() {
let mut graph = Graph::<i32, f64>::new();
let a = graph.add_node(0);
let b = graph.add_node(1);
graph.add_edge(a, b, 1.0);
graph.add_edge(a, a, 1.0);
let cover = min_weighted_vertex_cover(&graph);
assert!(cover.contains(&a));
assert!(covers_all_edges(&graph, &cover));
}
#[test]
fn test_vertex_cover_sparse_indices_after_removal() {
let mut graph = Graph::<i32, f64>::new();
let nodes: Vec<_> = (0..4).map(|i| graph.add_node(i)).collect();
graph.remove_node(nodes[1]);
graph.add_edge(nodes[0], nodes[2], 1.0);
graph.add_edge(nodes[2], nodes[3], 1.0);
let cover = min_weighted_vertex_cover(&graph);
assert!(covers_all_edges(&graph, &cover));
assert!(cover.contains(&nodes[2]));
}
}