From d11419d5362f0866f405147870e7f2b5a9ebcb19 Mon Sep 17 00:00:00 2001 From: starovoid Date: Sat, 12 Jul 2025 22:00:32 +0300 Subject: [PATCH 1/4] Use spfa and johnson from petgraph 0.8 --- Cargo.toml | 2 +- src/shortest_path/johnson.rs | 376 ----------------------------------- src/shortest_path/mod.rs | 6 +- src/shortest_path/spfa.rs | 306 ---------------------------- 4 files changed, 3 insertions(+), 687 deletions(-) delete mode 100644 src/shortest_path/johnson.rs delete mode 100644 src/shortest_path/spfa.rs diff --git a/Cargo.toml b/Cargo.toml index 7e249a5..48847c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ name = "graphalgs" bench = false [dependencies] -petgraph = "0.7" +petgraph = "0.8" nalgebra = "0.33" rand = "0.8" num-traits = "0.2" diff --git a/src/shortest_path/johnson.rs b/src/shortest_path/johnson.rs deleted file mode 100644 index 4a47a8a..0000000 --- a/src/shortest_path/johnson.rs +++ /dev/null @@ -1,376 +0,0 @@ -use std::cmp::Ordering; -use std::collections::{BinaryHeap, VecDeque}; -use std::ops::Sub; - -pub use petgraph::algo::{FloatMeasure, NegativeCycle}; -use petgraph::visit::{ - EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeIndexable, VisitMap, Visitable, -}; - -/// [Johnson algorithm](https://en.wikipedia.org/wiki/Johnson%27s_algorithm) for all pairs shortest path problem. -/// -/// Сompute the lengths of shortest paths in a weighted graph with -/// positive or negative edge weights, but no negative cycles. -/// -/// ## Arguments -/// * `graph`: weighted graph. -/// * `edge_cost`: closure that returns cost of a particular edge. -/// -/// ## Returns -/// * `Err`: if graph contains negative cycle. -/// * `Ok`: matrix `Vec>` of shortest distances, in cell **(i, j)** of which the length of the shortest path -/// from node **i** to node **j** is stored. -/// -/// # Examples -/// -/// ``` -/// use graphalgs::shortest_path::johnson; -/// use petgraph::Graph; -/// -/// let inf = f32::INFINITY; -/// -/// let graph = Graph::<(), f32>::from_edges(&[ -/// (0, 1, 2.0), (1, 2, 10.0), (1, 3, -5.0), -/// (3, 2, 2.0), (2, 3, 20.0), -/// ]); -/// -/// // Graph represented with the weight of each edge. -/// // 2 -/// // (0)------->(1) -/// // ___10____/| -/// // / | -5 -/// // v v -/// // (2)<--2----(3) -/// // \----20--->/ -/// -/// assert_eq!( -/// johnson(&graph, |edge| *edge.weight()), -/// Ok(vec![vec![0.0, 2.0, -1.0, -3.0], -/// vec![inf, 0.0, -3.0, -5.0], -/// vec![inf, inf, 0.0, 20.0], -/// vec![inf, inf, 2.0, 0.0]]) -/// ); -/// -/// -/// // Negative cycle. -/// let graph = Graph::<(), f32>::from_edges(&[ -/// (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)]); -/// -/// assert!(johnson(&graph, |edge| *edge.weight()).is_err()); -/// ``` -pub fn johnson(graph: G, mut edge_cost: F) -> Result>, NegativeCycle> -where - G: IntoEdges + IntoNodeIdentifiers + NodeIndexable + Visitable, - G::NodeId: Eq, - F: FnMut(G::EdgeRef) -> K, - K: FloatMeasure + Sub, -{ - // Add a new vertex to the graph with oriented edges with zero weight - // to all other vertices, and then run SPFA from it. - // The found distances will be used to change the edge weights in Dijkstra's - // algorithm to make them non-negative. - - let ix = |i| graph.to_index(i); - - let mut h = vec![K::zero(); graph.node_bound()]; - - // Queue of vertices capable of relaxation of the found shortest distances. - let mut queue: VecDeque = VecDeque::with_capacity(graph.node_bound()); - queue.extend(graph.node_identifiers()); - let mut in_queue = vec![true; graph.node_bound()]; - - // We will keep track of how many times each vertex appeared - // in the queue to be able to detect a negative cycle. - let mut visits = vec![0; graph.node_bound()]; - - while !queue.is_empty() { - let i = queue.pop_front().unwrap(); - in_queue[ix(i)] = false; - - // In a graph without a negative cycle, no vertex can improve - // the shortest distances by more than |V| times. - if visits[ix(i)] >= graph.node_bound() { - return Err(NegativeCycle(())); - } - visits[ix(i)] += 1; - - for edge in graph.edges(i) { - let j = edge.target(); - let w = edge_cost(edge); - - if h[ix(i)] + w < h[ix(j)] { - h[ix(j)] = h[ix(i)] + w; - - if !in_queue[ix(j)] { - in_queue[ix(j)] = true; - queue.push_back(j); - } - } - } - } - - // Run Dijkstra's algorithm from each vertex. - Ok(graph - .node_identifiers() - .map(|n| dijkstra_helper(&graph, n, &h, &mut edge_cost)) - .enumerate() - .map(|(source, dist)| { - dist.into_iter() - .enumerate() - .map(|(target, d)| d + h[target] - h[source]) - .collect() - }) - .collect()) -} - -/// Dijkstra's algorithm calculating shortest distances taking into account changes in weights. -/// Vector h - potential function calculated for each vertex. -/// The weight of each edge is recalculated using the formula -/// new_weight = weight(a, b) = h(a) - h(b). -fn dijkstra_helper(graph: G, start: G::NodeId, h: &[K], edge_cost: &mut F) -> Vec -where - G: IntoEdges + Visitable + NodeIndexable, - G::NodeId: Eq, - F: FnMut(G::EdgeRef) -> K, - K: FloatMeasure + Sub, -{ - let ix = |i| graph.to_index(i); - let mut visited = graph.visit_map(); - let mut distance = vec![K::infinite(); graph.node_bound()]; - let mut visit_next = BinaryHeap::new(); - - distance[ix(start)] = K::zero(); - visit_next.push(MinScored(K::zero(), start)); - - while let Some(MinScored(node_score, node)) = visit_next.pop() { - if visited.is_visited(&node) { - continue; - } - for edge in graph.edges(node) { - let next = edge.target(); - if visited.is_visited(&next) { - continue; - } - let next_score = node_score + edge_cost(edge) + h[ix(node)] - h[ix(next)]; - if next_score < distance[ix(next)] { - distance[ix(next)] = next_score; - } - visit_next.push(MinScored(next_score, next)); - } - visited.visit(node); - } - - distance -} - -/// A pair for use with a `BinaryHeap` in `dijkstra_helper`. -#[derive(Copy, Clone, Debug)] -pub struct MinScored(pub K, pub T); - -impl PartialEq for MinScored { - #[inline] - fn eq(&self, other: &MinScored) -> bool { - self.cmp(other) == Ordering::Equal - } -} - -impl Eq for MinScored {} - -impl PartialOrd for MinScored { - #[inline] - fn partial_cmp(&self, other: &MinScored) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for MinScored { - #[inline] - fn cmp(&self, other: &MinScored) -> Ordering { - let a = &self.0; - let b = &other.0; - if a > b { - Ordering::Less - } else if a < b { - Ordering::Greater - } else { - Ordering::Equal - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::generate::random_weighted_digraph; - use crate::shortest_path::floyd_warshall; - use petgraph::graph::Graph; - use petgraph::Directed; - use rand::Rng; - - fn graph1() -> Graph<(), f32> { - let mut graph = Graph::<(), f32>::new(); - let n0 = graph.add_node(()); - let n1 = graph.add_node(()); - let n2 = graph.add_node(()); - let n3 = graph.add_node(()); - let n4 = graph.add_node(()); - - graph.add_edge(n0, n1, 40.0); - graph.add_edge(n0, n4, 18.0); - graph.add_edge(n1, n0, 40.0); - graph.add_edge(n1, n4, 15.0); - graph.add_edge(n1, n2, 22.0); - graph.add_edge(n1, n3, 6.0); - graph.add_edge(n2, n1, 22.0); - graph.add_edge(n2, n3, 14.0); - graph.add_edge(n3, n4, 20.0); - graph.add_edge(n3, n1, 6.0); - graph.add_edge(n3, n2, 14.0); - graph.add_edge(n4, n0, 18.0); - graph.add_edge(n4, n1, 15.0); - graph.add_edge(n4, n3, 20.0); - - graph - } - - fn graph2() -> Graph<(), f32> { - let mut graph = Graph::<(), f32>::new(); - let n0 = graph.add_node(()); - let n1 = graph.add_node(()); - let n2 = graph.add_node(()); - let n3 = graph.add_node(()); - let n4 = graph.add_node(()); - let n5 = graph.add_node(()); - - graph.add_edge(n0, n1, 1.0); - graph.add_edge(n5, n1, -4.0); - graph.add_edge(n1, n4, 5.0); - graph.add_edge(n4, n1, 5.0); - graph.add_edge(n2, n1, 8.0); - graph.add_edge(n4, n3, 10.0); - graph.add_edge(n3, n2, 0.0); - graph.add_edge(n3, n2, -20.0); - - graph - } - - fn graph3() -> Graph<(), f64> { - let mut graph = Graph::<(), f64>::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, 10.0); - graph.add_edge(n0, n2, 5.0); - graph.add_edge(n1, n2, 2.0); - graph.add_edge(n2, n3, -10.0); - graph.add_edge(n3, n1, -1.0); - graph.add_edge(n1, n3, 16.0); - - graph - } - - fn graph4() -> Graph<(), f32> { - let mut graph = Graph::<(), f32>::new(); - graph.add_node(()); - graph - } - - fn graph5() -> Graph<(), f32> { - let mut graph = Graph::<(), f32>::new(); - let n0 = graph.add_node(()); - let n1 = graph.add_node(()); - let n2 = graph.add_node(()); - - graph.add_edge(n0, n1, 1.0); - graph.add_edge(n1, n0, -10.0); - graph.add_edge(n2, n2, 5.0); - graph - } - - #[test] - fn test_johnson_fully_connected() { - assert_eq!( - johnson(&graph1(), |edge| *edge.weight()), - Ok(vec![ - vec![0.0, 33.0, 52.0, 38.0, 18.0], - vec![33.0, 0.0, 20.0, 6.0, 15.0], - vec![52.0, 20.0, 0.0, 14.0, 34.0], - vec![38.0, 6.0, 14.0, 0.0, 20.0], - vec![18.0, 15.0, 34.0, 20.0, 0.0] - ]) - ); - } - - #[test] - fn test_johnson() { - let inf = f32::INFINITY; - - assert_eq!( - johnson(&graph2(), |edge| *edge.weight()), - Ok(vec![ - vec![0.0, 1.0, -4.0, 16.0, 6.0, inf], - vec![inf, 0.0, -5.0, 15.0, 5.0, inf], - vec![inf, 8.0, 0.0, 23.0, 13.0, inf], - vec![inf, -12.0, -20.0, 0.0, -7.0, inf], - vec![inf, -2.0, -10.0, 10.0, 0.0, inf], - vec![inf, -4.0, -9.0, 11.0, 1.0, 0.0], - ]) - ); - } - - #[test] - fn test_johnson_empty_graph() { - let graph = Graph::<(), f32>::new(); - assert_eq!(johnson(&graph, |edge| *edge.weight()), Ok(vec![])); - } - - #[test] - fn test_johnson_single_node() { - assert_eq!( - johnson(&graph4(), |edge| *edge.weight()), - Ok(vec![vec![0.0]]) - ); - } - - #[test] - fn test_johnson_negative_cycle() { - assert_eq!( - johnson(&graph3(), |edge| *edge.weight()), - Err(NegativeCycle(())) - ); - - assert_eq!( - johnson(&graph5(), |edge| *edge.weight()), - Err(NegativeCycle(())) - ); - - let mut graph = graph1(); - graph.add_edge(3.into(), 3.into(), -5.0); - assert_eq!( - johnson(&graph, |edge| *edge.weight()), - Err(NegativeCycle(())) - ); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_johnson_random() { - let mut rng = rand::thread_rng(); - - for n in 2..=50 { - let graph = Graph::<(), f64, Directed, usize>::from_edges( - random_weighted_digraph(n, rng.gen_range(1..n * (n - 1)), -10f64, 1000f64) - .unwrap() - .into_iter() - .map(|(edge, w)| (edge.0, edge.1, w.round())), - ); - - assert_eq!( - johnson(&graph, |edge| *edge.weight()), - floyd_warshall(&graph, |edge| *edge.weight()) - ); - } - } -} diff --git a/src/shortest_path/mod.rs b/src/shortest_path/mod.rs index 4cd0246..fee22ec 100644 --- a/src/shortest_path/mod.rs +++ b/src/shortest_path/mod.rs @@ -8,11 +8,9 @@ pub use shortest_distances::shortest_distances; mod floyd_warshall; pub use floyd_warshall::{distance_map, floyd_warshall}; -mod spfa; -pub use spfa::spfa; +pub use petgraph::algo::spfa; -mod johnson; -pub use johnson::johnson; +pub use petgraph::algo::johnson; mod seidel; pub use seidel::{apd, seidel}; diff --git a/src/shortest_path/spfa.rs b/src/shortest_path/spfa.rs deleted file mode 100644 index 08e4e6b..0000000 --- a/src/shortest_path/spfa.rs +++ /dev/null @@ -1,306 +0,0 @@ -//use std::collections::VecDeque; -use petgraph::algo::{FloatMeasure, NegativeCycle}; -use petgraph::visit::{EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeIndexable}; - -/// [Shortest Path Faster Algorithm](https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm). -/// Compute shortest distances from node `source` to all other. -/// -/// Compute shortest paths lengths in a weighted graph with positive or negative edge weights, -/// but with no negative cycles. -/// -/// ## Arguments -/// * `graph`: weighted graph. -/// * `source`: the source vertex, for which we calculate the lengths of the shortest paths to all the others. -/// -/// ## Returns -/// * `Err`: if graph contains negative cycle. -/// * `Ok`: a pair of a vector of shortest distances and a vector -/// of predecessors of each vertex along the shortest path. -/// -/// # Examples -/// -/// ``` -/// use petgraph::Graph; -/// use graphalgs::shortest_path::spfa; -/// -/// let mut g = Graph::new(); -/// let a = g.add_node(()); // node with no weight -/// let b = g.add_node(()); -/// let c = g.add_node(()); -/// let d = g.add_node(()); -/// let e = g.add_node(()); -/// let f = g.add_node(()); -/// g.extend_with_edges(&[ -/// (0, 1, 3.0), -/// (0, 3, 2.0), -/// (1, 2, 1.0), -/// (1, 5, 7.0), -/// (2, 4, -4.0), -/// (3, 4, -1.0), -/// (4, 5, 1.0), -/// ]); -/// -/// // Graph represented with the weight of each edge. -/// // -/// // 3 1 -/// // a ----- b ----- c -/// // | 2 | 7 | -/// // d f | -4 -/// // | -1 | 1 | -/// // \------ e ------/ -/// -/// assert_eq!(spfa(&g, a), Ok((vec![0.0 , 3.0, 4.0, 2.0, 0.0, 1.0], -/// vec![None, Some(a), Some(b), Some(a), Some(c), Some(e)] -/// )) -/// ); -/// -/// -/// // Negative cycle. -/// let graph = Graph::<(), f32>::from_edges(&[ -/// (0, 1, 2.0), (1, 2, 2.0), (2, 0, -10.0)]); -/// -/// assert!(spfa(&graph, 0.into()).is_err()); -/// ``` -#[allow(clippy::type_complexity)] -pub fn spfa( - graph: G, - source: G::NodeId, -) -> Result<(Vec, Vec>), NegativeCycle> -where - G: IntoEdges + IntoNodeIdentifiers + NodeIndexable, - G::EdgeWeight: FloatMeasure, -{ - let ix = |i| graph.to_index(i); - - let mut predecessor = vec![None; graph.node_bound()]; - let mut distance = vec![<_>::infinite(); graph.node_bound()]; - distance[ix(source)] = <_>::zero(); - - // Queue of vertices capable of relaxation of the found shortest distances. - let mut queue: Vec = Vec::with_capacity(graph.node_bound()); - let mut in_queue = vec![false; graph.node_bound()]; - queue.push(source); - in_queue[ix(source)] = true; - - // We will keep track of how many times each vertex appeared - // in the queue to be able to detect a negative cycle. - let mut visits = vec![0; graph.node_bound()]; - - while let Some(i) = queue.pop() { - in_queue[ix(i)] = false; - - // In a graph without a negative cycle, no vertex can improve - // the shortest distances by more than |V| times. - if visits[ix(i)] >= graph.node_bound() { - return Err(NegativeCycle(())); - } - visits[ix(i)] += 1; - - for edge in graph.edges(i) { - let j = edge.target(); - let w = *edge.weight(); - - if distance[ix(i)] + w < distance[ix(j)] { - distance[ix(j)] = distance[ix(i)] + w; - predecessor[ix(j)] = Some(i); - - if !in_queue[ix(j)] { - in_queue[ix(j)] = true; - queue.push(j); - } - } - } - } - - Ok((distance, predecessor)) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::generate::random_weighted_digraph; - use crate::shortest_path::bellman_ford; - use petgraph::graph::Graph; - use petgraph::Directed; - use rand::Rng; - - fn graph1() -> Graph<(), f64> { - let mut graph = Graph::<(), f64>::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, 10.0); - graph.add_edge(n0, n2, 5.0); - graph.add_edge(n1, n2, 2.0); - graph.add_edge(n2, n3, -10.0); - graph.add_edge(n3, n1, -1.0); - graph.add_edge(n1, n3, 16.0); - - graph - } - - fn graph2() -> Graph<(), f32> { - let mut graph = Graph::<(), f32>::new(); - let n0 = graph.add_node(()); - let n1 = graph.add_node(()); - let n2 = graph.add_node(()); - - graph.add_edge(n0, n1, 1.0); - graph.add_edge(n1, n0, -10.0); - graph.add_edge(n2, n2, 5.0); - graph - } - - #[test] - fn test_spfa() { - let inf = f32::INFINITY; - - let mut graph = Graph::<(), f32>::new(); - let n0 = graph.add_node(()); - let n1 = graph.add_node(()); - let n2 = graph.add_node(()); - let n3 = graph.add_node(()); - let n4 = graph.add_node(()); - let n5 = graph.add_node(()); - - graph.add_edge(n0, n1, 1.0); - graph.add_edge(n5, n1, -4.0); - graph.add_edge(n1, n4, 5.0); - graph.add_edge(n4, n1, 5.0); - graph.add_edge(n2, n1, 8.0); - graph.add_edge(n4, n3, 10.0); - graph.add_edge(n3, n2, 0.0); - graph.add_edge(n3, n2, -20.0); - - assert_eq!( - spfa(&graph, 0.into()).unwrap().0, - vec![0.0, 1.0, -4.0, 16.0, 6.0, inf] - ); - assert_eq!( - spfa(&graph, 1.into()).unwrap().0, - vec![inf, 0.0, -5.0, 15.0, 5.0, inf] - ); - assert_eq!( - spfa(&graph, 2.into()).unwrap().0, - vec![inf, 8.0, 0.0, 23.0, 13.0, inf] - ); - assert_eq!( - spfa(&graph, 3.into()).unwrap().0, - vec![inf, -12.0, -20.0, 0.0, -7.0, inf] - ); - assert_eq!( - spfa(&graph, 4.into()).unwrap().0, - vec![inf, -2.0, -10.0, 10.0, 0.0, inf] - ); - assert_eq!( - spfa(&graph, 5.into()).unwrap().0, - vec![inf, -4.0, -9.0, 11.0, 1.0, 0.0] - ); - } - - #[test] - fn test_spfa_strongly_connected() { - let mut graph = Graph::<(), f32>::new(); - let n0 = graph.add_node(()); - let n1 = graph.add_node(()); - let n2 = graph.add_node(()); - let n3 = graph.add_node(()); - let n4 = graph.add_node(()); - - graph.add_edge(n0, n1, 40.0); - graph.add_edge(n0, n4, 18.0); - graph.add_edge(n1, n0, 40.0); - graph.add_edge(n1, n4, 15.0); - graph.add_edge(n1, n2, 22.0); - graph.add_edge(n1, n3, 6.0); - graph.add_edge(n2, n1, 22.0); - graph.add_edge(n2, n3, 14.0); - graph.add_edge(n3, n4, 20.0); - graph.add_edge(n3, n1, 6.0); - graph.add_edge(n3, n2, 14.0); - graph.add_edge(n4, n0, 18.0); - graph.add_edge(n4, n1, 15.0); - graph.add_edge(n4, n3, 20.0); - - assert_eq!( - spfa(&graph, 0.into()).unwrap().0, - vec![0.0, 33.0, 52.0, 38.0, 18.0] - ); - assert_eq!( - spfa(&graph, 1.into()).unwrap().0, - vec![33.0, 0.0, 20.0, 6.0, 15.0] - ); - assert_eq!( - spfa(&graph, 2.into()).unwrap().0, - vec![52.0, 20.0, 0.0, 14.0, 34.0] - ); - assert_eq!( - spfa(&graph, 3.into()).unwrap().0, - vec![38.0, 6.0, 14.0, 0.0, 20.0] - ); - assert_eq!( - spfa(&graph, 4.into()).unwrap().0, - vec![18.0, 15.0, 34.0, 20.0, 0.0] - ); - } - - #[test] - fn test_spfa_single_node() { - let mut graph = Graph::<(), f32>::new(); - graph.add_node(()); - assert_eq!(spfa(&graph, 0.into()).unwrap().0, vec![0.0]); - } - - #[test] - fn test_spfa_negative_cycle() { - assert!(spfa(&graph1(), 0.into()).is_err()); - assert!(spfa(&graph2(), 0.into()).is_err()); - } - - #[test] - #[cfg_attr(miri, ignore)] - fn test_spfa_random() { - // Random tests against bellman_ford - let mut rng = rand::thread_rng(); - - for n in 2..=50 { - let graph = Graph::<(), f64, Directed, usize>::from_edges( - random_weighted_digraph(n, rng.gen_range(1..n * (n - 1)), -10f64, 1000f64) - .unwrap() - .into_iter() - .map(|(edge, w)| (edge.0, edge.1, w.round())), - ); - - for v in 0..graph.node_count() { - let spfa_res = spfa(&graph, v.into()); - let bf_res = bellman_ford(&graph, v.into()); - - if let Ok((spfa_dist, spfa_pred)) = spfa_res { - let bf_res = bf_res.unwrap(); - let bf_dist = bf_res.distances; - let bf_pred = bf_res.predecessors; - assert_eq!(spfa_dist, bf_dist); - - // Several shortest paths can exist to vertex. - for i in 0..graph.node_count() { - let s = spfa_pred[i]; - let b = bf_pred[i]; - match s { - None => assert!(b.is_none()), - Some(pred) => assert_eq!( - spfa_dist[graph.to_index(pred)] - + graph[graph.find_edge(pred, i.into()).unwrap()], - bf_dist[graph.to_index(pred)] - + graph[graph.find_edge(pred, i.into()).unwrap()], - ), - } - } - } else { - assert!(bf_res.is_err()); - } - } - } - } -} From df6cde708ef79441a212b2d9f0c27ff6eaf602de Mon Sep 17 00:00:00 2001 From: starovoid Date: Sat, 12 Jul 2025 22:16:43 +0300 Subject: [PATCH 2/4] Bring the code into compliance with petgraph 0.8 --- src/adj_matrix.rs | 15 ++++++++------- src/traits/edge_count.rs | 6 ++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/adj_matrix.rs b/src/adj_matrix.rs index fa175ea..9ec1bc5 100644 --- a/src/adj_matrix.rs +++ b/src/adj_matrix.rs @@ -122,8 +122,9 @@ mod test { use petgraph::csr::Csr; use petgraph::graph::Graph; use petgraph::graphmap::{DiGraphMap, UnGraphMap}; - use petgraph::matrix_graph::MatrixGraph; + use petgraph::matrix_graph::{MatrixGraph, UnMatrix}; use petgraph::stable_graph::StableGraph; + use std::hash::RandomState; fn float_to_scalar(w: &f64) -> f64 { *w @@ -189,7 +190,7 @@ mod test { #[test] fn test_unweighted_matrix_directed() { - let mut graph = MatrixGraph::new(); + let mut graph = MatrixGraph::<_, _, RandomState>::new(); let a = graph.add_node('a'); let b = graph.add_node('b'); let c = graph.add_node('c'); @@ -211,7 +212,7 @@ mod test { #[test] fn test_unweighted_matrix_undirected() { - let mut graph = MatrixGraph::new_undirected(); + let mut graph = UnMatrix::<_, _, RandomState>::new_undirected(); let a = graph.add_node('a'); let b = graph.add_node('b'); let c = graph.add_node('c'); @@ -369,7 +370,7 @@ mod test { #[test] fn test_weighted_matrix_undirected() { - let mut graph = MatrixGraph::new_undirected(); + let mut graph = UnMatrix::<_, _, RandomState>::new_undirected(); let a = graph.add_node('a'); let b = graph.add_node('b'); let c = graph.add_node('c'); @@ -390,7 +391,7 @@ mod test { #[test] fn test_weighted_matrix_directed() { - let mut graph = MatrixGraph::new(); + let mut graph = MatrixGraph::<_, _, RandomState>::new(); let a = graph.add_node('a'); let b = graph.add_node('b'); let c = graph.add_node('c'); @@ -411,7 +412,7 @@ mod test { #[test] fn test_weighted_graphmap_undirected() { - let mut graph = UnGraphMap::new(); + let mut graph = UnGraphMap::<_, _, RandomState>::new(); let a = graph.add_node('a'); let b = graph.add_node('b'); let c = graph.add_node('c'); @@ -432,7 +433,7 @@ mod test { #[test] fn test_weighted_graphmap_directed() { - let mut graph = DiGraphMap::new(); + let mut graph = DiGraphMap::<_, _, RandomState>::new(); let a = graph.add_node('a'); let b = graph.add_node('b'); let c = graph.add_node('c'); diff --git a/src/traits/edge_count.rs b/src/traits/edge_count.rs index 346ded6..f76e866 100644 --- a/src/traits/edge_count.rs +++ b/src/traits/edge_count.rs @@ -1,5 +1,7 @@ //! Graph with known number of edges. +use std::hash::BuildHasher; + use petgraph::csr::Csr; use petgraph::graph::{Graph, IndexType}; use petgraph::graphmap::{GraphMap, NodeTrait}; @@ -47,13 +49,13 @@ impl EdgeCount for GraphMap { } } -impl<'a, N: 'a, E: 'a, Ty: EdgeType> EdgeCount for &'a MatrixGraph { +impl<'a, N: 'a, E: 'a, S: BuildHasher, Ty: EdgeType> EdgeCount for &'a MatrixGraph { fn number_of_edges(self) -> usize { self.edge_count() } } -impl EdgeCount for MatrixGraph { +impl EdgeCount for MatrixGraph { fn number_of_edges(self) -> usize { self.edge_count() } From b85f045a6650f1c23422e657f28a4546924ae29b Mon Sep 17 00:00:00 2001 From: starovoid Date: Sat, 12 Jul 2025 22:20:10 +0300 Subject: [PATCH 3/4] Fix benches --- benches/all_simple_shortest_paths.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/all_simple_shortest_paths.rs b/benches/all_simple_shortest_paths.rs index b5dd37b..01b6c9c 100644 --- a/benches/all_simple_shortest_paths.rs +++ b/benches/all_simple_shortest_paths.rs @@ -119,7 +119,7 @@ fn n_spfa_bench_helper(c: &mut BenchmarkGroup, node_count: usize, dens b.iter(|| { let mut output = Vec::with_capacity(node_count); for n in graph.node_identifiers() { - output.push(spfa(&graph, n)); + output.push(spfa(&graph, n, |_| 1.0)); } black_box(output) }) From 9052cba29d6616d54cd536689a9b6b890642c79a Mon Sep 17 00:00:00 2001 From: starovoid Date: Sat, 12 Jul 2025 22:22:11 +0300 Subject: [PATCH 4/4] Satisfy clippy --- src/generate/randomg.rs | 4 ++-- src/mst/boruvka.rs | 2 +- src/mst/prim.rs | 2 +- src/shortest_path/floyd_warshall.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/generate/randomg.rs b/src/generate/randomg.rs index 6d85de0..e29425f 100644 --- a/src/generate/randomg.rs +++ b/src/generate/randomg.rs @@ -84,7 +84,7 @@ pub fn random_digraph( /// ## Returns /// * `Err`: if the required number of vertices is greater than the maximum possible. /// * `Ok`: set `HashMap<(usize, usize), K>` of edges with `usize` vertex indices, -/// where `K` is the type of weights. +/// where `K` is the type of weights. /// /// # Examples /// @@ -206,7 +206,7 @@ pub fn random_ungraph( /// ## Returns /// * `Err`: if the required number of vertices is greater than the maximum possible. /// * `Ok`: set `HashMap<(usize, usize), K>` of edges with `usize` vertex indices, -/// where `K` is the type of weights. +/// where `K` is the type of weights. /// /// # Examples /// diff --git a/src/mst/boruvka.rs b/src/mst/boruvka.rs index 0ff855d..a251741 100644 --- a/src/mst/boruvka.rs +++ b/src/mst/boruvka.rs @@ -19,7 +19,7 @@ use std::collections::HashSet; /// /// ## Returns /// * `HashSet<(usize, usize)>`: the set of edges of the resulting MST, -/// where each edge is denoted by a pair of vertex indices, index order is random. +/// where each edge is denoted by a pair of vertex indices, index order is random. /// /// # Examples /// ``` diff --git a/src/mst/prim.rs b/src/mst/prim.rs index 4ab9311..a08c865 100644 --- a/src/mst/prim.rs +++ b/src/mst/prim.rs @@ -16,7 +16,7 @@ use petgraph::visit::{ /// /// ## Returns /// * `Vec<(usize, usize)>`: the vector of edges of the resulting MST, -/// where each edge is denoted by a pair of vertex indices, index order is random. +/// where each edge is denoted by a pair of vertex indices, index order is random. /// /// # Examples /// ``` diff --git a/src/shortest_path/floyd_warshall.rs b/src/shortest_path/floyd_warshall.rs index ab8a645..9fa36bc 100644 --- a/src/shortest_path/floyd_warshall.rs +++ b/src/shortest_path/floyd_warshall.rs @@ -16,7 +16,7 @@ use petgraph::visit::{EdgeRef, GraphProp, IntoEdgeReferences, IntoNodeIdentifier /// ## Returns /// * `Err`: if graph contains negative cycle. /// * `Ok`: matrix `Vec>` of shortest distances, in cell **(i, j)** of which the length of the shortest path -/// from node **i** to node **j** is stored. +/// from node **i** to node **j** is stored. /// /// # Examples ///