@@ -14,7 +14,9 @@ use hashbrown::{HashMap, HashSet};
1414use petgraph:: visit:: { EdgeRef , IntoEdges , IntoNeighbors , IntoNodeIdentifiers , NodeCount } ;
1515use std:: hash:: Hash ;
1616
17- /// Return a list of cycles which form a basis for cycles of a given graph.
17+ /// Inner private function for `cycle_basis` and `cycle_basis_edges`.
18+ /// Returns a list of cycles which forms a basis of cycles of a given
19+ /// graph.
1820///
1921/// A basis for cycles of a graph is a minimal collection of
2022/// cycles such that any cycle in the graph can be written
@@ -29,29 +31,18 @@ use std::hash::Hash;
2931/// It may produce incorrect/unexpected results if the input graph has
3032/// parallel edges.
3133///
32- ///
3334/// Arguments:
3435///
3536/// * `graph` - The graph in which to find the basis.
3637/// * `root` - Optional node index for starting the basis search. If not
3738/// specified, an arbitrary node is chosen.
38- /// * `edges` - Optional bool for when the user requests the edges instead
39+ /// * `edges` - bool for when the user requests the edges instead
3940/// of the nodes of the cycles.
40- ///
41- /// # Example
42- /// ```rust
43- /// use petgraph::prelude::*;
44- /// use rustworkx_core::connectivity::cycle_basis;
45- ///
46- /// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
47- /// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
48- /// let mut res: Vec<Vec<NodeIndex>> = cycle_basis(&graph, Some(NodeIndex::new(0)), Some(false)).unwrap_nodes();
49- /// ```
5041
51- pub fn cycle_basis < G > (
42+ fn inner_cycle_basis < G > (
5243 graph : G ,
5344 root : Option < G :: NodeId > ,
54- edges : Option < bool > ,
45+ edges : bool ,
5546) -> EdgesOrNodes < G :: NodeId , G :: EdgeId >
5647where
5748 G : NodeCount ,
6152 G :: NodeId : Eq + Hash ,
6253 G :: EdgeId : Eq + Hash ,
6354{
64- let want_edges = edges == Some ( true ) ;
6555 let mut root_node = root;
6656 let mut graph_nodes: HashSet < G :: NodeId > = graph. node_identifiers ( ) . collect ( ) ;
6757 let mut cycles_edges: Vec < Vec < G :: EdgeId > > = Vec :: new ( ) ;
@@ -126,7 +116,7 @@ where
126116 used. insert ( neighbor, temp_set) ;
127117 // A self loop:
128118 } else if z == neighbor {
129- if want_edges {
119+ if edges {
130120 let cycle_edge: Vec < G :: EdgeId > = get_edge_between ( graph, z, z, true ) ;
131121 cycles_edges. push ( cycle_edge) ;
132122 } else {
@@ -137,7 +127,7 @@ where
137127 } else if !used. get ( & z) . unwrap ( ) . contains ( & neighbor) {
138128 let pn = used. get ( & neighbor) . unwrap ( ) ;
139129 let mut p = pred. get ( & z) . unwrap ( ) ;
140- if want_edges {
130+ if edges {
141131 let mut cycle: Vec < G :: EdgeId > = Vec :: new ( ) ;
142132 // Retreive all edges from z to neighbor.
143133 let mut neigh_edge: Vec < G :: EdgeId > =
@@ -191,67 +181,149 @@ where
191181 graph_nodes = graph_nodes. difference ( & temp_hashset) . copied ( ) . collect ( ) ;
192182 root_node = None ;
193183 }
194- if want_edges {
184+ if edges {
195185 EdgesOrNodes :: Edges ( cycles_edges)
196186 } else {
197187 EdgesOrNodes :: Nodes ( cycles_nodes)
198188 }
199189}
200190
201191/// Enum for custom return types of `cycle_basis()`.
202- pub enum EdgesOrNodes < N , E > {
192+ enum EdgesOrNodes < N , E > {
203193 Nodes ( Vec < Vec < N > > ) ,
204194 Edges ( Vec < Vec < E > > ) ,
205195}
206196/// Functions used to unwrap the desired datatype of `EdgesOrNodes`.
207197impl < N , E > EdgesOrNodes < N , E > {
208- pub fn unwrap_nodes ( self ) -> Vec < Vec < N > > {
209- use EdgesOrNodes :: * ;
198+ fn unwrap_nodes ( self ) -> Vec < Vec < N > > {
210199 match self {
211- Nodes ( x) => x,
212- Edges ( _) => vec ! [ ] ,
200+ Self :: Nodes ( x) => x,
201+ Self :: Edges ( _) => unreachable ! (
202+ "Function should only return instances of {}." ,
203+ std:: any:: type_name:: <N >( )
204+ ) ,
213205 }
214206 }
215- pub fn unwrap_edges ( self ) -> Vec < Vec < E > > {
216- use EdgesOrNodes :: * ;
207+ fn unwrap_edges ( self ) -> Vec < Vec < E > > {
217208 match self {
218- Edges ( x) => x,
219- Nodes ( _) => vec ! [ ] ,
209+ Self :: Edges ( x) => x,
210+ Self :: Nodes ( _) => unreachable ! (
211+ "Function should only return instances of {}." ,
212+ std:: any:: type_name:: <E >( )
213+ ) ,
220214 }
221215 }
222216}
223217
218+ /// Returns lists of `NodeIndex` representing cycles which form
219+ /// a basis for cycles of a given graph.
220+ ///
221+ /// A basis for cycles of a graph is a minimal collection of
222+ /// cycles such that any cycle in the graph can be written
223+ /// as a sum of cycles in the basis. Here summation of cycles
224+ /// is defined as the exclusive-or of the edges.
225+ ///
226+ /// This is adapted from
227+ /// Paton, K. An algorithm for finding a fundamental set of
228+ /// cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518.
229+ ///
230+ /// The function implicitly assumes that there are no parallel edges.
231+ /// It may produce incorrect/unexpected results if the input graph has
232+ /// parallel edges.
233+ ///
234+ ///
235+ /// Arguments:
236+ ///
237+ /// * `graph` - The graph in which to find the basis.
238+ /// * `root` - Optional node index for starting the basis search. If not
239+ /// specified, an arbitrary node is chosen.
240+ ///
241+ /// # Example
242+ /// ```rust
243+ /// use petgraph::prelude::*;
244+ /// use rustworkx_core::connectivity::cycle_basis;
245+ ///
246+ /// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
247+ /// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
248+ /// let mut res: Vec<Vec<NodeIndex>> = cycle_basis(&graph, Some(NodeIndex::new(0)));
249+ /// ```
250+ pub fn cycle_basis < G > ( graph : G , root : Option < G :: NodeId > ) -> Vec < Vec < G :: NodeId > >
251+ where
252+ G : NodeCount ,
253+ G : IntoEdges ,
254+ G : IntoNodeIdentifiers ,
255+ G :: NodeId : Eq + Hash ,
256+ G :: EdgeId : Eq + Hash ,
257+ {
258+ inner_cycle_basis ( graph, root, false ) . unwrap_nodes ( )
259+ }
260+
261+ /// Returns lists of `EdgeIndex` representing cycles which form
262+ /// a basis for cycles of a given graph.
263+ ///
264+ /// A basis for cycles of a graph is a minimal collection of
265+ /// cycles such that any cycle in the graph can be written
266+ /// as a sum of cycles in the basis. Here summation of cycles
267+ /// is defined as the exclusive-or of the edges.
268+ ///
269+ /// This is adapted from
270+ /// Paton, K. An algorithm for finding a fundamental set of
271+ /// cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518.
272+ ///
273+ /// The function implicitly assumes that there are no parallel edges.
274+ /// It may produce incorrect/unexpected results if the input graph has
275+ /// parallel edges.
276+ ///
277+ ///
278+ /// Arguments:
279+ ///
280+ /// * `graph` - The graph in which to find the basis.
281+ /// * `root` - Optional node index for starting the basis search. If not
282+ /// specified, an arbitrary node is chosen.
283+ ///
284+ /// # Example
285+ /// ```rust
286+ /// use petgraph::prelude::*;
287+ /// use rustworkx_core::connectivity::cycle_basis_edges;
288+ ///
289+ /// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
290+ /// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
291+ /// let mut res: Vec<Vec<EdgeIndex>> = cycle_basis_edges(&graph, Some(NodeIndex::new(0)));
292+ /// ```
293+ pub fn cycle_basis_edges < G > ( graph : G , root : Option < G :: NodeId > ) -> Vec < Vec < G :: EdgeId > >
294+ where
295+ G : NodeCount ,
296+ G : IntoEdges ,
297+ G : IntoNodeIdentifiers ,
298+ G :: NodeId : Eq + Hash ,
299+ G :: EdgeId : Eq + Hash ,
300+ {
301+ inner_cycle_basis ( graph, root, true ) . unwrap_edges ( )
302+ }
303+
224304#[ cfg( test) ]
225305mod tests {
226306 use crate :: connectivity:: cycle_basis;
307+ use crate :: connectivity:: cycle_basis_edges;
227308 use petgraph:: prelude:: * ;
309+ use petgraph:: stable_graph:: GraphIndex ;
228310
229- use super :: EdgesOrNodes ;
230-
231- fn sorted_cycle ( cycles : EdgesOrNodes < NodeIndex , EdgeIndex > , edges : bool ) -> Vec < Vec < usize > > {
311+ fn sorted_cycle < T > ( cycles : Vec < Vec < T > > ) -> Vec < Vec < usize > >
312+ where
313+ T : GraphIndex ,
314+ {
232315 let mut sorted_cycles: Vec < Vec < usize > > = vec ! [ ] ;
233- if edges {
234- let cycles: Vec < Vec < EdgeIndex > > = cycles. unwrap_edges ( ) ;
235- for cycle in cycles {
236- let mut cycle: Vec < usize > = cycle. iter ( ) . map ( |x : & EdgeIndex | x. index ( ) ) . collect ( ) ;
237- cycle. sort ( ) ;
238- sorted_cycles. push ( cycle) ;
239- }
240- } else {
241- let cycles: Vec < Vec < NodeIndex > > = cycles. unwrap_nodes ( ) ;
242- for cycle in cycles {
243- let mut cycle: Vec < usize > = cycle. iter ( ) . map ( |x : & NodeIndex | x. index ( ) ) . collect ( ) ;
244- cycle. sort ( ) ;
245- sorted_cycles. push ( cycle) ;
246- }
247- } ;
316+ for cycle in cycles {
317+ let mut cycle: Vec < usize > = cycle. iter ( ) . map ( |x : & T | x. index ( ) ) . collect ( ) ;
318+ cycle. sort ( ) ;
319+ sorted_cycles. push ( cycle) ;
320+ }
248321 sorted_cycles. sort ( ) ;
249322 sorted_cycles
250323 }
251324
252325 #[ test]
253326 fn test_cycle_basis_source ( ) {
254- let edges: bool = false ;
255327 let edge_list = vec ! [
256328 ( 0 , 1 ) ,
257329 ( 0 , 3 ) ,
@@ -268,17 +340,16 @@ mod tests {
268340 ] ;
269341 let graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
270342 let expected = vec ! [ vec![ 0 , 1 , 2 , 3 ] , vec![ 0 , 1 , 6 , 7 , 8 ] , vec![ 0 , 3 , 4 , 5 ] ] ;
271- let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) , Some ( edges ) ) ;
272- assert_eq ! ( sorted_cycle( res_0, false ) , expected) ;
273- let res_1 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 1 ) ) , Some ( edges ) ) ;
274- assert_eq ! ( sorted_cycle( res_1, false ) , expected) ;
275- let res_9 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 9 ) ) , Some ( edges ) ) ;
276- assert_eq ! ( sorted_cycle( res_9, false ) , expected) ;
343+ let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
344+ assert_eq ! ( sorted_cycle( res_0) , expected) ;
345+ let res_1 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 1 ) ) ) ;
346+ assert_eq ! ( sorted_cycle( res_1) , expected) ;
347+ let res_9 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 9 ) ) ) ;
348+ assert_eq ! ( sorted_cycle( res_9) , expected) ;
277349 }
278350
279351 #[ test]
280352 fn test_cycle_edge_basis_source ( ) {
281- let edges: bool = true ;
282353 let edge_list = vec ! [
283354 ( 0 , 0 ) ,
284355 ( 0 , 1 ) ,
@@ -291,17 +362,16 @@ mod tests {
291362 ] ;
292363 let graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
293364 let expected = vec ! [ vec![ 0 ] , vec![ 3 , 4 , 5 , 6 ] ] ;
294- let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) , Some ( edges ) ) ;
295- assert_eq ! ( sorted_cycle( res_0, true ) , expected) ;
296- let res_1 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 2 ) ) , Some ( edges ) ) ;
297- assert_eq ! ( sorted_cycle( res_1, true ) , expected) ;
298- let res_9 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 6 ) ) , Some ( edges ) ) ;
299- assert_eq ! ( sorted_cycle( res_9, true ) , expected) ;
365+ let res_0 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
366+ assert_eq ! ( sorted_cycle( res_0) , expected) ;
367+ let res_1 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 2 ) ) ) ;
368+ assert_eq ! ( sorted_cycle( res_1) , expected) ;
369+ let res_9 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 6 ) ) ) ;
370+ assert_eq ! ( sorted_cycle( res_9) , expected) ;
300371 }
301372
302373 #[ test]
303374 fn test_self_loop ( ) {
304- let edges: bool = false ;
305375 let edge_list = vec ! [
306376 ( 0 , 1 ) ,
307377 ( 0 , 3 ) ,
@@ -318,9 +388,9 @@ mod tests {
318388 ] ;
319389 let mut graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
320390 graph. add_edge ( NodeIndex :: new ( 1 ) , NodeIndex :: new ( 1 ) , 0 ) ;
321- let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) , Some ( edges ) ) ;
391+ let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
322392 assert_eq ! (
323- sorted_cycle( res_0, edges ) ,
393+ sorted_cycle( res_0) ,
324394 vec![
325395 vec![ 0 , 1 , 2 , 3 ] ,
326396 vec![ 0 , 1 , 6 , 7 , 8 ] ,
@@ -332,7 +402,6 @@ mod tests {
332402
333403 #[ test]
334404 fn test_self_loop_edges ( ) {
335- let edges: bool = true ;
336405 let edge_list = vec ! [
337406 ( 0 , 1 ) ,
338407 ( 0 , 3 ) ,
@@ -349,9 +418,9 @@ mod tests {
349418 ] ;
350419 let mut graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
351420 graph. add_edge ( NodeIndex :: new ( 1 ) , NodeIndex :: new ( 1 ) , 0 ) ;
352- let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) , Some ( edges ) ) ;
421+ let res_0 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
353422 assert_eq ! (
354- sorted_cycle( res_0, edges ) ,
423+ sorted_cycle( res_0) ,
355424 vec![
356425 vec![ 0 , 1 , 4 , 6 ] ,
357426 vec![ 0 , 3 , 5 , 9 , 10 ] ,
0 commit comments