use hashbrown::{HashMap, HashSet};
use petgraph::visit::{IntoNeighbors, IntoNodeIdentifiers, NodeCount};
use std::hash::Hash;
pub fn cycle_basis<G>(graph: G, root: Option<G::NodeId>) -> Vec<Vec<G::NodeId>>
where
G: NodeCount,
G: IntoNeighbors,
G: IntoNodeIdentifiers,
G::NodeId: Eq + Hash,
{
let mut root_node = root;
let mut graph_nodes: HashSet<G::NodeId> = graph.node_identifiers().collect();
let mut cycles: Vec<Vec<G::NodeId>> = Vec::new();
while !graph_nodes.is_empty() {
let temp_value: G::NodeId;
let root_index = match root_node {
Some(root_node) => root_node,
None => {
temp_value = *graph_nodes.iter().next().unwrap();
graph_nodes.remove(&temp_value);
temp_value
}
};
let mut stack: Vec<G::NodeId> = vec![root_index];
let mut pred: HashMap<G::NodeId, G::NodeId> = HashMap::new();
pred.insert(root_index, root_index);
let mut used: HashMap<G::NodeId, HashSet<G::NodeId>> = HashMap::new();
used.insert(root_index, HashSet::new());
while let Some(z) = stack.pop() {
for neighbor in graph.neighbors(z) {
if !used.contains_key(&neighbor) {
pred.insert(neighbor, z);
stack.push(neighbor);
let mut temp_set: HashSet<G::NodeId> = HashSet::new();
temp_set.insert(z);
used.insert(neighbor, temp_set);
} else if z == neighbor {
let cycle: Vec<G::NodeId> = vec![z];
cycles.push(cycle);
} else if !used.get(&z).unwrap().contains(&neighbor) {
let prev_n = used.get(&neighbor).unwrap();
let mut cycle: Vec<G::NodeId> = vec![neighbor, z];
let mut p = pred.get(&z).unwrap();
while !prev_n.contains(p) {
cycle.push(*p);
p = pred.get(p).unwrap();
}
cycle.push(*p);
cycles.push(cycle);
let neighbor_set = used.get_mut(&neighbor).unwrap();
neighbor_set.insert(z);
}
}
}
let mut temp_hashset: HashSet<G::NodeId> = HashSet::new();
for key in pred.keys() {
temp_hashset.insert(*key);
}
graph_nodes = graph_nodes.difference(&temp_hashset).copied().collect();
root_node = None;
}
cycles
}
#[cfg(test)]
mod tests {
use crate::connectivity::cycle_basis;
use petgraph::prelude::*;
fn sorted_cycle(cycles: Vec<Vec<NodeIndex>>) -> Vec<Vec<usize>> {
let mut sorted_cycles: Vec<Vec<usize>> = vec![];
for cycle in cycles {
let mut cycle: Vec<usize> = cycle.iter().map(|x| x.index()).collect();
cycle.sort();
sorted_cycles.push(cycle);
}
sorted_cycles.sort();
sorted_cycles
}
#[test]
fn test_cycle_basis_source() {
let edge_list = vec![
(0, 1),
(0, 3),
(0, 5),
(0, 8),
(1, 2),
(1, 6),
(2, 3),
(3, 4),
(4, 5),
(6, 7),
(7, 8),
(8, 9),
];
let graph = UnGraph::<i32, i32>::from_edges(edge_list);
let expected = vec![vec![0, 1, 2, 3], vec![0, 1, 6, 7, 8], vec![0, 3, 4, 5]];
let res_0 = cycle_basis(&graph, Some(NodeIndex::new(0)));
assert_eq!(sorted_cycle(res_0), expected);
let res_1 = cycle_basis(&graph, Some(NodeIndex::new(1)));
assert_eq!(sorted_cycle(res_1), expected);
let res_9 = cycle_basis(&graph, Some(NodeIndex::new(9)));
assert_eq!(sorted_cycle(res_9), expected);
}
#[test]
fn test_self_loop() {
let edge_list = vec![
(0, 1),
(0, 3),
(0, 5),
(0, 8),
(1, 2),
(1, 6),
(2, 3),
(3, 4),
(4, 5),
(6, 7),
(7, 8),
(8, 9),
];
let mut graph = UnGraph::<i32, i32>::from_edges(edge_list);
graph.add_edge(NodeIndex::new(1), NodeIndex::new(1), 0);
let res_0 = cycle_basis(&graph, Some(NodeIndex::new(0)));
assert_eq!(
sorted_cycle(res_0),
vec![
vec![0, 1, 2, 3],
vec![0, 1, 6, 7, 8],
vec![0, 3, 4, 5],
vec![1]
]
);
}
}