1111// under the License.
1212
1313use hashbrown:: { HashMap , HashSet } ;
14- use petgraph:: visit:: { IntoNeighbors , IntoNodeIdentifiers , NodeCount } ;
14+ use petgraph:: visit:: { EdgeRef , IntoEdges , IntoNeighbors , IntoNodeIdentifiers , NodeCount } ;
1515use std:: hash:: Hash ;
1616
1717/// Return a list of cycles which form a basis for cycles of a given graph.
@@ -116,9 +116,160 @@ where
116116 cycles
117117}
118118
119+ /// Return a list of edges representing cycles which form a basis for cycles of a given graph.
120+ ///
121+ /// A basis for cycles of a graph is a minimal collection of
122+ /// cycles such that any cycle in the graph can be written
123+ /// as a sum of cycles in the basis. Here summation of cycles
124+ /// is defined as the exclusive-or of the edges.
125+ ///
126+ /// This is adapted from
127+ /// Paton, K. An algorithm for finding a fundamental set of
128+ /// cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518.
129+ ///
130+ /// The function implicitly assumes that there are no parallel edges.
131+ /// It may produce incorrect/unexpected results if the input graph has
132+ /// parallel edges.
133+ ///
134+ ///
135+ /// Arguments:
136+ ///
137+ /// * `graph` - The graph in which to find the basis.
138+ /// * `root` - Optional node index for starting the basis search. If not
139+ /// specified, an arbitrary node is chosen.
140+ ///
141+ /// # Example
142+ /// ```rust
143+ /// use petgraph::prelude::*;
144+ /// use rustworkx_core::connectivity::cycle_basis;
145+ ///
146+ /// let edge_list = [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)];
147+ /// let graph = UnGraph::<i32, i32>::from_edges(&edge_list);
148+ /// let mut res: Vec<Vec<(NodeId, NodeId)>> = cycle_basis_edges(&graph, Some(NodeIndex::new(0)));
149+ /// ```
150+ pub fn cycle_basis_edges < G > ( graph : G , root : Option < G :: NodeId > ) -> Vec < Vec < ( G :: NodeId , G :: NodeId ) > >
151+ where
152+ G : NodeCount ,
153+ G : IntoNeighbors ,
154+ G : IntoEdges ,
155+ G : IntoNodeIdentifiers ,
156+ G :: NodeId : Eq + Hash ,
157+ {
158+ let mut root_node = root;
159+ let mut graph_nodes: HashSet < G :: NodeId > = graph. node_identifiers ( ) . collect ( ) ;
160+
161+ let mut cycles: Vec < Vec < ( G :: NodeId , G :: NodeId ) > > = Vec :: new ( ) ;
162+ while !graph_nodes. is_empty ( ) {
163+ let temp_value: G :: NodeId ;
164+ // If root_node is not set get an arbitrary node from the set of graph
165+ // nodes we've not "examined"
166+ let root_index = match root_node {
167+ Some ( root_node) => root_node,
168+ None => {
169+ temp_value = * graph_nodes. iter ( ) . next ( ) . unwrap ( ) ;
170+ graph_nodes. remove ( & temp_value) ;
171+ temp_value
172+ }
173+ } ;
174+ // Stack (ie "pushdown list") of vertices already in the spanning tree
175+ let mut stack: Vec < G :: NodeId > = vec ! [ root_index] ;
176+ // Map of node index to predecessor node index
177+ let mut pred: HashMap < G :: NodeId , G :: NodeId > = HashMap :: new ( ) ;
178+ pred. insert ( root_index, root_index) ;
179+ // Set of examined nodes during this iteration
180+ let mut used: HashMap < G :: NodeId , HashSet < G :: NodeId > > = HashMap :: new ( ) ;
181+ used. insert ( root_index, HashSet :: new ( ) ) ;
182+ // Walk the spanning tree
183+ while !stack. is_empty ( ) {
184+ // Use the last element added so that cycles are easier to find
185+ let z = stack. pop ( ) . unwrap ( ) ;
186+ // println!("Length of all edges from: {:?}", edges.len());
187+ for neighbor in graph. neighbors ( z) {
188+ // A new node was encountered:
189+ if !used. contains_key ( & neighbor) {
190+ pred. insert ( neighbor, z) ;
191+ stack. push ( neighbor) ;
192+ let mut temp_set: HashSet < G :: NodeId > = HashSet :: new ( ) ;
193+ temp_set. insert ( z) ;
194+ used. insert ( neighbor, temp_set) ;
195+ // A self loop:
196+ } else if z == neighbor {
197+ let cycle_edge: Vec < ( G :: NodeId , G :: NodeId ) > = graph
198+ . edges ( z)
199+ . filter ( |edge : & G :: EdgeRef | edge. source ( ) == z && edge. target ( ) == z)
200+ . map ( |edge : G :: EdgeRef | ( edge. source ( ) , edge. target ( ) ) )
201+ . collect ( ) ;
202+ cycles. push ( cycle_edge) ;
203+ // A cycle was found:
204+ } else if !used. get ( & z) . unwrap ( ) . contains ( & neighbor) {
205+ let pn = used. get ( & neighbor) . unwrap ( ) ;
206+ let mut cycle: Vec < ( G :: NodeId , G :: NodeId ) > = vec ! [ ] ;
207+ let mut p = pred. get ( & z) . unwrap ( ) ;
208+ // Retreive all edges from z to neighbor and vice versa
209+ let mut neigh_edge: Vec < ( G :: NodeId , G :: NodeId ) > = graph
210+ . edges ( z)
211+ . filter ( |edge : & G :: EdgeRef | {
212+ edge. source ( ) == neighbor || edge. target ( ) == neighbor
213+ } )
214+ . map ( |edge : G :: EdgeRef | ( edge. source ( ) , edge. target ( ) ) )
215+ . collect ( ) ;
216+ // Append to cycle
217+ cycle. append ( & mut neigh_edge) ;
218+ // Make last p_node == z
219+ let mut prev_p: & G :: NodeId = & z;
220+ // While p is in the neighborhood of neighbor
221+ while !pn. contains ( p) {
222+ // Retrieve all edges from prev_p to p and vice versa
223+ let mut neigh_edge: Vec < ( G :: NodeId , G :: NodeId ) > = graph
224+ . edges ( * prev_p)
225+ . filter ( |edge : & G :: EdgeRef | edge. target ( ) == * p || edge. source ( ) == * p)
226+ . map ( |edge : G :: EdgeRef | ( edge. source ( ) , edge. target ( ) ) )
227+ . collect ( ) ;
228+ // Append to cycle
229+ cycle. append ( & mut neigh_edge) ;
230+ // Update prev_p to p
231+ prev_p = p;
232+ // Retreive a new predecessor node from p and replace p
233+ p = pred. get ( p) . unwrap ( ) ;
234+ }
235+ // When loop ends add remaining edges from prev_p to p.
236+ let mut neigh_edge: Vec < ( G :: NodeId , G :: NodeId ) > = graph
237+ . edges ( * prev_p)
238+ . filter ( |edge : & G :: EdgeRef | edge. target ( ) == * p || edge. source ( ) == * p)
239+ . map ( |edge : G :: EdgeRef | ( edge. source ( ) , edge. target ( ) ) )
240+ . collect ( ) ;
241+ cycle. append ( & mut neigh_edge) ;
242+ // Also retreive all edges between the last p and neighbor
243+ let mut neigh_edge: Vec < ( G :: NodeId , G :: NodeId ) > = graph
244+ . edges ( * p)
245+ . filter ( |edge : & G :: EdgeRef | {
246+ edge. target ( ) == neighbor || edge. source ( ) == neighbor
247+ } )
248+ . map ( |edge : G :: EdgeRef | ( edge. source ( ) , edge. target ( ) ) )
249+ . collect ( ) ;
250+ cycle. append ( & mut neigh_edge) ;
251+
252+ // Once all edges within cycle have been found, push to cycle list.
253+ cycles. push ( cycle) ;
254+ let neighbor_set: & mut HashSet < G :: NodeId > = used. get_mut ( & neighbor) . unwrap ( ) ;
255+ neighbor_set. insert ( z) ;
256+ }
257+ }
258+ }
259+ let mut temp_hashset: HashSet < G :: NodeId > = HashSet :: new ( ) ;
260+ for key in pred. keys ( ) {
261+ temp_hashset. insert ( * key) ;
262+ }
263+ graph_nodes = graph_nodes. difference ( & temp_hashset) . copied ( ) . collect ( ) ;
264+ root_node = None ;
265+ }
266+ cycles
267+ }
268+
119269#[ cfg( test) ]
120270mod tests {
121271 use crate :: connectivity:: cycle_basis;
272+ use crate :: connectivity:: cycle_basis_edges;
122273 use petgraph:: prelude:: * ;
123274
124275 fn sorted_cycle ( cycles : Vec < Vec < NodeIndex > > ) -> Vec < Vec < usize > > {
@@ -132,6 +283,26 @@ mod tests {
132283 sorted_cycles
133284 }
134285
286+ fn sorted_cycle_edges ( cycles : Vec < Vec < ( NodeIndex , NodeIndex ) > > ) -> Vec < Vec < ( usize , usize ) > > {
287+ let mut sorted_cycles: Vec < Vec < ( usize , usize ) > > = vec ! [ ] ;
288+ for cycle in cycles {
289+ let mut cycle: Vec < ( usize , usize ) > = cycle
290+ . iter ( )
291+ . map ( |x| {
292+ if x. 0 < x. 1 {
293+ ( x. 0 . index ( ) , x. 1 . index ( ) )
294+ } else {
295+ ( x. 1 . index ( ) , x. 0 . index ( ) )
296+ }
297+ } )
298+ . collect ( ) ;
299+ cycle. sort ( ) ;
300+ sorted_cycles. push ( cycle) ;
301+ }
302+ sorted_cycles. sort ( ) ;
303+ sorted_cycles
304+ }
305+
135306 #[ test]
136307 fn test_cycle_basis_source ( ) {
137308 let edge_list = vec ! [
@@ -158,6 +329,28 @@ mod tests {
158329 assert_eq ! ( sorted_cycle( res_9) , expected) ;
159330 }
160331
332+ #[ test]
333+ fn test_cycle_edge_basis_source ( ) {
334+ let edge_list = vec ! [
335+ ( 0 , 0 ) ,
336+ ( 0 , 1 ) ,
337+ ( 1 , 2 ) ,
338+ ( 2 , 3 ) ,
339+ ( 2 , 5 ) ,
340+ ( 5 , 6 ) ,
341+ ( 3 , 6 ) ,
342+ ( 3 , 4 ) ,
343+ ] ;
344+ let graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
345+ let expected = vec ! [ vec![ ( 0 , 0 ) ] , vec![ ( 2 , 3 ) , ( 2 , 5 ) , ( 3 , 6 ) , ( 5 , 6 ) ] ] ;
346+ let res_0 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
347+ assert_eq ! ( sorted_cycle_edges( res_0) , expected) ;
348+ let res_1 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 2 ) ) ) ;
349+ assert_eq ! ( sorted_cycle_edges( res_1) , expected) ;
350+ let res_9 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 6 ) ) ) ;
351+ assert_eq ! ( sorted_cycle_edges( res_9) , expected) ;
352+ }
353+
161354 #[ test]
162355 fn test_self_loop ( ) {
163356 let edge_list = vec ! [
@@ -187,4 +380,34 @@ mod tests {
187380 ]
188381 ) ;
189382 }
383+
384+ #[ test]
385+ fn test_self_loop_edges ( ) {
386+ let edge_list = vec ! [
387+ ( 0 , 1 ) ,
388+ ( 0 , 3 ) ,
389+ ( 0 , 5 ) ,
390+ ( 0 , 8 ) ,
391+ ( 1 , 2 ) ,
392+ ( 1 , 6 ) ,
393+ ( 2 , 3 ) ,
394+ ( 3 , 4 ) ,
395+ ( 4 , 5 ) ,
396+ ( 6 , 7 ) ,
397+ ( 7 , 8 ) ,
398+ ( 8 , 9 ) ,
399+ ] ;
400+ let mut graph = UnGraph :: < i32 , i32 > :: from_edges ( & edge_list) ;
401+ graph. add_edge ( NodeIndex :: new ( 1 ) , NodeIndex :: new ( 1 ) , 0 ) ;
402+ let res_0 = cycle_basis_edges ( & graph, Some ( NodeIndex :: new ( 0 ) ) ) ;
403+ assert_eq ! (
404+ sorted_cycle_edges( res_0) ,
405+ vec![
406+ vec![ ( 0 , 1 ) , ( 0 , 3 ) , ( 1 , 2 ) , ( 2 , 3 ) ] ,
407+ vec![ ( 0 , 1 ) , ( 0 , 8 ) , ( 1 , 6 ) , ( 6 , 7 ) , ( 7 , 8 ) ] ,
408+ vec![ ( 0 , 3 ) , ( 0 , 5 ) , ( 3 , 4 ) , ( 4 , 5 ) ] ,
409+ vec![ ( 1 , 1 ) ] ,
410+ ]
411+ ) ;
412+ }
190413}
0 commit comments