11use crate :: { CsmGraph , GraphAlgorithms , GraphError , GraphView } ;
2+ use std:: cmp:: Reverse ;
3+ use std:: collections:: BinaryHeap ;
24use std:: collections:: VecDeque ;
35use std:: slice;
46
@@ -271,7 +273,6 @@ where
271273 Ok ( Some ( path) )
272274 }
273275
274- /// Finds the shortest path between two nodes in a weighted graph using Dijkstra's algorithm.
275276 fn shortest_weighted_path (
276277 & self ,
277278 start_index : usize ,
@@ -280,9 +281,6 @@ where
280281 where
281282 W : Copy + Ord + Default + std:: ops:: Add < Output = W > ,
282283 {
283- use std:: cmp:: Reverse ;
284- use std:: collections:: BinaryHeap ;
285-
286284 if !self . contains_node ( start_index) || !self . contains_node ( stop_index) {
287285 return Ok ( None ) ;
288286 }
@@ -329,7 +327,7 @@ where
329327 let weight = self . forward_edges . weights [ i] ;
330328 let new_dist = dist + weight;
331329
332- if distances[ v] . map_or ( true , |d | new_dist < d ) {
330+ if distances[ v] . is_none ( ) | | new_dist < distances [ v ] . unwrap ( ) {
333331 distances[ v] = Some ( new_dist) ;
334332 predecessors[ v] = Some ( u) ;
335333 pq. push ( ( Reverse ( new_dist) , v) ) ;
@@ -339,4 +337,110 @@ where
339337
340338 Ok ( None )
341339 }
340+
341+ /// Finds all Strongly Connected Components in the graph using Tarjan's algorithm.
342+ ///
343+ /// # Returns
344+ /// A vector of vectors, where each inner vector is a list of node indices
345+ /// belonging to a single SCC.
346+ fn strongly_connected_components ( & self ) -> Result < Vec < Vec < usize > > , GraphError > {
347+ let num_nodes = self . number_nodes ( ) ;
348+ if num_nodes == 0 {
349+ return Ok ( Vec :: new ( ) ) ;
350+ }
351+
352+ let mut dfs_num: Vec < Option < usize > > = vec ! [ None ; num_nodes] ;
353+ let mut low_link: Vec < Option < usize > > = vec ! [ None ; num_nodes] ;
354+ let mut on_stack: Vec < bool > = vec ! [ false ; num_nodes] ;
355+ let mut tarjan_stack: Vec < usize > = Vec :: new ( ) ;
356+ let mut time: usize = 0 ;
357+ let mut sccs: Vec < Vec < usize > > = Vec :: new ( ) ;
358+
359+ // Stack for iterative DFS. Stores (node_index, iterator_over_neighbors)
360+ // The iterator is used to keep track of which neighbor to visit next.
361+ let mut dfs_stack: Vec < ( usize , slice:: Iter < ' _ , usize > ) > = Vec :: new ( ) ;
362+
363+ for i in 0 ..num_nodes {
364+ if dfs_num[ i] . is_none ( ) {
365+ // Start DFS from node i
366+ let start_offset = self . forward_edges . offsets [ i] ;
367+ let end_offset = self . forward_edges . offsets [ i + 1 ] ;
368+ let neighbors_iter = self . forward_edges . targets [ start_offset..end_offset] . iter ( ) ;
369+ dfs_stack. push ( ( i, neighbors_iter) ) ;
370+
371+ // Simulate recursion
372+ while let Some ( ( u, neighbors) ) = dfs_stack. last_mut ( ) {
373+ // On first visit to u (pre-order traversal)
374+ if dfs_num[ * u] . is_none ( ) {
375+ dfs_num[ * u] = Some ( time) ;
376+ low_link[ * u] = Some ( time) ;
377+ time += 1 ;
378+ tarjan_stack. push ( * u) ;
379+ on_stack[ * u] = true ;
380+ }
381+
382+ // Process neighbors
383+ if let Some ( & v) = neighbors. next ( ) {
384+ if dfs_num[ v] . is_none ( ) {
385+ // Neighbor v not visited, "recurse"
386+ let v_start_offset = self . forward_edges . offsets [ v] ;
387+ let v_end_offset = self . forward_edges . offsets [ v + 1 ] ;
388+ let v_neighbors_iter =
389+ self . forward_edges . targets [ v_start_offset..v_end_offset] . iter ( ) ;
390+ dfs_stack. push ( ( v, v_neighbors_iter) ) ;
391+ } else if on_stack[ v] {
392+ // Neighbor v is on stack, back-edge
393+ low_link[ * u] = Some (
394+ low_link[ * u]
395+ . ok_or ( GraphError :: AlgorithmError ( "low_link for u not set" ) ) ?
396+ . min ( dfs_num[ v] . ok_or ( GraphError :: AlgorithmError (
397+ "dfs_num for v not set" ,
398+ ) ) ?) ,
399+ ) ;
400+ }
401+ } else {
402+ // All neighbors processed, "return" from u (post-order traversal)
403+
404+ // If u is the root of an SCC
405+ if dfs_num[ * u] == low_link[ * u] {
406+ let mut current_scc = Vec :: new ( ) ;
407+ loop {
408+ let node = tarjan_stack
409+ . pop ( )
410+ . ok_or ( GraphError :: AlgorithmError ( "tarjan_stack is empty" ) ) ?;
411+ on_stack[ node] = false ;
412+ current_scc. push ( node) ;
413+ if node == * u {
414+ break ;
415+ }
416+ }
417+ current_scc. reverse ( ) ; // SCC nodes are popped in reverse order
418+ sccs. push ( current_scc) ;
419+ }
420+
421+ // Update parent's low_link if u is not the root of an SCC
422+ // This must happen AFTER processing the current node's SCC, but BEFORE popping u from dfs_stack
423+ let popped_u = dfs_stack
424+ . pop ( )
425+ . ok_or ( GraphError :: AlgorithmError ( "DFS stack was empty in a post-order step, which should be impossible" ) ) ?
426+ . 0 ;
427+
428+ if let Some ( ( parent_node, _) ) = dfs_stack. last ( ) {
429+ low_link[ * parent_node] = Some (
430+ low_link[ * parent_node]
431+ . ok_or ( GraphError :: AlgorithmError (
432+ "low_link for parent_node not set" ,
433+ ) ) ?
434+ . min ( low_link[ popped_u] . ok_or ( GraphError :: AlgorithmError (
435+ "low_link for popped_u not set" ,
436+ ) ) ?) ,
437+ ) ;
438+ }
439+ }
440+ }
441+ }
442+ }
443+
444+ Ok ( sccs)
445+ }
342446}
0 commit comments