@@ -35,6 +35,8 @@ use std::hash::Hash;
3535/// * `graph` - The graph in which to find the basis.
3636/// * `root` - Optional node index for starting the basis search. If not
3737/// specified, an arbitrary node is chosen.
38+ /// * `edges` - Optional bool for when the user requests the edges instead
39+ /// of the nodes of the cycles.
3840///
3941/// # Example
4042/// ```rust
@@ -43,112 +45,14 @@ use std::hash::Hash;
4345///
4446/// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
4547/// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
46- /// let mut res: Vec<Vec<NodeIndex>> = cycle_basis(&graph, Some(NodeIndex::new(0)));
48+ /// let mut res: Vec<Vec<NodeIndex>> = cycle_basis(&graph, Some(NodeIndex::new(0)), Some(false)).unwrap_nodes( );
4749/// ```
48- pub fn cycle_basis < G > ( graph : G , root : Option < G :: NodeId > ) -> Vec < Vec < G :: NodeId > >
49- where
50- G : NodeCount ,
51- G : IntoNeighbors ,
52- G : IntoNodeIdentifiers ,
53- G :: NodeId : Eq + Hash ,
54- {
55- let mut root_node = root;
56- let mut graph_nodes: HashSet < G :: NodeId > = graph. node_identifiers ( ) . collect ( ) ;
57- let mut cycles: Vec < Vec < G :: NodeId > > = Vec :: new ( ) ;
58- while !graph_nodes. is_empty ( ) {
59- let temp_value: G :: NodeId ;
60- // If root_node is not set get an arbitrary node from the set of graph
61- // nodes we've not "examined"
62- let root_index = match root_node {
63- Some ( root_node) => root_node,
64- None => {
65- temp_value = * graph_nodes. iter ( ) . next ( ) . unwrap ( ) ;
66- graph_nodes. remove ( & temp_value) ;
67- temp_value
68- }
69- } ;
70- // Stack (ie "pushdown list") of vertices already in the spanning tree
71- let mut stack: Vec < G :: NodeId > = vec ! [ root_index] ;
72- // Map of node index to predecessor node index
73- let mut pred: HashMap < G :: NodeId , G :: NodeId > = HashMap :: new ( ) ;
74- pred. insert ( root_index, root_index) ;
75- // Set of examined nodes during this iteration
76- let mut used: HashMap < G :: NodeId , HashSet < G :: NodeId > > = HashMap :: new ( ) ;
77- used. insert ( root_index, HashSet :: new ( ) ) ;
78- // Walk the spanning tree
79- // Use the last element added so that cycles are easier to find
80- while let Some ( z) = stack. pop ( ) {
81- for neighbor in graph. neighbors ( z) {
82- // A new node was encountered:
83- if !used. contains_key ( & neighbor) {
84- pred. insert ( neighbor, z) ;
85- stack. push ( neighbor) ;
86- let mut temp_set: HashSet < G :: NodeId > = HashSet :: new ( ) ;
87- temp_set. insert ( z) ;
88- used. insert ( neighbor, temp_set) ;
89- // A self loop:
90- } else if z == neighbor {
91- let cycle: Vec < G :: NodeId > = vec ! [ z] ;
92- cycles. push ( cycle) ;
93- // A cycle was found:
94- } else if !used. get ( & z) . unwrap ( ) . contains ( & neighbor) {
95- let pn = used. get ( & neighbor) . unwrap ( ) ;
96- let mut cycle: Vec < G :: NodeId > = vec ! [ neighbor, z] ;
97- let mut p = pred. get ( & z) . unwrap ( ) ;
98- while !pn. contains ( p) {
99- cycle. push ( * p) ;
100- p = pred. get ( p) . unwrap ( ) ;
101- }
102- cycle. push ( * p) ;
103- cycles. push ( cycle) ;
104- let neighbor_set = used. get_mut ( & neighbor) . unwrap ( ) ;
105- neighbor_set. insert ( z) ;
106- }
107- }
108- }
109- let mut temp_hashset: HashSet < G :: NodeId > = HashSet :: new ( ) ;
110- for key in pred. keys ( ) {
111- temp_hashset. insert ( * key) ;
112- }
113- graph_nodes = graph_nodes. difference ( & temp_hashset) . copied ( ) . collect ( ) ;
114- root_node = None ;
115- }
116- cycles
117- }
11850
119- /// Return a list of edge indices representing cycles which form a basis for
120- /// cycles of a given graph.
121- ///
122- /// A basis for cycles of a graph is a minimal collection of
123- /// cycles such that any cycle in the graph can be written
124- /// as a sum of cycles in the basis. Here summation of cycles
125- /// is defined as the exclusive-or of the edges.
126- ///
127- /// This is adapted from
128- /// Paton, K. An algorithm for finding a fundamental set of
129- /// cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518.
130- ///
131- /// The function implicitly assumes that there are no parallel edges.
132- /// It may produce incorrect/unexpected results if the input graph has
133- /// parallel edges.
134- ///
135- ///
136- /// Arguments:
137- ///
138- /// * `graph` - The graph in which to find the basis.
139- /// * `root` - Optional node index for starting the basis search. If not
140- /// specified, an arbitrary node is chosen.
141- ///
142- /// # Example
143- /// ```rust
144- /// use petgraph::prelude::*;
145- /// use rustworkx_core::connectivity::cycle_basis_edges;
146- ///
147- /// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
148- /// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
149- /// let mut res: Vec<Vec<EdgeIndex>> = cycle_basis_edges(&graph, Some(NodeIndex::new(0)));
150- /// ```
151- pub fn cycle_basis_edges < G > ( graph : G , root : Option < G :: NodeId > ) -> Vec < Vec < G :: EdgeId > >
51+ pub fn cycle_basis < G > (
52+ graph : G ,
53+ root : Option < G :: NodeId > ,
54+ edges : Option < bool > ,
55+ ) -> EdgesOrNodes < G :: NodeId , G :: EdgeId >
15256where
15357 G : NodeCount ,
15458 G : IntoNeighbors ,
@@ -157,9 +61,11 @@ where
15761 G :: NodeId : Eq + Hash ,
15862 G :: EdgeId : Eq + Hash ,
15963{
64+ let want_edges = edges == Some ( true ) ;
16065 let mut root_node = root;
16166 let mut graph_nodes: HashSet < G :: NodeId > = graph. node_identifiers ( ) . collect ( ) ;
162- let mut cycles: Vec < Vec < G :: EdgeId > > = Vec :: new ( ) ;
67+ let mut cycles_edges: Vec < Vec < G :: EdgeId > > = Vec :: new ( ) ;
68+ let mut cycles_nodes: Vec < Vec < G :: NodeId > > = Vec :: new ( ) ;
16369
16470 // Method used to retrieve all the edges between an origin node and a target node.
16571 // Can be used to check if a node loops back to itself by enabling equiv
@@ -220,43 +126,59 @@ where
220126 used. insert ( neighbor, temp_set) ;
221127 // A self loop:
222128 } else if z == neighbor {
223- let cycle_edge: Vec < G :: EdgeId > = get_edge_between ( graph, z, z, true ) ;
224- cycles. push ( cycle_edge) ;
129+ if want_edges {
130+ let cycle_edge: Vec < G :: EdgeId > = get_edge_between ( graph, z, z, true ) ;
131+ cycles_edges. push ( cycle_edge) ;
132+ } else {
133+ let cycle: Vec < G :: NodeId > = vec ! [ z] ;
134+ cycles_nodes. push ( cycle) ;
135+ }
225136 // A cycle was found:
226137 } else if !used. get ( & z) . unwrap ( ) . contains ( & neighbor) {
227138 let pn = used. get ( & neighbor) . unwrap ( ) ;
228- let mut cycle: Vec < G :: EdgeId > = vec ! [ ] ;
229139 let mut p = pred. get ( & z) . unwrap ( ) ;
230- // Retreive all edges from z to neighbor and vice versa
231- let mut neigh_edge: Vec < G :: EdgeId > =
232- get_edge_between ( graph, z, neighbor, false ) ;
233- // Append to cycle
234- cycle. append ( & mut neigh_edge) ;
235- // Make last p_node == z
236- let mut prev_p: & G :: NodeId = & z;
237- // While p is in the neighborhood of neighbor
238- while !pn. contains ( p) {
239- // Retrieve all edges from prev_p to p and vice versa
140+ if want_edges {
141+ let mut cycle: Vec < G :: EdgeId > = Vec :: new ( ) ;
142+ // Retreive all edges from z to neighbor.
240143 let mut neigh_edge: Vec < G :: EdgeId > =
241- get_edge_between ( graph, * prev_p , * p , false ) ;
144+ get_edge_between ( graph, z , neighbor , false ) ;
242145 // Append to cycle
243146 cycle. append ( & mut neigh_edge) ;
244- // Update prev_p to p
245- prev_p = p;
246- // Retreive a new predecessor node from p and replace p
247- p = pred. get ( p) . unwrap ( ) ;
248- }
249- // When loop ends add remaining edges from prev_p to p.
250- let mut neigh_edge: Vec < G :: EdgeId > =
251- get_edge_between ( graph, * prev_p, * p, false ) ;
252- cycle. append ( & mut neigh_edge) ;
253- // Also retreive all edges between the last p and neighbor
254- let mut neigh_edge: Vec < G :: EdgeId > =
255- get_edge_between ( graph, * p, neighbor, false ) ;
256- cycle. append ( & mut neigh_edge) ;
257147
258- // Once all edges within cycle have been found, push to cycle list.
259- cycles. push ( cycle) ;
148+ // Make last p_node == z
149+ let mut prev_p: & G :: NodeId = & z;
150+ // While p is in the neighborhood of neighbor
151+ while !pn. contains ( p) {
152+ // Retrieve all edges from prev_p to p and vice versa
153+ let mut neigh_edge: Vec < G :: EdgeId > =
154+ get_edge_between ( graph, * prev_p, * p, false ) ;
155+ // Append to cycle
156+ cycle. append ( & mut neigh_edge) ;
157+ // Update prev_p to p
158+ prev_p = p;
159+ // Retreive a new predecessor node from p and replace p
160+ p = pred. get ( p) . unwrap ( ) ;
161+ }
162+ // When loop ends add remaining edges from prev_p to p.
163+ let mut neigh_edge: Vec < G :: EdgeId > =
164+ get_edge_between ( graph, * prev_p, * p, false ) ;
165+ cycle. append ( & mut neigh_edge) ;
166+ // Also retreive all edges between the last p and neighbor
167+ let mut neigh_edge: Vec < G :: EdgeId > =
168+ get_edge_between ( graph, * p, neighbor, false ) ;
169+ cycle. append ( & mut neigh_edge) ;
170+ // Once all edges within cycle have been found, push to cycle list.
171+ cycles_edges. push ( cycle) ;
172+ } else {
173+ // Append neighbor and z to cycle.
174+ let mut cycle: Vec < G :: NodeId > = vec ! [ neighbor, z] ;
175+ while !pn. contains ( p) {
176+ cycle. push ( * p) ;
177+ p = pred. get ( p) . unwrap ( ) ;
178+ }
179+ cycle. push ( * p) ;
180+ cycles_nodes. push ( cycle) ;
181+ }
260182 let neighbor_set: & mut HashSet < G :: NodeId > = used. get_mut ( & neighbor) . unwrap ( ) ;
261183 neighbor_set. insert ( z) ;
262184 }
@@ -269,39 +191,67 @@ where
269191 graph_nodes = graph_nodes. difference ( & temp_hashset) . copied ( ) . collect ( ) ;
270192 root_node = None ;
271193 }
272- cycles
194+ if want_edges {
195+ EdgesOrNodes :: Edges ( cycles_edges)
196+ } else {
197+ EdgesOrNodes :: Nodes ( cycles_nodes)
198+ }
199+ }
200+
201+ /// Enum for custom return types of `cycle_basis()`.
202+ pub enum EdgesOrNodes < N , E > {
203+ Nodes ( Vec < Vec < N > > ) ,
204+ Edges ( Vec < Vec < E > > ) ,
205+ }
206+ /// Functions used to unwrap the desired datatype of `EdgesOrNodes`.
207+ impl < N , E > EdgesOrNodes < N , E > {
208+ pub fn unwrap_nodes ( self ) -> Vec < Vec < N > > {
209+ use EdgesOrNodes :: * ;
210+ match self {
211+ Nodes ( x) => x,
212+ Edges ( _) => vec ! [ ] ,
213+ }
214+ }
215+ pub fn unwrap_edges ( self ) -> Vec < Vec < E > > {
216+ use EdgesOrNodes :: * ;
217+ match self {
218+ Edges ( x) => x,
219+ Nodes ( _) => vec ! [ ] ,
220+ }
221+ }
273222}
274223
275224#[ cfg( test) ]
276225mod tests {
277226 use crate :: connectivity:: cycle_basis;
278- use crate :: connectivity:: cycle_basis_edges;
279227 use petgraph:: prelude:: * ;
280228
281- fn sorted_cycle ( cycles : Vec < Vec < NodeIndex > > ) -> Vec < Vec < usize > > {
282- let mut sorted_cycles: Vec < Vec < usize > > = vec ! [ ] ;
283- for cycle in cycles {
284- let mut cycle: Vec < usize > = cycle. iter ( ) . map ( |x| x. index ( ) ) . collect ( ) ;
285- cycle. sort ( ) ;
286- sorted_cycles. push ( cycle) ;
287- }
288- sorted_cycles. sort ( ) ;
289- sorted_cycles
290- }
229+ use super :: EdgesOrNodes ;
291230
292- fn sorted_cycle_edges ( cycles : Vec < Vec < EdgeIndex > > ) -> Vec < Vec < usize > > {
231+ fn sorted_cycle ( cycles : EdgesOrNodes < NodeIndex , EdgeIndex > , edges : bool ) -> Vec < Vec < usize > > {
293232 let mut sorted_cycles: Vec < Vec < usize > > = vec ! [ ] ;
294- for cycle in cycles {
295- let mut cycle: Vec < usize > = cycle. iter ( ) . map ( |x| x. index ( ) ) . collect ( ) ;
296- cycle. sort ( ) ;
297- sorted_cycles. push ( cycle) ;
298- }
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+ } ;
299248 sorted_cycles. sort ( ) ;
300249 sorted_cycles
301250 }
302251
303252 #[ test]
304253 fn test_cycle_basis_source ( ) {
254+ let edges: bool = false ;
305255 let edge_list = vec ! [
306256 ( 0 , 1 ) ,
307257 ( 0 , 3 ) ,
@@ -318,16 +268,17 @@ mod tests {
318268 ] ;
319269 let graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
320270 let expected = vec ! [ vec![ 0 , 1 , 2 , 3 ] , vec![ 0 , 1 , 6 , 7 , 8 ] , vec![ 0 , 3 , 4 , 5 ] ] ;
321- let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
322- assert_eq ! ( sorted_cycle( res_0) , expected) ;
323- let res_1 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 1 ) ) ) ;
324- assert_eq ! ( sorted_cycle( res_1) , expected) ;
325- let res_9 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 9 ) ) ) ;
326- assert_eq ! ( sorted_cycle( res_9) , expected) ;
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) ;
327277 }
328278
329279 #[ test]
330280 fn test_cycle_edge_basis_source ( ) {
281+ let edges: bool = true ;
331282 let edge_list = vec ! [
332283 ( 0 , 0 ) ,
333284 ( 0 , 1 ) ,
@@ -340,16 +291,17 @@ mod tests {
340291 ] ;
341292 let graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
342293 let expected = vec ! [ vec![ 0 ] , vec![ 3 , 4 , 5 , 6 ] ] ;
343- let res_0 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
344- assert_eq ! ( sorted_cycle_edges ( res_0) , expected) ;
345- let res_1 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 2 ) ) ) ;
346- assert_eq ! ( sorted_cycle_edges ( res_1) , expected) ;
347- let res_9 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 6 ) ) ) ;
348- assert_eq ! ( sorted_cycle_edges ( res_9) , expected) ;
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) ;
349300 }
350301
351302 #[ test]
352303 fn test_self_loop ( ) {
304+ let edges: bool = false ;
353305 let edge_list = vec ! [
354306 ( 0 , 1 ) ,
355307 ( 0 , 3 ) ,
@@ -366,9 +318,9 @@ mod tests {
366318 ] ;
367319 let mut graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
368320 graph. add_edge ( NodeIndex :: new ( 1 ) , NodeIndex :: new ( 1 ) , 0 ) ;
369- let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
321+ let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) , Some ( edges ) ) ;
370322 assert_eq ! (
371- sorted_cycle( res_0) ,
323+ sorted_cycle( res_0, edges ) ,
372324 vec![
373325 vec![ 0 , 1 , 2 , 3 ] ,
374326 vec![ 0 , 1 , 6 , 7 , 8 ] ,
@@ -380,6 +332,7 @@ mod tests {
380332
381333 #[ test]
382334 fn test_self_loop_edges ( ) {
335+ let edges: bool = true ;
383336 let edge_list = vec ! [
384337 ( 0 , 1 ) ,
385338 ( 0 , 3 ) ,
@@ -396,9 +349,9 @@ mod tests {
396349 ] ;
397350 let mut graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
398351 graph. add_edge ( NodeIndex :: new ( 1 ) , NodeIndex :: new ( 1 ) , 0 ) ;
399- let res_0 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
352+ let res_0 = cycle_basis ( & graph, Some ( NodeIndex :: new ( 0 ) ) , Some ( edges ) ) ;
400353 assert_eq ! (
401- sorted_cycle_edges ( res_0) ,
354+ sorted_cycle ( res_0, edges ) ,
402355 vec![
403356 vec![ 0 , 1 , 4 , 6 ] ,
404357 vec![ 0 , 3 , 5 , 9 , 10 ] ,
0 commit comments