use crate::core::types::{BaseGraph, GraphConstructor, NodeId};
use std::collections::{HashMap, HashSet};
pub fn max_clique<A, Ty>(graph: &BaseGraph<A, f64, Ty>) -> HashSet<NodeId>
where
Ty: GraphConstructor<A, f64>,
{
let mut best = HashSet::new();
let neighbor_cache: HashMap<NodeId, HashSet<NodeId>> = graph
.nodes()
.map(|(u, _)| (u, graph.neighbors(u).collect()))
.collect();
for (node, _) in graph.nodes() {
let mut clique = HashSet::new();
clique.insert(node);
let node_neighbors = match neighbor_cache.get(&node) {
Some(neighbors) => neighbors,
None => continue, };
let mut neighbors: Vec<NodeId> = node_neighbors.iter().cloned().collect();
neighbors.sort_by_key(|u| {
std::cmp::Reverse(
neighbor_cache.get(u).map(|n| n.len()).unwrap_or(0), )
});
for v in neighbors {
let is_connected_to_all = clique.iter().all(|&w| {
neighbor_cache
.get(&w)
.map(|neighbors| neighbors.contains(&v))
.unwrap_or(false) });
if is_connected_to_all {
clique.insert(v);
}
}
if clique.len() > best.len() {
best = clique;
}
}
best
}
pub fn clique_removal<A, Ty>(graph: &BaseGraph<A, f64, Ty>) -> Vec<HashSet<NodeId>>
where
Ty: GraphConstructor<A, f64>,
{
let mut cliques = Vec::new();
let mut remaining: HashSet<NodeId> = graph.nodes().map(|(u, _)| u).collect();
while !remaining.is_empty() {
let clique = max_clique(graph)
.into_iter()
.filter(|u| remaining.contains(u))
.collect::<HashSet<_>>();
if clique.is_empty() {
break;
}
for u in &clique {
remaining.remove(u);
}
cliques.push(clique);
}
cliques
}
pub fn large_clique_size<A, Ty>(graph: &BaseGraph<A, f64, Ty>) -> usize
where
Ty: GraphConstructor<A, f64>,
{
max_clique(graph).len()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::types::Graph;
#[test]
fn test_max_clique_empty_graph() {
let graph: Graph<i32, f64> = Graph::new();
let clique = max_clique(&graph);
assert!(clique.is_empty());
}
#[test]
fn test_max_clique_single_node() {
let mut graph = Graph::new();
let n1 = graph.add_node(1);
let clique = max_clique(&graph);
assert_eq!(clique.len(), 1);
assert!(clique.contains(&n1));
}
#[test]
fn test_max_clique_triangle() {
let mut graph = Graph::new();
let n1 = graph.add_node(1);
let n2 = graph.add_node(2);
let n3 = graph.add_node(3);
graph.add_edge(n1, n2, 1.0);
graph.add_edge(n2, n3, 1.0);
graph.add_edge(n3, n1, 1.0);
let clique = max_clique(&graph);
assert_eq!(clique.len(), 3);
}
#[test]
fn test_clique_removal_empty() {
let graph: Graph<i32, f64> = Graph::new();
let cliques = clique_removal(&graph);
assert!(cliques.is_empty());
}
#[test]
fn test_large_clique_size() {
let mut graph = Graph::new();
let n1 = graph.add_node(1);
let n2 = graph.add_node(2);
graph.add_edge(n1, n2, 1.0);
assert_eq!(large_clique_size(&graph), 2);
}
}