use super::AlgorithmError;
use crate::graph::{Graph, GraphWithMutableEdges, NodeIndex};
pub fn transpose_graph<NI, G1, G2>(
source_graph: &G1,
target_graph: &mut G2,
) -> Result<(), AlgorithmError<NI>>
where
NI: NodeIndex,
G1: Graph<NI>,
G2: GraphWithMutableEdges<NI>,
AlgorithmError<NI>: From<G1::Error>,
AlgorithmError<NI>: From<G2::Error>,
{
for (source, destination) in source_graph.iter_edges()? {
target_graph.add_edge(destination, source)?;
}
Ok(())
}
pub fn transpose_graph_inplace<NI, G>(
graph: &mut G,
edge_buffer: &mut [(NI, NI)],
validate: bool,
) -> Result<(), AlgorithmError<NI>>
where
NI: NodeIndex + Copy,
G: Graph<NI> + GraphWithMutableEdges<NI>,
AlgorithmError<NI>: From<G::Error>,
{
let mut edge_count = 0;
for edge in graph.iter_edges()? {
if edge_count >= edge_buffer.len() {
return Err(AlgorithmError::ResultCapacityExceeded);
}
edge_buffer[edge_count] = edge;
edge_count += 1;
}
if validate {
for &(source, destination) in edge_buffer.iter().take(edge_count) {
if graph.contains_node(destination).is_err() {
return Err(AlgorithmError::GraphError(
crate::graph::GraphError::EdgeHasInvalidNode(destination),
));
}
if graph.contains_node(source).is_err() {
return Err(AlgorithmError::GraphError(
crate::graph::GraphError::EdgeHasInvalidNode(source),
));
}
}
}
for &(source, destination) in edge_buffer.iter().take(edge_count) {
graph.remove_edge(source, destination)?;
}
for &(source, destination) in edge_buffer.iter().take(edge_count) {
graph.add_edge(destination, source)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::edgelist::edge_list::EdgeList;
use crate::tests::collect_sorted;
#[test]
fn test_transpose_graph_simple() {
let source = EdgeList::<8, usize, _>::new([(0, 1), (1, 2)]);
let mut target = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([None; 8]);
transpose_graph(&source, &mut target).unwrap();
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(target.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(1, 0), (2, 1)]);
}
#[test]
fn test_transpose_graph_with_self_loops() {
let source = EdgeList::<8, usize, _>::new([(0, 0), (0, 1), (1, 1)]);
let mut target = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([None; 8]);
transpose_graph(&source, &mut target).unwrap();
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(target.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(0, 0), (1, 0), (1, 1)]);
}
#[test]
fn test_transpose_graph_empty() {
let source = EdgeList::<8, usize, [(usize, usize); 0]>::new([]);
let mut target = EdgeList::<8, usize, [Option<(usize, usize)>; 0]>::new([]);
transpose_graph(&source, &mut target).unwrap();
assert_eq!(target.iter_edges().unwrap().count(), 0);
}
#[test]
fn test_transpose_graph_complete() {
let source = EdgeList::<8, usize, _>::new([(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]);
let mut target = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([None; 8]);
transpose_graph(&source, &mut target).unwrap();
let mut source_edges = [(0usize, 0usize); 8];
let source_slice = collect_sorted(source.iter_edges().unwrap(), &mut source_edges);
let mut target_edges = [(0usize, 0usize); 8];
let target_slice = collect_sorted(target.iter_edges().unwrap(), &mut target_edges);
assert_eq!(source_slice, target_slice);
}
#[test]
fn test_transpose_graph_inplace_simple() {
let mut graph = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([
Some((0, 1)),
Some((1, 2)),
Some((0, 2)),
None,
None,
None,
None,
None,
]);
let mut buffer = [(0usize, 0usize); 8];
transpose_graph_inplace(&mut graph, &mut buffer, true).unwrap();
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(1, 0), (2, 0), (2, 1)]);
}
#[test]
fn test_transpose_graph_inplace_buffer_too_small() {
let mut graph = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([
Some((0, 1)),
Some((1, 2)),
Some((0, 2)),
None,
None,
None,
None,
None,
]);
let mut buffer = [(0usize, 0usize); 2];
let result = transpose_graph_inplace(&mut graph, &mut buffer, true);
assert!(matches!(
result,
Err(AlgorithmError::ResultCapacityExceeded)
));
}
#[test]
fn test_transpose_preserves_node_count() {
let source = EdgeList::<8, usize, _>::new([(0, 1), (1, 2), (2, 3), (3, 1)]);
let mut target = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([None; 8]);
transpose_graph(&source, &mut target).unwrap();
assert_eq!(
source.iter_nodes().unwrap().count(),
target.iter_nodes().unwrap().count()
);
let mut source_nodes = [0usize; 8];
let source_nodes_slice = collect_sorted(source.iter_nodes().unwrap(), &mut source_nodes);
let mut target_nodes = [0usize; 8];
let target_nodes_slice = collect_sorted(target.iter_nodes().unwrap(), &mut target_nodes);
assert_eq!(source_nodes_slice, target_nodes_slice);
}
#[test]
fn test_transpose_graph_inplace_no_validation() {
let mut graph = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([
Some((0, 1)),
Some((1, 2)),
Some((0, 2)),
None,
None,
None,
None,
None,
]);
let mut buffer = [(0usize, 0usize); 8];
transpose_graph_inplace(&mut graph, &mut buffer, false).unwrap();
let mut edges = [(0usize, 0usize); 8];
let edges_slice = collect_sorted(graph.iter_edges().unwrap(), &mut edges);
assert_eq!(edges_slice, &[(1, 0), (2, 0), (2, 1)]);
}
#[test]
fn test_transpose_graph_inplace_validate_vs_no_validate() {
let original_edges = [
Some((0, 1)),
Some((1, 2)),
Some((0, 3)),
None,
None,
None,
None,
None,
];
let mut graph1 = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new(original_edges);
let mut graph2 = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new(original_edges);
let mut buffer = [(0usize, 0usize); 8];
transpose_graph_inplace(&mut graph1, &mut buffer, true).unwrap(); transpose_graph_inplace(&mut graph2, &mut buffer, false).unwrap();
let mut edges1 = [(0usize, 0usize); 8];
let edges1_slice = collect_sorted(graph1.iter_edges().unwrap(), &mut edges1);
let mut edges2 = [(0usize, 0usize); 8];
let edges2_slice = collect_sorted(graph2.iter_edges().unwrap(), &mut edges2);
assert_eq!(edges1_slice, edges2_slice);
}
#[test]
fn test_double_transpose_identity() {
let original = EdgeList::<8, usize, _>::new([(0, 1), (1, 2), (0, 3)]);
let mut first_transpose = EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([None; 8]);
let mut second_transpose =
EdgeList::<8, usize, [Option<(usize, usize)>; 8]>::new([None; 8]);
transpose_graph(&original, &mut first_transpose).unwrap();
transpose_graph(&first_transpose, &mut second_transpose).unwrap();
let mut original_edges = [(0usize, 0usize); 8];
let original_slice = collect_sorted(original.iter_edges().unwrap(), &mut original_edges);
let mut final_edges = [(0usize, 0usize); 8];
let final_slice = collect_sorted(second_transpose.iter_edges().unwrap(), &mut final_edges);
assert_eq!(original_slice, final_slice);
}
}