diff --git a/src/algorithms.rs b/src/algorithms.rs index 3f2aa0e..5c6d147 100644 --- a/src/algorithms.rs +++ b/src/algorithms.rs @@ -14,15 +14,15 @@ //! [Breadth-first search] traverses a graph topology, exploring all neighboring vertices first //! before descending further into their neighborhoods. //! -//! Variants: [`bfs`], [`bfs_distances`], [`bfs_find`], [`bfs_find_where`] +//! Variants: [`bfs`], [`bfs_distances`], [`bfs_find`], [`bfs_find_where`]. //! -//! # Depth-first search +//! # Depth-first search //! //! [Depth-first search] traverses a graph topology, exploring each branch path as far as possible //! first before backtracking and exploring other branches. //! //! Variants: [`dfs`], [`dfs_visited`], [`dfs_find`], [`dfs_find_where`], [`dfs_find_path`], -//! [`dfs_find_path_where`] +//! [`dfs_find_path_where`]. //! //! [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search //! [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search @@ -52,17 +52,21 @@ impl Ord for DistanceOrderedVertex { } } -/// Return data type for [`dijkstra`] and [`dijkstra unweighted`]. +/// Return data type for [`dijkstra`] and [`dijkstra_unweighted`]. pub struct DijkstraResult { /// Vertex map of minimum distances from a given `source` vertex. pub distances: VertexMap>, - /// Vertex map of predecessors on some shortest path from a given `source` vertex. pub predecessors: VertexMap>, } // TODO: Generalize the return type of the weight function. -/// Dijkstra's algorithm with custom edge weights, returns minimum distances and predecessors. +/// [Dijkstra's algorithm] with custom edge weights, returns minimum distances and predecessors. +/// +/// Calculates the shortest paths from `source` to all vertices in `graph` with edge weights given +/// by `weight` function. Returns the distances from `source` to each vertex, and the predecessors +/// of each vertex on some shortest path from `source` to that vertex. Returns `None` for any vertex +/// not connected to `source`. /// /// # Panics /// @@ -85,6 +89,8 @@ pub struct DijkstraResult { /// assert_eq!(result.distances[target], Some(5)); /// assert_eq!(result.predecessors[target], Some(source)); /// ``` +/// +/// [Dijkstra's algorithm]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm pub fn dijkstra(graph: &G, source: G::Vertex, weight: W) -> DijkstraResult where G: GraphTopology, @@ -100,7 +106,11 @@ where } } -/// Dijkstra's algorithm with custom edge weights, returns minimum distances. +/// [Dijkstra's algorithm] with custom edge weights, returns minimum distances. +/// +/// Calculates the shortest paths from `source` to all vertices in `graph` with edge weights given +/// by `weight` function. Returns the distances from `source` to each vertex. Returns `None` for any +/// vertex not connected to `source`. /// /// # Panics /// @@ -110,7 +120,7 @@ where /// /// ``` /// # use grapherity::prelude::*; -/// # use grapherity::algorithms::{dijkstra, dijkstra_distances}; +/// # use grapherity::algorithms::dijkstra_distances; /// # use grapherity::models::Graph; /// let mut graph = Graph::new(); /// let source = graph.add_vertex(); @@ -122,6 +132,8 @@ where /// let distances = dijkstra_distances(&graph, source, |e| weights[e]); /// assert_eq!(distances[target], Some(5)); /// ``` +/// +/// [Dijkstra's algorithm]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm pub fn dijkstra_distances( graph: &G, source: G::Vertex, @@ -134,8 +146,13 @@ where dijkstra_impl(graph, source, weight, |_, _| {}) } -/// Dijkstra's algorithm with constant weights of *1* for all edges, returns minimum distances and -/// predecessors. +/// [Dijkstra's algorithm] with unit edge weights, returns minimum distances and predecessors. +/// +/// Calculates the shortest paths from `source` to all vertices in an unweighted `graph`. Returns +/// the distances from `source` to each vertex, and the predecessors of each vertex on some shortest +/// path from `source` to that vertex. Returns `None` for any vertex not connected to `source`. +/// +/// Prefer [`bfs`] for unweighted graphs, it has better time and space complexity. /// /// # Panics /// @@ -145,7 +162,7 @@ where /// /// ``` /// # use grapherity::prelude::*; -/// # use grapherity::algorithms::{dijkstra, dijkstra_unweighted}; +/// # use grapherity::algorithms::dijkstra_unweighted; /// # use grapherity::models::Graph; /// let mut graph = Graph::new(); /// let source = graph.add_vertex(); @@ -156,6 +173,8 @@ where /// assert_eq!(result.distances[target], Some(1)); /// assert_eq!(result.predecessors[target], Some(source)); /// ``` +/// +/// [Dijkstra's algorithm]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm pub fn dijkstra_unweighted(graph: &G, source: G::Vertex) -> DijkstraResult where G: GraphTopology, @@ -163,7 +182,13 @@ where dijkstra(graph, source, |_| 1) } -/// Dijkstra's algorithm with constant weights of *1* for all edges, returns minimum distances. +/// [Dijkstra's algorithm] with unit edge weights, returns minimum distances. +/// +/// Calculates the shortest paths from `source` to all vertices in an unweighted `graph`. Returns +/// the distances from `source` to each vertex. Returns `None` for any vertex not connected to +/// `source`. +/// +/// Prefer [`bfs_distances`] for unweighted graphs, it has better time and space complexity. /// /// # Panics /// @@ -173,7 +198,7 @@ where /// /// ``` /// # use grapherity::prelude::*; -/// # use grapherity::algorithms::{dijkstra, dijkstra_distances_unweighted}; +/// # use grapherity::algorithms::dijkstra_distances_unweighted; /// # use grapherity::models::Graph; /// let mut graph = Graph::new(); /// let source = graph.add_vertex(); @@ -183,6 +208,8 @@ where /// let distances = dijkstra_distances_unweighted(&graph, source); /// assert_eq!(distances[target], Some(1)); /// ``` +/// +/// [Dijkstra's algorithm]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm pub fn dijkstra_distances_unweighted( graph: &G, source: G::Vertex, @@ -233,11 +260,44 @@ where distances } +/// Return data type for [`bfs`]. pub struct BfsResult { + /// Vertex map of minimum distances from a given `source` vertex. pub distances: VertexMap>, + /// Vertex map of predecessors on some shortest path from a given `source` vertex. pub predecessors: VertexMap>, } +/// [Breadth-first search] traversal from `source`, returns distances and predecessors. +/// +/// Traverses vertices in `graph` starting from `source`, exploring all neighbors before descending +/// further. Returns the distances from `source` to each vertex, and the predecessors of each vertex +/// on some shortest path from `source` to that vertex. Returns `None` for any vertex not connected +/// to `source`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::bfs; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// let result = bfs(&graph, source); +/// assert_eq!(result.distances[target], Some(1)); +/// assert_eq!(result.predecessors[target], Some(source)); +/// ``` +/// +/// [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search pub fn bfs(graph: &G, source: G::Vertex) -> BfsResult where G: GraphTopology, @@ -253,6 +313,34 @@ where } } +/// [Breadth-first search] traversal from `source`, returns distances. +/// +/// Traverses vertices in `graph` starting from `source`, exploring all neighbors before descending +/// further. Returns the distances from `source` to each vertex. Returns `None` for any vertex not +/// connected to `source`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::bfs_distances; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// let distances = bfs_distances(&graph, source); +/// assert_eq!(distances[target], Some(1)); +/// ``` +/// +/// [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search pub fn bfs_distances(graph: &G, source: G::Vertex) -> VertexMap> where G: GraphTopology, @@ -260,6 +348,33 @@ where bfs_impl(graph, source, |_, _| true).distances } +/// [Breadth-first search] from `source` for `target`, returns the distance. +/// +/// Traverses vertices in `graph` starting from `source` until `target` is found, exploring all +/// neighbors before descending further. Returns the minimum distance from `source` to `target` if +/// `target` is a valid vertex of `graph` connected to `source`, or `None` otherwise. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::bfs_find; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// assert_eq!(bfs_find(&graph, source, target), Some(1)); +/// ``` +/// +/// [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search pub fn bfs_find(graph: &G, source: G::Vertex, target: G::Vertex) -> Option where G: GraphTopology, @@ -267,6 +382,35 @@ where bfs_find_where(graph, source, |v| v == target).map(|(_, distance)| distance) } +/// [Breadth-first search] from `source` for a vertex matching `predicate`, returns the vertex and +/// its distance. +/// +/// Traverses vertices in `graph` starting from `source` until a vertex satisfying `predicate` is +/// found, exploring all neighbors before descending further. Returns the first vertex satisfying +/// `predicate` and its minimum distance from `source`, or `None` if no such vertex is connected to +/// `source`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::bfs_find_where; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// assert_eq!(bfs_find_where(&graph, source, |v| v == target), Some((target, 1))); +/// ``` +/// +/// [Breadth-first search]: https://en.wikipedia.org/wiki/Breadth-first_search pub fn bfs_find_where(graph: &G, source: G::Vertex, predicate: P) -> Option<(G::Vertex, u32)> where G: GraphTopology, @@ -315,11 +459,44 @@ where } } +/// Return data type for [`dfs`]. pub struct DfsResult { + /// Vertex map indicating which vertices were visited during the search. pub visited: VertexMap, + /// Vertex map of predecessors on the DFS tree path from a given `source` vertex. pub predecessors: VertexMap>, } +/// [Depth-first search] traversal from `source`, returns visited vertices and predecessors. +/// +/// Traverses vertices in `graph` starting from `source`, exploring each branch as far as possible +/// before backtracking. Returns for each vertex whether it was visited, and the predecessors of +/// each vertex on the DFS tree path from `source` to that vertex. Any vertex not connected to +/// `source` is marked unvisited and has no predecessor. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::dfs; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// let result = dfs(&graph, source); +/// assert!(result.visited[target]); +/// assert_eq!(result.predecessors[target], Some(source)); +/// ``` +/// +/// [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search pub fn dfs(graph: &G, source: G::Vertex) -> DfsResult where G: GraphTopology, @@ -335,6 +512,34 @@ where } } +/// [Depth-first search] traversal from `source`, returns visited vertices. +/// +/// Traverses vertices in `graph` starting from `source`, exploring each branch as far as possible +/// before backtracking. Returns a map indicating which vertices were visited, i.e. which vertices +/// are connected to `source`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::dfs_visited; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// let visited = dfs_visited(&graph, source); +/// assert!(visited[target]); +/// ``` +/// +/// [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search pub fn dfs_visited(graph: &G, source: G::Vertex) -> VertexMap where G: GraphTopology, @@ -342,6 +547,33 @@ where dfs_impl(graph, source, |_, _| true).visited } +/// [Depth-first search] from `source` for `target`, returns whether it was found. +/// +/// Traverses vertices in `graph` starting from `source` until `target` is found, exploring each +/// branch as far as possible before backtracking. Returns `true` if `target` is a valid vertex of +/// `graph` connected to `source`, or `false` otherwise. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::dfs_find; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// assert!(dfs_find(&graph, source, target)); +/// ``` +/// +/// [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search pub fn dfs_find(graph: &G, source: G::Vertex, target: G::Vertex) -> bool where G: GraphTopology, @@ -349,6 +581,33 @@ where dfs_find_where(graph, source, |v| v == target).is_some() } +/// [Depth-first search] from `source` for a vertex matching `predicate`, returns the vertex. +/// +/// Traverses vertices in `graph` starting from `source` until a vertex satisfying `predicate` is +/// found, exploring each branch as far as possible before backtracking. Returns the first vertex +/// satisfying `predicate`, or `None` if no such vertex is connected to `source`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::dfs_find_where; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// graph.add_edge(source, target); +/// +/// assert_eq!(dfs_find_where(&graph, source, |v| v == target), Some(target)); +/// ``` +/// +/// [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search pub fn dfs_find_where(graph: &G, source: G::Vertex, predicate: P) -> Option where G: GraphTopology, @@ -396,6 +655,35 @@ where } } +/// [Depth-first search] from `source` for `target`, returns the path as a sequence of edges. +/// +/// Traverses vertices in `graph` starting from `source` until `target` is found, exploring each +/// branch as far as possible before backtracking. Returns some path from `source` to `target` as a +/// sequence of edges in traversal order if `target` is a valid vertex of `graph` connected to +/// `source`, or `None` otherwise. The returned path is empty if and only if `source` equals +/// `target`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::dfs_find_path; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// let e = graph.add_edge(source, target); +/// +/// assert_eq!(dfs_find_path(&graph, source, target), Some(vec![e])); +/// ``` +/// +/// [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search pub fn dfs_find_path(graph: &G, source: G::Vertex, target: G::Vertex) -> Option> where G: GraphTopology, @@ -403,6 +691,36 @@ where dfs_find_path_where(graph, source, |v| v == target) } +/// [Depth-first search] from `source` for a vertex matching `predicate`, returns the path as a +/// sequence of edges. +/// +/// Traverses vertices in `graph` starting from `source` until a vertex satisfying `predicate` is +/// found, exploring each branch as far as possible before backtracking. Returns some path from +/// `source` to the first vertex satisfying `predicate` as a sequence of edges in traversal order, +/// or `None` if no such vertex is connected to `source`. The returned path is empty if and only if +/// `source` satisfies `predicate`. +/// +/// Time complexity is *O(|V| + |E|)*, space complexity is *O(|V|)*. +/// +/// # Panics +/// +/// Panics if `source` is not a valid vertex of `graph`. +/// +/// # Examples +/// +/// ``` +/// # use grapherity::prelude::*; +/// # use grapherity::algorithms::dfs_find_path_where; +/// # use grapherity::models::Graph; +/// let mut graph = Graph::new(); +/// let source = graph.add_vertex(); +/// let target = graph.add_vertex(); +/// let e = graph.add_edge(source, target); +/// +/// assert_eq!(dfs_find_path_where(&graph, source, |v| v == target), Some(vec![e])); +/// ``` +/// +/// [Depth-first search]: https://en.wikipedia.org/wiki/Depth-first_search pub fn dfs_find_path_where(graph: &G, source: G::Vertex, predicate: P) -> Option> where G: GraphTopology,