Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_cut_nodes.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
51# ifndef TPL_CUT_NODES_H
52# define TPL_CUT_NODES_H
53
54# include <tpl_graph_utils.H>
55
56namespace Aleph
57{
114 template <class GT, class SA = Dft_Show_Arc<GT>>
116 {
118 GT *gptr = nullptr;
120 long curr_df = 0;
121 long curr_color = 1;
122
124
125 void cut_nodes(typename GT::Node *p, typename GT::Arc *a)
126 {
127 NODE_BITS(p).set_bit(Depth_First, true); // mark p as visited
128 low<GT>(p) = df<GT>(p) = curr_df++; // assign df number
129
130 // traverse arcs of p
131 bool p_is_cut_node = false;
132 for (Node_Arc_Iterator<GT, SA> i(p, sa); i.has_curr(); i.next_ne())
133 {
134 auto arc = i.get_curr();
135 if (arc == a)
136 continue; // a is the parent arc ==> ignore it
137
138 auto tgt = i.get_tgt_node();
140 {
141 if (not IS_ARC_VISITED(arc, Depth_First)) // non-tree arc?
142 low<GT>(p) = std::min(df<GT>(tgt), low<GT>(p));
143 continue;
144 }
145
146 if (IS_ARC_VISITED(arc, Depth_First))
147 continue;
148
149 ARC_BITS(arc).set_bit(Depth_First, true); // mark arc
150
151 cut_nodes(tgt, arc);
152 low<GT>(p) = std::min(low<GT>(tgt), low<GT>(p));
153 if (low<GT>(tgt) >= df<GT>(p) and df<GT>(tgt) != 0) // cut node?
154 p_is_cut_node = true;
155 }
156
157 // at this point, p has already been explored recursively
158 if (p_is_cut_node)
159 {
160 NODE_BITS(p).set_bit(Cut, true);
161 list_ptr->append(p);
162 }
163 }
164
165 public:
178 void cut_nodes(typename GT::Node *start,
180 {
181 curr_df = 0; // global visit counter
182 list_ptr = &list;
183
184 list_ptr->empty();
185
186 gptr->for_each_node([](auto p) // initialize nodes
187 {
188 NODE_COUNTER(p) = 0;
189 NODE_BITS(p).reset();
190 low<GT>(p) = -1;
191 });
192 gptr->reset_arcs();
193
194 NODE_BITS(start).set_bit(Depth_First, true); // mark start
195 df<GT>(start) = curr_df++;
196
197 int call_counter = 0; // recursion call counter
198
199 // Traverse arcs from start while the graph is not fully spanned
200 for (Node_Arc_Iterator<GT, SA> it(start, sa);
201 it.has_curr() and curr_df < gptr->get_num_nodes(); it.next_ne())
202 {
203 auto tgt = it.get_tgt_node();
205 continue;
206
207 auto arc = it.get_curr();
208 if (IS_ARC_VISITED(arc, Depth_First))
209 continue;
210
211 ARC_BITS(arc).set_bit(Depth_First, true);
212 cut_nodes(tgt, arc);
213 ++call_counter;
214 }
215
216 if (call_counter > 1) // is the root an articulation point?
217 { // yes ==> append it to the list
218 NODE_BITS(start).set_bit(Cut, true);
219 list_ptr->append(start);
220 }
221
223 }
224
225 private:
226 void paint_subgraph(typename GT::Node *p)
227 {
229
230 if (is_node_painted<GT>(p))
231 return;
232
234
235 for (Node_Arc_Iterator<GT, SA> it(p, sa); it.has_curr(); it.next_ne())
236 {
237 auto arc = it.get_curr();
238 if (is_arc_painted<GT>(arc))
239 continue;
240
241 auto tgt = it.get_tgt_node();
242 if (is_a_cut_node<GT>(tgt))
243 continue;
244
246 paint_subgraph(tgt);
247 }
248 }
249
251 {
253
254 // Paint connected blocks adjacent to p with different colors
255 for (Node_Arc_Iterator<GT, SA> it(p, sa); it.has_curr(); it.next_ne())
256 {
257 auto arc = it.get_curr();
258
260
261 auto tgt_node = it.get_tgt_node();
262 if (is_a_cut_node<GT>(tgt_node)) // is it a cut arc?
263 {
264 ARC_BITS(arc).set_bit(Cut, true); // mark as cut arc
265 continue; // move to next arc
266 }
267 else
268 {
269 paint_arc<GT>(arc, Cross_Arc); // mark as cross arc
270 if (is_node_painted<GT>(tgt_node))
271 continue;
272 }
273
274 // paint the block reachable through this arc
275 paint_subgraph(tgt_node);
276
277 curr_color++; // next color (next arc belongs to a different block)
278
280 }
281 }
282
284 const long & color,
285 GT & sg)
286 {
287 (void)color;
290
291 std::unique_ptr<typename GT::Node> tp_auto(new typename GT::Node(gp));
292 sg.insert_node(tp_auto.get());
294 NODE_BITS(gp).set_bit(Build_Subtree, true);
295
296 return tp_auto.release();
297 }
298
299 void map_subgraph(GT & sg, typename GT::Node *gsrc, const long & color)
300 {
302
303 auto tsrc = mapped_node<GT>(gsrc); // gsrc mapped into sg
304
305 // Traverse arcs of gsrc and insert into sg those with the requested color
306 for (Node_Arc_Iterator<GT, SA> i(gsrc, sa); i.has_curr(); i.next_ne())
307 {
308 auto garc = i.get_curr();
310 continue; // arc has a different color or was already visited
311
312 ARC_BITS(garc).set_bit(Build_Subtree, true);
313
314 auto gtgt = i.get_tgt_node();
315
317
318 typename GT::Node *ttgt = nullptr; // gtgt mapped into sg
319 if (IS_NODE_VISITED(gtgt, Build_Subtree)) // already in sg?
321 else
323
324 auto tarc = sg.insert_arc(tsrc, ttgt, garc->get_info());
326
327 map_subgraph(sg, gtgt, color);
328 }
329 }
330
331 public:
337 Compute_Cut_Nodes(const GT & g, SA __sa = SA())
338 : sa(__sa), gptr(&const_cast<GT &>(g)), state(Init)
339 {
340 /* empty */
341 }
342
353
361 void operator ()(typename GT::Node *start,
363 {
364 cut_nodes(start, list);
365 }
366
387 {
389 << "Cut nodes have not been computed or the class is in another phase";
390
393 curr_color = 1;
394
395 // Traverse each cut node and paint its adjacent blocks
397 i.has_curr(); i.next_ne())
398 paint_from_cut_node(i.get_curr());
399
400 state = Painted;
401
402 return curr_color;
403 }
404
415 void map_subgraph(GT & sg, const long & color)
416 {
417 ah_logic_error_if(state != Painted) << "Graph is not painted";
418
419 clear_graph(sg);
420
421 typename GT::Node *first = nullptr; // find the first node with the requested color
422
423 for (typename GT::Node_Iterator it(*gptr); it.has_curr(); it.next_ne())
424 if (get_color<GT>(it.get_curr()) == color)
425 first = it.get_curr();
426
427 if (first == nullptr) // did we find the color?
428 ah_domain_error_if(first == nullptr) << "Color does not exist in the graph";
429
430 // create first, insert it into sg, and map it
431 create_and_map_node(first, color, sg);
432 try
433 {
434 map_subgraph(sg, first, color); // map the component
435 }
436 catch (...)
437 {
438 clear_graph(sg);
439 }
440 }
441
462 {
463 ah_logic_error_if(state != Painted) << "Graph is not painted";
464
466
467 // Traverse the cut-node list and insert them into cut_graph
469 it.has_curr(); it.next_ne())
470 {
471 auto gp = it.get_curr();
472
474
475 std::unique_ptr<typename GT::Node> tp_auto(new typename GT::Node(gp));
476 cut_graph.insert_node(tp_auto.get());
477 GT::map_nodes(gp, tp_auto.release());
478 }
479
480 // Traverse arcs of g:
481 // - cut_graph will contain cut arcs (between cut nodes)
482 // - cross_arc_list will contain cross arcs (from cut nodes to blocks)
483 for (Arc_Iterator<GT, SA> it(*gptr, sa); it.has_curr(); it.next_ne())
484 {
485 auto garc = it.get_curr();
487 {
489 continue;
490 }
491
493 continue;
494
495 typename GT::Node *src = mapped_node<GT>(gptr->get_src_node(garc));
496 typename GT::Node *tgt = mapped_node<GT>(gptr->get_tgt_node(garc));
497
498 assert(src != nullptr and tgt != nullptr);
499
500 typename GT::Arc *arc =
501 cut_graph.insert_arc(src, tgt, garc->get_info());
502 GT::map_arcs(garc, arc);
503 }
504 }
505
524 GT & cut_graph,
526 {
528 << "Cut nodes have not been computed";
529
532
533 const long & num_colors = curr_color;
534
535 DynArray<GT *> blocks; // blocks in an array for fast access
536 // Whether it is empty or not indicates if it has been processed.
537 blocks.reserve(num_colors);
538
539 // Create an ordered list of empty components by color i
540 for (int i = 0; i < num_colors; ++i)
541 blocks.access(i) = &block_list.append(GT());
542
543 // Traverse nodes and copy/map according to color
544 for (typename GT::Node_Iterator it(*gptr); it.has_curr(); it.next_ne())
545 {
546 auto p = it.get_curr();
548 continue;
549
550 if (is_a_cut_node<GT>(p))
551 continue;
552
553 const long color = get_color<GT>(p);
554
555 GT & sg = *blocks.access(color - 1);
556
558
559 map_subgraph(sg, p, color);
560 }
561
563 }
564 };
565} // end namespace Aleph
566
567# endif // TPL_CUT_NODES_H
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
#define ah_logic_error_if(C)
Throws std::logic_error if condition holds.
Definition ah-errors.H:325
Computation of cut nodes (articulation points) of a graph.
void map_cut_graph(GT &cut_graph, DynDlist< typename GT::Arc * > &cross_arc_list)
Computes the mapped cut graph of a graph.
void map_subgraph(GT &sg, typename GT::Node *gsrc, const long &color)
GT::Node * create_and_map_node(typename GT::Node *gp, const long &color, GT &sg)
enum Aleph::Compute_Cut_Nodes::State state
void map_subgraph(GT &sg, const long &color)
Obtains a mapped copy of the component with the given color.
void operator()(DynDlist< typename GT::Node * > &list)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void paint_subgraph(typename GT::Node *p)
DynDlist< typename GT::Node * > * list_ptr
Compute_Cut_Nodes(const GT &g, SA __sa=SA())
Constructor for cut nodes calculator.
void compute_blocks(DynDlist< GT > &block_list, GT &cut_graph, DynDlist< typename GT::Arc * > &cross_arc_list)
Build mapped graphs around cut nodes.
void cut_nodes(typename GT::Node *start, DynDlist< typename GT::Node * > &list)
Computes the cut nodes.
long paint_subgraphs()
Paints the connected components around the cut nodes.
void cut_nodes(typename GT::Node *p, typename GT::Arc *a)
void paint_from_cut_node(typename GT::Node *p)
T & access(const size_t i) const noexcept
Fast access without checking allocation and bound_min_clock checking.
void reserve(const size_t l, const size_t r)
Allocate a range of entries.
Iterator dynamic list.
Dynamic doubly linked list with O(1) size and bidirectional access.
void empty() noexcept
Empty the list.
T & append(const T &item)
Append a copied item at the end of the list.
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Node * get_first_node() const
Return any node in the graph.
Definition tpl_graph.H:576
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
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
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
static void map_arcs(A1 *p, A2 *q) noexcept
Map the arcs through their cookies.
Definition graph-dry.H:1026
void reset_counter_nodes() const noexcept
Reset all the counters to zero for all the nodes of graph.
Definition graph-dry.H:1064
void reset_counter_arcs() const noexcept
Reset all the counters to zero for all the arcs of graph.
Definition graph-dry.H:1070
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
void for_each_node(Operation &operation) const
Unconditionally traverse all the nodes of graph and on each one perform an operation.
Definition graph-dry.H:1476
List_Graph< Graph_Node< int >, Graph_Arc< int > > GT
#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.
#define ARC_BITS(p)
Return the control bits of arc p.
void clear_graph(GT &g) noexcept
Clean a graph: all its nodes and arcs are removed and freed.
Definition tpl_graph.H:3549
#define IS_ARC_VISITED(p, bit)
Determine whether the bit field is or not set to one.
#define NODE_BITS(p)
Get the control bits of a node.
@ Depth_First
Definition aleph-graph.H:73
@ Build_Subtree
Definition aleph-graph.H:80
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
const long Cross_Arc
Special marker for arcs connecting a cut node to a non-cut block.
static long & color(typename GT::Node *p)
DynList< T > maps(const C &c, Op op)
Classic map operation.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1164
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1119
Utility algorithms and operations for graphs.