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 <ah-graph-concepts.H>
54
55# include <tpl_graph_utils.H>
56
57namespace Aleph {
58
72template <AlephGraph GT>
73inline static void __dfp_phase1(const GT & g,
74 typename GT::Node * p,
76{
78 return;
79
80 NODE_BITS(p).set_bit(Depth_First, true);
81
82 // Traverse outgoing arcs in depth-first order
83 for (auto it = g.get_out_it(p); it.has_curr(); it.next_ne())
84 {
85 auto a = it.get_current_arc_ne();
87 continue;
88
89 ARC_BITS(a).set_bit(Depth_First, true);
90
92 }
93
94 df.append(p); // Append node in postorder (finish time)
95 NODE_COUNTER(p) = df.size();
96}
97
112template <AlephGraph GT>
113inline static void __dfp_phase2_subgraph(const GT & g,
114 typename GT::Node * p,
115 GT & blk,
116 const int & color)
117{
119 return;
120
121 NODE_BITS(p).set_bit(Depth_First, true);
122
123 auto q = blk.insert_node(p->get_info());
124 NODE_COUNTER(q) = color;
125 GT::map_nodes(p, q);
126
127 for (auto it = g.get_out_it(p); it.has_curr(); it.next_ne())
128 {
129 auto a = it.get_current_arc_ne();
131 continue;
132 ARC_BITS(a).set_bit(Depth_First, true);
133
135 }
136}
137
150template <AlephGraph GT>
151inline static void __dfp_phase2_list(const GT & g,
152 typename GT::Node * p,
154{
156 return;
157
158 NODE_BITS(p).set_bit(Depth_First, true);
159
160 list.append(mapped_node<GT>(p));
161
162 for (auto it = g.get_out_it(p); it.has_curr(); it.next_ne())
163 {
164 auto a = it.get_current_arc_ne();
166 continue;
167 ARC_BITS(a).set_bit(Depth_First, true);
168
169 __dfp_phase2_list(g, it.get_tgt_node(), list);
170 }
171}
172
211template <AlephGraph GT>
212inline void kosaraju_connected_components(const GT & g,
215{
216 g.reset_nodes();
217 g.reset_arcs();
218
219 DynArray<typename GT::Node*> df; // Array for postorder (finish times)
220
221 // First DFS: compute finish times in postorder
222 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
223 __dfp_phase1(g, it.get_curr(), df);
224
225 GT gi = invert_digraph(g); // Transposed graph
226
227 DynArray<GT*> array; // Array of subgraph pointers indexed by color
228
229 // Second DFS: process nodes in decreasing order of finish time
230 for (long i = static_cast<long>(df.size()) - 1, color = 0; i >= 0; --i)
231 {
232 auto gp = df.access(i);
233 auto bp = mapped_node<GT>(gp);
235 continue;
236
237 GT & blk = blk_list.append(GT());
238 array[color] = &blk;
239
240 __dfp_phase2_subgraph(gi, bp, blk, color++); // DFS on transposed graph
241
243 }
244
245 // Classify arcs: internal to SCC or crossing between SCCs
246 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne())
247 {
248 auto a = it.get_curr();
249 auto gs = g.get_src_node(a);
250 auto gt = g.get_tgt_node(a);
251
252 // Double mapping: original graph → transposed graph → SCC subgraph
253 // First mapped_node: original node → transposed graph node
254 // Second mapped_node: transposed graph node → SCC subgraph node
257
258 const long & color = NODE_COLOR(bs);
259
260 if (color == NODE_COLOR(bt))
261 {
262 typename GT::Arc * ba = array.access(color)->insert_arc(bs, bt);
263 GT::map_arcs(a, ba);
264 }
265 else
266 arc_list.append(a);
267 }
268}
269
299template <AlephGraph GT>
302{
304
305 g.reset_nodes();
306 g.reset_arcs();
307
308 DynArray<typename GT::Node*> df; // Array for postorder (finish times)
309
310 // First DFS: compute finish times in postorder
311 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
312 __dfp_phase1(g, it.get_curr(), df);
313
314 GT gi = invert_digraph(g); // Transposed graph
315
316 // Second DFS: process nodes in decreasing order of finish time
317 for (long i = static_cast<long>(df.size()) - 1; i >= 0; --i)
318 {
319 auto gp = df.access(i);
320 auto bp = mapped_node<GT>(gp);
322 continue;
323
324 auto & blk = list.append(DynList<typename GT::Node*>());
325
327 }
328
329 return list;
330}
331
343template <AlephGraph GT>
345{
352 void operator () (const GT & g,
354 DynList<typename GT::Arc *> & arc_list) const
355 {
357 }
358
368};
369
382template <AlephGraph GT>
383inline size_t kosaraju_scc_count(const GT & g)
384{
385 return kosaraju_connected_components(g).size();
386}
387
403template <AlephGraph GT>
404inline bool is_strongly_connected(const GT & g)
405{
406 if (g.get_num_nodes() <= 1)
407 return true;
408
409 return kosaraju_scc_count(g) == 1;
410}
411
412} // end namespace Aleph
413
414# endif // KOSARAJU_H
C++20 concepts for the protocol shared by graph algorithms.
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
NodeInfo & get_info() noexcept
Return a modifiable reference to the data contained in the node.
Definition graph-dry.H:536
void reset_arcs() const
Reset all the arcs of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:975
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2908
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:779
Out_Iterator get_out_it(Node *p) const noexcept
Return an output iterator on the incoming nodes to p
Definition graph-dry.H:3205
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
static void map_arcs(A1 *p, A2 *q) noexcept
Map the arcs through their cookies.
Definition graph-dry.H:1074
void reset_nodes() const
Reset all the nodes of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:968
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2886
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
static void map_nodes(N1 *p, N2 *q) noexcept
Map the nodes through their cookies.
Definition graph-dry.H:1043
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:212
#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:383
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
#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:404
#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:73
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:113
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:151
static long & color(typename GT::Node *p)
Functor wrapper for Kosaraju's algorithm.
Definition kosaraju.H:345
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:352
Utility algorithms and operations for graphs.