use super::AlgorithmError;
use crate::graph::{Graph, NodeIndex};
use crate::visited::VisitedTracker;
pub fn connected_components<'a, G, NI, VT>(
graph: &G,
visited: &mut VT,
components: &mut [(&'a [NI], usize)],
node_buffer: &'a mut [NI],
) -> Result<usize, AlgorithmError<NI>>
where
G: Graph<NI>,
NI: NodeIndex,
VT: VisitedTracker<NI> + ?Sized,
AlgorithmError<NI>: From<G::Error>,
{
let mut component_count = 0;
let mut buffer_offset = 0;
for node in graph.iter_nodes()? {
if !visited.is_visited(&node) {
if component_count >= components.len() {
return Err(AlgorithmError::ResultCapacityExceeded);
}
let remaining_buffer = &mut node_buffer[buffer_offset..];
let component_size = dfs_component_collection(graph, &node, visited, remaining_buffer)?;
if buffer_offset + component_size > node_buffer.len() {
return Err(AlgorithmError::ResultCapacityExceeded);
}
components[component_count] = (&[], component_size);
buffer_offset += component_size;
component_count += 1;
}
}
let mut current_offset = 0;
for component in components.iter_mut().take(component_count) {
let component_size = component.1;
let component_slice = &node_buffer[current_offset..current_offset + component_size];
*component = (component_slice, component_size);
current_offset += component_size;
}
Ok(component_count)
}
fn dfs_component_collection<G, NI, VT>(
graph: &G,
start_node: &NI,
visited: &mut VT,
buffer: &mut [NI],
) -> Result<usize, AlgorithmError<NI>>
where
G: Graph<NI>,
NI: NodeIndex,
VT: VisitedTracker<NI> + ?Sized,
AlgorithmError<NI>: From<G::Error>,
{
let mut count = 0;
dfs_collect_recursive(graph, start_node, visited, buffer, &mut count)?;
Ok(count)
}
fn dfs_collect_recursive<G, NI, VT>(
graph: &G,
node: &NI,
visited: &mut VT,
buffer: &mut [NI],
count: &mut usize,
) -> Result<(), AlgorithmError<NI>>
where
G: Graph<NI>,
NI: NodeIndex,
VT: VisitedTracker<NI> + ?Sized,
AlgorithmError<NI>: From<G::Error>,
{
if visited.is_visited(node) {
return Ok(());
}
visited
.mark_visited(node)
.map_err(|_| AlgorithmError::VisitedTrackerCapacityExceeded)?;
if *count >= buffer.len() {
return Err(AlgorithmError::ResultCapacityExceeded);
}
buffer[*count] = *node;
*count += 1;
for neighbor in graph.outgoing_edges(*node)? {
if !visited.is_visited(&neighbor) {
dfs_collect_recursive(graph, &neighbor, visited, buffer, count)?
}
}
Ok(())
}
pub fn count_connected_components<G, NI, VT>(
graph: &G,
visited: &mut VT,
) -> Result<usize, AlgorithmError<NI>>
where
G: Graph<NI>,
NI: NodeIndex,
VT: VisitedTracker<NI> + ?Sized,
AlgorithmError<NI>: From<G::Error>,
{
let mut component_count = 0;
for node in graph.iter_nodes()? {
if !visited.is_visited(&node) {
dfs_mark_component(graph, &node, visited)?;
component_count += 1;
}
}
Ok(component_count)
}
fn dfs_mark_component<G, NI, VT>(
graph: &G,
start_node: &NI,
visited: &mut VT,
) -> Result<(), AlgorithmError<NI>>
where
G: Graph<NI>,
NI: NodeIndex,
VT: VisitedTracker<NI> + ?Sized,
AlgorithmError<NI>: From<G::Error>,
{
if visited.is_visited(start_node) {
return Ok(());
}
visited
.mark_visited(start_node)
.map_err(|_| AlgorithmError::VisitedTrackerCapacityExceeded)?;
for neighbor in graph.outgoing_edges(*start_node)? {
if !visited.is_visited(&neighbor) {
dfs_mark_component(graph, &neighbor, visited)?;
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::adjacency_list::map_adjacency_list::MapAdjacencyList;
use crate::containers::maps::{staticdict::Dictionary, MapTrait};
use crate::edgelist::edge_list::EdgeList;
use crate::edgelist::edge_node_list::EdgeNodeList;
#[test]
fn test_connected_components_edge_list() {
let edges = [(0, 1), (1, 2), (3, 4)];
let graph = EdgeList::<10, usize, _>::new(edges);
let mut visited = [false; 10];
let mut components: [(&[usize], usize); 5] = [(&[], 0); 5];
let mut node_buffer = [0usize; 10];
let component_count = connected_components(
&graph,
visited.as_mut_slice(),
&mut components,
&mut node_buffer,
)
.unwrap();
assert_eq!(component_count, 2);
assert_eq!(components[0].0.len(), 3); assert_eq!(components[1].0.len(), 2);
let mut all_nodes = [0usize; 10];
let mut total_nodes = 0;
for i in 0..component_count {
for &node in components[i].0 {
all_nodes[total_nodes] = node;
total_nodes += 1;
}
}
all_nodes[..total_nodes].sort();
assert_eq!(&all_nodes[..total_nodes], &[0, 1, 2, 3, 4]);
}
#[test]
fn test_count_connected_components() {
let edges = [(0, 1), (1, 2), (3, 4)];
let graph = EdgeList::<10, usize, _>::new(edges);
let mut visited = [false; 10];
let count = count_connected_components(&graph, visited.as_mut_slice()).unwrap();
assert_eq!(count, 2); }
#[test]
fn test_connected_components_single_component() {
let edges = [(0, 1), (1, 2), (2, 3)];
let graph = EdgeList::<10, usize, _>::new(edges);
let mut visited = [false; 10];
let count = count_connected_components(&graph, visited.as_mut_slice()).unwrap();
assert_eq!(count, 1); }
#[test]
fn test_connected_components_map_adjacency_list() {
let mut dict = Dictionary::<usize, [usize; 2], 5>::new();
dict.insert(0, [1, 2]).unwrap(); dict.insert(1, [0, 2]).unwrap(); dict.insert(2, [0, 1]).unwrap(); dict.insert(3, [3, 3]).unwrap();
let graph = MapAdjacencyList::new_unchecked(dict);
let mut visited = [false; 10];
let count = count_connected_components(&graph, visited.as_mut_slice()).unwrap();
assert_eq!(count, 2); }
#[test]
fn test_connected_components_empty_graph() {
let edges: [(usize, usize); 0] = [];
let graph = EdgeList::<5, usize, _>::new(edges);
let mut visited = [false; 5];
let result = count_connected_components(&graph, visited.as_mut_slice());
assert!(result.is_err()); }
#[test]
fn test_connected_components_edge_node_list_with_isolated() {
let edges = [(0, 1), (1, 2), (3, 4)];
let nodes = [0, 1, 2, 3, 4, 5]; let graph = EdgeNodeList::<usize, _, _>::new(edges, nodes).unwrap();
let mut visited = [false; 10];
let mut components: [(&[usize], usize); 5] = [(&[], 0); 5];
let mut node_buffer = [0usize; 10];
let component_count = connected_components(
&graph,
visited.as_mut_slice(),
&mut components,
&mut node_buffer,
)
.unwrap();
assert_eq!(component_count, 3);
let mut sizes = [0; 3];
for i in 0..component_count {
sizes[i] = components[i].0.len();
}
sizes.sort(); assert_eq!(sizes, [1, 2, 3]);
let mut all_nodes = [0usize; 10];
let mut total_nodes = 0;
for i in 0..component_count {
for &node in components[i].0 {
all_nodes[total_nodes] = node;
total_nodes += 1;
}
}
all_nodes[..total_nodes].sort();
assert_eq!(&all_nodes[..total_nodes], &[0, 1, 2, 3, 4, 5]);
}
#[test]
fn test_connected_components_all_isolated() {
let mut dict = Dictionary::<usize, [usize; 0], 5>::new();
dict.insert(0, []).unwrap();
dict.insert(1, []).unwrap();
dict.insert(2, []).unwrap();
let graph = MapAdjacencyList::new_unchecked(dict);
let mut visited = [false; 10];
let count = count_connected_components(&graph, visited.as_mut_slice()).unwrap();
assert_eq!(count, 3); }
#[test]
fn test_connected_components_edge_node_list_with_isolated_explicit() {
let edges = [(0, 1), (1, 2), (3, 4)];
let nodes = [0, 1, 2, 3, 4, 5]; let graph = EdgeNodeList::new(edges, nodes).unwrap();
let mut visited = [false; 10];
let mut components: [(&[usize], usize); 5] = [(&[], 0); 5];
let mut node_buffer = [0usize; 10];
let component_count = connected_components(
&graph,
visited.as_mut_slice(),
&mut components,
&mut node_buffer,
)
.unwrap();
assert_eq!(component_count, 3);
let mut sizes = [0; 3];
for i in 0..component_count {
sizes[i] = components[i].0.len();
}
sizes.sort(); assert_eq!(sizes, [1, 2, 3]);
let mut all_nodes = [0usize; 10];
let mut total_nodes = 0;
for i in 0..component_count {
for &node in components[i].0 {
all_nodes[total_nodes] = node;
total_nodes += 1;
}
}
all_nodes[..total_nodes].sort();
assert_eq!(&all_nodes[..total_nodes], &[0, 1, 2, 3, 4, 5]);
}
}