use std::collections::HashSet;
use std::hash::Hash;
use crate::traits::EdgeCount;
use petgraph::visit::{EdgeRef, IntoEdgeReferences, IntoNodeIdentifiers, NodeCount, NodeIndexable};
pub fn complement<G>(graph: G) -> HashSet<(usize, usize)>
where
G: IntoEdgeReferences + NodeCount + EdgeCount + IntoNodeIdentifiers + NodeIndexable,
G::NodeId: Eq + Hash,
{
let mut edges: HashSet<(G::NodeId, G::NodeId)> =
HashSet::with_capacity(graph.number_of_edges());
for edge in graph.edge_references() {
edges.insert((edge.source(), edge.target()));
}
let n = graph.node_count();
let edge_count = n * (n - 1) - graph.number_of_edges();
let mut compl: HashSet<(usize, usize)> = HashSet::with_capacity(edge_count);
for i in graph.node_identifiers() {
for j in graph.node_identifiers() {
if i != j && !edges.contains(&(i, j)) {
compl.insert((graph.to_index(i), graph.to_index(j)));
}
}
}
compl
}
#[cfg(test)]
mod tests {
use super::*;
use crate::generate::random_digraph;
use petgraph::algo::is_isomorphic;
use petgraph::graph::Graph;
use petgraph::Directed;
fn graph1() -> Graph<(), ()> {
let mut graph = Graph::<(), ()>::new();
let n0 = graph.add_node(());
let n1 = graph.add_node(());
let n2 = graph.add_node(());
let n3 = graph.add_node(());
graph.add_edge(n0, n1, ());
graph.add_edge(n1, n0, ());
graph.add_edge(n1, n2, ());
graph.add_edge(n2, n1, ());
graph.add_edge(n1, n3, ());
graph.add_edge(n3, n1, ());
graph
}
#[test]
fn test_complement() {
let expected = vec![(0, 2), (2, 0), (0, 3), (3, 0), (2, 3), (3, 2)]
.into_iter()
.collect::<HashSet<(usize, usize)>>();
assert_eq!(complement(&graph1()), expected);
for _ in 0..10 {
let graph =
Graph::<(), (), Directed, usize>::from_edges(random_digraph(20, 150).unwrap());
let compl = Graph::<(), (), Directed, usize>::from_edges(complement(&graph));
let compl_compl = Graph::<(), (), Directed, usize>::from_edges(complement(&compl));
assert!(is_isomorphic(&graph, &compl_compl));
}
}
}