use super::ContainerResultExt;
use super::AlgorithmError;
use crate::containers::maps::MapTrait;
use crate::graph::{GraphWithEdgeValues, NodeIndex};
pub fn kruskals<'a, NI, G, V, M>(
graph: &G,
edge_storage: &mut [(NI, NI, V)],
mut parent: M,
mst: &'a mut [(NI, NI, V)],
) -> Result<&'a [(NI, NI, V)], AlgorithmError<NI>>
where
NI: NodeIndex + Ord,
V: Copy + Ord,
G: GraphWithEdgeValues<NI, V>,
M: MapTrait<NI, NI>,
AlgorithmError<NI>: From<G::Error>,
{
for node in graph.iter_nodes()? {
parent.insert(node, node).capacity_error()?;
}
let mut edge_count = 0;
for (src, dst, weight_opt) in graph.iter_edge_values()? {
if let Some(weight) = weight_opt {
if src == dst {
continue;
}
if edge_count >= edge_storage.len() {
return Err(AlgorithmError::EdgeCapacityExceeded);
}
edge_storage[edge_count] = (src, dst, *weight);
edge_count += 1;
}
}
let edges = &mut edge_storage[..edge_count];
edges.sort_unstable_by_key(|(_, _, weight)| *weight);
fn find<NI: Copy + Eq + PartialOrd, M: MapTrait<NI, NI>>(
parent: &mut M,
node: NI,
) -> Result<NI, AlgorithmError<NI>> {
if let Some(&p) = parent.get(&node) {
if p != node {
let root = find(parent, p)?;
parent.insert(node, root).capacity_error()?; Ok(root)
} else {
Ok(node)
}
} else {
Ok(node)
}
}
fn union<NI: Copy + Eq + PartialOrd, M: MapTrait<NI, NI>>(
parent: &mut M,
u: NI,
v: NI,
) -> Result<(), AlgorithmError<NI>> {
let root_u = find(parent, u)?;
let root_v = find(parent, v)?;
if root_u != root_v {
parent.insert(root_u, root_v).capacity_error()?;
}
Ok(())
}
let mut mst_count = 0;
for (u, v, weight) in edges.iter() {
let root_u = find(&mut parent, *u)?;
let root_v = find(&mut parent, *v)?;
if root_u != root_v {
if mst_count >= mst.len() {
return Err(AlgorithmError::ResultCapacityExceeded);
}
mst[mst_count] = (*u, *v, *weight);
mst_count += 1;
union(&mut parent, *u, *v)?;
}
}
Ok(&mst[..mst_count])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::containers::maps::staticdict::Dictionary;
use crate::edgelist::edge_list::EdgeList;
use crate::edges::EdgeValueStruct;
#[test]
fn test_kruskals_simple() {
let edge_data = EdgeValueStruct([
(0usize, 1usize, 1i32), (0, 2, 3), (1, 3, 2), (2, 3, 4), ]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let mut edge_storage = [(0usize, 0usize, 0i32); 16];
let parent = Dictionary::<usize, usize, 16>::new();
let mut mst = [(0usize, 0usize, 0i32); 8];
let result = kruskals(&graph, &mut edge_storage, parent, &mut mst).unwrap();
assert_eq!(result.len(), 3);
let mut found_edges = [false; 3];
for &(u, v, w) in result {
if (u == 0 && v == 1 && w == 1) || (u == 1 && v == 0 && w == 1) {
found_edges[0] = true;
} else if (u == 1 && v == 3 && w == 2) || (u == 3 && v == 1 && w == 2) {
found_edges[1] = true;
} else if (u == 0 && v == 2 && w == 3) || (u == 2 && v == 0 && w == 3) {
found_edges[2] = true;
}
}
assert!(
found_edges.iter().all(|&found| found),
"Missing expected MST edges"
);
let total_weight: i32 = result.iter().map(|(_, _, w)| w).sum();
assert_eq!(total_weight, 6);
}
#[test]
fn test_kruskals_disconnected() {
let edge_data = EdgeValueStruct([
(0usize, 1usize, 5i32), (2, 3, 3), ]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let mut edge_storage = [(0usize, 0usize, 0i32); 16];
let parent = Dictionary::<usize, usize, 16>::new();
let mut mst = [(0usize, 0usize, 0i32); 8];
let result = kruskals(&graph, &mut edge_storage, parent, &mut mst).unwrap();
assert_eq!(result.len(), 2);
let mut found_edges = [false; 2];
for &(u, v, w) in result {
if (u == 0 && v == 1 && w == 5) || (u == 1 && v == 0 && w == 5) {
found_edges[0] = true;
} else if (u == 2 && v == 3 && w == 3) || (u == 3 && v == 2 && w == 3) {
found_edges[1] = true;
}
}
assert!(
found_edges.iter().all(|&found| found),
"Missing expected MST edges"
);
}
#[test]
fn test_kruskals_no_edges() {
let edge_data = EdgeValueStruct([
(0usize, 1usize, 1i32), ]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let mut edge_storage = [(0usize, 0usize, 0i32); 16];
let parent = Dictionary::<usize, usize, 16>::new();
let mut mst = [(0usize, 0usize, 0i32); 8];
let result = kruskals(&graph, &mut edge_storage, parent, &mut mst).unwrap();
assert_eq!(result.len(), 1);
assert_eq!(result[0], (0, 1, 1));
}
#[test]
fn test_kruskals_capacity_exceeded() {
let edge_data = EdgeValueStruct([(0usize, 1usize, 1i32), (1, 2, 2), (2, 3, 3)]);
let graph = EdgeList::<8, _, _>::new(edge_data);
let mut edge_storage = [(0usize, 0usize, 0i32); 2]; let parent = Dictionary::<usize, usize, 16>::new();
let mut mst = [(0usize, 0usize, 0i32); 8];
let result = kruskals(&graph, &mut edge_storage, parent, &mut mst);
assert!(matches!(result, Err(AlgorithmError::EdgeCapacityExceeded)));
}
}