@@ -140,6 +140,177 @@ where
140140 }
141141}
142142
143+ struct BFSAncestryWalker < G , N , VM > {
144+ graph : G ,
145+ walker : Bfs < N , VM > ,
146+ }
147+
148+ impl <
149+ G : GraphRef + Visitable + IntoNeighborsDirected < NodeId = N > ,
150+ N : Copy + Clone + PartialEq ,
151+ VM : VisitMap < N > ,
152+ > Iterator for BFSAncestryWalker < G , N , VM >
153+ {
154+ type Item = ( N , Vec < N > ) ;
155+
156+ fn next ( & mut self ) -> Option < Self :: Item > {
157+ self . walker . next ( self . graph ) . map ( |nx| {
158+ (
159+ nx,
160+ self . graph
161+ . neighbors_directed ( nx, petgraph:: Direction :: Outgoing )
162+ . collect ( ) ,
163+ )
164+ } )
165+ }
166+ }
167+
168+ /// Return the successors in a breadth-first-search from a source node
169+ ///
170+ /// Each iterator step returns the node indices in a bfs order from
171+ /// the specified node in the form:
172+ ///
173+ /// `(Parent Node, vec![children nodes])`
174+ ///
175+ /// # Arguments:
176+ ///
177+ /// * `graph` - The graph to search
178+ /// * `node` - The node to search from
179+ ///
180+ /// # Returns
181+ ///
182+ /// An iterator of nodes in BFS order where each item in the iterator
183+ /// is a tuple of the `NodeId` for the parent and a `Vec` of node ids
184+ /// it's successors. If a node in the bfs traversal doesn't have any
185+ /// successors it will still be present but contain an empty vec.
186+ ///
187+ /// # Example
188+ ///
189+ /// ```rust
190+ /// use rustworkx_core::traversal::bfs_successors;
191+ /// use rustworkx_core::petgraph::stable_graph::{StableDiGraph, NodeIndex};
192+ ///
193+ /// let graph: StableDiGraph<(), ()> = StableDiGraph::from_edges(&[
194+ /// (0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)
195+ /// ]);
196+ /// let successors: Vec<(usize, Vec<usize>)> = bfs_successors(&graph, NodeIndex::new(3))
197+ /// .map(|(x, succ)| (x.index(), succ.iter().map(|y| y.index()).collect()))
198+ /// .collect();
199+ /// assert_eq!(vec![(3_usize, vec![4_usize]), (4, vec![5]), (5, vec![])], successors);
200+ /// ```
201+ pub fn bfs_successors < G > (
202+ graph : G ,
203+ node : G :: NodeId ,
204+ ) -> impl Iterator < Item = ( G :: NodeId , Vec < G :: NodeId > ) >
205+ where
206+ G : GraphRef + Visitable + IntoNeighborsDirected ,
207+ {
208+ BFSAncestryWalker {
209+ graph,
210+ walker : Bfs :: new ( graph, node) ,
211+ }
212+ }
213+
214+ /// Return the predecessor in a breadth-first-search from a source node
215+ ///
216+ /// Each iterator step returns the node indices in a bfs order from
217+ /// the specified node in the form:
218+ ///
219+ /// `(Child Node, vec![parent nodes])`
220+ ///
221+ /// # Arguments:
222+ ///
223+ /// * `graph` - The graph to search
224+ /// * `node` - The node to search from
225+ ///
226+ /// # Returns
227+ ///
228+ /// An iterator of nodes in BFS order where each item in the iterator
229+ /// is a tuple of the `NodeId` for the child and a `Vec` of node ids
230+ /// it's predecessors. If a node in the bfs traversal doesn't have any
231+ /// predecessors it will still be present but contain an empty vec.
232+ ///
233+ /// # Example
234+ ///
235+ /// ```rust
236+ /// use rustworkx_core::traversal::bfs_predecessors;
237+ /// use rustworkx_core::petgraph::stable_graph::{StableDiGraph, NodeIndex};
238+ ///
239+ /// let graph: StableDiGraph<(), ()> = StableDiGraph::from_edges(&[
240+ /// (0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)
241+ /// ]);
242+ /// let predecessors: Vec<(usize, Vec<usize>)> = bfs_predecessors(&graph, NodeIndex::new(3))
243+ /// .map(|(x, succ)| (x.index(), succ.iter().map(|y| y.index()).collect()))
244+ /// .collect();
245+ /// assert_eq!(vec![(3_usize, vec![1_usize]), (1, vec![0]), (0, vec![])], predecessors);
246+ /// ```
247+ pub fn bfs_predecessors < G > (
248+ graph : G ,
249+ node : G :: NodeId ,
250+ ) -> impl Iterator < Item = ( G :: NodeId , Vec < G :: NodeId > ) >
251+ where
252+ G : GraphRef + Visitable + IntoNeighborsDirected ,
253+ {
254+ let reversed = Reversed ( graph) ;
255+ BFSAncestryWalker {
256+ graph : reversed,
257+ walker : Bfs :: new ( reversed, node) ,
258+ }
259+ }
260+
261+ #[ cfg( test) ]
262+ mod test_bfs_ancestry {
263+ use super :: { bfs_predecessors, bfs_successors} ;
264+ use crate :: petgraph:: graph:: DiGraph ;
265+ use crate :: petgraph:: stable_graph:: { NodeIndex , StableDiGraph } ;
266+
267+ #[ test]
268+ fn test_bfs_predecessors_digraph ( ) {
269+ let graph: DiGraph < ( ) , ( ) > =
270+ DiGraph :: from_edges ( & [ ( 0 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 4 ) , ( 3 , 4 ) , ( 4 , 5 ) ] ) ;
271+ let predecessors: Vec < ( usize , Vec < usize > ) > = bfs_predecessors ( & graph, NodeIndex :: new ( 3 ) )
272+ . map ( |( x, succ) | ( x. index ( ) , succ. iter ( ) . map ( |y| y. index ( ) ) . collect ( ) ) )
273+ . collect ( ) ;
274+ assert_eq ! (
275+ vec![ ( 3_usize , vec![ 1_usize ] ) , ( 1 , vec![ 0 ] ) , ( 0 , vec![ ] ) ] ,
276+ predecessors
277+ ) ;
278+ }
279+
280+ #[ test]
281+ fn test_bfs_successors ( ) {
282+ let graph: DiGraph < ( ) , ( ) > =
283+ DiGraph :: from_edges ( & [ ( 0 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 4 ) , ( 3 , 4 ) , ( 4 , 5 ) ] ) ;
284+ let successors: Vec < ( usize , Vec < usize > ) > = bfs_successors ( & graph, NodeIndex :: new ( 3 ) )
285+ . map ( |( x, succ) | ( x. index ( ) , succ. iter ( ) . map ( |y| y. index ( ) ) . collect ( ) ) )
286+ . collect ( ) ;
287+ assert_eq ! (
288+ vec![ ( 3_usize , vec![ 4_usize ] ) , ( 4 , vec![ 5 ] ) , ( 5 , vec![ ] ) ] ,
289+ successors
290+ ) ;
291+ }
292+
293+ #[ test]
294+ fn test_no_predecessors ( ) {
295+ let graph: StableDiGraph < ( ) , ( ) > =
296+ StableDiGraph :: from_edges ( & [ ( 0 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 4 ) , ( 3 , 4 ) , ( 4 , 5 ) ] ) ;
297+ let predecessors: Vec < ( usize , Vec < usize > ) > = bfs_predecessors ( & graph, NodeIndex :: new ( 0 ) )
298+ . map ( |( x, succ) | ( x. index ( ) , succ. iter ( ) . map ( |y| y. index ( ) ) . collect ( ) ) )
299+ . collect ( ) ;
300+ assert_eq ! ( vec![ ( 0_usize , vec![ ] ) ] , predecessors) ;
301+ }
302+
303+ #[ test]
304+ fn test_no_successors ( ) {
305+ let graph: StableDiGraph < ( ) , ( ) > =
306+ StableDiGraph :: from_edges ( & [ ( 0 , 1 ) , ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 4 ) , ( 3 , 4 ) , ( 4 , 5 ) ] ) ;
307+ let successors: Vec < ( usize , Vec < usize > ) > = bfs_successors ( & graph, NodeIndex :: new ( 5 ) )
308+ . map ( |( x, succ) | ( x. index ( ) , succ. iter ( ) . map ( |y| y. index ( ) ) . collect ( ) ) )
309+ . collect ( ) ;
310+ assert_eq ! ( vec![ ( 5_usize , vec![ ] ) ] , successors) ;
311+ }
312+ }
313+
143314#[ cfg( test) ]
144315mod test_ancestry {
145316 use super :: { ancestors, descendants} ;
0 commit comments