Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
kosaraju.H
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
50# ifndef KOSARAJU_H
51# define KOSARAJU_H
52
53# include <tpl_graph_utils.H>
54
55namespace Aleph {
56
70template <class GT>
71inline static void __dfp_phase1(const GT & g,
72 typename GT::Node * p,
74{
76 return;
77
78 NODE_BITS(p).set_bit(Depth_First, true);
79
80 // Traverse outgoing arcs in depth-first order
81 for (auto it = g.get_out_it(p); it.has_curr(); it.next_ne())
82 {
83 auto a = it.get_current_arc_ne();
85 continue;
86
87 ARC_BITS(a).set_bit(Depth_First, true);
88
90 }
91
92 df.append(p); // Append node in postorder (finish time)
93 NODE_COUNTER(p) = df.size();
94}
95
110template <class GT>
111inline static void __dfp_phase2_subgraph(const GT & g,
112 typename GT::Node * p,
113 GT & blk,
114 const int & color)
115{
117 return;
118
119 NODE_BITS(p).set_bit(Depth_First, true);
120
121 auto q = blk.insert_node(p->get_info());
122 NODE_COUNTER(q) = color;
123 GT::map_nodes(p, q);
124
125 for (auto it = g.get_out_it(p); it.has_curr(); it.next_ne())
126 {
127 auto a = it.get_current_arc_ne();
129 continue;
130 ARC_BITS(a).set_bit(Depth_First, true);
131
133 }
134}
135
148template <class GT>
149inline static void __dfp_phase2_list(const GT & g,
150 typename GT::Node * p,
152{
154 return;
155
156 NODE_BITS(p).set_bit(Depth_First, true);
157
158 list.append(mapped_node<GT>(p));
159
160 for (auto it = g.get_out_it(p); it.has_curr(); it.next_ne())
161 {
162 auto a = it.get_current_arc_ne();
164 continue;
165 ARC_BITS(a).set_bit(Depth_First, true);
166
167 __dfp_phase2_list(g, it.get_tgt_node(), list);
168 }
169}
170
209template <class GT>
210inline void kosaraju_connected_components(const GT & g,
213{
214 g.reset_nodes();
215 g.reset_arcs();
216
217 DynArray<typename GT::Node*> df; // Array for postorder (finish times)
218
219 // First DFS: compute finish times in postorder
220 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
221 __dfp_phase1(g, it.get_curr(), df);
222
223 GT gi = invert_digraph(g); // Transposed graph
224
225 DynArray<GT*> array; // Array of subgraph pointers indexed by color
226
227 // Second DFS: process nodes in decreasing order of finish time
228 for (long i = static_cast<long>(df.size()) - 1, color = 0; i >= 0; --i)
229 {
230 auto gp = df.access(i);
231 auto bp = mapped_node<GT>(gp);
233 continue;
234
235 GT & blk = blk_list.append(GT());
236 array[color] = &blk;
237
238 __dfp_phase2_subgraph(gi, bp, blk, color++); // DFS on transposed graph
239
241 }
242
243 // Classify arcs: internal to SCC or crossing between SCCs
244 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne())
245 {
246 auto a = it.get_curr();
247 auto gs = g.get_src_node(a);
248 auto gt = g.get_tgt_node(a);
249
250 // Double mapping: original graph → transposed graph → SCC subgraph
251 // First mapped_node: original node → transposed graph node
252 // Second mapped_node: transposed graph node → SCC subgraph node
255
256 const long & color = NODE_COLOR(bs);
257
258 if (color == NODE_COLOR(bt))
259 {
260 typename GT::Arc * ba = array.access(color)->insert_arc(bs, bt);
261 GT::map_arcs(a, ba);
262 }
263 else
264 arc_list.append(a);
265 }
266}
267
297template <class GT>
300{
302
303 g.reset_nodes();
304 g.reset_arcs();
305
306 DynArray<typename GT::Node*> df; // Array for postorder (finish times)
307
308 // First DFS: compute finish times in postorder
309 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
310 __dfp_phase1(g, it.get_curr(), df);
311
312 GT gi = invert_digraph(g); // Transposed graph
313
314 // Second DFS: process nodes in decreasing order of finish time
315 for (long i = static_cast<long>(df.size()) - 1; i >= 0; --i)
316 {
317 auto gp = df.access(i);
318 auto bp = mapped_node<GT>(gp);
320 continue;
321
322 auto & blk = list.append(DynList<typename GT::Node*>());
323
325 }
326
327 return list;
328}
329
341template <class GT>
343{
350 void operator () (const GT & g,
352 DynList<typename GT::Arc *> & arc_list) const
353 {
355 }
356
366};
367
380template <class GT>
381inline size_t kosaraju_scc_count(const GT & g)
382{
383 return kosaraju_connected_components(g).size();
384}
385
401template <class GT>
402inline bool is_strongly_connected(const GT & g)
403{
404 if (g.get_num_nodes() <= 1)
405 return true;
406
407 return kosaraju_scc_count(g) == 1;
408}
409
410} // end namespace Aleph
411
412# endif // KOSARAJU_H
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
NodeInfo & get_info() noexcept
Return a modifiable reference to the data contained in the node.
Definition graph-dry.H:494
void reset_arcs() const
Reset all the arcs of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:927
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2802
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
Out_Iterator get_out_it(Node *p) const noexcept
Return an output iterator on the incoming nodes to p
Definition graph-dry.H:3099
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
static void map_arcs(A1 *p, A2 *q) noexcept
Map the arcs through their cookies.
Definition graph-dry.H:1026
void reset_nodes() const
Reset all the nodes of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:920
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2780
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:737
static void map_nodes(N1 *p, N2 *q) noexcept
Map the nodes through their cookies.
Definition graph-dry.H:995
List_Graph< Graph_Node< int >, Graph_Arc< int > > GT
void kosaraju_connected_components(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Compute strongly connected components using Kosaraju's algorithm.
Definition kosaraju.H:210
#define NODE_COUNTER(p)
Get the counter of a node.
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
GT invert_digraph(const GT &g)
Compute the transpose (arc-reversed) digraph.
#define ARC_BITS(p)
Return the control bits of arc p.
size_t kosaraju_scc_count(const GT &g)
Count the number of strongly connected components.
Definition kosaraju.H:381
#define NODE_COLOR(p)
Synonymous of NODE_COUNTER.
#define IS_ARC_VISITED(p, bit)
Determine whether the bit field is or not set to one.
bool is_strongly_connected(const GT &g)
Check if a directed graph is strongly connected.
Definition kosaraju.H:402
#define NODE_BITS(p)
Get the control bits of a node.
@ Depth_First
Definition aleph-graph.H:73
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
static void __dfp_phase1(const GT &g, typename GT::Node *p, DynArray< typename GT::Node * > &df)
Depth-first search that computes finish times in postorder (Phase 1).
Definition kosaraju.H:71
static void __dfp_phase2_subgraph(const GT &g, typename GT::Node *p, GT &blk, const int &color)
DFS on transposed graph that builds an SCC subgraph (Phase 2).
Definition kosaraju.H:111
static long & df(typename GT::Node *p)
Internal helper: DFS discovery time stored in NODE_COUNTER(p).
static void __dfp_phase2_list(const GT &g, typename GT::Node *p, DynList< typename GT::Node * > &list)
DFS on transposed graph that builds an SCC node list (Phase 2).
Definition kosaraju.H:149
static long & color(typename GT::Node *p)
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Functor wrapper for Kosaraju's algorithm.
Definition kosaraju.H:343
void operator()(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list) const
Compute SCCs returning subgraphs and cross-arcs.
Definition kosaraju.H:350
Utility algorithms and operations for graphs.